/*
	show.c

	Take a file of grey scales and display them with dithering.
	The first line has the resolution dimensions.
						mcr
*/

#include <graphics/gfxbase.h>
#include <graphics/display.h>
#include <intuition/intuition.h>
#include <stdio.h>

struct	GfxBase		*GfxBase;	/* Export the library pointers */
struct	IntuitionBase	*IntuitionBase;
struct	RastPort	*rp;		/* Graphics structures           */
struct	ViewPort	*vp;
struct	Window		*w;		/* Intuition structures        */ 
struct	Screen		*screen;

struct	NewScreen	ns = {
	0, 0,				/* start position                */
	640, 400, 4,			/* width, height, depth          */
	15, 0,				/* detail pen, block pen         */
	HIRES|INTERLACE,		/* Hires ViewMode                */
	CUSTOMSCREEN,			/* screen type                   */
	NULL,				/* font to use                   */
	" Tracer Output ",		/* default title for screen      */
	NULL				/* pointer to additional gadgets */
};

struct NewWindow nw = {
	0, 11,				/* start position                */
	640, 386,			/* width, height                 */
	15, 0,				/* detail pen, block pen         */
	NULL,				/* IDCMP flags                   */
	BORDERLESS,			/* window flags                  */
	NULL,				/* pointer to first user gadget  */
	NULL,				/* pointer to user checkmark     */
	NULL,				/* window title                  */
	NULL,				/* pointer to screen (set below) */
	NULL,				/* pointer to superbitmap        */
	0, 0, 640, 386,			/* ignored since not sizeable    */
	CUSTOMSCREEN			/* type of screen desired        */
};

FILE	*in;
int	do_dither=0;

main(argc, argv)
int	argc;
char	**argv;
{
	char	wait[10];

	if(argv[1][0] == '-') {
		switch (argv[1][1]) {
		case	'd'	:
				do_dither = 1;
				break;

		default		:
				printf("option not recognized\n");
		}

		argv++;
	}

	if( !(in=fopen(argv[1], "r")) ) {
		printf("no input file\n");
		exit(-1);
	}
	if ( !(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library") ) ) {
		cleanup();
		exit(103);
	}

	if ( !( IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library") )
	 ) {
		cleanup();
		exit(103);
	}
	if ( !( screen = (struct Screen *)
		OpenScreen(&ns) )
	) { 
		cleanup();
		exit(103);
	}

	nw.Screen = screen;                /* Open window in our new screen */
	if ( !( w = (struct Window *)
		OpenWindow(&nw) )
	) {
		cleanup();
		exit(103);
	}

	vp = &screen->ViewPort;             /* Set colors in screen's VP    */
	rp = w->RPort;                      /* Render into the window's RP  */

	/* Set the color registers ( cut down on ugly greens )	*/
	SetRGB4(vp, 00, 00, 00, 00);
	SetRGB4(vp, 01, 01, 00, 01);    
	SetRGB4(vp, 02, 02, 01, 02);   
	SetRGB4(vp, 03, 03, 02, 03);
	SetRGB4(vp, 04, 04, 03, 04);
	SetRGB4(vp, 05, 05, 04, 05);
	SetRGB4(vp, 06, 06, 05, 06);
	SetRGB4(vp, 07, 07, 06, 07);
	SetRGB4(vp, 08, 08, 07, 08);
	SetRGB4(vp, 09, 09, 08, 09);
	SetRGB4(vp, 10, 10, 09, 10);
	SetRGB4(vp, 11, 11, 10, 11);
	SetRGB4(vp, 12, 12, 11, 12);
	SetRGB4(vp, 13, 13, 12, 13);
	SetRGB4(vp, 14, 14, 13, 14);
	SetRGB4(vp, 15, 15, 14, 15);

	show(in);
	
	gets(wait);

	cleanup();
}

cleanup()
{
	fclose(in);

	if (w)
		CloseWindow(w);

	if (screen)
		CloseScreen(screen);

	if (IntuitionBase)
		CloseLibrary(IntuitionBase);

	if (GfxBase)
		CloseLibrary(GfxBase);
}

show(in)
FILE	*in;
{
	int	x, y, ox, oy;

	fscanf(in, "%d %d\n", &ox, &oy);

	/* waste 8 bits */
	y = getc(in);

	if (do_dither) {
		for(y=0; y<oy; y++)
			for(x=0; x<ox; x++) {
				SetAPen(rp, dither(x, y, getc(in)) );

				if ( (x<640) && (y<400) )
					WritePixel(rp, x/*+100*/, y/*+30*/);
			}
	} else
		for(y=0; y<oy; y++)
			for(x=0; x<ox; x++) {
				SetAPen(rp, (getc(in) >> 4) );

				if ( (x<640) && (y<400) )
					WritePixel(rp, x/*+100*/, y/*+30*/);
			}
}


/* 8 x 8 dithering matrix */
static	int	matrix[8][8] = {
	{   0, 128,  32, 160,   8, 136,  40, 168 },
	{ 192,  64, 224,  96, 200,  72, 232, 104 },
	{  48, 176,  16, 144,  56, 184,  24, 152 },
	{ 240, 112, 208,  80, 248, 120, 216,  88 },
	{  12, 140,  44, 174,   4, 132,  36, 164 },
	{ 204,  76, 236, 108, 196,  68, 228, 100 },
	{  60, 188,  28, 156,  52, 180,  20, 148 },
	{ 252, 124, 210,  92, 244, 116, 212,  84 }
};

/*
	dithering by area access to matrix by using
	the MOD function on the x and y coordinates
*/
dither(x, y, level) /* dithering function */
register	int	x, y, level;
{
	register	int	base, dith;

	base = level >> 4;
	if (base == 0x0F)
		return(base);

	dith = (level & 0x0F) << 4;

	/*
	 * skew every second line over by half a grid to get a brick-layer's
	 * pattern, rather than a straight grid.  The human eye is too good
	 * at seeing straight lines when the points in the grid line up.
	 */
	x += (y & 8) >> 1;

	if ( dith > matrix [x%8] [y%8] )
		return(base+1);

	return(base);
}
