Saturday, August 26, 2017

Linear filtering of masked PNG images.

If you render your RGBA sprites in OpenGL using...

glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )
and you use GL_LINEAR filtering, then you may see black borders around your sprite edges.

The reason for the pixel artefacts on the border (they can be white too, or another colour) is that the linear sampling causes incorrect R/G/B to be summed. If one of the samples falls on a zero-alpha pixel, then that pixel's RGB colour gets weighed into the average, even though it is not visible.

This is a common pitfall in sprite rendering. The answer given on the stackexchange question is the correct one: you should use pre-multiplied alpha textures, and use instead:

glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA )

The downside of this is that PNGs are — per specification — non pre multiplied. And Inkscape can only create PNGs, not TIFFs which would support pre-multiplied alpha. Also, stb_image lacks TIFF support too. So how to solve this by keeping PNG as the source material?

The trick is to have the proper background colour set for pixels that have alpha 0 (fully transparent.) If you know that you will be blitting these sprites onto a white background, then these masked out pixels should be value ff/ff/ff/00. If you know that you will be blitting these sprites onto a red background instead, use value ff/00/00/00 instead.

This is all good and well, but software (like Cairo and Inkscape) often mistreat alpha-zero pixels. Cairo sets them all to 00/00/00/00 for instance, even though there may be colour information in the fully transparent pixels. This means you cannot anticipate the colour of the target buffer, as the masked out pixels get a black colour. In my code, I have my texture loader swap out the alpha-0 pixels with a new RGB value, that matches the background against which the sprites are rendered. Note that this solution results in lower quality than pre-multiplied alpha sprites, but does have the advantage that it is less of a hassle.

Above left, you can see the effect of having the wrong colour (black) for fully transparent pixels. On the image on the right, you see the same compositing, but where the sprite has its transparent pixel colour set to white.

My fellow game-dev Nick, from Slick Entertainment fame, suggested another approach of bleeding out the colour value into the transparent pixels. That makes the sprite material a little more versatile, as you can render them against any colour background. I think it does give a slightly less correct result though, for the case where you do know the background colour and prepare for that.

Wednesday, August 23, 2017

Match 3

I decided to challenge myself in writing a quick and dirty Match-3 game. Not sure, how I came up with the theme, but it occurred to me that Smileys with facial feature permutations would make for interesting content.

I spent a full day on art, using Inkscape and OpenClipArt. A big time saver is the Inkscape feature that lets you render a specified object from the command line, so I don't have to wrestle with the GUI to do all the exporting.

The next day was spent coding. The game is written in a C-Style C++, on top of my own engine with the help of SDL2. I'm happy to report that I had the basics working in only a day: you can swap Smileys, and after matching, the Smileys above fall down, and are replenished. No scoring yet, no sound, no visual effects. But I did put in a very cute feature for hints: All Smileys will look in the direction of a smiley you could swap for a match. I think that's a cute touch.

My matching mechanism is quite novel too, I think. Instead of simply matching up a colour or shape, you need to match up one of the facial features. So three Smileys with the same glasses will match up. So do three Smileys with the same hair. Or three Smileys with the same moustache/beard.

I found that this feature matching takes more mental effort than traditional colour matching. Is that a good thing or a bad thing? On one hand, it makes for less relaxing gameplay. On the other hand, it seems a more intense training for your mind. So it's a trade-off.

I am happy with the visual appeal of the board though. A varied collection of Smileys makes for a happy sight.

Saturday, August 5, 2017

Assert your assumptions.

A lot of software bugs are caused by the following scenario: The programmer assumed a certain situation and wrote code that would rely on this assumption. Very often, these mental assumptions are never made explicit, and live in the programmer's mind only. A standard weapon against these bugs in the arsenal of the coder is the assertion.

When working in teams I would often argue for the use of asserts in production code, to the astonishment of my colleagues. The most frequent objection to this would be the performance impact. However, the 98% of your code that is high level will never show a perceivable performance impact from asserts. The remaining 2% you just disable the asserts in non-debug builds. The inner loop of the physics solver, the inner loop of the collider, the inner loop of the path planner. Sure, leave them out there. For all other code? Ship your product with asserts! You'll be amazed at what gets triggered.

To take the controversy a small step further: I also firmly believe in making the asserts user-facing. Let's take Android apps for instance... instead of having Android report "Foo stopped working" I prefer to show a dialog with the assertion that failed, the file name and line nr. By doing this you can leverage your customer base to improve your app's stability. A certain user may detect the pattern: "Every time I do X after doing Y, I get a crash with message Z." Exactly the information the developer needs to fix the bug!

And just for good measure, (or is it overkill?) I took it further again: and sometimes will even show callstacks to users. For instance, a steam user is quickly able to screencapture and post it on steam, or email it to the dev. So much valuable info.

So last month, I was noticing crashes reported by Google Play on my Android app. And not always will users contact you with the crash report, so I even with pulling in the user for crash reports, the right information would not always reach me. One solution is to adopt a heavyweight framework to do these reports for me. Link to an analytics framework. But it's possible to make a very lightweight solution yourself.

I was interested in the assert message only. No need for user info, device info, anything. Just the assert message with source code line number. And this is very small data. Smaller than an UDP packet!

So I coded a minimalistic assert report server to run on Amazon's EC2. Just a few lines of Python code, where a socketserver.UDPServer prints out the datagrams it receives.

Client side, it is a little bit more code. Mine is in C, as I make NDK based Android Apps, but in Java it is even simpler. This slightly verbose C code will do the trick to open a socket and send a single datagram to my assert report server.

I am happy to report the assert report server is doing its job, and helps me to get on top of the crashes in my game. For future improvement, I should probably add an app version number to the assert message, so I will know if it is an old issue or not. Thank you for reading, and let me know what you think of assertions, and if you run assertions in your production code or not.