
/*
 *  MAIN.C
 *
 *  Bulging Bubbles Demo
 */

#include "bubbles.h"

TA Ta = { (ubyte *)"topaz.font", 8 };

NS Ns = {
    0, 0, 640, 200, 2, 0, 1,
    HIRES, CUSTOMSCREEN|SCREENQUIET, &Ta, (ubyte *)"", NULL, NULL
};

NW Nw = {
    0, 2, 64, 32, -1, -1,
    CLOSEWINDOW,
    WINDOWCLOSE|SIMPLE_REFRESH|BORDERLESS|NOCAREREFRESH|RMBTRAP,
    NULL,NULL,NULL,NULL,NULL,16,16,-1,-1,CUSTOMSCREEN
};

OBJECT *Grid;
OBJECT *Ball;

WIN *Win;
SCR *Scr;
RP  *Rp;

long S_width, S_height, S_midwidth, S_dblheight;

main(ac,av)
char *av[];
{
    IMESS *imess;
    SCR Screen;

    if (ac <= 1) {
	init_grid();
	init_ball();
    } else {
	init_file(av[1]);
    }
    init_objectmodule();
    init_bounce();
    openlibs(INTUITION_LIB|GRAPHICS_LIB);
    GetScreenData(&Screen, sizeof(Screen), WBENCHSCREEN, NULL);
    Ns.Width = Screen.Width;
    Ns.Height= Screen.Height;
    if (Scr = OpenScreen(&Ns)) {
	S_width = Scr->Width;
	S_height= Scr->Height;
	S_midwidth = S_width >> 1;
	S_dblheight= S_height<< 1;
	SetRGB4(&Scr->ViewPort,0, 0, 0, 0);
	SetRGB4(&Scr->ViewPort,3, 5, 5, 15);
	Nw.Screen = Scr;
	if (Win = OpenWindow(&Nw)) {
	    Rp = &Scr->RastPort;
	    for (;;) {
		bounce_ball();
		toggle_rport();
		displayobj(Rp,Grid);
		displayobj(Rp,Ball);
		if (imess = GetMsg(Win->UserPort))
		    break;
	    }
	    ReplyMsg(imess);
	    CloseWindow(Win);
	}
	CloseScreen(Scr);
    }
    closelibs(-1);
}

toggle_rport()
{
    if (Rp->Mask & 1) {
	SetRGB4(&Scr->ViewPort,1, 5, 5, 15);
	SetRGB4(&Scr->ViewPort,2, 0, 0, 0);
	Rp->Mask = 0x02;
	SetAPen(Rp,2);
    } else {
	SetRGB4(&Scr->ViewPort,2, 5, 5, 15);
	SetRGB4(&Scr->ViewPort,1, 0, 0, 0);
	Rp->Mask = 0x01;
	SetAPen(Rp,1);
    }
    WaitTOF();
    SetRast(Rp,0);
}

/*
 *  Create two objects:
 *	(1) A stationary grid	    Z=0, x/y -32768:65536/4
 *	(2) a ball (cube for now)
 */

init_grid()
{
    static long points[][3] = {
	-PMAXX,-PMAXY,0,      /* Border   */
	 PMAXX,-PMAXY,0,
	 PMAXX, PMAXY,0,
	-PMAXX, PMAXY,0,

	-0x0400,0x0700,0x0E00,
	-0x0280,0x0700,0x0E00,
	-0x0100,0x0700,0x0E00,
	-0x0D00,-0x0700,0,
	-0x0B80,-0x0700,0,
	-0x0A00,-0x0700,0,
	-0x1000,-0x0300,0x0400,
	-0x0E80,-0x0300,0x0400,
	-0x0D00,-0x0300,0x0400,
	-0x0C80,-0x05E0,0x0110,
	-0x0BC0,-0x0510,0x01F0,  /*  14  */
	-0x0900,-0x0700,0,
	-0x0400,0,0x700,
	-0x0300,-0x0700,0,
	-0x0610,-0x0300,0x0400,
	-0x0390,-0x0300,0x0400,
	-0x0200,-0x0700,0,
	-0x0100,0,0x0700,	 /*  21  */
	0x0100,-0x0300,0x0400,
	0x0400,0,0x0700,
	0x0300,-0x0700,0,
	0x0500,-0x0700,0,	    /*	25.. I	*/
	0x0700,-0x0700,0,
	0x0900,-0x0700,0,
	0x0500,0,0x0700,
	0x0700,0,0x0700,
	0x0900,0,0x0700,
	0x0D00,-0x0100,0x0600,
	0x0C00,0,0x0700,
	0x0A00,0,0x0700,
	0x0980,-0x0400,0x0300,
	0x0A00,-0x0700,0,
	0x0D00,-0x0700,0,
	0x0D00,-0x0500,0x0200,
	0x0C00,-0x0500,0x0200,
	0x0E00,-0x0700,0,
	0x0F80,-0x0300,0x0400,
	0x1100,0,0x0700,
	0x1200,-0x0300,0x0400,
	0x1300,-0x0700,0
    };
    static short connect[][2] = {
	0,1, 1,2, 2,3, 3,0,
	4,5, 5,6, 4,7, 5,8, 6,9, 9,8, 8,7, 7,10, 10,11, 11,13, 13,14, 14,12, 12,11,
	15,18, 18,16, 16,19, 19,17, 18,19,  /* A */
	20,21, 21,22, 22,23, 23,24,	    /* M */
	28,29, 29,30, 29,26, 25,26, 26,27,  /* I */
	31,32, 32,33, 33,34, 34,35, 35,36, 36,37, 37,38,    /* G */
	39,40, 40,41, 41,42, 42,43, 40,42
    };
    Grid = makeobject(
	points , sizeof(points)/sizeof(points[0]),
	connect, sizeof(connect)/sizeof(connect[0]),
	0,0,0
    );
}

init_ball()
{
    static long points[][3] = {
	-PSKIP/5 ,-PSKIP/5 , 0,
	 PSKIP/5 ,-PSKIP/5 , 0,
	 PSKIP/5 , PSKIP/5 , 0,
	-PSKIP/5 , PSKIP/5 , 0,
	-PSKIP/5 ,-PSKIP/5 , PSKIP*2/5,
	 PSKIP/5 ,-PSKIP/5 , PSKIP*2/5,
	 PSKIP/5 , PSKIP/5 , PSKIP*2/5,
	-PSKIP/5 , PSKIP/5 , PSKIP*2/5
    };
    static short connect[][2] = {
	0,1,1,2,2,3,3,0,
	4,5,5,6,6,7,7,4,
	0,4,1,5,2,6,3,7,
	0,6,1,7,2,4,3,5
    };

    Ball = makeobject(
	points , sizeof(points)/sizeof(points[0]),
	connect, sizeof(connect)/sizeof(connect[0]),
	0,0,0
    );
}

/*
 *  FILE FORMAT:
 *	<blankline>		     ignored
 *	# comment		    -comment
 *	DB numpoints numconnect     -begin ball definition
 *	DG numpoints numconnect     -begin grid definition
 *	P  X Y Z		    -define points (index begins at 0)
 *	C  A B			    -define line segments
 *	END			    -end of def.
 */

init_file(name)
char *name;
{
    FILE *fi = fopen(name,"r");
    char buf[256];

    if (fi == NULL) {
	puts("File not found");
	exit(1);
    }
    while (fgets(buf,256,fi)) {
	if (buf[0] == 'D') {
	    OBJECT **which;
	    long *points;
	    uword *connect;
	    long npts, ncon, ip, ic, c1, c2;

	    which = (buf[1] == 'B') ? &Ball : &Grid;
	    if (sscanf(buf+2,"%ld %ld", &npts, &ncon) != 2) {
		puts("Illegal format");
		exit(1);
	    }
	    points  = (long *)malloc(sizeof(long) * 3 * npts);
	    connect = (uword *)malloc(sizeof(short) * 2 * ncon);
	    ip = ic = 0;
	    while (fgets(buf,256,fi)) {
		switch(buf[0]) {
		case 'P':
		    if (ip >= npts) {
			puts("Beyond specified parameters");
			exit(1);
		    }
		    sscanf(buf+1,"%ld %ld %ld", &points[ip*3], &points[ip*3+1], &points[ip*3+2]);
		    ++ip;
		    break;
		case 'C':
		    if (ic >= ncon) {
			puts("Beyond specified parameters");
			exit(1);
		    }
		    sscanf(buf+1,"%ld %ld", &c1, &c2);
		    connect[ic*2] = c1;
		    connect[ic*2+1]=c2;
		    ++ic;
		    break;
		case 'E':
		    *which = makeobject(points,ip,connect,ic,0,0,0);
		    goto br2;
		}
	    }
br2:	    ;
	}
    }
    fclose(fi);
    if (!Ball)
	init_ball();
    if (!Grid)
	init_grid();
}


/*
 *  Bounce the ball within the domain (-PMAX,-PMAX,0) to (PMAX,PMAX,PMAX)
 *	-uniform Z deceleration
 *	-Z < 0 bounce + random acceleration load
 *
 *	-Camera attempts to match ball but is allowed only uniform
 *	 acceleration
 *
 *	-My position attempts to match camera but is allow only uniform
 *	 acceleration which is less than that for camera
 *
 *  Ball velocity clamped at 100
 */

long Bx,By,Bz,BAx,BAy,BAz,BVx,BVy,BVz;	/*  The Ball		*/
long Cx,Cy,Cz,CAx,CAy,CAz,CVx,CVy,CVz;	/*  Camera center pt	*/
long Mx,My,Mz,MAx,MAy,MAz,MVx,MVy,MVz;	/*  My position 	*/

init_bounce()
{
    Mx = My = Mz = 16384;
    BVx = 123;
    BVy = -56;
}

bounce_ball()
{
    BAz = -10;
    BVx += BAx; if (BVx > CLAMP) BVx = CLAMP; if (BVx < -CLAMP) BVx = -CLAMP;
    BVy += BAy; if (BVy > CLAMP) BVy = CLAMP; if (BVy < -CLAMP) BVy = -CLAMP;
    BVz += BAz; if (BVz > CLAMP) BVz = CLAMP; if (BVz < -CLAMP) BVz = -CLAMP;
    Bx += BVx;	if (Bx < -PMAXX|| Bx > PMAXX) { BVx = -BVx; Bx += 2*BVx; }
    By += BVy;	if (By < -PMAXY|| By > PMAXY) { BVy = -BVy; By += 2*BVy; }
    Bz += BVz;	if (Bz >  PMAXZ 	    ) { BVz = -BVz; Bz += 2*BVz; }
    if (Bz < 0) {
	/*  Elastic bounce plus boost	*/
	BVz = -BVz + (ran()&0xFFFF)%200;
	if (BVz > 300)
	    BVz = 250;
    }
    Ball->x = Bx;
    Ball->y = By;
    Ball->z = Bz;

    {
	uword theta,phi;
	short result;

	theta = ibearing(Bx-Cx,By-Cy);
	phi =	ibearing(irange(Bx-Cx,By-Cy),Bz-Cz);
	result = ICOS(phi);
	CAx += (5 * ((ICOS(theta) * result)>>15)) >> 15;
	CAy += (5 * ((ISIN(theta) * result)>>15)) >> 15;
	CAz += (5 * ISIN(phi)) >> 15;
    }
    {
	uword theta,phi;
	short result;

	theta = ibearing(Cx-Mx,Cy-My);
	phi =	ibearing(irange(Cx-Mx,Cy-My),Cz-Mz);
	result = ICOS(phi);
	MAx = (10 * ((ICOS(theta) * result)>>15)) >> 15;
	MAy = (10 * ((ISIN(theta) * result)>>15)) >> 15;
	MAz = (10 * ISIN(phi)) >> 15;
    }
    MVx += MAx; Mx += MVx;
    MVy += MAy; My += MVy;
    MVz += MAz; Mz += MVz;
    CVx += CAx; Cx += CVx;
    CVy += CAy; Cy += CVy;
    CVz += CAz; Cz += CVz;

    if (CAx > ACLAMP)CAx =ACLAMP; if (CAx < -ACLAMP)CAx = -ACLAMP;
    if (CAy > ACLAMP)CAy =ACLAMP; if (CAy < -ACLAMP)CAy = -ACLAMP;
    if (CAz > ACLAMP)CAz =ACLAMP; if (CAz < -ACLAMP)CAz = -ACLAMP;
    if (CVx > CCLAMP) CVx = CCLAMP; if (CVx < -CCLAMP) CVx = -CCLAMP;
    if (CVy > CCLAMP) CVy = CCLAMP; if (CVy < -CCLAMP) CVy = -CCLAMP;
    if (CVz > CCLAMP) CVz = CCLAMP; if (CVz < -CCLAMP) CVz = -CCLAMP;

    if (MAx > ACLAMP)MAx =ACLAMP; if (MAx < -ACLAMP)MAx = -ACLAMP;
    if (MAy > ACLAMP)MAy =ACLAMP; if (MAy < -ACLAMP)MAy = -ACLAMP;
    if (MAz > ACLAMP)MAz =ACLAMP; if (MAz < -ACLAMP)MAz = -ACLAMP;
    if (MVx > CCLAMP) MVx = CCLAMP; if (MVx < -CCLAMP) MVx = -CCLAMP;
    if (MVy > CCLAMP) MVy = CCLAMP; if (MVy < -CCLAMP) MVy = -CCLAMP;
    if (MVz > CCLAMP) MVz = CCLAMP; if (MVz < -CCLAMP) MVz = -CCLAMP;

    setcamera(Mx, My, Mz, Cx, Cy, Cz, 0);
}

