/* Screen Demo Program	 :ts=8 */

/* compile lc -L -iVINCLUDE: -iINCLATTICE: scdemo */

/*
Copyright (c) 1989 Commodore-Amiga, Inc.

Executables based on this information may be used in software
for Commodore Amiga computers. All other rights reserved.
This information is provided "as is"; no warranties are made.
All use is at your own risk, and no liability or responsibility
is assumed.
*/

#include <exec/types.h>
#include <exec/lists.h>
#include <exec/memory.h>

#include <graphics/displayinfo.h>

#include <utility/tagitem.h>
#include <intuition/intuition.h>

/* prototypes */
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/exec_protos.h>

#include <stdio.h>

struct  Library  *IntuitionBase;
struct  Library  *GfxBase;

struct List	ScreenList;		/* keep track of open screens	*/

struct ScreenNode	{
    struct MinNode	Sn_Node;
    struct Screen 	*sn_Screen;
};

struct Screen *addScreen();
void cleanup();
void freeScreens();
void drawRulers();

char	kbuff[257];

void showHelp(void)
{
    printf("commands:\n");
    printf("f - free screens        q - quit\n");
    printf("l - lo-res              L - lo-res interlace\n");
    printf("h - hi-res              H - hi-res interlace\n");
    printf("p - productivity        P - productivity interlace\n");
    printf("s - superhires          S - superhires interlace\n");
    printf("o - std overcan hires   O - video overscan hires\n");
    printf("a - A2024 10 Hz         A - A2024 15 Hz\n");
    printf("w - wide (scrolling) hi res\n");
    printf("z - VGA lores (70ns pixels)\n");
    printf("$ - hex display mode specifier\n");
}


void main(void)
{
    printf("SCDemo: accompanies V1.4 Beta 1.\n");

    NewList( &ScreenList );

    if (!(IntuitionBase = OpenLibrary("intuition.library", 36L)))
    { cleanup("no V36 intuition library\n"); }

    if (!(GfxBase = OpenLibrary("graphics.library", 36L)))
    { cleanup("no V36 graphics library\n"); }

    FOREVER
    {
	printf("screen command (? for list): ");
	if (!gets(kbuff)) cleanup("eof.\n");

	switch ( *kbuff )
	{
	case 'o':
	    addScreen( 0xf00, 0x555,
	    	SA_DisplayID,	HIRES_KEY,
		SA_Overscan,	OSCAN_STANDARD,
		SA_Title,	" Hires Standard Overscan ",
		TAG_END );
	    break;

	case 'O':
	    addScreen( 0xf00, 0x555,
	    	SA_DisplayID,	HIRES_KEY,
		SA_Overscan,	OSCAN_VIDEO,
		SA_Title,	" Hires Video Overscan ",
		TAG_END );
	    break;

	case 'a':
	    addScreen( 0xfff, 0x000,
	    	SA_DisplayID,	A2024TENHERTZ_KEY,
		SA_Title,	" A2024, 10 Hz ",
		TAG_END );
	    break;

	case 'A':
	    addScreen( 0x000, 0xfff,
	    	SA_DisplayID,	A2024FIFTEENHERTZ_KEY,
		SA_Title,	" A2024, 15 Hz ",
		TAG_END );
	    break;

	case 's':
	    addScreen( 0x005, 0xff0,
	    	SA_DisplayID,	SUPER_KEY,
		SA_Title,	" Super-Hires, Non-interlaced ",
		TAG_END );
	    break;

	case 'S':
	    addScreen( 0x005, 0xff0,
	    	SA_DisplayID,	SUPERLACE_KEY,
		SA_Title,	" Super-Hires, Interlaced ",
		TAG_END );
	    break;

	case 'p':
	    addScreen( 0xfff, 0x000,
	    	SA_DisplayID,	VGAPRODUCT_KEY,
		SA_Title,	" Productivity Mode ",
		TAG_END );
	    break;

	case 'P':	/* productivity, lace	*/
	    addScreen( 0x005, 0xf00,
	    	SA_DisplayID,	VGAPRODUCTLACE_KEY,
		SA_Title,	" Productivity, Interlaced ",
		TAG_END );
	    break;

	case 'z':
	    addScreen( 0xfff, 0x000,
	    	SA_DisplayID,	VGALORES_KEY,
		SA_Title,	" 70ns pixels, Doublescan ",
		TAG_END );
	    break;

	case 'h':
	    addScreen( 0x0f0, 0x555,
	    	SA_DisplayID,	HIRES_KEY,
		SA_Title,	" HiRes Text Overscan ",
		TAG_END );
	    break;

	case 'H':
	    addScreen( 0xf00, 0x555,
	    	SA_DisplayID,	HIRESLACE_KEY,
		SA_Title,	" HiRes Interlaced ",
		TAG_END );
	    break;

	case 'L':
	    addScreen( 0x0ff, 0x555,
	    	SA_DisplayID,	LORESLACE_KEY,
		SA_Title,	" LoRes Lace Screen ",
		TAG_END );
	    break;

	case 'l':
	    addScreen( 0x00f, 0x555,
	    	SA_DisplayID,	LORES_KEY,
		SA_Title,	" LoRes Screen ",
		TAG_END );
	    break;

 	case 'w':
	    addScreen( 0xf0f, 0x555,
	    	SA_DisplayID,	HIRES_KEY,
		SA_Title,	" Wide Scrolling HiRes Screen ",
		/* specify a DisplayClip region to scroll around
		 * in.  This is a reasonable region to use.
		 */
		SA_Overscan,	OSCAN_TEXT,
		SA_Width,	1100,
		SA_AutoScroll,	TRUE,	/* not working in beta 1? */
		TAG_END );
	    break;

	case 'f':
	    freeScreens();
	    break;

	case '?':
	    showHelp();
	    break;

	case 'q':
	case 'Q':
	    cleanup("bye.\n");
	    break;
	case '$':
	    {
	    	long	scanmode;
		int	scancount;

		/* skip '$' and get long hex value */
		scancount = sscanf( kbuff + 1, "%lx", &scanmode );
		if ( scancount == 1 )
		{
		    sprintf( kbuff,"Direct Mode Specification: %lx",scanmode);
		    addScreen( 0x0ff, 0x555,
		    	SA_DisplayID,	scanmode,
			TAG_END );
		    break;
		}
		else
		{
		    printf("couldn't parse: type '$ <hex num>'\n");
		}
	    }
	    break;
	default:
	    printf("don't know (%lx)\n", *kbuff, *kbuff);
	}
    }
}

void cleanup(char	*str)
{
    if (str) printf(str);

    freeScreens();

    if (IntuitionBase) CloseLibrary(IntuitionBase);
    if (GfxBase) CloseLibrary(GfxBase);

    exit (0);
    return;
}

/* free all screens	*/
void freeScreens(void)
{
    struct ScreenNode *sn;

    while (sn = (struct ScreenNode *) RemHead( &ScreenList ))
    {
	CloseWindow( sn->sn_Screen->FirstWindow );
	printf("freeing screen at %lx.\n", sn->sn_Screen );
	CloseScreen( sn->sn_Screen );
	FreeMem( sn, (long) sizeof *sn );
    }
    return;
}

char	*string = "Test String A B b CdEf m M n N o d D";

struct ColorSpec colorspec[] = {
    { 0 },
    { 1 },
    {-1 }
};

#define REDPART( color )	(( (color) >> 8 ) & 0xf )
#define GREENPART( color )	(( (color) >> 4 ) & 0xf )
#define BLUEPART( color )	(  (color) & 0xf )

struct Screen *addScreen(int	color0, int color1,ULONG	tags)
{
    struct ScreenNode *sn;
    struct Screen	*OpenScreenTags();
    struct Window	*OpenWindowTags();
    struct Window	*window;
    ULONG	errorcode;	/* for OpenScreen() errors	*/

    if (!(sn = (struct ScreenNode *)
    	  AllocMem((LONG)sizeof (struct ScreenNode), 0L )) )
    	return (NULL);

    colorspec[0].Red = REDPART( color0 );
    colorspec[0].Green = GREENPART( color0 );
    colorspec[0].Blue = BLUEPART( color0 );

    colorspec[1].Red = REDPART( color1 );
    colorspec[1].Green = GREENPART( color1 );
    colorspec[1].Blue = BLUEPART( color1 );

    sn->sn_Screen =  OpenScreenTags( NULL,
    			SA_Colors,	colorspec,
			SA_ErrorCode,	&errorcode,
			TAG_MORE,	&tags,	/* jump to varargs list */
			TAG_END );

    if ( sn->sn_Screen )
    {
	window = OpenWindowTags( NULL,
		WA_CustomScreen,	sn->sn_Screen,
		WA_Title, 		" Window in Screen ",
		TAG_END );

	printf("window at %lx\n", window );

        if ( window )	/* i.e., success */
        {
	    printf("new screen at %lx.\n", sn->sn_Screen);
	    AddTail(&ScreenList, (struct Node *) sn);

	    /* draw a little something at the bottom	*/
	    drawRulers( sn->sn_Screen );
	    return (sn->sn_Screen);
        }
	else
	{
	    printf( "couldn't get window for screen\n" );
	    CloseScreen( sn->sn_Screen );
	}
    }

    else
    {
	printf("can't open screen: ");
    	switch ( errorcode )
	{
	case OSERR_NOMONITOR:
	    printf("monitor not available.\n");
	    break;
	case OSERR_NOCHIPS:
	    printf("new chipset not available.\n");
	    break;
	case OSERR_NOMEM:
	    printf("memory not available.\n");
	    break;
	case OSERR_NOCHIPMEM:
	    printf("chip memory not available.\n");
	    break;
	case OSERR_PUBNOTUNIQUE:
	    printf("public screen already open.\n");
	    break;
	case OSERR_UNKNOWNMODE:
	    printf("mode ID is unknown.\n");
	    break;
	default:
	    printf("unknown error %ld\n", errorcode );
	}
    }
    FreeMem(sn, (LONG) sizeof (struct ScreenNode));
    return (NULL);
}

#define HRULEY		(90L)
#define VRULEX		(250L)
#define VRULESTART	(1)			/* start VRULE at 200	*/

#define HASHHEIGHT	(20L)		/* size of hash marks	*/
#define HASHWIDTH	(20L)

/*
 * draw rulers in screen
 */
UBYTE	posbuff[ 81 ];

void drawRulers(struct Screen *sc)
{
#if 0
    struct RastPort *rp = sc->FirstWindow->RPort;
#else
    struct RastPort *rp = &sc->RastPort;
#endif
    int		hunnert;
    int		pos;
    int		endpos;
    int		tlength;
    int		width = sc->Width;
    int		height = sc->Height;

    /* report total dimensions	*/
    sprintf( posbuff, "Left %d, Top %d, Width %d, Height %d.",
    	sc->LeftEdge, sc->TopEdge, sc->Width, sc->Height );
    SetAPen( rp, 1L );
    Move( rp, 10L, (LONG) HRULEY - 50 );
    Text( rp, posbuff, (LONG) strlen( posbuff ) );

    /* draw horizontal counters and hashmarks */
    SetAPen( rp, 1L );
    Move( rp, 0L, (LONG) HRULEY + HASHHEIGHT / 2 );
    Draw( rp, (LONG) width - 1, (LONG) HRULEY + HASHHEIGHT / 2 );

    for (hunnert = 0; (hunnert * 100) <= width; ++hunnert)
    {
	/* tall hashmark at X00	*/
	pos = hunnert * 100;
	endpos = pos + 100;
	SetAPen( rp, 3L );
	Move( rp, (LONG) pos, HRULEY );
	Draw( rp, (LONG) pos, HRULEY  + 2 * HASHHEIGHT);

	while (  (pos += 10) < endpos )
	{
	    if ( pos > (width - 1) ) goto BREAK1;
	    Move( rp, (LONG) pos, HRULEY );
	    Draw( rp, (LONG) pos, HRULEY  + HASHHEIGHT);
	}

	sprintf( posbuff, "%d", endpos);
	tlength = TextLength( rp, posbuff, (LONG) strlen( posbuff ) );
	SetAPen( rp, 7L );
	Move( rp, (LONG) endpos - tlength - 1,
	HRULEY  + 2 * HASHHEIGHT);
	Text( rp, posbuff, (LONG) strlen( posbuff ) );
    }
BREAK1:

    /* draw vertical counters */
    Move( rp, VRULEX + HASHWIDTH / 2, (LONG) VRULESTART * 100 );
    Draw( rp, VRULEX + HASHWIDTH / 2, (LONG) height - 1 );

    for (hunnert = VRULESTART;
	((hunnert * 100)) <= height; ++hunnert)
    {
	/* wide hashmark at X00	*/
	pos = hunnert * 100;
	endpos = pos + 100;
	Move( rp, VRULEX, (LONG) pos);
	Draw( rp,  VRULEX  + 2 * HASHWIDTH, (LONG) pos);

	while (  (pos += 10) < endpos )
	{
	    if ( pos > (height - 1) ) goto BREAK2;
	    Move( rp, VRULEX, (LONG) pos);
	    Draw( rp,  VRULEX  + HASHWIDTH, (LONG) pos);
	}

	sprintf( posbuff, "%d", endpos);
	tlength = TextLength( rp, posbuff, (LONG) strlen( posbuff ) );
	Move( rp, VRULEX - tlength - 1, (LONG) endpos - 1);
	Text( rp, posbuff, (LONG) strlen( posbuff ) );
    }
BREAK2:
    return;
}

/*
struct Window	*OpenWindowTags( nw,tags)
struct NewWindow	*nw;
ULONG			tags;
{
    struct Window	*OpenWindowTagList();

    return ( OpenWindowTagList( nw, &tags ) );
}
struct Screen	*

OpenScreenTags( ns, tag1, data1 )
struct NewScreen	*ns;
ULONG			tag1;
{
    struct Screen	*OpenScreenTagList();

    return ( OpenScreenTagList( ns, &tag1 ) );
}
*/