/* opalpcd.c v0.30
       program to display PhotoCD  pictures and save them to OpalVision
   files and display.  This will read the file and convert it to a 
   virtual screen which may be saved in a JPEG or IFF24 file.
   
   
   This program is based on hpcdtoppm by Hadmut Danisch  
   
   OH Yeah, Its going to take helluva lotta memory 
                       base =1.5m, 4base=6meg, 16base =24m 
                       Picked up and adapted by BAZZ on 3-2-93
I will have to use RGB toOV, and may have to break it up into
 several modules to save RAM. 
 
    Additions © BAZZ 1993, and similar conditions as Hadmut states apply, that
is pass it around all you want, but dont take credit for it (unless you 
add to it) and don't distribute for profit.  This is intended to enrich the 
Amiga community and is for educational purposes only.

    Rev .20
    As of 3-8 I had resolutions up thru Base working.  The decompression isnt
working right on 4Base and is being looked into.  This will print out on an
OpalVision screen.  The library should allown IFF24 conversion and is included
with many utilities.  It might work without it but not guaranteed.    
       
       
    Rev .30      
    As of April 15, Resolution 4 is working now but takes a machine with
12 Meg of FAST Ram to load the entire picture.  With 6-8 Meg fast you can 
crop parts out.  Unfortunately the requirement is h*w*6, and the only way
around it is radically rewriting the code.  I have no incentive to do this
since I have enough memory, and resolution 5 (3072x2048) isn't working yet.
doing a 'dummy test' found that none of the compression beyond the first
Luma compression worked.  When this works, I'll consider it. 
    The Overview mode is fixed now and shows 16 small pictures on a page. 
Pressing right button goes to next page, and pressing left exits.  When
the top is reached it cycles back to the first page.  
    Also fixed a bug that left Opal screen open if an error is encountered.
               
       This was compiled using SAS/C® V 6.02
               */




/* hpcdtoppm (Hadmut's pcdtoppm) v0.1
*  Copyright (c) 1992 by Hadmut Danisch (danisch@ira.uka.de).
*  Permission to use and distribute this software and its
*  documentation for noncommercial use and without fee is hereby granted,
*  provided that the above copyright notice appear in all copies and that
*  both that copyright notice and this permission notice appear in
*  supporting documentation. It is not allowed to sell this software in 
*  any way. This software is not public domain.
*/




#define xDEBUG
/* extern char *malloc(); */

#include <proto/all.h>
#include <opal/opallib.h>
#include <graphics/gfxbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <String.h>
#include <dos.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/asl.h>
#include <exec/execbase.h>
#include <graphics/gfxmacros.h>
#include <hardware/custom.h>
#
#include <devices/timer.h>
#include <workbench/startup.h>
#include <time.h>

#include <math.h>  /* lets give it something to REALLY Render */
#include <m68881.h> /* use co pro wherever possible */

typedef unsigned long dim;

#define BaseW ((dim)768)
#define BaseH ((dim)512)

#define   DISP_W   736
#define   DISP_H   476 /* hi-res screen */ 


#define slen 3072 /* try to keep all defines here! */


#define SECSIZE 0x800 /* 2k for CDrom */
#define RBMASK  0x0400 

#define ASKIP { argc--; argv ++;}
#define ABACK { argc++; argv --;} /* added incase we have something wrong */    

#define SeHead   2
#define L_Head   (1+SeHead)

#define SeBase16 18
#define L_Base16 (1+SeBase16)

#define SeBase4  72
#define L_Base4  (1+SeBase4)

#define SeBase   288
#define L_Base   (1+SeBase)
#define S_DEFAULT S_Base  /* default to base */


#define VERS     30   /* current version */



enum ERRORS { E_NONE,E_READ,E_WRITE,E_INTERN,E_ARG,E_OPT,E_MEM,E_HUFF,
       E_SEQ,E_SEQ1,E_SEQ2,E_SEQ3,E_SEQ4,E_SEQ5,E_SEQ6,E_SEQ7,E_POS,
       E_IMP,E_COOL,E_OVD,E_SCR,E_NCDS,E_ABT };

enum TURNS  { T_NONE,T_RIGHT,T_LEFT };

enum SIZES  { S_UNSPEC,S_Base16,S_Base4,S_Base,S_4Base,S_16Base,
    S_4BaseHC, S_Over,   };

/* Default taken when no size parameter given */



struct ph1 /* the header for the Photo CD file */
 {char id1[8];
  char ww1[14];
  char id2[20];
  char id3[4*16+4];
  short ww2;
  char id4[20];
  char ww3[2*16+1];
  char id5[4*16];
  char idx[11*16];
 } ;


struct _implane
 {dim  mwidth,mheight,
             iwidth,iheight;
  byte *im;
 };
typedef struct _implane implane;

/* PROTOTYPES */
void   getout(void), cleanup(enum ERRORS);
void   telltime(char *, unsigned int *);
int Display_Mode_Check(void);
int DoOpal(int,int, char *fname);
int GetNextPic(int,int);
int TurnOpal( struct OpalScreen *, UBYTE **, int,int,int,int,int);
struct OpalScreen *OpenOpal(void);
static void planealloc(implane *,dim,dim);

static void interpolate(implane *);
static void ycctorgb(dim,dim, implane *,implane *,implane *);
static void readhqt(dim,dim,dim);
static void readhqtsub(struct pcdhqt *source,struct myhqt *ziel,int *anzahl);


static void decompress(dim,dim,implane *,implane *, implane *);
static void clear(implane *,int);
static void druckeid(void );
static void sharpit(implane *);
enum ERRORS readplain(dim,dim,implane *,implane *,implane*);

/* Global Variables */
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct OpalBase *OpalBase;
struct OpalScreen *OScrn;
struct WBArg *WBArg;
BOOL FromWB;

__far UBYTE *Button = (UBYTE *)0xbfe001;	/* Nasty */
__far UWORD *RButton= (UWORD *)0xdff016; /* read right button */

__far extern struct Custom custom; /* for registers */


        /* bit 10, use dff016 for right */
#define RIGHT   custom.joy1dat & 2
#define LEFT    custom.joy1dat & 0x200
#define UP     ( custom.joy1dat & 1 )    
#define DOWN   ( custom.joy1dat & 0x100) 
#define FIRE    (*Button & 0x80)
     
static FILE *fin=0,*fout=0;
static char *pcdname=0,*ppmname=0;
static char nbuf[100];
static byte sbuffer[SECSIZE]; /* Increase, allow for reading 2 sectors */
static byte sbufaux[SECSIZE];
static byte lumadump[3100]; /* for null char for mode 6 */

static int do_sharp,backdrop,crop;
static int init;

implane Luma, Chroma1,Chroma2; /* make them global */
dim w,h;
static int version,cropx,cropw,cropy,croph,jpeg; /* coords for cropping */

unsigned int clock1[2],clock2[2]; /* for timer */
 enum TURNS turn=T_NONE;






/* Using preprocessor for inline-procs */
#ifdef DEBUG
#define SEEK(x) { if (fseek(fin,((x) * SECSIZE),0)) cleanup(E_READ);\
                  fprintf(stderr,"S-Position %x\n",ftell(fin)); }
#else
#define SEEK(x) { if (fseek(fin,((x) * SECSIZE),0)) cleanup(E_READ);}
#endif


#define SKIP(n)  { if (fseek(fin,(n),1)) cleanup(E_READ);}
#define SKIPr(n) { if (fseek(fin,(n),1)) return(E_READ);}

#define READBUF   fread(sbuffer,sizeof(sbuffer),1,fin)
#define READ2BUF  fread(sbuffer,sizeof(sbuffer),2,fin) /* allow for 2 sectors or 4K */

#define TRIF(x,u,o,a,b,c) ((x)<(u)? (a) : ( (x)>(o)?(c):(b)  ))
#define NORM(x) x=TRIF(x,0,255,0,x,255)

void getout()
{
    cleanup(E_ABT);
} /* just to get out, this is the ^C trap */    


void cleanup(e)  /* leave and display why */
enum ERRORS e;
{
   switch(e)
   {case E_NONE:   return;
    case E_IMP:    fprintf(stderr,"Sorry, Not yet implemented.\n"); break;
    case E_READ:   fprintf(stderr,"Error while reading.\n"); break;
    case E_WRITE:  fprintf(stderr,"Error while writing.\n"); break;
    case E_INTERN: fprintf(stderr,"Internal error.\n"); break;
    case E_ARG:    fprintf(stderr,"Arguments !\n"); 
                   fprintf(stderr,"OpalPCD Access for Amiga V. %d \n",VERS);
                   fprintf(stderr,"Usage: opalpcd [options] pcd-file [IFF24file]\n");
                   fprintf(stderr,"Opts:\n");
                   fprintf(stderr,"     -i Give some (buggy) informations from fileheader\n");
                   fprintf(stderr,"     -s Apply simple sharpness-operator on the Luma-channel\n");
                   fprintf(stderr,"     -d Show differential picture only \n");
                   fprintf(stderr,"     -r Rotate clockwise for portraits\n");
                   fprintf(stderr,"     -l Rotate counter-clockwise for portraits\n");
                   fprintf(stderr,"     -a Enable AutoSync for Opal Display  \n");
                   fprintf(stderr,"     -p Presentation SLideShow all Images in cd0:\n");
                   fprintf(stderr,"     -b To place image as backdrop upon exit \n"); 
                   fprintf(stderr,"     -c x y [w] [h] crop output image.  \n");
                   fprintf(stderr,"        where x,y =coords of upper left. w&h are size\n");
                   fprintf(stderr,"     -j [quality] Save in Jpeg instead of IFF24  \n"); 
                   fprintf(stderr,"     -O Extract thumbnails from Overview file\n");
                   fprintf(stderr,"     -1 Extract  128x192  from Image file\n");
                   fprintf(stderr,"     -2 Extract  256x384  from Image file\n");
                   fprintf(stderr,"     -3 Extract  512x768  from Image file\n");
                   fprintf(stderr,"     -4 Extract 1024x1536 from Image file\n");
                   fprintf(stderr,"     -5 Extract 2048x3072 from Image file\n");
                   fprintf(stderr,"     -6 Extract 1024X1536 Enhanced Chroma\n");
                   break;
    case E_OPT:    fprintf(stderr,"These Options are not allowed together.\n");break;
    case E_MEM:    fprintf(stderr,"Not enough memory !\n"); break;
    case E_HUFF:   fprintf(stderr,"Error in Huffman-Code-Table\n"); break;
    case E_SEQ:    fprintf(stderr,"Error in Huffman-Sequence\n"); break;
    case E_SEQ1:    fprintf(stderr,"Error1 in Huffman-Seque nce\n"); break;
    case E_SEQ2:    fprintf(stderr,"Error2 in Huffman-Sequence\n"); break;
    case E_SEQ3:    fprintf(stderr,"Error3 in Huffman-Sequence\n"); break;
    case E_SEQ4:    fprintf(stderr,"Error4 in Huffman-Sequence\n"); break;
    case E_SEQ5:    fprintf(stderr,"Error5 in Huffman-Sequence\n"); break;
    case E_SEQ6:    fprintf(stderr,"Error6 in Huffman-Sequence\n"); break;
    case E_SEQ7:    fprintf(stderr,"Error7 in Huffman-Sequence\n"); break;
    case E_POS:    fprintf(stderr,"Error in file-position\n"); break;
    case E_COOL:    fprintf(stderr,"Cannot opan opal.library \n"); break;
     case E_OVD:    fprintf(stderr,"Opalvision error      \n"); break;
     case E_SCR:    fprintf(stderr,"You need a 15KHZ scan rate(genlockable) screen  \n"); break;
    case E_NCDS:     fprintf(stderr," Slide Show available in Base/4 and Base Only \n"); break;
     case E_ABT:    fprintf(stderr," User Aborted with CTRL-C \n");
    default:       fprintf(stderr,"Unknown error %d ???\n",e);break;
   }
  if(fin) fclose(fin); /* close files */
  if(fout) fclose(fout);
  if (OpalBase!=NULL) /* if we did play with OpalVision, lets fix things */
		{   AmigaPriority();
            if (OScrn) FreeScreen24 (OScrn); /* oops, forgot */
             CloseScreen24 ();
		  CloseLibrary ((struct Library *)OpalBase);
   }

  exit(e); /* return the error */
}


static void planealloc(p,width,height)
  implane *p;
  dim width,height;
 {
  p->iwidth=p->iheight=0;
  p->mwidth=width;
  p->mheight=height;
    /* this is level II and freed by c startup, we should fix later */
  p->im = ( byte * ) malloc  (width*height);/* we know a byte is 1! */
  if(!(p->im)) cleanup(E_MEM);
 }
 




main(argc,argv)  /* MAIN  */
int argc;
char **argv;
{int i,bildnr;
char *opt;
int do_auto,cd_offset,do_info,do_diff,do_overskip,do_slide;
int cccnt=0,Err,a,orun=0;
enum SIZES size=S_UNSPEC;
UBYTE   *rgbps[3]; 
    enum ERRORS eret;
    do_info=do_auto=do_diff=do_overskip=do_sharp=0; 
    backdrop=do_slide=crop=jpeg=0; /* default to 0 */
    Luma.im=Chroma1.im=Chroma2.im = NULL;
    ASKIP;
    init=0;
    onbreak(getout); /* try to set a ctrl c trap */
        /* parse input line */
    cropx=cropy=-1; /* default meaning not set */
    cropw=DISP_W;  croph=DISP_H; /* default to one full screen */
    while((argc>0) && (**argv=='-')) {
         opt= (*argv)+1;
         ASKIP
         
      /* don't screw with anything between the while and this comment */
         
      if(!strcmp(opt,"c")) /* crop coordinates  */
            { /* now fetch coords */
               crop=255;
               if( isdigit( **argv) && (argc >0)) { /* see if following is a # */
                   cropx=atoi(*argv); cccnt++;
                   ASKIP
                   if(isdigit(**argv) && argc ){ /* look for cropy */
                        cropy=atoi(*argv); cccnt++; 
                        ASKIP
                        if(isdigit(**argv) && argc ){ /* look for cropw */
                            cropw=atoi(*argv); cccnt++;
                            ASKIP
                            if(isdigit(**argv)&&argc ){ /* look for croph */
                                croph=atoi(*argv); cccnt++; 
                                 ASKIP;
         
                                /* we got all four if we got here */
                            }    
                            else {  cropw=DISP_W; } /* cant use w w/o h*/   
                        }
                            
                   }
                   else {  cropx= -1; }
               }
                /* couldnt get cropx */ 
           printf( "cropping left = %d top = %d width = %d height =%d\n",cropx,cropy,cropw,croph);
                     continue; 
            }


        if(!strcmp(opt,"j")) /* select jpeg file mode  */
            {
               if (isdigit ( **argv) && (**argv != '-')&&(argc>0)) {
                         /* look for quality factor */
                   jpeg=atoi(*argv);
                   ASKIP
                }
               else { jpeg =  70;   } /* assume 70 if not spec */    
               if (jpeg <1 )  jpeg=1;
               if (jpeg >100) jpeg=100; 
                
               continue;                       
            }
   /*     printf("past my options %d  \n",argc);  */

        if(!strcmp(opt,"a")) /* slide show mode */
            {if (!do_auto ) do_auto=255;
            else cleanup(E_ARG);
            continue;
            }


        if(!strcmp(opt,"p")) /* slide show mode */
            {if (!do_slide ) do_slide=255;
            else cleanup(E_ARG);
            continue;
            }


        if(!strcmp(opt,"r"))
            {if (turn == T_NONE) turn=T_RIGHT;
            else cleanup(E_ARG);
            continue;

            }

        if(!strcmp(opt,"l"))
            {if (turn == T_NONE) turn=T_LEFT;
            else cleanup(E_ARG);
            continue;
            }

        if(!strcmp(opt,"i")) 
            { if (!do_info) do_info=1;
            else cleanup(E_ARG);
            continue;
            }


        if(!strcmp(opt,"d")) 
            { if (!do_diff) do_diff=1;
            else cleanup(E_ARG);
            continue;
            }
          if(!strcmp(opt,"b")) 
            { if (!backdrop) backdrop=1;
            else cleanup(E_ARG);
            continue;
            }

        if(!strcmp(opt,"s")) 
            { if (!do_sharp) do_sharp=1;
            else cleanup(E_ARG);
            continue;
            }


        if(!strcmp(opt,"x")) 
            { if (!do_overskip) do_overskip=1;
            else cleanup(E_ARG);
            continue;
            }



   /* get desired size */
        if((!strcmp(opt,"Base/16")) || (!strcmp(opt,"1"))  || (!strcmp(opt,"128x192")))
          {  if (size == S_UNSPEC) size = S_Base16;
            else cleanup(E_ARG);
            continue;
        }
        if((!strcmp(opt,"Base/4" )) || (!strcmp(opt,"2"))  || (!strcmp(opt,"256x384")))
            { if (size == S_UNSPEC) size = S_Base4;
            else cleanup(E_ARG);
            continue;
        }
        if((!strcmp(opt,"Base"   )) || (!strcmp(opt,"3"))  || (!strcmp(opt,"512x768")))
            { if (size == S_UNSPEC) size = S_Base;
            else cleanup(E_ARG);
            continue;
        }
        if((!strcmp(opt,"4Base"  )) || (!strcmp(opt,"4"))  || (!strcmp(opt,"1024x1536")))
            { if (size == S_UNSPEC) size = S_4Base;
            else cleanup(E_ARG);
             continue;
        }
        if((!strcmp(opt,"16Base" )) || (!strcmp(opt,"5"))  || (!strcmp(opt,"2048x3072")))
        { if (size == S_UNSPEC) size = S_16Base;
            else cleanup(E_ARG);
            continue;
            }
       if( (!strcmp(opt,"4BC" )) || (!strcmp(opt,"6")) )
        { if (size == S_UNSPEC) size = S_4BaseHC;
            else cleanup(E_ARG);
            continue;
            }


        if((!strcmp(opt,"Overview" )) || (!strcmp(opt,"0"))  || (!strcmp(opt,"O")))
            { if (size == S_UNSPEC) size = S_Over;
            else cleanup(E_ARG);
            continue;
            }

        fprintf(stderr,"Unknown option: -%s\n",opt);
            cleanup(E_ARG);
    }


  printf( "loop completed \n");

  if(size==S_UNSPEC) size=S_DEFAULT;

  if((argc<1) && !(do_slide)) cleanup(E_ARG); /* forgive lack of name if slide */
  if ( !(do_slide))pcdname= *argv;
    ASKIP;

  if(argc>0) 
   {ppmname= *argv;
    ASKIP;
   }
  if ( isdigit(*pcdname) &&  isdigit ( *(pcdname+1) ) && (strlen(pcdname)==2))
     { /*two digit number, use as easy file name  */
        
        strcpy(nbuf,"CD0:PHOTO_CD/IMAGES/IMG00"); /* build name */
        strcat(nbuf,pcdname);
        strcat(nbuf,".PCD");
        pcdname=nbuf; /* transfer pointer */
        if (size == S_Over) pcdname ="CD0:PHOTO_CD/OVERVIEW.PCD";
        /* for an overview, use this file 4-15-93 */
      }   
  if(argc>3) cleanup(E_ARG);
/*  if((size==S_Over) && (!ppmname)) cleanup(E_ARG); */
  if(do_info && (size==S_Over)) cleanup(E_OPT);
  if(do_diff && (size != S_4Base) && (size != S_16Base)&& (size != S_4BaseHC)) cleanup(E_OPT);
  if(do_overskip) cleanup(E_IMP);
  if(do_overskip && (size != S_Base4) && (size != S_Base16)) cleanup(E_OPT);
  if(do_slide) { /* for auto */
       
      ppmname=NULL; /* we wont save file */
      pcdname="CD0:PHOTO_CD/IMAGES/IMG0001.PCD"; /* the first on any disk */
      if (size > S_Base) {
            printf( "can't slideshow above base res \n");
            cleanup(E_ARG);    }      
   }
/*  printf( " infile %s jpeg %d slide %d argc %d \n",pcdname,jpeg,do_slide,argc);
*/
#ifdef DEBUG
fprintf(stderr,"Turn %d  Size %d Pcd %s  ppm %s\n",turn,size,pcdname,ppmname);
#endif

  if(!(fin=fopen(pcdname,"r"))) cleanup(E_READ);
  if(do_info) druckeid(); /* show ID code */
	OpalBase = (struct OpalBase *) OpenLibrary ("opal.library",0L);
	if (OpalBase==0L) /* opal opal library */
		cleanup (E_COOL);
	OScrn = NULL;
  i=timer(clock1); /* get clock */

  switch(size) /* perform the operation based on size */
   {
    case S_Base16: w=BaseW/4;
                   h=BaseH/4;
                   if (do_slide) cleanup( E_NCDS);

                   planealloc(&Luma   ,w,h);
                   planealloc(&Chroma1,w,h);
                   planealloc(&Chroma2,w,h);

                   SEEK(L_Head+1);
                   cleanup(readplain(w,h,&Luma,&Chroma1,&Chroma2));

                   interpolate(&Chroma1);
                   interpolate(&Chroma2);

                   ycctorgb(w,h,&Luma,&Chroma1,&Chroma2);
              /* Now Luma holds red, Chroma1 hold green, Chroma2 holds blue */

             
              /*     writepicture(w,h,&Luma,&Chroma1,&Chroma2,turn);*/
                   OpenOpal();
                   DoOpal(do_auto,do_slide,ppmname);
                   break;

    case S_Base4:  w=BaseW/2;
                   h=BaseH/2;
                   planealloc(&Luma   ,w,h);
                   planealloc(&Chroma1,w,h);
                   planealloc(&Chroma2,w,h);

                   SEEK(L_Head+L_Base16+1);
                   cleanup(readplain(w,h,&Luma,&Chroma1,&Chroma2));

                   interpolate(&Chroma1);
                   interpolate(&Chroma2);

                   ycctorgb(w,h,&Luma,&Chroma1,&Chroma2);
                   /* Now Luma holds red, Chroma1 hold green, Chroma2 holds blue */

                   OpenOpal();
                   DoOpal(do_auto,do_slide,ppmname);
                   break;

    case S_Base:   w=BaseW;
                   h=BaseH;
                 
                   planealloc(&Luma   ,w,h);
                   planealloc(&Chroma1,w,h);
                   planealloc(&Chroma2,w,h);
                   if (!OpenOpal()) cleanup(E_OVD);
                   SEEK(L_Head+L_Base16+L_Base4+1);
                   cleanup(readplain(w,h,&Luma,&Chroma1,&Chroma2));
                   interpolate(&Chroma1);
                   interpolate(&Chroma2);
                   ycctorgb(w,h,&Luma,&Chroma1,&Chroma2);
                   /* Now Luma holds red, Chroma1 hold green, Chroma2 holds blue */
                   DoOpal( do_auto,do_slide,ppmname); /* do all the nice OpalVision stuff */
                   break;
    case S_4BaseHC:
    case S_4Base:  w=BaseW*2;
                   h=BaseH*2;
                    if (do_slide) cleanup( E_NCDS);
                   planealloc(&Luma,w,h);  /* thats almost 5 meg! */
                   planealloc(&Chroma1,w,h);
                   planealloc(&Chroma2,w,h);  
                   if (!OpenOpal()) {
                      printf("Can't open Opal Screen.  Try a smaller area \n");
                      cleanup(E_OVD);
                   } 
 
                   SEEK(L_Head+L_Base16+L_Base4+1);
                   /* THIS IS ONLY THE SAME AS MODE 3! */
                   cleanup(readplain(w/2,h/2,&Luma,&Chroma1,&Chroma2));

                   interpolate(&Luma);
                   interpolate(&Chroma1);
                   interpolate(&Chroma1);
                   interpolate(&Chroma2);
                   interpolate(&Chroma2);  

                   if(do_diff) {clear(&Luma,128);clear(&Chroma1,156);clear(&Chroma2,137);}
                        /* above only clears */
        
                   cd_offset = L_Head + L_Base16 + L_Base4 + L_Base ;


                   SEEK(cd_offset + 4);     readhqt(w,h,1); 

                   SEEK(cd_offset + 5);  
                   decompress(w,h,&Luma,0,0); 
              /* add full LUMA res */
                   if (size== S_4BaseHC) { /* we are trying to fill colors*/
                        cd_offset=ftell(fin);
                        if(cd_offset % SECSIZE) cleanup(E_POS);
                        cd_offset/=SECSIZE;
                        SEEK(cd_offset+12);
                        readhqt(w*2,h*2,3);
                        printf(" gonna decomp the chroma now\n");
                        SEEK(cd_offset+14);
                        decompress(w*2,h*2,0,&Chroma1,&Chroma2);

                        /* try adding full chroma from highest sampling */
                   }     
                   ycctorgb(w,h,&Luma,&Chroma1,&Chroma2);  
                   /* Now Luma holds red, Chroma1 hold green, Chroma2 holds blue */
                    telltime("Time to Decode Picture:",clock1);

              /*    writepicture(w,h,&Luma,&Chroma1,&Chroma2,turn);*/
                   DoOpal( do_auto,do_slide,ppmname); /* try disp some */
                   break;

    case S_16Base: w=BaseW*4;
                   h=BaseH*4;
                     if (do_slide) cleanup( E_NCDS);
/* ------- Test mode Luma only  will fix later -------- */
                   planealloc(&Luma,w,h);
        /* test!           planealloc(&Chroma1,w,h);
                   planealloc(&Chroma2,w,h);
                   
                   TRY LUMA ONLY!   */
                   crop=255; /* we crop! */
                cropw=cropx=DISP_W; croph=cropy=DISP_H; /* TEST CROPPINGS */
                   OpenOpal();
                   SEEK(L_Head+L_Base16+L_Base4+1);
                   cleanup(readplain(w/4,h/4,&Luma,0,0));
                   interpolate(&Luma);
              /*     interpolate(&Chroma1);
                   interpolate(&Chroma1);
                   interpolate(&Chroma2);
                   interpolate(&Chroma2); */


                   cd_offset = L_Head + L_Base16 + L_Base4 + L_Base ;

                   SEEK(cd_offset + 4);             
                   readhqt(w/2,h/2,1);

                   SEEK(cd_offset + 5);
                   decompress(w/2,h/2,&Luma,0,0);
                   interpolate(&Luma); /* now we have a 4base, spread it out */
        /* we get to here OK */
                   cd_offset=ftell(fin);
                   if(cd_offset % SECSIZE) cleanup(E_POS);
                   cd_offset/=SECSIZE;

                   SEEK(cd_offset+12);
                   readhqt(w,h,1);

                   if(do_diff) {clear(&Luma,128);clear(&Chroma1,156);clear(&Chroma2,137);}

                   SEEK(cd_offset+14);
                   decompress(w,h,&Luma,0,0);
                /*   interpolate(&Chroma1);
                   interpolate(&Chroma2); */

           /*        ycctorgb(w,h,&Luma,&Chroma1,&Chroma2); */
                   /* Now Luma holds red, Chroma1 hold green, Chroma2 holds blue */
                   telltime("WE GOT 3Kx2K Luma only  TIME:",clock1);
                   DoOpal(do_auto,0,0); /* display a small bw chunk */

              /*     writepicture(w,h,&Luma,&Chroma1,&Chroma2,turn); */

                   break;

    case S_Over: /* we are going to render some small images */
       w=BaseW;
       h=BaseH; /* use a full size screen for now */
       
       planealloc(&Luma   ,w/4,h/4); /* allocate for tiny images */
       planealloc(&Chroma1,w/4,h/4);
       planealloc(&Chroma2,w/4,h/4);
       if( !(Chroma2.im) ) cleanup(E_MEM);
       rgbps[0]=Luma.im;
       rgbps[1]=Chroma1.im; /* copy pointers */
       rgbps[2]=Chroma2.im;  
       if (!( OpenOpal())) cleanup(E_OVD);
       OScrn->Pen_R=OScrn->Pen_G=0;
       OScrn->Pen_B=100; /* blue background */
      for(orun=0; orun <8 && !feof(fin); orun++){ /* loop each page (16 pix) */
       SetScreen24(OScrn); /* clear and install bkgrnd */
       for(bildnr=orun<<4;!feof(fin) && (bildnr< (orun+1)<<4);bildnr++){ /* ea pic*/
		       SEEK(5+SeBase16*bildnr);
    
		       eret=readplain(w/4,h/4,&Luma,&Chroma1,&Chroma2);
                       if(eret==E_READ) break;
                       cleanup(eret);

		       interpolate(&Chroma1);
		       interpolate(&Chroma2);
    
		       ycctorgb(w/4,h/4,&Luma,&Chroma1,&Chroma2); 
		       /* Now Luma holds red, Chroma1 hold green, Chroma2 holds blue */
               RGBtoOV(OScrn,rgbps,(bildnr&3)*190,((bildnr>>2)&3)*120,192,128);
               /* render each of 16 in */

        }   
           AutoSync24(do_auto);
         Err = (long)LowMemUpdate24 (OScrn,0);
        if ((Err>OL_ERR_MAXERR) && (!(OScrn->Flags&ILACE24)))
	    {   AutoSync24 (do_auto);
	      /*  Err = (long)LowMemUpdate24 (OScrn,6); */
		} 
       /* end of main loop.  If we save img, save last image */ 
         while ( ( *Button &0x040) &&(*RButton & RBMASK) ){ /* button for single show */
            Delay(10); } /* if no button down wait */
        
         if   (!(*RButton & RBMASK)){ /* right pushed */
            
             /* next page and continue */
            if ( feof(fin) ){ orun=-1; /* if we hit end of pix, start anew */
                rewind(fin); /* set position back to start */
                Delay(5); }
         }       
         else orun=20; /* put loop var high to exit, was left mouse button */ 
             
       } /* end of running loop, past here were done */ 
        
        if ( (OScrn) && (ppmname) ){ /* we can save file */
            if (jpeg)
              a=SaveJPEG24(OScrn,ppmname,NULL, jpeg);
            else  
              a=SaveIFF24(OScrn,ppmname, NULL,NULL); 
            if (a) printf( "iff save error # %d couldn't save picture\n",a);
            else printf( "file saved as %s \n",ppmname);
        }  
     
               if ( backdrop){ /* we want to leave image as backdrop */
            AmigaPriority ();
	        DualDisplay24 ();
	        Delay (2L);
	        LatchDisplay24 (TRUE);
	        Delay (2L);
    
        }                    
         FreeScreen24 (OScrn); /* clean up here */
	    CloseScreen24(); 
        return(0);    
    	     
                   break;

     default: cleanup(E_INTERN); 
   }
exit(0); /* exit normal */
}

#undef ASKIP



struct OpalScreen *OpenOpal() /* display and save OV */
                /* This just appropriats and opens the Opal Screen */
{
long scm;
int dw,dh;

    scm= OVERSCAN24;
    if ( w>3000) scm |= PLANES8 | PALMAP24; /* MAKE IT 8 BIT MONO FOR 3KX2K TEST */
    
   if (!Display_Mode_Check()) 
        cleanup( E_SCR); /* check for 15KHZ res */
      dw= DISP_W/2; dh=DISP_H/2; 
      if ( w> 400) {
        scm |= ILACE24 | HIRES24; /* if base & up do hires lace */
        dw=DISP_W; dh=DISP_H;
        if ( !crop) cropx=cropy=0;
      }  
      else {
        cropx= (dw-w+2)/2; /* center picture tiny res no crop possible */
        cropy= (dh-h+2)/2;
      }    
      
      if ( !crop ) {
              if (turn){
                OScrn = CreateScreen24(scm,max(dw,h),max(dh,w)) ; 
                             }  
              else 
                OScrn = CreateScreen24(scm,max(dw,w),max(dh,h)) ; 
                /* same size virtual screen */
             }
    else { /* set up for cropping */
        if  ((cropw>w) || (cropw < 32)) cropw=dw; /* limit width */
        if  ((croph>h) || (croph < 20)) croph=dh; /* default to center if bad*/
        if ( (cropx < 0) || (cropy <0 ) || (cropx>w) || (croph>h)  ) {
            /* invalid or unspecified values */
            cropx=(w-cropw)/2; /* center */
            cropy=(h-croph)/2; /* a normal 736x480 is disp if numbers bad */    
        }
        OScrn = CreateScreen24(scm,cropw,croph);
      /* create just for disp to test higher mode */
    }
            
    if ( !OScrn){
        printf( "Can't Alloc Opal Screen, Try a smaller area \n");
         }
        /* create the virtual screen to plop the data in */
    return(OScrn);
}    

int DoOpal(int asy,int slide, char *fname) /* fill display and save OV */
{
int a,dw,dh,pic,slerr,orun;
UBYTE *rgbp[4];
long Err;
     /* assume the Opal Screen is already made */
     if (!OScrn) cleanup(E_OVD); /* but check to make sure */
     pic=1; slerr=0; orun=1; /* init variables */
     dw= OScrn->Width; /* get these from Opal Screen structure */
     dh= OScrn->Height;
    /* below here updated for each pic, so loop on this ! */
    while (orun && (pic < 150)) {  /* keep doing this */ 
         rgbp[0]= Luma.im; /* set image area pointers */
         rgbp[1]= Chroma1.im;
         rgbp[2]= Chroma2.im;
         TurnOpal(OScrn,rgbp,cropx,cropy,dw,dh,turn); /* turn it */
         telltime("Picture loading & Decoding took",clock1);
   
             /* copy the data into the virtual screen */ 
	           AutoSync24(asy);
         Err = (long)LowMemUpdate24 (OScrn,0);
        if ((Err>OL_ERR_MAXERR) && (!(OScrn->Flags&ILACE24)))
	    {   AutoSync24 (asy);
	      /*  Err = (long)LowMemUpdate24 (OScrn,6); */
		} 
        if ( (OScrn) && (fname) ){ /* we can save file */
            if (jpeg)
              a=SaveJPEG24(OScrn,fname,NULL, jpeg);
            else  
              a=SaveIFF24(OScrn,fname, NULL,NULL); 
            if (a) printf( "iff save error # %d couldn't save picture\n",a);
            else printf( "file saved as %s \n",fname);
        }  
        
        if (Err < OL_ERR_MAXERR)
		{ CloseScreen24 ();
		  if (Err==OL_ERR_OUTOFMEM)
			printf ("Out of memory!! \n");
		  else if (Err==OL_ERR_CANTCLOSE)
			printf("OpalVision Display in Use.\n");
		  else
			printf("Error Displaying image!! \n");
		  cleanup(E_OVD);
		}    
        
        pic++;
        if (slide ) {
           
            slerr=GetNextPic(pic,0); 
            if (slerr ==9) Delay(600); /* 10 sec hold on last pic */
            if(slerr) orun=0; /* get the next file, if error,quit */
         /*   FadeOut24(25);*/

        }
        else orun=0;
        OVPriority();   
          Delay(10);
          
        if ( !(*Button & 0x040)) { /* button down for SLIDE */
            Delay(30); /* debounse */
            if (!(*Button & 0x040 )) orun=0; /* get out, is held down */
        }
              
	} 
     while ((*Button &0x040) && !(slide)){ /* button for single show */
            Delay(10); }
    if ( backdrop){ /* we want to leave image as backdrop */
        AmigaPriority ();
	    DualDisplay24 ();
	    Delay (2L);
	    LatchDisplay24 (TRUE);
	    Delay (2L);
    
    }                    
    FreeScreen24 (OScrn);
	CloseScreen24(); 
    return(0);    
}                                    

int GetNextPic(int pic,int res) /* slidesow, get next picture to OV */
{
static char *fn="CD0:PHOTO_CD/IMAGES/IMG0001.PCD";
int i,wm,ht;
    if(fin) fclose(fin); /* if it is open, close it */
    fin=NULL;
    if((pic>199) || (pic<0)) return(999); /* pic too high */
    wm=w/192; /* use to switch */
    ht= (pic/100); /* convert to digits */
    pic -= ht * 100; /* get it to 100 */
    *(fn+24)= h+48; 

    *(fn+25)=(pic/10)+48;
    *(fn+26)=(pic%10)+48;
 /*   printf("filename is %s\n",fn); */
    
    fin=fopen(fn,"r");
    if (!fin) return(9);
    switch(wm) { /* based on resolution */
        case 2 :    SEEK(L_Head+L_Base16+1); break;
        case 4 :    SEEK(L_Head+L_Base16+L_Base4+1) ; break;
        case 1 :    SEEK(L_Head+1); break;
        default: return(13);
    }
    Luma.iwidth=Luma.iheight=0;
    Chroma1.iwidth=Chroma1.iheight=0;
    Chroma2.iwidth=Chroma2.iheight=0;
    i=readplain(w,h,&Luma,&Chroma1,&Chroma2);
    if (fin) { fclose(fin); fin=NULL; }
/*     printf( "plane read %d w %d h %d i \n",w,h,i); */
    if(i) return(i); /* an error here break */
    interpolate(&Chroma1); 
    interpolate(&Chroma2); 
    ycctorgb(w,h,&Luma,&Chroma1,&Chroma2);
                    
      return(0); /* successful */
}

int TurnOpal( Oscr, rgbp, xos,yos,dw,dh,dir)
struct OpalScreen *Oscr;
UBYTE   *rgbp[3]; /* pointers for decoded Photo CD data */
int xos,yos,dw,dh,dir; /* offset and size of image, and dir 0=no 1=r else l 
        do cropping here, if unable to open screen, stash in file and 
        reload down the line */
{  /* this is to view images on edge.  To save memory we only buffer
    16 lines */
long size,lines;
int i,j,ystep;
UBYTE *buf,*rgbuf[3],*rp,*gp,*bp; /* pointers into array */
    lines=16;
    size=h*3*lines; /* well do 16 lines (initially columns ) at a time */
    buf=malloc(size); /* try to allocate the memory */
    rp=rgbuf[0]=buf;
    gp=rgbuf[1]=buf+(h*lines);/* set pointer */
    bp=rgbuf[2]=buf+(h*lines*2);
    
    if ( !buf) { 
        printf("can't allocate turn buffer, try closing some windows \n");        
        cleanup(E_MEM);
    }
    if (crop) { xos *= -1; /* invert since pcd larger than Opal */
                yos *= -1;
            }
    if ( dir==0) { 
        RGBtoOV ( OScrn,rgbp,xos,yos,w,h );
        return(3); /* do this step here */ 
    }
    if (turn==1) { /* right turn */
        /* start from bottom left j=column turned to row */
        for(j=0; j<w; j++){   
           for(i=h-1; i>=0; i--) { /* count up from bottom build one line*/
                ystep=(i*w)+j;
                *rp++=*(rgbp[0]+ ystep); /* copy pixels for each color */
                *gp++=*(rgbp[1]+ ystep);
                *bp++=*(rgbp[2]+ ystep);        
           }
           if(  ( ( j& 0x0F )==0x0f) || (j == w-1)) { /* update ea 16 lines*/
                rp=rgbuf[0]; /* eset pointers to bases */
                gp=rgbuf[1];
                bp=rgbuf[2];
                RGBtoOV( Oscr,rgbuf,xos,yos+j-lines+1,h,lines); /* convert it */
           
            }
           
        }
     }   
     else { /* left  turn */
        /* start from bottom left j=column turned to row */
        for(j=w-1; j>=0; j--){   
           for(i=0; i<h; i++) { /* count down build one line*/
                ystep=(i*w)+j;
                *rp++=*(rgbp[0]+ ystep); /* copy pixels for each color */
                *gp++=*(rgbp[1]+ ystep);
                *bp++=*(rgbp[2]+ ystep);        
           }
           if(   ( j& 0x0F )==0x00) { /* update ea 16 lines*/
                rp=rgbuf[0]; /* reset pointers to bases */
                gp=rgbuf[1];
                bp=rgbuf[2];
                RGBtoOV( Oscr,rgbuf,xos,yos+w-j-lines,h,lines); /* convert it */
           
            }
        }     
     }
     free(buf); /* let it go, we dont need it anymore */
     return(j);

        
 
}
enum ERRORS readplain(w,h,l,c1,c2)
dim w,h;
implane *l,*c1,*c2;
{
dim i;
byte *pl=0,*pc1=0,*pc2=0;

  if(l)
   { if ((l->mwidth<w) || (l->mheight<h) || (!l->im)) cleanup(E_INTERN);
     l->iwidth=w;
     l->iheight=h;
     pl=l->im;
   }

  if(c1)
   { if ((c1->mwidth<w/2) || (c1->mheight<h/2) || (!c1->im)) cleanup(0);
     c1->iwidth=w/2;                    /* bypass for test only */
     c1->iheight=h/2;
     pc1=c1->im;
   }

  if(c2)
   { if ((c2->mwidth<w/2) || (c2->mheight<h/2) || (!c2->im)) cleanup(0);
     c2->iwidth=w/2;
     c2->iheight=h/2;
     pc2=c2->im;
   }

  for(i=0;i<h/2;i++)
   {
    if(pl)
     { 
       if(fread(pl,w,1,fin)<1) return(E_READ);
       pl+= l->mwidth;

       if(fread(pl,w,1,fin)<1) return(E_READ);
       pl+= l->mwidth;
     }
    else SKIPr(2*w);
     
    if(pc1)
     { if(fread(pc1,w/2,1,fin)<1) return(E_READ);
       pc1+= c1->mwidth;
     }
    else SKIPr(w/2);
     
    if(pc2)
     { if(fread(pc2,w/2,1,fin)<1) return(E_READ);
       pc2+= c2->mwidth;
     }
    else SKIPr(w/2);


   }
#ifdef DEBUG
fprintf(stderr,"R-Position %x\n",ftell(fin));
#endif
  return E_NONE;
 }


static void interpolate(implane *p)
{
dim w,h,x,y,yi,h2,w2;
byte *optr,*nptr,*uptr;

  if ((!p) || (!p->im)) cleanup(E_INTERN);

  w=p->iwidth;
  h=p->iheight;

  if(p->mwidth  < 2*w ) cleanup(E_INTERN);
  if(p->mheight < 2*h ) cleanup(E_INTERN);


  w2=p->iwidth =2*w;
  h2=p->iheight=2*h;/* cut some multiplications by doing once at start */ 


  for(y=0;y<h;y++)
   {yi=h-1-y;
    optr=p->im+  yi*p->mwidth + (w-1);
    nptr=p->im+((yi*p->mwidth)<<1) + (w2 - 2);

    nptr[0]=nptr[1]=optr[0];

    for(x=1;x<w;x++)
     { optr--; nptr-=2;
       nptr[0]=optr[0];
       nptr[1]=(((int)optr[0])+((int)optr[1]))>>1;
     }              /* try sub divede by 2 with >>1 */    }

  for(y=0;y<h-1;y++)
   {optr=p->im + ((y*p->mwidth)<<1);
    nptr=optr+p->mwidth;
    uptr=nptr+p->mwidth;

    for(x=0;x<w2;x++)
      *(nptr++)=(((int)*(optr++))+((int)*(uptr++)))>>1;
   }

  bcopy(p->im + (h2-2)*p->mwidth, p->im + (h2-1)*p->mwidth,  w2);

 }

void telltime(tmsg, clock1) /* tell elapsed time, array at start is passed */
unsigned int clock1[2];
char *tmsg;
{
unsigned int x;
double t;
    x=timer(clock2); /* get time I came out of it */
    if( clock2[1] < clock1[1]) { /* take care of uS rollover */
        clock2[1]+= 1000000L;
        clock2[0]--; }
        
    clock2[1]-=clock1[1]; /* get diff in us */
    clock2[0]-=clock1[0];
    t=(double) (clock2[1]/1000000.0) +(double)clock2[0];
    printf( "%s %8.3f Sec.  \n",tmsg,t);
 }
 
static void ycctorgb(w,h,l,c1,c2)
dim w,h;
implane *l,*c1,*c2;
{
register dim x,y,i;
register  byte *pl,*pc1,*pc2;
  int red,green,blue;
  float L;
  static int init=0;
  static float XL[256],XC1[256],XC2[256],XC1g[256],XC2g[256];
/*
  if((!l ) || ( l->iwidth != w ) || ( l->iheight != h) || (! l->im)) cleanup(E_INTERN);
  if((!c1) || (c1->iwidth != w ) || (c1->iheight != h) || (!c1->im)) cleanup(E_INTERN);
  if((!c2) || (c2->iwidth != w ) || (c2->iheight != h) || (!c2->im)) cleanup(E_INTERN);
*/
  if(do_sharp) sharpit(l);


  if(!init)
   {init=1;
    for(i=0;i<256;i++)
     { XL[i]=1.3584 *  ((float)i );
      XC1[i]=2.2179 * (((float)i)-156.0);
      XC2[i]=1.8215 * (((float)i)-137.0);
      XC1g[i]= -0.194 * XC1[i];
      XC2g[i]= -0.509 * XC2[i];
     }
   }



  for(y=0;y<h;y++)
   {
    pl =  l->im + y *  l->mwidth;
    pc1= c1->im + y * c1->mwidth;
    pc2= c2->im + y * c2->mwidth;

    for(x=0;x<w;x++)
     {
     L = XL[*pl]; 

     red  =L + XC2[*pc2];
     green=L + XC1g[*pc1] + XC2g[*pc2]; 
     blue =L + XC1[*pc1];

     NORM(red);
     NORM(green);
     NORM(blue);

      *(pl++ )=red; 
      *(pc1++)=/*green */ green; 
      *(pc2++)=blue;
     }
 /*   printf("line %d raw is %d %d %d \n",y,*pl,*pc1,*pc2); */
   }

 }


static void druckeid()
{
 struct ph1 *d;
 char ss[100];

 SEEK(1);
 if(READBUF<1) cleanup(E_READ);
 d=(struct ph1 *)sbuffer;

#define dr(feld,kennung)   \
     strncpy(ss,feld,sizeof(feld));\
     ss[sizeof(feld)]=0;\
     fprintf(stderr,"%s: %s \n",kennung,ss);

dr(d->id1,"Id1")
dr(d->id2,"Id2")
dr(d->id3,"Id3")
dr(d->id4,"Id4")
dr(d->id5,"Id5")


#undef dr 

}



struct pcdword
 { byte high,low;
 };




struct pcdquad { byte len,highseq,lowseq,key;}; /* size=4 */
struct pcdhqt  { byte entries; struct pcdquad entry[256];}; /* size=1025*/
struct myhqt { unsigned long seq,mask,len; byte key; }; /* size=13 */


#define E ((unsigned long) 1)


static void readhqtsub(source,ziel,anzahl)
  struct pcdhqt *source;
  struct myhqt *ziel;
  int *anzahl;
 {int i;
  struct pcdquad *sub;
  struct myhqt *help;
  *anzahl=source->entries+1;

  for(i=0;i<*anzahl;i++)
   {sub= source->entry+i;
    help=ziel+i;

    help->seq = (((unsigned long) sub->highseq) << 24) |(((unsigned long) sub->lowseq) << 16);
    help->len = ((unsigned long) sub->len) +1;

    if(help->len > 16) cleanup(E_HUFF);

    help->key = sub->key;
    help->mask = ~ ( (E << (32-help->len)) -1); 

  }
#ifdef DEBUG
  for(i=0;i<*anzahl;i++)
   {help=ziel+i;
    fprintf(stderr,"H: %3d  %08lx & %08lx (%2d) = %02x = %5d  %8x\n",
        i, help->seq,help->mask,help->len,help->key,(signed char)help->key,
        help->seq & (~help->mask));
   }
#endif

}

static struct myhqt myhuffl[256],myhuff1[256],myhuff2[256];
static int          myhufflenl=0,myhufflen1=0,myhufflen2=0;

static void readhqt(w,h,n)
  dim w,h,n;
 {
  byte *ptr; /* fix type to placate compiler 3-6-93 */
  int a;
  if ( n==3 ) { /* if for decompressing highest get 2 sectors */
    a=fread(sbuffer,1,4000,fin); }
  else          a=READBUF; /* else, for second highest, get only 1 sector */
  if(a ==0 ) cleanup(E_READ);
  ptr = sbuffer;

  readhqtsub((struct pcdhqt *) ptr,myhuffl,&myhufflenl);

  if(n<2) return;
  ptr+=  4* myhufflenl;
  ptr++;
  readhqtsub((struct pcdhqt *) ptr,myhuff1,&myhufflen1);
  if(n<3) return;
  ptr+=  4* myhufflen1;
  ptr++;
  readhqtsub((struct pcdhqt *) ptr,myhuff2,&myhufflen2);
  printf( " Length of hqts %d\n",ptr-sbuffer);
}


#define nextbuf  {  nptr=sbuffer;  if(READBUF < 1) cleanup(E_READ);\
        }
#define checkbuf { if (nptr >= sbuffer + sizeof(sbuffer)) nextbuf; }
#define shiftout(n){ sreg<<=n; inh-=n; \
                     while (inh<=24) \
                      {checkbuf; \
                       sreg |= ((unsigned long)(*(nptr++)))<<(24-inh);\
                       inh+=8;\
                      }\
                    }  

/* I think the following routine is screwed since it works OK up to
   its usage 3/8/93 readhqt not called anymire */
   


static void decompress(w,h,f,f1,f2)
  dim w,h;
  implane *f,*f1,*f2;
 {
  register int i,htlen,sum;
  unsigned long sreg,maxwidth;
  unsigned int inh,n,zeile,segment,ident;
  struct myhqt *htptr,*hp;
  
  byte *nptr;
  byte *lptr;

/* try bypass this so we can decompress Chroma only */
/* 
  if((!f) || (!f->im)) cleanup(E_INTERN);
  if((f->iheight < h) || (f->iwidth<w)) cleanup(E_INTERN); */
  maxwidth=f->mwidth; 
  if (!f) maxwidth=w;
  sreg=0x0000;
  nextbuf;
  inh=32;
  lptr=0;
  shiftout(16);
  shiftout(16); 

  n=0;
  for(;;) /* keeps going and going*/
  {
    if((sreg & 0xffffff00) == 0xfffffe00)
     {shiftout(24);
      ident=sreg>>16;
      shiftout(16);

      zeile=(ident>>1) & 0x1fff;
      segment=ident>>14;
       /* the loop passes here about once each line */
/*      if (!( zeile & 127))  /* do each 16th line */
        fprintf(stderr,"Ident %4x Zeile:  %6d  Segment %3d Pixels bisher: %d\n",
          ident,zeile,segment,n);*/

      if(lptr && (n!=maxwidth)) cleanup(E_SEQ1);
      n=0;

/* zeile must mean height in pixel rows */
      if(zeile==h) return; /* WERE DONE */
      
      if(zeile > h) cleanup(E_SEQ2);

      switch(segment)
       {
        case 0: htlen=myhufflenl;
                htptr=myhuffl;
               
                 if(!f ){ /* do this if luma not used */
                    lptr=NULL;            
                    maxwidth=w;


                    }  /* to placate things */
                else { 
                    lptr=f->im + zeile*f->mwidth; /* set pointer */
                    maxwidth=f->iwidth;
                }
                break;

        case 2: if(!f1)/* cleanup(E_SEQ7); */ return;
                lptr=f1->im + (zeile>>1)*f1->mwidth;
                maxwidth=f1->iwidth;
                htlen=myhufflen1;
                htptr=myhuff1;
                break;
 
        case 3: if(!f2) cleanup(E_SEQ7);
                lptr=f2->im + (zeile>>1)*f2->mwidth;
                maxwidth=f2->iwidth;
                htlen=myhufflen2;
                htptr=myhuff2;
                if(zeile >= (h-9)) return; /* break off a little early */
           /* TEMP FIX FOR BUG IN SYSTEM READ OF LAST SECTOR.
             CHROMA RESOLUTION SLIGHTLY LOWER ON BOTTOM 4 LINES */     
                break;

        default:cleanup(E_SEQ3);
	} /* end of segment case statement */
  }
  else
  { /* DECOMPRESS THE PIXEL */
      if(n>maxwidth)/* cleanup(E_SEQ4);*/
         {printf("Nonfatal err4 line %d seg %d  \n",zeile,segment); return; }
      for(i=0,hp=htptr;(i<htlen) && ((sreg & hp->mask)!= hp->seq); i++,hp++);
      if(i>=htlen) cleanup(E_SEQ5);
      if (lptr) { /* if we are not saving, skip this much */  
        sum=((int)(*lptr)) + ((int)hp->key);
        /* add decompressed data to pixel */
        *(lptr++) = sum & 0xff ;
        /* ---THIS SEEMS TO HAVE FIXED THE PROBLEM,
            BAZZ 3-10-93! CHANGING NORM TO & 0XFF ; */
        n++; 
       } 
      shiftout(hp->len);

   } /* END OF ELSE ROUTINE */

 } /* END OF FOR(;;) INDEFINATE LOOP */



} /* END OF DECOMPRESS SUBROUTINE */




static void clear(l,n)
  implane *l;
  int n;
{ dim x,y;
  byte *ptr;
/*  l->iwidth=l->mwidth;
  l->iheight=l->mheight;
*/
  ptr=l->im;
  for (x=0;x<l->mwidth;x++)
    for (y=0; y<l->mheight;y++)
      *(ptr++)=n;
}


static void sharpit(l)
  implane *l;
 {int x,y,h,w,mw,akk;
  byte f1[slen],f2[slen],*old,*akt,*ptr,*work,*help,*optr;

  if((!l) || (!l->im)) cleanup(E_INTERN);
  if(l->iwidth > slen) cleanup(E_INTERN);

  old=f1; akt=f2;
  h=l->iheight;
  w=l->iwidth;
  mw=l->mwidth;

  for(y=1;y<h-1;y++)
   {
    ptr=l->im+ y*mw;
    optr=ptr-mw;
    work=akt;

    *(work++)= *(ptr++);
    for(x=1;x<w-1;x++)
     {  akk = 5*((int)ptr[0])- ((int)ptr[1])  - ((int)ptr[-1]) 
                              - ((int)ptr[mw]) - ((int)ptr[-mw]);
        NORM(akk);
        *(work++)=akk;
        ptr++;
     }

    *(work++)= *(ptr++);

    if(y>1) bcopy(old,optr,w);
    help=old;old=akt;akt=help;
     
   }

  bcopy(old,optr+mw,w);
 }
 
int Display_Mode_Check (void)
{ /* see if we are in high res */
   struct MonitorInfo MonitorInfo;
   DisplayInfoHandle Handle;
   ULONG ModeID;
   LONG Result;

	GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library",36L);
	if (GfxBase==NULL) return (TRUE);
	IntuitionBase = (struct IntuitionBase *)OpenLibrary ("intuition.library",0L);
	if (IntuitionBase==NULL)
		{ CloseLibrary ((struct Library *)GfxBase);
		  return (TRUE);
		}
	ModeID = GetVPModeID (&IntuitionBase->FirstScreen->ViewPort);
	Handle = FindDisplayInfo (ModeID);
	Result = GetDisplayInfoData (Handle,(UBYTE *)&MonitorInfo,
			sizeof (struct MonitorInfo),DTAG_MNTR,NULL);

	/*  If line frequency if >15Khz, a backdrop
	 * cannot be displayed.
	 */

	if (MonitorInfo.TotalColorClocks<220)
		{ CloseLibrary ((struct Library *)GfxBase);
		  CloseLibrary ((struct Library *)IntuitionBase);
		  return (FALSE);
		}
	CloseLibrary ((struct Library *)GfxBase);
	CloseLibrary ((struct Library *)IntuitionBase);
	return (TRUE);
}

