/* :ts=8 bk=0
*******************************************************************

* Ing.c - Un divertimento da Workbench - Scritto da Leo L. Schwab *

* Programma di pubblico dominio, si prega solo di lasciare i nomi *

**** Tradotto ed adattato a Aztec C V3.6 da Luigi R. Callegari ****

**********  Compilazione: cc Ing +L (interi a 32 bit)   ***********
**********        Linking : ln -lm32 -lc32 Ing          ***********

******************************************************************/

#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,	/* Dimensioni fissate dopo */
	0, 1,
	HIRES,
	CUSTOMSCREEN,
	NULL,
	NULL,			/*  Titolo fissato dopo */
	NULL, NULL
};

struct NewWindow windef = {
	0, 30, 150, 10,
	-1, -1,
	CLOSEWINDOW,
	WINDOWCLOSE|WINDOWDRAG|WINDOWDEPTH|SMART_REFRESH|ACTIVATE,
	NULL, NULL,
	(UBYTE *)"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;

void 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;

	/*  Scandisce tutte le finestre nel Workbench  */
	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;	/*  troppo piccola, lasciamo */
		if (wbwin -> Width > wb->Width - 40)
			continue;	/*  troppo larga, lasciamo */

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

		/*  Legge informazioni necessarie  */
		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;

		/* Calcolo della max velocita' verticale iniziale.
		Mi ci e' voluto un sacco di tempo per calcolare questa
		formula. Qui a Princeton studio altro...*/

		new -> maxdy = sqrt (2 * new->maxy + 0.25) - 0.5 + 1.0;

		/*  Crea bitmap e vi copia la finestra  */

		InitBitMap (&new -> bitmap, (long) DEPTH, wide, high);
		for (i=0; i<DEPTH; i++)
		if (!(new -> bitmap.Planes[i] = AllocRaster (wide, high)))
			die ("AllocRaster() non funziona!");

		WindowToFront (wbwin);	/*  WindowToFront() non funge  */
		Delay (5L);		/*  subito, quindi aspettiamo  */
		BltBitMap
		 (wbbm, (long) wbwin -> LeftEdge, (long) wbwin -> TopEdge,
		  &new -> bitmap, 0L, 0L,
		  wide, high, 0xC0L, 0xffL, NULL);

		this = new;
	}

	/* Letto e copiato tutte le finestre. Ora c'e' il bello */

	scr = OpenScreen (&scrdef);	/*  Clona il WorkBench  */
	bm1 = scr -> ViewPort.RasInfo -> BitMap;
	svp = &scr -> ViewPort;

	/* Crea secondo insieme di bitplanes per doppio buffer */

	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 ha fallito!");
	BltBitMap
	 (bm1, 0L, 0L, &bm2, 0L, 0L, wide, wbhigh, 0xc0L, 0xffL, NULL);

	/* Crea bitmap privata per conservare barra di titolo schermo */

	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 ha fallito!");
	BltBitMap
	 (bm1, 0L, 0L, &barmap, 0L, 0L, wide, barhigh, 0xc0L, 0xffL, NULL);

	i = 0;
	vbm = &scr -> ViewPort.RasInfo -> BitMap;
	abm = &bm2;
	while (1) {

		/*  Copia barra schermo  */

		BltBitMap (&barmap, 0L, 0L,
			   abm, 0L, 0L,
			   wide, barhigh, 0xc0L, 0xffL, NULL);

		/* Pulisce resto schermo */

		BltBitMap (abm, 0L, 0L,
			   abm, 0L, barhigh,
			   wide, wbhigh-barhigh, 0L, 0xffL, NULL);

		/* Copia finestre scandite all'indietro */

		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++;

			/*  Copia immagine finestra  */

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

		/* Questa e' la parte intrigante. Ho cercato di mantenere
		al minimo lo hashing, ma in certe fasi lunari e' sempre
		inevitabile */

		Forbid ();
		if (i) {	/*  Ping  */
			*vbm = bm1;
			abm = &bm2;
		} else {	/*  Pong  */
			*vbm = &bm2;
			abm = bm1;
		}
		i = !i;

		/*  Sorpresa!  Intuition se ne frega di questo! */

		ScrollVPort (svp);
		Permit ();

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

	/*  Rimetti l'originale  */
	Forbid ();
	*vbm = bm1;
	ScrollVPort (svp);	/*  Ping!  */
	Permit ();

	closestuff ();
}

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

	if (!(GfxBase = OpenLibrary ("graphics.library", 0L))) {
		printf ("Le routines grafiche???\n");
		closestuff ();
		exit (100);
	}

	if (!(win = OpenWindow (&windef))) {
		printf ("La finestra???\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);
	}
}



#asm
*\
*  :ts=8 bk=0
* Un altro generatore di numeri casuali!!! By Leo Schwab
* Grazie a Sam Dicker per l'idea.
* Per assembler Metacomco
*
* Chiamata:
*  long rnd (range);
*  long range;
*
* Assemblaggio con Metacomco
*  df1:c/assem rnd.s -o rnd.o
* 
*/

		blanks off
		section code
		xdef	_rnd

_rnd		lea	rndseed,a0	;Indirizzo deme
		move.l	4(sp),d1	;Gamma argomento
		tst.l	d1
		ble.s	setseed		;Seme di reset


		move.l	(a0),d0		;Legge seme
		ADD.L   D0,D0
		BHI.S   over
		EORI.L  #$1D872B41,D0
over
		move.l	d0,(a0)		;Salva nuovo seme
		andi.l	#$ffff,d0	;Forza in una word
		andi.l	#$ffff,d1
		divu	d1,d0		;Divide per gamma
		swap	d0		; resto (modulo)
		ext.l	d0
		rts

setseed		neg.l	d1		;Probabilmente non necessario
		move.l	d1,(a0)
		rts

		section data
rndseed		dc.l	0
		section code

#endasm

