Plot Mask Seems Broken For > 256 Colours
Andy S (2979) 504 posts |
I was in half a mind to post this in Community Support because if this is truly a reproducible bug I am astonished that no-one has noticed it before. I previously reported that on Paint the camera export tool was broken in the way it copied masks for 256 colour sprites. Now, on my RPCEmu setup at least, it seems to be utterly broken for any sprites with > 256 colours, as well. This is down to it relying on OS_SpriteOp 49 – Plot mask at user coords to copy the mask (it’s wrapped in a call to sprite_put_mask_given()). If I make a 16M colour sprite with Transparency Mask ticked (should be the regular binary mask); do some painting in the transparent colour; then use the camera tool in export mode to make a copy of the region of the sprite I painted on; then on the exported sprite all the pixels I tried to make transparent are instead showing in the foreground colour. I could understand if perhaps SpriteExtend was needed to support masks in the slightly newer high colour sprites, so I tried swapping in a call to OS_SpriteOp 50 – Plot Mask Scaled (via sprite_put_mask_scaled()) instead. The bug remains! I really hope this is just an issue with my RPCEmu setup. I tried my pre-bounty version of Paint, 2.20 (14-Oct-15) and it still happens. These bugs are really starting to frustrate me. I just want to make some headway with the bounty and I thought the Wrap option on Move Whole Sprite would be a nice quick thing to implement, then I hit another wall like this. I should have known better! |
Stuart Painting (5389) 714 posts |
I first tried it on a Pi 3B+ running RISC OS 5.26 and Paint 2.23 (11 November 2017). When performing the stated actions (16M sprite with mask, paint using transparent colour, use “camera” tool in export mode) the exported sprite doesn’t contain any transparent pixels, so the previous contents of those pixels are still visible. The experiment was repeated on an ArmBook running RISC OS 5.27 and Paint 2.30 (28 December 2019) with identical results. Looks like it’s a real bug :-(
That “palette file” bug I noticed three months ago had been lurking for nearly 25 years. Some features are not used all that often, it seems. |
Andy S (2979) 504 posts |
Thanks Stuart. Arrgh! That’s a bug in OS_SpriteOp then. For another variation of it, try again creating a 16M colour sprite with mask in Paint; flood fill with a solid colour like green; then rotate the sprite 45 degrees. Transparent areas will appear around the rotated block, as expected. As before, use the camera tool to export part of the sprite, such that it includes transparent and solid areas. This time, the exported sprite will look completely transparent, with no solid pixels visible. Unfortunately these aren’t bugs that I have either the time or knowledge to fix (I never really got very far with ARM assembler). This likely means one or more of my new Paint features, for example Wrap on Move Whole Sprite (which I’d just finished coding) will also be broken when using a mask with > 256 colours. A workaround could be coded to write the mask memory directly but realistically I won’t have time to do that. |
Andy S (2979) 504 posts |
Here’s a tiny bit of diagnostic information. 1. I made a 3 × 3 16M colour sprite with a mask in Paint. When I open the image in a hex editor, the mask data for the image created in 3. is FFFFFFFF FFFFFFFD FFFFFFFF. This means 1 word of data has been written for each 3 pixel row of the image. When I drag the camera tool over the whole image and use it to export the sprite, that sprite file’s mask data is then FFFFFFFF FFFFFFFF FFFFFFFF. More information to follow… |
Andy S (2979) 504 posts |
Aha! The mode word of these sprites is &301680B5
A workaround could be coded to write the mask memory directly but realistically I won’t have time to do that. It looks now like that might fall under the scope of the bounty after all, as one of the tasks is to add support for alpha masks. |
Stuart Painting (5389) 714 posts |
Are you sure about that? As far as I can see, a sprite mode word of &301680b5 decodes as: https://www.riscosopen.org/wiki/documentation/show/Sprite%20Mode%20Word |
Andy S (2979) 504 posts |
Are you sure about that? No, you’re absolutely right! I just debugged the mode word generation and bits 27-30 are 6 for the 16M colour sprite, which is Log2BPP + 1 and is correct. The top bit is zero, so these sprites should have a binary mask, which once again suggests a bug in the OS_SpriteOp mask routines. I’m going to try and create a 16M colour sprite with longer rows of 32 pixels. In that case I would expect a true binary mask to still have one word of data per row. If it has 8 words per row, then it is an alpha mask, which would mean the mask creation SWI isn’t obeying the mode word. If it has 1 word per row, then the mask plotting SWIs are broken. I think! |
Andy S (2979) 504 posts |
I’m going to try and create a 16M colour sprite with longer rows of 32 pixels. In that case I would expect a true binary mask to still have one word of data per row. And * drum roll *, it does have one word of data per row. I made a 32 × 1 pixel sprite, with the first 3 pixels red and the remaining 29 transparent. The mask data is just &00000007, so it’s a 1 bpp mask with the 3 leftmost (solid) pixels represented by the 3 least significant bits. If that’s as it should be, then the mask plotting SWIs are broken for > 256 colour sprites, which is what I originally thought. |
edwardx (1628) 37 posts |
Someone did. ROL fixed it in their version.
OS_SpriteOp 49 should only be used if the mode you’re plotting to has the same BPP as the sprite. For old format sprites the mask and the sprite have the same BPP. For a new format 16M colour sprite the mask is only 1 BPP, whilst the sprite is 32 BPP, so the mask is getting plotted 32 times as wide as it should be. It’s a bit strange that this depends on the BPP of the sprite rather than the mask. I’ve written some code to test switching output to the mask of a 16M colour sprite, and OS_SpriteOp 50 is working correctly for me. |
Andy S (2979) 504 posts |
It’s a bit strange that this depends on the BPP of the sprite rather than the mask. That’s fair enough for an 8 bpp image. For 32 bpp, broken is what I would call it. Even if you could make a 32 bpp mask, I doubt it would render correctly. I’ve written some code to test switching output to the mask of a 16M colour sprite, and OS_SpriteOp 50 is working correctly for me. Would you be willing to share a snippet of the code please? What’s not working in Paint is making a temporary sprite (with the same mode word as the original) and trying to plot the mask of the original into the temporary sprite’s mask. I’d like to see how you’re selecting the colours used and it would also help to know what version of SpriteExtend and RISC OS you’re running. |
Andy S (2979) 504 posts |
Actually, I say the temporary sprite is made “with the same mode word as the original” but Paint relies on OS_SpriteOp 16 to make the sprite. I hope that’s smart enough when output’s switched to a sprite instead of the screen to use the sprite’s mode rather than the screen’s. |
edwardx (1628) 37 posts |
RISC OS 5.27 (15-Dec-19) size% = 102400 DIM spr% size% spr%!0 = size% spr%!8 = 16 SYS "OS_SpriteOp", 256 + 9, spr% SYS "OS_SpriteOp", 256 + 10, spr%, "RAM::RamDisc0.$.SpriteFile" REM create a new 16M colour sprite and add a mask SYS "OS_SpriteOp", 256 + 15, spr%, "test", 0, 100, 100, &301680B5 SYS "OS_SpriteOp", 256 + 29, spr%, "test" REM plot mask of loaded sprite to mask of new sprite SYS "OS_SpriteOp", 256 + 61, spr%, "test", 0 TO r0, r1%, r2%, r3% SYS "OS_SpriteOp", 256 + 50, spr%, "newsprite", 0, 0, 0 SYS "OS_SpriteOp", r0, r1%, r2%, r3% REM plot mask of new sprite to screen SYS "OS_SpriteOp", 256 + 50, spr%, "test", 0, 0, 0 |
Andy S (2979) 504 posts |
Edit: Hmm, it might be working. The plot seems to write a larger rectangular area of the screen than the dimensions of the sprite (which is because the code’s making a 100 × 100 sprite. Never mind!). Also the bits I would expect to be solid look transparent (I think it needs some GCOL or OS_SetColour commands). I’ll have a play with it later. |
Andy S (2979) 504 posts |
I could understand if perhaps SpriteExtend was needed to support masks in the slightly newer high colour sprites, so I tried swapping in a call to OS_SpriteOp 50 – Plot Mask Scaled (via sprite_put_mask_scaled()) instead. The bug remains! Mea culpa, I think. OS_SpriteOp 50 is failing for me in my Wrap for Move Whole Sprite code. However, I hadn’t tried it in the code for the camera tool export code (also used in the scissor tool). I just updated the camera / scissor export code to use sprite_put_mask_scaled() in place of sprite_put_mask_given() and lo and behold, on my initial test with a 16M colour sprite it does seem to work correctly. I need to do more testing and work out why it’s not working for my Wrap function, but maybe this was just another Paint bug after all. |
Andy S (2979) 504 posts |
One thing that still doesn’t make sense to me in Paint, is that the coordinates that were derived from the mouse location seem to get negated when (and only when) the mask is plotted: sprwindow_swap_output_to_mask (&tempsprite, 0); os_swi2 (OS_SetColour, 1 << 4, 0); /* set empty gcol */ bbc_clg (); /* clear it all out */ os_swi2 (OS_SetColour, 1 << 4, -1); /* set solid gcol */ error = sprite_put_mask_given (sprite->file->spritearea, &ssid, -tools_pixel_to_point_x(&window->data->sprite, sprite->toolspace [1]), -tools_pixel_to_point_y(&window->data->sprite, sprite->toolspace [2])); sprwindow_swap_output_to_screen (); Anyone know why there’s a minus sign in this bit?: -tools_pixel_to_point_x(&window->data->sprite, sprite->toolspace [1]) |
Andy S (2979) 504 posts |
Edward thanks for you help with this. The fix I put in for the camera / scissor tool has actually just fixed my Move Whole Sprite code as well. My Wrap option has to make a temporary copy of the sprite and mask and although I was plotting the mask correctly with OS_SpriteOp 50, I overlooked the fact that the code to make the temporary copy of the mask was still using the broken camera paint call to OS_SpriteOp 49! I hope I haven’t wasted too many other people’s time. |
Alan Adams (2486) 1149 posts |
Sometimes explaining a problem to someone else is a good way to find a solution. |
Rick Murray (539) 13850 posts |
I explain to Cat. And when I get really stuck I beg Cat to tell me what I’m doing wrong because I know Cat knows (and is probably highly amused at this peculiar row of buttons that get prodded with wiggly appendages – it’s almost as if we have yet to invent cerebral interfacing (which is how Cat does it)). |
Rick Murray (539) 13850 posts |
Quick report of an issue in Paint. I’m using v2.26 (25 Aug 2019), so not the latest. Maybe this has been fixed? The issue is, when something is dragged into the window of an open sprite file (the one with all the icons) the thing dragged in is set as selected. Things should be ‘selected’ by user activity, not automatically. ;-) |