Finally got some school stuff out of the way so I can get back to the important things in life.... like the Nintendo DS.

Been messing around with touch-screen input a bit. It was fairly easy to get a demo running, but when I started trying to drag something around I found out that the touch screen uses a different coordinate system from the display. Dug around a little bit and came up with:


#define SCREEN_WIDTH 256
#define SCREEN_HEIGHT 192

// those are pixel positions of the two points you click
// when calibrating
#define TOUCH_CNTRL_X1 (*(vu8*)0x027FFCDC)
#define TOUCH_CNTRL_Y1 (*(vu8*)0x027FFCDD)
#define TOUCH_CNTRL_X2 (*(vu8*)0x027FFCE2)
#define TOUCH_CNTRL_Y2 (*(vu8*)0x027FFCE3)

// those are the corresponding touchscreen values:
#define TOUCH_CAL_X1 (*(vu16*)0x027FFCD8)
#define TOUCH_CAL_Y1 (*(vu16*)0x027FFCDA)
#define TOUCH_CAL_X2 (*(vu16*)0x027FFCDE)
#define TOUCH_CAL_Y2 (*(vu16*)0x027FFCE0)

// linear mapping can be used to go from touchscreen position to
// pixel position

// precalculate some values
static int16 TOUCH_WIDTH = TOUCH_CAL_X2 - TOUCH_CAL_X1;
static int16 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1;
static int16 CNTRL_WIDTH = TOUCH_CNTRL_X2 - TOUCH_CNTRL_X1;
static int16 CNTRL_HEIGHT = TOUCH_CNTRL_Y2 - TOUCH_CNTRL_Y1;


// reading pixel position:
int16 x = (IPC->touchX - (int16) TOUCH_CAL_X1)
* CNTRL_WIDTH / TOUCH_WIDTH + (int16) TOUCH_CNTRL_X1;
int16 y = (IPC->touchY - (int16) TOUCH_CAL_Y1)
* CNTRL_HEIGHT / TOUCH_HEIGHT + (int16) TOUCH_CNTRL_Y1;


at NDSTech Wiki. The needed calibration values don't seem to be in ndslib so I think you need to define them yourself. Took around a minute of messing around to get a nice demo working where you could drag something around on screen just like you'd expect.

Something I did in my code that's worth pointing out is changing the calculations a bit to get rid of any extra operations (especially the division). Granted, I'm not sure how much the compiler can take care of, but it probably doesn't hurt.

First, if you separate the
IPC->touchX - (int16) TOUCH_CAL_X1
terms, the entire TOUCH_CAL_X1 component only needs to be calculated once.

Second, you can trade out the arbitrary divide for a shift by preforming the divide ahead of time and shifting the result to avoid using floating point. Then undoing the shift whenever you use the value. The numbers are small enough that you shouldn't have to worry about overflow when multiplying with a larger number... I think. i.e.


#define SHIFT 4
static u16 scale_value = (CNTRL_WIDTH << SHIFT) / TOUCH_WIDTH;
...
(IPC->touchX * scale_value) >> SHIFT ...


Gotta look into compiler optimizations and figure out whether the above is worth the trouble if you specify -O2, etc.