/****************************************************************************/
/*                                                                          */
/*  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_io.c
 *		      Author: Rick Avila and Lisa Sobierajski
 *			Date: 02/01/92
 *		 Description: Input/Output Routines Of VolVis
 *	Modification History:
 *
 *		Who?		When?		Why?
 *	--------------------------------------------------------------------
 *
 */

#include <stdio.h>
#include <stdlib.h>	/* For malloc() and strtod() */
#include <fcntl.h>	/* For open()   */

#include "C_volvis.h"

#define C_MAX_FUN_DEGREE	10

extern	C_World		world;
extern	C_View		view;
extern  C_ImageTable	image_table;


int C_write_volume_to_file(volume, filename )
C_Volume	*volume;
char            *filename;
{
  int C_write_rle_slc_to_file();
  int C_write_uncompressed_slc_to_file();
  int     return_val;

        return_val =  C_write_rle_slc_to_file( volume, filename );
        if ( return_val == C_ERROR )
        {
            C_message("Could not save compressed slice file.\n");
            return_val = C_write_uncompressed_slc_to_file( volume, filename );
	    if ( return_val == C_OK ) 
                C_message("Saved uncompressed slc file\n");
	}
        return return_val;
}


int C_write_rle_slc_to_file( volume, filename )
C_Volume	*volume;
char		*filename;
{
	extern void		C_error_message();
        extern C_Byte           *C_encode_8bit_data();

	int		  fd;
	C_Voxel_8bit	  *dptr, *temp_dptr;
	C_Voxel_8bit	  *plane_ptr, *temp_plane_ptr;
	C_Voxel_8bit	  *encode_ptr;
	C_CompressionType compression_type = C_RUN_LENGTH_ENCODE;

	int		  i,j=0, y, z, bits_per_voxel = 8;
	float		  x_units, y_units, z_units;
	int		  x_voxels, y_voxels, z_voxels;
	int		  magic_num = C_SLICE_MAGIC;
	int		  first_time = TRUE, total_bytes, num_bytes;
	char		  string[C_MAX_STRING];

        if ( (fd = open( filename, O_RDONLY)) > 0 )
        {
          if ( C_MASTER_PROCESS )
          {
                C_error_message("That file already exists!\n");
                close(fd);
                return C_ERROR;
          }
          else
                exit(1);
        }

	switch ( volume->data_type )
	{
	    case C_GEOMETRIC_DATA:

		C_error_message("You can't save geometric data yet!!!\n");
		break;

	    case C_SCALAR_DATA_8BIT:

		fd = open( filename, O_WRONLY | O_CREAT, 0644 );
		if ( fd < 0 )
		{
			C_error_message("Can't open file!!!\n");
			return C_ERROR;
		}
	  
		write( fd, &(magic_num), sizeof(int) );

		x_voxels = volume->x_size_voxels - 2;
		y_voxels = volume->y_size_voxels - 2;
		z_voxels = volume->z_size_voxels - 2;
	      
		write( fd, &(x_voxels), sizeof(int) );
		write( fd, &(y_voxels), sizeof(int) );
		write( fd, &(z_voxels), sizeof(int) );
		write( fd, &(bits_per_voxel), sizeof(int) );
		x_units = volume->x_size_units / 
				(float) (volume->x_size_voxels-1);	
		y_units = volume->y_size_units / 
				(float) (volume->y_size_voxels-1);	
		z_units = volume->z_size_units / 
				(float) (volume->z_size_voxels-1);	
		write( fd, &(x_units), sizeof(float) );
		write( fd, &(y_units), sizeof(float) );
		write( fd, &(z_units), sizeof(float) );
		write( fd, &(volume->unit_type),   sizeof(C_UnitType) );
		write( fd, &(volume->data_origin), sizeof(C_DataOrigin) );
		write( fd, &(volume->data_modification), 
					      sizeof(C_DataModification) );
		write( fd, &(compression_type), 
					      sizeof(C_CompressionType) );

		total_bytes = x_voxels * y_voxels * z_voxels;

		dptr = volume->data.scalar_data_8bit->scalar_data;

		dptr += volume->x_size_voxels * volume->y_size_voxels;
		for ( z = 1; z < volume->z_size_voxels - 1; z++ )
		{
                  plane_ptr = (C_Voxel_8bit *) malloc ((x_voxels) *
	 				(y_voxels) * sizeof(C_Voxel_8bit));
		  if (!plane_ptr)
		  {
			  close( fd );
			  printf("died in write slice file\n");
			  return C_ERROR;
		  }
		  dptr += volume->x_size_voxels;
		  for ( y = 1; y < volume->y_size_voxels - 1; y++ )
		  {
		    dptr += 1;
		    for(i = 0; i< x_voxels ; i++)
			  plane_ptr[j++] = *(dptr++);
		    dptr += 1;
		  }
		  dptr += volume->x_size_voxels;

		  encode_ptr = C_encode_8bit_data(plane_ptr, j, &num_bytes);
                  if (!encode_ptr)
		  {
			  close( fd );
			  sprintf( string, "/bin/rm %s", filename );
			  system( string );
			  return C_ERROR;
		  }

		  write( fd, &num_bytes, sizeof(int));
		  write( fd, encode_ptr, num_bytes );

		  free(encode_ptr);
		  free(plane_ptr);

		  j=0;
		}

		close( fd );
		break;

	}
	return(C_OK);
		
}

int C_write_uncompressed_slc_to_file( volume, filename )
C_Volume	*volume;	/* Volume Structure To Read Data Into	    */
char		*filename;	/* Slice Data File To Be Read Into Volume   */
{

	extern void		C_error_message();
        extern C_Byte           *C_encode_8bit_data();

	int		  fd;
	C_Voxel_8bit	  *dptr, *temp_dptr;
	C_Voxel_8bit	  *plane_ptr, *temp_plane_ptr;
	C_CompressionType compression_type = C_NO_COMPRESSION;

	int		  i,j=0, y, z, bits_per_voxel = 8;
	int		count = 0;

	float		  x_units, y_units, z_units;
	int		  x_voxels, y_voxels, z_voxels;
	int		  magic_num = C_SLICE_MAGIC;
	int		  first_time = TRUE, total_bytes, num_bytes;
	char		  string[C_MAX_STRING];

        if ( (fd = open( filename, O_RDONLY)) > 0 )
        {
          if ( C_MASTER_PROCESS )
          {
                C_error_message("That file already exists!\n");
                close(fd);
                return C_ERROR;
          }
          else
                exit(1);
        }

	switch ( volume->data_type )
	{
	    case C_GEOMETRIC_DATA:

		C_error_message("You can't save geometric data yet!!!\n");
		break;

	    case C_SCALAR_DATA_8BIT:

		fd = open( filename, O_WRONLY | O_CREAT, 0644 );
		if ( fd < 0 )
		{
			C_error_message("Can't open file!!!\n");
			return C_ERROR;
		}
	  
		write( fd, &(magic_num), sizeof(int) );

		x_voxels = volume->x_size_voxels - 2;
		y_voxels = volume->y_size_voxels - 2;
		z_voxels = volume->z_size_voxels - 2;
	      
		write( fd, &(x_voxels), sizeof(int) );
		write( fd, &(y_voxels), sizeof(int) );
		write( fd, &(z_voxels), sizeof(int) );
		write( fd, &(bits_per_voxel), sizeof(int) );
		x_units = volume->x_size_units / 
				(float) (volume->x_size_voxels-1);	
		y_units = volume->y_size_units / 
				(float) (volume->y_size_voxels-1);	
		z_units = volume->z_size_units / 
				(float) (volume->z_size_voxels-1);	
		write( fd, &(x_units), sizeof(float) );
		write( fd, &(y_units), sizeof(float) );
		write( fd, &(z_units), sizeof(float) );
		write( fd, &(volume->unit_type),   sizeof(C_UnitType) );
		write( fd, &(volume->data_origin), sizeof(C_DataOrigin) );
		write( fd, &(volume->data_modification), 
					      sizeof(C_DataModification) );
		write( fd, &(compression_type), 
					      sizeof(C_CompressionType) );

		total_bytes = x_voxels * y_voxels * z_voxels;

		dptr = volume->data.scalar_data_8bit->scalar_data;

		dptr += volume->x_size_voxels * volume->y_size_voxels;
		for ( z = 1; z < volume->z_size_voxels - 1; z++ )
		{
                  plane_ptr = (C_Voxel_8bit *) malloc ((x_voxels) *
	 				(y_voxels) * sizeof(C_Voxel_8bit));
		  if (!plane_ptr)
		  {
			  close( fd );
			  printf("died in write slice file\n");
			  return C_ERROR;
		  }
		  dptr += volume->x_size_voxels;
		  for ( y = 1; y < volume->y_size_voxels - 1; y++ )
		  {
		    dptr += 1;
		    for(i = 0; i< x_voxels ; i++)
			  plane_ptr[j++] = *(dptr++);
		    dptr += 1;
		  }
		  dptr += volume->x_size_voxels;

		  write( fd, plane_ptr, x_voxels * y_voxels );

		  free(plane_ptr);
		  j=0;

		}

		close( fd );
		break;

	}
	return(C_OK);

}



/************************************************************************/
/*									*/
/*			Slice Data File Input				*/
/*									*/
/*	C_read_slc_from_file: Tries to read the slice file and if 	*/
/*	successfull reads the data file into the volume structure and	*/
/*	returnsi C_OK. If not successfull returns C_ERROR. 		*/
/*	Interpolation may be performed on the data during input but a 	*/
/*	Z interpolation	factor >= 1.0 must be given.			*/
/*									*/
/************************************************************************/

int C_read_slc_from_file( volume, file_name )
C_Volume	*volume;	/* Volume Structure To Read Data Into	    */
char		*file_name;	/* Slice Data File To Be Read Into Volume   */
{
	extern C_Voxel_8bit *C_decode_8bit_data();
	extern void C_error_message();

	int	file_id;
	char	full_name[C_MAX_STRING];
	char	temp_msg[C_MAX_STRING];
	int	i;
	C_UnitType	unit_type;	/* Measurement Type For Units	*/
	float		unit_amount;	/* Amount Equal To 1 VolVis Unit*/
	int	x_voxels;	/* Width Of Slices In Voxels 		*/
	int	y_voxels;	/* Height Of Slices In Voxels 		*/
	int	z_voxels;	/* Number Of Slices In Voxels 		*/
	float	x_units;	/* Width Of A Single Voxel In Units 	*/
	float	y_units;	/* Height Of A Single Voxel In Units 	*/
	float	z_units;	/* Depth Of A Single Voxel In Units 	*/
	int	data_size;	/* Number Of Bytes Needed To Store Data	*/
	int	plane_size;	/* Number Of Bytes In A Padded Plane 	*/
	int	x_counter;	/* Steps Through X Scan Lines 		*/
	int	y_counter;	/* Steps Through Y Planes		*/
	int	z_counter;	/* Steps Through Z Planes		*/
	C_Voxel_8bit	*voxel_ptr;/* Points To Scanned Data Array	*/
	C_Voxel_8bit	*plane_ptr;/* Pointer To Plane In Data Array	*/
	C_Voxel_8bit	*scan_ptr;/* Pointer To Scan Line In Data Array	*/
	C_Voxel_8bit	*sptr;
	C_Voxel_8bit	*pptr;
	C_Voxel_8bit	*compressed_ptr;
	int		compressed_size;
	int	magic_num;
	int	bits_per_voxel;
	C_DataOrigin		data_origin;
	C_DataModification	data_modification;
	C_CompressionType	data_compression;
	char	string[256];

	float	tmp_val;

	C_message("Reading Slice Data File\n");

	voxel_ptr = NULL;

	/* Add Appropriate Extension To File Name */
/***
	sprintf( full_name, "%s.%s", file_name, C_SLICE_EXTENSION );
***/

	sprintf( full_name, "%s", file_name);
	printf("full name in read slc from file is %s\n",full_name);


	if((file_id = open(full_name, O_RDONLY) ) <= 0 )
	{
		sprintf( temp_msg, "Can NOT Open %s\n", full_name );
		C_error_message( temp_msg );
		return( C_ERROR );
	}

	/****    Read the first four bytes and compare with     ****/
        /****    C_SLICE_MAGIC                                ****/
        read( file_id, &magic_num, sizeof(int) );

        /****    If the magic numbers do not match, this is not ****/
        /****    a texture file - print the appropriate error   ****/
        /****    message and return C_ERROR                     ****/
        if ( magic_num != C_SLICE_MAGIC )
        {
            sprintf( string, "%s is not a slice file!\n", file_name );
            C_error_message( string );
 
            switch ( magic_num )
            {
              case C_TEXTURE_MAGIC:
 
                sprintf( string, "%s is a texture file!\n", file_name );
                C_error_message( string );
                break;
 
              case C_IMAGE_MAGIC:
 
                sprintf( string, "%s is an image file!\n", file_name );
                C_error_message( string );
                break;
 
              case C_FUNCTION_MAGIC:
 
                sprintf( string, "%s is a function file!\n", file_name );
                C_error_message( string );
                break;
 
              case C_ANIMATION_MAGIC:
 
                sprintf( string, "%s is an animation file!\n", file_name );
                C_error_message( string );
                break;
 
              default:
 
                break;
 
            }
            close ( file_id );
            return C_ERROR;
        }


	/* Read In Header Information */
	read( file_id, &x_voxels, sizeof(int) );
	read( file_id, &y_voxels, sizeof(int) );
	read( file_id, &z_voxels, sizeof(int) );
	read( file_id, &bits_per_voxel, sizeof(int) );
	read( file_id, &x_units, sizeof(float) );
	read( file_id, &y_units, sizeof(float) );
	read( file_id, &z_units, sizeof(float) );
	read( file_id, &unit_type, sizeof(C_UnitType) );
	read( file_id, &data_origin, sizeof(C_DataOrigin) );
	read( file_id, &data_modification, sizeof(C_DataModification) );
	read( file_id, &data_compression, sizeof(C_CompressionType) );

	/* Read In Data With Correct Interpolation */
	switch( bits_per_voxel )
	{
	  case 8:
		/* The Addition Of 2 Is For Data Padding On The */
		/* Bounding Planes Of The Volume 		*/
		data_size = (x_voxels+2) * (y_voxels+2) * (z_voxels+2);

		voxel_ptr = (C_Voxel_8bit *)malloc( data_size );
		if( !voxel_ptr )
		{
		  C_error_message("Not Enough Memory To Input Data\n");
		  return( C_ERROR );
		}

		plane_size = (x_voxels+2) * (y_voxels+2);

		plane_ptr = voxel_ptr + plane_size + (x_voxels+2) + 1;

		scan_ptr = NULL;

		/* Read In Data By X Scan Lines - Due To Padding */
		for( z_counter=0; z_counter<z_voxels; z_counter++ )
		{
		  switch ( data_compression )
		  {
		    case C_NO_COMPRESSION:

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

		      read( file_id, scan_ptr, x_voxels * y_voxels );

		      break;

		    case C_RUN_LENGTH_ENCODE:
		      if ( scan_ptr )
			free( scan_ptr );
		      read( file_id, &compressed_size, sizeof( int ) );
		      compressed_ptr = (C_Voxel_8bit *)malloc(compressed_size);
		      read( file_id, compressed_ptr, compressed_size );

		      scan_ptr = C_decode_8bit_data( compressed_ptr, 
						     x_voxels * y_voxels ); 
		      free( compressed_ptr );
		      break;

		    default:

		      break;
		  }
		  sptr = scan_ptr;
		  pptr = plane_ptr;

		  for ( y_counter = 0; y_counter < y_voxels; y_counter++ )
		  {
		    for ( x_counter = 0; x_counter < x_voxels; x_counter++ )
			*(pptr++) = *(sptr++);
		    pptr += 2;
		  }

		  plane_ptr += plane_size;
		}
		/* Initialize Volume Structure */
		volume->data_type	= C_SCALAR_DATA_8BIT;
		volume->data.scalar_data_8bit	= C_New( C_ScalarData_8bit );


		volume->x_size_voxels	  = x_voxels+2;
		volume->y_size_voxels	  = y_voxels+2;
		volume->z_size_voxels	  = z_voxels+2;
	
		volume->x_size_units	  = x_units * (x_voxels+1);
		volume->y_size_units	  = y_units * (y_voxels+1);
		volume->z_size_units	  = z_units * (z_voxels+1);
		volume->unit_type	  = unit_type;

		volume->data_origin	  = data_origin;
		volume->data_modification = data_modification;

		break;


	  case 16:
		C_error_message("Can't handle 16 bit data yet!!!\n");
		break;

	  case 32:
		C_error_message("Can't handle 16 bit data yet!!!\n");
		break;

	  default:
		C_error_message("Internal Error\n");
		break;
	}

	close( file_id );
	/* Zero Out Padding Planes */
	C_clear_padding( voxel_ptr, 
			 volume->x_size_voxels,
			 volume->y_size_voxels,
			 volume->z_size_voxels  );

	volume->data.scalar_data_8bit->scalar_data = voxel_ptr;
	/* Initialize Any Additional Volume Entries */
        C_create_volume_matrices( volume );
        C_create_plane_equations( volume );

	volume->icon_8bit = NULL;
	volume->icon_24bit = NULL;

	volume->data.scalar_data_8bit->seg_type = C_ISO_SURFACE;
        volume->data.scalar_data_8bit->seg.isovalue  = 128.0;

	volume->data.scalar_data_8bit->seg.s_opacity = C_New( C_OpacityArray );
	
	for (i = 0; i < 256; i++)
		volume->data.scalar_data_8bit->seg.s_opacity->opacity[i] = 
				i/2550.0;

	volume->data.scalar_data_8bit->references = 1;

	C_message("Finished Reading Slice Data File\n");

	return( C_OK );
}

/************************************************************************/
/*									*/
/*			Voxel Data Array Padding			*/
/*									*/
/************************************************************************/
C_clear_padding( voxel_ptr, x_voxels, y_voxels, z_voxels )
C_Voxel_8bit	*voxel_ptr;	/* Pointer To C_Voxel_8bit Array	*/
int		x_voxels,	/* X Size Of Array		*/
		y_voxels,	/* Y Size Of Array		*/
		z_voxels;	/* Z Size Of Array		*/
{
		int	i;
		int	x_counter,	/* Used To Increment Through Array */
			y_counter,
			z_counter;
		int	plane_size;
		C_Voxel_8bit	*plane_ptr;
		C_Voxel_8bit	*scan_ptr;

		plane_size = x_voxels * y_voxels;

		/* Plane Z == 0 */
		plane_ptr = voxel_ptr;
		for( i=0; i<plane_size; i++ )
			*(plane_ptr++) = 0;

		/* Plane Z == z_voxels-1 */
		plane_ptr = voxel_ptr + (z_voxels-1)*plane_size;
		for( i=0; i<plane_size; i++ )
			*(plane_ptr++) = 0;

		/* Plane Y == 0 */
		plane_ptr = voxel_ptr;
		for( z_counter=0; z_counter<z_voxels; z_counter++ )
		{
			scan_ptr = plane_ptr;
			for( x_counter=0; x_counter<x_voxels; x_counter++ )
				*(scan_ptr++) = 0;

			plane_ptr += plane_size;
		}

		/* Plane Y == y_voxels-1 */
		plane_ptr = voxel_ptr + (y_voxels-1)*(x_voxels);
		for( z_counter=0; z_counter<z_voxels; z_counter++ )
		{
			scan_ptr = plane_ptr;
			for( x_counter=0; x_counter<x_voxels; x_counter++ )
				*(scan_ptr++) = 0;

			plane_ptr += plane_size;
		}

		/* Plane X == 0 */
		plane_ptr = voxel_ptr;
		for( y_counter=0; y_counter<y_voxels; y_counter++ )
		{
			scan_ptr = plane_ptr;
			for( z_counter=0; z_counter<z_voxels; z_counter++ )
			{
				*scan_ptr = 0;
				scan_ptr += plane_size;
			}

			plane_ptr += x_voxels;
		}

		/* Plane X == x_voxels-1 */
		plane_ptr = voxel_ptr + (x_voxels-1);
		for( y_counter=0; y_counter<y_voxels; y_counter++ )
		{
			scan_ptr = plane_ptr;
			for( z_counter=0; z_counter<z_voxels; z_counter++ )
			{
				*scan_ptr = 0;
				scan_ptr += plane_size;
			}

			plane_ptr += x_voxels;
		}
}
