/****************************************************************************/
/*                                                                          */
/*  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_parc.c
 *		      Author: Rick Avila
 *			Date: 08/10/92
 *		 Description: PARC Projection Algorithm - Ray Casting Part
 *	Modification History:
 *
 *		Who?		When?		Why?
 *	--------------------------------------------------------------------
 *
 */

#include <stdio.h>

#include "C_volvis.h"
#include "C_navigator.h"
#include "C_raytrace.h"

extern	C_World		world;
extern	C_View		view;
extern	C_NavInfo	nav_info;

#ifdef C_HP
void C_parc_polygon_projection()
{
	printf("PARC Not Supported on HPs - Yet!\n");
}
#endif

#ifdef C_SUN
void C_parc_polygon_projection()
{
	printf("PARC Not Supported on SUNs - Yet!\n");
}
#endif

#ifdef C_SGI
#ifdef C_X_GRAPHICS
void C_parc_polygon_projection()
{
        printf("PARC Not Supported in MOTIF Only Version - Yet!\n");
}
#endif
#endif


C_parc_cast_ray( xpixel, ypixel, ray_origin, ray_direction, world, color )
int			xpixel;		/* X Pixel Position Of Ray */
int			ypixel;		/* Y Pixel Position Of Ray */
C_FPosition             ray_origin;	/* Origin Of Ray */
C_FVector               ray_direction;	/* Direction Of Ray */
C_World                 *world;		/* Data To Send Ray Through 	*/
C_Color                 *color;		/* Return Color Of Ray 		*/
{
	int		volume_num;	/* Loop Through Volumes */
	long		z_front;	/* GL Zbuffer Values */
	long		z_back;
	int		front_sign;
	int		back_sign;

	double		front_dist;	/* World Distance Values */
	double		back_dist;

	double		near_plane;
	double		far_plane;

	double		temp;

	int		pixel_offset;

	C_FVector	local_direction;
	C_FPosition	local_zero, junk_point;

	C_RayTraceInfo	rt_info;
	C_IntersectInfo intersect_info;

	float		closest_distance;

	extern C_View	view;

	closest_distance = C_BIG_FLOAT;

	/* Set The Background Color If No Intersection Found */
	C_Set_Colorptr( color, 
		world->world_shade.bkgrnd_color.red, 
		world->world_shade.bkgrnd_color.green, 
		world->world_shade.bkgrnd_color.blue   );
/****
	C_Set_Colorptr( color, 255, 0, 0 );
****/

	/* Loop Through The Volumes */
	for( volume_num=0; volume_num<world->num_volumes; volume_num ++)
	{
	   if( world->volume[volume_num]->visible )
	   {
		/**************************************/
		/* Access The Correct Zbuffer Element */
		/**************************************/
	   	pixel_offset = ypixel*view.width_pixels + xpixel;

		z_front = *(nav_info.pj_win_info.zfront[volume_num] + 
				pixel_offset);
		z_back =  *(nav_info.pj_win_info.zback[volume_num]  + 
				pixel_offset);

		/*********************/
		/* Grab the Sign Bit */
		/*********************/
		if( z_front & 0x00800000 )
			front_sign = 0xff800000;
		else
			front_sign = 0x0;

		if( z_back & 0x00800000 )
			back_sign = 0xff800000;
		else
			back_sign = 0x0;

		/*************************************************/
		/* Take The Last 23 Bits And Ignore The Last Bit */
		/*************************************************/
		z_front = z_front & 0x007ffffe;
		z_back  = z_back & 0x007ffffe;

		/********************************/
		/* Reset The Sign Of The Number */
		/********************************/
		z_front = front_sign | z_front;
		z_back  = back_sign  | z_back;

		/**********************************************/
		/* Send Out Ray If Front Zbuffer Was Modified */
		/**********************************************/
		if( z_front < (nav_info.pj_win_info.max_zbuf-1) )
		{
		   near_plane = nav_info.pj_win_info.near_plane[volume_num];
		   far_plane = nav_info.pj_win_info.far_plane[volume_num];

		   /***********************/
		   /* Decode Front Values */
		   /***********************/
		   /* Scale Between -1.0 <-> 1.0 */
		   front_dist = (double)(z_front)/
			(double)(nav_info.pj_win_info.max_zbuf);

		   if( view.fov != 0.0 )   /* Use Perspective Transform */
		   {
		    	temp = (2.0*far_plane*near_plane)/
				((far_plane+near_plane) - 
				 (far_plane-near_plane)*front_dist);

		    	local_zero.x = view.c_sys.origin.x;
		    	local_zero.y = view.c_sys.origin.y;
		    	local_zero.z = view.c_sys.origin.z;

		    	C_transform_fvector( &(ray_direction), &(local_zero),
					&(local_direction), &(junk_point),
					&(view.wtol_units) );

		    	front_dist = temp/local_direction.z;
		   }
		   else			/* Use Parallel Transform */
		   {
			front_dist= ( (front_dist*(far_plane-near_plane)) +
				 	(far_plane+near_plane)
				      ) / 2.0;
		   }


		   /**********************/
		   /* Decode Back Values */
		   /**********************/
		   /* Scale Between -1.0 <-> 1.0 */
		   back_dist = (double)(z_back)/
			(double)(nav_info.pj_win_info.max_zbuf);

		   if( view.fov != 0.0 )   /* Use Perspective Transform */
		   {
		    	back_dist = (2.0*far_plane*near_plane)/
				((far_plane+near_plane) - 
				 (far_plane-near_plane)*back_dist);

		   	back_dist = back_dist/local_direction.z;
		   }
		   else			/* Use Parallel Transform */
		   {
		     back_dist = ( (back_dist*(far_plane-near_plane)) +
				 	(far_plane+near_plane)
				    ) / 2.0;
		   }

		   rt_info.ray_origin.x = ray_origin.x;
		   rt_info.ray_origin.y = ray_origin.y;
		   rt_info.ray_origin.z = ray_origin.z;

		   rt_info.ray_direction.x = ray_direction.x;
		   rt_info.ray_direction.y = ray_direction.y;
		   rt_info.ray_direction.z = ray_direction.z;

		   rt_info.ray_type = C_PARC_RAY;
		   rt_info.ray_level = 0;
		   rt_info.max_distance = back_dist + 1.0;

		   intersect_info.intersect_volume = volume_num;
		   intersect_info.intersect_distance = front_dist;

		   C_trace_ray( &rt_info, world, &view, &intersect_info );

		   if( intersect_info.intersect_distance < closest_distance )
		   {
		   	color->red = intersect_info.intersect_color.red;
		   	color->green = intersect_info.intersect_color.green;
		   	color->blue = intersect_info.intersect_color.blue;

/***
C_Set_Colorptr( color, 0, 255, 0 );
***/
			closest_distance = intersect_info.intersect_distance;
		   }
		}
	   }
	} /* End Of For Loop */
}

C_parc_free_memory()
{
	int	volume_num;

	/* Free Up The ZBuffer Memory */
	for( volume_num=0; volume_num<world.num_volumes; volume_num++ )
	{
		if( world.volume[volume_num]->visible )
		{
			free( nav_info.pj_win_info.zfront[volume_num] );
			free( nav_info.pj_win_info.zback[volume_num] );
		}
	}
}
