/*
** NewGads - makes the system gadgets look a little better
**
** Version 1.0
**
** Author: Edward Hutchins
**
** Based on the other program, 3dlook, which does the same thing
** This program will probably die a horrible death under 1.4!
*/

#define INTUITIONPRIVATE

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <proto/all.h>

/*
** defines
*/

#define DRAGPATTERN GADGETCOUNT
#define DOTPATTERN GADGETCOUNT+1

#define MAX_DATA 2048

#define ADDRSYSGAD(r,i) (IntuitionBase->SysGadgets[r][i])

#define DePrint(x)

/*
** Global variables
*/

struct IntuitionBase			*IntuitionBase;
 
typedef struct
{
	WORD		Res;
	WORD		Index;
	int			Num;
	USHORT		Offset1;
	SHORT		Depth1;
	USHORT		ImgOffset;
	USHORT		Offset2;
	SHORT		Depth2;
} GadList;

GadList			NewGads[20] =
{
	{ HIRESGADGET, UPFRONTGADGET, },
	{ HIRESGADGET, DOWNBACKGADGET, },
	{ HIRESGADGET, SIZEGADGET, },
	{ HIRESGADGET, CLOSEGADGET, },
	{ HIRESGADGET, SUPFRONTGADGET, },
	{ HIRESGADGET, SDOWNBACKGADGET, },
	{ LOWRESGADGET, UPFRONTGADGET, },
	{ LOWRESGADGET, DOWNBACKGADGET, },
	{ LOWRESGADGET, SIZEGADGET, },
	{ LOWRESGADGET, CLOSEGADGET, },
	{ LOWRESGADGET, SUPFRONTGADGET, },
	{ LOWRESGADGET, SDOWNBACKGADGET, },
	{ RESCOUNT, 0, },
};

char			*GadNames[] =
{
"UPFRONTGADGET",
"DOWNBACKGADGET",
"SIZEGADGET",
"CLOSEGADGET",
"DRAGGADGET",
"SUPFRONTGADGET",
"SDOWNBACKGADGET",
"SDRAGGADGET",
"DRAGPATTERN",
"DOTPATTERN",
NULL
};

USHORT			ImgData[MAX_DATA];
USHORT			Offset;

/*
** getstr - get a string of input
*/

void getstr( FILE *fp, char *buf )
{
	char			*p;

	fgets( buf, 80, fp );
	p = buf + strlen( buf );
	while (p > buf && *p < ' ') *p-- = '\0';
DePrint(("Got string %s\n", buf));
}

/*
** getnum - get a number
*/

SHORT getnum( FILE *fp )
{
	char			buf[80];

	fgets( buf, 80, fp );
DePrint(("Got num string %s\n", buf));
	return( (SHORT)atoi( buf ) );
}

/*
** gethex - get a hex number
*/

USHORT gethex( FILE *fp )
{
	char			buf[80];
	char			*p;
	USHORT			num;

	fgets( buf, 80, fp );
DePrint(("Got hex string %s ", buf));
	num = 0;
	p = buf;
	while (isxdigit(*p))
	{
		num = (num << 4) + (isdigit(*p) ? (*p - '0') : (toupper(*p) - ('A' - 10)));
		++p;
	}
DePrint(("Converted: %x\n", num));
	return( num );
}

/*
** printimage - print the contents of an image structure
*/

void printimage( struct Image *img )
{
	int			x, y, w, wu, h, d, bit;
	USHORT		*Bitplanes, *bitplane;
	char		Bits[6*16+1];
	char		*p;

	if (img == NULL) return;
	
	printf( "%d\n%d\n%d\n", img->Width, img->Height, img->Depth );

	w = ((img->Width + 15) & ~15);
	wu = w / 16;
	h = wu * img->Height;
	Bitplanes = img->ImageData;

	for (y = 0; y < img->Height; ++y)
	{
		p = Bits;
		for (x = 0; x < w; ++x)
		{
			*p = '\0';
			bit = 1 << (15-(x & 15));
			bitplane = Bitplanes + (x / 16);
			for (d = 0; d < img->Depth; ++d)
			{
				*p |= (*bitplane & bit) ? (1 << d) : 0;
				bitplane += h;
			}
			*p += '0';
			++p;
		}
		*p = '\0';
		printf( "%s\n", Bits );
		Bitplanes += wu;
	}
}

/*
** printgad - print the specs on a gadget
*/

void printgad( struct Gadget *gad )
{
	int				num;

	num = (gad->SelectRender == NULL) ? 1 : 2;
	printf( "%d\n", num );
	printimage( (struct Image *)gad->GadgetRender );
	if (num == 2) printimage( (struct Image *)gad->SelectRender );
}

/*
** PrintSysGads - print the standard gadgets
*/

void PrintSysGads( void )
{
	GadList			*glist = NewGads;
	struct Gadget			*gad;
	int				t;

	while (glist->Res != RESCOUNT)
	{
		gad = ADDRSYSGAD( glist->Res, glist->Index );
		printf( "%s\n%d\n", GadNames[glist->Index], glist->Res );
		printgad( gad );
		++glist;
	}

	printf( "%s\n", GadNames[DRAGPATTERN] );

	for (t = 0; t < 8; ++t)
		printf( "%4x\n", IntuitionBase->apattern[t] );

	printf( "%s\n", GadNames[DOTPATTERN] );

	for (t = 0; t < 4; ++t)
		printf( "%4x\n", IntuitionBase->bpattern[t] );
}

/*
** GetGadIndex - convert an ASCII name into an index
*/

WORD GetGadIndex( FILE *hFile )
{
	char			Name[80];
	WORD			t = 0;

	getstr( hFile, Name );

	while (GadNames[t] != NULL)
	{
		if (strcmp( Name, GadNames[t] ) == 0)
		{
DePrint(("Got %s as %d\n", Name, t));
			return( t );
		}
		++t;
	}
	return( -1 );
}

/*
** GetImage - get an image definition
*/

void GetImage( FILE *hFile, SHORT *dpth, struct Image *img )
{
	WORD			x, y, w, wu, h, d, depth, bit, planesize;
	USHORT			*Bitplanes, *bitplane;
	char			Bits[80];
	char			*p;

	w = getnum( hFile );
	h = getnum( hFile );
	depth = getnum( hFile );
DePrint(("Image is (%d,%d)×%d\n", w, h, depth));
	*dpth = depth;

	if ((img != NULL) && (w != img->Width || h != img->Height))
		printf( "NewGads warning: nonstandard gadget size!\n" );

	Bitplanes = &(ImgData[Offset]);
	w = (w + 15) & ~15;
	wu = w / 16;
	planesize = h * wu;
	Offset += planesize * depth;

	for (y = 0; y < h; ++y)
	{
		getstr( hFile, Bits );
DePrint(("Read %s\n", Bits));
		for (p = Bits; *p; ++p) *p -= '0';
		p = Bits;

		for (x = 0; x < w; ++x)
		{
			bit = 1 << (15-(x & 15));
			bitplane = Bitplanes + (x / 16);
			for (d = 0; d < depth; ++d)
			{
				*bitplane |= (*p & (1 << d)) ? bit : 0;
				bitplane += planesize;
			}
			++p;
		}
		Bitplanes += wu;
	}
DePrint(("Done with bitmap!\n"));
}

/*
** GetGadget - get a gadget definition
*/

void GetGadget( FILE *hFile, GadList *gl, WORD Index )
{
	struct Gadget			*gad;

	gl->Index = Index;
	gl->Res = getnum( hFile );
	gl->Num = getnum( hFile );

DePrint(("Working on res %d, num %d\n", gl->Res, gl->Num));
 	gad = ADDRSYSGAD( gl->Res, gl->Index );

	gl->Offset1 = Offset;
	GetImage( hFile, &(gl->Depth1), (struct Image *)gad->GadgetRender );
	if (gl->Num == 2)
	{
		gl->ImgOffset = Offset;
		*((struct Image *)&(ImgData[Offset])) = *((struct Image *)gad->GadgetRender);
		Offset += (1 + sizeof(struct Image)) >> 1;
		gl->Offset2 = Offset;
		GetImage( hFile, &(gl->Depth2), NULL );
	}
}

/*
** SetImage - set the image structure
*/

void SetImage( struct Image *img, USHORT offset, SHORT depth, USHORT *ChipMem )
{
	img->ImageData = ChipMem + offset;
	img->Depth = depth;
	img->PlanePick = (1 << depth) - 1;
	img->PlaneOnOff = 0;
}

/*
** SetGadget - set a gadget structure
*/

void SetGadget( GadList *gl, USHORT *ChipMem )
{
	struct Gadget			*gad;

	gad = ADDRSYSGAD( gl->Res, gl->Index );
	SetImage( (struct Image *)gad->GadgetRender, gl->Offset1, gl->Depth1, ChipMem );
	if (gl->Num == 2)
	{
		gad->Flags = (gad->Flags & ~GADGHIGHBITS) | GADGHIMAGE;
		gad->SelectRender = (APTR)(ChipMem + gl->ImgOffset);
		SetImage( (struct Image *)gad->SelectRender, gl->Offset2, gl->Depth2, ChipMem );
	}
}

/*
** SetPattern - set a pattern
*/

void SetPattern( FILE *hFile, USHORT *pat, int Max )
{
	int				t;

	for (t = 0; t < Max; ++t) pat[t] = gethex( hFile );
}

/*
** SetSysGads - set the system gadgets from a definition file
*/

void SetSysGads( char *DefFile )
{
	FILE			*hFile;
	WORD			Index;
	GadList			*glist = NewGads;
	GadList			*gl = NewGads;
	char			*ChipMem;
	ULONG			ChipMemSize;

	hFile = fopen( DefFile, "r" );
	if (hFile == 0) return;

	Offset = 0;

	while ((Index = GetGadIndex( hFile )) != -1)
	{
		switch (Index)
		{
		case DRAGPATTERN:
			SetPattern( hFile, IntuitionBase->apattern, 8 );
			break;
		case DOTPATTERN:
			SetPattern( hFile, IntuitionBase->bpattern, 4 );
			break;
		default:
			GetGadget( hFile, glist++, Index );
			break;
		}
	}

	fclose( hFile );

	/* no gadget images */
	if (Offset == 0) return;

	/* allocate the chip memory for the images */
	ChipMemSize = Offset * sizeof( USHORT );
	ChipMem = AllocMem( ChipMemSize, MEMF_CHIP );
	if (ChipMem == NULL)
	{
		printf( "Allocation failed!\n" );
		return;
	}

	memcpy( ChipMem, (char *)ImgData, ChipMemSize );

	Forbid();
	Disable();

	while (gl != glist) SetGadget( gl++, (USHORT *)ChipMem );

	Permit();
	Enable();
}

/*
** main - do it!
*/

void main( int argc, char *argv[] )
{
	IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 33 );
	if (IntuitionBase == NULL) exit( 0 );

	if (argc != 2) PrintSysGads();
	else SetSysGads( argv[1] );
}
