/*
 *			A R S . C
 *
 * Functions -
 *	draw_ars	draw an ARS
 *	draw_poly	draw polygons
 *
 *  Author -
 *	Michael John Muuss
 *	Paul Stay
 *  
 *  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: ars.c,v 2.3 86/03/10 21:00:50 mike Exp $ (BRL)";
#endif

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

extern void	free();
extern char	*malloc();
extern int	read();
extern long	lseek();

extern int	objfd;		/* from dir.c */

void	draw_ars(), draw_poly();
static float	*rd_curve();

/*
 *  			D R A W _ A R S
 */
/* ARGSUSED */
void
draw_ars( ap, dp, mat )
struct ars_rec *ap;	/* ARS A record pointer */
struct directory *dp;
mat_t mat;
{
	register int	i, j;
	register float **curves;	/* array of curve base addresses */
	static int pts_per_curve;
	static int ncurves;
	static vect_t base_vect;

	ncurves = ap->a_m;
	pts_per_curve = ap->a_n;

	/*
	 * Read all the curves into memory, and store their pointers
	 */
	i = (ncurves+1) * sizeof(float **);
	curves = (float **)malloc( (unsigned)i );
	for( i=0; i < ncurves; i++ )  {
		curves[i] = rd_curve( pts_per_curve );
	}

	/*
	 * Convert from vector to point notation IN PLACE
	 * by rotating vectors and adding base vector.
	 * Observe special treatment for base vector.
	 */
	for( i = 0; i < ncurves; i++ )  {
		register float *v;

		v = curves[i];
		for( j = 0; j < pts_per_curve; j++ )  {
			static vect_t	homog;

			if( i==0 && j == 0 )  {
				VMOVE( homog, v );
				MAT4X3PNT( base_vect, mat, homog );
				VSET( v, 0,0,0 );
			}

			MAT4X3VEC( homog, mat, v );
			VADD2( v, base_vect, homog );
			v += ELEMENTS_PER_VECT;
		}
		VMOVE( v, curves[i] );		/* replicate first point */
	}

	/*
	 *  Draw the "waterlines", by tracing each curve.
	 *  n+1th point is first point replicated by code above.
	 */
	for( i = 0; i < ncurves; i++ )  {
		register float *v1;

		v1 = curves[i];
		DM_GOTO( v1, PEN_UP );
		v1 += ELEMENTS_PER_VECT;
		for( j = 1; j <= pts_per_curve; j++, v1 += ELEMENTS_PER_VECT )
			DM_GOTO( v1, PEN_DOWN );
	}

	/*
	 *  Connect the Ith points on each curve, to make a mesh.
	 */
	for( i = 0; i < pts_per_curve; i++ )  {
		DM_GOTO( &curves[0][i*ELEMENTS_PER_VECT], PEN_UP );
		for( j = 1; j < ncurves; j++ )
			DM_GOTO( &curves[j][i*ELEMENTS_PER_VECT], PEN_DOWN );
	}

	/*
	 *  Free storage for faces
	 */
	for( i = 0; i < ncurves; i++ )  {
		free( (char *)curves[i] );
	}
	free( (char *)curves );
}

/*
 *			R D _ C U R V E
 *  
 *  rd_curve() reads a set of ARS B records and returns a pointer
 *  to a malloc()'ed memory area of float's to hold the curve.
 */
static float *
rd_curve(npts)
int npts;
{
	static int bytes;
	static int lim;
	static float *base;
	register float *fp;		/* pointer to temp vector */
	register int i;
	static union record r;

	/* Leave room for first point to be repeated */
	bytes = (npts+1) * sizeof(float) * ELEMENTS_PER_VECT;
	if( (fp = (float *)malloc((unsigned)bytes)) == (float *) 0 ) {
		(void)printf("ars.c/rd_curve():  malloc error");
		finish(13);
	}
	base = fp;

	while( npts > 0 )  {
		/* SHOULD BE a db_getmany() CALL */
		if( read( objfd, (char *) &r, sizeof(r) ) != sizeof(r) )
			(void)printf("ars.c/rd_curve():  read error");

		if( r.b.b_id != ID_ARS_B )  {
			(void)printf("ars.c/rd_curve():  non-ARS_B record!\n");
			break;
		}
		lim = (npts>8) ? 8 : npts;
		for( i=0; i<lim; i++ )  {
			VMOVE( fp, &r.b.b_values[i*3] );	/* cvt, too */
			fp += ELEMENTS_PER_VECT;
			npts--;
		}
	}
	return( base );
}

/*
 *  			D R A W _ P O L Y
 */
void
draw_poly( dp, xform )
struct directory *dp;
mat_t xform;
{
	register int i;
	static int n;		/* number of P_DATA records involved */
	static union record rec;
	static vect_t work;

	for( n=1; n < dp->d_len; n++ )  {
		db_getrec( dp, &rec, n );
		for( i=0; i < rec.q.q_count; i++ )  {
			MAT4X3PNT( work, xform, rec.q.q_verts[i] );
			VMOVE( rec.q.q_verts[i], work );
		}
		DM_GOTO( rec.q.q_verts[rec.q.q_count-1], PEN_UP );
		for( i=0; i < rec.q.q_count; i++ )  {
			DM_GOTO( rec.q.q_verts[i], PEN_DOWN );
		}
	}
}
