; 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 ; If this is a new format sprite, we must remove any lefthand wastage LDR LR, [R2, #spMode] MOV R10, #0 CMP LR, #256 LDRHS LR, [R2, #spLBit] CMPHS LR, #1 BLO %FT05 ; Wastage removal needed ; Recalculate the sprite width and header MOV R11, LR ; R11 becomes shift amount LDR LR, [R2, #spRBit] SUB LR, LR, R11 LDR R3, [R2, #spWidth] ADD LR, LR, R3, LSL #5 ; LR = Bit width of sprite, minus 1 MOV R4, LR, LSR #5 ; New spWidth AND LR, LR, #31 ; New spRBit STR R10, [R2, #spLBit] STR R4, [R2, #spWidth] STR LR, [R2, #spRBit] ; Shrink sprite size if we've lost a column of words TEQ R3, R4 LDRNE LR, [R2, #spNext] LDRNE R3, [R2, #spHeight] SUBNE LR, LR, #4 SUBNE LR, LR, R3, LSL #2 STRNE LR, [R2, #spNext] ORRNE R11, R11, #1<<31 ; Set top bit of R11 to act as a flag ; Allocate temp buffer large enough for a single scanline MOV R3, R4, LSL #2 ADD R3, R3, #8 ; note +8 so that we can blindly write the last word, even if it's empty MOV R0, #ModHandReason_Claim Push "R2" SWI XOS_Module MOVVC R10, R2 Pull "R2" ADDVS sp, sp, #4 BVS %FT30 05 ; 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] TEQ R10, #0 RSBNE R9, R11, #32 BNE %FT50 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 15 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 ] MOV R10, #0 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 MOVS R2, R10 MOVNE R0, #ModHandReason_Free SWINE XOS_Module ; Release temp buffer 35 SWI XOS_RestoreCursors Pull R14 RETURNVS 50 ; R1 = file handle ; R2 = screen addr ; R5 = source width, bytes ; R6 = height-1 ; R7 = source stride ; R9 = left shift amount ; R10 = temp buffer ; R11 = right shift amount ; if top bit is set, indicates destination is narrower than source Push "R5,R7" ; Work from right to left to hurt my brain less ; LR used to hold the bits which were shifted out of the right of the ; previously written word (i.e. the word to the right of the current) MOV LR, #0 ADD R2, R2, R5 ADD R10, R10, R5 55 LDR R0, [R2, #-4]! ORR R3, LR, R0, LSR R11 MOV LR, R0, LSL R9 STR R3, [R10, #-4]! SUBS R5, R5, #4 BEQ %FT65 60 CMP R5, #4*4 BLT %BT55 ; Do 4 words at a time LDMDB R2!, {R0, R3, R4, R7} ORR R8, LR, R7, LSR R11 MOV LR, R7, LSL R9 ORR R7, LR, R4, LSR R11 MOV LR, R4, LSL R9 ORR R4, LR, R3, LSR R11 MOV LR, R3, LSL R9 ORR R3, LR, R0, LSR R11 MOV LR, R0, LSL R9 STMDB R10!, {R3, R4, R7, R8} SUBS R5, R5, #4*4 BNE %BT60 65 Pull "R5,R7" MOV R8, R2 MOV R2, R10 SUB R3, R5, R11, LSR #29 ; Work out actual row length MOV R0, #2 SWI XOS_GBPB BVS %BT40 ADD R2, R8, R7 SUBS R6, R6, #1 BGE %BT50 MOV R2, R10 MOV R0, #ModHandReason_Free SWI XOS_Module B %BT15 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