home *** CD-ROM | disk | FTP | other *** search
- /* The GIMP -- an image manipulation program
- * Copyright (C) 1995 Spencer Kimball and Peter Mattis
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
- #include <string.h>
-
- #include "tile_cache.h"
- #include "tile_manager.h"
- #include "tile_swap.h"
-
- #include "tile_manager_pvt.h"
- #include "tile_pvt.h" /* ick. */
-
-
- static int tile_manager_get_tile_num (TileManager *tm,
- int xpixel,
- int ypixel);
-
-
- TileManager*
- tile_manager_new (int toplevel_width,
- int toplevel_height,
- int bpp)
- {
- TileManager *tm;
- int width, height;
-
- tm = g_new (TileManager, 1);
-
- tm->user_data = NULL;
- tm->validate_proc = NULL;
-
- width = toplevel_width;
- height = toplevel_height;
-
- tm->width = width;
- tm->height = height;
- tm->bpp = bpp;
- tm->ntile_rows = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
- tm->ntile_cols = (width + TILE_WIDTH - 1) / TILE_WIDTH;
- tm->tiles = NULL;
-
- return tm;
- }
-
- void
- tile_manager_destroy (TileManager *tm)
- {
- int ntiles;
- int i;
-
- if (tm->tiles)
- {
- ntiles = tm->ntile_rows * tm->ntile_cols;
-
- for (i = 0; i < ntiles; i++)
- {
- TILE_MUTEX_LOCK (tm->tiles[i]);
- tile_detach (tm->tiles[i], tm, i);
- }
-
- g_free (tm->tiles);
- }
-
- g_free (tm);
- }
-
-
- void
- tile_manager_set_validate_proc (TileManager *tm,
- TileValidateProc proc)
- {
- tm->validate_proc = proc;
- }
-
-
- Tile*
- tile_manager_get_tile (TileManager *tm,
- int xpixel,
- int ypixel,
- int wantread,
- int wantwrite)
- {
- int tile_num;
-
- tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel);
- if (tile_num < 0)
- return NULL;
-
- return tile_manager_get (tm, tile_num, wantread, wantwrite);
- }
-
- Tile*
- tile_manager_get (TileManager *tm,
- int tile_num,
- int wantread,
- int wantwrite)
- {
- Tile **tiles;
- Tile **tile_ptr;
- int ntiles;
- int nrows, ncols;
- int right_tile;
- int bottom_tile;
- int i, j, k;
-
- ntiles = tm->ntile_rows * tm->ntile_cols;
-
- if ((tile_num < 0) || (tile_num >= ntiles))
- return NULL;
-
- if (!tm->tiles)
- {
- tm->tiles = g_new (Tile*, ntiles);
- tiles = tm->tiles;
-
- nrows = tm->ntile_rows;
- ncols = tm->ntile_cols;
-
- right_tile = tm->width - ((ncols - 1) * TILE_WIDTH);
- bottom_tile = tm->height - ((nrows - 1) * TILE_HEIGHT);
-
- for (i = 0, k = 0; i < nrows; i++)
- {
- for (j = 0; j < ncols; j++, k++)
- {
- tiles[k] = g_new (Tile, 1);
- tile_init (tiles[k], tm->bpp);
- tile_attach (tiles[k], tm, k);
-
- if (j == (ncols - 1))
- tiles[k]->ewidth = right_tile;
-
- if (i == (nrows - 1))
- tiles[k]->eheight = bottom_tile;
- }
- }
- }
-
- tile_ptr = &tm->tiles[tile_num];
-
- if (wantwrite && !wantread)
- {
- g_warning("WRITE-ONLY TILE... UNTESTED!");
- }
-
- /*
- if ((*tile_ptr)->share_count &&
- (*tile_ptr)->write_count)
- fprintf(stderr," >> MEEPITY %d,%d << ",
- (*tile_ptr)->share_count,
- (*tile_ptr)->write_count
- ); */
-
- if (wantread)
- {
- TILE_MUTEX_LOCK (*tile_ptr);
- if (wantwrite)
- {
- if ((*tile_ptr)->share_count > 1)
- {
- /* Copy-on-write required */
- Tile *newtile = g_new (Tile, 1);
-
- tile_init (newtile, (*tile_ptr)->bpp);
- newtile->ewidth = (*tile_ptr)->ewidth;
- newtile->eheight = (*tile_ptr)->eheight;
- newtile->valid = (*tile_ptr)->valid;
- newtile->data = g_new (guchar, tile_size (newtile));
-
- if (!newtile->valid)
- g_warning ("Oh boy, r/w tile is invalid... we suck. Please report.");
-
- if ((*tile_ptr)->rowhint)
- {
- tile_sanitize_rowhints (newtile);
- i = newtile->eheight;
- while (i--)
- {
- newtile->rowhint[i] = (*tile_ptr)->rowhint[i];
- }
- }
-
- if ((*tile_ptr)->data != NULL)
- {
- memcpy (newtile->data, (*tile_ptr)->data, tile_size (newtile));
- }
- else
- {
- tile_lock (*tile_ptr);
- memcpy (newtile->data, (*tile_ptr)->data, tile_size (newtile));
- tile_release (*tile_ptr, FALSE);
- }
-
- tile_detach (*tile_ptr, tm, tile_num);
- TILE_MUTEX_LOCK (newtile);
- tile_attach (newtile, tm, tile_num);
- *tile_ptr = newtile;
- }
-
- (*tile_ptr)->write_count++;
- (*tile_ptr)->dirty = TRUE;
- }
- /* else
- {
- if ((*tile_ptr)->write_count)
- fprintf(stderr,"STINK! r/o on r/w tile /%d\007 ",(*tile_ptr)->write_count);
- } */
- TILE_MUTEX_UNLOCK (*tile_ptr);
- tile_lock (*tile_ptr);
- }
-
- return *tile_ptr;
- }
-
- void
- tile_manager_get_async (TileManager *tm,
- int xpixel,
- int ypixel)
- {
- Tile *tile_ptr;
- int tile_num;
-
- tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel);
- if (tile_num < 0)
- return;
-
- tile_ptr = tm->tiles[tile_num];
-
- tile_swap_in_async (tile_ptr);
- }
-
- void
- tile_manager_validate (TileManager *tm,
- Tile *tile)
- {
- tile->valid = TRUE;
-
- if (tm->validate_proc)
- (* tm->validate_proc) (tm, tile);
-
- /* DEBUG STUFF -> if (tm->user_data)
- {
- fprintf(stderr,"V%p ",tm->user_data);
- fprintf(stderr,"V");
- }
- else
- {
- fprintf(stderr,"v");
- } */
-
- }
-
- void
- tile_manager_invalidate_tiles (TileManager *tm,
- Tile *toplevel_tile)
- {
- double x, y;
- int row, col;
- int num;
-
- col = toplevel_tile->tlink->tile_num % tm->ntile_cols;
- row = toplevel_tile->tlink->tile_num / tm->ntile_cols;
-
- x = (col * TILE_WIDTH + toplevel_tile->ewidth / 2.0) / (double) tm->width;
- y = (row * TILE_HEIGHT + toplevel_tile->eheight / 2.0) / (double) tm->height;
-
- if (tm->tiles)
- {
- col = x * tm->width / TILE_WIDTH;
- row = y * tm->height / TILE_HEIGHT;
- num = row * tm->ntile_cols + col;
- tile_invalidate (&tm->tiles[num], tm, num);
- }
- }
-
-
- void
- tile_invalidate_tile (Tile **tile_ptr, TileManager *tm,
- int xpixel, int ypixel)
- {
- int tile_num;
-
- tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel);
- if (tile_num < 0) return;
-
- tile_invalidate (tile_ptr, tm, tile_num);
- }
-
-
- void
- tile_invalidate (Tile **tile_ptr, TileManager *tm, int tile_num)
- {
- Tile *tile = *tile_ptr;
-
- TILE_MUTEX_LOCK (tile);
-
- if (!tile->valid)
- goto leave;
-
- if (tile->share_count > 1)
- {
- /* This tile is shared. Replace it with a new, invalid tile. */
- Tile *newtile = g_new (Tile, 1);
-
- tile_init (newtile, tile->bpp);
- newtile->ewidth = tile->ewidth;
- newtile->eheight = tile->eheight;
- tile_detach (tile, tm, tile_num);
- TILE_MUTEX_LOCK (newtile);
- tile_attach (newtile, tm, tile_num);
- tile = *tile_ptr = newtile;
- }
-
- if (tile->listhead)
- tile_cache_flush (tile);
-
- tile->valid = FALSE;
- if (tile->data)
- {
- g_free (tile->data);
- tile->data = NULL;
- }
- if (tile->swap_offset != -1)
- {
- /* If the tile is on disk, then delete its
- * presence there.
- */
- tile_swap_delete (tile);
- }
-
- leave:
- TILE_MUTEX_UNLOCK (tile);
- }
-
-
- void
- tile_manager_map_tile (TileManager *tm,
- int xpixel,
- int ypixel,
- Tile *srctile)
- {
- int tile_row;
- int tile_col;
- int tile_num;
-
- if ((xpixel < 0) || (xpixel >= tm->width) ||
- (ypixel < 0) || (ypixel >= tm->height))
- {
- g_warning ("tile_manager_map_tile: tile co-ord out of range.");
- return;
- }
-
- tile_row = ypixel / TILE_HEIGHT;
- tile_col = xpixel / TILE_WIDTH;
- tile_num = tile_row * tm->ntile_cols + tile_col;
-
- tile_manager_map (tm, tile_num, srctile);
- }
-
- void
- tile_manager_map (TileManager *tm,
- int tile_num,
- Tile *srctile)
- {
- Tile **tiles;
- Tile **tile_ptr;
- int ntiles;
- int nrows, ncols;
- int right_tile;
- int bottom_tile;
- int i, j, k;
-
- ntiles = tm->ntile_rows * tm->ntile_cols;
-
- if ((tile_num < 0) || (tile_num >= ntiles))
- {
- g_warning ("tile_manager_map: tile out of range.");
- return;
- }
-
- if (!tm->tiles)
- {
- g_warning ("tile_manager_map: empty tile level - init'ing.");
-
- tm->tiles = g_new (Tile*, ntiles);
- tiles = tm->tiles;
-
- nrows = tm->ntile_rows;
- ncols = tm->ntile_cols;
-
- right_tile = tm->width - ((ncols - 1) * TILE_WIDTH);
- bottom_tile = tm->height - ((nrows - 1) * TILE_HEIGHT);
-
- for (i = 0, k = 0; i < nrows; i++)
- {
- for (j = 0; j < ncols; j++, k++)
- {
- /* printf(",");fflush(stdout);*/
-
- tiles[k] = g_new (Tile, 1);
- tile_init (tiles[k], tm->bpp);
- tile_attach (tiles[k], tm, k);
-
- if (j == (ncols - 1))
- tiles[k]->ewidth = right_tile;
-
- if (i == (nrows - 1))
- tiles[k]->eheight = bottom_tile;
- }
- }
-
- /* g_warning ("tile_manager_map: empty tile level - done.");*/
- }
-
- tile_ptr = &tm->tiles[tile_num];
-
- /* printf(")");fflush(stdout);*/
-
- if (!srctile->valid)
- g_warning("tile_manager_map: srctile not validated yet! please report.");
-
- TILE_MUTEX_LOCK (*tile_ptr);
- if ((*tile_ptr)->ewidth != srctile->ewidth ||
- (*tile_ptr)->eheight != srctile->eheight ||
- (*tile_ptr)->bpp != srctile->bpp) {
- g_warning ("tile_manager_map: nonconformant map (%p -> %p)",
- srctile, *tile_ptr);
- }
- tile_detach (*tile_ptr, tm, tile_num);
-
-
- /* printf(">");fflush(stdout);*/
-
- TILE_MUTEX_LOCK (srctile);
-
- /* printf(" [src:%p tm:%p tn:%d] ", srctile, tm, tile_num); fflush(stdout);*/
-
- tile_attach (srctile, tm, tile_num);
- *tile_ptr = srctile;
-
- TILE_MUTEX_UNLOCK (srctile);
-
- /* printf("}");fflush(stdout);*/
- }
-
- static int
- tile_manager_get_tile_num (TileManager *tm,
- int xpixel,
- int ypixel)
- {
- int tile_row;
- int tile_col;
- int tile_num;
-
- if ((xpixel < 0) || (xpixel >= tm->width) ||
- (ypixel < 0) || (ypixel >= tm->height))
- return -1;
-
- tile_row = ypixel / TILE_HEIGHT;
- tile_col = xpixel / TILE_WIDTH;
- tile_num = tile_row * tm->ntile_cols + tile_col;
-
- return tile_num;
- }
-
- void
- tile_manager_set_user_data (TileManager *tm,
- void *user_data)
- {
- tm->user_data = user_data;
- }
-
- void *
- tile_manager_get_user_data (TileManager *tm)
- {
- return tm->user_data;
- }
-
- int
- tile_manager_level_width (TileManager *tm)
- {
- return tm->width;
- }
-
- int
- tile_manager_level_height (TileManager *tm)
- {
- return tm->height;
- }
-
- int
- tile_manager_level_bpp (TileManager *tm)
- {
- return tm->bpp;
- }
-
- void
- tile_manager_get_tile_coordinates (TileManager *tm, Tile *tile, int *x, int *y)
- {
- TileLink *tl;
-
- for (tl = tile->tlink; tl; tl = tl->next)
- {
- if (tl->tm == tm) break;
- }
-
- if (tl == NULL)
- {
- g_warning ("tile_manager_get_tile_coordinates: tile not attached to manager");
- return;
- }
-
- *x = TILE_WIDTH * (tl->tile_num % tm->ntile_cols);
- *y = TILE_HEIGHT * (tl->tile_num / tm->ntile_cols);
- }
-
-
- void
- tile_manager_map_over_tile (TileManager *tm, Tile *tile, Tile *srctile)
- {
- TileLink *tl;
-
- for (tl = tile->tlink; tl; tl = tl->next)
- {
- if (tl->tm == tm) break;
- }
-
- if (tl == NULL)
- {
- g_warning ("tile_manager_map_over_tile: tile not attached to manager");
- return;
- }
-
- tile_manager_map (tm, tl->tile_num, srctile);
- }
-
-
-
-
-