; Copyright 2010 Castle Technology 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. ; ; > Sources.SprOp ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; OS_SpriteOp decoding entry point ; Entry: R0 = reason code ; R12 --> private word ; Exit : R0-R7 may be used to contain results ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ My_SpriteOp ROUT Debug so, "Sprite Extend sprite op called...",r0 Push "R1" AND r1, r0, #&FF CMP r1, #SpriteReason_CheckSpriteArea CMPNE r1, #myminreason Pull "R1" ASSERT SpriteReason_CheckSpriteArea < myminreason MOVCC pc, lr Push "R10-R11,LR" ; Stash the entry reason code including area flags STR R0,spritecode STR R13,stackframe ; for calling OS_SpriteOp MOV R14,#VduDriverWorkSpace + BgEcfOraEor STR R14,save_ecflimit ; mask plotting uses bg ecf pattern JumpAddress LR,My_SpriteExit,forward AND R10, R0, #&FF ; First look for CheckSpriteArea which would otherwise make the jump table huge CMP r10, #SpriteReason_CheckSpriteArea BEQ Go_CheckSpriteArea ; Do the rest... SUB r10, r10, #myminreason CMP R10,#mymaxreason-myminreason ADDCC PC,PC,R10,LSL #2 Pull "R10-R11,PC" mymaxreason * SpriteReason_ReadSaveAreaSize + 1 myminreason * SpriteReason_AppendSprite myjptable B Go_AppendSprite ; 35 SpriteReason_AppendSprite B Go_SetPointerShape ; 36 SpriteReason_SetPointerShape B Go_CreateRemovePalette ; 37 SpriteReason_CreateRemovePalette Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" B Go_PlotMaskScaled ; 50 SpriteReason_PlotMaskScaled B Go_PaintCharScaled ; 51 SpriteReason_PaintCharScaled B Go_PutSpriteScaled ; 52 SpriteReason_PutSpriteScaled B Go_PutSpriteGreyScaled ; 53 SpriteReason_PutSpriteGreyScaled Pull "R10-R11, PC" B Go_PlotMaskTransformed ; 55 SpriteReason_PlotMaskTransformed B Go_PutSpriteTransformed ; 56 SpriteReason_PutSpriteTransformed B Go_InsertDeleteRows ; 57 SpriteReason_InsertDeleteRows B Go_InsertDeleteColumns ; 58 SpriteReason_InsertDeleteColumns Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" Pull "R10-R11, PC" [ {FALSE} Pull "R10-R11, PC" ; 63 Unsupported SpriteReason_PutSpriteScaledCalibrated Pull "R10-R11, PC" ; 64 Unsupported SpriteReason_PutSpriteTransformedCalibrated Pull "R10-R11, PC" ; 65 Unsupported SpriteReason_TileSpriteScaled ] ASSERT (.-myjptable) = (mymaxreason-myminreason) * 4 My_SpriteExit LDRVC R0,spritecode 01 Pull "R10-R11,LR,PC" Go_SpriteOp Push "R10-R12,LR" 01 LDR R10,stackframe Push "PC" ; set up return address LDMIA R10,{R10-R11,PC} ; call rest of vector owners NOP ; returns here or next instruction Pull "R10-R12,PC" TestFor16or32bpp ROUT ; return V=1 if R2 points at a 16/32bpp sprite Push "R0-R3,R11,LR" MOV R11, #0 B %FT40 TestForMaskAnyDepth ; fault a new format sprite with mask Push "R0-R3,R11,LR" LDR R0,[R2,#spMode] MOVS R0,R0,LSR #27 LDMEQFD R13!,{R0-R3,R11,PC} B %FT32 TestForMaskAtDepth ; fault a mask at 16/32bpp Push "R0-R3,R11,LR" ;reject any T=5 or T=6 sprites which have a mask, and also (later) any ;attempts to add a palette to one MOV R11,#1 40 ;should be called after findsprite has been called LDR R0,[R2,#spMode] CMP R0,#256 BCC %FT10 ; go if a screen mode number MOV R0,R0,LSR #27 ; isolate the type alone CMP R0,#SpriteType_New16bpp BCC %FT20 ; under 16bpp, so don't care 30 CMP R11,#0 BEQ %FT50 32 LDR R0,[R2,#spImage] LDR R1,[R2,#spTrans] TEQ R0,R1 BEQ %FT20 ; no mask, so no complaints 50 ADR R0, ErrorBlock_BadDepth addr R1, Title BL copy_error_one ; returns V set STR R0,[R13] STR R1,[R13,#4] Pull "R0-R3,R11,PC" MakeSpriteErrorBlock BadDepth,,BadDepth 10 ;it's a mode number Push "R2" MOV R1,#VduExt_Log2BPP SWI XOS_ReadModeVariable BCS %BT50 CMP R2,#4 Pull "R2" BCS %BT30 ; 16 or 32 bpp so check for a mask 20 Pull "R0-R3,R11,PC" ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SpriteReason_CreateRemovePalette ; -------------------------------- ; Entry: r0 = 37 (SpriteReason_CreateRemovePalette) (+0 / 256 / 512) ; r1 -> sprite control block ; r2 -> sprite name / sprite ; r3 = -1: read palette size ; = 0: remove palette ; <> 0: add palette (bit 31=1, add extended palette) ; ; Exit : V=1 => r0 -> error block ; ; r3 =-1 on entry then r3 = size of palette block, =0 if none ; r4 -> palette block, =0 if none ; r5 = mode ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Go_CreateRemovePalette Push "r1-r11, lr" BL findsprite ; r2 -> sprite block Pull "r1-r11, PC",VS CMP r3, #-1 BNE addremoveit ; skip read palette size ADD r3, r2, #spImage LDMIA r3, {r3, r4} ; r3,r4 offsets to mask/image CMP r3, r4 MOVGT r3, r4 ; r3 -> top of palette block SUB r3, r3, #spPalette ; r3 = size of palette block MOVS r3, r3, ASR #3 ; r3 = number of colours in palette block ADDNE r4, r2, #spPalette ; r4 -> palette block to return MOVEQ r4, #0 ; or =0 if no palette LDR r5, [r2, #spMode] ; r5 = mode number ADD lr, sp, #4*2 ; lr -> r3 in return frame STMIA lr, {r3, r4, r5} CLRV Pull "r1-r11, pc" addremoveit TEQ r3, #0 ; remove the palette? BNE addpalette ; remove palette, simple case, assuming r1 -> sprite control block, r2 -> sprite ; we must move the data in the sprite and then update the header followed by ; the control block. removepalette LDR r4, [r2, #spImage] ; r4 = offset to image LDR r5, [r2, #spTrans] ; r5 = offset to trans mask CMP r4, r5 MOVGT r4, r5 ; r4 = offset to first part of sprite data LDR r8, [r1, #saFree] ; r8 = free index into sprite area SUBS r0, r4, #spPalette ; r0 = size of palette block, if none then exit! ADDNE r9, r2, #spPalette ADDNE r10, r1, r8 ; r10 -> free in sprite area BLNE move_memory_down SUB r8, r8, r0 ; adjust free space STR r8, [r1, #saFree] LDR r3, [r2, #spNext] ; adjust next sprite pointer SUB r3, r3, r0 STR r3, [r2, #spNext] ADD r3, r2, #spImage ; adjust offsets to image data LDMIA r3, {r4, r5} SUB r4, r4, r0 SUB r5, r5, r0 STMIA r3, {r4, r5} CLRV Pull "r1-r11, pc" ; add sprite palettes, this involves creating a gap for the sprite ; palette and then writing the actual data for the palette into this area ; these routines will use a general purpose function 'addpalette' taking ; r1,r2 as sprite pointers and r4 as a mask to be applied to the maximum ; number of colours. This mask is used to generate the real number of ; colours written into the sprite header. addpalette ; the test for 16/32bpp only occurs here, so that read palette size, and ; remove palette won't complain LDR r0, [r2, #spMode] ; r0 = mode MOVS lr, r0, LSR #27 ; EQ for old format sprite, NE otherwise BEQ %FT10 ;now allow T=1 to T=4 to have palettes CMP lr, #SpriteType_New16bpp BCC %FT10 ADR r0, ErrorBlock_BadDepth addr R1, Title BL copy_error_one ; this call sets V Pull "r1-r11, PC",VS 10 TST r3, #1:SHL:31 ; add extended palette? MOVNE r4, #255 MOVEQ r4, #63 ; max colours that can be added Push "r1-r2" LDR r0, [r2, #spMode] ; r0 = mode MOV r1, #VduExt_Log2BPP SWI XOS_ReadModeVariable ; no need to check for CS here - will already ADR r1, palettetables ; have happened in TestFor16or32bpp LDR r5, [r1, r2, ASL #2] ; r5 = offset to palette tables ADD r5, r5, r1 ; r5 -> absolute table MOV r8, #2 ; shift =2 as reading from table (single entries) MOV r0, #1 MOV r1, r0, ASL r2 RSB r3, r0, r0, ASL r1 ; r3 = maximum number of colours AND r4, r3, r4 ; r4 = maximum number of written colours Pull "r1-r2" ; preserve sprite pointers ADD r0, r4, #1 MOV r0, r0, ASL #3 ; r0 = size of a palette block ADD r6, r2, #spImage LDMIA r6, {r6, r7} ; r6, r7 -> sprite, mask MOV lr, r6 CMP lr, r7 MOVGT lr, r7 ; lr =lowest offset SUBS lr, lr, #spPalette ; lr =size of current palette SUBNE r0, r0, lr ADDNE r5, r2, #spPalette ; if adjusting size then modify from current palette MOVNE r8, #3 ; shift =3, reading from sprite palette (double entries) LDR r9, [r1, #saFree] LDR r10, [r1, #saEnd] ADD r9, r9, r0 ; r9 => end of free area CMP r9, r10 ; is there enough room? BHI add_no_room ; no, so complain! STR r9, [r1, #saFree] ; store new offset to start of free area ADD r10, r9, r1 ; r10 -> new start of free area SUB r10, r10, r0 ; r10 -> old start of free area ; = end address+1 of block to move LDR r9, [r2, #spNext] ADD r9, r9, r0 STR r9, [r2, #spNext] ; adjust the offset to next sprite ADD r6, r6, r0 ADD r7, r7, r0 ADD r9, r2, #spImage STMIA r9, {r6, r7} ; stash updated image + mask offsets ADD r9, r2, #spPalette ; r9 -> start of current palette ADD r9, r9, lr ; r9 -> end of current palette+1 ; = start address of block to move BL move_memory_up ADD r6, r2, #spPalette ; r6 -> destination buffer ADD r6, r6, r4, LSL #3 LDR r7, =&0F0F0F00 ; r7 = masked used when ensuring palette entries ; r1 -> sprite blk ; r2 -> sprite ; r3 = total colours (ie. 1, 3, 15, 255) ; r4 = number of colours to write ( 1, 3, 15, 63 / 255) ; r5 -> table containing base palette entries ; r6 -> block to write data into ; r7 = &0F0F0F00 ; r8 = shift to use when getting palette entries addpalette_main AND r0, r4, #15 ADD r0, r5, r0, LSL r8 LDR r0, [r0] ; r0 = BGR combination TEQ r3, #255 ; is it a 8bpp palette? BNE addpalette_gotvalues BIC r0, r0, #&80000000 ; transfer hard blue bit AND lr, r4, #&80 ORR r0, r0, lr, LSL #31-7 BIC r0, r0, #&00C00000 ; transfer hard green bit AND lr, r4, #&60 ORR r0, r0, lr, LSL #23-6 BIC r0, r0, #&00008000 ; transfer hard red bit AND lr, r4, #&10 ORR r0, r0, lr, LSL #15-4 BIC r0, r0, r7 ORR r0, r0, r0, LSR #4 ; change from &B0G0R00 -> &BBGGRR00 addpalette_gotvalues ORR r0, r0, #&10 STR r0, [r6],#4 STR r0, [r6],#-12 ; write and advance index SUBS r4, r4, #1 BGE addpalette_main ; loop whilst colour counter >= 0 Pull "r1-r11, pc" add_no_room ADR r0, ErrorBlock_NotEnoughRoom addr r1, Title BL copy_error_one ; Always sets the V flag Pull "r1-r11, PC" MakeSpriteErrorBlock NotEnoughRoom,,NoMem ; tables for creating default palettes palettetables DCD bpp1 -palettetables DCD bpp2 -palettetables DCD bpp4 -palettetables DCD bpp8 -palettetables bpp1 DCD &00000000 ; black DCD &FFFFFF00 ; white bpp2 DCD &00000000 ; black DCD &0000FF00 ; red DCD &00FFFF00 ; yellow DCD &FFFFFF00 ; white bpp4 DCD &00000000 ; black DCD &0000FF00 ; red DCD &00FF0000 ; green DCD &00FFFF00 ; yellow DCD &FF000000 ; blue DCD &FF00FF00 ; magenta DCD &FFFF0000 ; cyan DCD &FFFFFF00 ; white DCD &00000000 ; black DCD &0000FF00 ; red DCD &00FF0000 ; green DCD &00FFFF00 ; yellow DCD &FF000000 ; blue DCD &FF00FF00 ; magenta DCD &FFFF0000 ; cyan DCD &FFFFFF00 ; white bpp8 DCD &00000000 ; 0000 DCD &10101000 ; 0001 DCD &20202000 ; 0010 DCD &30303000 ; 0011 DCD &00004000 ; 0100 DCD &10105000 ; 0101 DCD &20206000 ; 0110 DCD &30307000 ; 0111 DCD &40000000 ; 1000 DCD &50101000 ; 1001 DCD &60202000 ; 1010 DCD &70303000 ; 1011 DCD &40004000 ; 1100 DCD &50105000 ; 1101 DCD &60206000 ; 1110 DCD &70307000 ; 1111 LTORG ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SpriteReason_SetPointerShape ; ---------------------------- ; Entry: R1 --> sprite area ; R2 --> sprite name/address ; R3 bits 0..3 = pointer shape number (1..4) ; R3 bit 4 set => don't use the sprite's image ; R3 bit 5 set => don't use the sprite's palette ; R3 bit 6 set => don't set the current shape number afterwards ; R4,R5 = coordinates of active point (pixels from top-left) ; R6 --> factors (<=0 ==> use default, depending on mode) ; R7 --> pixel translation table (==> 2 bpp) ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Go_SetPointerShape Push "R10,R11,LR" Debug so,"Regs at start = ",R0,R1,R2,R3,R4 Debug so," ",R5,R6,R7,R8,R9 spp_ptrno * 2_00001111 spp_noimage * 2_00010000 spp_nopalette * 2_00100000 spp_nosetnum * 2_01000000 tempareasize * &200 Debug pt, "R3 = ",R3 TST R3,#spp_noimage BLEQ go_setimage Pull "R10,R11,PC",VS Debug pt, "done setimage" TST R3,#spp_nopalette BLEQ go_setpointerpalette Pull "R10,R11,PC",VS Debug pt, "done setpalette" TST R3,#spp_nosetnum BLEQ go_setpointernum Debug pt, "done setno",R3 LDRVC R0, spritecode Debug gs,"Regs at end = ",R0,R1,R2,R3,R4 Debug gs," ",R5,R6,R7,R8,R9 Pull "R10,R11,PC" go_setimage LDR R0,spritecode Push "R0-R7,LR" ; may need to find sprite again Debug pt,"Input sprite:",#spritecode,R1,R2 BL findsprite ; R2 --> sprite definition BLVC TestFor16or32bpp Debug pt,"Input sprite address is:",R2 MOV R1,R2 ; R1 --> sprite definition MOV R11,R2 ; R11 --> sprite definition Debug so,"gonna do a create sprite" LDRVC R0,[R2,#spMode] BLVC readspritevars ; log2px/y BLVC readvduvars ; inlog2px/y, save_inlog2bpp BVS %FT99 Debug so,"still gonna do a create sprite" ASSERT saEnd=0 ; create area header for output sprite MOV R14,#tempareasize ; should be big enough STR R14,[sp,-R14]! MOV R14,#0 STR R14,[sp,#saNumber] MOV R14,#saExten STR R14,[sp,#saFirst] STR R14,[sp,#saFree] Debug so,"definately still gonna do a create sprite" MOV R0,#SpriteReason_CreateSprite ; create output sprite ADD R0,R0,#&100 MOV R1,sp ADRL R2,sillyname MOV R3,#0 ; no palette MOV R4,#32 ; 32 pixels wide MOV R5,#32 ; 32 pixels high MOV R6,#1 ; mode 1 seems reasonable Debug pt,"Output sprite:",R0,R1,R2,R3,R4 SWI XOS_SpriteOp Debug so,"returned from create swi" BVS %FT96 Debug so,"V not set" 96 MOVVC R0,#SpriteReason_SwitchOutputToSprite ADDVC R0,R0,#&100 MOVVC R3,#0 ; no save area SWIVC XOS_SpriteOp ; on exit R0-R3 = old params Debug so,"returned from swi" ADDVS sp,sp,#tempareasize BVS %FT99 Debug so,"V not set" Push "R0-R3" ADD R14,sp,#4*4 + tempareasize + 1*4 LDMIA R14,{R1-R7} Debug pt,"Recovered input params:",R1,R2,R3,R4,R5,R6,R7 CMP R6,#0 LDMNEIA R6,{R2-R5} ; user-supplied scaling BNE %FT01 MOV R14,#1 LDR R2,inlog2px ; if no R6, make up the values! MOV R2,R14,LSL R2 LDR R3,inlog2py MOV R3,R14,LSL R3 LDR R4,log2px MOV R4,R14,LSL R4 LDR R5,log2py MOV R5,R14,LSL R5 LDR R14,Log2bpp ; double-pixel modes ... MOV R4,R4,LSL R14 ; ... are not quite as they seem ! LDR R14,Log2bpc MOV R4,R4,ASR R14 LDR R14,modeflags TST R14,#Flag_HiResMono MOVNE R4,R4,LSL #1 ; 1/2 width in hi-res mono 01 Push "R2-R5" MOV R6,sp MOV R0,#SpriteReason_PutSpriteScaled ; plot input into output ADD R0,R0,#&200 MOV R2,R11 ; R2 --> sprite LDR R3,[R2,#spLBit] ; first bit number used RSB R3,R3,#1 ; remember bits are inclusive LDR R14,[R2,#spRBit] ; R14 = no of bits used in r.h. word ADD R3,R3,R14 LDR R14,[R2,#spWidth] ; R14 = no of words in the middle + 1 ADD R3,R3,R14,LSL #5 ; R3 = total width (bits) LDR R14,save_inlog2bpc MOV R4,R3,LSR R14 ; R4 = width (pixels) Debug pt,"Input sprite width =",R4 SUB R6,R6,#4 BL mulR4 ; scale to output pixels ADD R6,R6,#4 RSBS R3,R4,#32 ; R3 = x-coordinate to plot sprite at MOVLT R3,#0 ; keep lhs visible! LDR R4,[R2,#spHeight] ADD R4,R4,#1 ; R4 = input height (pixels) BL mulR4 Push "R3,R4" ; R4 = height of pointer (pixels) MOV R3,R3,LSL #2 ; sprite is in mode 1 (log2px = 2) MOV R4,R4,LSL #2 ; sprite is in mode 1 (log2py = 2) RSB R4,R4,#32*4 ; make top-left match up MOV R5,#0 LDR R14,modeflags TEQ R7,#0 ; PRM 1-780 zero means no table supplied BNE %FT05 TST R14,#Flag_HiResMono ADRNE R7,hiresmonottr ; use built in table iff R7=0 and in hi-res mono 05 Debug pt,"Input sprite address,x,y =",R2,R3,R4 SWI XOS_SpriteOp Pull "R10,R11" ; R10,R11 = xcoord,height ADD R14,sp,#4*4 ; skip factor block LDMIA R14,{R0-R3} ; SwitchOutput back to old parameters Debug pt,"Switching back to",R0,R1,R2,R3 SWI XOS_SpriteOp ADD R2,sp,#8*4+saExten ; R2 --> output sprite Debug pt,"Output sprite address =",R2 LDR R5,[R2,#spImage] ADD R14,R2,R5 ; R14 --> sprite image Debug pt,"Output sprite image =",R14 MOV R5,#0 ; stick in reason code (= 0) Push "R5,R6,R14" ; [sp + 8] = sprite ptr CMP R11,#32 MOVGT R11,#32 ADD R1,sp,#2 ; need correct alignment STRB R11,[R1,#3] MOV R14,#16/2 ; R14 = width (bytes) STRB R14,[R1,#2] ADD R14,sp,#3*4 + 8*4 + tempareasize + 3*4 LDMIA R14,{R3-R5} ; shape no, active X, active Y AND R3,R3,#spp_ptrno ; bottom 4 bits = shape no STRB R3,[R1,#1] SUB R6,R6,#4 ; fool it so x-values used BL mulR4 ADD R4,R4,R10 ; allow for sprite origin STRB R4,[R1,#4] MOV R4,R5 ADD R6,R6,#4 ; fool it so y-values used BL mulR4 STRB R4,[R1,#5] [ debugpt LDMIA sp,{R3-R5} Debug pt,"OS_Word block =",R3,R4,R5 ] MOV R0,#OsWord_DefinePointerAndMouse SWI XOS_Word ADD sp,sp,#3*4 + 8*4 + tempareasize ; correct stack 99 LDR R14,[sp],#4 STR R14,spritecode ; may be needed later Pull "R1-R7,PC" hiresmonottr DCB 0,1,3,3 ; translate colour 2 into colour 3 ALIGN sillyname DCB "pointer",0 ALIGN go_setpointerpalette Push "R1-R5,LR" Debug pt,"Input sprite:",#spritecode,R1,R2 BL findsprite ; R2 --> sprite definition Debug pt,"Input sprite address:",R2 LDRVC R0,[R2,#spMode] MOV R1, R2 BLVC readspritevars ; get save_inlog2bpp Pull "R1-R5,PC",VS ; MOV R14,#1 LDR R5,save_inlog2bpp MOV R5,R14,LSL R5 ; R5 = no of elements in ttr table MOV R3,#3 ; start with colour 3 01 TEQ R7,#0 ; PRM 1-780 zero means no table supplied MOVEQ R4,R3 ; substitute 1:1 translation BEQ %FT03 ; got colour MOV R4,#0 02 LDRB R14,[R7,R4] TEQ R14,R3 ; found it? BEQ %FT03 ADD R4,R4,#1 CMP R4,R5 ; R5 = no of entries in table BCC %BT02 B %FT04 ; don't bother programming palette 03 Debug pt,"Programming palette entry",R4 MOV R14,#spPalette+1 ; point at RGB of first flash state ADD R4,R14,R4,LSL #3 ; 8 bytes per palette entry LDR R14,[R2,#spImage] CMP R14,R4 ; is there a palette entry for this? BLE %FT04 SWI XOS_WriteI+19 ; program palette MOV R0,R3 SWI XOS_WriteC ; mouse colour number SWI XOS_WriteI+25 ; program mouse colour ADD R0,R2,R4 MOV R1,#3 SWI XOS_WriteN ; R,G,B 04 SUBS R3,R3,#1 BNE %BT01 ; forget colour 0 Pull "R1-R5,PC" go_setpointernum Push "R1-R3,LR" MOV R0,#&6A AND R1,R3,#spp_ptrno ; pointer shape MOV R2,#0 ; pointer linked to mouse SWI XOS_Byte Pull "R1-R3,PC" ; Scale to output pixels ; Entry: R4 = input coordinate (pixels) ; R6 --> scale factors ([R6,#4] and [R6,#12]) ; Exit: R4 = R4 * R6!4 / R6!12 mulR4 Push "R5,R11,LR" LDR R14,[R6,#1*4] ; y-magnification MUL R11,R14,R4 LDR R5,[R6,#3*4] ; y-division DivRem R4,R11,R5, R14 ; R4 = output height Pull "R5,R11,PC" ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SpriteReason_PaintCharScaled ; ---------------------------- ; Entry: R1 = character code ; R3,R4 = x,y coordinates ; R6 --> scale factors ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Go_PaintCharScaled Push "R1-R9,LR" STRB R1,charblock ADRL R1,charblock MOV R0,#OsWord_ReadCharacterDefinition SWI XOS_Word BLVC readvduvars BVS exitchar ; ; contruct a sprite header in module workspace ; MOV R10, #0 MOV R11, #7 ; Mode 0 sprite starting uses bits 0-7 ADR R14,areahdr ; 3 words for area header, LDMIA R14,{R1-R3,R6-R8} ; and 3 for sprite name MOV R5,#spriteSize+4*8*2 ; R5 = 44 + 2*8 rows of 1 word ADD R4,R5,#spriteCB-areaCB ; R4 = saFree ADR R14,areaCB Debug ch,"areaCB = &",R14 STMIA R14!,{R1-R3,R4,R5,R6-R8,R10} ; up to spWidth MOV R8,#7 ; R8 = spHeight (no of rows - 1) MOV R9,#0 ; R9 = spLbit STMIA R14!,{R8,R9,R11} ; R11 = spRbit MOV R8,#spriteSize ADD R9,R8,#4*8 ; R9 = R8 + 8 rows of 1 word MOV R11, #0 ; mode 0 sprite STMIA R14!,{R8,R9,R11} ; R14 --> sprite pixels SUB R7,R9,R8 ADD R7,R14,R7 ; R7 --> sprite mask ; ; now construct a sprite mask from the character definition ; ADRL R10, charblock+1 MOV R5, #8 01 LDRB R9, [R10], #1 MOV R8, R9, LSR #7 TST R9, #&40 ORRNE R8, R8, #&02 TST R9, #&20 ORRNE R8, R8, #&04 TST R9, #&10 ORRNE R8, R8, #&08 TST R9, #&08 ORRNE R8, R8, #&10 TST R9, #&04 ORRNE R8, R8, #&20 TST R9, #&02 ORRNE R8, R8, #&40 TST R9, #&01 ORRNE R8, R8, #&80 STR R8, [R7], #4 SUBS R5, R5, #1 BNE %BT01 ; ; now set up the parameters for a scaled mask plot ; MOV R14,#VduDriverWorkSpace + FgEcfOraEor STR R14,save_ecflimit ; char painting uses fg ecf pattern ADR R1,areaCB ADD R2,R1,#spriteCB-areaCB ADD R14,R13,#2*4 ; salvage params from stack LDMIA R14,{R3-R7} MOV R0,#&200 ; indicates that R2 --> sprite defn ADD R0,R0,#SpriteReason_PlotMaskScaled LDR R14,spritecode Push "R14" STR R0,spritecode MOV r0, #SpriteReason_PaintCharScaled BL Go_PlotMaskScaled Pull "R14" STR R14,spritecode exitchar Pull "R1-R9,PC" areahdr DCD spriteAreaSize DCD 1 DCD spriteCB - areaCB spritehdr DCB "character",0,0,0 ; Note - 12 chars long exactly ALIGN ; ; Read Vdu Variables ; also process the ones that the OS doesn't always provide ; vduinputbuffer DCD VduExt_XEigFactor ; log2 pixels per unit (x) DCD VduExt_YEigFactor ; log2 pixels per unit (y) DCD VduExt_Log2BPP ; for no. of colours DCD VduExt_Log2BPC ; for double-pixel modes DCD VduExt_OrgX DCD VduExt_OrgY DCD VduExt_GWLCol ; graphics window DCD VduExt_GWBRow DCD VduExt_GWRCol DCD VduExt_GWTRow DCD VduExt_LineLength DCD VduExt_ScreenStart DCD VduExt_YWindLimit DCD VduExt_ModeFlags ; for hi-res mono checking DCD -1 readvduvars Push "R0-R4,LR" ; ; read real vdu variables (mode is only required for PaintChar) ; ADR R0,vduinputbuffer ADR R1,vduoutputbuffer SWI XOS_ReadVduVariables BVS %FT99 MOV R0,#1 LDR R14,Log2bpc MOV R14,R0,ASL R14 STR R14,BPC ; bpc = 2^log2bpc LDR R14,Log2bpp MOV R14,R0,ASL R14 STR R14,BPP ; bpp = 2^log2bpp Debug sc,"ScreenStart,YWindLimit,LineLength,bpc =",#screenstart,#ywindlimit,#linelength,#BPC 99 STRVS R0,[R13] Pull "R0-R4,PC" ; ; read mode-specific info for mode (R0) ; readspritevars ; NB saved registers extended to include R3 purely for jpeg. ; R0=the sprite's mode word ; R1->the sprite Push "R1-R3,LR" [ jpeg [ {TRUE} ; look for a JPEG sprite, and if you find it lie about these dimensions. LDR R2,[R1,#spImage] ; get offset to image data ADD R2,R2,R1 ; get address of image data ADD R2,R2,#4 ; skip past compression ID word ; LDRB R3,[R2,#6] ; get 6th byte ; CMP R3,#'J' ; give me a J? ; BNE rsv_not_jpeg_file ; LDRB R3,[R2,#7] ; if so, get 7th byte ; CMP R3,#'F' ; give me a F? ; LDREQB R3,[R2,#8] ; if so, get 8th byte ; CMPEQ R3,#'I' ; give me a I? ; LDREQB R3,[R2,#9] ; if so, get 9th byte ; CMPEQ R3,#'F' ; give me a F? ; BNE rsv_not_jpeg_file ; what does that spell? ; This test is watered down a bit, to allow slightly more deviant files ; (eg. the ones that Tony Sumner finds on the net). Anything really wrong will ; still get caught later on in the C code. Still, note this increases (slightly) ; the risk that an innocent normal sprite will get accused of being JPEG. ; Alternative test: LDRB R3,[R2] ; load first byte CMP R3,#&ff ; is it ff? LDREQB R3,[R2,#1] ; load second byte CMPEQ R3,#&d8 ; is it d8? LDREQB R3,[R2,#2] ; load third byte CMPEQ R3,#&ff ; is it ff? BNE rsv_not_jpeg_file ; We have found a JPEG file - pretend it's a 32bpp sprite. Debug in,"It's a JPEG file" LDR R3,spritecode ; check we're doing a PutSpriteScaled AND R3,R3,#255 ; mask out to get op code CMP R3,#SpriteReason_PutSpriteScaled Pull "R1-R3,LR",NE ; if not, discard stuff from readspritevars Pull "R0-R12,PC",NE ; and exit doing nothing. ; >>>> should produce an error return here. MOV R3,#5 ; log2 of 32 STR R3,save_inlog2bpc STR R3,save_inlog2bpp MOV R3,#32 ; bits per pixel STR R3,save_inbpp MOV R3,#1 ; log2 of 2 OS-units STR R3,inlog2px ; pretend to be VGA-size pixels STR R3,inlog2py ; pretend to be VGA-size pixels STR R3,is_it_jpeg ; mark as a JPEG sprite STR R0,inmode ; the mode vars are correct for mode 20 (old format) or new format compressed sprites. STR R1,save_sprite ; so that later code can find the JPEG data again Pull "R1-R3,PC" rsv_not_jpeg_file ; if the last sprite was jpeg but this one is not then we MUST reload the sprite variables. LDR R3,is_it_jpeg ; was the last one JPEG? 0 -> not JPEG CMP R3,#0 MOVNE R3,#0 ; if the previous one was JPEG STRNE R3,is_it_jpeg ; mark as not a JPEG sprite this time MOVNE R14,#-1 ; force reload of sprite mode vars LDREQ R14,inmode ; else, vars reflect this sprite's mode | MOV R14,#0 ; jpeg stuff outside jpeg condition? stupid? (GPS) STR R14,is_it_jpeg ; ditto LDR R14,inmode ; check for sprite vars already right ] ] TEQ R0,R14 Pull "R1-R3,PC",EQ ; already have these variables! STR R0,inmode MOV R1,#VduExt_Log2BPC SWI XOS_ReadModeVariable SETV CS STRVC R2,save_inlog2bpc ; input log2(bytes per char) MOVVC R1,#VduExt_Log2BPP SWIVC XOS_ReadModeVariable STRVC R2,save_inlog2bpp ; input log2(bits per pixel) MOVVC R1,#VduExt_XEigFactor SWIVC XOS_ReadModeVariable STRVC R2,inlog2px MOVVC R1,#VduExt_YEigFactor SWIVC XOS_ReadModeVariable STRVC R2,inlog2py Pull "R1-R3,PC",VS MOV R14,#1 LDR R1,save_inlog2bpp MOV R14,R14,ASL R1 STR R14,save_inbpp Debug in,"Input log2bpc/p, bpp = ",#save_inlog2bpc,#save_inlog2bpp,#save_inbpp Pull "R1-R3,PC" ; ; Find sprite address given areaCBptr/name ; Entry: [spritecode] = reason code (including bits above bit 7) ; R1 = areaCBptr ; R2 --> sprite name ; Exit: R2 --> sprite definition ; findsprite Push "LR" LDR R0,spritecode BL getspritename BLVC getspriteaddr Pull "PC" ; Entry: R0 = original sprite code getspritename Push "R0-R1,R3-R4,LR" BICS R14,R0,#&FF ; R0 < 256 ==> system sprite (can't!) TEQ R14,#&200 ; R2 --> sprite already STREQ R2,spritename ; if so, 1st word is sprite addr BEQ %FT99 ADRL R3,spritename ADD R4,R3,#12 01 LDRB R0,[R2],#1 CMP R0,#" " ; ignore control characters and <space> too! BLS %FT02 ASCII_LowerCase R0,R14 STRB R0,[R3],#1 CMP R3,R4 ; terminate after 12 characters BCC %BT01 02 MOV R0,#0 03 CMP R3,R4 ; pad with nulls STRCCB R0,[R3],#1 BCC %BT03 99 STRVS R0,[R13] Pull "R0-R1,R3-R4,PC" MakeSpriteErrorBlock NoWorkSpace,,NoWork ; ; scan the sprite list to find the address ; getspriteaddr Push "R1,R3-R9,LR" BICS R14,R0,#&FF ; R0 < 256 ==> system sprite (can't!) BNE %FT00 MOV R0,#3 SWI XOS_ReadDynamicArea TEQ R1,#0 ADREQ R0, ErrorBlock_NoWorkSpace ; can't do anything with this! addr r1, Title, EQ BLEQ copy_error_one ; Always sets the V bit BVS %FT99 MOV R1,R0 ; R1 -> system sprite area STR R1,[sp] ; return for AppendSprite 00 TEQ R14,#&200 ; R2 --> sprite already BEQ %FT99 ADRL R14,spritename LDMIA R14,{R3,R4,R5} LDR R14,[R1,#saFree] ADD R9,R1,R14 ; R9 --> free area LDR R14,[R1,#saFirst] ADD R2,R1,R14 ; R2 --> first sprite 04 CMP R2,R9 [ debuger BCC %FT01 ADR R14,spritename DebugS er,"Sprite doesn't exist ",R14 01 ] BLCS get_sprite_doesnt_exist_error ; r0-> error block, V set BVS %FT99 LDMIA R2,{R1,R6,R7,R8} ; get link plus name TEQ R6,R3 TEQEQ R7,R4 TEQEQ R8,R5 ADDNE R2,R2,R1 BNE %BT04 99 Pull "R1,R3-R9,PC" ; makepalette16bpp ; convert palette to 16bpp for output to 16bpp mode plotting directly from palette ; if this is not done, the spriteextend blitter will run out of registers! makepalette16bpp [ debugso Push "R1-R7,LR" LDR r7, sprite_doesnt_exist_error Debug so, "converting palette..." | Push "R1-R6,LR" ] LDR r1, save_inbpp MOV r2, #1 MOV r1, r2, LSL r1 ; number of entries in palette Debug so, "going to do this many entries = ",R1 LDR r2, trns_palette ; pointer to palette data ADRL r3, newtranstable ; where to store altered palette STR r3, trns_palette ; where to store altered palette 01 LDR r4, [r2], #8 MOV r4, r4, LSR #8 ; BBGGRR00 to 00BBGGRR ; r4 = in2, r5 = im1, r6 = ttr ; fedcba9876543210 fedcba9876543210 ; in2 = 00000000bbbbbbbb ggggggggrrrrrrrr AND r5,r4,#&F80000 ; im1 = 00000000bbbbb000 0000000000000000 MOV r6,r5,LSL #7 ; ttr = 0bbbbb0000000000 AND r5,r4,#&F800 ; im1 = 0000000000000000 ggggg00000000000 ORR r6,r6,r5,LSL #10 ; ttr = 0bbbbbggggg00000 AND r5,r4,#&F8 ; im1 = 0000000000000000 00000000rrrrr000 ORR r4,r6,r5,LSL #13 ; in2 = 0bbbbbgggggrrrrr ; NB result in top half of register ; Needs two work registers MOV r4, r4, LSR #16 Debug so, "gonna store thingy at thingy",R4,R3 STR r4, [R3],#4 SUBS r1, r1, #1 Debug so, "R1 now ",R1 BNE %BT01 [ debugso ; check workspace word at end of 'newtranstable' space to confirm we haven't walked off the edge LDR r6, sprite_doesnt_exist_error Debug so, "converted palette...check words are ",R6, R7 Pull "R1-R7,PC" | Pull "R1-R6,PC" ] ; ; Fatal exits for divide by zero and other panics ; MakeInternatErrorBlock DivZero diverror ADR R0, ErrorBlock_DivZero addr r1, Title BL copy_error_one ; Always sets the V bit exitbiggie Pull "R1-R9,PC" ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SpriteOp_PutSpriteGreyScaled ; ---------------------------- ; Entry: [spritecode] = reason code ; R1 --> areaCBptr ; R2 --> sprite name ; R3,R4 = coords ; R5 = 0 ; R6 --> scaling factors ; R7 --> pixel translation table ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Go_PutSpriteGreyScaled Push "LR" ADR R0, ErrorBlock_NoGrScl BL copy_error_one ; also sets V Pull "PC" MakeSpriteErrorBlock NoGrScl ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SpriteOp_PlotMaskScaled ; ----------------------- ; Entry: [spritecode] = reason code ; R1 --> areaCBptr ; R2 --> sprite name ; R3,R4 = coords ; R6 --> scaling factors ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Go_PlotMaskScaled Push "R1-R9,LR" MOV R5,#8 ; avoid masko being knackered later MOV R7,#0 ; no pixel translation MOV R8,#0 ; no calibration table B %FT01 getbgaction DCD VduExt_GPLBMD DCD -1 getfgaction DCD VduExt_GPLFMD DCD -1 getbgcolour DCD VduExt_GBCOL DCD -1 MakeSpriteErrorBlock BadTranslation,,BadTran ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SpriteOp_PutSpriteScaled ; ------------------------ ; Entry: [spritecode] = reason code ; R1 --> areaCBptr ; R2 --> sprite name ; R3,R4 = coords ; R5 = 0 ; R6 --> scaling factors ; R7 --> pixel translation table ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Go_PutSpriteScaled Push "R1-R9,LR" MOV R8,#0 ; no printer calibration table 01 Debug in,"Draw sprite: R0,R1,R2 =",R0,R1,R2 Debug in,"Coords, gcol, &scale, &ttr =",R3,R4,R5,R6,R7 Debug in,"Calibration table =",R8 CLRPSR I_bit, R14 ; re-enable interrupts [ flagbit MOV R14, R5, LSR #4 STR R14, trns_flags2 ; store flags [ widetrans Debug so,"flags are ",R14 BICS R14, R14, #flg2_ignorettr + flg2_widetrans + flg2_ditheron | BICS R14, R14, #flg2_ignorettr + flg2_ditheron ] Debug so,"flags are ",R14 ADRNEL R0, ErrorBlock_BadFlags addr r1, Title, NE BLNE copy_error_one ; Always sets the V bit BVS exitbiggie ] AND R5,R5,#&0F ; only bottom 4 bits are interesting STR R8,calibration_table ; ; Check to see if truecolour sprites should be dithered ; [ flagbit LDR r0, trns_flags2 TST r0, #flg2_ditheron MOVEQ r0, #0 MOVNE r0, #1 STR r0, dither_truecolour ] ; ; see if reason code indicated a sprite name or sprite pointer in R2 ; BL findsprite ; R2 --> sprite MOVVC R1,R2 ; now R1 --> sprite ; read input/output mode variables BLVC readvduvars LDRVC R0,[r1,#spMode] BLVC readspritevars BVS exitbiggie Debug cc,"read sprite vars",R1 ; Alternate entry point from JPEG plotting putsprscaled_frompjs LDR R0,[R1,#spMode] ; get sprite's original mode STR R0,save_spr_type ; ; read scaling factors (set up default if necessary) ; CMP R6,#0 LDMNEIA R6,{R8-R11} BNE %FT01 MOV R8, #1 MOV R9, #1 MOV R10, #1 MOV R11, #1 01 ;let's try to rationalise the scale factors... ; ************************************************* ; *** DivRem - Integer division and remainder *** ; *** rc := ra DIV rb; ra := ra REM rb *** ; *** rb preserved, rtemp corrupt *** ; *** DivRem rc, ra, rb, rtemp *** ; ************************************************* Push "R5-R7" MOV R5, R8 DivRem R7, R5, R10, R6 CMP R5, #0 MOVEQ R8, R7 MOVEQ R10, #1 MOV R5, R9 DivRem R7, R5, R11, R6 CMP R5, #0 MOVEQ R9, R7 MOVEQ R11, #1 Pull "R5-R7" STR R8,save_xmag STR R9,save_ymag STR R10,save_xdiv STR R11,save_ydiv Debug in,"x mag/div, y mag/div:",r8,r9,r10,r11 [ ignore_ttr ; ; check for a ttr. If it's present and the sprite has a full entry palette set up to ; use that instead. ; MOV R14, #0 STR R14, trns_palette LDR R14,[R1,#spImage] CMP R14,#SpriteCBsize BEQ has_no_palette LDR R0,[R1,#spTrans] CMP R0,#SpriteCBsize BEQ has_no_palette ;validate it (to exclude 8bpp without full palettes) ;test is that palette size should be 8*ncolours ;find the lower of the sprite start and mask start CMP R14,R0 MOVCS R14,R0 SUB R14,R14,#SpriteCBsize MOV R14,R14,LSR #3 ;divide by 8 for number of palette entries MOV R0,#1 LDR R9,save_inbpp MOV R0,R0,ASL R9 CMP R0,R14 BNE has_no_palette [ flagbit LDR R14, trns_flags2 Debug so,"Checking ttr flag", R14 TST R14, #flg2_ignorettr BEQ has_no_palette ;use ttr and ignore any palette 01 | Debug so,"ttr flag is not set" B has_no_palette ] Debug so, "We're going to plot from palette" LDR R14,[R1,#spTrans] ADD R14,R1,#SpriteCBsize STR R14, trns_palette LDR R14, BPP CMP R14, #16 MOVEQ r7, #0 ; junk any translation table we were given to stop checktrans overwriting 16bpp palette BLEQ makepalette16bpp has_no_palette ] ; ; validate supplied translation table (if any) ; Debug cc,"about to check trans table",R1 CMP R7,#0 ; 0 ==> no translation BLNE checktrans BVS exitbiggie Debug cc,"trans table is OK",R1 [ ignore_ttr ; if doing a sprite of <16bpp to >8bpp, and it has a palette, change the ttr pointer ; to point at the palette data instead of the ttr data. Note that the two are different ; formats, so there is also a different plotting routine to include too... LDR R14, BPP ; output bpp CMP R14, #16 MOVCC R14, #0 STRCC R14, trns_palette BCC %FT45 LDR R14, save_inbpp CMP R14, #16 MOVCS R14, #0 STRCS R14, trns_palette BCS %FT45 LDR R14, trns_palette TEQ R14, #0 MOVNE R7,R14 MOVEQ R14,#0 STREQ R14, trns_palette ;only non-zero if going to use this ; trns_palette doubles as a pointer to the palette up this far, and then becomes a ; compilation flag for the macro generation (with the value being passed in as the ; ttr address) 45 ] STR R7,ColourTTR CMP R7,#0 BNE notrans LDRB R14,spritecode ; R14 = bottom 8 bits of reason code TEQ R14,#SpriteReason_PlotMaskScaled [ jpeg LDRNE R14,is_it_jpeg CMPNE R14,#1 Debug gs,"1. is it JPEG?",R0 ] LDRNE R14,save_inbpp LDRNE R0,BPP TEQNE R14,R0 ; OK if same bpp or mask plotting ;however, don't error if going 16>32 or 32>16 BEQ notrans ;dispose of the equal case CMP R0,#16 CMPEQ R14,#32 BEQ notrans CMP R0,#32 CMPEQ R14,#16 BEQ notrans errtrans ADRL R0,ErrorBlock_BadTranslation ; different bpp ==> must have table errexitscaled addr r1, Title BL copy_error_one ; Always set the V bit Debug so,"error from trans table" BVS exitbiggie notrans Debug so,"Checked out trans table palette" ; ; try to optimise by using existing sprite plot code ; can only be done if bpp equal, no trans, no scaling and output not to sprite ; [ debug TEQ R7,#0 LDREQ R14,save_inbpp LDREQ R0,BPP TEQEQ R14,R0 ; if same bpp, try to optimise LDREQ R14,vduspritename TEQEQ R14,#0 LDR R6,save_xmag ; load always! LDR R7,save_ymag ; load always! LDREQ R8,save_xdiv LDREQ R9,save_ydiv TEQEQ R6,R8 TEQEQ R7,R9 BNE %FT87 87 | TEQ R7,#0 LDREQ R14,save_inbpp ANDS R7, R14, #32+16 ; If we're dealing with deep sprites then the kernel is slower!!! LDREQ R0,BPP TEQEQ R14,R0 ; if same bpp, try to optimise LDREQ R14,vduspritename TEQEQ R14,#0 LDR R6,save_xmag ; load always! LDR R7,save_ymag ; load always! LDREQ R8,save_xdiv LDREQ R9,save_ydiv TEQEQ R6,R8 TEQEQ R7,R9 BNE cantdoinOS [ jpeg LDREQ R0,is_it_jpeg TEQEQ R0,#0 Debug gs,"is it JPEG?",R0 BNE cantdoinOS ] ; ; if all parameters are ineffective, call the OS routine! ; LDR R0,spritecode AND R14,R0,#&FF ; R14 = reason code only BIC R0,R0,#&FF ; R0 = code except for reason code TEQ R14,#SpriteReason_PutSpriteScaled ORREQ R0,R0,#SpriteReason_PutSpriteUserCoords BEQ %FT01 TEQ R14,#SpriteReason_PlotMaskScaled ORREQ R0,R0,#SpriteReason_PlotMaskUserCoords LDREQ R14,save_ecflimit ; is this background plotting? TEQEQ R14,#VduDriverWorkSpace + BgEcfOraEor BNE cantdoinOS 01 LDMIA R13,{R1,R2} ; get original R1,R2 Debug so,"doing it in OS" BL Go_SpriteOp ; call the OS version if there is one Pull "R1-R9,PC" cantdoinOS ] Debug so,"we can't do it in OS" ; ; convert coords to internal pixels ; R6,R7 = x,y magnification ; LDR R14,orgx ADD R3,R3,R14 LDR R14,log2px MOV R3,R3,ASR R14 LDR R14,orgy ADD R4,R4,R14 LDR R14,log2py MOV R4,R4,ASR R14 ; convert to internal form ; ; bodge x-coords (inc. graphics window) so we can forget double-pixels ; LDR R14,Log2bpc LDR R0,Log2bpp SUBS R14,R14,R0 MOVNE R3,R3,LSL R14 LDRNE R0,gwx0 MOVNE R0,R0,LSL R14 STRNE R0,gwx0 LDRNE R0,gwx1 ADDNE R0,R0,#1 ; make exclusive MOVNE R0,R0,LSL R14 SUBNE R0,R0,#1 ; make inclusive again STRNE R0,gwx1 ; ; bodge x multiplier and divisor ; MOVNE R6,R6,LSL R14 STRNE R6,save_xmag LDR R14,save_inlog2bpc LDR R0,save_inlog2bpp SUBS R14,R14,R0 LDRNE R0,save_xdiv MOVNE R0,R0,LSL R14 STRNE R0,save_xdiv ; ; R8, [save_ysize] <-- size of sprite in pixels (NOT double-pixels) ; LDR R11,save_inlog2bpp ; R11 = log2 ( bpp ) LDR R0,[R1,#spLBit] Debug so, "spLBit is ? = ",R0 LDR R2,[R1,#spRBit] Debug so, "spRbit is ? = ",R2 SUB R2,R2,R0 ADD R2,R2,#1 ; make inclusive Debug so, "R2 is ? = ",R2 LDR R0,[R1,#spWidth] Debug so, "Spwidth = ",R0 ADD R8,R2,R0,ASL #5 ; 32 bits per word Debug so, "R8 = ",R8 [ jpeg ; >>> old-format (ie pilot development) JPEG files are mode 20 sprites, with JPEG data. ; For such a sprite the 'width' is quoted as if log2bpp were 2, ie 4bpp sprites, ; so that Draw gets the right width for the sprite. But this means we must shift ; right by 2 rather than by r11, which will be 5. Debug gs, "X-size 1 = ",R8 LDR R14,is_it_jpeg CMP R14,#0 MOVEQ R8,R8,ASR R11 BEQ %FT01 ; It's JPEG - check for mode 20 or other. LDR R14,inmode CMP R14,#20 MOVEQ R8,R8,ASR #2 ; temp format - ASR by 2 MOVNE R8,R8,ASR R11 ; kosher new Medusa Sprite format - ASR by 5 Debug gs, "X-size 2 = ",R8 ; >>>> This option can be thrown away when we're sure that pilot-format JPEG files ; don't exist any more. ; ; Finally, JPEG files claim to have twice as many pixels as they actually do. ; ; This is in case we want to do interpolation in the X direction on scaling up. ; MOV R8,R8,LSL #1 ; R8 = no of pixels 1 | MOV R8,R8,ASR R11 ; R8 = no of pixels ] STR R8,save_inputxsize Debug so, "X-size 3 = ",R8 LDR R14,[R1,#spHeight] ADD R14,R14,#1 STR R14,save_inputysize ; ; do x-clipping ; Entry: R6 = x-magnification ; R8 = input x-size ; Exit: R9 = xleft ; [save_xcoord] = start x-coord on screen ; [save_xcount] = initial xcount ; [save_xsize] = output x-size ; Debug cc,"Do x-clipping",r6,r8 LDR R14,gwx0 SUBS R9,R14,R3 MOVLT R9,#0 ; R9 = no of pixels to skip on left ADD R14,R3,R9 STR R14,save_xcoord MUL R2,R8,R6 ; R2 = x-size * x-mag LDR R0,save_xdiv ; R0 = x-div TEQ R0,#0 BEQ diverror DivRem R8,R2,R0, R14 ; R8 = no of output pixels LDR R14,gwx1 ADD R14,R14,#1 SUB R14,R14,R3 CMP R8,R14 ; clip on right MOVGT R8,R14 SUBS R8,R8,R9 ; R8 = number of output pixels BLE exitbiggie ; none of sprite is visible STR R8,save_xsize LDR R14,save_xdiv MUL R10,R9,R14 ; R10 = initial count TEQ R6,#0 BEQ diverror DivRem R9,R10,R6, R14 ; R9 = initial INPUT pixel coord RSB R10,R10,R6 ; R10 = amount of 1st input pixel left STR R10,save_xcount Debug in,"xcoord,xleft,xcount,xsize =",#save_xcoord,R9,#save_xcount,#save_xsize ; ; do y-clipping ; Entry: [save_inputysize] = input y-size ; Exit: R10 = ybot ; [save_ycoord] = start y-coord on screen ; [save_ycount] = initial y-counter ; [save_ysize] = output y-size ; Debug cc,"Do y-clipping",r10 LDR R14,gwy0 SUBS R10,R14,R4 MOVLT R10,#0 ; R10 = no of pixels to skip at bottom ADD R14,R4,R10 STR R14,save_ycoord LDR R8,save_inputysize MUL R2,R8,R7 ; R2 = y-size * ymag LDR R0,save_ydiv TEQ R0,#0 BEQ diverror DivRem R8,R2,R0, R14 ; R8 = no of output pixels LDR R14,gwy1 ADD R14,R14,#1 SUB R14,R14,R4 CMP R8,R14 MOVGT R8,R14 SUBS R8,R8,R10 ; number of output pixels BLE exitbiggie STR R8,save_ysize LDR R14,save_ydiv MUL R8,R10,R14 ; R8 = initial count TEQ R7,#0 BEQ diverror DivRem R10,R8,R7, R14 ; R10 = initial INPUT pixel y-coord RSB R8,R8,R7 ; R8 = amount of first input pixel left STR R8,save_ycount Debug in,"ycoord,ybot,ycount,ysize =",#save_ycoord,R10,#save_ycount,#save_ysize ; ; update ChangedBox coords (if enabled) ; Entry: [save_xcoord],[save_ycoord],[save_xsize],[save_ysize] set up ; LDR R14,changedbox ; read in initialisation routine LDR R0,[R14],#4 TST R0,#1 ; enabled? BEQ %FT01 Push "R3-R10" LDR R3,save_xcoord ; coordinate after clipping LDR R4,save_ycoord ; ditto LDR R5,save_xsize ; size in output pixels LDR R6,save_ysize ; ditto LDR R7,Log2bpc LDR R8,Log2bpp SUBS R7,R7,R8 MOVNE R3,R3,ASR R7 ; unbodge double-pixel stuff MOVNE R5,R5,ASR R7 ADD R5,R3,R5 ADD R6,R4,R6 SUB R5,R5,#1 ; make inclusive SUB R6,R6,#1 LDMIA R14,{R7-R10} ; original box CMP R7,R3 MOVGT R7,R3 CMP R8,R4 MOVGT R8,R4 CMP R9,R5 MOVLT R9,R5 CMP R10,R6 MOVLT R10,R6 STMIA R14,{R7-R10} ; new box Pull "R3-R10" 01 ; ; get input address and shift ; Entry: R9,R10 = initial input pixel coord (within sprite) ; R11 = input log2bpp ; Exit: [save_inptr] --> first input word ; [save_inshift] = initial bit position ; [save_inoffset] = length of 1 sprite row (bytes) ; [save_masko] = offset from image to mask (0 ==> none) ; [save_maskinshift] = initial mask bit position ; [save_maskinptr] => first mask word ; [save_maskinoffset] = length of 1 mask row (bytes) ; [ jpeg ; for a JPEG sprite we'll need the actual coordinates, not the computed ; address, for the input data. Debug cc,"input coords",R9,R10 STR R9,in_x STR R10,in_y ] ; set up things for 1bpp masks too - we decide later whether to use it AND R14,R9,#31 ; mask is 1bpp, and there's no lh wastage ; so this is a lot simpler! STR R14,save_maskinshift ; save the inshift value for later Push "R9" ; save unadjusted R9 for later LDR R14,[R1,#spLBit] ADD R9,R14,R9,LSL R11 ; R9 = initial bit position AND R14,R9,#31 STR R14,save_inshift LDR R14,[R1,#spImage] [ debugso MOV R0, R14 Debug so,"Sprite Image at", R0 ] ADD R14,R1,R14 ; R14 --> sprite image LDR R0,[R1,#spTrans] ADD R0,R1,R0 ; R0 --> sprite mask Debug so,"Sprite mask at", R0 TST R5,#8 MOVEQ R0,R14 ; R0=R14 ==> no mask SUBS R0,R0,R14 BICEQ R5,R5,#8 ; R5 bit 3 ==> is there a mask? STR R0,save_masko LDR R2,[R1,#spHeight] SUB R10,R2,R10 ; R10 = no of rows from top LDR R3,save_inputxsize ; number of pixels(==number of bits) ANDS R4,R3,#&1F ; R4=number of bits MOVNE R4,#1 ; R4=1 if R3 MOD 31 is not zero ADD R4,R4,R3,LSR #5 ; R4=number of words MOV R4,R4,ASL #2 ; R4=number of bytes for full row STR R4,save_maskinoffset LDR R2,[R1,#spWidth] ADD R2,R2,#1 MOV R2,R2,ASL #2 ; R2 = line length STR R2,save_inoffset MOV R9,R9,ASR #5 ; R9 = word offset Pull "R3" ; pull unaltered R9 from earlier MOV R3,R3,ASR #5 ADD R11,R0,R3,ASL #2 ; R11= mask addr + byte offset MLA R3,R10,R4,R11 ; R3= #rows * bytes_per_row + maskaddr & byteoffset ; R3=> first mask input word LDR R11,[R1,#spImage] ADD R3,R3,R11 ADD R3,R3,R1 STR R3,save_maskinptr Debug so, "Maskinptr is = ",R3 ADD R14,R14,R9,ASL #2 MLA R14,R10,R2,R14 ; R14 --> first input word STR R14,save_inptr ; note that this points at the start of the last row of the sprite! Debug in,"inptr,inshift,inoffset,masko =",#save_inptr,#save_inshift,#save_inoffset,#save_masko ; ; get output address and shift ; Entry: [save_x/ycoord] = output x,y coord ; [screenstart], [ywindlimit], [linelength] set up ; Exit: [save_outptr] --> output address ; [save_outword] = initial marker bit position ; [save_outoffset] = line length ; LDR R3,save_xcoord LDR R4,save_ycoord LDR R11,Log2bpp ; R11 = output log2(bpp) LDR R14,ywindlimit SUB R4,R14,R4 ; R4 = no of rows down from top LDR R2,save_ecflimit ADD R14,R2,R4,ASL #3 ; R14 = offset into ecf table ADD R14,R14,#8 ; R14 --> initial ecf position STR R14,save_ecfptr LDR R14,linelength STR R14,save_outoffset LDR R2,screenstart MLA R10,R14,R4,R2 ; R10 = R2 + (R14 * R4) MOV R3,R3,ASL R11 AND R14,R3,#31 ; R14 = initial bit posn in word; MOV R3,R3,ASR #5 ADD R10,R10,R3,ASL #2 ; R10 --> output address STR R10,save_outptr MOV R0,#&80000000 MOV R0,R0,LSR R14 ; R0 = initial marker bit STR R0,save_outword Debug in,"Outptr, outword =",#save_outptr,#save_outword ; Register summary: ; ; R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 ; ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ; spriteptr xcoord ycoord gcol x-mag y-mag ; -x- -x- R3 R4 R6 R7 -x- -x- -x- log2bpp ; outoffset inoffset ydiv yadd ysize ycount ; inshift ; in1 in2 inptr outptr outword outmask xdiv xadd xsize xcount masko bpp inmask ; ; in1 in2 inptr outptr outword outmask xdiv xadd xsize xcount ttr bpp inbpp ; -x- -x- ecfptr ecfora ecfeor ; ; compute xadd, yadd ; ASSERT yadd<>R6 STR R7,save_yadd ; yadd = size of input pixels (y-mag) LDR R14,save_xdiv ADD xadd,R14,R6 ; xadd = save_xdiv + xmag STR xadd,save_xadd MOV R14,#-1 ; bit set ==> don't touch! STR R14,save_outmask MOV R14,#0 STR R14,save_vcount ; bodge for 1st row ; Jump to the C code run time compiler B new_putscaled_compiler ;----------------------------------------------------------------------------- ; Function to validate the pixel translation table, remapping as required ; to take into account depth changes etc. ; ; in R7 -> pixtrans table supplied to call ; out R0 -> error block (V set) ; R7 -> pixtrans table (may have been relocated!) ;----------------------------------------------------------------------------- ; The following rules apply: ; ; 1/2/4/8 to 1/2/4/8 bpp : no change ; 8 to 16/32 bpp : use mungeGCOL8toXX routine, applied here ; 16/32 to 1/2/4/8 bpp : only valid table is a CTrans 32K table providing 5 bit mappings ; 16 to 16 bpp : no table allowed ; 32 to 32 bpp : no table allowed ; 16/32 to 32/16 bpp : no table, but a munge function will be applied instead ; (nb, this is called during plotting, since there's no table ; to modify in advance) ; ; ColourTrans uses the following structure for the return from Select/GenerateTable: ; ; Word 0 : &33324B2E "32K." ; Word 4 : Pointer to the 32K table ; Word 8 : &33324B2E "32K." ; checktrans Entry LDR LR,save_inbpp MOV R8,#1 MOV R8,R8,ASL LR ; R8 = number of input colours LDR R9,BPP ; R9 = output depth MOV R10,#0 ; R10 = index / counter CMP LR,#16 BCC checktrans1 ; branch if input is 8bpp or below ;now check out the following: ; 16 -> 16 : \ ; ; 32 -> 32 : \__ A table should never be used, however if one is presented ; 16 -> 32 : / it will be discarded but not faulted here. ; 32 -> 16 : / ; 16/32 -> 8 or lower : table must be CTrans 32K type CMP R9,#16 BCS checktrans_ignorettr ;this is 16/32 to 8/lower, so check for a 32K table [ jpeg ; JPEG possibility - might get 32bpp data into small target, with no table. LDR LR,is_it_jpeg TEQ LR,#0 ; 0 -> not JPEG BNE checktrans_exitok ] LDR LR,word32k LDR R8,[R7,#0] CMP R8,LR BNE checktrans_giveerror LDR R8,[R7,#8] CMP R8,LR BNE checktrans_giveerror B checktrans_exitok checktrans_ignorettr MOVS R7,#0 B checktrans_exitok word32k = "32K." checktrans1 CMP R9,#16 ; are we outputting to >= 16 bit per pixel BLT checktrans_old ; if not then ignore the remapping ; For backwards compatibility we attempt to remap the colours by taking the GCOL ; byte which is in VIDC 1 format and convert it to a word value sensible for this ; depth of display. ; The functions which decode this byte now look for a word value which is then ; combined into the scan line being rendered. Push "R0-R2,R9" LDR R9,Log2bpp SUB R9,R9,#3 ; convert the output Log2 bpp into a sensible index for conversion [ widetrans ; don't need to do anything for 32bpp, for 15bpp entries need to be moved to ; be word based. Problem is that CTrans produces a half word table, but the ; plot code here expects them to be words LDR R14,trns_flags2 ; get the flag word TST R14,#flg2_widetrans ; if set we don't need to do the expansion BEQ no_widetrans ; skip if new bit is unset TSTNE R9,#2 ; check for 32bpp (note the the SUB #3 above) LDMNEFD R13!,{R0-R2,R9} ; it is 32bit - reload registers... BNE checktrans_exitok ; ...and go straight out Debug so,"We're gonna scribble all over newtranstable 1" ;now do the expansion needed for 15bpp ADR R2,newtranstable ; new table space MOV R8,R8,LSR #1 ; loading a word collects two entries, so ; halve the number of colours to do expand_15bpp SUBS R8,R8,#1 ; decrement count Pull "R0-R2,R9",MI ; when we go minus we've finished, reload registers... ADRMI R7,newtranstable ; ...change the translation table pointer... BMI checktrans_exitok ; ...and get out of here! LDR R0,[R7,R8,LSL #2] ; load two values from original ctrans table MOV LR,R0,LSR #16 ; put the second value in the low 16 bits of LR EOR R0,R0,LR,LSL #16 ; and remove the second value from R0 MOV R8,R8,LSL #1 ; double the output pointer cos we've two words to store STR R0,[R2,R8,LSL #2] ; store the first word ADD R8,R8,#1 ; increment STR LR,[R2,R8,LSL #2] ; and store the second word MOV R8,R8,LSR #1 ; and bring the output pointer back to normal B expand_15bpp ; back to the loop to check for completion no_widetrans ] ADR R2,newtranstable ; -> new translation table (passed out on exit) converttrans_new SUBS R8,R8,#1 Pull "R0-R2,R9",MI ; preserve important registers ADRMI R7,newtranstable BMI checktrans_exitok LDRB R0,[R7,R8] MOV LR,PC ADD PC,PC,R9,LSL #2 ; call function to remap the colour byte STR R0,[R2,R8,LSL #2] ; and store the converted value B converttrans_new ; outbpp = 3 (and inbpp < 4 log2bpp) B mungeGCOL8to16 ; outbpp = 4 ; Fall mungeGCOL8to32 ; outbpp = 5 ; thru mungeGCOL8to32 Push "R2,LR" ; fedcba98 76543210 fedcba98 76543210 ; R0 = bbggrrtt MOV R2,R0,LSL #4 ; R2 = bbgg rrtt ORR R2,R2,R0,LSL#10 ; R2 = bb ggrrXXgg rrtt ORR R2,R2,R0,LSL#16 ; R2 = bbggrrXX ggrrXXgg rrtt AND LR,R0,#&03 ; LR = tt BIC R2,R2,#&3F0000 ; R2 = bb ggrrXXgg rrtt BIC R2,R2,#&3F00 ; R2 = bb gg rrtt ORR R2,R2,R14,LSL #12 ; R2 = bb ggtt rrtt ORR R0,R2,R14,LSL #20 ; R0 = bbtt ggtt rrtt ORR R0,R0,R0,LSR #4 ; R0 = bbttbbtt ggttggtt rrttrrtt Pull "R2,PC" mungeGCOL8to16 [ vidc20 ; fedcba9876543210fedcba9876543210 Push "R2,LR" ; R0 = bbggrrtt MOV LR,R0,LSL #30 ; LR = tt ORR R2,LR,R0,LSR #6 ; R2 = tt bb ORR LR,LR,R0,LSR #4 ; LR = tt bbgg BIC LR,LR,#&0C ; LR = tt gg MOV R0,R0,LSL #1 ; R0 = bbggrrtt AND R0,R0,#&1E ; R0 = rrtt ORR R0,R0,LR,ROR #24 ; R0 = ggtt rrtt ORR R0,R0,R2,ROR #19 ; R0 = bbtt ggtt rrtt ;and now fill in the bottom bit of the colour MOV LR,LR,LSR #30 ; LR = tt AND LR,LR,#1 ; LR = t ORR LR,LR,LR,LSL #5 ; LR = t t ORR LR,LR,LR,LSL #5 ; LR = t t t ORR R0,R0,LR ; R0 = bbtttggtttrrttt Pull "R2,PC" | ; Tim's function for remapping the packed GCOL number to a value ; suitable for display memory. AND R1,R0,#4_000033 ORR R0,R1,R0,LSL #4 AND R1,R0,#4_030330 EOR R1,R1,R1,LSR #6 EOR R1,R1,R1,LSR #4 AND R1,R1,#4_000330 EOR R0,R0,R1,LSL #4 MOV PC,LR ] checktrans_old SUBS R8,R8,#1 ; loop until -ve value BMI checktrans_exitok ;fix bug that was making this routine inactive! AMG LDRB LR,[R7,R10] ; get a byte from the table MOVS LR,LR,LSR R9 ; if any bits are non-zero that shouldn't be then complain BEQ checktrans_old checktrans_giveerror Debug so, "We think the ttable is duff (XXX)" ADRL R0,ErrorBlock_BadTranslation addr R1,Title BL copy_error_one ; returns error block with V set, for bad table EXIT checktrans_exitok CLRV EXIT ; some of these values used in SprTrans mc_gcol * 2_00000111 ; bits 0..2 of R5 mc_hasmask * 2_00001000 ; bit 3 of R5 mc_ttr * 2_00010000 ; R7 mc_plotmask * 2_00100000 ; R0 mc_transformed * 2_01000000 ; 0 if scaled, 1 if transformed sprite plot [ ignore_ttr mc_ttrispalette * 2_10000000 ; use palette instead of ttr (ttr points at it) ] mcb_inbpp * 8 mcb_outbpp * 16 mcb_sprtype * 24 xxx * 2 BNE * &1A000000 BCS * &2A000000 BCC * &3A000000 BMI * &4A000000 BPL * &5A000000 BVS * &6A000000 BVC * &7A000000 BHI * &8A000000 BLS * &9A000000 BGE * &AA000000 BLT * &BA000000 BGT * &CA000000 BLE * &DA000000 BAL * &EA000000 BNV * &FA000000 ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SpriteOp_AppendSprite ; --------------------- ; Entry: R0 = reason code ; R1 = areaCBptr ; R2 = name/ptr of 1st sprite ; R3 = name/ptr of 2nd sprite ; R4 = flags (0 ==> merge horizontally, else vertically) ; Exit: 1st sprite is result of merging both ; 2nd sprite is deleted ; scratch space used (no extra memory apart from that) ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Go_AppendSprite Push "R1-R11,LR" CLRPSR I_bit, R14 ; re-enable interrupts BL findsprite STRVC R1,sp1_areaCBptr ; R1 may be updated if system area MOVVC R5,R2 ; R5 --> first sprite MOVVC R2,R3 BLVC findsprite ; R2 --> second sprite BVS %FT99 ; ; Algorithm: ; check that sprites are compatible - if not, give error/adjust sprite ; move sprite2 to end of sprites ; move sprite1 just before sprite2 ; eliminate sprite2 header ; if masked, swap(mask1,data2) ; if R4=0 (horiz. merge) interleave rows of data (& then masks if nec) ; reclaim wastage (depends on h/v merge) of data + masks ; correct sprite end ptrs, no of sprites etc. ; correct size of sprite ; TEQ R2,R5 ; same sprite? BEQ badappend LDR R14,[R2,#spMode] LDR R0,[R5,#spMode] Debug ag,"Modes are",R0,R14 ; Merged from 0.62 (GPS) TEQ R0,R14 BNE badappend ; can't merge different modes ; ; check that rows/columns are same (depends on R4) ; TEQ R4,#0 ; R4=0 ==> horiz merge (check rows) BNE %FT01 LDR R14,[R2,#spHeight] LDR R0,[R5,#spHeight] Debug ag,"Heights are",R0,R14 ; Merged from 0.62 (GPS) TEQ R0,R14 BEQ %FT02 badappend Debug ag,"Bad append, setting up error block and exiting" ADR R0, ErrorBlock_BadAppend addr r1, Title BL copy_error_one ; Always sets the V bit B %FT99 MakeSpriteErrorBlock BadAppend,,AppErr 01 Push "R2" BL getspritewidth ; R2 --> sprite defn, R3 = width MOV R2,R5 MOV R6,R3 BL getspritewidth Pull "R2" Debug ag,"Widths are",R3,R6 ; Merged from 0.62 (GPS) TEQ R3,R6 BNE badappend 02 ; ; if one has a mask & the other doesn't, create mask ; LDR R14,[R2,#spImage] LDR R0,[R2,#spTrans] EORS R6,R0,R14 MOVNE R6,#-1 ; R6 = (2nd sprite has mask) LDR R14,[R5,#spImage] LDR R0,[R5,#spTrans] EORS R0,R0,R14 MOVNE R0,#-1 TEQ R0,R6 ; if same, skip next bit BEQ %FT01 Debug ag,"One of the sprites has no mask" ; Merged from 0.62 (GPS) Push "R2" TEQ R6,#0 MOVNE R2,R5 ; if 2nd sprite has mask, enmask 1st MOV R0,#SpriteReason_CreateMask ADD R0,R0,#&200 ; since R2 --> sprite definition BL Go_SpriteOp ; call MOS version Pull "R2" BVS %FT99 ; error (eg. memory full) 01 ; ; move sprites to end of memory (need to get addresses back again) ; LDMFD R13,{R1-R3} BL findsprite MOVVC R5,R2 ; R5 --> first sprite MOVVC R2,R3 BLVC findsprite ; R2 --> second sprite BVS %FT99 Debug ag,"First sprite is at",R5 ; Merged from 0.62 (GPS) Debug ag,"Second sprite is at",R2 ; Merged from 0.62 (GPS) LDR R3,[R1,#saFree] ; R3 --> end of sprites Debug ag,"End of sprite area is",R3 ; Merged from 0.62 (GPS) ADD R3,R1,R3 MOV R1,R2 ; R1 --> sprite2 LDR R2,[R1,#spNext] ADD R2,R1,R2 ; R2 --> end of sprite2 Debug ag,"End of sprite2 is",R2 ; Merged from 0.62 (GPS) BL swapblocks MOV R6,R1 ; R6 --> sprite2 (in new position) CMP R5,R2 ; if sprite1 was after sprite2 DebugIf CS,ag,"Sprite1 was after sprite2" ; Merged from 0.62 (GPS) SUBCS R14,R3,R1 SUBCS R5,R5,R14 ; move down by (R3-R1) ie. sprite2 size MOV R3,R1 MOV R1,R5 ; R1 --> sprite1 LDR R2,[R1,#spNext] ADD R2,R1,R2 Debug ag,"End of sprite1 is",R2 ; Merged from 0.62 (GPS) BL swapblocks ; R1 --> sprite1 (in new position) ; ; note the sprite mode of sprite 1 (should = sprite2) ; and the spNext parameter of sprite 2 ; LDR R2, [R1,#spMode] ; Merged from 0.62 (GPS) STR R2, sp_mode ; Merged from 0.62 (GPS) LDR R2, [R6,#spNext] ; Merged from 0.62 (GPS) STR R2, sp2_next ; Merged from 0.62 (GPS) ; ; note down sprite1's header ; MOV R2,R1 ADRL R3,sp1_data BL savespriteheader ; sets up R5,R7-R11 ; ; note down sprite2's header, and delete it ; MOV R2,R6 ADRL R3,sp2_data BL savespriteheader ; sets up R5,R7-R11 MOV R1,R6 ; destination ADD R2,R1,R10 ; source (image) LDR R3,[R1] SUB R3,R3,R10 ; counter BL copyblock ; R3 bytes from R2 to R1 MOV R2,R6 ; R2 --> sprite2 image ; ; if there is a mask (new or old), swap (mask1, image2) & do both sets of data ; SUBS R11,R11,R10 ; offset from image to mask (sprite2) BEQ %FT01 Debug ag,"These sprites have masks!" ; Merged from 0.62 (GPS) LDR R1,sp1_header LDR R14,[R1,#spTrans] ; R1 --> start of sprite1 mask ADD R1,R1,R14 ; R2 --> sprite2 image ADD R3,R2,R11 ; R3 --> end of sprite2 image BL swapblocks ; R2, R1 --> image2, mask1 Push "R1,R3" MOV R3,R1 ; R3 --> end of image2 LDR R1,sp1_header SUB R14,R3,R1 STR R14,sp1_trans ; for later LDR R14,sp1_image ADD R1,R1,R14 ; R1 --> start of image1 BL mergeblocks ; takes note of R4 Pull "R1,R2" ; R1 --> mask1, R2 --> mask2 LDR R3,sp2_trans LDR R14,sp2_next ; Merged from 0.62 (GPS) SUB R3,R14,R3 ; R3 = size of mask2 (poss+) - From 0.62 (GPS) ADD R3,R2,R3 ; R3 --> end of mask2 LDR R14,sp1_header SUB R14,R1,R14 Push "R14" ; merged from 0.62 (GPS) LDR R14, sp_mode ; merged from 0.62 (GPS) MOVS R14, R14, LSR #27 ; Old or new? merged from 0.62 (GPS) Pull "R14" ; merged from 0.62 (GPS) DebugIf EQ,ag,"Old format mergeblocks to be executed" ; merged from 0.62 (GPS) BLEQ mergeblocks ; if old format merged from 0.62 (GPS) DebugIf NE,ag,"New format mergeblocks to be executed" ; merged from 0.62 (GPS) BLNE maskmergeblocks ; if new format merged from 0.62 (GPS) B %FT02 ; ; otherwise just merge the images ; 01 Debug ag,"These sprites don't have masks" ; merged from 0.62 (GPS) LDR R1,sp1_header LDR R14,sp1_image ADD R1,R1,R14 ; R1 --> sprite1 image LDR R2,sp2_header ; R2 --> sprite2 image LDR R14,sp2_imagesize ADD R3,R2,R14 ; R3 --> end of sprite2 image BL mergeblocks 02 ; ; now rationalise the final image - shunt all bits down ; Debug ag,"Now rationalising..." ; merged from 0.62 (GPS) LDR R2,sp1_header LDR R3,sp1_image ADD R1,R2,R3 MOV R3,R1 BL chunterblock ; R1 --> start of block LDR R0,sp1_image LDR R14,sp1_trans TEQ R14,R0 ; was there a mask? BEQ %FT03 ; if not, skip the next bit SUB R14,R3,R2 ; merged from 0.62 (GPS) STR R14,[R2,#spTrans] ; point to mask merged from 0.62 (GPS) LDR R14, sp_mode ; merged from 0.62 (GPS) MOVS R14, R14, LSR #27 ; New or old format mask? merged from 0.62 (GPS) DebugIf EQ,ag,"Old format chunterblock to be executed" ; merged from 0.62 (GPS) BLEQ chunterblock ; process old format mask merged from 0.62 (GPS) DebugIf EQ,ag,"New format chunterblock to be executed" ; merged from 0.62 (GPS) BLNE maskchunterblock ; process new format mask merged from 0.62 (GPS) 03 SUB R14,R3,R2 STR R14,[R2,#spNext] ; sprite size LDR R2,sp1_areaCBptr SUB R14,R3,R2 STR R14,[R2,#saFree] ; area size LDR R14,[R2,#saNumber] SUB R14,R14,#1 ; sprite2 deleted STR R14,[R2,#saNumber] 99 MOVVC r0, #35 ; made conditional to stop error block being junked (GPS) Pull "R1-R11,PC" ; Chunterblock ; ; Entry: R1 --> input data ; R3 --> output data ; R4 = 0/1 (horizontal/vertical merge) ; [sp1/2_data] = original state of sprites ; [sp1/2_imagesize] = amount of data to process ; Exit: R1 --> end of input ; R3 --> end of output ; [[sp1_header]] contains correct width, height, lbit, rbit ; sprite data crunched into shape ; chunterblock Push "R5-R11,LR" Debug ag,"Chunterblock entry R1,R3,R4",R1,R3,R4 TEQ R4,#0 BNE %FT04 LDR R11,sp1_height ; R11 = no of rows to do (-1) 01 MOV R10,R3 ; original output ptr LDR R5,sp1_width ; R5 = no of intermediate words LDR R6,sp1_lbit ; R6 = input bit wastage on left MOV R7,#0 ; R7 = no of bits set up (none) LDR R8,sp1_rbit ; bit non-wastage on right BL chunterrow ; R7 = no of bits set up in last word LDR R5,sp2_width LDR R6,sp2_lbit LDR R8,sp2_rbit BL chunterrow TEQ R7,#0 MOVEQ R7,#32 ADDNE R3,R3,#4 ; skip last word if anything in it SUBS R11,R11,#1 BPL %BT01 B setupwidth 04 LDR R11,sp1_height 01 LDR R5,sp1_width ; R5 = no of intermediate words LDR R6,sp1_lbit ; R6 = input bit wastage on left MOV R7,#0 ; R7 = no of bits set up (none) LDR R8,sp1_rbit ; bit non-wastage on right BL chunterrow ; R7 = no of bits set up in last word TEQ R7,#0 ADDNE R3,R3,#4 ; skip last word if anything in it SUBS R11,R11,#1 BPL %BT01 LDR R11,sp2_height 02 MOV R10,R3 LDR R5,sp2_width ; R5 = no of intermediate words LDR R6,sp2_lbit ; R6 = input bit wastage on left MOV R7,#0 ; R7 = no of bits set up (none) LDR R8,sp2_rbit ; bit non-wastage on right BL chunterrow ; R7 = no of bits set up in last word TEQ R7,#0 MOVEQ R7,#32 ADDNE R3,R3,#4 ; skip last word if anything in it SUBS R11,R11,#1 BPL %BT02 LDR R14,sp1_height LDR R0,sp2_height ADD R14,R14,R0 ADD R14,R14,#1 ; since each is <no of rows>-1 STR R14,[R2,#spHeight] ; ; R2 --> sprite header, R3-R10 = width of 1 row, R7 = spRBit+1, spLBit=0 ; setupwidth SUB R14,R3,R10 MOV R14,R14,LSR #2 SUB R14,R14,#1 STR R14,[R2,#spWidth] ; spWidth = no of words - 1 MOV R14,#0 STR R14,[R2,#spLBit] ; spLBit = 0 SUB R7,R7,#1 STR R7,[R2,#spRBit] ; spRBit = R7-1 Debug ag,"Chunterblock exit R1,R3,R4",R1,R3,R4 Pull "R5-R11,PC" ; Maskchunterblock ; ; Entry: R1 --> input data ; R3 --> output data ; R4 = 0/1 (horizontal/vertical merge) ; [sp1/2_data] = original state of sprites ; [sp1/2_imagesize] = amount of data to process ; Exit: R1 --> end of input ; R3 --> end of output ; [[sp1_header]] contains correct width, height, lbit, rbit ; sprite data crunched into shape ; ; NOTE: Only called for new format (1bpp) sprites ; maskchunterblock Push "R5-R11,LR" Debug ag,"Chunterblock entry R1,R3,R4",R1,R3,R4 TEQ R4,#0 ; Vertical or horizontal join? BNE %FT04 ; Go elsewhere if vertical join LDR R11,sp1_height ; R11 = no of rows to do (-1) 01 MOV R10,R3 ; original output ptr LDR R8,sp1_rbit LDR R5,sp1_width ; R5 = no of intermediate words BL FindMaskWidth ; Alters R5 & sets up R8 to Rbit MOV R6,#0 ; Lbit wastage = 0 MOV R7,#0 ; R7 = no of bits set up (none) BL chunterrow ; R7 = no of bits set up in last word LDR R8,sp2_rbit LDR R5,sp2_width BL FindMaskWidth ; Alters R5 & sets up R8 to Rbit for mask MOV R6,#0 ; Lbit wastage always = 0 BL chunterrow TEQ R7,#0 MOVEQ R7,#32 ADDNE R3,R3,#4 ; skip last word if anything in it SUBS R11,R11,#1 ; One line less to do... BPL %BT01 ; Do the next one Debug ag,"Maskchunterblock exit R1,R3,R4",R1,R3,R4 Pull "R5-R11,PC" 04 LDR R11,sp1_height 01 LDR R8,sp1_rbit LDR R5,sp1_width ; R5 = no of intermediate words BL FindMaskWidth ; Convert R5 & set up R8 MOV R6,#0 ; Lbit is zero for this format sprite MOV R7,#0 ; R7 = no of bits set up (none) BL chunterrow ; R7 = no of bits set up in last word TEQ R7,#0 ADDNE R3,R3,#4 ; skip last word if anything in it SUBS R11,R11,#1 BPL %BT01 LDR R11,sp2_height 02 MOV R10,R3 LDR R8,sp2_rbit LDR R5,sp2_width ; R5 = no of intermediate words BL FindMaskWidth MOV R6,#0 ; Lbit = 0 always MOV R7,#0 ; R7 = no of bits set up (none) BL chunterrow ; R7 = no of bits set up in last word TEQ R7,#0 MOVEQ R7,#32 ADDNE R3,R3,#4 ; skip last word if anything in it SUBS R11,R11,#1 BPL %BT02 Pull "R5-R11,PC" ; ; R2 --> sprite header, R3-R10 = width of 1 row, R7 = spRBit+1, spLBit=0 ; masksetupwidth SUB R14,R3,R10 MOV R14,R14,LSR #2 SUB R14,R14,#1 STR R14,[R2,#spWidth] ; spWidth = no of words - 1 MOV R14,#0 STR R14,[R2,#spLBit] ; spLBit = 0 SUB R7,R7,#1 STR R7,[R2,#spRBit] ; spRBit = R7-1 Pull "R2,R5-R11,PC" ; Chunterrow ; ; Entry: R1 --> input data ; R3 --> output data (some of 1st word may be valid) ; R5 = no of whole words to do (excluding the end 2) ; R6 = bit offset of 1st valid bit in input word ; R7 = bit offset of 1st unused bit in output word ; R8 = bit offset of last used bit in output word ; Exit: R1 --> end of input data ; R3 --> end of output data ; R7 = no of valid bits in [R3] - 0..31 (if 32, output word & go on) ; chunterrow Push "R0,R5,R6,R8-R10,LR" Debug ag,"Chunterrow entered R1,R3,R5-R8",R1,R3,R5,R6,R7,R8 ADD R8,R8,#1 ; make exclusive LDR R0,[R1],#4 MOV R0,R0,LSR R6 LDR R14,[R3] RSB R10,R7,#32 ; for later MOV R14,R14,LSL R10 MOV R14,R14,LSR R10 ORR R14,R14,R0,LSL R7 TEQ R5,#0 RSBEQ R9,R6,R8 ; R9 = no of valid bits shifted in RSBNE R9,R6,#32 ADD R7,R7,R9 CMP R7,#32 SUBCS R7,R7,#32 STRCS R14,[R3],#4 MOVCS R14,R0,LSR R10 ; R14 = rest of input word RSB R9,R7,#32 ; R9 = no of bits to be carried over ; ; R14 = output word, R7 = no of valid bits, R1 --> input (from bit 0) ; TEQ R5,#0 BEQ %FT05 ; 1st word = last - we've finished! MOV R6,#0 SUBS R5,R5,#1 BEQ %FT04 ; middle section is null TEQ R7,#0 BNE %FT02 01 LDR R14,[R1],#4 ; do this the quick way! STR R14,[R3],#4 SUBS R5,R5,#1 BNE %BT01 MOV R14,#0 ; no more bits remaining! B %FT04 02 LDR R0,[R1],#4 ; R0 = input word - from bit 0 ORR R14,R14,R0,LSL R7 STR R14,[R3],#4 MOV R14,R0,LSR R9 ; R14 = remaining bits of R0 SUBS R5,R5,#1 BNE %BT02 ; ; R1 --> final word of input, R3 --> next output word ; R14 = output word, R7 = no of valid bits, R6 = first valid bit in [R1] ; 04 LDR R0,[R1],#4 ; read final word MOV R0,R0,LSR R6 SUB R8,R8,R6 ; no of bits used in R0 ORR R14,R14,R0,LSL R7 ADD R7,R7,R8 CMP R7,#32 SUBCS R7,R7,#32 STRCS R14,[R3],#4 MOVCS R14,R0,LSR R9 05 TEQ R7,#0 ; avoid splattering next word of input STRNE R14,[R3] ; for next time Debug ag,"Chunterrow exit R1,R3,R5-R8",R1,R3,R5,R6,R7,R8 Pull "R0,R5,R6,R8-R10,PC" ; Savespriteheader ; ; Entry: R2 --> sprite definition ; R3 --> where to put data ; Exit: R5,R7-R11 = width,height,Lbit,Rbit,Image,Trans ; also copied to [R3] ; [R3,#header] = address of header block ; [R3,#imagesize] = size of sprite image (excl. mask) ; savespriteheader Push "R2,LR" STR R2,[R3,#sp1_header-sp1_data] LDR R14,[R2],#spWidth LDMIA R2,{R5,R7-R11} ; width,height,Lbit,Rbit,Image,Trans STMIA R3,{R5,R7-R11} Debug ag,"Sprite header",R5,R7,R8,R9,R10,R11 LDR R14,[R1,#spNext] ; Try & work out the image size TEQ R10,R11 ; Hang on, but is there a mask? LDRNE R14,[R1,#spTrans] ; Yes, so we have to work it out different SUB R14,R14,R10 ; Convert the offset to a 'size' STR R14,[R3,#sp1_imagesize-sp1_data] Pull "R2,PC" ; Getspritewidth ; ; Entry: R2 --> sprite defn ; Exit: R3 = sprite width (bits) ; getspritewidth Push "LR" LDR R14,[R2,#spLBit] LDR R3,[R2,#spRBit] SUB R3,R3,R14 ADD R3,R3,#1 ; make inclusive LDR R14,[R2,#spWidth] ADD R3,R3,R14,LSL #5 ; 32 bits per word Debug ag,"Getspritewidth thinks the sprite width (bits) is",R3 Pull "PC" ; Swapblocks ; ; Entry: R1 --> start of 1st block ; R2 --> start of 2nd block (consecutive) ; R3 --> end of 2nd block ; Exit: blocks swapped over ; R1 --> start of 1st block (after 2nd block) ; R2 --> start of 2nd block ; swapblocks Push "R3,LR" Debug mg,"Swap blocks: ",R1,R2,R3 TEQ R1,R2 TEQNE R2,R3 ; Z set if either block is null SUB R14,R3,R2 ; R14 = length of 2nd block MOV R2,R1 ADD R1,R1,R14 Pull "R3,PC",EQ ; ensure R1,R2 set up correctly on exit Push "R1,R2" MOV R1,R2 MOV R2,R3 BL reverseblock LDR R2,[R13,#0*4] ; reverse new 2nd block BL reverseblock MOV R1,R2 LDR R2,[R13,#2*4] ; reverse new 1st block BL reverseblock Pull "R1-R3,PC" ; Reverse block ; ; Entry: R1 --> start of block ; R2 --> end of block (JUST AFTER) ; Exit: block reversed (words) ; reverseblock Push "R1-R4,LR" 01 CMP R1,R2 LDRCC R3,[R1] LDRCC R4,[R2,#-4]! STRCC R3,[R2] STRCC R4,[R1],#4 BLT %BT01 Pull "R1-R4,PC" ; Copyblock ; ; Entry: R1 --> destination ; R2 --> source ; R3 = no of bytes (must be a whole number of words) ; copyblock Debug mg,"Copy block (to, from, count): ",R1,R2,R3 TEQ R1,R2 ; check for null copy TEQNE R3,#0 MOVEQ PC,LR Push "R1-R3,LR" CMP R1,R2 BCS copyup 01 LDR R14,[R2],#4 STR R14,[R1],#4 SUBS R3,R3,#4 BGT %BT01 Pull "R1-R3,PC" copyup ADD R1,R1,R3 ADD R2,R2,R3 01 LDR R14,[R2,#-4]! STR R14,[R1,#-4]! SUBS R3,R3,#4 BGT %BT01 Pull "R1-R3,PC" ; Mergeblocks ; ; Entry: R1,R2,R3 --> delimit 2 blocks (consecutive) ; R4 = 0/1 (merge horizontally/vertically) ; mergeblocks Debug mg,"Merge blocks: ",R1,R2,R3 TEQ R4,#0 MOVNE PC,LR ; vertical merge Push "R1-R3,R5-R6,LR" LDR R5,sp1_width ADD R5,R5,#1 MOV R5,R5,LSL #2 ; R5 = size of 1 row (bytes) LDR R6,sp2_width ADD R6,R6,#1 MOV R6,R6,LSL #2 ; R6 = size of 1 row (bytes) 01 ADD R1,R1,R5 CMP R1,R2 BCS %FT02 ; no more to do ADD R3,R2,R6 BL swapblocks ADD R1,R2,R6 MOV R2,R3 B %BT01 02 Pull "R1-R3,R5-R6,PC" ; Maskmergeblocks ; ; Entry: R1,R2,R3 --> delimit 2 blocks (consecutive) ; R4 = 0/1 (merge horizontally/vertically) ;NOTE: Only called for new format sprites ; maskmergeblocks Debug mg,"Mask merge blocks: ",R1,R2,R3 TEQ R4,#0 MOVNE PC,LR ; vertical merge, so return Push "R1-R3,R5-R6,R8,LR" LDR R8,sp2_rbit LDR R5,sp2_width BL FindMaskWidth ;Convert R5 ADD R6,R5,#1 MOV R6,R6,LSL #2 ; R6 = size of 1 row (bytes) Debug ag,"Size of 1 row of sprite2 is (bytes)",R6 LDR R8,sp1_rbit LDR R5,sp1_width BL FindMaskWidth ;Convert R5 ADD R5,R5,#1 MOV R5,R5,LSL #2 ; R5 = size of 1 row (bytes) Debug ag,"Size of 1 row of sprite1 is (bytes)",R5 01 ADD R1,R1,R5 CMP R1,R2 BCS %FT02 ; no more to do ADD R3,R2,R6 BL swapblocks ADD R1,R2,R6 MOV R2,R3 B %BT01 02 Pull "R1-R3,R5-R6,R8,PC" ; FindMaskWidth - convert spWidth for data to spWidth for mask (1bpp masks) ; ; NOTE: This routine should be similar to GetMaskspWidth in VduGrafH except it does ; not return the updated PSR ; ; Internal routine. ; ; in: R5 = spWidth (ie width in words-1) ; R8 = spRbit ; (expects R2->sprite info) ; ; out: R5 = spWidth (words -1) for mask data ; R8 = Last bit (spRBit) used in mask data ; MUST only be called for new format sprites FindMaskWidth ROUT Push "R0, LR" Debug ag,"Entered GetMaskspWidth with R5,R8",R5,R8 LDR LR, sp_mode ; fetch the sprite mode MOVS LR, LR, LSR #27 ; isolate the sprite type and test for =0 Pull "R0, PC",EQ ; if an old format sprite, return R5 unchanged ; treat any T>max sprites as 32bpp CMP LR, #SpriteType_MAX MOVCS LR, #SpriteType_Substitute ; bugfix 9/8/93: get log2bpp this way ADRL R0, NSM_bpptable LDRB LR, [R0, LR] ; get the log2bpp to LR RSB LR, LR, #5 ; and change to 5-log2bpp MOV R5, R5, LSL LR ; number of pixels for full words RSB LR, LR, #5 ; now switch back to log2bpp ADD R8, R8, #1 ADD R5, R5, R8, LSR LR 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 Debug ag,"Left GetMaskspWidth with R5,R8",R5,R8 Pull "R0, PC" ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SpriteOp_CheckSpriteArea ; ------------------------ ; Entry: R0 = reason code ; R1 = areaCBptr ; R10 & R11 stacked ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Go_CheckSpriteArea MOVS r0, r0, LSR #8 ; system area sprites historically not checked MOVEQ pc, lr Push "r1-r5, lr" ; 6 regs + r0/r10/r11 to mess with, total 9 TST r1, #3 ; at least need an aligned area to start with BNE %FT99 ASSERT SpriteAreaCBsize = (4 * 4) LDMIA r1, {r2-r5} Debug so, "Read saEnd/saNumber/saFirst/saFree",r2,r3,r4,r5 ORR r14, r4, r5 TST r14, #3 BNE %FT99 ; saFirst or saFree not word aligned CMP r4, r5 ; saFirst > saFree CMPLS r5, r2 ; saFree > saEnd BHI %FT99 ADD r11, r1, r5 ; abs address of end of used portion ADD r10, r1, r2 ; abs address of end of entire area B %FT40 10 ; For each sprite, do the following checks Debug so, "Contemplating sprite at",r1 ADD r0, r1, #SpriteCBsize CMP r0, r11 ; range check the header before reading from it BHI %FT99 Debug so," + passed control block accessible" CheckAlignedAndWithin r1,spNext,r11,r0 Debug so," + passed spNext within used area test" CheckAlignedAndWithin r1,spImage,r10,r0 Debug so," + passed spImage within area test" CheckAlignedAndWithin r1,spTrans,r10,r0 Debug so," + passed spTrans within area test" LDR r4, [r1, #spLBit] LDR r0, [r1, #spRBit] ORR r0, r0, r4 CMP r0, #32 BCS %FT99 Debug so," + passed LBit/RBit bit count test" LDR r5, [r1, #spMode] ASSERT SpriteType_Old = 0 MOVS r0, r5, LSR#27 TEQNE r4, #0 BNE %FT99 Debug so," + passed if new type sprite has LBit=0" LDR r0, [r1, #spWidth] LDR r4, [r1, #spHeight] ADD r0, r0, #1 MOV r0, r0, LSL#2 ; width in bytes because bw = (ww + 1) x 4 MLA r4, r0, r4, r0 ; image bytes because bw x (h + 1) = (bw x h) + bw Debug so," ...(w + 1) x (h + 1) in bytes",r4 LDR r0, [r1, #spImage] LDR r2, [r1, #spTrans] TEQ r0, r2 ; check if there's a mask BEQ %FT20 Debug so," ...has a mask" SUB r14, r2, r0 CMP r14, r4 BCC %FT99 Debug so," + passed image space >= image size" ASSERT SpriteType_Old = 0 MOVS r14, r5, LSR#27 BNE %FT15 Debug so," ...type = MODE number",r5 LDR r14, [r1, #spNext] SUB r14, r14, r2 CMP r14, r4 BCC %FT99 Debug so," + passed mask space >= image size" SUB r2, r2, r0 TEQ r2, r14 BNE %FT99 Debug so," + passed mask space = image space" B %FT30 15 Debug so," ...type = new sprite type",r5 TST r5, #1 MOVNE r14, r5, LSL#18 MOVNES r14, r14, LSR#19 ; horizontal dpi in bits 1-13 MOVNE r14, r5, LSL#5 MOVNES r14, r14, LSR#19 ; vertical dpi in bits 14-26 BEQ %FT99 Debug so," + mode b0=1 and non zero dpi" ADRL r4, NSM_bpptable MOV r14, r5, LSR#27 LDRB r4, [r4, r14] Debug so," ...log2bpp",r4 LDR r0, [r1, #spRBit] ADD r0, r0, #1 MOV r0, r0, LSR r4 ; pixels_in_part_words = (spRBit + 1) >> log2bpp RSB r14, r4, #5 LDR r4, [r1, #spWidth] MOV r4, r4, LSL r14 ; pixels_in_whole_words = width << (5 - log2bpp) ADD r14, r0, r4 ADD r14, r14, #31 BIC r14, r14, #31 ; round up to nearest whole word MOV r14, r14, LSR#3 ; convert to bytes since it's assumed 1bpp LDR r0, [r1, #spHeight] MLA r14, r0, r14, r14 ; bytes size = width * (height + 1) LDR r0, [r1, #spNext] ADD r2, r14, r2 TEQ r0, r2 BNE %FT99 Debug so," + image dimensions as 1bpp mask = mask size of",r14 B %FT30 20 Debug so," ...has no mask" LDR r14, [r1, #spNext] SUB r14, r14, r0 CMP r14, r4 BCC %FT99 Debug so," + passed image space >= image size" 30 ; Next SUB r3, r3, #1 LDR r4, [r1, #spNext] 40 ADD r1, r1, r4 TEQ r3, #0 BNE %BT10 Debug so, "Passed all checks" CLRV Pull "r1-r5, pc" 99 Debug so, "There's something wrong with the sprite area" ADR r0, ErrorBlock_BadData BL copy_error_one ; also sets V Pull "r1-r5, pc" MakeSpriteErrorBlock BadData,,BadData END