#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#define get16(x) ((x[1]<<8)|x[0])

typedef struct {
  unsigned char       manufacturer;
  unsigned char       version;
  unsigned char       encoding;
  unsigned char       bitsperpixel;
  unsigned char       xmin[2],  ymin[2];
  unsigned char       xmax[2],  ymax[2];
  unsigned char       hDpi[2],  vDpi[2];
  unsigned char       colormap[48];
  unsigned char       reserved;
  unsigned char       nplanes;
  unsigned char       bitsPerLine[2];
  unsigned char       paletteInfo[2];
  unsigned char       hscreenSize[2], vscreenSize[2];
  unsigned char       filler[54];
}PCX_header;

int main(int argc, char *argv[])
{
    FILE* input;
    FILE* output;

    PCX_header     header;
    unsigned char* buffer;
    unsigned char* ptr;
    unsigned char* pptr;
    unsigned char* nextLine;
    unsigned char  out[32];
    unsigned int   w, h;

    unsigned int i, j, l;

    unsigned char c, p;

    if(argc < 3) {
        fprintf(stderr,"Usage: %s input.pcx output.bin\n",argv[0]);
        return 1;
    }

    /* Read pcx file */
    if(!(input = fopen(argv[1],"rb"))) {
        fprintf(stderr,"Error while loading %s\n",argv[1]);
        return 1;
    }


    fread(&header, 1, sizeof(PCX_header), input);

    if((header.bitsperpixel * header.nplanes) != 24) {
        fprintf(stderr,"%s must be a 24bpp pcx image\n",argv[1]);
        fclose(input);
        return 1;
    }

    w = get16(header.xmax) - get16(header.xmin) + 1;
    h = get16(header.ymax) - get16(header.ymin) + 1;

    buffer = (unsigned char*)malloc(w * h * 3 * sizeof(unsigned char));
    assert(buffer);

    ptr = buffer;
    for(i=0; i<h; ++i) {
                nextLine = ptr + w * 3;
                pptr = ptr;

                p = 0;
                do {
                        fread(&c, 1, sizeof(unsigned char), input);
                        if ((c & 0xC0) == 0xC0) {
                                j = c & 0x3F;
                                fread(&c, 1, sizeof(unsigned char), input);

                                while (j--) {
                                        *pptr = c;
                                        pptr += 3;
                                        if (pptr >= nextLine) {
                                                p++;
                                                pptr = ptr + p;
                                        }
                                }
                        } else {
                                *pptr = c;
                                pptr += 3;
                                if (pptr >= nextLine) {
                                        p++;
                                        pptr = ptr + p;
                                }
                        }
                } while (p < 3);

                ptr = nextLine;
    }

    fclose(input);

    ////////////////////////////////////////////////////////////////////


	/* Open output */
    if(!(output = fopen(argv[2],"wb"))) {
       fprintf(stderr,"Error while opening %s\n",argv[2]);
        return 1;
    }

	for(j=0; j<h; j+=8)
	{
		for(i=0; i<w; i+=8)
		{
			ptr  = buffer + (i + (j*w))*3;
			pptr = out;
			for(l=0; l<8; ++l, ptr+=3*w, pptr+=2)
			{
				p =   (ptr[21]& 1) | (ptr[18]& 2) | (ptr[15]& 4) | (ptr[12]&  8)
					| (ptr[ 9]&16) | (ptr[ 6]&32) | (ptr[ 3]&64) | (ptr[ 0]&128);
	
				pptr[0 ] = p;
				pptr[1 ] = p;
				pptr[16] = p;
				pptr[17] = p;
			}
			fwrite( out, 1, 32, output );		
		}
	}

	free(buffer);
	
    fclose(output);
	
    return 0;
}
