/****************************************************************************/
/*                                                                          */
/*  VolVis is a volume visualization system for investigating, manipulating */
/*  and rendering geometric and volumetric data.                            */
/*                                                                          */
/*  Copyright (C) 1993 by the Research Foundation of the State University   */
/*                            of New York                                   */
/*                                                                          */
/*  This program is free software; you can redistribute it and/or modify    */
/*  it under the terms of the GNU General Public License as published by    */
/*  the Free Software Foundation; either version 1, or (at your option)     */
/*  any later version.                                                      */
/*                                                                          */
/*  This program is distributed in the hope that it will be useful,         */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of          */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           */
/*  GNU General Public License for more details.                            */
/*                                                                          */
/*  You should have received a copy of the GNU General Public License       */
/*  along with this program; if not, write to the Free Software             */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               */
/*                                                                          */
/*  For information on VolVis, contact us at:                               */
/*                                                                          */
/*                volvis@cs.sunysb.edu                         (email)      */
/*                                                                          */
/*                Lisa Sobierajski & Ricardo Avila             (US Mail)    */
/*                Department of Computer Science                            */
/*                State University of New York at Stony Brook               */
/*                Stony Brook, New York  11794-4400                         */
/*                                                                          */
/****************************************************************************/




/*
 *			File: C_image_control.c
 *		      Author: Lisa Sobierajski 
 *			Date: 
 *		 Description: Volume Control Routines Of VolVis
 *	Modification History:
 *
 *		Who?		When?		Why?
 *	--------------------------------------------------------------------
 *
 */


# include <stdio.h>
# include <string.h>
# include "C_volvis.h"

int C_enter_volume( world, volume, volume_name, file_name )
C_World			*world;
C_Volume		*volume;
char			*volume_name;
char			*file_name;
{
	extern C_View	view;
	int		loop;
	char		tmp_name[30];

	/****	Check if there are any available entries	****/

	if ( world->num_volumes == C_MAX_VOLUMES )
	{
		C_error_message("Too many volumes!!!\n");
		return C_ERROR;
	}

	world->volume[world->num_volumes] = volume;

	/****   Check if this name exists already - if it    ****/
	/****   does, find the first number we can append to ****/
	/****   it to make it unique			     ****/
	
	loop = 1;

	sprintf( tmp_name, "%s", volume_name );

	while ( C_get_volume_index(world, tmp_name ) != C_NO_MATCH )
	{
		loop++;
		sprintf(tmp_name, "%s_%d", volume_name, loop );
	}

	/****	Now make a copy of the volume_name    ****/
	volume->volume_name = 
		(char *) malloc( sizeof(char)*(strlen(tmp_name) + 1) );
	strcpy(volume->volume_name, tmp_name);

	/****	Now make a copy of the file_name    ****/
	if ( file_name )
	{
	  volume->file_name = 
		(char *) malloc( sizeof(char)*(strlen(file_name) + 1) );
	  strcpy(volume->file_name, file_name);
	}
	else
	{
	  volume->file_name = NULL;
	}

	(world->num_volumes)++;


        /*  Put the view in a good place if this is the  */
        /*  first volume loaded into the world           */

        if ( world->num_volumes == 1 )
        {
/***
printf("gonna put a cut in\n");
        volume->num_cuts = 1;
        volume->local_cut[0] = C_New( C_CutGeom );
        volume->local_cut[0]->cut_type = C_SIMPLE_BOX_CUT;
        volume->local_cut[0]->cut.box_cut = (float *)malloc( 6*sizeof(float) );
printf("setting up cut\n");
        *(volume->local_cut[0]->cut.box_cut     ) = volume->x_size_voxels/2;
        *(volume->local_cut[0]->cut.box_cut + 1 ) = 0.0;
        *(volume->local_cut[0]->cut.box_cut + 2 ) = 0.0;
        *(volume->local_cut[0]->cut.box_cut + 3 ) = volume->x_size_voxels - 1;
        *(volume->local_cut[0]->cut.box_cut + 4 ) = volume->y_size_voxels - 1;
        *(volume->local_cut[0]->cut.box_cut + 5 ) = volume->z_size_voxels - 1;
printf("done\n");
****/

                view.orig_c_sys.origin.x =
                view.c_sys.origin.x      =
                        world->volume[0]->x_size_units / 2.0;
                view.orig_c_sys.origin.y =
                view.c_sys.origin.y      =
                        world->volume[0]->y_size_units / 2.0;
                view.orig_c_sys.origin.z =
                view.c_sys.origin.z      =
                        -world->volume[0]->z_size_units;

                view.orig_c_sys.x_axis.x =
                view.c_sys.x_axis.x      = 1.0;
                view.orig_c_sys.x_axis.y =
                view.c_sys.x_axis.y      = 0.0;
                view.orig_c_sys.x_axis.z =
                view.c_sys.x_axis.z      = 0.0;

                view.orig_c_sys.y_axis.x =
                view.c_sys.y_axis.x      = 0.0;
                view.orig_c_sys.y_axis.y =
                view.c_sys.y_axis.y      = 1.0;
                view.orig_c_sys.y_axis.z =
                view.c_sys.y_axis.z      = 0.0;
                view.c_sys.y_axis.z      = 0.0;
 
                view.orig_c_sys.z_axis.x =
                view.c_sys.z_axis.x      = 0.0;
                view.orig_c_sys.z_axis.y =
                view.c_sys.z_axis.y      = 0.0;
                view.orig_c_sys.z_axis.z =
                view.c_sys.z_axis.z      = 1.0;
 
                C_identity3D( &(view.transform) );
                C_create_view_matrices( &view );
        }

	C_update_system( C_VOLUME_CREATED );

	return C_OK;

}

int C_delete_volume( world, volume_name )
C_World			*world;
char			*volume_name;
{
	void		C_free_volume();

	int		index;
	C_Volume	*volume;
	int		loop;

	index = C_get_volume_index( world, volume_name );
	
	if ( index == C_NO_MATCH ) return C_ERROR;

	volume = world->volume[index];

	C_free_volume( volume );

	for ( loop = index; loop < world->num_volumes - 1; loop++ )
		world->volume[loop] = world->volume[loop+1];

	world->volume[world->num_volumes] = NULL;

	world->num_volumes--;

	C_update_system( C_VOLUME_DELETED );
}

void C_free_volume( volume )
C_Volume	*volume;
{

	void		C_free_scalar_data_8bit();
	void		C_free_geo_data();
	void		C_free_cut_geom();
	void		C_free_volume_texture();
	void		C_free_parc_info();

	int		loop;


	switch ( volume->data_type )
	{
	  case C_SCALAR_DATA_8BIT:

		C_free_scalar_data_8bit( volume->data.scalar_data_8bit );
		break;
		
	  case C_GEOMETRIC_DATA:

		C_free_geo_data( volume->data.geo_data );
		break;

	  default:

		C_error_message("fix this\n");
		break;
	}

	for ( loop = 0; loop < volume->num_cuts; loop++ )
		C_free_cut_geom( volume->local_cut[loop] );

	if ( volume->color_data.single_color )
		free( volume->color_data.single_color );

	if ( volume->color_data.color_array )
		free( volume->color_data.color_array );

	switch ( volume->texture_type )
	{
	    case C_VOLUME_TEXTURE:
		C_free_volume_texture( volume->texture.voltex );
		break;

	    case C_RAD_TEXTURE:
		C_free_volume_texture( volume->texture.radtex );
		break;
	}

	if ( volume->local_shade.simple_shade )
		free( volume->local_shade.simple_shade );

	if ( volume->local_shade.array_shade )
		free( volume->local_shade.array_shade );

	if ( volume->volume_name )
		free( volume->volume_name );

	if ( volume->file_name )
		free( volume->file_name );
	
	if ( volume->icon_8bit )
		free( volume->icon_8bit );
	
	if ( volume->icon_24bit )
		free( volume->icon_24bit );

	C_free_parc_info( volume->p_info );


}

void C_free_scalar_data_8bit( scalar_data )
C_ScalarData_8bit	*scalar_data;
{
	if (!scalar_data) return;

	scalar_data->references--;

	if ( scalar_data->references <= 0 )
	{
	    switch ( scalar_data->seg_type )
	    {
		case C_ISO_SURFACE:
		    break;

		case C_SCALAR_OPACITY:
		    if ( scalar_data->seg.s_opacity )
			free( scalar_data->seg.s_opacity );
		    break;
	    }

	    if ( scalar_data->scalar_data )
		free( scalar_data->scalar_data );

	    free( scalar_data );
	}
}

void C_free_geo_data( geo_data )
C_GeoData		*geo_data;
{
	if ( !geo_data ) return;

	switch ( geo_data->geo_type )
	{
	    case C_POLYGON:
		if ( geo_data->geo_object.polygon )
			free ( geo_data->geo_object.polygon );
		break;

	    case C_MULTIPOLY:
	    case C_HOLLOW_MULTIPOLY:
		if ( geo_data->geo_object.polygon )
			free ( geo_data->geo_object.polygon );
		break;

	    case C_TORUS:
	    case C_HOLLOW_TORUS:
		if ( geo_data->geo_object.torus )
			free ( geo_data->geo_object.torus );
		break;
	}

	free( geo_data );
}

void C_free_cut_geom( cut_geom )
C_CutGeom		*cut_geom;
{
	if ( !cut_geom ) return;

	switch( cut_geom->cut_type )
	{
	    case C_PLANE_CUT:
		if ( cut_geom->cut.plane )
			free( cut_geom->cut.plane );
		break;

	}

	free( cut_geom );
}

void C_free_volume_texture( volume_texture )
C_VolTexture		*volume_texture;
{
	if ( !volume_texture ) return;

	volume_texture->references--;

	if ( volume_texture->references <= 0 )
	{
		if ( volume_texture->red )
			free( volume_texture->red );

		if ( volume_texture->green )
			free( volume_texture->green );

		if ( volume_texture->blue )
			free( volume_texture->blue );

		free( volume_texture );
		
		volume_texture = NULL;
	}
}

void C_free_parc_info( parc_info )
C_ParcInfo		*parc_info;
{
	C_ParcSubNode	*node_ptr;
	C_ParcSubNode	*next_node_ptr;

	if ( !parc_info ) return;

	node_ptr = parc_info->sub_list;
	
	while ( node_ptr )
	{
		next_node_ptr = node_ptr->next;
		free( node_ptr );
		node_ptr = next_node_ptr;
	}

	free( parc_info );
}

int C_get_volume_index( world, volume_name )
C_World			*world;
char			*volume_name;
{
	int	loop;

	for (loop = 0; loop < world->num_volumes; loop++)
	{
		if (strcmp( volume_name, world->volume[loop]->volume_name )
			== 0 ) 
		{
			return loop;
		}
	}
		
	return C_NO_MATCH;
}

int C_check_for_name( world, name )
C_World                 *world;
char                    *name;
{
        int     loop;

        for (loop = 0; (loop < world->num_volumes); loop++)
        {
                if (strcmp( name, world->volume[loop]->volume_name )
                        == 0 )
        	{
			return (loop + 1);
		}
	}
        for (loop = 0; loop < world->num_lights; loop++)
        {
                if (strcmp( name, world->light[loop]->light_name )
                        == 0 )
                {
                        return (loop + world->num_volumes + 1);
		}
	}

	return (0);
}

int C_clone_volume( orig_vol )
C_Volume	*orig_vol;
{
        extern void     C_copy_matrix();
        extern void     C_copy_plane();
        extern void     C_copy_c_sys();
        extern int      C_enter_volume();
 
        extern C_World  world;
 
        int             loop;
        char            new_name[20];
        C_Volume        *clone_vol;
        C_Polygon       *clone_poly;
        C_Polygon       *orig_poly;
 
        C_create_volume( &clone_vol, orig_vol->color_type,
                     orig_vol->shade_type );
 
        if ( !clone_vol ) return C_ERROR;
 
        C_copy_c_sys( &(orig_vol->orig_c_sys), &(clone_vol->orig_c_sys) );
        C_copy_c_sys( &(orig_vol->c_sys), &(clone_vol->c_sys) );
        C_copy_matrix( &(orig_vol->transform), &(clone_vol->transform) );
	 
        clone_vol->unit_type = orig_vol->unit_type;

        C_copy_matrix(&(orig_vol->wtol_voxels), &(clone_vol->wtol_voxels));
        C_copy_matrix(&(orig_vol->ltow_voxels), &(clone_vol->ltow_voxels));
        C_copy_matrix(&(orig_vol->wtol_units),  &(clone_vol->wtol_units));
        C_copy_matrix(&(orig_vol->ltow_units),  &(clone_vol->ltow_units));

        clone_vol->x_size_voxels = orig_vol->x_size_voxels;
        clone_vol->y_size_voxels = orig_vol->y_size_voxels;
        clone_vol->z_size_voxels = orig_vol->z_size_voxels;
        clone_vol->x_size_units = orig_vol->x_size_units;
        clone_vol->y_size_units = orig_vol->y_size_units;
        clone_vol->z_size_units = orig_vol->z_size_units;

        for ( loop = 0; loop < C_NUM_FACES; loop++ )
            C_copy_plane( &(orig_vol->plane_equation[loop]),
                          &(clone_vol->plane_equation[loop]) );

        clone_vol->data_type = orig_vol->data_type;

        clone_vol->num_cuts = orig_vol->num_cuts;
        for ( loop = 0; loop < orig_vol->num_cuts; loop++ )
        {
            clone_vol->local_cut[loop] = C_New( C_CutGeom );
            if (!clone_vol->local_cut[loop])
            {
                    C_error_message("Not enough memory to clone\n");
                    C_free_volume( clone_vol );
                    return C_ERROR;
            }
            clone_vol->local_cut[loop]->cut_type =
                    orig_vol->local_cut[loop]->cut_type;

            switch( clone_vol->local_cut[loop]->cut_type )
            {
                case C_PLANE_CUT:

                    clone_vol->local_cut[loop]->cut.plane = C_New(C_Plane);
                    if (!clone_vol->local_cut[loop]->cut.plane)
                    {
                        C_error_message("Not enough memory to clone\n");
                        C_free_volume( clone_vol );
                        return C_ERROR;
                    }
                    C_copy_plane( orig_vol->local_cut[loop]->cut.plane,
                                  clone_vol->local_cut[loop]->cut.plane );

                    break;

                case C_SIMPLE_BOX_CUT:

/*****  Fill this in!!!!   ****/

                    break;
            }
        }

        switch( clone_vol->color_type )
        {
                case C_SINGLE_COLOR:

                    clone_vol->color_data.single_color->red =
                            orig_vol->color_data.single_color->red;
                    clone_vol->color_data.single_color->green =
                            orig_vol->color_data.single_color->green;
                    clone_vol->color_data.single_color->blue =
                            orig_vol->color_data.single_color->blue;

                    break;

                case C_COLOR_ARRAY:

/************Fill this in!!!!***********/

                    break;
        }


        switch ( clone_vol->shade_type )
        {
              case C_SIMPLE_SHADE:

                clone_vol->local_shade.simple_shade->diffuse_coef =
                   orig_vol->local_shade.simple_shade->diffuse_coef;
                clone_vol->local_shade.simple_shade->specular_coef =
                   orig_vol->local_shade.simple_shade->specular_coef;
                clone_vol->local_shade.simple_shade->specular_power =
                   orig_vol->local_shade.simple_shade->specular_power;
                clone_vol->local_shade.simple_shade->transmit_coef =
                   orig_vol->local_shade.simple_shade->transmit_coef;
                clone_vol->local_shade.simple_shade->transmissitivity =
                   orig_vol->local_shade.simple_shade->transmissitivity;
                clone_vol->local_shade.simple_shade->index_of_refraction =
                   orig_vol->local_shade.simple_shade->index_of_refraction;

                break;

              case C_ARRAY_SHADE:

/**************Fill In!!!**************/

                break;

        }

        clone_vol->texture_type = orig_vol->texture_type;

        switch( clone_vol->texture_type )
        {
                case C_VOLUME_TEXTURE:

                    clone_vol->texture.voltex = orig_vol->texture.voltex;
                    clone_vol->texture.voltex->references++;

                    break;
        }

        clone_vol->visible           = orig_vol->visible;
        clone_vol->modifiable        = orig_vol->modifiable;
        clone_vol->data_origin       = orig_vol->data_origin;
        clone_vol->data_modification = orig_vol->data_modification;

        clone_vol->data_type = orig_vol->data_type;

        switch( clone_vol->data_type )
        {
              case C_GEOMETRIC_DATA:

                clone_vol->data.geo_data = C_New( C_GeoData );
                if ( !clone_vol->data.geo_data )
                {
                    C_error_message("Not enough memory to clone\n");
                    C_free_volume( clone_vol );
                    return C_ERROR;
                }
                clone_vol->data.geo_data->geo_type =
                    orig_vol->data.geo_data->geo_type;

                switch ( clone_vol->data.geo_data->geo_type )
                {
                    case C_SPHERE:
                    case C_HOLLOW_SPHERE:
                    case C_CYLINDER:
                    case C_HOLLOW_CYLINDER:
                        break;

                    case C_POLYGON:

                        clone_vol->data.geo_data->geo_object.polygon =
                                C_New( C_Polygon );
                        if (!clone_vol->data.geo_data->geo_object.polygon )
                        {
                            C_error_message("Not enough memory to clone\n");
                            C_free_volume( clone_vol );
                            return C_ERROR;
                        }

                        clone_poly =
                            clone_vol->data.geo_data->geo_object.polygon;
                        orig_poly =
                            orig_vol->data.geo_data->geo_object.polygon;

                        C_copy_plane( &(orig_poly->plane),
                                      &(clone_poly->plane) );

                        clone_poly->num_vertices = orig_poly->num_vertices;

                        clone_poly->vertices = ( C_FPosition *)
                            malloc( sizeof( C_FPosition ) *
                                    clone_poly->num_vertices );

                        for ( loop = 0; loop < clone_poly->num_vertices;
                              loop++ )
                        {
                            clone_poly->vertices[loop].x =
                                    orig_poly->vertices[loop].x;
                            clone_poly->vertices[loop].y =
                                    orig_poly->vertices[loop].y;
                            clone_poly->vertices[loop].z =
                                    orig_poly->vertices[loop].z;
                        }

                        break;

/***** fill in other cases   *************/
                }

                break;

              case C_SCALAR_DATA_8BIT:

                clone_vol->data.scalar_data_8bit = C_New(C_ScalarData_8bit);
                if ( !clone_vol->data.scalar_data_8bit )
                {
                    C_error_message("Not enough memory to clone\n");
                    C_free_volume( clone_vol );
                    return C_ERROR;
                }

                clone_vol->data.scalar_data_8bit->seg_type =
                            orig_vol->data.scalar_data_8bit->seg_type;

                clone_vol->data.scalar_data_8bit->seg.isovalue =
                    orig_vol->data.scalar_data_8bit->seg.isovalue;

		clone_vol->data.scalar_data_8bit->seg.s_opacity = 
			C_New( C_OpacityArray );

                if ( !clone_vol->data.scalar_data_8bit->seg.s_opacity )
                {
                        C_error_message("Not enough memory to clone\n");
                        C_free_volume( clone_vol );
                        return C_ERROR;
                }

		for ( loop = 0; loop < 255; loop++ )
			clone_vol->data.scalar_data_8bit->
					seg.s_opacity->opacity[loop] = 
			orig_vol->data.scalar_data_8bit->
					seg.s_opacity->opacity[loop]; 

                clone_vol->data.scalar_data_8bit->scalar_data =
                    orig_vol->data.scalar_data_8bit->scalar_data;

                clone_vol->data.scalar_data_8bit->references++;

                if ( (C_parc_subdivide( clone_vol,
                                        orig_vol->p_info->sub_level )) ==
                      C_ERROR )
                {
                    if ( (C_parc_subdivide( clone_vol, 0 )) == C_ERROR )
                    {
                        C_error_message("Not enough memory to clone\n");
                        C_free_volume( clone_vol );
                        return C_ERROR;
                    }
                }

        }

        if ( (C_enter_volume( &world, clone_vol, orig_vol->volume_name,
                        orig_vol->file_name )) == C_ERROR )
                return C_ERROR;

	return C_OK;

}
