
/*
 * xanim_fli.c
 *
 * Copyright (C) 1990,1991,1992,1993,1994 by Mark Podlipec. 
 * All rights reserved.
 *
 * This software may be freely copied, modified and redistributed
 * without fee provided that this copyright notice is preserved 
 * intact on all copies and modified copies.
 * 
 * There is no warranty or other guarantee of fitness of this software.
 * It is provided solely "as is". The author(s) disclaim(s) all
 * responsibility and liability with respect to this software's usage
 * or its effect upon hardware or computer systems.
 *
 */
#include "xanim_fli.h" 

LONG Is_FLI_File();
void Fli_Read_File();
static void FLI_Read_Header();
ULONG FLI_Read_Frame_Header();
FLI_FRAME *FLI_Add_Frame();
ULONG FLI_Decode_BRUN();
ULONG FLI_Decode_LC();
ULONG FLI_Decode_COPY();
ULONG FLI_Decode_BLACK();
ULONG FLI_Decode_LC7();
static void FLI_Read_COLOR();

XA_ACTION *ACT_Get_Action();
XA_CHDR *ACT_Get_CMAP();
void ACT_Add_CHDR_To_Action();
void ACT_Setup_Mapped();
void ACT_Get_CCMAP();


void UTIL_Sub_Image();
ULONG UTIL_Get_LSB_Long();
ULONG UTIL_Get_LSB_Short();

static ColorReg fli_cmap[FLI_MAX_COLORS];
static Fli_Header fli_hdr;
static Fli_Frame_Header frame_hdr;

static FLI_FRAME *fli_frame_start,*fli_frame_cur;
static ULONG fli_frame_cnt;
static ULONG fli_imagex,fli_imagey,fli_imagec;
static ULONG fli_max_fsize;

/* 
 * FLI has time period of 1/70th sec where  FLC has time period of 1 ms.
 */
#define FLI_TIME_PERIOD   ((fli_hdr.magic == 0xaf11)?(14):(1))

static XA_CHDR *fli_chdr;

FLI_FRAME *FLI_Add_Frame(time,act)
ULONG time;
XA_ACTION *act;
{
  FLI_FRAME *fframe;

  fframe = (FLI_FRAME *) malloc(sizeof(FLI_FRAME));
  if (fframe == 0) TheEnd1("FLI_Add_Frame: malloc err");

  fframe->time = time;
  fframe->act = act;
  fframe->next = 0;

  if (fli_frame_start == 0) fli_frame_start = fframe;
  else fli_frame_cur->next = fframe;

  fli_frame_cur = fframe;
  fli_frame_cnt++;
  return(fframe);
}

static void FLI_Free_Frame_List(fframes)
FLI_FRAME *fframes;
{
  FLI_FRAME *ftmp;
  while(fframes != 0)
  {
    ftmp = fframes;
    fframes = fframes->next;
    FREE(ftmp,0x2000);
  }
}

/*
 *
 */
LONG Is_FLI_File(filename)
char *filename;
{
  FILE *fin;
  ULONG data;

  if ( (fin=fopen(filename,"r")) == 0) return(FALSE);

  data = UTIL_Get_LSB_Long(fin);  /* read past size */
  data = UTIL_Get_LSB_Short(fin); /* read magic */
  fclose(fin);
  if ( (data == 0xaf11) || (data == 0xaf12) ) return(TRUE);
  return(FALSE);
}


static void FLI_Read_Header(fp,fli_hdr)
FILE *fp;
Fli_Header *fli_hdr;
{
  LONG i;

  fli_hdr->size   = UTIL_Get_LSB_Long(fp);
  fli_hdr->magic  = UTIL_Get_LSB_Short(fp);
  fli_hdr->frames = UTIL_Get_LSB_Short(fp);
  fli_hdr->width  = UTIL_Get_LSB_Short(fp);
  fli_hdr->height = UTIL_Get_LSB_Short(fp);
  fli_hdr->res1   = UTIL_Get_LSB_Short(fp);
  fli_hdr->flags  = UTIL_Get_LSB_Short(fp);
  fli_hdr->speed  = UTIL_Get_LSB_Short(fp);
  if (fli_hdr->speed <= 0) fli_hdr->speed = 1;
  fli_hdr->next   = UTIL_Get_LSB_Long(fp);
  fli_hdr->frit   = UTIL_Get_LSB_Long(fp);
  for(i=0;i<102;i++) fgetc(fp);   /* ignore unused part of Fli_Header */

  fli_imagex=fli_hdr->width;
  fli_imagey=fli_hdr->height;
  if ( (fli_hdr->magic != 0xaf11) && (fli_hdr->magic != 0xaf12) )
  {
   fprintf(stderr,"imagex=%lx imagey=%lx\n",fli_imagex,fli_imagey);
   fprintf(stderr,"Fli Header Error magic %lx not = 0xaf11\n",fli_hdr->magic);
   TheEnd();
  }
}

ULONG FLI_Read_Frame_Header(fp,frame_hdr)
FILE *fp;
Fli_Frame_Header *frame_hdr;
{
  LONG i,size,magic;

  size  = UTIL_Get_LSB_Long(fp);
  magic = UTIL_Get_LSB_Short(fp);

  while( (magic != 0xf1fa) && (magic != 0xf100))
  {
     size =  ((size >> 8) & 0x00ffffff) | (fgetc(fp) & 0x00ff);
     magic =  ((magic >> 8) & 0x00ffffff) | (fgetc(fp) & 0x00ff);
     if ( feof(fp) ) return(0);
  }
  frame_hdr->size = size;
  frame_hdr->magic = magic;
  frame_hdr->chunks = UTIL_Get_LSB_Short(fp);
  for(i=0;i<8;i++) fgetc(fp);	/* ignore unused part of Fli_Frame_Header */

  DEBUG_LEVEL1 
	fprintf(stderr,"Frame Header size %lx  magic %lx  chunks %ld\n",
		frame_hdr->size,frame_hdr->magic,frame_hdr->chunks);

  return(1);
}

void Fli_Read_File(fname,anim_hdr)
char *fname;
XA_ANIM_HDR *anim_hdr;
{
  FILE *fin;
  LONG i,j,ret;
  XA_ACTION *act;
  UBYTE *pic;
  ULONG pic_size,tmp_frame_cnt;

  if ( (fin=fopen(fname,"r")) == 0)
  { 
    fprintf(stderr,"can't open Fli File %s for reading\n",fname); 
    TheEnd();
  }
 
  pic = 0;
  fli_chdr = 0;
  fli_frame_start = 0;
  fli_frame_cur = 0;
  fli_frame_cnt = 0;
  fli_max_fsize = 0;

  FLI_Read_Header(fin,&fli_hdr);

  if (xa_verbose) fprintf(stderr,"   Size %ldx%ld Frames= %ld Magic= %lx\n",
	fli_hdr.width, fli_hdr.height,fli_hdr.frames,fli_hdr.magic);

    /* Allocate image buffer so deltas may be applied if buffering */
  pic_size = fli_imagex * fli_imagey;
  if (xa_buffer_flag == TRUE)
  {
    pic = (UBYTE *) malloc( pic_size );
    if (pic == 0) TheEnd1("BufferAction: malloc failed");
  }


  tmp_frame_cnt = 0;
  while( FLI_Read_Frame_Header(fin, &frame_hdr) != 0)
  {
    ULONG fli_time,frame_read_size;

    tmp_frame_cnt++;
    fli_time = XA_GET_TIME(fli_hdr.speed * FLI_TIME_PERIOD);
    
    if (frame_hdr.magic == 0xf100)
    {
      LONG i;
      DEBUG_LEVEL1 
	 fprintf(stderr,"FLI 0xf100 Frame: size = %lx\n",frame_hdr.size);
      for(i=0;i<(frame_hdr.size - 16);i++) fgetc(fin);
      if (frame_hdr.size & 0x01) fgetc(fin); 
    }
    else if (frame_hdr.chunks==0)  /* this frame is for timing purposes */
    {
      DEBUG_LEVEL1 fprintf(stderr," FLI DELAY %ld\n",fli_hdr.speed);
      act = ACT_Get_Action(anim_hdr,ACT_DELAY);
      act->data = 0;
      FLI_Add_Frame(fli_time,act);
    }
    else /* this frame has real data in it */
    {
      /* Loop through chunks in the frame
       */
      frame_read_size = 10;
      for(j=0;j<frame_hdr.chunks;j++)
      {
        LONG chunk_size;
	ULONG chunk_type;
   
	/* only last chunk in frame should have full time(j must stay signed)*/
        if (j < (frame_hdr.chunks - 1) ) fli_time = 0;
	else fli_time = XA_GET_TIME(fli_hdr.speed * FLI_TIME_PERIOD);
        chunk_size = UTIL_Get_LSB_Long(fin);
        chunk_type = UTIL_Get_LSB_Short(fin);
	frame_read_size += 6 + chunk_size;
        if (chunk_size & 0x01) frame_read_size++;
        DEBUG_LEVEL2 fprintf(stderr,"  chunk %ld) size %lx  type %lx tot %lx\n",
		j,chunk_size,chunk_type,frame_read_size);
        switch(chunk_type)
        {
          case CHUNK_4:     /* FLI Color with 8 bits RGB */
		DEBUG_LEVEL1 fprintf(stderr," FLI COLOR(4)\n");
		FLI_Read_COLOR(anim_hdr,fin,fli_time,8,frame_hdr.chunks);
		break;
          case FLI_COLOR:     /* FLI Color with 6 bits RGB */
		DEBUG_LEVEL1 fprintf(stderr," FLI COLOR(11)\n");
		FLI_Read_COLOR(anim_hdr,fin,fli_time,6,frame_hdr.chunks);
		break;
          case FLI_LC:
          case FLI_LC7:
          case FLI_BRUN:
          case FLI_COPY:
          case FLI_BLACK:
		{
		  ACT_DLTA_HDR *dlta_hdr;
		 
		  if (chunk_type==FLI_COPY) chunk_size = pic_size;
		  else	chunk_size -= 6;

		  act = ACT_Get_Action(anim_hdr,ACT_DELTA);
		  FLI_Add_Frame(fli_time,act);

		  if ( (chunk_type == FLI_BLACK) && (chunk_size != 0) )
					TheEnd1("FLI BLACK: size err\n");
		  else if (chunk_size > 0)
		  {
		    if (xa_file_flag == TRUE)
		    {
 		      dlta_hdr = (ACT_DLTA_HDR *) malloc(sizeof(ACT_DLTA_HDR));
 		      if (dlta_hdr == 0) TheEnd1("FLI CHUNK: malloc failed");
		      act->data = (UBYTE *)dlta_hdr;
		      dlta_hdr->data = 0;
		      dlta_hdr->fpos  = ftell(fin);
		      dlta_hdr->fsize = chunk_size;
 		      fseek(fin,chunk_size,1); /* move past this chunk */
		      if (chunk_size > fli_max_fsize) 
					fli_max_fsize = chunk_size;
		    }
		    else
		    {
 		      dlta_hdr = (ACT_DLTA_HDR *)
				malloc(sizeof(ACT_DLTA_HDR) + chunk_size);
 		      if (dlta_hdr == 0) TheEnd1("FLI CHUNK: malloc failed");
		      act->data = (UBYTE *)dlta_hdr;
		      dlta_hdr->data = (UBYTE *)
				((ULONG)dlta_hdr + sizeof(ACT_DLTA_HDR));
		      dlta_hdr->fpos = dlta_hdr->fsize = 0;
 		      ret = fread( dlta_hdr->data, chunk_size, 1, fin);
 		      if (ret != 1) TheEnd1("FLI DLTA: read failed");
		    }
		  }
		  else TheEnd1("FLI DLTA: invalid size");

		  dlta_hdr->flags = ACT_SNGL_BUF;
		  dlta_hdr->xpos = dlta_hdr->ypos = 0;
		  dlta_hdr->xsize = fli_imagex;
		  dlta_hdr->ysize = fli_imagey;
		  dlta_hdr->special = 0;
		  switch(chunk_type)
		  {
		   case FLI_LC7:
			DEBUG_LEVEL1 fprintf(stderr," FLI LC(7)\n");
			dlta_hdr->delta = FLI_Decode_LC7;
			break;
		  case FLI_LC:
			DEBUG_LEVEL1 fprintf(stderr," FLI LC(12)\n");
			dlta_hdr->delta = FLI_Decode_LC;
			break;
		  case FLI_BLACK:
			DEBUG_LEVEL1 fprintf(stderr," FLI BLACK(13)\n");
			dlta_hdr->delta = FLI_Decode_BLACK;
			break;
		  case FLI_BRUN:
			DEBUG_LEVEL1 fprintf(stderr," FLI BRUN(15)\n");
			dlta_hdr->delta = FLI_Decode_BRUN;
			break;
		  case FLI_COPY:
			DEBUG_LEVEL1 fprintf(stderr," FLI COPY(16)\n");
			dlta_hdr->delta = FLI_Decode_COPY;
			break;
		 }
		 ACT_Add_CHDR_To_Action(act,fli_chdr);
		 if (xa_buffer_flag == TRUE)
		 {
		   ULONG xpos,ypos,xsize,ysize;
		   dlta_hdr->delta(pic,dlta_hdr->data,fli_chdr->map,FALSE,
			fli_imagex,fli_imagey,8,&xpos,&ypos,&xsize,&ysize,0);
		   xsize -= xpos; ysize -= ypos;
		   FREE(dlta_hdr,0x2000); act->data = 0;
		   ACT_Setup_Mapped(act,pic,fli_chdr,
			xpos,ypos,xsize,ysize,fli_imagex,fli_imagey,FALSE,0,
			FALSE,TRUE,FALSE);
		 } /* end of buffer */
		}
		break;
 
          case FLI_MINI:
		{
		  LONG i;
		  DEBUG_LEVEL1 fprintf(stderr," FLI MINI(18) ignored.\n");
		  for(i=0;i<(chunk_size-6);i++) fgetc(fin);
	          if (chunk_size & 0x01) fgetc(fin);
		}
		break;

           default: 
             {
               LONG i;
	       fprintf(stderr,"FLI Unsupported Chunk: type = %lx size=%lx\n",
					chunk_type,chunk_size);
               for(i=0;i<(chunk_size-6);i++) fgetc(fin);
	       if (chunk_size & 0x01) fgetc(fin);
             }
	         
		 break;
        } /* end of switch */
      } /* end of chunks is frame */
    } /* end of not Timing Frame */
  } /* end of frames in file */
  if (pic != 0) { FREE(pic,0x2000); pic=0;}
  fclose(fin);

  anim_hdr->frame_lst = (XA_FRAME *)
		malloc(sizeof(XA_FRAME) * (fli_frame_cnt + 1));
  if (anim_hdr->frame_lst == NULL) TheEnd1("FLI_Read_Anim: malloc err");

  fli_frame_cur = fli_frame_start;
  i = 0;
  while(fli_frame_cur != 0)
  {
    if (i > fli_frame_cnt)
    {
      fprintf(stderr,"FLI_Read_Anim: frame inconsistency %ld %ld\n",
                i,fli_frame_cnt);
      break;
    }
    anim_hdr->frame_lst[i].time = fli_frame_cur->time;
    anim_hdr->frame_lst[i].act = fli_frame_cur->act;
    fli_frame_cur = fli_frame_cur->next;
    i++;
  }
  anim_hdr->imagex = fli_imagex;
  anim_hdr->imagey = fli_imagey;
  anim_hdr->imagec = fli_imagec;
  anim_hdr->imaged = 8; /* nop */
  anim_hdr->max_fsize = fli_max_fsize;
  anim_hdr->frame_lst[i].time = 0;
  anim_hdr->frame_lst[i].act  = 0;
  if (tmp_frame_cnt > fli_hdr.frames) anim_hdr->loop_frame = 1;
  else anim_hdr->loop_frame = 0;
  if (i > 0) anim_hdr->last_frame = i - 1;
  else i = 0;
  FLI_Free_Frame_List(fli_frame_start);
  if (xa_buffer_flag == FALSE) anim_hdr->anim_flags |= ANIM_SNG_BUF;
  if (xa_file_flag == TRUE) anim_hdr->anim_flags |= ANIM_USE_FILE;
  anim_hdr->fname = anim_hdr->name; /* data file is same as name */
}


/*
 * Routine to Decode a Fli BRUN chunk
 */
ULONG
FLI_Decode_BRUN(image,delta,map,map_flag,imagex,imagey,imaged,
						xs,ys,xe,ye,special)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;		/* Special Info. */
{
  ULONG i,j,k,packets,size,x,offset,pix_size;

  *xs = *ys = 0; *xe = imagex; *ye = imagey;
  pix_size = (map_flag==TRUE)?x11_bytes_pixel:1;
  for(i=0; i < imagey; i++)
  {
    offset = i * imagex;
    packets = *delta++;

    x=0;
    for(j= 0; j < packets; j++)
    {
      size = *delta++;
      if (size & 0x80)         /* size < 0 so there is -size unique bytes */
      {
        size = 256-size; 
        if (map_flag == TRUE)
        {
          if (pix_size == 4)
            for(k=x;k<(x+size);k++)
                ((ULONG *)(image))[k+offset] = (ULONG)(map[*delta++]);
          else if (pix_size == 2)
            for(k=x;k<(x+size);k++)
                ((USHORT *)(image))[k+offset] = (USHORT)(map[*delta++]);
          else
            for(k=x;k<(x+size);k++)
                ((UBYTE *)(image))[k+offset] = (UBYTE)(map[*delta++]);
        }
        else
        {
          for(k=x;k<(x+size);k++)
                ((UBYTE *)(image))[k+offset] = (UBYTE)(*delta++);
        }

        x += size;   
      }
      else                     /* size is pos repeat next byte size times */
      {
        ULONG d;
        d = *delta++;
        if (map_flag == TRUE)
        {
          if (pix_size == 4)
            for(k=x;k<(x+size);k++)
                ((ULONG *)(image))[k+offset] = (ULONG)(map[d]);
          else if (pix_size == 2)
             for(k=x;k<(x+size);k++)
                ((USHORT *)(image))[k+offset] = (USHORT)(map[d]);
          else
             for(k=x;k<(x+size);k++)
                ((UBYTE *)(image))[k+offset] = (UBYTE)(map[d]);
        }
        else
        {
          for(k=x;k<(x+size);k++)
                ((UBYTE *)(image))[k+offset] = (UBYTE)(d);
        }
        x+=size;   
      }
    } /* end of packets per line */
  } /* end of line */
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

/*
 * Routine to Decode an Fli LC chunk
 */

ULONG
FLI_Decode_LC(image,delta,map,map_flag,imagex,imagey,imaged,xs,ys,xe,ye,special)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;		/* Special Info. */
{
  ULONG i,j,k,packets,size,x,offset;
  ULONG start,lines,skip,minx,maxx,pix_size;

  pix_size = (map_flag==TRUE)?x11_bytes_pixel:1;
  start = *delta++; start |= *delta++ << 8;  /* lines to skip */
  lines = *delta++; lines |= *delta++ << 8;  /* number of lines */

  minx = imagex; 
  maxx = 0;
 
  for(i=start;i<(start+lines);i++)
  {
    offset = i * imagex;
    packets = *delta++;

    x=0;
    for(j=0;j<packets;j++)
    {
      skip = *delta++;   /* this is the skip count */
      size = *delta++;

      if (j==0) if (skip < minx) minx = skip;
      x+=skip;
      if (size==0) 
      {
/* PODTEMP
        size = *delta++;
        fprintf(stderr,"size==0 what to we do? next is %ld\n",size);
        TheEnd();
*/
      }
      else if (size & 0x80) /* next byte repeated -size times */
      {
        ULONG d;
        size = 256-size; 
        d = *delta++;
	if (map_flag == TRUE)
        {
	  if (pix_size == 4)
            for(k=x;k<(x+size);k++) 
		((ULONG *)(image))[k+offset] = (ULONG)(map[d]);
	  else if (pix_size == 2)
             for(k=x;k<(x+size);k++) 
		((USHORT *)(image))[k+offset] = (USHORT)(map[d]);
	  else
             for(k=x;k<(x+size);k++) 
		((UBYTE *)(image))[k+offset] = (UBYTE)(map[d]);
        }
        else
        {
          for(k=x;k<(x+size);k++) 
		((UBYTE *)(image))[k+offset] = (UBYTE)(d);
        }
        x+=size;   
      }
      else /* size is pos */
      {
        if (map_flag == TRUE)
        {
          if (pix_size == 4)
            for(k=x;k<(x+size);k++) 
		((ULONG *)(image))[k+offset] = (ULONG)(map[*delta++]);
          else if (pix_size == 2)
            for(k=x;k<(x+size);k++) 
		((USHORT *)(image))[k+offset] = (USHORT)(map[*delta++]);
          else
            for(k=x;k<(x+size);k++) 
		((UBYTE *)(image))[k+offset] = (UBYTE)(map[*delta++]);
        }
        else
        {
          for(k=x;k<(x+size);k++) 
		((UBYTE *)(image))[k+offset] = (UBYTE)(*delta++);
        }

        x+=size;   
      }
    } /* end of packets per line */
    if (x > maxx) maxx = x;
  } /* end of line */

  if (xa_optimize_flag == TRUE)
  {
   *ys = start;
   *ye = start + lines;
   *xs = minx;
   if (maxx > imagex) maxx=imagex;
   if (maxx > minx) *xe = maxx;
   else *xe = imagex;
  }
  else { *ys = 0; *ye = imagey; *xs = 0; *xe = imagex; }

  DEBUG_LEVEL1 fprintf(stderr,"      LC: xypos=<%ld %ld> xysize=<%ld %ld>\n",
                        *xs,*ys,*xe,*ye);

  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

ULONG
FLI_Decode_COPY(image,delta,map,map_flag,imagex,imagey,imaged,
						xs,ys,xe,ye,special)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;
{
  ULONG image_size = imagex * imagey;
  *xs = *ys = 0; *xe = imagex; *ye = imagey;
  if (map_flag)
  {
    if (x11_bytes_pixel == 4)
    { ULONG *i_ptr = (ULONG *)image;
      while(image_size--) *i_ptr++ = (ULONG)map[ *delta++ ];
    }
    else if (x11_bytes_pixel == 2)
    { USHORT *i_ptr = (USHORT *)image;
      while(image_size--) *i_ptr++ = (USHORT)map[ *delta++ ];
    }
    else
    { UBYTE *i_ptr = (UBYTE *)image;
      while(image_size--) *i_ptr++ = (UBYTE)map[ *delta++ ];
    }
  } 
  else memcpy( (char *)image,(char *)delta,image_size);
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

ULONG
FLI_Decode_BLACK(image,delta,map,map_flag,imagex,imagey,imaged,
						xs,ys,xe,ye,special)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;
{
  ULONG image_size = imagex * imagey;
  *xs = *ys = 0; *xe = imagex; *ye = imagey;
  if (map_flag)
  {
    ULONG black = map[0];
    if (x11_bytes_pixel == 4)
    { ULONG *i_ptr = (ULONG *)image;
      while(image_size--) *i_ptr++ = (ULONG)black;
    }
    else if (x11_bytes_pixel == 2)
    { USHORT *i_ptr = (USHORT *)image;
      while(image_size--) *i_ptr++ = (USHORT)black;
    }
    else
    { UBYTE *i_ptr = (UBYTE *)image;
      while(image_size--) *i_ptr++ = (UBYTE)black;
    }
  } 
  else memset( (char *)image,0,image_size);
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}


/*
 * Routine to read an Fli COLOR chunk
 */
static void FLI_Read_COLOR(anim_hdr,fin,fli_time,cbits,num_of_chunks)
XA_ANIM_HDR *anim_hdr;
FILE *fin;
ULONG fli_time,cbits;
ULONG num_of_chunks;
{
 XA_ACTION *act;
 ULONG k,l,c_index,packets,skip,colors,cnt;
 ULONG mask;

 mask = (0x01 << cbits) - 1;
 packets = UTIL_Get_LSB_Short(fin);
 c_index = 0;

 DEBUG_LEVEL1 fprintf(stderr,"   packets = %ld\n",packets);
 cnt=2;
 for(k=0;k<packets;k++)
 {
  skip = fgetc(fin);
  colors=fgetc(fin);
  DEBUG_LEVEL1 fprintf(stderr,"      skip %ld colors %ld\n",skip,colors);
  cnt+=2;
  if (colors==0) colors=FLI_MAX_COLORS;
  c_index += skip;
  for(l = 0; l < colors; l++)
  {
   fli_cmap[c_index].red   = fgetc(fin) & mask;
   fli_cmap[c_index].green = fgetc(fin) & mask;
   fli_cmap[c_index].blue  = fgetc(fin) & mask;
   DEBUG_LEVEL5 fprintf(stderr,"         %ld)  <%lx %lx %lx>\n", 
		  l,fli_cmap[l].red, fli_cmap[l].green,fli_cmap[l].blue);
   c_index++;
  } /* end of colors */
  cnt+= 3 * colors;
 } /* end of packets */
 if (cnt&0x01) fgetc(fin);  /* read pad byte if needed */

 /* if only one chunk in frame this is a cmap change only */
 if ( (num_of_chunks==1) && (fli_chdr != 0) )
 {
   act = ACT_Get_Action(anim_hdr,0);
   ACT_Get_CCMAP(act,fli_cmap,FLI_MAX_COLORS,0,cbits,cbits,cbits);
   FLI_Add_Frame(fli_time,act);
   ACT_Add_CHDR_To_Action(act,fli_chdr);
 }
 else
   fli_chdr = ACT_Get_CMAP(fli_cmap,FLI_MAX_COLORS,0,FLI_MAX_COLORS,0,
							cbits,cbits,cbits);
}

/*
 * Routine to Decode an Fli LC chunk
 */
ULONG
FLI_Decode_LC7(image,delta,map,map_flag,imagex,imagey,imaged,xs,ys,xe,ye,special)
UBYTE *image;		/* Image Buffer. */
UBYTE *delta;		/* delta data. */
ULONG *map;		/* used if it's going to be remapped. */
ULONG map_flag;		/* whether or not to use remap_map info. */
ULONG imagex,imagey;	/* Size of image buffer. */
ULONG imaged;		/* Depth of Image. (IFF specific) */
ULONG *xs,*ys;		/* pos of changed area. */
ULONG *xe,*ye;		/* size of changed area. */
ULONG special;		/* Special Info. */
{
  ULONG i,j,x,y;
  ULONG packets,blocks,xoff,cnt,tmp_data0,tmp_data1;
  ULONG minx,maxx,miny,pix_size;
  UBYTE *ptr;
  

  minx = imagex;
  maxx = 0;
  miny = imagey;

  pix_size = (map_flag==TRUE)?x11_bytes_pixel:1;
  ptr = image;
  y = 0;
  packets = *delta++; packets |= *delta++ << 8;  /* # of packets */

  DEBUG_LEVEL5 fprintf(stderr,"pkts=%ld\n",packets);

  for(i=0; i < packets; i++)
  {
   
    blocks = *delta++; blocks |= *delta++ << 8; 

    DEBUG_LEVEL5 fprintf(stderr,"     %ld) ",i);

/*POD NOTE: possibly somehting about ((blocks & 0xc000) == 0x8000)
 * being a special code for odd-byte-lenght images????
 */
    if ((blocks & 0xc000) == 0x8000)
    {
	fprintf(stderr,"FLI: Whoa...blocks %lx Contact Author!\n",blocks);
    }
    if (blocks & 0x8000)  /* neg lines to jump */
    {
      blocks = 0x10000 - blocks;
      y += blocks;
      DEBUG_LEVEL5 fprintf(stderr,"     yskip %ld",blocks);
      blocks = *delta++; blocks |= *delta++ << 8;
    }
    DEBUG_LEVEL5 fprintf(stderr,"     blocks = %ld\n",blocks);

    if (xa_optimize_flag == TRUE) if (y < miny) miny = y;

    ptr  = (UBYTE *)( (ULONG)(image) + y*imagex*pix_size);
    x = 0;

    for(j=0; j < blocks; j++)
    {
      xoff = (ULONG) *delta++;  /* x offset */
      cnt  = (ULONG) *delta++;  /* halfword count */
      ptr += (xoff * pix_size);
      x += xoff;

      DEBUG_LEVEL5 
        fprintf(stderr,"          %ld) xoff %lx  cnt = %lx",j,xoff,cnt);

      if (cnt & 0x80)
      {
        cnt = 256 - cnt;
        DEBUG_LEVEL5 fprintf(stderr,"               NEG %ld\n",cnt);
        if (xa_optimize_flag == TRUE)
        {  
          if (x < minx) minx = x;
          x += (cnt << 1);
          if (x > maxx) maxx = x;
        }

	if (map_flag == TRUE)
        {
          tmp_data0 = map[*delta++];
          tmp_data1 = map[*delta++];
          if (pix_size == 4)
	  { 
	    ULONG *ulp = (ULONG *)ptr;
            while(cnt--) { *ulp++ = (ULONG)tmp_data0;
			   *ulp++ = (ULONG)tmp_data1; }
	    ptr = (UBYTE *)ulp;
          }
          else if (pix_size == 2)
	  { 
	    USHORT *usp = (USHORT *)ptr;
	    while(cnt--) { *usp++ = (USHORT)tmp_data0;
			   *usp++ = (USHORT)tmp_data1; }
	    ptr = (UBYTE *)usp;
          }
          else
            while(cnt--) { *ptr++ = (UBYTE)tmp_data0;
                           *ptr++ = (UBYTE)tmp_data1; }
	}
	else
	{
          tmp_data0 = *delta++;
          tmp_data1 = *delta++;
          while(cnt--) { *ptr++ = (UBYTE)tmp_data0;
                         *ptr++ = (UBYTE)tmp_data1; }
	}

      }
      else
      {   /* cnt is number of unique pairs of bytes */
        DEBUG_LEVEL5 fprintf(stderr,"               POS %ld\n",cnt);
/*PODTMP*/
if (cnt == 0) fprintf(stderr,"FLC: cnt == 0\n");
        if (xa_optimize_flag == TRUE)
        {
          if (cnt == 1)  /* potential NOPs just to move x */
          {
            if ( (*ptr != *delta) || (ptr[1] != delta[1]) )  
            {
              if (x < minx) minx = x; 
              x += (cnt << 1);
              if (x > maxx) maxx = x;
            }
          }
	  else
          {
            if (x < minx) minx = x; 
            x += (cnt << 1);
            if (x > maxx) maxx = x;
          }
        }
        if (map_flag == TRUE)
        {
          if (pix_size == 4)
	  { 
	    ULONG *ulp = (ULONG *)ptr;
	    while(cnt--) { *ulp++ = (ULONG)map[*delta++];
                           *ulp++ = (ULONG)map[*delta++]; }
	    ptr = (UBYTE *)ulp;
          }
          else if (pix_size == 2)
	  { 
	    USHORT *usp = (USHORT *)ptr;
	    while(cnt--) { *usp++ = (USHORT)map[*delta++];
			   *usp++ = (USHORT)map[*delta++]; }
	    ptr = (UBYTE *)usp;
          }
          else
             while(cnt--) { *ptr++ = (UBYTE)map[*delta++];
			    *ptr++ = (UBYTE)map[*delta++]; }
        }
        else
             while(cnt--) { *ptr++ = (UBYTE) *delta++;
			    *ptr++ = (UBYTE) *delta++; }

      } 
    } /* (j) end of blocks */
    y++;
  } /* (i) end of packets */

DEBUG_LEVEL3
 fprintf(stderr,"      LC: minx miny (%ld %ld), maxx maxy (%ld %ld)\n",
     minx,miny,maxx,y);

  if (xa_optimize_flag == TRUE)
  {
    if (minx >= imagex) minx = 0; 
    if (miny >= imagey) miny = 0; 

    *xs = minx;
    *ys = miny;

    if (maxx > minx) *xe = maxx + 2; /*POD QUEST? why the 2 and not 1 */
    else             *xe = imagex;

    if (y > miny) *ye = y + 1;
    else          *ye = imagey;
  }
  else { *xs = 0; *ys = 0; *xe = imagex; *ye = imagey; }
  DEBUG_LEVEL1 fprintf(stderr,"      LC: xypos=<%ld %ld> xysize=<%ld %ld>\n",
		 *xs,*ys,*xe,*ye);
  if (map_flag) return(ACT_DLTA_MAPD);
  else return(ACT_DLTA_NORM);
}

