/*******************    PCHG STUFF   **********************************
 *
 * Various bits of code for the handling of multi-palette chunks.
 * Based upon the code in 'PCHGLib12.lha' by Sebastiano Vigna.
 * 'PCHGLib12.lha' can be found on aminet in the drawer gfx/misc.
 * See also 'PCHG_FastDecomp()' in the file 'miscasm.a'.
 */

#include <exec/exec.h>

#include <proto/exec.h>
#include <pchg.h>

extern void 										*PCHGDecomp;
extern struct PCHGHeader				*PCHGData;
extern void 										*PCHGLineData;

static void *PCHG_InitCMAP(struct PCHGHeader *PCHG, APTR LineMask, APTR LineData, UBYTE *cmap);
void *PCHG_SetCMAP(struct PCHGHeader *PCHG, APTR LineMask, APTR LineData, UBYTE *cmap, WORD line);
void __asm PCHG_FastDecomp(	register __a0 void *Source,
				register __a1 void *Dest,
				register __a2 WORD *TreeCode,
				register __d0 ULONG OriginalSize);

BOOL PCHG_ParsePCHG(struct PCHGHeader *PCHG, UBYTE *cmap)
{
	struct PCHGCompHeader *pch;
	BOOL ret = FALSE;

	if (PCHG->Compression == PCHG_COMP_HUFFMANN)
	{
		pch = (void *)&PCHG[1];
		if( PCHGDecomp = AllocVec(pch->OriginalDataSize, MEMF_PUBLIC|MEMF_CLEAR))
		{
			PCHG_FastDecomp((char *)&pch[1]+pch->CompInfoSize, PCHGDecomp, (WORD *)((char *)&pch[1]+pch->CompInfoSize-2), pch->OriginalDataSize);
			PCHGData = PCHGDecomp;
			ret = TRUE;
		}
	}
	else
	{
		if (PCHG->Compression == PCHG_COMP_NONE)
		{
			PCHGData = PCHG;
			ret = TRUE;
		}
	}
	PCHGLineData = (ULONG *)&PCHG[1]+(PCHG->LineCount+31)/32;
	PCHGLineData = PCHG_InitCMAP(PCHG, (void *)&PCHG[1], PCHGLineData, cmap);
	return(ret);
}

static void *PCHG_InitCMAP(struct PCHGHeader *PCHG, APTR LineMask, APTR LineData, UBYTE *cmap)
{
	WORD line;

	for(line = PCHG->StartLine; line < 0; line++)
	{
		LineData = PCHG_SetCMAP(PCHG, LineMask, LineData, cmap, line);
	}
	return(LineData);
}

void *PCHG_SetCMAP(struct PCHGHeader *PCHG, APTR LineMask, APTR LineData, UBYTE *cmap, WORD line)
{
	LONG j;
	struct SmallLineChanges *slc;
	UWORD *RGB;
	struct BigLineChanges *blc;
	struct BigPaletteChange *bpl;
	ULONG *Mask;
	UBYTE *colptr;
	UWORD colrgb,reg;
	void	*ret;

	Mask = LineMask;
	blc = (void *)(slc = LineData);
	ret = LineData;

	if(line>=PCHG->StartLine)
	{
		line -= PCHG->StartLine;
		if(Mask[line/32] & 1UL<<(31-(line%32)))
		{
			if (PCHG->Flags & PCHGF_12BIT)
			{
				RGB = (UWORD *)&slc[1];
				for(j=0; j<slc->ChangeCount16; j++)
				{
					colptr = cmap+((*RGB>>12)*3);
					colrgb = *RGB & 0x0FFF;
					reg = colrgb &0x0F00;
					colptr[0] = reg>>4|reg>>8;
					reg = colrgb &0x00F0;
					colptr[1] = reg|reg>>4;
					reg = colrgb &0x000F;
					colptr[2] = reg|reg<<4;
					RGB++;
				}
				for(j=0; j<slc->ChangeCount32; j++)
				{
					colptr = cmap+(((*RGB>>12)+16)*3);
					colrgb = *RGB & 0x0FFF;
					reg = colrgb &0x0F00;
					colptr[0] = reg>>4|reg>>8;
					reg = colrgb &0x00F0;
					colptr[1] = reg|reg>>4;
					reg = colrgb &0x000F;
					colptr[2] = reg|reg<<4;
					RGB++;
				}
				ret = (void *)RGB;
			}
			else
			{
				if(PCHG->Flags & PCHGF_32BIT)
				{
					bpl = (void *)&blc[1];
					for(j=0; j<blc->ChangeCount; j++)
					{
						colptr = cmap+(bpl->Register*3);
						colptr[0] = bpl->Red;
						colptr[1] = bpl->Green;
						colptr[2] = bpl->Blue;
						bpl++;
					}
				}
				ret = (void *)bpl;
			}
		}
	}
	return(ret);
}
