diff options
-rw-r--r-- | Mosaic.c | 708 | ||||
-rw-r--r-- | patchlvl.h | 16 |
2 files changed, 724 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; diff --git a/patchlvl.h b/patchlvl.h new file mode 100644 index 0000000..a626944 --- /dev/null +++ b/patchlvl.h @@ -0,0 +1,16 @@ +/* + * XRADARVERSION is a string for the version specifier. The leading + * number is the major version number, the letter is the revision ("a" + * for alpha release, "b" for beta release, "c", and so on), and the + * trailing number is the patchlevel. + */ + +/* + * Keep these in sync with VERSION in Makefile.in + */ +#ifndef XRADARVERSION +#define XRADARVER 3 +#define XRADARREV 1 +#define XRADARPLVL 7 +#define XRADARVERSION "xradar-version-317" +#endif |