I did some research on the GP2x’s touch screen yesterday. It seems that none of the unofficial devkits support it out of the box. There is at least one version of SDL compiled for the 2x that has code supporting the touch screen, but it’s not wired into SDL as a mouse; it’s a non-standard extension.
Looking around for some example code led me to a simple demonstration of how to read the touch screen. It’s as easy as opening the device as a file and reading its contents into a struct every time the stylus position needs to be updated. After tidying the code up and refactoring it into a static class I added it into the GP2x version of Woopsi to try it out.
First impressions - the GP2x touch screen is rubbish.
On the DS, holding the stylus at a point on the touch screen and reading out the values in a loop will return the same value every time. On the GP2x, doing the same will result in a different value every time. The value is usually up to 3 pixels out, but occasionally jumps up to 10 pixels out. This wouldn’t be a problem if we were using a GUI that consisted of nothing but large buttons, but Woopsi is becoming increasingly complex and has draggable gadgets. Draggable gadgets don’t work if the stylus jumps around unpredictably.
There are several possible explanations for this behaviour. The first possibility, based on GPH’s previous “efforts” at providing human interface devices, is that the touch screen is just crap. The three versions of GP32 and the first two versions of the GP2x had unusable mini-joysticks, whilst the current version has a usable but imperfect d-pad. I wouldn’t be at all surprised if they’d fitted the console with cheap screens. CPU speed is another one - the touch screen apparently gets more accurate as the CPU is clocked faster, so adding in the CPU clock speed code and bumping that might help. Yet another is framerate - the GP2x version of Woopsi needs some hefty optimisation (which I’ll do much later, when the DS version is finished) and takes several frames to complete a single program loop. It could be that this is throwing out the co-ordinates. Both of these theories require testing.
A more likely possibility is that co-ordinate jitter is an inherent problem in this kind of touch screen technology. It’s possible that the DS hardware has jitter correction or smoothing built-in, and serves pre-corrected values to the developer. The GP2x obviously doesn’t, so it’s up to the coder to solve the problem in code.
I had a quick go at solving this yesterday. The most obvious way to solve the problem is to take multiple samples of the touch screen co-ordinates and average them. I wrote a routine that would take 5 samples of the co-ordinates then find the mean average, and use that value as the stylus position. This did not work.
I then extended the routine a little - compare each of the sample values with the mean, and discard any that are outside an acceptable error boundary. Take the mean of the remaining samples and use that as the value. That didn’t work either.
It then occurred to me that the touch screen driver probably only updates its co-ordinates once every vertical blank, so I was actually only taking the mean of a single value. I’ll have to test this to be certain. If it does appear to be the case, I’ve got another plan. If I allocate a 5-slot queue and add a value to it every frame, I can take the mean of those values and use that as the stylus position. It would mean that the stylus movement would be slightly sluggish, as the current position would be based on the past 5 observed positions, but it should reduce the jitter problem.
Other possibilities include researching filtering and damping algorithms or using some sort of linear interpolation routine to try and work out which observed values make sense and which are obviously incorrect, and maybe even try to predict where the stylus will move next.
Distant memories of physics lessons and the “root mean square” might point me in the right direction…