/****************************************************************************/
/*                                                                          */
/*  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: MOTIF_nav_projection.c
 *		      Author: Rick Avila 
 *			Date: 08/15/92
 *		 Description: GL and Motif Windowing Routines Of The 
 *			      Navigator Wireframe Window  
 *	Modification History:
 *
 *		Who?		When?		Why?
 *	--------------------------------------------------------------------
 *
 */

#include <stdio.h>
#include <math.h>
#include <Xm/ToggleBG.h>
#include <Xm/ToggleB.h>
#include <Xm/SelectioB.h>
#include <Xm/RowColumn.h>
#include <Xm/PushBG.h>
#include <Xm/LabelG.h>
#include <Xm/Scale.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/BulletinB.h>
#include <Xm/DrawingA.h>
#include <Xm/MainW.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>

#include "C_volvis.h"
#include "C_navigator.h"
#include "MOTIF_windefs.h"
#include "C_ide.h"
#include "C_help.h"

Widget		nav_options_bbdialog;

extern	C_View		view;
extern  C_World		world;

/* Global Variables For Motif Windowing */
extern Widget		vv_toplevel;
extern Widget		nav_pj_bbdialog;
extern C_WindowDefs	window_defs;

nav_create_pj_window()
{
	Arg		args[40];	/* Argument List */
	int		n;		/* Argument Count */

	Widget		slider_frame;
	Widget		button_frame;
	Widget		pj_frame;
	Widget		rowcol;
	Widget		pj_drawing_area;
	Widget		button;
	Widget		slider;
	XmString	label_string;

	extern	C_View		view;
	extern C_NavInfo	nav_info;
	extern Widget		create_pj_drawing_area();
	extern void		nav_optionsCB();
	extern void		nav_update_velocityCB();
	extern void		nav_update_speed_stepCB();
	extern void		close_callback();
	extern void		help_callback();

	/**************************************************/		
	/* Create The Navigator Projection Bulletin Board */
	/**************************************************/		
	n=0;
	XtSetArg( args[n], XmNx, 0 ); n++;
	XtSetArg( args[n], XmNy, 0 ); n++;
	XtSetArg( args[n], XmNresize, True ); n++;
	XtSetArg( args[n], XmNautoUnmanage, False ); n++;
	C_Set_Color_Dialog( args, n, window_defs );
	label_string = XmStringCreate( "Navigator Projection", 
					XmSTRING_DEFAULT_CHARSET);
        XtSetArg( args[n], XmNdialogTitle, label_string ); n++;
	nav_pj_bbdialog = XmCreateBulletinBoardDialog( vv_toplevel,
		"Navigator Projection", args, n );

	/********************************/
	/* Create A Frame For Slider(s) */
	/********************************/
	n=0;
	XtSetArg( args[n], XmNx, view.width_pixels + 20 ); n++;
	XtSetArg( args[n], XmNy, 0 ); n++;
	XtSetArg( args[n], XmNwidth, 100 ); n++;
	XtSetArg( args[n], XmNheight, 200 ); n++;
	C_Set_Color_Frame( args, n, window_defs );
	slider_frame = XmCreateFrame( nav_pj_bbdialog, "slider_frame", args,n);
	XtManageChild( slider_frame );

	nav_info.pj_win_info.slider_frame = slider_frame;

	/* Create Velocity Slider */
	n = 0;
        label_string = XmStringCreate("V", XmSTRING_DEFAULT_CHARSET );
	XtSetArg( args[n], XmNtitleString, label_string ); n++;
	XtSetArg( args[n], XmNorientation, XmVERTICAL ); n++;
	XtSetArg( args[n], XmNhighlightOnEnter, 1); n++;
	XtSetArg( args[n], XmNminimum, C_NAV_MIN_FLY_SPEED ); n++;
	XtSetArg( args[n], XmNmaximum, C_NAV_MAX_FLY_SPEED ); n++;
	XtSetArg( args[n], XmNdecimalPoints, 0 ); n++;
	XtSetArg( args[n], XmNshowValue, TRUE ); n++;
	XtSetArg( args[n], XmNvalue, (int)( nav_info.fly_speed ) ); n++;
	XtSetArg( args[n], XmNscaleMultiple, 1 ); n++;
        XtSetArg( args[n], XmNscaleHeight, view.height_pixels ); n++;
	C_Set_Color_Scale( args, n, window_defs );
	slider = XtCreateManagedWidget("V", xmScaleWidgetClass, 
					slider_frame, args, n );

	nav_info.pj_win_info.velocity_slider = slider;

	XtAddCallback(  slider, XmNvalueChangedCallback, 
			nav_update_velocityCB, &nav_info );

	XtAddCallback(  slider, XmNdragCallback, 
			nav_update_velocityCB, &nav_info );

	/****************************************/
	/*	Create A Frame For Buttons	*/
	/****************************************/
	n=0;
	XtSetArg( args[n], XmNx, 0 ); n++;
	XtSetArg( args[n], XmNy, view.height_pixels + 20 ); n++;
	XtSetArg( args[n], XmNtopWidget, slider_frame ); n++;
	C_Set_Color_Frame( args, n, window_defs );
	button_frame = XmCreateFrame( nav_pj_bbdialog, "button_frame", args,n);
	XtManageChild( button_frame );

	nav_info.pj_win_info.button_frame = button_frame;

	/***********************************/
	/* Create A RowCol For The Buttons */
	/***********************************/
	n=0;
	C_Set_Color_RowColumn( args, n, window_defs );
	XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
	rowcol = XmCreateRowColumn(button_frame, "nav_rowcol", args, n);
	XtManageChild( rowcol );

	/************************************************/
	/*     Create The Close Button			*/
	/************************************************/
	n=0;
	XtSetArg( args[n], XmNx, 10 ); n++;
	XtSetArg( args[n], XmNy, view.height_pixels + 20 ); n++;
	C_Set_Color_Button( args, n, window_defs );
	button = XmCreatePushButton( rowcol, "Close", args, n );
	XtManageChild( button );

	XtAddCallback(  button, XmNactivateCallback, close_callback, 
			nav_pj_bbdialog );

	/************************************************/
	/*     Create The Help Button			*/
	/************************************************/
	n=0;
	XtSetArg( args[n], XmNx, 78 ); n++;
	XtSetArg( args[n], XmNy, view.height_pixels + 20 ); n++;
	C_Set_Color_Button( args, n, window_defs );
	button = XmCreatePushButton( rowcol, "Help", args, n );
	XtManageChild( button );
	XtAddCallback(  button, XmNactivateCallback, help_callback, 
			C_NAV_PROJECTION_HELP );

	/************************************************/
	/*     Create The Options Button		*/
	/************************************************/
	n = 0;
	XtSetArg( args[n], XmNx, 135 ); n++;
	XtSetArg( args[n], XmNy, view.height_pixels + 20); n++;
	C_Set_Color_Button( args, n, window_defs);
	button = XmCreatePushButton( rowcol, "Options", args, n);
	XtManageChild( button );
	XtAddCallback( button, XmNactivateCallback, nav_optionsCB,
		       rowcol );

	/*************************************************************/
	/*	Create A Frame For Navigator Projection Drawing Area */
	/*************************************************************/
	n=0;
	XtSetArg( args[n], XmNx, 0 ); n++;
	XtSetArg( args[n], XmNy, 0 ); n++;
	XtSetArg( args[n], XmNwidth, view.width_pixels ); n++;
	XtSetArg( args[n], XmNheight, view.height_pixels ); n++;
	XtSetArg( args[n], XmNresize, True ); n++;
	C_Set_Color_Frame( args, n, window_defs );
	pj_frame = XmCreateFrame( nav_pj_bbdialog, "nav_wf_frame", args, n );
	XtManageChild( pj_frame );

	/********************************************************/		
	/*	Create The Navigator Projection	Drawing Area 	*/
	/********************************************************/		
	pj_drawing_area = create_pj_drawing_area( pj_frame );
}

void nav_set_velocity_slider()
{
	extern C_NavInfo	nav_info;

	/* Set the new slider value */
	XmScaleSetValue( nav_info.pj_win_info.velocity_slider, 
			 (int)(nav_info.fly_speed) );
}

void nav_update_velocityCB(w, nav_info, call_data)
Widget			w;
C_NavInfo		*nav_info;
XmScaleCallbackStruct	*call_data;
{
	/* Set The Fly Speed To The New Slider Value */
	nav_info->fly_speed = (float)(call_data->value);
}

void nav_update_speed_stepCB(w, nav_info, call_data)
Widget			w;
C_NavInfo		*nav_info;
XmScaleCallbackStruct	*call_data;
{
	/* Set The Speed Step To The New Slider Value */
	nav_info->speed_step = (float)(call_data->value) / 10.0;
}

void nav_update_rotate_stepCB(w, nav_info, call_data)
Widget			w;
C_NavInfo		*nav_info;
XmScaleCallbackStruct	*call_data;
{
	/* Set The Rotate Step To The New Slider Value */
	nav_info->rotate_step = (float)(call_data->value) / 10.0;
}

void nav_optionsCB( w, client_data, call_data )
Widget		w;
XtPointer	client_data;
XtPointer	call_data;
{
	extern void	create_options_window();

	if( !nav_options_bbdialog )
		create_options_window();

	XtManageChild( nav_options_bbdialog );
}

void create_options_window()
{
	int		i;
	int		n;
	Arg		args[20];
	XmString	string;
	XmString	label_string;
	Widget		row_column;
	Widget		objects[10];
	Widget		button;
	Widget 		label;
	Widget 		frame;
	Widget		toggle[12];
	Widget 		rc_side, 
			pulldown_side, 
			sub_menu_side, 
			rc_relocate;
	Widget  	speed_step_slider;
	Widget  	rotate_step_slider;
	Widget		toggle_button;
	static	char	*side_name[12] = 
				{ "-X", "+X", 
				  "-Y", "+Y",
				  "-Z", "+Z"};
	int	xpos;

	extern C_World		world;
	extern C_View		view;
	extern C_NavInfo	nav_info;
	extern void 		set_new_view();
	extern void 		set_new_side();
	extern void		nav_update_rotate_stepCB();
	extern void		close_callback();
	extern void		help_callback();

	void			nav_toggle_save_flight();

	/* Setup a dialog box for navigator options */
	n = 0;
	XtSetArg( args[n], XmNx, 0 ); n++;
	XtSetArg( args[n], XmNy, 0 ); n++;
	XtSetArg( args[n], XmNautoUnmanage, False ); n++;

	label_string = XmStringCreate( "Navigator Options", 
					XmSTRING_DEFAULT_CHARSET);
	C_Set_Color_Dialog( args, n, window_defs );
        XtSetArg( args[n], XmNdialogTitle, label_string ); n++;
        nav_options_bbdialog = XmCreateBulletinBoardDialog( vv_toplevel,
                       "Navigator Options Window", args, n );

        /* Add a close button */
	n=0;
	XtSetArg( args[n], XmNx, 100); n++;
	XtSetArg( args[n], XmNy, 250 ); n++;
	C_Set_Color_Button( args, n, window_defs );
	button = XmCreatePushButton( nav_options_bbdialog, "Close", args, n );
	XtManageChild( button );

	XtAddCallback( button, XmNactivateCallback, close_callback, 
			nav_options_bbdialog );

        /* Add a help button */
	n=0;
	XtSetArg( args[n], XmNx, 200); n++;
	XtSetArg( args[n], XmNy, 250 ); n++;
	C_Set_Color_Button( args, n, window_defs );
	button = XmCreatePushButton( nav_options_bbdialog, "Help", args, n );
	XtManageChild( button );

	XtAddCallback( button, XmNactivateCallback, help_callback, 
			nav_options_bbdialog );

	/*  Add a lable for the toggles */
	n=0;
	XtSetArg( args[n], XmNx, 40 ); n++;
	XtSetArg( args[n], XmNy, 15 ); n++;
	C_Set_Color_Label( args, n, window_defs );
	label = XmCreateLabel(nav_options_bbdialog, "View", args, n);
	XtManageChild( label );

	/* Add a frame for the toggles */
	n = 0;
    	XtSetArg (args[n], XmNshadowType, XmSHADOW_ETCHED_IN);  n++;
   	XtSetArg (args[n], XmNx, 5);  n++;
   	XtSetArg (args[n], XmNy, 40);  n++;

	C_Set_Color_Frame( args, n, window_defs );
    	frame = XmCreateFrame( nav_options_bbdialog, "frame", args, n);
    	XtManageChild (frame);
	
	/* Create a radiobox for the toggles */
	n = 0;
	C_Set_Color_RowColumn( args, n, window_defs );
	rc_side = XmCreateRadioBox(frame, "rc_side", args, n); 
	XtManageChild (rc_side);

	/* Create the six toggles */
	for (i = 0; i<6; i++)
	{
	    n = 0;

	    string = XmStringCreate (side_name[i],
					XmSTRING_DEFAULT_CHARSET);
	    XtSetArg (args[n], XmNlabelString, string); n++;
	    XtSetArg( args[n], XmNset, 0); n++;

	    C_Set_Color_ToggleGadget( args, n, window_defs );

	    toggle[i] = XmCreateToggleButtonGadget(rc_side, 
				   side_name[i], args, n);
	    XmStringFree (string);
	    XtManageChild(toggle[i]);
  	    XtAddCallback( toggle[i], XmNvalueChangedCallback, 
					set_new_side, i );
	}

	/* Add pulldown menu for object selection */
	n = 0;
   	XtSetArg (args[n], XmNx, 100);  n++;
   	XtSetArg (args[n], XmNy, 10);  n++;
	C_Set_Color_RowColumn( args, n, window_defs );
	row_column = XmCreateRowColumn( nav_options_bbdialog, "rc", args, n); 
	XtManageChild (row_column);


	n = 0;
	C_Set_Color_PullDown( args, n, window_defs );
	nav_info.pj_opt_win_info.pulldown = XmCreatePulldownMenu(
			row_column, "pulldown", args, n); 
	/* No objects in the world */
	if(!world.num_volumes)
	{
	    n = 0;
	    string = XmStringCreate("No Volumes", XmSTRING_DEFAULT_CHARSET);
	    XtSetArg (args[n], XmNlabelString, string); n++;
	    nav_info.pj_opt_win_info.vol[0] = 
		XmCreatePushButtonGadget( nav_info.pj_opt_win_info.pulldown, 
		"No Volumes", args, n);
	    XmStringFree (string);
	    XtManageChild(nav_info.pj_opt_win_info.vol[0]);
	}
	/* Add objects to menu */
	else
	{
	  for (i=0; i<world.num_volumes; i++)
	  { 

	    string = XmStringCreate (world.volume[i]->volume_name, 
					XmSTRING_DEFAULT_CHARSET);
	    n = 0;
	    XtSetArg (args[n], XmNlabelString, string); n++;
	    nav_info.pj_opt_win_info.vol[i] = 
			XmCreatePushButtonGadget( 
			nav_info.pj_opt_win_info.pulldown, 
			world.volume[i]->volume_name, args, n);
	    XtManageChild(nav_info.pj_opt_win_info.vol[i]);

	    XtAddCallback(nav_info.pj_opt_win_info.vol[i], XmNactivateCallback, 
			  set_new_view, i);

	    XmStringFree(string);
	  }

	  nav_info.pj_opt_win_info.previous_vol = i;
	  nav_info.pj_opt_win_info.num_volumes = world.num_volumes;
	}

	/* Create submenu */
	n = 0;
	string = XmStringCreate ("Object", XmSTRING_DEFAULT_CHARSET);
	XtSetArg (args[n], XmNlabelString, string); n++;
	XtSetArg (args[n], XmNsubMenuId, nav_info.pj_opt_win_info.pulldown);n++;
	C_Set_Color_OptionMenu( args, n, window_defs );
	nav_info.pj_opt_win_info.sub_menu = 
		XmCreateOptionMenu( row_column, "option_menu", args, n);
	XtManageChild(nav_info.pj_opt_win_info.sub_menu);

	/*	Create Speed Step	*/
	/* Adding a speed increment slider */
	n = 0;
        label_string = XmStringCreate("Speed Step", XmSTRING_DEFAULT_CHARSET );
	XtSetArg( args[n], XmNtitleString, label_string ); n++;
	XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
	XtSetArg( args[n], XmNminimum, 0 ); n++;
	XtSetArg( args[n], XmNmaximum, 10 * C_NAV_MAX_FLY_SPEED ); n++;
	XtSetArg( args[n], XmNdecimalPoints, 1 ); n++;
	XtSetArg( args[n], XmNshowValue, TRUE ); n++;
	XtSetArg( args[n], XmNvalue, (int) (10.0 * nav_info.speed_step) ); n++;
	XtSetArg( args[n], XmNscaleMultiple, 1 ); n++;
        XtSetArg( args[n], XmNscaleWidth, 200); n++;
        XtSetArg( args[n], XmNx, 100 ); n++;
        XtSetArg( args[n], XmNy, 70); n++;
	C_Set_Color_Scale( args, n, window_defs );
	speed_step_slider = XtCreateManagedWidget("Speed Step", 
			xmScaleWidgetClass, nav_options_bbdialog, args, n );

	XtAddCallback( speed_step_slider, XmNvalueChangedCallback, 
			nav_update_speed_stepCB, &nav_info );

	XtAddCallback( speed_step_slider, XmNdragCallback,
			nav_update_speed_stepCB, &nav_info );

	XtManageChild(speed_step_slider);

	/* Add Turn Speed slider */
	n = 0;
        label_string = XmStringCreate("Turn Speed", XmSTRING_DEFAULT_CHARSET );
	XtSetArg( args[n], XmNtitleString, label_string ); n++;
	XtSetArg( args[n], XmNorientation, XmHORIZONTAL ); n++;
	XtSetArg( args[n], XmNminimum, 0 ); n++;
	XtSetArg( args[n], XmNmaximum, 500 ); n++;
	XtSetArg( args[n], XmNdecimalPoints, 1 ); n++;
	XtSetArg( args[n], XmNshowValue, TRUE ); n++;
	XtSetArg( args[n], XmNvalue, 
			(int) (10.0 * nav_info.rotate_step) ); n++;
	XtSetArg( args[n], XmNscaleMultiple, 1 ); n++;
        XtSetArg( args[n], XmNscaleWidth, 200); n++;
        XtSetArg( args[n], XmNx, 100 ); n++;
        XtSetArg( args[n], XmNy, 130); n++;
	C_Set_Color_Scale( args, n, window_defs );
	rotate_step_slider = XtCreateManagedWidget("Turn Speed", 
			xmScaleWidgetClass, nav_options_bbdialog, args, n );

	XtAddCallback(  rotate_step_slider, XmNvalueChangedCallback, 
			nav_update_rotate_stepCB, &nav_info );

	XtAddCallback(  rotate_step_slider, XmNdragCallback, 
			nav_update_rotate_stepCB, &nav_info );

	XtManageChild(rotate_step_slider);

	n = 0;
	XtSetArg( args[n], XmNx, 100 ); n++;
	XtSetArg( args[n], XmNy, 200 ); n++;
	XtSetArg( args[n], XmNlabelString, 
		XmStringCreate( "Save Next Flight", XmSTRING_DEFAULT_CHARSET)); 
	n++;
	XtSetArg( args[n], XmNset, nav_info.save_next_flight ); n++;

	C_Set_Color_ToggleGadget( args, n, window_defs );

	toggle_button = XmCreateToggleButtonGadget(nav_options_bbdialog, 
				   "save next flight", args, n);
	XmStringFree (string);
	XtManageChild(toggle_button);
  	XtAddCallback( toggle_button, XmNvalueChangedCallback, 
		       nav_toggle_save_flight, NULL );
}


void update_nav_options()
{
	int		vol;
	int		n;
	Arg		args[10];
	XmString	string;

	extern C_NavInfo	nav_info;
	extern void		set_new_view();

	/* Update objects in for the nav option menu dynamically */
	if( nav_options_bbdialog )
	{
		if( nav_info.pj_opt_win_info.num_volumes == 0 )
		{
			/* Destroy The Single NO_VOLUMES Widget */
			if( world.num_volumes )
			    XtDestroyWidget(nav_info.pj_opt_win_info.vol[0]);
			else
			    return;
		}
		else
		{
		    /* Destroy All Previously Created Volume Widgets */
		    for(vol=0; vol < nav_info.pj_opt_win_info.num_volumes;vol++)
		    {
			XtDestroyWidget(nav_info.pj_opt_win_info.vol[vol]);
		    }
		}

		for( vol=0; vol < world.num_volumes; vol++)
		{
		   string = XmStringCreate(world.volume[vol]->volume_name, 
					XmSTRING_DEFAULT_CHARSET);
		   n = 0;
		   XtSetArg(args[n], XmNlabelString, string); n++;
		   nav_info.pj_opt_win_info.vol[vol] = 
		   	XmCreatePushButtonGadget( 
			nav_info.pj_opt_win_info.pulldown, 
		   	world.volume[vol]->volume_name, args, n);

		   XtAddCallback(nav_info.pj_opt_win_info.vol[vol],
			XmNactivateCallback, set_new_view, vol);

	      	   XtManageChild(nav_info.pj_opt_win_info.vol[vol]);

		   XmStringFree(string);
		}

		/* Set The New Number Of Volumes */
		 nav_info.pj_opt_win_info.num_volumes = world.num_volumes;

		/* If Last Selected Volume Is Out Of Range Then Reset To 0 */
		if( nav_info.pj_opt_win_info.previous_vol >= world.num_volumes )
			nav_info.pj_opt_win_info.previous_vol = 0;

		/* Keep the Same Menu Selection As Before */
		n = 0;
		XtSetArg( args[n], XmNmenuHistory, 
			nav_info.pj_opt_win_info.vol[
			  nav_info.pj_opt_win_info.previous_vol] ); n++;
		XtSetArg(args[n], XmNsubMenuId, 
			nav_info.pj_opt_win_info.pulldown ); n++;
		XtSetValues( nav_info.pj_opt_win_info.sub_menu, args, n );
	}
}

void nav_toggle_save_flight(w, client_data, call_data)
Widget		w;
XtPointer	client_data;
XtPointer	call_data;
{
	extern C_NavInfo	nav_info;

	if ( nav_info.save_next_flight )
		nav_info.save_next_flight = FALSE;
	else
		nav_info.save_next_flight = TRUE;
}

void set_new_side(w, client_data, call_data)
Widget		w;
int		client_data;
XtPointer	call_data;
{
	extern C_NavInfo	nav_info;

	/* Set The Current Side Of An Object To Look At With View */
	nav_info.pj_opt_win_info.current_side = client_data;

	/*  If there are objects in the world and no object was selected
	    yet then assign current volume to be the first object */
	if( world.num_volumes )
	{
		if(nav_info.pj_opt_win_info.current_volume < 0)
			nav_info.pj_opt_win_info.current_volume = 0;

		/* If the number of volumes = 1 then current volume */
		/* is the first object */
		if(world.num_volumes == 1)
		{
			nav_info.pj_opt_win_info.current_volume = 0;
		}

		C_orient_view( &nav_info );
	}
}

void set_new_view(w, client_data, call_data)
Widget		w;
int		client_data;
XtPointer	call_data;
{
	extern C_NavInfo	nav_info;

	if( client_data == -1 )
		return;

	/* Set The Current Side Of An Object To Look At With View */
	nav_info.pj_opt_win_info.current_volume = client_data;

	C_orient_view( &nav_info );
}

C_orient_view( nav_info )
C_NavInfo	*nav_info;
{
	int		i,j,k;
	C_FPosition	start_pos, 
			end_pos, 
			start_pos_world, 
			end_pos_world;
	C_FPosition	view_dir, 
			temp_view, 
			temp_origin;
	float		temp_float;
	C_Volume	*volume;
	int		in_volume = TRUE;
	int		vol_num;
	extern 		C_rotate_view_local();

	extern void	C_copy_c_sys();
	extern void	C_identity3D();
	extern void	nav_update();

	volume = world.volume[nav_info->pj_opt_win_info.current_volume];

	/* Center of the object locally */
	start_pos.x = (volume->x_size_units / 2.0);
	start_pos.y = (volume->y_size_units / 2.0);
	start_pos.z = (volume->z_size_units / 2.0);

	/* Setup viewing properties */
        view.c_sys.x_axis.x      = 1.0;
        view.c_sys.x_axis.y      = 0.0;
        view.c_sys.x_axis.z      = 0.0;

        view.c_sys.y_axis.x      = 0.0;
        view.c_sys.y_axis.y      = 1.0;
        view.c_sys.y_axis.z      = 0.0;
 
        view.c_sys.z_axis.x      = 0.0;
        view.c_sys.z_axis.y      = 0.0;
        view.c_sys.z_axis.z      = 1.0;

	/* Setting the point of view */
	end_pos.x = start_pos.x;
	end_pos.y = start_pos.y;
	end_pos.z = start_pos.z - 1.0;

	/* Transform local into world coordinates */
	C_transform_fposition( &(start_pos), &(start_pos_world),
                 &(volume->ltow_units) );
	C_transform_fposition( &(end_pos), &(end_pos_world),
                 &(volume->ltow_units) );

	/* Setup origin of view */
	temp_view.x = view.c_sys.origin.x = start_pos_world.x;
	temp_view.y = view.c_sys.origin.y = start_pos_world.y;
	temp_view.z = view.c_sys.origin.z = start_pos_world.z;
	temp_view.z = view.c_sys.origin.z -= 1.5 * volume->z_size_units;

	/* Reset viewing matrix */
	C_identity3D( &(view.transform) );

        C_create_view_matrices( &view );

	/* Store new coordinates as originals */
	C_copy_c_sys( &(view.c_sys.origin), &(view.orig_c_sys.origin) );

	/* Determine the side of view */
	switch( nav_info->pj_opt_win_info.current_side )
	{
	    /* X CASE */
	    case 0:
		      C_rotate_view_world(&view, C_Y_AXIS, 
					  C_Deg_To_Rad(90.0),
					  &start_pos_world);
		      break;
	    case 1:
		      C_rotate_view_world(&view, C_Y_AXIS, 
					  C_Deg_To_Rad(-90.0),
					  &start_pos_world);
		      break;
	    /* Y CASE */
	    case 2:
		      C_rotate_view_world(&view, C_X_AXIS, 
					  C_Deg_To_Rad(-90.0),
					  &start_pos_world);
		      break;
	    case 3:
		      C_rotate_view_world(&view, C_X_AXIS, 
					  C_Deg_To_Rad(90.0),
					  &start_pos_world);
		      break;
	    /* Z CASE */
	    case 4:
		      /* No Rotation Necessary */
		      break;
	    case 5:
		      C_rotate_view_world(&view, C_Y_AXIS, 
					  C_Deg_To_Rad(180.0),
					  &start_pos_world);
		      break;
	    default:  break;
	}


	temp_view.x = view.c_sys.origin.x;
	temp_view.y = view.c_sys.origin.y;
	temp_view.z = view.c_sys.origin.z;
    
	/*  This was suppose to check if you are in an object but
	    didn't have time to debug and test */
/*****
	while(in_volume)
	{
	    for(vol_num = 0; vol_num < world.num_volumes; vol_num++)
	    {
		volume = world.volume[vol_num];

		temp_origin.x = volume->c_sys.origin.x + volume->x_size_units;
		temp_origin.y = volume->c_sys.origin.y + volume->y_size_units;
		temp_origin.z = volume->c_sys.origin.z + volume->z_size_units;

		printf("Origin of Object is %f %f %f\n",
		       volume->c_sys.origin.x, volume->c_sys.origin.y,
		       volume->c_sys.origin.z);

		printf("The view is at %f %f %f\n",
			view.c_sys.origin.x, 
			view.c_sys.origin.y, 
			view.c_sys.origin.z);

		printf("Upper limit for object is %f %f %f\n",
		       temp_origin.x, temp_origin.y, temp_origin.z);


		if((view.c_sys.origin.x > volume->c_sys.origin.x) &&
		   (view.c_sys.origin.x < temp_origin.x) &&
		   (view.c_sys.origin.y > volume->c_sys.origin.y) &&
		   (view.c_sys.origin.y < temp_origin.y) &&
		   (view.c_sys.origin.z > volume->c_sys.origin.z) &&
		   (view.c_sys.origin.z < temp_origin.z))
		{
		/****	printf("You are in an object\n"); ****  /
			view.c_sys.origin.z += 100.0;
			view.c_sys.z_axis.x = 
				-(view.c_sys.origin.x - start_pos_world.x);
			view.c_sys.z_axis.y = 
				-(view.c_sys.origin.y - start_pos_world.y);
			view.c_sys.z_axis.z = 
				-(view.c_sys.origin.z - start_pos_world.z);
			nav_update();
		}
		else
		{
			in_volume = FALSE;
		/****	printf("You are in the CLEAR\n"); ****  /
		}

	     }
	}
*****/
	/* Setup vector of viewing direction */
	view.c_sys.z_axis.x = -(view.c_sys.origin.x -start_pos_world.x);
	view.c_sys.z_axis.y = -(view.c_sys.origin.y -start_pos_world.y);
	view.c_sys.z_axis.z = -(view.c_sys.origin.z -start_pos_world.z);

	C_Normalize(    view.c_sys.z_axis.x, 
			view.c_sys.z_axis.y, 
			view.c_sys.z_axis.z, temp_float );

	/* Update The Navigator */
	nav_update();
}

void nav_pj_expose_CB(w, client_data, call_data)
Widget          w;
int             client_data;
XtPointer       call_data;
{
	static int	first_call = TRUE;

	extern void	nav_pj_init();
	extern void	nav_update();

	/**********************************************/
	/* Check To See If This Is The First Expose   */
	/* If So, Then Initialize The GL Drawing Area */
	/**********************************************/
	if( first_call )
	{
		nav_pj_init();

		first_call = FALSE;
	}

        if( !(XtIsManaged(w)) )
                return;

        /* Draw The Contents Of The Navigator Projection Window */
	nav_update();
}

void nav_pj_resize_CB(w, client_data, call_data)
Widget          w;
int             client_data;
XtPointer       call_data;
{
        extern void	nav_update();

        nav_update();
}

void nav_pj_input_CB( w, client_data, event )
Widget		w;
XtPointer	client_data;
XEvent		*event;
{
	void	nav_fly();

	switch( event->type )
	{
		case KeyPress:
			break;
		case ButtonPress:
			break;
		case ButtonRelease:
			switch(event->xbutton.button)
			{
		  	   case Button1:
				nav_fly( w );
				break;
			}
			break;
		case MotionNotify:
			break;
	}

}

void nav_fly( w )
Widget	w;
{
	extern C_World		world;
	extern C_View		view;
	extern C_NavInfo	nav_info;


	C_NavFlyStatus	fly_status;	/* Navigator Flight Status */
	float		x_rot,		/* X, Y, & Z View Rotation */
			y_rot,
			z_rot;

	int		animate_fd;
	int		anim_count;
	int		loop;

	float		trans_x = 0.0;
	float		trans_y = 0.0;

	float		project_time;
	float		forward_dist;

        extern C_IDE_VD_configuration       IDE_active_config;

        extern int      C_ide_get_selection();
        extern void     C_ide_get_token();
        extern int      C_ide_test_end();
        
	extern void	C_update_system();
	void		nav_save_world_state();
	void		nav_set_velocity_slider();

	C_Time_Val	prev_time;
	C_Time_Val	current_time;
        C_IDE_token     token;
        int             selection;

	C_CoordSys	tmp_c_sys;
	C_Matrix	tmp_matrix;
	C_Matrix	rotation_matrix;
	C_Matrix	translation_matrix;
	int		i, j;
	float		old_x_pos, old_y_pos, old_z_pos;
	int		old_pos_valid;

	extern void	C_get_time();
	extern double	C_diff_sec();
	extern int	C_write_env_to_file();

	anim_count = 0;

	/***  Save an environment if the user wants to generate a flight ***/
	/***  file.  Use the filename from the animator.		 ***/
	if ( nav_info.save_next_flight )
	{
		system("/bin/rm testflight.env");
		C_write_env_to_file( "testflight.env" );
		system("/bin/rm testflight.flt");
		animate_fd = open( "testflight.flt", 
			O_WRONLY | O_CREAT, 0644 );
	}

 
	C_get_time( &prev_time );

	/* Update The Navigator To Get Timing Information */
	C_update_system( C_VIEW_MODIFIED );

	C_get_time( &current_time );

	project_time = C_diff_sec( &prev_time, &current_time );

	forward_dist =  nav_info.fly_speed * project_time;

	fly_status = C_NAV_FLYTHROUGH;
	while( fly_status == C_NAV_FLYTHROUGH )
	{
		/* Get The Position Of The Cursor */
                C_ide_get_token(&token, w);

		switch ( IDE_active_config.ori )
		{
		  case C_MOUSE:

			/* Get The Position Of The Cursor */

                	x_rot = (2.0*(-1*(token.pos2d.y-1)))-1;
                	y_rot = (2.0*token.pos2d.x)-1;

			x_rot *= nav_info.rotate_step * project_time;
			y_rot *= nav_info.rotate_step * project_time;
			z_rot = 0.0;

			/* Rotate About Local X & Y Axis */

			C_rotate3D( C_X_AXIS, C_Deg_To_Rad(x_rot),
				    &rotation_matrix );

			C_rotate3D( C_Y_AXIS, C_Deg_To_Rad(y_rot),
				    &tmp_matrix );

			C_matrix_multiply( C_POST_MULTIPLY, 
				&rotation_matrix, &tmp_matrix );
			break;

		  case C_SPACEBALL:

			for( i = 0; i < 4; i++ )
		  	for ( j = 0; j < 4; j++ )
				rotation_matrix.matrix[i][j] = 
					token.rotation.matrix[j][i];
			break;

                   case C_DATAGLOVE:
                        
                         rotation_matrix = token.rotation;

                         break;
		}
	
                selection = C_ide_get_selection();
                switch( selection )
		{
                   case -1: 
			     break;
                   case 1:   z_rot = 1.0;
                             C_rotate_view_local(&view, C_Z_AXIS,
                             C_Deg_To_Rad(z_rot), &(view.c_sys.origin) );
                             break;
                   case 2:   z_rot = -1.0;
                             C_rotate_view_local(&view, C_Z_AXIS,
                             C_Deg_To_Rad(z_rot), &(view.c_sys.origin) );              
                             break;
                   case 3:   
                        if(     (nav_info.fly_speed - nav_info.speed_step) >
                                 C_NAV_MIN_FLY_SPEED )
                        {
                            nav_info.fly_speed -= nav_info.speed_step;
                        }
                        else
                        {
                            C_message("You Can't Go Any Faster In Reverse\n");
                            nav_info.fly_speed = C_NAV_MIN_FLY_SPEED;
                        }

                        nav_set_velocity_slider();

                        break;

                    case 4: 
                        if(     (nav_info.fly_speed + nav_info.speed_step) <
                                 C_NAV_MAX_FLY_SPEED )
                        {
                            nav_info.fly_speed += nav_info.speed_step;
                        }
                        else
                        {
                            nav_info.fly_speed = (float) C_NAV_MAX_FLY_SPEED;
                            C_message("You Can't Go Any Faster\n");
                        }

                        nav_set_velocity_slider();
                        break;
                   default:  break;
                 }

		/* Move Forward */
		if ( IDE_active_config.pos3dx == C_MOUSE &&
		     IDE_active_config.pos3dy == C_MOUSE &&
		     IDE_active_config.pos3dz == C_MOUSE )
		{
			C_translate3D( 0.0, 0.0, forward_dist, 
				       &translation_matrix );
		}
		else
		{
			if ( old_pos_valid )
			{
				C_translate3D( 
					(token.pos3d.x - old_x_pos ),
					(token.pos3d.y - old_y_pos ),
					(token.pos3d.z - old_z_pos ),
					&translation_matrix );
			}
			else
			{
				C_identity3D( &translation_matrix );
				old_pos_valid = TRUE;
			}

			old_x_pos = token.pos3d.x;
			old_y_pos = token.pos3d.y;
			old_z_pos = token.pos3d.z;
		}

		C_matrix_multiply( C_POST_MULTIPLY, &rotation_matrix, 
				   &translation_matrix );

		C_matrix_multiply( C_PRE_MULTIPLY, &rotation_matrix, 
				   &(view.wtol_units) );
			
		C_matrix_multiply( C_POST_MULTIPLY, &rotation_matrix, 
				   &(view.ltow_units) );

		C_matrix_multiply( C_POST_MULTIPLY, 
				    &(view.transform), &(rotation_matrix) ); 

		C_transform_c_sys( &(view.orig_c_sys), &(view.c_sys), 
				   &(view.transform) );

		C_create_view_matrices( &view );

		if ( nav_info.save_next_flight )
		{
			write( animate_fd, &(anim_count), sizeof(int) );
			write( animate_fd, &(x_rot), sizeof(float) );
			write( animate_fd, &(y_rot), sizeof(float) );
			write( animate_fd, &(z_rot), sizeof(float) );
			write( animate_fd, &(trans_x), sizeof(float) );
			write( animate_fd, &(trans_y), sizeof(float) );
			write( animate_fd, &(forward_dist), sizeof(float) );
		}

		/* Update The Navigator */
		C_update_system( C_VIEW_MODIFIED );

                if (C_ide_test_end(w))
                    fly_status = C_NAV_NOFLY;

		/* Store Previous Time */
		prev_time.sec  = current_time.sec;
		prev_time.usec = current_time.usec;

		/* Get The Current Time */
		C_get_time( &current_time );

		project_time = C_diff_sec( &prev_time, &current_time );
		forward_dist =  nav_info.fly_speed * project_time;

		anim_count++;
	}

	if ( nav_info.save_next_flight )
		close( animate_fd );

}

void nav_setup_extra_draw_info( extra_draw_info, proj_type, near, far )
C_ExtraDrawInfo		*extra_draw_info;
C_NavProjectionType     proj_type;
float			near, far;
{
	extern C_NavInfo	nav_info;

        switch( proj_type )
        {
            case C_NAV_WIREFRAME:
            case C_NAV_WIREFRAME_KEY:
                break;
            case C_NAV_PROJECTION:
            case C_PARC_FRONT_PROJECTION:
            case C_PARC_BACK_PROJECTION:
		extra_draw_info->display = 
			XtDisplay( nav_info.pj_win_info.drawing_area );	
		extra_draw_info->window = 
			XtWindow( nav_info.pj_win_info.drawing_area );	
		extra_draw_info->gc = nav_info.pj_win_info.gc;
		extra_draw_info->pixmap = nav_info.pj_win_info.pixmap;
		extra_draw_info->near_plane = near;
		extra_draw_info->far_plane = far;
		C_copy_matrix( &(nav_info.pj_win_info.vol_to_view_matrix),
			       &(extra_draw_info->vol_to_view_matrix) );
		C_copy_matrix( &(nav_info.pj_win_info.projection_matrix),
			       &(extra_draw_info->projection_matrix) );
		extra_draw_info->width_pixels = 
			nav_info.pj_win_info.width_pixels;
		extra_draw_info->height_pixels = 
			nav_info.pj_win_info.height_pixels;
                break;
        }

}


