home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / tile_manager.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-29  |  12.1 KB  |  555 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 <string.h>
  20.  
  21. #include "tile_cache.h"
  22. #include "tile_manager.h"
  23. #include "tile_swap.h"
  24.  
  25. #include "tile_manager_pvt.h"
  26. #include "tile_pvt.h"            /* ick. */
  27.  
  28.  
  29. static int tile_manager_get_tile_num (TileManager *tm,
  30.                        int xpixel,
  31.                        int ypixel);
  32.  
  33.  
  34. TileManager*
  35. tile_manager_new (int toplevel_width,
  36.           int toplevel_height,
  37.           int bpp)
  38. {
  39.   TileManager *tm;
  40.   int width, height;
  41.  
  42.   tm = g_new (TileManager, 1);
  43.  
  44.   tm->user_data = NULL;
  45.   tm->validate_proc = NULL;
  46.  
  47.   width = toplevel_width;
  48.   height = toplevel_height;
  49.  
  50.   tm->width = width;
  51.   tm->height = height;
  52.   tm->bpp = bpp;
  53.   tm->ntile_rows = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
  54.   tm->ntile_cols = (width + TILE_WIDTH - 1) / TILE_WIDTH;
  55.   tm->tiles = NULL;
  56.   
  57.   return tm;
  58. }
  59.  
  60. void
  61. tile_manager_destroy (TileManager *tm)
  62. {
  63.   int ntiles;
  64.   int i;
  65.  
  66.   if (tm->tiles)
  67.     {
  68.       ntiles = tm->ntile_rows * tm->ntile_cols;
  69.  
  70.       for (i = 0; i < ntiles; i++)
  71.     {
  72.       TILE_MUTEX_LOCK (tm->tiles[i]);
  73.       tile_detach (tm->tiles[i], tm, i);
  74.     }
  75.  
  76.       g_free (tm->tiles);
  77.     }
  78.  
  79.   g_free (tm);
  80. }
  81.  
  82.  
  83. void
  84. tile_manager_set_validate_proc (TileManager      *tm,
  85.                 TileValidateProc  proc)
  86. {
  87.   tm->validate_proc = proc;
  88. }
  89.  
  90.  
  91. Tile*
  92. tile_manager_get_tile (TileManager *tm,
  93.                int          xpixel,
  94.                int          ypixel,
  95.                int          wantread,
  96.                int          wantwrite)
  97. {
  98.   int tile_num;
  99.  
  100.   tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel);
  101.   if (tile_num < 0)
  102.     return NULL;
  103.  
  104.   return tile_manager_get (tm, tile_num, wantread, wantwrite);
  105. }
  106.  
  107. Tile*
  108. tile_manager_get (TileManager *tm,
  109.           int          tile_num,
  110.           int          wantread,
  111.           int          wantwrite)
  112. {
  113.   Tile **tiles;
  114.   Tile **tile_ptr;
  115.   int ntiles;
  116.   int nrows, ncols;
  117.   int right_tile;
  118.   int bottom_tile;
  119.   int i, j, k;
  120.  
  121.   ntiles = tm->ntile_rows * tm->ntile_cols;
  122.  
  123.   if ((tile_num < 0) || (tile_num >= ntiles))
  124.     return NULL;
  125.  
  126.   if (!tm->tiles)
  127.     {
  128.       tm->tiles = g_new (Tile*, ntiles);
  129.       tiles = tm->tiles;
  130.  
  131.       nrows = tm->ntile_rows;
  132.       ncols = tm->ntile_cols;
  133.  
  134.       right_tile = tm->width - ((ncols - 1) * TILE_WIDTH);
  135.       bottom_tile = tm->height - ((nrows - 1) * TILE_HEIGHT);
  136.  
  137.       for (i = 0, k = 0; i < nrows; i++)
  138.     {
  139.       for (j = 0; j < ncols; j++, k++)
  140.         {
  141.           tiles[k] = g_new (Tile, 1);
  142.           tile_init (tiles[k], tm->bpp);
  143.           tile_attach (tiles[k], tm, k);
  144.  
  145.           if (j == (ncols - 1))
  146.         tiles[k]->ewidth = right_tile;
  147.  
  148.           if (i == (nrows - 1))
  149.         tiles[k]->eheight = bottom_tile;
  150.         }
  151.     }
  152.     }
  153.  
  154.   tile_ptr = &tm->tiles[tile_num];
  155.  
  156.   if (wantwrite && !wantread)
  157.     {
  158.       g_warning("WRITE-ONLY TILE... UNTESTED!");
  159.     }
  160.  
  161.   /*
  162.   if ((*tile_ptr)->share_count &&
  163.       (*tile_ptr)->write_count)
  164.     fprintf(stderr," >> MEEPITY %d,%d << ",
  165.         (*tile_ptr)->share_count,
  166.         (*tile_ptr)->write_count
  167.         ); */
  168.  
  169.   if (wantread) 
  170.     {
  171.       TILE_MUTEX_LOCK (*tile_ptr);
  172.       if (wantwrite) 
  173.     {
  174.       if ((*tile_ptr)->share_count > 1) 
  175.         {
  176.           /* Copy-on-write required */
  177.           Tile *newtile = g_new (Tile, 1);
  178.  
  179.           tile_init (newtile, (*tile_ptr)->bpp);
  180.           newtile->ewidth  = (*tile_ptr)->ewidth;
  181.           newtile->eheight = (*tile_ptr)->eheight;
  182.           newtile->valid   = (*tile_ptr)->valid;
  183.           newtile->data    = g_new (guchar, tile_size (newtile));
  184.  
  185.           if (!newtile->valid)
  186.         g_warning ("Oh boy, r/w tile is invalid... we suck.  Please report.");
  187.  
  188.               if ((*tile_ptr)->rowhint)
  189.               {
  190.                 tile_sanitize_rowhints (newtile);
  191.             i = newtile->eheight;
  192.             while (i--)
  193.           {
  194.             newtile->rowhint[i] = (*tile_ptr)->rowhint[i];
  195.           }
  196.               }
  197.  
  198.           if ((*tile_ptr)->data != NULL) 
  199.         {
  200.           memcpy (newtile->data, (*tile_ptr)->data, tile_size (newtile));
  201.         }
  202.           else
  203.         {
  204.           tile_lock (*tile_ptr);
  205.           memcpy (newtile->data, (*tile_ptr)->data, tile_size (newtile));
  206.           tile_release (*tile_ptr, FALSE);
  207.         }
  208.  
  209.           tile_detach (*tile_ptr, tm, tile_num);
  210.           TILE_MUTEX_LOCK (newtile);
  211.           tile_attach (newtile, tm, tile_num);
  212.           *tile_ptr = newtile;
  213.         }
  214.  
  215.       (*tile_ptr)->write_count++;
  216.       (*tile_ptr)->dirty = TRUE;
  217.     }
  218.     /*       else
  219.     {
  220.       if ((*tile_ptr)->write_count)
  221.         fprintf(stderr,"STINK! r/o on r/w tile /%d\007  ",(*tile_ptr)->write_count);
  222.     } */
  223.       TILE_MUTEX_UNLOCK (*tile_ptr);
  224.       tile_lock (*tile_ptr);
  225.     }
  226.  
  227.   return *tile_ptr;
  228. }
  229.  
  230. void
  231. tile_manager_get_async (TileManager *tm,
  232.                         int          xpixel,
  233.                         int          ypixel)
  234. {
  235.   Tile *tile_ptr;
  236.   int tile_num;
  237.  
  238.   tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel);
  239.   if (tile_num < 0)
  240.     return;
  241.  
  242.   tile_ptr = tm->tiles[tile_num];
  243.  
  244.   tile_swap_in_async (tile_ptr);
  245. }
  246.  
  247. void
  248. tile_manager_validate (TileManager *tm,
  249.                Tile        *tile)
  250. {
  251.   tile->valid = TRUE;
  252.  
  253.   if (tm->validate_proc)
  254.     (* tm->validate_proc) (tm, tile);
  255.  
  256. /* DEBUG STUFF ->  if (tm->user_data)
  257.     {
  258.             fprintf(stderr,"V%p  ",tm->user_data);
  259.       fprintf(stderr,"V");
  260.     }
  261.   else
  262.     {
  263.       fprintf(stderr,"v");
  264.     } */
  265.  
  266. }
  267.  
  268. void
  269. tile_manager_invalidate_tiles (TileManager *tm,
  270.                    Tile        *toplevel_tile)
  271. {
  272.   double x, y;
  273.   int row, col;
  274.   int num;
  275.  
  276.   col = toplevel_tile->tlink->tile_num % tm->ntile_cols;
  277.   row = toplevel_tile->tlink->tile_num / tm->ntile_cols;
  278.  
  279.   x = (col * TILE_WIDTH + toplevel_tile->ewidth / 2.0) / (double) tm->width;
  280.   y = (row * TILE_HEIGHT + toplevel_tile->eheight / 2.0) / (double) tm->height;
  281.  
  282.   if (tm->tiles)
  283.     {
  284.       col = x * tm->width / TILE_WIDTH;
  285.       row = y * tm->height / TILE_HEIGHT;
  286.       num = row * tm->ntile_cols + col;
  287.       tile_invalidate (&tm->tiles[num], tm, num);
  288.     }
  289. }
  290.  
  291.  
  292. void
  293. tile_invalidate_tile (Tile **tile_ptr, TileManager *tm, 
  294.               int xpixel, int ypixel)
  295. {
  296.   int tile_num;
  297.  
  298.   tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel);
  299.   if (tile_num < 0) return;
  300.   
  301.   tile_invalidate (tile_ptr, tm, tile_num);
  302. }
  303.  
  304.  
  305. void
  306. tile_invalidate (Tile **tile_ptr, TileManager *tm, int tile_num)
  307. {
  308.   Tile *tile = *tile_ptr;
  309.  
  310.   TILE_MUTEX_LOCK (tile);
  311.  
  312.   if (!tile->valid) 
  313.     goto leave;
  314.  
  315.   if (tile->share_count > 1) 
  316.     {
  317.       /* This tile is shared.  Replace it with a new, invalid tile. */
  318.       Tile *newtile = g_new (Tile, 1);
  319.  
  320.       tile_init (newtile, tile->bpp);
  321.       newtile->ewidth  = tile->ewidth;
  322.       newtile->eheight = tile->eheight;
  323.       tile_detach (tile, tm, tile_num);
  324.       TILE_MUTEX_LOCK (newtile);
  325.       tile_attach (newtile, tm, tile_num);
  326.       tile = *tile_ptr = newtile;
  327.     }
  328.  
  329.   if (tile->listhead)
  330.     tile_cache_flush (tile);
  331.  
  332.   tile->valid = FALSE;
  333.   if (tile->data) 
  334.     {
  335.       g_free (tile->data);
  336.       tile->data = NULL;
  337.     }
  338.   if (tile->swap_offset != -1)
  339.     {
  340.       /* If the tile is on disk, then delete its
  341.        *  presence there.
  342.        */
  343.       tile_swap_delete (tile);
  344.     }
  345.  
  346. leave:
  347.   TILE_MUTEX_UNLOCK (tile);
  348. }
  349.  
  350.  
  351. void
  352. tile_manager_map_tile (TileManager *tm,
  353.                int          xpixel,
  354.                int          ypixel,
  355.                Tile        *srctile)
  356. {
  357.   int tile_row;
  358.   int tile_col;
  359.   int tile_num;
  360.  
  361.   if ((xpixel < 0) || (xpixel >= tm->width) ||
  362.       (ypixel < 0) || (ypixel >= tm->height))
  363.     {
  364.       g_warning ("tile_manager_map_tile: tile co-ord out of range.");
  365.       return;
  366.     }
  367.  
  368.   tile_row = ypixel / TILE_HEIGHT;
  369.   tile_col = xpixel / TILE_WIDTH;
  370.   tile_num = tile_row * tm->ntile_cols + tile_col;
  371.  
  372.   tile_manager_map (tm, tile_num, srctile);
  373. }
  374.  
  375. void
  376. tile_manager_map (TileManager *tm,
  377.           int          tile_num,
  378.           Tile        *srctile)
  379. {
  380.   Tile **tiles;
  381.   Tile **tile_ptr;
  382.   int ntiles;
  383.   int nrows, ncols;
  384.   int right_tile;
  385.   int bottom_tile;
  386.   int i, j, k;
  387.  
  388.   ntiles = tm->ntile_rows * tm->ntile_cols;
  389.  
  390.   if ((tile_num < 0) || (tile_num >= ntiles))
  391.     {
  392.       g_warning ("tile_manager_map: tile out of range.");
  393.       return;
  394.     }
  395.  
  396.   if (!tm->tiles)
  397.     {
  398.       g_warning ("tile_manager_map: empty tile level - init'ing.");
  399.  
  400.       tm->tiles = g_new (Tile*, ntiles);
  401.       tiles = tm->tiles;
  402.  
  403.       nrows = tm->ntile_rows;
  404.       ncols = tm->ntile_cols;
  405.  
  406.       right_tile = tm->width - ((ncols - 1) * TILE_WIDTH);
  407.       bottom_tile = tm->height - ((nrows - 1) * TILE_HEIGHT);
  408.  
  409.       for (i = 0, k = 0; i < nrows; i++)
  410.     {
  411.       for (j = 0; j < ncols; j++, k++)
  412.         {
  413.           /*          printf(",");fflush(stdout);*/
  414.  
  415.           tiles[k] = g_new (Tile, 1);
  416.           tile_init (tiles[k], tm->bpp);
  417.           tile_attach (tiles[k], tm, k);
  418.  
  419.           if (j == (ncols - 1))
  420.         tiles[k]->ewidth = right_tile;
  421.  
  422.           if (i == (nrows - 1))
  423.         tiles[k]->eheight = bottom_tile;
  424.         }
  425.     }
  426.  
  427.       /*      g_warning ("tile_manager_map: empty tile level - done.");*/
  428.     }
  429.  
  430.   tile_ptr = &tm->tiles[tile_num];
  431.  
  432.   /*  printf(")");fflush(stdout);*/
  433.  
  434.   if (!srctile->valid)
  435.     g_warning("tile_manager_map: srctile not validated yet!  please report.");
  436.  
  437.   TILE_MUTEX_LOCK (*tile_ptr);
  438.   if ((*tile_ptr)->ewidth  != srctile->ewidth ||
  439.       (*tile_ptr)->eheight != srctile->eheight ||
  440.       (*tile_ptr)->bpp     != srctile->bpp) {
  441.     g_warning ("tile_manager_map: nonconformant map (%p -> %p)",
  442.            srctile, *tile_ptr);
  443.   }
  444.   tile_detach (*tile_ptr, tm, tile_num);
  445.  
  446.  
  447.   /*  printf(">");fflush(stdout);*/
  448.  
  449.   TILE_MUTEX_LOCK (srctile);
  450.  
  451.   /*  printf(" [src:%p tm:%p tn:%d] ", srctile, tm, tile_num); fflush(stdout);*/
  452.  
  453.   tile_attach (srctile, tm, tile_num);
  454.   *tile_ptr = srctile;
  455.  
  456.   TILE_MUTEX_UNLOCK (srctile);
  457.  
  458.   /*  printf("}");fflush(stdout);*/
  459. }
  460.  
  461. static int
  462. tile_manager_get_tile_num (TileManager *tm,
  463.                    int xpixel,
  464.                    int ypixel)
  465. {
  466.   int tile_row;
  467.   int tile_col;
  468.   int tile_num;
  469.  
  470.   if ((xpixel < 0) || (xpixel >= tm->width) ||
  471.       (ypixel < 0) || (ypixel >= tm->height))
  472.     return -1;
  473.  
  474.   tile_row = ypixel / TILE_HEIGHT;
  475.   tile_col = xpixel / TILE_WIDTH;
  476.   tile_num = tile_row * tm->ntile_cols + tile_col;
  477.  
  478.   return tile_num;
  479. }
  480.  
  481. void 
  482. tile_manager_set_user_data (TileManager *tm,
  483.                 void        *user_data)
  484. {
  485.   tm->user_data = user_data;
  486. }
  487.  
  488. void *
  489. tile_manager_get_user_data (TileManager *tm)
  490. {
  491.   return tm->user_data;
  492. }
  493.  
  494. int 
  495. tile_manager_level_width  (TileManager *tm) 
  496. {
  497.   return tm->width;
  498. }
  499.  
  500. int 
  501. tile_manager_level_height (TileManager *tm)
  502. {
  503.   return tm->height;
  504. }
  505.  
  506. int 
  507. tile_manager_level_bpp    (TileManager *tm)
  508. {
  509.   return tm->bpp;
  510. }
  511.  
  512. void
  513. tile_manager_get_tile_coordinates (TileManager *tm, Tile *tile, int *x, int *y)
  514. {
  515.   TileLink *tl;
  516.  
  517.   for (tl = tile->tlink; tl; tl = tl->next) 
  518.     {
  519.       if (tl->tm == tm) break;
  520.     }
  521.  
  522.   if (tl == NULL) 
  523.     {
  524.       g_warning ("tile_manager_get_tile_coordinates: tile not attached to manager");
  525.       return;
  526.     }
  527.  
  528.   *x = TILE_WIDTH * (tl->tile_num % tm->ntile_cols);
  529.   *y = TILE_HEIGHT * (tl->tile_num / tm->ntile_cols);
  530. }
  531.  
  532.   
  533. void
  534. tile_manager_map_over_tile (TileManager *tm, Tile *tile, Tile *srctile)
  535. {
  536.   TileLink *tl;
  537.  
  538.   for (tl = tile->tlink; tl; tl = tl->next) 
  539.     {
  540.       if (tl->tm == tm) break;
  541.     }
  542.  
  543.   if (tl == NULL) 
  544.     {
  545.       g_warning ("tile_manager_map_over_tile: tile not attached to manager");
  546.       return;
  547.     }
  548.  
  549.   tile_manager_map (tm, tl->tile_num, srctile);
  550. }
  551.  
  552.   
  553.  
  554.                 
  555.