// 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

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

// The two functions in this file are exact clones of those in OpalLoad.c
// but This code is compiled with -m2 -O -mt
// and is only called if at least a 020 is present

void
RGBToScreen020(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 (j = 0;
		  j < Height;
		  ++j) {
		if (ProgressWnd) {
	      GT_SetGadgetAttrs(ProgressGadgets[GDX_Pass2],ProgressWnd,NULL,
   	  							GTSL_Level,(ULONG)j,TAG_END);
			HandleProgressIDCMP();
   	}
		for (i = 0;
			  i < Width;
			  ++i) {
			// Find closest color
			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();
		}
	}
}

void
PaletteToScreen020(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;
	ULONG NewPen[256];

   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;

	if ((handle = FindDisplayInfo(pic->ilbm->camg)) &&
		 (GetDisplayInfoData(handle,(UBYTE *)&queryinfo,sizeof(queryinfo),DTAG_DISP,NULL))) {
		if ((pic->ilbm->Bmhd.nPlanes == 6) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
								 	GTTX_Text,(ULONG)MyGetMsg(MSG_REMAPH6),
									TAG_END);
			isHAM6 = TRUE;
		}
		else {
			if ((pic->ilbm->Bmhd.nPlanes == 8) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
				isHAM8 = TRUE;
	    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
								 	GTTX_Text,(ULONG)MyGetMsg(MSG_REMAPH8),
									TAG_END);
			}
			else {
		  		if ((pic->ilbm->Bmhd.nPlanes == 6) && (queryinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE)) {
		  			isEHB = TRUE;
		    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
 	 										 	GTTX_Text,(ULONG)MyGetMsg(MSG_REMAPEHB),
												TAG_END);
		  		}
		  		else {
		    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
 										 	GTTX_Text,(ULONG)MyGetMsg(MSG_REMAPIL),
											TAG_END);
					for (i = 0;
						(i < pic->ilbm->ncolors);
						i++) {
						maxdiff = 0x7FFFFFFF;
						for (k = 0;
							  k < maxcol;
							  ++k) {
							t = pic->ilbm->RGB[i*4+1] - r[k];
							diff = t*t*3;
							t = pic->ilbm->RGB[i*4+2] - g[k];
							diff += (t*t*6);
							t = pic->ilbm->RGB[i*4+3] - b[k];
							diff += (t*t);
							if (diff < maxdiff) {
								maxdiff = diff;
								NewPen[i] = k;
							}
						}
					}
		  		}
			}
		}
	}
	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();
	  	}
	  	ReadPixelLine8(Rp,0,j,pic->ilbm->Bmhd.w,Array,&TRP);
	  	arrayp = Array;
		if (isHAM6) {
	  		rr = gg = bb = 0;
	   	for (i = 0;
		  		  i < pic->ilbm->Bmhd.w;
	   		  ++i) {
	   		penno = *arrayp;
	   		switch (penno & 0x30) {
	   		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) {
				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) {
			   	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 {
			   	for (i = 0;
				  		  i < pic->ilbm->Bmhd.w;
			   		  ++i) {
			   		penno = *arrayp;
						*arrayp++ = NewPen[penno];
					}
				}
			}
   	}
   	WritePixelLine8(Rp,0,j,pic->ilbm->Bmhd.w,Array,&TRP);
	}
}

void
PaletteToEGS020(struct RastPort *Rp,struct Picture *pic,UBYTE *plane,UBYTE *r,UBYTE *g,UBYTE *b) {
	UWORD	i,j;			// loop counters
	LONG	penno;
	UBYTE	rr,gg,bb;
	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)"Converting HAM6 to EGS",
									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)"Converting HAM8 to EGS",
									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)"Converting EHB to EGS",
												TAG_END);
		  		}
		  		else {
		  			// standard ILBM
		    	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Mess],ProgressWnd,NULL,
 										 	GTTX_Text,(ULONG)"Converting ILBM to EGS",
											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 to EGS
		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;
	   		}
	   		*plane++ = rr;
	   		*plane++ = gg;
	   		*plane++ = bb;
	   		plane++;
	   		arrayp++;
			}
	  	}
	  	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;
	   			}
		   		*plane++ = rr;
		   		*plane++ = gg;
	   			*plane++ = bb;
	   			plane++;
		   		arrayp++;
				}
	  		}
	  		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;
			   		*plane++ = rr;
			   		*plane++ = gg;
	   				*plane++ = bb;
	   				plane++;
			   		arrayp++;
					}
		  		}
		  		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];
			   		*plane++ = rr;
			   		*plane++ = gg;
	   				*plane++ = bb;
	   				plane++;
			   		arrayp++;
					}
				}
			}
   	}
		plane += (pic->EGS_BitMap->BytesPerRow - (4*pic->ilbm->Bmhd.w));
	}
}
