/**************************************************************************
 PCX2TRAW - by Lee Hamel (Patch), hamell@cx.pdx.edu, *Avalanche* coder
 July 14th, 1993
**************************************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>

typedef struct {
		char    manufacturer;
		char    version;
		char    encoding;
		char    bits_per_pixel;
		int     xmin,ymin;
		int     xmax,ymax;
		int     hres;
		int     vres;
		char    palette[48];
		char    reserved;
		char    colour_planes;
		int     bytes_per_line;
		int     palette_type;
		char    filler[58];
	       } PCXHEAD;

#define         PCXHEADSIZE     sizeof(PCXHEAD)

PCXHEAD header;
unsigned int width, depth, bytes, i, i2, showflag = 0;
unsigned char palette[768];
FILE *infile, *outfile;
unsigned char *tempptr, *picture;
char pcxfile[20],rawfile[20],palfile[20];

void Read_PCX_Line(unsigned int vidoffset)
{
  unsigned char c, run;
  unsigned int n = 0;

  _asm
  {
    cld
    mov         di,[vidoffset]
  }

  do
  {
    c = fgetc(infile) & 0xff;
    if ((c & 0xc0) == 0xc0)             /* if it's a run of bytes field */
    {
      run = c & 0x3f;                   /* and off the high bits */
      c = fgetc(infile);                /* get the run byte */
      n += run;                         /* run the byte */
      for (i2 = 0; i2 < run; i2++)
	*picture++ = c;

      if (showflag == 0)
      {
	_asm
	{
		mov     ax,0a000h
		mov     es,ax
		mov     al,[c]
		xor     ch,ch
		mov     cl,[run]
		rep     stosb
	}
      }
    }
    else
    {
      n++;
      *picture++ = c;

      if (showflag == 0)
      {
	_asm
	{
		mov     ax,0a000h
		mov     es,ax
		mov     al,[c]
		stosb
	}
      }
    }
  }
  while (n < bytes);
}

void Unpack_PCX_File(void)
{
  for (i = 0; i < 768; i++)
    palette[i] = palette[i] >> 2;

  if (showflag == 0)
  {
    _asm
    {
		mov     ax,0013h
		int     10h
		mov     ax,1012h
		xor     bx,bx
		mov     cx,256
		mov     dx,offset palette
		int     10h
    }
  }

  /* make a temporary pointer too */
  tempptr = picture = (unsigned char *) malloc((size_t) 64000);
  for (i = 0; i < depth; i++)
      Read_PCX_Line(i * 320);
}

void Dump_PCX(void)
{
    outfile = fopen(palfile,"wb");
    for (i = 0; i < 768; i++)
	fprintf(outfile,"%c",palette[i]);
    fclose(outfile);

    outfile = fopen(rawfile,"wb");

    /* start at pixel 0 */
    picture = tempptr;
    for (i = 0; i < 16000; i++)
    {
	fprintf(outfile,"%c",*picture);
	picture += 4;
    }

    /* start at pixel 1 */
    tempptr++;
    picture = tempptr;
    for (i = 0; i < 16000; i++)
    {
	fprintf(outfile,"%c",*picture);
	picture += 4;
    }

    /* start at pixel 2 */
    tempptr++;
    picture = tempptr;
    for (i = 0; i < 16000; i++)
    {
	fprintf(outfile,"%c",*picture);
	picture += 4;
    }

    /* start at pixel 3 */
    tempptr++;
    picture = tempptr;
    for (i = 0; i < 16000; i++)
    {
	fprintf(outfile,"%c",*picture);
	picture += 4;
    }

    fclose(outfile);

    if (showflag == 1)
    {
	_asm {
		 mov ax,0003h
		 int 10h
	     }
    }
}

void Help(void)
{
  printf("\n");
  printf("PCX2TRAW - Converts a PCX pic to tweaked mode RAW format\n");
  printf("           by Patch (hamell@rigel.cs.pdx.edu)           \n");
  printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n");
  printf("Usage: pcx2traw PCXFILE [-SHOW]\n");
  printf("where: PCXFILE    - the PCX file to read (no extension)\n");
  printf("       -SHOW      - show the PCX to the screen\n\n");
  printf("Example call: pcx2traw picture\n");
  printf("- This will read the file PICTURE and output the palette to PICTURE.PAL\n");
  printf("  and the image data to PICTURE.RAW.  The raw format is this: every\n");
  printf("  4th byte is saved for plane 0, then 1, then 2, then 3.  So pixels\n");
  printf("  0, 4, 8, etc. will be saved (16000 bytes), then plane 1 pixels start\n");
  printf("  for the next 16000 bytes (pixels 1, 5, 9, etc.) and so on for all 4\n");
  printf("  planes.  Can then be output using REP MOVSD for a count of 4000 for\n");
  printf("  each plane.  Fast as hell.\n");
  exit(1);
}

void main(int argc, char *argv[])
{
  if (argc == 1) Help();

  {
    strcpy(pcxfile,argv[1]);
    strcpy(rawfile,argv[1]);
    strcpy(palfile,argv[1]);
    strcat(pcxfile,".pcx");
    strcat(rawfile,".raw");
    strcat(palfile,".pal");

    if ((infile = fopen(pcxfile,"rb")) != NULL)
    {
      if (fread((char *)&header,1,PCXHEADSIZE,infile) == PCXHEADSIZE)
      {
	if (header.manufacturer == 0x0a && header.version == 5)
	{
	  if (!fseek(infile,-769L,SEEK_END))
	  {
	    if (fgetc(infile) == 0x0c && fread(palette,1,768,infile) == 768)
	    {
	      fseek(infile,128L,SEEK_SET);
	      width = header.xmax - header.xmin + 1;
	      depth = header.ymax - header.ymin + 1;
	      bytes = header.bytes_per_line;

	      /*
	      printf("Width = %d\n",width);
	      printf("Depth = %d\n",depth);
	      printf("Bytes = %d\n",bytes);
	      printf("Chars per row = %d\n",charsrow);
	      */

	      showflag = stricmp(argv[2],"-SHOW");
	      Unpack_PCX_File();
	      Dump_PCX();

	      free((unsigned char *) picture);
	    }
	    else printf("Error reading palette\n");
	  }
	  else printf("Error seeking to palette\n");
	}
	else printf("Not a 256 color PCX file\n");
      }
      else printf("Error reading %s\n",argv[4]);
      fclose(infile);
    }
    else printf("Error opening %s\n",argv[4]);
  }
}
