 /*
  * Khoros: $Id: convert_3D.c,v 1.1 1991/05/10 15:56:56 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: convert_3D.c,v 1.1 1991/05/10 15:56:56 khoros Exp $";
#endif

 /*
  * $Log: convert_3D.c,v $
 * Revision 1.1  1991/05/10  15:56:56  khoros
 * Initial revision
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.

 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "X3D.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name: convert_3D.c                           <<<<
   >>>>                                                       <<<<
   >>>>   description:     3D Conversion Utilities            <<<<
   >>>>                                                       <<<<
   >>>>                                                       <<<<
   >>>>      routines: 					      <<<<
   >>>>			_X3D_convert_wc_to_dc()	      	      <<<<
   >>>>			_X3D_convert_wc_to_dc_seg()   	      <<<<
   >>>>                                                       <<<<
   >>>>			X3D_convert_point_wc_to_dc()          <<<<
   >>>>			X3D_convert_point_wc_to_ndc()         <<<<
   >>>>                                                       <<<<
   >>>> modifications:					      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */


/************************************************************
*
*  MODULE NAME: _X3D_convert_wc_to_dc
*
*      PURPOSE: Converts a array of 3D world coordinate points 
*               to device coordinates and stores them as XPoints 
*		for later calls to X11 routines
*
*        INPUT: graphics - the X3D graphics structure
*	        coords   - array of world coordinates input
*		size     - number of points to convert
*
*       OUTPUT: points   - XPoint array of device coordinates
*
*    CALLED BY: X3D_draw_polyline(), X3D_draw_marker(), 
*		X3D_draw_polygon
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int _X3D_convert_wc_to_dc (graphics, coords, points, size)

X3DGraphics	*graphics;
Coord		*coords;
XPoint		*points;
int		size;
{
	register int  i;
	register Real x, y, z, w;
	Coord    *scale;


	if(!(_X3D_scale_wc_coords(graphics->scale, coords, &scale, size)))
	   return(FALSE);

	if (graphics->projection == Perspective)
	{
	   for (i = 0; i < size; i++)
	   {
	       _X3D_vector_mult(scale[i], graphics->matrix, x, y, z, w);
	       if (w != 0)
	       {
	          points[i].x = x/w + 0.5;
	          points[i].y = y/w + 0.5;
	       }
	       else
	       {
	          points[i].x = x + 0.5;
	          points[i].y = y + 0.5;
	       }
	   }
	}
	else
	{
	   for (i = 0; i < size; i++)
	   {
	       _X3D_vector_mult(scale[i], graphics->matrix, x, y, z, w);
	       points[i].x = x + 0.5;
	       points[i].y = y + 0.5;
	   }
	}

	if (coords != scale)
	   free(scale);

	return(TRUE);
}



/************************************************************
*
*  MODULE NAME: _X3D_convert_wc_to_dc_seg
*
*      PURPOSE: Converts a array of 3D world coordinate segments 
*               to device coordinates and stores them as XSegments 
*		for later calls to X11 routines
*
*        INPUT: graphics - the X3D graphics structure
*	        coords   - array of world coordinates input
*		size     - number of points to convert
*
*       OUTPUT: segments  - XSegment array of device coordinates
*
*    CALLED BY: X3D_draw_segment
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


int _X3D_convert_wc_to_dc_seg (graphics, coords, segments, size)

X3DGraphics	*graphics;
Coord		*coords;
XSegment	*segments;
int		size;
{
	register int   i, j;
	register Real  x, y, z, w;
	Coord    *scale;

	if(!(_X3D_scale_wc_coords(graphics->scale, coords, &scale, size)))
	   return(FALSE);

	j = 0;
	if (graphics->projection == Perspective)
	{
	   for (i = 0; i < size; i += 2)
	   {
	       _X3D_vector_mult(scale[i], graphics->matrix, x, y, z, w);
	       if (w != 0)
	       {
	          segments[j].x1 = x/w + 0.5;
	          segments[j].y1 = y/w + 0.5;
	       }
	       else
	       {
	          segments[j].x1 = x + 0.5;
	          segments[j].y1 = y + 0.5;
	       }

               _X3D_vector_mult(scale[i +1], graphics->matrix, x, y, z, w);
               if (w != 0)
               {
                  segments[j].x2 = x/w + 0.5;
                  segments[j].y2 = y/w + 0.5;
               }
               else
               {
                  segments[j].x2 = x + 0.5;
                  segments[j].y2 = y + 0.5;
               }
	       j++;
	   }
	}
	else
	{
	   for (i = 0; i < size; i += 2)
	   {
	       _X3D_vector_mult(scale[i], graphics->matrix, x, y, z, w);
	       segments[j].x1 = x + 0.5;
	       segments[j].y1 = y + 0.5;

	       _X3D_vector_mult(scale[i+1], graphics->matrix, x, y, z, w);
	       segments[j].x2 = x + 0.5;
	       segments[j].y2 = y + 0.5;

	       j++;
	   }
	}

	if (coords != scale)
	   free(scale);

	return(TRUE);
}



/************************************************************
*
*  MODULE NAME: X3D_convert_point_wc_to_dc
*
*      PURPOSE: Converts a 3D world coordinate point
*               to device coordinates and stores it the
*		X and Y variables.
*
*        INPUT: id	- the X3D graphics structure
*	        coord   - array of world coordinates input
*
*       OUTPUT: x, y    - the dc result.
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/



int X3D_convert_point_wc_to_dc (id, coord, x_out, y_out)

int	id;
Coord	coord;
Real	*x_out, *y_out;
{
	register Real  x, y, z, w;
	Coord	 scale;
	X3DGraphics *graphics;


        if (!(graphics = _X3D_get_graphics(id)))
        {
           (void) fprintf (stderr,"X3D_convert_point_wc_to_dc:");
           (void) fprintf (stderr,"\t unknown graphics id %d\n",id);
           return(FALSE);
        }

	if(!(_X3D_scale_wc_coord(graphics->scale, coord, &scale)))
	   return(FALSE);

	if (graphics->projection == Perspective)
	{
	   _X3D_vector_mult(scale, graphics->matrix, x, y, z, w);
	   if (w != 0)
	   {
	      *x_out = x/w;
	      *y_out = y/w;
	   }
	   else
	   {
	      *x_out = x;
	      *y_out = y;
	   }
	}
	else
	{
	   _X3D_vector_mult(scale, graphics->matrix, x, y, z, w);
	   *x_out = x;
	   *y_out = y;
	}
	return(TRUE);
}




/************************************************************
*
*  MODULE NAME: X3D_convert_point_wc_to_ndc
*
*      PURPOSE: Converts a 3D world coordinate point
*               to the unit cube and stores them in the routine
*		coordinate.
*
*        INPUT: id	   - the X3D graphics structure
*	        coord_in   - the world coordinate input point
*
*       OUTPUT: coord_out  - the normalized coordinate output point
*
*    CALLED BY: application program
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/



int X3D_convert_point_wc_to_ndc (id, coord_in, coord_out)

int	id;
Coord	coord_in, *coord_out;
{
	register Real x, y, z, w, center_x, center_y, center_z,
		      xmin, ymin, zmin;
	Coord	      scale;
	X3DGraphics   *graphics;
	Matrix	      matrix1, matrix2;


        if (!(graphics = _X3D_get_graphics(id)))
        {
           (void) fprintf (stderr,"X3D_convert_point_wc_to_dc:");
           (void) fprintf (stderr,"\t unknown graphics id %d\n",id);
           return(FALSE);
        }

	if(!(_X3D_scale_wc_coord(graphics->scale, coord_in, &scale)))
	   return(FALSE);

	/*
 	 * Convert to unit cube.
 	 */
	_X3D_matrix_set_ndc(graphics->xv_min, graphics->xv_max,
			    graphics->yv_min, graphics->yv_max,
			    graphics->wc_min, graphics->wc_max, matrix1);

	center_x = center_y = center_z = 0.5;
	X3D_matrix_set_translate(-center_x, -center_y, -center_z, matrix2);
	_X3D_matrix_mult(matrix1, matrix2, matrix1);

	_X3D_matrix_set_viewing(graphics->theta, graphics->alpha,
			       graphics->eye_dist, matrix2);
	_X3D_matrix_mult(matrix1, matrix2, matrix1);
	X3D_matrix_set_translate(center_x, center_y, center_z, matrix2);
	_X3D_matrix_mult(matrix1, matrix2, matrix1);

        /*
         *  Set the scale about the origin
         */
        xmin = (graphics->xv_max - graphics->xv_min)/1.0;
        ymin = (graphics->yv_max - graphics->yv_min)/1.0;
        zmin = (graphics->yv_max - graphics->yv_min)/1.0;
        X3D_matrix_set_scale(xmin, ymin, zmin, matrix2);
        _X3D_matrix_mult(matrix1, matrix2, matrix1);

        X3D_matrix_set_translate(graphics->xv_min, graphics->yv_min, 0.0,
                                 matrix2);
        _X3D_matrix_mult(matrix1, matrix2, matrix1);


	_X3D_vector_mult(scale, matrix1, x, y, z, w);
	coord_out->x = x;
	coord_out->y = y;
	coord_out->z = z;
	return(TRUE);
}
