; 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.VduGrafA
;
; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver code - Graphics rectangle, triangle
;
; Author R C Manby
; Date   5.9.86
;

; *****************************************************************************
;
;       GenLineParm - Generate a control block for a line
;
;       Internal routine, called by TriangleFill, LowerTri, ParallelogramFill,
;        SegmentLineO5, GenArcParmBlk, GenSegParmBlk, LineDraw
;
; in:   R0 (X), R1(Y) hold start of line
;       R2 (X), R3(Y) hold end of line
;
; out:  R0..R6 hold the following control 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
;

GenLineParm ROUT
        MOV     R7, R2          ; EndX,EndY - might be worth passing them
        MOV     R8, R3          ;            in R7,R8 not R2,R3

        SUB     R3, R7, R0      ; Crude deltaX
        SUB     R4, R8, R1      ; Crude deltaY

        CMP     R4, R3
        MOVLT   R2, #0          ; if deltaY >= deltaX R2 := -1
        MOVGE   R2, #-1         ;                else R2 := 0
                                ; this is used to fudge the bres
                                ; variable so lines of grad -1 are
                                ; the same as lines of grad 1

        MOVS    R5, R3, ASR #31 ; R5 := SGN(DeltaX)
        MOVPL   R5, #1
        RSBMI   R3, R3, #0      ; DeltaX := ABS(DeltaX)

        MOVS    R6, R4, ASR #31 ; R6 := SGN(DeltaY)
        MOVPL   R6, #1
        RSBMI   R4, R4, #0      ; DeltaY := ABS(DeltaY)

        CMP     R4, R3          ; Bres = MAX(DeltaX,DeltaY) + fudge factor
        ADDPL   R2, R4, R2
        ADDMI   R2, R3, R2

        RSB     R2, R4, R2, ASR #1 ; Bres = Bres/2 - DeltaY
        MOV     PC, R14         ; Return

; *****************************************************************************
;
;       AdvLineParm - Advance a set of line parameters
;
;       Internal routine, called by TrapFill, SegLineStep, ArcLineStep,
;        LineDraw, InYWind, InXWind
;
; in:   R0..R6, (R7,R8) hold a line parameter block
;
; out:  R0 (X), R1 (Y) R2 (Bres) updated
;
; Format of a control block
;       R0 - StartX (CurrentX)
;       R1 - StartY (CurrentY)
;       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            (Not used in this routine, so)
;       R8 - EndY            (doesnt need to be passed in)
;

AdvLineParm ROUT
        CMP     R2, #0          ; If Bres +ve, advance in X dirn only
        ADDLT   R1, R1, R6      ; Advance in Y dirn
        ADDLTS  R2, R2, R3      ; Add DeltaX to Bres
                                ; If new Bres +ve advance X as well
                                ; Advance X
        SUBGE   R2, R2, R4      ; Sub DeltaY from Bres to advance in X dirn
        ADDGE   R0, R0, R5      ; Add or subtract 1 dependent on sign DeltaX
        MOV     PC, R14

; *****************************************************************************
;
;       AdvLineParm_GE - Macro to advance line in XDirn if flags are GE
;
;       Used by Triangles,Parallelograms,Arcs etc
;
; Use:          CMP R2,#0
;               AdvLineParm_GE
;
; Instead of:   CMP R2,#0
;               BLGE AdvLineParm
;

        MACRO
        AdvLineParm_GE
        SUBGE   R2, R2, R4
        ADDGE   R0, R0, R5
        MEND

; *****************************************************************************
;
;       RectangleFill - Fill a rectangle
;
;       External routine, and RectFillA entry point used by BlockCopyMove, CLG
;        and RectFillB entry point used by PlotMask
;
; in:   ICursor & NewPt mark a diagonal of the rectangle
;
; out:  R0-R11 corrupt
;
;

RectangleFill ROUT
        ADD     R11,WsPtr,#GCsIX        ; load ICursor & NewPt
        LDMIA   R11, {R0-R3}
RectFillA
        Push    R14
RectFillB
        SortT   R0, R2, R11             ; ensure R0 holds the lesser X value
        SortT   R3, R1, R11             ; ensure R1 holds the higher Y value

        BL      CheckAcceleration
        BNE     RectFillC

; try calling GraphicsV for some acceleration

; R0 = left, R1 = top, R2 = right, R3 = bottom

        ADD     R4, WsPtr, #GWLCol
        LDMIA   R4, {R4-R7}             ; GWLCol,GWBRow,GWRCol,GWTRow

        CMP     R6, R0                  ; Test xcoords against window
        CMPGE   R2, R4
        CMPGE   R7, R3                  ; Test ycoords against window
        CMPGE   R1, R5
        MOVLT   PC, R14                 ; Quit if above,below,left or right

        Greatest R0, R0, R4             ; Clip all coords to window
        Greatest R3, R3, R5
        Least   R2, R2, R6
        Least   R1, R1, R7

        LDR     R4, [WsPtr, #GColAdr]
        Push    "R0-R4"
        MOV     R0, #GVRender_Sync
        MOV     R1, #GVRender_FillRectangle
        MOV     R2, R13
        LDR     R4, [WsPtr, #CurrentGraphicsVDriver]
        MOV     R4, R4, LSL #24
        ORR     R4, R4, #GraphicsV_Render
        BL      CallGraphicsV
        TEQ     R4, #GraphicsV_Complete
        Pull    "R0-R4"
        Pull    PC, EQ

; if it didn't claim, we proceed with the pre-clipped coordinates

RectFillC
        MOV     R11, R3                 ; place end Y out of harm's way
10
        BL      NewHLine
        SUB     R1, R1, #1              ; step Y down a line
        CMP     R1, R11
        BGE     %BT10
        Pull    PC

; *****************************************************************************
;
;       TriangleFill - Triangular area fill
;
;       External routine
;
; in:   OldCs, ICursor & NewPt are verticies of the triangle
;
; out:  R0-R11 corrupt
;

TriangleFill ROUT
        Push    R14
        ADD     R11, WsPtr, #OldCsX             ; vertices are OldCs,ICursor
        LDMIA   R11, {R0-R5}                    ; and NewPt
        BL      LowerTri                        ; sort vertices and fill the
                                                ; lower triangle
        ADD     R11, WsPtr, #Vertex2X           ; restart TLine1 to run from
        LDMIA   R11, {R0-R3}                    ; Vertex2 to Vertex3
        ADD     R11, WsPtr, #TLine1
TriangleFil5                                    ; entry point from par fill
        BL      GenLineParm
        STMIA   R11, {R0-R8}                    ; initialise parameter block
        STR     R8, [WsPtr, #TEndY]             ; end Y point for both lines
        BL      TrapFill                        ; fill the upper trapezoid
        MOV     R0, R9                          ; fill top line LeftX,RightX
        MOV     R2, R10                         ; leftY already in R1
        BL      NewHLine
        Pull    PC

; *****************************************************************************
;
;       LowerTri - Sort 3 vertices and fill the lower triangle between the
;        points up to but excluding the horizontal through the middle point
;
;       Internal routine, called by TriangleFill and ParallelogramFill
;

LowerTri ROUT
        Push    R14
        CompSwapT R0,R1, R2,R3, R14 ; bubble highest vertex into R4,R5
        CompSwapT R2,R3 ,R4,R5, R14

        CompSwapT R0,R1, R2,R3, R14 ; place lowest in R0,R1 and middle in R2,R3

        ADD     R11, WsPtr, #Vertex1X
        STMIA   R11, {R0-R7}                    ; save all our vertices

        MOV     R9, R0                          ; initalise TLeftX,TRightX
        MOV     R10, R0                         ; to lowest point
        BL      GenLineParm                     ; Run TLine1 from lowest to
        ADD     R11, WsPtr, #TLine1             ; middle point
        STMIA   R11, {R0-R8}
        STR     R8, [WsPtr, #TEndY]             ; this line ends first

        ADD     R2, WsPtr, #Vertex3X            ; run TLine2 from lowest to
        LDMIA   R2, {R2, R3}                    ; highest point
        BL      GenLineParm
        ADD     R11, WsPtr, #TLine2
        STMIA   R11, {R0-R8}
        BL      TrapFill                        ; fill the lower trapezoid

        Pull    PC

; *****************************************************************************
;
;       ParallelogramFill - Fill a parallelogram
;
;       External routine
;
; in:   OldCs, ICursor & NewPt are 3 vertices of the parallelogram
;
; out:  R0-R11 corrupt
;

ParallelogramFill ROUT
        Push    R14
        ADD     R11, WsPtr, #OldCsX             ; vertices are OldCs,ICursor
        LDMIA   R11, {R0-R5}                    ; and NewPt

; now calculate Vertex4 from other three

        ADD     R6, R0, R4      ; Vertex4X := Vertex1X + Vertex3X - Vertex2X
        SUB     R6, R6, R2

        ADD     R7, R1, R5      ; Vertex4Y := Vertex1Y + Vertex3Y - Vertex2Y
        SUB     R7, R7, R3

        CompSwapT R0,R1, R2,R3, R14 ; Bubble the highest point into R6,R7
        CompSwapT R2,R3 ,R4,R5, R14
        CompSwapT R4,R5 ,R6,R7, R14

        BL      LowerTri        ; sort other vertices and draw lower triangle

        ADD     R11, WsPtr, #Vertex2X           ; restart TLine1 to run from
        LDMIA   R11!, {R0-R3}                   ; Vertex2 to Vertex4
        STR     R3, [WsPtr, #TEndY]             ; and indicate line Vertex1 to
        LDMIA   R11, {R2,R3}                    ; Vertex3 as the next to finish

        BL      GenLineParm
        ADD     R11, WsPtr, #TLine1
        STMIA   R11, {R0-R8}                    ; TLine1 parameter block

        BL      TrapFill                        ; fill the middle trapezoid

        ADD     R11, WsPtr, #Vertex3X           ; restart TLine2 to run from
        LDMIA   R11, {R0-R3}                    ; Vertex3 to Vertex4
        ADD     R11, WsPtr, #TLine2
        B       TriangleFil5                    ; Use common code with
                                                ; triangles to initialise and
                                                ; fill upper trapezoid

; *****************************************************************************
;
;       TrapFill - Fill a trapezoid
;
;       Internal routine, called by TriangleFill, LowerTri, ParallelogramFill
;
; in:   R9  = TLeftX    }  the line limits for this scanline
;       R10 = TRightX   }
;
; out:  R9,R10 updated
;

TrapFill ROUT
        Push    R14
10
        ADD     R11, WsPtr, #TLine1     ; Advance TLine1 until currentY about
        BL      TrapLineStep            ; to change, or end of line reached

        ADD     R11, WsPtr, #TLine2     ; ditto TLine2
        BL      TrapLineStep

        LDR     R11, [WsPtr, #TEndY]
        CMP     R11, R1                 ; if CurrentY = EndY
        Pull    PC, EQ                  ; then quit

        MOV     R0, R9                  ; LeftX
        MOV     R2, R10                 ; RightX
                                        ; LeftY already in R1
        BL      NewHLine                ; Plot current scanline

        ADD     R11, WsPtr, #TLine1     ; advance TLine1 to next scanline
        LDMIA   R11, {R0-R6}
        BL      AdvLineParm
        STMIA   R11, {R0-R2}            ; save the changes

        MOV     R9, R0                  ; assume currentX will be LeftX

        ADD     R11, WsPtr, #TLine2     ; advance TLine2 to next scanline
        LDMIA   R11, {R0-R6}
        BL      AdvLineParm
        STMIA   R11, {R0-R2}            ; save the changes

        CMP     R0, R9                  ; LeftX=Min(CurrentX,CurrentY)
        MOVGE   R10, R0                 ; RightX=Max(CurrentX,CurrentY)
        MOVLT   R10, R9
        MOVLT   R9, R0
        B       %BT10                   ; continue with next scanline


; *****************************************************************************
;
;       TrapLineStep - Step line parameters until CurrentY about to change
;        or end of line reached - compares CurrentX with line limits
;        (LeftX,RightX) and widens them if needed
;
;       Internal routine, called by TrapFill
;
; in:   R9  = LeftX
;       R10 = RightX
;       R11 = address of parameter block
;
; out:  R0-R8 parameter block for this line
;       R9, R10 updated
;       R11 preserved
;

TrapLineStep ROUT
        Push    R14
        LDMIA   R11, {R0-R8}            ; get line parameter block
        CMP     R8, R1                  ; if on last scanline
        MOVEQ   R0, R7                  ; then set currentX to EndX
        BEQ     TrapLin20               ;     (bres unchanged, but who cares)

        CMP     R2, #0                  ; else While bres >= 0 do AdvLineParm
TrapLin10                               ;      {step until Y about to change}
        ADDGE   R0, R0, R5
        SUBGES  R2, R2, R4
        BGE     TrapLin10

TrapLin20
        STMIA   R11, {R0-R2}            ; update the changes to parameter block
        CMP     R0, R9                  ; LeftX=Min(LeftX,CurrentX)
        MOVLT   R9, R0
        CMP     R0, R10
        MOVGT   R10, R0                 ; RightX=Max(RightX,CurrentX)
        Pull    PC



        END