/****************************************************************************/
/*                                                                          */
/*  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: GL_nav_projection.c
 *		      Author: Rick Avila 
 *			Date: 08/15/92
 *		 Description: GL Drawing Routines For The Navigator 
 *			      Projection Drawing Areas
 *	Modification History:
 *
 *		Who?		When?		Why?
 *	--------------------------------------------------------------------
 *
 */

#include <stdio.h>
#include <math.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/keysym.h>
#include <Xm/Xm.h>
#include <Xm/DrawingA.h>
#include <X11/Xirisw/GlxMDraw.h>

#include "C_volvis.h"
#include "C_navigator.h"
#include "C_nav_draw.h"

extern	C_World		world;
extern	C_NavInfo	nav_info;


Widget create_pj_drawing_area( parent )
Widget parent;
{
	Arg			args[20];	/* Argument List */
	int			n;
	int			image_size;
	static GLXconfig 	glxConfig[] =
				{
					{ GLX_NORMAL, GLX_DOUBLE, TRUE },
					{ GLX_NORMAL, GLX_RGB, TRUE },
					{ GLX_NORMAL, GLX_ZSIZE, GLX_NOCONFIG },
					{ 0, 0, 0 }
				};
	extern C_View		view;
	extern void		nav_pj_expose_CB();
	extern void		nav_pj_resize_CB();
#ifdef NO_IDE
	extern void		nav_pj_input_CB();
#endif

	/********************************************************/
	/*      Create a Drawing Area For Wireframe Projection  */
	/********************************************************/
	n=0;
	XtSetArg( args[n], XmNx, 0 );
	XtSetArg( args[n], XmNy, 0 );
	XtSetArg( args[n], XmNwidth, view.width_pixels ); n++;
	XtSetArg( args[n], XmNheight, view.height_pixels ); n++;
	XtSetArg( args[n], XmNsensitive, True ); n++;
	XtSetArg( args[n], GlxNglxConfig, glxConfig ); n++;
	nav_info.pj_win_info.drawing_area = 
		GlxCreateMDraw( parent, "nav_drawing_area", args, n );
	XtManageChild( nav_info.pj_win_info.drawing_area );

	XtAddCallback( nav_info.pj_win_info.drawing_area, 
			GlxNexposeCallback, nav_pj_expose_CB, NULL );

	XtAddCallback( nav_info.pj_win_info.drawing_area, 
			GlxNresizeCallback, nav_pj_resize_CB, NULL );

#ifdef NO_IDE
	XtAddEventHandler( nav_info.pj_win_info.drawing_area, ButtonReleaseMask,
                        FALSE, nav_pj_input_CB, NULL );
#endif

	return( nav_info.pj_win_info.drawing_area );
}

/************************************************************************/
/*									*/
/*			Navigator Projection Routines			*/
/*									*/
/************************************************************************/
void nav_pj_init()
{
	void nav_clear_buffers();
	long	zbits;

        GLXwinset( XtDisplay(nav_info.pj_win_info.drawing_area),
		   XtWindow(nav_info.pj_win_info.drawing_area) );

	/***************************/
	/* Enable Double Buffering */
	/***************************/
        doublebuffer();

	/**********************************/
	/* Enable RGB Color Specification */
	/**********************************/
	RGBmode();

	/*****************************************************/
	/* Set ZBuffer Range To Values Supported By Hardware */
	/*****************************************************/
	glcompat(GLC_ZRANGEMAP, 0);

	/**************************************/
	/* Retrieve The Maximum ZBuffer Value */
	/**************************************/
	nav_info.pj_win_info.max_zbuf = getgdesc( GD_ZMAX );

	/**************************************/
	/* Retrieve The Minimum ZBuffer Value */
	/**************************************/
	nav_info.pj_win_info.min_zbuf = getgdesc( GD_ZMIN );

	/*********************************************************/
	/* Set The Minimum & Maximum Depth Stored In The ZBuffer */
	/*********************************************************/
	lsetdepth( getgdesc(GD_ZMIN), getgdesc(GD_ZMAX) );

	/*********************/
	/* Enable Zbuffering */
	/*********************/
	zbuffer( TRUE );
	zfunction( ZF_LESS );

	zbits = getgdesc( GD_BITS_NORM_ZBUFFER );

	if( (zbits != 23) && (zbits != 24) )
	{
	   C_error_message("Zbuffer Depth Unsupported For PARC Projections");
	}

	/*****************************/
	/* Clear The Color & ZBuffer */
	/*****************************/
	frontbuffer( TRUE );
	nav_clear_buffers( C_NAV_PROJECTION );
	frontbuffer( FALSE );

	mmode( MVIEWING );
	nmode( NAUTO );		/* Normals Normalized Except When Orthonormal */
				/* Viewing */
}

void nav_wf_init()
{
	void nav_clear_buffers();
 
	/************************************************/
	/*						*/
	/* 	Initialize The Wireframe Area 		*/
	/*						*/
	/************************************************/
        GLXwinset( XtDisplay(nav_info.wf_win_info.drawing_area),
		   XtWindow(nav_info.wf_win_info.drawing_area) );

	/***************************/
	/* Enable Double Buffering */
	/***************************/
        doublebuffer();

	/**********************************/
	/* Enable RGB Color Specification */
	/**********************************/
	RGBmode();

	/*****************************************************/
	/* Set ZBuffer Range To Values Supported By Hardware */
	/*****************************************************/
	glcompat(GLC_ZRANGEMAP, 0);

	/**************************************/
	/* Retrieve The Maximum ZBuffer Value */
	/**************************************/
	nav_info.wf_win_info.max_zbuf = getgdesc( GD_ZMAX );

	/*********************************************************/
	/* Set The Minimum & Maximum Depth Stored In The ZBuffer */
	/*********************************************************/
	lsetdepth( getgdesc(GD_ZMIN), getgdesc(GD_ZMAX) );

	/*********************/
	/* Enable Zbuffering */
	/*********************/
	zbuffer( TRUE );
	zfunction( ZF_LESS );

	/*****************************/
	/* Clear The Color & ZBuffer */
	/*****************************/
	frontbuffer( TRUE );
	nav_clear_buffers( C_NAV_WIREFRAME );
	frontbuffer( FALSE );

	mmode( MVIEWING );
}

void nav_wf_key_init()
{
	void nav_clear_buffers();

	/************************************************/
	/*						*/
	/* 	Initialize The Wireframe Key Area 	*/
	/*						*/
	/************************************************/
        GLXwinset( XtDisplay(nav_info.wf_key_win_info.drawing_area),
		   XtWindow(nav_info.wf_key_win_info.drawing_area) );

	/***************************/
	/* Enable Double Buffering */
	/***************************/
        doublebuffer();

	/**********************************/
	/* Enable RGB Color Specification */
	/**********************************/
	RGBmode();

	/*****************************************************/
	/* Set ZBuffer Range To Values Supported By Hardware */
	/*****************************************************/
	glcompat(GLC_ZRANGEMAP, 0);

	/**************************************/
	/* Retrieve The Maximum ZBuffer Value */
	/**************************************/
	nav_info.wf_key_win_info.max_zbuf = getgdesc( GD_ZMAX );

	/*********************************************************/
	/* Set The Minimum & Maximum Depth Stored In The ZBuffer */
	/*********************************************************/
	lsetdepth( getgdesc(GD_ZMIN), getgdesc(GD_ZMAX) );

	/*********************/
	/* Enable Zbuffering */
	/*********************/
	zbuffer( TRUE );
	zfunction( ZF_LESS );

	/*****************************/
	/* Clear The Color & ZBuffer */
	/*****************************/
	frontbuffer( TRUE );
	nav_clear_buffers( C_NAV_WIREFRAME_KEY );
	frontbuffer( FALSE );

	mmode( MVIEWING );
}

void nav_clear_buffers( proj_type )
C_NavProjectionType	proj_type;	/* Selects Projection Type */
{
	unsigned long	gl_color;	/* GL Color Representation */

	switch( proj_type )
	{
	  case C_NAV_PROJECTION:
	  case C_PARC_FRONT_PROJECTION:
	  case C_PARC_BACK_PROJECTION:
        	GLXwinset( XtDisplay(nav_info.pj_win_info.drawing_area),
		   	XtWindow(nav_info.pj_win_info.drawing_area));
		break;
	  case C_NAV_WIREFRAME:
		GLXwinset( XtDisplay(nav_info.wf_win_info.drawing_area),
			XtWindow(nav_info.wf_win_info.drawing_area));
		break;
	  case C_NAV_WIREFRAME_KEY:
		GLXwinset( XtDisplay(nav_info.wf_key_win_info.drawing_area),
			    XtWindow(nav_info.wf_key_win_info.drawing_area));
		break;
	}

	/**************************/
	/* Clear Color & Z Buffer */
	/**************************/
	switch( proj_type )
	{
		case C_NAV_PROJECTION:
			/*******************************************/
			/* Set GL Background Color Here With cpack */
			/*******************************************/
			gl_color = ((world.world_shade.bkgrnd_color.red) |
		    		(world.world_shade.bkgrnd_color.green << 8) |
		    		(world.world_shade.bkgrnd_color.blue  << 16) );

			/* Clear The Drawing Area */
			czclear( gl_color, nav_info.pj_win_info.max_zbuf );
			break;
		case C_NAV_WIREFRAME:
			/* Clear The Drawing Area & ZBuffer */
			czclear( 0x0, nav_info.wf_win_info.max_zbuf );
			break;
		case C_NAV_WIREFRAME_KEY:
			/* Clear The Drawing Area & ZBuffer */
			czclear( 0x0, nav_info.wf_key_win_info.max_zbuf );
			break;
		case C_PARC_FRONT_PROJECTION:
			/* Clear The Drawing Area & ZBuffer */
			czclear( 0x0, nav_info.pj_win_info.max_zbuf );
			break;
		case C_PARC_BACK_PROJECTION:
			/* Clear The Drawing Area & ZBuffer */
			czclear( 0x0, nav_info.pj_win_info.min_zbuf );
			break;
	}
}

void nav_set_viewing( proj_type, nav_info, volume_num )
C_NavProjectionType	proj_type;	/* Selects Projection Type */
C_NavInfo		*nav_info;	/* Navigator Structure */
int			volume_num;	/* Volume Being Projected */
{
        extern  void    get_window_size();
	int 		i,j;
	static int      xsize = -1;
	static int      ysize = -1;
	float		aspect;
	float		near_plane;
	float		far_plane;
	float		closest;
	float		farthest;
	float		temp_close;
	float		temp_far;
	float		extra_dist;
	float		view_width;
	float		view_height;
	C_View		*view_ptr;
	C_Light		*light;
	C_FPosition	v_pos;
	C_FPosition	new_v_pos;
	C_Matrix	temp_matrix;
	
	Coord		pos_and_orient[4][4];
	static Coord	allign_matrix[4][4] =
			{
				1.0,  0.0,  0.0,  0.0,
				0.0,  1.0,  0.0,  0.0,
				0.0,  0.0, -1.0,  0.0,
				0.0,  0.0,  0.0,  1.0
			};

	extern C_View	view;
	extern void	C_distance_to_view();

	switch( proj_type )
	{
	   case C_NAV_PROJECTION:
	   case C_PARC_FRONT_PROJECTION:
	   case C_PARC_BACK_PROJECTION:
        	GLXwinset( XtDisplay( nav_info->pj_win_info.drawing_area ),
		   	   XtWindow(  nav_info->pj_win_info.drawing_area ));
                get_window_size(nav_info->pj_win_info.drawing_area, 
                                &xsize, &ysize);
		break;
	   case C_NAV_WIREFRAME:
		GLXwinset( XtDisplay( nav_info->wf_win_info.drawing_area ),
			   XtWindow(  nav_info->wf_win_info.drawing_area ));
                get_window_size(nav_info->wf_win_info.drawing_area,
                                &xsize, &ysize);
		break;
	   case C_NAV_WIREFRAME_KEY:
		GLXwinset( XtDisplay( nav_info->wf_key_win_info.drawing_area ),
			   XtWindow(  nav_info->wf_key_win_info.drawing_area ));
                get_window_size(nav_info->wf_key_win_info.drawing_area,
                                &xsize, &ysize);
		break;
	}

	/******************/
	/* Set Up Viewing */
	/******************/

	aspect = (float)xsize/(float)ysize;

	mmode( MVIEWING );

	switch( proj_type )
	{
	   case C_NAV_PROJECTION:
	   case C_PARC_FRONT_PROJECTION:
	   case C_PARC_BACK_PROJECTION:
	   case C_NAV_WIREFRAME:
		/* Allign The Viewing Matrix */
		/* This Flips The Z Values Since GL is Right-Handed And */
		/* VolVis is Left-Handed */
		loadmatrix( allign_matrix );
		break;
	}

	switch( proj_type )
	{
	   case C_NAV_PROJECTION:
	   case C_PARC_FRONT_PROJECTION:
	   case C_PARC_BACK_PROJECTION:
		view_ptr = &view;
		break;
	   case C_NAV_WIREFRAME:
		view_ptr = &(nav_info->wf_win_info.view);
		break;
	   case C_NAV_WIREFRAME_KEY:
		view_ptr = NULL;
		break;
	}

	/************************************************************/
	/* Compute Distances To Near & Far Plane For Any Projection */
	/************************************************************/
	switch( proj_type )
	{
	   case C_NAV_WIREFRAME_KEY:
		closest  = 0.1;
		farthest = 2.0;
		break;
	   case C_NAV_PROJECTION:
	   case C_NAV_WIREFRAME:
		closest = C_BIG_FLOAT;
		farthest = -C_BIG_FLOAT;
		for( i=0; i<world.num_volumes; i++ )
		{
			C_distance_to_view( view_ptr, i, 
					    &temp_close, &temp_far);

			/* Computes Average Side Distance Divided By 4 */
			extra_dist = 
				(world.volume[i]->x_size_units +
				 world.volume[i]->y_size_units +
				 world.volume[i]->y_size_units)/12.0;

			temp_close = temp_close - extra_dist;
			temp_far = temp_far + extra_dist;

			if( temp_close < closest )
				closest = temp_close;

			if( temp_far > farthest )
				farthest = temp_far;
		}
		
		if( world.num_volumes == 0 )
		{
			closest  = 0.1;
			farthest = 2.0;
		}

		break;
	   case C_PARC_FRONT_PROJECTION:
	   case C_PARC_BACK_PROJECTION:
		C_distance_to_view( view_ptr, volume_num, &closest, &farthest );

		/* Comutes Average Side Distance Divided By 4 */
		extra_dist = 
			(world.volume[volume_num]->x_size_units +
			 world.volume[volume_num]->y_size_units +
			 world.volume[volume_num]->y_size_units)/12.0;

		closest = closest - extra_dist;
		farthest = farthest + extra_dist;
		break;
	}

	/********************************************************/
	/* Add Light And View Distances To Near & Far Plane For */
	/* Wireframe Projection 				*/
	/********************************************************/
	switch( proj_type )
	{
	   case C_NAV_WIREFRAME:

		/***********************/
		/* Get Light Distances */
		/***********************/
		extra_dist = 50.0;	/* Should Not Clip Light Jack */

		for( i=0; i<world.num_lights; i++ )
		{
			light = world.light[i];

			switch( light->light_type )
			{
			  case C_POINT_LIGHT:
			    v_pos.x = light->light.light_point->light_pos.x;
			    v_pos.y = light->light.light_point->light_pos.y;
			    v_pos.z = light->light.light_point->light_pos.z;
			    break;
			  case C_VOLUME_LIGHT:
			    v_pos.x = light->light.light_volume->c_sys.origin.x;
			    v_pos.y = light->light.light_volume->c_sys.origin.y;
			    v_pos.z = light->light.light_volume->c_sys.origin.z;
			}

	   		/* Transform Vertex Into Current View C_Sys */
			C_transform_fposition(  &v_pos, &new_v_pos, 
						&(view_ptr->wtol_units));

			temp_close = new_v_pos.z - extra_dist;
			temp_far = new_v_pos.z + extra_dist;

			if( temp_close < closest )
				closest = temp_close;

			if( temp_far > farthest )
				farthest = temp_far;
		}

		/**********************/
		/* Get View Distances */
		/**********************/
		if( view.fov == 0.0 )
		{
		    view_width = view.width_units;
		    view_height = view.height_units;
		}
		else
		{
		    view_width  = view.width_units  * C_PERSPECTIVE_VIEW_SCALE;
		    view_height = view.height_units * C_PERSPECTIVE_VIEW_SCALE;
		}

		for( i=0; i<4; i++ )
		{
		   /* Compute Bounding Vertices Of Wireframe View */
		   switch( i )
		   {
			case 0:
			   v_pos.x = view.c_sys.origin.x;
			   v_pos.y = view.c_sys.origin.y;
			   v_pos.z = view.c_sys.origin.z;
			   break;
			case 1:
			   v_pos.x += (view_width * view.c_sys.x_axis.x);
			   v_pos.y += (view_width * view.c_sys.x_axis.y);
			   v_pos.z += (view_width * view.c_sys.x_axis.z);
			   break;
			case 2:
			   v_pos.x += (view_height * view.c_sys.y_axis.x);
			   v_pos.y += (view_height * view.c_sys.y_axis.y);
			   v_pos.z += (view_height * view.c_sys.y_axis.z);
			   break;
			case 3:
			   v_pos.x -= (view_width * view.c_sys.x_axis.x);
			   v_pos.y -= (view_width * view.c_sys.x_axis.y);
			   v_pos.z -= (view_width * view.c_sys.x_axis.z);
		   }

		   /* Transform Vertex Into Current View C_Sys */
		   C_transform_fposition(  &v_pos, &new_v_pos,
					   &(view_ptr->wtol_units));

		   temp_close = new_v_pos.z - extra_dist;
		   temp_far = new_v_pos.z + extra_dist;

		   if( temp_close < closest )
			closest = temp_close;

		   if( temp_far > farthest )
			farthest = temp_far;
		}
		break;
	   case C_NAV_PROJECTION:
	   case C_PARC_FRONT_PROJECTION:
	   case C_PARC_BACK_PROJECTION:
	   case C_NAV_WIREFRAME_KEY:
		break;
	}

	if( farthest < 2.0 )
		farthest = 2.0;

	if( closest < 0.1 )
		closest = 0.1;

	/* Store Closest And Farthest Information */
	switch( proj_type )
	{
	   case C_NAV_PROJECTION:
	   case C_NAV_WIREFRAME:
	   case C_NAV_WIREFRAME_KEY:
	     near_plane = closest;
	     far_plane  = farthest;
	     break;
	   case C_PARC_FRONT_PROJECTION:
	   case C_PARC_BACK_PROJECTION:
	     near_plane = nav_info->pj_win_info.near_plane[volume_num] =closest;
	     far_plane  = nav_info->pj_win_info.far_plane[volume_num] =farthest;
	}

	/* Specify The Area Of The GL Window */
	switch( proj_type )
	{
	   case C_NAV_PROJECTION:
	   case C_PARC_FRONT_PROJECTION:
	   case C_PARC_BACK_PROJECTION:
		viewport( 0, nav_info->pj_win_info.width_pixels-1,
		  	  0, nav_info->pj_win_info.height_pixels-1 );
		break;
	   case C_NAV_WIREFRAME:
		viewport( 0, nav_info->wf_win_info.view.width_pixels-1,
			  0, nav_info->wf_win_info.view.height_pixels-1 );
		break;
	   case C_NAV_WIREFRAME_KEY:
		viewport( 0, nav_info->wf_key_win_info.width_pixels-1,
			  0, nav_info->wf_key_win_info.height_pixels-1 );
		break;
	}

	/* These Only Modify The GL Projection Matrix */
	switch( proj_type )
	{
	  case C_NAV_PROJECTION:
	  case C_PARC_FRONT_PROJECTION:
	  case C_PARC_BACK_PROJECTION:
	  case C_NAV_WIREFRAME:
		if( view.fov != 0.0 )
		{
		   perspective( (Angle)((C_Rad_To_Deg(view_ptr->fov))*10),
					aspect, near_plane, far_plane );
		}
		else
		{
			ortho(	-(view_ptr->width_units/2.0), 
			 	 (view_ptr->width_units/2.0),
				-(view_ptr->height_units/2.0),
			 	 (view_ptr->height_units/2.0),
			  	 near_plane, far_plane );
		}
		break;
	   case C_NAV_WIREFRAME_KEY:
		near_plane = -1.0;
		far_plane = 1.0;
		ortho( -(xsize/2.0), (xsize/2.0),
		       -(ysize/2.0), (ysize/2.0),
			near_plane, far_plane );
		break;
	}

	switch( proj_type )
	{
	   case C_NAV_PROJECTION:
	   case C_PARC_FRONT_PROJECTION:
	   case C_PARC_BACK_PROJECTION:
	   case C_NAV_WIREFRAME_KEY:
		mmode( MVIEWING );
		break;
	   case C_NAV_WIREFRAME:
		for( i=0; i<4; i++ )
		for( j=0; j<4; j++ )
		{
		    pos_and_orient[i][j] = view_ptr->wtol_units.matrix[j][i];
		}

		/* Set Position & Orientation Of View */
		mmode( MVIEWING );
		multmatrix( pos_and_orient );

		break;
	}

	/************************************/
	/* Use Appropriate Zbuffer Function */
	/************************************/
	switch( proj_type )
	{
		case C_NAV_PROJECTION:
			zfunction( ZF_LESS );
			break;
		case C_NAV_WIREFRAME:
			zfunction( ZF_LESS );
			break;
		case C_NAV_WIREFRAME_KEY:
			zfunction( ZF_LESS );
			break;
		case C_PARC_FRONT_PROJECTION:
			zfunction( ZF_LESS );
			break;
		case C_PARC_BACK_PROJECTION:
			zfunction( ZF_GREATER );
			break;
	}
}

void nav_set_lighting( proj_type )
C_NavProjectionType	proj_type;	/* Selects Projection Type */
{
	unsigned long		gl_color;	/* GL Color Representation */
	float			gl_light[C_MAX_LIGHTS][20];
	float			gl_material[20];
	float			gl_light_model[20];
	C_PointLight		*light_ptr;
	C_Color			*color_ptr;
	int			light_num;
	C_FPosition		new_pos;
	extern C_View		view;

        GLXwinset( XtDisplay(nav_info.pj_win_info.drawing_area),
		   XtWindow(nav_info.pj_win_info.drawing_area));

	/*************************************************/
	/* Lighting Is Not Necessary For PARC Projections */
	/*************************************************/
	switch( proj_type )
	{
		case C_PARC_FRONT_PROJECTION:
		case C_PARC_BACK_PROJECTION:
			return;
	}

	/* Setup light sources and light properties */
	for( light_num = 0; light_num<world.num_lights; light_num++ )
	{
		if( world.light[light_num]->visible )
		{
		   light_ptr = world.light[light_num]->light.light_point;
                   C_transform_fposition( &(light_ptr->light_pos),
                                &new_pos, &(view.wtol_units) );

		   gl_light[light_num][0] = LCOLOR;
		   gl_light[light_num][1] = 
			(float)(light_ptr->light_color.red)/255.0;
		   gl_light[light_num][2] = 
			(float)(light_ptr->light_color.green)/255.0;
		   gl_light[light_num][3] = 
			(float)(light_ptr->light_color.blue)/255.0;
		   gl_light[light_num][4] = POSITION;
		   gl_light[light_num][5] =  new_pos.x;
		   gl_light[light_num][6] =  new_pos.y;
		   gl_light[light_num][7] =  new_pos.z;
		   gl_light[light_num][8] =  1.000;
		   gl_light[light_num][9] = LMNULL;
		   lmdef( DEFLIGHT, light_num+1, 3, &(gl_light[light_num][0]) );

		   /* Bind The GL Light & Light Model Definition */
		   switch( light_num )
		   {
			case 0:
				lmbind( LIGHT0,	1 );
				break;
			case 1:
				lmbind( LIGHT1,	2 );
				break;
			case 2:
				lmbind( LIGHT2,	3 );
				break;
			case 3:
				lmbind( LIGHT3,	4 );
				break;
			case 4:
				lmbind( LIGHT4,	5 );
				break;
			case 5:
				lmbind( LIGHT5,	6 );
				break;
			case 6:
				lmbind( LIGHT6,	7 );
				break;
			case 7:
				lmbind( LIGHT7,	8 );
				break;
		   }
		}
	}

	/**************************************/
	/* Set GL Light Model Definition Here */
	/**************************************/
	color_ptr = &(world.world_shade.ambient_color);
	gl_light_model[0] = AMBIENT;
	gl_light_model[1] =  
	  ((float)color_ptr->red * world.world_shade.ambient_coef)/255.0;
	gl_light_model[2] = 
	  ((float)color_ptr->green * world.world_shade.ambient_coef)/255.0;
	gl_light_model[3] =
	  ((float)color_ptr->blue * world.world_shade.ambient_coef)/255.0;
	gl_light_model[4] = LOCALVIEWER;
	gl_light_model[5] =  1.000;
	gl_light_model[6] = TWOSIDE;
	gl_light_model[7] =  0.000;
	gl_light_model[8] = LMNULL;
	lmdef( DEFLMODEL,	1, 4, gl_light_model );

	lmbind( LMODEL,	1 );
}

void nav_set_shading( proj_type, volume )
C_NavProjectionType	proj_type;	/* Selects Projection Type */
C_Volume		*volume;
{
	unsigned long	gl_color;	/* GL Color Representation */
	float		gl_material[20];
	C_Color		*color_ptr;
	C_PointLight	*light_ptr;

        GLXwinset( XtDisplay(nav_info.pj_win_info.drawing_area),
		   XtWindow(nav_info.pj_win_info.drawing_area));

	/***************************************************************/
	/* Shading Is Not Necessary For PARC Projections - Use 1 Color */
	/***************************************************************/
	switch( proj_type )
	{
		case C_PARC_FRONT_PROJECTION:
		case C_PARC_BACK_PROJECTION:
			RGBcolor( 0, 255, 0 );
			return;
	}

	/***********************************/
	/* Set GL Material Properties Here */
	/***********************************/
	color_ptr = &(world.world_shade.ambient_color);
	light_ptr = world.light[world.num_lights-1]->light.light_point;

	gl_material[0] = AMBIENT;
	gl_material[1] = 
	  ((float)color_ptr->red * world.world_shade.ambient_coef)/255.0;
	gl_material[2] =
	  ((float)color_ptr->green * world.world_shade.ambient_coef)/255.0;
	gl_material[3] =
	  ((float)color_ptr->blue * world.world_shade.ambient_coef)/255.0;

	switch ( volume->color_type )
	{
	  case C_SINGLE_COLOR:

	    gl_material[4] = DIFFUSE;
	    gl_material[5] = 
	     ( volume->local_shade.simple_shade->diffuse_coef *
	       (float)(volume->color_data.single_color->red) )/255.0;
	    gl_material[6] =
	     ( volume->local_shade.simple_shade->diffuse_coef *
	       (float)(volume->color_data.single_color->green) )/255.0;
	    gl_material[7] =
	     ( volume->local_shade.simple_shade->diffuse_coef *
	       (float)(volume->color_data.single_color->blue) )/255.0;
    
	    break;

	  case C_TEXTURE_COLOR:

	    gl_material[4] = DIFFUSE;
	    gl_material[5] = 1.0;
	    gl_material[6] = 1.0;
	    gl_material[7] = 1.0;
    
	    break;
	}

	gl_material[8] = SPECULAR;
	gl_material[9] = 
	 ( volume->local_shade.simple_shade->specular_coef *
	   (float)(light_ptr->light_color.red) )/255.0;
	gl_material[10] = 
	 ( volume->local_shade.simple_shade->specular_coef *
	   (float)(light_ptr->light_color.red) )/255.0;
	gl_material[11] =
	 ( volume->local_shade.simple_shade->specular_coef *
	   (float)(light_ptr->light_color.red) )/255.0;

    
	gl_material[12] = SHININESS;
	if( volume->local_shade.simple_shade->specular_power <= 128.0 )
	  gl_material[13] = volume->local_shade.simple_shade->specular_power;
	else
	  gl_material[13] = 128;

	gl_material[14] = LMNULL;
	lmdef( DEFMATERIAL,	1, 5, gl_material );

	 /* Bind The GL Material Definition */
	lmbind( MATERIAL, 	1 );
}

void nav_get_zbuffer( proj_type, volume_num )
C_NavProjectionType	proj_type;	/* Selects Projection Type */
int			volume_num;
{
	/* Read The Z Values From Zbuffer */
	readsource( SRC_ZBUFFER );

	switch( proj_type )
	{
	  case C_PARC_FRONT_PROJECTION:
	    lrectread( 	0, 0,
		nav_info.pj_win_info.width_pixels-1,
		nav_info.pj_win_info.height_pixels-1,
		(unsigned long *)nav_info.pj_win_info.zfront[volume_num] );

	    break;
	  case C_PARC_BACK_PROJECTION:
	    lrectread( 	0, 0,
		nav_info.pj_win_info.width_pixels-1,
		nav_info.pj_win_info.height_pixels-1,
		(unsigned long *)nav_info.pj_win_info.zback[volume_num] );
	    break;
	}
}

void nav_unset_shading( proj_type )
C_NavProjectionType	proj_type;	/* Selects Projection Type */
{

	/***************************************************************/
	/* Shading Is Not Necessary For PARC Projections - Use 1 Color */
	/***************************************************************/
	switch( proj_type )
	{
		case C_PARC_FRONT_PROJECTION:
		case C_PARC_BACK_PROJECTION:
			RGBcolor( 0, 0, 0 );
			return;
	}

	/******************************/
	/* Unbind Material Definition */
	/******************************/
	lmbind( MATERIAL, 0 );
}

void nav_unset_lighting( proj_type )
C_NavProjectionType	proj_type;	/* Selects Projection Type */
{
	int light_num;

	/*************************************************/
	/* Lighting Is Not Necessary For PARC Projections */
	/*************************************************/
	switch( proj_type )
	{
		case C_PARC_FRONT_PROJECTION:
		case C_PARC_BACK_PROJECTION:
			return;
	}

	/****************************/
	/* Unbind Each Light Source */
	/****************************/
	for( light_num = 0; light_num<world.num_lights; light_num++ )
	{
		switch( light_num )
		{
			case 0:
				lmbind( LIGHT0,	0 );
				break;
			case 1:
				lmbind( LIGHT1,	0 );
				break;
			case 2:
				lmbind( LIGHT2,	0 );
				break;
			case 3:
				lmbind( LIGHT3,	0 );
				break;
			case 4:
				lmbind( LIGHT4,	0 );
				break;
			case 5:
				lmbind( LIGHT5,	0 );
				break;
			case 6:
				lmbind( LIGHT6,	0 );
				break;
			case 7:
				lmbind( LIGHT7,	0 );
				break;
		}
	}
}

void C_parc_polygon_projection()
{
	int			image_size;
	int			volume_num;
	extern C_View		view;
	extern void		nav_expose_projection_win();

	/****************************************************************/
	/* Make Sure Navigator Projection Window Is Up And Not Occluded */
	/****************************************************************/
	nav_expose_projection_win();

	/********************************************************/
	/*							*/
	/*	Allocate Zbuffers And Project Polygons For 	*/
	/*	PARC Projection					*/
	/*							*/
	/********************************************************/
	image_size = view.width_pixels * view.height_pixels;

	for( volume_num=0; volume_num<world.num_volumes; volume_num++ )
	{
	   if( world.volume[volume_num]->visible )
	   {
	     /*************************************/
	     /* Allocate Memory For Front ZBuffer */
	     /*************************************/
	     nav_info.pj_win_info.zfront[volume_num] = 
			(long *)malloc(image_size*sizeof(long));

	     if( !nav_info.pj_win_info.zfront[volume_num] )
	     {
		C_error_message("Not Enough Memory For Navigator Z Buffer\n");
		return;
	     }

	     /************************************/
	     /* Allocate Memory For Back ZBuffer */
	     /************************************/
	     nav_info.pj_win_info.zback[volume_num] = 
			(long *)malloc(image_size*sizeof(long));

	     if( !nav_info.pj_win_info.zback[volume_num] )
	     {
		C_error_message("Not Enough Memory For Navigator Z Buffer\n");
		return;
	     }
	   }
	} /* End Of For Loop */

	/***************************************************************/
	/* Project Back Facing Polygons To Get Far Distances At Pixels */
	/***************************************************************/
	nav_projection_draw( C_PARC_BACK_PROJECTION );

	/*****************************************************************/
	/* Project Front Facing Polygons To Get Near Distances At Pixels */
	/*****************************************************************/
	nav_projection_draw( C_PARC_FRONT_PROJECTION );
}

/* Provides The Smallest And Largest Distance From The Volumes */
/* Vertices To The View - Note: The Smallest May Be Negative! */
void C_distance_to_view( view, volume_num, smallest, largest )
C_View	*view;
int	volume_num;
float	*smallest;
float	*largest;
{
	int		i;
	C_Volume	*volume;	/* Volume Pointer */
	float		x_units;	/* X Unit Distance Of Volume */
	float		y_units;	/* Y Unit Distance Of Volume */
	float		z_units;	/* Z Unit Distance Of Volume */
	C_FPosition	v_pos;		/* Volume Vertex Position */
	C_FPosition	new_v_pos;	/* New Volume Vertex Position */
	C_FPosition	orig;		/* Volume Origin */
	C_FVector	x_vec;
	C_FVector	y_vec;
	C_FVector	z_vec;
	float		closest_vertex;
	float		farthest_vertex;

	extern		C_transform_fposition();

	volume = world.volume[volume_num];

	orig.x = volume->c_sys.origin.x;
	orig.y = volume->c_sys.origin.y;
	orig.z = volume->c_sys.origin.z;

	x_units = volume->x_size_units;
	y_units = volume->y_size_units;
	z_units = volume->z_size_units;

	x_vec.x = x_units*volume->c_sys.x_axis.x;
	x_vec.y = x_units*volume->c_sys.x_axis.y;
	x_vec.z = x_units*volume->c_sys.x_axis.z;

	y_vec.x = y_units*volume->c_sys.y_axis.x;
	y_vec.y = y_units*volume->c_sys.y_axis.y;
	y_vec.z = y_units*volume->c_sys.y_axis.z;

	z_vec.x = z_units*volume->c_sys.z_axis.x;
	z_vec.y = z_units*volume->c_sys.z_axis.y;
	z_vec.z = z_units*volume->c_sys.z_axis.z;

	closest_vertex = C_BIG_FLOAT;
	farthest_vertex = -C_BIG_FLOAT;

	/* Transform The Volume Vertices Into View C_Sys */
	for( i=0; i<8; i++ )
	{
	   /* Start Vertex With Origin */
	   v_pos.x = orig.x;
	   v_pos.y = orig.y;
	   v_pos.z = orig.z;

	   switch( i )
	   {
		case 0:
		   /* Leave Position At Origin */
		   break;
		case 1:	/* Move To Positive X */
		   v_pos.x += x_vec.x;
		   v_pos.y += x_vec.y;
		   v_pos.z += x_vec.z;
		   break;
		case 2:/* Move To Positive X,Y */
		   v_pos.x += x_vec.x + y_vec.x;
		   v_pos.y += x_vec.y + y_vec.y;
		   v_pos.z += x_vec.z + y_vec.z;
		   break;
		case 3: /* Move To Positive Y */
		   v_pos.x += y_vec.x;
		   v_pos.y += y_vec.y;
		   v_pos.z += y_vec.z;
		   break;
		case 4: /* Move To Positive Z */
		   v_pos.x += z_vec.x;
		   v_pos.y += z_vec.y;
		   v_pos.z += z_vec.z;
		   break;
		case 5: /* Move To Positive X,Z */
		   v_pos.x += z_vec.x + x_vec.x;
		   v_pos.y += z_vec.y + x_vec.y;
		   v_pos.z += z_vec.z + x_vec.z;
		   break;
		case 6: /* Move To Positive X,Y,Z */
		   v_pos.x += z_vec.x + x_vec.x + y_vec.x;
		   v_pos.y += z_vec.y + x_vec.y + y_vec.y;
		   v_pos.z += z_vec.z + x_vec.z + y_vec.z;
		   break;
		case 7:
		   v_pos.x += z_vec.x + y_vec.x;
		   v_pos.y += z_vec.y + y_vec.y;
		   v_pos.z += z_vec.z + y_vec.z;
	   }

	   /* v_pos Now Contains One Of 8 Vertex Coordinates */

	   /* Transform Vertex Into View C_Sys */
	   C_transform_fposition( &v_pos, &new_v_pos,
			&(view->wtol_units) );

	   /* Look For Closest Vertex */
	   if( new_v_pos.z < closest_vertex )
		closest_vertex = new_v_pos.z;
	
	   /* Look For Farthest Vertex */
	   if( new_v_pos.z > farthest_vertex )
		farthest_vertex = new_v_pos.z;
	}

	*smallest = closest_vertex;
	*largest = farthest_vertex;
}
