[net.micro.amiga] DUAL-PLAYFIELD Screens -- Example

jimm@amiga.UUCP (James D. Mackraz) (11/03/86)

::

    The following is an example of using a dual-playfield screen.
    Contrary to what it says in the Intuition Manual, the way
    to do this is to open a normal, single-playfiled screen and
    then to mutate it into a dual-playfield, providing your
    own bit map and planes, and auxilliary data structures.

    The example given performs this mutation on the workbench screen,
    but such intrusive behavior is not recommended for any purpose
    other than demonstration and playing around.  (And perhaps the
    odd subliminal message.)

    There are certain constraints which must be understood as to the
    number of bitplanes in the two playfields which are allowed, and
    the formulas for color mapping the two playfields are only hinted
    at in this example, so you must still consult the manuals.

    Note the constant FANCYVERSION, which if defined non-zero results
    in a more exciting demo than the version of this program supplied
    in the Intuition Revision notes (which are to be distributed to
    developers).

    Note also that like most of my previous examples, this program
    was produced under GreenHills C, and come with no guarantee to
    compile and run under any other system.

    Although I am no longer an employee of Commodore-Amiga, Inc., it
    is my pleasure to continue to support and be a member of the
    Amiga developers community.  See you at the Developer's Conference.

				Jim Mackraz
				(amiga!jimm)

/** wbdualpf.c **/
/* 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>

#define printf  kprintf

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
#ifdef FANCYVERSION
#define VISUALTICKS	30	/* intuiticks per frame	*/
#define CYCLETICKS	5	/* 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	*/
    BOOL   it_is_done = FALSE;		/* success flag			*/
    int	   counter = 0;			/* for timing the visuals	*/

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

    if (!(GfxBase = (struct GfxBase *)
	OpenLibrary("graphics.library", 0)))
    {
	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(sizeof(struct RasInfo), MEMF_PUBLIC|MEMF_CLEAR)))
    {
	printf("alloc rasinfo failed\n");
	goto EXITING;
    }

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

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

    /* we'll use 1 plane. */
    if (!(bmap2->Planes[0] =
	(UWORD *) AllocRaster(wbscreen->Width, 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(sizeof (struct RastPort), MEMF_PUBLIC)))
    {
	printf("alloc rastport failed\n");
	goto EXITING;
    }
    InitRastPort(rport2);
    rport2->BitMap = bmap2;

    SetRast(rport2, 0);

    /* 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 = TRUE;

    Permit();

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

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

    drawSomething(rport2);

    printf("test program ok\n");

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

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

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

	case CLOSEWINDOW:
	    printf("event CLOSEWINDOW\n");
	    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, sizeof (struct RastPort));
    if (bmap2) 
    {
	if (bmap2->Planes[0])
	{
	    FreeRaster(bmap2->Planes[0], wbscreen->Width, wbscreen->Height);
	}
	FreeMem(bmap2, sizeof (struct BitMap));
    }
    if (rinfo2) FreeMem(rinfo2, sizeof (struct RasInfo));

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

    exit (exitval);
}

#ifdef 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, 9, 0xF, 0, 0);
	break;
    case 1:
	SetRGB4(vp, 9, 0, 0xF, 0);
	break;
    case 2:
	SetRGB4(vp, 9, 0, 0, 0xF);
	break;
    }
}

struct pt_st {
    int x;
    int y;
    };

typedef struct pt_st Pt;

drawSomething(rp)
struct RastPort *rp;
{
    int width, height;
    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(width);
    vertex.x   = RangeRand(width);
    end.x   = RangeRand(width);

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

    SetAPen(rp, 1);

    /* 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, 1);

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

#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));
}