 /*
  * Khoros: $Id: utils.c,v 1.3 1992/03/20 22:51:44 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: utils.c,v 1.3 1992/03/20 22:51:44 dkhoros Exp $";
#endif

 /*
  * $Log: utils.c,v $
 * Revision 1.3  1992/03/20  22:51:44  dkhoros
 * VirtualPatch5
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * 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 "viewimage.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>         	Viewimage Utilities		      <<<<
   >>>>                                                       <<<<
   >>>>			init_image()			      <<<<
   >>>>			update_image()			      <<<<
   >>>>			set_colormap()			      <<<<
   >>>>			transfer_colormap()		      <<<<
   >>>>			init_xresources()		      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
*  Module Name: init_image
*
*      Purpose: This routine initializes an image to be used
*		by viewimage.  The routine will take a file
*		name, read in and initialze the image to be
*		displayed by editimage.  We also will prepare
*
*
*        Input: infile -
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/

int init_image(img_infile, shape_infile, clip_infile, elev_infile, cmap_infile,
	       use_cmap)

char	*img_infile;
char	*shape_infile; 
char    *clip_infile;
char	*elev_infile;
char	*cmap_infile;
int	use_cmap;
{
	struct xvimage *shape, *clip, *cmap;
	struct xvimage *readimage(), **create_images_list();

	/*
	 *  initialize global xvdisplay structure
	 */
	if (img_infile != NULL) images = readimage(img_infile);
	else images = NULL;

	if (shape_infile != NULL) shape = readimage(shape_infile);
	else shape = NULL;
	if (clip_infile != NULL) clip = readimage(clip_infile);
	else clip = NULL;
	if (cmap_infile != NULL) cmap = readimage(cmap_infile);
	else cmap = NULL;
	if (elev_infile != NULL) elevation = readimage(elev_infile);
	else elevation = images;
	
	if (images != NULL && elevation != NULL) {
	   if((images->row_size != elevation->row_size) ||
	      (images->col_size != elevation->col_size) ) {
	      (void)fprintf(stderr,"Elevation data and Imagery data must have same row and column sizes\n");
		exit(1);
	   }
	}

	/*
	 *  After reading in the display image, if use_cmap is False then
	 *  we should delete the maps associated with that image.
	 */
	if (use_cmap == False && images != NULL)
	{
	   if (images->maps != NULL) free(images->maps);
	   images->maps		     = NULL;
	   images->map_storage_type   = VFF_MAPTYP_NONE;
	   images->map_scheme 	     = VFF_MS_NONE;
	   images->map_enable 	     = VFF_MAP_OPTIONAL;
	   images->color_space_model = VFF_CM_NONE;
	   images->map_row_size    =
	   images->map_col_size    =
	   images->map_subrow_size = 0;
	}
	else if (cmap != NULL && images != NULL)
	{
	   transfer_colormap(cmap, images);
	   freeimage(cmap);
	}


	/*
	 *  initialize the image bands
	 */
	if (!(xvdisplay = xvd_init_xvdisplay(display, images, shape, clip,
			NULL, True, False, False, NULL)))
	{
           return(False);  
	}
	init_xresources(xvdisplay);

	/*
	 *  Seperate out the image bands so that we can change bands later.
	 */
	if (images != NULL)
	{
	   band =  create_images_list(images->num_data_bands);
	   if (!lvbandsprt(images, band, NULL, False))
	   {
	       xvf_error_wait("leditimage", "lvbandsprt failed!\n", NULL);
	       return(False);
	   }
	}
	else
	{
	   band = NULL;
	}

	/*
	 *  Seperate out the overlay bands so that we can change overlay
	 *  bands later.
	if (overlays != NULL)
	{
	   ovband =  create_images_list(overlays->num_data_bands);
	   if (!lvbandsprt(overlays, ovband, NULL, False))
	   {
	      xvf_error_wait("leditimage", "lvbandsprt failed for seperating \
out overlay bands!\n", NULL);
	      overlays = NULL;
	      ovband = NULL;
	   }
	}
	 */

	/*
	 *  Initialize the global indecies
	 */
	return(True);
}



/************************************************************
*
*  Module Name: update_image
*
*      Purpose: This routine updates the xvdisplay structure
*		with the new "image".   update_image calls
*		xvd_update_image() with the global xvdisplay
*		structure and the new/updated image.  If the
*		image passed is NULL then xvd_update_image()
*		will use the one in the xvdisplay structure.
*
*		The next part is update the various parts of
*		editimage's display structures to reflect the
*		changes in the updated image.
*
*        Input: image - image to be updated
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/


update_image(image)

struct xvimage *image;
{
	int    width, height, create_zoom;
	struct xvimage *readimage(), **create_images_list();



	/*
	 *  call the xvdisplay update routine to update the associated
	 *  resources in the xvdisplay structure.
	 */
	if (!xvd_update_image(xvdisplay, image))
	   return;

	/*
	 *  If there is no current image or the image has changed then we
	 *  split the image into multiple image bands.
	 */
	if (image != NULL && image != images)
	{
	   /*
	    *  Seperate out the image bands so that the user can change bands
	    *  later.
	    */
	   if (band != NULL) free(band);

	   images = image;
	   band =  create_images_list(images->num_data_bands);
	   if (!lvbandsprt(images, band, NULL, False))
	   {
	       xvf_error_wait("leditimage", "lvbandsprt failed!\n", NULL);
	       return;
	   }
	}
	set_colormap();
	update_thres();
}



/************************************************************
*
*  Module Name: transfer_colormap
*
*      Purpose: This routine is used to transfer one images maps
*		to another.
*
*        Input: source  - the source image with the maps
*		dest    - the destination image to recieve the maps
*
*       Output: none
*
*   Written By: Danielle Argiro & Mark Young
*
*************************************************************/


transfer_colormap(source, dest)

struct xvimage *source, *dest;
{
	if (dest->maps != NULL && dest->map_row_size > 0)
	   free(dest->maps);

	dest->map_scheme	= source->map_scheme;
	dest->map_storage_type  = source->map_storage_type;
	dest->map_row_size 	= source->map_row_size;
	dest->map_col_size 	= source->map_col_size;
	dest->map_subrow_size   = source->map_subrow_size;
	dest->map_enable	= source->map_enable;
	dest->maps_per_cycle 	= source->maps_per_cycle;
	dest->color_space_model = source->color_space_model;
	dest->maps 		= source->maps;

	source->maps = NULL; 
}



/************************************************************
*
*  Module Name: set_colormap
*
*      Purpose: This routine sets the colormap for each of the
*               different display widgets (raster, pseudo, lut).
*
*        Input: none
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/


set_colormap()
{
	xvdisplay->raster = plot->workspace;
	xvd_set_colormap(plot->workspace, xvdisplay->colormap);
	xvd_set_colormap(pseudo->pseudo, xvdisplay->colormap);
	xvd_set_colormap(lut->toplevel, xvdisplay->colormap);
	xvd_set_colormap(thres->toplevel, xvdisplay->colormap);
}



/************************************************************
*
*  MODULE NAME: init_xresources
*
*      PURPOSE: initializes certain X resources for the different
*		display utilites.  Such as the red, green, blue pixels
*		used in displaying the lut ramps.
*
*        INPUT: none
*
*       OUTPUT: none
*
*   WRITTEN BY: Mark Young
*
*************************************************************/


init_xresources(xvdisplay)

DisplayStructure *xvdisplay;
{
	XColor	   color, exact;
	XGCValues  values;
	unsigned   long mask;

	int	   screen = XDefaultScreen(display);
	Window	   rootwindow = XDefaultRootWindow(display);
	Colormap   colormap = XDefaultColormap(display, screen),
		   xvd_colormap = xvdisplay->colormap;


	/*
	 *  Get the black, white, & grey colors
	 */
	if (XAllocNamedColor(display, colormap, "black", &color, &exact))
	   black = color.pixel;
	else black = XBlackPixel(display, screen);

	if (XAllocNamedColor(display, colormap, "white", &color, &exact))
	   white = color.pixel;
	else white = XWhitePixel(display, screen);

	if (XAllocNamedColor(display, colormap, "grey", &color, &exact))
	   grey = color.pixel;
	else grey = white;

	/*
	 *  Get the RGB colors
	 */
	if (XAllocNamedColor(display, colormap, "red", &color, &exact))
	   red = color.pixel;
	else red = white;

	if (XAllocNamedColor(display, colormap, "green", &color, &exact))
	   green = color.pixel;
	else green = white;

	if (XAllocNamedColor(display, colormap, "blue", &color, &exact))
	   blue = color.pixel;
	else blue = white;

	/*
	 *  Get the CMY colors
	 */
	if (XAllocNamedColor(display, colormap, "cyan", &color, &exact))
	   cyan = color.pixel;
	else cyan = white;

	if (XAllocNamedColor(display, colormap, "magenta", &color, &exact))
	   magenta = color.pixel;
	else magenta = white;

	if (XAllocNamedColor(display, colormap, "yellow", &color, &exact))
	   yellow = color.pixel;
	else yellow = white;

	if (XAllocNamedColor(display, xvd_colormap, "white", &color, &exact))
	   plot_foreground = color.pixel;
	else plot_foreground = white;

	if (XAllocNamedColor(display, xvd_colormap, "black", &color, &exact))
	   plot_background = color.pixel;
	else plot_background = black;

	if (XAllocNamedColor(display, xvd_colormap, "yellow", &color, &exact))
	   plot_color = color.pixel;
	else plot_color = plot_foreground;

	mask = GCLineWidth | GCFunction | GCForeground | GCBackground;
	values.line_width = 0;
	values.function = GXcopy;
	values.foreground = white;
	values.background = black;
	gc_set = XCreateGC(display, rootwindow, mask, &values);

	mask = GCLineWidth | GCFunction | GCPlaneMask | GCForeground;
	values.line_width = 0;
	values.function = GXxor;
	values.foreground = ~0;
	values.plane_mask = black ^ white;
	gc_xor = XCreateGC(display, rootwindow, mask, &values);

	mask = GCLineWidth | GCFunction | GCForeground | GCBackground;
	values.line_width = 0;
	values.function = GXcopy;
	values.foreground = white;
	values.background = black;
	gc = XCreateGC(display, rootwindow, mask, &values);
}



/************************************************************
*
*  Module Name: store_colors
*
*      Purpose: This routine stores the colors in the X color
*		array into the xvdisplay colormap.  The routine
*		also calls refresh_display to refresh the different
*		displays.
*
*        Input: xcolors -  the xcolors to be stored into the
*			   xvdisplay colormap.
*		num     -  the number of xcolors to be stored.
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/


store_colors(xcolors, index, num)

XColor	xcolors[];
int	index, num;
{
	int    i, j;
	XColor store[MAX_PIXELS];

	for (i = 0, j = 0; i < num; i++)
	{
	    if (active[i+index])
	       store[j++] = xcolors[i+index];
	}

	/*
	 *  Store the X colors into the colormap
	 */
	if (j > 0)
	{
	   XStoreColors(display, xvdisplay->colormap, store, j);
	   refresh_displays(index, num);
	}
}



/************************************************************
*
*  Module Name: refresh_displays
*
*      Purpose: This routine refreshes the visible displays.
*		The displays consists of "pixels", "pseudo",
*		"lut", "position".  If the widget display is
*		visible then we call it's refresh routine to
*		update it.  This routine is called when inputing
*		a new image or region of interest.  This
*		routine is also called after storing new colors
*		into the xvdisplay colormap.
*
*        Input: none
*
*       Output: Calls the different refresh routines to update
*		the different displays.
*
*   Written By: Mark Young
*
*************************************************************/


refresh_displays(index, num)

int	num, index;
{

	/*
	if (xvd_check_visibility(xvdisplay->raster) == True)
	   refresh_position();
	*/

	if (xvd_check_visibility(pseudo->pseudo) == True)
	   refresh_pseudo();

	if (xvd_check_visibility(lut->toplevel) == True)
	   refresh_lut(index, num);
}



/************************************************************
*
*  Module Name: refresh_palette
*
*      Purpose: This routine is used to refresh the color palette.
*		The color palette is used to show the color ramp
*		for a few of the display windows.  The threshold
*		display uses the palette as a visual cue so that
*		the users understands what part of the palette they
*		are affecting.
*
*        Input: widget     -  the widget for the event
*		clientData -  not used
*		event      -  the event
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/

void refresh_palette(widget, clientData, event)

Widget widget;
caddr_t clientData;
XEvent  *event;
{
	XEvent	  next;
	Window	  root;
	float	  xfact;
	int	  status, i, j, x, num;
	unsigned  int width, height, dummy;


	/*
         *  refresh the colortable display, but first eat all the exposure
         *  events.
         */
        do
        {
           status = XCheckWindowEvent(display, XtWindow(widget), ExposureMask,
				      &next);
	} while (status);

	/*
	 *  Get the tables geometry (width & height) so that we know how
	 *  much to fill.
	 */
	if (!XGetGeometry(XtDisplay(widget), XtWindow(widget), &root, &x, &x,
			   &width, &height,  &dummy, &dummy))
	{
	   xvf_error_wait("Window does not exist.","redisplay_lut", NULL);
	   return;
	}

	/*
	 *  Find out how many cells we need to divide the colortable into.
	 */
	for (i = 0, num = 0; i < MAX_PIXELS; i++)
	   if (xvdisplay->active[i] > 0) num++;

	if (num == 0) return;

	xfact = width/((float) num);
	for (i = 0, j = 0; i < MAX_PIXELS; i++)
	{
	   if (xvdisplay->active[i] > 0)
	   {
	      XSetForeground(display, gc, xvdisplay->xcolors[i].pixel);
	      x = xfact*j;
	      width = xfact*(j+1)-x;
	      XFillRectangle(display,XtWindow(widget), gc, x, 0, width, height);
	      j++;
	   }
	}
}



/************************************************************
*
*  Module Name: set_floatarg
*
*      Purpose: This routine is used to set a float resource
*		in the arg list.
*
*        Input: args	- argument list
*		i	- argument index
*		label	- label of the resource
*		value	- float value to be set
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/

set_floatarg(args, i, label, value)

Arg   *args;
int   i;
char  *label;
float *value;
{
	if (sizeof(float) > sizeof(XtArgVal))
	{
	   XtSetArg(args[i], label, value);
	}
	else
	{
	   XtArgVal *l_top = (XtArgVal *) value;
	   XtSetArg(args[i], label, *l_top);
	}
}
