aboutsummaryrefslogtreecommitdiff
path: root/Mosaic.c
diff options
context:
space:
mode:
authorlecoanet2000-01-13 10:04:43 +0000
committerlecoanet2000-01-13 10:04:43 +0000
commitdf255eeaa3dda716d0875e57058ee8c68f1d2132 (patch)
tree0effd2f019b08b2977337a5fdc220ae0af8c5248 /Mosaic.c
parentc565c357ebbcaa5608761b28eb63a15c850f22b4 (diff)
downloadtkzinc-df255eeaa3dda716d0875e57058ee8c68f1d2132.zip
tkzinc-df255eeaa3dda716d0875e57058ee8c68f1d2132.tar.gz
tkzinc-df255eeaa3dda716d0875e57058ee8c68f1d2132.tar.bz2
tkzinc-df255eeaa3dda716d0875e57058ee8c68f1d2132.tar.xz
*** empty log message ***
Diffstat (limited to 'Mosaic.c')
-rw-r--r--Mosaic.c708
1 files changed, 708 insertions, 0 deletions
diff --git a/Mosaic.c b/Mosaic.c
new file mode 100644
index 0000000..22331ee
--- /dev/null
+++ b/Mosaic.c
@@ -0,0 +1,708 @@
+/*
+ * Mosaic.c -- Implementation of Mosaic item.
+ *
+ * Authors : Patrick Lecoanet.
+ * Creation date :
+ *
+ * $Id$
+ */
+
+/*
+ * Copyright (c) 1993 - 1999 CENA, Patrick Lecoanet --
+ *
+ * This code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This code 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this code; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*
+ **********************************************************************************
+ *
+ * Included files
+ *
+ **********************************************************************************
+ */
+#include <alloca.h>
+
+#include "Item.h"
+#include "Geo.h"
+#ifdef XTOOLKIT
+#include "Radar.h"
+#else
+/* PLC : à completer */
+#endif
+
+
+/*
+ **********************************************************************************
+ *
+ * Constants.
+ *
+ **********************************************************************************
+ */
+
+static const char rcsid[] = "$Imagine: Mosaic.c,v 1.7 1997/08/11 12:29:18 lecoanet Exp $";
+static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $";
+
+static const char invalid_attribute[] = "RadarMosaic : Invalid attribute.";
+static const char read_only_attribute[] = "This attribute is read only.";
+
+
+/*
+ **********************************************************************************
+ *
+ * Specific Mosaic item record
+ *
+ **********************************************************************************
+ */
+
+typedef struct _MosaicItemStruct {
+ ItemStruct header;
+
+ /* Public data */
+ int x; /* Origin world coordinates */
+ int y;
+ int tile_size;
+ int row_count; /* Number of tiles per row */
+ int column_count; /* Number of tiles per column */
+ RadarColor *tile_palette; /* Color palette for tiles */
+ int *color_usage; /* Numbers of merged rectangles */
+ /* using the corresponding color */
+ /* in the palette. */
+ int palette_size; /* Number of colors in palette */
+ unsigned char *tile_colors; /* Color for each tile */
+
+ /* Private data */
+} MosaicItemStruct, *MosaicItem;
+
+
+/*
+ **********************************************************************************
+ *
+ * Init --
+ *
+ **********************************************************************************
+ */
+
+static void
+Init(Item item)
+{
+ MosaicItem mosaic = (MosaicItem) item;
+
+#ifdef XTOOLKIT
+ ITEM_COMMON_INIT(item, NULL, wi->mosaic_res.visibility, wi->mosaic_res.sensitivity,
+ wi->mosaic_res.priority);
+ mosaic->tile_size = wi->mosaic_res.tile_size;
+ mosaic->row_count = wi->mosaic_res.row_count;
+ mosaic->column_count = wi->mosaic_res.column_count;
+#else
+ /* PLC : à écrire */
+#endif
+
+ mosaic->x = 0;
+ mosaic->y = 0;
+ mosaic->tile_palette = NULL;
+ mosaic->color_usage = NULL;
+ mosaic->palette_size = 0;
+ mosaic->tile_colors = NULL;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Clone --
+ *
+ **********************************************************************************
+ */
+
+static void
+Clone(Item item)
+{
+ MosaicItem mosaic = (MosaicItem) item;
+
+ item->user_data = NULL;
+
+ if (mosaic->tile_palette) {
+ RadarColor *tile_palette;
+
+ tile_palette = (RadarColor *) RadarMalloc(mosaic->palette_size*sizeof(RadarColor));
+ memcpy(tile_palette, mosaic->tile_palette, mosaic->palette_size*sizeof(RadarColor));
+ mosaic->tile_palette = tile_palette;
+ }
+
+ /*
+ * The cached info is still up to date so keep it.
+ */
+ if (mosaic->color_usage) {
+ int *color_usage;
+
+ color_usage = (int *) RadarMalloc(mosaic->palette_size*sizeof(int));
+ memcpy(color_usage, mosaic->color_usage, mosaic->palette_size*sizeof(int));
+ mosaic->color_usage = color_usage;
+ }
+
+ if (mosaic->tile_colors) {
+ int size = mosaic->row_count*mosaic->column_count*sizeof(unsigned char);
+ unsigned char *tile_colors;
+
+ tile_colors = (unsigned char *) RadarMalloc(size);
+ memcpy(tile_colors, mosaic->tile_colors, size);
+ mosaic->tile_colors = tile_colors;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Remove --
+ *
+ **********************************************************************************
+ */
+
+static void
+Remove(Item item)
+{
+ MosaicItem mosaic = (MosaicItem) item;
+
+ if (mosaic->tile_palette) {
+ RadarFree(mosaic->tile_palette);
+ }
+
+ if (mosaic->color_usage) {
+ RadarFree(mosaic->color_usage);
+ }
+
+ if (mosaic->tile_colors) {
+ RadarFree(mosaic->tile_colors);
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Configure --
+ *
+ **********************************************************************************
+ */
+
+static void
+Configure(Item item,
+ RadarList attrs,
+ RadarBool *draw_item,
+ RadarBool *draw_label,
+ RadarBool *compute_coord,
+ RadarBool init)
+{
+ WidgetInfo *wi = item->wi;
+ MosaicItem mosaic = (MosaicItem) item;
+ RadarAttr *attr;
+ unsigned int i, size, num_attrs;
+ RadarBool b_value;
+ unsigned char *tile_colors = NULL;
+ RadarColor *tile_palette = NULL;
+ RadarBool resize_palette = False;
+ RadarBool resize_colors = False;
+
+ num_attrs = RadarListSize(attrs);
+ for (i = 0; i < num_attrs; i++) {
+ attr = (RadarAttr *) RadarListAt(attrs, i);
+
+ switch (attr->name) {
+ ITEM_COMMON_CONFIGURE;
+
+ case RadarItemX:
+ if (mosaic->x != attr->value) {
+ mosaic->x = attr->value;
+ *draw_item = *compute_coord = True;
+ }
+ break;
+
+ case RadarItemY:
+ if (mosaic->y != attr->value) {
+ mosaic->y = attr->value;
+ *draw_item = *compute_coord = True;
+ }
+ break;
+
+ case RadarItemTilePalette:
+ tile_palette = (RadarColor *) attr->value;
+ *draw_item = True;
+ break;
+
+ case RadarItemTileColors:
+ tile_colors = (unsigned char *) attr->value;
+ *draw_item = True;
+ break;
+
+ case RadarItemTileSize:
+ if (attr->value >= 0 &&
+ mosaic->tile_size != attr->value) {
+ mosaic->tile_size = attr->value;
+ *draw_item = *compute_coord = True;
+ }
+ break;
+
+ case RadarItemPaletteSize:
+ if (attr->value >= 0) {
+ mosaic->palette_size = attr->value;
+ resize_palette = True;
+ }
+ break;
+
+ case RadarItemRowCount:
+ if (attr->value >= 0 && mosaic->row_count != attr->value) {
+ mosaic->row_count = attr->value;
+ resize_colors = True;
+ *draw_item = *compute_coord = True;
+ }
+ break;
+
+ case RadarItemColumnCount:
+ if (attr->value >= 0 && mosaic->column_count != attr->value) {
+ mosaic->column_count = attr->value;
+ resize_colors = True;
+ *draw_item = *compute_coord = True;
+ }
+ break;
+
+ default:
+ RadarWarning(invalid_attribute);
+ break;
+ }
+ }
+
+ if (tile_palette) {
+ if (mosaic->tile_palette) {
+ RadarFree(mosaic->tile_palette);
+ }
+ mosaic->tile_palette = (RadarColor *) RadarMalloc(mosaic->palette_size*sizeof(RadarColor));
+ memcpy(mosaic->tile_palette, tile_palette, mosaic->palette_size*sizeof(RadarColor));
+ }
+ else if (resize_palette) {
+ tile_palette = (RadarColor *) RadarMalloc(mosaic->palette_size*sizeof(RadarColor));
+ memcpy(tile_palette, mosaic->tile_palette, mosaic->palette_size*sizeof(RadarColor));
+ RadarFree(mosaic->tile_palette);
+ mosaic->tile_palette = tile_palette;
+ /* The palette size has changed, erase the cached info
+ * and let the appropriate code fault on it to recreate.
+ */
+ RadarFree(mosaic->color_usage);
+ mosaic->color_usage = NULL;
+ }
+
+ if (tile_colors) {
+ /* Here we could optimize the damaged area. No
+ opt should be taken if init or compute_coord.*/
+ if (mosaic->tile_colors) {
+ RadarFree(mosaic->tile_colors);
+ }
+ size = mosaic->row_count * mosaic->column_count;
+ mosaic->tile_colors = (unsigned char *) RadarMalloc(size*sizeof(unsigned char));
+ memcpy(mosaic->tile_colors, tile_colors, size*sizeof(unsigned char));
+ /*
+ * The color counts might need update, let the code fault on an
+ * empty cache.
+ */
+ RadarFree(mosaic->color_usage);
+ mosaic->color_usage = NULL;
+ }
+ else if (resize_colors) {
+ size = mosaic->row_count * mosaic->column_count;
+ tile_colors = (unsigned char *) RadarMalloc(size*sizeof(unsigned char));
+ memcpy(tile_colors, mosaic->tile_colors, size*sizeof(unsigned char));
+ RadarFree(mosaic->tile_colors);
+ mosaic->tile_colors = tile_colors;
+ /*
+ * The color counts might need update, let the code fault on an
+ * empty cache.
+ */
+ RadarFree(mosaic->color_usage);
+ mosaic->color_usage = NULL;
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Query --
+ *
+ **********************************************************************************
+ */
+
+static void
+Query(Item item,
+ RadarList attrs)
+{
+ MosaicItem mosaic = (MosaicItem) item;
+ unsigned int i, num_attrs;
+ RadarAttr *attr;
+
+ num_attrs = RadarListSize(attrs);
+ for (i = 0; i < num_attrs; i++) {
+ attr = (RadarAttr *) RadarListAt(attrs, i);
+
+ switch (attr->name) {
+ ITEM_COMMON_QUERY;
+
+ case RadarItemX:
+ *((int *) attr->value) = mosaic->x;
+ break;
+
+ case RadarItemY:
+ *((int *) attr->value) = mosaic->y;
+ break;
+
+ case RadarItemTilePalette:
+ *((RadarColor **) attr->value) = mosaic->tile_palette;
+ break;
+
+ case RadarItemTileColors:
+ *((unsigned char **) attr->value) = mosaic->tile_colors;
+ break;
+
+ case RadarItemTileSize:
+ *((int *) attr->value) = mosaic->tile_size;
+ break;
+
+ case RadarItemPaletteSize:
+ *((int *) attr->value) = mosaic->palette_size;
+ break;
+
+ case RadarItemRowCount:
+ *((int *) attr->value) = mosaic->row_count;
+ break;
+
+ case RadarItemColumnCount:
+ *((int *) attr->value) = mosaic->column_count;
+ break;
+
+ default:
+ RadarWarning(invalid_attribute);
+ break;
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ComputeCoordinates --
+ *
+ **********************************************************************************
+ */
+
+static void
+ComputeCoordinates(Item item)
+{
+ WidgetInfo *wi = item->wi;
+ MosaicItem mosaic = (MosaicItem) item;
+ RadarPos x_dev, y_dev;
+
+ ResetBBox(&item->item_bounding_box);
+
+ /* Compute device coordinates */
+ x_dev = X_TO_DEVICE(wi, mosaic->x);
+ y_dev = Y_TO_DEVICE(wi, mosaic->y);
+
+ /* Compute bounding box */
+ AddPointToBBox(&item->item_bounding_box, x_dev, y_dev);
+ AddPointToBBox(&item->item_bounding_box,
+ x_dev + (RadarPos) LENGTH_TO_DEVICE(wi, mosaic->tile_size * mosaic->column_count),
+ y_dev + (RadarPos) LENGTH_TO_DEVICE(wi, mosaic->tile_size * mosaic->row_count));
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * ToArea --
+ * Tell if the object is entirely outside (-1),
+ * entirely inside (1) or in between (0).
+ *
+ **********************************************************************************
+ */
+
+static int
+ToArea(Item item,
+ XRectangle *area)
+{
+ return -1;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Draw --
+ *
+ **********************************************************************************
+ */
+
+static void
+Draw(Item item)
+{
+ WidgetInfo *wi = item->wi;
+ MosaicItem mosaic = (MosaicItem) item;
+ RadarPos delta_x_min, delta_x_max;
+ RadarPos delta_y_min, delta_y_max;
+ RadarPos x_dev = X_TO_DEVICE(wi, mosaic->x);
+ RadarPos y_dev = Y_TO_DEVICE(wi, mosaic->y);
+ RadarDim delta_x_dev, delta_y_dev;
+ RadarDim offset_x, offset_y;
+ unsigned int start_row, stop_row;
+ unsigned int start_col, stop_col;
+ XGCValues values;
+ unsigned int i, j;
+ XRectangle *rect;
+ XRectangle **run_cache;
+ int *run_cache_index;
+ int num_adj_tiles;
+ unsigned char current_color;
+
+ if (mosaic->palette_size == 0 || mosaic->tile_palette == NULL ||
+ mosaic->tile_colors == NULL) {
+ return;
+ }
+
+ delta_x_min = wi->damaged_area.x - x_dev;
+ delta_x_max = wi->damaged_area.x + wi->damaged_area.width - x_dev;
+ delta_y_min = wi->damaged_area.y - y_dev;
+ delta_y_max = wi->damaged_area.y + wi->damaged_area.height - y_dev;
+
+ if (delta_x_min < 0) {
+ start_col = 0;
+ }
+ else {
+ start_col = MIN(mosaic->column_count,
+ MAX(0, (LENGTH_FROM_DEVICE(wi, delta_x_min)/mosaic->tile_size)-1));
+ }
+
+ if (delta_x_max < 0) {
+ stop_col = 0;
+ }
+ else {
+ stop_col = LENGTH_FROM_DEVICE(wi, delta_x_max)/mosaic->tile_size;
+ stop_col += LENGTH_FROM_DEVICE(wi, delta_x_max) % mosaic->tile_size ? 1 : 0;
+ stop_col = MIN(mosaic->column_count, stop_col+1);
+ }
+
+ if (delta_y_min < 0) {
+ start_row = 0;
+ }
+ else {
+ start_row = MIN(mosaic->row_count,
+ MAX(0, (LENGTH_FROM_DEVICE(wi, delta_y_min)/mosaic->tile_size)-1));
+ }
+
+ if (delta_y_max < 0) {
+ stop_row = 0;
+ }
+ else {
+ stop_row = LENGTH_FROM_DEVICE(wi, delta_y_max)/mosaic->tile_size;
+ stop_row += LENGTH_FROM_DEVICE(wi, delta_y_max) % mosaic->tile_size ? 1 : 0;
+ stop_row = MIN(mosaic->row_count, stop_row+1);
+ }
+
+ values.fill_style = FillSolid;
+ XChangeGC(wi->dpy, wi->gc, GCFillStyle, &values);
+
+ if (!mosaic->color_usage) {
+ int *color_usage;
+
+ /*
+ * Build the color usage cache on the fly.
+ */
+ color_usage = (int *) XtMalloc(mosaic->palette_size*sizeof(int));
+ memset(color_usage, 0, mosaic->palette_size*sizeof(int));
+
+ /*
+ * First computes the max number of runs for each color.
+ */
+ for (i = 0; i < mosaic->row_count; i++) {
+ current_color = mosaic->tile_colors[i*mosaic->column_count];
+ for (j = 0; j < mosaic->column_count; j++) {
+ /*
+ * If at end of row or the next tile is not of the same color
+ * as the current one, the current run is complete.
+ */
+ if (j == mosaic->column_count - 1 ||
+ mosaic->tile_colors[i*mosaic->column_count + j + 1] != current_color) {
+ /*
+ * Update the cache if possible (not a transparent color).
+ */
+ if (current_color < mosaic->palette_size) {
+ color_usage[current_color]++;
+ }
+ /*
+ * Look at the next tile color.
+ */
+ if (j != mosaic->column_count - 1) {
+ current_color = mosaic->tile_colors[i*mosaic->column_count + j + 1];
+ }
+ }
+ }
+ }
+
+ mosaic->color_usage = color_usage;
+ }
+
+ /*
+ * Allocate memory to store the runs color by color.
+ */
+ run_cache = (XRectangle **) alloca(mosaic->palette_size*sizeof(XRectangle *));
+ run_cache_index = (int *) alloca(mosaic->palette_size*sizeof(int));
+ memset(run_cache_index, 0, mosaic->palette_size*sizeof(int));
+ for (i = 0; i < mosaic->palette_size; i++) {
+ if (mosaic->color_usage[i] != 0) {
+ run_cache[i] = (XRectangle *) alloca(mosaic->color_usage[i]*sizeof(XRectangle));
+ }
+ }
+
+ /*
+ * Now that the run cache is set up, fill it.
+ */
+/* printf("===>start_row:%d, stop_row:%d, start_col:%d, stop_col:%d\n",
+ * start_row, stop_row, start_col, stop_col);
+ */
+ for (i = start_row; i < stop_row; i++) {
+ current_color = mosaic->tile_colors[i*mosaic->column_count + start_col];
+ num_adj_tiles = 0;
+ for (j = start_col; j < stop_col; j++) {
+ /*
+ * If at end of row or the next tile is not of the same color
+ * as the current one, the current run is complete.
+ */
+/* printf("lin:%d, col:%d, #tiles:%d, cur_color:%d, next_color:%d\n",
+ * i, j, num_adj_tiles, current_color,
+ * mosaic->tile_colors[i*mosaic->column_count + j + 1]);
+ */
+
+ if (j == stop_col - 1 ||
+ mosaic->tile_colors[i*mosaic->column_count + j + 1] != current_color) {
+
+ if (current_color < mosaic->palette_size) {
+ /*
+ * Record the current run.
+ */
+ offset_x = LENGTH_TO_DEVICE(wi, mosaic->tile_size * (j - num_adj_tiles));
+ offset_y = LENGTH_TO_DEVICE(wi, mosaic->tile_size * i);
+ delta_x_dev = LENGTH_TO_DEVICE(wi, mosaic->tile_size * (j+1)) - offset_x;
+ delta_y_dev = LENGTH_TO_DEVICE(wi, mosaic->tile_size * (i+1)) - offset_y;
+ rect = &run_cache[current_color][run_cache_index[current_color]];
+ rect->x = x_dev + (RadarPos) offset_x;
+ rect->y = y_dev + (RadarPos) offset_y;
+ rect->width = delta_x_dev;
+ rect->height = delta_y_dev;
+/* printf("Adding x:%d, y:%d, with:%d, height:%d\n",
+ * rect->x, rect->y, rect->width, rect->height);
+ */
+ run_cache_index[current_color]++;
+ }
+
+ /*
+ * Reset the current values and continue
+ */
+ if (j != stop_col - 1) {
+ current_color = mosaic->tile_colors[i*mosaic->column_count + j + 1];
+ num_adj_tiles = 0;
+ }
+ }
+ else
+ num_adj_tiles++;
+ }
+ }
+
+ /*
+ * And now the firework ;-)
+ */
+ for (i = 0; i < mosaic->palette_size; i++) {
+ if (mosaic->color_usage[i] != 0) {
+/* printf("color_usage:%d, run_cache_index:%d\n",
+ * mosaic->color_usage[i], run_cache_index[i]);
+ */
+ values.foreground = mosaic->tile_palette[i];
+ XChangeGC(wi->dpy, wi->gc, GCForeground, &values);
+ XFillRectangles(wi->dpy, wi->draw_buffer, wi->gc,
+ run_cache[i], run_cache_index[i]);
+ }
+ }
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Pick --
+ * Nothing to pick, we are almost transparent.
+ *
+ **********************************************************************************
+ */
+
+static RadarBool
+Pick(Item item,
+ XPoint *p,
+ RadarDim aperture,
+ RadarBool closest,
+ RadarList items)
+{
+ return False;
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * PostScript --
+ *
+ **********************************************************************************
+ */
+
+static void
+PostScript(Item item,
+ PostScriptInfo ps_info)
+{
+}
+
+
+/*
+ **********************************************************************************
+ *
+ * Exported functions struct --
+ *
+ **********************************************************************************
+ */
+
+static ItemClassStruct MOSAIC_ITEM_CLASS = {
+ sizeof(MosaicItemStruct),
+ False,
+ 0,
+ Init,
+ Clone,
+ Remove,
+ Configure,
+ Query,
+ ComputeCoordinates,
+ ToArea,
+ Draw,
+ Pick,
+ PostScript
+};
+
+RadarItemClassId RadarMosaic = (RadarItemClassId) &MOSAIC_ITEM_CLASS;