; 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.VduGrafJ ; ; ARTHUR OPERATING SYSTEM - Vdu Drivers ; ======================= ; ; Vdu driver code - Sprite stuff ; ; Author R C Manby ; Date 10.11.86 ; ; ***************************************************************************** ; ; GetSpriteUserCoords - Pick up area of screen as sprite using ; given external coordinates ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite name ; R3 = 0 => exclude palette data ; 1 => include palette data ; R4,R5 = (X,Y) EXTERNAL coordinates of one corner of box ; R6,R7 = (X,Y) EXTERNAL coordinates of opposite corner of box ; GetSpriteUserCoords ROUT Push "R1-R3, R14" ADD R8, WsPtr, #GCsX LDMIA R8, {R9,R10} ; preserve GCsX,GCsY around EIG MOV R0, R4 MOV R1, R5 MOV R2, #4 ; indicate absolute coord BL EIG MOV R4, R0 MOV R5, R1 MOV R0, R6 MOV R1, R7 BL EIG MOV R6, R0 MOV R7, R1 STMIA R8, {R9,R10} ; restore GcsX,GCsY Pull "R1-R3, R14" B GetSpr05 ; ***************************************************************************** ; ; GetSprite - Pick up area of screen bounded by OldCs and GCsI as sprite ; ; External routine + GetSpr05 called by GetSpriteUserCoords ; (also external) ; ; in: R1 -> sprite area ; R2 -> sprite name ; R3 = 0 => exclude palette data ; 1 => include palette data ; OldCsX,OldCsY = (X,Y) INTERNAL coordinates of one corner of box ; GCsIX, GCsIY = (X,Y) INTERNAL coordinates of opposite corner of box ; GetSprite ROUT ADD R4, WsPtr, #OldCsX ; pickup area given by OldCs LDMIA R4, {R4-R7} ; and GCsIX GetSpr05 Push R14 [ {TRUE} GraphicsMode R0 BNE %FT70 | LDR R0, [WsPtr, #NPix] TEQ R0, #0 BEQ %FT70 ; quit with error if not graphics mode ] KillSpChoosePtr SortT R4, R6, R8 ; R4 ,R5, R6 ,R7 N.B. BotL & SortT R5, R7, R8 ; sL ,sB, sR ,sT TopR LDR R8, [WsPtr, #YWindLimit] SUB R8, R8, R7 ; use inverted sT as index AND R8, R8, #7 ; into EcfPatternTable STR R8, [WsPtr, #SGetEcfIndx] LDR R0, [WsPtr, #ModeNo] STR R0, [WsPtr, #SGetMode] ; needs setting up before CreateHeader Push R2 BL SpriteCtrlBlk BVC %FT90 ; sprite already exists, so be clever Pull R2 ; restore name pointer ; R1 ,R2 ,R3 ,R4,R5,R6,R7 BL CreateHeader ; In : AreaPtr,NamePtr,Palette ,sl,sb,sr,st ; Out: ImageSize,lx,ty, BVS %FT80 ; Error, (no room/not a graphics mode) BL GetSpriteData ; R1 -> sprite area, R2 -> sprite ; now add the sprite to the sprite area LDR R3, [R2, #spNext] ; total size of new sprite LDMIA R1, {R4-R7} ; saEnd,saNumber,saFirst,saFree ADD R5, R5, #1 ADD R7, R7, R3 STMIA R1, {R4-R7} ; have we made a new format sprite ? if so no left hand wastage is allowed. LDR R3, [R2, #spMode] CMP R3, #256 BLCS RemoveLeftHandWastage BL SelectSprite SWI XOS_RestoreCursors Pull R14 RETURNVC 70 ADRL R0, SpriteErr_NotGraphics [ International BL TranslateError ] 75 STR R0, [WsPtr, #RetnReg0] 80 ; return point after an error Pull R14 RETURNVS ; come here if sprite already exists ; we want to extend or reduce existing sprite as necessary 90 ADD R13, R13, #4 ; throw away stacked name ptr LDR R14, [WsPtr, #VduSprite] TEQ R14, R2 ; if same as vdu output sprite ADREQL R0, SpriteErr_SpriteIsCurrentDest [ International BLEQ TranslateError ] BEQ %BT75 ; then error [ No26bitCode ADR R14, %FT95 | ADR R14, %FT95+SVC_mode ; Enable interrupts on return from PostCreateHeader ] Push "R1, R14" ADD R8, WsPtr, #NameBuf LDMIA R8, {R9-R11} ; load 3 words of name ADD R8, WsPtr, #SGetName STMIA R8, {R9-R11} ; and store in SGetName Push "R1, R2, R3" ; save sprite area, sprite, palflag BL PreCreateHeader Pull "R1, R2" ; restore sprite area ptr + sprite ptr BVS %FT93 ; R4 = total size of sprite Push R4 ; save new size of sprite LDR R0, [R2, #spNext] SUBS R3, R4, R0 ; compare required size with existing MOV R3, R3, ASR #2 ; no. of words to extend/reduce by BEQ %FT94 ; [is exactly right already] BHI %FT92 ; need to extend sprite ; need to reduce sprite RSB R3, R3, #0 ; no. of words to reduce by LDR R4, [R2, #spImage] SUB R4, R0, R4 ; offset from Image to Next SUB R4, R4, R3, LSL #2 ; dest. start as offset from spImage BL RemoveWords RSB R3, R3, #0 ; put R3 back to no. of words to extend B %FT94 ; need to extend sprite 92 BL ExtendSpriteByR3 93 ADDVS R13, R13, #4*4 ; junk size, palflag, ; sprite area, fake return address BVS %BT80 ; no room to extend sprite 94 Pull R4 ; restore new size of sprite B PostCreateHeader ; come back to here after PostCreateHeader exits ; R1 -> sprite area, R2 -> sprite, R3 = no. of words to extend by 95 [ No26bitCode ; Enable interrupts here for 32bit machines WritePSRc SVC_mode, R14 ] BL GetSpriteData BL SelectSprite ; have we made a new format sprite ? if so no left hand wastage is allowed. LDR R3, [R2, #spMode] CMP R3, #256 BLCS RemoveLeftHandWastage SWI XOS_RestoreCursors Pull R14 RETURNVC ; ***************************************************************************** GetSpriteData ROUT Push "R1-R3, R14" SWI XOS_RemoveCursors MOV R0, R4 MOV R1, R5 BL ScreenAddr MOV R0, R2 ; screen addr of TopL of area LDMIA R13, {R4,R5} ; R4->sprite area, R5->sprite LDR R1, [WsPtr, #SGetImage] ADD R1, R1, R5 ; memory address LDR R2, [WsPtr, #SGetWidth] ADD R2, R2, #1 ; sprite width (words) LDR R3, [WsPtr, #SGetHeight] ; height ADD R3, R3, #1 LDR R8, [WsPtr, #SGetTopMargin] ; gap above window (rows) LDR R9, [WsPtr, #SGetBotMargin] ; below (rows) LDR R10, [WsPtr, #SGetLWrdMargin] ; left of (words) LDR R11, [WsPtr, #SGetRWrdMargin] ; right of (words) SUB R2, R2, R10 SUBS R2, R2, R11 ; number words in window per scanline BLEQ PaintSprite ; Left or Right of window BEQ %FT60 SUB R3, R3, R8 SUBS R3, R3, R9 ; number of rows in window BLEQ PaintSprite ; above or below window BEQ %FT60 LDR R14, [WsPtr, #LineLength] ; offset from RHend of row to LHend SUB R14, R14, R2, LSL #2 ; of next row STR R14, [WsPtr, #SGetRowOfst] LDR R11, [WsPtr, #SGetLBitMargin] MOV R5, #&FFFFFFFF MOV R5, R5, LSL R11 ; LmarginMask LDR R11, [WsPtr, #SGetRBitMargin] MOV R6, #&FFFFFFFE MVN R6, R6, LSL R11 ; RmarginMask SUBS R2, R2, #1 STR R2, [WsPtr, #SGetColWCnt] ; if only one word in window per row ANDEQ R5, R5, R6 ; then combine L&R masks MOVEQ R6, R5 STR R5, [WsPtr, #SGetLBitMargin] STR R6, [WsPtr, #SGetRBitMargin] LDR R5, [WsPtr, #SGetTopMargin] ; paint TopMargin (if any) CMP R5, #0 BLNE PaintBlock ; R0 ,R1 ,R2 ,R3 ,R4 .. R11 ; ScrAdr,MemAdr,ColWCnt,RowCnt,{8 words from screen}, 10 LDR R4, [WsPtr, #SGetLWrdMargin] ; paint 1 row of LHmargin (if any) CMP R4, #0 BLNE PaintRow ; on exit R6 holds word of BgEcf, if not called ; R6 is corrupt, but it doesn't matter LDR R2, [WsPtr, #SGetColWCnt] ; on screen word count ( >0 in words) LDR R5, [WsPtr, #SGetLBitMargin] LDR R4, [R0], #4 ; get first on screen word AND R4, R4, R5 BIC R6, R6, R5 ; Write BgEcf (or nonsense) to out of window ORR R4, R4, R6 ; pixels STR R4, [R1], #4 SUBS R2, R2, #1 BLT %FT50 ; if all plotted SUBS R2, R2, #8 ; try for 8 words 20 LDMCSIA R0!, {R4-R11} ; copy 8 words from screen to memory STMCSIA R1!, {R4-R11} SUBCSS R2, R2, #8 BCS %BT20 30 ADDS R2, R2, #8 LDR R6, [WsPtr,#SGetEcfIndx] ADD R6, WsPtr, R6, LSL #2 LDR R6, [R6, #BgEcf] ; BgEcf for this scanline LDR R5, [WsPtr,#SGetRBitMargin] BIC R6, R6, R5 40 LDR R4, [R0], #4 ANDEQ R4, R4, R5 ORREQ R4, R4, R6 STR R4, [R1], #4 SUBS R2, R2, #1 BCS %BT40 50 LDR R4, [WsPtr, #SGetRWrdMargin] CMP R4, #0 BLNE PaintRow LDR R2, [WsPtr, #SGetColWCnt] LDR R4, [WsPtr, #SGetRowOfst] LDR R5, [WsPtr,#SGetEcfIndx] ADD R0, R0, R4 ; offset ScrAdr to next row ADD R5, R5, #1 AND R5, R5, #7 STR R5, [WsPtr, #SGetEcfIndx] ; update EcfIndx to next row SUBS R3, R3, #1 BGT %BT10 ; do next screen line LDR R5, [WsPtr, #SGetBotMargin] ; paint bottom margin (if any) CMP R5, #0 BLNE PaintBlock 60 Pull "R1-R3, PC" ; ***************************************************************************** ; ; PaintSprite - Paint the whole of the sprite in background colour ; ; Internal routine, called by GetSprite when all area is outside window ; ; in: R1 -> first byte in sprite ; PaintSprite ROUT LDR R5, [WsPtr, #SGetHeight] ADD R5, R5, #1 ; R5 = number of rows in sprite ; and drop thru to ... ; ***************************************************************************** ; ; PaintBlock - Paint a number of rows of the sprite in background colour ; ; Internal routine, called by GetSprite to do area above and below window ; and dropped thru to by PaintSprite ; ; in: R1 -> start of first row to paint ; R5 = number of rows to do ; ; out: Flags preserved PaintBlock ROUT [ No26bitCode MRS R4, CPSR Push "R4,R14" | Push R14 ] LDR R4, [WsPtr, #SGetWidth] ADD R4, R4, #1 10 BL PaintRow LDR R6, [WsPtr, #SGetEcfIndx] ADD R6, R6, #1 AND R6, R6, #7 STR R6, [WsPtr, #SGetEcfIndx] SUBS R5, R5, #1 BNE %BT10 [ No26bitCode Pull "R4,R14" MSR CPSR_f, R4 MOV PC,R14 | Pull PC,,^ ; we must preserve the flags ] ; ***************************************************************************** ; ; PaintRow - Paint part of a row in sprite with background colour ; ; Internal routine, called by GetSprite to do areas left+right of window ; and by PaintBlock ; ; in: R1 -> first word to paint ; R4 = number of words to paint ; ; out: R4 preserved ; PaintRow ROUT Push R4 LDR R6, [WsPtr, #SGetEcfIndx] ADD R6, WsPtr, R6, LSL #2 LDR R6, [R6, #BgEcf] ; BgEcf for this scanline 10 STR R6, [R1], #4 SUBS R4, R4, #1 BNE %BT10 Pull R4 MOV PC, R14 ; ***************************************************************************** ; ; CreateSprite - Create a sprite with given attributes ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite name ; R3 = 0/1 => exclude/include palette data ; R4 = width in pixels ; R5 = height in pixels ; R6 = mode number of sprite ; CreateSprite ROUT Push R14 KillSpChoosePtr BL DeleteSpriteByName ; delete any existing sprite STR R6, [WsPtr, #SGetMode] ; needs setting up before CreateHeader SUB R6, R4, #1 ; width in pixels-1 SUB R7, R5, #1 ; height-1 MOV R4, #0 MOV R5, #0 ; R3 ,R4,R5,R6,R7 BL CreateHeader ; In : Palette,sl,sb,sr,st ; Out: ImageSize Pull PC, VS ; if error, then bomb out MOV R4, #0 ; clear R3 words at offset 0 in sprite BL ClearWords ; ie clear image to 0 ; Now add the sprite to the sprite area LDR R3, [R2, #spNext] ; total size of new sprite LDMIA R1, {R4-R7} ; saEnd,saNumber,saFirst,saFree ADD R5, R5, #1 ADD R7, R7, R3 STMIA R1, {R4-R7} Pull R14 RETURNVC ; ***************************************************************************** ; ; CreateHeader - Create a header and info for a sprite ; ; Internal routine, called by GetSprite, CreateSprite, ScreenSave ; ; in: R1 -> sprite area ; R2 -> sprite name ; R3 = 0/1 => exclude/include palette data ; R4,R5 = (X,Y) INTERNAL coordinate of bottom left ; R6,R7 = (X,Y) INTERNAL coordinate of top right ; ; out: R1 preserved ; R2 -> new sprite ; R3 = size of image in words ; R4,R5 = (X,Y) INTERNAL coordinate of top left of on screen area ; R0, R6-R11 corrupted ; CreateHeader ROUT Push "R1, R14" Push R3 BL GetName ; name returned in R9-R11 ADD R8, WsPtr, #SGetName STMIA R8, {R9-R11} ; save the name away BL PreCreateHeader Pull "R0, R1, PC", VS ; now the updating the sprite area bit LDR R1, [R13, #1*4] ; reload sprite area ptr off stack LDR R2, [R1, #saFree] LDR R5, [R1, #saEnd] SUB R5, R5, R2 CMP R5, R4 BCC %FT10 ADD R2, R2, R1 ; address of new sprite PostCreateHeader ADD R5, WsPtr, #SGetName LDMIA R5, {R5-R11} ; R4 spNext, R5-R7 spName(0..2), ; R8 spWidth, R9 spHeight, R10 spLBit, R11 spRBit STMIA R2, {R4-R11} ; write control block for sprite LDR R11, [WsPtr, #SGetImage] STR R11, [R2, #spImage] STR R11, [R2, #spTrans] ; spImage=spTrans ie no mask LDR R11, [WsPtr, #SGetMode] STR R11, [R2, #spMode] ANDS LR, R11, #15<<27 ; do we have an old or new sprite ? BEQ %FT09 TEQ LR, #SpriteType_RISCOS5<<27 ; RISC OS 5 type? [ NoARMT2 ANDEQ LR, R11, #127<<20 MOVEQ LR, LR, LSR #20 | UBFXEQ LR, R11, #20, #7 ] MOVNE LR, LR, LSR #27 09 ADD R4, WsPtr, #SGetTopLeft LDMIA R4, {R4, R5} ; (R4,R5) = TopLeft of 'on screen' area Pull R11 ; R11 = 0/1 for (ex/in)clude palette ;amg 25th May 1994. We now allow palettes on new format sprites in 8bpp and below CMP LR,#SpriteType_New16bpp BCS %FT11 ; check for new 16/32 bpp TEQ R11,#0 ; was a palette wanted in the first place? BLNE WritePaletteToSprite ; do it if so ; ;only allow palette data to be written if EQ and R11<>0 ; ; BNE %FT11 ; ; TEQ R11, #0 ; BLNE WritePaletteToSprite 11 Pull "R1, R14" RETURNVC 10 ADRL R0, SpriteErr_NoRoom [ International BL TranslateError ] STR R0, [WsPtr, #RetnReg0] Pull "R0, R1, R14" ; junk palflag, sprite area ptr RETURNVS ; ***************************************************************************** ; ; SanitizeSGetMode - Convert SGetMode into a new format sprite word if necessary ; ; If SGetMode is either a) a mode selector pointer, or ; b) a mode number which has more than 8bpp ; then SGetMode is replaced by a suitable sprite mode word ; ; amg: 15/10/93: changed to be more keen to generate old format mode numbers. It is ; now also called from createsprite, so it will pass through a new ; sprite mode word unchanged. Mode numbers will be unchanged. Mode ; selectors will be changed to a mode number if one of suitable ; eigs and depth exists --- size of screen is *not* taken into ; account here. ; in: WsPtr -> VDU workspace ; ; out: If OK, then ; V=0 ; All registers preserved ; else ; V=1 ; r0 -> error ; RetnReg0 -> error ; endif ; SanitizeSGetMode Entry "r0-r4,r11" LDR r11, [WsPtr, #SGetMode] CMP r11, #&100 BCC %FT20 ; [not a mode selector or new format sprite word] TST r11, #1 ; is it already a new format sprite word? EXIT NE 10 MOV r0, r11 ; r0 -> mode selector [ ModeSelectors BL ValidateModeSelector STRVS r0, [sp] STRVS r0, [WsPtr, #RetnReg0] EXIT VS ] 15 ; convert to new format sprite word MOV r4, r11 ; preserve the mode for later ;amg: add check for log2bpp=log2bpc MOV r0, r4 MOV r1, #VduExt_Log2BPC SWI XOS_ReadModeVariable MOV R3,R2 MOV r0, r4 MOV r1, #VduExt_Log2BPP SWI XOS_ReadModeVariable CMP R3, R2 BNE %FT90 MOV r0, r4 MOV r1, #VduExt_ModeFlags SWI XOS_ReadModeVariable MOV r3, r2 MOV r0, r4 MOV r1, #VduExt_NColour SWI XOS_ReadModeVariable ; work out the sprite type. Note: Only dealing with RGB colour space here! ADDS r2, r2, #1 MOVEQ r11, #SpriteType_New32bpp BEQ %FT16 CMP r2, #1<<24 MOVEQ r11, #SpriteType_New24bpp BEQ %FT16 CMP r2, #1<<12 MOVEQ r11, #SpriteType_New4K BEQ %FT16 CMP r2, #1<<1 MOVEQ r11, #SpriteType_New1bpp BEQ %FT16 CMP r2, #1<<2 MOVEQ r11, #SpriteType_New2bpp BEQ %FT16 CMP r2, #1<<4 MOVEQ r11, #SpriteType_New4bpp BEQ %FT16 CMP r2, #1<<8 CMPNE r2, #1<<6 MOVEQ r11, #SpriteType_New8bpp BEQ %FT16 CMP r2, #1<<16 BNE %FT90 ; Could be 565 or 1555 TST r3, #ModeFlag_64k MOVEQ r11, #SpriteType_New16bpp MOVNE r11, #SpriteType_New64K 16 ; work out whether we need a RISC OS 5 mode word or not ANDS r3, r3, #ModeFlag_DataFormat_Mask ; Any relevant modeflags set? TSTEQ r11, #&F0 ; Type too big for 4 bits? BEQ %FT17 ; RISC OS 5 style sprite mode word ORR r11, r3, r11, LSL #20 ; sprite type plus mode flags ORR r11, r11, #1 + (SpriteType_RISCOS5<<27) MOV r1, #VduExt_XEigFactor SWI XOS_ReadModeVariable ORR r11, r11, r2, LSL #4 ; put xdpi into position MOV r1, #VduExt_YEigFactor SWI XOS_ReadModeVariable ORR r11, r11, r2, LSL #6 ; put ydpi into position STR r11, [WsPtr, #SGetMode] ; store new value EXIT 17 ; "New"-style sprite mode word MOV r11, r11, LSL #27 ORR r11, r11, #1 MOV r1, #VduExt_XEigFactor SWI XOS_ReadModeVariable MOV lr, #180 MOV lr, lr, LSR r2 ; cope with 45, 90, 180 dpi ORR r11, r11, lr, LSL #1 ; put into xdpi position MOV r1, #VduExt_YEigFactor SWI XOS_ReadModeVariable MOV lr, #180 MOV lr, lr, LSR r2 ORR r11, r11, lr, LSL #14 ; put into ydpi position STR r11, [WsPtr, #SGetMode] ; store new value ;now check if we can force it back to a mode number ;if the bpp is > 8 the answer is no AND r2, r11, #15<<27 CMP r2, #SpriteType_New16bpp EXIT CS BIC r0, r11, #&F8000000 ; take off the type information ADR r1, substitute_list ADD r2, r1, #12 ; end of list 27 LDR r3, [r1], #4 TEQ r3, r0 BEQ %FT28 TEQ r1, r2 EXIT EQ ; can't do anything with it BNE %BT27 28 ADD r1, r1, #8 ; point at modes word, allowing for post inc ADD r1, r1, r11, LSR #27 ; add in the sprite's type SUB r1, r1, #1 ; and reduce it by one LDRB r1, [r1] ; fetch the right mode number ;if we got 255, we can't save the day CMP r1,#255 STRNE r1, [WsPtr, #SGetMode] ; and store it EXIT substitute_list DCD &001680B5 ;90 X 90 DPI, X/Y EIG 1 1 DCD &000B40B5 ;90 X 45 DPI, X/Y EIG 1 2 DCD &000B405B ;45 X 45 DPI, X/Y EIG 2 2 ;amg: used to use mode 4 for 2 colour eig 2 x 2 - now doesn't because of ;confusion about double pixels DCD &1C1B1A19 ;modes 25, 26, 27, 28 for 90 x 90 DCD &0F0C0800 ;modes 0, 8, 12, 15 for 90 x 45 DCD &0D0901FF ;modes n/a, 1, 9, 13 for 45 x 45 20 MOV r0, r11 ; check if bpp for mode is > 8 MOV r1, #VduExt_Log2BPP SWI XOS_ReadModeVariable CMP r2, #4 BCS %BT15 ; if so then convert to new format sprite as well EXIT 90 ADRL R0, ErrorBlock_BadMODE [ International BL TranslateError ] STR r0, [sp] STR r0, [WsPtr, #RetnReg0] SETV EXIT ; ***************************************************************************** PreCreateHeader ROUT Push R14 BL SanitizeSGetMode ; convert SGetMode to new format sprite if nec. Pull PC, VS ; duff mode selector ;amg 25th May 1994 ;We now allow palettes on new format sprites of 8bpp and below ; ;force to no palette space if a new format sprite ; LDR LR, [WsPtr, #SGetMode] ; get the mode ; MOVS LR, LR, LSR #27 ; set NE if new ; MOVNE R3, #0 ; turn off palette LDR LR, [WsPtr, #SGetMode] ; get the sprite mode word BIC LR, LR, #&80000000 ; ignore alpha mask flag CMP LR, #SpriteType_RISCOS5<<27 MOVLO LR, LR, LSR #7 ; shift sprite type to its RISC OS 5 location ANDHS LR, LR, #127<<20 ; or get RISC OS 5 type as-is CMP LR, #SpriteType_New16bpp<<20 ; check for true colour MOVHS R3, #0 ; turn off the palette request TEQ R3, #0 ; convert R3 into mask to (ex/in)clude MOVNE R3, #&FF ; space for palette data ; amg need more palette space in case it's going to be a full palette ORRNE R3, R3, #&300 Push "R6, R7" ; preserve R6,R7 over the call ADD R2, WsPtr, #SGetNext BL SetupSprModeData ; R6 ,R7 ,R8 ,R9 ,R10 ,R11 ; Out: RdNCol,WrNCol,BytePC,XShft,NPix,Log2BPC ; amg 26th October 1993 - kill another bit of Arthur compatibility in favour ; of full palette 8bpp sprites ; AND R6, R6, #63 ; make 64 palette entries like MOS 1.2 LDR R7,[WsPtr,#ModeFlags] TST R7, #ModeFlag_FullPalette ANDEQ R6, R6, #63 ADD R6, R6, #1 ; number of palette entries in this mode AND R3, R3, R6 ; if (palette not wanted) OR (256 colour mode) ; then R3=0 else R3=number of palette entries ; N.B. in 256 colour modes we end up ignoring ; the palette Pull "R6,R7" Pull PC, VS ; error, not a graphics mode MOV R3, R3, LSL #3 ; two words per palette entry ADD R3, R3, #SpriteCBsize STR R3, [WsPtr, #SGetImage] ; R0-R3 now free for use ; R4 ,R5, R6 ,R7 ; sL ,sB, sR ,sT SUB R0, R7, R5 ; height-1 STR R0, [WsPtr, #SGetHeight] ADD R0, R0, #1 ; actual height in rows LDR R1, [WsPtr, #GWTRow] ; if SpriteTopRow > GWTopRow SUBS R2, R7, R1 MOVGT R7, R1 ; then clip for ScreenAddr's benefit MOVLE R2, #0 Least R2, R2, R0 STR R2, [WsPtr, #SGetTopMargin] ; number of blank rows at top LDR R1, [WsPtr, #GWBRow] SUBS R2, R1, R5 MOVLT R2, #0 Least R2, R2, R0 STR R2, [WsPtr, #SGetBotMargin] ; number of blank rows at bottom WordOffset R0,R4, R9,R10,R11 ; offset to sL WordOffset R1,R6, R9,R10,R11 ; to sR SUB R2, R1, R0 ; width-1 STR R2, [WsPtr, #SGetWidth] ADD R2, R2, #1 ; actual width in words BitLOffset R3,R4, R9,R10,R11 ; LBit STR R3, [WsPtr, #SGetLBit] BitROffset R3,R6, R9,R10,R11 ; RBit STR R3, [WsPtr, #SGetRBit] LDR R8, [WsPtr, #GWLCol] Greatest R4,R4,R8 WordOffset R3,R4, R9,R10,R11 ; offset to clipL SUB R3, R3, R0 Least R3,R3,R2 STR R3, [WsPtr, #SGetLWrdMargin] ; no. of blank words at left BitLOffset R3,R4, R9,R10,R11 STR R3, [WsPtr, #SGetLBitMargin] ; no. of blank words at right LDR R8, [WsPtr, #GWRCol] Least R6, R6, R8 WordOffset R3,R6, R9,R10,R11 ; offset to clipR SUB R3, R1, R3 Least R3, R3, R2 STR R3, [WsPtr, #SGetRWrdMargin] BitROffset R3,R6, R9,R10,R11 STR R3, [WsPtr, #SGetRBitMargin] ADD R0, WsPtr, #SGetTopLeft STMIA R0, {R4, R7} ; store top & left of 'on screen' area LDR R0, [WsPtr, #SGetWidth] LDR R1, [WsPtr, #SGetHeight] ADD R0, R0, #1 ; width in words ADD R1, R1, #1 ; height in words MUL R3, R1, R0 ; image size in words LDR R4, [WsPtr, #SGetImage] ADD R4, R4, R3, LSL #2 ; total size in bytes Pull R14 RETURNVC ; ***************************************************************************** ; ; Decide mask size ; ; Internal routine called from CreateMask ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = size of image data (bytes) ; ; out: R3 = size of mask data (words) DecideMaskSize ROUT Entry "R5,R8" LDR LR, [R2, #spMode] ; get the sprite mode MOVS LR, LR, LSR #27 ; isolate the type MOVEQ R3,R3,LSR #2 ; if T=0 then return the same size as EXIT EQ ; the image (but returns in words not ; bytes) LDR R5, [R2, #spWidth] BL GetMaskspWidth ; get mask width information LDR LR, [R2, #spHeight] ; number of rows (minus 1) ADD R5, R5, #1 ; width in words ADD LR, LR, #1 ; height in rows MUL R3, LR, R5 ; number of words for the mask EXIT ; ***************************************************************************** ; ; CreateMask - Add mask to sprite or set existing mask to 'solid' ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; CreateMask ROUT Push R14 KillSpChoosePtr LDR R4, [R2, #spNext] LDR R5, [R2, #spImage] ; NB Image=Trans if NO mask LDR R6, [R2, #spTrans] SUB R3, R4, R6 BL DecideMaskSize ; returns R3=size of mask (words) TEQ R5, R6 BNE %FT10 ; mask exists MOV R6, R4 BL ExtendSprite ADRVSL R0, SpriteErr_NotEnoughRoom ; only error is NoRoomToInsert [ International BLVS TranslateError ] STRVS R0, [WsPtr, #RetnReg0] ; correct this to 'Not enough room' Pull PC, VS STR R6, [R2, #spTrans] ; new spTrans := old spNext 10 ; R3 mask size (words), R6 spTrans ADD R6, R6, R2 MOV R4, #&FFFFFFFF 20 STR R4, [R6], #4 SUBS R3, R3, #1 BNE %BT20 Pull R14 RETURNVC ; ***************************************************************************** ; ; RemoveMask - Remove mask from sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; RemoveMask ROUT Push R14 KillSpChoosePtr LDR R4, [R2, #spNext] LDR R5, [R2, #spImage] ; NB spTrans = spImage, if NO mask LDR R6, [R2, #spTrans] TEQ R5, R6 BEQ %FT10 ; no mask so ignore SUB R3, R4, R6 BL DecideMaskSize ; returns R3=size in words SUB R4, R6, R5 BL RemoveWords LDR R5, [R2, #spImage] ; spTrans := spImage, ie NO mask STR R5, [R2, #spTrans] 10 Pull R14 RETURNVC ; ***************************************************************************** ; ; WritePaletteToSprite - Write palette information into sprite CB ; ; Internal routine, called by CreateHeader ; ; in: R2 -> sprite ; ; out: All registers preserved ; WritePaletteToSprite ROUT Push "R0-R4, R14" LDR R0, [WsPtr, #SprReadNColour] ; highest palette entry ; amg 26th October 1993 - this bit of Arthur compatibility bites the ; dust to make screensaving full palette sprites work properly ; AND R0, R0, #63 ; make 63 if 255 like MOS 1.20 LDR R4, [WsPtr,#ModeFlags] TST R4, #ModeFlag_FullPalette ANDEQ R0, R0, #63 ADD R4, R2, R0, LSL #3 ADD R4, R4, #spPalette ; ptr to last pal pos in spPalette 10 MOV R1, #16 ; read 'normal' colour SWI XOS_ReadPalette STMIA R4, {R2,R3} SUB R4, R4, #8 SUBS R0, R0, #1 BCS %BT10 Pull "R0-R4,PC" ; ***************************************************************************** ; ; WritePaletteFromSprite - Write palette from information in sprite CB ; ; Internal routine, called by ScreenLoad ; ; in: R2 -> sprite ; ; out: All registers preserved ; WritePaletteFromSprite ROUT Push "R0-R6, R14" LDR R0, [WsPtr, #ModeNo] LDR R1, [R2, #spMode] [ {TRUE} :LAND: ModeSelectors ;logic for this routine ; ;[WsPtr, #ModeNo] is the current mode/ptr to mode selector ;R2 points at sprite data ;[WsPtr, #SloadModeSel] is 36 bytes for building a mode selector for the sprite ; ;sprite mode < 256 ? ;yes: equal to current mode ? ; yes: already in correct mode. done. ; no: change to mode sprite wants, done. ;no: build a mode selector for the sprite ; check pixel depth, xres, yres, xdpi and ydpi ; all identical ? ; yes: already in suitable mode. done. ; no: change mode. done. ;if we do a mode change, remember to re-remove cursors ;amg 15 Oct '93 Screensave is about to be changed to use a representative ;mode number of the eigs and depth (only), so screenload no longer believes ;the screen mode number in the file. ;amg 21 Dec '93 Slight modification - if the screen mode change failed, and ;we have an old screen mode number, use that as a last gasp ; CMP R1, #256 ; BCS %FT30 ;branch if a new format sprite mode word ; CMP R1, R0 ;are we in the right (old style) mode ? ; BEQ %FT10 ; MOV R0,#ScreenModeReason_SelectMode ; SWI XOS_ScreenMode ; STRVS R0, [WsPtr, #RetnReg0] ;exit on error ; Pull "R0-R6,PC", VS ; B %FT40 ;otherwise get on with it 30 ; new format sprite mode word ; build the mode selector at SLoadModeSel MOV R5, R1 ;keep the mode number/sprite mode word safe ;do the absolutes first MOV R3, #-1 STR R3, [WsPtr, #SloadModeSel+ModeSelector_FrameRate] STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+16] ;list terminator after two pairs STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+32] ;list terminator after four pairs MOV R3, #128 STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+20] ;modeflags value, if needed MOV R3, #VduExt_NColour STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+24] MOV R3, #255 STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+28] MOV R3, #1 STR R3, [WsPtr, #SloadModeSel+ModeSelector_Flags] MOV R3, #VduExt_XEigFactor STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars] ; modevar 1 = xeig MOV R3, #VduExt_YEigFactor STR R3, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+8] ; modevar 2 = Yeig ;now the things from the sprite ; MOV R3, R1, LSR #27 ;sprite type ; ADRL R4, NSM_bpptable-4 ;readmodevar's table ; LDR R3, [R4, R3, LSL #2] ;word index ; STR R3, [WsPtr, #SloadModeSel+ModeSelector_PixelDepth] ;change to calling read mode variable to cope with mode number or sprite mode word MOV R4, R2 ;save the sprite pointer MOV R0, R5 ;sprite mode word/mode number MOV R1, #VduExt_Log2BPP SWI XOS_ReadModeVariable STR R2, [WsPtr, #SloadModeSel+ModeSelector_PixelDepth] MOV R3, R2 ;if log2bpp=3, and size of palette data indicates full palette, we need to force ;a suitable mode CMP R3, #3 BNE %FT40 ADD LR, R4, #spImage ;point to image/mask start LDMIA LR,{R2,LR} ;fetch them CMP R2,LR ;which is bigger ? MOVGT R2,LR ;use the least SUB R2,R2,#spPalette ;and the palette size is... CMP R2,#&800 ;full entry 256 colour ;change the mode selector so it includes a modeflags word ;(following two words already set up) MOVEQ R2, #0 ;amg 28/4/94 bugfix - following inst wasn't conditional STREQ R2, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+16] 40 MOV R2, R4 ;restore the sprite pointer LDR R4, [R2, #spWidth] ;number of words MOV R4, R4, LSL #5 ;convert to a number of bits LDR LR, [R2, #spRBit] ;last bit used ADD LR, LR, #1 ;convert to number of bits ADD R4, R4, LR ;combine MOV R4, R4, LSR R3 ;and convert to pixels STR R4, [WsPtr, #SloadModeSel+ModeSelector_XRes] LDR R3, [R2, #spHeight] ADD R3, R3, #1 STR R3, [WsPtr, #SloadModeSel+ModeSelector_YRes] MOV R6, R2 ;save the sprite pointer for later ;that leaves the x and y eig factors, which are derived ;from the dpi MOV R0, R5 ;R0 = sprite mode word MOV R1, #VduExt_XEigFactor SWI XOS_ReadModeVariable STRCC R2, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+4] MOVCC R1, #VduExt_YEigFactor SWICC XOS_ReadModeVariable STRCC R2, [WsPtr, #SloadModeSel+ModeSelector_ModeVars+12] BCS %FT90 ;we canna take it captain.... ;do the comparison which involve the mode selectors first ;depth LDR LR, [WsPtr, #ModeNo] LDR R3, [LR, #ModeSelector_PixelDepth] LDR R4, [WsPtr, #SloadModeSel+ModeSelector_PixelDepth] TEQ R3, R4 BNE %FT80 ;need to change mode to new mode selr LDR R3, [LR, #ModeSelector_XRes] LDR R4, [WsPtr, #SloadModeSel+ModeSelector_XRes] TEQ R3, R4 BNE %FT80 ;need to change mode to new mode selr LDR R3, [LR, #ModeSelector_YRes] LDR R4, [WsPtr, #SloadModeSel+ModeSelector_YRes] TEQ R3, R4 BNE %FT80 ;need to change mode to new mode selr ;now the eigs LDR R3, [WsPtr, #XEigFactor] LDR R4, [WsPtr, #SloadModeSel+ModeSelector_Flags+4] TEQ R3, R4 BNE %FT80 ;need to change mode to new mode selr LDR R3, [WsPtr, #YEigFactor] LDR R4, [WsPtr, #SloadModeSel+ModeSelector_Flags+12] TEQ R3, R4 BEQ %FT10 ;this mode is suitable 80 MOV R0,#ScreenModeReason_SelectMode ADD R1,WsPtr,#SloadModeSel SWI XOS_ScreenMode [ {TRUE} ;ensure we preserve the error pointer in situations where we can't try to ;fall back to the mode number in the sprite header ;if it errored try again if there's a mode number available BVC %FT40 LDR R1, [R6, #spMode] BICS R14, R1, #&FF ; EQ if sprite mode is a number (< 256), (V still set afterwards) MOVEQ R0, #ScreenModeReason_SelectMode SWIEQ XOS_ScreenMode ; if called, will set V appropriately | ;if it errored try again if there's a mode number available BVC %FT40 MOV R0, #ScreenModeReason_SelectMode LDR R1, [R6, #spMode] BICS R14, R1, #&FF ; EQ if sprite mode is a number (< 256), (V still set afterwards) SWIEQ XOS_ScreenMode ; if called, will set V appropriately ] STRVS R0, [WsPtr, #RetnReg0] ;exit on error Pull "R0-R6,PC", VS B %FT40 ;otherwise get on with it 90 ADRL R0,SpriteErr_InvalidSpriteMode [ International BL TranslateError | SETV ] STR R0, [WsPtr, #RetnReg0] Pull "R0-R6,PC" | ;as originally done this code tended to compare mode specifiers against new ;sprite mode words, and worse still tried to select a mode from a new sprite ;mode word. the rewrite above takes a more logical approach CMP R0, R1 ; if already in correct mode BEQ %FT10 ; then skip [ ModeSelectors MOV r0, #ScreenModeReason_SelectMode SWI XOS_ScreenMode | MOV R0, #22 SWI XOS_WriteC MOVVC R0, R1 SWIVC XOS_WriteC ] STRVS R0, [WsPtr, #RetnReg0] Pull "R0-R6,PC", VS ] 40 SWI XOS_RemoveCursors ; remove cursors again 10 MOV R2, R6 LDR R3, [R2, #spImage] CMP R3, #spPalette ; will clear V if EQ Pull "R0-R6, PC", EQ ; no palette data LDR R4, [WsPtr, #NColour] ADD R3, R2, #spPalette ADD R3, R3, R4, LSL #3 20 LDMIA R3, {R1,R2} MOV R0, R4 BL SendPalettePair Pull "R0-R6, PC", VS SUB R3, R3, #8 SUBS R4, R4, #1 ; (V will be cleared by this) BCS %BT20 Pull "R0-R6, PC" ; ***************************************************************************** ; ; SendPalettePair - Program palette with flash pair ; ; Internal routine, called by WritePaletteFromSprite ; ; in: R0 = logical colour ; R1 = first flash colour ; R2 = second flash colour ; ; out: R1 corrupted ; SendPalettePair ROUT Push "R0-R3, R14" TEQ R1, R2 ; are colours the same ? BNE %FT10 ; if not then do in two halves MOV R3, #16 BL SendPaletteEntry ; then send with 16 Pull "R0-R3, PC" 10 MOV R3, #17 ; else send 1st flash with 17 BL SendPaletteEntry MOVVC R1, R2 MOVVC R3, #18 ; then 2nd flash with 18 BLVC SendPaletteEntry Pull "R0-R3, PC" ; ***************************************************************************** ; ; SendPaletteEntry - Program one palette entry ; ; Internal routine, called by SendPalettePair ; ; in: R0 = logical colour ; R1 = physical colour BGRx ; R3 = PP field to use ; ; out: All registers preserved ; SendPaletteEntry ROUT Push "R0,R1, R14" BIC R1, R1, #&7F ; clear all bits except sup. bit ORR R1, R1, R3 ; or in new bits MOV R0, R0, LSL #24 ; move log. col. up to top 8 bits Push "R0, R1" ; create an OSWORD block at R13+3 MOV R0, #12 ADD R1, R13, #3 ; R1 -> block SWI XOS_Word STRVS R0, [WsPtr, #RetnReg0] ADD R13, R13, #8 Pull "R0,R1, PC" END