1 /* File: icon.c */
2 
3 /* Purpose: icon stuff */
4 
5 /*
6  * Copyright (c) 1997-2001 Tim Baker
7  *
8  * This software may be copied and distributed for educational, research, and
9  * not for profit purposes provided that this copyright and statement are
10  * included in all such copies.
11  */
12 
13 #include "tnb.h"
14 #include "icon.h"
15 
16 unsigned char *g_palette_rgb;
17 
18 t_icon_data *g_icon_data; /* Array of icon types */
19 int g_icon_data_count = 0; /* Number of icon types */
20 Tcl_HashTable g_icon_table; /* Hash table for icon types */
21 long g_icon_length = 0; /* Length in bytes of one icon */
22 int g_icon_size = 0; /* Icon dimensions (16, 24 or 32) */
23 int g_icon_depth = 0; /* Icon depth (8, 16 or 24 bpp) */
24 int g_pixel_size; /* Num bytes per pixel (1, 2, 3 or 4) */
25 int g_icon_pixels; /* Num pixels per icon (16x16, 24x24, 32x32) */
26 
27 
28 int *g_background = NULL;
29 
30 bool g_icon_map_changed = FALSE;
31 
32 
init_palette(void)33 void init_palette(void)
34 {
35 	if (Palette_Init(g_interp) != TCL_OK)
36 		quit(Tcl_GetStringResult(g_interp));
37 
38 	g_palette_rgb = Palette_GetRGB();
39 }
40 
41 
42 /*
43  *
44  */
Icon_AddType(t_icon_data * data)45 static void Icon_AddType(t_icon_data *data)
46 {
47 	int new;
48 	t_icon_data iconData, *icon_data_ptr = &iconData;
49 	Tcl_HashEntry *hPtr;
50 	memset(icon_data_ptr, 0, sizeof(t_icon_data));
51 	icon_data_ptr->desc = string_make(data->desc);
52 	icon_data_ptr->icon_count = data->icon_count;
53 	icon_data_ptr->icon_data = data->icon_data;
54 	icon_data_ptr->depth = data->depth;
55 	icon_data_ptr->bypp = data->bypp;
56 	icon_data_ptr->width = data->width;
57 	icon_data_ptr->height = data->height;
58 	icon_data_ptr->pitch = data->pitch;
59 	icon_data_ptr->length = data->length;
60 	icon_data_ptr->pixels = data->pixels;
61 
62 	g_icon_data = Array_Append(g_icon_data, &g_icon_data_count,
63 		sizeof(t_icon_data), icon_data_ptr);
64 
65 	hPtr = Tcl_CreateHashEntry(&g_icon_table, data->desc, &new);
66 	Tcl_SetHashValue(hPtr, (ClientData) (g_icon_data_count - 1));
67 }
68 
69 
70 /*
71  * Initialize the icon environment. This should be called once with
72  * the desired dimensions of the icons to use (16x16, 24x24 or 32x32).
73  */
init_icons(int size,int depth)74 void init_icons(int size, int depth)
75 {
76 	int i, n, y, x, y2, x2;
77 	t_assign_icon assign;
78 	t_icon_data icon_data, *icon_data_ptr = &icon_data;
79 	unsigned char *rgb = Colormap_GetRGB();
80 
81 	/* Initialize the Icon library */
82 	if (Icon_Init(g_interp, size, depth) != TCL_OK)
83 	{
84 		quit(Tcl_GetStringFromObj(Tcl_GetObjResult(g_interp), NULL));
85 	}
86 
87 	/*
88 	 * The TYPE_NONE/"none" type icon is a single masked icon with an empty
89 	 * mask. It is suitable for equipment displays when no item is present
90 	 * in a slot.
91 	 */
92 	icon_data_ptr->desc = "none";
93 	icon_data_ptr->icon_count = 1;
94 	C_MAKE(icon_data_ptr->icon_data, g_icon_length, byte);
95 	for (i = 0; i < g_icon_length; i++)
96 	{
97 		icon_data_ptr->icon_data[i] = 0x00;
98 	}
99 
100 	icon_data_ptr->depth = g_icon_depth;
101 	icon_data_ptr->bypp = g_pixel_size;
102 	icon_data_ptr->width = g_icon_size;
103 	icon_data_ptr->height = g_icon_size;
104 	icon_data_ptr->pitch = g_icon_size * g_pixel_size;
105 	icon_data_ptr->length = g_icon_size * g_icon_size * g_pixel_size;
106 	icon_data_ptr->pixels = g_icon_size * g_icon_size;
107 
108 	Icon_AddType(icon_data_ptr);
109 
110 	for (i = 0; i < g_icon_length; i++)
111 	{
112 		if (g_icon_depth != 8)
113 			icon_data_ptr->icon_data[i] = 0; /* Black (RGB 0,0,0) */
114 		else
115 			icon_data_ptr->icon_data[i] = COLORMAP_BLACK;
116 	}
117 
118 	/*
119 	 * The TYPE_BLANK/"blank" icon type is a single black unmasked icon
120 	 */
121 	icon_data_ptr->desc = "blank";
122 	icon_data_ptr->icon_count = 1;
123 	C_MAKE(icon_data_ptr->icon_data, g_icon_length, byte);
124 	for (i = 0; i < g_icon_length; i++)
125 	{
126 		if (g_icon_depth != 8)
127 			icon_data_ptr->icon_data[i] = 0; /* Black (RGB 0,0,0) */
128 		else
129 			icon_data_ptr->icon_data[i] = COLORMAP_BLACK;
130 	}
131 
132 	icon_data_ptr->depth = g_icon_depth;
133 	icon_data_ptr->bypp = g_pixel_size;
134 	icon_data_ptr->width = g_icon_size;
135 	icon_data_ptr->height = g_icon_size;
136 	icon_data_ptr->pitch = g_icon_size * g_pixel_size;
137 	icon_data_ptr->length = g_icon_size * g_icon_size * g_pixel_size;
138 	icon_data_ptr->pixels = g_icon_size * g_icon_size;
139 
140 	Icon_AddType(icon_data_ptr);
141 
142 	/*
143 	 * The TYPE_DEFAULT/"default" icon type is a single multicolored
144 	 * unmasked icon. If we see it, it probably means we forgot to
145 	 * assign an icon to something.
146 	 */
147 	icon_data_ptr->desc = "default";
148 	icon_data_ptr->icon_count = 1;
149 	C_MAKE(icon_data_ptr->icon_data, g_icon_length, byte);
150 	n = 0, y2 = 0;
151 	for (y = 0; y < 16; y++)
152 	{
153 		int dy = 0;
154 		if (g_icon_size == 24)
155 		{
156 			if (!(y & 1)) dy++;
157 		}
158 		if (g_icon_size == 32) dy++;
159 		x2 = 0;
160 		for (x = 0; x < 16; x++)
161 		{
162 			int dx = 0;
163 			if (g_icon_size == 24)
164 			{
165 				if (!(x & 1)) dx++;
166 			}
167 			if (g_icon_size == 32) dx++;
168 			PixelSet_RGB(icon_data_ptr->icon_data + (x2 * g_pixel_size) + (y2 * g_icon_size * g_pixel_size),
169 				rgb[0], rgb[1], rgb[2], g_pixel_size);
170 			PixelSet_RGB(icon_data_ptr->icon_data + ((x2 + dx) * g_pixel_size) + (y2 * g_icon_size * g_pixel_size),
171 				rgb[0], rgb[1], rgb[2], g_pixel_size);
172 			PixelSet_RGB(icon_data_ptr->icon_data + (x2 * g_pixel_size) + ((y2 + dy) * g_icon_size * g_pixel_size),
173 				rgb[0], rgb[1], rgb[2], g_pixel_size);
174 			PixelSet_RGB(icon_data_ptr->icon_data + ((x2 + dx) * g_pixel_size) + ((y2 + dy) * g_icon_size * g_pixel_size),
175 				rgb[0], rgb[1], rgb[2], g_pixel_size);
176 			rgb += 3;
177 
178 			n++;
179 			x2 += dx ? 2 : 1;
180 		}
181 		y2 += dy ? 2 : 1;
182 	}
183 
184 	icon_data_ptr->depth = g_icon_depth;
185 	icon_data_ptr->bypp = g_pixel_size;
186 	icon_data_ptr->width = g_icon_size;
187 	icon_data_ptr->height = g_icon_size;
188 	icon_data_ptr->pitch = g_icon_size * g_pixel_size;
189 	icon_data_ptr->length = g_icon_size * g_icon_size * g_pixel_size;
190 	icon_data_ptr->pixels = g_icon_size * g_icon_size;
191 
192 	Icon_AddType(icon_data_ptr);
193 
194 
195 	assign.type = ICON_TYPE_DEFAULT;
196 	assign.index = 0;
197 
198 
199 	/*
200 	 * When a feature is masked, or a masked icon is drawn on
201 	 * a feature, we may use the icon assigned to a different feature
202 	 * as the background.
203 	 */
204 	C_MAKE(g_background, z_info->f_max, int);
205 
206 	/* Clear the color hash table */
207 	Palette_ResetHash();
208 
209 	if (init_widget(g_interp, g_icon_depth) != TCL_OK)
210 		quit(Tcl_GetStringFromObj(Tcl_GetObjResult(g_interp), NULL));
211 
212 	/* if (CanvasWidget_Init(g_interp) != TCL_OK)
213 		quit(Tcl_GetStringFromObj(Tcl_GetObjResult(g_interp), NULL)); */
214 }
215 
216 
217 #include <limits.h>
218 #ifndef USHRT_MAX
219 #define USHRT_MAX 65535
220 #endif
221 
222 int PixelPtrToLong(IconPtr p, int bypp);
223 void PixelLongToPtr(IconPtr dst, int pixel, int bypp);
224 
225 /* Hack -- Standard 16 "term" colors. User should be able to change */
226 int g_term_palette[16] = {255, 0, 250, 17, 217, 196, 199, 101, 129,
227 	247, 30, 5, 35, 185, 180, 52};
228 
229 /* Actual 8/16/24 pixel values for above */
230 unsigned long g_term_colormap[16];
231 
232 
InitPixelSize(Tcl_Interp * interp)233 static int InitPixelSize(Tcl_Interp *interp)
234 {
235 	BitmapType bitmap;
236 
237 	bitmap.width = bitmap.height = 10;
238 	bitmap.depth = g_icon_depth;
239 	Bitmap_New(interp, &bitmap);
240 	g_pixel_size = bitmap.pixelSize;
241 	Bitmap_Delete(&bitmap);
242 
243 	return TCL_OK;
244 }
245 
246 RGBInfo g_rgbi;
247 
CountBits(unsigned long mask)248 static int CountBits(unsigned long mask)
249 {
250 	int n;
251 
252 	for (n = 0; mask != 0; mask &= mask - 1)
253 		n++;
254 	return n;
255 }
256 
InitRGBInfo(Tcl_Interp * interp)257 static void InitRGBInfo(Tcl_Interp *interp)
258 {
259 	Tk_Window tkwin = Tk_MainWindow(interp);
260 	Visual *visual = Tk_Visual(tkwin);
261 
262 	g_rgbi.red_mask = visual->red_mask;
263 	g_rgbi.green_mask = visual->green_mask;
264 	g_rgbi.blue_mask = visual->blue_mask;
265 
266 #ifdef PLATFORM_WIN
267 	/* XXX Always 5-5-5 */
268 	g_rgbi.red_mask = 0x7c00;
269 	g_rgbi.green_mask = 0x03e0;
270 	g_rgbi.blue_mask = 0x001f;
271 #endif
272 
273 	g_rgbi.red_count = CountBits(g_rgbi.red_mask);
274 	g_rgbi.green_count = CountBits(g_rgbi.green_mask);
275 	g_rgbi.blue_count = CountBits(g_rgbi.blue_mask);
276 
277 	g_rgbi.red_shift = g_rgbi.red_count + g_rgbi.green_count + g_rgbi.blue_count - 8;
278 	g_rgbi.green_shift = g_rgbi.green_count + g_rgbi.blue_count - 8;
279 	g_rgbi.blue_shift = -(g_rgbi.blue_count - 8);
280 
281 	g_rgbi.extra = ~(g_rgbi.red_mask | g_rgbi.green_mask | g_rgbi.blue_mask);
282 }
283 
284 
SetPix8(unsigned char * p,int r,int g,int b)285 static void SetPix8(unsigned char *p, int r, int g, int b)
286 {
287 	/* NOTE: Not Colormap */
288 	*p = Palette_RGB2Index(r, g, b);
289 }
290 
SetPix16(unsigned char * p,int r,int g,int b)291 void SetPix16(unsigned char *p, int r, int g, int b)
292 {
293 	int r2 = (r << g_rgbi.red_shift) & g_rgbi.red_mask;
294 	int g2 = (g << g_rgbi.green_shift) & g_rgbi.green_mask;
295 	int b2 = (b >> g_rgbi.blue_shift) & g_rgbi.blue_mask;
296 
297 	*((unsigned short *) p) = g_rgbi.extra | r2 | g2 | b2;
298 }
299 
SetPix24(unsigned char * p,int r,int g,int b)300 static void SetPix24(unsigned char *p, int r, int g, int b)
301 {
302 	*p++ = b;
303 	*p++ = g;
304 	*p++ = r;
305 	if (g_pixel_size == 4)
306 		*p++ = 0xFF;
307 }
308 
PixelSet_RGB(IconPtr dst,int r,int g,int b,int bypp)309 void PixelSet_RGB(IconPtr dst, int r, int g, int b, int bypp)
310 {
311 	switch (bypp)
312 	{
313 		case 1:
314 			SetPix8(dst, r, g, b);
315 			break;
316 		case 2:
317 			SetPix16(dst, r, g, b);
318 			break;
319 		case 3:
320 		case 4:
321 			SetPix24(dst, r, g, b);
322 			break;
323 	}
324 }
325 
PixelLongToPtr(IconPtr p,int pixel,int bypp)326 void PixelLongToPtr(IconPtr p, int pixel, int bypp)
327 {
328 	switch (bypp)
329 	{
330 		case 1:
331 			*p = (unsigned char) pixel;
332 			break;
333 		case 2:
334 			*((unsigned short *) p) = pixel & 0xFFFF;
335 			break;
336 		case 3:
337 		{
338 			unsigned char *p2 = (unsigned char *) &pixel;
339 			*p++ = *p2++;
340 			*p++ = *p2++;
341 			*p++ = *p2++;
342 			break;
343 		}
344 		case 4:
345 			*((unsigned long *) p) = pixel;
346 			break;
347 	}
348 }
349 
PixelPtrToLong(IconPtr p,int bypp)350 int PixelPtrToLong(IconPtr p, int bypp)
351 {
352 	switch (bypp)
353 	{
354 		case 1:
355 			return *p;
356 		case 2:
357 			return *(unsigned short *) p;
358 		case 3:
359 			return p[0] + (p[1] << 8) + (p[2] << 16); /* ??? */
360 		case 4:
361 			return *(int *) p;
362 	}
363 	return 0;
364 }
365 
366 
367 /*
368  * objcmd_icon --
369  */
objcmd_icon(ClientData dummy,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])370 static int objcmd_icon(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
371 {
372 	static cptr cmdOption[] = {"size", NULL};
373 	enum {IDX_SIZE};
374 	int option;
375 	Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
376 
377 	/* Hack - ignore parameter */
378 	(void) dummy;
379 
380 	/* Required number of arguments */
381     if (objc < 2)
382     {
383 		Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
384 		return TCL_ERROR;
385     }
386 
387 	/* Get requested option */
388     if (Tcl_GetIndexFromObj(interp, objv[1], cmdOption, "option", 0,
389 		&option) != TCL_OK)
390 	{
391 		return TCL_ERROR;
392     }
393 
394 	switch (option)
395 	{
396 		case IDX_SIZE: /* size */
397 			Tcl_SetIntObj(resultPtr, g_icon_size);
398 			break;
399 	}
400 
401 	/* Success */
402 	return TCL_OK;
403 }
404 
405 
406 /*
407  * Initialization.
408  */
Icon_Init(Tcl_Interp * interp,int size,int depth)409 int Icon_Init(Tcl_Interp *interp, int size, int depth)
410 {
411 	/* Only initialize once */
412 	if (g_icon_size != 0) return TCL_OK;
413 
414 	/* Require a known icon size */
415 	if ((size != 16) && (size != 24) && (size != 32))
416 	{
417 		Tcl_SetStringObj(Tcl_GetObjResult(interp),
418 			format("invalid icon size \"%d\": must be 16, 24 or 32", size), -1);
419 		return TCL_ERROR;
420 	}
421 
422 	/* Require a known icon depth */
423 	if ((depth != 8) && (depth != 16) && (depth != 24))
424 	{
425 		Tcl_SetStringObj(Tcl_GetObjResult(interp),
426 			format("invalid icon depth \"%d\": must be 8, 16 or 24", depth), -1);
427 		return TCL_ERROR;
428 	}
429 
430 	/* Remember the requested icon size */
431 	g_icon_size = size;
432 
433 	/* Remember the requested icon depth */
434 	g_icon_depth = depth;
435 
436 	if (InitPixelSize(interp) != TCL_OK)
437 	{
438 		return TCL_ERROR;
439 	}
440 
441 	/* Remember number of pixels in an icon */
442 	g_icon_pixels = size * size;
443 
444 	/* Remember the number of bytes in an icon */
445 	g_icon_length = g_icon_pixels * g_pixel_size;
446 
447 	/***** RETURN ERROR IF PALETTE NOT INITIALIZED *****/
448 
449 	g_palette_rgb = Palette_GetRGB();
450 
451 	if (g_icon_depth == 16) InitRGBInfo(interp);
452 
453 
454 
455 
456 	/* New block here */
457 	{
458 		int i, paletteIndex;
459 		for (i = 0; i < 16; i++)
460 		{
461 			paletteIndex = g_term_palette[i];
462 			switch (g_icon_depth)
463 			{
464 				case 8:
465 					g_term_colormap[i] = g_palette2colormap[paletteIndex];
466 					break;
467 				case 16:
468 				{
469 					unsigned short pix16;
470 					unsigned char *rgb = &g_palette_rgb[paletteIndex * 3];
471 					SetPix16((unsigned char *) &pix16, rgb[0], rgb[1], rgb[2]);
472 					g_term_colormap[i] = pix16;
473 					break;
474 				}
475 				case 24:
476 				{
477 					unsigned char *rgb = &g_palette_rgb[paletteIndex * 3];
478 					unsigned char *pix24 = (unsigned char *) &g_term_colormap[i];
479 					SetPix24(pix24 + 1, rgb[0], rgb[1], rgb[2]);
480 					break;
481 				}
482 			}
483 		}
484 	}
485 
486 	/*
487 	 * This is an array of t_icon_data types, which specify
488 	 * the icon data and optional mask data for each type of
489 	 * icon. Icon types are defined through the "icon createtype"
490 	 * command.
491 	 */
492 	MAKE(g_icon_data, t_icon_data);
493 	g_icon_data_count = 0;
494 
495 	/*
496 	 * This hash table maps symbolic names of icon types (as defined
497 	 * through the "icon createtype" command) to indexes into
498 	 * the g_icon_data[] array above.
499 	 */
500 	Tcl_InitHashTable(&g_icon_table, TCL_STRING_KEYS);
501 
502 	Tcl_CreateObjCommand(interp, "icon", objcmd_icon, NULL, NULL);
503 
504 	return TCL_OK;
505 }
506 
Icon_Exit(void)507 void Icon_Exit(void)
508 {
509 	int i;
510 
511 	if (g_icon_size == 0) return;
512 
513 	/* Check each icon type */
514 	for (i = 0; i < g_icon_data_count; i++)
515 	{
516 		t_icon_data *iconDataPtr = &g_icon_data[i];
517 
518 		/* Help the memory debugger */
519 		if (iconDataPtr->icon_data)
520 			FREE(iconDataPtr->icon_data);
521 	}
522 }
523