aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/obm/ObmW/GtermMapping.c
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /vendor/x11iraf/obm/ObmW/GtermMapping.c
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'vendor/x11iraf/obm/ObmW/GtermMapping.c')
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermMapping.c2189
1 files changed, 2189 insertions, 0 deletions
diff --git a/vendor/x11iraf/obm/ObmW/GtermMapping.c b/vendor/x11iraf/obm/ObmW/GtermMapping.c
new file mode 100644
index 00000000..21e4760d
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermMapping.c
@@ -0,0 +1,2189 @@
+
+
+
+/* refresh_source -- Refresh a portion of a mapping given the source rect
+ * to be refreshed. If the given source rect is not within the mapping,
+ * this is a no-op.
+ */
+static
+refresh_source (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ register Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of source to be refreshed */
+{
+ int sx1, sx2, sy1, sy2, snx, sny;
+ int dx1, dx2, dy1, dy2, dnx, dny;
+ int valid;
+
+
+ /* Do nothing if mapping not defined and enabled.
+ */
+ if (!(valid = valid_mapping (w, mp))) {
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_source: valid=%d\n", valid);
+ return (ERR);
+ }
+ if (!mp->enabled) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR ref_src: mapping %d not enabled\n",
+ mp->mapping);
+ return (OK);
+ }
+
+ /* Compute the intersection of the modified region of the source raster
+ ** with the rectangular region of the source raster affected by the given
+ ** mapping.
+ */
+ sx1 = max (x1, mp->sx);
+ sy1 = max (y1, mp->sy);
+ sx2 = min(x1 + nx, mp->sx + mp->snx) - 1;
+ sy2 = min(y1 + ny, mp->sy + mp->sny) - 1;
+ snx = sx2 - sx1 + 1;
+ sny = sy2 - sy1 + 1;
+
+ /* Do nothing if the rectangles do not intersect.
+ */
+ if (snx <= 0 || sny <= 0)
+ return (OK);
+
+ /* Compute the destination rect affected by the mapped source rect.
+ */
+ dx1 = mp->x_extent[sx1 - mp->sx].lo;
+ dx2 = mp->x_extent[sx2 - mp->sx].hi;
+ if (dx1 > dx2) {
+ dx1 = mp->x_extent[sx2 - mp->sx].lo;
+ dx2 = mp->x_extent[sx1 - mp->sx].hi;
+ }
+
+ dy1 = mp->y_extent[sy1 - mp->sy].lo;
+ dy2 = mp->y_extent[sy2 - mp->sy].hi;
+ if (dy1 > dy2) {
+ dy1 = mp->y_extent[sy2 - mp->sy].lo;
+ dy2 = mp->y_extent[sy1 - mp->sy].hi;
+ }
+
+ dnx = dx2 - dx1 + 1;
+ dny = dy2 - dy1 + 1;
+
+ if (CacheXImage) /* MF004 */
+ DestroyCachedXImage(); /* MF004 */
+
+ if (DBG_TRACE) {
+ fprintf(stderr, "refresh_source -- refreshing src (%d,%d) (%d,%d)\n",
+ sx1, sy1, snx, sny);
+ fprintf(stderr, "refresh_source -- refreshing dest (%d,%d) (%d,%d)\n",
+ dx1, dy1, dnx, dny);
+ dbg_printMappings (w);
+ }
+
+ /* Perform the refresh operation. */
+ return (refresh_destination (w, mp, dx1, dy1, dnx, dny));
+}
+
+
+/* refresh_destination -- Refresh (redraw) the pixels in the given destination
+ * rect. The mapping operand defines how to generate the value of each output
+ * pixel. This is the routine which does all the real work of a mapping,
+ * computing the values of the output pixels and writing to the destination
+ * drawable. Note: the destination rect must be specified in raster pixel
+ * coordinates (no NDC).
+ */
+static
+refresh_destination (w, mp, x1, y1, nx, ny)
+ GtermWidget w;
+ Mapping mp; /* mapping defining refresh operation */
+ int x1, y1, nx, ny; /* region of destination to be refreshed */
+{
+ Raster sr, dr, pr;
+ Display *display = w->gterm.display;
+ int scaling, xflip, yflip, delxin=0, delxout=0;
+ int ox, oy, rop, clip, mapping, i, j;
+ int src, st, sx, sy, snx, sny;
+ int dst, dt, dx, dy, dnx, dny;
+ int xoff, yoff, p1, p2, q1, q2;
+ float xscale, yscale;
+ struct mapping *np, p_mp;
+ XImage *xin, *xout;
+ int status = OK;
+ Pixmap pixmap; /* MF004 */
+
+ Region clip_region, mask_region;
+ uchar *old_xin_lp, *old_xout_lp;
+ uchar *xin_lp, *xout_lp, *op;
+ int xin_bpl, xout_bpl;
+ int *xmap, *ymap, valid;
+ XRectangle r;
+ XImage *img1 = (XImage *) NULL,
+ *img2 = (XImage *) NULL,
+ *img3 = (XImage *) NULL,
+ *img4 = (XImage *) NULL,
+ *img5 = (XImage *) NULL;
+
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "refresh_destination ENTER[0x%x]: pos=%d,%d sz=%d,%d\n",
+ w, x1,y1,nx,ny);
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Do nothing if mapping not defined and enabled. */
+ if (!(valid = valid_mapping (w, mp))) {
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: valid=%d\n", valid);
+ return (ERR);
+ }
+ if (!mp->enabled) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR ref_dst: mapping %d not enabled\n",
+ mp->mapping);
+ return (OK);
+ }
+
+
+ if (DBG_CMAPS && DBG_CM_VERB)
+ dbg_printCmaps (w);
+ if (DBG_TRACE)
+ dbg_printRasters (w);
+
+
+ /* Offsets into the x_*,y_* mapping lookup tables. */
+ xoff = x1 - mp->dx;
+ yoff = y1 - mp->dy;
+
+ /* Get source and destination rects. */
+ dst = mp->dst;
+ dx = x1; dy = y1;
+ dnx = nx; dny = ny;
+
+ src = mp->src;
+ p1 = mp->x_srcpix[xoff];
+ q1 = mp->y_srcpix[yoff];
+ p2 = mp->x_srcpix[xoff + nx - 1];
+ q2 = mp->y_srcpix[yoff + ny - 1];
+ sx = min (p1, p2);
+ sy = min (q1, q2);
+ snx = abs (p2 - p1) + 1;
+ sny = abs (q2 - q1) + 1;
+
+ /* Define some local variables. */
+ sr = &w->gterm.rasters[src];
+ dr = &w->gterm.rasters[dst];
+ pr = &w->gterm.rasters[0]; /* display pixmap raster */
+ mapping = mp->mapping;
+ scaling = mp->scaling;
+ xscale = mp->xscale;
+ yscale = mp->yscale;
+ rop = mp->rop;
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "refresh_destination: src,dst = %d,%d st,dt = %s[%d],%s[%d]\n",
+ src, dst,
+ (sr->type == 1 ? "image" : "pixmap"), sr->depth,
+ (dr->type == 1 ? "image" : "pixmap"), dr->depth);
+ fprintf (stderr,
+ "refresh: gterm.pixmap=0x%x src.pixmap=0x%x dest.pixmap=0x%x\n",
+ w->gterm.pixmap, sr->r.pixmap, dr->r.pixmap);
+ fprintf (stderr,
+ "refresh: gterm.pixmap=0x%x src.ximage=0x%x dest.ximage=0x%x\n",
+ w->gterm.pixmap, sr->r.ximage, dr->r.ximage);
+ fprintf (stderr,
+ "refresh_destination: src=>(%d,%d : %d,%d) dst=>(%d,%d : %d,%d)\n",
+ sx, sy, snx, sny, dx, dy, dnx, dny);
+ }
+
+
+ /* Basic error checking.
+ */
+ if (!sr->type || !dr->type) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR: invalid src or dest type\n");
+ return (ERR);
+
+ } else if (snx <= 0 || sny <= 0 || dnx == 0 || dny == 0) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR: negative src position or zero size\n");
+ return (ERR);
+
+ } else if (src < 0 || src > w->gterm.maxRasters ||
+ dst < 0 || dst > w->gterm.maxRasters) {
+ if (DBG_TRACE)
+ fprintf (stderr, "ERROR: invalid src or dest value\n");
+ return (ERR);
+ }
+
+
+ /* Do we have a flip in X or Y? */
+ xflip = mp->dnx < 0;
+ yflip = mp->dny < 0;
+
+ /* Any higher numbered mappings which map to the same destination as the
+ * mapping MP will obscure the current mapping. Construct a clip mask
+ * defining the region of the destination we can write to. This will be
+ * the region not obscured by any higher numbered, active mappings.
+ */
+ clip = False;
+ clip_region = XCreateRegion();
+ r.x = dx;
+ r.y = dy;
+ r.width = dnx;
+ r.height = dny;
+#ifdef sun
+ /* As far as I can tell the Sun (probably in the OW X server) has an
+ * off by one bug affecting clipping in the server. A clip region is
+ * too small by one pixel at the right and bottom, causing these pixels
+ * to not be written when refreshing the screen (usually this shows up
+ * as black lines on the screen when a region is refreshed). So far
+ * I haven't seen this on any other platform. The problem is imperfectly
+ * understood and the following workaround may not completely workaround
+ * the problem.
+ */
+ r.width++; r.height++;
+#endif
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ for (np = mp->next; np; np = np->next) {
+ struct mapping p_np;
+
+ if (!np->enabled || np->dst != dst)
+ continue;
+ get_pixel_mapping (w, np, &p_np, 0);
+
+ r.x = p_np.dx; r.y = p_np.dy;
+ r.width = abs(p_np.dnx);
+ r.height = abs(p_np.dny);
+
+ if (XRectInRegion (clip_region,
+ r.x, r.y, r.width, r.height) != RectangleOut) {
+
+ mask_region = XCreateRegion();
+ XUnionRectWithRegion (&r, mask_region, mask_region);
+ XSubtractRegion (clip_region, mask_region, clip_region);
+ XDestroyRegion (mask_region);
+ clip++;
+ }
+ }
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: xflip=%d yflip=%d clip=%d scaling=%d\n",
+ xflip, yflip, clip, scaling);
+
+ if (clip && dr->type == PixmapRaster)
+ XSetRegion (w->gterm.display, w->gterm.exposeGC, clip_region);
+
+
+ /* Handle the special case of a pixmap to pixmap (or window) copy in
+ * the server with no scaling.
+ */
+ if (!scaling && sr->type == PixmapRaster && dr->type == PixmapRaster) {
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: pixmap-to-pixmap copy %d <-> %d\n",
+ src, dst);
+
+ if (src == 0 && dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: pixmap copy src=dst=0\n");
+
+ XCopyArea (display,
+ w->gterm.pixmap, w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+
+ XCopyArea (display,
+ GPMtoRPM(w, dr), dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+
+ /* Update the root display shadow pixmap.
+ */
+ XCopyArea (display,
+ pr->shadow_pixmap, pr->shadow_pixmap,
+ w->gterm.expose8GC, sx, sy, snx, sny, dx, dy);
+
+ } else {
+ Raster rp = &w->gterm.rasters[src-1];
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "refresh_destination: pixmap copy src || dst != 0\n");
+ fprintf (stderr, "src=%d dest=%d shadow=0x%x ximage=0x%x\n",
+ src, dst, dr->shadow_pixmap, rp->r.ximage);
+ dbg_printRasters (w);
+ fprintf (stderr,
+ "src=%d,%d %d %d dest=%d,%d %d %d (src=%d dst=%d)\n",
+ sx, sy, snx, sny, dx, dy, dnx, dny, src, dst);
+ }
+
+ XCopyArea (display,
+ RPMtoRPM(sr, dr), dr->r.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+
+
+ /* Update the shadow pixmap.
+ */
+ XCopyArea (display,
+ sr->shadow_pixmap, dr->shadow_pixmap,
+ w->gterm.expose8GC, sx, sy, snx, sny, dx, dy);
+
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient))
+ XCopyArea (display,
+ RPMtoGPM (sr, w), w->gterm.pixmap,
+ w->gterm.exposeGC, sx, sy, snx, sny, dx, dy);
+ }
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: spec_case: pixmap copy no scaling\n");
+
+ goto done;
+ }
+
+ /* Any other case requires working on ximages in the client. The first
+ * step is to get the source ximage.
+ */
+ if (sr->type == PixmapRaster) {
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: source type is PixmapRaster[%d]\n", src);
+
+ /* Source is a pixmap but we need a local copy as either the
+ * destination is not a pixmap, or we need to do some scaling.
+ */
+ if (CacheXImage) { /* MF004 */
+ pixmap = (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap;
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: xin is cached XImage ");
+ fprintf (stderr, " src=%d pix=0x%x dims=%d,%d\n",
+ src, w->gterm.pixmap, sr->width, sr->height);
+ }
+
+ xin = GetCachedXImage (w, pixmap, sr->width, sr->height);
+ if (xin == NULL) {
+ xin = XGetImage (display, pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ } else
+ NewCachedXImage (w, xin, pixmap, sr->width, sr->height);
+ }
+
+ } else { /* MF004 */
+
+ /*
+ */
+ if (w->gterm.w_depth > ColormapDepth) {
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "src=%d dst=%d d_ras=%d %d x %d pr=0x%x sr=0x%x\n",
+ src, dst, w->gterm.d_raster, sr->width, sr->height,
+ pr->shadow_pixmap, sr->shadow_pixmap);
+ dbg_printRasters (w);
+ }
+
+ xin = XGetImage (display, sr->shadow_pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+
+ } else {
+ xin = XGetImage (display,
+ (src || !w->gterm.pixmap) ? sr->r.pixmap : w->gterm.pixmap,
+ 0, 0, sr->width, sr->height, 0xff, ZPixmap);
+ }
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: xin is drawable '%s'\n",
+ (src || !w->gterm.pixmap) ? "sr raster" : "gterm pixmap");
+ fprintf (stderr,
+ "refresh_destination: xin size=%d,%d bpp=%d bpl=%d\n",
+ xin->width, xin->height, xin->bits_per_pixel,
+ xin->bytes_per_line);
+ }
+
+ if (xin == NULL) {
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } /* MF004 */
+
+ } else {
+ /* Source is an ximage. */
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: src type is XImage (sr->r.ximage)\n");
+
+ xin = sr->r.ximage;
+ }
+
+ /* Handle the special case of a copy of an ximage to an output pixmap
+ * with no scaling.
+ */
+ if (!scaling && dr->type == PixmapRaster) {
+
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: NO scaling, dest=Pixmap\n");
+
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: dest == 0\n");
+
+ XPutImage (display,
+ w->gterm.pixmap, w->gterm.exposeGC,
+ (img1=IMGtoGPM(w,xin,sx,sy,dnx,dny)),
+ sx, sy, dx, dy, dnx, dny);
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "\n\nrefresh: gterm.pixmap=0x%x dest.pixmap=0x%x\n\n",
+ w->gterm.pixmap, dr->r.pixmap);
+
+ XCopyArea (display,
+ GPMtoRPM (w, dr), dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+
+ if (w->gterm.w_depth > ColormapDepth) {
+ XPutImage (display, pr->shadow_pixmap, w->gterm.expose8GC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ }
+
+ } else {
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: xin dst > 0\n");
+ fprintf (stderr,
+ "refresh_destination: src=(%d,%d) => %d,%d : %d,%d\n",
+ sx, sy, dx, dy, dnx, dny);
+ fprintf (stderr,
+ "refresh_destination: dr->shadow_pixmap = 0x%x\n",
+ dr->shadow_pixmap);
+ fprintf (stderr, "refresh_destination: xin => %d x %d x %d\n",
+ xin->width, xin->height, xin->depth);
+ }
+
+ /* Copy the 'xin' to the 'dr->r.pixmap'
+ */
+ XPutImage (display,
+ dr->r.pixmap, w->gterm.exposeGC,
+ (img2=IMGtoRPM(w,xin,dr,sx,sy,dnx,dny)),
+ sx, sy, dx, dy, dnx, dny);
+
+
+ if (w->gterm.w_depth > ColormapDepth) {
+ XPutImage (display, dr->r.pixmap, w->gterm.exposeGC,
+ (img3=IMGtoRPM(w,xin,dr,sx,sy,dnx,dny)),
+ sx, sy, dx, dy, dnx, dny);
+
+ /* Shadow the pixmap with an 8-bit version for readback.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "updating shadow_pixmap........................0x%x\n",
+ dr->shadow_pixmap);
+ XPutImage (display, dr->shadow_pixmap,
+ w->gterm.expose8GC, xin,
+ sx, sy, dx, dy, dnx, dny);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: NO scaling, dest=Pixmap -- DONE\n");
+
+ goto done;
+ }
+
+ /* Get output ximage.
+ */
+ if (dr->type == ImageRaster) {
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: dest type is XImage (dr->r.ximage)\n");
+
+ xout = dr->r.ximage;
+ ox = dx;
+ oy = dy;
+
+ } else {
+
+ uchar *data = (uchar *) XtCalloc (dnx * dny, sizeof(uchar));
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: dest type is Pixmap, create XImage\n");
+
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "refresh_destination: creating 8-bit ximage....%d x %d\n",
+ dnx, dny);
+
+ xout = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, dnx, dny, 8, 0);
+
+ if (xout == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ ox = 0;
+ oy = 0;
+ delxout++;
+ }
+
+ xin_lp = (uchar *)xin->data;
+ xout_lp = (uchar *)xout->data;
+ xin_bpl = xin->bytes_per_line;
+ xout_bpl = xout->bytes_per_line;
+
+ /* Map a region of the input ximage XIN to the output ximage XOUT. Various
+ * approaches are used to generate the output data, depending upon what
+ * type of scaling we are doing.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh: scaling=%d xin=0x%x xout=0x%x\n",
+ scaling, xin, xout);
+
+ if (!scaling) {
+ /* No scaling. Copy a region of the ximage xin to xout without
+ * spatially scaling the image data.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ xin_lp = (uchar *)xin->data + sy * xin_bpl + sx;
+ xout_lp = (uchar *)xout->data + oy * xout_bpl + ox;
+
+ for (j=0; j < dny; j++) {
+ memmove (xout_lp, xin_lp, dnx);
+ xin_lp += xin_bpl;
+ xout_lp += xout_bpl;
+ }
+
+ } else if (scaling == M_INTZOOM) {
+ /* Integer zoom. The zoom factor is an integer, allowing the zoomed
+ * image to be calculated without using the xmap,ymap lookup tables.
+ */
+ if (clip && dr->type == ImageRaster)
+ goto zoom;
+
+ scale_intzoom (xin_lp,xin_bpl, xout_lp,xout_bpl, sx,sy, ox,oy,dnx,dny,
+ xflip,yflip, (int)(xscale + 0.5), (int)(yscale + 0.5));
+
+ } else if (scaling == M_ZOOM) {
+ /* We have a zoom, or one-to-many, scaling. Zoom scaling is always
+ * done with pixel replication. The [xy]_srcpix arrays in the mapping
+ * descriptor give the source pixel corresponding to each mapped pixel
+ * in the destination raster.
+ */
+zoom:
+ xmap = &mp->x_srcpix[xoff];
+ ymap = &mp->y_srcpix[yoff];
+
+ scale_zoom (xin_lp, xin_bpl, xout_lp, xout_bpl,
+ xmap, ymap, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL);
+
+ } else if (scaling == M_DEZOOM) {
+ /* We have a dezoom, or many-to-one, scaling. A block of pixels in
+ * the input raster are combined to generate the value of each output
+ * pixel, using one of several antialias algorithms to compute the
+ * output pixel value.
+ */
+ float *x_src = &mp->x_src[xoff];
+ float *y_src = &mp->y_src[yoff];
+ int near_unitary = (xscale > 0.5 && yscale > 0.5);
+ int function;
+
+ /* Get the antialising function to be applied. */
+ if (!(function = (mp->rop & R_MFMask)))
+ function = MF_NEAREST;
+
+ /* If the dezoom factor is small and either MF_BILINEAR or
+ * MF_NEAREST is enabled, use the indicated method to sample the
+ * input data. This uses all the data but minimizes smoothing.
+ */
+ if ((function & (MF_BILINEAR|MF_NEAREST)) && near_unitary)
+ function = (function & MF_BILINEAR) ? MF_BILINEAR : MF_NEAREST;
+ else if (function != (function & (MF_BILINEAR|MF_NEAREST)))
+ function &= ~(MF_BILINEAR|MF_NEAREST);
+
+filter:
+ /* This can take a while so update the display. */
+ XFlush (w->gterm.display);
+
+ /* If the filtering operation involves any arithmetic combinations
+ * of pixels we must convert pixel numbers to pixel intensity values
+ * before performing the filtering operation. This is a case where
+ * we would be better off if frame buffers were maintained using
+ * pixel intensities rather than hardware pixel numbers.
+ */
+ if (function != MF_NEAREST) {
+ uchar *data = (uchar *) XtMalloc (xin->width * xin->height);
+ if (data == NULL) {
+ status = ERR;
+ goto done;
+ }
+
+ mf_getinten (w,
+ xin_lp, xin->width, xin->height, xin_bpl, sx,sy,
+ data, xin->width, xin->height, xin_bpl, sx,sy, snx,sny);
+
+ if (!delxin) {
+ xin = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, xin->width, xin->height, 8, 0);
+ if (xin == NULL) {
+ XtFree ((char *)data);
+ status = ERR;
+ goto done;
+ }
+ delxin++;
+ } else {
+ XtFree ((char *)xin->data);
+ xin->data = (char *) data;
+ }
+ xin_lp = (uchar *)xin->data;
+ }
+
+ /* Filter the source rect to the destination.
+ */
+ switch (function) {
+ case MF_NEAREST:
+ scale_nearest (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BILINEAR:
+ scale_bilinear (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src, y_src, ox, oy, dnx, dny,
+ (clip && dr->type == ImageRaster) ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BLKAVG:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 0, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_BOXCAR:
+ scale_boxcar (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, 1, clip ? clip_region : (Region)NULL
+ );
+ break;
+ case MF_LOWPASS:
+ scale_lowpass (
+ xin_lp, xin->width, xin->height, xin_bpl,
+ xout_lp, xout->width, xout->height, xout_bpl,
+ x_src,y_src, sx,sy,snx,sny, ox,oy,dnx,dny,
+ xscale,yscale, clip ? clip_region : (Region)NULL
+ );
+ break;
+ default:
+ function = MF_BILINEAR;
+ goto filter;
+ }
+
+ /* If the operation was performed in intensity space convert back
+ * to pixel number.
+ */
+ if (function != MF_NEAREST)
+ mf_getpixel (w,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy,
+ xout_lp, xout->width, xout->height, xout_bpl, ox,oy, dnx,dny);
+
+ } else {
+ status = ERR;
+ goto done;
+ }
+
+ /* Copy the scaled ximage to the output pixmap, if any.
+ */
+ if (dr->type == PixmapRaster) {
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: COPY TO OUTPUT PIXMAP\n");
+
+ if (dst == 0 && w->gterm.pixmap && !(rop & R_Transient)) {
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: dst=0\n");
+ fprintf (stderr,
+ "refresh_destination: src=(%d,%d) => %d,%d : %d,%d\n",
+ ox, oy, dx, dy, dnx, dny);
+ }
+
+ XPutImage (display,
+ w->gterm.pixmap, w->gterm.exposeGC,
+ (img4=IMGtoGPM(w,xout,ox,oy,dnx,dny)),
+ ox, oy, dx, dy, dnx, dny);
+
+ XCopyArea (display,
+ GPMtoRPM (w, dr), dr->r.pixmap,
+ w->gterm.exposeGC, dx, dy, dnx, dny, dx, dy);
+
+ if (w->gterm.w_depth > ColormapDepth) {
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "updating shadow_pixmap........................0x%x\n",
+ dr->shadow_pixmap);
+ fprintf (stderr,
+ "updating %d,%d to %d,%d %d %d\n",
+ ox, oy, dx, dy, dnx, dny);
+ }
+ XPutImage (display, dr->shadow_pixmap,
+ w->gterm.expose8GC, xout, ox, oy, dx, dy, dnx, dny);
+ }
+
+ } else {
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "refresh_destination: xout dst > 0\n");
+ fprintf (stderr,
+ "refresh_destination: src=(%d,%d) => %d,%d : %d,%d\n",
+ ox, oy, dx, dy, dnx, dny);
+ }
+
+ XPutImage (display,
+ dr->r.pixmap, w->gterm.exposeGC,
+ (img5=IMGtoRPM(w,xout,dr,ox,oy,dnx,dny)),
+ ox, oy, dx, dy, dnx, dny);
+
+ if (w->gterm.w_depth > ColormapDepth) {
+ /*
+ XPutImage (display, pr->r.pixmap, w->gterm.exposeGC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ */
+
+ /* Shadow the pixmap with an 8-bit version for readback.
+ */
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "updating shadow_pixmap........................0x%x\n",
+ dr->shadow_pixmap);
+ fprintf (stderr,
+ "updating %d,%d to %d,%d %d %d\n",
+ ox, oy, dx, dy, dnx, dny);
+ }
+ XPutImage (display, dr->shadow_pixmap,
+ w->gterm.expose8GC, xout,
+ ox, oy, dx, dy, dnx, dny);
+ }
+ }
+ }
+
+done:
+ /* Clean up.
+ */
+ if (delxin) XDestroyImage (xin);
+ if (delxout) XDestroyImage (xout);
+
+ if (img1) XDestroyImage (img1);
+ if (img2) XDestroyImage (img2);
+ if (img3) XDestroyImage (img3);
+ if (img4) XDestroyImage (img4);
+ if (img5) XDestroyImage (img5);
+
+ XDestroyRegion (clip_region);
+ if (clip && dr->type == PixmapRaster)
+ XSetClipMask (w->gterm.display, w->gterm.exposeGC, None);
+
+ if (DBG_TRACE)
+ fprintf (stderr, "refresh_destination: doing mappings status=%d\n",
+ status);
+
+ /* Execute any mappings defined on the raster just updated. */
+ if (status == OK) {
+
+ GtRefreshPixels (w, dst, GtPixel, dx, dy, dnx, dny);
+
+ if (dst == 0) {
+ Region clip_region = (Region)NULL;
+ XRectangle r;
+
+ clip_region = XCreateRegion();
+ r.x = dx; r.y = dy;
+ r.width = dnx; r.height = dny;
+ XUnionRectWithRegion (&r, clip_region, clip_region);
+
+ update_transients (w, clip_region);
+ XDestroyRegion (clip_region);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf(stderr, "refresh_destination: LEAVING status=%d\n", status);
+
+ return (status);
+}
+
+
+/* scale_zoom -- Compute the given destination rect from the input image,
+ * using pixel replication and the given x and y dst->scr pixels maps.
+ */
+static
+scale_zoom (idata,ibpl, odata,obpl, xmap,ymap, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ register int *xmap; /* src coords of each dst pixel */
+ int *ymap; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i, j;
+ register uchar *ip, *op;
+ uchar *last_ip = NULL;
+ uchar *last_op = NULL;
+
+ for (j=0; j < dny; j++) {
+ ip = idata + ymap[j] * ibpl;
+ op = odata + (j+dy) * obpl + dx;
+
+ if (!clip_region) {
+ if (ip == last_ip)
+ memmove (op, last_op, dnx);
+ else {
+ for (i=0; i < dnx; i++) {
+ op[i] = ip[xmap[i]];
+ }
+ }
+ last_ip = ip;
+ last_op = op;
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = ip[xmap[i]];
+ }
+ }
+}
+
+
+/* scale_intzoom -- Compute the given destination rect from the input image,
+ * using pixel replication and integer scaling. This is functionally
+ * equivalent to scale_zoom using the lookup tables, but optimized for the
+ * case of integer scaling.
+ */
+static
+scale_intzoom (idata,ibpl,odata,obpl, sx,sy,dx,dy,dnx,dny, xflip,yflip, nx,ny)
+
+ uchar *idata, *odata; /* input, output data */
+ int ibpl, obpl; /* bytes per line */
+ int sx, sy; /* start coords of src rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xflip, yflip; /* set if x or y is flipped */
+ int nx, ny; /* replication factors */
+{
+ register int n;
+ register int pix;
+ register uchar *ip, *op;
+ uchar *otop, *olast, *lp;
+ int i, j, k;
+
+ olast = odata + (dy + dny) * obpl - dnx + dx;
+
+ if (xflip) {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+
+ op = odata + (dy + (yflip ? (dny-ny-j) : j)) * obpl + dx + dnx;
+ otop = lp = op - dnx;
+
+
+ /* Why are the case statements below necessary, doesn't the
+ * default case do the same thing regardless of what nx is? MJF
+ */
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix; *--op = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ *--op = pix; *--op = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *--op = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op > otop)
+ *--op = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ } else {
+ for (j=0, k=0; j < dny; j += ny, k++) {
+ ip = idata + (sy + k) * ibpl + sx;
+ op = lp = odata + (dy + (yflip ? (dny-ny-j) : j)) * obpl + dx;
+ otop = op + dnx;
+
+ /* Replicate a block of pixels. */
+ switch (nx) {
+ case 2:
+ for (n = (dnx/2); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 3:
+ for (n = (dnx/3); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 4:
+ for (n = (dnx/4); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 5:
+ for (n = (dnx/5); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 6:
+ for (n = (dnx/6); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 7:
+ for (n = (dnx/7); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ case 8:
+ for (n = (dnx/8); --n >= 0; ) {
+ pix = *ip++;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ *op++ = pix; *op++ = pix;
+ }
+ break;
+ default:
+ for (n = (dnx/nx); --n >= 0; ) {
+ pix = *ip++;
+ for (i=nx; --i >= 0; )
+ *op++ = pix;
+ }
+ break;
+ }
+
+ /* Fill the last partial pixel. */
+ pix = *ip++;
+ while (op < otop)
+ *op++ = pix;
+
+ /* Replicate in Y. */
+ for (n=ny, op=lp; --n > 0; ) {
+ op += obpl;
+ if (op <= olast)
+ memmove (op, lp, dnx);
+ }
+ }
+ }
+}
+
+
+/* scale_nearest -- Compute the given destination rect from the input image,
+ * using the nearest neighbor technique.
+ */
+static
+scale_nearest (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i, j;
+ register uchar *op;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = y_src[j];
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = x_src[i];
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* scale_bilinear -- Compute the given destination rect from the input image,
+ * using bilinear interpolation.
+ */
+static
+scale_bilinear (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = x_src[i] - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = y_src[j] - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* scale_lowpass -- Apply a lowpass filter to a region of a 2D data array.
+ * The region ox,oy,nx,ny of the output data array is calculated by running
+ * a convolution kernel over the region of the input data array at ix,iy.
+ * The size of the convolution kernel is adjusted to match the scale factors
+ * xscale, yscale.
+ */
+static
+scale_lowpass (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ Region clip_region; /* clip Region or null */
+{
+ uchar *data;
+
+ if ((data = (uchar *) XtMalloc (inx * iny)) == NULL)
+ return;
+
+ /* Run a lowpass filter over the input rect. */
+ lw_convolve (idata,inx,iny,ibpl, sx,sy, data,inx,iny,ibpl, sx,sy,
+ snx,sny, xscale,yscale);
+
+ /* Sample the filtered data to generate the output rect. */
+ scale_nearest (data,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ dx,dy,dnx,dny, clip_region);
+
+ XtFree ((char *)data);
+}
+
+
+/* lw_convolve -- Convolution primitive for scale_lowpass.
+ */
+static
+lw_convolve (idata,inx,iny,ibpl,ix,iy, odata,onx,ony,obpl,ox,oy,
+ nx, ny, xscale, yscale)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ix, iy; /* size of input array, start pos */
+ int onx, ony, ox, oy; /* size of output array, start pos */
+ int ibpl, obpl; /* bytes per line */
+ int nx, ny; /* size of output region */
+ float xscale, yscale; /* determines amount of smoothing */
+{
+ register uchar *ip;
+ register int l, m, x, hx, pixval;
+ int kx, ky, hy, i, j, y;
+ uchar *lp[11], *op;
+
+ /* Determine kernel size (min 3x3, max 7x7). */
+ if (xscale < 0.1)
+ hx = 3;
+ else if (xscale >= 0.5)
+ hx = 1;
+ else
+ hx = ((int)(1.0 / xscale)) / 2;
+
+ if (yscale < 0.1)
+ hy = 3;
+ else if (yscale >= 0.5)
+ hy = 1;
+ else
+ hy = ((int)(1.0 / yscale)) / 2;
+
+ kx = hx * 2 + 1;
+ ky = hy * 2 + 1;
+
+ /* Compute the output data.
+ */
+ for (j=0; j < ny; j++) {
+ /* Get line pointers. */
+ op = odata + (j+oy) * obpl + ox;
+ for (i=0; i < ky; i++) {
+ y = iy + j - hy + i;
+ if (y < 0)
+ y = 0;
+ else if (y >= iny)
+ y = iny - 1;
+ lp[i] = y * ibpl + idata;
+ }
+
+ /* Compute a line of output pixels */
+ for (i=0; i < nx; i++) {
+ x = ix + i;
+ pixval = 0;
+
+ if (x < hx) {
+ /* Near left edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][max(0,x-hx+l)];
+ } else if (x >= inx - hx) {
+ /* Near right edge. */
+ for (m=0; m < ky; m++)
+ for (l=0; l < kx; l++)
+ pixval += lp[m][min(inx-1,x-hx+l)];
+ } else {
+ /* In central region. */
+ for (m=0; m < ky; m++) {
+ ip = lp[m] + x - hx;
+ for (l=0; l < kx; l++)
+ pixval += ip[l];
+ }
+ }
+
+ op[i] = (float)pixval / (float)(kx * ky) + 0.5;
+ }
+ }
+}
+
+
+/* scale_boxcar -- Apply a boxcar filter to a region of a 2D data array
+ * and interpolate the result to the output grid. The region ox,oy,nx,ny of
+ * the output data array is calculated by block averaging the corresponding
+ * source rect and then sampling the reduced image using bilinear interpolation
+ * to compute the output pixel raster. This antialiasing technique aims to
+ * be as fast as possible but still does a reasonable job of reducing the
+ * image.
+ */
+static
+scale_boxcar (idata,inx,iny,ibpl, odata,onx,ony,obpl, x_src,y_src,
+ sx,sy,snx,sny, dx,dy,dnx,dny, xscale,yscale, interp, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int sx, sy, snx, sny; /* source rect */
+ int dx, dy, dnx, dny; /* destination rect */
+ float xscale, yscale; /* scale factors */
+ int interp; /* set if interpolation is desired */
+ Region clip_region; /* clip Region or null */
+{
+ int xblock, yblock;
+ int x1, x2, y1, y2, nx, ny;
+ float xstep, ystep;
+ int xoff, yoff;
+ uchar *bp;
+
+ /* Determine blocking factors. If interpolation is disabled we need
+ * to block one step more than for the linear interpolate case in order
+ * to ensure that all the data is used.
+ */
+ xblock = max(1, (int) (1.0 / xscale));
+ if (!interp && (1.0 / xscale) - xblock > ZOOM_TOL)
+ xblock++;
+ yblock = max(1, (int) (1.0 / yscale));
+ if (!interp && (1.0 / yscale) - yblock > ZOOM_TOL)
+ yblock++;
+
+ /* Align the input region for the given blocking factors. */
+ x1 = sx / xblock * xblock; x2 = (sx + snx - 1) / xblock * xblock;
+ y1 = sy / yblock * yblock; y2 = (sy + sny - 1) / yblock * yblock;
+ nx = (x2 - x1) / xblock + 1; ny = (y2 - y1) / yblock + 1;
+
+ /* Compute the block averaged input rect. */
+ if (xblock > 1 || yblock > 1) {
+ if ((bp = (uchar *) XtMalloc (nx * ny)) == NULL)
+ return;
+ bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, bp, xblock, yblock);
+ idata = bp;
+ inx = ibpl = nx;
+ iny = ny;
+ xoff = x1; yoff = y1;
+ xstep = 1.0 / xblock; ystep = 1.0 / yblock;
+ } else {
+ bp = NULL;
+ xoff = yoff = 0;
+ xstep = ystep = 1.0;
+ }
+
+ /* Interpolate the input rect to the output grid. */
+ if (interp &&
+ ((1.0 / xscale) - xblock) > ZOOM_TOL ||
+ ((1.0 / yscale) - yblock) > ZOOM_TOL) {
+
+ /* Use bilinear interpolation to compute the output grid. */
+ bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+
+ } else {
+ /* Extract pixels from block averaged input data. */
+ bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region);
+ }
+
+ if (bp)
+ XtFree ((char *)bp);
+}
+
+
+/* bx_boxcar -- Block average primitive for scale_boxcar.
+ */
+static
+bx_boxcar (idata,inx,iny,ibpl, x1,y1,x2,y2, obuf, xblock, yblock)
+ uchar *idata; /* input data array */
+ int inx, iny, ibpl; /* array dimensions */
+ int x1,y1,x2,y2; /* region to be block averaged */
+ uchar *obuf; /* output array */
+ int xblock, yblock; /* blocking factors */
+{
+ register uchar *ip, *op;
+ register int count, i, *sp;
+ int obpl, block, nxblocks, nyblocks, j, k;
+ uchar *lp, *bp;
+ int *sb;
+
+ nxblocks = obpl = (x2 - x1) / xblock + 1;
+ nyblocks = (y2 - y1) / yblock + 1;
+ count = xblock * yblock;
+
+ if ((sb = (int *) XtMalloc (obpl * sizeof(int))) == NULL)
+ return;
+
+ /* I don't think the following works for pixel values allocated from the
+ * default colormap, as the pixel values are not sequentially allocated.
+ */
+ for (block = 0; block < nyblocks; block++) {
+ lp = idata + ibpl * (block * yblock + y1) + x1;
+ bp = obuf + block * obpl;
+
+ memset (sb, 0, obpl * sizeof(int));
+ for (k=yblock; --k >= 0; lp += ibpl)
+ for (j=nxblocks, ip=lp, sp=sb; --j >= 0; sp++)
+ for (i=xblock; --i >= 0; )
+ *sp += *ip++;
+
+ for (i=obpl, sp=sb, op=bp; --i >= 0; )
+ *op++ = *sp++ / count;
+ }
+
+ XtFree ((char *)sb);
+}
+
+
+/* bx_extract -- Block extract primitive for scale_boxcar.
+ */
+static
+bx_extract (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* full input array */
+ int onx, ony, obpl; /* full input array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int dx, dy, dnx, dny; /* destination rect */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ Region clip_region; /* clip Region or null */
+{
+ register int m, n, i;
+ register uchar *op;
+ int j;
+
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ n = (y_src[j] - yoff) * ystep;
+
+ if (!clip_region) {
+ for (i=0; i < dnx; i++) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy)) {
+ m = (x_src[i] - xoff) * xstep;
+ op[i] = idata[n * ibpl + m];
+ }
+ }
+ }
+}
+
+
+/* bx_interp -- Bilinear interpolation primitive for scale_boxcar.
+ */
+static
+bx_interp (idata,inx,iny,ibpl, odata,onx,ony,obpl,
+ x_src,y_src, xoff,yoff,xstep,ystep, dx,dy,dnx,dny, clip_region)
+
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ float *x_src, *y_src; /* src coords of each dst pixel */
+ int xoff, yoff; /* offset of input region */
+ float xstep, ystep; /* scale of input region */
+ int dx, dy, dnx, dny; /* destination rect */
+ Region clip_region; /* clip Region or null */
+{
+ register int i;
+ register uchar *op;
+ register float *lp, *w1, *w2;
+ int buflen, line, *px, pixel, j;
+ float lo_w, hi_w, x, y;
+ uchar *lo, *hi;
+ float *buf;
+
+ buflen = (3 * dnx + 2) * sizeof(float) + dnx * sizeof(int);
+ if ((buf = (float *) XtMalloc (buflen)) == NULL)
+ return;
+
+ lp = buf + 1;
+ w1 = lp + dnx + 1;
+ w2 = w1 + dnx;
+ px = (int *)(w2 + dnx);
+
+ /* Compute the weight vectors at each point in X. */
+ for (i=0; i < dnx; i++) {
+ x = ((x_src[i] - xoff) * xstep) - 0.5;
+ px[i] = (int) x;
+ w1[i] = 1.0 - (x - (int)x);
+ w2[i] = 1.0 - w1[i];
+ }
+
+ /* For each line of the destination rect first interpolate in Y to the
+ * y_src coordinate of the output line, then interpolate in X to compute
+ * the final output pixels.
+ */
+ for (j=0; j < dny; j++) {
+ op = odata + (j+dy) * obpl + dx;
+ y = ((y_src[j] - yoff) * ystep) - 0.5;
+ line = (int) y;
+ lo = idata + line * ibpl;
+ hi = idata + min (iny - 1, line + 1) * ibpl;
+ lo_w = 1.0 - (y - line);
+ hi_w = 1.0 - lo_w;
+
+ /* Interpolate in Y to the line at y_src[j]. */
+ for (i=0; i < dnx; i++) {
+ pixel = px[i];
+ lp[i] = (float)lo[pixel] * lo_w + (float)hi[pixel] * hi_w;
+ }
+ lp[-1] = lp[0];
+ lp[dnx] = lp[dnx-1];
+
+ /* Interpolate in X to the final output pixels. */
+ if (!clip_region) {
+ for (i=0; i < dnx; i++)
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ } else {
+ for (i=0; i < dnx; i++)
+ if (XPointInRegion (clip_region, i + dx, j + dy))
+ op[i] = lp[i] * w1[i] + lp[i+1] * w2[i];
+ }
+ }
+
+ XtFree ((char *)buf);
+}
+
+
+/* mf_getinten -- Copy the source rect to the destination rect, converting
+ * pixel numbers to pixel intensities.
+ */
+static
+mf_getinten (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_out (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* mf_getpixel -- Copy the source rect to the destination rect, converting
+ * pixel intensities to pixel numbers.
+ */
+static
+mf_getpixel (w, idata,inx,iny,ibpl, sx,sy, odata,onx,ony,obpl, dx,dy, nx,ny)
+
+ GtermWidget w;
+ uchar *idata, *odata; /* input, output data */
+ int inx, iny, ibpl; /* dimensions of input array */
+ int onx, ony, obpl; /* dimensions of output array */
+ int sx, sy; /* source offset */
+ int dx, dy; /* destination offset */
+ int nx, ny; /* size of region */
+{
+ register Pixel *cmap;
+ register uchar *ip, *op;
+ register int n;
+ int j;
+
+ cmap = get_cmap_in (w);
+ for (j=0; j < ny; j++) {
+ ip = idata + ibpl * (sy + j) + sx;
+ op = odata + obpl * (dy + j) + dx;
+ for (n = nx; --n >= 0; )
+ *op++ = (cmap[*ip++]);
+ }
+}
+
+
+/* get_regions -- For each pixel I in the sequence of DNX pixels starting at DX
+ * there is an associated value XMAP[I]. Compare this sequence to an alternate
+ * sequence and return a list of subregions {XS,XE,XV} for which the XMAP
+ * values are equal (XV=0), not equal (XV=1), or not common to (XV=2) the two
+ * regions. The number of regions output is returned as the function value.
+ */
+static
+get_regions (xs,xe,xv, max_regions, dx, dnx, xmap, alt_dx, alt_dnx, alt_xmap)
+ int *xs, *xe, *xv, max_regions;
+ int dx, dnx, *xmap;
+ int alt_dx, alt_dnx, *alt_xmap;
+{
+ register int state, current;
+ register int nx, i;
+ int offset, old_i;
+
+ offset = dx - alt_dx;
+ nx = 0;
+
+ for (i=0; i < dnx; i++) {
+ if (nx >= max_regions-1)
+ return (0);
+
+ /* Determine whether or not this pixel is mapped the same in both
+ * sequences.
+ */
+ old_i = i + offset;
+ if (alt_dnx <= 0 || old_i < 0 || old_i >= alt_dnx)
+ state = 2;
+ else
+ state = (xmap[i] != alt_xmap[old_i]);
+
+ /* When the state boundary is crossed add a range. */
+ if (i == 0) {
+ xs[nx] = dx;
+ xv[nx] = current = state;
+ }
+ if (state != current) {
+ xe[nx] = dx + i - 1;
+ xs[++nx] = dx + i;
+ xv[nx] = current = state;
+ }
+ if (i == dnx-1)
+ xe[nx++] = dx + i;
+ }
+
+ return (nx);
+}
+
+
+/* get_rects -- Combine two lists of regions, one in X and the other in Y,
+ * to produce a list of 2D rectangles defining the regions outlined by the
+ * region lists. Only rects for which the given condition is true in either
+ * X or Y are selected. Adjacent rects are combined.
+ */
+static
+get_rects (o_rl, max_rects, xs,xe,xv,nx, ys,ye,yv,ny, xcond,ycond)
+ XRectangle *o_rl; /* receives list of rectangles */
+ int max_rects; /* max rectangles out */
+ int *xs, *xe, *xv, nx; /* X list of regions */
+ int *ys, *ye, *yv, ny; /* Y list of regions */
+ int xcond, ycond; /* X,Y condition bitflags */
+{
+ register int i, j;
+ XRectangle rl[MAX_REGIONS];
+ int limit = min (max_rects, MAX_REGIONS);
+ int o_nrects=0, nrects=0;
+ int i1, i2, j1, j2;
+
+ /* Get initial list of rects matching the given X and Y conditions.
+ * Rects which are adjacent in X are combined to form one larger rect.
+ */
+ for (j=0; j < ny; j++) {
+ for (i=0; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond)) {
+ /* Collapse rects adjacent in X. */
+ for (i1 = i2 = i++; i < nx; i++) {
+ if ((xv[i] & xcond) || (yv[j] & ycond))
+ i2 = i;
+ else
+ break;
+ }
+
+ rl[nrects].x = xs[i1];
+ rl[nrects].y = ys[j];
+ rl[nrects].width = xe[i2] - xs[i1] + 1;
+ rl[nrects].height = ye[j] - ys[j] + 1;
+
+ if (++nrects >= limit)
+ return (nrects);
+ }
+ }
+ }
+
+ /* Now scan the rect list and collapse rects which are adjacent in Y
+ * into one larger rect. Find all the rects that are at the same X
+ * and write them to the output list, collapsing rects that are adjacent
+ * in Y in the process.
+ */
+ for (i=0; i < nx; i++)
+ for (j=0; j < nrects; ) {
+ /* Find first rect if any. */
+ for (j1=0, j2 = -1; j < nrects; j++)
+ if (rl[j].x == xs[i]) {
+ j1 = j2 = j++;
+ break;
+ }
+
+ /* Collapse rects adjacent in Y. */
+ for ( ; j < nrects; j++)
+ if (rl[j].x == xs[i])
+ if (rl[j].y == rl[j2].y + rl[j2].height &&
+ rl[j].width == rl[j1].width)
+ j2 = j;
+ else
+ break;
+
+ /* Output the rect. */
+ if (j2 >= j1) {
+ o_rl[o_nrects].x = rl[j1].x;
+ o_rl[o_nrects].y = rl[j1].y;
+ o_rl[o_nrects].width = rl[j1].width;
+ o_rl[o_nrects].height = rl[j2].y + rl[j2].height - rl[j1].y;
+
+ if (++o_nrects >= max_rects)
+ return (o_nrects);
+ }
+ }
+
+ return (o_nrects);
+}
+
+
+/* rect_intersect -- Compute the intersection of two rects. The area of
+ * the intersection is returned as the function value, i.e., zero is
+ * returned if the rects do not intersect.
+ */
+static
+rect_intersect (in, r1, r2)
+ register XRectangle *in;
+ register XRectangle *r1, *r2;
+{
+ int x1, y1, x2, y2;
+
+ x1 = max (r1->x, r2->x);
+ y1 = max (r1->y, r2->y);
+ x2 = min ((int)r1->x + (int)r1->width, (int)r2->x + (int)r2->width) - 1;
+ y2 = min ((int)r1->y + (int)r1->height, (int)r2->y + (int)r2->height) - 1;
+
+ in->x = x1;
+ in->y = y1;
+ in->width = max (0, x2 - x1 + 1);
+ in->height = max (0, y2 - y1 + 1);
+
+ return (in->width * in->height);
+}
+
+
+/* save_mapping -- Store a mapping in a mapping descriptor.
+ */
+static
+save_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int mapping, rop;
+ int src, st, sx,sy,sw,sh;
+ int dst, dt, dx,dy,dw,dh;
+{
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = sw; mp->sny = sh;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dw; mp->dny = dh;
+ mp->defined = mp->enabled = mp->refresh = 1;
+ mp->mapping = mapping;
+ mp->rop = rop;
+}
+
+/* load_mapping -- Load a mapping from a mapping descriptor.
+ */
+static
+load_mapping (mp, mapping, rop, src, st, sx,sy,sw,sh, dst, dt, dx,dy,dw,dh)
+ register Mapping mp;
+ int *mapping, *rop;
+ int *src, *st, *sx,*sy,*sw,*sh;
+ int *dst, *dt, *dx,*dy,*dw,*dh;
+{
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *sw = mp->snx; *sh = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dw = mp->dnx; *dh = mp->dny;
+ *mapping = mp->mapping;
+ *rop = mp->rop;
+}
+
+
+/* get_pixel_mapping -- Copy a mapping, converting to pixel coordinates in
+ * the process if the mapping is not already in pixel coordinates.
+ */
+static
+get_pixel_mapping (w, mp1, mp2, update)
+ GtermWidget w;
+ register Mapping mp1; /* input mapping */
+ register Mapping mp2; /* output mapping */
+ int update; /* update mapping */
+{
+ float maxndc = (float)MAXNDC;
+
+ mp2->mapping = mp1->mapping;
+ mp2->refresh = mp1->refresh;
+ mp2->enabled = mp1->enabled;
+ mp2->rop = mp1->rop;
+
+ if (!(mp2->defined = mp1->defined))
+ return;
+
+ mp2->src = mp1->src;
+ if (mp1->st == GtPixel) {
+ mp2->st = mp1->st;
+ mp2->sx = mp1->sx; mp2->sy = mp1->sy;
+ mp2->snx = mp1->snx; mp2->sny = mp1->sny;
+ } else {
+ float width = w->gterm.rasters[mp1->src].width;
+ float height = w->gterm.rasters[mp1->src].height;
+ mp2->sx = mp1->sx * width / maxndc;
+ mp2->sy = (MAXNDC - (mp1->sy + abs(mp1->sny))) * height / maxndc;
+ mp2->snx = mp1->snx * width / maxndc;
+ mp2->sny = mp1->sny * height / maxndc; /* NDC flipped in Y */
+ mp2->st = GtPixel;
+ }
+
+ mp2->dst = mp1->dst;
+ if (mp1->dt == GtPixel) {
+ mp2->dt = mp1->dt;
+ mp2->dx = mp1->dx; mp2->dy = mp1->dy;
+ mp2->dnx = mp1->dnx; mp2->dny = mp1->dny;
+ } else {
+ float width = w->gterm.rasters[mp1->dst].width;
+ float height = w->gterm.rasters[mp1->dst].height;
+ mp2->dx = mp1->dx * width / maxndc;
+ mp2->dy = (MAXNDC - (mp1->dy + abs(mp1->dny))) * height / maxndc;
+ mp2->dnx = mp1->dnx * width / maxndc;
+ mp2->dny = mp1->dny * -height / maxndc; /* NDC flipped in Y */
+ mp2->dt = GtPixel;
+ }
+
+ /* The lookup tables are already in pixel space, so we can propagate
+ * these to the new mapping if the old mapping was updated.
+ */
+ if (update && mp1->updated) {
+ if (mp2->mapdata = (uchar *) XtMalloc (mp1->datalen)) {
+
+ memmove (mp2->mapdata, mp1->mapdata, mp1->datalen);
+ mp2->datalen = mp1->datalen;
+ mp2->scaling = mp1->scaling;
+ mp2->xscale = mp1->xscale;
+ mp2->yscale = mp1->yscale;
+
+ mp2->x_extent = (mapExtent *)
+ ((uchar *)mp1->x_extent - mp1->mapdata + mp2->mapdata);
+ mp2->y_extent = (mapExtent *)
+ ((uchar *)mp1->y_extent - mp1->mapdata + mp2->mapdata);
+ mp2->x_srcpix = (int *)
+ ((uchar *)mp1->x_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->y_srcpix = (int *)
+ ((uchar *)mp1->y_srcpix - mp1->mapdata + mp2->mapdata);
+ mp2->x_src = (float *)
+ ((uchar *)mp1->x_src - mp1->mapdata + mp2->mapdata);
+ mp2->y_src = (float *)
+ ((uchar *)mp1->y_src - mp1->mapdata + mp2->mapdata);
+
+ mp2->updated = 1;
+ }
+ } else
+ mp2->updated = 0;
+}
+
+/* valid_mapping -- Perform some sanity checks on a mapping to verify that
+ * it contains something meaningful.
+ */
+static
+valid_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register int x, y;
+ int snx, sny, dnx, dny;
+ int s_width, s_height, d_width, d_height;
+ Raster sr, dr;
+
+ if (!mp || !mp->defined)
+ return (False);
+
+ if (mp->src < 0 || mp->src >= w->gterm.maxRasters)
+ return (False);
+ if (mp->dst < 0 || mp->dst >= w->gterm.maxRasters)
+ return (False);
+
+ sr = &w->gterm.rasters[mp->src];
+ dr = &w->gterm.rasters[mp->dst];
+ if (!sr->type || !dr->type)
+ return (False);
+
+ switch (mp->st) {
+ case GtPixel:
+ s_width = sr->width; s_height = sr->height;
+ break;
+ case GtNDC:
+ s_width = MAXNDC + 1; s_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ switch (mp->dt) {
+ case GtPixel:
+ d_width = dr->width; d_height = dr->height;
+ break;
+ case GtNDC:
+ d_width = MAXNDC + 1; d_height = MAXNDC + 1;
+ break;
+ default:
+ return (False);
+ }
+
+ snx = mp->snx; dnx = abs(mp->dnx);
+ sny = mp->sny; dny = abs(mp->dny);
+ if (snx <= 0 || dnx <= 0 || sny <= 0 || dny <= 0)
+ return (False);
+
+ x = mp->sx; y = mp->sy;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+ x = mp->sx + snx - 1; y = mp->sy + sny - 1;
+ if (x < 0 || x >= s_width || y < 0 || y >= s_height)
+ return (False);
+
+ x = mp->dx; y = mp->dy;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+ x = mp->dx + dnx - 1; y = mp->dy + dny - 1;
+ if (x < 0 || x >= d_width || y < 0 || y >= d_height)
+ return (False);
+
+ return (True);
+}
+
+
+/* initialize_mapping -- Initialize the contents of a mapping descriptor.
+ */
+static
+initialize_mapping (mp)
+ register Mapping mp;
+{
+ memset ((char *)mp, 0, sizeof(struct mapping));
+}
+
+
+/* update_mapping -- Update the portion of a mapping descriptor used at
+ * runtime to execute the mapping. This information consists of several
+ * lookup tables and other parameters describing how a destination pixel
+ * maps back to a source pixel and vice versa.
+ */
+static
+update_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ register uchar *op;
+ register int i, j, k;
+ int snx, sny, dnx, dny, sx, sy, dx, dy;
+ int xmax, ymax, lo, hi, edge1, edge2;
+ int temp, xflip=0, yflip=0;
+ struct mapping p_mp;
+ float pixwidth, *fp;
+ int *ip;
+
+ if (mp->updated)
+ return;
+
+ /* The internal lookup tables are in pixel units. */
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 0);
+
+ if ((snx = p_mp.snx) <= 0 || (sny = p_mp.sny) <= 0)
+ return;
+
+ if ((dnx = p_mp.dnx) < 0) {
+ dnx = -dnx;
+ xflip++;
+ }
+ if ((dny = p_mp.dny) < 0) {
+ dny = -dny;
+ yflip++;
+ }
+
+ sx = p_mp.sx;
+ sy = p_mp.sy;
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ xmax = dnx - 1;
+ ymax = dny - 1;
+
+ /* Discard the temporary mapping.
+ free_mapping (w, &p_mp);
+ */
+
+ /* Get scale factors. */
+ mp->xscale = (float)dnx / (float)snx;
+ mp->yscale = (float)dny / (float)sny;
+
+ /* Determine type of scaling to be used. */
+ if (mp->xscale < 1.0 || mp->yscale < 1.0) {
+ mp->scaling = M_DEZOOM;
+ } else if (mp->xscale > 1.0 || mp->yscale > 1.0) {
+ mp->scaling = M_ZOOM;
+ if (abs(mp->xscale - (int)(mp->xscale+0.5)) < ZOOM_TOL &&
+ abs(mp->yscale - (int)(mp->yscale+0.5)) < ZOOM_TOL)
+ mp->scaling = M_INTZOOM;
+ } else
+ mp->scaling = (xflip || yflip) ? M_ZOOM : M_NOSCALING;
+
+ /* Get a data buffer for the lookup tables. */
+ mp->datalen =
+ snx * sizeof(mapExtent) + /* xy, extent */
+ sny * sizeof(mapExtent) +
+ dnx * sizeof(int) + /* xy, srcpix */
+ dny * sizeof(int) +
+ dnx * sizeof(float) + /* xy, src */
+ dny * sizeof(float);
+
+ if (mp->mapdata)
+ mp->mapdata = (uchar *) XtRealloc ((char *)mp->mapdata, mp->datalen);
+ else
+ mp->mapdata = (uchar *) XtMalloc (mp->datalen);
+ if (mp->mapdata == NULL)
+ return;
+
+ /* Set the table pointers. */
+ op = mp->mapdata;
+ mp->x_extent = (mapExtent *) op; op += snx * sizeof(mapExtent);
+ mp->y_extent = (mapExtent *) op; op += sny * sizeof(mapExtent);
+ mp->x_srcpix = (int *) op; op += dnx * sizeof(int);
+ mp->y_srcpix = (int *) op; op += dny * sizeof(int);
+ mp->x_src = (float *) op; op += dnx * sizeof(float);
+ mp->y_src = (float *) op; op += dny * sizeof(float);
+
+ /* Compute the backpointers to the source raster for each destination
+ * pixel center.
+ */
+ for (i=0, ip = mp->x_srcpix, fp = mp->x_src; i < dnx; i++) {
+ fp[i] = ((xflip ? xmax - i : i) + 0.5) / mp->xscale + sx;
+ ip[i] = fp[i];
+ }
+ for (i=0, ip = mp->y_srcpix, fp = mp->y_src; i < dny; i++) {
+ fp[i] = ((yflip ? ymax - i : i) + 0.5) / mp->yscale + sy;
+ ip[i] = fp[i];
+ }
+
+ /* Compute the extent arrays. These define the range of destination
+ * pixels affected by each source pixel.
+ */
+ lo = dnx - 1 + dx;
+ hi = dx;
+ for (i=0; i < snx; i++) {
+ mp->x_extent[i].lo = lo;
+ mp->x_extent[i].hi = hi;
+ }
+ lo = dny - 1 + dy;
+ hi = dy;
+ for (i=0; i < sny; i++) {
+ mp->y_extent[i].lo = lo;
+ mp->y_extent[i].hi = hi;
+ }
+
+ /* Map the left and right or top and bottom edges of each destination
+ * pixel back into the source rect and update the corresponding extent
+ * entries to indicate that these source pixels are used to compute the
+ * destination pixel.
+ */
+ pixwidth = 1.0 - ZOOM_TOL;
+
+ for (i=0; i < dnx; i++) {
+ edge1 = (xflip ? xmax - i : i) / mp->xscale;
+ edge2 = (xflip ? xmax - (i-pixwidth) : (i+pixwidth)) / mp->xscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (snx - 1, edge2);
+
+ for (j=edge1, k = dx + i; j <= edge2; j++) {
+ if (mp->x_extent[j].lo > k)
+ mp->x_extent[j].lo = k;
+ if (mp->x_extent[j].hi < k)
+ mp->x_extent[j].hi = k;
+ }
+ }
+
+ for (i=0; i < dny; i++) {
+ edge1 = (yflip ? ymax - i : i) / mp->yscale;
+ edge2 = (yflip ? ymax - (i-pixwidth) : (i+pixwidth)) / mp->yscale;
+ if (edge1 > edge2) {
+ temp = edge1; edge1 = edge2; edge2 = temp;
+ }
+ edge1 = max (0, edge1);
+ edge2 = min (sny - 1, edge2);
+
+ for (j=edge1, k = dy + i; j <= edge2; j++) {
+ if (mp->y_extent[j].lo > k)
+ mp->y_extent[j].lo = k;
+ if (mp->y_extent[j].hi < k)
+ mp->y_extent[j].hi = k;
+ }
+ }
+
+ mp->updated = 1;
+}
+
+
+/* free_mapping -- Free any storage used internally by a mapping descriptor,
+ * and deactivate the mapping.
+ */
+static
+free_mapping (w, mp)
+ GtermWidget w;
+ register Mapping mp;
+{
+ mp_unlink (w, mp);
+ mp->defined = mp->enabled = mp->updated = 0;
+ if (mp->mapdata) {
+ XtFree ((char *) mp->mapdata);
+ mp->mapdata = NULL;
+ mp->datalen = 0;
+ mp->x_extent = mp->y_extent = NULL;
+ mp->x_srcpix = mp->y_srcpix = NULL;
+ mp->x_src = mp->y_src = NULL;
+ mp->updated = 0;
+ }
+}
+
+static void
+mp_linkafter (w, mp, ref_mp)
+ register GtermWidget w;
+ register Mapping mp;
+ register Mapping ref_mp;
+{
+ register Mapping map;
+
+ /* Don't use the reference mapping unless it is already linked or
+ * the list is empty.
+ */
+ if (w->gterm.mp_head) {
+ for (map = w->gterm.mp_head; map && map != ref_mp; map = map->next)
+ ;
+ if (map != ref_mp)
+ ref_mp = NULL;
+ }
+
+ mp->prev = ref_mp;
+ mp->next = ref_mp ? ref_mp->next : NULL;
+ if (ref_mp && ref_mp->next)
+ ref_mp->next->prev = mp;
+ if (ref_mp)
+ ref_mp->next = mp;
+
+ if (!w->gterm.mp_tail || ref_mp == w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ if (!w->gterm.mp_head)
+ w->gterm.mp_head = mp;
+}
+
+
+static void
+mp_unlink (w, mp)
+ register GtermWidget w;
+ register Mapping mp;
+{
+ if (mp->prev)
+ mp->prev->next = mp->next;
+ if (mp->next)
+ mp->next->prev = mp->prev;
+ if (w->gterm.mp_head == mp)
+ w->gterm.mp_head = mp->next;
+ if (w->gterm.mp_tail == mp)
+ w->gterm.mp_tail = mp->prev;
+
+ mp->prev = mp->next = NULL;
+}
+
+
+