/* Pro2BMP.c - converts Amiga 3-D Professional RGB files to 24-bit
   Microsoft Windows 3.0 format - djh */
   
#include <stdio.h>
#include <stdlib.h>

#define PROIDLEN 9
#define STD_METHOD 1
#define RGBSIZE 3 /* Aztec pads sizeof(rgb) to 4! */

typedef struct {
  /*char identifier[9];*/
  short width,height,vxoff,vyoff,
        vwidth,vheight;
  long dflags,method;
} ProRGBHeader;

typedef struct {
  unsigned char r,g,b;
} rgb;

#define BM 0x4D42

typedef struct {
  unsigned char b,g,r;
} w_rgb;

typedef struct {
  /*short bfType;	avoid SPARC alignment problems - deal separately! */
  long bfSize;
  short bfReserved1,bfReserved2;
  long bfOffBits;
} BITMAPFILEHEADER;

typedef struct {
  long biSize,biWidth,biHeight;
  short biPlanes,biBitCount;
  long biCompression,biSizeImage,
       biXPelsPerMeter,biYPelsPerMeter,
       biClrUsed,biClrImportant;
} BITMAPINFOHEADER;

SafeRead(fp,buf,len)
FILE *fp;
char *buf;
int len;
{
  if (fread(buf,1,len,fp)!=len) {
    puts("\nError while reading file.\n");
    return(TRUE);
  }

  return(FALSE);
}

SafeWrite(fp,buf,len)
FILE *fp;
char *buf;
int len;
{
  if (fwrite(buf,1,len,fp)!=len) {
    puts("\nError while writing file.\n");
    return(TRUE);
  }

  return(FALSE);
}

Swap4(arg)
int arg;
{
   return (
     ((arg&0xFF000000) >> 24) |
     ((arg&0x00FF0000) >> 8) |
     ((arg&0x0000FF00) << 8) |
     ((arg&0x000000FF) << 24));
}

Swap2(arg)
int arg;
{
   return (
     ((arg&0xFF00) >> 8) |
     ((arg&0x00FF) << 8));
}

   unsigned char 
main(argc,argv)
int argc;
char *argv[];
{
  static char pro_id[PROIDLEN+1];
  ProRGBHeader pro_hdr;
  static BITMAPFILEHEADER bm;
  static BITMAPINFOHEADER bi;
  UBYTE *buf=NULL,*tmp;
  rgb *switch_p,color;
  w_rgb *switch_b;
  int i,j,linesize,bufsize;
  unsigned short word;
  FILE *fp=NULL;

  puts("Pro2BMP: 3-D Professional to Windows converter - djh\n");

  if (argc<3) {
    puts("Usage: Pro2BMP <infile> <outfile>");
    goto cleanup;
  }

  if (!(fp=fopen(argv[1],"r"))) {
    printf("Error: couldn't open ProRGB file %s for reading.\n",argv[1]);
    goto cleanup;
  }

  if (SafeRead(fp,pro_id,PROIDLEN)) goto cleanup;
  if (SafeRead(fp,&pro_hdr,sizeof(pro_hdr))) goto cleanup;

  if (pro_hdr.method!=STD_METHOD) {
    printf("\nError: storage method %d not recognized!\n",pro_hdr.method);
    goto cleanup;
  }

  printf("Converting [Width=%d,Height=%d]... ",pro_hdr.width,pro_hdr.height);

  linesize=pro_hdr.width*RGBSIZE;
  bufsize=linesize*pro_hdr.height;

  tmp=buf=AllocMem(bufsize,MEMF_CHIP|MEMF_CLEAR);

  for (i=0;i<pro_hdr.height;i++) {
    if (SafeRead(fp,tmp,linesize)) goto cleanup;
    tmp+=linesize;
  }

  fclose(fp); fp=NULL;

  if (!(fp=fopen(argv[2],"w"))) {
    printf("Error: couldn't open BMP file %s for writing.\n",argv[2]);
    goto cleanup;
  }

  word=Swap2(BM);
  if (SafeWrite(fp,&word,sizeof(word))) goto cleanup;

  bm.bfSize=
    Swap4(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(short)+bufsize);
  bm.bfOffBits=
    Swap4(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(short));
  if (SafeWrite(fp,&bm,sizeof(bm))) goto cleanup;

  bi.biSize=Swap4(sizeof(BITMAPINFOHEADER));
  bi.biSizeImage=Swap4(bufsize);
  bi.biWidth=Swap4(pro_hdr.width);
  bi.biHeight=Swap4(pro_hdr.height);
  bi.biPlanes=Swap2(1);
  bi.biBitCount=Swap2(24);

  if (SafeWrite(fp,&bi,sizeof(bi))) goto cleanup;
  
  for (i=0;i<pro_hdr.height;i++) {
    tmp-=linesize;

    switch_p=(rgb *)tmp;
    switch_b=(w_rgb *)tmp;

    for (j=0;j<pro_hdr.width;j++) {
      color=*switch_p++;
      switch_b->r=color.r;
      switch_b->g=color.g;
      switch_b->b=color.b;
      switch_b++;
    }

    if (SafeWrite(fp,tmp,linesize)) goto cleanup;
  }

  puts("Done.");

cleanup:
  if (buf) FreeMem(buf,bufsize);
  if (fp) fclose(fp);
}
