[comp.sys.amiga] The Next Step: ing.c

ewhac@well.UUCP (02/05/87)

[ The line eater is really Pac Man moonlighting. ]

	To atone for my sin of posting a 200+ line MCIBTYC-type flame, I
have created the following little goodie.  Once again, I invite comments
from Commodore or Amiga (or both) regarding this code.  I'm doing unusual
things, and wonder just how well-behaved such tromping is.

	Remember, if you don't say anything, I'll assume the code is
practical, and may end up using it in a commercial product one day (yes,
this is a threat).

	Oh well.  Enjoy your new toy.

					Schwab

###############  Apply Andy Finkel's drill here.  ########################
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	ing.c
#	rnd.s
# This archive created: Wed Feb  4 22:49:40 1987
# By:	Leo 'Bols Ewhac' Schwab ()
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
	Welcome to Ing, the next logical step in Boing-type display hacks.
It took me about two evenings to cook this up.  This is written for the Manx
3.20a compiler.  Conversion to Lettuce C *should* be simple.

	To make this monster:

	Copy the heapmem.o module to your working directory.
	cc ing.c
	as rnd.s
	ln ing.o rnd.o heapmem.o -lm -lc -o ing

USEAGE:
	This works best from the Workbench.  Open a few small to medium-
sized windows (2-4 is good).  Then run Ing.  Enjoy.  To stop the program, go
back to the Workbench screen and click on Ing's close gadget.

NOTES:
	I tried my best to eliminate display hashing, but it still happens
under certain phases of the moon.  However, it seems to be completely
Intuition-friendly, so you can drag the screen around all you want.

	I'm a bit disappointed at the performance, and suspect that it could
be made to run faster, but I've no idea how.  Suggestions would be
appreciated.

	I'm reasonably sure that I'm cleaning up everything properly when I
exit.  If anyone discovers that I'm not, please point it out to me.

	Have fun.

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 ________		 ___			Leo L. Schwab
	   \		/___--__		The Guy in The Cape
  ___  ___ /\		    ---##\		ihnp4!ptsfa!well!ewhac
      /   X  \_____    |  __ _---))			..or..
     /   /_\--    -----+==____\ // \  _		well ---\
___ (   o---+------------------O/   \/ \	dual ----> !unicom!ewhac
     \     /		    ___ \_  (`o )	hplabs -/       ("AE-wack")
 ____ \___/			     \_/
	      Recumbent Bikes:			"Work FOR?  I don't work FOR
	    The _O_n_l_y Way To Fly!		anybody!  I'm just having fun."
SHAR_EOF
fi
if test -f 'ing.c'
then
	echo shar: "will not over-write existing file 'ing.c'"
else
cat << \SHAR_EOF > 'ing.c'
/* :ts=8 bk=0
 * ing.c:  The next logical step in "Boing"-type display hacks.
 *
 * Written by Leo L. Schwab		8702.3
 * Released into the public domain, but please keep the original author's
 * name on it.
 *
 * Note: After preliminary experiments, I get the impression that this could
 * somehow be faster.  Suggestions appreciated.
 */

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

#define	DEPTH		2


extern void	*OpenLibrary(), *OpenWindow(), *OpenScreen(), *AllocRaster(),
		*GetMsg(), *malloc();
extern long	VBeamPos();


struct NewScreen scrdef = {
	0, 0, 0, 0, DEPTH,	/*  Size filled in later  */
	0, 1,
	HIRES,
	CUSTOMSCREEN,
	NULL,
	NULL,			/*  Title filled in later  */
	NULL, NULL
};

struct NewWindow windef = {
	0, 30, 150, 10,
	-1, -1,
	CLOSEWINDOW,
	WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH | SMART_REFRESH | ACTIVATE,
	NULL, NULL,
	"Ing!",
	NULL, NULL,
	0, 0, 0, 0,
	WBENCHSCREEN
};


struct wlist {
	struct wlist *next, *prev;
	struct BitMap bitmap;
	long sizx, sizy;
	int maxx, maxy;
	int x, y, dx, dy;
	int maxdy;
};


struct Screen	*scr, *wb;
struct Window	*win;
struct BitMap	*bm1, bm2, barmap;
struct wlist	*listbase;
void		*IntuitionBase, *GfxBase;


main ()
{
	struct Window		*wbwin;
	struct ViewPort		*svp;
	register struct BitMap	*abm;
	struct BitMap		*wbbm, **vbm;
	register struct wlist	*this = NULL;
	struct wlist		*new;
	long			wide, high, barhigh, wbhigh;
	int			i;
	void			*msg;

	openstuff ();
	rnd ((short) -VBeamPos());
	wb = win -> WScreen;	/*  Workbench screen  */
	wbbm = wb -> RastPort.BitMap;
	scrdef.LeftEdge = wb -> LeftEdge;
	scrdef.TopEdge	= wb -> TopEdge;
	scrdef.Width	= wb -> Width;
	scrdef.Height	= wbhigh = wb -> Height;

	/*  Scan all windows in workbench screen  */
	for (wbwin = wb -> FirstWindow; wbwin; wbwin = wbwin -> NextWindow) {
		if (wbwin->Flags & BACKDROP && wbwin->Flags & WBENCHWINDOW) {
			scrdef.DefaultTitle = wbwin -> ScreenTitle;
			continue;
		}

		if (wbwin -> Height > wbhigh-21)
			continue;	/*  too tall, no fun  */
		if (wbwin -> Width > wb->Width - 40)
			continue;	/*  too wide, no fun  */

		/*  Allocate new entry in list  */
		if (!(new = malloc (sizeof (*new))))
			die ("malloc failed.");
		new -> prev = this;
		new -> next = NULL;
		if (this)
			this -> next = new;
		listbase = new;

		/*  Grab necessary info  */
		wide = new -> sizx = wbwin -> Width;
		high = new -> sizy = wbwin -> Height;
		new -> maxx = wb -> Width - wide;
		new -> maxy = wb -> Height - high;
		new -> x = wbwin -> LeftEdge;
		new -> y = wbwin -> TopEdge;
		new -> dx = new -> dy = 0;

		/*
		 * Compute maximum initial vertical velocity.
		 * (Do you know how long it took me to arrive at this
		 * formula?)
		 * Note:  If gravity is anything other than one, this
		 * formula falls apart.
		 */
		new -> maxdy = sqrt (2 * new->maxy + 0.25) - 0.5 + 1.0;

		/*  Create bitmap and copy window into it  */
		InitBitMap (&new -> bitmap, (long) DEPTH, wide, high);
		for (i=0; i<DEPTH; i++)
		if (!(new -> bitmap.Planes[i] = AllocRaster (wide, high)))
			die ("AllocRaster failed.");

		WindowToFront (wbwin);	/*  WindowToFront() doesn't happen  */
		Delay (5L);		/*  immediately, so wait.  */
		BltBitMap
		 (wbbm, (long) wbwin -> LeftEdge, (long) wbwin -> TopEdge,
		  &new -> bitmap, 0L, 0L,
		  wide, high, 0xC0L, 0xffL, NULL);

		this = new;
	}

	/*  All windows scanned and copied, now to do the hard part  */
	scr = OpenScreen (&scrdef);	/*  Clone WorkBench  */
	bm1 = scr -> ViewPort.RasInfo -> BitMap;
	svp = &scr -> ViewPort;

	/*  Make second set of bitplanes for double buffering  */
	wide = wb -> Width;
	InitBitMap (&bm2, (long) DEPTH, wide, wbhigh);
	for (i=0; i<DEPTH; i++)
		if (!(bm2.Planes[i] = AllocRaster (wide, wbhigh)))
			die ("AllocRaster 2 failed.");
	BltBitMap
	 (bm1, 0L, 0L, &bm2, 0L, 0L, wide, wbhigh, 0xc0L, 0xffL, NULL);

	/*  Create private bitmap to hold screen title bar  */
	barhigh = wb -> BarHeight;
	InitBitMap (&barmap, (long) DEPTH, wide, barhigh);
	for (i=0; i<DEPTH; i++)
		if (!(barmap.Planes[i] = AllocRaster (wide, barhigh)))
			die ("AllocRaster 3 failed.");
	BltBitMap
	 (bm1, 0L, 0L, &barmap, 0L, 0L, wide, barhigh, 0xc0L, 0xffL, NULL);

	i = 0;
	vbm = &scr -> ViewPort.RasInfo -> BitMap;
	abm = &bm2;
	while (1) {
		/*  Copy screen bar  */
		BltBitMap (&barmap, 0L, 0L,
			   abm, 0L, 0L,
			   wide, barhigh, 0xc0L, 0xffL, NULL);
		/*  Clear rest of screen  */
		BltBitMap (abm, 0L, 0L,
			   abm, 0L, barhigh,
			   wide, wbhigh-barhigh, 0L, 0xffL, NULL);

		/*  Scan window copies backwards  */
		for (this = listbase; this; this = this -> prev) {
			if ((this -> x += this -> dx) > this -> maxx) {
				this -> x = this->maxx * 2 - this->x;
				this -> dx = -this -> dx;
			} else if (this -> x < 0) {
				this -> x = -this -> x;
				this -> dx = -this -> dx;
			}

			if ((this -> y += this -> dy) > this -> maxy) {
				this -> y = this -> maxy;
				this -> dy = -rnd (this->maxdy - 4) - 4;
				this -> dx = rnd (31) - 15;
			} else
				this -> dy++;

			/*  Copy window image  */
			BltBitMap
			 (&this -> bitmap, 0L, 0L,
			  abm, (long) this -> x, (long) this -> y,
			  this -> sizx, this -> sizy, 0xc0L, 0xffL, NULL);
		}

		/*
		 * This is the hairy part.  I've tried to arrange things so
		 * that there will be a minimum of hashing, but under certain
		 * phases of the moon, it's unavoidable.  Sorry.
		 */
		Forbid ();
		if (i) {	/*  Ping  */
			*vbm = bm1;
			abm = &bm2;
		} else {	/*  Pong  */
			*vbm = &bm2;
			abm = bm1;
		}
		i = !i;
		/*  Surprise!  Intuition doesn't mind this!  */
		ScrollVPort (svp);
		Permit ();

		if (msg = GetMsg (win -> UserPort)) {
			ReplyMsg (msg);
			break;
		}
		WaitTOF ();
	}

	/*  Restore the original  */
	Forbid ();
	*vbm = bm1;
	ScrollVPort (svp);	/*  Ping!  */
	Permit ();

	closestuff ();
}


openstuff ()
{
	if (!(IntuitionBase = OpenLibrary ("intuition.library", 0L))) {
		printf ("Intuition missing.\n");
		exit (100);
	}

	if (!(GfxBase = OpenLibrary ("graphics.library", 0L))) {
		printf ("Art shop closed.\n");
		closestuff ();
		exit (100);
	}

	if (!(win = OpenWindow (&windef))) {
		printf ("Window painted shut.\n");
		closestuff ();
		exit (100);
	}
}

die (str)
char *str;
{
	puts (str);
	closestuff ();
	exit (100);
}

closestuff ()
{
	register int i;

	for (i=0; i<DEPTH; i++) {
		if (barmap.Planes[i])
			FreeRaster (barmap.Planes[i],
				    (long) wb->Width, (long) wb->BarHeight);
		if (bm2.Planes[i])
			FreeRaster (bm2.Planes[i],
			 	    (long) wb->Width, (long) wb->Height);
	}

	if (listbase)		freelist ();
	if (scr)		CloseScreen (scr);
	if (win)		CloseWindow (win);
	if (GfxBase)		CloseLibrary (GfxBase);
	if (IntuitionBase)	CloseLibrary (IntuitionBase);
}

freelist ()
{
	register struct wlist *this = listbase, *tmp;
	register int i;

	while (this) {
		for (i=0; i<DEPTH; i++)
			if (this -> bitmap.Planes[i])
				FreeRaster (this -> bitmap.Planes[i],
					    this -> sizx, this -> sizy);
		tmp = this;
		this = this -> prev;
		free (tmp);
	}
}
SHAR_EOF
fi
if test -f 'rnd.s'
then
	echo shar: "will not over-write existing file 'rnd.s'"
else
cat << \SHAR_EOF > 'rnd.s'
*\
*  :ts=8
* Yet Another random number generator.  By Leo Schwab.
* Based on an idea posted on the USENET (Thanks, Sam Dicker!)
* For the Manx assembler.
*
* Calling convention:
*  short rnd (range);
*  short range;
*
* 8606.30
*/

		public    _rnd

_rnd		lea	rndseed,a0	Get address of seed
		move.w	4(sp),d1	Get range argument
		tst.w	d1
		ble.s	setseed		Go reset seed


		move.l	(a0),d0		Get seed
		ADD.L   D0,D0
		BHI.S   over
		EORI.L  #$1D872B41,D0
over
		move.l	d0,(a0)		Save new seed
		andi.l	#$ffff,d0	Coerce into word
		divu	d1,d0		Divide by range
		swap	d0		 and get remainder (modulus)
		rts

setseed		neg.w	d1		Probably don't need this
		move.l	d1,(a0)
		rts

		dseg
rndseed		dc.l	0
		cseg
SHAR_EOF
fi
exit 0
#	End of shell archive

ali@navajo.UUCP (02/06/87)

Keywords:

In article <2526@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes:
>	Welcome to Ing, the next logical step in Boing-type display hacks.
I like it. As much as oing!

>.. To stop the program, go back to the Workbench screen and click on Ing's
>close gadget.
I think you should've required the user to click on the close gadget of the
COPY of the Ing! window to end the program. Now *that* would've been some
game.

>	I'm a bit disappointed at the performance...
Oh, it seems fast enough. Watching it for a few minutes makes me dizzy,
and any faster would've been worse!

Anyway, thanks Leo, for yet another display hack.

Ali Ozer, ali@navajo.stanford.edu