masked sprites

bbc micro/electron/atom/risc os coding queries and routines
Post Reply
User avatar
jubber
Posts: 379
Joined: Sat May 14, 2016 1:05 pm
Contact:

masked sprites

Post by jubber »

I'm continuing my slow lumbering progress through ARM assembler and I've got to the point of being able to load a sprite file made in !Paint, grab individual 32x32 MODE9 sprites and plot them, providing they're nicely aligned. My next experiment has been with masking.

My working routine for an aligned 32x32 sprite with a mask (R0 = screen address, R1=sprite, R2=mask) does something like

Code: Select all

LDMIA R0,{R3-R6}
LDMIA R2!,{R7-R10}
BIC R3,R3,R7
BIC R4,R4,R8
BIC R5,R5,R9
BIC R6,R6,R10
MVN R7,R7 : MVN R8,R8 : MVN R9,R9 : MVN R10,R10
LDMIA R1!,{R11-R14}
BIC R11,R11,R7 : BIC R12,R12,R8 : BIC R13,R13,R9 : BIC R14,R14,R10
ORR R3,R3,R11 : ORR R4,R4,R12 : ORR R5,R5,R13 : ORR R6,R6,R14
STMIA R0,{R3-R6}
ADD R0,R0,#160
And doing this 32 times in an unrolled loop. Seems logical but...

Elsewhere I've seen routines that plot masked sprites either just using ANDs followed by ORRs (I can't work out how this would work) or BICs like me, but then the four ORRs but no MVN (flipping the mask) and BICs in the middle. Neither approach works when I try it.

Are those other routines only appropriate to MODE 13, using a different kind of mask from !Paint or employing some other tactic I've failed to understand?

Cheers!
joachim
Posts: 325
Joined: Wed Jun 21, 2006 2:20 am
Location: Germany
Contact:

Re: masked sprites

Post by joachim »

To get rid of the MVN and second BIC you just need to make sure that all the masked-off bits in your sprite data are already 0.

IIRC, !Paint has the irritating habit of leaving the RGB data as whatever it was before when you mark a pixel transparent. You can probably fix this in !Paint by changing all the masked bits to black and then back to transparent (I haven't tried this in MODE 9 but I see no reason it shouldn't work). Or you can write your own code to postprocess the sprite data from !Paint, effectively by running the BIC R11,R11,R7 ahead of time so that it isn't in the sprite plot loop.

This should leave you with sprite code that's just a BIC followed by an ORR. There's no real advantage to having an AND followed by an ORR instead, but you would do that if you stored the mask in the inverted sense (255=transparent instead of 0=transparent).
User avatar
jubber
Posts: 379
Joined: Sat May 14, 2016 1:05 pm
Contact:

Re: masked sprites

Post by jubber »

Joachim - thanks so much! This was stuck in my head all last night - and believe me if you already have insomnia, trying to do bitwise maths in your head does not help matters. Clearing the bits to black in !Paint seems to work as you suggest, and I can get rid of the extra MVN/BIC commands.

During my goofing around with this stuff it occurred to me that you could probably use colour 0 as a mask somehow and ditch the extra mask data - but I'm not sure if that approach would be faster and/or more fiddly.

My next challenge is obviously going to be getting these things plotting at non aligned addresses, which doesn't look like fun.

Thanks again for the assist!
User avatar
tricky
Posts: 7722
Joined: Tue Jun 21, 2011 9:25 am
Contact:

Re: masked sprites

Post by tricky »

On the beeb, a common approach is to have a copy of the sprite per pixel within a byte, maybe that is also used on the 32 bit :)

I've never written any arm code, although I did read the books cover to cover bitd.

One technique I used for z80 was to store the sprite and mask data interleaved which saved a register pair, but I don't know how useful this would be on the arm.
User avatar
Rich Talbot-Watkins
Posts: 2054
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: masked sprites

Post by Rich Talbot-Watkins »

On the Beeb, since it works byte-at-a-time, the "0 as mask" thing is easily done with a 256 byte lookup table which yields an appropriate mask byte for each value - but that approach wouldn't work on the ARM so you'd have to do it without a table which is probably much slower. One approach is:

Code: Select all

; MODE 9 plotting

MOV mask,#&F
  ....
ANDS R0,mask,spritedata
STRNEB R0,[screen,#0]
ANDS R0,mask,spritedata,LSR #4
STRNEB R0,[screen,#1]
ANDS R0,mask,spritedata,LSR #8
STRNEB R0,[screen,#2]
ANDS R0,mask,spritedata,LSR #12
STRNEB R0,[screen,#3]
ANDS R0,mask,spritedata,LSR #16
STRNEB R0,[screen,#4]
  ...etc...
ANDS R0,mask,spritedata,LSR #28
STRNEB R0,[screen,#7]
Another approach might be:

Code: Select all


MOV mask,#0
TST spritedata,#&F
ORRNE mask,mask,#&F
TST spritedata,#&F0
ORRNE mask,mask,#&F0
TST spritedata,#&F00
ORRNE mask,mask,#&F00
TST spritedata,#&F000
ORRNE mask,mask,#&F000
  ...etc...
TST spritedata,#&F0000000
ORRNE mask,mask,#&F0000000
LDR R0,[screen]
BIC R0,R0,mask
ORR R0,R0,spritedata
STR R0,[screen]
The first one tries to minimise instructions, while the second tries to minimise stores. Neither are as good as loading an (interleaved) mask and BIC/ORRing the sprite!

Here's a thread I started ages ago on how people used to do sprite routines for MODE 13, in case it's useful!
viewtopic.php?t=10771
User avatar
jubber
Posts: 379
Joined: Sat May 14, 2016 1:05 pm
Contact:

Re: masked sprites

Post by jubber »

it was useful! I used it to confirm my basic BIC/ORR logic was sound. I'm going to try and work out what is going on with the LSR/LSL stuff for pushing the sprite sideways by a pixel, in order to handle non aligned sprite plotting - which I think will be the same in MODE 9, albeit needing 8 different routines not just 4, possibly.

IanJ has already suggested 8 pre-calculated sprites per enemy, which would be a bit faster but obviously use a ton more ram. I'll try and get something working then have a look at enemy numbers. Palette swaps might be my oldschool friend here :-)
User avatar
jubber
Posts: 379
Joined: Sat May 14, 2016 1:05 pm
Contact:

Re: masked sprites

Post by jubber »

Actually - I do have a question Rich. In the masked routines in your very handy spreadsheet the shifts are explicit - so presumably there would need to be four such routines in a 256 colour mode. Is there a speed penalty to using register shifts instead, other than the initial setup code (checking X)? You'd need to free up R13 and R14 - although maybe only one of them in MODE 9
User avatar
Rich Talbot-Watkins
Posts: 2054
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: masked sprites

Post by Rich Talbot-Watkins »

Hey Robin, yeah shifts by register are slower, so you'd ideally want 4 different routines in Mode 13, or 4 shifted versions of the sprite.

Yep I think my register allocation is a bit off in those examples, but hopefully it's a good start!
User avatar
IanJeffray
Posts: 6019
Joined: Sat Jun 06, 2020 3:50 pm
Contact:

Re: masked sprites

Post by IanJeffray »

Rich Talbot-Watkins wrote: Wed Dec 06, 2023 4:40 pm ANDS R0,mask,spritedata
STRNEB R0,[screen,#0]
ANDS R0,mask,spritedata,LSR #4
STRNEB R0,[screen,#1]
Umm... that's going to set every second pixel to zero and stretch out the graphic 2x horizontally.
User avatar
Rich Talbot-Watkins
Posts: 2054
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: masked sprites

Post by Rich Talbot-Watkins »

Yeah quite right. I'm so used to writing for 8bpp modes. So only the second approach works for Mode 9.

I'm quite rusty on Archimedes coding as you can tell!
Post Reply

Return to “programming”