/*
	SCCS id:	%Z% %M%	%I%
	Last edit: 	%G% at %U%
	Retrieved: 	%H% at %T%
	SCCS archive:	%P%

	Author:		Gary S. Moss
			U. S. Army Ballistic Research Laboratory
			Aberdeen Proving Ground
			Maryland 21005-5066
			(301)278-6647 or AV-298-6647
*/
#if ! defined( lint )
static
char	sccsTag[] = "mat_db.c: %Z% %M%	%I%	last edit %G% at %U%";
#endif
#include <stdio.h>
#include "../h/machine.h"
#include "./mat_db.h"

static FILE		*mat_db_fp;
static Mat_Db_Entry	mat_db_table[MAX_MAT_DB];
static int		mat_db_size = 0;
Mat_Db_Entry		mat_dfl_entry =
				{
				0,		/* Material id.		*/
				7,		/* Shininess.		*/
				0.6,		/* Specular weight.	*/
				0.3,		/* Diffuse weight.	*/
				0.0,		/* Transparency.	*/
				0.0,		/* Transmission.	*/
				0.0,		/* Refractive index.	*/
				255, 255, 255,	/* Diffuse RGB values.	*/
				MF_USED,	/* Mode flag.		*/
				"(default)"	/* Material name.	*/
				};
Mat_Db_Entry		mat_nul_entry =
				{
				0,		/* Material id.		*/
				0,		/* Shininess.		*/
				0.0,		/* Specular weight.	*/
				0.0,		/* Diffuse weight.	*/
				0.0,		/* Transparency.	*/
				0.0,		/* Transmission.	*/
				0.0,		/* Refractive index.	*/
				0, 0, 0,	/* Diffuse RGB values.	*/
				MF_NULL,	/* Mode flag.		*/
				"(null)"	/* Material name.	*/
				};
HIDDEN int	get_Entry(), put_Entry();
HIDDEN int	mat_W_Open();

/*	m a t _ O p e n _ D b ( )
	Open file, return file pointer or NULL.
 */
FILE *
mat_Open_Db( mat_db_file )
char	*mat_db_file;
	{	register	Mat_Db_Entry	*entry;
	if( (mat_db_fp = fopen( mat_db_file, "r" )) == NULL )
		{
		(void) fprintf( stderr,
				"Could not open %s for reading.\n",
				mat_db_file
				);
		return	mat_db_fp; /* NULL */
		}
	/* Mark all entries as NULL.					*/
	for( entry = mat_db_table; entry < &mat_db_table[MAX_MAT_DB]; entry++ )
		entry->mode_flag = MF_NULL;
	return	mat_db_fp;
	}

/*	m a t _ C l o s e _ D b ( )
	Close material database input file.  Return success or failure.
 */
mat_Close_Db()
	{
	return	fclose( mat_db_fp );
	}

/*	m a t _ P r i n t _ D b ( )
	Print material database entry.
 */
mat_Print_Db( tty_fp, material_id )
FILE	*tty_fp;
int	material_id;
	{
		Mat_Db_Entry	*entry;
		
	if( material_id < MAX_MAT_DB )
		entry = &mat_db_table[material_id];
	else
		return	-1;
	if( entry->mode_flag == MF_NULL )
		entry = &mat_nul_entry;
	(void) fprintf( tty_fp,
			"  material id         %d\n",
			entry->id
			);
	(void) fprintf(	tty_fp,
			"  material name       \"%s\"\n",
			entry->name[0] == '\0' ? "(untitled)" : entry->name
			);
	(void) fprintf( tty_fp,
			"  shininess           %d\n",
			entry->shine
			);
	(void) fprintf( tty_fp,
			"  specular weight     %lf\n",
			entry->wgt_specular
			);
	(void) fprintf( tty_fp,
			"  diffuse weight      %lf\n",
			entry->wgt_diffuse
			);
	(void) fprintf( tty_fp,
			"  transparency        %lf\n",
			entry->transparency
			);
	(void) fprintf( tty_fp,
			"  transmission        %lf\n",
			entry->transmission
			);
	(void) fprintf( tty_fp,
			"  refractive index    %lf\n",
			entry->refrac_index
			);
	(void) fprintf( tty_fp,
			"  diffuse color       %d %d %d\n",
			entry->df_rgb[0],
			entry->df_rgb[1],
			entry->df_rgb[2]
			);
	return	1;
	}

/*	m a t _ A s c _ R e a d _ D b ( )
	Read ASCII material database into table, return number of entries.
 */
mat_Asc_Read_Db()
	{
	Mat_Db_Entry	*entry;

	mat_db_size = 0;
	for(	entry = mat_db_table;
		entry < &mat_db_table[MAX_MAT_DB]
	     && get_Entry( entry );
		++entry
		)
		mat_db_size++;
	return	mat_db_size;
	}

/*	m a t _ B i n _ R e a d _ D b ( )
	Read binary material database into table, return number of entries.
 */
mat_Bin_Read_Db()
	{
	Mat_Db_Entry	*entry;

	mat_db_size = 0;
	for(	entry = mat_db_table;
		entry < &mat_db_table[MAX_MAT_DB]
	     && fread( (char *) entry, sizeof(Mat_Db_Entry), 1, mat_db_fp ) == 1;
		++entry
		)
		mat_db_size++;
	return	mat_db_size;
	}
/*	m a t _ P u t _ D b _ E n t r y ( )
	Create or overwrite entry in material table.
 */
mat_Put_Db_Entry( material_id )
int	material_id;
	{
	register Mat_Db_Entry	*entry;
	static char		input_Buf[BUFSIZ];
	int			red, grn, blu;

	if( material_id < MAX_MAT_DB )
		{
		entry = &mat_db_table[material_id];
		entry->id = material_id;
		}
	else
		{
		(void) fprintf( stderr,
			"Material table full, MAX_DB_ENTRY too small.\n"
				);
		return	0;
		}
	entry_Prompt( "material name" );
	if( gets( input_Buf ) == NULL )
		return	0;
	if( input_Buf[0] != '\0' )
		(void) strncpy( entry->name, input_Buf, MAX_MAT_NM );
	entry_Prompt( "shine" );
	if( gets( input_Buf ) == NULL )
		return	0;
	if( input_Buf[0] != '\0' )
		(void) sscanf( input_Buf, "%d", &entry->shine );
	entry_Prompt( "specular weighting [0.0 .. 1.0]" );
	if( gets( input_Buf ) == NULL )
		return	0;
	if( input_Buf[0] != '\0' )
		(void) sscanf( input_Buf, "%lf", &entry->wgt_specular );
	entry_Prompt( "diffuse weighting [0.0 .. 1.0]" );
	if( gets( input_Buf ) == NULL )
		return	0;
	if( input_Buf[0] != '\0' )
		(void) sscanf( input_Buf, "%lf", &entry->wgt_diffuse );
	entry_Prompt( "transparency [0.0 .. 1.0]" );
	if( gets( input_Buf ) == NULL )
		return	0;
	if( input_Buf[0] != '\0' )
		(void) sscanf( input_Buf, "%lf", &entry->transparency );
	entry_Prompt( "transmission [0.0 .. 1.0]" );
	if( gets( input_Buf ) == NULL )
		return	0;
	if( input_Buf[0] != '\0' )
		(void) sscanf( input_Buf, "%lf", &entry->transmission );
	entry_Prompt( "refractive index [0.9 .. 5.0]" );
	if( gets( input_Buf ) == NULL )
		return	0;
	if( input_Buf[0] != '\0' )
		(void) sscanf( input_Buf, "%lf", &entry->refrac_index );
	entry_Prompt( "diffuse RGB values [0 .. 255]" );
	if( gets( input_Buf ) == NULL )
		return	0;
	if(	input_Buf[0] != '\0'
	     &&	sscanf( input_Buf, "%d %d %d", &red, &grn, &blu ) == 3
		)
		{
		entry->df_rgb[0] = red;
		entry->df_rgb[1] = grn;
		entry->df_rgb[2] = blu;
		}
	entry->mode_flag = MF_USED;
	if( material_id+1 > mat_db_size )
		mat_db_size = material_id+1;
	return	1;
	}

/*	m a t _ G e t _ D b _ E n t r y ( )
	Return pointer to entry indexed by id or NULL.
 */
Mat_Db_Entry *
mat_Get_Db_Entry( material_id )
int	material_id;
	{
	if( material_id < mat_db_size )
		return	&mat_db_table[material_id];
	else
		return	MAT_DB_NULL;
	}

HIDDEN
get_Entry( entry )
register Mat_Db_Entry	*entry;
	{	register char	*ptr;
		int		items;
		int		red, grn, blu, mode;
	if( fgets( entry->name, MAX_MAT_NM, mat_db_fp ) == NULL )
		return	0;
	ptr = &entry->name[strlen(entry->name) - 1];
	if( *ptr == '\n' )
		/* Read entire line.					*/
		*ptr = '\0';
	else	/* Skip rest of line.					*/
		while( getc( mat_db_fp ) != '\n' )
			;
	if( (items = fscanf( mat_db_fp, "%d %d", &entry->id, &entry->shine )) != 2 )
		{
		(void) fprintf( stderr, "Could not read integers (%d read)!\n", items );
		return	0;
		}
	if(	fscanf(	mat_db_fp,
			"%lf %lf %lf %lf %lf",
			&entry->wgt_specular,
			&entry->wgt_diffuse,
			&entry->transparency,
			&entry->transmission,
			&entry->refrac_index
			) != 5
		)
		{
		(void) fprintf( stderr, "Could not read floats!\n" );
		return	0;
		}
	if( fscanf( mat_db_fp, "%d %d %d", &red, &grn, &blu ) != 3 )
		{
		(void) fprintf( stderr, "Could not read chars!\n" );
		return	0;
		}
	entry->df_rgb[0] = red;
	entry->df_rgb[1] = grn;
	entry->df_rgb[2] = blu;
	if( fscanf( mat_db_fp, "%d", &mode ) != 1 )
		{
		(void) fprintf( stderr, "Could not read char!\n" );
		return	0;
		}
	entry->mode_flag = mode;
	while( getc( mat_db_fp ) != '\n' )
		; /* Gobble rest of line.				*/
	return	1;
	}

HIDDEN
put_Entry( entry )
register Mat_Db_Entry	*entry;
	{
	if( entry->mode_flag == MF_NULL )
		entry = &mat_nul_entry;
	(void) fprintf( mat_db_fp, "%s\n", entry->name );
	(void) fprintf( mat_db_fp, "%d\n%d\n", entry->id, entry->shine );
	(void) fprintf(	mat_db_fp,
			"%lf\n%lf\n%lf\n%lf\n%lf\n",
			entry->wgt_specular,
			entry->wgt_diffuse,
			entry->transparency,
			entry->transmission,
			entry->refrac_index
			);
	(void) fprintf(	mat_db_fp,
			"%u %u %u\n",
			(unsigned) entry->df_rgb[0],
			(unsigned) entry->df_rgb[1],
			(unsigned) entry->df_rgb[2]
			);
	(void) fprintf( mat_db_fp, "%u\n", (unsigned) entry->mode_flag );
	return	1;
	}

HIDDEN
mat_W_Open( file )
char	*file;
	{
	if( file != NULL )
		{	register FILE	*fp;
		if( (fp = fopen( file, "w+" )) == NULL )
			{
			(void) fprintf( stderr,
					"Could not open %s for writing.\n",
					file
					);
			return	0;
			}
		else
			{
			mat_db_fp = fp;
			setbuf( mat_db_fp, malloc( BUFSIZ ) );
			}
		}
	/* else default to last database accessed.			*/
	if( mat_db_fp == NULL )
		{
		(void) fprintf( stderr,
				"Material database needed, no default!\n"
				);
		return	0;
		}
	return	fseek( mat_db_fp, 0L, 0 ) == 0;
	}
entry_Prompt( str )
{
	fprintf(stderr,str);
	fflush(stderr);
}
