Atari ST Raw Data Format - HoraceAndTheSpider/Bloodwych-68k GitHub Wiki

So, in Atari 320x200, 16 color, you always have one quadword for one pixelblock of 16 pixels. Each word describes one plane and got 16 bits for the 16 pixels. The lowest significant colorplane comes first, and the very first bit (so, the MSB of the first byte) stands for the lowest significant colorplane of the first pixel. This piece of code looks confusing, but should give you the color of the selected pixel (0...15) pretty fast. You always have to place the pointer at such a quadword margin.

// p = pointer to a quadword (one pixelblock of 16 pixels)
// n = selected pixelnumber
int get_atari_pixelcolor(char* p, int n)
{
  switch (n)
  {
    case  0: return ((p[6] & 0x80) >> 4) | ((p[4] & 0x80) >> 5) | ((p[2] & 0x80) >> 6) | ((p[0] & 0x80) >> 7);
    case  1: return ((p[6] & 0x40) >> 3) | ((p[4] & 0x40) >> 4) | ((p[2] & 0x40) >> 5) | ((p[0] & 0x40) >> 6);
    case  2: return ((p[6] & 0x20) >> 2) | ((p[4] & 0x20) >> 3) | ((p[2] & 0x20) >> 4) | ((p[0] & 0x20) >> 5);
    case  3: return ((p[6] & 0x10) >> 1) | ((p[4] & 0x10) >> 2) | ((p[2] & 0x10) >> 3) | ((p[0] & 0x10) >> 4);
    case  4: return ((p[6] &  0x8)     ) | ((p[4] &  0x8) >> 1) | ((p[2] &  0x8) >> 2) | ((p[0] &  0x8) >> 3);
    case  5: return ((p[6] &  0x4) << 1) | ((p[4] &  0x4)     ) | ((p[2] &  0x4) >> 1) | ((p[0] &  0x4) >> 2);
    case  6: return ((p[6] &  0x2) << 2) | ((p[4] &  0x2) << 1) | ((p[2] &  0x2)     ) | ((p[0] &  0x2) >> 1);
    case  7: return ((p[6] &  0x1) << 3) | ((p[4] &  0x1) << 2) | ((p[2] &  0x1) << 1) | ((p[0] &  0x1)     );
    case  8: return ((p[7] & 0x80) >> 4) | ((p[5] & 0x80) >> 5) | ((p[3] & 0x80) >> 6) | ((p[1] & 0x80) >> 7);
    case  9: return ((p[7] & 0x40) >> 3) | ((p[5] & 0x40) >> 4) | ((p[3] & 0x40) >> 5) | ((p[1] & 0x40) >> 6);
    case 10: return ((p[7] & 0x20) >> 2) | ((p[5] & 0x20) >> 3) | ((p[3] & 0x20) >> 4) | ((p[1] & 0x20) >> 5);
    case 11: return ((p[7] & 0x10) >> 1) | ((p[5] & 0x10) >> 2) | ((p[3] & 0x10) >> 3) | ((p[1] & 0x10) >> 4);
    case 12: return ((p[7] &  0x8)     ) | ((p[5] &  0x8) >> 1) | ((p[3] &  0x8) >> 2) | ((p[1] &  0x8) >> 3);
    case 13: return ((p[7] &  0x4) << 1) | ((p[5] &  0x4)     ) | ((p[3] &  0x4) >> 1) | ((p[1] &  0x4) >> 2);
    case 14: return ((p[7] &  0x2) << 2) | ((p[5] &  0x2) << 1) | ((p[3] &  0x2)     ) | ((p[1] &  0x2) >> 1);
    case 15: return ((p[7] &  0x1) << 3) | ((p[5] &  0x1) << 2) | ((p[3] &  0x1) << 1) | ((p[1] &  0x1)     );
  }
  return 0;
}

To read the Avatar's picture, load to char avatar[4096];
Then plot like that:
Code: [Select]
for (int c=0; c<16; c++)
  for (int y=0; y<16; y++)
    for (int x=0; x<32; x++)
    {
      int pixblock = x / 8; // 8 bytes per pixelblock
      if (x<16)
        putpixel_somewhere(c, x, y, get_ataripixelcolor(&avatar[256*c + 16*y + 8*pixblock], x));
      else
        putpixel_somewhere(c, x, y, get_ataripixelcolor(&avatar[256*c + 16*y + 8*pixblock], x-16));
    }