/****************************************************************************/
/*                                                                          */
/*  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_ide_mouse.c
 *                  Author: He, Taosong
 *                  Date:   1/18/93
 *           Description: C routines for driving input device mouse 
 *  Modification History:
 *
 *         who?         when?           why?
 *    -----------------------------------------------------------
 *
 */

/******************************************************************/
/*                The standard C include file                     */
/******************************************************************/


#include <stdio.h>
#include <math.h>

/******************************************************************/
/*                  VolVis include file                           */
/******************************************************************/

#include "C_volvis.h"
#include "C_ide.h"

/* Global variable: ide_data_token. 
   This variable include all the information about the input device mouse. */

extern C_IDE_token ide_data_token[C_MAX_RD_NUMBER];

/* Gloabl variable: mouse_input_mode.
   These two variables defines the mode of mouse.
*/

static int mouse_input_mode=MOUSE_ONE_AXIS_MODE;

/* Global variable: start_x, start_y.
   These two variables defines the start position of the mouse.
*/

static int start_x=0.0, start_y=0.0;

/*
 *        Procedure Name: track_mouse_position
 *          Return Value: void
 *       Input Variables: The new position of the mouse
 *      Output Variables:
 *      Update Variables: Global variable ide_data_token[C_MOUSE]
 *      Global Variables: IDE_active_window_information. Records some 
 *                        parameters of the current active window.
 *                        ide_data_token[C_MOUSE].
 *           Description: Track the mouse position and update the mouse
 *                        token with the newest position (Triad method.)
 */

void track_mouse_position(x_cor, y_cor)
int        x_cor, y_cor;
{

     extern void mouse_report_token();
     extern C_IDE_window_information IDE_active_window_information;
     extern C_IDE_simulation_method C_ide_simulation_method;
     char   temp_str[100];

     float x_inc,y_inc,z_inc;
     static float diff_x,diff_y;
     static float end_x,end_y;

     end_x= (float)x_cor;
     end_y= (float)(IDE_active_window_information.height-y_cor);


     if (C_ide_simulation_method.unit != C_PIXEL) 
     {
      ide_data_token[C_MOUSE].pos2d.x=end_x/IDE_active_window_information.width;
      ide_data_token[C_MOUSE].pos2d.y=end_y/IDE_active_window_information.height;
     }
     else
     {
      ide_data_token[C_MOUSE].pos2d.x=end_x;
      ide_data_token[C_MOUSE].pos2d.y=end_y;
     } 

     diff_x=end_x-start_x;
     diff_y=end_y-start_y;

     start_x=end_x; 
     start_y=end_y;

     x_inc=diff_x;
     y_inc=diff_y;
     z_inc=0.707*(x_inc+y_inc);

     if (C_ide_simulation_method.unit != C_PIXEL)
     {
      x_inc /= IDE_active_window_information.width;
      y_inc /= IDE_active_window_information.height;
      z_inc =  0.707*(x_inc+y_inc);
     }
 
     if (mouse_input_mode==MOUSE_THREE_AXES_MODE)
     {
     if ( (x_inc >= y_inc ) && (x_inc >= z_inc) ) { y_inc=0.0; z_inc=0.0; }
     else if ( (y_inc >= x_inc ) && (y_inc >= z_inc) ) {y_inc=0.0; z_inc=0.0;}
     else {x_inc=0.0; y_inc=0.0;}
     }

     ide_data_token[C_MOUSE].pos3d.x += x_inc;
     ide_data_token[C_MOUSE].pos3d.y += y_inc;
     ide_data_token[C_MOUSE].pos3d.z += z_inc;

     sprintf(temp_str, "x2d:%.2f y2d:%.2f x:%.2f y:%.2f z:%.2f",
               ide_data_token[C_MOUSE].pos2d.x,
               ide_data_token[C_MOUSE].pos2d.y,
               ide_data_token[C_MOUSE].pos3d.x,
               ide_data_token[C_MOUSE].pos3d.y,
               ide_data_token[C_MOUSE].pos3d.z);

     mouse_report_token(temp_str);
     
 }

/* A group of variable concering the initializing of arcball. */
static float start_orientation_x,
             start_orientation_y, 
             start_orientation_z;
static float cent_x, cent_y;
static float radius; 

/*
 *        Procedure Name: track_mouse_orientation
 *          Return Value: void 
 *       Input Variables: new position of the mouse pointer.
 *      Output Variables:
 *      Update Variables: ide_data_token[C_MOUSE]
 *      Global Variables: IDE_active_window_information
 *                        ide_data_token[C_MOUSE]
 *           Description: Use arcball method to interprete the pointer 
 *                        movement into quaternion representation of the
 *                        orientation                   
 */

void track_mouse_orientation(x_cor, y_cor)
  int     x_cor, y_cor;
{
     extern  void mouse_report_token();
     char    temp_str[100];

     extern  C_IDE_window_information        IDE_active_window_information;

     float distance;

     float r,s;
     static float diff_x,diff_y;
     static float end_x, end_y;


     end_x=(float)x_cor;
     end_y=(float)(IDE_active_window_information.height-y_cor);

     diff_x=end_x-cent_x;
     diff_y=end_y-cent_y;


     ide_data_token[C_MOUSE].quaternion.x=diff_x/radius;
     ide_data_token[C_MOUSE].quaternion.y=diff_y/radius;
     
     r=ide_data_token[C_MOUSE].quaternion.x*ide_data_token[C_MOUSE].quaternion.x+
       ide_data_token[C_MOUSE].quaternion.y*ide_data_token[C_MOUSE].quaternion.y;
 
     if (r>1) r=1.0;

     ide_data_token[C_MOUSE].quaternion.z=sqrt(1.0-r);
     

     distance=(ide_data_token[C_MOUSE].quaternion.x-start_orientation_x)*
              (ide_data_token[C_MOUSE].quaternion.x-start_orientation_x)+
              (ide_data_token[C_MOUSE].quaternion.y-start_orientation_y)*
              (ide_data_token[C_MOUSE].quaternion.y-start_orientation_y)+
              (ide_data_token[C_MOUSE].quaternion.z-start_orientation_z)*
              (ide_data_token[C_MOUSE].quaternion.z-start_orientation_z);
     if (distance > 4) distance=4;
     distance=sqrt(distance)/4;
     
     ide_data_token[C_MOUSE].quaternion.w = sqrt(1.0-distance*distance);
     ide_data_token[C_MOUSE].quaternion.x = distance* ide_data_token[C_MOUSE].quaternion.x;
     ide_data_token[C_MOUSE].quaternion.y = distance* ide_data_token[C_MOUSE].quaternion.y;
     ide_data_token[C_MOUSE].quaternion.z = distance* ide_data_token[C_MOUSE].quaternion.z;

     sprintf(temp_str, 
              "x: %.2f  y: %.2f  z: %.2f  w: %.2f",
              ide_data_token[C_MOUSE].quaternion.x,
              ide_data_token[C_MOUSE].quaternion.y,
              ide_data_token[C_MOUSE].quaternion.z,
              ide_data_token[C_MOUSE].quaternion.w);
     
     mouse_report_token(temp_str);

}

/* Global variable which tell whether the movement is the first movement 
   after initialization. */

static int mouse_first_flag=0;

/*
 *        Procedure Name: initialize_mouse
 *          Return Value: void
 *       Input Variables: new position of the mouse pointer
 *      Output Variables: 
 *      Update Variables: ide_data_token[C_MOUSE]
 *      Global Variables: IDE_active_window_information
 *                        ide_data_token[C_MOUSE]
 *           Description: Initialize the mouse token
 */

void initialize_mouse(xcor, ycor)
int xcor, ycor;
{
   extern C_IDE_window_information IDE_active_window_information;

   float r;
   float diff_x,diff_y;

   start_x=(float)xcor;
   start_y=(float)ycor;
    
   if (mouse_input_mode==MOUSE_ARCBALL_MODE) 
          {
            cent_x=(float)IDE_active_window_information.width/2; 
            cent_y=(float)IDE_active_window_information.height/2;

            radius=cent_x;
            if (radius > cent_y) radius=cent_y;

            diff_x=start_x-cent_x;
            diff_y=start_y-cent_y;
 

            start_orientation_x=diff_x/radius;
            start_orientation_y=diff_y/radius;
            r=start_orientation_x*start_orientation_x +
              start_orientation_y*start_orientation_y;
            if (r>1) r=1; 
            start_orientation_z=sqrt(1.0-r); 
         }

/* after the initialization, set the flag to be 0 */

   mouse_first_flag=0;   
     
}

/*
 *        Procedure Name: monitor_mouse_motion 
 *          Return Value: void
 *       Input Variables: the new position of the mouse pointer 
 *      Output Variables: 
 *      Update Variables: 
 *      Global Variables: 
 *                        mouse_first_flag;
 *           Description: When user start or end the tracking, this function
 *                        is called to set some parameters.
 */

void monitor_mouse_motion(x_cor, y_cor)
int x_cor, y_cor;
{
extern C_IDE_simulation_method C_ide_simulation_method;

     if (mouse_first_flag)
      {
         initialize_mouse(x_cor, y_cor);
      }
     if (mouse_input_mode==MOUSE_ARCBALL_MODE)
         track_mouse_orientation(x_cor, y_cor);
     else
      {

         track_mouse_position(x_cor, y_cor);
      }
}

/*
 *        Procedure Name: mouse_set_mode
 *          Return Value: void
 *       Input Variables: The mode of mouse
 *      Output Variables: 
 *      Update Variables: mouse_input_mode 
 *      Global Variables: mouse_input_mode 
 *           Description: Assign the mode to mouse.  
 */

void mouse_set_mode(mode)
int mode;             /* mode can be: MOUSE_ONE_AXIS_MODE,
                       *              MOUSE_THREE_AXES_MODE,
                       *              MOUSE_ARCBALL_MODE
                       */
{
   mouse_input_mode= mode;
} 

/*
 *        Procedure Name: mouse_set_orientation_value
 *          Return Value: void
 *       Input Variables: index of the Euler Angles: flag
 *                        orientation value
 *      Output Variables:
 *      Update Variables: ide_data_token[C_MOUSE] 
 *      Global Variables: ide_data_token[C_MOUSE]
 *           Description: Assign the orientation value to correspondent
 *                        Euler Angles
 */

void mouse_set_orientation_value(flag, value)
int flag;
float value;
{
  switch (flag)
   {
    case 1: ide_data_token[C_MOUSE].orientation.a=value;
            break;
    case 2: ide_data_token[C_MOUSE].orientation.b=value;
            break;
    case 3: ide_data_token[C_MOUSE].orientation.r=value;
            break;
   }
}
  

/*
 *        Procedure Name: C_report_ide_data_token[C_MOUSE]
 *          Return Value: void
 *       Input Variables: 
 *      Output Variables:
 *      Update Variables: 
 *      Global Variables: ide_data_token[C_MOUSE]
 *           Description: Display the current mouse information 
 */

void C_report_mouse_token()
{
  extern void mouse_report_token();

  char temp_str[100];

  sprintf(temp_str," x=%.2f y=%.2f z=%.2f a=%.2f e=%.2f r=%.2f ",
          ide_data_token[C_MOUSE].pos3d.x,
          ide_data_token[C_MOUSE].pos3d.y,
          ide_data_token[C_MOUSE].pos3d.z,
          ide_data_token[C_MOUSE].orientation.a,
          ide_data_token[C_MOUSE].orientation.b,
          ide_data_token[C_MOUSE].orientation.r);

  mouse_report_token(temp_str);
}

/*
 *        Procedure Name: C_init_mouse 
 *          Return Value: void
 *       Input Variables:
 *      Output Variables:
 *      Update Variables:
 *      Global Variables: ide_data_token[C_MOUSE]
 *                        if the machine can not handle the kb event in the
 *                        drawingarea: mouse_timeout
 *           Description: Initialize the mouse pointer position. Also, 
 *                        activate the event monitor when the system does
 *                        not have event handler.
 */

void C_init_mouse()
{

  ide_data_token[C_MOUSE].pos3d.x = 0.0;
  ide_data_token[C_MOUSE].pos3d.y = 0.0;
  ide_data_token[C_MOUSE].pos3d.z = 0.0;

  mouse_first_flag = 1;

}


