/** wbdualpf.c :ts=8 **/
/* Turn the workbench into dual playfield.
 *
 * You can use the same trick for your own screens,
 * which is the recommended method for creating dual-playfield
 * screens.
 *
 * -Start with a new, single-playfield screen
 *  (don't set DUALPF in NewScreen.ViewModes)
 * -Allocate a second playfield, set up a rastport for
 *  rendering into it, and install it into your open screen
 *  as shown here.  Intuition will never know about or use your
 *  second playfield for its rendering (menus, gadgets, etc.).
 * -Be sure to remove evidence of your deed before CloseScreen().
 */

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

#include <functions.h>

#ifdef ORIGINALCODE
#define printf  kprintf
#endif

struct  Remember    *rememberkey = NULL;
struct  Window      *getNewWind();

struct  IntuitionBase   *IntuitionBase;
struct  GfxBase         *GfxBase;

ULONG   flg = ACTIVATE | WINDOWCLOSE | NOCAREREFRESH | WINDOWDRAG
	    | WINDOWDEPTH | SIMPLE_REFRESH;

ULONG   iflg = CLOSEWINDOW | INTUITICKS ;

#define FANCYVERSION 1
#if FANCYVERSION
#define VISUALTICKS	30	/* intuiticks per frame	*/
#define CYCLETICKS	3	/* intuiticks per pen color	*/
#endif

main()
{
    struct  IntuiMessage    *msg;
    struct Window   *window = NULL;
    WORD    exitval = 0;

    /* hold data from *msg  */
    ULONG   class;

    /* specific for this test	*/
    struct Screen *wbscreen;
    struct RasInfo *rinfo2 = NULL;	/* second playfield rasinfo ... */
    struct BitMap  *bmap2 = NULL;	/* ... and bitmap		*/
    struct RastPort *rport2 = NULL;	/* for rendering into bmap2	*/
    int	   it_is_done = 0;		/* success flag			*/
    int	   counter = 0;			/* for timing the visuals	*/

    if (!(IntuitionBase = (struct IntuitionBase *)
	OpenLibrary("intuition.library", 0L)))
    {
	printf("NO INTUITION LIBRARY\n");
	exitval = 1;
	goto EXITING;
    }

    if (!(GfxBase = (struct GfxBase *)
	OpenLibrary("graphics.library", 0L)))
    {
	printf("NO GRAPHICS LIBRARY\n");
	exitval = 2;
	goto EXITING;
    }

    /* get a window on the workbench	*/
    window = getNewWind(320, 20, 300, 50, flg, iflg);
    if (window == NULL)
    {
	printf("test: can't get window.\n");
	exitval = 1;
	goto EXITING;
    }


    /* ------ Add a second playfield for Workbench ------------ */

    wbscreen = window->WScreen;		/* find it	*/

    /* allocate second playfield's rasinfo, bitmap, and bitplane	*/

    if (!(rinfo2 = (struct RasInfo *)
	AllocMem((LONG) sizeof(struct RasInfo), (LONG) MEMF_PUBLIC|MEMF_CLEAR)))
    {
	printf("alloc rasinfo failed\n");
	goto EXITING;
    }

    if (!(bmap2 = (struct BitMap *)
	AllocMem((LONG) sizeof(struct BitMap), (LONG) MEMF_PUBLIC|MEMF_CLEAR)))
    {
	printf("alloc bitmap failed\n");
	goto EXITING;
    }

    InitBitMap(bmap2, 1L, (LONG) wbscreen->Width, (LONG) wbscreen->Height);

    /* we'll use 1 plane. */
    if (!(bmap2->Planes[0] =
	(UBYTE *) AllocRaster((LONG) wbscreen->Width, (LONG) wbscreen->Height)))
    {
	printf("alloc raster failed\n");
	goto EXITING;
    }

    /* get a rastport, and set it up for rendering into bmap2	*/
    if (!(rport2 = (struct RastPort *)
	AllocMem((LONG) sizeof (struct RastPort), (LONG) MEMF_PUBLIC)))
    {
	printf("alloc rastport failed\n");
	goto EXITING;
    }
    InitRastPort(rport2);
    rport2->BitMap = bmap2;

    SetRast(rport2, 0L);

    /* manhandle viewport: install second playfield and change modes	*/
    Forbid();

    rinfo2->BitMap = bmap2;	/* install my bitmap in my rasinfo	*/

    wbscreen->ViewPort.RasInfo->Next = rinfo2;
		/* install rinfo for viewport's second playfield	*/

    wbscreen->ViewPort.Modes |= DUALPF;
				/* convert viewport			*/
    it_is_done = 1;

    Permit();

    /* set my foreground color */
    SetRGB4(&wbscreen->ViewPort, 9L, 0L, (LONG) 0xF, 0L);
    /* color 9 is color 1 for second playfield of hi-res viewport */

    /* put viewport changed into effect	*/
    MakeScreen(wbscreen);
    RethinkDisplay();

    drawSomething(rport2);

    FOREVER
    {
	if ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)) == NULL)
	{
	    Wait((ULONG) 1<<window->UserPort->mp_SigBit);
	    continue;
	}

	class   = msg->Class;
	ReplyMsg(msg);

	switch (class)
	{
	case INTUITICKS:
#if FANCYVERSION
	    setPrimary(&wbscreen->ViewPort);	/* cycles colors */
	    if (counter++ > VISUALTICKS)
	    {
		counter = 0;
		SetRast(rport2, 0L);
		drawSomething(rport2);
	    }
#endif
	    break;

	case CLOSEWINDOW:
	    goto EXITING;
	default:
	    printf("unknown event: class %lx\n", class);
	}
    }

EXITING:
    /* clean up dual-playfield trick	*/
    if (it_is_done)
    {
	Forbid();
	wbscreen->ViewPort.RasInfo->Next = NULL;
	wbscreen->ViewPort.Modes &= ~DUALPF;
	Permit();
	MakeScreen(wbscreen);
	RethinkDisplay();
    }

    if (rport2) FreeMem(rport2, (LONG) sizeof (struct RastPort));
    if (bmap2) 
    {
	if (bmap2->Planes[0])
	{
	    FreeRaster(bmap2->Planes[0],
	    	(LONG) wbscreen->Width, (LONG) wbscreen->Height);
	}
	FreeMem(bmap2, (LONG) sizeof (struct BitMap));
    }
    if (rinfo2) FreeMem(rinfo2, (LONG) sizeof (struct RasInfo));

    if (window) CloseWindow(window);
    if (GfxBase) CloseLibrary(GfxBase);
    if (IntuitionBase) CloseLibrary(IntuitionBase);

    exit (exitval);
}

#if FANCYVERSION
/* cycle pen 1's color */
setPrimary(vp)
struct ViewPort *vp;
{
    static int current = 0;

    /* pen 1 is color 9 for second playfield in hires */
    /* feel free too do this elegantly */

    if (!(current++ % CYCLETICKS)) return;

    switch ((current/CYCLETICKS)%3)
    {
    case 0:
	SetRGB4(vp, 9L, 0xFL, 0L, 0L);
	break;
    case 1:
	SetRGB4(vp, 9L, 0L, 0xFL, 0L);
	break;
    case 2:
	SetRGB4(vp, 9L, 0L, 0L, 0xFL);
	break;
    }
}

struct pt_st {
    ULONG x;
    ULONG y;
    };

typedef struct pt_st Pt;

drawSomething(rp)
struct RastPort *rp;
{
    int width, height;
    LONG   RangeRand();
    int i;

    Pt start, vertex, end;	/* random reference lines */
    Pt p0, p1;		/* endpoints to be drawn	*/

    width = rp->BitMap->BytesPerRow * 8;
    height = rp->BitMap->Rows;

    /* set up two random reference lines */
    start.x = RangeRand((LONG) width);
    vertex.x   = RangeRand((LONG) width);
    end.x   = RangeRand((LONG) width);

    start.y = RangeRand((LONG) height);
    vertex.y = RangeRand((LONG) height);
    end.y   = RangeRand((LONG) height);

    SetAPen(rp, 1L);

    /* draw lines connecting intermediate points */
    for (i = 0; i <= 0x100; i += 0x10)
    {
	/* point between start and vertex */
	p0.x = (start.x * (0xFF - i) + vertex.x  * i) >> 8;
	p0.y = (start.y * (0xFF - i)  + vertex.y * i) >> 8;

	/* point between vertex and end	*/
	p1.x = (vertex.x * (0xFF - i) + end.x * i) >> 8;
	p1.y = (vertex.y * (0xFF - i) + end.y * i) >> 8;

	Move(rp, p0.x, p0.y);
	Draw(rp, p1.x, p1.y);
    }

}

#else

drawSomething(rp)
struct RastPort *rp;
{
    int width, height;
    int r, c;

    width = rp->BitMap->BytesPerRow * 8;
    height = rp->BitMap->Rows;

    SetAPen(rp, 1L);

    for (r = 0; r < height; r += 40)
	for (c = 0; c < width; c += 40)
	{
	    Move(rp, 0L, (LONG) r);
	    Draw(rp, (LONG) c, 0L);
	}
}

#endif

struct  Window * getNewWind(left, top, width, height, flg, iflg)
SHORT   left, top, width, height;
ULONG   flg, iflg;
{
    struct  Window  *OpenWindow();
    struct  NewWindow   nw;

    nw.LeftEdge =   (SHORT) left;
    nw.TopEdge  =   (SHORT) top;
    nw.Width    =   (SHORT) width;
    nw.Height   =   (SHORT) height;
    nw.DetailPen    =   (UBYTE) -1;
    nw.BlockPen =   (UBYTE) -1;
    nw.IDCMPFlags   =   (ULONG) iflg;

    nw.Flags    =   (ULONG) flg;

    nw.FirstGadget  =   (struct Gadget *)   NULL;
    nw.CheckMark    =   (struct Image *)    NULL;
    nw.Title    =   (UBYTE *)   " Dual Playfield Mole ";
    nw.Screen   =   (struct Screen *)   NULL;
    nw.BitMap   =   (struct BitMap *)   NULL;
    nw.MinWidth =   (SHORT) 50;
    nw.MinHeight=   (SHORT) 30;
    /* work around bug  */
    nw.MaxWidth =   (SHORT) nw.Width;
    nw.MaxHeight    =   (SHORT) nw.Height;
    nw.Type     =   (USHORT) WBENCHSCREEN;

    return ((struct Window *) OpenWindow(&nw));
}


