; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > &.Source.VduGrafF
;
; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver code - Solid & Dotted Line drawing routines
;
; Author R C Manby
; Date   27.10.86
;


;
;
;
;------------------------------------------------------------------------------
;
; DoOsbyte163_242 - Set dotted line length and return status information
; ===============
;
; We are only interested in OsByte 163,242,0..66
;
; OsByte 163,242,0..64 set dotted line length
;        163,242,0      set default dot pattern and length
;        163,242,1..64  set specified pattern length
;
; OsByte 163,242,65 return graphics status
;                   returns R1 = &Cn (means GXR on & flood on (for GXR))
;                                    (means SpriteRom on (for master/compact))
;                                  n = dotted line length MOD 64
;                           R2 = number of sprite pages
;
; OsByte 163,242,66 return sprite status
;                   returns R1 = R2 = 0 if no sprite selected
;                           R1 = current sprite width
;                           R2 = current sprite height
;
; When entered, we know it is FX 163,242,n
; Exit by MOV PC, R14 if still don't understand (ie n>66)
; Otherwise exit with Pull PC

DoOsbyte163_242 ROUT
        CMP R2,#66
        MOVHI PC, R14                   ; Not 0..66, so pass it on

        Push "R3-R12"                   ; Preserve the world
        VDWS WsPtr                      ; Point R12 at Vdu driver workspace

        CMP R2,#65
        BLLT SetPatLength               ; R2 holds 0/1..64    ; PSR preserved
        BLT OsByte_QuitA
        BGT OsByte163_242_66

OsByte163_242_65                        ; OsByte 163,242,65 - graphics status
        LDR R1,[WsPtr,#DotLineLength]
        AND R1,R1,#&3F                  ; Dot count MOD 64
        ORR R1,R1,#&C0                  ; GXR on, Flood on
        LDR R2,[WsPtr,#SpAreaStart]
        CMP R2,#0
        LDRNE R2,[R2,#saEnd]            ; SpriteWS size
        B OsByte_QuitA

OsByte163_242_66                        ; OsByte 163,242,66 - sprite status

        MOV R0,#SpriteReason_ReadSpriteSize
        LDR R2,=SpChooseName
        ADD R2,R2,WsPtr                 ; Sprite name ptr

        SWI XOS_SpriteOp

        MOVVS R1,#0                     ; If no sprite memory, or no sprite
        MOVVS R2,#0                     ; chosen, return 0,0 as width,height

        MOVVC R1,R3                     ; else return width,height in pixels
        MOVVC R2,R4

OsByte_QuitA
        Pull "R3-R12,PC"                ; restore registers and claim call
;
;
;
;------------------------------------------------------------------------------




        MACRO
        WriteToScreen $Adr,$Msk,$Ecf, $a,$b,$c
        LDMIA $Ecf,{$a,$b}
        AND $a,$a,$Msk
        AND $b,$b,$Msk
 [ AvoidScreenReads
        CMP $a,#&FFFFFFFF
        LDRNE $c,[$Adr]
 |
        LDR $c,[$Adr]
 ]
        ORR $c,$c,$a
        EOR $c,$c,$b
        STR $c,[$Adr]
        MEND


;
;
;
;------------------------------------------------------------------------------




rXCnt    RN 0
rYCnt    RN 1
rBres    RN 2
rDeltaY  RN 3
rPixShft RN 4
rScrAdr  RN 5
rPixMsk  RN 6
rDotPtr  RN 7

rEcfPtr  RN 8

rEcfBase RN 8
rEcfIndx RN 9
rDeltaX  RN 10
rScanStp RN 11

rDotCnt    RN 9
rDotPatLSW RN 10
rDotPatMSW RN 11

rDOTCnt    RN 10
rDOTPatLSW RN 11
rDOTPatMSW RN 14


;
;------------------------------------------------------------------------------
;
; LineDraw - General line drawing routine
; ========
;
; On entry, ICursor is the start point of the line
;           NewPt is the end point
;
;           R2 holds plot code, where bits mean :-
;              bit 5  clear/set - include/exclude initial point
;              bit 4  clear/set - solid/dotted line
;              bit 3  clear/set - include/exclude final point
;
;              bit 5  implies   - restart/continue dot pattern
;
LineDrawSolid
        TST     R2, #&03                ; if a no action one
        MOVEQ   PC, R14                 ; then do nowt, just shunt coords
LineDrawDotted ROUT
        EOR     R11, R2, #&18   ; Flip solid/dotted flag, and final point flag
                                ; bit 4 set/clear - solid/dotted line
                                ; bit 3 set/clear - include/exclude final point
        MOV     R9, #0
        ADD     R10, WsPtr, #LineDotCnt

        TST     R11, #&10
        STRNE   R9, [WsPtr, #LineDotPtr]        ; Solid line
        STREQ   R10, [WsPtr, #LineDotPtr]       ; Dotted line

        TSTEQ   R11, #&20               ; If dotted line & first point included
        STREQ   R9, [WsPtr, #LineDotCnt] ; then force a restart of the pattern

        STR     R9, [WsPtr, #PostCycleCount]    ; Assume all dots get plotted

        ADD R0,WsPtr,#GCsIX             ;Start ICursor
        LDMIA R0,{R0,R1,R2,R3}          ;End NewPt

        TEQ     R1, R3                  ; If line is horizontal
        BEQ     TryHLine                ; try to use HLine
        [ UseVLineOnSolidLines
        TEQ     R0, R2                  ; If line is vertical
        BEQ     TryVLine                ; try to use VLine
CantUseVLine
        ]
CantUseHLineOrVLine
        SaveRetAdr

        Difference R4,R0,R2
        Difference R5,R1,R3
        Greatest R10,R4,R5
        ADD R10,R10,#1                  ;Total number of dots on line

        BL GenLineParm                  ;Generate line control block
                                        ; in R0..R8

        TST R11,#&20                    ;If first point excluded
        SUBNE R10,R10,#1                ; then dec DotCycleCount and
        BLNE AdvLineParm                ;      advance to first pixel and

        TST R11,#&08                    ;If last point excluded
        SUBEQ R10,R10,#1                ; then dec DotCycleCount

        CMP R10,#0                      ;IF DotCycleCount <= 0
        Return LE                       ; then nothing to plot

        STR R10,[WsPtr,#DotCycleCount]
        STR R11,[WsPtr,#LineEndPtFlags]

        WINDow R0,R1, R9,R10,R11,R14    ;If start point outside window
        BLLT LineStartsOutsideWindow    ; then panic {won't return if whole
                                        ;             line outside window}

        WINDow R7,R8, R9,R10,R11,R14    ;If end point outside window
        BLLT LineEndsOutsideWindow      ; then panic as well

;
; R0    ,R1    ,R2  ,R3    ,R4    ,R5   ,R6
; StartX,StartY,Bres,DeltaX,DeltaY,StepX,StepY
;

                                        ;Modify StepX (+1/-1 means right/left)
        CMP R5,#0                       ; to give PixelMask shift factor
        LDR R5,[WsPtr,#BytesPerChar]    ; "Left"
        RSBPL R5,R5,#0                  ; "Right"

                                        ;Modify StepY (+1/-1 means up/down)
        CMP R6,#0                       ; to give offset to next scan line
        LDR R6,[WsPtr,#LineLength]      ; "Down"
        RSBPL R6,R6,#0                  ; "Up"

        Push "R2-R6"                    ;Bres,DeltaX,DeltaY,StepX,StepY

        BL ScreenAddr
        MOV R7,R2                       ;Screen Adr
        MOV R8,R3                       ;Pixel Mask

        LDR R9,[WsPtr, #YWindLimit]
        SUB R9,R9,R1                    ;subtract Y from YWindLimit
        AND R9,R9,#7                    ;EcfIndx

        Pull "R2-R6"                    ;Bres,DeltaX,DeltaY,StepX,StepY

        LDR R0,[WsPtr,#DotCycleCount]   ;Number of on screen pixels
        CMP R0,#0                       ; An LPO line starting outside & ending
        Return LE                       ;  on the window leaves zero dots!

        LDR R1,[WsPtr,#LineDotPtr]
        CMP R1,#0
        BNE DotDashLine

SolidLine ROUT
        Push    R12
        LDR     R1, [WsPtr, #GColAdr]           ; Base address of ECF
        ADD     R1, R1, R9, LSL #3              ; current address of ECF
;
; R0    ,R1     ,R2  ,R3    ,R4    ,R5     ,R6     ,R7    ,R8  ,R9
; PixCnt,EcfBase,Bres,DeltaX,DeltaY,MskShft,LineStp,ScrAdr,Mask,Indx
;

        LDMIA   R1,  {R9, R10}                  ; R9 = zgora; R10 = zgeor
20
        MOV     R12, R8
30
        SUBS    R0, R0, #1                      ; Dec pixel count
        BEQ     %FT57                           ; if zero, then finish off

40
; Advance the screen address and pixel mask one pixel

        TEQ     R2, #0                  ; If Bres positive
        BPL     %FT55                   ; then advance in X dirn only
                                        ; else advance in Y direction, which
                                        ; may involve advancing X afterwards
45
        AND     R14, R9, R12                    ; R14 = zgora AND pixmask
 [ AvoidScreenReads
        CMP     R14, #&FFFFFFFF
        LDRNE   R11, [R7]                       ; R11 = word from screen
 |
        LDR     R11, [R7]                       ; R11 = word from screen
 ]
        ORR     R11, R11, R14                   ; OR with screen
        AND     R14, R10, R12                   ; R14 = zgeor AND pixmask
        EOR     R11, R11, R14                   ; EOR with screen
        STR     R11, [R7], R6                   ; and store back, moving on

        CMP     R6, #&80000000          ; C=1 => going up the screen
        TSTCS   R1, #63                 ; so check being at word 0 of ECF
        SUBCS   R1, R1, #8              ; and then subtract 2 words
        ADDCC   R1, R1, #8              ; else add on 2 words first
        TSTCC   R1, #63                 ; and then test for wrap
        BEQ     %FT60
        LDMIA   R1,  {R9, R10}          ; reload zgora and zgeor
        ADDS    R2, R2, R3              ; Advance Bres, in Y dirn

        BMI     %BT20                   ; [don't need to move in X direction]
50
        MOV     R12, #0                 ; clear total pixel mask
55
;
; Advance in X direction
;
        CMP     R5, #&80000000          ; if +ve then RORing, so test if
        TSTCC   R8, #1                  ; bottom bit set before shifting
        MOV     R8, R8, ROR R5          ; shift word
        TSTCS   R8, #1                  ; else test after shifting
        SUB     R2, R2, R4              ; always advance Bres in X direction
        ORREQ   R12, R12, R8            ; if not wrapped, OR in new pixel
        BEQ     %BT30                   ; and loop

57
 [ AvoidScreenReads
        TEQ     R12, #0
        BEQ     %FT58
 ]
        AND     R14, R9, R12                    ; R14 = zgora AND pixmask
 [ AvoidScreenReads
        MVNS    R11, R14
        LDRNE   R11, [R7]                       ; R11 = word from screen
 |
        LDR     R11, [R7]                       ; R11 = word from screen
 ]
        ORR     R11, R11, R14                   ; OR with screen
        AND     R14, R10, R12                   ; R14 = zgeor AND pixmask
        EOR     R11, R11, R14                   ; EOR with screen
 [ AvoidScreenReads
        STR     R11, [R7]                       ; and store back
58      SUBCC   R7, R7, #4                      ; increment or decrement
        ADDCS   R7, R7, #4
 |
        STRCC   R11, [R7], #-4                  ; and store back
        STRCS   R11, [R7], #4                   ; incrementing or decrementing
 ]

        MOV     R12, R8                 ; reset total pixel mask

        SUBS    R0, R0, #1
        Pull    "R12, PC", LT           ; exit if COMPLETELY finished
        BEQ     %BT57                   ; if no more to do, then output word!
        TEQ     R2, #0                  ; test Bres again
        BPL     %BT55
        B       %BT45


; come here when ECF wraps (ie every eight Y coords)

60
        ADDCS   R1, R1, #64             ; if wrap and going up, then add 64
        SUBCC   R1, R1, #64             ; if wrap and going down, subtract 64
        LDMIA   R1,  {R9, R10}          ; reload zgora and zgeor
        ADDS    R2, R2, R3              ; Advance Bres, in Y dirn
        BMI     %BT20                   ; [don't need to move in X direction]
        B       %BT50

; *****************************************************************************
;
;       TryHLine - Try to use HLine (we already know Y1=Y2)
;
; in:   R0 = X1
;       R1 = R3 = Y
;       R2 = X2
;       R11 = plot code EOR &18
;         bit 3 set => include last point
;         bit 4 set => solid
;         bit 5 set => exclude first point
;

TryHLine ROUT
        TST     R11, #&10               ; is it dotted
        BEQ     CantUseHLineOrVLine     ; yes, then can't use HLine

        CMP     R2, R0
        MOVGE   R4, #1
        MOVLT   R4, #-1
        TST     R11, #&20               ; if first point excluded
        ADDNE   R0, R0, R4              ; then move R0 one pixel towards R2
        TST     R11, #&08               ; if last point excluded
        SUBEQ   R2, R2, R4              ; then move R2 one pixel towards R0

        CMP     R2, R0                  ; check order again
        EORLT   R0, R0, R2              ; make sure R0 <= R2
        EORLT   R2, R0, R2
        EORLT   R0, R0, R2
        RSBLT   R4, R4, #0              ; if swapped, then invert sign of R4
        TEQNE   R4, #1                  ; if order is now different
                                        ; (and they're not equal now)
        MOVNE   PC, R14                 ; then there's nothing to plot
        B       NewHLine                ; else go and do it!

; *****************************************************************************
;
;       TryVLine - Try to use VLine (we already know X1=X2)
;
; in:   R0 = R2 = X
;       R1 = Y1
;       R3 = Y2
;       R11 = plot code EOR &18
;         bit 3 set => include last point
;         bit 4 set => solid
;         bit 5 set => exclude first point
;

TryVLine ROUT
        TST     R11, #&10               ; is it dotted
        BEQ     CantUseHLineOrVLine     ; yes, then can't use VLine (or HLine)

; now make sure that we are using a solid pattern (not an ECF)
; this is true if the appropriate GCOL action is < 8

        AND     R4, R11, #3             ; look at bottom 2 bits of R11
        CMP     R4, #2                  ; to check which action
                                        ; (already ruled out 0 (no action))
        LDRCC   R4, [WsPtr, #GPLFMD]    ; <2 => 1 => foreground action
        MOVEQ   R4, #4                  ; =2 => 2 => invert action
        LDRHI   R4, [WsPtr, #GPLBMD]    ; >2 => 3 => background action
        CMP     R4, #8                  ; is it a solid action
        BCS     CantUseVLine

        CMP     R3, R1
        MOVGE   R4, #1
        MOVLT   R4, #-1
        TST     R11, #&20               ; if first point excluded
        ADDNE   R1, R1, R4              ; then move R1 one pixel towards R3
        TST     R11, #&08               ; if last point excluded
        SUBEQ   R3, R3, R4              ; then move R3 one pixel towards R1

        CMP     R3, R1                  ; check order again
        EORLT   R1, R1, R3              ; make sure R1 <= R3
        EORLT   R3, R1, R3
        EORLT   R1, R1, R3
        RSBLT   R4, R4, #0              ; if swapped, then invert sign of R4
        TEQNE   R4, #1                  ; if order is now different
                                        ; (and they're not equal now)
        MOVNE   PC, R14                 ; then there's nothing to plot
        B       NewVLine                ; else go and do it!


;
;
;
DotDashLine

;
; R0    ,R1    ,R2  ,R3    ,R4    ,R5     ,R6     ,R7    ,R8  ,R9
; PixCnt,DotPtr,Bres,DeltaX,DeltaY,MskShft,LineStp,ScrAdr,Mask,Indx
;

DotDash20
        LDMIA R1,{rDOTCnt,rDOTPatLSW,rDOTPatMSW}

        CMP rDOTCnt,#0

        ADDEQ rDOTCnt,WsPtr,#DotLineStyle               ;Restart pattern
        LDMEQIA rDOTCnt,{rDOTPatLSW,rDOTPatMSW}
        LDREQ rDOTCnt,[WsPtr,#DotLineLength]

        SUB rDOTCnt,rDOTCnt,#1

        MOVS rDOTPatMSW,rDOTPatMSW,LSL #1
        ORR rDOTPatMSW,rDOTPatMSW,rDOTPatLSW,LSR #31
        MOV rDOTPatLSW,rDOTPatLSW,LSL #1

        STMIA R1,{rDOTCnt,rDOTPatLSW,rDOTPatMSW}

        BCC DotDash30                           ;Don't plot this dot

        LDR R10,[WsPtr,#GColAdr]                ;Base address of ECF
        ADD R10,R10,R9,LSL #3                   ;Address of ECFora & ECFeor
        WriteToScreen R7,R8,R10, R10,R11,R14

DotDash30
        SUBS R0,R0,#1                           ;Dec pixel count
        BEQ DotDash60                           ;Finished on screen

DotDash40
;
; Advance the screen address and pixel mask one pixel
;

        CMP R2,#0               ;If Bres positive
        BPL DotDash50           ;then advance in X dirn only
                                ;else advance in Y direction, which may
                                ;     involve advancement in X afterwards

        CMP R6,#0               ;Advance Ecf to next scanline
        SUBLT R9,R9,#1          ; "Up" = (Old-1) Mod 7
        ADDGE R9,R9,#1          ; "Doun" = (Old+1) Mod 7
        AND R9,R9,#7

        ADD R7,R7,R6                    ;Advance screen address one scanline

        ADDS R2,R2,R3                   ;Advance Bres, in Y dirn
        BMI DotDash20                   ;
                                        ; may now need advancing in X dirn
DotDash50
;
; Advance in X direction
;
; Rotate PixMsk to next pixel position, altering ScrAdr if we cross to
;  the next word.
;

        TST     R8, R5                  ;If PixMsk at MSEnd of word
                                        ; and shifting left
        ADDMI   R7, R7, #4              ;then inc ScrAdr  {PixMsk will wrap}

        MOVS    R8, R8, ROR R5          ;Move PixMsk

                                        ;If PixMsk now at MSEnd of word
        RSBMIS  R11, R5, #0             ; and shift was right
        SUBMI   R7, R7, #4              ;then dec ScrAdr  {PixMsk wrapped}

        SUB     R2, R2, R4              ;Advance Bres, in X dirn
        B       DotDash20

DotDash60

        LDR R0,[WsPtr,#PostCycleCount]
        CMP R0,#0
        BLNE AdvanceDotPattern

        Return

        LTORG

 DCD 0 ; *** Inserted for diagnostic purposes !  ***

;
;
;
;------------------------------------------------------------------------------
;
; LineEndsOutSideWindow
; =====================
;
LineEndsOutsideWindow

        Push "R0-R8,Link"       ;Push whole parameter block

        ADD R0,WsPtr,#GCsIX             ;Start ICursor
        LDMIA R0,{R0,R1,R2,R3}          ;End NewPt
        Swap R0,R2
        Swap R1,R3

        BL GenLineParm                  ;Generate line control block
                                        ; in R0..R8
        LDR R11,[WsPtr,#LineEndPtFlags]

        TST R11,#&08                    ;If last point excluded
        BLEQ AdvLineParm                ; then advance to actual last point

        Push "R0,R1"                    ;EndX,EndY

        WindowRes R11,R0,R1, R7,R8,R9,R10       ;R11 := Window(End)

;
; R0  ,R1  ,R2  ,R3    ,R4    ,R5   ,R6   ,        ,R11
; EndX,EndY,Bres,DeltaX,DeltaY,StepX,StepY,        ,WEnd
;

        TST R11,#&C                             ;If above/below window
        BEQ LEO10

        BL InYWind                              ; then bring Y into window

        WindowRes R11,R0,R1, R7,R8,R9,R10       ;R11 := Window(NewEnd)

LEO10
        TST R11,#&3
        BEQ LEO20                       ;If start outside X window

        BL InXWind

        WindowRes R11,R0,R1, R7,R8,R9,R10       ;R11 := Window(NewEnd)

LEO20
        Pull "R9,R10"                           ;EndX,EndY

        Difference R0,R0,R9
        Difference R1,R1,R10
        Greatest R0,R0,R1

        LDR R1,[WsPtr,#DotCycleCount]
        SUB R1,R1,R0
        STR R1,[WsPtr,#DotCycleCount]
        STR R0,[WsPtr,#PostCycleCount]

        Pull "R0-R8,PC"
;
;
;
;------------------------------------------------------------------------------
;
; LineStartsOutSideWindow
; =======================
;
LineStartsOutsideWindow

        Push Link
        Push "R0,R1"                    ;StartX,StartY

        Push "R5,R6"
        WindowRes R10,R0,R1, R5,R6,R9,R14       ;R10 := Window(Start)
        WindowRes R11,R7,R8, R5,R6,R9,R14       ;R11 := Window(End)
        Pull "R5,R6"

        TST R10,R11
        BNE LineOutsideWindow           ;Line completely outside window


;
; R0    ,R1    ,R2  ,R3    ,R4    ,R5   ,R6   ,R7  ,R8    ,R10   ,R11
; StartX,StartY,Bres,DeltaX,DeltaY,StepX,StepY,EndX,EndY  ,WStart,WEnd
;

        TST R10,#&C                             ;If above/below window
        BEQ LSO10

        Push R11
        BL InYWind                              ; then bring Y into window
        Pull R11

        Push "R6-R8"
        WindowRes R10,R0,R1, R6,R7,R8,R9       ;R10 := Window(NewStart)
        Pull "R6-R8"

        TST R10,R11
        BNE LineOutsideWindow           ;Line completely outside window
LSO10
        TST R10,#&3
        BEQ LSO20                       ;If start outside X window

        Push R11
        BL InXWind
        Pull R11

        Push "R6-R8"
        WindowRes R10,R0,R1, R6,R7,R8,R9        ;R10 := Window(NewStart)
        Pull "R6-R8"
        CMP R10,#0

        BNE LineOutsideWindow           ;Cannot clip to window
LSO20
        Pull "R9,R10"           ;StartX,StartY

        Push "R0-R8"
        Difference R0,R0,R9
        Difference R1,R1,R10
        Greatest R0,R0,R1
        BL AdvanceDotPattern
        Pull "R0-R8"

        Pull "PC"


LineOutsideWindow
        Pull "R0,R1"                    ;Balance the stack
        LDR R0,[WsPtr,#DotCycleCount]
        BL AdvanceDotPattern

        Pull "Link"
        Return                          ;To caller of the line routine
;
;
;
;------------------------------------------------------------------------------
;


lpStartX  RN 0
lpStartY  RN 1
lpBres    RN 2
lpDeltaX  RN 3
lpDeltaY  RN 4
lpStepX   RN 5
lpStepY   RN 6






;
; InYWind - Bring a set of line parameters into the Y window
; =======
;
; On entry, R0-R6 contain a line parameter block
;       R0 - StartX
;       R1 - StartY
;       R2 - Bres
;       R3 - DeltaX
;       R4 - DeltaY
;       R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version)
;       R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version)
;       R7 - EndX
;       R8 - EndY
;
;       R9  - gwbrow
;       R10 - gwtrow
;
; Algorithm:
;  1. Calculate distance to Y window
;  2. Change StartY by (distance-1)
;  3. Add (distance-1)*DeltaX to Bres
;  4. Divide Bres by DeltaY
;  5. Subtract (quotient+1)*DeltaY from Bres
;  6. Change StartX by (quotient+1)
;  7. Do one more pixel advance by AdvLineParm
;      (N.B. this is always the Bres -ve case)
;
;
;
InYWind
        SaveRetAdr

        LDR R9,[WsPtr,#GWBRow]
        LDR R10,[WsPtr,#GWTRow]
                                        ;(1)
        CMP lpStepY,#0
        SUBGE R11,R9,lpStartY
        SUBLT R11,lpStartY,R10
        SUB R11,R11,#1                  ;(Distance to window) - 1

        BL InYW30                       ;Steps 2-6

        BL AdvLineParm                  ;Step to first pixel in window
        Return
;
; Flags still valid, GE/LT
;
; R11 holds distance to window -1
;
InYW30                                  ;(2)
        ADDGE lpStartY,lpStartY,R11             ;StartY := GWBRow-1
        SUBLT lpStartY,lpStartY,R11             ;StartY := GWTRow+1
                                        ;(3)
        MOV R10,lpDeltaX
        MUL R9,R11,R10
        ADDS lpBres,lpBres,R9                   ;Bres := Bres+(dist-1)*DeltaX

                                                ;If lpBres now -ve,
        MOVLT PC,Link                           ;then don't modify StartX
                                                ;     (quotient+1 is 0)
                                                ;else
        MOV R10,lpDeltaY
; *****Change made by DJS
; Use new DivRem macro, not old DIVREM
; Original code was:
;        DIVREM R11,lpBres,R10,R9
        DivRem R11,lpBres,R10,R9
; *****End of change made by DJS
        SUB lpBres,lpBres,lpDeltaY

        ADD R11,R11,#1                          ; quotient := 1+bres/deltay
                                        ;(6)
        CMP lpStepX,#0
        ADDGE lpStartX,lpStartX,R11
        SUBLT lpStartX,lpStartX,R11

        MOV PC,Link




;
; InXWind - Bring a set of line parametres into the X window
; =======
;
; On entry, R0-R6 contain a line parameter block
;       R0 - StartX
;       R1 - StartY
;       R2 - Bres
;       R3 - DeltaX
;       R4 - DeltaY
;       R5 - StepX (+1/-1) (Equv bit6 of Sign in 6502 version)
;       R6 - StepY (+1/-1) (Equv bit7 of Sign in 6502 version)
;       R7 - EndX
;       R8 - EndY
;
;       R9  - gwlcol
;       R10 - gwrcol
;
; Algorithm:
;  1. Replace Bres by -Bres-1
;  2. Swap StartX and StartY
;  3. Swap DeltaX and DeltaY
;  3a Swap StepX and StepY
;  4. Calculate distance to X window
;  5. Do steps 2-6 of InYWind
;  6. Repeat steps 1-3
;  7. Do one more pixel advance by AdvLineParm
;      (N.B. this is always the Bres +ve case)
;
InXWind
        SaveRetAdr

        LDR R9,[WsPtr,#GWLCol]
        LDR R10,[WsPtr,#GWRCol]
                                        ;(1)
        MVN lpBres,lpBres
                                        ;(2)(3)
        Push "lpStartX,lpDeltaX,lpStepX"
        Push "lpStartY,lpDeltaY,lpStepY"
        Pull "lpStartX,lpDeltaX,lpStepX"
        Pull "lpStartY,lpDeltaY,lpStepY"

        CMP lpStepY,#0                  ;Really StepX
        SUBGE R11,R9,lpStartY
        SUBLT R11,lpStartY,R10
        SUB R11,R11,#1                  ;(Distance to window) - 1

        BL InYW30                               ;Steps 2-6
                                        ;(1)
        MVN lpBres,lpBres
                                        ;(2)(3)
        Push "lpStartX,lpDeltaX,lpStepX"
        Push "lpStartY,lpDeltaY,lpStepY"
        Pull "lpStartX,lpDeltaX,lpStepX"
        Pull "lpStartY,lpDeltaY,lpStepY"

        BL AdvLineParm                  ;Step to first pixel in window
        Return




;
; rDotPtr    RN 7
; rDotCnt    RN 9
; rDotPatLSW RN 10
; rDotPatMSW RN 11

;
; On entry R0 holds number of places to step dot pattern
;
AdvanceDotPattern
        LDR R1,[WsPtr,#DotCycleCount]
        SUB R1,R1,R0
        STR R1,[WsPtr,#DotCycleCount]

        LDR rDotPtr,[WsPtr,#LineDotPtr]
        CMP rDotPtr,#0
        MOVEQ PC,Link

        LDR R1,[WsPtr,#DotLineLength]
        MOV R2,R1
; *****Change made by DJS
; Use new DivRem macro, not old DIVREM
; Original code was:
;        DIVREM R3,R0,R2,R4              ;R0:=R0 REM DotLineLength
        DivRem R3,R0,R2,R4              ;R0:=R0 REM DotLineLength
; *****End of change made by DJS

        LDMIA rDotPtr,{rDotCnt,rDotPatLSW,rDotPatMSW}

        CMP rDotCnt,R0
        SUBLT R0,R0,rDotCnt

        ADDLT rDotCnt,WsPtr,#DotLineStyle               ;Restart pattern
        LDMLTIA rDotCnt,{rDotPatLSW,rDotPatMSW}
        LDRLT rDotCnt,[WsPtr,#DotLineLength]

        SUB rDotCnt,rDotCnt,R0                          ;New value

 [ {TRUE}

; need special code if R0 > 32

        RSBS    R1, R0, #32
        MOVLT   rDotPatMSW, rDotPatLSW
        MOVLT   rDotPatLSW, #0                          ; probably not necessary
        SUBLT   R0, R0, #32
        RSBLT   R1, R0, #32

        MOV rDotPatMSW,rDotPatMSW,LSL R0
        ORR rDotPatMSW,rDotPatMSW,rDotPatLSW,LSR R1
        MOV rDotPatLSW,rDotPatLSW,LSL R0
 |

; old code

        RSB R1,R0,#32
        MOV rDotPatMSW,rDotPatMSW,LSL R0
        ORR rDotPatMSW,rDotPatMSW,rDotPatLSW,LSR R1
        MOV rDotPatLSW,rDotPatLSW,LSL R0
 ]

        STMIA rDotPtr,{rDotCnt,rDotPatLSW,rDotPatMSW}

        MOV PC,Link
;
;---------------------------------------------------------------------------
;

        END