; 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.VduGrafG ; ; ARTHUR OPERATING SYSTEM - Vdu Drivers ; ======================= ; ; Vdu driver code - Sprite stuff ; ; Author R C Manby ; Date 10.11.86 ; RangeB * 256 RangeC * 512 ; Macros for various sprite operations MACRO KillSpChoosePtr MOV R0, #0 STR R0, [WsPtr, #SpChoosePtr] MEND MACRO CopyDown $to,$from,$bytes, $tmp, $tmp2 LDR $tmp2, [WsPtr, #VduSprite] ; sprite being output to by Vdu ADD $tmp, $from, $bytes SUB $tmp, $tmp, #1 ; from + bytes -1 CMP $tmp2, $to ; if VOTS >= to CMPCS $tmp, $tmp2 ; and from+bytes-1 >= VOTS BCC %FT00 Push "R0, R14" SUB R0, $to, $from ; then adjust address vars BL AdjustSpriteAddress ; by offset = to-from Pull "R0, R14" 00 CMP $bytes, #0 ; bytes must be a multiple of 4 01 LDRNE $tmp, [$from], #4 STRNE $tmp, [$to], #4 SUBNES $bytes, $bytes, #4 BNE %BT01 MEND MACRO CopyUp $to,$from,$bytes, $tmp, $tmp2 LDR $tmp2, [WsPtr, #VduSprite] ; sprite being output to by Vdu ADD $tmp, $to, $bytes SUB $tmp, $tmp, #1 ; to + bytes -1 CMP $tmp2, $from ; if VOTS >= from CMPCS $tmp, $tmp2 ; and to+bytes-1 >= VOTS BCC %FT00 Push "R0, R14" SUB R0, $to, $from ; then adjust address vars BL AdjustSpriteAddress ; by offset = to-from Pull "R0, R14" 00 01 SUBS $bytes, $bytes, #4 LDRCS $tmp, [$from, $bytes] STRCS $tmp, [$to, $bytes] BHI %BT01 MEND ; copy R0 bytes from R3 to R2 (R2+:=R0; R3+:=R0) ; corrupts R0, R4-R11, R14 ; NB not used at present MACRO CopyDownFast SUBS R0, R0, #9*4 10 LDMCSIA R3!, {R4-R11,R14} STMCSIA R2!, {R4-R11,R14} SUBCSS R0, R0, #9*4 BCS %BT10 ADDS R0, R0, #9*4 20 LDRNE R4, [R3], #4 STRNE R4, [R2], #4 SUBNES R0, R0, #4 BNE %BT20 MEND MACRO ClearWords $from,$words, $tmp MOV $tmp,#0 01 SUBS $words, $words, #1 STRCS $tmp, [$from], #4 BHI %BT01 MEND ; ***************************************************************************** ; ; AdjustSpriteAddress - Move VduSprite, ScreenStart, CursorAddr and ; InputCursorAddr by R0 ; ; Internal routine, called by routines that use macros ; CopyDown, CopyUp ; ; in: R0 = no. of bytes to add on (can be -ve) ; AdjustSpriteAddress ROUT Push R14 LDR R14, [WsPtr, #VduSprite] ADD R14, R14, R0 STR R14, [WsPtr, #VduSprite] LDR R14, [WsPtr, #ScreenStart] ADD R14, R14, R0 STR R14, [WsPtr, #ScreenStart] B AdjustCursorVars ; update CursorAddr, InputCursorAddr ; ***************************************************************************** ; ; SpriteInit - Setup sprite workspace on reset (called whenever break ; is pressed) ; SpriteInit ROUT Push R14 BL ClearSpritePtrName ; clear SpChoosePtr,SpChooseName Pull PC LTORG ; ***************************************************************************** ; ; Vdu23_27 - SCHOOSE/SGET a numbered sprite ; ; in: QQ?0 = 0 => Select sprite STR$(QQ?1) for plotting ; QQ?0 = 1 => Sget an area of screen and put it in sprite STR$(QQ?1) ; Vdu23_27 ROUT LDRB R0, [WsPtr, #QQ+1] CMP R0, #1 MOVCC R3, #SpriteReason_SelectSprite ; 0-Select sprite MOVEQ R3, #SpriteReason_GetSprite ; 1-Pickup sprite MOVHI PC, R14 Push R14 LDRB R0, [WsPtr, #QQ+2] ; sprite number ADD R1, WsPtr, #NameBuf MOV R2, #4 SWI XOS_BinaryToDecimal MOV R0, #13 STRB R0, [R1, R2] ; $NameBuf := STR$(n) MOV R0, R3 ; R0 = sprite-op reason code MOV R2, R1 ; R2 -> sprite name MOV R3, #0 ; extension gap size SWI XOS_SpriteOp ; perform operation, ignore errors Pull PC ; ***************************************************************************** ; ; SpritePlot - PLOT &E8-&EF,X,Y ; ; in: R2 = plot code ; ; The 2 LSBits of the plot code specify fg/bg colour and action as :- ; 0 => No effect eqv. of Gcol(5,c) ; 1 => Plot sprite using foreground Gcol action ; 2 => Invert eqv. of Gcol(4,c) ; 3 => Plot mask in background colour and Gcol action ; SpritePlot ROUT Push R14 AND R3, R2, #3 ; 2 LSBits of plot code CMP R3, #1 MOVCC R5, #5 ; gcol action - no effect LDREQ R5, [WsPtr, #GPLFMD] ; foreground MOVHI R5, #4 ; invert or background AND R5, R5, #&0F ; knock out any ecf bits LDR R2, [WsPtr, #SpChoosePtr] ; If ChoosePtr <> 0 CMP R2, #0 BNE %FT10 ; then use as pointer to sprite MOV R0, #SpriteReason_SelectSprite ; else select it first LDR R2, =SpChooseName ADD R2, R2, WsPtr ; sprite name ptr SWI XOS_SpriteOp LDR R2, [WsPtr, #SpChoosePtr] 10 ; R2 points to the sprite CMP R3, #3 MOVNE R0, #RangeC+SpriteReason_PutSprite LDREQ R0, =RangeC+SpriteReason_PlotMask LDR R1, [WsPtr, #SpAreaStart] SWI XOS_SpriteOp ; perform operation, ignoring errors Pull PC ; ***************************************************************************** ; ; SwiSpriteOp - Entry point for SWI OS_SpriteOp ; ; in: R0 = sprite op reason code ; R1 -> sprite area (usually) ; R2 -> sprite (usually) ; R3..? parameters ; SwiSpriteOp ROUT Push R14 BranchNotJustUs %F10, SpriteV, R11, R14 ; we are sole owners of SpriteV, so call our internal routine Push PC ; push address of SwiSpriteReturn B SpriteVecHandler & 0 SwiSpriteReturn Pull R14 ORRVS R14, R14, #V_bit ; if error, set V_bit in link ExitSWIHandler ; we are not the sole owners of SpriteV, so call the vector 10 MOV R10, #SpriteV BL %FT20 Pull R14 ORRVS R14, R14, #V_bit ; if error, set V_bit in link ExitSWIHandler 20 CallAVector ; ***************************************************************************** ; ; SpriteVecHandler - Default owner of SpriteV ; ; in: R0-R7 contain our entry parameters ; ; out: R0-R7 contain exit parameters ; R8-R12 are preserved ; MACRO SpriteOpDispatch $cond ADD$cond PC, R10, R11, ASR #8 MEND MACRO SpriteOpEntry $addr, $flags & (($addr - SwiSpriteOpCallTb) :SHL: 8) + $flags MEND ; The end of this code is put before the beginning, so that ; SpriteDispatchReturn + SVC_mode is within ADR reach of the dispatcher BadReasonCode ROUT ADRL R0, SpriteErr_BadReasonCode [ International BL TranslateError ] B %FT20 SpriteIsCurrentDest ADRL R0, SpriteErr_SpriteIsCurrentDest [ International BL TranslateError ] B %FT20 15 ADRL R0, SpriteErr_DoesntExist [ International BL TranslateError ] 20 ; Exit SWI with error, error code in R0 STR R0, [WsPtr, #RetnReg0] 30 SETV ; indicate an error ; and drop thru to... SpriteDispatchReturn ADD R11, WsPtr, #RetnReg0 LDMIA R11, {R0-R9} ; Restore R0-R9 MOV R10, R13 ; Point at old returned registers Push "R0-R9" ; Save new returned registers on stack LDMIA R10, {R0-R9} ; Load old returned registers STMIA R11, {R0-R9} ; and put them in the dump area Pull "R0-R9" ; restore new returned registers ADD R13, R13, #10*4 ; remove stack frame Pull "R10-R12,PC" SpriteVecHandler Push "R10-R12" WritePSRc SVC_mode, WsPtr ; Re-enable interupts VDWS WsPtr ; Point R12 at Vdu driver workspace ADD R11, WsPtr, #RetnReg0 SUB R13, R13, #10*4 ; Create stack frame for old RetnRegs MOV R10, R13 ; Keep pointer to this frame Push "R0-R9" ; Save new regs while we copy old ones LDMIA R11, {R0-R9} ; Load old regs STMIA R10, {R0-R9} ; and push them onto stack Pull "R0-R9" ; Restore new regs STMIA R11, {R0-R9} ; Dump R0-R9 CMP R0, #RangeC + &100 ; if top bits out of range BCS BadReasonCode ; then error CMP R0, #RangeB ; if Range A type LDRCC R1, [WsPtr, #SpAreaStart] ; then point at MOS sprite area AND R0, R0, #&FF ; Kill the range bits CMP R0, #(SwiSpriteOpCallTb_End-SwiSpriteOpCallTb)/4 BCS BadReasonCode ADR R10, SwiSpriteOpCallTb ADR R14, SpriteDispatchReturn ; return address LDR R11, [R10, R0, LSL #2] ; load (offset<<8) + flags TST R11, #SSO_ScreenNotAllowed ; if call can specify screen (R2=0) TEQEQ R2, #0 ; and it is specified MOVEQ R1, #0 ; then make sprite area ptr 0 as well TSTNE R11, #SSO_NeedsSomething ; or nothing needed anyway SpriteOpDispatch EQ ; then dispatch TEQ R1, #0 ; else needs sprite area ptr ADREQ R0, SpriteErr_NoWorkSpace ; so if zero then invalid [ International BLEQ TranslateError ] BEQ %BT20 TST R11, #SSO_DangerAreaOp ; if not a danger area op BEQ %FT32 ; then skip LDR R9, [WsPtr, #VduSpriteArea] ; else check if sprite area is same TEQ R9, R1 BEQ SpriteIsCurrentDest ; and error if so 32 TST R11, #SSO_NeedsSprite ; if doesn't need sprite BNE %FT33 TEQ R0,#SpriteReason_CreateSprite BEQ %FT21 TEQ R0,#SpriteReason_ScreenSave TEQNE R0,#SpriteReason_GetSprite TEQNE R0,#SpriteReason_GetSpriteUserCoords SpriteOpDispatch NE ; let it go if we're not interested in it LDR R9,[WsPtr, #Log2BPP] ; fetch the current bpp CMP R9,#4 SpriteOpDispatch CC ; let it go if below 16bpp 22 CMP R3,#0 BNE %FT34 ; bang if it has a palette SpriteOpDispatch ; then dispatch 21 ;createsprite. R6=mode number or sprite mode word, or => mode descriptor Push "R0-R3,R14" MOV R0,R6 MOV R1,#VduExt_Log2BPP SWI XOS_ReadModeVariable MOVCS R2,#0 CMP R2,#4 Pull "R0-R3,R14" SpriteOpDispatch CC B %BT22 33 TEQ R2, #0 ; if sprite ptr is zero it's a boob BEQ %BT15 ; so say SpriteDoesntExist LDR R9, [WsPtr, #RetnReg0] CMP R9, #RangeC ; if not range C then must look up BCS %FT35 ; sprite name and convert to pt4 Push R14 BL SpriteCtrlBlk ; in: R2 -> name; out: R2 -> sprite Pull R14 BVS %BT15 ; no such sprite 35 ;medusa note. ; ;On Medusa masks and palettes for 16/32bpp sprites are in a transient state ;Medusa will fault 16/32bpp mask/palette operations, in readiness for the ;introduction of new (more compact) mask/palette formats. ; ;another medusa note. ; ;Mask operations using 1bpp masks on new format sprites are now being included. ;However palettes on 16/32bpp are still not allowed. ; ;amg 12/11/93, sort out the logic here so that palettes on new format sprites ;really do get faulted ;amg 25th May 1994. We now allow palettes on new format sprites of 8bpp ;and below ; find the sprite type Push "R14" LDR R9,[R2,#spMode] ANDS R14,R9,#15<<27 ; get the sprite type BEQ %FT37 ; t=0 (ie old format) CMP R14,#SpriteType_RISCOS5<<27 ; if it's a RISC OS 5 sprite mode word MOVEQ R14,R9,LSR #20 ; then get the actual sprite type MOVNE R14,R14,LSR #27 ANDEQS R14,R14,#127 MOVEQ R14,#SpriteType_Substitute ; Panic and treat as 32bpp? CMP R14,#SpriteType_New16bpp ; check sprite type number BCC %FT38 ; despatch if new format and under 16bpp 39 ; so, does it have a palette ADD R9,R2,#spImage LDMIA R9,{R9,R14} ; pick up offsets to mask & image CMP R9,R14 MOVGT R9,R14 ; R9->top of palette block SUBS R9,R9,#spPalette ; R9 = size of palette block BEQ %FT38 ; no palette, so no error Pull "R14" 34 ADRL R0, SpriteErr_NoMaskOrPaletteAllowedInThisDepth [ International BL TranslateError ] B %BT20 37 ;however, until mode selectors work there are some 16/32bpp old modes Push "R0-R3" ; save context MOV R0,R9 MOV R1,#VduExt_Log2BPP SWI XOS_ReadModeVariable ; read log2bpp for the sprite's mode MOV R9,R2 ; and move it for posterity Pull "R0-R3" CMP R9,#4 BCS %BT39 ; log2bpp of 4 = 16bpp, so see if we want to fault it 38 TST R11, #SSO_DangerOp ; if a destructive op Pull "R14" BEQ %FT40 LDR R9, [WsPtr, #VduSprite] TEQ R9, R2 BEQ SpriteIsCurrentDest ; then stop him! 40 TST R11, #SSO_NeedsSpriteModeData SpriteOpDispatch EQ Push "R5-R7, R10, R11, R14" BL SetupSprModeData Pull "R5-R7, R10, R11, R14" SpriteOpDispatch VC B %BT30 ; Invalid spMode field SSO_ScreenNotAllowed * 1 :SHL: 0 SSO_NeedsSomething * 1 :SHL: 1 SSO_NeedsSprite * 1 :SHL: 2 SSO_NeedsSpriteModeData * 1 :SHL: 3 SSO_DangerOp * 1 :SHL: 4 SSO_DangerAreaOp * 1 :SHL: 5 Group1 * SSO_ScreenNotAllowed Group2 * Group1 + SSO_NeedsSomething Group3 * Group2 + SSO_NeedsSprite Group4 * Group3 + SSO_NeedsSpriteModeData Group5 * SSO_NeedsSomething + SSO_NeedsSprite SwiSpriteOpCallTb SpriteOpEntry BadReasonCode, Group1 SpriteOpEntry BadReasonCode, Group1 SpriteOpEntry ScreenSave, Group1 SpriteOpEntry ScreenLoad, Group1 SpriteOpEntry BadReasonCode, Group1 ; 4 SpriteOpEntry BadReasonCode, Group1 ; 5 SpriteOpEntry BadReasonCode, Group1 ; 6 SpriteOpEntry BadReasonCode, Group1 ; 7 ; The following need valid workspace SpriteOpEntry ReadAreaCB, Group2 SpriteOpEntry ClearSprites, Group2 + SSO_DangerAreaOp ; *SNew SpriteOpEntry LoadSpriteFile, Group2 + SSO_DangerAreaOp ; *SLoad <filename> SpriteOpEntry MergeSpriteFile, Group2 + SSO_DangerAreaOp ; *SMerge <filename> SpriteOpEntry SaveSpriteFile, Group2 ; *SSave <filename> SpriteOpEntry ReturnName, Group2 SpriteOpEntry GetSprite, Group2 ; *SGet <name> SpriteOpEntry CreateSprite, Group2 SpriteOpEntry GetSpriteUserCoords, Group2 SpriteOpEntry BadReasonCode, Group2 ; 17 CheckSpriteArea SpriteOpEntry BadReasonCode, Group2 ; 18 SpriteOpEntry BadReasonCode, Group2 ; 19 SpriteOpEntry BadReasonCode, Group2 ; 20 SpriteOpEntry BadReasonCode, Group2 ; 21 SpriteOpEntry BadReasonCode, Group2 ; 22 SpriteOpEntry BadReasonCode, Group2 ; 23 ; The following need a sprite SpriteOpEntry SelectSprite, Group3 ; *SChoose <n> [<m>] SpriteOpEntry DeleteSprite, Group3 + SSO_DangerOp ; *SDelete <n> SpriteOpEntry RenameSprite, Group3 ; *SRename SpriteOpEntry CopySprite, Group3 ; *SCopy SpriteOpEntry PutSprite, Group3 SpriteOpEntry CreateMask, Group3 SpriteOpEntry RemoveMask, Group3 + SSO_DangerOp SpriteOpEntry InsertRow, Group3 + SSO_DangerOp SpriteOpEntry DeleteRow, Group3 + SSO_DangerOp SpriteOpEntry FlipAboutXAxis, Group3 SpriteOpEntry PutSpriteUserCoords, Group3 SpriteOpEntry BadReasonCode, Group3 ; 35 AppendSprite SpriteOpEntry BadReasonCode, Group3 ; 36 SetPointerShape SpriteOpEntry BadReasonCode, Group3 ; 37 CreateRemovePalette SpriteOpEntry BadReasonCode, Group3 ; 38 CreateRemoveAlpha SpriteOpEntry BadReasonCode, Group3 ; 39 ; The following need sprite mode data SpriteOpEntry ReadSpriteSize, Group4 SpriteOpEntry ReadPixelColour, Group4 SpriteOpEntry WritePixelColour, Group4 SpriteOpEntry ReadPixelMask, Group4 SpriteOpEntry WritePixelMask, Group4 SpriteOpEntry InsertCol, Group4 + SSO_DangerOp SpriteOpEntry DeleteCol, Group4 + SSO_DangerOp SpriteOpEntry FlipAboutYAxis, Group4 + SSO_DangerOp SpriteOpEntry PlotMask, Group4 SpriteOpEntry PlotMaskUserCoords, Group4 SpriteOpEntry BadReasonCode, Group4 ; 50 PlotMaskScaled SpriteOpEntry BadReasonCode, Group4 ; 51 PaintCharScaled SpriteOpEntry BadReasonCode, Group4 ; 52 PutSpriteScaled SpriteOpEntry BadReasonCode, Group4 ; 53 PutSpriteGreyScaled SpriteOpEntry RemoveLeftHandWastage, Group4 SpriteOpEntry BadReasonCode, Group4 ; 55 PlotMaskTransformed SpriteOpEntry BadReasonCode, Group4 ; 56 PutSpriteTransformed SpriteOpEntry BadReasonCode, Group4 ; 57 InsertDeleteRows SpriteOpEntry BadReasonCode, Group4 ; 58 InsertDeleteColumns SpriteOpEntry BadReasonCode, Group4 ; 59 pseudo reason used by Wimp ; The following need (sprite area + sprite) or (anything + 0), meaning screen SpriteOpEntry SwitchOutputToSprite, Group5 ; 60 SpriteOpEntry SwitchOutputToMask, Group5 ; 61 SpriteOpEntry ReadSaveAreaSize, Group5 ; 62 SwiSpriteOpCallTb_End ; ***************************************************************************** ; ; SetupSprModeData - Set up registers and variables from the sprite mode ; ; Internal routine: called by sprite dispatch, CreateHeader ; ; in: R2 -> sprite ; ; out: R0-R5 preserved ; R6 = ReadNColour (for a single screen pixel) ; R7 = WriteNColour (=R6 except in double pixel modes) ; R8 = BytesPerChar } ; R9 = XShftFactor } calculated from Log2BPC which is BitsPerPix ; R10 = NPix } corrected for double pixel modes ; R11 = Log2BPC } ; ; SprReadNColour..SprLog2BPC setup accordingly ; ; If error, then RetnReg0 updated SetupSprModeData ROUT Push R14 LDR R11, [R2, #spMode] CMP r11, #&100 ; check for mode selector/new format sprite word BCC %FT05 ; [it's a mode number so check for known ones] TST r11, #1 ; if it's a new format sprite word BNE %FT10 ; then call pushmodeinfo to get info on it B %FT20 ; else it's a mode selector, which is illegal as a sprite mode word 05 BranchIfKnownMode R11, %FA10 Push "R2-R4" MOV R2, R11 BL OfferModeExtensionAnyMonitor Pull "R2-R4" BNE %FT20 10 MOV R10, R11 BL PushModeInfoAnyMonitor BVS %FT30 ; if duff new format sprite word, return error LDR R11, [R13, #wkModeFlags] TST R11, #ModeFlag_NonGraphic BNE %FT15 ; non-graphic mode STR R11, [WsPtr, #SprModeFlags] LDR R11, [R13, #wkLog2BPC] ; Log2BPC LDR R14, [R13, #wkLog2BPP] ; Log2BPP ADD R13, R13, #PushedInfoSize MOV R7, #1 RSB R9, R11, #5 ; XShftFactor RSB R10, R7, R7, LSL R9 ; NPix MOV R6, R7, LSL R14 MOV R8, R7, LSL R11 ; BytesPerChar RSB R6, R7, R7, LSL R6 ; ReadNColour RSB R7, R7, R7, LSL R8 ; WriteNColour Push R5 ADD R5, WsPtr, #SprReadNColour STMIA R5, {R6-R11,R14} ; SprRead..SprLog2BPP CLRV Pull "R5, PC" 15 ADD R13, R13, #PushedInfoSize 20 ADRL R0, SpriteErr_InvalidSpriteMode [ International BL TranslateError ] 30 STR R0, [WsPtr, #RetnReg0] SETV Pull pc ; ***************************************************************************** ; Blocks for sprite errors SpriteErr_NoWorkSpace MakeErrorBlock Sprite_NoWorkSpace SpriteErr_NoRoom MakeErrorBlock Sprite_NoRoom SpriteErr_DoesntExist MakeErrorBlock Sprite_DoesntExist SpriteErr_NoSprites MakeErrorBlock Sprite_NoSprites SpriteErr_NotGraphics MakeErrorBlock Sprite_NotGraphics SpriteErr_NotEnoughRoom MakeErrorBlock Sprite_NotEnoughRoom SpriteErr_BadSpriteFile MakeErrorBlock Sprite_BadSpriteFile SpriteErr_NoRoomToMerge MakeErrorBlock Sprite_NoRoomToMerge SpriteErr_Bad2ndPtr MakeErrorBlock Sprite_Bad2ndPtr SpriteErr_InvalidRowOrCol MakeErrorBlock Sprite_InvalidRowOrCol SpriteErr_InvalidHeight MakeErrorBlock Sprite_InvalidHeight SpriteErr_InvalidWidth MakeErrorBlock Sprite_InvalidWidth SpriteErr_NoRoomToInsert MakeErrorBlock Sprite_NoRoomToInsert SpriteErr_SpriteAlreadyExists MakeErrorBlock Sprite_SpriteAlreadyExists SpriteErr_InvalidSpriteMode MakeErrorBlock Sprite_InvalidSpriteMode SpriteErr_BadReasonCode MakeErrorBlock Sprite_BadReasonCode SpriteErr_CantInTeletext MakeErrorBlock Sprite_CantInTeletext SpriteErr_InvalidSaveArea MakeErrorBlock Sprite_InvalidSaveArea SpriteErr_SpriteIsCurrentDest MakeErrorBlock Sprite_SpriteIsCurrentDest SpriteErr_NoMaskOrPaletteAllowedInThisDepth MakeErrorBlock Sprite_NoMaskOrPaletteAllowedInThisDepth ; ***************************************************************************** ; ; ClearSprites - Clear sprite area (*SNEW) ; ; External routine + dropped thru to ; ClearSprites ROUT LDR R2, [R1, #saFirst] STR R2, [R1, #saFree] MOV R2, #0 STR R2, [R1,#saNumber] LDR R0, [WsPtr, #RetnReg0] ; if rangeb or rangec CMP R0, #RangeB BHS DoesNowt ; exit immediately ; else its rangea, so drop thru to ... ClearSpritePtrName ROUT MOV R0, #0 STR R0, [WsPtr, #SpChoosePtr] STR R0, [WsPtr, #SpChooseName] STR R0, [WsPtr, #SpChooseName+4] STR R0, [WsPtr, #SpChooseName+8] MOV R0, #13 STRB R0, [WsPtr, #SpChooseName+12] ; *SChoose <null name> DoesNowt RETURNVC ; ***************************************************************************** ; ; ReadAreaCB - Read information from sprite area CB into registers ; ; External routine ; ; in: R1 -> sprite area ; ; out: R2 = offset to end of sprite area (ie total size) ; R3 = number of sprites in area ; R4 = offset to first sprite ; R5 = offset to first free word ; ReadAreaCB ROUT LDMIA R1, {R2,R3,R4,R5} ; saEnd,saNumber,saFirst,saFree ADD R11, WsPtr, #RetnReg2 STMIA R11, {R2,R3,R4,R5} RETURNVC ; ***************************************************************************** ; ; SelectSprite - Select a named sprite for use by PLOT &E8..&EF ; ; External routine + called by GetSprite ; ; in: R2 -> sprite CB ; ; out: R0, R9..R11 corrupted ; If not using system sprite area, then R2 -> address of sprite ; SelectSprite ROUT Push R14 LDR R0, [WsPtr, #RetnReg0] ; if not in system sprite area CMP R0, #RangeB STRCS R2, [WsPtr, #RetnReg2] ; return the sprite address Pull PC, CS STR R2, [WsPtr, #SpChoosePtr] ; else store name & address ADD R14, R2, #spName ; for use by PLOT LDMIA R14, {R9,R10,R11} ; load 12 bytes of name LDR R14, =SpChooseName ADD R14, R14, WsPtr ; RetnReg2 NOT altered, so user STMIA R14, {R9,R10,R11} ; can't poke the workspace Pull PC ; ***************************************************************************** ; ; ReturnName - Return name of nth sprite in sprite area as a string ; ; External routine ; ; in: R1 -> sprite area ; R2 -> buffer ; R3 = max buffer length ; R4 = sprite number (n) ; ; out: R3 actual string length ; RetnReg3 updated ; ReturnName ROUT LDR R5, [R1, #saNumber] ; check for 1 <= R4 <= saNumber CMP R4, #1 CMPGE R5, R4 BGE %FT05 ADRL R0, SpriteErr_DoesntExist ; out of range, so generate error [ International Push "lr" BL TranslateError_VClear Pull "lr" ] STR R0, [WsPtr, #RetnReg0] RETURNVS 05 LDR R5, [R1, #saFirst] ADD R5, R5, R1 ; ptr to 1st sprite 10 SUBS R4, R4, #1 LDRNE R6, [R5, #spNext] ; if not sprite we want ADDNE R5, R5, R6 ; chain to next one BNE %BT10 ADD R5, R5, #spName ; found sprite, R5 -> name SUBS R3, R3, #1 MOVLS R3, #0 ; if was 0 or 1 then set R3 to 0 STRLS R3, [WsPtr, #RetnReg3] STREQB R3, [R2] ; if was 1 then store 0 terminator MOVLS PC, R14 ; if was 0 or 1 then exit (assume SUB cleared V) CMP R3, #SpriteNameSize ; if length > maximum sprite name len MOVHI R3, #SpriteNameSize ; then limit to maximum sprite name len ; R3 is now maximum number of characters to store, excluding terminator MOV R6, R2 ; remember start address 20 LDRB R4, [R5], #1 ; load a byte from sprite name CMP R4, #" " ; if char > " " STRHIB R4, [R2], #1 ; then store character and inc ptr SUBHIS R3, R3, #1 ; and decrement character count BHI %BT20 ; loop until char<=" " or count expired MOV R4, #0 ; store terminating 0 STRB R4, [R2] SUB R3, R2, R6 ; R3 = no. of characters, STR R3, [WsPtr, #RetnReg3] ; excluding terminator RETURNVC ; indicate no error ; ***************************************************************************** ; ; RenameSprite - Rename a sprite ; ; External routine (AlreadyExists is used by CopySprite) ; ; in: R2 -> sprite ; R3 -> new name ; RenameSprite ROUT Push "R2, R14" MOV R2, R3 BL GetName ; returns name in R9-R11 BL SpriteCtrlBlk ; try to find sprite of that name BVC AlreadyExists Pull "R2, R14" ADD R8, R2, #spName STMIA R8, {R9-R11} KillSpChoosePtr ; in case it points to renamed sprite RETURNVC AlreadyExists ; sprite with new name already exists Pull "R3, R14" TEQ R2, R3 ; if it's the same one, then exit VC RETURNVC ; (SRename/SCopy fred fred is allowed) ADRL R0, SpriteErr_SpriteAlreadyExists [ International Push "lr" BL TranslateError Pull "lr" ] STR R0, [WsPtr,#RetnReg0] RETURNVS ; ***************************************************************************** ; ; CopySprite - Make a copy of a sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 -> new name ; CopySprite ROUT Push "R2, R14" ; save ptr to sprite to be copied MOV R2, R3 BL GetName ; returns new name in R9-R11 BL SpriteCtrlBlk ; try to find sprite of that name BVC AlreadyExists ; [we found one of that name] Pull R2 LDR R8, [R1, #saFree] ADD R8, R8, R1 ; address sprite will be copied to ADD R8, R8, #spName ; address of its name field BL AppendSprite ; copy it STMVCIA R8, {R9-R11} ; if copy OK, rename it Pull PC ; exit with V clear/set appropriately ; ***************************************************************************** ; ; ReadSpriteSize - Read sprite size and other info ; ; External routine ; ; in: R2 -> sprite ; ; out: R1,R2 preserved ; R3 = width in pixels ; R4 = height in pixels ; R5 = 0/1 for solid/transparent ; R6 = mode sprite was defined in ; ; RetnReg3..RetnReg6 updated ; ReadSpriteSize ROUT ADD R3, R2, #spWidth LDMIA R3, {R3,R4,R5,R6} ; spWidth,spHeight,spLBit,spRBit ADD R4, R4, #1 ; R4 := height in pixels ADD R3, R3, #1 ; R3 := width in words RSB R3, R5, R3, LSL #5 ; convert to bits and sub LH wastage SUB R3, R3, #31 ; subtract RH wastage ADD R3, R3, R6 LDR R11, [WsPtr, #SprLog2BPC] MOV R3, R3, LSR R11 ; number of pixels in row LDR R5, [R2, #spImage] LDR R6, [R2, #spTrans] SUBS R5, R5, R6 MOVNE R5, #1 ; if spImage=spTrans then no mask LDR R6, [R2, #spMode] ADD R11, WsPtr, #RetnReg3 STMIA R11, {R3-R6} RETURNVC ; ***************************************************************************** ; ; ReadSpriteWidth - Read width of a sprite ; ; Internal routine, called by PlotMask, InsertCol, DeleteCol ; ; in: R2 -> sprite ; ; out: R0 = sprite width in pixels ; All other registers preserved ; ReadSpriteWidth ROUT Push "R4-R6, R14" ADD R0, R2, #spWidth LDMIA R0, {R0,R4,R5,R6} ; spWidth,spHeight,spLBit,spRBit ADD R0, R0, #1 ; width in words RSB R0, R5, R0, LSL #5 SUB R0, R0, #31 ADD R0, R0, R6 ; total number of bits in row LDR R5, [WsPtr, #SprLog2BPC] MOV R0, R0, LSR R5 ; number of pixels in row Pull "R4-R6, PC" ; ***************************************************************************** ; ; DeleteSpriteByName ; ; Internal routine, called by MergeSprite, GetSprite, CreateSprite ; ; in: R1 -> sprite area ; R2 -> name of sprite to be deleted ; ; out: All registers preserved ; DeleteSpriteByName ROUT Push "R2-R4, R14" BL SpriteCtrlBlk ; R2: In , SpriteNamePtr ; Out, SpriteCBptr BLVC DeleteSprite ; if found, then delete it Pull "R2-R4, PC" ; ***************************************************************************** ; ; DeleteSprite ; ; External routine + called by DeleteSpriteByName ; ; in: R1 -> sprite area ; R2 -> sprite ; ; out: All registers preserved ; DeleteSprite ROUT Push "R0, R3,R4, R14" LDR R3, [R2, #spNext] ADD R3, R3, R2 LDR R0, [R1, #saFree] ADD R0, R0, R1 SUB R0, R0, R3 CopyDown R2, R3, R0, R14, R4 LDR R3, [R1, #saNumber] ; decrement sprite count SUB R3, R3, #1 STR R3, [R1, #saNumber] SUB R3, R2, R1 ; (R2 points to first free location) STR R3, [R1, #saFree] ; update saFree KillSpChoosePtr ;Because the sprites have moved Pull "R0, R3,R4, PC" ; ***************************************************************************** ; ; GetName - Read sprite name into buffer, lower cased, padded to 12 chars ; ; Internal routine, called by RenameSprite, CopySprite, ; SpriteCtrlBlk, CreateHeader ; ; in: R2 -> sprite name (terminated by char <= 32) ; ; out: Name returned in R9-R11 and NameBuf ; All other registers preserved ; GetName ROUT Push "R2-R5, R14" ADD R3, WsPtr, #NameBuf MOV R4, #SpriteNameSize 10 LDRB R5, [R2], #1 uk_LowerCase R5, R14 CMP R5, #" " STRHIB R5, [R3], #1 SUBHIS R4, R4, #1 ; loop until char<=32 or done 12 chars BHI %BT10 MOV R5, #0 CMP R4, #0 ; pad with 0 or more nulls 20 STRHIB R5, [R3], #1 SUBHIS R4, R4, #1 BHI %BT20 ADD R9, WsPtr, #NameBuf LDMIA R9, {R9-R11} ; name returned in R9-R11 and NameBuf Pull "R2-R5, PC" ; ***************************************************************************** ; ; SpriteCtrlBlk - Search for control block of named sprite ; ; Internal routine, called by sprite dispatch, RenameSprite, ; CopySprite, DeleteSpriteByName ; ; in: R1 -> sprite area ; R2 -> sprite name ; ; out: V=0 => R2 -> sprite ; V=1 => sprite not found ; R2 -> first free byte (this fact not used by anyone yet) ; All other registers preserved ; SpriteCtrlBlk ROUT Entry "R3-R11" ASSERT saNumber = 4 ASSERT saFirst = 8 LDMIB R1, {R4,R5} ; saNumber, saFirst ADD R3, R5, R1 ; point to first sprite/free space CMP R4, #0 BEQ %FT20 ; no sprites, exit with R3 pointing ; at free space and R4=0 BL GetName ; search name in R9-R11 and NameBuf 10 LDMIA R3, {R5, R6,R7,R8} ; spNext, spName(0..2) CMP R6, R9 CMPEQ R7, R10 CMPEQ R8, R11 ; (V:=0 if equal) BEQ %FT30 ; sprite found ADD R3, R3, R5 SUBS R4, R4, #1 ; try next sprite BNE %BT10 20 SETV ; indicate not found 30 MOV R2, R3 ; R2 -> sprite or to free space EXIT ; As above, but uses source name directly without passing it through GetName ; Name must be word aligned and in correct format! SpriteCtrlBlkNoGetName ALTENTRY ASSERT saNumber = 4 ASSERT saFirst = 8 LDMIB R1, {R4,R5} ; saNumber, saFirst ADD R3, R5, R1 ; point to first sprite/free space CMP R4, #0 BEQ %BT20 ; no sprites, exit with R3 pointing LDMIA R2, {R9-R11} B %BT10 LTORG ; ***************************************************************************** ; ; InternaliseCoords - Convert from external to internal coords ; for sprite plotting ; ; Internal routine called by PutSpriteUserCoords, PlotMaskUserCoords ; ; in: R3 = external X coordinate ; R4 = external Y coordinate ; ; out: R3 = internal X coordinate ; R4 = internal Y coordinate ; R1, R2, R5 preserved ; InternaliseCoords ROUT Push "R1,R2,R5, R14" MOV R0, R3 ; put external coordinate in R0,R1 MOV R1, R4 ADD R7, WsPtr, #GCsX LDMIA R7, {R8,R9} ; preserve GCsX,GCsY around EIG MOV R2, #4 ; indicate absolute coords BL EIG STMIA R7, {R8,R9} ; restore GcsX,GCsY MOV R3, R0 ; internal coord of plotting point MOV R4, R1 Pull "R1,R2,R5, PC" ; ***************************************************************************** ; ; PutSpriteUserCoords - Draw sprite to screen using given ext. coords ; ; External routine ; ; in: R1 -> sprite area (not used) ; R2 -> sprite ; R3 = X coordinate to plot at ; R4 = Y coordinate to plot at ; R5 = GCOL action to be used ; PutSpriteUserCoords ROUT Push R14 BL InternaliseCoords Pull R14 B PutSpri20 ; ***************************************************************************** ; ; PutSprite - Draw sprite to screen at NewPt ; ; External routine + PutSpri20 called by PutSpriteUserCoords ; (also external) ; ; in: R1 -> sprite area (not used) ; R2 -> sprite ; R5 = GCOL action to be used ; ; Values held in Ram ; ; N.B. The ordering of these variables is VERY important ; rearrange at your peril ; ; Within the 'memory to screen' drawing loop, WsPtr (R12) points at ; ScrAdr, variables either side being loaded/saved in groups using ; LDMDB / STMIA / LDMIB ; ; SPltWidth } ; SPltHeight } ; SPltScrOff } ; SPltMemOff } LDMDB ; WsPtr -> SPltScrAdr } STMIA ; SPltColCnt } } LDMIB ; SPltMemAdr } ; SPltShftR } ; SPltShftL } ; ; SPltMskAdr ; ; SPltLMask ; SPltRMask ; ; SPltzgooPtr ; ; PutSprite ROUT ASSERT NewPtY = NewPtX +4 ADD R3, WsPtr, #NewPtX LDMIA R3, {R3, R4} ; plot sprite at NewPt(X,Y) PutSpri20 GraphicsMode R0 BNE PutSpriNotGraphics ; quit with error if not graphics mode Push "WsPtr, R14" ; push both so R12,R14 are free for use Push "R2" ; save the pointer to the sprite BL GenSpritePlotParmBlk Pull "R11" BVS SpriteOffScreen SWI XOS_RemoveCursors ; assume no error can occur! LDR R5, [WsPtr, #SPltMemAdr] LDR R6, [WsPtr, #SPltMskAdr] TEQ R6, #0 BEQ %FT20 ADD R6, R6, R5 STR R6, [WsPtr, #SPltMskAdr] LDR R14, [R11, #spMode] MOVS R8,R14,ASR #27 ; check for wide mask BMI PutSpriWideMaskErr TEQ R8,#SpriteType_RISCOS5 [ NoARMT2 ANDEQ R8, R14, #127<<20 MOVEQ R8, R8, LSR #20 | UBFXEQ R8, R14, #20, #7 ] ;note: new format 1bpp sprites are thrown at the old routine, since it ;will render them faster CMP R8, #2 BCC TransPlot ; it's got transparent bits in it! ( BCS NewTransPlot ; it's got 1bpp transparent bits in it!!! 20 ; Plot sprite ignoring transparency mask (if any) ADD R11, WsPtr, #SPltzgooMasks LDMIA R11, {R8-R11} ; masks for screen access (zgoo..zgee) LDR R2, [WsPtr, #SPltAction] ; GCOL action ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr at SPltScrAdr LDMIA WsPtr, {R0-R1,R5-R7} TST R2, #7 BNE SolPl10 ; not store, do it slowly ; SimpleCase SolPlFast10 ; R0 ,R1 , R5 ,R6 ,R7 ,(R8 ,R9 ,R10 ,R11 ) ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,(zgoo,zgeo,zgoe,zgee) ; Plot the first (leftmost) word 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 R4, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word AND R3, R2, R4 ; mask down to just the required pixels [ AvoidScreenReads CMP R4, #&FFFFFFFF LDRNE R2, [R0] ; plot 1 word BICNE R2, R2, R4 ; knock out mask bits ORRNE R3, R2, R3 ; and or sprite bits | LDR R2, [R0] ; plot 1 word BIC R2, R2, R4 ; knock out mask bits ORR R3, R2, R3 ; and or sprite bits ] STR R3, [R0], #4 SUBS R1, R1, #1 BLT SolPlFast50 ; if all plotted, try next scanline ; else try for blocks of 7 SUBS R1, R1, #7 BLT SolPlFast30 TEQ R6, #0 ; if shift needed, use loop 20 BNE SolPlFast20 ; else loop 15 SolPlFast15 ; R0 ,R1 ,R5 ; ScrAdr,ColCnt, ,MemAdr LDMIA R5!, {R2-R4,R8-R11} ; read 7 words STMIA R0!, {R2-R4,R8-R11} ; write 7 words back to screen SUBS R1, R1, #7 BGE SolPlFast15 B SolPlFast30 SolPlFast20 ; R0 ,R1 ,R5 ,R6 ,R7 ; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL LDMIA R5, {R2-R4,R8-R11,R14} ; 8 words needed, gives 7 after shift ADD R5, R5, #7*4 ; advance source ptr 7 words ShiftR R2,R3, R6,R7 ; shift right R6 bits ShiftR R3,R4, R6,R7 ; we only want result words ShiftR R4,R8, R6,R7 ; R2-R4, R8-R11 ShiftR R8,R9, R6,R7 ShiftR R9,R10, R6,R7 ShiftR R10,R11, R6,R7 ShiftR R11,R14, R6,R7 STMIA R0!, {R2-R4,R8-R11} ; write 7 words back to screen SUBS R1, R1, #7 BGE SolPlFast20 SolPlFast30 ; try 1 word at a time ADDS R1, R1, #7 ; R0 ,R1 , R5 ,R6 ,R7 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL ; If EQ this is rightmost word SolPlFast40 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 BEQ SolPlFast45 ; if rightmost word, jump out. STR R2, [R0], #4 SUBS R1, R1, #1 B SolPlFast40 SolPlFast45 LDR R4, [WsPtr, #SPltRMask-SPltScrAdr] AND R3, R2, R4 ; mask down to just the required pixels [ AvoidScreenReads CMP R4, #&FFFFFFFF LDRNE R2, [R0] ; plot 1 word BICNE R2, R2, R4 ; knock out mask bits ORRNE R3, R2, R3 ; and or sprite bits | LDR R2, [R0] ; plot 1 word BIC R2, R2, R4 ; knock out mask bits ORR R3, R2, R3 ; and or sprite bits ] STR R3, [R0], #4 SolPlFast50 ; now try the next scanline LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 ; Width,Height,ScrOff,MemOff ADD R0, R0, R3 ADD R5, R5, R4 SUBS R2, R2, #1 STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] BGE SolPlFast10 ; plot next scanline ComplicatedExit SWI XOS_RestoreCursors SpriteOffScreen Pull "WsPtr, R14" RETURNVC PutSpriWideMaskErr ; Not supported! SWI XOS_RestoreCursors Pull "WsPtr, R14" PutSpriWideMaskErr2 ADRL R0, SpriteErr_InvalidSpriteMode B %FT90 PutSpriNotGraphics ADRL R0, SpriteErr_NotGraphics 90 [ International Push "lr" BL TranslateError Pull "lr" ] STR R0, [WsPtr, #RetnReg0] RETURNVS ; Complicated case SolPl10 ROUT ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee ; Plot the first (leftmost) word 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 OrrEor R3,R2, R10,R11 ; form EOR mask OrrEor R2,R2, R8,R9 ; form OR mask LDR R4, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word AND R2, R2, R4 ; mask down to just the required pixels AND R3, R3, R4 LDR R4, [R0] ; plot 1 word OrrEor R4,R4, R2,R3 STR R4, [R0], #4 SUBS R1, R1, #1 BLT SolPl50 ; if all plotted, try next scanline ; else try for blocks of 4 SUBS R1, R1, #4 BLT SolPl30 SolPl20 STMIA WsPtr, {R0,R1} ; save ScrAdr,ColCnt ; R0 ,R1 ,R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 ; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee LDMIA R5, {R0-R4} ; 5 words needed, gives 4 after shift ADD R5, R5, #16 ; advance source ptr 4 words STR R5, [WsPtr, #SPltMemAdr-SPltScrAdr] ShiftR R0,R1, R6,R7 ; shift R4-R0 right R6 bits ShiftR R1,R2, R6,R7 ; we only want result words R3-R0 ShiftR R2,R3, R6,R7 ShiftR R3,R4, R6,R7 LDR R4, [WsPtr] ; get screen address LDMIA R4, {R4-R7} ; get 4 screen words ORoreorEORoreor R4,R0, R8,R9,R10,R11, R14 ORoreorEORoreor R5,R1, R8,R9,R10,R11, R14 ORoreorEORoreor R6,R2, R8,R9,R10,R11, R14 ORoreorEORoreor R7,R3, R8,R9,R10,R11, R14 LDR R0, [WsPtr] ; screen address STMIA R0!, {R4-R7} ; write 4 words back to screen LDMIB WsPtr, {R1,R5-R7} ; reload anything we shat on SUBS R1, R1, #4 BGE SolPl20 SolPl30 ; try 1 word at a time ADDS R1, R1, #4 ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee ; If EQ this is rightmost word SolPl40 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 OrrEor R3,R2, R10,R11 ; form EOR mask OrrEor R2,R2, R8,R9 ; form OR LDREQ R4, [WsPtr, #SPltRMask-SPltScrAdr] ; if rightmost word, ANDEQ R2, R2, R4 ; mask down to just the ANDEQ R3, R3, R4 ; required pixels LDR R4, [R0] OrrEor R4,R4, R2,R3 STR R4, [R0], #4 SUBS R1, R1, #1 BGE SolPl40 SolPl50 ; now try the next scanline LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 ; Width,Height,ScrOff,MemOff ADD R0, R0, R3 ADD R5, R5, R4 SUBS R2, R2, #1 STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] BGE SolPl10 ; plot next scanline B ComplicatedExit ; ***************************************************************************** ; ; NewTransPlot - Plot sprite using 1 bpp transparency mask ; Called with R11 -> sprite, R8 = sprite type ; TransPlot is used for 1bpp new sprites since it will be faster NewTransPlot ROUT ; need to derive: bpp, and 1<<(5-log2bpp) ADRL R0, NSM_bpptable-4 LDR R10, [R0, R8, LSL #2] ; get the log2bpp to R10 ;R10=log2bpp, R11=>sprite LDR R8, [R11, #spWidth] ; words-1 ADD R9, R8, #1 MOV R9, R9, LSL #2 ; number of bytes per row STR R9, [WsPtr, #SPltMaskRowPtr] LDR R9, [R11, #spRBit] ; last bit used ADD R9, R9, #1 ; change to number of bits MOV R9, R9, LSR R10 ; number of pixels RSB R0, R10, #5 MOV R8, R8, LSL R0 ; number of pixels for full words ADD R8, R8, R9 ; total number of pixels ANDS R9, R8, #&1F MOVNE R9, #4 BIC R8, R8, #&1F ADD R9, R9, R8, LSR #3 ; number of bytes per mask row STR R9, [WsPtr, #SPltMaskRowLen] LDR R8, [R11, #spImage] LDR R9, [R11, #spTrans] ADD R8, R8, R11 ADD R9, R9, R11 ;RSB R0, R10, #5 <- DONE ABOVE MOV R1, #1 MOV R2, R1, LSL R0 ; r2 holds number of pixels per word MOV R3, R1, LSL R10 ; r3 holds bits per pixel ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr, at SPltScrAdr LDMIA WsPtr, {R0-R1,R5-R7,R14} STR R2, [WsPtr, #SPltPixPerWord-SPltScrAdr] STR R3, [WsPtr, #SPltBPP-SPltScrAdr] ; sort out where to begin in 1bpp mask (rewritten Aug '93) MOV LR, R9 ; LR = mask pointer MOV R3, #0 ; R3 = mask bit CMP R5, R8 ; R5=>data to plot, R8=>start of sprite BEQ %FT11 ; nothing to do, go store R3 & LR BCC %FT13 ; start is before sprite data ;R3, R9, r10, R11 free ;R2 comes in holding pix per word ;if R6 is non zero the image will be a word early. MOV R9, R5 ; working copy of pointer within sprite CMP R6, #0 ADDNE R9, R9, #4 ; take out the extra word for now LDR R11,[WsPtr, #SPltMaskRowLen-SPltScrAdr] ; bytes per mask row SUBS R10, R9, R8 ; difference in bytes LDR R8,[WsPtr, #SPltMaskRowPtr-SPltScrAdr] ; loaded with bytes per image row BEQ %FT13 14 ;is it less than a row of data CMP R10, R8 BCC %FT12 ; yes it is ;deal with a row (or more of data) SUB R10, R10, R8 ADD LR, LR, R11 B %BT14 12 ;start point is on this row. subtract 4 from difference and add ;pix per word to mask bit/ptr until diff=0 CMP R10, #0 BEQ %FT13 SUB R10, R10, #4 ADD R3, R3, R2 CMP R3, #32 SUBCS R3, R3, #32 ADDCS LR, LR, #4 CMP R10, #0 BNE %BT12 13 ;deal with R6 CMP R6,#0 BEQ %FT11 SUBS R3, R3, R2 ;subtract pix per word ADDMI R3, R3, #32 SUBMI LR, LR, #4 ;deal with going into previous word 11 STR R3, [WsPtr, #SPltMaskBit-SPltScrAdr] STR LR, [WsPtr, #SPltMaskPtr-SPltScrAdr] ; and save it for the end of row increments STR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] STR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] ADD R11, WsPtr, #SPltzgooMasks-SPltScrAdr LDMIA R11, {R8-R11} ; masks for screen access (zgoo..zgee) NTrnPl10 ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11, R14 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee, ; ; As far as possible this is based on the original transplot. ; ; Plot the first (leftmost) word BL getmaskword MOV R2, R3 BL getmaskword_noinc ShiftR R2,R3, R6,R7 ; we only need result word R2 LDMIA R5, {R3,R4} ; fetch and shift image ADD R5, R5, #4 ShiftR R3,R4, R6,R7 ; shift R4,R3 right R6 places OrrEor R4,R3, R10,R11 ; form EOR mask OrrEor R3,R3, R8,R9 ; form OR mask AND R3, R3, R2 ; clear out any transparent pixels AND R4, R4, R2 LDR R2, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word AND R3, R3, R2 ; mask down to just the required pixels AND R4, R4, R2 LDR R2, [R0] ; plot 1 word OrrEor R2,R2, R3,R4 STR R2, [R0], #4 SUBS R1, R1, #1 BLT NTrnPl50 ; if all plotted, try next scanline ; else try for blocks of 2 SUBS R1, R1, #2 BLT NTrnPl30 NTrnPl20 STMIA WsPtr, {R0,R1} ; ScrAdr,ColCnt ; R0 ,R1 ,R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 , R14 ; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee, MskAdr BL getmaskword MOV R0, R3 BL getmaskword MOV R1, R3 BL getmaskword_noinc MOV R2, R3 ShiftR R0,R1, R6,R7 ShiftR R1,R2, R6,R7 ; aligned mask in R0,R1 LDMIA R5, {R2-R4} ; 3 image words needed, gives 2 after ADD R5, R5, #8 ; shifting STR R5, [WsPtr, #SPltMemAdr-SPltScrAdr] ShiftR R2,R3, R6,R7 ShiftR R3,R4, R6,R7 ; aligned image in R2,R3 LDR R4, [WsPtr] ; screen address LDMIA R4, {R4,R5} ; 2 screen words ORoreorEORoreorMASK R4,R2,R0, R8,R9,R10,R11, R14 ORoreorEORoreorMASK R5,R3,R1, R8,R9,R10,R11, R14 LDR R0, [WsPtr] ; screen address STMIA R0!, {R4,R5} ; write 2 words back to screen LDMIB WsPtr, {R1,R5,R6} ; reload anything we shat on SUBS R1, R1, #2 BGE NTrnPl20 NTrnPl30 ; try 1 word at a time ADDS R1, R1, #2 ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee ; If EQ this is rightmost word NTrnPl40 BL getmaskword MOV R2, R3 BL getmaskword_noinc ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places, result in R2 LDMIA R5, {R3,R4} ; fetch and align image ADD R5, R5, #4 ShiftR R3,R4, R6,R7 ; shift R4,R3 right R6 places, result in R3 OrrEor R4,R3, R10,R11 ; form EOR mask OrrEor R3,R3, R8,R9 ; form OR AND R3, R3, R2 ; clear out transparant pixels AND R4, R4, R2 LDREQ R2, [WsPtr, #SPltRMask-SPltScrAdr] ; if rightmost word, ANDEQ R3, R3, R2 ; mask down to just the ANDEQ R4, R4, R2 ; required pixels LDR R2, [R0] OrrEor R2,R2, R3,R4 STR R2, [R0], #4 SUBS R1, R1, #1 BGE NTrnPl40 NTrnPl50 ; now try the next scanline ; BEWARE ... genspriteplotparmblock returns values for memoff and ; scroff which take account of alignment of screen and sprite data ; ; Do not alter the logic below unless you really know what ; to expect from this routine!! LDR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] LDR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] LDR R2, [WsPtr, #SPltMaskRowLen-SPltScrAdr] ADD LR, LR, R2 STR LR, [WsPtr, #SPltMaskPtr-SPltScrAdr] STR R3, [WsPtr, #SPltMaskBit-SPltScrAdr] STR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] STR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 ; Width,Height,ScrOff,MemOff ADD R0, R0, R3 ADD R5, R5, R4 SUBS R2, R2, #1 STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] BGE NTrnPl10 ; plot next scanline SWI XOS_RestoreCursors Pull "WsPtr, R14" RETURNVC ; get a mask word without incrementing the pointers getmaskword_noinc ROUT Push "R4, R5, LR" LDR R4, [WsPtr, #SPltMaskBit-SPltScrAdr] LDR R5, [WsPtr, #SPltMaskPtr-SPltScrAdr] BL getmaskword ; preserves flags STR R4, [WsPtr, #SPltMaskBit-SPltScrAdr] STR R5, [WsPtr, #SPltMaskPtr-SPltScrAdr] LDMFD R13!,{R4,R5,R15} ; must preserve flags ; get a mask word, and increment pointers getmaskword ROUT Push "R2,R4,R5,R6,R7,R8,R14" MRS R8, CPSR ;R6 -> mask ;R7 = bit offset ;return in R3, update R6, R7, restore other registers MOV R3, #0 ; initial result LDR LR, [WsPtr, #SPltPixPerWord-SPltScrAdr] ; pixels per word LDR R2, [WsPtr, #SPltBPP-SPltScrAdr] ; bpp LDR R7, [WsPtr, #SPltMaskBit-SPltScrAdr] LDR R6, [WsPtr, #SPltMaskPtr-SPltScrAdr] LDR R4, [R6] ; get the mask word 10 CMP R7, #0 LDREQ R4, [R6] ; fetch a new word if required MOV R5, R4, LSR R7 ; shift desired bit down to bit 0 MOV R3, R3, LSR #1 ; shift down the result by one bit ORR R3, R3, R5, LSL #31 ; and put bit 0 in at bit 31 ; now use an ASR of bpp-1 to finish off SUB R5, R2, #1 MOV R3, R3, ASR R5 ADD R7, R7, #1 ; next mask bit CMP R7, #32 ; on to next word ? ADDEQ R6, R6, #4 ; increment mask word pointer MOVEQ R7, #0 ; bit pointer back to 0 ; but don't fetch new word until it is needed! SUBS LR, LR, #1 ; one pixel done BNE %BT10 STR R7, [WsPtr, #SPltMaskBit-SPltScrAdr] STR R6, [WsPtr, #SPltMaskPtr-SPltScrAdr] ;result in R3, MaskBit/MaskPtr adjusted MSR CPSR_f, R8 LDMFD R13!,{R2,R4,R5,R6,R7,R8,R15} ; must save flags LTORG ; ***************************************************************************** ; ; TransPlot - Plot sprite using transparency mask ; TransPlot ADD R11, WsPtr, #SPltzgooMasks LDMIA R11, {R8-R11} ; masks for screen access (zgoo..zgee) ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr, at SPltScrAdr LDMIA WsPtr, {R0-R1,R5-R7,R14} TrnPl10 ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11, R14 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee, MskAdr ; Plot the first (leftmost) word LDMIA R14, {R2,R3} ; fetch and shift mask right R6 places ADD R14, R14, #4 ShiftR R2,R3, R6,R7 ; we only need result word R2 LDMIA R5, {R3,R4} ; fetch and shift image ADD R5, R5, #4 ShiftR R3,R4, R6,R7 ; shift R4,R3 right R6 places ; we only need result word R3 OrrEor R4,R3, R10,R11 ; form EOR mask OrrEor R3,R3, R8,R9 ; form OR mask AND R3, R3, R2 ; clear out any transparent pixels AND R4, R4, R2 LDR R2, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word AND R3, R3, R2 ; mask down to just the required pixels AND R4, R4, R2 LDR R2, [R0] ; plot 1 word OrrEor R2,R2, R3,R4 STR R2, [R0], #4 SUBS R1, R1, #1 BLT TrnPl50 ; if all plotted, try next scanline ; else try for blocks of 2 SUBS R1, R1, #2 BLT TrnPl30 TrnPl20 STMIA WsPtr, {R0,R1} ; ScrAdr,ColCnt ; R0 ,R1 ,R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 , R14 ; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee, MskAdr LDMIA R14, {R0-R2} ; 3 mask words, gives 2 after shifting ADD R14, R14, #8 ; advance mask ptr 2 words ShiftR R0,R1, R6,R7 ShiftR R1,R2, R6,R7 ; aligned mask in R0,R1 LDMIA R5, {R2-R4} ; 3 image words needed, gives 2 after ADD R5, R5, #8 ; shifting STR R5, [WsPtr, #SPltMemAdr-SPltScrAdr] ShiftR R2,R3, R6,R7 ShiftR R3,R4, R6,R7 ; aligned image in R2,R3 LDR R4, [WsPtr] ; screen address LDMIA R4, {R4,R5} ; 2 screen words ORoreorEORoreorMASK R4,R2,R0, R8,R9,R10,R11, R6 ORoreorEORoreorMASK R5,R3,R1, R8,R9,R10,R11, R6 LDR R0, [WsPtr] ; screen address STMIA R0!, {R4,R5} ; write 2 words back to screen LDMIB WsPtr, {R1,R5-R6} ; reload anything we shat on SUBS R1, R1, #2 BGE TrnPl20 TrnPl30 ; try 1 word at a time ADDS R1, R1, #2 ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ,R10 ,R11 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,zgoo,zgeo,zgoe,zgee ; If EQ this is rightmost word TrnPl40 LDMIA R14, {R2,R3} ; fetch and align trans mask ADD R14, R14, #4 ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places, result in R2 LDMIA R5, {R3,R4} ; fetch and align image ADD R5, R5, #4 ShiftR R3,R4, R6,R7 ; shift R4,R3 right R6 places, result in R3 OrrEor R4,R3, R10,R11 ; form EOR mask OrrEor R3,R3, R8,R9 ; form OR AND R3, R3, R2 ; clear out transparant pixels AND R4, R4, R2 LDREQ R2, [WsPtr, #SPltRMask-SPltScrAdr] ; if rightmost word, ANDEQ R3, R3, R2 ; mask down to just the ANDEQ R4, R4, R2 ; required pixels LDR R2, [R0] OrrEor R2,R2, R3,R4 STR R2, [R0], #4 SUBS R1, R1, #1 BGE TrnPl40 TrnPl50 ; now try the next scanline LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 ; Width,Height,ScrOff,MemOff ADD R0, R0, R3 ADD R5, R5, R4 ADD R14, R14, R4 SUBS R2, R2, #1 STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] BGE TrnPl10 ; plot next scanline SWI XOS_RestoreCursors Pull "WsPtr, R14" RETURNVC LTORG ; ***************************************************************************** ; ; PlotMaskUserCoords - Draw a rectangle through a sprite mask ; using given external coordinates ; ; External routine ; ; in: R1 -> sprite area (not used) ; R2 -> sprite ; R3 = X coordinate to plot at ; R4 = Y coordinate to plot at ; PlotMaskUserCoords ROUT Push R14 BL InternaliseCoords Pull R14 B PlotMa20 ; ***************************************************************************** ; ; PlotNewMask ; ; Version of PlotMask for new 1bpp format sprites ; ; R0 = sprite mode word ; R2 -> sprite ; R10 = bits 27-31 of mode word PlotNewMask ROUT TEQ R10, #SpriteType_RISCOS5 [ NoARMT2 ANDEQ R10, R0, #127<<20 MOVEQ R10, R10, LSR #20 | UBFXEQ R10, R0, #20, #7 ] ADRL R0, NSM_bpptable-4 LDR R10, [R0, R10, LSL #2] ;get the log2bpp ;derive mask row length ;r10=log2bpp, r2=>sprite LDR R8, [R2, #spWidth] ; words-1 ADD R9, R8, #1 ; total words for a line of image MOV R9, R9, LSL #2 ; total bytes for a line of image STR R9, [WsPtr, #SPltMaskRowPtr] ; save it for determining mask start position LDR R9, [R2, #spRBit] ; last bit used ADD R9, R9, #1 ; change to number of bits MOV R9, R9, LSR R10 ; number of pixels RSB R0, R10, #5 MOV R8, R8, LSL R0 ; number of pixels for full words ADD R8, R8, R9 ; total number of pixels ANDS R9, R8, #&1F MOVNE R9, #4 BIC R8, R8, #&1F ADD R9, R9, R8, LSR #3 ; number of bytes per mask row STR R9, [WsPtr, #SPltMaskRowLen] MOV R1, #1 MOV R0, R1, LSL R0 ;number of pixels MOV R6, R1, LSL R10 ;bits per pixel STR R0, [WsPtr, #SPltPixPerWord] STR R6, [WsPtr, #SPltBPP] LDR R0, [R2, #spHeight] ADD R0, R0, R4 LDR R10, [WsPtr, #GWTRow] Least R0, R0, R10 ; top scanline within window LDR R10, [WsPtr, #YWindLimit] SUB R0, R10, R0 ; flip Y AND R0, R0, #7 STR R0, [WsPtr, #SPltEcfIndx] ; index into Ecf ADD R0, WsPtr, R0, LSL #3 ADD R0, R0, #BgEcfOraEor STR R0, [WsPtr, #SPltEcfPtr] ; ptr to ECF for highest row plotted ;STR R2, [WsPtr, #SPltMaskRowPtr] ;temp, to save it LDR R8, [R2, #spImage] LDR R9, [R2, #spTrans] ADD R8, R8, R2 ADD R9, R9, R2 Push "WsPtr, R14" ; push both so R12,R14 are free for use Push "R2" BL GenSpritePlotParmBlk Pull "R2" BVS SpriteOffScreen SWI XOS_RemoveCursors ; assume no error can occur! ;LDR R2, [WsPtr, #SPltMaskRowPtr] ;recover pointer to sprite LDR R8, [R2, #spImage] ;offset to image LDR R9, [R2, #spTrans] ;offset to mask ADD R8, R8, R2 ;change to address of image ADD R9, R9, R2 ;change to address of mask LDR R5, [WsPtr, #SPltMemAdr] ;start memory address to plot LDR LR, [WsPtr, #SPltMskAdr] ;start mask address to plot TEQ LR, #0 ;off screen ? BEQ SpriteOffScreen ;so plot nothing ;amg 19/1/94 rip out the original algorithm and replace it with the correct one ;used with newtransplot which correctly handles genspriteplotparmblk's oddities ;now deal with sprites where we aren't starting ;at the beginning.... LDR R2, [WsPtr, #SPltPixPerWord] ;pick up pixels per word MOV LR, R9 ;save mask address MOV R3, #0 ;set mask pixel counter to 0 CMP R5, R8 ;memory address to plot from = image address ? BEQ %FT11 ;yes - no fudging needed BCC %FT13 MOV R9, R5 ;working copy of plot start within sprite CMP R6, #0 ADDNE R9, R9, #4 ;take out the extra word for now LDR R11, [WsPtr, #SPltMaskRowLen] ;bytes per mask row SUBS R10, R9, R8 ;difference between plot start & sprite start LDR R8, [WsPtr, #SPltMaskRowPtr] ;bytes per image row BEQ %FT13 ;no difference 14 ;is it less than a row of data different ? CMP R10, R8 BCC %FT12 ;yes, it is ;deal with whole rows SUB R10, R10, R8 ;decrease difference by size of image row ADD LR, LR, R11 ;increase mask pointer by size of mask row B %BT14 ;and loop until less than a row to do 12 ;start pointer is on this row. reduce the difference and increase the mask start ;point until they match CMP R10, #0 ;check for nothing to do BEQ %FT13 SUB R10, R10, #4 ;reduce image by a word ADD R3, R3, R2 ;increase mask start pixel by the number of ;pixels in that word CMP R3, #32 SUBCS R3, R3, #32 ADDCS LR, LR, #4 ;get the mask bit back into a word's worth CMP R10, #0 ;extra test down here to avoid taking two BNE %BT12 ;branches 13 ;remember R6 ? uncompensate now CMP R6, #0 BEQ %FT11 SUBS R3, R3, R2 ;go back by the number of pixels in a word ADDMI R3, R3, #32 SUBMI LR, LR, #4 ;deal with going back into previous mask word 11 STR R3, [WsPtr, #SPltMaskBit] ;starting mask bit to plot STR LR, [WsPtr, #SPltMaskPtr] ;starting mask word to plot ; and save it for the end of row increments STR R3, [WsPtr, #SPltMaskRowBit] STR LR, [WsPtr, #SPltMaskRowPtr] STR LR, [WsPtr, #SPltMskAdr] STR LR, [WsPtr, #SPltMemAdr] ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr at SPltScrAdr LDMIA WsPtr, {R0-R1,R5-R7} LDR R5, [WsPtr, #SPltMaskPtr-SPltScrAdr] LDR R8, [WsPtr, #SPltEcfPtr-SPltScrAdr] 10 LDMIA R8, {R8,R9} ; ora,eor for this row ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,ora,eor ; Plot the first (Leftmost) word BL getmaskword MOV R2, R3 BL getmaskword_noinc ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places ; we only need result word R2 LDR R10, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word AND R2, R2, R10 ; mask down to just the required pixels LDR R4, [R0] ; plot 1 word OrrEorMASK R4,R2, R8,R9, R14 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 STMIA WsPtr, {R0,R1} ; save ScrAdr,ColCnt ; R0 ,R1 ,R5 ,R6 ,R7 ; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL BL getmaskword MOV R0, R3 BL getmaskword MOV R1, R3 BL getmaskword MOV R2, R3 BL getmaskword MOV R8, R3 BL getmaskword_noinc MOV R4,R3 MOV R3,R8 ShiftR R0,R1, R6,R7 ; shift R4-R0 right R6 bits ShiftR R1,R2, R6,R7 ; we only want result words R3-R0 ShiftR R2,R3, R6,R7 ShiftR R3,R4, R6,R7 LDR R4, [WsPtr] ; get screen address LDMIA R4, {R8-R11} ; get 4 screen words LDR R6, [WsPtr, #SPltEcfPtr-SPltScrAdr] LDMIA R6, {R6,R7} ; ora,eor for this row OrrEorMASK R8,R0, R6,R7, R14 ; Scr:=ScrOR(oraANDmsk)EOR(eorANDmsk) OrrEorMASK R9,R1, R6,R7, R14 OrrEorMASK R10,R2, R6,R7, R14 OrrEorMASK R11,R3, R6,R7, R14 LDR R0, [WsPtr] ; screen address STMIA R0!, {R8-R11} ; write 4 words back to screen LDMIB WsPtr, {R1,R5-R7} ; reload anything we shat on SUBS R1, R1, #4 BGE %BT20 30 ; try 1 word at a time ADDS R1, R1, #4 ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,ora,eor ; If EQ this is rightmost word LDR R8, [WsPtr, #SPltEcfPtr-SPltScrAdr] LDMIA R8, {R8,R9} ; ora,eor for this row LDR R10, [WsPtr, #SPltRMask-SPltScrAdr] 40 BL getmaskword MOV R2, R3 BL getmaskword_noinc ShiftR R2,R3, R6,R7 ; shift R3,R2 right R6 places, result in R2 ; we only need result word R2 ANDEQ R2, R2, R10 ; if rightmost word, mask down to just the ; required pixels LDR R4, [R0] OrrEorMASK R4,R2, R8,R9, R14 STR R4, [R0], #4 SUBS R1, R1, #1 BGE %BT40 50 ; now try the next scanline ; BEWARE ... genspriteplotparmblock returns values for memoff and ; scroff which take account of alignment of screen and sprite data ; ; Do not alter the logic below unless you really know what ; to expect from this routine!! LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 ; Width,Height,ScrOff,MemOff LDR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] LDR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] LDR R2, [WsPtr, #SPltMaskRowLen-SPltScrAdr] ADD LR, LR, R2 STR LR, [WsPtr, #SPltMaskPtr-SPltScrAdr] STR R3, [WsPtr, #SPltMaskBit-SPltScrAdr] STR LR, [WsPtr, #SPltMaskRowPtr-SPltScrAdr] STR R3, [WsPtr, #SPltMaskRowBit-SPltScrAdr] LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 ; Width,Height,ScrOff,MemOff ADD R0, R0, R3 ADD R10, WsPtr, #(SPltEcfPtr-SPltScrAdr) LDMIA R10, {R8,R9} ; EcfPtr,EcfIndx ADD R8, R8, #8 ; step both to next row in Ecf ADD R9, R9, #1 CMP R9, #8 MOVGE R9, #0 ; it's a wrap! SUBGE R8, R8, #(8*8) STMIA R10, {R8,R9} SUBS R2, R2, #1 STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] BGE %BT10 ; plot next scanline SWI XOS_RestoreCursors Pull "WsPtr, R14" RETURNVC ; ***************************************************************************** ; ; PlotMask - Draw a rectangle through a sprite mask ; ; External routine + PlotMa20 called by PlotMaskUserCoords ; (also external) ; ; in: R1 -> sprite area (not used) ; R2 -> sprite ; PlotMask ROUT ASSERT NewPtY = NewPtX +4 ADD R3, WsPtr, #NewPtX LDMIA R3, {R3, R4} ; plot sprite at NewPt(X,Y) PlotMa20 GraphicsMode R0 BNE PutSpriNotGraphics ; quit with error if not graphics mode LDR R5, [WsPtr, #GPLBMD] ; background GCOL action ORR R5, R5, #8 ; force 'use mask' LDR R10, [R2, #spImage] LDR R11, [R2, #spTrans] TEQ R10, R11 ; spImage=spTrans if no mask BEQ %FT90 ; so plot a rectangle LDR R0, [R2, #spMode] MOVS R10, R0, ASR #27 BMI PutSpriWideMaskErr2 BNE PlotNewMask LDR R0, [R2, #spHeight] ADD R0, R0, R4 LDR R10, [WsPtr, #GWTRow] Least R0, R0, R10 ; top scanline within window LDR R10, [WsPtr, #YWindLimit] SUB R0, R10, R0 ; flip Y AND R0, R0, #7 STR R0, [WsPtr, #SPltEcfIndx] ; index into Ecf ADD R0, WsPtr, R0, LSL #3 ADD R0, R0, #BgEcfOraEor STR R0, [WsPtr, #SPltEcfPtr] ; ptr to ECF for highest row plotted Push "WsPtr, R14" ; push both so R12,R14 are free for use BL GenSpritePlotParmBlk BVS SpriteOffScreen SWI XOS_RemoveCursors ; assume no error can occur! LDR R5, [WsPtr, #SPltMemAdr] LDR R6, [WsPtr, #SPltMskAdr] TEQ R6, #0 BEQ SpriteOffScreen ADD R6, R6, R5 STR R6, [WsPtr, #SPltMskAdr] STR R6, [WsPtr, #SPltMemAdr] ADD WsPtr, WsPtr, #SPltScrAdr ; repoint WsPtr at SPltScrAdr LDMIA WsPtr, {R0-R1,R5-R7} LDR R8, [WsPtr, #SPltEcfPtr-SPltScrAdr] 10 LDMIA R8, {R8,R9} ; ora,eor for this row ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,ora,eor ; Plot the first (Leftmost) word 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 R10, [WsPtr, #SPltLMask-SPltScrAdr] ; on leftmost word AND R2, R2, R10 ; mask down to just the required pixels LDR R4, [R0] ; plot 1 word OrrEorMASK R4,R2, R8,R9, R14 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 STMIA WsPtr, {R0,R1} ; save ScrAdr,ColCnt ; R0 ,R1 ,R5 ,R6 ,R7 ; ScrAdr,ColCnt, ,MemAdr,ShftR,ShftL LDMIA R5, {R0-R4} ; 5 words needed, gives 4 after shift ADD R5, R5, #16 ; advance source ptr 4 words STR R5, [WsPtr, #SPltMemAdr-SPltScrAdr] ShiftR R0,R1, R6,R7 ; shift R4-R0 right R6 bits ShiftR R1,R2, R6,R7 ; we only want result words R3-R0 ShiftR R2,R3, R6,R7 ShiftR R3,R4, R6,R7 LDR R4, [WsPtr] ; get screen address LDMIA R4, {R8-R11} ; get 4 screen words LDR R6, [WsPtr, #SPltEcfPtr-SPltScrAdr] LDMIA R6, {R6,R7} ; ora,eor for this row OrrEorMASK R8,R0, R6,R7, R14 ; Scr:=ScrOR(oraANDmsk)EOR(eorANDmsk) OrrEorMASK R9,R1, R6,R7, R14 OrrEorMASK R10,R2, R6,R7, R14 OrrEorMASK R11,R3, R6,R7, R14 LDR R0, [WsPtr] ; screen address STMIA R0!, {R8-R11} ; write 4 words back to screen LDMIB WsPtr, {R1,R5-R7} ; reload anything we shat on SUBS R1, R1, #4 BGE %BT20 30 ; try 1 word at a time ADDS R1, R1, #4 ; R0 ,R1 , R5 ,R6 ,R7 ,R8 ,R9 ; ScrAdr,ColCnt, MemAdr,ShftR,ShftL,ora,eor ; If EQ this is rightmost word LDR R8, [WsPtr, #SPltEcfPtr-SPltScrAdr] LDMIA R8, {R8,R9} ; ora,eor for this row LDR R10, [WsPtr, #SPltRMask-SPltScrAdr] 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 ANDEQ R2, R2, R10 ; if rightmost word, mask down to just the ; required pixels LDR R4, [R0] OrrEorMASK R4,R2, R8,R9, R14 STR R4, [R0], #4 SUBS R1, R1, #1 BGE %BT40 50 ; now try the next scanline LDMDB WsPtr, {R1,R2,R3,R4} ; R1 ,R2 ,R3 ,R4 ; Width,Height,ScrOff,MemOff ADD R0, R0, R3 ADD R5, R5, R4 ADD R10, WsPtr, #(SPltEcfPtr-SPltScrAdr) LDMIA R10, {R8,R9} ; EcfPtr,EcfIndx ADD R8, R8, #8 ; step both to next row in Ecf ADD R9, R9, #1 CMP R9, #8 MOVGE R9, #0 ; it's a wrap! SUBGE R8, R8, #(8*8) STMIA R10, {R8,R9} SUBS R2, R2, #1 STRGE R2, [WsPtr, #SPltHeight-SPltScrAdr] BGE %BT10 ; plot next scanline SWI XOS_RestoreCursors Pull "WsPtr, R14" RETURNVC ; Sprite has no mask or gcol says dont use it, so draw a rectangle 90 Push R14 BL ReadSpriteWidth ; on exit R0=width in pixels ADD R5, R3, R0 MOV R0, R3 ; x0 MOV R1, R4 ; y0 LDR R3, [R2, #spHeight] ADD R3, R3, R4 ; y1 SUB R2, R5, #1 ; x1 LDR R4, [WsPtr, #CursorFlags] TST R4, #ClipBoxEnableBit BLNE ClipPlotMask ADD R4, WsPtr, #BgEcfOraEor ; select Bg colour & action STR R4, [WsPtr, #GColAdr] B RectFillB ClipPlotMask ROUT Push "R0-R7,R10,R11, R14" ADD R10, R13, #2*4 ; R10 -> last point (R2,R3) MOV R11, #2 ; merge two points BL MergeR11PointsFromR10 Pull "R0-R7,R10,R11, PC" ; ***************************************************************************** ; ; GenSpritePlotParmBlk - Generate lots of useful variables to help us ; to plot sprite ; ; Internal routine, called by PutSprite, PlotMask, ScreenLoad ; ; in: R2 -> sprite ; R3 = X coordinate to plot at ; R4 = Y coordinate to plot at ; R5 = GCOL action ; GenSpritePlotParmBlk ROUT Push R14 AND R5, R5, #&F ; lose any ECF colour bits LDR R6, [R2, #spImage] LDR R7, [R2,#spTrans] SUB R6, R7, R6 ; offset from Image to Trans mask ; =0 if no mask STR R5, [WsPtr, #SPltAction] ; save action for simple case spotting CMP R5, #8 ; if GCOL action < 8 MOVLT R6, #0 ; plot as solid anyway STR R6, [WsPtr, #SPltMskAdr] AND R5, R5, #7 MOV R5, R5, LSL #2 ; 4 bits for each LDR R6, =TBscrmasks MOV R6, R6, ROR R5 ; put correct bits in top 4 bits MOV R7, R6, ASR #31 ; set R7 to 0 or -1 on bit 31 MOV R6, R6, LSL #1 MOV R8, R6, ASR #31 ; set R8 to 0 or -1 on bit 30 MOV R6, R6, LSL #1 MOV R9, R6, ASR #31 ; set R9 to 0 or -1 on bit 29 MOV R6, R6, LSL #1 MOV R10, R6, ASR #31 ; set R10 to 0 or -1 on bit 28 ADD R6, WsPtr, #SPltzgooMasks STMIA R6, {R7-R10} ; store zgoo, zgeo, zgoe, zgee MOV R14, R2 ; leave sprite CB ptr in R14 MOV R0, R3 ; leave X coord in R0 MOV R1, R4 ; leave Y coord in R1 ADD R11, R14, #spWidth LDMIA R11, {R2,R3} ; Width-1, Height-1 ADD R4, WsPtr, #GWLCol ; R4 ,R5 ,R6 ,R7 LDMIA R4, {R4,R5,R6,R7} ; LCol,BRow,RCol,TRow SUBS R5, R5, R1 MOVLT R5, #0 ; no. of rows below window ADD R1, R1, R3 ; Coord of topLH of sprite SUBS R7, R1, R7 MOVLT R7, #0 ; no. of rows above window SUB R1, R1, R7 ; clipped topLH coord ADD R5, R5, R7 ; reduction factor for height ADD R2, R2, #1 MOV R8, R14 LDR R9, [WsPtr, #CursorFlags] TST R9, #ClipBoxEnableBit BLNE ClipSpritePlot MOV R14, R8 MUL R3, R7, R2 ; word offset into sprite image Push "R3,R5" ; word offset and height reduction Push R14 BL ScreenAddr Pull R14 MOV R4, R2 ; address of top left corner LDR R5, [R14, #spImage] ADD R5, R5, R14 ; address of sprite image Pull R6 ADD R5, R5, R6, LSL #2 LDR R9, [WsPtr, #XShftFactor] LDR R10, [WsPtr, #NPix] LDR R11, [WsPtr, #Log2BPC] BitLOffset R7,R0, R9,R10,R11 ; R7 := bit position to align to WordOffset R8,R0, R9,R10,R11 ; R8 := word offset on line LDR R0, [WsPtr, #GWRCol] BitROffset R1,R0, R9,R10,R11 WordOffset R2,R0, R9,R10,R11 Push "R1,R2" LDR R0, [WsPtr, #GWLCol] BitLOffset R1,R0, R9,R10,R11 WordOffset R2,R0, R9,R10,R11 Push "R1,R2,R8" ADD R11, R14, #spWidth LDMIA R11, {R0,R1,R6,R8} ; Width-1, Height-1, LBit, RBit MOV R3, #0 ; offset to next row in sprite SUBS R6, R6, R7 ; no. of bits to shift sprite ; before plotting ; use R7 as LBit SUBS R8, R8, R6 ; calculate new RBit ADDLT R8, R8, #32 ADDLT R3, R3, #4 CMP R8, #32 SUBGE R8, R8, #32 SUBGE R3, R3, #4 ; R9 Offset on line to plot point, R7 LBit ; R11 Offset on line to GWLCol R10 bit position Pull "R10,R11" Pull R9 SUBS R9, R11, R9 SUBLT R11, R11, R9 ADDGT R4, R4, R9, LSL #2 ADDGT R5, R5, R9, LSL #2 ADDGT R3, R3, R9, LSL #2 CMPEQ R10, R7 MOVGT R7, R10 ; R10 Offset to GWRCol, R9 bit position ; R11 Offset to RHedge of sprite, R8 RBit ADD R11, R11, R0 SUB R11, R11, R3, ASR #2 Pull "R9,R10" SUBS R10, R11, R10 ADDGT R3, R3, R10, LSL #2 CMPEQ R8, R9 MOVGT R8, R9 Pull R10 SUBS R1, R1, R10 ; correct height BLT %FT20 SUBS R0, R0, R3, ASR #2 ; corrected width BLT %FT20 LDR R2,[WsPtr,#LineLength] SUB R2, R2, #4 SUB R2, R2, R0, LSL #2 ; offset to next screen line MOV R9, #&FFFFFFFE ; RHand partial word mask MVN R9, R9, LSL R8 MOV R8, #&FFFFFFFF MOV R8, R8, LSL R7 ; LHand partial word mask ANDEQ R8, R8, R9 ; if width=0, combine LH & RH masks MOVEQ R9, R8 CMP R6, #0 ADDLT R6, R6, #32 ; correct if neg SUBLT R5, R5, #4 RSB R7, R6, #32 ; its complement ADD R11, WsPtr, #SPltWidth STMIA R11, {R0,R1,R2,R3,R4} ; SPltWidth..SPltScrAdr ADD R11, WsPtr, #SPltColCnt STMIA R11, {R0,R5,R6,R7} ; SPltColCnt..SPltShftL ADD R11, WsPtr, #SPltMskAdr STMIB R11, {R8,R9} ; SPltLMask,SPltRMask CLRV Pull PC 20 SETV Pull PC LTORG END