#include #include #include #include #include #include #include #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); }