For a demo on C64 I need a program to paint some sprites, i.e. a bitmap painter. What is better suitable for digital-painting than a touch screen? Among my devices with a touch sensitive screen - Nintendo DS and PocketPC(*) - I chose the latter one.
(*) with an OMAP 850 multipurpose processor
Story
With PellesC there is a free dev-Tool for Win32 and PocketPC available, featuring a custom c-compiler, derived from lcc-compiler. The IDE is comfortable, allowing to upload the built executable and to execute it with simple key-shortcuts.
Program sketch, first three steps: Allow to
(a) draw on the screen, i.e. read stylus position and draw points (SetPixel) or lines (MoveTo, LineTo),
(b) load a bmp file into the drawing area,
(c) save the drawing area to a bmp.
Steps (a) and (b) were simple to implement. Saving wasn't.
Examination
The file was opened, but 0 (zero) bytes were written. Slowly debugging line per line I realized that
bfh->bfSize = dwFileHeaderSize + bmi->bmiHeader.biSizeImage;
caused the error (which was not reported).
After reading lots of online-material I stumbled across the explanation:
The ARM processor requires long integers (DWORDS), i.e. 4-byte variables to be aligned to memory adresses which are a multitude of 4.
The struct storing the BITMAPFILEHEADER bfh is packed though, i.e.
#pragma pack( 2 ) short bfType; // byte [0..1] int bfSize; // byte [2..5] ... #pragma pack( )
which apparently causes bfType to be packed. Accessing bfSize then causes a data misalignment error.
So I cloned the BITMAPFILEHEADER struct
struct MYBITMAPFILEHEADER { short bfType; // byte [0..1] int bfSize; // bytes [4..7] short bfReserved1; short bfReserved2; int bfOffBits; };
and aligned it's variable pointer to multiple of 4 adresses:
__unaligned struct MYBITMAPFILEHEADER *bfh; // ARM processor!!!
Now, the above assignment doesn't cause any data misalignment fault, yet the struct size is 16 bytes when it shall be 14.
In the end I use a simple char-array, fill it
char mybfh[14]; WORD p_shortint; DWORD p_int; p_shortint =0x4d42; memcpy(mybfh,&p_shortint,2); p_int = dwFileHeaderSize +bmi->bmiHeader.biSizeImage; memcpy(mybfh+2,&p_int,4); p_shortint =0; memcpy(mybfh+6,&p_shortint,2); memcpy(mybfh+8,&p_shortint,2); p_int = dwFileHeaderSize; memcpy(mybfh+10,&p_int,4);
...and write it into the bitmap file.