; 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.VduGrafI
;
; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver code - Sprite stuff
;
; Author R C Manby
; Date   10.11.86
;
; CHANGES
; -------
; 12.04.94   W Turner   Updated to allow the use of 1bpp masks
; 12.01.95   G Simms    Fixed MED-04130 where New format sprites with
;                       LH wastage were being created.

; *****************************************************************************
;
;       FlipAboutXAxis - Flip sprite about X axis
;
;       External routine
;
; in:   R2 -> sprite
;

FlipAboutXAxis ROUT
        Push    R14

        BL      MaskOffset
        MOV     R7, R0                  ; 0/offset for nomask/mask
        LDR     R4, [R2, #spWidth]      ; width-1
        LDR     R5, [R2, #spHeight]     ; height-1
        LDR     R6, [R2, #spImage]
        TEQ     R5, #0
        BEQ     %FT05                   ; nothing to do, if only 1 row

        ADD     R0, R2, R6              ; R0 -> top row in image
        ADD     R3, R4, #1              ; width
        MUL     R1, R5, R3              ; R1 = word offset to bottom row
        ADD     R1, R0, R1, LSL #2      ; R1 -> bottom row in image

        Push    "R0-R1, R2, R4-R5, R7"      ; preserve ptrs & mask offset
        BL      FlipAbX10               ; flip main image
        Pull    "R0-R1, R2, R4-R5, R7"

        CMP     R7, #0
        BEQ     %FT05                   ; No mask so skip this bit

        ADD     R0, R0, R7              ; Update the start pointer

        ;If a new format sprite (we know it has a mask)
        ;redo R1 & call the 'GetMaskspWidth' routine to alter R3

        LDR     R8, [R2, #spMode]       ; Get sprite mode
        MOVS    R8, R8, LSR #27         ; Isolate sprite type & test for 0

        ADDEQ   R1, R1, R7              ; Old format, so simple
        BEQ     %FT04

        ;Here, we know it is a 1bpp or alpha mask
        MOV     R6, R5                  ; Better keep R5 safe, we'll need it in a bit
        MOV     R5, R4                  ; The sub wants R4 in r5
        BL      GetMaskspWidth          ; Update the 'width' if needed
        ADD     R3, R5, #1              ; R3=width in words

        MUL     R1, R6, R3              ; R1 = word offset to bottom row
        ADD     R1, R0, R1, LSL #2      ; R1 -> Bottom row in image
04
        BL      FlipAbX10               ; flip mask
05
        Pull    R14
        RETURNVC

; *****************************************************************************
;
;       FlipAbX10 - Flip area given ptrs and width
;
;       Internal routine, called by FlipAboutXAxis
;
; in:   R0 -> top row
;       R1 -> bottom row
;       R3 = width in words
;
; out:  R0-R2,R4-R11 corrupted
;       R3 preserved
;

FlipAbX10 ROUT
10
        SUBS    R2, R3, #4              ; initialise width count
        BLT     %FT30
20                                      ; flip in blocks of 4 words
        LDMIA   R0, {R4-R7}
        LDMIA   R1, {R8-R11}
        STMIA   R1!, {R4-R7}
        STMIA   R0!, {R8-R11}
        SUBS    R2, R2, #4
        BGE     %BT20
30
        ADDS    R2, R2, #4
        BLE     %FT50
40                                      ; do remaining words one by one
        LDR     R4, [R0]
        LDR     R8, [R1]
        STR     R4, [R1], #4
        STR     R8, [R0], #4
        SUBS    R2, R2, #1
        BNE     %BT40
50
        SUB     R1, R1, R3, LSL #3      ; point to previous row
        CMP     R1, R0
        BHI     %BT10                   ; loop until pointers meet or cross
        MOV     PC, R14                 ; only R3 preserved

; *****************************************************************************
;
;       FlipAboutYAxis - Flip a sprite about Y axis
;
;       External routine
;
; in:   R2 -> sprite
;

FlipAboutYAxis ROUT
        Push    R14

        BL      MaskOffset
        MOV     R8, R0                  ;Bung result in R8 'till we want it...

        ADD     R3, R2, #spWidth
        LDMIA   R3, {R3-R7}     ; R3     ,R4      ,R5    ,R6    ,R7
                                ; spWidth,spHeight,spLBit,spRBit,spImage
        ADD     R3, R3, #1              ; use width as row offset (words)

        MUL     R4, R3, R4              ; R4=width x (height-1) in words
        ADD     R4, R4, R3              ; R4=width x height in words
        ADD     R4, R7, R4, LSL #2      ; offset past end of sprite image
        ADD     R4, R4, R2              ; address past end of image

        RSB     R5, R5, #31             ; reflect LBit & RBit
        RSB     R6, R6, #31
        STR     R5, [R2, #spRBit]       ; new RBit := 31- old LBit
        STR     R6, [R2, #spLBit]       ; new LBit := 31- old RBit
        ADD     R0, R2, R7              ; R0 -> start of first row
        LDR     R11, [WsPtr, #SprBytesPerChar]  ; shift factor to
                                                ; reach next pixel
        LDR     R9, [WsPtr, #SprWriteNColour]   ; mask for leftmost pixel
        MOV     R10, R9, ROR R11                ; mask for rightmost pixel

        Push    "R0, R2, R5-R8"
        BL      FlipAbY10               ; Do the sprite image
        Pull    "R0, R2, R5-R8"

        Push    "R0,R8"
        LDR     R8, [R2, #spMode]       ; Get sprite mode
        MOVS    R8, R8, LSR #27         ; Isolate sprite type & test for 0
        BEQ     %FT03                   ; If old format ignore next bit

        ; If this is a new format sprite we may have to remove any LH
        ; wastage that was created by the flip.
        CMP     R6, #0                  ; Is there any LH wastage?
        BEQ     %FT03                   ; If not skip the next bit.
        MOV     R8, R6
        BL      RemLHWastage
        ; If this is a new format sprite then LH wastage = 0 and the RH wastage
        ; is the same as it was to start with.
        RSB     R5, R6, #31             ; restore old RBit
        MOV     R6, #0
        STR     R5, [R2, #spRBit]       ; new RBit := 31- old LBit
        STR     R6, [R2, #spLBit]       ; new LBit := 0
03
        Pull    "R0,R8"
        CMP     R8, #0                  ; Does the sprite have a mask?
        BEQ     %FT05                   ; Nope, so skip the mask flip!

        ;Now, is it an old or new sprite?
        LDR     R1, [R2, #spMode]       ; Get sprite mode
        ADD     R0, R0, R8              ; R0 points to start of mask
        MOVS    R1, R1, LSR #27         ; Isolate sprite type & test for 0

        ADDEQ   R4, R4, R8              ;R4 points to end of mask now
        BEQ     %FT04                   ;Skip the next bit (it's for new format only)

        Push    "R5"
        LDR     R5, [R2, #spWidth]
        BL      GetMaskspWidth
        ADD     R3, R5, #1              ;R3 is new row offset (words)
        Pull    "R5"

        Push    "R8"                    ;Last Bit used for mask, this will enable
                                        ;us to remove the left hand wastage after
                                        ;the flip

        LDR     R4, [R2, #spHeight]
        LDR     R8, [R2, #spTrans]
        MUL     R4, R3, R4              ; R4=width x (height-1) in words
        ADD     R4, R4, R3              ; R4=width x height in words
        ADD     R4, R8, R4, LSL #2      ; offset past end of sprite mask
        ADD     R4, R4, R2              ; address past end of mask

        ADD     R0, R2, R8              ; R0 -> start of first row of mask
;        LDR     R11, [WsPtr, #SprBytesPerChar]  ; shift factor to
                                                ; reach next pixel
;        LDR     R9, [WsPtr, #SprWriteNColour]   ; mask for leftmost pixel

        MOV     R11, #1
        MOV     R9, #1

        MOV     R10, R9, ROR R11                ; mask for rightmost pixel

        Push    "R0"
        BL      FlipAbY10               ; Now do the mask
        Pull    "R0"
        Pull    "R8"                    ; Retrieve last bit used to find LHwastage
        RSB     R8, R8, #31
        CMP     R8, #0
        BEQ     %FT05
        BL      RemLHWastage
        B       %FT05
04
        BL      FlipAbY10               ; Now do the mask
05
        Pull    R14
        RETURNVC

; *****************************************************************************
;
;       FlipAbY10 - Flip area given ptrs and width
;
;       Internal routine, called by FlipAboutYAxis
;
; N.B. This reflects 'user pixels', ie in double pixel modes it
;      reflects pairs of screen pixels, this should not matter.
;
; ON ENTRY, we have R0, R3-R4, R9-R11
; ON EXIT, of these, only R0 is corrupted

; Internally:
;       R0  RowPtr, R1 LPtr , R2 RPtr , R3 Row offset, R4 EndAdr
;       R5  LWord , R6 RWord, R7 LTemp, R8 RTemp     , R9 LPixMask
;       R10 RPixMask, R11 ShftFactor, R14 Cnt

; R0-R2, R5-R8 get corrupted

FlipAbY10
        Push    R14
10
        MOV     R1, R0                  ; R1 -> left end of row
        ADD     R0, R0, R3, LSL #2      ; R0 -> past right end of row
        MOV     R2, R0                  ; R2 := R0
20
        LDR     R5, [R1]
        LDR     R6, [R2, #-4]!
        MOV     R14, #32                ; total number of bits to process
30                                      ; circular pixel shift of LWord & RWord
        AND     R7, R5, R9              ; leftmost pixel (LSPart of LWord)
        AND     R8, R6, R10             ; rightmost pixel (MSPart of RWord)
        ORR     R5, R8, R5, LSR R11
        ORR     R6, R7, R6, LSL R11
        SUBS    R14, R14, R11           ; process next pixel
        BNE     %BT30                   ; TMD 12-Jan-88 bug fixed here
                                        ; I had changed RCM's code and put BCS

        STR     R5, [R1], #4
        STR     R6, [R2]
        CMP     R2, R1
        BHI     %BT20                   ; loop until pointers meet or cross

        CMP     R0, R4
        BCC     %BT10                   ; if address < end, reflect next row

        Pull    R14
        MOV     PC, R14

; *****************************************************************************
;
;       RemLHWastage - Dedicated routine to remove x bits of LH wastage
;                      after a new format Sprite has been flipped
;
;       On Entry:    R0 = Start of data
;                    R3 = Row Offset
;                    R4 = End of data
;                    R8 = No. Bits to Remove
;       R0  RowPtr, R1 LPtr , R2 RPtr , R3 Row offset, R4 EndAdr

RemLHWastage
        Push    "R1,R2,R5-R8,R14"
10
;start of loop for each line
        MOV     R1, R0                  ; R1 -> left end of row
        ADD     R0, R0, R3, LSL #2      ; R0 -> past right end of row
        SUB     R2, R0, #4              ; R2 -> last word in row
                                        ;         (used for loop check)
        LDR     R5, [R1]                ; load current word
20
;Start of loop for each word
        CMP     R2, R1
        ;If we have reached the last word then just shift and store
        MOVEQ   R5, R5, LSR R8
        STREQ   R5, [R1]
        BEQ     %FT99
        ;There are more words left so we need to shift in the LSBits from the next
        ;word.
        LDR     R6, [R1, #4]           ; load next word
        MOV     R5, R5, LSR R8         ; Throw away wastage bits in current word
        RSB     R14, R8, #32
        MOV     R7, R6, LSL R14        ; Move LSBs from next word to current
        ORR     R5, R5, R7
        STR     R5, [R1],#4            ; store current word
        MOV     R5, R6                 ; move next word to current word ready for
                                       ; next loop iteration.

        B       %BT20
;        CMP     R2, R1
;        BHI     %BT20                   ; loop until pointers meet or cross

99
        CMP     R0, R4
        BCC     %BT10                   ; if address < end, reflect next row

        Pull    "R1,R2,R5-R8,R14"
        MOV     PC, R14


        END