/* AVLoad.c - (C) ARCHOS
 *
 * This is an example of how to load a 12-bit ILBM AVIDEO image or a
 * 24-bit IFF image into a 12-bit AVIDEO extended BitMap suitable
 * for AVideo graphics boards.
 *
 * The file format may be standard IFF ILBM format or
 * special 12-bit AVIDEO ILBM or 12,15,18,21,24 standard ILBM.
 *
 * If picture depth is greater than 8, all bit planes pointers are stores
 * in the static array 'picPlanes[]' pointed to by the last BitMap plane pointer:
 *    BitMap->Planes[7] = (PLANEPTR *)planes;
 *
 * Also if bitmap depth is greater than 8, flag AVIDEOBM must be set in
 * BitMap->Flags.
 *
 * Once loaded, the bitmap must be forwarded to AVideo server for display
 * within an AVideoMsg (see avideoMsg.c).
 */

#include "readpict.h"
#include "avideo.h"
#if AVLIB
   #include "avlib.h"
#endif

#define  NCOLORS     32
#define  OVSLORESW 	(768/2)
#define  OVSHIRESW 	768
#define  OVSNOLACEH  290
#define  OVSLACEH  	580

struct BitMap *getBitMap( ILBMFrame *ilbmFrame ); /* adapted IFF bitmap allocator */

static struct BitMap  *avBm; /* bitmap to be loaded */
static PLANEPTR picPlanes[24+4]; /* bitmap extension plane array + CHIP buffer */
static UWORD  picModes; /* loaded picture view modes */
static UWORD  picColors[32]; /* loaded picture color map */
WORD  Pop; /* queer global needed by IFF package */

static UWORD AVSetBitMap( struct BitMap *bm, LONG planeSz );
static UWORD IFFError( LONG iffp );

/* AVLoadPict -- load an AVIDEO 12-bit or an IFF 24-bit image into
 * given bitmap, bm.
 * 'name' is the picture ILBM file name.
 * Partial loading of bitmap planes is possible if
 * 'planeMask' bits are set for planes NOT to be loaded.
 * If the image is 12-bit and beyond (15,21 and 24-bit),
 * bitmap planes are stored in an array pointed to
 * by bm->Planes[7].
 */
UWORD AVLoadPict( char *name, struct BitMap *bm,  LONG planeMask )
{
	LONG  error = 0;
	ILBMFrame iFrame;   /* Top level "client frame".*/
   LONG  fp;
	WORD  i,count;
	UWORD	 *in,*out;
   PLANEPTR *planes;
   WORD saveFlags;

	AVFreeBm( bm ); /* load one picture at a time ==> free last bitmap first */
   bm->Flags = AVType();
	for (count=i=0;  i<24;  i++) { /* set planes not to be loaded */
		if (planeMask & (1L << i)) /* bit set ==> mask this plane */
			picPlanes[i] = (APTR)-1L; /* see getBitMap() below */
		else
			count++;
	}
	if (count == 0) /* all planes are masked */
		return(0);
   avBm = bm;

	if (fp = Open(name, (LONG)MODE_OLDFILE)) {
		error = ReadPicture(fp, bm, &iFrame, NULL); /* standard ILBM read routine */
      Close(fp);
		if (error != IFF_DONE ) {
			error = IFFError(error);
      } else {
			out = picColors;
         if ( bm->Planes[7] == NULL ) { /* standard AMiga BitMap */
   			in  = (UWORD *)iFrame.colorMap;
	   		for (i=0; i<NCOLORS; i++) /* get color table */
		   		*out++ = *in++;
            bm->pad = 0;
         } else { /* AVIDEO 12 bit image: shading greys into table */
	   		for( i=0; i<NCOLORS; i++ )
	   		   *out++ = (i<<8) | (i<<4) | i;
         }
			error = 0;
		}
   } else {
		error = 216;
   }
	return(error);
}

/* AVFreeBm -- free allocated bitmap planes : non null planes are freed.
 * CAUTION: this routine also attempts to free the bitmap planes
 * stored in the plane array pointed to by bm->Planes[].
 */
UWORD  AVFreeBm( struct BitMap *bm )
{
   LONG  pSize;
	PLANEPTR  *planes;
	WORD  i;

	if (bm) {
   	pSize = (LONG)bm->BytesPerRow * bm->Rows;
		planes = (PLANEPTR *)bm->Planes[7];
		if (bm->Flags & (AVIDEO12|AVIDEO24)) {
			if ( planes ) {
				for (i=0; i<(24+4); i++ ) {
					if (planes[i]  &&  planes[i]!=(PLANEPTR)-1L)
   						FreeMem(planes[i], pSize );
					planes[i] = NULL;
					if (i < 8)
						bm->Planes[i] = NULL;
				}
			}
		} else {
			for (i=0;  i<8;  i++) {
				if (bm->Planes[i])
					FreeMem(bm->Planes[i], pSize );
				bm->Planes[i] = NULL;
			}
		}
   	bm->Flags = 0;
		bm->pad   = 0;
   }
	return(0);
}


/* AVPicModes -- return loaded picture view modes
 */
UWORD AVPicModes( void )
{
	return(picModes);
}

/* AVPicColorTable -- return loaded picture color table
 */
UWORD *AVPicColors( VOID )
{
	return( &picColors[0] );
}

/* IFFError -- translate (approximately) IFF style errors into AVideo error codes
 */
static UWORD  IFFError( LONG iffp )
{
	UWORD  error = 0;

   switch(iffp) {
      case(DOS_ERROR):  error = 214; break;
  	   case(NOT_IFF):  error = 215; break;
     	case(NO_FILE):  error = 216; break;
      case(CLIENT_ERROR):  error = 217; break;
      case(BAD_FORM):  error = 218; break;
  	   case(SHORT_CHUNK):  error = 219; break;
     	case(BAD_IFF):  error = 220; break;
	}
   return(error);
}

/* getBitMap -- called in from GetBODY() in readpict.c
 */
struct BitMap	*getBitMap(	register ILBMFrame	*iframe )
{
	LONG  i;
	BitMapHeader *bmh = &iframe->bmHdr;
	WORD	nPlanes = bmh->nPlanes;
	struct BitMap *bm = avBm; /* bitmap to read in */
	LONG	planeSz;
   LONG  w,h;

   if (bmh->pageWidth < bmh->w) {
      if ((bmh->pageWidth = bmh->w) > OVSHIRESW)
			bmh->pageWidth = OVSHIRESW;
      bmh->x = 0;
   }
   if (bmh->pageHeight < bmh->h) {
      if ((bmh->pageHeight = bmh->h) > OVSLACEH)
			bmh->pageHeight = OVSLACEH;
      bmh->y = 0;
   }
	if ( iframe->foundCAMG ) {
		picModes = (UWORD)(iframe->camgChunk.ViewModes & 0xffffL);
		if ((picModes & HIRES)==FALSE   &&   bmh->pageWidth >= OVSLORESW)
			bmh->pageWidth = OVSLORESW;
		if ((picModes & LACE)==FALSE   &&   bmh->pageHeight >= OVSNOLACEH)
			bmh->pageHeight = OVSNOLACEH;
	}
   w = bmh->pageWidth;
   h = bmh->pageHeight;
   planeSz  = (h * w) / 8;
	if ( iframe->foundCAMG == FALSE ) {
		picModes  = ( w > (768/2) ) ? HIRES : 0;
		picModes |= ( h > 292 ) ? LACE  : 0;
	}
   if (nPlanes > 12) {
      if (bm->Flags & AVIDEO24)
         nPlanes = 24;
      else if (bm->Flags & AVIDEO12)
         nPlanes = 12;
      else
         return(NULL);
   }
  	InitBitMap(bm,nPlanes,w,h);
	if ( nPlanes < 8 ) {
		for(i=0;  i<nPlanes;  i++)
			if ((bm->Planes[i]=(PLANEPTR)AllocMem(planeSz,MEMF_CHIP))==NULL)
            return(NULL);
		for(;  i<8;  i++)
			bm->Planes[i] = NULL;
      bm->pad = 0;
   } else if (AVSetBitMap(bm, planeSz)) {
      return(NULL);
   }
	return(bm);
}

/* AVSetBitMap -- Set extended bitmap: bm->Planes[7] contains the address
 * of the plane array. Those planes not to be loaded are marked with their
 * entry equal to 1L in picPlanes[].
 */
static UWORD AVSetBitMap( struct BitMap *bm, LONG planeSz )
{
   WORD i, j;
   WORD depth;
   WORD error = 0;
   PLANEPTR  *planes = &picPlanes[0];
   UWORD *lst;
   static UWORD planeLst24[24+4] = {
         6, 23,15,7,  13,5, 22,14, 20,12, 4,21,  2, 19,11,3,  9, 1, 18,10, 16,8, 0, 17, 24,25,26,27 };
/* 24-b  R1 B0 G0 R0  G2 R2 B1 G1  B3 G3 R3 B2   R5 B4 G4 R4  G6 R6 B5 G5  B7 G7 R7 B6 */
   static UWORD planeLst12[24+4] = {
         2, 11,7, 3,  5, 1, 10,6,  8, 4, 0, 9,   12,13,14,15, 16,17,18,19, 20,21,22,23, 24,25,26,27 };
/* 12-b  R1 B0 G0 R0  G2 R2 B1 G1  B3 G3 R3 B2 */



	bm->Planes[7] = (PLANEPTR)planes;
	bm->pad  = 0;
   depth = bm->Depth;

   if (bm->Flags & AVIDEO24) { /* AVIDEO24 boards */
      if (depth == 12)
         lst = planeLst12;
      else
         lst = planeLst24;
      for (i=0;  i<depth;  i++)
        	if (planes[lst[i]] = (PLANEPTR)AllocMem(planeSz,MEMF_PUBLIC|MEMF_CHIP))
  	         bm->pad++;
         else
            break;
      if (i < 4)
         return(1);
      if (i < depth) {
			if (i > 4)
				FreeMem(planes[lst[--i]],planeSz);
         depth += 4;
         for (;  i<depth;  i++)
           	if ((planes[lst[i]] = (PLANEPTR)AllocMem(planeSz,MEMF_PUBLIC)) == NULL)
  	            break;
         if (i < depth)
            return(2);
      }
      while (i < 24)
         planes[lst[i++]] = NULL;
      while (i < (24+4))
         planes[i++] = NULL;
   } else if (bm->Flags & AVIDEO12) { /* AVIDEO12 & AVIDEO24 boards */
      for (i=0;  i<depth;  i++)
        	if (planes[i] = (PLANEPTR)AllocMem(planeSz,MEMF_PUBLIC|MEMF_CHIP))
  	         bm->pad++;
         else
            break;
      if (i < 4)
         return(1);
      if (i < depth) {
			if (i > 4)
				FreeMem(planes[--i],planeSz);
         depth += 4;
         for (;  i<depth;  i++)
           	if ((planes[i] = (PLANEPTR)AllocMem(planeSz,MEMF_PUBLIC)) == NULL)
  	            break;
         if (i < depth)
            return(2);
      }
      while (i<(24+4))
         planes[i++] = NULL;
   } else {
      error = 3;
   }
   return(error);
}

