/* * Copyright(c) 1997, Space Science and Engineering Center, UW-Madison * Refer to "McIDAS Software Acquisition and Distribution Policies" * in the file mcidas/data/license.txt */ /**** $Id: mci_updt.c,v 1.48 2019/11/14 19:50:04 davep Exp $ ****/ #include #include "mci.h" #include "mcidasp.h" /* #define TIME_FRAME_UPDATE */ /* #define TIME_100_FRAMES */ /* #define DEBUG_FRAME_UPDATE */ #if defined(TIME_FRAME_UPDATE) || defined(TIME_100_FRAMES) #include #endif /* TIME_FRAME_UPDATE || TIME_100_FRAMES */ /* bit values for which colormap(s) changed */ typedef enum changedColormapFlag { changedNone = 0x0000, changedBackground = 0x0100, changedGraphics = 0x0400, changedImage = 0x0800 } changedColormapFlag; static void frame2image_slow(const unsigned char *frame, const unsigned long *colorhash, unsigned elems, unsigned lines, int ul_elem, int ul_line, int lr_elem, int lr_line, Bool do_zoom); static void frame2image_z8(const unsigned char *frame, const unsigned long *colorhash, unsigned elems, unsigned lines, int ul_elem, int ul_line, int lr_elem, int lr_line, Bool do_zoom); static void frame2image_warp(const unsigned char *frame, const unsigned long *colorhash, unsigned elems, unsigned lines); static void frame_to_image(int frame_num, unsigned elems, unsigned lines, int ul_elem, int ul_line, int lr_elem, int lr_line, Bool do_zoom); static void frame_combine(unsigned elems, unsigned lines); static void frame_rgb(int frame, Bool do_zoom); static void image_to_pixmap(pixmapInfo *pinfo, unsigned elems, unsigned lines, int ul_elem, int ul_line, int lr_elem, int lr_line); static changedColormapFlag frame_colormap_changes(int frame_num); unsigned char* ImageBuffer=NULL; int ImageBufferSize=0; unsigned char* ImageBufferR=NULL; int ImageBufferRSize=0; unsigned char* ImageBufferG=NULL; int ImageBufferGSize=0; unsigned char* ImageBufferB=NULL; int ImageBufferBSize=0; /* ** Name: ** frame2image_slow - slow'n'safe frame translation ** ** Interface: ** #include "mci.h" ** ** static void ** frame2image_slow(const unsigned char *frame, ** const unsigned long *colorhash, ** unsigned elems, unsigned lines, ** int ul_elem, int ul_line, int lr_elem, int lr_line, ** Bool do_zoom) ** ** Input: ** frame - pointer to frame bytes ** colorhash - pointer to hashed color table ** elems - number of elements in frame ** lines - number of lines in frame ** ul_elem - leftmost changed element ** ul_line - uppermost changed line ** lr_elem - rightmost changed element ** lr_line - lowermost changed line ** do_zoom - nonzero if frame should be zoomed ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** none ** ** Remarks: ** non-optimal but safe method of translating a McIDAS frame to an XImage ** ** Categories: ** none */ static void frame2image_slow(const unsigned char *frame, const unsigned long *colorhash, unsigned elems, unsigned lines, int ul_elem, int ul_line, int lr_elem, int lr_line, Bool do_zoom) { int top = lines - lr_line; int bottom = lines - ul_line + 1; int left = ul_elem - 1; int right = lr_elem; int start; int span; int i, j, k, l; /* quick fix */ unsigned char* BPointer=ImageBuffer; /* point to the static Image Buffer */ frame=BPointer; /* offset from start of frame to start of update */ start = 0; if (top > 0) { start += elems * top; } if (left > 0) { start += left; } /* span between end of one row and beginning of next */ span = elems - (right - left); /* image Y coord is reversed */ bottom = lr_line; top = ul_line; if (!do_zoom) { #ifdef M0ASSERT_ON const unsigned char *fstart = frame; const unsigned char *fend = frame + (lines * elems) - 1; #endif /* M0ASSERT_ON */ /* write actual pixels to image buffer */ frame += start; top--; for (i = bottom - 1; i >= top; i--) { for (j = left; j < right; j++) { #ifdef M0ASSERT_ON unsigned long floc = frame - fstart; unsigned long ix, iy; unsigned long fx, fy; M0ASSERT(frame >= fstart); M0ASSERT(frame <= fend); ix = j; iy = lines - i - 1; fx = floc % elems; fy = floc / elems; M0ASSERT(iy == fy); M0ASSERT(ix == fx); #endif /* M0ASSERT_ON */ XPutPixel(image->image, j, i, colorhash[*frame]); frame++; } frame += span; } } else { /* zoom starting & ending points */ bottom = (bottom - 1) * zoom_factor; top *= zoom_factor; left *= zoom_factor; right = (right - 1) * zoom_factor; /* write actual pixels to zoomed image buffer */ frame += start; for (i = bottom; i >= top; i -= zoom_factor) { for (j = left; j <= right; j += zoom_factor) { for (k = 0; k < (int)zoom_factor; k++) { for (l = 0; l < (int)zoom_factor; l++) { XPutPixel(image->image, j + l, i + k, colorhash[*frame]); } } frame++; } frame += span; } } } /* ** Name: ** frame2image_z8 - quick frame translation for Z8 XImages ** ** Interface: ** #include "mci.h" ** ** static void ** frame2image_z8(const unsigned char *frame, ** const unsigned long *colorhash, ** unsigned elems, unsigned lines, ** int ul_elem, int ul_line, int lr_elem, int lr_line, ** Bool do_zoom) ** ** Input: ** frame - pointer to frame bytes ** colorhash - pointer to hashed color table ** elems - number of elements in frame ** lines - number of lines in frame ** ul_elem - leftmost changed element ** ul_line - uppermost changed line ** lr_elem - rightmost changed element ** lr_line - lowermost changed line ** do_zoom - nonzero if frame should be zoomed ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** none ** ** Remarks: ** none ** ** Categories: ** none */ static void frame2image_z8(const unsigned char *frame, const unsigned long *colorhash, unsigned elems, unsigned lines, int ul_elem, int ul_line, int lr_elem, int lr_line, Bool do_zoom) { unsigned char* BPointer=ImageBuffer; /* point to the static Image Buffer */ unsigned char* IPointer=(unsigned char*)image->image->data; /* Pointer to X Image buffer */ int dxB,dxI; int y,zv,zh; int BPL=image->image->bytes_per_line; unsigned char* End; unsigned char Color; if(!do_zoom) { /* set the starting positions for accessing the data */ BPointer+=(lines-ul_line)*elems+ul_elem-1; IPointer+=(ul_line-1)*BPL+ul_elem-1; /* amount to set per pass */ dxB=lr_elem-ul_elem+1; /* width of pass in the buffer */ dxI=BPL-dxB; /* width of pass in the IMAGE */ for(y=ul_line;y<=lr_line;y++) { for(End=BPointer+dxB;BPointerimage->bytes_per_line; int i, k, l; int image_prev_line; const unsigned char *frame_end; /* offset from start of frame to start of update */ start = 0; if (top > 0) { start += elems * top; } if (left > 0) { start += left; } /* span between end of one row and beginning of next */ span = elems - (right - left); /* image Y coord is reversed */ bottom = lr_line; top = ul_line - 1; if (!do_zoom) { #ifdef M0ASSERT_OFF const unsigned char *fstart = frame; const unsigned char *fend = frame + (lines * elems) - 1; const char *istart = image->image->data; const char *iend = image->image->data + (lines * bytes_per_line) - 1; #endif /* M0ASSERT_OFF */ /* write actual pixels to image buffer */ image_data = image->image->data + ((bottom - 1) * bytes_per_line); image_prev_line = elems + bytes_per_line; frame += start; for (i = bottom; i > top; i--) { image_data += left; for (frame_end = frame + right - left; frame < frame_end; frame++) { #ifdef M0ASSERT_OFF unsigned long iloc = image_data - istart; unsigned long floc = frame - fstart; unsigned long ix, iy; unsigned long fx, fy; M0ASSERT(frame >= fstart); M0ASSERT(frame <= fend); M0ASSERT(image_data >= istart); M0ASSERT(image_data <= iend); ix = (iloc % bytes_per_line); iy = lines - (iloc / bytes_per_line); M0ASSERT(iy > 0); iy--; fx = floc % elems; fy = floc / elems; M0ASSERT(iy == fy); M0ASSERT(ix == fx); #endif /* M0ASSERT_OFF */ *image_data = (char )colorhash[*frame]; image_data++; } image_data += elems - right; image_data -= image_prev_line; frame += span; } } else { int lzoom = left * zoom_factor; /* write actual pixels to zoomed image buffer */ elems *= zoom_factor; image_data = image->image->data + (((bottom * zoom_factor) - 1) * bytes_per_line); image_prev_line = elems + bytes_per_line; frame += start; image_data += lzoom; for (i = bottom; i > top; i--) { for (k = zoom_factor; k > 0; k--) { for (frame_end = frame + right - left; frame < frame_end; frame++) { for (l = 0; l < zoom_factor; l++) { *image_data = (char )colorhash[*frame]; image_data++; } } if (k > 1) { frame -= right - left; } else { frame += span; } image_data += elems - (right - left) * zoom_factor; image_data -= image_prev_line; } } } } #endif /* ** Name: ** frame2image_warp - translate frame to window-sized image ** ** Interface: ** #include "mci.h" ** ** static void ** frame2image_warp(const unsigned char *frame, ** const unsigned long *colorhash, ** unsigned elems, unsigned lines) ** ** Input: ** frame - pointer to frame bytes ** colorhash - pointer to hashed color table ** elems - number of elements in frame ** lines - number of lines in frame ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** none ** ** Remarks: ** none ** ** Categories: ** none */ static void frame2image_warp(const unsigned char *frame, const unsigned long *colorhash, unsigned elems, unsigned lines) { double warp_x = (double )elems / (double )window_width; double warp_y = (double )lines / (double )window_height; double frm_x, frm_y; int ix, iy; int fx, fy; int diff; const unsigned char *fzero; /* = frame; */ /* quick fix */ unsigned char* BPointer=ImageBuffer; /* point to the static Image Buffer */ frame=BPointer; fzero=frame; frm_y = (double )lines - warp_y; fy = lines - 1; for (iy = window_height - 1; iy >= 0; iy--) { frm_x = 0.0; fx = 0; for (ix = 0; ix < (int)window_width; ix++) { if (fx < frm_x) { diff = frm_x - fx; frame += diff; fx += diff; } XPutPixel(image->image, ix, iy, colorhash[*frame]); frm_x += warp_x; } frm_y -= warp_y; if (fy > frm_y) { diff = fy - (int )frm_y; if (diff > 0) { frame = fzero + (diff * elems); fzero = frame; fy -= diff; } else { frame = fzero; } } else { frame = fzero; } } } /* ** Name: ** frame_to_image - translate McIDAS frame to XImage ** ** Interface: ** #include "mci.h" ** ** static void ** frame_to_image(int frame_num, unsigned elems, unsigned lines, ** int ul_elem, int ul_line, int lr_elem, int lr_line, ** Bool do_zoom) ** ** Input: ** frame_num - pointer to frame bytes ** elems - number of elements in frame ** lines - number of lines in frame ** ul_elem - leftmost changed element ** ul_line - uppermost changed line ** lr_elem - rightmost changed element ** lr_line - lowermost changed line ** do_zoom - nonzero if frame should be zoomed ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** none ** ** Remarks: ** none ** ** Categories: ** none */ static void frame_to_image(int frame_num, unsigned elems, unsigned lines, int ul_elem, int ul_line, int lr_elem, int lr_line, Bool do_zoom) { static Bool not_warned = False; const Fint *frame_base; M0frameflags *frame_flags; unsigned char *frame; const Fint *stretch; int i; int val; unsigned long mystretch[256]; unsigned char *IPointer,*FPointer; /* ImageBuffer and FrameData Pointers */ #ifdef M0ASSERT_ON { M0ASSERT(frame_num >= 1); M0ASSERT(frame_num <= number_of_frames); M0ASSERT((int)elems <= ELEM_SIZE(frame_num)); M0ASSERT((int)lines <= LINE_SIZE(frame_num)); M0ASSERT(ELEM_SIZE(frame_num) <= (int)image->max_width); M0ASSERT(LINE_SIZE(frame_num) <= (int)image->max_height); } #endif /* M0ASSERT_ON */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("Writing frame %d to image buffer\n", frame_num); #endif /* DEBUG_FRAME_UPDATE */ /* get pointer to frame data for the requested frame */ frame_base = FRAME_BASE(frame_num); /* ptr to frame data */ frame = FRAME_DATA(frame_base); /* get pointer to frame flags */ frame_flags = FRAME_FLAGS(frame_base); /* get pointer to stretch table */ stretch = FRAME_STRETCH(frame_base); /* build a hashed pixel table using the stretch table */ for (i = 0; i < 256; i++) { val = stretch[i]; if ((val >= (NUM_UC_COLORS - num_image_colors)) && (val < NUM_UC_COLORS)) { mystretch[i] = image_cell[val - (NUM_UC_COLORS - num_image_colors)].pixel; } else if ((val >= BKGND_COLORS + CURSOR_COLORS) && (val < (BKGND_COLORS + CURSOR_COLORS + num_graphics_colors))) { mystretch[i] = graphics_cell[val - (BKGND_COLORS + CURSOR_COLORS)].pixel; } else { mystretch[i] = bkgnd_color.pixel; } } /* Build an image buffer to copy the graphics and raw data too */ /* If the buffer is not of the correct size reallocate it */ if(ImageBufferSizeimage->format == ZPixmap) && (image->image->bits_per_pixel == 8) && (image->image->bitmap_bit_order == BitmapBitOrder(display))) { frame2image_z8(frame, mystretch, elems, lines, ul_elem, ul_line, lr_elem, lr_line, do_zoom); } else { if (not_warned) { Mceprintf("Using slow processing for %s-%d%s images\n", (image->image->format == XYPixmap ? "XY" : (image->image->format == ZPixmap ? "Z" : "??")), image->image->bits_per_pixel, (image->image->bitmap_bit_order == BitmapBitOrder(display) ? "" : " bit-flipped")); not_warned = False; } frame2image_slow(frame, mystretch, elems, lines, ul_elem, ul_line, lr_elem, lr_line, do_zoom); } if (do_zoom) { image->cur_width = elems * zoom_factor; image->cur_height = lines * zoom_factor; image->zoom_factor = zoom_factor; } else { image->cur_width = elems; image->cur_height = lines; image->zoom_factor = 1; } } else { /* warp frame to window */ frame2image_warp(frame, mystretch, elems, lines); image->cur_width = window_width; image->cur_height = window_height; image->zoom_factor = 1; } } /* ** Name: ** framecombine_slow - slow'n'safe frame combination ** ** Interface: ** #include "mci.h" ** ** static void ** framecombine_slow(int rgbframes[3], ** unsigned elems, unsigned lines, ** int grframe, ** int gb_shm_key ** bool do_zoom) ** ** Input: ** rgbframes - array of 3 frame numbers for R, G, B ** elems - number of elements in frame ** lines - number of lines in frame ** grframe - if nonzero get graphics from this frame ** gb_shm_key - if nonzero get G, B frame data from this shm key ** do_zoom - nonzero if frame should be zoomed ** ** INPUT and Output: ** none ** ** Output: ** none ** ** Return values: ** none ** ** Remarks: ** non-optimal but safe method of combining McIDAS frames into an XImage ** ** Categories: ** none */ static void framecombine_slow(int rgbframes[3], unsigned elems, unsigned lines, int grframe, int gb_shm_key, Bool do_zoom) { int top = 0; int bottom = lines; int right = elems; int allocated = 1; int start; unsigned char *f_alloc[3]; const unsigned char *frame[3]; const int *stretch[3]; const unsigned *color[3]; int frame_elems[3], frame_lines[3]; int f, i, j; int iz, jz, k, l; unsigned char *m0gbuc; XVisualInfo *vlist; XVisualInfo vtemplate; int match; int Red,Green,Blue; /* color mask values */ int ColorOrder=1; /* set to 1 if RGB or 0 if BGR */ /* --- Need to determine the color order RGB vs BGR being the most common */ memset(&vtemplate,0,sizeof(XVisualInfo)); vtemplate.screen=screen_num; vtemplate.depth=24; vlist=XGetVisualInfo(display,VisualScreenMask|VisualDepthMask, &vtemplate,&match); if(vlist!=NULL) { for(i=0;iGreen && Green>Blue) ColorOrder=1; /* have an RGB video card */ else if(Blue>Green && Green>Red) ColorOrder=0; /* have a BGR video card */ break; } } XFree(vlist); } /* connect to our gb_shm_key if provided */ if (gb_shm_key > 0) { m0gbuc = (unsigned char *)M0shmat(gb_shm_key, 0); } /* offset from start of frame to start of update */ start = 0; /* find frame-specific values */ for (f = 0; f < 3; f++) { const Fint *frame_base; const Fint *gr_base; size_t frame_bytes; /* get frame dimensions */ frame_elems[f] = ELEM_SIZE(rgbframes[f]); frame_lines[f] = LINE_SIZE(rgbframes[f]); /* get start of frame metadata */ frame_base = FRAME_BASE(rgbframes[f]); gr_base = frame_base; if (grframe > 0) { gr_base = FRAME_BASE(grframe); } /* try to allocate a new frame */ frame_bytes = frame_elems[f] * frame_lines[f]; if (allocated) { f_alloc[f] = (unsigned char *)malloc(frame_bytes); } else { f_alloc[f] = 0; } if (!f_alloc[f]) { allocated = 0; } else { frame[f] = f_alloc[f]; if (grframe > 0) { if (!image_visible) { memset(f_alloc[f], 0, frame_bytes); } else if (gb_shm_key > 0 && f > 0) { memmove(f_alloc[f], (m0gbuc + ((f-1)*frame_bytes)), frame_bytes); } else if (rgbframes[f] > 0) { memmove(f_alloc[f], FRAME_DATA(frame_base), frame_bytes); } else { memset(f_alloc[f], 0, frame_bytes); } M0GraphicsDecodeToImageBuffer(grframe, (unsigned char *)f_alloc[f]); } else { memmove(f_alloc[f], FRAME_DATA(frame_base), frame_bytes); M0GraphicsDecodeToImageBuffer(rgbframes[f], (unsigned char *)f_alloc[f]); } /* get location of frame stretch table */ stretch[f] = FRAME_STRETCH(gr_base); /* get location of frame color table */ color[f] = FRAME_COLOR(gr_base); } } if (!allocated) { Mceprintf("Couldn't allocate buffers for combined frame\n"); } else { /* image Y coord is reversed */ bottom = lines; top = 1; /* write actual pixels to image buffer */ top--; for (i = bottom - 1; i >= 1; i--) { for (j = 0; j < right; j++) { unsigned long pixel; pixel = 0; for (f = 0; f < 3; f++) { #ifdef M0ASSERT_ON_IGNORED unsigned long floc = frame - fstart; unsigned long ix, iy; unsigned long fx, fy; M0ASSERT(frame >= fstart); M0ASSERT(frame <= fend); ix = j; iy = lines - i - 1; fx = floc % elems; fy = floc / elems; M0ASSERT(iy == fy); M0ASSERT(ix == fx); #endif /* M0ASSERT_ON_IGNORED */ if (i <= frame_lines[f] && j < frame_elems[f]) { unsigned c = color[f][stretch[f][*frame[f]++]]; switch (f) { case 0: if(ColorOrder==1) pixel |= (RGBR(c)<<16); else pixel |= RGBR(c); break; case 1: pixel |= (RGBG(c)<<8); break; case 2: if(ColorOrder==1) pixel |= RGBB(c); else pixel |= (RGBB(c)<<16); break; } } } /* No zoom, 1:1 */ if (!do_zoom) { XPutPixel(image->image, j, i, pixel); } /* Zoom */ else { iz = i * zoom_factor; jz = j * zoom_factor; for (k = 0; k < (int)zoom_factor; k++) { for (l = 0; l < (int)zoom_factor; l++) { XPutPixel(image->image, jz + l, iz + k, pixel); } } } } } } if (gb_shm_key > 0) { shmdt(m0gbuc); } /* clean up temporarily allocated memory */ for(f=0;f<3;f++) { if (f_alloc[f]) { free(f_alloc[f]); } } } static void frame_combine(unsigned elems, unsigned lines) { #ifdef DEBUG_FRAME_UPDATE Mcdprintf("Combining %ux%u frames in image buffer\n", elems, lines); #endif /* DEBUG_FRAME_UPDATE */ /* write pixels to image buffer */ framecombine_slow(combineframe, elems, lines, 0, 0, False); image->cur_width = elems; image->cur_height = lines; image->zoom_factor = 1; } static void frame_rgb(int frame_num, Bool do_zoom) { const Fint *frame_base; M0frameflags *frame_flags; unsigned char *frame; int rgb_frames[3]; int frame_type; unsigned elems, lines; int i, ul_elem, ul_line, lr_elem, lr_line; /* get pointer to frame data for the requested frame */ frame_base = FRAME_BASE(frame_num); /* ptr to frame data */ frame = FRAME_DATA(frame_base); /* get pointer to frame flags */ frame_flags = FRAME_FLAGS(frame_base); /* get dimensions */ elems = ELEM_SIZE(frame_num); lines = LINE_SIZE(frame_num); ul_elem = 1; ul_line = 1; lr_elem = elems; lr_line = lines; /* Combine from other frame data */ if (frame_flags->frame_type == 1) { rgb_frames[0] = frame_flags->r_frame; rgb_frames[1] = frame_flags->g_frame; rgb_frames[2] = frame_flags->b_frame; framecombine_slow(rgb_frames, elems, lines, frame_num, 0, do_zoom); } /* Combine from linked shared memory segment */ else if (frame_flags->frame_type == 2) { rgb_frames[0] = frame_flags->r_frame; rgb_frames[1] = frame_flags->g_frame; rgb_frames[2] = frame_flags->b_frame; framecombine_slow(rgb_frames, elems, lines, frame_num, frame_flags->gb_shm_key, do_zoom); } if (do_zoom) { image->cur_width = elems * zoom_factor; image->cur_height = lines * zoom_factor; image->zoom_factor = zoom_factor; } else { image->cur_width = elems; image->cur_height = lines; image->zoom_factor = 1; } } /* ** Name: ** image_to_pixmap - copy minimal piece of XImage to pixmap buffer ** ** Interface: ** #include "mci.h" ** ** static void ** image_to_pixmap(pixmapInfo *pinfo, unsigned elems, unsigned lines, ** int ul_elem, int ul_line, int lr_elem, int lr_line) ** ** Input: ** pinfo - pixmap buffer to update ** elems - number of elements in image ** lines - number of lines in image ** ul_elem - leftmost changed element ** ul_line - uppermost changed line ** lr_elem - rightmost changed element ** lr_line - lowermost changed line ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** none ** ** Remarks: ** none ** ** Categories: ** none */ static void image_to_pixmap(pixmapInfo *pinfo, unsigned elems, unsigned lines, int left, int top, int right, int bottom) { #ifdef M0ASSERT_ON { M0ASSERT(elems <= image->max_width); M0ASSERT(lines <= image->max_height); M0ASSERT(elems <= pinfo->max_width); M0ASSERT(lines <= pinfo->max_height); M0ASSERT(left > 0); M0ASSERT(left <= elems); M0ASSERT(top > 0); M0ASSERT(top <= lines); M0ASSERT(right > 0); M0ASSERT(right <= elems); M0ASSERT(bottom > 0); M0ASSERT(bottom <= lines); M0ASSERT(left <= right); M0ASSERT(top <= bottom); } #endif /* M0ASSERT_ON */ /* zoom dimensions if desired */ if (image->zoom_factor > 1) { left = ((left - 1) * image->zoom_factor) + 1; top = ((top - 1) * image->zoom_factor) + 1; right *= image->zoom_factor; bottom *= image->zoom_factor; } else if (!support_zoom) { double warp_x = (double )window_width / (double )elems; double warp_y = (double )window_height / (double )lines; left = (left - 1) * warp_x; if (left < 1) { left = 1; } top = (top - 1) * warp_y; if (top < 1) { top = 1; } right = (right + 1) * warp_x; if (right > window_width) { right = window_width; } bottom = (bottom + 1) * warp_y; if (bottom > window_height) { bottom = window_height; } } /* copy image to pixmap */ #ifdef MIT_SHM_EXTENSION if (image->shared) { XShmPutImage(display, pinfo->pixmap, image_gc, image->image, left - 1, top - 1, left - 1, top - 1, right - left + 1, bottom - top + 1, False); } else #endif /* MIT_SHM_EXTENSION */ { XPutImage(display, pinfo->pixmap, image_gc, image->image, left - 1, top - 1, left - 1, top - 1, right - left + 1, bottom - top + 1); } pinfo->cur_width = image->cur_width; pinfo->cur_height = image->cur_height; pinfo->zoom_factor = image->zoom_factor; XSync(display, False); } /* ** Name: ** is_color_changed - return nonzero if McIDAS color differs ** from XColor ** ** Interface: ** #include "mci.h" ** ** Bool ** is_color_changed(unsigned color_word, XColor *cell) ** ** Input: ** color_word - McIDAS color ** cell - pointer to X color ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** none ** ** Remarks: ** none ** ** Categories: ** none */ Bool is_color_changed(unsigned color_word, XColor *cell) { unsigned red, green, blue; /* extract colors from this word */ red = (RGBR(color_word) << 8) & 0xff00; green = (RGBG(color_word) << 8) & 0xff00; blue = (RGBB(color_word) << 8) & 0xff00; /* return false if color didn't change */ if (red == (*cell).red && green == (*cell).green && blue == (*cell).blue) { return(False); } /* change colormap cell */ (*cell).flags = DoRed | DoGreen | DoBlue; (*cell).red = red; (*cell).green = green; (*cell).blue = blue; #ifdef DEBUG_COLOR_CHANGES if (cell == &bkgnd_color) { Mcdprintf("is_color_changed: updating bkgnd_color to %d/%d/%d\n", ((*cell).red >> 8), ((*cell).green >> 8), ((*cell).blue >> 8)); } else if (cell >= &graphics_cell[0] && cell <= &graphics_cell[num_graphics_colors-1]) { int grnum = cell - &graphics_cell[0]; Mcdprintf("is_color_changed: updating graphics_cell[%d] to %d/%d/%d\n", grnum, ((*cell).red >> 8), ((*cell).green >> 8), ((*cell).blue >> 8)); } #endif /* DEBUG_COLOR_CHANGES */ return(True); } /* ** Name: ** frame_colormap_changes - return bitmapped list of changed colormaps ** ** Interface: ** #include "mci.h" ** ** static changedColormapFlag ** frame_colormap_changes(int frame_num) ** ** Input: ** frame_num - number of frame to check ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** bitmap list of all colormaps which have changed values ** ** Remarks: ** none ** ** Categories: ** none */ static changedColormapFlag frame_colormap_changes(int frame_num) { changedColormapFlag changed; Fint *frame_base; unsigned *mccolor; int *mcstretch; int i; unsigned stretch_color; unsigned median_word; int image_offset; #ifdef M0ASSERT_ON { M0ASSERT((frame_num >= 1) && (frame_num <= number_of_frames)); } #endif /* M0ASSERT_ON */ /* change flag is first word of frame */ frame_base = FRAME_BASE(frame_num); /* get pointers to color and stretch tables */ mccolor = FRAME_COLOR(frame_base); mcstretch = FRAME_STRETCH(frame_base); /* sanity-check stretch table */ for (i = 0; i < 256; i++) { stretch_color = mcstretch[i]; if (stretch_color > NUM_UC_COLORS) { stretch_color %= NUM_UC_COLORS; Mceprintf("Adjusted stretch %d from %d to %d\n", i, mcstretch[i], stretch_color); mcstretch[i] = stretch_color; } } /* check (and possibly alter) McIDAS colormaps */ changed = changedNone; /* if only graphics are turned off, calculate a nice median color */ if (image_visible && !graphics_visible) { unsigned long med_red, med_blue, med_green; med_red = med_blue = med_green = 0; for (i = 0; i < num_image_colors; i++) { median_word = mccolor[BKGND_COLORS+CURSOR_COLORS+num_graphics_colors+i]; med_red += RGBR(median_word); med_green += RGBG(median_word); med_blue += RGBB(median_word); } med_red /= num_image_colors; med_green /= num_image_colors; med_blue /= num_image_colors; median_word = RGBF(0, med_red, med_green, med_blue); } else { median_word = RGBF(0, (((unsigned )bkgnd_color.red) >> 8), (((unsigned )bkgnd_color.green) >> 8), (((unsigned )bkgnd_color.blue) >> 8)); } /* check background color */ if (is_color_changed(mccolor[0], &bkgnd_color)) { #ifdef DEBUG_COLOR_CHANGES Mcdprintf("frame_colormap_changes: changed bkgnd_color(%d/%d/%d)\n", (bkgnd_color.red >> 8), (bkgnd_color.green >> 8), (bkgnd_color.blue >> 8)); #endif /* DEBUG_COLOR_CHANGES */ changed |= changedBackground; } /* check graphics colors */ for (i = 0; i < num_graphics_colors; i++) { if (is_color_changed(graphics_visible ? mccolor[BKGND_COLORS+CURSOR_COLORS+i] : median_word, &graphics_cell[i])) { #ifdef DEBUG_COLOR_CHANGES unsigned x = (graphics_visible ? mccolor[BKGND_COLORS+CURSOR_COLORS+i] : median_word); Mcdprintf("frame_colormap_changes: changed graphics_cell[%d](%d/%d/%d)\n", i, (graphics_cell[i].red >> 8), (graphics_cell[i].green >> 8), (graphics_cell[i].blue >> 8)); #endif /* DEBUG_COLOR_CHANGES */ changed |= changedGraphics; } } /* check image colors */ image_offset = BKGND_COLORS+CURSOR_COLORS+num_graphics_colors; for (i = 0; i < num_image_colors; i++) { if (is_color_changed(image_visible ? mccolor[image_offset+i] : median_word, &image_cell[i])) { changed |= changedImage; } } return(changed); } /* ** Name: ** update_frame - display frame in image window ** ** Interface: ** #include "mci.h" ** ** void ** update_frame(int frame_num, Bool update_window, Bool do_resize) ** ** Input: ** frame_num - number of frame to display ** update_window - True if frame should be written to the window ** do_resize - True if window has already been resized ** ** Input and Output: ** none ** ** Output: ** none ** ** Return values: ** none ** ** Remarks: ** this routine has been hacked mercilessly ** ** Categories: ** none */ void update_frame(int frame_num, Bool update_window, Bool do_resize) { #if defined(TIME_FRAME_UPDATE) || defined(TIME_100_FRAMES) struct timeval now; unsigned long time0; unsigned long time1, time2, time3, time4, time5; unsigned long time6, time7, time8, time9, timeA; static unsigned long sect1 = 0, sect2 = 0, sect3 = 0, sect4 = 0, sect5 = 0; static unsigned long sect6 = 0, sect7 = 0, sect8 = 0, sect9 = 0, sectA = 0; #endif /* TIME_FRAME_UPDATE || TIME_100_FRAMES */ #if defined(TIME_FRAME_UPDATE) || defined(TIME_100_FRAMES) static unsigned reps = 0; #endif /* TIME_FRAME_UPDATE || TIME_100_FRAMES */ M0frameflags *frame_flags; pixmapInfo *pinfo; unsigned elems, lines; unsigned zelems, zlines; int RGB_MODE; int r_frame, g_frame, b_frame; Bool zoom_changed; Bool do_zoom; Bool dirty; static Bool FirstPass=True; /* need to set up the color maps in PsuedoColor mode once before */ /* doing any blitting -- after that, all is well */ #ifdef M0ASSERT_ON M0ASSERT((frame_num >= 1) && (frame_num <= number_of_frames)); #endif /* M0ASSERT_ON */ RGB_MODE = 0; frame_flags = FRAME_FLAGS(FRAME_BASE(frame_num)); /* Make RGB from other frames */ if (frame_flags->frame_type == 1) { r_frame = frame_flags->r_frame; g_frame = frame_flags->g_frame; b_frame = frame_flags->b_frame; Mcdprintf("frame %d is RGB from frames %d, %d, %d\n", frame_num, r_frame, g_frame, b_frame); lines = LINE_SIZE(frame_num); elems = ELEM_SIZE(frame_num); if ( (r_frame > 0 && (lines != LINE_SIZE(r_frame) || elems != ELEM_SIZE(r_frame))) || (g_frame > 0 && (lines != LINE_SIZE(g_frame) || elems != ELEM_SIZE(g_frame))) || (b_frame > 0 && (lines != LINE_SIZE(b_frame) || elems != ELEM_SIZE(b_frame))) ) { Mceprintf("Frame sizes must match\n"); return; } RGB_MODE = 1; } /* Make RGB from ADDE */ else if (frame_flags->frame_type == 2) { Mcdprintf("frame %d is RGB from datasets\n", frame_num); RGB_MODE = 2; } #ifdef DEBUG_FRAME_UPDATE Mcdprintf("update_frame(%d)\n", frame_num); #endif /* DEBUG_FRAME_UPDATE */ #if defined(TIME_FRAME_UPDATE) || defined(TIME_100_FRAMES) gettimeofday(&now, NULL); time0 = USEC_TIME(now); time1 = time2 = time3 = time4 = time5 = 0; time6 = time7 = time8 = time9 = timeA = 0; #endif /* TIME_FRAME_UPDATE || TIME_100_FRAMES */ /* if necessary, update cursor information in UC */ if (MCIMAGE_MODE && Mcluc(UC_UPDATE_CURSOR_INFO)) { update_brightness(1); update_lat_lon(1); } /* get information for appropriate pixmap buffer */ pinfo = pixmap_info(frame_num); if (pinfo == NULL) { Mceprintf("no pixmap for frame %d (in update_image())\n", frame_num); return; } /* nothing to do if not updating window and using image buffers */ if (!update_window && pinfo->is_image_buffer) { return; } /* see if user has forced redraw */ char *redraw = getenv("MCREDRAW_IMAGE"); if (redraw) mark_frame_dirty(frame_num); /* remember whether or not this frame is dirty */ if (COMBINE_MODE) { dirty = 1; } else if (RGB_MODE) { dirty = is_dirty_frame(frame_num); } else { dirty = is_dirty_frame(frame_num); } /* get height & width for this frame */ if (!COMBINE_MODE && !RGB_MODE) { lines = LINE_SIZE(frame_num); elems = ELEM_SIZE(frame_num); } else if (RGB_MODE) { lines = LINE_SIZE(frame_num); elems = ELEM_SIZE(frame_num); } else { int i, l, e; for (i = lines = elems = 0; i < 3; i++) { l = LINE_SIZE(combineframe[i]); if (l > lines) { lines = l; } e = ELEM_SIZE(combineframe[i]); if (e > elems) { elems = e; } } } /* make a private copy of the zoom state */ do_zoom = zoomed; /* get zoomed/warped height & width */ if (do_zoom) { zelems = elems * zoom_factor; zlines = lines * zoom_factor; } else if (!support_zoom) { zelems = window_width; zlines = window_height; } else { zelems = elems; zlines = lines; } #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time1 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("1:Found pixmap, got lock, did some math\n"); #endif /* DEBUG_FRAME_UPDATE */ if (pinfo->max_height < zlines || pinfo->max_width < zelems) { unsigned wid = pinfo->max_width > zelems ? pinfo->max_width : zelems; unsigned hgt = pinfo->max_height > zlines ? pinfo->max_height : zlines; if (resize_pixmap_entry(pinfo, wid, hgt)) { /* change frame flags to indicate that our frame is dirty */ mark_frame_dirty(frame_num); } else { if (do_zoom) { Mceprintf("Not enough memory to zoom frame %d\n", frame_num); do_zoom = False; } else { Mceprintf("Not enough memory to resize %sframe %d\n", (BRIEFING_MODE ? "briefing " : (COMBINE_MODE ? "combine" : "")), frame_num); if (!support_zoom) { resize_window(elems, lines); } } zlines = lines; zelems = elems; } #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time2 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("2:Resized pixmap\n"); #endif /* DEBUG_FRAME_UPDATE */ } if (image->max_height < zlines || image->max_width < zelems) { if (!resize_image((image->max_width > zelems ? image->max_width : zelems), (image->max_height > zlines ? image->max_height : zlines))) { Mceprintf("Failed to resize image\n"); cleanup_and_exit(SIGUSR1); } /* change frame flags to indicate that our frame is dirty */ mark_frame_dirty(frame_num); #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time3 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("3:Resized image\n"); #endif /* DEBUG_FRAME_UPDATE */ } /* nonzero if zoom-related changes are causing a complete redraw */ if (support_zoom) { zoom_changed = (pinfo->zoom_factor != (do_zoom ? zoom_factor : 1)); } else { zoom_changed = zelems != pinfo->cur_width || zlines != pinfo->cur_height; } #ifdef DEBUG_FRAME_UPDATE { Mcdprintf(" %sdirty", dirty ? "" : "!"); Mcdprintf(" %szoom_changed", zoom_changed ? "" : "!"); if (pinfo->is_image_buffer && current_frame != frame_num) { Mcdprintf(" (is_img_buf && cur_frame != frame_num)"); } else { if (pinfo->is_image_buffer) { Mcdprintf(" (is_img_buf && !(cur_frame %d != frame_num %d))", current_frame, frame_num); } else if (current_frame != frame_num) { Mcdprintf(" (!is_img_buf && cur_frame != frame_num)"); } else { Mcdprintf(" !(is_img_buf && cur_frame %d != frame_num %d)", current_frame, frame_num); } } Mcdprintf("\n"); } #endif /* DEBUG_FRAME_UPDATE */ /* * if frame was changed, * or if zoom was toggled, * or if we're using a single pixmap buffer and this is a new frame, * write the frame to a pixmap */ if (dirty || zoom_changed || (pinfo->is_image_buffer && current_frame != frame_num)) { int ul_elem, ul_line, lr_elem, lr_line; /* turn off frame-change flag, since we're about to copy the image */ if (!COMBINE_MODE && !RGB_MODE) { mark_frame_clean(frame_num, &ul_elem, &ul_line, &lr_elem, &lr_line); } else if (RGB_MODE) { if (RGB_MODE == 1) { if (frame_flags->r_frame > 0) { mark_frame_clean(frame_flags->r_frame, &ul_elem, &ul_line, &lr_elem, &lr_line); } if (frame_flags->g_frame > 0) { mark_frame_clean(frame_flags->g_frame, &ul_elem, &ul_line, &lr_elem, &lr_line); } if (frame_flags->b_frame > 0) { mark_frame_clean(frame_flags->b_frame, &ul_elem, &ul_line, &lr_elem, &lr_line); } } } else { int i; for (i = 0; i < 3; i++) { mark_frame_clean(combineframe[i], &ul_elem, &ul_line, &lr_elem, &lr_line); } } /* if we switched frames and are using image buffer, update everything */ if (zoom_changed || (pinfo->is_image_buffer && current_frame != frame_num) || COMBINE_MODE || RGB_MODE) { ul_elem = 1; ul_line = 1; lr_elem = elems; lr_line = lines; } #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time4 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ /* if running in NON-8bit visual then update the colormap BEFORE the Pixmap step */ /* or if on the first pass in Psuedo-color mode so that the Colortables and pixmaps */ /* have an initial state */ if(Mcluc(UC_NON_VIS_8BIT) || FirstPass) { FirstPass=False; /* if (update_window) -- update by default in this mode*/ { changedColormapFlag cmap_change_bits; cmap_change_bits = frame_colormap_changes(frame_num); if (cmap_change_bits != changedNone) { if (cmap_change_bits & changedBackground) save_colors(&bkgnd_color, 1); } if (cmap_change_bits & changedGraphics) save_colors(graphics_cell, num_graphics_colors); if (cmap_change_bits & changedImage) save_colors(image_cell, num_image_colors); } } #ifdef DEBUG_FRAME_UPDATE Mcdprintf("4:Ready for updates\n"); #endif /* DEBUG_FRAME_UPDATE */ /* copy the frame to our image buffer */ if (COMBINE_MODE) { frame_combine(elems, lines); } else if (RGB_MODE) { frame_rgb(frame_num, do_zoom); } else { frame_to_image(frame_num, elems, lines, ul_elem, ul_line, lr_elem, lr_line, do_zoom); } #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time5 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("5:Updated image buffer\n"); #endif /* DEBUG_FRAME_UPDATE */ image_to_pixmap(pinfo, elems, lines, ul_elem, ul_line, lr_elem, lr_line); #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time6 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("6:Updated pixmap buffer\n"); #endif /* DEBUG_FRAME_UPDATE */ /* Mark new RGB frame as clean */ if (RGB_MODE) { /* Set dirty=0 to work around DEFINE MCIMAGE_MODE check in mark_frame_clean */ M0frameflags *frame_flags = FRAME_FLAGS(FRAME_BASE(frame_num)); frame_flags->dirty = 0; mark_frame_clean(frame_num, &ul_elem, &ul_line, &lr_elem, &lr_line); } } /* if running an 8bit visual then update the colormap AFTER the Pixmap step */ if(!Mcluc(UC_NON_VIS_8BIT)) { if (update_window) { changedColormapFlag cmap_change_bits; cmap_change_bits = frame_colormap_changes(frame_num); if (cmap_change_bits != changedNone) { if (cmap_change_bits & changedBackground) save_colors(&bkgnd_color, 1); } if (cmap_change_bits & changedGraphics) save_colors(graphics_cell, num_graphics_colors); if (cmap_change_bits & changedImage) save_colors(image_cell, num_image_colors); } } if (update_window) { #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time7 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("7:Stored colormap changes\n"); #endif /* DEBUG_FRAME_UPDATE */ /* autoresize window? */ if (auto_resize && do_resize) { resize_window(zelems, zlines); } /* update the window */ copy_and_fill(pinfo->pixmap, offset_x, offset_y, zelems, zlines, window, 0, 0, window_width, window_height); #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time8 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("8:Copied and filled\n"); #endif /* DEBUG_FRAME_UPDATE */ /* frame is now updated */ current_frame = frame_num; /* if we're managing the cursor, draw it in now */ if (MCIMAGE_MODE) { invalidate_cursor_patch(); draw_big_cursor(); } #ifdef TIME_FRAME_UPDATE gettimeofday(&now, NULL); time9 = USEC_TIME(now); #endif /* TIME_FRAME_UPDATE */ #ifdef DEBUG_FRAME_UPDATE Mcdprintf("9:Drew big cursor\n"); #endif /* DEBUG_FRAME_UPDATE */ XSync(display, False); } #ifdef DEBUG_FRAME_UPDATE { const char *pmstr = "Buffered"; const char *shstr = "Local"; if (pinfo->is_image_buffer) pmstr = "Offscreen"; #ifdef MIT_SHM_EXTENSION if (image->shared) shstr = "Shared"; #endif /* MIT_SHM_EXTENSION */ Mcdprintf("Used %s pixmap, %s image\n", pmstr, shstr); } #endif /* DEBUG_FRAME_UPDATE */ #if defined(TIME_FRAME_UPDATE) || defined(TIME_100_FRAMES) gettimeofday(&now, NULL); timeA = USEC_TIME(now); #define updatesect(s, t0, t1) if ((t1)>0) (s)+=(t1)-(t0); else (t1)=(t0) updatesect(sect1, time0, time1); updatesect(sect2, time1, time2); updatesect(sect3, time2, time3); updatesect(sect4, time3, time4); updatesect(sect5, time4, time5); updatesect(sect6, time5, time6); updatesect(sect7, time6, time7); updatesect(sect8, time7, time8); updatesect(sect9, time8, time9); updatesect(sectA, time9, timeA); #undef updatesect reps++; time0 = sect1 + sect2 + sect3 + sect4 + sect5; time0 += sect6 + sect7 + sect8 + sect9 + sectA; #ifdef TIME_FRAME_UPDATE #define pcttime(val) (unsigned long)((((float)(val))/((float)(time0)))*100) Mcdprintf("update_frame times: %ld(%ld) %ld(%ld) %ld(%ld) %ld(%ld) %ld(%ld) %ld(%ld) %ld(%ld) %ld(%ld) %ld(%ld) %ld(%ld)\n", sect1, pcttime(sect1), sect2, pcttime(sect2), sect3, pcttime(sect3), sect4, pcttime(sect4), sect5, pcttime(sect5), sect6, pcttime(sect6), sect7, pcttime(sect7), sect8, pcttime(sect8), sect9, pcttime(sect9), sectA, pcttime(sectA)); #undef pcttime #endif /* TIME_FRAME_UPDATE */ #ifdef TIME_100_FRAMES if (reps >= 100) #endif /* TIME_100_FRAMES */ { time0 /= (long)reps; Mcdprintf("Average update time: %7.4f (for %d reps)\n", (double )time0/1000000.0, reps); #ifdef TIME_100_FRAMES cleanup_and_exit(0); #endif /* TIME_100_FRAMES */ } #endif /* TIME_FRAME_UPDATE || TIME_100_FRAMES */ }