#include <intuition/intuition.h>
#include <functions.h>
#include <libraries/dos.h>
#include <exec/memory.h>
#include <stdio.h>

struct IntuitionBase *IntuitionBase = 0;
struct GfxBase *GfxBase = 0;
struct Screen *Screen = 0;

/*--------------------------------------------------------------------------*/

void allclose (error)

int error;

{
   if (Screen) CloseScreen (Screen);
   if (GfxBase) CloseLibrary (GfxBase);
   if (IntuitionBase) CloseLibrary (IntuitionBase);
   exit (error);
}

/*--------------------------------------------------------------------------*/

void intopen()

{
   IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library",0L);
   if (IntuitionBase == NULL)
   {
      printf ("Kann intuition.library nicht öffnen!\n");
      allclose (10);
   }
}

/*--------------------------------------------------------------------------*/

void gfxopen()

{
   GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library",0L);
   if (GfxBase == NULL)
   {
      printf ("Kann graphics.library nicht öffnen!\n");
      allclose (10);
   }
}

/*--------------------------------------------------------------------------*/

struct Screen *scropen (breite, hoehe, planes, modes)

SHORT breite, hoehe, planes;
USHORT modes;

{
   struct NewScreen NewScreen;

   NewScreen.LeftEdge = 0; NewScreen.TopEdge = 0;
   NewScreen.Width = breite; NewScreen.Height = hoehe;
   NewScreen.Depth = planes;
   NewScreen.DetailPen = 0; NewScreen.BlockPen = 1;
   NewScreen.ViewModes = modes;
   NewScreen.Type = CUSTOMSCREEN;
   NewScreen.Font = NULL;
   NewScreen.DefaultTitle = NULL;
   NewScreen.Gadgets = NULL;
   NewScreen.CustomBitMap = NULL;
   Screen = (struct Screen *) OpenScreen (&NewScreen);
   if (Screen == NULL)
   {
      printf("Kann Screen nicht öffnen!\n");
      allclose (10);
   }
   ShowTitle (Screen,FALSE);
   return (Screen);
}

/*--------------------------------------------------------------------------*/

void err (str, f, bf, l, clr)

char *str;
struct FileHandle *f;
UBYTE *bf;
long l;
int clr;

{
   printf (str);
   Close (f);
   if (clr)
      FreeMem (bf, l);
   allclose (10L);
}

/*--------------------------------------------------------------------------*/

int cmp (a)

char *a;

{
   int i,j, in;
   char ch[25], *b, *c;

   b = a;
   c = (char *)ch;
   strcpy (ch,"FORMILBMBMHDCAMGCMAPBODY");
   for (j=6; j > 0; j--)
   {
      a = b;
      in = 1;
      for (i=0; i<=3; i++)
         if (*a++ != *c++)
            in = 0;
      if (in == 1)
         break;
   }
   return (j);
}

/*--------------------------------------------------------------------------*/

UBYTE *filecopy (str, len)

char *str;
long *len;

{
   struct FileHandle *fp;
   long in, *BufL;
   UBYTE buf[8], *BufFile;

   if ((fp = Open (str, MODE_OLDFILE)) == NULL)
      {printf ("File nicht zu öffnen!\n"); exit (10L);}
   if ((in = Read (fp, buf, 8L)) == -1L)
      err ("File nicht lesbar!\n", fp, BufFile, *len, 0);
   BufL = (long *) (buf);
   if (cmp((char *)BufL++) != 6)
      err ("Kein IFF File!\n", fp, BufFile, *len, 0);
   *len = *BufL;
   if ((BufFile = AllocMem (*len, MEMF_PUBLIC)) == NULL)
      err ("Zu wenig Speicher!\n", fp, BufFile, *len, 0);
   if ((in = Read (fp, BufFile, *len)) == -1L)
      err ("Lesefehler!\n", fp, BufFile, *len, 0);
   if (in != *len)
      err ("Filelänge falsch!\n", fp, BufFile, *len, 0);
   Close (fp);
   return (BufFile);
}

/*--------------------------------------------------------------------------*/

int GetBMHD (x, y, p, m, c, BWW)

SHORT *x, *y, *p;
USHORT *m;
UBYTE *c;
UWORD **BWW;

{
   int len;
   UWORD *BW;

   *BWW += 2;
   len = (int) **BWW;
   BW = (UWORD *) *BWW;
   BW++;
   *x = *BW++;
   if (*x > 352)
      *m |= HIRES;
   *y = *BW++;
   if (*y > 282)
      *m |= LACE;
   BW +=2;
   *p = (*BW++)>>8;
   if (*p == 6)
      *m |= HAM;
   *c = (*BW++)>>8;
   if (*c > 1)
      return (0);
   *BWW = *BWW + len/2 + 1;
   return (1);
}

/*--------------------------------------------------------------------------*/

void GetCAMG (m, BWW)

USHORT *m;
UWORD **BWW;

{
   int len;
   UWORD *BW;

   *BWW += 2;
   len = (int) **BWW;
   BW = (UWORD *) *BWW;
   BW += 2;
   *m = (*BW) & (EXTRA_HALFBRITE | HAM | LACE | HIRES);
   *BWW = *BWW + len/2 + 1;
}

/*--------------------------------------------------------------------------*/

void GetCMAP (BWW)

UWORD **BWW;

{
   int len;
   long z, rot, gruen, blau;
   UBYTE *BB;

   *BWW += 2;
   len = (int) **BWW;
   BB = (UBYTE *) *BWW;
   BB += 2;
   for (z=0; z < len/3; z++)
   {
      rot = *BB++;
      gruen = *BB++;
      blau = *BB++;
      SetRGB4 (&Screen->ViewPort, z, rot>>4, gruen>>4, blau>>4);
   }
   *BWW = *BWW + len/2 + 1;
}

/*--------------------------------------------------------------------------*/

void GetBODY (x, y, p, c, BWW)

SHORT *x, *y, *p;
UBYTE *c;
UWORD **BWW;

{
   long s, z, b, w, bd8;
   register UBYTE *BB, *PlHiZeig[6];
   UBYTE byte1;
   BYTE byte;

   *BWW += 1;
   BB = (UBYTE *) *BWW;
   BB += 4;
   for (b=0; b < *p; b++)
      PlHiZeig[b] = Screen->RastPort.BitMap->Planes[b];
   bd8 = (*x)/8;
   for (z=0; z < *y; z++)
      for (b=0; b < *p; b++)
      {
         s = 0;
         do
         {
            if (*c == 0)
            {
               *PlHiZeig[b]++ = *BB++;
               s++;
            }
            else
            {
               byte = *BB++;
               if (byte == -128)
                  ;
               else if (byte >= 0)
               {
                  for (w=0; w <= byte; w++)
                     *PlHiZeig[b]++ = *BB++;
                  s += w;
               }
               else
               {
                  byte1 = *BB++;
                  for (w=0; w <= -byte; w++)
                     *PlHiZeig[b]++ = byte1;
                  s += w;
               }
            }
         } while (s < bd8);
      }
}

/*--------------------------------------------------------------------------*/

main (argc, argv)

int argc;
char *argv[];

{
   int bekannt, ChunkNr;
   long DatLen;
   char *LeftMouse;
   SHORT breite, hoehe, plz;
   USHORT mode;
   UBYTE comp, *BufZeig, *Buffer;
   UWORD *BufWord;

   if (argc != 2)
   {
      printf ("Usage: %s Picture_Name\n", argv[0]);
      exit (10L);
   }
   mode = NULL;
   intopen ();
   gfxopen ();
   BufZeig = filecopy (argv[1], &DatLen);
   Buffer = BufZeig;
   BufWord = (UWORD *) Buffer;
   if (cmp((char *)BufWord) != 5)
   {
      printf ("Kein IFF Bild\n");
      FreeMem (Buffer, DatLen);
      exit (10L);
   }
   BufWord += 2;
   do
   {
      ChunkNr = cmp((char *)BufWord++);
      switch (ChunkNr)
      {
         case 4 : 
         {
            bekannt = GetBMHD (&breite, &hoehe, &plz, &mode, &comp, &BufWord);
            if (!bekannt)
            {
               printf ("Unbekannter Packalgorithmus!\n");
               FreeMem (Buffer, DatLen);
               allclose (0L);
            }
            break;
         }
         case 3 :
         {
            GetCAMG (&mode, &BufWord);
            break;
         }
         case 2 :
         {
            Screen = scropen (breite, hoehe, plz, mode);
            GetCMAP (&BufWord);
            break;
         }
         case 1 :
         {
            GetBODY (&breite, &hoehe, &plz, &comp, &BufWord);
            LeftMouse = (char *) 0xbfe001;
            while ((*LeftMouse & 0x40)==0x40)
               Delay (5L);
            break;
         }
      }
   } while (ChunkNr != 1);
   FreeMem (Buffer, DatLen);
   allclose (0L);
}

/*--------------------------------------------------------------------------*/
