/****************************************************************************/
/*                                                                          */
/*  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_motif_win.c
 *		      Author: Rick Avila & Morita
 *			Date: 03/07/92
 *		 Description: Motif Windowing Routines Of VolVis
 *	Modification History:
 *
 *		Who?		When?		Why?
 *	--------------------------------------------------------------------
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <malloc.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/BulletinB.h>
#include <Xm/LabelG.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/DrawingA.h>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <Xm/TextF.h>
#include <unistd.h>
#include <pwd.h>

#include "C_volvis.h"
#include "MOTIF_windefs.h"
#include "C_fio.h"
#include "C_help.h"

/* Global Variables For Motif Windowing */
extern Widget		vv_toplevel;	/* VolVis toplevel Shell Widget */
extern Widget		fio_bbdialog;	/* File I/O Bulletin Board Dialog */
extern C_WindowDefs	window_defs;
extern C_World		world;
extern C_View		view;
extern C_ImageTable	image_table;

/*
 *        Procedure Name:  create_save_icon 
 *          Return Value:  none 
 *       Input Variables:  icon		- contains information about one icon 
 *			   index	- index into the volume table  
 *      Output Variables:   
 *      Update Variables:
 *      Global Variables:  world.volume - volume table of VolVis 
 *                        
 *           Description:  This function will create an icon for either an
 *			   image or slice file.  It will either read the 
 *			   image table in volvis or the volume table in
 *			   volvis and create a icon to be displayed on the 
 *			   drawing area.
 */

void create_save_icon(icon,index)
Icon_Info *icon;
int	  index;
{
  extern char 	*get_extension();
  extern void 	make_blank_icon();
  extern int 	machine_24_bit();
  int		read_image_table();
  int		read_world_volume_table();

  int		i;
  char		*extension;
  C_Image       image_data;
 
	extension = get_extension(icon->filename);
 
	if (strcmp(extension,"img")==0)
	{
	    /* read the image in the image table */
	    if (read_image_table(icon,index, &image_data) == C_ERROR)
		make_blank_icon(icon);
	}
	else if (strcmp(extension,"slc") == 0)
 	{
	    if (machine_24_bit(icon->button))
	    {
		if (world.volume[index]->icon_24bit == NULL)
		/* if icon was not created for the volume */
		{
		    /* read the volume table and create an icon image */
		    if (read_world_volume_table(icon,index) == C_ERROR)
			make_blank_icon(icon);

		    world.volume[index]->icon_24bit = (unsigned int *) 
			malloc( C_ICON_IMAGE_HEIGHT * C_ICON_IMAGE_WIDTH * 
			sizeof(unsigned int));

		    if (!world.volume[index]->icon_24bit)
		    {
			C_error_message("Out of Memory Creating Save Icons");
			exit(1);
		    }

		    /* save the icon in the volume */
		    for(i=0;i< C_ICON_IMAGE_HEIGHT * C_ICON_IMAGE_WIDTH;++i)
			*(world.volume[index]->icon_24bit + i) = 
				*(icon->icon_24_data + i);
		}
		else  
		/* icon is in the volume, just copy it into the icon to be 
		 * displayed
		 */
		{
		    icon->icon_24_data = (unsigned int *) 
			malloc(C_ICON_IMAGE_HEIGHT * C_ICON_IMAGE_WIDTH *
			sizeof(unsigned int));
		    for(i=0;i< C_ICON_IMAGE_HEIGHT * C_ICON_IMAGE_WIDTH;++i)
			*(icon->icon_24_data + i) = 
				*(world.volume[index]->icon_24bit + i);
		}
	    }
	    else
	    {
		if (world.volume[index]->icon_8bit == NULL)
                /* if icon was not created for the volume */
		{
                    /* read the volume table and create an icon image */
		    if (read_world_volume_table(icon,index) == C_ERROR)
			make_blank_icon(icon);

		    world.volume[index]->icon_8bit = (unsigned char *) 
			malloc(C_ICON_IMAGE_HEIGHT * C_ICON_IMAGE_WIDTH * 
			sizeof(unsigned char));

		    if (!world.volume[index]->icon_8bit)
                    {   
                        C_error_message("Out Of Memory Creating Save Icons !!");
                        exit(1);
                    }
 
                    /* save the icon in the volume */
		    for(i=0;i< C_ICON_IMAGE_HEIGHT * C_ICON_IMAGE_WIDTH;++i)
			*(world.volume[index]->icon_8bit + i) = 
				*(icon->icon_8_data + i);
		}
		else
                /* icon is in the volume, just copy it into the icon to be 
                 * displayed
                 */
		{
		    icon->icon_8_data = (unsigned char *) 
			malloc(C_ICON_IMAGE_HEIGHT * C_ICON_IMAGE_WIDTH * 
			sizeof(unsigned char));
		    for(i=0;i< C_ICON_IMAGE_HEIGHT * C_ICON_IMAGE_WIDTH;++i)
			*(icon->icon_8_data + i) = 
				*(world.volume[index]->icon_8bit + i);
		}		
	    }
	}
}

/*
 *        Procedure Name:  read_image_table 
 *          Return Value:  int		- if reading image table was sucessful 
 *       Input Variables:  icon		- contains information about one icon
 *                         index        - index into the volume table
 *			   image_data  	- used to contain the image   
 *      Output Variables: 
 *      Update Variables:
 *      Global Variables:  image_table  - the volvis image table 
 *                        
 *           Description:  This function will read the image table according
 *			   to the index passed in.  This image read is going
 *			   to be resized to the correct icon image and then
 *			   saved into the icon which is to be displayed on
 *			   the drawing area.  The header information of the
 *			   icon will be updated here as well
 */

int read_image_table(icon,index,image_data)
Icon_Info *icon;
int	  index;
C_Image   *image_data;
{

  int 		size_of_image,		/* size of the image read */  
   		i,j,
   		STATUS;			/* status of the read */
  C_VolTexture  *texture_data;		/* used to call another function */

	size_of_image = image_table.image_entry[index]->image->width *
				image_table.image_entry[index]->image->height;

	icon->image_info.width	= image_table.image_entry[index]->image->width;
	icon->image_info.height = image_table.image_entry[index]->image->height;
	icon->image_info.depth	= image_table.image_entry[index]->image->depth;
	icon->image_info.render_type = 
	      image_table.image_entry[index]->image->image_info.render_type;
        icon->image_info.image_accuracy = 
              image_table.image_entry[index]->image->image_info.image_accuracy;
	icon->image_info.compute_time = 
	      image_table.image_entry[index]->image->image_info.compute_time;
        icon->image_info.compute_shadows = 
              image_table.image_entry[index]->image->image_info.compute_shadows;

        icon->image_info.levels_of_reflection =
              image_table.image_entry[index]->image->image_info.levels_of_reflection;
        icon->image_info.levels_of_transmission =
              image_table.image_entry[index]->image->image_info.levels_of_transmission;

        icon->image_info.levels_of_indirect_light =
              image_table.image_entry[index]->image->image_info.levels_of_indirect_light;

	if ((image_data->red = ( C_Byte * ) 
		  malloc( size_of_image * sizeof( C_Byte ))) == NULL)
	{
	    C_error_message("Not Enough Memory To Save The Image !!!\n");
	    return C_ERROR;			
	}

	/* read the red component of the image */
	for (j=0;j<size_of_image;++j)
	    *(image_data->red +j) = 
			*(image_table.image_entry[index]->image->red +j);

	if ( icon->image_info.depth == 3 )
	{
	    if ((image_data->green = ( C_Byte * ) 
		 malloc( size_of_image * sizeof( C_Byte ))) == NULL)
	    {
		C_error_message("Not Enough Memory To Read The Image !!!\n");
		return C_ERROR;			
	    }

	    if ((image_data->blue = ( C_Byte * ) 
			  malloc( size_of_image * sizeof( C_Byte ))) == NULL)
	    {
		C_error_message("Not Enough Memory To Read The Image !!!\n");
		return C_ERROR;			
	    }

	    for (j=0;j<size_of_image;++j)
	    {
	        /* read the green component of the image */
		*(image_data->green +j) = 
			*(image_table.image_entry[index]->image->green +j);

	        /* read the blue component of the image */
		*(image_data->blue +j) = 
			*(image_table.image_entry[index]->image->blue +j);
	    }
	}
	    
	/* convert the image to C_ICON_IMAGE_WIDTH by C_ICON_IMAGE_HEIGHT */
	if (data_conversion(icon->image_info.height, 
            icon->image_info.width, 0,icon,texture_data,*image_data) == C_ERROR)
	    return C_ERROR;

	return(C_OK);
}

/*
 *        Procedure Name:  read_world_volume_table 
 *          Return Value:  int		-  see if read was valid  
 *       Input Variables:  icon 	-  contains information about one icon
 *                         index        -  index into the volume table 
 *      Output Variables: 
 *      Update Variables:
 *      Global Variables:  world.volume -  the volvis world table  
 *           Description:  This function will read the volume table according
 *			   to the index passed in.  An icon will be created
 * 			   from the volume read.  The header information 
 *			   will be updated also.

 */
int read_world_volume_table(icon,index)
Icon_Info   *icon;
int	    index;
{
  extern int  decide_axis();
  extern int  resize_image();

  int 		code,		/* which way to read the volume */
   		loop = 0,       
   		i = 0, j = 0,
   		x_voxels,  y_voxels,  z_voxels,
   		x_counter, y_counter, z_counter,
   		STATUS;  	/* progress status */

  C_Voxel_8bit 	*max_ptr;
  C_Voxel_8bit 	*scan_ptr;
  C_Voxel_8bit 	*temp_scan_ptr;
  C_Voxel_8bit 	*column_scan_ptr;
  C_Voxel_8bit 	*temp_max_ptr;


	/* update the header information */
	x_voxels = icon->slice_info.x_voxels =
				  world.volume[index]->x_size_voxels;
	y_voxels = icon->slice_info.y_voxels =
				  world.volume[index]->y_size_voxels;
	z_voxels = icon->slice_info.z_voxels = 
	 			  world.volume[index]->z_size_voxels;

	icon->slice_info.unit_type = world.volume[index]->unit_type;
	icon->slice_info.data_origin = world.volume[index]->data_origin;
	icon->slice_info.data_modification = 
			world.volume[index]->data_modification;
	icon->slice_info.bits_per_voxel = 8;
	icon->slice_info.x_units = world.volume[index]->x_size_units;
	icon->slice_info.y_units = world.volume[index]->y_size_units;
	icon->slice_info.z_units = world.volume[index]->z_size_units;

	/* decide which way we should look at the volume */
	code = decide_axis(x_voxels, y_voxels, z_voxels);		    

	if (code == C_XY_Z)
	/* if we are reading from XY in direction of Z */
	{
        	max_ptr = (C_Voxel_8bit *) malloc(x_voxels * y_voxels);
        	bzero(max_ptr, sizeof(C_Voxel_8bit) * x_voxels * y_voxels);
	}
	else if (code == C_XZ_Y)
	/* if we are reading from XZ in direction of Y */
	{
		max_ptr = (C_Voxel_8bit *) malloc(x_voxels * z_voxels);
        	bzero(max_ptr, sizeof(C_Voxel_8bit) * x_voxels * z_voxels);
	}
	else if (code == C_YZ_X)
	/* if we are reading from YZ in direction of X */
	{
		max_ptr = (C_Voxel_8bit *) malloc(z_voxels * y_voxels);
		bzero(max_ptr, sizeof(C_Voxel_8bit) * z_voxels * y_voxels);
	}

        if (!max_ptr)
        {
            C_error_message("Out Of Memory Finding maximum projection !!!\n");
            return( C_ERROR );
        }

        scan_ptr = NULL;
        temp_max_ptr = max_ptr;
  	
	for( z_counter = 0; z_counter < z_voxels; ++z_counter )
	{
	    if (scan_ptr)
		free(scan_ptr);

	    scan_ptr = (C_Voxel_8bit *) malloc(x_voxels * y_voxels);

	    if (!scan_ptr)
	    {
		C_error_message("Not enough memory to read one slice\n");
		return(C_ERROR);
	    }

	    /* read one slice of the volume */
	    j=0;
	    for(i = loop; i< loop + x_voxels * y_voxels; ++i)
		*(scan_ptr + j++) = 
		  *(world.volume[index]->data.scalar_data_8bit->scalar_data+ i);
		
	    /* read the next slice next time */
	    loop += x_voxels * y_voxels;

	    if (code == C_XY_Z)
            /* if we want to move in Z direction */
	    {
                /* we are moving oppsite of the direction we read
                   the slice
                */
		temp_scan_ptr = scan_ptr + x_voxels * y_voxels;
		temp_max_ptr  = max_ptr;
                for (y_counter = y_voxels; y_counter >0; y_counter--)
                {   
                    /* go to beginning of the next row */
                    temp_scan_ptr -= x_voxels;
                    for(x_counter =  0; x_counter < x_voxels; x_counter++)
                    {
                        if (*temp_scan_ptr > *temp_max_ptr)
                            *temp_max_ptr = *temp_scan_ptr;
                        temp_max_ptr++;
                        temp_scan_ptr++;
                    }
                    /* go back to beginning of  a row */
                    temp_scan_ptr -= x_voxels;
                }
	    }
	    else if (code == C_XZ_Y)
            /* if we want to move in Y direction */
	    {
                /* we don't have to worry about the direction in which
                   we are reading the slice because we could be looking
                   from either the top or the bottom
                */
		temp_scan_ptr = scan_ptr;
		for ( y_counter = 0; y_counter < y_voxels; y_counter++ )
		{
		    for ( x_counter = 0; x_counter < x_voxels; x_counter++ )
		    {
			if (*temp_scan_ptr > *temp_max_ptr)
				*temp_max_ptr = *temp_scan_ptr;
			temp_max_ptr++;
			temp_scan_ptr++;
		    }
                    /* keep comparing one row */
		    temp_max_ptr -= x_voxels;
		}
                /* finds one row of the max ptr at a time */
		temp_max_ptr += x_voxels;
	    }
	    else if (code == C_YZ_X)
            /* if we want to move in X direction */
	    {
                /* we don't have to worry about the direction in which
                   we are reading the slice because we could be looking
                   from either the left side or the right
                */ 
		temp_scan_ptr = scan_ptr;
		for ( x_counter = 0; x_counter < x_voxels; x_counter++ )
		{
                    /* we are reading a column at a time */
		    column_scan_ptr = temp_scan_ptr;
		    for ( y_counter = 0; y_counter < y_voxels; y_counter++ )
		    {
			if (*column_scan_ptr > *temp_max_ptr)
				*temp_max_ptr = *column_scan_ptr;
			temp_max_ptr++;

                        /* goto the next row with the same column position*/
			column_scan_ptr += x_voxels;
		    }
		    temp_max_ptr -= y_voxels;
		    temp_scan_ptr++;
		}
		temp_max_ptr += y_voxels;
	    }
	}/* end of for loop, for z counter */

        /* resize the image to C_ICON_IMAGE_WIDTH by C_ICON_IMAGE_HIEGHT */
	if ( code == C_XY_Z )
	    STATUS = resize_image(icon, max_ptr, x_voxels, y_voxels);

	else if ( code == C_XZ_Y )
	    STATUS = resize_image(icon, max_ptr, x_voxels, z_voxels);

	else if ( code == C_YZ_X ) 
	    STATUS = resize_image(icon, max_ptr, y_voxels, z_voxels);
        else
            STATUS = C_ERROR;

	free(max_ptr);
	return( STATUS );
}
