/*************************************************************************

	form*Z by auto*des*sys, Inc.
	Copyright (c) 1989-2004 auto*des*sys, Inc.  All rights reserved.

	File:			sinewave.c
	Author:			auto*des*sys, Inc.
	Created on:		01/26/04
	Description:	Sinewave shader plugins.  Shades surfaces
					as if they had a sine wave pattern on them.
					This plugin consists of 4 plugins: color,
					transparency, bump, and background shader
					plugins.

*************************************************************************/

/* standard headers */

#include <math.h>

/* this plugin's header */

#include "sinewave.h"

/* required for plugin's source file implementing plugin entry function */

#include "fz_plugin_glue_api.h"

/* generic plugin functions */
static fzrt_error_td	sinewave_check_config(const fzpl_fset_glue_fset* const fset_glue, const fzpl_host_config_td* const hostConfig);
static fzrt_error_td	sinewave_acquire_fsets(void);
static void				sinewave_release_fsets(void);
static fzrt_error_td	sinewave_init(const fzpl_fset_glue_fset* const fset_glue, const fzpl_host_config_td* const hostConfig);
static fzrt_error_td	sinewave_finit(const fzpl_fset_glue_fset* const fset_glue);

/* functions called by formZ to fill a shader's function set */
/* with pointers to sinewave's own callback functions. */
static fzrt_error_td	sinewave_colr_fill_fset(const fzpl_fset_def_ptr fset_def, fzpl_fset_td* const fset);
static fzrt_error_td	sinewave_trns_fill_fset(const fzpl_fset_def_ptr fset_def, fzpl_fset_td* const fset);
static fzrt_error_td	sinewave_bump_fill_fset(const fzpl_fset_def_ptr fset_def, fzpl_fset_td* const fset);
static fzrt_error_td	sinewave_bgnd_fill_fset(const fzpl_fset_def_ptr fset_def, fzpl_fset_td* const fset);

/* required plugin entry point function */
FZPL_PLUGIN_FUNC(fzrt_error_td) fz_plugin_entry(const fzpl_fset_glue_fset* const fset_glue, fzpl_command_td cmd, const fzpl_host_config_td* const hostConfig);


/* shader callback functions used by all */
/* (they do not have to be shared though, */
/* each could provide its own) */
static fzrt_error_td 	sinewave_name(char* name, fzrt_int max_len);
static fzrt_error_td 	sinewave_post_render(void* shdr_data);

/* color shader callback functions */
static fzrt_error_td	sinewave_colr_uuid(fzrt_UUID_td uuid);
static fzrt_error_td 	sinewave_colr_io_version(fzpl_vers_td* version);
static fzrt_error_td	sinewave_colr_set_parameters(void);
static fzrt_error_td 	sinewave_colr_pre_render(void** shdr_data);
static fz_rgb_float_td	sinewave_colr_shade_pixel(void* shdr_data);
static fz_rgb_float_td	sinewave_colr_avg_color(void);
static fzrt_error_td	sinewave_colr_iface_tmpl(
	fzrt_int				windex,		
	fz_fuim_tmpl_ptr	fuim_tmpl, 	
	fz_shdr_ptr			shdr_ptr,	
	fzrt_int				parent_group
);

/* transparency shader callback functions */
static fzrt_error_td	sinewave_trns_uuid(fzrt_UUID_td uuid);
static fzrt_error_td 	sinewave_trns_io_version(fzpl_vers_td* version);
static fzrt_error_td	sinewave_trns_set_parameters(void);
static fzrt_error_td 	sinewave_trns_pre_render(void** shdr_data);
static double		 	sinewave_trns_shade_pixel(void* shdr_data);
static double		 	sinewave_trns_avg_value(void);

/* bump shader callback functions */
static fzrt_error_td	sinewave_bump_uuid(fzrt_UUID_td uuid);
static fzrt_error_td 	sinewave_bump_io_version(fzpl_vers_td* version);
static fzrt_error_td	sinewave_bump_set_parameters(void);
static fzrt_error_td 	sinewave_bump_pre_render(void** shdr_data);
static double		 	sinewave_bump_shade_pixel(void* shdr_data);

/* background shader callback functions */
static fzrt_error_td	sinewave_bgnd_uuid(fzrt_UUID_td uuid);
static fzrt_error_td 	sinewave_bgnd_io_version(fzpl_vers_td* version);
static fzrt_error_td	sinewave_bgnd_set_parameters(void);
static fzrt_error_td 	sinewave_bgnd_pre_render(void** shdr_data);
static fz_rgb_float_td	sinewave_bgnd_shade_pixel(void* shdr_data);



/************************************************************************
							Plugin Functions
*************************************************************************/

/************************************************************************
	glossy_check_config
		A first pass check to see if the plugin can be loaded.  It does
		the following:
			Acquires formZ function sets.
			Checks licensing.
			Informs the application if this plugin is dependent on
				function sets from other plugins.
*************************************************************************/
static fzrt_error_td sinewave_check_config(const fzpl_fset_glue_fset* const fset_glue, const fzpl_host_config_td* const hostConfig)
/************************************************************************/
{
	fzrt_error_td err = FZRT_NOERR;

	/* assign our copy of the plugin fset pointer to that which formZ provides */
	_fset_glue = fset_glue;

	/* Make sure required application defined function sets are available */
	/* Release the function sets at unload. */

	err = sinewave_acquire_fsets();

	/* IF NEEDED: Check License */

	/* IF NEEDED: Tell the plugin manager what plugins this plugins are dependent on */

	if ( err != FZRT_NOERR )
	{
		sinewave_release_fsets();
	}

	return err;
}


/************************************************************************
	sinewave_acquire_fsets
		Acquires all formZ function sets used by this plugin.
*************************************************************************/
static fzrt_error_td sinewave_acquire_fsets(void)
/************************************************************************/
{
	fzrt_error_td err = FZRT_NOERR;


	err = _fset_glue->fzpl_fset_acquire( FZ_SHDR_FSET_TYPE,
								   FZ_SHDR_FSET_VERSION,
								   FZRT_UUID_NULL,
								   FZPL_TYPE_STRING(fz_shdr_fset),
								   sizeof(_shdr_funcs),
								   (fzpl_fset_td*)&_shdr_funcs );
	

	if (err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_TYPE_FSET_TYPE,
									   FZ_TYPE_FSET_VERSION,
									   FZRT_UUID_NULL,
									   FZPL_TYPE_STRING(fz_type_fset),
									   sizeof(_type_funcs),
									   (fzpl_fset_td*)&_type_funcs );
	}
	
	if (err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FZRT_MEM_FSET_TYPE,
									   FZ_FZRT_MEM_FSET_VERSION,
									   FZRT_UUID_NULL,
									   FZPL_TYPE_STRING(fz_fzrt_mem_fset),
									   sizeof(_mem_funcs),
									   (fzpl_fset_td*)&_mem_funcs );
	}

	if (err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FZRT_BASE_FSET_TYPE,
									   FZ_FZRT_BASE_FSET_VERSION,
									   FZRT_UUID_NULL,
									   FZPL_TYPE_STRING(fz_fzrt_base_fset),
									   sizeof(_base_funcs),
									   (fzpl_fset_td*)&_base_funcs );
	}

	if (err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FZRT_FILE_FSET_TYPE,
									   FZ_FZRT_FILE_FSET_VERSION,
									   FZRT_UUID_NULL,
									   FZPL_TYPE_STRING(fz_fzrt_file_fset),
									   sizeof(_file_funcs),
									   (fzpl_fset_td*)&_file_funcs );
	}
	
	if (err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_FUIM_FSET_TYPE,
									   FZ_FUIM_FSET_VERSION,
									   FZRT_UUID_NULL,
									   FZPL_TYPE_STRING(fz_fuim_fset),
									   sizeof(_fuim_funcs),
									   (fzpl_fset_td*)&_fuim_funcs );
	}
	
	if (err == FZRT_NOERR)
	{
		err = _fset_glue->fzpl_fset_acquire( FZ_RMTL_FSET_TYPE,
									   FZ_RMTL_FSET_VERSION,
									   FZRT_UUID_NULL,
									   FZPL_TYPE_STRING(fz_rmtl_fset),
									   sizeof(_rmtl_funcs),
									   (fzpl_fset_td*)&_rmtl_funcs );
	}

	return err;
}

/************************************************************************
	sinewave_release_fsets
		Releases all formZ function sets used.
*************************************************************************/
static void sinewave_release_fsets(void)
/************************************************************************/
{
	_fset_glue->fzpl_fset_release( (fzpl_fset_td*)&_type_funcs );
	_fset_glue->fzpl_fset_release( (fzpl_fset_td*)&_shdr_funcs );
	_fset_glue->fzpl_fset_release( (fzpl_fset_td*)&_mem_funcs );
	_fset_glue->fzpl_fset_release( (fzpl_fset_td*)&_base_funcs );
	_fset_glue->fzpl_fset_release( (fzpl_fset_td*)&_file_funcs );
}



/************************************************************************
	sinewave_init
		Loads localization strings from resource file.
		Registers plugins and their associated function sets.
*************************************************************************/
static fzrt_error_td sinewave_init(const fzpl_fset_glue_fset* const fset_glue, const fzpl_host_config_td* const hostConfig)
/************************************************************************/
{
	fzrt_error_td		err = FZRT_NOERR;
	/* resource file variables */
	fzrt_floc_ptr		floc;
	fzrt_fzr_ref_td		resource_ref;
	char				buffer[STRING_SIZE];

	/* Get resource file localization strings */
	
	/* initialize file locator structure */
	err = _file_funcs.fzrt_file_floc_init(&floc);
	if (err == FZRT_NOERR)
	{
		/* get the location of this plugin */
		err = _fset_glue->fzpl_plugin_file_get_floc(floc);

		if (err == FZRT_NOERR)
		{
			/* open the resource file eg. sinewave.ENU.fzr */
			err = _base_funcs.fzrt_fzr_open(floc, "sinewave", &resource_ref);

			if (err == FZRT_NOERR)
			{
				/* get the localized resource strings for this plugin */
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 1, buffer);
				strcpy(_name, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 2, buffer);
				strcpy(_color1, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 3, buffer);
				strcpy(_color2, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 4, buffer);
				strcpy(_trns1, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 5, buffer);
				strcpy(_trns2, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 6, buffer);
				strcpy(_bump1, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 7, buffer);
				strcpy(_bump2, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 8, buffer);
				strcpy(_wave_height, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 9, buffer);
				strcpy(_fuzz, buffer);
				_base_funcs.fzrt_fzr_get_string(resource_ref, 1, 10, buffer);
				strcpy(_full_name, buffer);

				/* close the resource file */
				err = _base_funcs.fzrt_fzr_close(resource_ref);
			}
			/* throw away floc */
			_file_funcs.fzrt_file_floc_finit(&floc);
		}
	}

	/* Register plugin and fsets */

	/* register a shader plugin */
	if (err == FZRT_NOERR)
	{	
		err = fset_glue->fzpl_plugin_register( SINEWAVE_PLUGIN_UUID,
										 _full_name,
										 SINEWAVE_PLUGIN_VERSION,
										 SINEWAVE_PLUGIN_VENDOR,
										 SINEWAVE_PLUGIN_URL,
										 FZ_SHDR_EXTS_TYPE,
										 FZ_SHDR_EXTS_VERSION,
										 NULL /*error string function*/,
										 0,
										 NULL,
										 &_sinewave_plugin_runtime_id );
	}

	/* register a color shader fset for the plugin */
	if (err == FZRT_NOERR)
	{
		err = fset_glue->fzpl_plugin_add_fset( _sinewave_plugin_runtime_id,
										 FZ_SHDR_CBAK_COLR_FSET_TYPE,
										 FZ_SHDR_CBAK_COLR_FSET_VERSION,
										 FZ_SHDR_CBAK_COLR_FSET_NAME,
										 FZPL_TYPE_STRING(fz_shdr_cbak_colr_fset),
										 sizeof(fz_shdr_cbak_colr_fset),
										 sinewave_colr_fill_fset,
										 FALSE);
	}									 

	/* register a transparency shader fset for the plugin */
	if (err == FZRT_NOERR)				 
	{
		err = fset_glue->fzpl_plugin_add_fset( _sinewave_plugin_runtime_id,
										 FZ_SHDR_CBAK_TRNS_FSET_TYPE,
										 FZ_SHDR_CBAK_TRNS_FSET_VERSION,
										 FZ_SHDR_CBAK_TRNS_FSET_NAME,
										 FZPL_TYPE_STRING(fz_shdr_cbak_trns_fset),
										 sizeof(fz_shdr_cbak_trns_fset),
										 sinewave_trns_fill_fset,
										 FALSE);
	}

	/* register a bump shader fset for the plugin */
	if (err == FZRT_NOERR)
	{
		err = fset_glue->fzpl_plugin_add_fset( _sinewave_plugin_runtime_id,
										 FZ_SHDR_CBAK_BUMP_FSET_TYPE,
										 FZ_SHDR_CBAK_BUMP_FSET_VERSION,
										 FZ_SHDR_CBAK_BUMP_FSET_NAME,
										 FZPL_TYPE_STRING(fz_shdr_cbak_bump_fset),
										 sizeof(fz_shdr_cbak_bump_fset),
										 sinewave_bump_fill_fset,
										 FALSE);
	}
		
	/* register a background shader fset for the plugin */
	if (err == FZRT_NOERR)
	{
		err = fset_glue->fzpl_plugin_add_fset( _sinewave_plugin_runtime_id,
										 FZ_SHDR_CBAK_BGND_FSET_TYPE,
										 FZ_SHDR_CBAK_BGND_FSET_VERSION,
										 FZ_SHDR_CBAK_BGND_FSET_NAME,
										 FZPL_TYPE_STRING(fz_shdr_cbak_bgnd_fset),
										 sizeof(fz_shdr_cbak_bgnd_fset),
										 sinewave_bgnd_fill_fset,
										 FALSE);
	}

	if ( err != FZRT_NOERR )
	{
		sinewave_release_fsets();
		err = _base_funcs.fzrt_error_set(FZRT_UNKNOWN_ERROR, FZRT_ERROR_SEVERITY_ERROR, FZRT_ERROR_CONTEXT_FZRT, 0);
	}

	return err;
}

/************************************************************************
	sinewave_finit
		Unregisters plugins.  Releases formZ function sets.
*************************************************************************/
static fzrt_error_td sinewave_finit(const fzpl_fset_glue_fset* const fset_glue)
/************************************************************************/
{
	fzrt_error_td err = FZRT_NOERR;

	err = _fset_glue->fzpl_plugin_unregister(_sinewave_plugin_runtime_id);
	
	sinewave_release_fsets();

	return err;
}



/************************************************************************
							Plugin Fill Functions
*************************************************************************/

/************************************************************************
	sinewave_colr_fill_fset
		Fills the fset structure with the callback functions for a
		color shader plugin.
*************************************************************************/
static fzrt_error_td sinewave_colr_fill_fset(const fzpl_fset_def_ptr fset_def, fzpl_fset_td* const fset)
/************************************************************************/
{
	fzrt_error_td				err = FZRT_NOERR;
	fz_shdr_cbak_colr_fset	*shdr_cbak_fset;

	if ( fset_def && fset )
	{
		_fset_glue->fzpl_fset_def_check( fset_def,
								   FZ_SHDR_CBAK_COLR_FSET_VERSION,
								   FZPL_TYPE_STRING(fz_shdr_cbak_colr_fset),
								   sizeof(fz_shdr_cbak_colr_fset),
								   FZPL_VERSION_OP_NEWER );
		if (err == FZRT_NOERR)
		{
			shdr_cbak_fset = (fz_shdr_cbak_colr_fset*)fset;

			shdr_cbak_fset->fz_shdr_cbak_colr_uuid				= sinewave_colr_uuid;
			shdr_cbak_fset->fz_shdr_cbak_colr_name				= sinewave_name;
			shdr_cbak_fset->fz_shdr_cbak_colr_version			= sinewave_colr_io_version;
			shdr_cbak_fset->fz_shdr_cbak_colr_set_parameters	= sinewave_colr_set_parameters;
			shdr_cbak_fset->fz_shdr_cbak_colr_pre_render		= sinewave_colr_pre_render;
			shdr_cbak_fset->fz_shdr_cbak_colr_post_render		= sinewave_post_render;
			shdr_cbak_fset->fz_shdr_cbak_colr_pixel				= sinewave_colr_shade_pixel;
			shdr_cbak_fset->fz_shdr_cbak_colr_avg				= sinewave_colr_avg_color;
			shdr_cbak_fset->fz_shdr_cbak_colr_iface_tmpl		= sinewave_colr_iface_tmpl;
		}
	}
	else
		err = _base_funcs.fzrt_error_set(FZRT_BAD_PARAM_ERROR, FZRT_ERROR_SEVERITY_ERROR, FZRT_ERROR_CONTEXT_FZRT, 0);

	return err;
}

/************************************************************************
	sinewave_trns_fill_fset
		Fills the fset structure with the callback functions for a
		transparency shader plugin.
*************************************************************************/
static fzrt_error_td sinewave_trns_fill_fset(const fzpl_fset_def_ptr fset_def, fzpl_fset_td* const fset)
/************************************************************************/
{
	fzrt_error_td				err = FZRT_NOERR;
	fz_shdr_cbak_trns_fset	*shdr_cbak_fset;

	if ( fset_def && fset )
	{
		_fset_glue->fzpl_fset_def_check( fset_def,
								   FZ_SHDR_CBAK_TRNS_FSET_VERSION,
								   FZPL_TYPE_STRING(fz_shdr_cbak_trns_fset),
								   sizeof(fz_shdr_cbak_trns_fset),
								   FZPL_VERSION_OP_NEWER );
		if (err == FZRT_NOERR)
		{
			shdr_cbak_fset = (fz_shdr_cbak_trns_fset*)fset;

			shdr_cbak_fset->fz_shdr_cbak_trns_uuid				= sinewave_trns_uuid;
			shdr_cbak_fset->fz_shdr_cbak_trns_name				= sinewave_name;
			shdr_cbak_fset->fz_shdr_cbak_trns_version			= sinewave_trns_io_version;
			shdr_cbak_fset->fz_shdr_cbak_trns_set_parameters	= sinewave_trns_set_parameters;
			shdr_cbak_fset->fz_shdr_cbak_trns_pre_render		= sinewave_trns_pre_render;
			shdr_cbak_fset->fz_shdr_cbak_trns_post_render		= sinewave_post_render;
			shdr_cbak_fset->fz_shdr_cbak_trns_pixel				= sinewave_trns_shade_pixel;
			shdr_cbak_fset->fz_shdr_cbak_trns_avg				= sinewave_trns_avg_value;
		}
	}
	else
		err = _base_funcs.fzrt_error_set(FZRT_BAD_PARAM_ERROR, FZRT_ERROR_SEVERITY_ERROR, FZRT_ERROR_CONTEXT_FZRT, 0);

	return err;
}

/************************************************************************
	sinewave_bump_fill_fset
		Fills the fset structure with the callback functions for a
		bump shader plugin.
*************************************************************************/
static fzrt_error_td sinewave_bump_fill_fset(const fzpl_fset_def_ptr fset_def, fzpl_fset_td* const fset)
/************************************************************************/
{
	fzrt_error_td				err = FZRT_NOERR;
	fz_shdr_cbak_bump_fset	*shdr_cbak_fset;

	if ( fset_def && fset )
	{
		_fset_glue->fzpl_fset_def_check( fset_def,
								   FZ_SHDR_CBAK_BUMP_FSET_VERSION,
								   FZPL_TYPE_STRING(fz_shdr_cbak_bump_fset),
								   sizeof(fz_shdr_cbak_bump_fset),
								   FZPL_VERSION_OP_NEWER );
		if (err == FZRT_NOERR)
		{
			shdr_cbak_fset = (fz_shdr_cbak_bump_fset*)fset;

			shdr_cbak_fset->fz_shdr_cbak_bump_uuid				= sinewave_bump_uuid;
			shdr_cbak_fset->fz_shdr_cbak_bump_name				= sinewave_name;
			shdr_cbak_fset->fz_shdr_cbak_bump_version			= sinewave_bump_io_version;
			shdr_cbak_fset->fz_shdr_cbak_bump_set_parameters	= sinewave_bump_set_parameters;
			shdr_cbak_fset->fz_shdr_cbak_bump_pre_render		= sinewave_bump_pre_render;
			shdr_cbak_fset->fz_shdr_cbak_bump_post_render		= sinewave_post_render;
			shdr_cbak_fset->fz_shdr_cbak_bump_pixel				= sinewave_bump_shade_pixel;
		}
	}
	else
		err = _base_funcs.fzrt_error_set(FZRT_BAD_PARAM_ERROR, FZRT_ERROR_SEVERITY_ERROR, FZRT_ERROR_CONTEXT_FZRT, 0);

	return err;
}

/************************************************************************
	sinewave_bgnd_fill_fset
		Fills the fset structure with the callback functions for a
		background shader plugin.
*************************************************************************/
static fzrt_error_td sinewave_bgnd_fill_fset(const fzpl_fset_def_ptr fset_def, fzpl_fset_td* const fset)
/************************************************************************/
{
	fzrt_error_td				err = FZRT_NOERR;
	fz_shdr_cbak_bgnd_fset	*shdr_cbak_fset;

	if ( fset_def && fset )
	{
		_fset_glue->fzpl_fset_def_check( fset_def,
								   FZ_SHDR_CBAK_BGND_FSET_VERSION,
								   FZPL_TYPE_STRING(fz_shdr_cbak_bgnd_fset),
								   sizeof(fz_shdr_cbak_bgnd_fset),
								   FZPL_VERSION_OP_NEWER );
		if (err == FZRT_NOERR)
		{
			shdr_cbak_fset = (fz_shdr_cbak_bgnd_fset*)fset;

			shdr_cbak_fset->fz_shdr_cbak_bgnd_uuid				= sinewave_bgnd_uuid;
			shdr_cbak_fset->fz_shdr_cbak_bgnd_name				= sinewave_name;
			shdr_cbak_fset->fz_shdr_cbak_bgnd_version			= sinewave_bgnd_io_version;
			shdr_cbak_fset->fz_shdr_cbak_bgnd_set_parameters	= sinewave_bgnd_set_parameters;
			shdr_cbak_fset->fz_shdr_cbak_bgnd_pre_render		= sinewave_bgnd_pre_render;
			shdr_cbak_fset->fz_shdr_cbak_bgnd_post_render		= sinewave_post_render;
			shdr_cbak_fset->fz_shdr_cbak_bgnd_pixel				= sinewave_bgnd_shade_pixel;
		}
	}
	else
		err = _base_funcs.fzrt_error_set(FZRT_BAD_PARAM_ERROR, FZRT_ERROR_SEVERITY_ERROR, FZRT_ERROR_CONTEXT_FZRT, 0);

	return err;
}


/************************************************************************
						Required Plugin Function
*************************************************************************/

/************************************************************************
	fz_plugin_entry
		The main entry point for a formZ plugin.
*************************************************************************/
FZPL_PLUGIN_FUNC(fzrt_error_td) fz_plugin_entry(const fzpl_fset_glue_fset* const fset_glue, fzpl_command_td cmd, const fzpl_host_config_td* const hostConfig)
/************************************************************************/
{
	fzrt_error_td err = FZRT_NOERR;

	switch ( cmd )
	{
		case FZPL_PLUGIN_CHECK:
			err = sinewave_check_config ( fset_glue, hostConfig );
		break;
		
		case FZPL_PLUGIN_INITIALIZE:
			err = sinewave_init ( fset_glue, hostConfig );
		break;
		
		case FZPL_PLUGIN_EXIT:
			err = sinewave_finit ( fset_glue );
		break;
	}

	return err;
}

/************************************************************************
					Sinewave Shader Data Structures
*************************************************************************/

/************************************************************************
	enum
		Description
			Indices for the parameters that show up in the options
			dialog.
*************************************************************************/
enum
{	PARAM_ID_1 = 0,
	PARAM_ID_2,
	PARAM_ID_HEIGHT,
	PARAM_ID_FUZZ
};

#define PARAM_UUID_COL_1			"\x9d\x2c\x4f\x2a\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_COL_2			"\x9d\x2c\x4f\xf8\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_COL_HEIGHT		"\x9d\x2c\x51\x00\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_COL_FUZZ			"\x9d\x2c\x51\xfc\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"

#define PARAM_UUID_TRN_1			"\x9d\x2c\x52\xc4\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_TRN_2			"\x9d\x2c\x53\x8e\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_TRN_HEIGHT		"\x9d\x2c\x54\x5e\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_TRN_FUZZ			"\x9d\x2c\x55\x26\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"

#define PARAM_UUID_BMP_1			"\x9d\x2c\x55\xee\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_BMP_2			"\x9d\x2c\x56\xbe\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_BMP_HEIGHT		"\x9d\x2c\x57\x84\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"
#define PARAM_UUID_BMP_FUZZ			"\x9d\x2c\x58\x7e\x9f\xee\x11\xda\x8e\x35\x00\x03\x93\x63\x5d\xbc"

/************************************************************************
	sinewave_data_td
		Description
			Structure to hold storage for parameters for the options
			dialog.
		
		Members
			col1 - color of first part of sine wave
			col2 - color of second part of sine wave
			val1 - transparency or bump value of first part of sine wave
			val2 - transparency or bump value of second part of sine wave
			ampl - amplitude of sine wave
			fuzz - how fuzzy boundary is between two regions
			min_left  - where the sine wave begins on the left
			min_right - where the sine wave begins on the right
			max_left  - where the sine wave ends on the left
			max_right - where the sine wave ends on the right
*************************************************************************/
typedef struct
{	fz_rgb_float_td 	col1;
	fz_rgb_float_td 	col2;
	double			val1;
	double			val2;
	double			ampl;
	double			fuzz;
	double			min_left;
	double			min_right;
	double			max_left;
	double			max_right;
} sinewave_data_td;


/************************************************************************
					Sinewave Pre-Render Helper Functions
*************************************************************************/

/************************************************************************
	make_data_storage
		Allocates memory for a sinewave_data_td.  Used by multiple
		shaders.
*************************************************************************/
static void* make_data_storage(void)
/************************************************************************/
{
	void	*storage=NULL;
	
	_mem_funcs.fz_mem_zone_alloc(NULL, sizeof(sinewave_data_td), FALSE, (fzrt_ptr*)&storage);
	
	return storage;
}


/************************************************************************
	get_parameters_with_colors
		Gets parameters from options dialog and stores in sinewave data
		structure.
*************************************************************************/
static void get_parameters_with_colors(sinewave_data_td* sinewave)
/************************************************************************/
{
	fz_type_td data;

	/* get params from dialog, store into data structure */
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_1, &data);
	_type_funcs.fz_type_get_rgb_float(&data, &sinewave->col1);
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_2, &data);
	_type_funcs.fz_type_get_rgb_float(&data, &sinewave->col2);
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_HEIGHT, &data);
	_type_funcs.fz_type_get_double(&data, &sinewave->ampl);
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_FUZZ, &data);
	_type_funcs.fz_type_get_double(&data, &sinewave->fuzz);

}


/************************************************************************
	get_parameters_with_floats
		Gets parameters from options dialog and stores in sinewave data
		structure.
*************************************************************************/
static void get_parameters_with_floats(sinewave_data_td* sinewave)
/************************************************************************/
{
	fz_type_td data;

	/* get params from dialog, store into data structure */
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_1, &data);
	_type_funcs.fz_type_get_double(&data, &sinewave->val1);
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_2, &data);
	_type_funcs.fz_type_get_double(&data, &sinewave->val2);
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_HEIGHT, &data);
	_type_funcs.fz_type_get_double(&data, &sinewave->ampl);
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_FUZZ, &data);
	_type_funcs.fz_type_get_double(&data, &sinewave->fuzz);
}

/************************************************************************
	calc_boundaries
		Amplitude of the sine wave kept in check, as well as the
		fuzziness between the two regions of the sine wave.  Fuzziness
		parameter affects when to begin and end the fuzziness on both
		sides of the sine wave and top and bottom.
*************************************************************************/
static void calc_boundaries(sinewave_data_td* sinewave)
/************************************************************************/
{
	/* keep sine wave within boundaries */
	sinewave->ampl *= 0.25;
	if (sinewave->ampl < 0.0)
		sinewave->ampl = 0.0;
	
	/* scale fuzziness */
	sinewave->fuzz *= 0.25;
	if (sinewave->fuzz < 0.0)
		sinewave->fuzz = 0.0;
	if (sinewave->fuzz > 0.25)
		sinewave->fuzz = 0.25;
	
	/* set where to start and end the sine wave */
	/* boundaries based on the fuzziness. */
	sinewave->min_left 	= 0.25 - sinewave->fuzz;
	sinewave->min_right = 0.25 + sinewave->fuzz;
	sinewave->max_left 	= 0.75 - sinewave->fuzz;
	sinewave->max_right = 0.75 + sinewave->fuzz;
}





/************************************************************************
					Sinewave Shader Helper Functions
*************************************************************************/

/************************************************************************
	compute_sinewave_float_value
		Computes a value for the current pixel, based on the current
		parameter data and the current coordinate as to where it lies
		on the sine wave curve.
*************************************************************************/
static double compute_sinewave_float_value(sinewave_data_td* sinewave)
/************************************************************************/
{
	fz_xy_td  st;
	double ss, tt;
	double trn;
	
	/* get current texture space coordinate */
	_shdr_funcs.fz_shdr_get_tspace_st(&st);

	/* apply saw tooth filter w/sine function */
	ss = _shdr_funcs.fz_shdr_saw_tooth(st.x, 1.0);
	tt = _shdr_funcs.fz_shdr_saw_tooth(st.y, 1.0) + sin(ss * FZ_2PI)*sinewave->ampl;
	tt = _shdr_funcs.fz_shdr_saw_tooth(tt, 1.0);

	/* apply fuzziness */
	tt = _shdr_funcs.fz_shdr_smooth_step(sinewave->min_left, sinewave->min_right, tt) *
		 (1.0 - _shdr_funcs.fz_shdr_smooth_step(sinewave->max_left, sinewave->max_right, tt) );

	/* apply linear interpolation */
	trn = sinewave->val1 * tt + (1.0 - tt) * sinewave->val2;
	
	return trn;
}

/************************************************************************
	compute_sinewave_color_value
		Computes a color for the current pixel, based on the current
		parameter data and the current coordinate as to where it lies
		on the sine wave curve.
*************************************************************************/
static fz_rgb_float_td compute_sinewave_color_value(sinewave_data_td* sinewave, fz_xy_td* st)
/************************************************************************/
{
	double ss, tt;
	fz_rgb_float_td col;
	
	/* apply saw tooth filter w/sine function */
	ss = _shdr_funcs.fz_shdr_saw_tooth(st->x, 1.0);
	tt = _shdr_funcs.fz_shdr_saw_tooth(st->y, 1.0) + sin(ss * FZ_2PI)*sinewave->ampl;
	tt = _shdr_funcs.fz_shdr_saw_tooth(tt, 1.0);

	/* apply fuzziness */
	tt = _shdr_funcs.fz_shdr_smooth_step(sinewave->min_left, sinewave->min_right, tt) *
		 (1.0 - _shdr_funcs.fz_shdr_smooth_step(sinewave->max_left, sinewave->max_right, tt) );

	/* apply linear interpolation */
	col.red   = (float)(sinewave->col1.red   * tt + (1.0 - tt) * sinewave->col2.red);
	col.green = (float)(sinewave->col1.green * tt + (1.0 - tt) * sinewave->col2.green);
	col.blue  = (float)(sinewave->col1.blue  * tt + (1.0 - tt) * sinewave->col2.blue);
	
	return col;
}




/************************************************************************
				Sinewave General Shader Callbacks (used by all)
*************************************************************************/

/************************************************************************
	sinewave_name
		Tells formZ what the name of these plugins is.
*************************************************************************/
static fzrt_error_td sinewave_name(char* name, fzrt_int max_len)
/************************************************************************/
{
	strncpy(name, _name, max_len);
	return FZRT_NOERR;
}


/************************************************************************
	sinewave_post_render
		Frees storage of parameters of options dialog.
*************************************************************************/
static fzrt_error_td sinewave_post_render(void* shdr_data)
/************************************************************************/
{
	if (shdr_data != NULL)
	{
		_mem_funcs.fz_mem_zone_free(NULL, (fzrt_ptr*)&shdr_data);
	}
	return FZRT_NOERR;
}




/************************************************************************
					Sinewave Color Shader Callbacks
*************************************************************************/

/************************************************************************
	sinewave_colr_uuid
		Returns the UUID of the color function set of the plugin.
*************************************************************************/
static fzrt_error_td sinewave_colr_uuid(fzrt_UUID_td uuid)
/************************************************************************/
{
	_base_funcs.fzrt_UUID_copy(SINEWAVE_COLR_PLUGIN_UUID, uuid);
	return FZRT_NOERR;
}

/************************************************************************
	sinewave_colr_io_version
		Tells formZ the version of this plugin's data io.
		This is NOT the same thing as the plugin's version.
		The io of the data may not necessarily change between plugin versions.
*************************************************************************/
static fzrt_error_td sinewave_colr_io_version(fzpl_vers_td* version)
/************************************************************************/
{
	*version = SINEWAVE_COLR_PLUGIN_DATA_IO_VERSION;
	return FZRT_NOERR;
}

/************************************************************************
	sinewave_colr_set_parameters
		Tells formZ what parameters to cause to show up in the "options"
		dialog of the shader.
*************************************************************************/
static fzrt_error_td sinewave_colr_set_parameters(void)
/************************************************************************/
{
	fz_rgb_float_td def_col1;
	fz_rgb_float_td def_col2;
	
	/* default colors */
	def_col1.red   = 0.0;
	def_col1.green = 0.0;
	def_col1.blue  = 0.0;
	def_col2.red   = 1.0;
	def_col2.green = 1.0;
	def_col2.blue  = 1.0;
	
	/* 2d texture mapping */
	_shdr_funcs.fz_shdr_set_wrapped(TRUE);
	/* allow scaling */
	_shdr_funcs.fz_shdr_set_scale_parm(1.0);
	/* allow area sampling */
	_shdr_funcs.fz_shdr_set_area_sample_parm(TRUE);

	/* color of first part of sine wave */
	_shdr_funcs.fz_shdr_set_col_parm(_color1, &def_col1, PARAM_ID_1);
	/* color of second part of sine wave */
	_shdr_funcs.fz_shdr_set_col_parm(_color2, &def_col2, PARAM_ID_2);
	/* amplitude of sine wave */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_wave_height, 0.5, 1, 1, PARAM_ID_HEIGHT);
	/* fuzziness of boundary */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_fuzz, 0.1, 1, 1, PARAM_ID_FUZZ);

	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_1,PARAM_UUID_COL_1);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_2,PARAM_UUID_COL_2);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_HEIGHT,PARAM_UUID_COL_HEIGHT);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_FUZZ,PARAM_UUID_COL_FUZZ);	


	return FZRT_NOERR;
}

/************************************************************************
	sinewave_colr_pre_render
		Allocates memory, grabs parameter options, pre-computes data.
*************************************************************************/
static fzrt_error_td sinewave_colr_pre_render(void** shdr_data)
/************************************************************************/
{
	fzrt_error_td	  err = FZRT_NOERR;
	sinewave_data_td* sinewave;
	
	*shdr_data = NULL;
	/* allocate memory */
	*shdr_data = make_data_storage();
	if(*shdr_data == NULL)
		err = -1;
	else
	{
		/* use pointer to shdr_data as a pointer to sinewave_data_td. */
		sinewave = (sinewave_data_td*)*shdr_data;
		/* get parameters */
		get_parameters_with_colors(sinewave);
		/* compute how wavey and how fuzzy boundary is (based on params) */
		calc_boundaries(sinewave);
	}

	return err;
}

/************************************************************************
	sinewave_colr_shade_pixel
		Computes the color for the current pixel.
		(Called many times, once for each pixel).
*************************************************************************/
static fz_rgb_float_td sinewave_colr_shade_pixel(void* shdr_data)
/************************************************************************/
{
	sinewave_data_td* sinewave;
	fz_rgb_float_td	  col;
	fz_xy_td			  st;

	sinewave = (sinewave_data_td*)shdr_data;

	/* get current pixel space coordinate */
	_shdr_funcs.fz_shdr_get_tspace_st(&st);
	
	col = compute_sinewave_color_value(sinewave, &st);

	return col;
}


/************************************************************************
	sinewave_colr_avg_color
		Computes and returns the average color of this shader, as needed
		by formZ in some instances.
*************************************************************************/
static fz_rgb_float_td sinewave_colr_avg_color(void)
/************************************************************************/
{
	fz_rgb_float_td col, col1, col2;
	fz_type_td	 data;
	
	/* don't have access to sinewave storage, so grab color parameters */
	/* directly. */
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_1, &data);
	_type_funcs.fz_type_get_rgb_float(&data, &col1);
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_2, &data);
	_type_funcs.fz_type_get_rgb_float(&data, &col2);

	/* just a simple average of the two, could do something more */
	/* complicated if desired. */
	col.red   = (float)((col1.red   + col2.red)   * 0.5);
	col.green = (float)((col1.green + col2.green) * 0.5);
	col.blue  = (float)((col1.blue  + col2.blue)  * 0.5);

	return col;
}


/************************************************************************
	sinewave_colr_iface_tmpl
		Creates the options dialog for the shader explicitely. This is to
		show how a customized shader dialog can be written. Note, that
		the dialog items are created as animatable parameters.
*************************************************************************/
static fzrt_error_td	sinewave_colr_iface_tmpl(
	fzrt_int				windex,		
	fz_fuim_tmpl_ptr	fuim_tmpl, 	
	fz_shdr_ptr			shdr_ptr,	
	fzrt_int				parent_group
)
{
	short			g1,align[5];
	fzrt_int			id;
	fzrt_ptr		parm_ptr;
	fz_rmtl_ptr		rmtl;
	fz_tag_td		rmtl_tag;

	/* GET SURFACE STYLE */
	_rmtl_funcs.fz_shdr_ptr_rmtl_from_shdr_ptr(windex,shdr_ptr,&rmtl);
	_rmtl_funcs.fz_rmtl_ptr_to_tag(windex,rmtl,&rmtl_tag);

	/* STANDARD SCALE*/
	_shdr_funcs.fz_shdr_fuim_create_scale_items(fuim_tmpl,shdr_ptr,parent_group,NULL,&id);
	align[0] = id;
	
	/* COLOR 1 */
	_shdr_funcs.fz_shdr_get_parm_ptr(shdr_ptr,PARAM_ID_1,&parm_ptr);
	g1 = _fuim_funcs.fz_fuim_new_text_static(fuim_tmpl,parent_group, FZ_FUIM_NONE, 
	FZ_FUIM_FLAG_HORZ | FZ_FUIM_FLAG_GFLT , _color1, NULL,NULL);
	align[1] = _fuim_funcs.fz_fuim_new_color_box_anim(fuim_tmpl, g1, FZ_FUIM_NONE, FZ_FUIM_FLAG_NONE,
		NULL, (float *)parm_ptr,0,windex,FZ_FUIM_ANIM_SURF_TYPE,&rmtl_tag,PARAM_UUID_COL_1);

	/* COLOR 2 */
	_shdr_funcs.fz_shdr_get_parm_ptr(shdr_ptr,PARAM_ID_2,&parm_ptr);
	g1 = _fuim_funcs.fz_fuim_new_text_static(fuim_tmpl,parent_group, FZ_FUIM_NONE, 
	FZ_FUIM_FLAG_HORZ | FZ_FUIM_FLAG_GFLT , _color2, NULL,NULL);
	align[2] = _fuim_funcs.fz_fuim_new_color_box_anim(fuim_tmpl, g1, FZ_FUIM_NONE, FZ_FUIM_FLAG_NONE,
		NULL, (float *)parm_ptr,0,windex,FZ_FUIM_ANIM_SURF_TYPE,&rmtl_tag,PARAM_UUID_COL_2);

	/* HEIGHT */
	_shdr_funcs.fz_shdr_get_parm_ptr(shdr_ptr,PARAM_ID_HEIGHT,&parm_ptr);
	_fuim_funcs.fz_fuim_new_slider_edit_pcent_float_anim(fuim_tmpl,parent_group,_wave_height,FZ_FUIM_NONE,
		FZ_FUIM_NONE,0.0,1.0,0.0,100.0,0,100,FZ_FUIM_RANGE_MIN | FZ_FUIM_RANGE_MIN_INCL, NULL, NULL,(float*) parm_ptr,
		0,windex,FZ_FUIM_ANIM_SURF_TYPE,&rmtl_tag,PARAM_UUID_COL_HEIGHT,
		&align[3], NULL);

	/* FUZZ */
	_shdr_funcs.fz_shdr_get_parm_ptr(shdr_ptr,PARAM_ID_FUZZ,&parm_ptr);
	_fuim_funcs.fz_fuim_new_slider_edit_pcent_float_anim(fuim_tmpl,parent_group,_fuzz,FZ_FUIM_NONE,
		FZ_FUIM_NONE,0.0,1.0,0.0,100.0,0.0,100.0,
		FZ_FUIM_RANGE_MIN | FZ_FUIM_RANGE_MIN_INCL |
		FZ_FUIM_RANGE_MAX | FZ_FUIM_RANGE_MAX_INCL, NULL,NULL, 
		(float*) parm_ptr,
		0,windex,FZ_FUIM_ANIM_SURF_TYPE,&rmtl_tag,PARAM_UUID_COL_FUZZ,
		&align[4], NULL);


	/* STANDARD AREA SAMPLE */
	_shdr_funcs.fz_shdr_fuim_create_asample_items(fuim_tmpl,shdr_ptr,parent_group,NULL);
	
	/* ALIGN ITEMS */
	_fuim_funcs.fz_fuim_item_align(fuim_tmpl, FZ_FUIM_ALIGN_VLFT | FZ_FUIM_ALIGN_MAX, 5, align);

	return(FZRT_NOERR);
}

/************************************************************************
					Sinewave Transparency Shader Callbacks
*************************************************************************/

/************************************************************************
	sinewave_trns_uuid
		Returns the UUID of the transparency function set of the
		plugin.
*************************************************************************/
static fzrt_error_td sinewave_trns_uuid(fzrt_UUID_td uuid)
/************************************************************************/
{
	_base_funcs.fzrt_UUID_copy(SINEWAVE_TRNS_PLUGIN_UUID, uuid);
	return FZRT_NOERR;
}

/************************************************************************
	sinewave_trns_io_version
		Tells formZ the version of this plugin's data io.
		This is NOT the same thing as the plugin's version.
		The io of the data may not necessarily change between plugin versions.
*************************************************************************/
static fzrt_error_td sinewave_trns_io_version(fzpl_vers_td* version)
/************************************************************************/
{
	*version = SINEWAVE_TRNS_PLUGIN_DATA_IO_VERSION;
	return FZRT_NOERR;
}

/************************************************************************
	sinewave_trns_set_parameters
		Tells formZ what parameters to cause to show up in the "options"
		dialog of the shader.
*************************************************************************/
static fzrt_error_td sinewave_trns_set_parameters(void)
/************************************************************************/
{
	/* 2d texture mapping */
	_shdr_funcs.fz_shdr_set_wrapped(TRUE);
	/* allow scaling */
	_shdr_funcs.fz_shdr_set_scale_parm(1.0);
	/* allow area sampling */
	_shdr_funcs.fz_shdr_set_area_sample_parm(TRUE);

	/* transparency value of first part of sine wave */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_trns1, 0.0, 1, 1, PARAM_ID_1);
	/* transparency value of second part of sine wave */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_trns2, 1.0, 1, 1, PARAM_ID_2);
	/* amplitude of sine wave */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_wave_height, 0.5, 1, 1, PARAM_ID_HEIGHT);
	/* fuzziness of boundary */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_fuzz, 0.1, 1, 1, PARAM_ID_FUZZ);


	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_1,PARAM_UUID_TRN_1);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_2,PARAM_UUID_TRN_2);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_HEIGHT,PARAM_UUID_TRN_HEIGHT);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_FUZZ,PARAM_UUID_TRN_FUZZ);	


	return FZRT_NOERR;
}

/************************************************************************
	sinewave_trns_pre_render
		Allocates memory, grabs parameter options, pre-computes data.
*************************************************************************/
static fzrt_error_td sinewave_trns_pre_render(void** shdr_data)
/************************************************************************/
{
	fzrt_error_td	  err = FZRT_NOERR;
	sinewave_data_td* sinewave;
	
	*shdr_data = NULL;
	/* allocate memory */
	*shdr_data = make_data_storage();
	if(*shdr_data == NULL)
		err = -1;
	else
	{
		/* use pointer to shdr_data as a pointer to sinewave_data_td. */
		sinewave = (sinewave_data_td*)*shdr_data;
		/* get parameters */
		get_parameters_with_floats(sinewave);
		/* compute how wavey and how fuzzy boundary is (based on params) */
		calc_boundaries(sinewave);
	}

	return err;
}

/************************************************************************
	sinewave_trns_shade_pixel
		Computes the transparency value for the current pixel.
		(Called many times, once for each pixel).
*************************************************************************/
static double sinewave_trns_shade_pixel(void* shdr_data)
/************************************************************************/
{
	sinewave_data_td* sinewave;
	double			  trn;

	sinewave = (sinewave_data_td*)shdr_data;

	trn = compute_sinewave_float_value(sinewave);

	return trn;
}

/************************************************************************
	sinewave_trns_avg_value
		Computes and returns the average color of this shader, as needed
		by formZ in some instances.
*************************************************************************/
static double sinewave_trns_avg_value(void)
/************************************************************************/
{
	double		trn, trn1, trn2;
	fz_type_td	data;
	
	/* don't have access to sinewave storage, so grab transparency */
	/* parameters directly. */
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_1, &data);
	_type_funcs.fz_type_get_double(&data, &trn1);
	_shdr_funcs.fz_shdr_get_parm(PARAM_ID_2, &data);
	_type_funcs.fz_type_get_double(&data, &trn2);

	/* just a simple average of the two, could do something more */
	/* complicated if desired. */
	trn = (trn1 + trn2) * 0.5;

	return trn;
}





/************************************************************************
						Sinewave Bump Shader Callbacks
*************************************************************************/

/************************************************************************
	sinewave_bump_uuid
		Returns the UUID of the bump function set of the plugin.
*************************************************************************/
static fzrt_error_td sinewave_bump_uuid(fzrt_UUID_td uuid)
/************************************************************************/
{
	_base_funcs.fzrt_UUID_copy(SINEWAVE_BUMP_PLUGIN_UUID, uuid);
	return FZRT_NOERR;
}

/************************************************************************
	sinewave_bump_io_version
		Tells formZ the version of this plugin's data io.
		This is NOT the same thing as the plugin's version.
		The io of the data may not necessarily change between plugin versions.
*************************************************************************/
static fzrt_error_td sinewave_bump_io_version(fzpl_vers_td* version)
/************************************************************************/
{
	*version = SINEWAVE_BUMP_PLUGIN_DATA_IO_VERSION;
	return FZRT_NOERR;
}

/************************************************************************
	sinewave_bump_set_parameters
		Tells formZ what parameters to cause to show up in the "options"
		dialog of the shader.
*************************************************************************/
static fzrt_error_td sinewave_bump_set_parameters(void)
/************************************************************************/
{

	/* 2d texture mapping */
	_shdr_funcs.fz_shdr_set_wrapped(TRUE);
	/* allow scaling */
	_shdr_funcs.fz_shdr_set_scale_parm(1.0);
	/* allow area sampling */
	_shdr_funcs.fz_shdr_set_area_sample_parm(TRUE);

	/* bump height value of first part of sine wave */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_bump1, 0.0, 1, 1, PARAM_ID_1);
	/* bump height value of second part of sine wave */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_bump2, 1.0, 1, 1, PARAM_ID_2);
	/* amplitude of sine wave */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_wave_height, 0.5, 1, 1, PARAM_ID_HEIGHT);
	/* fuzziness of boundary */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_fuzz, 0.1, 1, 1, PARAM_ID_FUZZ);


	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_1,PARAM_UUID_BMP_1);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_2,PARAM_UUID_BMP_2);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_HEIGHT,PARAM_UUID_BMP_HEIGHT);	
	_shdr_funcs.fz_shdr_set_parm_anim_id(PARAM_ID_FUZZ,PARAM_UUID_BMP_FUZZ);	

	return FZRT_NOERR;
}

/************************************************************************
	sinewave_bump_pre_render
		Allocates memory, grabs parameter options, pre-computes data.
*************************************************************************/
static fzrt_error_td sinewave_bump_pre_render(void** shdr_data)
/************************************************************************/
{
	fzrt_error_td	  err = FZRT_NOERR;
	sinewave_data_td* sinewave;
	
	*shdr_data = NULL;
	/* allocate memory */
	*shdr_data = make_data_storage();
	if(*shdr_data == NULL)
		err = -1;
	else
	{
		/* use pointer to shdr_data as a pointer to sinewave_data_td. */
		sinewave = (sinewave_data_td*)*shdr_data;
		/* get parameters */
		get_parameters_with_floats(sinewave);
		/* compute how wavey and how fuzzy boundary is (based on params) */
		calc_boundaries(sinewave);
	}

	return err;
}

/************************************************************************
	sinewave_bump_shade_pixel
		Computes the bump height value for the current pixel.
		(Called many times, once for each pixel).
*************************************************************************/
static double sinewave_bump_shade_pixel(void* shdr_data)
/************************************************************************/
{
	sinewave_data_td* sinewave;
	double			  bump;

	sinewave = (sinewave_data_td*)shdr_data;

	bump = compute_sinewave_float_value(sinewave);

	return bump;
}





/************************************************************************
					Sinewave Background Shader Callbacks
*************************************************************************/

/************************************************************************
	sinewave_bgnd_uuid
		Returns the UUID of the background function set of the
		plugin.
*************************************************************************/
static fzrt_error_td sinewave_bgnd_uuid(fzrt_UUID_td uuid)
/************************************************************************/
{
	_base_funcs.fzrt_UUID_copy(SINEWAVE_BGND_PLUGIN_UUID, uuid);
	return FZRT_NOERR;
}

/************************************************************************
	sinewave_bgnd_io_version
		Tells formZ the version of this plugin's data io.
		This is NOT the same thing as the plugin's version.
		The io of the data may not necessarily change between plugin versions.
*************************************************************************/
static fzrt_error_td sinewave_bgnd_io_version(fzpl_vers_td* version)
/************************************************************************/
{
	*version = SINEWAVE_BGND_PLUGIN_DATA_IO_VERSION;
	return FZRT_NOERR;
}

/************************************************************************
	sinewave_bgnd_set_parameters
		Tells formZ what parameters to cause to show up in the "options"
		dialog of the shader.
*************************************************************************/
static fzrt_error_td sinewave_bgnd_set_parameters(void)
/************************************************************************/
{
	fz_rgb_float_td def_col1;
	fz_rgb_float_td def_col2;
	
	/* default colors */
	def_col1.red   = 0.0;
	def_col1.green = 0.0;
	def_col1.blue  = 0.0;
	def_col2.red   = 1.0;
	def_col2.green = 1.0;
	def_col2.blue  = 1.0;

	/* allow scaling */
	_shdr_funcs.fz_shdr_set_scale_parm(1.0);
	/* allow area sampling */
	_shdr_funcs.fz_shdr_set_area_sample_parm(TRUE);

	/* color of first part of sine wave */
	_shdr_funcs.fz_shdr_set_col_parm(_color1, &def_col1, PARAM_ID_1);
	/* color of second part of sine wave */
	_shdr_funcs.fz_shdr_set_col_parm(_color2, &def_col2, PARAM_ID_2);
	/* amplitude of sine wave */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_wave_height, 0.5, 1, 1, PARAM_ID_HEIGHT);
	/* fuzziness of boundary */
	_shdr_funcs.fz_shdr_set_sld_flt_parm(_fuzz, 0.1, 1, 1, PARAM_ID_FUZZ);

	return FZRT_NOERR;
}

/************************************************************************
	sinewave_bgnd_pre_render
		Allocates memory, grabs parameter options, pre-computes data.
*************************************************************************/
static fzrt_error_td sinewave_bgnd_pre_render(void** shdr_data)
/************************************************************************/
{
	fzrt_error_td	  err = FZRT_NOERR;
	sinewave_data_td* sinewave;
	
	*shdr_data = NULL;
	/* allocate memory */
	*shdr_data = make_data_storage();
	if(*shdr_data == NULL)
		err = -1;
	else
	{
		/* use pointer to shdr_data as a pointer to sinewave_data_td. */
		sinewave = (sinewave_data_td*)*shdr_data;
		/* get parameters */
		get_parameters_with_colors(sinewave);
		/* compute how wavey and how fuzzy boundary is (based on params) */
		calc_boundaries(sinewave);
	}

	return err;
}

/************************************************************************
	sinewave_bgnd_shade_pixel
		Computes the color for the current pixel.
		(Called many times, once for each pixel).
*************************************************************************/
static fz_rgb_float_td sinewave_bgnd_shade_pixel(void* shdr_data)
/************************************************************************/
{
	sinewave_data_td* sinewave;
	fz_rgb_float_td	  col;
	fz_xy_td			  xy;

	sinewave = (sinewave_data_td*)shdr_data;

	/* get current pixel space coordinate */
	_shdr_funcs.fz_shdr_get_ispace_xy(&xy);
	
	col = compute_sinewave_color_value(sinewave, &xy);

	return col;
}

