Hue Shifting with Transforms

Recently I had the opportunity to fiddle with some image adjustment algorithms to show an approximate preview for a texture on a mesh which among others included a hue shift.

Of course shifting the hue is no big deal, there’s already of plethora of online resources that demonstrate how to change a RGB color to HSL and back which makes hue shifting as easy as incrementing a value, which is very nifty of course, however let’s assume you already have a setup that computes a matrix to adjust brightness, contrast and saturation which is sent to a shader, this is where things get interesting.

Now the obvious solution would have been to modify the shader, pass the hue value do the adjustment and be done with it, however that broke backwards compatibility, so this was not an option. Luckily, HSL isn’t just a formula, once you try to visualize RGB as a coordinate system instead of pixel values, you start to realize that a rotation on the (1,1,1) axis would essentially create a hue shift, HSL is only a convention to bring the Z (or blue in our case) axis to the (1,1,1) direction so you can make the rotation.

So let’s consider that Create*Rotation would make a rotation matrix on the specified axis with the specified angle and that MultiplyMatrix multiplies two matrices leaving the result in the last argument, then the following sequence will create a matrix adjustment for a hue shift:

CreateXRotation(xrot, PI / 4)
CreateYRotation(yrot, PI / 6)
CreateZRotation(hueShift, hue)
CreateYRotation(invyRot, -PI / 6)
CreateXRotation(invxRot, -PI / 4)
MultiplyMatrix(xrot, yrot, tohsl)
MultiplyMatrix(tohsl, hueShift, shiftedMat)
MultiplyMatrix(invyRot, invxRot, torgb)
MultiplyMatrix(shiftedMat, torgb, adjustment)

Which gives us an adjustment matrix that we can premultiply into the existing matrix, problem solved and we keep backwards compatibility.

One thing to be noted is that hue has to be in radians, the most intuitive course of action is to let users specify it in degrees then turn it into radians before creating the matrix, but that is just a minor detail.

And there you have it, an easy to use transform to implement hue shifting when working with HSL values is not an option

Troll Game Jam

I tend to really like game jams because I always learn a lot of things during the 24-ish hours of non stop development, so when a friend told me he is organizing a small LD like competition, my coder senses went all tingly.

I’ve long been an advocate of diversity, so just for the fun of it I wanted to see if I can do a game based on Qt that could run on anything (anything as in every platform that supports Qt), so this time around I fired up QtCreator and started making the game.

Interestingly enough, it took around 6 hours to implement a standard game of snake and another 6 for the rest of the gameplay,¬† and I say that because everything is made in C++. When I started game development I transitioned to interpreted and JITed languages because pushing pixels in C++ was a very long process, even with existing frameworks, maybe it’s the development experience I’ve gained over the years, but that no longer seems to be true, so it’s definitely something that I’ll explore in the future.

Back to the game though, the idea was to create a game so buggy that it becomes a challenge to play it. I think I’ve managed to do that to some degree, however if you don’t want to take my word for it, you can download it here

lase shooting snakes

The classic game of snake with lasers

I’m calling it a troll game jam because the unofficial focus of the jam was trolling the other opponents, and since at least for now I’m the only one with a playable prototype, I think I might have lost that round, but on the other hand something pretty fun came out of it.

Android support soon to follow.

Watch out for the APIs

There’s an old saying in the computer industry that says you should be lenient with what you receive and accurate with what you give, mainly it means that when parsing data you receive, it’s not uncommon to receive bad input, so it would be nice of you to either tell the program or person that generated the error that they did something wrong, try to correct the data or use a default.

Back in the real world though, writing software has taught me that this is just saying that gets ignored to several degrees by almost every API. My guess is that once the spec is done, no one actually bothers to actually whatever comes out. This post serves as a list for the problems people seem to ignore when they  make an API for C++.

Let’s start with a little bit of math, for those not very interested in 3D concepts, a Quaternion is a 4 element vector that you can turn into a rotation matrix. It basically represents the rotation around an axis, so when you see a Quaternion class with a constructor that looks like the following:

Quaternion(double, Vector3&);

your natural reaction would be to assume that it initializes the new quaternion so that it represents the rotation specified by the double argument around the axis represented by the Vector class, right ? Well as it turns out, it more often than not it just copies the values into its’ members. How on earth is that more useful than something that it was created for is beyond me, but that’s probably because I’ve actually used quaternions.

Moving on to some geometry, when you’re working with images you’re bound to run into something that requires coordinates. Now there are a lot of ways to say where an image begins and where it ends, but fortunately only two of them are used in practice. Most of you have probably seen the one where coordinates start in the upper left corner and go toward the bottom right as they increase, so for instance if you have a resolution of 1280 x 800, then the bottom right corner is (1280, 800). The second one is the mathematical one where images start in the bottom left corner and go towards the upper right, however this one is seldomly present in libraries, so if you insist that the Y axis should be up because that’s how things were in highschool, then at least leave a comment to let the rest of the world know that the top should be bigger than the bottom of the image in order for something to work.

And last, but not least, never ever use STL in an API, ever. Containers are awesome for programming in general, I agree, but when you want to send data from one dll to another you have to keep in mind that the people making the other library are sometimes using other tools than your own, and containers are almost never compatible between toolsets, something always crashes sooner or later unless everyone uses the same compiler and linker, in theory that’s not much of a problem, in practice however you’re often forced by the environment you’re developing for to use certain tools if you want to be able to debug your application. So in the end it all comes down to either using some really awkward hacks to be able to accommodate the library or dropping that library altogether. This is why nice, clean APIs are usually made in C, well that and no name mangling to take into account when importing functions by hand.

So yeah, making an API isn’t as easy as one would originally assume, however if you have some patience and are lenient with what you expect from it sometimes it’s not that bad, after all everyone makes mistakes, they’re ok so long as you learn to recognise them early.

Pinballs’ story

I really like stories, generally because there’s something you can learn from them and I particularly enjoy dev stories because not only you learn from them, but at least in my case I end up learning something useful.

This dev story is about the reason that neat little time waster called pinball wasn’t included in any windows release after XP. I guess “management reasons” was a bit of a no-brainer, but often times software engineers stay overtime to make things they believe in happen, I for one have done so on some occasions, so my curiosity naturally settled on the question, why didn’t anyone really want pinball in the next release, the answer? poorly written code.

You know something is truly badly written when the guys writing the operating system it runs on can’t figure it out, as it turns out the issue was quickly diagnosed, but finding the actual code that created it was a bit like finding an accidental piece of hair in your lasagna. It’s too bad they didn’t get to the bottom of that floating point problem though, would’ve made for a better story in my opinion, but at least I can say I learned to be more wary of rounding errors.

Anyway, the story is here, make sure to read the comments as well, they provide some further interesting insight.

Defcamp Conclusions

It’s only natural that if I write an introductory post regarding an event, then I should also follow up with some conclusions, more so when the event itself was to say the least awe inspiring.

Now I know one or two things about security, it’s as much a hobby as it is a curiosity of mine, though I’m not the “I don’t know what that is but I know I’m gonna break it” type, I like to understand common pitfalls so that if hypothetically someone were to try and break my code at least they’d say it posed some sort of a challenge, so this conference was a bit of a head rush for me, quantity and quality playing equal roles.

However what happens in Defcamp, stays in Defcamp so I’m not going to go into a lot of detail regarding the contents of the presentations, if you want them, send them an email, I just want to point out that everyone there did the same things you’d do, they only saw them differently, so if that’s what you’re after, then you’re definitely going to want to participate next year.

As for me, count me in next year as well, I have a flag to catch.

Icon Misfortune

Around 60-70% of the tasks that you will receive as a programmer will be simple and very easy to do. Generally, you can suppose that the rest will be the same, the difference however is that they will generate bugs, and I’m not talking the kind that will turn out to be tasks themselves, rather about the ones that will spawn out of nowhere and persist for no apparent reason.

Let’s say for instance that you receive an icon set that needs to end up in a ribbon menu, the project used some other form of UI toolkit so you need to create a managed buffer, dump the raw image data in there and set that as a data source for the ribbon because in this case it’s better for everyone if small resources are embedded in a dll. And you do this and it works, only every icon looks normal except one. So each icon is 32×32 and they also get forcibly resized by the api to a 32×32 image when they get set and yet just one of them is 42×42.

Of course a quick debugging session revealed that the culprit was the DPI which is where the fun just started because of course everyone swears that unless otherwise specified WPF bitmaps are created with a default 96 dpi and that DPI settings only have a getter, so they are locked there and that’s where they will stay.
This is where you start to learn new things, remember the raw image data I was dumping in the stream? As it turns out, the PNG standard says that width and height aren’t enough to describe the dimensions of a picture, you should also save the DPI and to make everything perfect, if you go down to section 13.6 you see this little gem:

Non-square pixels can be represented (see pHYs Physical pixel dimensions), but viewers are not required to account for them; a viewer can present any PNG datastream as though its pixels are square.

Well guess what because of this tiny detail, every viewer I used showed the image as a normal 32×32 picture, except for that ribbon button.

Of course editing an image header to solve a little misunderstanding due to inconsistency isn’t really that much of a story in itself, but the way you get there usually is.