; 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.VduGrafH ; ; ARTHUR OPERATING SYSTEM - Vdu Drivers ; ======================= ; ; Vdu driver code - Sprite stuff ; ; Authors RManby, TDobson ; Started 10.11.86 ; ************************************************************ ; *** C h a n g e L i s t (better late than never!) *** ; ************************************************************ ; Date Description ; ---- ----------- ; 17-Feb-88 Created change list ; Fixed bug in SLOAD (errors weren't reported) ; 08-Apr-88 Changed LoadFile to use open with nodir + mustopen ; 20-May-88 Changed NoRoomToLoad to NotEnoughRoom ; ***************************************************************************** ; ; MergeSpriteFile - Merge sprite file from filing system ; ; External routine ; ; in: R1 -> sprite area ; R2 -> filename ; MergeSpriteFile ROUT Push R14 KillSpChoosePtr LDR R3, [R1, #saFree] ADD R3, R3, R1 BL LoadFile ; R1 -> sprite area, R2 -> filename Pull PC, VS ; R3 -> free space SUB R2, R3, #4 BL MergeSpriteAreas ; in: R1 -> destination, R2 -> source, V=0 Pull R14 RETURNVC ; ***************************************************************************** ; ; LoadSpriteFile - Load sprite file from filing system ; ; External routine ; ; in: R1 -> sprite area ; R2 -> filename ; LoadSpriteFile ROUT KillSpChoosePtr ADD R3, R1, #saNumber ; R3 = load address ; and drop thru to LoadFile (V will be set/cleared by that routine) ; ***************************************************************************** ; ; LoadFile - Load sprite file to particular address ; ; Internal routine, called by LoadSpriteFile, MergeSpriteFile ; ; in: R1 -> sprite area ; R2 -> filename ; R3 = load address ; ; out: VS => error during load, R0 -> error ; VC => loaded OK, R0 undefined ; R1-R11 preserved ; LoadFile ROUT Push "R1-R6, R14" ; new version (07-Dec-89) to help broadcast loader a bit Push "R2,R3" ; filename ptr, load address LDR R6, [R1, #saEnd] ADD R6, R6, R1 SUB R6, R6, R3 ; free space = saEnd-LoadAddress MOV R0, #OSFile_ReadInfo MOV R1, R2 ; filename ptr SWI XOS_File ; OSFILE(5), returns R0 type, R4 length BVS %FT10 ; R0 file type, R4 length TEQ R0, #object_file ; if not a file BNE %FT08 ; then make into suitable error CMP R6, R4 ; will file fit in available space ? ADRCCL R0, SpriteErr_NotEnoughRoom [ International BLCC TranslateError ] BCC %FT10 ; There is room to load file, so load the lot MOV R0, #OSFile_Load Pull "R1, R2" ; filename ptr, load address MOV R3, #0 ; use given address SWI XOS_File BVS %FT20 ; TMD 07-Oct-91 (G-RO-9262) ; New code inserted here ; Check validity of sprite file ; R4 = file length from XOS_File above ; TMD 06-Mar-92 (RP-0589) ; Validity check weakened to only check that ; offset to first sprite is < length of file LDR R3, [sp, #2*4] ; R3 = load address LDR R1, [R3, #saFirst-4] ; offset to first sprite must be < length of file CMP R1, R4 Pull "R1-R6, PC",CC ; R0 is corrupt, R1-R11 preserved, V=0 ; it was a bad file, so make it look like an empty sprite area before erroring ; so that in SLoad case we don't get a naff sprite area. 05 MOV R0, #0 STR R0, [R3, #saNumber-4] MOV R0, #SpriteAreaCBsize STR R0, [R3, #saFirst-4] STR R0, [R3, #saFree-4] ADRL R0, SpriteErr_BadSpriteFile [ International BL TranslateError ] B %FT20 08 MOV R2, R0 MOV R0, #OSFile_MakeError ; then make into suitable error SWI XOS_File 10 ADD R13, R13, #2*4 ; balance stack 20 Pull "R1-R6, R14" ; return with error STR R0, [WsPtr, #RetnReg0] RETURNVS ; R1-R11 preserved ; ***************************************************************************** ; ; SaveSpriteFile - Save sprite area to filing system ; ; External routine ; ; in: R1 -> sprite area ; R2 -> filename ; SaveSpriteFile ROUT LDR R3, [R1, #saNumber] ; if no sprites TEQ R3, #0 BEQ %FT10 ; then quit with error Push R14 ADD R4, R1, #saNumber ; save sprite area, excluding LDR R5, [R1, #saFree] ; free space or saEnd ADD R5, R5, R1 MOV R0, #OSFile_SaveStamp MOV R1, R2 ; filename ptr LDR R2, =&FF9 ; type=SpriteFile MOV R3, #0 ; junk SWI XOS_File ; save file STRVS R0, [WsPtr, #RetnReg0] Pull PC 10 ADRL R0, SpriteErr_NoSprites [ International Push "lr" BL TranslateError Pull "lr" ] STR R0, [WsPtr, #RetnReg0] RETURNVS LTORG ; ***************************************************************************** ; ; MergeSpriteAreas - Merge two sprite areas ; ; Internal routine, called by MergeSpriteFile ; ; in: R1 -> destination sprite area ; R2 -> source sprite area ; V=0 ; ; out: All registers preserved ; MergeSpriteAreas ROUT TEQ R2, #0 ; validate R2 (R1 already checked) BEQ %FT90 Push "R1-R7, R14" ; Maintain two pointers to destination area - a read pointer and a write ; pointer. Enumerate all the sprites in the destination. If the corresponding ; sprite is found in the source area, advance the read pointer but leave the ; write pointer as-is. If the sprite isn't found, and read ptr != write ptr, ; CopyDown the dest sprite from read to write and then advance both pointers. ; ; Once all dest sprites enumerated, append entire src area to end of dest. ; ; This algorithm isn't optimal (O(N^2) search), but memory moved is O(N), which ; is a big improvement over the original implementation (O(N^2)). MOV R3, R1 ; R3 = dest area MOV R1, R2 ; R1 = src area ASSERT saNumber = 4 ASSERT saFirst = 8 LDMIB R3, {R4, R5} MOV R2, R3 MOV R6, R5 MOV R7, R4 ; Loop start is slightly ugly to allow sneaky re-use of ADD instructions 05 ADD R6, R6, R2 ; write ptr 06 ADD R5, R5, R2 ; read ptr 10 SUBS R4, R4, #1 BLT %FT50 ADD R2, R5, #spName BL SpriteCtrlBlkNoGetName LDR R2, [R5, #spNext] SUBVC R7, R7, #1 ; Sprite found, reduce dest sprite count BVC %BT06 ; Advance read ptr ; Sprite not found, copy down if necessary CMP R5, R6 BEQ %BT05 ; Advance read & writr ptr CopyDown R6, R5, R2, R14, R0 ; Advances R5 & R6 for us B %BT10 50 ; All duplicate sprites in dest removed ; Update area header and SpChoosePtr SUB R6, R6, R3 ; New saFree LDR R5, [R3, #saFree] CMP R6, R5 BEQ %FT55 STR R7, [R3, #saNumber] STR R6, [R3, #saFree] KillSpChoosePtr ; Only kill if something was deleted, to match old behaviour 55 ; Append src sprites ASSERT saNumber = 4 ASSERT saFirst = 8 LDMIB R1, {R4, R5} ADD R2, R5, R1 MOV R1, R3 60 SUBS R4, R4, #1 BLT %FT80 BL AppendSprite ; return R2 -> next sprite ; or error 'NoRoomToMerge' BVC %BT60 80 Pull "R1-R7, PC" ; exit with V already set up 90 ADRL R0, SpriteErr_Bad2ndPtr [ International Push "lr" BL TranslateError Pull "lr" ] STR R0, [WsPtr, #RetnReg0] RETURNVS ; ***************************************************************************** ; ; MergeSprite - Merge sprite into sprite area ; ; Internal routine, called by MergeSpriteAreas ; ; in: R1 -> destination area ; R2 -> source sprite ; ; out: R2 -> past end of source sprite (ie next sprite) ; MergeSprite ROUT Push "R1, R3-R5, R14" ADD R2, R2, #spName BL DeleteSpriteByName ; in: R1-R2; out: all preserved SUB R2, R2, #spName AddSprite LDR R3, [R1, #saFree] LDR R5, [R1, #saEnd] SUB R5, R5, R3 ; amount of free ram in dest area LDR R4, [R2, #spNext] ; space needed for sprite CMP R5, R4 BCC %FT10 ADD R3, R3, R1 ; first free locn in dest. area CopyDown R3,R2,R4,R5,R14 ; NB CopyDown will exit with R3 -> end ; of dest area LDR R4, [R1, #saNumber] ; update number of sprites ADD R4, R4, #1 STR R4, [R1, #saNumber] SUB R3, R3, R1 ; and free space offset STR R3, [R1, #saFree] Pull "R1, R3-R5, R14" RETURNVC ; ignore 'not found' from DeleteSprite 10 Pull "R1, R3-R5, R14" ADRL R0, SpriteErr_NoRoomToMerge [ International Push "lr" BL TranslateError Pull "lr" ] STR R0, [WsPtr, #RetnReg0] RETURNVS ; ***************************************************************************** ; ; AppendSprite - Append sprite to sprite area ; ; Internal routine, called by CopySprite ; ; in: R1 -> destination area ; R2 -> source sprite ; ; out: R2 -> past end of source sprite (ie next sprite) ; AppendSprite ROUT Push "R1, R3-R5, R14" B AddSprite ; ***************************************************************************** ; ; ExtendHorizontally - Add one column to RHS of the sprite ; ; Internal routine, called by InsertCol ; ; in: R1 -> sprite area ; R2 -> sprite ; ExtendHorizontally ROUT Push "R3-R6, R9-R11, R14" LDR R3, [R2, #spRBit] LDR R4, [WsPtr, #SprBytesPerChar] ADD R3, R3, R4 ; alter spRBit to include next pixel CMP R3, #32 BCC %FT20 ; >=32 means add 1 word to each row LDR R3, [R2, #spHeight] ADD R3, R3, #1 ; extend by (spHeight+1) words BL ExtendSprite ; (space doubled if mask present) Pull "R3-R6, R9-R11, PC", VS ; no room, then give error MOV R4, #0 BL MaskOffset ; use spHeight+1 as row counter, MOVNE R3, R3, LSL #1 ; doubled if mask present LDRNE R5, [R2, #spTrans] ; correct mask ptr, if mask present ADDNE R5, R5, R3, LSL #1 ; R3 is words*2, hence LSL STRNE R5, [R2, #spTrans] BL InsertWords ; Insert R3 words at position R4 in ; sprite, ie at beginning LDR R5, [R2, #spWidth] ADD R5, R5, #1 ; new spWidth STR R5, [R2, #spWidth] LDR R9, [R2, #spImage] ADD R9, R9, R2 ; to ADD R10, R9, R3, LSL #2 ; from 10 MOV R11, R5, LSL #2 ; move one row CopyDown R9,R10,R11,R14,R6 ; To,From,Size, Temp STR R4, [R9], #4 ; add 1 word at RH end of row SUBS R3, R3, #1 BHI %BT10 ; next row LDR R3, [WsPtr, #SprBytesPerChar] SUBS R3, R3, #1 20 STR R3, [R2, #spRBit] Pull "R3-R6, R9-R11, R14" RETURNVC ; ***************************************************************************** ; ; ReduceHorizontally - Remove some bits from the RHS of the sprite ; ; Internal routine, called by DeleteCol ; ; in: R0 = number of bits to delete off right hand side ; R1 -> sprite area ; R2 -> sprite ; ReduceHorizontally ROUT Push "R3-R6, R9-R11, R14" LDR R3, [R2, #spRBit] SUBS R3, R3, R0 ; alter spRBit to exclude those bits ADDCC R3, R3, #32 ; if underflow then extract whole word STR R3, [R2, #spRBit] BCS %FT20 ; < 0 means remove 1 word per row LDR R3, [R2, #spHeight] ADD R3, R3, #1 ; remove (spHeight+1) words MOV R4, #0 BL MaskOffset MOVNE R3, R3, LSL #1 ; doubled if mask present LDRNE R5, [R2, #spTrans] ; correct mask ptr, if mask present SUBNE R5, R5, R3, LSL #1 ; R3 is words*2, hence LSL STRNE R5, [R2, #spTrans] LDR R9, [R2, #spImage] ADD R9, R9, R2 ; to MOV R10, R9 ; from LDR R5, [R2, #spWidth] 10 MOV R11, R5, LSL #2 ; move one row CopyDown R9,R10,R11,R14,R6 ; To,From,Size, Temp ADD R10, R10, #4 ; skip unwanted word SUBS R3, R3, #1 BHI %BT10 ; next row ; R9 -> past end of this sprite ; R10 -> next sprite SUB R3, R10, R9 MOV R3, R3, LSR #2 ; no. of words to remove SUB R4, R9, R2 LDR R9, [R2, #spImage] SUB R4, R4, R9 ; byte offset within image BL RemoveWords LDR R5, [R2, #spWidth] SUB R5, R5, #1 ; new spWidth STR R5, [R2, #spWidth] 20 Pull "R3-R6, R9-R11, R14" RETURNVC ; ***************************************************************************** ; ; InsertRow - Insert blank row into sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = row number to insert below (0 => bottom, spHeight+1 => above top) ; InsertRow ROUT Push "R0,R4,R14" MOV R0, #57 ; SpriteOp reason code for insert/delete rows ORR R0, R0, #512 ;Set it to use pointers to user area & sprite MOV R4, #1 ; We're only inserting one row! (put 1 in) SWI XOS_SpriteOp BVS %FT20 Pull "R0,R4,R14" RETURNVC ; exit OK 20 STR R0, [WsPtr, #RetnReg0] Pull "R0,R4,R14" RETURNVS ; exit with error ; ***************************************************************************** ; ; DeleteRow - Delete row from sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = row number to remove (0=bottom, spHeight=top) ; DeleteRow ROUT Push "R0,R4,R14" MOV R0, #57 ; SpriteOp reason code for insert/delete rows ORR R0, R0, #512 ;Set it to use pointers to user area & sprite MVN R4, #0 ; We're only removing one row! (put -1 in) SWI XOS_SpriteOp BVS %FT20 Pull "R0,R4,R14" RETURNVC ; exit OK 20 STR R0, [WsPtr, #RetnReg0] Pull "R0,R4,R14" RETURNVS ; exit with error ; ***************************************************************************** ; ; InsertCol - Insert blank column into sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = column to insert at (0 => before left..width => after right) ; InsertCol ROUT Push "R0,R4,R14" MOV R0, #58 ; SpriteOp reason code for insert/delete cols ORR R0, R0, #512 ;Set it to use pointers to user area & sprite MOV R4, #1 ; We're only inserting one column! (put 1 in) SWI XOS_SpriteOp BVS %FT20 Pull "R0,R4,R14" RETURNVC ; exit OK 20 STR R0, [WsPtr, #RetnReg0] Pull "R0,R4,R14" RETURNVS ; exit with error ; ***************************************************************************** ; ; DeleteCol - Delete column from sprite ; ; External routine, and LHWastageEntry called from RemoveLeftHandWastage ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = column number to remove (0 => left, width-1 => right) ; DeleteCol ROUT Push "R0,R4,R14" MOV R0, #58 ; SpriteOp reason code for insert/delete cols ORR R0, R0, #512 ;Set it to use pointers to user area & sprite MVN R4, #0 ; We're only removing one row! (put -1 in) SWI XOS_SpriteOp BVS %FT20 Pull "R0,R4,R14" RETURNVC ; exit OK 20 STR R0, [WsPtr, #RetnReg0] Pull "R0,R4,R14" RETURNVS ; exit with error ; ***************************************************************************** ; ; ExtendSprite - Add R3 words to the end of the sprite (R3*2 if mask) ; ; Internal routine, called by ExtendHorizontally, InsertRow, CreateMask, ; and ExtendSpriteByR3 called by GetSprite ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = no. of words to insert (gets doubled if mask present) ; ExtendSpriteByR3 ROUT Push "R3, R8-R11, R14" B ExtendSprite10 ExtendSprite ROUT Push "R3, R8-R11, R14" BL MaskOffset MOVNE R3, R3, LSL #1 ; double no. of words if mask present ExtendSprite10 LDR R10, [R1, #saEnd] LDR R11, [R1, #saFree] SUB R10, R10, R3, LSL #2 CMP R10, R11 BCC %FT10 LDR R10, [R2, #spNext] ADD R10, R10, R2 ; copy source ADD R9, R10, R3, LSL #2 ; copy destination LDR R11, [R1, #saFree] ADD R11, R11, R1 SUB R11, R11, R10 ; size (bytes) to copy CopyUp R9,R10,R11, R14, R8 ; To,From,Size,Temp, Temp2 LDR R9, [R1, #saFree] ADD R9, R9, R3, LSL #2 STR R9, [R1, #saFree] ; update saFree LDR R9, [R2, #spNext] ADD R9, R9, R3, LSL #2 STR R9, [R2, #spNext] ; update spNext Pull "R3, R8-R11, R14" RETURNVC 10 ADRL R0, SpriteErr_NoRoomToInsert [ International BL TranslateError ] STR R0, [WsPtr, #RetnReg0] Pull "R3, R8-R11, R14" RETURNVS ; ***************************************************************************** ; ; InsertWords - Insert R3 words into given sprite at specified position ; ; Internal routine, called by ExtendHorizontally, InsertRow ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = number of words to insert ; R4 = insertion point (byte offset within sprite image) ; ; NB Assumes ExtendSprite has been called to leave R3 extra words ; at the end of the sprite ; ; out: All registers preserved ; InsertWords ROUT Push "R8-R11, R14" LDR R10, [R2, #spImage] ADD R10, R10, R2 ADD R10, R10, R4 ; copy source ADD R9, R10, R3, LSL #2 ; copy destination LDR R11, [R2, #spNext] ADD R11, R11, R2 SUB R11, R11, R9 ; size (bytes) to copy CopyUp R9,R10,R11, R14,R8 ; To,From,Size,Temp, Temp2 Pull "R8-R11, R14" RETURNVC ; ***************************************************************************** ; ; ClearWords - Clear R3 words in sprite ; ; Internal routine, called by InsertRow, CreateSprite ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = number of words to clear ; R4 = byte offset within sprite image to clear from ; ; out: All registers preserved ; ClearWords ROUT Push "R9-R11, R14" LDR R10, [R2, #spImage] ADD R10, R10, R2 ADD R10, R10, R4 ; clear from MOVS R9, R3 MOVNE R11, #0 10 STRNE R11, [R10], #4 SUBNES R9, R9, #1 BNE %BT10 Pull "R9-R11, R14" RETURNVC ; ***************************************************************************** ; ; RemoveWords - Delete R3 words from given sprite ; ; Internal routine, called by ReduceHorizontally, DeleteRow, RemoveMask, ; GetSprite ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = number of words to remove ; R4 = removal point (byte offset within sprite image) ; ; out: All registers preserved ; spNext (in sprite) and spFree (in sprite area) updated ; RemoveWords ROUT Push "R8-R11, R14" LDR R9, [R2, #spImage] ADD R9, R9, R2 ADD R9, R9, R4 ; copy destination ADD R10, R9, R3, LSL #2 ; copy source LDR R11, [R1, #saFree] ADD R11, R11, R1 SUB R11, R11, R10 ; size (bytes) to copy CopyDown R9,R10,R11, R14,R8 ; To,From,Size,Temp, temp2 SUB R9, R9, R1 STR R9, [R1, #saFree] ; update saFree LDR R9, [R2, #spNext] SUB R9, R9, R3, LSL #2 STR R9, [R2, #spNext] ; update spNext Pull "R8-R11, PC" ; ***************************************************************************** ; ; MaskOffset - Read mask size (0 if absent) ; ; Internal routine, called by ExtendHorizontally, ReduceHorizontally, ; InsertRow, DeleteRow, ExtendSprite, FlipAboutXAxis ; ; in: R2 -> sprite ; ; out: R0 = 0 if no mask, otherwise mask size ; EQ if no mask, NE if mask present ; MaskOffset ROUT Push R14 LDR R0, [R2, #spImage] LDR R14, [R2, #spTrans] SUBS R0, R14, R0 ; offset from Image to Trans mask ; =0 if no mask Pull PC ; return EQ/NE for nomask/mask ; ***************************************************************************** ; ; ReadPixelColour - Read colour of a pixel in a given sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = X coordinate of pixel (0 = left) ; R4 = Y coordinate of pixel (0 = bottom) ; ; out: RetnReg5 = colour (0..NColour) or 0..63 ; RetnReg6 = tint 0 or 0/64/128/192 ; ReadPixelColour ROUT Push R14 BL SpriteGenAddr ; returns R6, R7 Pull PC, VS ; Address, Bit position LDR R5, [R6] ; word from sprite LDR R6, [WsPtr, #SprReadNColour] CMP R6, #63 ; check for 256 colour MOVEQ R6, #255 AND R0, R6, R5, LSR R7 ; extract one pixel (bit0..) CMP R6, #255 MOVNE R2, R0 ; colour = pixel MOVNE R3, #0 ; tint = 0 BNE %FT10 ;now check for size of palette ADD R2, R2, #spImage ; point to image/mask start LDMIA R2, {R2, R3} CMP R3, R3 MOVGT R3, R3 SUB R2, R2, #spPalette CMP R2, #&0800 BEQ %FT05 ;see comment below - for this call to work we have to temporarily ;set NColour to SprReadNColour LDR R8,[WsPtr,#NColour] STR R6,[WsPtr,#NColour] BL ExtractTintAndColour ; else extract colour & tint from pixel STR R8,[WsPtr,#NColour] B %FT10 05 MOV R2, R0 MOV R3, #0 10 STR R2, [WsPtr, #RetnReg5] ; pass colour in R5 STR R3, [WsPtr, #RetnReg6] ; and tint in R6 Pull R14 RETURNVC ; ***************************************************************************** ; ; WritePixelColour - Write a pixel in a given sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = X coordinate of pixel (0 = left) ; R4 = Y coordinate of pixel (0 = bottom) ; R5 = pixel colour ; R6 = tint ; ; out: R1-R11 preserved ; ; amg: note. need to handle full palettes differently here - since the GCOL and TINT ; model should not apply. Check for a full palette on an 8bpp sprite and deal with ; it accordingly. ; amg: bug fix to MED-01885. Although ReadPixel and WritePixel use SprReadNColour, ; then call AddTintToColour which uses NColour - being the screen's value not the ; sprites. Therefore, the safest fix this near freeze is to simply temporarily change ; the NColour value for the call, and then restore it. WritePixelColour ROUT Push "R1-R4, R14" LDR R8, [WsPtr, #SprReadNColour] AND R0, R5, R8 ; limit colour to 0..NColour CMP R8, #63 ; check for 256 colours CMPNE R8, #255 BNE %FT08 ; despatch non 8bpp ;now need to determine size of 8bpp sprite's palette ADD R3, R2, #spImage ; point to image/mask start LDMIA R3, {R2, R3} ; fetch them CMP R2, R3 ; which is higher MOVGT R2, R3 ; use the lesser SUB R2, R2, #spPalette ; subtract start offset CMP R2, #&800 [ {FALSE} MOVNE R3, R6 ; then combine ;see comment above - for this call to work we have to temporarily ;set NColour to SprReadNColour LDRNE R7,[WsPtr,#NColour] STRNE R8,[WsPtr,#NColour] BLNE AddTintToColour ; colour & tint STRNE R7,[WsPtr,#NColour] | BEQ %FT05 ; Rather than mess around with NColour, just include the guts of the tinting code here MOV r1, r6, LSR #6 ; r1 = 0 0 0 0 0 0 T1 T0 AND r1, r1, #3 AND r2, r0, #2_00100001 ; r2 = 0 0 B3 0 0 0 0 R2 ORR r1, r1, r2, LSL #2 ; r1 = B3 0 0 0 0 R2 T1 T0 AND r2, r0, #2_00010000 ; r2 = 0 0 0 B2 0 0 0 0 ORR r1, r1, r2, LSR #1 ; r1 = B3 0 0 0 B2 R2 T1 T0 AND r2, r0, #2_00001110 ; r2 = 0 0 0 0 G3 G2 R3 0 ORR r0, r1, r2, LSL #3 ; r0 = B3 G3 G2 R3 B2 R2 T1 T0 ] B %FT05 ; 8 bpp take this branch 08 ADDCC R0, R0, R8 ; else index into full colour table ADRCCL R5, TBFullCol LDRCCB R0, [R5, R0] ; N.B. a table of bytes BCC %FT05 ; 1,2,4 bpp take this branch ; if 16bpp only need to shift round once, if 32bpp not at all LDR LR, [WsPtr,#SprLog2BPP] CMP LR, #4 MOV R5, R0 BCS %FT06 ; 32 bpp takes this branch B %FT07 ; and 16 bpp takes this one 05 ORR R5, R0, R0, LSL #8 ; expand byte value into a word 07 ORR R5, R5, R5, LSL #16 06 Pull "R1-R4" BL SpriteGenAddr ; returns R6, R7 Pull PC, VS ; Address, Bit position LDR R8, [WsPtr, #SprWriteNColour] AND R5, R5, R8 ; limit colour to pixel width LDR R0, [R6] ; word from sprite BIC R0, R0, R8, LSL R7 ORR R0, R0, R5, LSL R7 STR R0, [R6] Pull R14 RETURNVC ; ***************************************************************************** ; ; ReadPixelMask - Read mask state for a pixel in a given sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = X coordinate of pixel (0 = left) ; R4 = Y coordinate of pixel (0 = bottom) ; ; out: RetnReg5 = 0/1 (transparent/solid) or 0-255 for alpha-mask sprites ; ReadPixelMask ROUT Push R14 LDR R5, [R2, #spImage] LDR R6, [R2, #spTrans] SUBS R5, R6, R5 ; offset from Image to Trans mask BEQ %FT20 ; if =0, no mask so pixel is solid BL SpriteMaskAddr ; returns R6, R7 Pull PC, VS ; Address, Bit position LDR R5, [R6, R5] ; word from mask LDR LR, [R2, #spMode] ; check mask type MOVS LR, LR, ASR #27 MOVMI R5, R5, LSR R7 ; alpha mask ANDMI R5, R5, #255 BMI %FT10 MOVNE R6, #1 ; 1bpp mask LDREQ R6, [WsPtr, #SprReadNColour] ANDS R5, R6, R5, LSR R7 ; extract one mask pixel (bit0..) MOVNE R5, #1 10 STR R5, [WsPtr, #RetnReg5] Pull R14 RETURNVC 20 LDR LR, [R2, #spMode] ; check mask type TST LR, #&80000000 MOVEQ R5, #1 MOVNE R5, #255 STR R5, [WsPtr, #RetnReg5] Pull R14 RETURNVC ; ***************************************************************************** ; ; WritePixelMask - Write a pixel in the mask for a given sprite ; ; External routine ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = X coordinate of pixel (0 = left) ; R4 = Y coordinate of pixel (0 = bottom) ; R5 = pixel mask 0/1 (transparent/solid) or 0-255 for alpha-mask sprites ; WritePixelMask ROUT Push R14 LDR R8, [R2, #spImage] LDR R9, [R2, #spTrans] SUBS R9, R9, R8 ; offset from Image to Trans mask BEQ %FT10 ; if =0, no mask so quit BL SpriteMaskAddr ; returns R6, R7 Pull PC, VS ; Address, Bit position LDR LR, [R2, #spMode] MOVS LR, LR, ASR #27 MOVMI R8, #255 ; alpha mask BMI %FT05 LDREQ R8, [WsPtr, #SprWriteNColour] MOVNE R8, #1 ; 1bpp mask TEQ R5, #0 MOVNE R5, R8 05 LDR R0, [R6, R9] ; word from mask BIC R0, R0, R8, LSL R7 ORR R0, R0, R5, LSL R7 STR R0, [R6, R9] 10 Pull R14 RETURNVC ; ***************************************************************************** ; ; SpriteGenAddr - Generate address for a given (X,Y) position ; ; SpriteMaskAddr - For use on mask (copes with old/new/alpha masks) ; ; Internal routine, called by InsertCol, DeleteCol, ReadPixelColour, ; WritePixelColour, ReadPixelMask, WritePixelMask ; ; Note that InsertCol and DeleteCol are *not* being altered for the ; present round of 1bpp mask work. ; ; ; in: R1 -> sprite area ; R2 -> sprite ; R3 = X coordinate of pixel (0 = left) ; R4 = Y coordinate of pixel (0 = bottom) ; ; out: R6 = address ; R7 = bit position of pixel ; R1-R5, R8-R11 preserved ; V=1 => outside sprite, R0 -> error ; SpriteMaskAddr ROUT Push "R1-R5, R8-R11, LR" LDR R11, [R2, #spMode] MOVS R11, R11, LSR #27 ; get the sprite type from the mode word BEQ %FT10 ; branch: old format, use old routine as is ADD R5, R2, #spWidth LDMIA R5, {R5-R8} ; R5 ,R6 ,R7 ,R8 ; spWidth,spHeight,spLBit,spRBit SUBS R4, R6, R4 ; invert Y coord BCC %FT90 ; must be in range 0..spHeight BL GetMaskspWidth ; change R5 to suit the mask width ; and R8 to new last bit used MLA R0, R5, R4, R4 ; word offset to row = Y*(width+1) ;for new format masks the depth is fixed, so... TST R11, #16 ; alpha mask or 1bpp mask? MOVEQ R11, #0 ; Log2BPC MOVEQ R9, #5 ; XShftFactor MOVEQ R10, #31 ; SprNPix MOVNE R11, #3 ; Log2BPC MOVNE R9, #2 ; XShftFactor MOVNE R10, #3 ; SprNPix B %FT20 ; and continue in the old code SpriteGenAddr Push "R1-R5, R8-R11, LR" 10 ADD R5, R2, #spWidth LDMIA R5, {R5-R8} ; R5 ,R6 ,R7 ,R8 ; spWidth,spHeight,spLBit,spRBit SUBS R4, R6, R4 ; invert Y coord BCC %FT90 ; must be in range 0..spHeight MLA R0, R5, R4, R4 ; word offset to row = Y*(width+1) LDR R9, [WsPtr, #SprXShftFactor] LDR R10, [WsPtr, #SprNPix] LDR R11, [WsPtr, #SprLog2BPC] 20 BitLOffset R6,R3, R9,R10,R11 WordOffset R3,R3, R9,R10,R11 ; sprite starts LBit bits into word ; so add LBit to bit offset ADD R7, R6, R7 ADD R3, R3, R7, LSR #5 ; if offset>=32 then inc word address AND R7, R7, #31 ; force offset into range 0..31 CMP R3, R5 ; R3 should now be in range 0..spWidth CMPEQ R7, R8 ; if R3=spWidth, then check bit posn BHI %FT90 ; is within sprite ADD R6, R0, R3 ; word offset into sprite ADD R6, R2, R6, LSL #2 LDR R8, [R2, #spImage] ADD R6, R6, R8 ; byte address of word in sprite Pull "R1-R5, R8-R11, LR" RETURNVC 90 ADRL R0, SpriteErr_InvalidRowOrCol [ International Push "lr" BL TranslateError Pull "lr" ] STR R0, [WsPtr, #RetnReg0] Pull "R1-R5, R8-R11, LR" RETURNVS ; ***************************************************************************** ; ; GetMaskspWidth - convert spWidth for data to spWidth for mask (1bpp & alpha masks) ; ; Internal routine, called from spritemaskaddr & switchouputtomask ; ; in: R5 = spWidth (ie width in words-1) ; (expects R2->sprite) ; ; out: R5 = spWidth (words -1) for mask data ; R8 modified for new last bit used in mask data ; should only be called for new format sprites, but will cope with old too ;NOTE: If any changes are made to this routine, please look at the SpriteExtend ;source too, as there is a very similiar routine there too (in SprAdjSize). WT GetMaskspWidth ROUT Push "R0,LR" LDR R0, [R2, #spMode] ; fetch the sprite mode ANDS LR, R0, #15<<27 ; isolate the sprite type and test for =0 Pull "R0,PC",EQ ; if an old format sprite, return R5 unchanged TEQ LR, #SpriteType_RISCOS5<<27 [ NoARMT2 ANDEQ LR, R0, #127<<20 MOVEQ LR, LR, LSR #20 | UBFXEQ LR, R0, #20, #7 ] MOVNE LR, LR, LSR #27 ; treat any T>max sprites as 32bpp CMP LR, #SpriteType_RO5MAX MOVCS LR, #SpriteType_Substitute TST R0, #&80000000 ; bugfix 9/8/93: get log2bpp this way ADRL R0, NSM_bpptable-4 LDR LR, [R0, LR, LSL #2] ; get the log2bpp to LR RSB R0, LR, #5 ; and change to 5-log2bpp MOV R5, R5, LSL R0 ; width in pixels LDR R0, [R2, #spRBit] ADD R0, R0, #1 ADD R5, R5, R0, LSR LR MOVNE R5, R5, LSL #3 ; make 8 times wider if alpha mask ANDS LR, R5, #&1F ; fit exactly in a number of words ? SUB R8, LR, #1 ; alter the last bit used for the mask data ; fix bug MED-01130.... AND R8, R8, #&1F ; ....bring back into range 00-1F (may be -1 here) MOVNE LR, #1 ; if not, add an extra word ADD R5, LR, R5, LSR #5 ; add the whole number of words SUB R5, R5, #1 ; returns as words-1 Pull "R0,PC" ; ***************************************************************************** ; ; RemoveLeftHandWastage - Remove left-hand wastage from a sprite ; ; Internal routine, but made external for testing ; ; in: R1 -> sprite area ; R2 -> sprite ; RemoveLeftHandWastage ROUT LDR R0, [R2, #spLBit] CMP R0, #0 ; is there any wastage ? MOVEQ PC, R14 ; no, then exit straight away Push "R1, R2, R14" ; get stack the same as in DeleteCol LDR R11, [R2, #spImage] ADD R11, R11, R2 ; R11 := address of first word MOV R7, #0 ; bit position of first pixel STR R7, [R2, #spLBit] ; pretend LBit = 0 MOV R10, #0 ; byte offset from LH end to delete pt. LDR R9, [R2, #spWidth] MOV R9, R9, LSL #2 ; byte offset from delete pt to LH end ; of next row -4 LDR R8, [R2, #spNext] ADD R8, R8, R2 ; first byte after sprite MOV R2, R0 ; number of bits to delete LHWastageEntry RSB R3, R2, #32 ; LShft := 32-RShft MOV R4, #1 RSB R4, R4, R4, LSL R7 ; mask for pixels left of deletion pt. MVN R5, R4 ; inclusive & right of extractn. pt. ; R0, R1, R2 ,R3 ,R4 ,R5 ,R6 ,R7 ,R8 ,R9 ,R10 .R11 ; , , RShft,LShft,LMask,RMask, ,WordCnt,EndAdr,WordOff,RowOff,Adr ; R11 -> LH end of row 10 ADD R11, R11, R10 ; step to deletion point LDR R0, [R11] AND R1, R5, R0, LSR R2 ; extract & shift rightmost pixels ; (ie MSBits) AND R0, R4, R0 ; extract leftmost pixels (ie LSBits) ORR R0, R0, R1 ; recombine (unwanted pixel removed) LDR R1, [R11, #4] ; shift leftmost pixel of next word ORR R0, R0, R1, LSL R3 ; in at rightmost end of this word STR R0, [R11], #4 ; NB #4 to cope with naff rowoff (R10) CMP R9, #0 BEQ %FT30 MOV R7, R9 20 LDMIA R11,{R0,R1} ; now do a 1 pixel shift left MOV R0, R0, LSR R2 ; of the rest of the row ORR R0, R0, R1, LSL R3 STR R0, [R11], #4 SUBS R7, R7, #4 BGT %BT20 ; R11 -> LH end of next row 30 CMP R8, R11 BHI %BT10 ; if EndAdr>Adr, do next row MOV R0, R2 ; R0 = number of bits to delete LDMFD R13, {R1,R2} BL ReduceHorizontally Pull "R1-R2, R14" RETURNVC 60 STR R0, [WsPtr, #RetnReg0] 70 Pull "R1-R2, R14" RETURNVS END