/*
 *  			D R A W S O L . C
 *
 * Functions -
 *  	draw_arb8	draw an ARB8
 *  	draw_ell	draw an ELLipsoid
 *  	draw_tor	draw a TORoid
 *  	draw_tgc	draw a Truncated General Cone
 *  
 *  Author -
 *	Michael John Muuss
 *  
 *  Source -
 *	SECAD/VLD Computing Consortium, Bldg 394
 *	The U. S. Army Ballistic Research Laboratory
 *	Aberdeen Proving Ground, Maryland  21005
 *  
 *  Copyright Notice -
 *	This software is Copyright (C) 1985 by the United States Army.
 *	All rights reserved.
 */
#ifndef lint
static char RCSid[] = "@(#)$Header: drawsol.c,v 2.2 85/08/07 05:18:43 mike Exp $ (BRL)";
#endif

#include <math.h>
#include <stdio.h>
#include "./machine.h"	/* special copy */
#include "../h/vmath.h"
#include "../h/db.h"
#include "ged.h"
#include "dm.h"

static void	edraw(), face();

void	draw_arb8(), draw_tgc(), draw_ell(), draw_tor();

/*
 *  			D R A W _ A R B 8
 *
 * Draw an ARB8, which is represented as a vector
 * from the origin to the first point, and 7 vectors
 * from the first point to the remaining points.
 */
void
draw_arb8( origp, matp )
struct solidrec *origp;
register matp_t matp;
{
	register int i;
	register float *ip;
	register float *op;
	static vect_t work;
	static struct solidrec sr;

	/* Because we will modify the values, make a private copy */
	sr = *origp;		/* struct copy */
	
	/*
	 * Convert from vector to point notation for drawing.
	 */
	MAT4X3PNT( &sr.s_values[0], matp, &origp->s_values[0] );

	ip = &origp->s_values[1*3];
	op = &sr.s_values[1*3];
	for( i=1; i<8; i++ )  {
		VADD2( work, &origp->s_values[0], ip );
		MAT4X3PNT( op, matp, work );
		ip += 3;
		op += 3;
	}

	face( sr.s_values, 0, 1, 2, 3 );
	face( sr.s_values, 4, 0, 3, 7 );
	face( sr.s_values, 5, 4, 7, 6 );
	face( sr.s_values, 1, 5, 6, 2 );
}

/*
 *			F A C E
 *
 * This routine traces one face of an ARB8
 */
static void
face( valp, a, b, c, d )
register float *valp;
{
	DM_GOTO( &valp[a*3], PEN_UP );
	DM_GOTO( &valp[b*3], PEN_DOWN );
	DM_GOTO( &valp[c*3], PEN_DOWN );
	DM_GOTO( &valp[d*3], PEN_DOWN );
}

/* Names for GENELL fields */
#define VELL	&sr.s_values[0]
#define AELL	&sr.s_values[3]
#define BELL	&sr.s_values[6]
#define CELL	&sr.s_values[9]

/*
 *  			D R A W _ E L L
 */
void
draw_ell( origp, matp )
struct solidrec *origp;
register matp_t matp;
{
	register int i;
	register float *op;	/* Used for scanning vectors */
	register float *ip;
	float top[16*3];
	float middle[16*3];
	float bottom[16*3];
	static struct solidrec sr;	/* local copy of the solid record */

	/* copy the original */
	sr = *origp;

	/*
	 * Rotate, translate, and scale the V point.
	 * Simply rotate and scale the A, B, and C vectors.
	 */


	MAT4X3PNT( &sr.s_values[0], matp, &origp->s_values[0] );

	ip = &origp->s_values[1*3];
	op = &sr.s_values[1*3];
	for(i=1; i<4; i++) {
		MAT4X3VEC( op, matp, ip );
		op += 3;
		ip += 3;
	}


	ellipse( top, VELL, AELL, BELL );
	ellipse( bottom, VELL, BELL, CELL );
	ellipse( middle, VELL, AELL, CELL );

	edraw( top );
	edraw( bottom );
	edraw( middle );
}

/* Names for TORUS fields */
#define F1 	&sr.s_values[0]
#define F2	&sr.s_values[3]
#define F3	&sr.s_values[6]
#define F4	&sr.s_values[9]
#define F5	&sr.s_values[12]
#define F6	&sr.s_values[15]
#define F7	&sr.s_values[18]
#define F8	&sr.s_values[21]

/*
 *  			D R A W _ T O R
 *
 * The TORUS has the following input fields:
 *	F1	V from origin to center
 *	F2	Radius Vector, Normal to plane of torus
 *	F3,F4	perpindicular, to CENTER of torus (for top, bottom)
 *	F5,F6	perpindicular, for inner edge
 *	F7,F8	perpindicular, for outer edge
 *
 * The following ellipses have to be constructed:
 *	C1	top ellipse
 *	C2	bottom ellipse
 *	C3	inner ellipse
 *	C4	outer ellipse
 */
void
draw_tor( origp, matp )
struct solidrec *origp;
register matp_t matp;
{
	register int i;
	register float *op;
	register float *ip;
	float C1[16*3];
	float C2[16*3];
	float C3[16*3];
	float C4[16*3];
	static vect_t	tempv;		/* Torus vector addition area */
	static struct solidrec sr;	/* copy of original */

	/* copy the original */
	sr = *origp;

	/*
	 * Rotate, translate, and scale the V point.
	 * All other vectors are merely scaled and translated.
	 */
	MAT4X3PNT( &sr.s_values[0], matp, &origp->s_values[0] );

	ip = &origp->s_values[1*3];
	op = &sr.s_values[1*3];
	for(i=1; i<8; i++)  {
		MAT4X3VEC( op, matp, ip );
		op += 3;
		ip += 3;
	}

	VADD2(tempv,F1,F2);	/* center point of TOP */
	ellipse(C1,tempv,F3,F4);	/* top */

	VSUB2(tempv,F1,F2);
	ellipse(C4,tempv,F3,F4);	/* bottom */
 
	ellipse(C2,F1,F5,F6);	/* inner */
	ellipse(C3,F1,F7,F8);	/* outer */
 
	edraw(C1);
	edraw(C2);
	edraw(C3);
	edraw(C4);

	DM_GOTO(&C1[0*3],PEN_UP);
	DM_GOTO(&C2[0*3],PEN_DOWN);
	DM_GOTO(&C4[0*3],PEN_DOWN);
	DM_GOTO(&C3[0*3],PEN_DOWN);
	DM_GOTO(&C1[0*3],PEN_DOWN);
 
	DM_GOTO(&C1[4*3],PEN_UP);
	DM_GOTO(&C2[4*3],PEN_DOWN);
	DM_GOTO(&C4[4*3],PEN_DOWN);
	DM_GOTO(&C3[4*3],PEN_DOWN);
	DM_GOTO(&C1[4*3],PEN_DOWN);

	DM_GOTO(&C1[8*3],PEN_UP);
	DM_GOTO(&C2[8*3],PEN_DOWN);
	DM_GOTO(&C4[8*3],PEN_DOWN);
	DM_GOTO(&C3[8*3],PEN_DOWN);
	DM_GOTO(&C1[8*3],PEN_DOWN);
 
	DM_GOTO(&C1[12*3],PEN_UP);
	DM_GOTO(&C2[12*3],PEN_DOWN);
	DM_GOTO(&C4[12*3],PEN_DOWN);
	DM_GOTO(&C3[12*3],PEN_DOWN);
	DM_GOTO(&C1[12*3],PEN_DOWN);
}

/* Names for TGC fields */
#define VVAL	&sr.s_values[0]
#define HVAL	&sr.s_values[3]
#define AVAL	&sr.s_values[6]
#define BVAL	&sr.s_values[9]
#define CVAL	&sr.s_values[12]
#define DVAL	&sr.s_values[15]

/*
 *  			D R A W _ T G C
 *
 * Draw a generalized cone (TGC)
 *
 * Rotate, translate, & scale the V point.
 * (V is from the origin to the base of the cone).
 * The rest (H, A, B, C, D) are all relative to V or V+H
 */
void
draw_tgc( origp, matp )
struct solidrec *origp;
register matp_t matp;
{
	register int i;
	register float *op;	/* Used for scanning vectors */
	register float *ip;
	float top[16*3];
	float bottom[16*3];
	static vect_t	work;		/* Vector addition work area */
	static struct solidrec sr;	/* copy of original record */

	sr = *origp;	/* copy original record */

	MAT4X3PNT( &sr.s_values[0], matp, &origp->s_values[0] );

	ip = &origp->s_values[1*3];
	op = &sr.s_values[1*3];
	for( i=1; i<6; i++ )  {
		MAT4X3VEC( op, matp, ip );
		op += 3;
		ip += 3;
	}

	ellipse( bottom, VVAL, AVAL, BVAL );
	VADD2( work, VVAL, HVAL );
	ellipse( top, work, CVAL, DVAL );

	/* Draw the top */
	edraw( top );

	/* Draw the bottom */
	edraw( bottom );

	/* Draw connections */
	for( i=0; i<16; i += 4 )  {
		DM_GOTO( &top[i*3], PEN_UP );
		DM_GOTO( &bottom[i*3], PEN_DOWN );
	}
}

/*
 *			E D R A W
 *
 * Trace out the edge of an ellipse.
 * This routine was formerly a macro, but was
 * made a subroutine to decrease core use.
 * Efficiency should not suffer much.
 */
static void
edraw( floatp )
register float *floatp;
{
	register int i;

	DM_GOTO( &floatp[15*3], PEN_UP );
	for( i=0; i<16; i++ )  {
		DM_GOTO( floatp, PEN_DOWN );
		floatp += 3;
	}
}
