// TSMorph - Amiga Morphing program
// Copyright (C) © 1993  Topicsave Limited

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

// mpaddock@cix.compulink.co.uk

//	$Author: M_J_Paddock $
//	$Date: 1992/08/08 01:09:24 $
//	$Revision: 1.5 $

// Include precompiled headers if required
#ifndef TSMORPH_H
#include "TSMorph.h"
#endif

#include "JPEG_LS/jinclude.h"

extern UWORD FileFormat = 0;	// Format of file being loaded

/* Loads an image (in various formats)
 * pic     : pointer to Picture structure
 * filename: filename to load
 * Returns : TRUE if loaded OK
 */
BOOL
MyLoadBrush (struct Picture *pic,UBYTE *filename) {
	BOOL OpenILBM = FALSE;	// Are we loading a (<24 plane) ILBM
	char *e = NULL;			// First
	char *e1 = NULL;			// and second part of error message
	long hnum;					// Help number
	long err;					// Error flag
	BPTR fh;						// File handle
	UBYTE buffer[5]="\0\0\0\0";	// First 4 bytes of file for identification

	// Try and open file and read 1st 4 bytes
	if (fh = Open(filename,MODE_OLDFILE)) {
		FRead(fh,buffer,4,1);
		// check if a sort of IFF file
		if (!strcmp(buffer,"LIST") ||
			 !strcmp(buffer,"CAT ") ||
			 !strcmp(buffer,"FORM")) {
			FileFormat = FORMAT_IFF;
		}
		else {
			// check if a JFIF JPEG
			if ((buffer[0] == 0xFF) &&
				 (buffer[1] == 0xD8)) {
				FileFormat = FORMAT_JPEG;
			}
			else {
				// check if a GIF
				if ((buffer[0] == 'G') &&
					 (buffer[1] == 'I') &&
					 (buffer[2] == 'F')) {
					FileFormat = FORMAT_GIF;
				}
				else {
					// check if a PPM
					if ((buffer[0] == 'P') &&
						 ((buffer[1] == '2') ||
						  (buffer[1] == '3') ||
						  (buffer[1] == '5') ||
						  (buffer[1] == '6'))) {
						FileFormat = FORMAT_PPM;
					}
					else {
						// Otherwise default to TARGA (the only other format we load)
						FileFormat = FORMAT_TARGA;
					}
				}
			}
		}
		Close(fh);
	}
	else {
		// error file not found
		FileFormat = 0;
		e = "File does not exist '%s'";
		hnum = HE_NoFile;
		e1 = filename;
	}
	// If the file is and IFF and we only open ILBMs in some cases then perform some checks
	if ((FileFormat == FORMAT_IFF) && ((OpenMode == OPEN_ILBM_IF_ILBM) || (OpenMode == OPEN_ILBM_IF_COLOURS))) {
		if (pic->ilbm->ParseInfo.iff = AllocIFF()) {
			err = queryilbm(pic->ilbm,filename);
			if (!err) {
				if (OpenMode == OPEN_ILBM_IF_COLOURS) {
					// if we only open if screen colours then check depth
					if (!(pic->ilbm->Bmhd.nPlanes > TSMorphWnd->WScreen->BitMap.Depth)) {
						OpenILBM = TRUE;
					}
				}
				else {	// OpenMode == OPEN_ILBM_IF_ILBM
					// if open if an ILBM then check < 24 bits
					if (pic->ilbm->Bmhd.nPlanes < 24) {
						OpenILBM = TRUE;
					}
				}
			}
			FreeIFF(pic->ilbm->ParseInfo.iff);
			pic->ilbm->ParseInfo.iff = NULL;
		}
		else {
			e = "Unable to AllocIFF";
			hnum = HE_AllocIFF;
		}
	}
	// If we always open ILBM or the above checks out OK then try and open
	if (OpenILBM || ((OpenMode == OPEN_ILBM_ALWAYS) && !e)) {
		if (pic->ilbm->ParseInfo.iff = AllocIFF()) {
			// set up IFF stuff and load image
			pic->ilbm->ParseInfo.propchks = props;
			pic->ilbm->ParseInfo.collectchks = nowt;
			pic->ilbm->ParseInfo.stopchks = stops;
			if (loadbrush(pic->ilbm,filename)) {
				closeifile(&(pic->ilbm->ParseInfo));
				e = "Failure loading Image '%s'";
				e1 = filename;
				hnum = HE_LoadImage;
			}
			else {
				closeifile(&(pic->ilbm->ParseInfo));
				FreeIFF(pic->ilbm->ParseInfo.iff);
				pic->ilbm->ParseInfo.iff = NULL;
				return TRUE;
			}
		}
		else {
			e = "Unable to AllocIFF";
			hnum = HE_AllocIFF;
		}
	}
	else {
		// otherwise try and load using another format
		if (!e) {
			return OpalLoad(pic,filename);
		}
	}
	Error(e,"OK",e1,hnum);
	return FALSE;
}

/* Loads an image (in various formats)
 * pic     : pointer to Picture structure
 * filename: filename to load
 * Returns : TRUE if loaded OK
 */
BOOL OpalLoad(struct Picture *pic,UBYTE *filename) {
	char 					*e		= NULL;	// Error message main text
	char					*e1 	= NULL;	// sub text,
	long 					Err;				// OpalError
	ULONG					hnum;				// Help on error
	struct OpalScreen	*OScrn;			// OpalScreen
	UBYTE					*p[3]= {NULL,NULL,NULL};	// rbg planes
	UBYTE r[256],g[256],b[256];		// rgb colors of screen (8 bit)
	UWORD					i;					// loop counter
	UWORD 				color;			// Colour
	UBYTE *red,*green,*blue;			// rgb pointers
	UWORD					maxcol;			// Number of colors
	UWORD xadd;								// bytes to add to get to next line
	decompress_info_ptr info;			// Load JPEG stuff
	BOOL					ReMap = FALSE;	// Have to remap ourselves
	struct RastPort	Rp;				// Rast port for conversion
	struct DCTVCvtHandle	*handle=NULL;	// DCTV conversion stuff
	UWORD					*DCTVcolors=NULL;	// DCTV palette

	OpenProgressWindow();		// Open the progress window
	if (ProgressWnd) {
  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
	 						 GTTX_Text,(ULONG)"Creating Colormap",
							 TAG_END);
		HandleProgressIDCMP();
	}
	// Store and set up to 256 colours
  	maxcol = min((1 << TSMorphWnd->WScreen->BitMap.Depth),256);
	for (i=0; i < maxcol; ++i) {
		color = GetRGB4(TSMorphWnd->WScreen->ViewPort.ColorMap,i);
		r[i]=((color&0x0f00)>>4)|((color&0x0f00)>>8);
		g[i]=(color&0x00f0)|((color&0x00f0)>>4);
		b[i]=((color&0x000f)<<4)|(color&0x000f);
	}
	// If we are not opening OPAL and the file is IFF
	if ((OpenMode != OPEN_OPAL) &&
		 (FileFormat == FORMAT_IFF)) {
		// try and load IFF
		if (pic->ilbm->ParseInfo.iff = AllocIFF()) {
			pic->ilbm->ParseInfo.propchks = props;
			pic->ilbm->ParseInfo.collectchks = nowt;
			pic->ilbm->ParseInfo.stopchks = stops;
			if (ProgressWnd) {
		  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
	 								 GTTX_Text,(ULONG)"Loading ILBM",
									 TAG_END);
				HandleProgressIDCMP();
			}
			if (loadbrush(pic->ilbm,filename)) {
				closeifile(&(pic->ilbm->ParseInfo));
				e = "Failure loading Image '%s'";
				e1 = filename;
				hnum = HE_LoadImage;
			}
			else {
				closeifile(&(pic->ilbm->ParseInfo));
				if (pic->ilbm->Bmhd.nPlanes == 24) {
					// 24 bit image - free colours
					freecolors(pic->ilbm);
					if (ProgressWnd) {
				  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
	 										 GTTX_Text,(ULONG)"Converting 24 bit to Chunky",
											 TAG_END);
						HandleProgressIDCMP();
					}
					// Allocate Chunky planes
					if ((p[0] = AllocVec(((((pic->ilbm->Bmhd.w+15)>>4)<<4)*pic->ilbm->Bmhd.h),0)) &&
	  			       (p[1] = AllocVec(((((pic->ilbm->Bmhd.w+15)>>4)<<4)*pic->ilbm->Bmhd.h),0)) &&
  		      		 (p[2] = AllocVec(((((pic->ilbm->Bmhd.w+15)>>4)<<4)*pic->ilbm->Bmhd.h),0))) {
  		      		// Convert to chunky RGB
  		      		if (InitArray(pic->ilbm->Bmhd.w) && PlanarToChunky(pic,pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h,p[0],p[1],p[2])) {
  		      			// Bytes to add to get to next row
							xadd = (((pic->ilbm->Bmhd.w+15)>>4)<<4) - pic->ilbm->Bmhd.w;
							red = p[0];
							blue = p[2];
							green = p[1];
							if (ProgressWnd) {
	   		  	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
   	  	   		 	 						 GTTX_Text,(ULONG)"Remapping 24 bit palette",
     		    									 TAG_END);
			     	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
	   		  	    	   					 GTSL_Level,0,
     		   		 							 GTSL_Max,pic->ilbm->Bmhd.h-1,TAG_END);
								HandleProgressIDCMP();
     				    	}
     				    	// Convert to screen palette using 020 if present
							if (((struct ExecBase *)SysBase)->AttnFlags & AFF_68020) {
								RGBToScreen020(red,green,blue,pic->ilbm->Bmhd.h,pic->ilbm->Bmhd.w,maxcol,xadd,r,g,b);
							}
		 					else {
								RGBToScreen000(red,green,blue,pic->ilbm->Bmhd.h,pic->ilbm->Bmhd.w,maxcol,xadd,r,g,b);
							}
							if (ProgressWnd) {
				  			   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
  					 								 GTTX_Text,(ULONG)"Converting 24 bit to Planar",
			  										 TAG_END);
								HandleProgressIDCMP();
							}
							// Convert back to planar
							if (ChunkyToPlanar(pic,pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h,p[0])) {
								// Free everything and return ok
								FreeArray();
								FreeVec(p[0]);
								FreeVec(p[1]);
								FreeVec(p[2]);
								CloseProgressWindow();
								return TRUE;
							}
							// Free everything
							else {
								e = "Unable to allocate memory for bitmap";
								hnum = HE_AllocPlanes;
							}
						}
						else {
							e = "Unable to allocate memory for bitmap";
							hnum = HE_AllocPlanes;
						}
						FreeArray();
					}
					else {
						e = "Unable to allocate memory for bitmap";
						hnum = HE_AllocPlanes;
					}
					if (p[0]) FreeVec(p[0]);
					if (p[1]) FreeVec(p[1]);
					if (p[2]) FreeVec(p[2]);
				}
				else {
					// not a 24 bit image
					// If we have dctv.library then check if a DCTV image
					if (DCTVBase && TestDCTVSignature(pic->ilbm->brbitmap)) {
						if (ProgressWnd) {
					  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
	 											 GTTX_Text,(ULONG)"Converting DCTV to Chunky",
												 TAG_END);
							HandleProgressIDCMP();
						}
						// Allocate and set up DCTV palette
						if (DCTVcolors = AllocVec(2L<<pic->ilbm->Bmhd.nPlanes,NULL)) {
							for (i=0; i < (1L<<pic->ilbm->Bmhd.nPlanes); ++i) {
								DCTVcolors[i] = ((pic->ilbm->RGB[i*4+1] & 0xf0) << 4) |
													 ((pic->ilbm->RGB[i*4+2] & 0xf0)) |
													 ((pic->ilbm->RGB[i*4+3] & 0xf0) >> 4);
							}
							// Allocate RGB chunky planes and DCTV stuff
							if ((p[0] = AllocVec(((((pic->ilbm->Bmhd.w+15)>>4)<<4)*pic->ilbm->Bmhd.h),0)) &&
		  			      	 (p[1] = AllocVec(((((pic->ilbm->Bmhd.w+15)>>4)<<4)*pic->ilbm->Bmhd.h),0)) &&
  			      			 (p[2] = AllocVec(((((pic->ilbm->Bmhd.w+15)>>4)<<4)*pic->ilbm->Bmhd.h),0)) &&
  		      				 (InitArray(pic->ilbm->Bmhd.w)) &&
								 (handle = AllocDCTVCvtTags(pic->ilbm->brbitmap,
													DCTVCVTA_Type, DCTVCVTT_DCTVtoRGB,
													DCTVCVTA_Width, (((pic->ilbm->Bmhd.w+15)>>4)<<4),
													DCTVCVTA_Height, pic->ilbm->Bmhd.h,
													DCTVCVTA_Flags, ((pic->ilbm->camg & LACE)?DCTVCVTF_Lace:0)|
																		DCTVCVTF_CustomRGBBuf,
													DCTVCVTA_ColorTable, DCTVcolors,
													TAG_END))) {
								handle->Red = p[0];
								handle->Green = p[1];
								handle->Blue = p[2];
								if (ProgressWnd) {
						     	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
	   		  	   		   					 GTSL_Level,0,
     		   										 GTSL_Max,pic->ilbm->Bmhd.h-1,TAG_END);
		   		  	   		GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass1],ProgressWnd,NULL,
	   		  	    	   					 GTSL_Level,1,
     		   		 							 GTSL_Max,2,TAG_END);
									HandleProgressIDCMP();
   	  		   			}
   	  		   			// use dctv.library to convert to chunky
								while (handle->DstLineNum < handle->Height) {
									CvtDCTVLine(handle);
									if ((handle->DstLineNum > 0) &&
										 (handle->DstLineNum <= handle->Height)) {
										if (ProgressWnd) {
							    	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
	   		  	    		  					 GTSL_Level,handle->DstLineNum-1,
	   		  	    	  						 TAG_END);
											HandleProgressIDCMP();
										}
										handle->Red += (((pic->ilbm->Bmhd.w+15)>>4)<<4);
										handle->Green += (((pic->ilbm->Bmhd.w+15)>>4)<<4);
										handle->Blue += (((pic->ilbm->Bmhd.w+15)>>4)<<4);
									}
								}
								if (ProgressWnd) {
		   		  	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
  	  		   		 	 						 GTTX_Text,(ULONG)"Remapping DCTV palette",
  		   	 									 TAG_END);
			   	  	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass1],ProgressWnd,NULL,
   		  	   	 	   					 GTSL_Level,2,
  		   		 								 TAG_END);
				      		   GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
	  		  	    	   						 GTSL_Level,0,
  		   		 								 TAG_END);
	  		   		 		}
	  		   		 		// convert to screen palette and then to planar (see above)
								xadd = (((pic->ilbm->Bmhd.w+15)>>4)<<4) - pic->ilbm->Bmhd.w;
								red = p[0];
								blue = p[2];
								green = p[1];
								if (((struct ExecBase *)SysBase)->AttnFlags & AFF_68020) {
									RGBToScreen020(red,green,blue,pic->ilbm->Bmhd.h,pic->ilbm->Bmhd.w,maxcol,xadd,r,g,b);
								}
		 						else {
									RGBToScreen000(red,green,blue,pic->ilbm->Bmhd.h,pic->ilbm->Bmhd.w,maxcol,xadd,r,g,b);
								}
								if (ProgressWnd) {
			  					   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
				 										 GTTX_Text,(ULONG)"Converting to Planar",
		  												 TAG_END);
									HandleProgressIDCMP();
								}
								if (ChunkyToPlanar(pic,pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h,p[0])) {
									FreeVec(DCTVcolors);
									freecolors(pic->ilbm);
									FreeArray();
									FreeVec(p[0]);
									FreeVec(p[1]);
									FreeVec(p[2]);
									CloseProgressWindow();
									FreeDCTVCvt(handle);
									return TRUE;
								}
								else {
									e = "Unable to allocate memory for bitmap";
									hnum = HE_AllocPlanes;
								}
							}
							else {
								e = "Unable to allocate memory for bitmap";
								hnum = HE_AllocPlanes;
							}
							FreeArray();
							if (handle) {
								FreeDCTVCvt(handle);
							}
							if (p[0]) FreeVec(p[0]);
							if (p[1]) FreeVec(p[1]);
							if (p[2]) FreeVec(p[2]);
						}
						else {
							e = "Unable to allocate memory for bitmap";
							hnum = HE_AllocPlanes;
						}
						FreeVec(DCTVcolors);
					}
					else {
						// not 24 bit and not DCTV
						// Convert image planar to screen palette planar (using 020+ if present)
						if (InitArray(pic->ilbm->Bmhd.w)) {
							if (ProgressWnd) {
						      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
					   	  							GTSL_Max,pic->ilbm->Bmhd.h-1,TAG_END);
								HandleProgressIDCMP();
							}
							InitRastPort(&Rp);
							Rp.BitMap = pic->ilbm->brbitmap;
							maxcol = min(maxcol,1<<pic->ilbm->Bmhd.nPlanes);
							if (((struct ExecBase *)SysBase)->AttnFlags & AFF_68020) {
								PaletteToScreen020(&Rp,pic,maxcol,r,g,b);
							}
 							else {
								PaletteToScreen000(&Rp,pic,maxcol,r,g,b);
							}
							// and clean up
							FreeArray();
							freecolors(pic->ilbm);
							CloseProgressWindow();
							return TRUE;
						}
						else {
							e = "Unable to allocate memory for bitmap";
							hnum = HE_AllocPlanes;
						}
					}
				}
			}
		}
		else {
			e = "Unable to AllocIFF";
			hnum = HE_AllocIFF;
		}
	}
	// If we are not opening OPAL and the file is not IFF
   if ((OpenMode != OPEN_OPAL) &&
   	  (FileFormat != FORMAT_IFF)) {
   	// if the screen is < 8 colours or we do not allow palette changes or image is not JPEG then
   	// we will remap later. Otherwise the JPEG code will code will use its own palette
		if ((TSMorphWnd->WScreen->BitMap.Depth < 3) || (FileFormat != FORMAT_JPEG) ||
		    (!PaletteAllowed)) {
			ReMap = TRUE;
		}
		if (ProgressWnd) {
    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
    	 						 GTTX_Text,
    	 						 (FileFormat == FORMAT_JPEG)?(ULONG)"Loading JFIF":
    	 						 (FileFormat == FORMAT_GIF)?(ULONG)"Loading GIF":
    	 						 (FileFormat == FORMAT_PPM)?(ULONG)"Loading PPM":
    	 						 (FileFormat == FORMAT_TARGA)?(ULONG)"Loading Targa?":
    	 						 (ULONG)"Loading ?",
   							 TAG_END);
			HandleProgressIDCMP();
		}
		// try and Load image (JFIF,GIF,PPM,TARGA)
		if ((info = LoadJPEG(filename,ReMap?0:min(1<<TSMorphWnd->WScreen->BitMap.Depth,256),r,g,b,&(p[0]))) &&
   		 ((info->output_file) || (p[0] && p[1] && p[2]))) {
   		if (info->output_file) {
   			p[0] = (UBYTE *)info->output_file;
   			p[1] = p[0] + (((info->image_width+15)>>4)<<4) * info->image_height;
   			p[2] = p[1] + (((info->image_width+15)>>4)<<4) * info->image_height;
   		}
			// Allocate BitMap
			if (ProgressWnd) {
   	 	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
    		 						 GTTX_Text,(ULONG)"Allocating Bitmap",
   								 TAG_END);
				HandleProgressIDCMP();
			}
			pic->ilbm->Bmhd.nPlanes = min(TSMorphWnd->WScreen->BitMap.Depth,8);
			pic->ilbm->Bmhd.w = info->image_width;
			pic->ilbm->Bmhd.h = info->image_height;
			if (InitArray(pic->ilbm->Bmhd.w) && (pic->ilbm->brbitmap = AllocMem(sizeof(struct BitMap),MEMF_CLEAR))) {
				InitBitMap(pic->ilbm->brbitmap,pic->ilbm->Bmhd.nPlanes,info->image_width,info->image_height);
				for (i=0;
					(i < pic->ilbm->Bmhd.nPlanes) && !e;			// Allow up to 8 bitplanes
					++i) {
					if (!(pic->ilbm->brbitmap->Planes[i] = AllocRaster(pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h))) {
						e = "Unable to allocate memory for bitmap";
						hnum = HE_AllocPlanes;
					}
				}
			}
			else {
				e = "Unable to allocate memory for bitmap";
				hnum = HE_AllocPlanes;
			}
			if (!e) {
				if (ProgressWnd) {
		    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
    			 						 GTTX_Text,(ULONG)"Converting to Planar",
   									 TAG_END);
					HandleProgressIDCMP();
 				}
 				// Remap the RGB image to screen palette if required (see above)
 				if (ReMap) {
					xadd = (((info->image_width+15)>>4)<<4) - info->image_width;
					red = p[0];
					blue = p[2];
					green = p[1];
					if (ProgressWnd) {
	     	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
   	  	    	 						 GTTX_Text,(ULONG)"Remapping palette",
     		    							 TAG_END);
	     	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
	     	    	   					 GTSL_Level,0,
     		    							 GTSL_Max,info->image_height-1,TAG_END);
						HandleProgressIDCMP();
     		    	}
					if (((struct ExecBase *)SysBase)->AttnFlags & AFF_68020) {
						RGBToScreen020(red,green,blue,info->image_height,info->image_width,maxcol,xadd,r,g,b);
					}
 					else {
						RGBToScreen000(red,green,blue,info->image_height,info->image_width,maxcol,xadd,r,g,b);
					}
				}
				if (ProgressWnd) {
			  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
  				 						 GTTX_Text,(ULONG)"Converting to Planar",
  										 TAG_END);
					HandleProgressIDCMP();
				}
				// Then convert back to planar
				if (ChunkyToPlanar(pic,info->image_width,info->image_height,p[0])) {
					if (!ReMap) {
						// not remapping so reformat JPEGs palette to our format
						if (ProgressWnd) {
				    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
    					 						 GTTX_Text,(ULONG)"Creating Colormap",
   											 TAG_END);
							HandleProgressIDCMP();
						}
						if (pic->ilbm->colortable = (Color4 *)AllocMem(min(1<<TSMorphWnd->WScreen->BitMap.Depth,256)*sizeof(Color4),NULL)) {
							pic->ilbm->ncolors = min(1<<TSMorphWnd->WScreen->BitMap.Depth,256);
							pic->ilbm->ctabsize = pic->ilbm->ncolors*sizeof(Color4);
							for (i = 0;
							     i < pic->ilbm->ncolors;
							     ++i) {
								pic->ilbm->colortable[i] = ((r[i] & 0xf0) << 4) | (g[i] & 0xf0) | (b[i] >> 4);
							}
						}
					}
					// Free everything and return OK
					FreeArray();
					FreeVec(p[0]);
					CloseProgressWindow();
					return TRUE;
				}
				else {
					e = "Unable to allocate memory for bitmap";
					hnum = HE_AllocPlanes;
				}
				// Free everything
			}
			FreeArray();
			if (pic->ilbm->brbitmap) {
				for (i = 0;
					  (i < pic->ilbm->Bmhd.nPlanes);			// Allow up to 8 bitplanes
					  ++i) {
					if (!(pic->ilbm->brbitmap->Planes[i])) {
						FreeRaster(pic->ilbm->brbitmap->Planes[i],pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h);
						pic->ilbm->brbitmap->Planes[i] = NULL;
					}
				}
				FreeMem(pic->ilbm->brbitmap,sizeof(struct BitMap));
				pic->ilbm->brbitmap = NULL;
			}
			FreeVec(p[0]);
		}
	}
	// If we have not hit a fatal error yet, and opal.library is available then try it
	if (!e && OpalBase) {
		if (ProgressWnd) {
	  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
   	 						 GTTX_Text,(ULONG)"Loading using opal.library",
   							 TAG_END);
			HandleProgressIDCMP();
		}
		Err = LoadImage24(NULL,filename,VIRTUALSCREEN24|FORCE24);
		if (Err < OL_ERR_MAXERR) {
			switch (Err) {
			case OL_ERR_OUTOFMEM:
				e = "Failure - Out of memory - loading '%s'";
				break;
			case OL_ERR_OPENFILE:
				e = "Failure - Opening file - loading '%s'";
				break;
			case OL_ERR_FORMATUNKNOWN:
				e = "Failure - Unknown Format - loading '%s'";
				break;
			case OL_ERR_NOTILBM:
				e = "Failure - Not an ILBM file - loading '%s'";
				break;
			case OL_ERR_FILEREAD:
				e = "Failure - Reading file - loading '%s'";
				break;
			case OL_ERR_BADIFF:
				e = "Failure - Bad IFF Format - loading '%s'";
				break;
			case OL_ERR_CANTCLOSE:
				e = "Failure - Can not Close - loading '%s'";
				break;
			case OL_ERR_BADJPEG:
				e = "Failure - Bad JPEG Format - loading '%s'";
				break;
			case OL_ERR_UNSUPPORTED:
				e = "Failure - Unsupported Format - loading '%s'";
				break;
			case OL_ERR_CTRLC:
			case OL_ERR_NOTHUMBNAIL:
			case OL_ERR_OPENSCREEN:
			case OL_ERR_FILEWRITE:
			default:
				e = "Failure - Unknown problem - loading '%s'";
				break;
			}
			e1 = filename;
			hnum = HE_OpalVision;
		}
		else {
			if (ProgressWnd) {
		  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
   		 						 GTTX_Text,(ULONG)"Converting to RGB",
   								 TAG_END);
				HandleProgressIDCMP();
			}
			OScrn = (struct OpalScreen *)Err;
			// Allocate chunky bit maps
			if ((p[0] = AllocVec(((((OScrn->Width+15)>>4)<<4)*OScrn->Height),0)) &&
	  	       (p[1] = AllocVec(((((OScrn->Width+15)>>4)<<4)*OScrn->Height),0)) &&
  		       (p[2] = AllocVec(((((OScrn->Width+15)>>4)<<4)*OScrn->Height),0))) {
  		      // Convert Opal vision screen to RGB
  		   	OVtoRGB(OScrn,p,0,0,((OScrn->Width+15)>>4)<<4,OScrn->Height);
				if (ProgressWnd) {
			  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
   			 						 GTTX_Text,(ULONG)"Allocating Bitmap",
   									 TAG_END);
					HandleProgressIDCMP();
				}
				pic->ilbm->Bmhd.nPlanes = min(TSMorphWnd->WScreen->BitMap.Depth,8);
				pic->ilbm->Bmhd.w = OScrn->Width;
				pic->ilbm->Bmhd.h = OScrn->Height;
				// Allocate BitMap
				if (InitArray(pic->ilbm->Bmhd.w) && (pic->ilbm->brbitmap = AllocMem(sizeof(struct BitMap),MEMF_CLEAR))) {
					InitBitMap(pic->ilbm->brbitmap,pic->ilbm->Bmhd.nPlanes,OScrn->Width,OScrn->Height);
					for (i=0;
						(i < pic->ilbm->Bmhd.nPlanes) && !e;			// Allow up to 8 bitplanes
						++i) {
						if (!(pic->ilbm->brbitmap->Planes[i] = AllocRaster(pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h))) {
							e = "Unable to allocate memory for bitmap";
							hnum = HE_AllocPlanes;
						}
					}
				}
				else {
					e = "Unable to allocate memory for bitmap";
					hnum = HE_AllocPlanes;
				}
				// remap to screen palette and convert to planar - see above
				if (!e) {
					xadd = (((OScrn->Width+15)>>4)<<4) - OScrn->Width;
					red = p[0];
					blue = p[2];
					green = p[1];
					if (ProgressWnd) {
	     	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
   	  	    	 						 GTTX_Text,(ULONG)"Remapping OPAL palette",
     		    							 TAG_END);
	     	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
	     	    	   					 GTSL_Level,0,
     		    							 GTSL_Max,OScrn->Height-1,TAG_END);
						HandleProgressIDCMP();
     		    	}
					if (((struct ExecBase *)SysBase)->AttnFlags & AFF_68020) {
						RGBToScreen020(red,green,blue,OScrn->Height,OScrn->Width,maxcol,xadd,r,g,b);
					}
 					else {
						RGBToScreen000(red,green,blue,OScrn->Height,OScrn->Width,maxcol,xadd,r,g,b);
					}
					if (ProgressWnd) {
				  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
   				 						 GTTX_Text,(ULONG)"Converting to Planar",
   										 TAG_END);
						HandleProgressIDCMP();
					}
					if (!ChunkyToPlanar(pic,OScrn->Width,OScrn->Height,p[0])) {
						e = "Unable to allocate memory for bitmap";
						hnum = HE_AllocPlanes;
					}
					// Free everything and return
				}
				else {
					if (pic->ilbm->brbitmap) {
						for (i = 0;
							  (i < pic->ilbm->Bmhd.nPlanes);			// Allow up to 8 bitplanes
							  ++i) {
							if (!(pic->ilbm->brbitmap->Planes[i])) {
								FreeRaster(pic->ilbm->brbitmap->Planes[i],pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h);
								pic->ilbm->brbitmap->Planes[i] = NULL;
							}
						}
						FreeMem(pic->ilbm->brbitmap,sizeof(struct BitMap));
						pic->ilbm->brbitmap = NULL;
					}
				}
				FreeArray();
			}
			else {
				e = "Unable to allocate memory for bitmap";
				hnum = HE_AllocPlanes;
			}
			if (ProgressWnd) {
		  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
			 						 GTTX_Text,(ULONG)"Cleaning up",
									 TAG_END);
				HandleProgressIDCMP();
			}
 	   	if (p[0]) FreeVec(p[0]);
	   	if (p[1]) FreeVec(p[1]);
  			if (p[2]) FreeVec(p[2]);
			FreeScreen24(OScrn);
			if (!e) {
				pic->Opal = TRUE;
				CloseProgressWindow();
				return TRUE;
			}
		}
	}
	else {
		if (!e) {
			e = "No opal.library";
			hnum = HE_NoOpal;
		}
	}
	// display error and return
	Error(e,"OK",e1,hnum);
	CloseProgressWindow();
	return FALSE;
}

extern struct RastPort 	RP={0},			// Work Rast Ports
 								TRP={0};
extern struct BitMap TBM={0};				// Temp bitmap
extern UBYTE *plane0=NULL;					// Planes for temporary bit maps
extern UBYTE *plane1=NULL;
extern UBYTE *plane2=NULL;
extern UBYTE *plane3=NULL;
extern UBYTE *plane4=NULL;
extern UBYTE *plane5=NULL;
extern UBYTE *plane6=NULL;
extern UBYTE *plane7=NULL;
extern UBYTE *Array=NULL;

/* Allocate and initialise things for image conversion
 * w : width of image
 */
BOOL
InitArray(UWORD w) {
	if ((plane0 = AllocVec((((w+15)>>4)<<4),MEMF_CHIP)) &&
     	 (plane1 = AllocVec((((w+15)>>4)<<4),MEMF_CHIP)) &&
     	 (plane2 = AllocVec((((w+15)>>4)<<4),MEMF_CHIP)) &&
     	 (plane3 = AllocVec((((w+15)>>4)<<4),MEMF_CHIP)) &&
     	 (plane4 = AllocVec((((w+15)>>4)<<4),MEMF_CHIP)) &&
     	 (plane5 = AllocVec((((w+15)>>4)<<4),MEMF_CHIP)) &&
     	 (plane6 = AllocVec((((w+15)>>4)<<4),MEMF_CHIP)) &&
     	 (plane7 = AllocVec((((w+15)>>4)<<4),MEMF_CHIP)) &&
     	 (Array = AllocVec((((w+15)>>4)<<4),MEMF_CLEAR))) {
  	   InitRastPort(&RP);
      InitRastPort(&TRP);
      InitBitMap(&TBM,8,w,1);
      TRP.BitMap = &TBM;
      TBM.Planes[0]=plane0;
      TBM.Planes[1]=plane1;
  	   TBM.Planes[2]=plane2;
     	TBM.Planes[3]=plane3;
      TBM.Planes[4]=plane4;
      TBM.Planes[5]=plane5;
      TBM.Planes[6]=plane6;
  	   TBM.Planes[7]=plane7;
		return TRUE;
	}
	FreeArray();
	return FALSE;
}

/* Free everything allocated
 * by InitArray()
 */
void
FreeArray(void) {
 	if (plane0) {
 		FreeVec(plane0);
 		plane0 = NULL;
 	}
   if (plane1) {
   	FreeVec(plane1);
   	plane1 = NULL;
   }
   if (plane2) {
   	FreeVec(plane2);
   	plane2 = NULL;
   }
   if (plane3) {
   	FreeVec(plane3);
   	plane3 = NULL;
   }
   if (plane4) {
   	FreeVec(plane4);
   	plane4 = NULL;
   }
   if (plane5) {
   	FreeVec(plane5);
   	plane5 = NULL;
   }
   if (plane6) {
   	FreeVec(plane6);
   	plane6 = NULL;
   }
   if (plane7) {
   	FreeVec(plane7);
   	plane7 = NULL;
   }
   if (Array) {
   	FreeVec(Array);
   	Array = NULL;
   }
}

/* Convert Chunky 8 bit to planar
 * Always return true (historical)
 * pic    - picture pointer
 * w      - width
 * h      - height
 * chunky - chunky plane
 */
BOOL
ChunkyToPlanar(struct Picture *pic,UWORD w,UWORD h,UBYTE *chunky) {
  	RP.BitMap = pic->ilbm->brbitmap;
 	WritePixelArray8(&RP,0,0,w-1,h-1,chunky,&TRP);
 	return TRUE;
}
/* Convert 24 bit chunky to RGB planar
 * Always return true (historical)
 * pic    - picture pointer
 * w      - width
 * h      - height
 * r,g,b  - chunky pointers
 */
BOOL
PlanarToChunky(struct Picture *pic,UWORD w,UWORD h,UBYTE *r,UBYTE *g,UBYTE *b) {
	struct BitMap 		BM;
   InitBitMap(&BM,8,w,h);
  	RP.BitMap = &BM;
   BM.Planes[0] = pic->ilbm->brbitmap->Planes[0];
   BM.Planes[1] = pic->ilbm->brbitmap->Planes[1];
   BM.Planes[2] = pic->ilbm->brbitmap->Planes[2];
   BM.Planes[3] = pic->ilbm->brbitmap->Planes[3];
   BM.Planes[4] = pic->ilbm->brbitmap->Planes[4];
   BM.Planes[5] = pic->ilbm->brbitmap->Planes[5];
   BM.Planes[6] = pic->ilbm->brbitmap->Planes[6];
   BM.Planes[7] = pic->ilbm->brbitmap->Planes[7];
   // Convert red to chunky
   ReadPixelArray8(&RP,0,0,w-1,h-1,r,&TRP);
   WaitBlit();
   BM.Planes[0] = pic->ilbm->brbitmap->Planes[8];
   BM.Planes[1] = pic->ilbm->brbitmap->Planes[9];
   BM.Planes[2] = pic->ilbm->brbitmap->Planes[10];
   BM.Planes[3] = pic->ilbm->brbitmap->Planes[11];
   BM.Planes[4] = pic->ilbm->brbitmap->Planes[12];
   BM.Planes[5] = pic->ilbm->brbitmap->Planes[13];
   BM.Planes[6] = pic->ilbm->brbitmap->Planes[14];
   BM.Planes[7] = pic->ilbm->brbitmap->Planes[15];
   // and green
   ReadPixelArray8(&RP,0,0,w-1,h-1,g,&TRP);
   WaitBlit();
   BM.Planes[0] = pic->ilbm->brbitmap->Planes[16];
   BM.Planes[1] = pic->ilbm->brbitmap->Planes[17];
   BM.Planes[2] = pic->ilbm->brbitmap->Planes[18];
   BM.Planes[3] = pic->ilbm->brbitmap->Planes[19];
   BM.Planes[4] = pic->ilbm->brbitmap->Planes[20];
   BM.Planes[5] = pic->ilbm->brbitmap->Planes[21];
   BM.Planes[6] = pic->ilbm->brbitmap->Planes[22];
   BM.Planes[7] = pic->ilbm->brbitmap->Planes[23];
   // and blue
   ReadPixelArray8(&RP,0,0,w-1,h-1,b,&TRP);
   WaitBlit();
   return TRUE;
}

/* RGB to screen palette
 * 68000/010 version
 * red,green,blue : chunky pointers - result is pallete mapped chunky in red
 * Height,Width   : image size
 * maxcol         : number of colours
 * xadd           : skip at end of line
 * r,g,b          : r,g,b palette
 */
void
RGBToScreen000(UBYTE *red,UBYTE *green,UBYTE *blue,UWORD Height,UWORD Width,
						  UWORD maxcol,UWORD xadd,UBYTE *r,UBYTE *g,UBYTE *b) {
	UWORD i,j,k;
	ULONG maxdiff;
	ULONG diff;
	LONG 	t;
	UWORD index;

	// for each line
	for (j = 0;
		  j < Height;
		  ++j) {
		if (ProgressWnd) {
	      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
   	  							GTSL_Level,(ULONG)j,TAG_END);
			HandleProgressIDCMP();
   	}
   	// for each pixel
		for (i = 0;
			  i < Width;
			  ++i) {
			// Find closest color based on:
			// red_difference*sqrt(3)+green_difference*srqt(6)+blue_difference
			// (some sort of logic in the figures somewhere)
			maxdiff = 0x7FFFFFFF;
			for (k = 0;
				  k < maxcol;
				  ++k) {
				t = *red - r[k];
				diff = t*t*3;
				t = *green - g[k];
				diff += (t*t*6);
				t = *blue - b[k];
				diff += (t*t);
				if (diff < maxdiff) {
					maxdiff = diff;
					index = k;
				}
			}
			// Store index to color
			*red = index;
			++red;
			++green;
			++blue;
		}
		red += xadd;
		green += xadd;
		blue += xadd;
		if (ProgressWnd) {
			HandleProgressIDCMP();
		}
	}
}

/* Palette to screen palette
 * 68000/010 version
 * Rp    : work rast port
 * pic   : picture pointer
 * maxcol: number of colours
 * r,g,b : r,g,b palette
 */
void
PaletteToScreen000(struct RastPort *Rp,struct Picture *pic,UWORD maxcol,
								UBYTE *r,UBYTE *g,UBYTE *b) {
	UWORD	i,j,k;			// loop counters
	LONG	penno;
	UBYTE	rr,gg,bb;
	ULONG maxdiff;
	ULONG diff;
	UWORD index;
	LONG	t;					// temp diff
	UWORD EHB;
	BOOL isHAM6 = FALSE;
	BOOL isHAM8 = FALSE;
	BOOL isEHB = FALSE;
	struct DisplayInfo queryinfo;
	DisplayInfoHandle handle;
	struct BitMap 		BM;
	UBYTE *arrayp;

	// Initialise stuff
   InitBitMap(&BM,pic->ilbm->Bmhd.nPlanes,pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h);
  	RP.BitMap = &BM;
   InitBitMap(&TBM,pic->ilbm->Bmhd.nPlanes,pic->ilbm->Bmhd.w,1);
   TRP.BitMap = &TBM;
   TBM.Planes[0]=plane0;
   TBM.Planes[1]=plane1;
   TBM.Planes[2]=plane2;
  	TBM.Planes[3]=plane3;
   TBM.Planes[4]=plane4;
   TBM.Planes[5]=plane5;
   TBM.Planes[6]=plane6;
   TBM.Planes[7]=plane7;

	// based on CAMG chunk determine special type of image
	if ((handle = FindDisplayInfo(pic->ilbm->camg)) &&
		 (GetDisplayInfoData(handle,(UBYTE *)&queryinfo,sizeof(queryinfo),DTAG_DISP,NULL))) {
		// 6 plane HAM
		if ((pic->ilbm->Bmhd.nPlanes == 6) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
								 	GTTX_Text,(ULONG)"Remapping HAM6 palette",
									TAG_END);
			isHAM6 = TRUE;
		}
		else {
			// 8 plane HAM
			if ((pic->ilbm->Bmhd.nPlanes == 8) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
				isHAM8 = TRUE;
	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
								 	GTTX_Text,(ULONG)"Remapping HAM8 palette",
									TAG_END);
			}
			else {
				// 6 plane EHB
		  		if ((pic->ilbm->Bmhd.nPlanes == 6) && (queryinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE)) {
		  			isEHB = TRUE;
		    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
 	 										 	GTTX_Text,(ULONG)"Remapping EHB palette",
												TAG_END);
		  		}
		  		else {
		  			// standard ILBM
		    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
 										 	GTTX_Text,(ULONG)"Remapping ILBM palette",
											TAG_END);
		  		}
			}
		}
	}
	// for each line
	for (j = 0;
		 j < pic->ilbm->Bmhd.h;
		 ++j) {
		if (ProgressWnd) {
	      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
  							GTSL_Level,(ULONG)j,TAG_END);
			HandleProgressIDCMP();
	  	}
	  	// convert line to chunky
	  	ReadPixelLine8(Rp,0,j,pic->ilbm->Bmhd.w,Array,&TRP);
	  	arrayp = Array;
	  	// for each pixel depending on mode convert line to screen palette (like palette to screen)
		if (isHAM6) {
			// rgb = 0 at start of line
	  		rr = gg = bb = 0;
	   	for (i = 0;
		  		  i < pic->ilbm->Bmhd.w;
	   		  ++i) {
	   		penno = *arrayp;
	   		switch (penno & 0x30) {	// HAM selection
	   		case 0:
		   		rr = pic->ilbm->RGB[penno*4+1];
		   		gg = pic->ilbm->RGB[penno*4+2];
	   			bb = pic->ilbm->RGB[penno*4+3];
	   			break;
	   		case 0x10:
	   			bb = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		case 0x20:
	   			rr = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		case 0x30:
	   			gg = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		}
				// Find closest color
				maxdiff = 0x7FFFFFFF;
				for (k = 0;
					  k < maxcol;
					  ++k) {
					t = rr - r[k];
					diff = t*t*3;
					t = gg - g[k];
					diff += (t*t*6);
					t = bb - b[k];
					diff += (t*t);
					if (diff < maxdiff) {
						maxdiff = diff;
						index = k;
					}
				}
				*arrayp++ = index;
			}
	  	}
	  	else {
	  		if (isHAM8) {
	  			// very similar to HAM6
				rr = gg = bb = 0;
		   	for (i = 0;
			  		  i < pic->ilbm->Bmhd.w;
		   		  ++i) {
		   		penno = *arrayp;
		   		switch (penno & 0xc0) {
		   		case 0:
			   		rr = pic->ilbm->RGB[penno*4+1];
		   			gg = pic->ilbm->RGB[penno*4+2];
	   				bb = pic->ilbm->RGB[penno*4+3];
	   				break;
		   		case 0x40:
		   			bb = (penno&0x3f)<<2;
	   				break;
	   			case 0x80:
	   				rr = (penno&0x3f)<<2;
	   				break;
		   		case 0xc0:
		   			gg = (penno&0x3f)<<2;
	   				break;
	   			}
					// Find closest color
					maxdiff = 0x7FFFFFFF;
					for (k = 0;
						  k < maxcol;
						  ++k) {
						t = rr - r[k];
						diff = t*t*3;
						t = gg - g[k];
						diff += (t*t*6);
						t = bb - b[k];
						diff += (t*t);
						if (diff < maxdiff) {
							maxdiff = diff;
							index = k;
						}
					}
					*arrayp++ = index;
				}
	  		}
	  		else {
	  			if (isEHB) {
	  				// simple - just check highest plane and divide by two if required
			   	for (i = 0;
				  		  i < pic->ilbm->Bmhd.w;
			   		  ++i) {
			   		penno = *arrayp;
			   		EHB = (penno & 0x20)?1:0;
			   		penno &= 0x1f;
			   		rr = pic->ilbm->RGB[penno*4+1]>>EHB;
			   		gg = pic->ilbm->RGB[penno*4+2]>>EHB;
			   		bb = pic->ilbm->RGB[penno*4+3]>>EHB;
						// Find closest color
						maxdiff = 0x7FFFFFFF;
						for (k = 0;
							  k < maxcol;
							  ++k) {
							t = rr - r[k];
							diff = t*t*3;
							t = gg - g[k];
							diff += (t*t*6);
							t = bb - b[k];
							diff += (t*t);
							if (diff < maxdiff) {
								maxdiff = diff;
								index = k;
							}
						}
						*arrayp++ = index;
					}
		  		}
		  		else {
		  			// simple palette remap
			   	for (i = 0;
				  		  i < pic->ilbm->Bmhd.w;
			   		  ++i) {
			   		penno = *arrayp;
			   		rr = pic->ilbm->RGB[penno*4+1];
			   		gg = pic->ilbm->RGB[penno*4+2];
			   		bb = pic->ilbm->RGB[penno*4+3];
						// Find closest color
						maxdiff = 0x7FFFFFFF;
						for (k = 0;
							  k < maxcol;
							  ++k) {
							t = rr - r[k];
							diff = t*t*3;
							t = gg - g[k];
							diff += (t*t*6);
							t = bb - b[k];
							diff += (t*t);
							if (diff < maxdiff) {
								maxdiff = diff;
								index = k;
							}
						}
						*arrayp++ = index;
					}
				}
			}
   	}
   	// Convert line from chunky palette to planar
   	WritePixelLine8(Rp,0,j,pic->ilbm->Bmhd.w,Array,&TRP);
	}
}
