
/*
 *  OBJECT.C
 *
 */

#include "bubbles.h"

extern long S_width, S_height, S_midwidth, S_dblheight;

static uword maxpts, maxcon;

static long X,Y,Z;
static long CX,CY,CZ;
static short Cost, Cosp, Sint, Sinp, CostCosp, CospSint, SintSinp, SinpCost;
static long *Scrx, *Scry, *Scrz;
static uword CTheta, CPhi;

OBJECT *
makeobject(pts, npts, con, ncon, x, y, z)
long *pts;
uword *con;
{
    register OBJECT *obj = malloc(sizeof(OBJECT));
    register short i;

    obj->points = pts;
    obj->connect= con;
    obj->npts = npts;
    obj->ncon = ncon;
    obj->x = x;
    obj->y = y;
    obj->z = z;
    obj->theta = obj->phi = obj->rot = 0;

    if (npts > maxpts)	maxpts = npts;
    if (ncon > maxcon)	maxcon = ncon;

    return(obj);
}

init_objectmodule()
{
    Scrx = malloc(sizeof(long) * (maxpts+1));
    Scry = malloc(sizeof(long) * (maxpts+1));
    Scrz = malloc(sizeof(long) * (maxpts+1));
}

setcamera(x,y,z,cx,cy,cz,rot)
{
    X=x;
    Y=y;
    Z=z;
    CX=cx;
    CY=cy;
    CZ=cz;
    CTheta = ibearing(cx-x,cy-y);
    CPhi   = ibearing(irange(cx-x,cy-y),cz-z);

    Cost = ICOS(CTheta);	/*  returns signed -32767 to 32767  */
    Cosp = ICOS(CPhi);
    Sint = ISIN(CTheta);
    Sinp = ISIN(CPhi);
    CostCosp = (Cost * Cosp) >> 15;
    CospSint = (Cosp * Sint) >> 15;
    SintSinp = (Sint * Sinp) >> 15;
    SinpCost = (Sinp * Cost) >> 15;
}

setcamerad(x,y,z,cx,cy,cz,rot)
{
    setcamera(X+x,Y+y,Z+z,CX+cx,CY+cy,CZ+cz,rot);
}


displayobj(rp,obj)
RP *rp;
OBJECT *obj;
{
    register long x,y,z;
    register long *scrx,*scry,*scrz;
    short i;
    long *p;
    long dx,dy,dz;

    dx = obj->x - X;
    dy = obj->y - Y;
    dz = obj->z - Z;
    scrx = Scrx;
    scry = Scry;
    scrz = Scrz;

    for (p = obj->points, i = obj->npts; i; --i, p += 3,++scrx,++scry,++scrz) {

	/*
	 *  Transform to center
	 */

	x = p[0]+dx;
	y = p[1]+dy;
	z = p[2]+dz;

	/*
	 *  Align with Z access pointing ahead (Z>0 is visible). X heading
	 *  to the right, Y heading up
	 */

	scrz[0] = (((short)x * CostCosp)>>15) + (((short)y * CospSint)>>15) + (((short)z * Sinp)>>15);
	scrx[0] = -((((short)y * Cost)>>15) - (((short)x * Sint)>>15));
	scry[0] = -(((short)x * SinpCost)>>15) - (((short)y * SintSinp)>>15) + (((short)z * Cosp)>>15);

	/*
	 *  Add Perspective approximation.
	 */

	if (scrz[0] > 0) {
	    scrx[0] = (scrx[0] << 8) / (scrz[0] + 256);
	    scry[0] = (scry[0] << 8) / (scrz[0] + 256);
	} else {
	    scrx[0] = (scrx[0] * (-scrz[0] + 256)) >> 8;
	    scry[0] = (scry[0] * (-scrz[0] + 256)) >> 8;
	}
    }
    connect(rp,obj->connect,obj->ncon);
}

connect(rp,connect,ncon)
register uword *connect;
{
    register long x1,y1,z1;
    register long x2,y2,z2;
    for (; ncon; --ncon, connect += 2) {
	x1 = S_midwidth+Scrx[connect[0]];  x2 = S_midwidth+Scrx[connect[1]];
	y1 = S_height-Scry[connect[0]]	;  y2 = S_height-Scry[connect[1]];
	z1 = Scrz[connect[0]];	    z2 = Scrz[connect[1]];

	if (z1 < 0 && z2 < 0)
	    continue;
	if (z1 < 0) {	    /*	Calculate x & y intercept with window	*/
	    x1 -= z1 * (x2 - x1) / (z2 - z1);
	    y1 -= z1 * (y2 - y1) / (z2 - z1);
	}
	if (z2 < 0) {
	    x2 -= z2 * (x1 - x2) / (z1 - z2);
	    y2 -= z2 * (y1 - y2) / (z1 - z2);
	}

	if (y1 < 0) {		/*  CLIP PT A	*/
	    if (y2 <= 0)
		continue;
	    x1 += y1 * (x2 - x1) / (y1 - y2);
	    y1 = 0;
	} else
	if (y1 >= S_dblheight) {
	    if (y2 >= S_dblheight)
		continue;
	    x1 += (y1 - S_dblheight) * (x2 - x1) / (y1 - y2);
	    y1 = S_dblheight-1;
	}
	if (x1 < 0) {
	    if (x2 <= 0)
		continue;
	    y1 += x1 * (y2 - y1) / (x1 - x2);
	    x1 = 0;
	} else
	if (x1 >= S_width) {
	    if (x2 >= S_width)
		continue;
	    y1 += (x1 - S_width) * (y2 - y1) / (x1 - x2);
	    x1 = S_width-1;
	}
	if (y2 < 0) {		/*  CLIP PT B	*/
	    if (y1 <= 0)
		continue;
	    x2 += y2 * (x1 - x2) / (y2 - y1);
	    y2 = 0;
	} else
	if (y2 >= S_dblheight) {
	    if (y1 >= S_dblheight)
		continue;
	    x2 += (y2 - S_dblheight) * (x1 - x2) / (y2 - y1);
	    y2 = S_dblheight-1;
	}
	if (x2 < 0) {
	    if (x1 <= 0)
		continue;
	    y2 += x2 * (y1 - y2) / (x2 - x1);
	    x2 = 0;
	} else
	if (x2 >= S_width) {
	    if (x1 >= S_width)
		continue;
	    y2 += (x2 - S_width) * (y1 - y2) / (x2 - x1);
	    x2 = S_width-1;
	}

	if (x1 < 0 || x1 >= S_width || y1 < 0 || y1 >= S_dblheight ||
	    x2 < 0 || x2 >= S_width || y1 < 0 || y2 >= S_dblheight) {
	    printf("Softerror: %ld %ld %ld %ld\n", x1, y1>>1, x2, y2>>1);
	} else {
	    static long lastx,lasty;
	    if ((lastx != x1) || (lasty != y1))
		Move(rp,x1,y1>>1);
	    Draw(rp,x2,y2>>1);
	    lastx = x2;
	    lasty = y2;
	}
    }
}

