/*
**
**      Projekt         : ShowPicasso - IFF für PicassoII
**      Version         : 1.04
**      File            : ShowPicasso
**      Status          : Public Domain
**
**      Autor           : Ranner Michael
**      Datum           :  7. November 1993
**      Letzte Änderung : 11. Juni 1994
**
**      This programm will only run, if the monitor file supplied
**      with your graphics card is installed and running.
**
**      Anmerkung       : Strukturierung verbessern;
**                        Optimierungen durchführen;
**
*/

extern struct Library *SysBase;
extern struct Library *DOSBase;
struct Library   *VilIntuiBase;
struct Library  *IntuitionBase;
struct Library       *IconBase;
struct Library        *AslBase;
struct Library        *GfxBase;
struct Library   *IFFParseBase;
struct Library     *LocaleBase;

#include "ShowPicasso.h"

struct Catalog *catalog = NULL;

static UBYTE version[]   = "$VER: ShowPicasso 1.04 - © Ranner Michael (11.06.94)";
static UBYTE templ[]     = "FILENAME/M,DD=DEFDIR/K,PAT/K,CB=CBUF/K/N,NC=NOCENTER/S,NS=NOAUTOSCROLL/S,"
                           "BH=BEHIND/S,HI15/S,HI16/S,QU=QUIET/S,RHEIGHT/K/N,RWIDTH/K/N,RTOP/K/N,"
                           "RLEFT/K/N,PUBSCREEN/K";

static struct {
               UBYTE  **pics;
               UBYTE   *ddir;
               UBYTE   *pat;
               LONG    *cbuf;
               LONG   nocent;
               LONG   noscrl;
               LONG   behind;
               LONG     hi15;
               LONG     hi16;
               LONG    quiet;
               LONG  *height;
               LONG   *width;
               LONG     *top;
               LONG    *left;
               UBYTE *pubscr;
              } cliparams={ NULL,NULL,NULL,NULL,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,NULL,NULL,NULL,NULL,NULL };

/* Strukturen für den Picassoscreen */

struct TagItem screentags[] = { { TAVIS_SCREEN_WIDTH },
                                { TAVIS_SCREEN_HEIGHT },
	                        { TAVIS_SCREEN_DEPTH },
                                { TAVIS_OPEN_BEHIND, FALSE },
                                { TAVIS_BEST_MODEID, TRUE },
                                { TAVIS_ALLOW_FALLBACK },
                                { TAVIS_AUTOSCROLL, TRUE },
                                { TAG_DONE } };

struct TagItem modetags[] = { { TAVIS_SCREEN_WIDTH },
                              { TAVIS_SCREEN_HEIGHT },
	                      { TAVIS_SCREEN_DEPTH },
                              { TAG_DONE } };

struct NewWindow     nw;  
struct Screen *s = NULL;
struct Window *w = NULL;

/* Globale Flags */

UWORD        IFFSTATE; /* Flags für IFF */
UWORD USERFLGS = NULL; /* Programm Flags User/Privat */

BOOL  WARGFLG = FALSE; /* Flag für Workbench args */
BOOL  FILEFLG = FALSE; /* File von Shell oderr WB   */
BOOL  WBSTART = TRUE;  /* Flag für Start von WB  */

/* Default Strings */

static UBYTE nullstr[]   = "";
static UBYTE dpatstr[]   = "#?";

UBYTE         *pubscrname=NULL;

/* Filenamenliste */

UBYTE         *dirname=nullstr;
UBYTE         *pattern=dpatstr;
BPTR             *dirlock=NULL;
ULONG           *filename=NULL;
UBYTE               nfile=NULL;

struct FileRequester  *fr=NULL;
struct RDArgs        *rda=NULL;
struct DiskObject   *dobj=NULL;

/* Strukturen für ASL File Requester */

ULONG aslh,aslw,aslt,asll; /* Angaben des User für Größe und Position des Filerequester */

struct TagItem ASLFRtags[] = { { ASLFR_TitleText, (LONG)"ShowPicasso" },
                               { ASL_FuncFlags, FILF_MULTISELECT|FILF_PATGAD },
                               { ASL_Dir },
                               { ASL_Pattern },
                               { ASL_Height },
                               { ASL_Width },
                               { ASL_LeftEdge },
                               { ASL_TopEdge },
                               { ASLFR_Screen },
                               { TAG_DONE } };

/* IFF ILBM */

struct IFFHandle *picture=NULL;
BitMapHeader        *bmhd=NULL;
UBYTE              *color=NULL;

/* Buffer für Entpackroutine */

ULONG          cbufsize=0x4000;   /* Größe von cbuf für AllocVec() */
UBYTE               *cbuf=NULL;   /* Zwischenspeicher für gecrunchte Daten */

/* Unterroutinen */

#include "sp_protos.h"
#include "sp_catalog.c"
#include "sp_tools.c"
#include "sp_iff.c"

/* Öffnen und Schließen der Bild Datei 
**
** Gibt einen BYTE Wert zurück der das Dateiformat bestimmt.
** 0 Fehler
** 1 IFF-ILBM
** 2 IFF-RGBN
** 3 IFF-RGB8
**
*/

BYTE OpenPic(UBYTE *picname)
{
 LONG error=NULL;
 BPTR filehandle=NULL;
 BYTE type;

 if(picture=AllocIFF())
 {

  if(filehandle=Open(picname,MODE_OLDFILE))
  {
   picture->iff_Stream = filehandle;
   InitIFFasDOS(picture);

   if(!(error = OpenIFF(picture,IFFF_READ)))
   {

    if(type = IsIFF(picture)) return(type); 
    else OutText(GetString(MSG_NOTKNOWN));
    CloseIFF(picture);
   }
   else OutText(GetString(MSG_EOPENIFF));
  }
  else OutText(GetString(MSG_NOFILE));
 }
 else OutText(GetString(MSG_EALLOCMEM));

 if(filehandle)
 { 
  Close(filehandle);
  picture->iff_Stream = NULL;
 }
 return(NULL);
}

VOID ClosePic(BPTR filehandle)
{
 if(picture)
 { 
  CloseIFF(picture);
  FreeIFF(picture);
 }
 if(filehandle) Close(filehandle);
}

/* Öffnen eines Picasso Screen */

BOOL OpenDisplay(BitMapHeader *bmap,ULONG mode)
{
 struct  DimensionInfo dimension;
 DisplayInfoHandle        handle; 

 UBYTE        sd = bmap->nPlanes;
 UWORD              sw = bmap->w;
 UWORD              sh = bmap->h;
 BOOL            TRYAGAIN = TRUE;

 if(USERFLGS & UFLG_BEHIND) screentags[3].ti_Data = TRUE; /* Screen Behind */

 if(sd == 12) sd = 15L;                 /* Screentiefe 15 Bit bei 12 Planes */
 if(USERFLGS & PFLG_TRUECLR)
 {
  if(USERFLGS & PFLG_TC15BIT) sd = 15L; /* Screentiefe 15 Bit bei Hicolor */
  if(USERFLGS & PFLG_TC16BIT) sd = 16L; /* Screentiefe 16 Bit bei Hicolor */
 }
 if(mode & HAM_KEY)
 {
  if(sd == 6) sd = 15L;                 /* Screentiefe 15 Bit bei HAM6 */
  if(sd == 8) sd = 24L;                 /* Screentiefe 24 Bit bei HAM8 */
 }

TryAgain:

 if(!(USERFLGS & UFLG_NOSCROLL))
 {
  modetags[0].ti_Data = sw;
  modetags[1].ti_Data = sh;
  modetags[2].ti_Data = sd;
  screentags[4].ti_Tag = TAVIS_SCREEN_MODEID;
  screentags[4].ti_Data = VillageBestModeID(modetags);

  if(handle = FindDisplayInfo(screentags[4].ti_Data))
  {
   if(GetDisplayInfoData(handle,(UBYTE *)&dimension,sizeof(dimension),DTAG_DIMS,TAG_DONE))
   {
    if(dimension.Nominal.MaxX+1 > sw) sw = dimension.Nominal.MaxX+1;
    if(dimension.Nominal.MaxY+1 > sh) sh = dimension.Nominal.MaxY+1;
   }
  }
 }

 screentags[0].ti_Data = sw; /* Screenweite */
 screentags[1].ti_Data = sh; /* Screenhöhe  */
 screentags[2].ti_Data = sd; /* Screentiefe */


 if(s = OpenVillageScreenTagList(screentags))
 {
  nw.LeftEdge  = 0; 
  nw.TopEdge   = 0;
  nw.Width     = s->Width;
  nw.Height    = s->Height;
  nw.FirstGadget = NULL; 
  nw.Title     = NULL;
  nw.IDCMPFlags= IDCMP_VANILLAKEY | IDCMP_MOUSEBUTTONS;
  nw.Flags     = WFLG_BACKDROP | WFLG_BORDERLESS | WFLG_RMBTRAP | WFLG_ACTIVATE;
  nw.Type      = CUSTOMSCREEN;
  nw.Screen    = s;

  if (w = OpenWindow(&nw)) return(TRUE);
 }
 else 
 {
  if(TRYAGAIN)
  {
   if((USERFLGS & PFLG_TRUECLR) && (USERFLGS & UFLG_AUTO16))
   {
    sd = 16;
    USERFLGS |= PFLG_TC16BIT;
    TRYAGAIN = FALSE;
    goto TryAgain;
   }
  }
 }
 return(FALSE);
}

VOID CloseDisplay(VOID)
{
 if(w) 
 {
  CloseWindow(w);
  w = NULL;
 }
 if(s) 
 {
  CloseVillageScreen(s);
  s = NULL;
 }
}

VOID GetPubScrName(UBYTE *name)
{
 register LONG i;

 if(pubscrname = AllocVec(strlen(name),MEMF_PUBLIC|MEMF_CLEAR))
 {
  for(i=0; i<strlen(name); i++) pubscrname[i] = name[i];
 }
}

/* Shell Argumente einlesen */


VOID GetArgs(int arg,struct WBStartup *wbs)
{
 struct WBArg     *wbargs;

 UBYTE        **toolarray;
 STRPTR            string;
 BPTR               olock;
 BPTR               dlock;
 register          LONG i;


 if(arg) /* Start von Shell */
 {
  if(rda = ReadArgs(templ,(LONG *)&cliparams,NULL))
  {
   if(cliparams.ddir) dirname = cliparams.ddir;
   if(cliparams.pat) pattern = cliparams.pat;
   if(cliparams.pubscr) GetPubScrName(cliparams.pubscr);
   if(cliparams.cbuf) cbufsize = *(cliparams.cbuf) * 1024L;
   if(cliparams.nocent) USERFLGS |= UFLG_NOCENTER;
   if(cliparams.noscrl) USERFLGS |= UFLG_NOSCROLL;
   if(cliparams.behind) USERFLGS |= UFLG_BEHIND;
   if(cliparams.hi15) USERFLGS |= PFLG_TC15BIT;
   if(cliparams.hi16) USERFLGS |= PFLG_TC16BIT;
   if(cliparams.quiet) USERFLGS |= UFLG_QUIET;
   if(cliparams.height) aslh = *(cliparams.height);
   if(cliparams.width) aslw = *(cliparams.width);
   if(cliparams.top) aslt = *(cliparams.top);
   if(cliparams.left) asll = *(cliparams.left);
   if(cliparams.pics)
   {
    FILEFLG = TRUE;

    FOREVER
    {
     if(!(cliparams.pics[nfile])) break;
     nfile++;
    }

    if(filename = AllocVec(4 * nfile,MEMF_PUBLIC|MEMF_CLEAR))
    {
     for(i=0; i < nfile; i++) filename[i] = (ULONG)(cliparams.pics[i]);
    }
   }
  }
 }
 else     /* Start von Workbench */
 {
  wbargs = wbs->sm_ArgList;
  dlock = wbargs->wa_Lock;
  olock = CurrentDir(dlock);
  
  if((wbargs->wa_Name) && (dobj=GetDiskObject(wbargs->wa_Name)))
  {
   toolarray = (UBYTE **)dobj->do_ToolTypes;
   if(string = FindToolType(toolarray,"DEFDIR")) dirname = string;
   if(string = FindToolType(toolarray,"PATTERN")) pattern = string;
   if(string = FindToolType(toolarray,"CBUF"))
   {
    if(!(cbufsize = 1024L * stol(string))) cbufsize = 0x4000;
   }
   if(string = FindToolType(toolarray,"RHEIGHT")) aslh = stol(string);
   if(string = FindToolType(toolarray,"RWIDTH")) aslw = stol(string);
   if(string = FindToolType(toolarray,"RTOP")) aslt = stol(string);
   if(string = FindToolType(toolarray,"RLEFT")) asll = stol(string);
   if(MatchToolValue(FindToolType(toolarray,"CENTER"),"NO")) USERFLGS |= UFLG_NOCENTER;
   if(MatchToolValue(FindToolType(toolarray,"AUTOSCROLL"),"NO")) USERFLGS |= UFLG_NOSCROLL;
   if(MatchToolValue(FindToolType(toolarray,"BEHIND"),"YES")) USERFLGS |= UFLG_BEHIND;
   if(string = FindToolType(toolarray,"HICOLOR"))
   {
    if(MatchToolValue(string,"15")) USERFLGS |= PFLG_TC15BIT;
    if(MatchToolValue(string,"16")) USERFLGS |= PFLG_TC16BIT;
    if(MatchToolValue(string,"AUTO")) USERFLGS |= UFLG_AUTO16;
   }
   if(string = FindToolType(toolarray,"PUBSCREEN")) GetPubScrName(string); 
  }
  CurrentDir(olock);

  if((wbs->sm_NumArgs) > 1)
  {
   FILEFLG = TRUE;
   WARGFLG = TRUE;

   nfile = (wbs->sm_NumArgs) - 1;

   if((dirlock = AllocVec(nfile * 4,MEMF_PUBLIC|MEMF_CLEAR)) &&
      (filename = AllocVec(nfile * 4,MEMF_PUBLIC|MEMF_CLEAR)))
   {
    for(i=0; i < nfile; i++)
    {
     wbargs++;
     if(wbargs->wa_Lock) { dirlock[i] = wbargs->wa_Lock; }
     else { dirlock[i] = dlock; }
     filename[i] = (ULONG)wbargs->wa_Name;
    }
   }
  }
 }   
}


/* ASL Filerequester */


BOOL FileRequest(void)
{
 struct Screen *pubscr;
 struct WBArg  *frargs;

 ULONG rh=400L,rw=318L;
 ULONG      rleft,rtop;
 BOOL      error=FALSE;
 register       LONG i;

 if(pubscr = LockPubScreen(pubscrname))
 {

  if(!fr)
  {
   if(aslh)
   {
    rh = aslh; /* Benutzerwert für Requesterhöhe übernehmen */
    if(rh < 155) rh = 155L;
   }
   else
   {
    if(pubscr->Height <= 400) rh = 200L; /* Defaultwerte */
   }

   if(aslw)
   {
    rw = aslw; /* Benutzerwert übernehmen; Default Requesterweite ist 318 */
    if(rw < 262) rw = 262L;
   }

   if(asll) rleft = asll; /* Benutzerwert für Left Position übernehmen */
   else rleft = (pubscr->Width -  rw) / 2; /* Default: Requester in der Mitte zentriert. */

   if(aslt) rtop = aslt; /* Benutzerwert für Top Position übernehmen */
   else rtop  = (pubscr->Height - rh) / 2; /* -''- */

   ASLFRtags[2].ti_Data = (LONG)dirname; /* Parameter in die Tags schreiben */
   ASLFRtags[3].ti_Data = (LONG)pattern;
   ASLFRtags[4].ti_Data = rh;
   ASLFRtags[5].ti_Data = rw;
   ASLFRtags[6].ti_Data = rleft; 
   ASLFRtags[7].ti_Data = rtop;
   ASLFRtags[8].ti_Data = (LONG)pubscr;

   /* Abfrage auf Workbench 2.1, wenn ja, kann Requester auf jedem Pubscreen öffnen */

   if((AslBase->lib_Version) < 38L) ASLFRtags[8].ti_Tag = TAG_DONE; 

   fr = (struct FileRequester *)AllocAslRequest(ASL_FileRequest,ASLFRtags);

  }

  if(fr)
  {

   if(AslRequest(fr,NULL))
   {

    if(nfile = fr->rf_NumArgs)
    {
     frargs = fr->rf_ArgList;
     dirname = fr->rf_Dir;

     if(filename = AllocVec(4 * nfile,MEMF_PUBLIC|MEMF_CLEAR))
     {
      for(i = 0; i < fr->rf_NumArgs; i++) filename[i] = (ULONG)frargs[i].wa_Name;
     } 
    } 
   }
   else error = TRUE;

  }
  else error = TRUE;

  UnlockPubScreen(NULL,pubscr);
 }

 else
 {
  OutText(GetString(MSG_NOPUBSCR));
  error = TRUE;
 }

 return(error);
}


/* Hauptprogramm */


VOID main(int argc,struct WBStartup *wbs)
{
 struct      Message *msg=NULL;
 struct  ContextNode *top=NULL;

 LONG               error=NULL;
 LONG          filecnt,size[3];
 /* ULONG         secs,mics,secs1; */
 BPTR              dlock,olock;
 BYTE                 datatype;
 ULONG                  modeid;
 ULONG                  ncolor; /* number of colors */
 register LONG             i,j;

 if(OpenLibs())
 {
  if(argc) WBSTART = FALSE;
  if(LocaleBase) catalog = OpenCatalogA(NULL,"showpicasso.catalog",NULL);
  GetArgs(argc,wbs);
  if(GetWorkSpace())
  {
   do
   {
    if(!FILEFLG) FILEFLG = FileRequest();

    if(filename)
    {

     if(dirname) dlock = Lock(dirname,ACCESS_READ); 

     for(filecnt=0; filecnt < nfile; filecnt++)
     {
      IFFSTATE = NULL;
      USERFLGS &= 0xf0ff;

      if(USERFLGS & UFLG_AUTO16) USERFLGS &= 0x00ff; /* Falls "HICOLOR=AUTO" Hicolor Bits  wieder löschen */

      if(WARGFLG) { olock = CurrentDir(dirlock[filecnt]); }
      else { if(dirname) olock = CurrentDir(dlock); }

       

      if(datatype = OpenPic((UBYTE *)*(filename+filecnt)))
      {

       switch(datatype)
       {
        case 1:

        IFFSTATE |= ILBMFLG;
        break;

        case 2:

        IFFSTATE |= RGBNFLG;
        break;

        case 3:

        IFFSTATE |= RGB8FLG;
        break;
       }

       FOREVER
       {
        error=ParseIFF(picture,IFFPARSE_RAWSTEP);

        if(error == IFFERR_EOC) continue;
        else if(error) error = ERR_PRSIFF;

        if(top=CurrentChunk(picture))
        {

         if((top->cn_ID) == ID_BMHD)
         {
          if(IFFSTATE & BMHDFLG) error = ERR_CHKE2T;
          else
          {
           if(GetBMHD(picture,bmhd))
           {
            if(bmhd->nPlanes == 13)                 /* Pseudo 13 für RGBN */
            {
             bmhd->nPlanes = 12;
            }
            if(bmhd->nPlanes == 24) USERFLGS |= PFLG_TRUECLR;
            if(bmhd->nPlanes == 25)                 /* Pseudo 25 für RGB8 */
            {
             USERFLGS |= PFLG_TRUECLR;
             bmhd->nPlanes = 24;
            }
           }
           else error = ERR_MGLIFF;
           IFFSTATE |= BMHDFLG;
          }
          ncolor = 1L<<bmhd->nPlanes;
         }

         if((top->cn_ID) == ID_CAMG) 
         {
          if(IFFSTATE & CAMGFLG) error = ERR_CHKE2T;
          else
          {
           if(GetCAMG(picture,&modeid))
           {
            if(modeid & EXTRAHALFBRITE_KEY)
            {
             ncolor = 32;
            }
            if(modeid & HAM_KEY)
            {
             if(bmhd->nPlanes == 6) ncolor = 16;
             if(bmhd->nPlanes == 8) ncolor = 64;
            }
           }
           else error = ERR_MGLIFF;
           IFFSTATE |= CAMGFLG;
          }
         }

         if((top->cn_ID) == ID_CMAP)
         {
          if(IFFSTATE & CMAPFLG) error = ERR_CHKE2T;
          else
          {
           if(!((USERFLGS & PFLG_TRUECLR) || (IFFSTATE & RGBNFLG)))
           {
            if(!GetCMAP(picture,color,ncolor)) error = ERR_MGLIFF;
           }
           IFFSTATE |= CMAPFLG;
          }
         }

         if((top->cn_ID) == ID_BODY)
         {
          if((IFFSTATE & BMHDFLG) && ((USERFLGS & PFLG_TRUECLR) || (IFFSTATE & CMAPFLG) || (IFFSTATE & RGBNFLG))) break;
          else error = ERR_MGLIFF;
         }
        }
        if(error) break;
       }

       /* CurrentTime(&secs,&mics); */

       if((!error) && OpenDisplay(bmhd,modeid))
       {

        /* Kein Error nur möglich wenn BODY Chunk gefunden 
           Auslesen der Chunk Daten, konvertieren und in   
           die Bitmap schreiben. Farbregister setzen */

        if((IFFSTATE & CMAPFLG) && !(USERFLGS & PFLG_TRUECLR))
        {
         j=0;         

         Delay(2L);

         /* Without the Delay() function the color registers will not be correctly set.
            This seems to be a bug in the firmware */
         

         /* Das seltsame j<<(8-bmhd->nPlanes) kommt durch die seltsame
            Planar => Chunky Konvertierung zustande (Assembler). */

         for(i=0; i <= (3*ncolor-3); i += 3)
         {
          SETRGB(s,j<<(8-bmhd->nPlanes),color[i],color[i+1],color[i+2]);
          j++;
         }

         if(modeid & EXTRAHALFBRITE_KEY)
         {
          for(i=0; i <= (3*ncolor-3); i += 3)
          {
           SETRGB(s,j<<(8-bmhd->nPlanes),color[i]>>1L,color[i+1]>>1L,color[i+2]>>1L);
           j++;
          }
         }
        }

        if(IFFSTATE & ILBMFLG)
        {
         if(!GetBODY_ILBM(picture,bmhd,modeid,s)) error = ERR_MGLIFF;
        }
        else
        {
         if(!GetBODY_RGBx(picture,bmhd,s)) error = ERR_MGLIFF;
        }

        if(USERFLGS & UFLG_BEHIND) ScreenToFront(s);
        /* CurrentTime(&secs1,&mics); */

        if(!error)
        {
         Wait(WSig);
         while(msg = GetMsg(w->UserPort)) ReplyMsg(msg);
        }
       }
       else if(!error) error = ERR_NOSCR;
       CloseDisplay();

       switch(error)
       {
        case ERR_CHKE2T:
        OutText(GetString(MSG_CHKEXIST2));
        break;

        case ERR_MGLIFF:
        OutText(GetString(MSG_MIFFILBM));
        break;

        case ERR_PRSIFF:
        OutText(GetString(MSG_MIFFILBM));
        break;

        case ERR_NOSCR:
        OutText(GetString(MSG_NOSCR));
        break;
       }

       if(argc && !error && !(USERFLGS & UFLG_QUIET)) 
       {
        size[0] = bmhd->w;
        size[1] = bmhd->h;
        size[2] = bmhd->nPlanes;
        VPrintf("%ldx%ldx%ld : ",size);
        PutStr((UBYTE *)*(filename+filecnt));
        PutStr("\n");
        /*
        error = secs1 - secs;
        VPrintf(" - Zeit: %ld s\n",&error);
        */
       }

       ClosePic(picture->iff_Stream);
      }

      if(WARGFLG) { CurrentDir(olock); }
      else { if(dirname) CurrentDir(olock); }
     }

     if(dirname) UnLock(dlock);
      
     FreeVec(filename);
     filename = NULL;
    }
   } while(!FILEFLG);

   if(dirlock) FreeVec(dirlock);
   if(pubscrname) FreeVec(pubscrname);
   if(dobj) FreeDiskObject(dobj);
   if(fr) FreeAslRequest(fr);
   if(rda) FreeArgs(rda);

   FreeWorkSpace();
  }
  else OutText(GetString(MSG_EALLOCMEM));  
 }
 else OutText(GetString(MSG_EOPENLIBS));
 CloseLibs();
}
