; 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.VduGrafK
;
; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver code - Sprite stuff
;
; Author R C Manby
; Date   5.3.87
;

; *****************************************************************************
;
;       ScreenSave - Save screen within graphics window as a sprite file
;
;       External routine
;
; in:   R2 -> file name
;       R3 = 0/1 => exclude/include palette data
;

ScreenSave ROUT
        Push    R14
        SWI     XOS_RemoveCursors

      [ {TRUE}
        GraphicsMode R0
        BNE     %FT20
      |
        LDR     R0, [WsPtr, #NPix]
        CMP     R0, #0
        BEQ     %FT20                   ; quit with error if not graphics mode
      ]

                                        ; build a temporary sprite area header
        ADD     R1, WsPtr, #ScrSavAreaCB
        MOV     R4, #&7FFFFFFF                  ; size, very large
        MOV     R5, #1                          ; one sprite
        LDR     R6, =(ScrSavSpriteCB-ScrSavAreaCB) ;saFirst
        MOV     R7, R6                          ; saFree=saFirst
        STMIA   R1, {R4-R7}

        ADD     R11, WsPtr, #GWLCol             ; R4 ,R5 ,R6 ,R7
        LDMIA   R11, {R4,R5,R6,R7}              ; wL ,wB ,wR ,wT

        LDR     R0, [WsPtr, #ModeNo]
        STR     R0, [WsPtr, #SGetMode]  ; needs setting up before CreateHeader

        Push    R2                      ; preserve file name pointer

        ; if it is a mode selector mode with >256 colours force it to have no
        ; palette. CreateHeader will deal with <=256.
        LDR     R2, [WsPtr, #Log2BPP]
        CMP     R2, #4
        MOVCS   R3, #0

        ; amg 25th May 1994. The above is no longer completely true. We still
        ; don't allow palettes on 16/32bpp. Below that (whether new or old
        ; format of sprite) palettes are now allowed. No actual code change
        ; here, but CreateHeader has been changed.

        ADR     R2, ScrSavSpriteName
                                        ;      R3     ,R4,R5,R6,R7
        BL      CreateHeader            ; In : Palette,sl,sb,sr,st
        ADDVS   sp, sp, #4              ; (if error, junk stacked filename ptr and exit)
        BVS     %FT35
                                        ; Out: ImageSize
                                        ; now add the sprite to the sprite area
        LDR     R3, [R2, #spNext]       ; total size of new sprite
        LDMIA   R1, {R4,R5,R6,R7}       ; saEnd,saNumber,saFirst,saFree
        ADD     R7, R7, R3              ; new saFree
        MOV     R4, R7
        STMIA   R1, {R4,R5,R6,R7}

; Create file to prevent "Can't extend"

        [ AssemblingArthur :LOR: Module
        MOV     R0, #OSFile_CreateStamp
        LDR     R1, [R13, #0]           ; R1 -> filename
        LDR     R2, =&FF9               ; Type=SpriteFile
        MOV     R3, #0                  ; Junk
        MOV     R4, #0
        SUB     R5, R7, #4              ; File size (ie exclude saEnd)
        SWI     XOS_File
        |
        CLRV
        ]
        Pull    R1
        BVS     %FT30

; OpenUp file and save the Sprite area and sprite headers

        [ AssemblingArthur :LOR: Module
        MOV     R0, #open_update :OR: open_mustopen :OR: open_nodir
        |
        MOV     R0, #open_write
        ]
        SWI     XOS_Find
        BVS     %FT30

        MOV     R1, R0
        MOV     R0, #2                  ; write bytes to file

        LDR     R2, =(ScrSavAreaCB+saNumber)
        ADD     R2, R2, WsPtr
        LDR     R3, =(ScrSavSpriteCB+spImage)
        LDR     R3, [WsPtr, R3]
        ADD     R3, R3, #(SpriteAreaCBsize-saNumber)

        MOV     R4, #0
        SWI     XOS_GBPB
        BVS     %FT40                   ; FileSwitchGotYa !

        Push    R1
        LDR     R0, [WsPtr, #GWLCol]
        LDR     R1, [WsPtr, #GWTRow]
        BL      ScreenAddr              ; R2 = ScrAdr of TopL of area
        Pull    R1

        LDR     R5, [WsPtr, #SGetWidth]
        ADD     R5, R5, #1
        MOV     R5, R5, LSL #2           ; width (bytes)
        LDR     R6, [WsPtr, #SGetHeight] ; height-1

        LDR     R7, [WsPtr, #LineLength]
        SUBS    R7, R7, R5              ; zero then can do as one lump
        MLAEQ   R5, R6, R5, R5          ; R5 = R5*(R6+1)
        MOVEQ   R6, #0                  ; only one chunk to do

;
; R0    ,R1    ,R2    ,R3    ,R4    ,R5   ,R6    ,R7
;       ,Handle,ScrAdr,Size  ,      ,Width,RowCnt,RowOfSt

10
        MOV     R0, #2
        MOV     R3, R5
        SWI     XOS_GBPB
        BVS     %FT40                   ; something went wrong

        ADD     R2, R2, R7              ; step to next screen line
        SUBS    R6, R6, #1
        BGE     %BT10

        MOV     R0, #0                  ; close file
        SWI     XOS_Find
        BVS     %FT30
        SWI     XOS_RestoreCursors
        Pull    R14
        RETURNVC                        ; no error, return VC

20
        ADRL    R0, SpriteErr_NotGraphics
      [ International
        BL      TranslateError
      |
        SETV
      ]
        B       %FT30

40                                      ; return point after an error
        STR     R0, [WsPtr, #RetnReg0]  ; R0 ptr to message, R1 file handle
        MOV     R0, #0                  ; close file
        SWI     XOS_Find
30                                      ; return point after an error
        STRVS   R0, [WsPtr, #RetnReg0]  ; R0 ptr to message
35
        SWI     XOS_RestoreCursors
        Pull    R14
        RETURNVS

ScrSavSpriteName
        = "screendump", 0
        ALIGN

        LTORG

; *****************************************************************************
;
;       ScreenLoad - Plot sprite file directly into graphics window
;
;       External routine
;
; in:   R2 -> file name
;

ScreenLoad ROUT
        Push    R14
        SWI     XOS_RemoveCursors

        MOV     R0, #open_read+open_mustopen+open_nodir
        MOV     R1, R2
        SWI     XOS_Find
        BVS     %FT80

        STR     R0, [WsPtr, #ScrLoaHandle]
        MOV     R1, R0
        MOV     R0, #4                          ; read areaCB from file
        ADD     R2, WsPtr, #ScrLoaAreaCB+saNumber
        MOV     R3, #(SpriteAreaCBsize-saNumber)
        MOV     R4, #0
        SWI     XOS_GBPB
        BVS     %FT70                           ; FileSwitchGotYa !

        MOV     R0, #3                          ; read spriteCB from file
        ADD     R2, WsPtr, #ScrLoaSpriteCB
        MOV     R3, #SpriteCBsize
        ADD     R3, R3, #MaxSpritePaletteSize
        LDR     R4, [WsPtr, #(ScrLoaAreaCB+saFirst)]
        SUB     R4, R4, #4
        SWI     XOS_GBPB
        BVS     %FT70

        ADD     R2, WsPtr, #ScrLoaSpriteCB
        BL      WritePaletteFromSprite          ; mode change (if needed)
        ;branch to 75 rather than 70 because RetnRegR0 is already set up
        BVS     %FT75                           ; and palette setting

      [ {TRUE}
        GraphicsMode R0
        BNE     %FT60
      |
        LDR     R0, [WsPtr, #NPix]
        CMP     R0, #0
        BEQ     %FT60                   ; quit with error if not graphics mode
      ]

; now check for being able to do it all at once

        ADD     R0, WsPtr, #GWLCol              ; R3=GWLCol; R4=GWBRow
        LDMIA   R0, {R3-R6}                     ; R5=GWRCol; R6=GWTRow

        ADD     R0, WsPtr, #ScrLoaSpriteCB
        ADD     R0, R0, #spWidth                ; R7=width-1; R8=height-1
        LDMIA   R0, {R7-R10}                    ; R9=LBit; R10=RBit

        SUB     R5, R5, R3                      ; R5 = window width
        LDR     R0, [WsPtr, #XWindLimit]
        TEQ     R0, R5                          ; if window width=full screen
        TEQEQ   R9, #0                          ; and LBit=0
        TEQEQ   R10, #31                        ; and RBit=31
        BNE     %FT05

        ADD     R5, R5, #1                      ; R5 = screen width in pixels
        ADD     R7, R7, #1                      ; R7 = sprite width in words
        LDR     R0, [WsPtr, #NPix]
        MLA     R0, R7, R0, R7                  ; R0 = width*(npix+1)
        TEQ     R0, R5                          ; and spritewidth=full screen
        BNE     %FT05

      [ {TRUE}
        LDR     R14, [WsPtr, #Log2BPC]
        MOV     R1, R5, LSL R14                 ; bit size of 1 row of pixels
        MOV     R1, R1, LSR #3                  ; byte size of 1 row of pixels
        LDR     R14, [WsPtr, #LineLength]       ; LineLength (in bytes)
        TEQ     R1, R14                         ; if they differ (eg interlaced mode)
        BNE     %FT05                           ;   then we can't optimise
      ]

; we know we can do it all in one chunk
; work out screen address and sprite offset

        LDR     R1, [WsPtr, #CursorFlags]       ; if computing clip box
        TST     R1, #ClipBoxEnableBit
        Push    "R0-R4", NE
        BLNE    SetClipBoxToFullScreen          ; then set to full screen
        Pull    "R0-R4", NE                     ; above routine preserves PSR

        MOV     R7, R7, LSL #2                  ; R7 = line width in bytes
        ADD     R1, R8, R4                      ; R1 = height-1 + GWBRow = YT
        SUBS    R9, R1, R6                      ; if YT > GWTRow then
                                                ; start at row (YT-GWTRow)
        MOVHI   R1, R6                          ; and YT=GWTRow, else
        MOVLS   R9, #0                          ; start at row 0 (and YT=YT)

        LDR     R0, [WsPtr, #ScrLoaAreaCB+saFirst]
        ADD     R2, WsPtr, #ScrLoaSpriteCB
        LDR     R2, [R2, #spImage]
        ADD     R0, R0, R2
        SUB     R0, R0, #4                      ; R0=offset into file of image
        MLA     R4, R7, R9, R0                  ; add on vertical wastage*width

        SUB     R9, R8, R9                      ; R9 = height-1-wastage
        MLA     R9, R7, R9, R7                  ; number of bytes to transfer

        MOV     R0, #0
        BL      ScreenAddr                      ; R2 := screen address
        MOV     R3, R9

        LDR     R1, [WsPtr, #ScrLoaHandle]
        MOV     R0, #3                          ; read from this position
        SWI     XOS_GBPB
        BVS     %FT70                           ; if error
        B       %FT52                           ; no error

; can't do it all at once; R3 = GWLCol, R4 = GWBRow

05
        ADD     R2, WsPtr, #ScrLoaSpriteCB      ; point at the spriteCB
        MOV     R5, #0
        BL      GenSpritePlotParmBlk            ; "plotting" at (GWLCol,GWBRow)
        BVS     %FT55                           ; off screen (not an error)

        ADD     R2, WsPtr, #ScrLoaSpriteCB
        LDR     R4, [WsPtr, #SPltMemAdr]        ; convert MemAdr into
        LDR     R5, [WsPtr, #ScrLoaAreaCB+saFirst]
        SUB     R4, R4, #4
        SUB     R4, R4, R2
        ADD     R4, R4, R5
        STR     R4, [WsPtr, #ScrLoaFilPtr]      ; file ptr

        LDR     R4, [R2, #spWidth]              ; convert spWidth into
        ADD     R4, R4, #1
        MOV     R4, R4, LSL #2
        STR     R4, [WsPtr, #ScrLoaFilOfst]     ; file ptr offset

        LDR     R4, [WsPtr, #SPltColCnt]
        ADD     R4, R4, #2
        MOV     R4, R4, LSL #2
        STR     R4, [WsPtr, #ScrLoaBytes]

        ADD     R4, WsPtr, #ScrLoaBuffer
        STR     R4, [WsPtr, #SPltMemAdr]
        STR     R4, [WsPtr, #ScrLoaBufAdr]

10                                              ; read row from file
        ADD     R1, WsPtr, #ScrLoaHandle
        LDMIA   R1, {R1,R2,R3,R4}               ; Handle,BufAdr,Bytes,FilPtr
        MOV     R0, #3
        SWI     XOS_GBPB
        BVS     %FT70

        ADD     R0, WsPtr, #SPltScrAdr
        LDMIA   R0, {R0-R1,R5-R7}       ; R0    ,R1    ,     R5    ,R6   ,R7
                                        ; ScrAdr,ColCnt,     BufAdr,ShftR,ShftL

        LDMIA   R5, {R2,R3}             ; plot the first (leftmost) word
        ADD     R5, R5, #4

        ShiftR  R2,R3, R6,R7            ; shift R3,R2 right R6 places
                                        ; we only need result word R2

        LDR     R3, [WsPtr, #SPltLMask] ; on leftmost word, mask down
        AND     R2, R2, R3              ; to just the required pixels

        LDR     R4, [R0]                ; plot 1 word
        BIC     R4, R4, R3
        ORR     R4, R4, R2
        STR     R4, [R0], #4

        SUBS    R1, R1, #1
        BLT     %FT50                   ; if all plotted, try next scanline
                                        ; else try for blocks of 4
        SUBS    R1, R1, #4
        BLT     %FT30

20
        ;R0    ,R1         ,R5    ,R6   ,R7
        ;ScrAdr,ColCnt,    ,BufAdr,ShftR,ShftL

        LDMIA   R5, {R2,R3,R8-R10}      ; 5 words needed, gives 4 after shift
        ADD     R5, R5, #16             ; advance source ptr 4 words

        ShiftR  R2,R3, R6,R7            ; shift R4-R0 right R6 bits
        ShiftR  R3,R8, R6,R7            ; we only want result words R3-R0
        ShiftR  R8,R9, R6,R7
        ShiftR  R9,R10,R6,R7

        STMIA   R0!, {R2,R3,R8-R9}      ; write 4 words back to screen
        SUBS    R1, R1, #4
        BGE     %BT20

30                                      ; try 1 word at a time
        ADDS    R1, R1, #4

;R0    ,R1    ,     R5    ,R6   ,R7
;ScrAdr,ColCnt,     BufAdr,ShftR,ShftL
;
; If EQ this is rightmost word

        BEQ     %FT45
40
        LDMIA   R5, {R2,R3}
        ADD     R5, R5, #4

        ShiftR  R2,R3, R6,R7            ; shift R3,R2 right R6 places
                                        ; we only need result word R2
        STR     R2, [R0], #4
        SUBS    R1, R1, #1
        BGT     %BT40

45
        LDMIA   R5, {R2,R3}
        ADD     R5, R5, #4

        ShiftR  R2,R3, R6,R7            ; shift R3,R2 right R6 places
                                        ; we only need result word R2

        LDR     R3, [WsPtr, #SPltRMask] ; rightmost word, so mask down to
        AND     R2, R2, R3              ; just the required pixels

        LDR     R4, [R0]
        BIC     R4, R4, R3
        ORR     R4, R4, R2
        STR     R4, [R0], #4

50                                      ; now try the next scanline
        ADD     R11, WsPtr, #SPltWidth
        LDMIA   R11, {R1,R2,R3,R4}      ; Width,Height,ScrOff,MemOff
        ADD     R5, R0, R3
        SUBS    R2, R2, #1
        STMIA   R11, {R1,R2,R3,R4,R5}   ; Width,Height,ScrOff,MemOff,ScrAdr

        ADD     R11, WsPtr, #ScrLoaHandle ; R1    ,R2    ,R3   ,R4    ,R5
        LDMIA   R11, {R1,R2,R3,R4,R5}     ; Handle,BufAdr,Bytes,FilPtr,FilOfst
        ADD     R4, R4, R5
        STR     R4, [WsPtr, #ScrLoaFilPtr]
        BGE     %BT10                   ; plot next scanline
52
        MOV     R0, #0                  ; close file
        SWI     XOS_Find
        BVS     %FT80
55
        SWI     XOS_RestoreCursors
        Pull    R14
        RETURNVC

60
        ADRL    R0,SpriteErr_NotGraphics
      [ International
        BL      TranslateError
      ]
70                                      ; return point after an error
        STR     R0, [WsPtr, #RetnReg0]  ; R0 ptr to message, R1 file handle
75
        MOV     R0, #0                  ; close file
        SWI     XOS_Find
80                                      ; error, file not open
        STRVS   R0, [WsPtr, #RetnReg0]
        SWI     XOS_RestoreCursors
        Pull    R14
        RETURNVS


        END