/* Screen Demo Program	 :ts=8 */

/*
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 "sysall.h"

#include <stdio.h>

/* temp define for graphics/view.h	*/
#ifndef SUPERHIRES
#define SUPERHIRES	(0x40)
#endif

struct  IntuitionBase   *IntuitionBase;
struct  GfxBase         *GfxBase;

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

struct ScreenNode	{
    struct Node	sn_Node;	
    struct Screen *sn_Screen;
};

struct Screen *addScreen();

struct Node		*RemHead();
struct Screen	*OpenScreen();

struct TextAttr SafeFont = { (UBYTE *) "topaz.font", 8, 0, 0, };

/** some strings to feed my alert generator	*/

char	*deathstrings[] = {
    "This is not a test.",
    "                                You are dead now.",
    NULL
};

char	*alertstrings[] = {
    "This is a test.",
    "It is only a test.",
    "Please be aware that this is a test.",
    NULL
};

char	kbuff[257];

showHelp()
{
    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");
}

ULONG	errorcode;	/* for OpenScreen() errors	*/

main()
{
    struct ExtNewScreen ns;
    struct TagItem  nsext[3];
    struct Rectangle oscanrect;

    struct TagItem  *idtag;
    struct TagItem  *dcliptag;

    printf("SCDemo: accompanies V1.4 alpha 15.\n");

    NewList( &ScreenList );

    /* not all library versions work with all screens	*/
    if (!(IntuitionBase = 
	(struct IntuitionBase *) OpenLibrary("intuition.library", 36L)))
    { cleanup("no V36 intuition library\n"); }

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

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

	/* may override these in some cases	*/
	ns.LeftEdge = ns.TopEdge = 0;
	ns.Width 	=	STDSCREENWIDTH;
	ns.Height 	=	STDSCREENHEIGHT;
	ns.Depth	=	1;

	ns.DetailPen	=	0;
	ns.BlockPen	=	1;
	ns.Gadgets	=	NULL;
	ns.CustomBitMap	=	NULL;
	ns.Font		=	&SafeFont;
	ns.Type		=	CUSTOMSCREEN | NS_EXTENDED;
	ns.Extension	=	nsext;

	/* extension data	*/
	/* 32 bit display ID	*/
	idtag		=	&nsext[0];
	idtag->ti_Tag	=	NSTAG_DISPLAY;
	idtag->ti_Data	=	0;

	/* get specific error code back from OpenScreen()	*/
	nsext[1].ti_Tag =	NSTAG_ERROR;
	nsext[1].ti_Data =	(ULONG) &errorcode;

	/* display clipping rectangle (override)	*/
	dcliptag	=	&nsext[2];
	dcliptag->ti_Tag =	NSTAG_STDDCLIP;
	dcliptag->ti_Data =	OSCAN_TEXT;	/* standard dims	*/

	nsext[3].ti_Tag =	TAG_DONE;

	switch ( *kbuff )
	{
	case 'o':
	    idtag->ti_Data	= HIRES_KEY;
	    dcliptag->ti_Data	= OSCAN_STANDARD;

	    ns.DefaultTitle	= (UBYTE *) " HiRes Standard Overscan ";

	    QueryOverscan( &ns, &oscanrect, (LONG) OSCAN_STANDARD );
	    ns.LeftEdge	=	oscanrect.MinX;
	    ns.TopEdge	=	oscanrect.MinY;

	    addScreen(&ns, 0xf00, 0x555);
	    break;

	case 'O':
	    idtag->ti_Data	= HIRES_KEY;
	    dcliptag->ti_Data	= OSCAN_VIDEO;

	    ns.DefaultTitle	= (UBYTE *) " HiRes Video Overscan ";

	    QueryOverscan( &ns, &oscanrect, (LONG) OSCAN_MAX );
	    ns.LeftEdge	=	oscanrect.MinX;
	    ns.TopEdge	=	oscanrect.MinY;
	    /* use STDSCREENWIDTH/HEIGHT */

	    addScreen(&ns, 0xf00, 0x555);
	    break;

	case 'a':
	    printf(" do a2024 10 Hz\n");
	    idtag->ti_Data	= A2024TENHERTZ_KEY;
	    ns.DefaultTitle	= (UBYTE *) " A2024, 10 Hz ";
	    addScreen(&ns, 0xfff, 0x000);
	    break;

	case 'A':
	    idtag->ti_Data	= A2024FIFTEENHERTZ_KEY;
	    ns.DefaultTitle	= (UBYTE *) " A2024, 15 Hz ";
	    addScreen(&ns, 0x000, 0xfff);
	    break;

	case 's':
	    idtag->ti_Data	= SUPER_KEY;

	    ns.DefaultTitle	= (UBYTE *) " Super-Hires, Non-interlaced";
	    addScreen(&ns, 0x005, 0xff0);
	    break;

	case 'S':
	    idtag->ti_Data	= SUPERLACE_KEY;
	    ns.DefaultTitle	= (UBYTE *) " Super-Hires Interlaced";
	    addScreen(&ns, 0x005, 0xff0);
	    break;

	case 'p':
	    idtag->ti_Data	= VGAPRODUCT_KEY;
	    ns.DefaultTitle	= (UBYTE *) " Productivity Mode ";
	    addScreen(&ns, 0xfff, 0x000);
	    break;

	case 'P':	/* productivity, lace	*/
	    idtag->ti_Data	= VGAPRODUCTLACE_KEY;
	    ns.DefaultTitle	= (UBYTE *) " Productivity, Interlaced ";
	    addScreen(&ns, 0x005,0xf00);
	    break;

	case 'z':
	    idtag->ti_Data	= VGALORES_KEY;
	    ns.DefaultTitle	= (UBYTE *) " 70ns pixels, Doublescan ";
	    addScreen(&ns, 0xfff, 0x000);
	    break;

	case 'h':
	    idtag->ti_Data	= HIRES_KEY;
	    ns.DefaultTitle	= (UBYTE *) " HiRes Text Overscan ";
	    addScreen(&ns, 0x0f0, 0x555);
	    break;

	case 'H':
	    idtag->ti_Data	= HIRESLACE_KEY;
	    ns.DefaultTitle	= (UBYTE *) " HiRes Interlace ";
	    addScreen(&ns, 0xf00, 0x555);
	    break;

	case 'L':
	    idtag->ti_Data =	LORESLACE_KEY;
	    ns.DefaultTitle	= (UBYTE *) " LoRes Lace Screen ";
	    addScreen(&ns, 0x0ff, 0x555);
	    break;

	case 'l':
	    idtag->ti_Data =	LORES_KEY;
	    ns.DefaultTitle	= (UBYTE *) " LoRes Screen ";
	    addScreen(&ns, 0x00f, 0x555);
	    break;

 	case 'w':
	    idtag->ti_Data	= HIRES_KEY;
	    ns.Width	=	1100;
	    ns.DefaultTitle	= (UBYTE *) " Wide Scrolling Hi-Res Screen ";
	    ns.Type	|=	AUTOSCROLL;
	    addScreen(&ns, 0xf0f, 0x555);
	    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 )
		{
		    idtag->ti_Data =	scanmode;
		    sprintf( kbuff,"Direct Mode Specification: %lx",scanmode);
		    ns.DefaultTitle	= (UBYTE *) kbuff;
		    addScreen(&ns, 0x0ff, 0x555);
		    break;
		}
		else
		{
		    printf("couldn't parse: type '$ <hex num>'\n");
		}
	    }
	    break;
	default:
	    printf("don't know (%lx)\n", *kbuff, *kbuff);
	}
    }
}

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

    freeScreens();

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

    exit (0);
}

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

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

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

struct Screen *
addScreen( ns, color0, color1 )
struct ExtNewScreen *ns;
int				color0, color1;
{
    struct ScreenNode *sn;
    struct RastPort	*rp;

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

    if (sn->sn_Screen = OpenScreen(ns))
    {
	printf("new screen at %lx.\n", sn->sn_Screen);
	AddTail(&ScreenList, sn);

	SetRGB4( &sn->sn_Screen->ViewPort, 0L,
	    (LONG) (color0 >> 8) & 0xf, 
	    (LONG) (color0 >> 4) & 0xf,
	    (LONG) color0 & 0xf);

	SetRGB4( &sn->sn_Screen->ViewPort, 1L,
	    (LONG) (color1 >> 8) & 0xf, 
	    (LONG) (color1 >> 4) & 0xf,
	    (LONG) color1 & 0xf);

	/* draw a little something at the bottom	*/
	rp =  &sn->sn_Screen->RastPort;

#if 1
	drawRulers( sn->sn_Screen );
#else
	SetAPen( rp, (LONG) 1 );
	Move( rp, (LONG) 50, (LONG) 100 );
	Text( rp, string, (LONG) strlen( string ) );

	Move( rp, (LONG) 10, (LONG) 10);
	Draw( rp, (LONG) 90, (LONG) 90);

	Move( rp,
	    (LONG) 0, (LONG) sn->sn_Screen->Height - 1);
	Draw( rp,
	    (LONG) sn->sn_Screen->Width-1,(LONG) sn->sn_Screen->Height - 1);
	Draw( rp,
	    (LONG) 10, (LONG) sn->sn_Screen->Height/2);
	Draw( rp,
	    (LONG) sn->sn_Screen->Width-10, (LONG) sn->sn_Screen->Height/2);
	Draw( rp,
	    (LONG) 0, (LONG) sn->sn_Screen->Height - 1);
#endif
	return (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 ];

drawRulers( sc )
struct Screen *sc;
{
    struct RastPort *rp = &sc->RastPort;
    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;
}
