home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / image_map.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  11.3 KB  |  385 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <glib.h>
  22.  
  23. #include "apptypes.h"
  24.  
  25. #include "appenv.h"
  26. #include "drawable.h"
  27. #include "gdisplay.h"
  28. #include "gimage.h"
  29. #include "gimage_mask.h"
  30. #include "image_map.h"
  31. #include "tile_manager.h"
  32.  
  33. #include "tile_manager_pvt.h"
  34.  
  35.  
  36. #define WAITING 0
  37. #define WORKING 1
  38.  
  39. #define WORK_DELAY 1
  40.  
  41. /*  Local structures  */
  42. typedef struct _ImageMap
  43. {
  44.   GDisplay          *gdisp;
  45.   GimpDrawable      *drawable;
  46.   TileManager       *undo_tiles;
  47.   ImageMapApplyFunc  apply_func;
  48.   gpointer           user_data;
  49.   PixelRegion        srcPR, destPR;
  50.   void              *pr;
  51.   gint               state;
  52.   gint               idle;
  53. } _ImageMap;
  54.  
  55.  
  56. /**************************/
  57. /*  Function definitions  */
  58.  
  59. static gint
  60. image_map_do (gpointer data)
  61. {
  62.   _ImageMap *_image_map;
  63.   GImage *gimage;
  64.   PixelRegion shadowPR;
  65.   int x, y, w, h;
  66.  
  67.   _image_map = (_ImageMap *) data;
  68.  
  69.   if (! (gimage = drawable_gimage ( (_image_map->drawable))))
  70.     {
  71.       _image_map->state = WAITING;
  72.       return FALSE;
  73.     }
  74.  
  75.   /*  Process the pixel regions and apply the image mapping  */
  76.   (* _image_map->apply_func) (&_image_map->srcPR, &_image_map->destPR, _image_map->user_data);
  77.  
  78.   x = _image_map->destPR.x;
  79.   y = _image_map->destPR.y;
  80.   w = _image_map->destPR.w;
  81.   h = _image_map->destPR.h;
  82.  
  83.   /*  apply the results  */
  84.   pixel_region_init (&shadowPR, gimage->shadow, x, y, w, h, FALSE);
  85.   gimage_apply_image (gimage, _image_map->drawable, &shadowPR,
  86.               FALSE, OPAQUE_OPACITY, REPLACE_MODE, NULL, x, y);
  87.  
  88.   /*  display the results  */
  89.   if (_image_map->gdisp)
  90.     {
  91.       drawable_update ( (_image_map->drawable), x, y, w, h);
  92.       gdisplay_flush_now (_image_map->gdisp);
  93.     }
  94.  
  95.   _image_map->pr = pixel_regions_process (_image_map->pr);
  96.  
  97.   if (_image_map->pr == NULL)
  98.     {
  99.       _image_map->state = WAITING;
  100.       gdisplays_flush ();
  101.       return FALSE;
  102.     }
  103.   else
  104.     return TRUE;
  105. }
  106.  
  107. ImageMap
  108. image_map_create (void         *gdisp_ptr,
  109.           GimpDrawable *drawable)
  110. {
  111.   _ImageMap *_image_map;
  112.  
  113.   _image_map = g_new (_ImageMap, 1);
  114.   _image_map->gdisp = (GDisplay *) gdisp_ptr;
  115.   _image_map->drawable = drawable;
  116.   _image_map->undo_tiles = NULL;
  117.   _image_map->state = WAITING;
  118.  
  119.   /* Interactive tools based on image_map disable the undo stack */
  120.   /* to avert any unintented undo interaction through the UI     */
  121.  
  122.   gimp_image_undo_freeze(_image_map->gdisp->gimage);
  123.   gdisplay_set_menu_sensitivity (_image_map->gdisp);
  124.   return (ImageMap) _image_map;
  125. }
  126.  
  127. void
  128. image_map_apply (ImageMap           image_map,
  129.          ImageMapApplyFunc  apply_func,
  130.          void              *user_data)
  131. {
  132.   _ImageMap *_image_map;
  133.   gint x1, y1, x2, y2;
  134.  
  135.   _image_map = (_ImageMap *) image_map;
  136.   _image_map->apply_func = apply_func;
  137.   _image_map->user_data = user_data;
  138.  
  139.   /*  If we're still working, remove the timer  */
  140.   if (_image_map->state == WORKING)
  141.     {
  142.       gtk_idle_remove (_image_map->idle);
  143.       pixel_regions_process_stop (_image_map->pr);
  144.       _image_map->pr = NULL;
  145.     }
  146.  
  147.   /*  Make sure the drawable is still valid  */
  148.   if (! drawable_gimage ( (_image_map->drawable)))
  149.     return;
  150.  
  151.   /*  The application should occur only within selection bounds  */
  152.   drawable_mask_bounds ( (_image_map->drawable), &x1, &y1, &x2, &y2);
  153.  
  154.   /*  If undo tiles don't exist, or change size, (re)allocate  */
  155.   if (!_image_map->undo_tiles ||
  156.       _image_map->undo_tiles->x != x1 ||
  157.       _image_map->undo_tiles->y != y1 ||
  158.       _image_map->undo_tiles->width != (x2 - x1) ||
  159.       _image_map->undo_tiles->height != (y2 - y1))
  160.     {
  161.       /*  If either the extents changed or the tiles don't exist, allocate new  */
  162.       if (!_image_map->undo_tiles ||
  163.       _image_map->undo_tiles->width != (x2 - x1) ||
  164.       _image_map->undo_tiles->height != (y2 - y1))
  165.     {
  166.       /*  Destroy old tiles--If they exist  */
  167.       if (_image_map->undo_tiles != NULL)
  168.         tile_manager_destroy (_image_map->undo_tiles);
  169.       
  170.       /*  Allocate new tiles  */
  171.       _image_map->undo_tiles = tile_manager_new ((x2 - x1), (y2 - y1),
  172.                              drawable_bytes ( (_image_map->drawable)));
  173.     }
  174.  
  175.       /*  Copy from the image to the new tiles  */
  176.       pixel_region_init (&_image_map->srcPR, drawable_data ( (_image_map->drawable)),
  177.              x1, y1, (x2 - x1), (y2 - y1), FALSE);
  178.       pixel_region_init (&_image_map->destPR, _image_map->undo_tiles,
  179.              0, 0, (x2 - x1), (y2 - y1), TRUE);
  180.  
  181.       copy_region (&_image_map->srcPR, &_image_map->destPR);
  182.  
  183.       /*  Set the offsets  */
  184.       _image_map->undo_tiles->x = x1;
  185.       _image_map->undo_tiles->y = y1;
  186.     }
  187.   else /* _image_map->undo_tiles exist AND drawable dimensions have not changed... */
  188.     {
  189.       /* Reset to initial drawable conditions.            */
  190.       /* Copy from the backup undo tiles to the drawable  */
  191.       pixel_region_init (&_image_map->srcPR, _image_map->undo_tiles, 0, 0,
  192.              _image_map->undo_tiles->width,
  193.              _image_map->undo_tiles->height,
  194.              FALSE);
  195.       pixel_region_init (&_image_map->destPR, drawable_data ( (_image_map->drawable)),
  196.              _image_map->undo_tiles->x, _image_map->undo_tiles->y,
  197.              _image_map->undo_tiles->width,
  198.              _image_map->undo_tiles->height,
  199.              TRUE);
  200.  
  201.       copy_region (&_image_map->srcPR, &_image_map->destPR);
  202.     }
  203.  
  204.   /*  Configure the src from the drawable data  */
  205.   pixel_region_init (&_image_map->srcPR, _image_map->undo_tiles,
  206.              0, 0, (x2 - x1), (y2 - y1), FALSE);
  207.  
  208.   /*  Configure the dest as the shadow buffer  */
  209.   pixel_region_init (&_image_map->destPR, drawable_shadow ( (_image_map->drawable)),
  210.              x1, y1, (x2 - x1), (y2 - y1), TRUE);
  211.  
  212.   /*  Apply the image transformation to the pixels  */
  213.   _image_map->pr = pixel_regions_register (2, &_image_map->srcPR, &_image_map->destPR);
  214.  
  215.   /*  Start the intermittant work procedure  */
  216.   _image_map->state = WORKING;
  217.   _image_map->idle = gtk_idle_add (image_map_do, image_map);
  218. }
  219.  
  220. void
  221. image_map_commit (ImageMap image_map)
  222. {
  223.   _ImageMap *_image_map;
  224.   gint x1, y1, x2, y2;
  225.  
  226.   _image_map = (_ImageMap *) image_map;
  227.  
  228.   if (_image_map->state == WORKING)
  229.     {
  230.       gtk_idle_remove (_image_map->idle);
  231.  
  232.       /*  Finish the changes  */
  233.       while (image_map_do (image_map)) ;
  234.     }
  235.  
  236.   /*  Make sure the drawable is still valid  */
  237.   if (! drawable_gimage ( (_image_map->drawable)))
  238.     return;
  239.  
  240.   /* Interactive phase ends: we can commit an undo frame now */
  241.   gimp_image_undo_thaw(_image_map->gdisp->gimage);
  242.  
  243.   /*  Register an undo step  */
  244.   if (_image_map->undo_tiles)
  245.     {
  246.       x1 = _image_map->undo_tiles->x;
  247.       y1 = _image_map->undo_tiles->y;
  248.       x2 = _image_map->undo_tiles->x + _image_map->undo_tiles->width;
  249.       y2 = _image_map->undo_tiles->y + _image_map->undo_tiles->height;
  250.       drawable_apply_image ( (_image_map->drawable), x1, y1, x2, y2, _image_map->undo_tiles, FALSE);
  251.     }
  252.  
  253.   gdisplay_set_menu_sensitivity (_image_map->gdisp);
  254.   g_free (_image_map);
  255. }
  256.  
  257. void
  258. image_map_clear (ImageMap image_map)
  259. {
  260.   _ImageMap *_image_map;
  261.   PixelRegion srcPR, destPR;
  262.  
  263.   _image_map = (_ImageMap *) image_map;
  264.  
  265.   if (_image_map->state == WORKING)
  266.     {
  267.       gtk_idle_remove (_image_map->idle);
  268.       pixel_regions_process_stop (_image_map->pr);
  269.       _image_map->pr = NULL;
  270.     }
  271.  
  272.   _image_map->state = WAITING;
  273.   /*  Make sure the drawable is still valid  */
  274.   if (! drawable_gimage ( (_image_map->drawable)))
  275.     return;
  276.  
  277.   /*  restore the original image  */
  278.   if (_image_map->undo_tiles)
  279.     {
  280.       /*  Copy from the drawable to the tiles  */
  281.       pixel_region_init (&srcPR, _image_map->undo_tiles, 0, 0,
  282.              _image_map->undo_tiles->width,
  283.              _image_map->undo_tiles->height,
  284.              FALSE);
  285.       pixel_region_init (&destPR, drawable_data ( (_image_map->drawable)),
  286.              _image_map->undo_tiles->x, _image_map->undo_tiles->y,
  287.              _image_map->undo_tiles->width,
  288.              _image_map->undo_tiles->height,
  289.              TRUE);
  290.  
  291.       /* if the user has changed the image depth get out quickly */
  292.       if (destPR.bytes != srcPR.bytes) 
  293.     {
  294.       g_message ("image depth change, unable to restore original image");
  295.       tile_manager_destroy (_image_map->undo_tiles);
  296.           gimp_image_undo_thaw(_image_map->gdisp->gimage);
  297.           gdisplay_set_menu_sensitivity (_image_map->gdisp);
  298.       g_free (_image_map);
  299.       return;
  300.     }
  301.       
  302.       copy_region (&srcPR, &destPR);
  303.  
  304.       /*  Update the area  */
  305.       drawable_update ( (_image_map->drawable),
  306.                _image_map->undo_tiles->x, _image_map->undo_tiles->y,
  307.                _image_map->undo_tiles->width,
  308.                _image_map->undo_tiles->height);
  309.  
  310.       /*  Free the undo_tiles tile manager  */
  311.       tile_manager_destroy (_image_map->undo_tiles);
  312.       _image_map->undo_tiles = NULL;
  313.     }
  314. }
  315.  
  316. void
  317. image_map_abort (ImageMap image_map)
  318. {
  319.   _ImageMap *_image_map = (_ImageMap *) image_map;
  320.  
  321.   image_map_clear(image_map);
  322.   gimp_image_undo_thaw(_image_map->gdisp->gimage);
  323.   gdisplay_set_menu_sensitivity (_image_map->gdisp);
  324.   g_free (image_map);
  325. }
  326.  
  327. unsigned char *
  328. image_map_get_color_at (ImageMap image_map, 
  329.             gint     x, 
  330.             gint     y)
  331. {
  332.   Tile          *tile;
  333.   unsigned char *src;
  334.   unsigned char *dest;
  335.   _ImageMap     *_image_map;
  336.  
  337.   if (!image_map)
  338.     return NULL;
  339.  
  340.   _image_map = (_ImageMap *) image_map;
  341.  
  342.   if (x >= 0 && x < gimp_drawable_width (_image_map->drawable) && 
  343.       y >= 0 && y < gimp_drawable_height (_image_map->drawable))
  344.     {
  345.       /* Check if done damage to original image */
  346.       if (!_image_map->undo_tiles)
  347.     return (gimp_drawable_get_color_at (_image_map->drawable, x, y));
  348.  
  349.       if (!image_map ||
  350.       (!gimp_drawable_gimage(_image_map->drawable) && 
  351.        gimp_drawable_is_indexed(_image_map->drawable)) ||
  352.       x < 0 || y < 0 ||
  353.       x >= _image_map->undo_tiles->width ||
  354.       y >= _image_map->undo_tiles->height)
  355.     {
  356.       return NULL;
  357.     }
  358.  
  359.       dest = g_new(unsigned char, 5);
  360.  
  361.       tile = tile_manager_get_tile (_image_map->undo_tiles, x, y,
  362.                     TRUE, FALSE);
  363.  
  364.       src = tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT);
  365.  
  366.       gimp_image_get_color (gimp_drawable_gimage(_image_map->drawable),
  367.                 gimp_drawable_type (_image_map->drawable), dest, src);
  368.  
  369.       if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_drawable_type (_image_map->drawable)))
  370.     dest[3] = src[gimp_drawable_bytes (_image_map->drawable) - 1];
  371.       else
  372.     dest[3] = 255;
  373.       if (gimp_drawable_is_indexed (_image_map->drawable))
  374.     dest[4] = src[0];
  375.       else
  376.     dest[4] = 0;
  377.       tile_release (tile, FALSE);
  378.       return dest;
  379.     }
  380.   else /* out of bounds error */
  381.     {
  382.       return NULL;
  383.     }
  384. }
  385.