aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/ximtool/raster.c
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /vendor/x11iraf/ximtool/raster.c
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'vendor/x11iraf/ximtool/raster.c')
-rw-r--r--vendor/x11iraf/ximtool/raster.c2995
1 files changed, 2995 insertions, 0 deletions
diff --git a/vendor/x11iraf/ximtool/raster.c b/vendor/x11iraf/ximtool/raster.c
new file mode 100644
index 00000000..51652241
--- /dev/null
+++ b/vendor/x11iraf/ximtool/raster.c
@@ -0,0 +1,2995 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <Obm.h>
+#include <ObmW/Gterm.h>
+#include "ximtool.h"
+#include "iis.h"
+
+/* Slackware/RedHat4.2 compatibility hack. */
+#if defined(linux) && defined(isalnum)
+#undef isalnum
+#define isalnum(c) (isalpha(c)||isdigit(c))
+#endif
+
+
+#define DBG_RASTER 0
+
+
+/*
+ * RASTER.C -- Raster pixel (frame buffer) routines. These are the routines
+ * which create and manipulate the frame buffers and the graphics pipeline
+ * to the screen.
+ *
+ * xim_initialize (xim, config, nframes, hardreset)
+ * xim_reset (xim, w)
+ * xim_resize (xim, w)
+ * xim_refresh (xim)
+ *
+ * xim_setFrame (xim, frame)
+ * xim_setReferenceFrame (chan, frame)
+ * xim_setDisplayFrame (xim, frame)
+ * xim_initFrame (xim, frame, nframes, config, memModel)
+ * xim_delFrame (xim, frame)
+ * xim_matchFrames (xim, frames, reference_frame)
+ * xim_registerFrames (xim, frames, reference_frame)
+ * xim_fitFrame (xim)
+ * xim_tileFrames (xim, frame_list)
+ *
+ * xim_cursorMode (xim, state)
+ *
+ * xim_setMapping (xim, fb, frame, mapping, src, dst, fill_mode)
+ * xim_setZoom (xim, fb, frame, mapping, src, dst,
+ * xcen,ycen, xmag,ymag, xoff,yoff, absolute)
+ * xim_setFlip (xim, fb, flip_x, flip_y)
+ * xim_setColormap (name, dirs, red, green, blue, ncolors)
+ * xim_setRop (xim, fb, rop)
+ * rop = xim_getAntialias (xim, s)
+ *
+ * xim_getScreen (xim, frame, sx, sy, width, height, depth)
+ * bool = xim_onScreen (xim, frame)
+ *
+ * xim_setCursorPos (xim, sx, sy)
+ * xim_getCursorPos (xim, sx, sy, raster, frame)
+ *
+ * pixels = xim_readDisplay (xim, x0,y0,nx,ny, w,h, r,g,b, ncolors)
+ * stat = xim_writeDisplay (xim, frame, mapname, pixels, w,h, r,g,b, ncolors)
+ *
+ * xim_message (xim, object, message)
+ * xim_msgi (xim, object, intval)
+ * xim_alert (xim, text, ok_action, cancel_action)
+ */
+
+/* Define some builtin colormaps. */
+static Lut aips0 = {
+#include "data/aips0.lut"
+};
+static Lut blue = {
+#include "data/blue.lut"
+};
+static Lut color = {
+#include "data/color.lut"
+};
+static Lut green = {
+#include "data/green.lut"
+};
+static Lut halley = {
+#include "data/halley.lut"
+};
+static Lut heat = {
+#include "data/heat.lut"
+};
+static Lut rainbow = {
+#include "data/rainbow.lut"
+};
+static Lut red = {
+#include "data/red.lut"
+};
+static Lut staircase = {
+#include "data/staircase.lut"
+};
+static Lut standard = {
+#include "data/standard.lut"
+};
+
+static void get_fbconfig();
+static void set_colorbar();
+static int get_dirfile();
+static void load_testpattern();
+static void set_nframes();
+static void xim_frameRegion();
+static void xim_colortables();
+extern char *getenv();
+double strtod();
+
+#define TOL 0.0001
+
+
+/* XIM_INITIALIZE -- Initialize the imaging subsystem. Read the config file
+ * and create the frame buffers, mappings, and colormaps.
+ */
+void
+xim_initialize (xim, config, nframes, hardreset)
+register XimDataPtr xim;
+int config;
+int nframes;
+int hardreset;
+{
+ register Widget gt = xim->gt;
+ register FrameBufPtr fb;
+ register int i;
+
+ unsigned short m_red[MAX_COLORS];
+ unsigned short m_green[MAX_COLORS];
+ unsigned short m_blue[MAX_COLORS];
+ char *fname, *ip, *op, sbuf[8192];
+ String maps[MAX_COLORMAPS], dirs[4];
+ int max_cmaps, first, ngray, rgb_len, nfiles, n;
+ static int nbuiltin_cmaps = 0;
+ int display_frame = 1;
+ char cmapname[SZ_NAME];
+ char buf[SZ_LINE];
+ FbConfigPtr cf;
+ ColorMapPtr cm;
+ struct dir *dp;
+ int startup;
+ DIR *dir;
+
+ /* The gterm widget handle should already have been set by the
+ * GUI during startup.
+ */
+ if (!gt) {
+ fprintf (stderr, "xim_initialize: no gterm-image widget!!\n");
+ exit (1);
+ }
+
+ /* Inform the GUI that the frame buffers are being initialized.
+ * The initialize parameter is set to "startup" during program
+ * startup, "restart" at the start of an initialization during
+ * execution, and "done" when initialization is completed.
+ */
+ startup = (xim->nframes == 0);
+ xim_message (xim, "initialize", startup ? "startup" : "restart");
+
+ if (hardreset || startup || config != xim->fb_configno) {
+ xim_msgi (xim, "frame", 0);
+ xim_message (xim, "frameTitle", "");
+ set_nframes (xim, 0);
+ cm = &colormaps[DEF_COLORMAP-1];
+ strcpy (cmapname, cm->name);
+ hardreset = 1;
+
+ /* Get frame buffer configurations. */
+ get_fbconfig (xim);
+
+ /* Remove any existing border highlight marker. */
+ if (xim->gm_border) {
+ GmDestroy (xim->gm_border);
+ xim->gm_border = NULL;
+ }
+
+ /* Initialize the frame buffers. */
+ if (DBG_RASTER)
+ fprintf (stderr, "xim_initialize: Raster init.....\n");
+ GtRasterInit (gt);
+ if (DBG_RASTER)
+ fprintf (stderr, "xim_initialize: Raster init.....DONE\n");
+ for (i=1; i <= MAX_FRAMES; i++)
+ xim->frames[i].frameno = 0;
+
+ cf = &xim->fb_config[config-1];
+ nframes = (nframes <= 0) ? cf->nframes : nframes;
+
+ if (startup) {
+ /* Set initial tile frames list to be all frames if starting
+ * up in tile frames mode.
+ */
+ if (xim->tileFrames && nframes > 1) {
+ xim->tileFramesList = 0;
+ xim->nTileFrames = 0;
+ for (i=0; i < nframes; i++) {
+ xim->tileFramesList |= (1 << i);
+ xim->nTileFrames++;
+ }
+ }
+ } else {
+ xim->display_frame = 0;
+ xim->df_p = NULL;
+ for (i=0; i < XtNumber(xim->chan); i++) {
+ IoChanPtr chan = &xim->chan[i];
+ if (chan->type)
+ xim_setReferenceFrame (chan, 1);
+ }
+ if (xim->cursor_chan)
+ xim->cursor_chan = &xim->chan[0];
+ }
+
+ xim->rop = xim->antialias ?
+ xim_getAntialias (xim, xim->antialiasType) : 0x00;
+ xim->fb_configno = config = max(1, min(MAX_FBCONFIG, config));
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: ........................SETNFRAME\n");
+ set_nframes (xim, nframes);
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: ........................SETNFRAME DONE\n");
+
+ /* Initialize the tile framing options. */
+ xim->tileByRows = 1;
+ xim->tileTopDown = 1;
+ xim->tileLabels = 0;
+
+ /* Set the new frame size. */
+ sprintf (buf, "%d %d %d", cf->width, cf->height, 8);
+ xim_message (xim, "frameSize", buf);
+
+ /* Create the frames. */
+ for (i=1; i <= nframes; i++) {
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: ...............INITFRAME %d\n",i);
+ xim_initFrame (xim, i, nframes, cf, xim->memModel);
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: ...............INITFRAME %d DONE\n",i);
+ }
+
+ /* Reinitialize the tile framing. */
+ if (xim->tileFrames) {
+ xim->tileFramesList = 0;
+ xim->nTileFrames = 0;
+ for (i=0; i < nframes; i++) {
+ xim->tileFramesList |= (1 << i);
+ xim->nTileFrames++;
+ }
+ }
+
+ xim->width = cf->width;
+ xim->height = cf->height;
+ GtSetLogRes (gt, cf->width, cf->height);
+
+ } else {
+ /* Soft reset. */
+ display_frame = xim->display_frame;
+ fb = &xim->frames[display_frame-1];
+ cm = &colormaps[fb->colormap-1];
+ strcpy (cmapname, cm->name);
+
+ for (i=0; i < ncolormaps; i++) {
+ cm = &colormaps[i];
+ GtFreeColormap (gt, cm->mapno);
+ }
+ }
+
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: ........................CMAP SETUP\n");
+ /* Set up the colormap to emulate the IIS/imtool colormap. Set
+ * xim->ncolors to the length of the grayscale region of the colormap
+ * returned by iiscolormap so that our other colormaps will have the
+ * same size.
+ */
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: xim->ncolors = %d\n", xim->ncolors);
+ xim_iiscolormap (gt, m_red,m_green,m_blue, &first, &ngray, &rgb_len);
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: writeColormap: first=%d ngray=%d len=%d\n",
+ first, ngray, rgb_len);
+ GtWriteColormap (gt, 0, first, rgb_len, m_red, m_green, m_blue);
+ if ((xim->ncolors = ngray) < 0) {
+ fprintf (stderr, "ERROR: No colormap cells available.\n");
+ exit (1);
+ }
+
+
+ /* Initialize the color tables.
+ */
+ max_cmaps = nbuiltin_cmaps ? nbuiltin_cmaps : MAX_COLORMAPS;
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: init colortables: xim->ncolors = %d\n",
+ xim->ncolors);
+ for (ncolormaps=0; ncolormaps < max_cmaps; ncolormaps++) {
+ cm = &colormaps[ncolormaps];
+ if (!cm->name[0])
+ break;
+ cm->mapno = GtNextColormap (gt);
+ xim_setColormap (cm->name, NULL, m_red, m_green, m_blue,
+ xim->ncolors);
+ GtWriteColormap (gt, cm->mapno, first, xim->ncolors,
+ m_red, m_green, m_blue);
+ }
+ if (DBG_RASTER)
+ fprintf (stderr, "xim_initialize: init colortables: DONE\n");
+
+ /* The first time this is called count the number of builtin cmaps. */
+ if (nbuiltin_cmaps == 0)
+ nbuiltin_cmaps = ncolormaps;
+
+ /* Get the names of the two user defined colormaps, if any. */
+ nfiles = 0;
+ maps[nfiles++] = xim->userCMap1;
+ maps[nfiles++] = xim->userCMap2;
+
+ /* If any user colormap directories are specified get the names
+ * of the colormap files in these directories.
+ */
+ dirs[0] = "./";
+ dirs[1] = xim->userCMapDir1;
+ dirs[2] = xim->userCMapDir2;
+ dirs[3] = NULL;
+
+ for (i=1, op=sbuf; dirs[i]; i++) {
+ if (strcmp (dirs[i], "none") != 0) {
+ if (dir = opendir (dirs[i])) {
+ while ((n = get_dirfile (dir, op, SZ_FNAME)) > 0) {
+ maps[nfiles++] = op;
+ op += n + 1;
+ if (nfiles >= MAX_COLORMAPS)
+ break;
+ }
+ closedir (dir);
+ }
+ }
+ }
+
+ /* Add all the user specified colormaps to the colormap table.
+ */
+ for (i=0; i < nfiles && ncolormaps < MAX_COLORMAPS; i++) {
+ fname = maps[i];
+ if (strcmp (fname, "none") != 0) {
+ if (xim_setColormap (fname, dirs,
+ m_red, m_green, m_blue, xim->ncolors) == OK) {
+
+ cm = &colormaps[ncolormaps++];
+ cm->mapno = GtNextColormap (gt);
+
+ /* Use root portion of filename as the colormap name. */
+ for (ip=fname; *ip; ip++)
+ if (*ip == '/')
+ fname = ip + 1;
+ for (ip=fname, op=cm->name; *ip && *ip != '.'; ip++) {
+ *op++ = *ip;
+ if (op - cm->name >= SZ_CMAPNAME)
+ break;
+ }
+ *op = '\0';
+
+ GtWriteColormap (gt, cm->mapno, first, xim->ncolors,
+ m_red, m_green, m_blue);
+ }
+ }
+ }
+
+ /* Pass the list of colortables on to the user interface. */
+ xim_colortables (xim);
+
+ /* Set initial display frame. */
+ xim_setDisplayFrame (xim, display_frame);
+
+ /* Force the initial default colormap to be loaded. */
+ fb = &xim->frames[display_frame-1];
+ for (i=0; i < ncolormaps; i++) {
+ cm = &colormaps[i];
+ if (strcmp (cm->name, cmapname) == 0)
+ break;
+ }
+ if (i >= ncolormaps)
+ cm = &colormaps[DEF_COLORMAP-1];
+
+ GtLoadColormap (gt, cm->mapno, fb->offset, fb->scale);
+ xim_enhancement (xim, fb);
+
+ /* Set options. */
+/* xim_message (xim, "cmfocus", xim->cm_focus ? "True" : "False");*/
+ xim_message (xim, "autoscale", xim->autoscale ? "True" : "False");
+ xim_message (xim, "antialias", xim->antialias ? "True" : "False");
+ xim_message (xim, "tileFrames", xim->tileFrames ? "True" : "False");
+
+ xim_message (xim, "initialize", "done");
+
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initialize: ................................RETURNING\n");
+}
+
+
+/* XIM_RESET -- Called when the active gterm widget is set or changed.
+ */
+void
+xim_reset (xim, w)
+XimDataPtr xim;
+Widget w;
+{
+ unsigned short iomap[MAX_COLORS];
+ int iomap_len;
+
+ if (!w)
+ return;
+
+ /* The following assumes that the GUI does a setGterm first for the
+ * colorbar and second for the main image window. The first thing we
+ * do is set the iomap so that all ximtool color and pixel i/o will
+ * see the emulated IIS color model.
+ */
+ if (xim->cb == NULL) {
+ xim->cb = w;
+ xim_iisiomap (w, iomap, &iomap_len);
+ GtPostResizeProc (w, set_colorbar, xim);
+ GtWriteIomap (w, iomap, 0, iomap_len);
+ } else {
+ xim->gt = w;
+ xim_iisiomap (w, iomap, &iomap_len);
+ GtPostResizeProc (w, xim_resize, xim);
+ GtWriteIomap (w, iomap, 0, iomap_len);
+ }
+}
+
+
+/* XIM_RESIZE -- Called when the active gterm widget is resized. We need to
+ * resize the zoom raster and modify the zoom mapping for each frame to
+ * reflect the new window size.
+ */
+void
+xim_resize (xim, w)
+XimDataPtr xim;
+Widget w;
+{
+ register FrameBufPtr fb;
+ int junk, sx, sy, width, height, depth;
+ int i, active, frame, mapping, zoomtype;
+ float xscale, yscale, scale;
+ char buf[SZ_LINE];
+
+
+ /* This case is true during startup. */
+ if (xim->nframes <= 0)
+ return;
+
+ /* Get new screen size. In tile frame mode select the first frame
+ * in the list for the size, which may not always be frame 1.
+ */
+ if (xim->tileFrames && !(xim->tileFramesList & 1)) {
+ if (xim->nframes == 0)
+ return;
+ for (i=1; i <= xim->nframes; i++)
+ if (xim->tileFramesList & (1 << (i-1))) {
+ xim_getScreen (xim, i, &sx, &sy, &width, &height, &depth);
+ break;
+ }
+ } else
+ xim_getScreen (xim, 1, &sx, &sy, &width, &height, &depth);
+
+ /* Compute the new scale factor required to scale the source to the
+ * destination at magnification 1.0.
+ */
+ if (xim->autoscale) {
+ xscale = (float)width / (float)xim->width;
+ yscale = (float)height / (float)xim->height;
+ scale = min (xscale, yscale);
+ } else {
+ xscale = 1.0;
+ yscale = 1.0;
+ scale = 1.0;
+ }
+
+ /* Adjust the mapping for each frame. */
+ for (frame=1; frame <= xim->nframes; frame++) {
+ fb = &xim->frames[frame-1];
+ mapping = fb->zoommap;
+
+ /* For rapid frame blink, split screen, etc. the zoom raster
+ * must be the same size as the screen so we must resize this
+ * raster when the display window is resized. The CreateRaster
+ * call will delete the old raster and all its mappings and
+ * create a new one. We must then restore the mappings, and
+ * if this is an active display frame, refresh the mapping.
+ */
+ active = xim_onScreen (xim, frame);
+
+ if (fb->zoomras) {
+ GtQueryRaster (w, fb->zoomras, &zoomtype, &junk, &junk, &junk);
+ GtCreateRaster (w, fb->zoomras, zoomtype, width, height, depth);
+ xim_setMapping (xim, NULL, frame, fb->dispmap,
+ fb->zoomras, 0, M_FILL);
+ if (!active) {
+ GtDisableMapping (w, fb->dispmap, 0);
+ xim_setMapping (xim, NULL, frame, fb->zoommap,
+ fb->raster, fb->zoomras, M_FILL);
+ GtDisableMapping (w, fb->zoommap, 0);
+ }
+ } else {
+ if (active) {
+ GtEnableMapping (w, fb->dispmap, 0);
+ GtSetDisplayRaster (w, xim->display_frame);
+ } else
+ GtDisableMapping (w, fb->dispmap, 0);
+ }
+
+ /* Set the new mapping. */
+ fb->xscale = fb->yscale = scale;
+ xim_setZoom (xim, fb, frame, mapping, fb->raster, fb->zoomras,
+ fb->xcen, fb->ycen, fb->xmag, fb->ymag,
+ fb->xoff, fb->yoff, False);
+ }
+
+ /* Refresh the screen for any active mappings. Any mappings
+ * defined on any visible frame should be refreshed, since a
+ * redraw clears the display window.
+ */
+ for (frame=1; frame <= xim->nframes; frame++) {
+ if (xim_onScreen (xim, frame)) {
+ int junk, width, height, depth;
+ fb = &xim->frames[frame-1];
+ GtQueryRaster (w, fb->raster, &junk, &width, &height, &depth);
+ GtRefreshPixels (w, fb->raster, GtPixel, 0, 0, width, height);
+ }
+ }
+
+ /* Highlight the current frame. */
+ xim_highlightFrame (xim, xim->display_frame);
+
+ sprintf (buf, "%d %d %d %d", sx, sy, width, height);
+ xim_message (xim, "resize", buf);
+}
+
+
+/* XIM_REFRESH -- Refresh the current display frame.
+ */
+void
+xim_refresh (xim)
+XimDataPtr xim;
+{
+ register FrameBufPtr fb = xim->df_p;
+ int junk, width, height, depth;
+
+ GtQueryRaster (xim->gt, fb->raster, &junk, &width, &height, &depth);
+ GtRefreshPixels (xim->gt, fb->raster, GtPixel, 0, 0, width, height);
+}
+
+
+/* XIM_CLOSE -- Free any raster specific resources.
+ */
+void
+xim_close (xim)
+register XimDataPtr xim;
+{
+}
+
+
+/* XIM_SETFRAME -- Configure a frame to be both the display and reference
+ * frame.
+ */
+void
+xim_setFrame (xim, frame)
+register XimDataPtr xim;
+int frame;
+{
+ xim_setDisplayFrame (xim, frame);
+}
+
+
+/* XIM_SETREFERENCEFRAME -- Set the frame used for frame buffer i/o.
+ */
+void
+xim_setReferenceFrame (chan, frame)
+register IoChanPtr chan;
+int frame;
+{
+ register XimDataPtr xim = (XimDataPtr) chan->xim;
+ register FrameBufPtr fb;
+ int frameno;
+
+ /* Ignore request if channel not active. */
+ if (!chan->type)
+ return;
+
+ frameno = max(1, min(MAX_FRAMES, frame));
+ fb = &xim->frames[frameno-1];
+
+ /* Ignore request if not a valid frame. */
+ if (fb->frameno > 0) {
+ chan->reference_frame = frameno;
+ chan->rf_p = fb;
+ }
+}
+
+
+/* XIM_SETDISPLAYFRAME -- Set the frame which is displayed.
+ */
+void
+xim_setDisplayFrame (xim, frame)
+register XimDataPtr xim;
+int frame;
+{
+ register FrameBufPtr fb;
+ register Widget gt = xim->gt;
+ FrameBufPtr old_fb = xim->df_p;
+ int frameno, old_frameno;
+ char buf[256];
+
+ old_frameno = old_fb ? old_fb->frameno : 0;
+ frameno = max(1, min(MAX_FRAMES, frame));
+ fb = &xim->frames[frameno-1];
+
+ /* Ignore request if not a valid frame. */
+ if (fb->frameno > 0 && (!old_fb || frameno != old_frameno)) {
+ /* Special case: if tile frame mode is in effect and we are
+ * displaying a frame not in the tile list, clear the screen
+ * before displaying the frame. Likewise, if displaying an
+ * untiled frame while in tile frame mode and then reverting
+ * to display of a tiled frame, clear the screen and display
+ * all the tiled frames.
+ */
+ if (xim->tileFrames && old_fb) {
+ int tile_old = (xim->tileFramesList & (1 << old_frameno-1));
+ int tile_new = (xim->tileFramesList & (1 << frameno-1));
+
+ if (tile_old && !tile_new)
+ GtClearScreen (gt);
+ else if (!tile_old && tile_new) {
+ GtClearScreen (gt);
+/* xim_resize (xim, gt);*/
+ }
+ }
+
+ /* Map the new frame. */
+ xim->df_p = fb;
+ xim->display_frame = frameno;
+ GtEnableMapping (gt, fb->dispmap, 0);
+
+ /* Unmap the old frame. */
+ if (old_fb && !xim_onScreen (xim, old_frameno)) {
+ FrameBufPtr old_fb = &xim->frames[old_frameno-1];
+ GtDisableMapping (gt, old_fb->dispmap, 0);
+ }
+
+ /* Display the new frame. */
+ if (GtActiveMapping (gt, fb->zoommap)) {
+ GtRefreshMapping (gt, fb->dispmap);
+ } else {
+ GtEnableMapping (gt, fb->zoommap, 0);
+ GtRefreshMapping (gt, fb->zoommap);
+ }
+ GtSetDisplayRaster (gt, frameno);
+
+
+ /* Highlight the new frame if in tileFrames mode. */
+ xim_highlightFrame (xim, frameno);
+
+ /* Load the colormap only if it differs from what we already
+ * have. This avoids the waste of repeatedly reloading the
+ * colormap when blinking frames that have matched colormaps.
+ */
+ if (!old_fb || fb->colormap != old_fb->colormap ||
+ abs (fb->offset - old_fb->offset) > 0.001 ||
+ abs (fb->scale - old_fb->scale) > 0.001) {
+
+ GtSetColormapFocus (-1); /* force full update */
+ GtLoadColormap (gt, fb->colormap, fb->offset, fb->scale);
+ GtSetColormapFocus (xim->cm_focus);
+ }
+
+ xim_msgi (xim, "frame", frameno);
+ xim_message (xim, "frameTitle", fb->ctran.imtitle);
+ xim_message (xim, "xflip", fb->xflip ? "true" : "false");
+ xim_message (xim, "yflip", fb->yflip ? "true" : "false");
+ xim_frameRegion (xim, fb);
+
+ sprintf (buf, "%g %g %g %g %g %g %g %g",
+ fb->xmag, fb->ymag, fb->xcen, fb->ycen,
+ fb->xscale, fb->yscale, fb->xoff, fb->yoff);
+ xim_message (xim, "frameView", buf);
+ }
+}
+
+
+/* XIM_INITFRAME -- Initialize a frame buffer.
+ */
+void
+xim_initFrame (xim, frame, nframes, config, memModel)
+register XimDataPtr xim;
+int frame, nframes;
+FbConfigPtr config;
+char *memModel;
+{
+ register FrameBufPtr fb = &xim->frames[frame-1];
+ register Widget gt = xim->gt;
+ int sx, sy, width, height, depth;
+ char buf[SZ_LINE];
+
+ if (frame < 1 || frame > MAX_FRAMES)
+ return;
+
+ xim_delFrame (xim, frame);
+ memset ((void *)fb, 0, sizeof(FrameBuf));
+
+ /* Create the frame buffer. */
+ fb->frameno = frame;
+ fb->raster = GtNextRaster (gt);
+
+ if (DBG_RASTER) {
+ fprintf (stderr,
+ "xim_initFrame: Creating CLIENT raster for frame=%d raster=%d (%dx%dx%d)\n",
+ frame, fb->raster,
+ config->width, config->height, DEF_FRAME_DEPTH);
+ fprintf (stderr,
+ "xim_initFrame: Creating memModel=%s frame=%d raster=%d (%d x %d)\n",
+ memModel, frame, fb->raster, config->width, config->height);
+ }
+
+ if (GtCreateRaster (gt, fb->raster, GtClient,
+ config->width, config->height, DEF_FRAME_DEPTH) < 0) {
+
+ fprintf (stderr, "cannot create %dx%d frame buffer #%d\n",
+ config->width, config->height, frame);
+ return;
+ }
+
+ /* Get region of screen to be written into. */
+ xim_getScreen (xim, frame, &sx, &sy, &width, &height, &depth);
+
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initFrame: [%d of %d] screen size -- %d x %d x %d\n",
+ frame, nframes, width, height, depth);
+
+ /* Set up the graphics pipeline to the screen. The "memory model"
+ * determines memory is used, trading off memory usage against speed
+ * for operations like zoom/pan and blink.
+ */
+
+ if (strcmp (memModel, "fast") == 0) {
+ /* Use both client and server memory to achieve the best
+ * possible performance. The frame buffer raster (type ximage)
+ * is mapped to a server pixmap with the zoom/pan mapping, and
+ * the server pixmap is mapped to the screen with the one-to-one
+ * frame display mapping.
+ */
+fast: fb->zoomras = GtNextRaster (gt);
+ if (GtCreateRaster (gt,
+ fb->zoomras, GtServer, width, height, depth) < 0)
+ goto nice;
+
+ xim_setMapping (xim, fb, frame, fb->zoommap = GtNextMapping(gt),
+ fb->raster, fb->zoomras, xim->autoscale ? M_ASPECT : M_UNITARY);
+ xim_setMapping (xim, fb, frame, fb->dispmap = GtNextMapping(gt),
+ fb->zoomras, 0, M_FILL);
+
+ } else if (strcmp (memModel, "beNiceToServer") == 0) {
+ /* Minimize use of X server memory, but keep zoom raster to speed
+ * up blinks. Everything is the same as with the "fast" memory
+ * model except that the zoom raster is an ximage rather than
+ * server pixmap raster.
+ */
+nice: fb->zoomras = GtNextRaster (gt);
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initFrame: creating 'nice' model (0x%x)\n",
+ fb->zoomras);
+ if (GtCreateRaster (gt,
+ fb->zoomras, GtClient, width, height, depth) < 0)
+ goto small;
+
+ xim_setMapping (xim, fb, frame, fb->zoommap = GtNextMapping(gt),
+ fb->raster, fb->zoomras, xim->autoscale ? M_ASPECT : M_UNITARY);
+ xim_setMapping (xim, fb, frame, fb->dispmap = GtNextMapping(gt),
+ fb->zoomras, 0, M_FILL);
+
+ } else if (strcmp (memModel, "small") == 0) {
+ /* Minimize both client and server memory as far as possible.
+ * Only the frame buffer raster is used, the zoom/pan mapping
+ * maps directly to the screen and is also used as the screen
+ * mapping.
+ *
+ * FIXME: On TrueColor visuals we can have an issue here where
+ * the display pixmap is 24-bits and various things (e.g. pixel
+ * readback) are expecting 8-bits.
+ */
+small: fb->zoomras = 0;
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_initFrame: creating 'small' model (0x%x)\n",
+ fb->zoomras);
+
+ xim_setMapping (xim, fb, frame, fb->zoommap = GtNextMapping(gt),
+ fb->raster, fb->zoomras, xim->autoscale ? M_ASPECT : M_UNITARY);
+ fb->dispmap = fb->zoommap;
+
+ } else {
+ fprintf (stderr,
+ "unrecognized memModel `%s', default to `fast'\n", memModel);
+ goto fast;
+ }
+
+ /* Set up the default colormap. */
+ fb->colormap = DEF_COLORMAP;
+ fb->offset = 0.5;
+ fb->scale = (xim->invert ? -1.0 : 1.0);
+ xim_enhancement (xim, fb);
+
+ /* Disable frame display initially if not mapped to screen. */
+ if (xim_onScreen (xim, frame)) {
+ GtEnableMapping (gt, fb->dispmap, 0);
+ GtSetDisplayRaster (gt, frame);
+ } else
+ GtDisableMapping (gt, fb->dispmap, 0);
+
+ set_nframes (xim, max (xim->nframes, frame));
+}
+
+
+/* XIM_DELFRAME -- Delete a frame.
+ */
+void
+xim_delFrame (xim, frame)
+register XimDataPtr xim;
+int frame;
+{
+ register FrameBufPtr fb = &xim->frames[frame-1];
+ register Widget gt = xim->gt;
+
+ if (frame < 1 || frame > MAX_FRAMES)
+ return;
+ if (fb->frameno <= 0)
+ return;
+
+ GtFreeMapping (gt, fb->dispmap);
+ if (fb->zoommap != fb->dispmap)
+ GtFreeMapping (gt, fb->zoommap);
+ if (fb->zoomras)
+ GtDestroyRaster (gt, fb->zoomras);
+ if (fb->raster)
+ GtDestroyRaster (gt, fb->raster);
+
+ fb->frameno = 0;
+ if (xim->nframes == frame)
+ set_nframes (xim, frame - 1);
+}
+
+
+/* XIM_ERASEFRAME -- Erase a frame.
+ */
+void
+xim_eraseFrame (xim, frame)
+register XimDataPtr xim;
+int frame;
+{
+ FrameBufPtr fb = &xim->frames[frame-1];
+ Widget gt = xim->gt;
+ int Z = 0;
+
+ GtSetPixels (gt, fb->raster, GtPixel, Z,Z,Z,Z, CMS_BACKGROUND, 0);
+}
+
+
+/* XIM_FITFRAME -- Attempt to resize the display window to be the same
+ * size as the frame buffer.
+ */
+void
+xim_fitFrame (xim)
+register XimDataPtr xim;
+{
+ register Widget gt = xim->gt;
+
+ GtCreateRaster (gt, 0, GtServer, xim->width, xim->height, 8);
+}
+
+
+/* XIM_TILEFRAMES -- Set or clear tile frame mode.
+ */
+void
+xim_tileFrames (xim, frame_list)
+register XimDataPtr xim;
+int frame_list;
+{
+ register int i;
+ register Widget w = xim->gt;
+ register FrameBufPtr fb;
+ char buf[SZ_LINE];
+ int mapping;
+
+
+ /* Get list of frames to be tiled. */
+ xim->tileFramesList = frame_list;
+ for (i=0, xim->nTileFrames = 0; i < xim->nframes; i++)
+ if (frame_list & (1 << i))
+ xim->nTileFrames++;
+
+ /* Remove any existing border highlight marker. */
+ if (xim->gm_border) {
+ GmDestroy (xim->gm_border);
+ xim->gm_border = NULL;
+ }
+
+ xim->tileFrames = (frame_list != 0);
+ GtClearScreen (w);
+ initialize_shadow_pixmap (w, 0);
+ xim_resize (xim, w);
+
+ /* Entering tile frame mode.
+ */
+ if (xim->tileFrames) {
+
+ /* Ensure that the display frame is set to one of the
+ * tiled frames.
+ */
+ if (!(xim->tileFramesList & (1 << xim->display_frame-1))) {
+ for (i=1; i <= xim->nframes; i++)
+ if (xim->tileFramesList & (1 << (i-1))) {
+ xim->df_p = NULL;
+ xim->display_frame = 0;
+ xim_setFrame (xim, i);
+ break;
+ }
+ }
+
+
+ /* Change the stacking order of the frame mappings if
+ * necessary so that any frames not in the tile list are
+ * displayed above the tiled frames. If this is not
+ * done the untiled frames may be obscured by the tiled
+ * frames.
+ */
+ for (i=0, mapping=0; i < xim->nframes; i++)
+ if (xim->tileFramesList & (1 << i)) {
+ fb = &xim->frames[i];
+ if (!mapping)
+ mapping = fb->dispmap;
+ else if (GtCompareMappings (w, mapping, fb->dispmap) < 0)
+ mapping = fb->dispmap;
+ }
+ for (i=0; i < xim->nframes; i++)
+ if (!(xim->tileFramesList & (1 << i))) {
+ fb = &xim->frames[i];
+ GtRaiseMapping (w, fb->dispmap, mapping);
+ }
+ }
+
+ /* Highlight the current frame. */
+ xim_highlightFrame (xim, xim->display_frame);
+
+ sprintf (buf, "%s", xim->tileFrames ? "True" : "False");
+ xim_message (xim, "tileFrames", buf);
+}
+
+
+/* XIM_HIGHLIGHTFRAME -- If in tile frames mode, highlight the current frame
+ * by coloring the border of the frame.
+ */
+xim_highlightFrame (xim, frame)
+register XimDataPtr xim;
+int frame;
+{
+ /* If we are tiling frames highlight the new display frame. */
+ if (xim->gm_border) {
+ GmDestroy (xim->gm_border);
+ xim->gm_border = NULL;
+ }
+
+ if (xim->tileFrames && xim->highlightFrames) {
+ int sx, sy, width, height, depth;
+ int interactive, erase;
+ XtPointer gm;
+ Arg args[20];
+ int nargs = 0;
+
+ xim_getScreen (xim, frame, &sx, &sy, &width, &height, &depth);
+ if (sx > 0 && sy > 0) {
+ gm = (XtPointer) GmCreate (xim->gt, Gm_Box,
+ interactive=False);
+
+ XtSetArg (args[nargs], GmX, sx + (width-1)/2); nargs++;
+ XtSetArg (args[nargs], GmY, sy + (height-1)/2); nargs++;
+ XtSetArg (args[nargs], GmWidth, (width-1)/2+1); nargs++;
+ XtSetArg (args[nargs], GmHeight, (height-1)/2+1); nargs++;
+ XtSetArg (args[nargs], GmLineWidth, xim->tileBorder); nargs++;
+ XtSetArg (args[nargs], GmSensitive, False); nargs++;
+ XtSetArg (args[nargs], GmVisible, True); nargs++;
+ XtSetArg (args[nargs], GmActivated, True); nargs++;
+
+ GmLower (gm, NULL);
+ GmSetAttribute (gm, GmLineColor, xim->borderColor, XtRString);
+ GmSetAttributes (gm, args, nargs, XtRInt);
+
+ xim->gm_border = gm;
+ }
+ xim_labelTiles (xim);
+ }
+}
+
+
+/* XIM_LABELTILES -- Label the tile with the frame number.
+ */
+xim_labelTiles (xim)
+register XimDataPtr xim;
+{
+ FrameBufPtr fb;
+ MappingPtr mp;
+ Widget gt = xim->gt;
+ XtPointer gm;
+ Arg args[10];
+ char text[256], tw[16];
+ register int i, j, len;
+ int sx, sy, width, height, depth, nargs=0;
+
+ static XtPointer labels[MAX_FRAMES];
+ static int label_init = 1;
+
+ if (!(xim->tileFrames && xim->tileLabels > 0))
+ return;
+
+ /* Initialize the label markers. */
+ if (label_init) {
+ /* First time through make sure we're all NULL. */
+ for (i=0; i < MAX_FRAMES; i++)
+ labels[i] = (XtPointer) NULL;
+ label_init = 0;
+ } else {
+ /* Free up the existing labels. */
+ for (i=0; labels[i] && i < MAX_FRAMES; i++) {
+ GmDestroy (labels[i]);
+ labels[i] = (XtPointer) NULL;
+ }
+ }
+
+
+ for (i=0; i < xim->nframes; i++) {
+ if (xim->tileFramesList & (1 << i)) {
+ xim_getScreen (xim, i+1, &sx, &sy, &width, &height, &depth);
+ fb = &xim->frames[i];
+ switch (xim->tileLabels) {
+ case 1: /* frame number */
+ sprintf (text, " %d ", i+1);
+ break;
+ case 2: /* image name */
+ if (fb->nmaps == 0) {
+ strcpy (text, " Blank ");
+ } else {
+ mp = &fb->mapping[0];
+ len = strlen (mp->ref);
+ for (j=len-1; mp->ref[j] != '/' && j > 0; j--) ;
+ sprintf (text, " %s ", &mp->ref[++j]);
+ }
+ break;
+ case 3: /* image title */
+ if (fb->nmaps == 0) {
+ strcpy (text, " Blank ");
+ } else {
+ len = strlen (fb->ctran.imtitle);
+ for (j=0; fb->ctran.imtitle[j] != ' ' && j < len; j++) ;
+ j += 3;
+ sprintf (text, " %s ", &fb->ctran.imtitle[j]);
+ }
+ break;
+ }
+
+
+ /* Now draw the label as a text marker on the tile. We use
+ * markers since they can be placed as needed in the frame
+ * and provide a background which lets them be read despite
+ * whatever image scaling is in place.
+ */
+ gm = (XtPointer) GmCreate (xim->gt, Gm_Text, False);
+
+ nargs = 0; /* initialize */
+ len = strlen (text);
+ sprintf (tw, "%dch", len);
+
+ XtSetArg (args[nargs], GmX, sx + 10); nargs++;
+ XtSetArg (args[nargs], GmY, sy + height - 20); nargs++;
+ XtSetArg (args[nargs], GmLineWidth, 0); nargs++;
+ XtSetArg (args[nargs], GmSensitive, True); nargs++;
+ XtSetArg (args[nargs], GmVisible, True); nargs++;
+ XtSetArg (args[nargs], GmActivated, True); nargs++;
+ XtSetArg (args[nargs], GmImageText, True); nargs++;
+
+ GmSetAttribute (gm, GmWidth, tw, XtRString);
+ GmSetAttribute (gm, GmHeight, "1ch", XtRString);
+ GmSetAttribute (gm, GmTextBgColor, "black", XtRString);
+ GmSetAttribute (gm, GmTextColor, "yellow", XtRString);
+ GmSetAttribute (gm, GmText, text, XtRString);
+ GmSetAttributes (gm, args, nargs, XtRInt);
+ GmMarkpos (gm);
+ GmRedraw (gm, GXcopy, True);
+
+ labels[i] = gm; /* save the marker ptr */
+ }
+ }
+}
+
+
+/* XIM_MATCHFRAMES -- Make the color enhancement of the listed frames match
+ * that of the indicated frame.
+ */
+void
+xim_matchFrames (xim, frames, reference_frame)
+XimDataPtr xim;
+int *frames;
+int reference_frame;
+{
+ register FrameBufPtr fr, fb = &xim->frames[reference_frame-1];
+ register int *ip, i;
+ Widget gt = xim->gt;
+ char buf[256];
+ int bits;
+
+ /* If frames is NULL match all frames. Set one bit in BITS for
+ * each frame to be modified. This ensures that each frame is
+ * only modified once, even if the same frame is listed more than
+ * once.
+ */
+ if (frames) {
+ for (ip=frames, bits=0; *ip; ip++)
+ bits |= (1 << (*ip - 1));
+ } else {
+ for (i=1, bits=0; i <= xim->nframes; i++)
+ bits |= (1 << (i - 1));
+ }
+
+ for (i=0; i < xim->nframes; i++) {
+ fr = &xim->frames[i];
+ if (fr != fb && (bits & (1 << (fr->frameno - 1)))) {
+ fr->colormap = fb->colormap;
+ fr->offset = fb->offset;
+ fr->scale = fb->scale;
+ xim_enhancement (xim, fr);
+ }
+ }
+}
+
+
+/* XIM_REGISTERFRAMES -- Register the listed frames with the given reference
+ * frame, i.e. set the field center and scale of each frame to match the
+ * reference frame.
+ */
+void
+xim_registerFrames (xim, frames, reference_frame, offsets)
+XimDataPtr xim;
+int *frames;
+int reference_frame;
+int offsets;
+{
+ register int *ip, i;
+ register FrameBufPtr fr, fb = &xim->frames[reference_frame-1];
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ Widget gt = xim->gt;
+ int bits, rop;
+
+ /* If frames is NULL register all frames. Set one bit in BITS for
+ * each frame to be modified. This ensures that each frame is
+ * only modified once, even if the same frame is listed more than
+ * once.
+ */
+ if (frames) {
+ for (ip=frames, bits=0; *ip; ip++)
+ bits |= (1 << (*ip - 1));
+ } else {
+ for (i=1, bits=0; i <= xim->nframes; i++)
+ bits |= (1 << (i - 1));
+ }
+
+ GtGetMapping (gt, fb->zoommap,
+ &rop, &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+
+ for (i=0; i < xim->nframes; i++) {
+ fr = &xim->frames[i];
+
+/* if (fr != fb && (bits & (1 << (fr->frameno - 1)))) {*/
+ if ((bits & (1 << (fr->frameno - 1)))) {
+ fr->xcen = fb->xcen; fr->ycen = fb->ycen;
+ fr->xmag = fb->xmag; fr->ymag = fb->ymag;
+ fr->xflip = fb->xflip; fr->yflip = fb->yflip;
+
+ if (!xim_onScreen (xim, fb->frameno))
+ GtDisableMapping (gt, fr->zoommap, 0);
+
+ if (offsets) {
+ /* fb is the current display buffer, fr is some other
+ * frame in the list. To do the offsets we must
+ * first subtract the offset of the current display
+ * and then add the offset peculiar to the frame.
+ */
+
+ int nsx, nsy;
+
+ nsx = (int)(sx - fb->xoff + fr->xoff);
+ nsy = (int)(sy - fb->yoff + fr->yoff);
+
+ GtSetMapping (gt, fr->zoommap, xim->rop,
+ fr->raster, st,nsx,nsy, snx,sny,
+ fr->zoomras,dt,dx,dy,dnx,dny);
+ GtRefreshMapping (gt, fr->zoommap);
+
+ } else {
+ GtSetMapping (gt, fr->zoommap, xim->rop,
+ fr->raster, st,sx,sy, snx,sny,
+ fr->zoomras,dt,dx,dy,dnx,dny);
+ }
+ }
+ }
+
+ /* A normal registration zeroes the offsets for each frame. */
+ if (!offsets) {
+ for (i=0; i < xim->nframes; i++) {
+ fr = &xim->frames[i];
+ fr->xoff = fr->yoff = 0;
+ }
+ }
+ xim_labelTiles (xim);
+}
+
+
+/* XIM_CURSORMODE -- Enter or leave cursor mode. The remote client issues
+ * a cursor read request via the datastream, then blocks until a cursor
+ * value is returned. The GUI is responsible for signalling to the user
+ * that the application is waiting for cursor input, and for returning the
+ * cursor value when the cursor read finishes.
+ */
+void
+xim_cursorMode (xim, state)
+register XimDataPtr xim;
+int state;
+{
+ /* The GUI is responsible for implementing cursor reads. */
+ xim_message (xim, "cursorMode", state ? "on" : "off");
+}
+
+
+/* XIM_SETMAPPING -- Set up a mapping between two rasters.
+ */
+void
+xim_setMapping (xim, fb, frame, mapping, src, dst, fill_mode)
+register FrameBufPtr fb;
+register XimDataPtr xim;
+int frame;
+int mapping;
+int src, dst;
+int fill_mode;
+{
+ register Widget gt = xim->gt;
+ int src_type, src_width, src_height, src_depth;
+ int dst_type, dst_width, dst_height, dst_depth, dst_x, dst_y;
+ float xscale, yscale, scale;
+ int dx, dy, dnx, dny;
+ int sx, sy, snx, sny;
+
+ /* Get dimensions of source and destination rasters. */
+ if (GtQueryRaster (gt, src,
+ &src_type, &src_width, &src_height, &src_depth) == 0)
+ return;
+
+ /* Get region of destination to be written into. */
+ if (dst == 0) {
+ xim_getScreen (xim, frame,
+ &dst_x, &dst_y, &dst_width, &dst_height, &dst_depth);
+ } else {
+ if (GtQueryRaster (gt, dst,
+ &dst_type, &dst_width, &dst_height, &dst_depth) == 0)
+ return;
+ dst_x = dst_y = 0;
+ }
+
+ xscale = (float)dst_width / (float)src_width;
+ yscale = (float)dst_height / (float)src_height;
+
+ switch (fill_mode) {
+ case M_UNITARY:
+ /* Set up a unitary (one-to-one) mapping, i.e. one pixel in the
+ * source is mapped to one pixel in the destination. The mapped
+ * region is the center of both rasters.
+ */
+ xscale = yscale = 1.0;
+ /* fall through */
+
+ case M_ASPECT:
+ /* Scale the source to fit the destination, preserving the
+ * aspect ratio and displaying all source pixels.
+ */
+ scale = min (xscale, yscale);
+ if (abs(scale - (int)(scale+0.5)) < TOL)
+ scale = (int)(scale+0.5);
+
+ dnx = src_width * scale;
+ if (dnx > dst_width) {
+ /* Clip source rect. */
+ dnx = dst_width;
+ snx = dnx;
+ sx = max (0, (src_width + 1) / 2 - snx / 2);
+ dx = 0;
+ } else {
+ /* Clip destination rect. */
+ snx = src_width;
+ sx = 0;
+ dx = max (0, (dst_width + 1) / 2 - dnx / 2);
+ }
+
+ dny = src_height * scale;
+ if (dny > dst_height) {
+ /* Clip source rect. */
+ dny = dst_height;
+ sny = dny;
+ sy = max (0, (src_height + 1) / 2 - sny / 2);
+ dy = 0;
+ } else {
+ /* Clip destination rect. */
+ sny = src_height;
+ sy = 0;
+ dy = max (0, (dst_height + 1) / 2 - dny / 2);
+ }
+
+ GtSetMapping (gt, mapping, xim->rop,
+ src, GtPixel, sx, sy, snx, sny,
+ dst, GtPixel, dst_x + dx, dst_y + dy, dnx, dny);
+ break;
+
+ case M_FILL:
+ /* Scale the source to fill the destination window.
+ */
+ GtSetMapping (gt, mapping, xim->rop,
+ src, GtPixel, 0, 0, src_width, src_height,
+ dst, GtPixel, dst_x, dst_y, dst_width, dst_height);
+ break;
+ }
+
+ if (fb && mapping == fb->zoommap) {
+ fb->xmag = 1.0;
+ fb->ymag = 1.0;
+ fb->xscale = xscale;
+ fb->yscale = yscale;
+ fb->xcen = (src_width + 1) / 2.0;
+ fb->ycen = (src_height + 1) / 2.0;
+ fb->xflip = fb->yflip = 0;
+ }
+}
+
+
+/* XIM_SETZOOM -- Modify a mapping between two rasters given the specified
+ * view center and zoom factors.
+ */
+void
+xim_setZoom (xim, fb, frame, mapping, src, dst, xcen,ycen,xmag,ymag, xoff,yoff, absolute)
+register XimDataPtr xim;
+register FrameBufPtr fb;
+int frame;
+int mapping;
+int src, dst;
+float xcen, ycen; /* center of source raster region to be mapped */
+float xmag, ymag; /* magnification in each axis */
+float xoff, yoff; /* offset in each axis */
+Boolean absolute; /* ignore xscale/yscale */
+{
+ register Widget gt = xim->gt;
+ int src_type, src_width, src_height, src_depth;
+ int dst_type, dst_width, dst_height, dst_depth, dst_x, dst_y;
+ int sx1, sx2, sy1, sy2, snx, sny;
+ int dx1, dx2, dy1, dy2, dnx, dny;
+ int fx1, fx2, fy1, fy2, shift;
+ int src_recenter_allowed = 1;
+ int dst_recenter_allowed = 1;
+ int xreplicate, yreplicate;
+ int scale, max_x, max_y, bias;
+ float xscale, yscale;
+ char buf[256];
+
+
+ /* Get dimensions of source and destination rasters. */
+ if (GtQueryRaster (gt, src,
+ &src_type, &src_width, &src_height, &src_depth) == 0)
+ return;
+
+ /* Get region of destination to be written into. */
+ if (dst == 0) {
+ xim_getScreen (xim, frame,
+ &dst_x, &dst_y, &dst_width, &dst_height, &dst_depth);
+ } else {
+ if (GtQueryRaster (gt, dst,
+ &dst_type, &dst_width, &dst_height, &dst_depth) == 0)
+ return;
+ dst_x = dst_y = 0;
+ }
+
+ /* Use old center if none given. */
+ if (xcen <= 0)
+ xcen = fb->xcen;
+ if (ycen <= 0)
+ ycen = fb->ycen;
+
+ /* Get scaling ratios. */
+ if (absolute) {
+ xscale = xmag;
+ yscale = ymag;
+ } else {
+ xscale = xmag * fb->xscale;
+ yscale = ymag * fb->yscale;
+ }
+
+ /* Avoid roundoff if integer scaling. */
+ if (xreplicate = (abs(xscale - (int)(xscale+0.5)) < TOL))
+ xscale = (int)(xscale+0.5);
+ if (yreplicate = (abs(yscale - (int)(yscale+0.5)) < TOL))
+ yscale = (int)(yscale+0.5);
+
+ /* Sanity check, return if we're getting too small. */
+ if (xscale < TOL || yscale < TOL)
+ return;
+
+
+ /* Map the destination rect back into the source with the given
+ * zoom factor and center, clipping the source rect at the source
+ * raster boundary.
+ */
+src_recenter:
+ max_x = src_width - 1;
+ max_y = src_height - 1;
+
+ snx = (int) (dst_width / xscale) + 1;
+ sny = (int) (dst_height / yscale) + 1;
+
+ sx1 = (int) (xcen - snx / 2.0 + 0.5 + xoff); /*********/
+ sx2 = (int) (xcen + snx / 2.0 + 0.5);
+ sy1 = (int) (ycen - sny / 2.0 + 0.5 + yoff); /*********/
+ sy2 = (int) (ycen + sny / 2.0 + 0.5);
+
+ /* Fiddle the source rect slightly if necessary to achieve the
+ * requested snx,sny. This corrects for any pixel selection errors
+ * introduced in the float to integer truncation. This is a small
+ * effect but it can be apparent at high pixel magnifications.
+ */
+ sx2 -= ((sx2 - sx1 + 1) - snx);
+ sy2 -= ((sy2 - sy1 + 1) - sny);
+
+ if (src_recenter_allowed) {
+ /* Adjust the center of the source rect to make it fit on the
+ * source raster, but only if only one edge extends beyond the
+ * raster boundary. If both edges are out of bounds we just
+ * clip below.
+ *
+ * MJF 9/29 - The changes to fx2/fy2 below are to fix an off-by-one
+ * error in the center pixel computed by an integer zoom. For
+ * example, display a 256sq image, invert the cmap and zoom by
+ * two, the center is different than a straight centering op done
+ * by the pan function. The effect is that hardcopy has an extra
+ * border on two sides.
+ */
+ fx1 = (sx1 < 0) ? -sx1 : 0;
+ fx2 = (sx2 > max_x) ? (max_x - sx2 + 1) : 0;
+ if (fx1 && !fx2 || !fx1 && fx2)
+ xcen += (fx1 + fx2);
+
+ fy1 = (sy1 < 0) ? -sy1 : 0;
+ fy2 = (sy2 > max_y) ? (max_y - sy2 + 1) : 0;
+ if (fy1 && !fy2 || !fy1 && fy2)
+ ycen += (fy1 + fy2);
+
+ src_recenter_allowed = 0;
+ goto src_recenter;
+ }
+
+ /* Clip the source rect to the raster boundary. */
+ sx1 = max(0, min(max_x, sx1));
+ sx2 = max(0, min(max_x, sx2));
+ sy1 = max(0, min(max_y, sy1));
+ sy2 = max(0, min(max_y, sy2));
+
+ snx = sx2 - sx1 + 1;
+ sny = sy2 - sy1 + 1;
+
+
+ /* Map the zoomed, possibly centered, and clipped source rect back
+ * to the destination.
+ */
+ max_x = dst_width - 1;
+ max_y = dst_height - 1;
+
+ dx1 = (int) ((sx1-0.5 - xcen) * xscale + dst_width / 2.0 + 0.5);
+ dx2 = (int) ((sx2+0.5 - xcen) * xscale + dst_width / 2.0 + 0.5);
+ dy1 = (int) ((sy1-0.5 - ycen) * yscale + dst_height / 2.0 + 0.5);
+ dy2 = (int) ((sy2+0.5 - ycen) * yscale + dst_height / 2.0 + 0.5);
+
+ if (dst_recenter_allowed) {
+ /* If the unclipped destination rect extends out of bounds on
+ * one side or the other (but not both), shift it slightly to
+ * try to recenter it on the destination raster. This tends
+ * to cancel out rounding errors occurring in the calculation
+ * of the destination rect.
+ */
+ fx1 = (dx1 < 0) ? -dx1 : 0;
+ fx2 = (dx2 > max_x) ? (max_x - dx2) : 0;
+ if (fx1 && !fx2 || !fx1 && fx2) {
+ shift = (fx1 + fx2);
+ dx1 += shift;
+ dx2 += shift;
+ }
+
+ fy1 = (dy1 < 0) ? -dy1 : 0;
+ fy2 = (dy2 > max_y) ? (max_y - dy2) : 0;
+ if (fy1 && !fy2 || !fy1 && fy2) {
+ shift = (fy1 + fy2);
+ dy1 += shift;
+ dy2 += shift;
+ }
+
+ /* If the destination rect does not fill the destination raster,
+ * center it in the raster.
+ */
+ if ((dx2 - dx1 + 1) < dst_width) {
+ shift = (dx1 + (max_x - dx2)) / 2 - dx1;
+ dx1 += shift;
+ dx2 += shift;
+ }
+
+ if ((dy2 - dy1 + 1) < dst_height) {
+ shift = (dy1 + (max_y - dy2)) / 2 - dy1;
+ dy1 += shift;
+ dy2 += shift;
+ }
+ }
+
+ /* Clip to the edge of the destination raster. */
+ dx1 = max(0, min(max_x, dx1));
+ dx2 = max(0, min(max_x, dx2));
+ dy1 = max(0, min(max_y, dy1));
+ dy2 = max(0, min(max_y, dy2));
+
+ dnx = dx2 - dx1 + 1;
+ dny = dy2 - dy1 + 1;
+
+ /* Attempt to integerize things if integer scaling is selected. This
+ * can leave a blank pixel or two at the edge depending upon the
+ * window size and scaling.
+ */
+ scale = (int)xscale;
+ if (xreplicate && dnx != snx * scale) {
+ if (snx < src_width) {
+ snx = max(1, min(src_width, dnx / scale));
+ dnx = max(1, min(dst_width, snx * scale));
+ } else if (dnx < dst_width) {
+ dnx = max(1, min(dst_width, snx * scale));
+ snx = max(1, min(src_width, dnx / scale));
+ }
+ if ((bias = ((dx2 - dx1 + 1) - dnx) / 2) > 0) {
+ dx1 += bias;
+ dx2 += bias;
+ }
+ }
+ scale = (int)yscale;
+ if (yreplicate && dny != sny * scale) {
+ if (sny < src_height) {
+ sny = max(1, min(src_height, dny / scale));
+ dny = max(1, min(dst_height, sny * scale));
+ } else if (dny < dst_height) {
+ dny = max(1, min(dst_height, sny * scale));
+ sny = max(1, min(src_height, dny / scale));
+ }
+ if ((bias = ((dy2 - dy1 + 1) - dny) / 2) > 0) {
+ dy1 += bias;
+ dy2 += bias;
+ }
+ }
+
+
+
+ /* Set the mapping. */
+ initialize_shadow_pixmap (gt, dst);
+ GtSetMapping (gt, mapping, xim->rop,
+ src, GtPixel, sx1, sy1, snx, sny,
+ dst, GtPixel, dst_x + dx1, dst_y + dy1,
+ fb->xflip ? -dnx : dnx,
+ fb->yflip ? -dny : dny);
+
+ /* Update the frame buffer zoom/pan/flip parameters. */
+ fb->xcen = xcen; fb->ycen = ycen;
+ fb->xoff = xoff; fb->yoff = yoff;
+
+ if (absolute) {
+ fb->xmag = xmag / fb->xscale;
+ fb->ymag = ymag / fb->yscale;
+ } else {
+ fb->xmag = xmag;
+ fb->ymag = ymag;
+ }
+
+ xim_frameRegion (xim, fb);
+ sprintf (buf, "%g %g %g %g %g %g %g %g",
+ fb->xmag, fb->ymag, fb->xcen, fb->ycen,
+ fb->xscale, fb->yscale, fb->xoff, fb->yoff);
+ xim_message (xim, "frameView", buf);
+}
+
+
+/* XIM_GETSCREEN -- Determine the region of the display window to which
+ * the given frame is mapped.
+ */
+xim_getScreen (xim, frame, sx, sy, width, height, depth)
+register XimDataPtr xim;
+int frame;
+int *sx, *sy;
+int *width, *height, *depth;
+{
+ register int i;
+ int border = xim->tileBorder;
+ int rtype, scr_width, scr_height;
+ int twidth, theight, tileno, frameno;
+ int tilex, tiley;
+ int nrows = xim->tileRows, ncols = xim->tileCols;
+
+ if (GtQueryRaster (xim->gt, 0,
+ &rtype, &scr_width, &scr_height, depth) == 0)
+ return;
+
+ /* Use the entire display window if we are not tiling frames, if
+ * there aren't enough frames to tile, or if the given frame is
+ * not in the list of tile frames.
+ */
+ if (!xim->tileFrames || xim->nframes <= 1 ||
+ !(xim->tileFramesList & (1 << frame-1))) {
+ *sx = *sy = 0;
+ *width = scr_width;
+ *height = scr_height;
+ return;
+ }
+
+ /* Get index of frame in tile Frames list. */
+ for (i=1, frameno=0; i <= xim->nframes; i++) {
+ if (xim->tileFramesList & (1 << (i-1))) {
+ frameno++;
+ if (frame == i)
+ break;
+ }
+ }
+
+ /* Now compute the size of each tile. */
+ tileno = frameno - 1;
+ twidth = (scr_width - (ncols * 2 * border)) / ncols;
+ theight = (scr_height - (nrows * 2 * border)) / nrows;
+
+ /* Get the "coordinates" of the tile in the mosaic. */
+ if (xim->tileByRows) {
+ tilex = tileno % ncols;
+ tiley = tileno / ncols;
+ } else {
+ tilex = tileno / nrows;
+ tiley = tileno % nrows;
+ }
+ if (!xim->tileTopDown)
+ tiley = (nrows - tiley - 1);
+
+ /* Finally, get the placement of the tile on the screen. */
+ *sx = tilex * twidth + ((tilex*2+1) * border);
+ *sy = tiley * theight + ((tiley*2+1) * border);
+
+ *width = twidth;
+ *height = theight;
+}
+
+
+/* XIM_ONSCREEN -- Test whether the given frame is visible onscreen.
+ */
+xim_onScreen (xim, frame)
+register XimDataPtr xim;
+int frame;
+{
+ if (xim->tileFrames)
+ return ((xim->tileFramesList & (1 << (frame-1))) != 0);
+ else
+ return (frame == xim->display_frame);
+}
+
+
+/* XIM_SETFLIP -- Modify a mapping to flip the frame in X and/or Y.
+ */
+void
+xim_setFlip (xim, fb, flip_x, flip_y)
+register XimDataPtr xim;
+register FrameBufPtr fb;
+int flip_x, flip_y;
+{
+ register Widget gt = xim->gt;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int rop;
+
+ if (!flip_x && !flip_y)
+ return;
+
+ if (flip_x)
+ fb->xflip = !fb->xflip;
+ if (flip_y)
+ fb->yflip = !fb->yflip;
+
+ GtGetMapping (gt, fb->zoommap,
+ &rop, &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+
+ dnx = abs (dnx);
+ dnx = fb->xflip ? -dnx : dnx;
+ dny = abs (dny);
+ dny = fb->yflip ? -dny : dny;
+
+ GtSetMapping (gt, fb->zoommap,
+ rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+
+ xim_message (xim, "xflip", fb->xflip ? "true" : "false");
+ xim_message (xim, "yflip", fb->yflip ? "true" : "false");
+}
+
+
+/* XIM_SETROP -- Modify the rasterop portion of a mapping.
+ */
+void
+xim_setRop (xim, fb, rop)
+register XimDataPtr xim;
+register FrameBufPtr fb;
+int rop;
+{
+ register Widget gt = xim->gt;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int oldrop;
+
+ GtGetMapping (gt, fb->zoommap,
+ &oldrop, &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+
+ GtSetMapping (gt, fb->zoommap,
+ rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+}
+
+
+/* XIM_SETCURSORPOS -- Set the cursor position.
+ */
+void
+xim_setCursorPos (xim, sx, sy)
+register XimDataPtr xim;
+float sx, sy; /* raster coordinates */
+{
+ GtSetRaster (xim->gt, xim->df_p->frameno);
+ GtSetCursorPos (xim->gt, (int)sx, (int)sy);
+ GtSetRaster (xim->gt, 0);
+}
+
+
+/* XIM_GETCURSORPOS -- Get the cursor position. This is done to a fractional
+ * pixel precision if the image is zoomed.
+ */
+void
+xim_getCursorPos (xim, sx, sy, raster, frame)
+register XimDataPtr xim;
+float *sx, *sy;
+int *raster, *frame;
+{
+ register FrameBufPtr fb;
+ DPoint pv1, pv2;
+ int rx, ry, rmap;
+ int src, x, y, i;
+
+ GtGetCursorPos (xim->gt, &x, &y);
+ src = GtSelectRaster (xim->gt, 0, GtPixel, x,y, GtNDC, &rx, &ry, &rmap);
+
+ pv1.x = rx; pv1.y = ry;
+ GtNDCToPixel (xim->gt, src, &pv1, &pv2, 1);
+ *sx = pv2.x;
+ *sy = pv2.y;
+
+ if (raster)
+ *raster = src;
+
+ if (frame) {
+ *frame = xim->display_frame;
+ for (i=1; i < xim->nframes; i++) {
+ fb = &xim->frames[i-1];
+ if (fb->raster == src || fb->zoomras == src) {
+ *frame = fb->frameno;
+ break;
+ }
+ }
+ }
+}
+
+
+/* XIM_READDISPLAY -- Read a region of the current display frame and return
+ * the pixels and corresponding RGB colormap. We allocate a pointer to the
+ * pixels that needs to be freed later on. Note this routine returns an
+ * 8 bit RGB colormap.
+ */
+unsigned char *
+xim_readDisplay (xim, x0,y0,nx,ny, w,h, r,g,b, ncolors)
+register XimDataPtr xim;
+int x0,y0,nx,ny; /* region to extract (input) */
+int *w, *h; /* size of output region (output). */
+unsigned char *r, *g, *b; /* colortable (output) */
+int *ncolors; /* size of colortable (output) */
+{
+ register Widget gt = xim->gt;
+ register int i, j;
+
+ int raster, x1, y1, nc;
+ int first, nelem, maxelem;
+ char buf[SZ_LINE], *tmpfile;
+ unsigned short *rs, *gs, *bs;
+ int junk, width, height, depth;
+ unsigned short *cmap=NULL, *iomap=NULL;
+ unsigned char *pixels=NULL;
+ static int debug = 0;
+
+ /* The display is raster zero. */
+ raster = 0;
+
+ /* Get the size of the raster we're going to extract. If nx or ny
+ * is zero use the entire raster, else use the indicated region.
+ * If a region is given clip it to the raster boundary.
+ */
+ if (GtQueryRaster (gt, raster, &junk, &width, &height, &depth) == 0)
+ goto error;
+
+
+ if (nx <= 0 || ny <= 0) {
+ x0 = y0 = 0;
+ nx = width;
+ ny = height;
+ } else {
+ x1 = min (width-1, x0 + nx - 1);
+ y1 = min (height-1, y0 + ny - 1);
+ x0 = max (0, x0);
+ y0 = max (0, y0);
+ nx = x1 - x0 + 1;
+ ny = y1 - y0 + 1;
+ }
+
+ /* Get a pixel buffer and read the pixels. */
+ if (nx*ny <= 0 || !(pixels = (unsigned char *) malloc (nx * ny)))
+ goto error;
+ if (GtReadPixels (gt, raster, pixels, 8, x0, y0, nx, ny) < 0)
+ goto error;
+
+
+ /* Get Gterm widget colormap. */
+ if (!(cmap = (ushort *) malloc (3 * MAX_COLORS * sizeof(ushort))))
+ goto error;
+
+ rs = cmap;
+ gs = rs + MAX_COLORS;
+ bs = gs + MAX_COLORS;
+
+ if (depth == 8) {
+ nc = GtReadColormap (gt, raster, 0, MAX_COLORS, rs,gs,bs);
+ if (nc <= 0)
+ goto error;
+
+
+ /* Get the RGB color associated with each pixel. To determine
+ ** this we must consider both the Gterm widget colormap and iomap.
+ ** The iomap maps client pixels to Gterm widget pixels, and the
+ ** colormap maps Gterm widget pixels to RGB values. GtReadPixels
+ ** returns client pixels, so to get the RGB value associated with
+ ** each client pixel we must run the client pixel through the iomap
+ ** to get the Gterm widget pixel, and then use this to look up the
+ ** RGB value in the widget's colormap. When reading the display
+ ** (raster=0) we get the colormap corresponding to the image as
+ ** currently windowed, hence the output image will be rendered as
+ ** in the current display. Note: the Gterm widget maps are 16 bits,
+ ** while we return an 8 bit RGB colormap to our caller.
+ */
+ /* Get iomap. */
+ if (!(iomap = (ushort *) malloc (MAX_COLORS * sizeof(ushort))))
+ goto error;
+ GtReadIomap (gt, iomap, 0, MAX_COLORS);
+
+ if (debug) {
+ register short pmin = MAX_COLORS, pmax = 0, i, j;
+ fprintf (stderr, "iomap\n");
+ for (i=0; i < MAX_COLORS; ) {
+ for (j=0; j < 8 && i < MAX_COLORS; j++) {
+ pmin = (iomap[i] < pmin ? iomap[i] : pmin);
+ pmax = (iomap[i] > pmax ? iomap[i] : pmax);
+ fprintf (stderr, "%3d(%3d) ", i, iomap[i++]);
+ }
+ fprintf (stderr, "\n");
+
+ }
+ fprintf (stderr, "iomap min = %d max = %d\n", pmin, pmax);
+ fprintf (stderr, "Gterm Colormap\n");
+ for (i=0; i < MAX_COLORS; ) {
+ for (j=1; j < 4 && i < MAX_COLORS; j++)
+ fprintf (stderr, " %3d(%3d,%3d,%3d)",i,
+ (rs[i]>>8),(gs[i]>>8),(bs[i++]>>8));
+ fprintf (stderr, "\n");
+ }
+ fflush (stderr);
+ }
+
+ /* Output the colormap. */
+ for (i=0; i < nc; i++) {
+ j = iomap[i];
+ r[i] = (rs[j] >> 8);
+ g[i] = (gs[j] >> 8);
+ b[i] = (bs[j] >> 8);
+ }
+ for (i=nc; i < MAX_COLORS; i++) {
+ j = iomap[i];
+ r[i] = (rs[j] >> 8);
+ g[i] = (gs[j] >> 8);
+ b[i] = (bs[j] >> 8);
+ }
+
+ } else {
+ unsigned long lut[MAX_COLORS];
+ int start = 10; /* static colors offset */
+
+ GtReadLUT (gt, lut, 0, MAX_COLORS);
+
+ nc = 216;
+ for (i=0; i < nc; i++) {
+ r[i] = (lut[i] >> 16) & 0xff;
+ g[i] = (lut[i] >> 8) & 0xff;
+ b[i] = (lut[i] ) & 0xff;
+ }
+ }
+
+ *w = nx;
+ *h = ny;
+ *ncolors = nc; /* includes static colors */
+
+ if (debug) {
+ fprintf (stderr,
+ "xim_readDisplay: w=%d h=%d d=%d\n", width, height, depth);
+ for (i=0; i < nc; i++)
+ fprintf (stderr, "xim_readDisplay[%3d]: %3d %3d %3d\n",
+ i, r[i], g[i], b[i]);
+ }
+
+ free ((char *) cmap);
+ free ((char *) iomap);
+
+ return (pixels);
+
+error:
+ if (cmap)
+ free ((char *) cmap);
+ if (iomap)
+ free ((char *) iomap);
+ if (pixels)
+ free ((char *) pixels);
+ return (NULL);
+}
+
+
+/* XIM_WRITEDISPLAY -- Load the current display frame from the pixel array
+ * and RGB colormap passed in the input arguments. The data is assumed to
+ * be 8 bit pseudocolor.
+ */
+int
+xim_writeDisplay (xim, frame, mapname, pixels, w,h, r,g,b, ncolors)
+register XimDataPtr xim;
+int frame; /* display frame to be written */
+char *mapname; /* colormap name to be written */
+unsigned char *pixels;
+int w, h;
+unsigned char *r, *g, *b;
+int ncolors;
+{
+ register int i, j;
+ register FrameBufPtr fb;
+ register Widget gt = xim->gt;
+ unsigned short rs[MAX_COLORS], gs[MAX_COLORS], bs[MAX_COLORS];
+ unsigned short iomap[MAX_COLORS], sv_iomap[MAX_COLORS];
+ unsigned short invmap[MAX_COLORS];
+ int want, npix, nx, ny, sx0, sy0, dx0, dy0;
+ int sx, sy, width, height, depth;
+ float xzoom, yzoom, zoom;
+ int debug=0, autoscale=xim->autoscale;
+ unsigned char *gtpix;
+ ColorMapPtr cm;
+
+
+ if (DBG_RASTER)
+ fprintf (stderr, "raster writeDisplay: .......................");
+
+ /* If frame=0 use the current display frame. */
+ if (frame < 1) frame = xim->display_frame;
+
+ /* Create additional frames if needed. */
+ if (frame > xim->nframes) {
+ for (i=1; i <= frame; i++) {
+ fb = &xim->frames[i-1];
+ if (fb->frameno != i) {
+ xim_initFrame (xim, i, frame,
+ &xim->fb_config[xim->fb_configno-1], xim->memModel);
+
+ /* If we're in tile mode, add the frame to the tile list
+ * and if needed resize the tile frames.
+ */
+ if (xim->tileFrames) {
+ xim->tileFramesList |= (1 << (i-1));
+ xim->nTileFrames++;
+ xim_tileFrames (xim, xim->tileFramesList);
+ }
+ }
+ }
+ }
+
+
+ /* Erase the existing frame before disabling the mapping, otherwise
+ * we get a white background when the new image is loaded.
+ */
+ xim_eraseFrame (xim, frame);
+
+ fb = &xim->frames[frame-1];
+ GtDisableMapping (gt, fb->dispmap, 0);
+
+ /* Substitute a one-to-one iomap so that we don't confuse colors for
+ * a non-continuous tone (grayscale) image.
+ */
+ GtReadIomap (gt, sv_iomap, 0, MAX_COLORS);
+ for (i=0; i < MAX_COLORS; i++)
+ iomap[i] = FIRST_COLOR + min (xim->ncolors, i);
+ GtWriteIomap (gt, iomap, 0, MAX_COLORS);
+
+ /* If debug mode is enabled compute and print the minimum and maximum
+ * pixel values and a histogram or count of the number of pixels at
+ * each value.
+ */
+ if (debug) {
+ int count[MAX_COLORS];
+ int v, lo, hi;
+
+ memset ((void *)count, 0, sizeof(count));
+ for (i=0, lo=MAX_COLORS, hi=0; i < w*h; i++) {
+ v = pixels[i];
+ count[v]++;
+ if (v < lo)
+ lo = v;
+ else if (v > hi)
+ hi = v;
+ }
+ fprintf (stderr, "%s: w=%d h=%d min=%d max=%d\n",
+ mapname, w, h, lo, hi);
+
+ for (i=0, j=0; i < MAX_COLORS; i++)
+ if (count[i]) {
+ fprintf (stderr, " %3d(%4d)", i, min(9999,count[i]));
+ if (++j >= 7) {
+ fprintf (stderr, "\n");
+ j = 0;
+ }
+ }
+ if (j)
+ fprintf (stderr, "\n");
+
+ fprintf (stderr, "zeros: ");
+ for (i=0; i < MAX_COLORS; i++)
+ if (!count[i])
+ fprintf (stderr, " %d", i);
+ fprintf (stderr, "\n");
+ }
+
+ /* Invert the iomap. We want to map standard pixels 0-N to the range
+ * FC-FC+N in Gterm color space (FC is shorthand for FIRST_COLOR).
+ * GtWritePixels will process pixels through the ximtool iomap so we
+ * need to compute invmap, which tells us the input value needed to
+ * get the desired value of out the iomap.
+ GtReadIomap (gt, iomap, 0, MAX_COLORS);
+ memset ((void *)invmap, 0, sizeof(invmap));
+ for (i=0; i < MAX_COLORS; i++)
+ invmap[iomap[i]] = i;
+ if (!(gtpix = (unsigned char *) malloc (npix = w * h)))
+ return (-1);
+ for (i=0; i < npix; i++) {
+ want = FIRST_COLOR + pixels[i];
+ gtpix[i] = invmap[want];
+ }
+ free ((char *) gtpix);
+ */
+
+ /* If the image is too large to fit in the existing frame clip it
+ * to fit (we need to add an auto-resize option here later).
+ */
+ if (w > xim->width) {
+ nx = xim->width;
+ sx0 = (w - nx) / 2;
+ dx0 = 0;
+ } else {
+ nx = w;
+ sx0 = 0;
+ dx0 = (xim->width - w) / 2;
+ }
+
+ if (h > xim->height) {
+ ny = xim->height;
+ sy0 = (h - ny) / 2;
+ dy0 = 0;
+ } else {
+ ny = h;
+ sy0 = 0;
+ dy0 = (xim->height - h) / 2;
+ }
+
+ /* Load the frame. The GtWritePixels call loads to the raster
+ * associated with the frame, not the frame number directly.
+ */
+ if (nx <= xim->width && ny <= xim->height) {
+ GtWritePixels (gt, fb->raster, pixels, 8, dx0, dy0, nx, ny);
+ } else {
+ unsigned char *ip = pixels + sy0 * w + sx0;
+ for (i=0; i < ny; i++, ip += w)
+ GtWritePixels (gt, fb->raster, ip, 8, dx0, dy0+i, nx, 1);
+ }
+
+ /* Get screen size. */
+ xim_getScreen (xim, 1, &sx, &sy, &width, &height, &depth);
+
+ /* Compute the new scale factor required to scale the source to the
+ * destination at magnification 1.0.
+ */
+ if (autoscale) {
+ xzoom = (float)width / (float)nx;
+ yzoom = (float)height / (float)ny;
+ zoom = min (xzoom, yzoom);
+ } else {
+ xzoom = 1.0;
+ yzoom = 1.0;
+ zoom = 1.0;
+ }
+
+ /* Set the new mapping. */
+ fb->xmag = fb->ymag = zoom;
+ fb->xcen = xim->width / 2;
+ fb->ycen = xim->height / 2;
+
+ /* Zoom it to fill the display window. */
+ xim_setZoom (xim, fb, frame, fb->zoommap, fb->raster, fb->zoomras,
+ fb->xcen, fb->ycen, fb->xmag, fb->ymag,
+ fb->xoff, fb->yoff, True);
+
+ /* Check if the named colortable is already defined. If not, add
+ * another one. If ncolors=0 omit the colortable handling, e.g.
+ * when loading a raster that doesn't have a colormap.
+ */
+ if (ncolors > 0) {
+ for (i=0, cm=NULL; i < ncolormaps; i++)
+ if (strcmp (colormaps[i].name, mapname) == 0) {
+ cm = &colormaps[i];
+ break;
+ }
+ if (!cm) {
+ if (ncolormaps >= MAX_COLORMAPS - 1)
+ cm = &colormaps[ncolormaps];
+ else {
+ cm = &colormaps[ncolormaps++];
+ cm->mapno = GtNextColormap (gt);
+ }
+ strcpy (cm->name, mapname);
+ ncolormaps = min (MAX_COLORMAPS-1, ncolormaps);
+
+ /* Pass the list of colortables on to the user interface. */
+ xim_colortables (xim);
+ }
+
+ for (i=0; i < ncolors; i++) {
+ rs[i] = (r[i] << 8);
+ gs[i] = (g[i] << 8);
+ bs[i] = (b[i] << 8);
+ }
+
+ if (DBG_RASTER)
+ fprintf (stderr,"raster writeDisplay: writing colormap.......");
+ GtWriteColormap (gt, cm->mapno,
+ FIRST_COLOR, min(ncolors,xim->ncolors), rs, gs, bs);
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "raster writeDisplay: writing colormap.......DONE");
+
+ fb->offset = 0.5;
+ fb->scale = (xim->invert ? -1.0 : 1.0);
+ fb->colormap = cm->mapno;
+ } else
+ cm = &colormaps[fb->colormap-1];
+
+ /* Display the frame. */
+ GtEnableMapping (gt, fb->dispmap, 1);
+ GtSetDisplayRaster (gt, xim->display_frame);
+ xim_setDisplayFrame (xim, frame);
+
+ GtSetColormapFocus (-1); /* force full update */
+ GtLoadColormap (gt, cm->mapno, fb->offset, fb->scale);
+ GtSetColormapFocus (xim->cm_focus);
+ xim_enhancement (xim, fb);
+
+ GtWriteIomap (gt, sv_iomap, 0, MAX_COLORS);
+
+ if (DBG_RASTER)
+ fprintf (stderr, "raster writeDisplay: ......................DONE");
+ return (0);
+}
+
+
+/* XIM_MESSAGE -- Send a message to the user interface.
+ */
+void
+xim_message (xim, object, message)
+register XimDataPtr xim;
+char *object;
+char *message;
+{
+ char msgbuf[SZ_MSGBUF];
+
+ sprintf (msgbuf, "setValue {%s}", message);
+ ObmDeliverMsg (xim->obm, object, msgbuf);
+}
+
+
+/* XIM_MSGI -- Like xim_message, but the message is an integer value.
+ */
+void
+xim_msgi (xim, object, value)
+register XimDataPtr xim;
+char *object;
+int value;
+{
+ char msgbuf[SZ_LINE];
+ sprintf (msgbuf, "setValue {%d}", value);
+ ObmDeliverMsg (xim->obm, object, msgbuf);
+}
+
+
+/* XIM_ALERT -- Issue an alert to the server. The message text input will
+ * be displayed and either the ok (proceed) or cancel action will be taken,
+ * causing the action text input to be sent back to the client to be
+ * executed as a command. This is used to alert the server (i.e. user) of
+ * unusual circumstances and determine whether or not the server wants to
+ * proceed. An alert with no actions is a warning.
+ */
+void
+xim_alert (xim, text, ok_action, cancel_action)
+register XimDataPtr xim;
+char *text; /* message text */
+char *ok_action; /* command sent back to client for "ok" */
+char *cancel_action; /* command sent back to client for "cancel" */
+{
+ char msgbuf[SZ_LINE];
+ sprintf (msgbuf, "setValue {{%s} {%s} {%s}}", text,
+ ok_action ? ok_action : "", cancel_action ? cancel_action : "");
+ ObmDeliverMsg (xim->obm, "alert", msgbuf);
+}
+
+
+/*
+ * Internal Routines.
+ * -------------------
+ */
+
+/* XIM_FRAMEREGION -- Called when the value of the frameRegion UI parameter
+ * needs to be updated.
+ */
+static void
+xim_frameRegion (xim, fb)
+register XimDataPtr xim;
+register FrameBufPtr fb;
+{
+ int rop, src, dst;
+ int st, sx, sy, snx, sny;
+ int dt, dx, dy, dnx, dny;
+ char buf[SZ_LINE];
+
+ if (GtGetMapping (xim->gt, fb->zoommap, &rop,
+ &src, &st, &sx, &sy, &snx, &sny,
+ &dst, &dt, &dx, &dy, &dnx, &dny) == -1)
+ return;
+
+ /* args: frame x y width height */
+ sprintf (buf, "%d %d %d %d %d", fb->frameno, sx, sy, snx, sny);
+ xim_message (xim, "frameRegion", buf);
+}
+
+
+/* XIM_COLORTABLES -- Called when the "colortables" UI parameter needs to be
+ * updated, i.e., when some change to the list of colormaps has occurred.
+ */
+static void
+xim_colortables (xim)
+XimDataPtr xim;
+{
+ register char *ip, *op;
+ char buf[MAX_COLORMAPS*40];
+ int i;
+
+ for (i=0, op=buf; i < ncolormaps; i++) {
+ *op++ = '"';
+ for (ip = colormaps[i].name; *op = *ip++; op++)
+ ;
+ *op++ = '"';
+ *op++ = '\n';
+ }
+ *op++ = '\0';
+
+ xim_message (xim, "colortables", buf);
+}
+
+
+/* XIM_ENHANCEMENT -- Called when the "enhancement" UI parameter needs to
+ * be updated for a frame.
+ */
+xim_enhancement (xim, fb)
+register XimDataPtr xim;
+register FrameBufPtr fb;
+{
+ char buf[SZ_LINE];
+
+ sprintf (buf, "%d \"%s\" %0.3f %0.3f", fb->frameno,
+ colormaps[fb->colormap-1].name, fb->offset, fb->scale);
+ xim_message (xim, "enhancement", buf);
+
+
+ /* Force an update of the colorbar. On TrueColor visuals this
+ ** is required since the colormap doesn't automatically update
+ ** the display.
+ */
+ set_colorbar (xim, xim->cb);
+}
+
+
+/* GET_FBCONFIG -- Read the XIMTOOL startup file to get the set of possible
+ * frame buffer sizes.
+ *
+ * File format: configno nframes width height [extra fields]
+ * e.g., 1 2 512 512
+ * 2 2 800 800
+ * 3 1 1024 1024 # comment
+ */
+static void
+get_fbconfig (xim)
+register XimDataPtr xim;
+{
+ register char *ip;
+ register FILE *fp = NULL;
+ int config, nframes, width, height, i;
+ char lbuf[SZ_LINE+1], *fname;
+ static char *fb_paths[] = {
+ "/usr/local/lib/imtoolrc",
+ "/opt/local/lib/imtoolrc",
+ "/iraf/iraf/dev/imtoolrc",
+ "/local/lib/imtoolrc",
+ "/usr/iraf/dev/imtoolrc",
+ "/usr/local/iraf/dev/imtoolrc",
+ NULL};
+
+ /* Initialize the config table. */
+ xim->fb_configno = 1;
+ for (i=0; i < MAX_FBCONFIG; i++) {
+ xim->fb_config[i].nframes = 1;
+ xim->fb_config[i].width = DEF_FRAME_WIDTH;
+ xim->fb_config[i].height = DEF_FRAME_HEIGHT;
+ }
+
+ /* Now add in some defaults for commonly used sizes based on the
+ * standard IRAF imtoolrc file, we'll avoid any instrument specific
+ * configurations.
+ */
+ xim->fb_config[0].width = xim->fb_config[0].height = 512;
+ xim->fb_config[1].width = xim->fb_config[1].height = 800;
+ xim->fb_config[2].width = xim->fb_config[2].height = 1024;
+ xim->fb_config[3].width = xim->fb_config[3].height = 1600;
+ xim->fb_config[4].width = xim->fb_config[4].height = 2048;
+ xim->fb_config[5].width = xim->fb_config[5].height = 4096;
+
+ /* Attempt to open the config file. */
+ if ((fname=getenv(FBCONFIG_ENV1)) || (fname=getenv(FBCONFIG_ENV2)))
+ fp = fopen (fname, "r");
+ if (!fp && (fname = getenv ("HOME"))) {
+ sprintf (lbuf, "%s/%s", fname, FBCONFIG_1);
+ fp = fopen (fname = lbuf, "r");
+ if (fp) {
+ xim->imtoolrc = (char *) XtCalloc (SZ_LINE, sizeof(char));
+ strncpy (xim->imtoolrc, fname, strlen(fname));
+ }
+ }
+ if (!fp)
+ fp = fopen (fname = xim->imtoolrc, "r");
+ for (i=0; !fp && fb_paths[i]; i++) {
+ if ((fp = fopen (fname = fb_paths[i], "r"))) {
+ xim->imtoolrc = XtCalloc(strlen(fb_paths[i]+1),sizeof(char));
+ strncpy (xim->imtoolrc, fb_paths[i],strlen(fb_paths[i]));
+ break;
+ }
+ }
+ if (!fp) {
+ fprintf (stderr,
+ "Warning: No frame buffer configuration file found.\n");
+ return;
+ }
+
+
+ /* Scan the frame buffer configuration file.
+ */
+ while (fgets (lbuf, SZ_LINE, fp) != NULL) {
+ /* Skip comment lines and blank lines. */
+ for (ip=lbuf; *ip == ' ' || *ip == '\t'; ip++)
+ ;
+ if (*ip == '\n' || *ip == '#')
+ continue;
+ if (!isdigit (*ip))
+ continue;
+ switch (sscanf (ip, "%d%d%d%d", &config,&nframes,&width,&height)) {
+ case 4:
+ break; /* normal case */
+ case 3:
+ height = width; /* default to square format */
+ break;
+ default:
+ fprintf (stderr, "ximtool: bad config `%s'\n", ip);
+ continue;
+ }
+
+ nframes = max (1, nframes);
+ width = max (1, width);
+ height = max (1, height);
+
+ /* Since the frame buffer is stored in a memory pixrect
+ * (effectively), the line length should be an integral number
+ * of 16 bit words.
+ */
+ if (width & 1) {
+ fprintf (stderr, "imtool warning: fb config %d [%d-%dx%d] - ",
+ config, nframes, width, height);
+ fprintf (stderr, "frame width should be even, reset to %d\n",
+ --width);
+ }
+
+ config = max(1, min(MAX_FBCONFIG, config)) - 1;
+ xim->fb_config[config].nframes = nframes;
+ xim->fb_config[config].width = width;
+ xim->fb_config[config].height = height;
+ }
+
+ if (fp) fclose (fp);
+}
+
+
+/* XIM_GETANTIALIAS -- Convert a antialias algorithm expressed as a string
+ * into a Gterm rasterop code.
+ */
+xim_getAntialias (xim, s)
+XimDataPtr xim;
+char *s;
+{
+ register char *ip, *op;
+ char word[SZ_NAME];
+ int rop = 0;
+
+ for (ip=s; *ip && isspace(*ip); ip++)
+ ;
+
+ while (*ip) {
+ for (op=word; *ip && isalnum(*ip); ip++)
+ *op++ = isupper(*ip) ? tolower(*ip) : *ip;
+ *op++ = '\0';
+
+ if (strcmp (word, "nearest") == 0)
+ rop |= MF_NEAREST;
+ else if (strcmp (word, "bilinear") == 0)
+ rop |= MF_BILINEAR;
+ else if (strcmp (word, "area") == 0)
+ rop |= MF_AREA;
+ else if (strcmp (word, "blkavg") == 0)
+ rop |= MF_BLKAVG;
+ else if (strcmp (word, "boxcar") == 0)
+ rop |= MF_BOXCAR;
+ else if (strcmp (word, "lowpass") == 0)
+ rop |= MF_LOWPASS;
+ else if (strcmp (word, "gaussian") == 0)
+ rop |= MF_GAUSSIAN;
+
+ while (*ip && !isalnum(*ip))
+ ip++;
+ }
+
+ return (rop);
+}
+
+
+/* XIM_SETCOLORMAP -- Set up the RGB lookup tables used to map the windowed
+ * monochrome output of a frame buffer into the hardware colormap.
+ */
+xim_setColormap (function, dirs, m_red, m_green, m_blue, nelem)
+char *function; /* type of colormap */
+String *dirs;
+unsigned short *m_red;
+unsigned short *m_green;
+unsigned short *m_blue;
+int nelem;
+{
+ register int i, j;
+ register char *ip, *op;
+ static int seed = 0;
+ int v, vsat, step;
+ int knot[7];
+ float frac;
+
+
+ if (DBG_RASTER)
+ fprintf (stderr,
+ "xim_setColormap: name='%s' nelem=%d\n", function, nelem);
+
+ vsat = MAX_COLORS - 1;
+ step = MAX_COLORS / 6;
+ for (i=0; i < 7; i++)
+ knot[i] = i * step;
+ knot[6] = vsat;
+
+ if (dirs) {
+ /* Load the colormap from a file. */
+ char fname[SZ_FNAME];
+ char lbuf[SZ_LINE];
+ TripletPtr p;
+ Lut user;
+ FILE *fp;
+
+ /* Get full file pathname. If the same file is found in multiple
+ * directories the first version found is used.
+ */
+ strcpy (fname, function);
+ for (i=0; function[0] != '/' && dirs[i]; i++) {
+ for (ip=dirs[i], op=fname; *ip; )
+ *op++ = *ip++;
+ if (op > fname && *(op-1) != '/')
+ *op++ = '/';
+ for (ip=function; *ip; )
+ *op++ = *ip++;
+ *op = '\0';
+ if (access (fname, 0) == 0)
+ break;
+ }
+
+ /* Try to open the file. */
+ if ((fp = fopen (fname, "r")) == NULL) {
+ fprintf (stderr, "cannot open %s\n", fname);
+ return (ERR);
+ }
+
+ /* Scan the file. The user colormap may have any number of
+ * RGB pairs up to a maximum of MAX_COLORS (256).
+ */
+ user.lutlen = 0;
+ while (fgets (lbuf, SZ_LINE, fp)) {
+ char *np, *next;
+ float v[3];
+
+ /* Ignore blank lines and comment lines. */
+ for (ip=lbuf; isspace(*ip); ip++)
+ ;
+ if (*ip == '\0' || *ip == '#')
+ continue;
+ if (user.lutlen+1 >= MAX_COLORS)
+ break;
+
+ /* Get an RGB entry. */
+ p = &user.hue[user.lutlen++];
+ for (i=0, np=ip; i < 3; i++, np=next) {
+ v[i] = strtod (np, &next);
+ if (next == np) {
+ fclose (fp);
+ return (ERR);
+ }
+ }
+
+ p->red = v[0];
+ p->green = v[1];
+ p->blue = v[2];
+ }
+
+ fclose (fp);
+ if (user.lutlen <= 0)
+ return (ERR);
+
+ /* Scale the user colormap to fit the NELEMS colors required
+ * for the output colormap. nelem and lutlen must be the same
+ * to disable scaling and preserve the exact colortable values.
+ */
+ for (i=0; i < nelem; i++) {
+ float x, w1, w2;
+ float r, g, b;
+
+ x = (float)i / (float)(nelem - 1) * (user.lutlen - 1);
+ j = max(0, min(user.lutlen-1, (int)x));
+ w1 = 1.0 - (x - j);
+ w2 = 1.0 - w1;
+
+ r = user.hue[j].red;
+ g = user.hue[j].green;
+ b = user.hue[j].blue;
+
+ if (w2 > 0.0001 && j+1 < user.lutlen) {
+ r = r * w1 + user.hue[j+1].red * w2;
+ g = g * w1 + user.hue[j+1].green * w2;
+ b = b * w1 + user.hue[j+1].blue * w2;
+ }
+
+ m_red[i] = r * vsat;
+ m_green[i] = g * vsat;
+ m_blue[i] = b * vsat;
+ }
+
+ } else if (strncmp (function, "Grayscale", 9) == 0) {
+ for (i=0; i < nelem; i++)
+ m_red[i] = m_green[i] = m_blue[i] =
+ (float)i / (float)(nelem - 1) * vsat;
+
+ } else if (strncmp (function, "HSV", 3) == 0) {
+ /* HSV: hue varies uniformly from 270 to 360 and back to 270.
+ * Value varies from zero to one using a cube root relation
+ * which causes the value to approach 1.0 rapidly away from zero.
+ * Saturation is zero near the endpoints, causing the curve
+ * to range from black to white at the endpoints, but ranges
+ * to 1.0 at the halfway point, causing nearly saturated colors
+ * in the middle of the range.
+ */
+ for (i=0; i < nelem; i++) {
+ float h, s, v, r, g, b;
+ double pow(), sin();
+
+ frac = 1.0 - ((float)i / (float)(nelem - 1));
+ h = frac * 360.0 + 270.0;
+ s = abs (sin (frac * 3.1416));
+ v = pow ((1.0 - frac), (1.0 / 3.0));
+
+ hsv_to_rgb (h, s, v, &r, &g, &b);
+ m_red[i] = r * vsat;
+ m_green[i] = g * vsat;
+ m_blue[i] = b * vsat;
+ }
+
+ } else if (strncmp (function, "Heat", 4) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = heat.hue[j].red * vsat;
+ m_green[i] = heat.hue[j].green * vsat;
+ m_blue[i] = heat.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Ramp", 4) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = heat.hue[j].red * (frac * (vsat * 2));
+ m_green[i] = heat.hue[j].green * (frac * (vsat * 2));
+ m_blue[i] = heat.hue[j].blue * (frac * (vsat * 2));
+ }
+
+ } else if (strncmp (function, "AIPS0", 5) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = aips0.hue[j].red * vsat;
+ m_green[i] = aips0.hue[j].green * vsat;
+ m_blue[i] = aips0.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Color", 5) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = color.hue[j].red * vsat;
+ m_green[i] = color.hue[j].green * vsat;
+ m_blue[i] = color.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Staircase", 9) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = staircase.hue[j].red * vsat;
+ m_green[i] = staircase.hue[j].green * vsat;
+ m_blue[i] = staircase.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Standard", 8) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = standard.hue[j].red * vsat;
+ m_green[i] = standard.hue[j].green * vsat;
+ m_blue[i] = standard.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Red", 3) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = red.hue[j].red * vsat;
+ m_green[i] = red.hue[j].green * vsat;
+ m_blue[i] = red.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Green", 5) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = green.hue[j].red * vsat;
+ m_green[i] = green.hue[j].green * vsat;
+ m_blue[i] = green.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Blue", 4) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = blue.hue[j].red * vsat;
+ m_green[i] = blue.hue[j].green * vsat;
+ m_blue[i] = blue.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Halley", 6) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = halley.hue[j].red * vsat;
+ m_green[i] = halley.hue[j].green * vsat;
+ m_blue[i] = halley.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Rainbow1", 8) == 0) {
+ for (i=0; i < nelem; i++)
+ m_red[i] = m_green[i] = m_blue[i] = 0;
+
+ for (i=knot[0]; i <= knot[1]; i++)
+ m_blue[i] = vsat * (i - knot[0]) / step;
+ for (i=knot[1]; i <= knot[2]; i++)
+ m_blue[i] = vsat;
+ for (i=knot[2]; i <= knot[3]; i++)
+ m_blue[i] = vsat * (knot[3] - i) / step;
+
+ for (i=knot[1]; i <= knot[2]; i++)
+ m_green[i] = vsat * (i - knot[1]) / step;
+ for (i=knot[2]; i <= knot[4]; i++)
+ m_green[i] = vsat;
+ for (i=knot[4]; i <= knot[5]; i++)
+ m_green[i] = vsat * (knot[5] - i) / step;
+
+ for (i=knot[3]; i <= knot[4]; i++)
+ m_red[i] = vsat * (i - knot[3]) / step;
+ for (i=knot[4]; i <= knot[6]; i++)
+ m_red[i] = vsat;
+
+ for (i=knot[5]; i <= knot[6]; i++) {
+ if ((v = vsat * (i - knot[5]) / step) > vsat)
+ v = vsat;
+ m_green[i] = m_blue[i] = v;
+ }
+
+ } else if (strncmp (function, "Rainbow2", 8) == 0) {
+ for (i=0; i < nelem; i++) {
+ frac = (float)i / (float)(nelem - 1);
+ j = frac * (heat.lutlen - 1);
+ m_red[i] = rainbow.hue[j].red * vsat;
+ m_green[i] = rainbow.hue[j].green * vsat;
+ m_blue[i] = rainbow.hue[j].blue * vsat;
+ }
+
+ } else if (strncmp (function, "Random16", 8) == 0) {
+ int red, green, blue;
+
+ if (!seed)
+ seed = time(0);
+ srand (seed++);
+
+ for (i=0; i < nelem; ) {
+ red = ((rand() >> 4) % vsat);
+ green = ((rand() >> 4) % vsat);
+ blue = ((rand() >> 4) % vsat);
+
+ for (j=0; i < nelem && j < nelem/16; j++, i++) {
+ m_red[i] = red;
+ m_green[i] = green;
+ m_blue[i] = blue;
+ }
+ }
+
+ } else if (strncmp (function, "Random8", 7) == 0) {
+ int red, green, blue;
+
+ if (!seed)
+ seed = time(0);
+ srand (seed++);
+
+ for (i=0; i < nelem; ) {
+ red = ((rand() >> 4) % vsat);
+ green = ((rand() >> 4) % vsat);
+ blue = ((rand() >> 4) % vsat);
+
+ for (j=0; i < nelem && j < nelem/8; j++, i++) {
+ m_red[i] = red;
+ m_green[i] = green;
+ m_blue[i] = blue;
+ }
+ }
+
+ } else if (strncmp (function, "Random", 6) == 0) {
+ if (!seed)
+ seed = time(0);
+ srand (seed++);
+ for (i=0; i < nelem; i++) {
+ m_red[i] = ((rand() >> 4) % vsat);
+ m_green[i] = ((rand() >> 4) % vsat);
+ m_blue[i] = ((rand() >> 4) % vsat);
+ }
+ }
+
+ /* Scale colormap values to 16 bits. */
+ for (i=0; i < nelem; i++) {
+ m_red[i] <<= 8;
+ m_green[i] <<= 8;
+ m_blue[i] <<= 8;
+ }
+
+ return (OK);
+}
+
+
+hsv_to_rgb (h, s, v, r, g, b)
+float h, s, v;
+float *r, *g, *b;
+{
+ register int i;
+ float f, p, q, t;
+
+ while (h >= 360.0)
+ h -= 360.0;
+
+ h /= 60.0;
+ i = (int) h;
+ f = h - i;
+ p = v * (1 - s);
+ q = v * (1 - s*f);
+ t = v * (1 - s * (1.0 - f));
+
+ switch (i) {
+ case 0:
+ *r = v; *g = t; *b = p;
+ break;
+ case 1:
+ *r = q; *g = v; *b = p;
+ break;
+ case 2:
+ *r = p; *g = v; *b = t;
+ break;
+ case 3:
+ *r = p; *g = q; *b = v;
+ break;
+ case 4:
+ *r = t; *g = p; *b = v;
+ break;
+ case 5:
+ *r = v; *g = p; *b = q;
+ break;
+ }
+}
+
+
+/* GET_DIRFILE -- Get the next file name from an open directory file.
+ */
+static int
+get_dirfile (dir, outstr, maxch)
+DIR *dir;
+char *outstr;
+int maxch;
+{
+ register int n;
+ register struct dirent *dp;
+ register char *ip, *op;
+ int status;
+
+ for (dp = readdir(dir); dp != NULL; dp = readdir(dir))
+ if (dp->d_ino != 0) {
+ n = strlen (dp->d_name);
+ status = n;
+ for (ip=dp->d_name, op=outstr; --n >= 0; )
+ *op++ = *ip++;
+ *op = EOS;
+ return (status);
+ }
+
+ return (EOF);
+}
+
+
+/* LOAD_TESTPATTERN -- Load a test pattern into the given frame.
+ */
+static void
+load_testpattern (xim, frame, type)
+XimDataPtr xim;
+int frame;
+int type; /* not used */
+{
+ register FrameBufPtr fb = &xim->frames[frame];
+ register int i, j, ncolors;
+ int rtype, width, height, depth;
+ unsigned char *data;
+
+ if (GtQueryRaster (xim->gt, fb->raster,
+ &rtype, &width, &height, &depth) == 0)
+ return;
+
+ data = (unsigned char *) XtMalloc (width);
+ if (data == (unsigned char *)NULL)
+ return;
+
+ ncolors = xim->ncolors;
+ for (j=0; j < height; j++) {
+ for (i=0; i < width; i++)
+ data[i] = (((i + j) * 10) % ncolors);
+ GtWritePixels (xim->gt, fb->raster, data, 8, 0, j, width, 1);
+ }
+
+ XtFree ((char *)data);
+}
+
+
+/* SET_COLORBAR -- Write the colorbar pixels.
+ */
+static void
+set_colorbar (xim, w)
+XimDataPtr xim;
+Widget w;
+{
+ register int i;
+ static int initialized = 0;
+ int first, ngray, rgb_len, rtype, width, height, depth;
+ unsigned short m_red[MAX_COLORS];
+ unsigned short m_green[MAX_COLORS];
+ unsigned short m_blue[MAX_COLORS];
+ unsigned char *data;
+
+
+ if (!w)
+ return;
+
+ if (DBG_RASTER)
+ fprintf (stderr, "SETTING COLORBAR PIXELS...... init = %d\n",
+ initialized);
+
+ if (GtQueryRaster (w, 0, &rtype, &width, &height, &depth) == 0)
+ return;
+
+ data = (unsigned char *) XtMalloc (width * height);
+ for (i=0; i < width; i++)
+ data[i] = ((float)i / (float)(width - 1) * (xim->ncolors - 1));
+
+ for (i=1; i < height; i++)
+ memmove (data + i * width, data, width);
+
+ if (!initialized) {
+ xim_iiscolormap (w, m_red,m_green,m_blue, &first, &ngray, &rgb_len);
+ GtWriteColormap (w, 0, first, rgb_len, m_red, m_green, m_blue);
+
+ xim_setColormap ("Grayscale", NULL, m_red, m_green, m_blue, ngray);
+ GtWriteColormap (w, 0, first, ngray, m_red, m_green, m_blue);
+
+ xim->ncolors = ngray;
+ initialized++;
+ }
+
+ GtWritePixels (w, 0, data, 8, 0, 0, width, height);
+ XtFree ((char *)data);
+
+ if (DBG_RASTER)
+ fprintf (stderr, "SETTING COLORBAR PIXELS...... DONE\n");
+}
+
+
+/* SET_NFRAMES -- Called when the number of frame buffers changes.
+ */
+static void
+set_nframes (xim, nframes)
+XimDataPtr xim;
+int nframes;
+{
+ xim->nframes = nframes;
+ xim_msgi (xim, "nframes", nframes);
+}