[comp.sys.amiga.tech] back to dual playfields under Intuition

FelineGrace@cup.portal.com (Dana B Bourgeois) (09/30/89)

[[ line-eater food ]]

Here is the example from the 1.2 Enhancer Manual.  Had a couple extra
hours and typed it in.  Enjoy!

Dana Bourgeois @ cup.portal.com
/********************************************************************

* Example program for Dual-Playfield Screens

*

* copyright Commodore-Amiga, Inc., Sept. 1986. use at will

* author: jim mackraz(amiga!jimm)
*********************************************************************

* Turn the workbench into dual playfield.

* You can use the same trick for your own screens,
* which is the recommended method for creating duall-playfield
* screens. (Please don't really do this to the Workbench.)
*
* Start with a new, single-playfield screen
* (don't set DUALPF in NewScreen.ViewModes)
* Allocate a second palyfield, 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 playfiled for its rendering(menus, gadgets, etc.).
* Be sure to remove evidence of your deed before CloseScreen().
*/

#define printf kprintf


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

struct IntuitionBase	*IntuitionBase;
struct GfxBase		*GfxBase;

ULONG iflg=CLOSEWINDOW;

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 RasPort *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 0);

		exitval=1;
		goto EXITING;
	}

	if(!(GfxBase=(struct GfxBase *)
		OpenLibrary("graphics.library",0)))

	{
		printf("NO GRAPHICS LIBRARY0);
		exitval=2;
		goto EXITING;
	}

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

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

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

/* allocate seconde palyfield's rasinfo, bitmap, and bitplane */
	if(!rinfo2=(struct RasInfo *)
		AllocMem(sizeof(struct RasInfo),
		MEMF_PUBLIC|MEMF_CLEAR)))
	{
		printf("alloc rasinfo failed0);
		goto EXITING;
	}

	if(!(bmap2=struct BitMap *)
		AllocMem(sizeof(struct BitMap),
		MEMF_PUBLIC|MEMF_CLEAR)))
	{
		printf("aloc bitmap failed0);
		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 failed0);
		goto EXITING;
	}

/* get a tastport, and set it up for rendering into bmap2 */
	if(!(rport2=(struct RastPort *)
		AllocMem(sizeof(struct RastPort), MEMF_PUBLIC)))
	{
		printf("alloc rastport failed0);
		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.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 ok0);

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

		class=msg->Class;
		ReplyMsg(msg);
		switch(class)
		{
		case CLOSEWINDOW:
			printf("event CLOSEWINDOW0);
			goto EXITING;
		default:
			printf("unknown event class%1x0,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);
}

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

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 Mode";
	nw.Screen=(struct Screen *)NULL;
	nw.BitMap=(struct BitMap *)NULL;
	nw.MinWidth=(struct BitMap *)NULL;
	nw.MInWidth=(SHORT)50;
	nw.MinHeight=(SHORT)30;
/* work around a bug */
	nw.MaxWidth=(SHORT)nw.Width;
	nw.MaxHeight=(SHORT)nw.Height;
	nw.Type=(SHORT)WBENCHSCREEN;

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

rap@peck.ardent.com (Rob Peck) (10/03/89)

In article <22679@cup.portal.com> FelineGrace@cup.portal.com (Dana B Bourgeois) writes:
>Here is the example from the 1.2 Enhancer Manual.  Had a couple extra
>hours and typed it in.  Enjoy!
>
>Dana Bourgeois @ cup.portal.com
>
>		 [ example deleted ]

MANY thanks to Dana for typing it in.  There are, it seems, a few typos
in his posting :-(, BUT, starting from an original file on a DEVCON disk,
I created this demo that does:

	1.  Dual Playfield (on a custom screen, not Workbench)
	2.  The second playfield is twice as tall as the first one,
	    implementing a slow-scroll (rolling credits) demo.
	3.  Dynamic modification of the Playfield priorities where
	    playfield one (owned by intuition) is alternatively
	    the front or the rear playfield.  (The scrolling text
	    does an under/over/under as it crawls upscreen.)
	    Uses the CINIT, CWAIT, CMOVE, CEND macros.
	    Cleans up after itself.   May or may not handle
	    low memory conditions gracefully (have not tried,
	    but I think so.

Hope it helps.  Feedback and questions welcome at:
DATAPATH, POBox 1828, Los Gatos, CA 95031-1828



Rob Peck


/* interleave.c */

/* A demo that uses Amiga's dual playfield capability, interleaving the
 * priority between Playfield 1 (owned by Intuition) and Playfield 2
 * created, managed and owned by the user.  Additional "tricks" used
 * is the creation of two bitmap structures, one of which tells MakeScreen
 * that the second playfield is the same size as the display, and the
 * second bitmap manages a drawing area that is actually twice as long
 * as that which is displayed.  Thus we draw into it, and scroll those
 * parts through the actual view by remaking the screen.  Very little
 * data gets moved each time a scroll occurs, so this COULD even be
 * used to scroll a full HAM screen; we do half-a-ham as it is in this
 * example.  Also, this could be made slightly more efficient by copying
 * UWORDS instead of UBYTES when the scroll has occured.  The reason for
 * the byte copying in the first place is to redisplay the TOP half of
 * the scrolling playfield area instead of the bottom half effectively
 * allowing immediate reuse of the bottom half for a continuation of
 * a scroll (after a full 200 lines have been scrolled, the offscreen
 * part and the onscreen part are identical, allowing a reuse of the
 * top half instead of displaying the last line of the scroll of the
 * bottom half.
 *
 * Rob Peck 10/1/89.
 */

/* Code structured for LATTICE 5.02, by Rob Peck
   based on original work done by Jim Mackraz in
   his "cpr.c" demo for the Washington DC 1988 developer's
   conference (CINIT/CMOVE/CWAIT/CEND demo) and his
   wbdualpf example (adding second playfield to workbench).
*/
 
#include "exec/types.h"
#include "intuition/intuition.h"
#include "hardware/custom.h"
#include "graphics/copper.h"
#include "graphics/gfxmacros.h"

/* A Lattice requirement */
extern struct Custom __far custom;

struct  IntuitionBase   *IntuitionBase;
struct  GfxBase         *GfxBase;

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

struct NewWindow nw = {
	0,12,310,185,0,1,CLOSEWINDOW,
	ACTIVATE|WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE,
	NULL,NULL,"CloseMe",NULL,NULL,
	5,5,-1,-1,CUSTOMSCREEN };

struct NewScreen ns = {
	0, 0,320, 200,3,1, 0,SPRITES,CUSTOMSCREEN,&myfont1,
	(UBYTE *)"dualpf",NULL,NULL };

extern struct Screen *OpenScreen();
extern struct Window *OpenWindow();
extern void ReUseLowerBuffer();

SHORT first_time=TRUE;

main()
{
    UBYTE *initialptr[3];
    UBYTE *from[3], *to[3];
    SHORT scroll;
    SHORT i, j;
    LONG mapsize, rowsize_in_bytes;
    
    struct  IntuiMessage    *msg;
    struct Window   *window = NULL;
    WORD    exitval = 0;

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

    /* specific for this test	*/
    struct Screen *screen;
    struct RasInfo *rinfo2 = NULL;	/* second playfield rasinfo ... */
    struct BitMap  *bmap2 = NULL;	/* ... and bitmap		*/
    struct BitMap  *bmap3 = NULL;	/* CHANGE */
    struct RastPort *rport2 = NULL;	/* for rendering into bmap3**   */
    struct RastPort *rp = NULL;
    int	   it_is_done = 0;		/* success flag			*/

    struct UCopList *ucl;
    struct ViewPort *vp;

    ucl = NULL;
    first_time = TRUE;

    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;
    }
    screen = OpenScreen(&ns);   
    if(screen == NULL)
    {
        exitval = 3;
        printf("screen wont open\n");
        goto EXITING;
    }
    nw.Screen = screen;
    
    window = OpenWindow(&nw);
    if (window == NULL)
    {
	printf("test: can't get window.\n");
	exitval = 1;
	goto EXITING;
    }
    rp = window->RPort;

    SetAPen(rp, (LONG)3);
    SetDrMd(rp, (LONG)JAM1);
    RectFill(rp, 3L,  15L, 307L, 35L);
    RectFill(rp, 3L,  45L, 307L, 65L);
    RectFill(rp, 3L,  75L, 307L, 95L);
    RectFill(rp, 3L,  105L, 307L, 125L);

    SetAPen(rp, 0L);
    SetBPen(rp, 1L);
    SetDrMd(rp, (LONG)JAM2);

    Move(rp, 10L, 30L);
    Text(rp, "Intuition Playfield (1) is 'behind'",35L);
    Move(rp, 10L, 60L);
    Text(rp, "Intuition Playfield (1) is 'infront'",36L);
    Move(rp, 10L, 90L);
    Text(rp, "Intuition Playfield (1) is 'behind'",35L);
    Move(rp, 10L, 120L);
    Text(rp, "Intuition Playfield (1) is 'infront'",36L);

    if ( !(ucl = (struct UCopList *)
	      AllocMem( (LONG) sizeof (struct UCopList), 
	(LONG) MEMF_CHIP | (LONG) MEMF_CLEAR) )) goto OUT;

    CINIT( ucl, 400L );
	/* Move playfield 2 alternatively in front/behind */

    CWAIT( ucl, 27L, 5L);
    CMOVE( ucl, custom.bplcon2,  (long)0x64);
    CWAIT( ucl, 57L, 5L);
    CMOVE( ucl, custom.bplcon2,  (long)0x24);
    CWAIT( ucl, 87L, 5L);
    CMOVE( ucl, custom.bplcon2,  (long)0x64);
    CWAIT( ucl, 117L, 5L);
    CMOVE( ucl, custom.bplcon2,  (long)0x24);
    CEND ( ucl );
    vp = &screen->ViewPort;
    vp->UCopIns = ucl;

OUT:

    /* ------ Add a second playfield ----------- */

    /* 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 (!(bmap3 = (struct BitMap *)
       		AllocMem((LONG)sizeof(struct BitMap),
			(LONG)MEMF_PUBLIC|MEMF_CLEAR)))
    {
	printf("alloc bitmap failed\n");
	goto EXITING;
    }
    InitBitMap(bmap3, 1L, (LONG) screen->Width, (LONG) screen->Height);

    if (!(bmap2 = (struct BitMap *)
      		AllocMem((LONG)sizeof(struct BitMap),
			(LONG)MEMF_PUBLIC|MEMF_CLEAR)))
    {
	printf("alloc bitmap failed\n");
	goto EXITING;
    }
    InitBitMap(bmap2, 2L, (LONG) screen->Width, (LONG)(screen->Height<<1));

    /* we'll use 3 planes. */
    for(i=0; i<3; i++)
    {
        if (!(bmap2->Planes[i] =
	    (UBYTE *) AllocRaster((LONG) screen->Width,
	     (LONG) (screen->Height<<1))))
        {
	    printf("alloc raster failed\n");
	    goto EXITING;
        }
    }
    /* bmap3 makes the memory area look like a normalsized screen,
     * bmap2 is what we actually draw into, however.  It has its 
     * own rastport, and the memory actually never changes.  What
     * WE do, however, to make it scroll, is to change the pointers
     * within bmap3 to show different parts of bitmap2.  A scroll
     * from top to bottom consists of showing the top portion of
     * bitmap2, then line by line, moving the pointers down to line
     * 200.  We can feel free to draw into any portion of bitmap2
     * that is not currently being shown onscreen thru bmap3.
     * In the scrolling case, we move data that is currently onscreen
     * to an offscreen location so that when a full top to bottom
     * scroll has happened, we can quickly switch the pointers to
     * show the offscreen portion instead of the onscreen one
     * (reshow the top part of the buffer) freeing us to quickly
     * update the offscreen part which is now again available.
     */

    for(i=0; i<3; i++)
    {
        initialptr[i] = (UBYTE *)bmap2->Planes[i];
        bmap3->Planes[i] = (PLANEPTR)initialptr[i];
    }
    mapsize = (bmap3->BytesPerRow * bmap3->Rows);
	/* converted it from bytes to words for more efficiency */
    rowsize_in_bytes = (bmap3->BytesPerRow);
    
    /* 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 = bmap3;	/* install my bitmap in my rasinfo	*/

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

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

    Permit();

    /* set my foreground color */
    SetRGB4(&screen->ViewPort, 9L, 0L, (LONG) 0xF, 0L);
    /* color 9 is color 1 for second playfield of hi-res viewport */
    SetRGB4(&screen->ViewPort, 10L, 10L, 2L, 3L);
    /* put viewport changed into effect	*/
    MakeScreen(screen);
    RethinkDisplay();

    SetAPen(rport2, 1L);
    SetBPen(rport2, 2L);
    SetDrMd(rport2, (LONG)JAM2);
    Move(rport2, 30L, 195L);
    Text(rport2, "First this line appears", 23L);
    Move(rport2, 30L, 395L);
    Text(rport2, "Then this line appears ", 23L);
    
    scroll  = 200;
    for(;;)
    {
	if ((msg = (struct IntuiMessage *)
		GetMsg(window->UserPort)) == NULL)
        { 
	    WaitTOF();
	    if(scroll != 200)
	    {
	       Forbid();
	       for(i=0; i<3; i++)
               {
  	           bmap3->Planes[i] = (PLANEPTR)
	                             (((LONG)bmap3->Planes[i]) 
		  		       + bmap3->BytesPerRow);
	       }
	       Permit();
	           /* Pointers are moved; now show the new display
		    * before you can copy the on-display bottommost
		    * line to the line that JUST scrolled offscreen
		    */
	       MakeScreen(screen);
	       RethinkDisplay();
		   /* Now copy the data from bottomline to most recent
                    * scrollee.
                    */
	       for(j=0; j<3; j++)
               {
	            for(i=0; i<rowsize_in_bytes; i++)
                    {
		    /* copies a row from each bit plane */
		        *to[j] = *from[j];
		        to[j]++;
		        from[j]++;
		    }
	       }
	    }
	    else
            {
		scroll = 0;
		for(i=0; i<3; i++)
                {
		   to[i]   =   (UBYTE *)initialptr[i];
		   from[i] =   (UBYTE *)((LONG)initialptr[i] + mapsize);
		   Forbid();
		      bmap3->Planes[i] = (PLANEPTR)initialptr[i];
		   Permit();
		}
		/* Adjusted the pointers to repoint to the upper half
		 * of the scrolling display buffer... so we now can
		 * remake the diaplay and show this part instead of
		 * the lower half and reuse it.
		 */
	        MakeScreen(screen);
	        RethinkDisplay();
	    }
	    if(scroll == 0) ReUseLowerBuffer(rport2);
	    scroll++;
	    continue;
	}
	class   = msg->Class;
	ReplyMsg(msg);

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

EXITING:
    if(ucl)
    {
	vp->UCopIns = NULL;
	
	FreeCopList( ucl->FirstCopList );
	FreeMem( ucl, (LONG) sizeof (struct UCopList) );
    }

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

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

    if (window) CloseWindow(window);
    if (screen) CloseScreen(screen);

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

    exit (exitval);
}

/* This could be used to put one screen after another of text to be
 * scrolled into the visible area.  Based on where it is called, one
 * has to actually copy a whole screen at a time before the scrolling
 * can continue, but this can be adjusted any way the user likes.
 */
void ReUseLowerBuffer(r)
struct RastPort *r;
{
    if(!first_time)
    {
        Move(r, 30L, 395L);
        Text(r, "Finally, this line repeats", 26L);
    }
    else
    {
	first_time = FALSE;
    }
}