/*
 *			S P L I N E . C
 *
 * Functions -
 *	draw_spline	draw an B-Spline
 *
 *  Author -
 *	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: spline.c,v 1.6 86/04/09 01:11:16 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 */

#define HDIVIDE(a,b)  \
	(a)[X] = (b)[X] / (b)[H];\
	(a)[Y] = (b)[Y] / (b)[H];\
	(a)[Z] = (b)[Z] / (b)[H];

static void	skip_kv();
static float	*rd_mesh();

/*
 *                     D R A W _ S P L I N E
 */
void
draw_spline( ap, dp, mat )
struct B_solid *ap;		/* SPLINE header record */
struct directory *dp;
mat_t mat;
{
	register int i, j;
	static union record rec;
	register float *vp;
	register float *mesh;
	int cur_gran;
	int nby;

	cur_gran = 1;
	while( cur_gran < dp->d_len )  {
		db_getrec( dp, &rec, cur_gran++ );
		if( rec.u_id != ID_BSURF )  {
			printf("%d non-BSURF record in spline?\n", cur_gran);
			return;
		}
		if( rec.d.d_geom_type != 3 && rec.d.d_geom_type != 4 )  {
			printf("BSURF geom_type=%d?\n", rec.d.d_geom_type);
			return;
		}
		/* Skip the knot_vector records */
		cur_gran += rec.d.d_nknots;

		nby = rec.d.d_nctls * sizeof(union record);
		if( (mesh = (float *)malloc(nby)) == (float *)0 )  {
			printf("draw_spline:  malloc error\n");
			return;
		}
		db_getmany( dp, (char *)mesh, cur_gran, rec.d.d_nctls );
		cur_gran += rec.d.d_nctls;

		/* Transform all the control points */
		vp = mesh;
		i = rec.d.d_ctl_size[0]*rec.d.d_ctl_size[1];
		for( ; i>0; i--, vp += rec.d.d_geom_type )  {
			static vect_t	homog;
			if( rec.d.d_geom_type == 3 )  {
				MAT4X3PNT( homog, mat, vp );
				VMOVE( vp, homog );
			} else {
				HDIVIDE( homog, vp );
				MAT4X3PNT( vp, mat, homog );
				/* Leaves us with [x,y,z,1] */
			}
		}


		/* 
		 * Draw the control mesh, by tracing each curve.
		 */
#define CTL_POS(a,b)	((((a)*rec.d.d_ctl_size[1])+(b))*rec.d.d_geom_type)
		vp = mesh;

		for( i = 0; i < rec.d.d_ctl_size[0]; i++) {
			DM_GOTO( vp, PEN_UP );
			vp += rec.d.d_geom_type;
			for( j = 1; j < rec.d.d_ctl_size[1]; j++ )  {
				/** CTL_POS( i, j ); **/
				DM_GOTO( vp, PEN_DOWN );
				vp += rec.d.d_geom_type;
			}
		}

		/*
		 *  Connect the Ith points on each curve, to make a mesh.
		 */
		for( i = 0; i < rec.d.d_ctl_size[1]; i++ )  {
			vp = mesh+CTL_POS( 0, i );
			DM_GOTO( vp, PEN_UP );
			for( j = 1; j < rec.d.d_ctl_size[0]; j++ )  {
				vp = mesh+CTL_POS( j, i );
				DM_GOTO( vp, PEN_DOWN );
			}
		}

		free( (char *)mesh );
	}
}

void
move_spline( ap, dp, mat )
struct B_solid *ap;		/* SPLINE header record */
struct directory *dp;
mat_t mat;
{
	static union record rec;
	register float *vp;
	register float *mesh;
	int cur_gran;
	int nby;

	cur_gran = 1;
	while( cur_gran < dp->d_len )  {
		db_getrec( dp, &rec, cur_gran++ );
		if( rec.u_id != ID_BSURF )  {
			printf("non-BSURF record in spline?\n");
			return;
		}
		if( rec.d.d_geom_type != 3 && rec.d.d_geom_type != 4 )  {
			printf("BSURF geom_type=%d?\n", rec.d.d_geom_type);
			return;
		}
		/* Skip the knot_vector records */
		cur_gran += rec.d.d_nknots;

		nby = rec.d.d_nctls * sizeof(union record);
		if( (mesh = (float *)malloc(nby)) == (float *)0 )  {
			printf("move_spline:  malloc error\n");
			return;
		}
		db_getmany( dp, (char *)mesh, cur_gran, rec.d.d_nctls );

		/* Transform all the control points */
		vp = &mesh[(rec.d.d_ctl_size[0]*rec.d.d_ctl_size[1]-1)*
			rec.d.d_geom_type];
		for( ; vp > mesh; vp -= rec.d.d_geom_type )  {
			static vect_t	homog;
			if( rec.d.d_geom_type == 3 )  {
				MAT4X3PNT( homog, mat, vp );
				VMOVE( vp, homog );
			} else {
				/**** Need MAT4X4PNT!! ****/
				HDIVIDE( homog, vp );
				MAT4X3PNT( vp, mat, homog );
				vp[H] = 1;
				/* Leaves us with [x,y,z,1] */
			}
		}
		db_putmany( dp, (char *)mesh, cur_gran, rec.d.d_nctls );
		cur_gran += rec.d.d_nctls;
		free( (char *)mesh );
	}
}

void
dbpr_spline( dp )
register struct directory *dp;
{
	register int cur_gran;
	union record rec;

	db_getrec( dp, &rec, 0 );
	(void)printf("%s:  SPLINE, %d surfaces (%d granules)\n",
		dp->d_namep, rec.B.B_nsurf, dp->d_len );

	cur_gran = 1;
	while( cur_gran < dp->d_len )  {
		db_getrec( dp, &rec, cur_gran++ );
		if( rec.u_id != ID_BSURF )  {
			printf("non-BSURF record in spline?\n");
			return;
		}
		if( rec.d.d_geom_type != 3 && rec.d.d_geom_type != 4 )  {
			printf("BSURF geom_type=%d?\n", rec.d.d_geom_type);
			return;
		}
		(void)printf(" Surf order %d x %d\n",
			rec.d.d_order[0],
			rec.d.d_order[1]);
		(void)printf(" Knot vec %d + %d, Control points %d x %d\n",
			rec.d.d_kv_size[0], rec.d.d_kv_size[1],
			rec.d.d_ctl_size[0], rec.d.d_ctl_size[1]);
		(void)printf(" geom_type=%d, %d knot %d ctl granules\n",
			rec.d.d_geom_type,
			rec.d.d_nknots, rec.d.d_nctls );
		cur_gran += rec.d.d_nctls + rec.d.d_nknots;
	}
}
