; 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.VduGrafC
;
; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver code - Ellipse outline & fill
;
; Author R C Manby
; Date   29.9.86
;




;
;
;
;------------------------------------------------------------------------------
;
; EllipseOutline
; ==============
;
; On entry, OldCs is centre of the ellipse
;           ICursor is a point giving the width of the ellipse
;           NewPt is the highest/lowest point on the ellipse
;
; On exit, R0..R11 corrupt
;
EllipseOutline
        SaveRetAdr

        BL GenEllParm
        B EllipseOut20
EllipseOut10
        BL AdvEllParm
EllipseOut20
                                ; Registers hold
                                ;   R4 , R5  , R6  , R7  , R8  , R9  , R10
                                ;  ellY,prevL,prevR,thisL,thisR,nextL,nextR

        MOV R0,R7               ;Left line runs from thisL rightwards
        MOV R1,R4
        Greatest R3,R5,R9
        SUB R3,R3,#1
        Greatest R3,R3,R7       ; to max(thisL, max(prevL-1,nextL-1))

        MOV R2,R8               ;Right line runs from thisR leftwards
        Least R4,R6,R10
        ADD R4,R4,#1
        Least R4,R4,R8          ; to min(thisR, min(prevR+1,nextR+1))

        BL EllDoubleHLine       ;Any overlap handled by EllDoubleHLine

        LDR R0,[WsPtr,#EllBlkSliceCnt]
        CMP R0,#0
        BGE EllipseOut10
        B EllipseFi30           ;Use common code with ellipse fill for
                                ; last scanline
;
;
;
;
;------------------------------------------------------------------------------
;
; EllipseFill
; ===========
;
; On entry, OldCs is centre of the ellipse
;           ICursor is a point giving the width of the ellipse
;           NewPt is the highest/lowest point on the ellipse
;
; On exit, R0..R11 corrupt
;
EllipseFill
        SaveRetAdr

        BL GenEllParm
        B EllipseFi20
EllipseFi10
        BL AdvEllParm
EllipseFi20
                                ; Registers hold
                                ;   R4 , R5  , R6  , R7  , R8  , R9  , R10
                                ;  ellY,prevL,prevR,thisL,thisR,nextL,nextR

        MOV R0,R7                       ;Draw slice thisL -> thisR
        MOV R1,R4
        MOV R2,R8

        BL EllHLine

        LDR R0,[WsPtr,#EllBlkSliceCnt]
        CMP R0,#0
        BGE EllipseFi10
EllipseFi30
        LDR R0,[WsPtr,#EllNextL]        ;Last slice nextL -> nextR
        LDR R1,[WsPtr,#EllBlkEllY]
        ADD R1,R1,#1
        LDR R2,[WsPtr,#EllNextR]

        BL EllHLine

        Return
;
;
;
; EllHLine - Draw a slice then reflect around ellipse origin
; ========
;
; On entry, R0 (X) - Left point of line
;           R1 (Y) - Y ordinate of line
;           R2 (X) - Right point of line
;
; On exit,  R0..R11 corrupt
;
EllHLine
        SaveRetAdr

        LDR R3,[WsPtr,#OldCsX]          ;All points relative to OldCs
        LDR R4,[WsPtr,#OldCsY]

        ADD R11,WsPtr,#EllHLineWs       ;Save points given plus centre of
        STMIA R11,{R0-R4}               ; ellipse for later use

        ADD R0,R3,R0                    ;OldCsX + LeftX
        ADD R1,R4,R1                    ;OldCsY + Y
        ADD R2,R3,R2                    ;OldCsX + RightX

        BL NewHLine                     ;Draw top slice

        ADD R11,WsPtr,#EllHLineWs
        LDMIA R11,{R3-R7}

        CMP R4,#0                       ;If EllY = 0
        Return EQ                       ; then quit to prevent double plotting
                                        ; else reflect around ellipse origin

        SUB R0,R6,R5                    ;OldCsX - RightY
        SUB R1,R7,R4                    ;OldCsY - Y
        SUB R2,R6,R3                    ;OldCsX - LeftY

        BL NewHLine

        Return
;
;
;
; EllDoubleHLine
; ==============
;
; On entry, R0 (X) - Left most point
;           R1 (Y) - y ordinate of line
;           R2 (X) - Right most point
;           R3 (X) - end of left most line
;           R4 (X) - start of right most line
;
EllDoubleHLine
        CMP R3,R4                               ;If end of left line overlaps
                                                ; start of right
        BGE EllHLine                            ;then draw and reflect R0->R2
                                                ;else
        SaveRetAdr

        ADD R11,WsPtr,#EllDoubleHLineWs
        STMIA R11,{R0-R4}

        MOV R2,R3                               ;Draw and reflect R0->R3
        BL EllHLine

        ADD R11,WsPtr,#EllDoubleHLineWs
        LDMIA R11,{R0-R4}
        MOV R0,R4
        BL EllHLine                             ;Draw and reflect R4->R2

        Return
;
;
;
;------------------------------------------------------------------------------
;
; GenEllParm - Generate a control block for an ellipse
; ==========
;
; On entry, OldCs is centre of the ellipse
;           ICursor is a point giving the width of the ellipse
;           NewPt is the highest/lowest point on the ellipse
;
; On exit, EllBlk holds the ellipse parameter block
;
;          EllThisL..EllNextR setup
;
;          R4      - EllY
;          R5, R6  - prevL,prevR
;          R7, R8  - thisL,thisR
;          R9, R10 - nextL,nextR
;
;
; Format of ellipse parameter block
;
; Var      R0 - SliceCnt            count of slices remaining
;          R1 - EllYSqr             square of current slice height
;          R2 - OddNo               used to give next EllYSqr value
;          R3 - XOffset  [bb.bb]    offset in X dirn along shear line
;          R4 - EllY
; Const    R5 - ShearX   [bb.bb]    shear factor per scanline
;          R6 - SliceX   [0bb.b]    axis ratio
;          R7 - MaxYSqr  [bbbb]
;
;
;
GenEllParm
        SaveRetAdr

        ADD R11,WsPtr,#OldCsX
        LDMIA R11,{R0,R1, R2,R3, R4,R5}         ;OldCs, ICursor, NewPt

        SUBS R6,R2,R0
        RSBLT R6,R6,#0                  ;R6 := ABS(width of slice)
                                        ;R6 is sliceX (ie maxwidth)
        SUBS R7,R5,R1
        MOV R8,R7
        RSBLT R7,R7,#0                  ;R7 := ABS(height of ellipse)

;
; Leave R0,R1,R2 intact upto here
;       R6 is ABS(width of slice)

        BEQ EllipseZeroHeight           ;If NewPtY=OldCsY draw a single line

        SUBS R5,R4,R0
        EOR R8,R8,R5
        RSBLT R5,R5,#0                  ;R5 := ABS(shear at top of ellipse)

;
; R5 holds shear in x dirn
; R6 holds width
; R7 holds height (also shearY)
; R8 sign bit is slope of shearline
;

        MOV R0,R7                       ;Setup SliceCnt

        MOV R9,R5,LSL #16
        DivRem R5,R9,R7,R10,norem       ;R5 := totalshear/ellipseheight

        CMP R8,#0
        RSBLT R5,R5,#0                  ;Correct for negative slope

        MOV R7,R0                       ;Div R6,R6,R0 using R7,R9,R10
        MOV R9,R6,LSL #8
        DivRem R6,R9,R7,R10,norem       ;R6 := slicewidth/ellipseheight


; R5 holds shear per scanline
; R6 ratio of ellipse axis

        MUL R7,R0,R0    ;MaxYSqr

        MOV R1,#0       ;EllYSqr
        MOV R2,#1       ;Oddno
        MOV R3,#0       ;XOffset
        MOV R4,#-2      ;EllY

        ADD R11,WsPtr,#EllBlk
        STMIA R11,{R0-R7}

        BL AdvEllP20                    ;Start by calculating first two slices
        STR R9,[WsPtr,#EllThisL]        ;Limits passed back in R9,R10
        STR R10,[WsPtr,#EllThisR]

        BL AdvEllP20

        ADD R11,WsPtr,#EllThisL
        LDMIA R11,{R7,R8}

        RSB R5,R10,#0                   ;prevL := -nextR
        RSB R6,R9,#0                    ;prevR := -nextL

                                        ; Stretch slice if disconnected

        Least R7,R7,R6                  ; thisL := min(thisL,prevR)
        Least R7,R7,R10                 ; thisL := min(thisL,nextR)

        Greatest R8,R8,R5               ; thisR := max(thisR,prevL)
        Greatest R8,R8,R9               ; thisR := max(thisR,nextL)

        STMIA R11,{R7,R8,R9,R10}

        Return                  ; On return, registers hold
                                ;   R4 , R5  , R6  , R7  , R8  , R9  , R10
                                ;  ellY,prevL,prevR,thisL,thisR,nextL,nextR
;
;
;
; EllipseZeroHeight - Draw a single line, no pips
; =================
;
; On entry, R0 (X), R1 (Y) holds centre of ellipse
;           R6 is ABS(width of slice/2)
;
EllipseZeroHeight

        ADD R2,R0,R6
        SUB R0,R0,R6

        Pull Link                       ;Return address into ellipse code
        Pull Link                       ;Return address to whoever called
                                        ; ellipses

        B NewHLine                      ;Sorted coords
                                        ;This will return to whoever called
                                        ; the ellipse code
;
;
;
;------------------------------------------------------------------------------
;
; AdvEllParm
; ==========
;
; On entry, R11 points to ellipse parameter block
;
; On exit, EllBlk, EllThisL..EllNextR updated
;
;          R4      - EllY
;          R5, R6  - prevL,prevR
;          R7, R8  - thisL,thisR
;          R9, R10 - nextL,nextR
;
;
; Format of ellipse parameter block
;
; Var      R0 - SliceCnt            count of slices remaining
;          R1 - EllYSqr             square of current slice height
;          R2 - OddNo               used to give next EllYSqr value
;          R3 - XOffset  [bb.bb]    offset in X dirn along shear line
;          R4 - EllY
; Const    R5 - ShearX   [bb.bb]    shear factor per scanline
;          R6 - SliceX   [0bb.b]    axis ratio
;          R7 - MaxYSqr  [bbbb]
;
;
;
AdvEllParm
        SaveRetAdr

        BL AdvEllP20            ;Advance scanline
                                ; On return, registers hold
                                ;   R4 ,   R9  , R10
                                ;  ellY,  nextL,nextR

                                ;Shuffle points
                                ;R9/R10 -> nextLR
                                ;nextLR -> thisLR - stretch if disconnected
                                ;thisLR -> prevLR

        ADD R11,WsPtr,#EllThisL
        LDMIA R11,{R5,R6, R7,R8}
                                        ; Stretch slice if disconnected
        Greatest R8,R8,R9               ; thisR := max(thisR,nextL)
        Least R7,R7,R10                 ; thisL := min(thisL,nextR)

        STMIA R11,{R7,R8, R9,R10}
        Return                  ;   R4 , R5  , R6  , R7  , R8  , R9  , R10
                                ;  ellY,prevL,prevR,thisL,thisR,nextL,nextR
;
;
;
;
;
;
;
AdvEllP20
        SaveRetAdr

        ADD R11,WsPtr,#EllBlk
        LDMIA R11,{R0-R7}       ;Load ellipse parm block

        SUB R7,R7,R1            ;Sqroot(MaxYSqr-EllYSqr)
        MOV R11,#24             ;Use 24 instead of 16 iterations in the
        BL SquareRootAlt        ; SquareRoot routine, gives result [0bb.b]

                                ;Mult by axis ratio
        MOV R7,R6               ; [0bb.b] * [0bb.b]
        MUL R9,R7,R8            ; Result in R9 is [bb.bb]

        ADD R10,R3,R9           ;NextR   [bb.bb]
        ADD R10,R10,#&8000
        MOV R10,R10,ASR #16     ;         [00bb]

        SUB R9,R3,R9            ;NextL   [bb.bb]
        ADD R9,R9,#&8000
        MOV R9,R9,ASR #16       ;         [00bb]

        ADD R1,R1,R2            ;New value of EllYSqr by adding oddno
        ADD R2,R2,#2            ;Next oddno in sequence

        ADD R3,R3,R5            ;XOffSet for next scanline
        SUB R0,R0,#1            ;Decrement count of slices left
        ADD R4,R4,#1            ;Increment EllY

        ADD R11,WsPtr,#EllBlk
        STMIA R11,{R0,R1,R2,R3,R4}      ;Save updated section

        Return                  ;   R4 ,   R9  , R10
                                ;  ellY,  nextL,nextR

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


        END