1 /*	memory.c
2 	Copyright (C) 2004-2021 Mark Tyler and Dmitry Groshev
3 
4 	This file is part of mtPaint.
5 
6 	mtPaint is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 3 of the License, or
9 	(at your option) any later version.
10 
11 	mtPaint is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with mtPaint in the file COPYING.
18 */
19 
20 #include "global.h"
21 #undef _
22 #define _(X) X
23 
24 #include "mygtk.h"
25 #include "memory.h"
26 #include "vcode.h"
27 #include "ani.h"
28 #include "png.h"
29 #include "mainwindow.h"
30 #include "otherwindow.h"
31 #include "layer.h"
32 #include "inifile.h"
33 #include "canvas.h"
34 #include "prefs.h"
35 #include "channels.h"
36 #include "toolbar.h"
37 #include "viewer.h"
38 #include "csel.h"
39 #include "thread.h"
40 
41 
42 grad_info gradient[NUM_CHANNELS];	// Per-channel gradients
43 double grad_path, grad_x0, grad_y0;	// Stroke gradient temporaries
44 grad_map graddata[NUM_CHANNELS + 1];	// RGB + per-channel gradient data
45 grad_store gradbytes;			// Storage space for custom gradients
46 int grad_opacity;			// Preview opacity
47 
48 /// Vectorized low-level drawing functions
49 
50 void (*put_pixel)(int x, int y) = put_pixel_def;
51 void (*put_pixel_row)(int x, int y, int len, unsigned char *xsel) = put_pixel_row_def;
52 
53 #define ROW_BUFLEN 2048 /* Preferred length of internal row buffer */
54 
55 /// Bayer ordered dithering
56 
57 const unsigned char bayer[16] = {
58 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
59 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 };
60 
61 /// Tint tool - contributed by Dmitry Groshev, January 2006
62 
63 int tint_mode[3];		// [0] = off/on, [1] = add/subtract, [2] = button (none, left, middle, right : 0-3)
64 
65 int mem_cselect;
66 int mem_blend;
67 int mem_unmask;
68 int mem_gradient;
69 
70 int paint_gamma;
71 
72 /// BLEND MODE SETTINGS
73 
74 int blend_mode = BLEND_HUE;
75 int blend_src;
76 
77 /// FLOOD FILL SETTINGS
78 
79 double flood_step;
80 int flood_cube, flood_img, flood_slide;
81 
82 int smudge_mode;
83 
84 /// QUANTIZATION SETTINGS
85 
86 int quan_sqrt;	// "Diameter based weighting" - use sqrt of pixel count
87 
88 /// IMAGE
89 
90 int mem_undo_depth = DEF_UNDO;		// Current undo depth
91 image_info mem_image;			// Current image
92 image_info mem_clip;			// Current clipboard
93 image_state mem_state;			// Current edit settings
94 
95 int mem_background = 180;		// Non paintable area
96 
97 unsigned char mem_brushes[PATCH_WIDTH * PATCH_HEIGHT * 3];
98 					// Preset brushes screen memory
99 int mem_clip_x = -1, mem_clip_y = -1;	// Clipboard location on canvas
100 int mem_nudge = -1;			// Nudge pixels per SHIFT+Arrow key during selection/paste
101 
102 transform_state mem_bcsp[2];
103 
104 /// UNDO ENGINE
105 
106 #define TILE_SIZE 64
107 #define TILE_SHIFT 6
108 #define MAX_TILEMAP ((((MAX_WIDTH + TILE_SIZE - 1) / TILE_SIZE + 7) / 8) * \
109 	((MAX_HEIGHT + TILE_SIZE - 1) / TILE_SIZE))
110 #define UF_TILED 0x01
111 #define UF_FLAT  0x02
112 #define UF_SIZED 0x04
113 #define UF_ORIG  0x08 /* Unmodified state */
114 #define UF_ACCUM 0x10 /* Cumulative */
115 
116 int mem_undo_limit;		// Max MB memory allocation limit
117 int mem_undo_common;		// Percent of undo space in common arena
118 int mem_undo_opacity;		// Use previous image for opacity calculations?
119 
120 int mem_undo_fail;		// Undo space shortfall
121 
122 typedef struct {
123 	unsigned int n, size, freecnt;
124 	void *datastore, *freelist;
125 } memchunks;
126 
127 #define UNDO_STORESIZE 1023 /* Leave space for memory block header */
128 
129 static memchunks undo_datastore = { UNDO_STORESIZE, sizeof(undo_data) };
130 static memchunks undo_items = { DEF_UNDO, sizeof(undo_item) };
131 
132 /// PATTERNS
133 
134 int pattern_B;				// Let colour B have its own pattern
135 unsigned char *mem_pattern;		// Original 0-1 pattern
136 unsigned char mem_col_pat[8 * 8];	// Indexed 8x8 colourised pattern using colours A & B
137 unsigned char mem_col_pat24[8 * 8 * 3];	// RGB 8x8 colourised pattern using colours A & B
138 
139 /// TOOLS
140 
141 tool_info tool_state = { TOOL_SQUARE, TOOL_SQUARE, { 1, 1, 255 } };
142 				// Type, brush, size/flow/opacity
143 int pen_down;			// Are we drawing? - Used to see if we need to do an UNDO
144 int tool_ox, tool_oy;		// Previous tool coords - used by continuous mode
145 int mem_continuous;		// Area we painting the static shapes continuously?
146 
147 
148 
149 /// PALETTE
150 
151 int mem_pal_id_c, mem_pal_ab_c;	// Text & A/B highlight colors
152 
153 unsigned char mem_pals[PALETTE_WIDTH * PALETTE_HEIGHT * 3];
154 				// RGB screen memory holding current palette
155 int mem_brush_list[NUM_BRUSHES][3] = {		// Preset brushes parameters
156 { TOOL_SPRAY, 5, 1 }, { TOOL_SPRAY, 7, 1 }, { TOOL_SPRAY, 9, 2 },
157 { TOOL_SPRAY, 13, 2 }, { TOOL_SPRAY, 15, 3 }, { TOOL_SPRAY, 19, 3 },
158 { TOOL_SPRAY, 23, 4 }, { TOOL_SPRAY, 27, 5 }, { TOOL_SPRAY, 31, 6 },
159 
160 { TOOL_SPRAY, 5, 5 }, { TOOL_SPRAY, 7, 7 }, { TOOL_SPRAY, 9, 9 },
161 { TOOL_SPRAY, 13, 13 }, { TOOL_SPRAY, 15, 15 }, { TOOL_SPRAY, 19, 19 },
162 { TOOL_SPRAY, 23, 23 }, { TOOL_SPRAY, 27, 27 }, { TOOL_SPRAY, 31, 31 },
163 
164 { TOOL_SPRAY, 5, 15 }, { TOOL_SPRAY, 7, 21 }, { TOOL_SPRAY, 9, 27 },
165 { TOOL_SPRAY, 13, 39 }, { TOOL_SPRAY, 15, 45 }, { TOOL_SPRAY, 19, 57 },
166 { TOOL_SPRAY, 23, 69 }, { TOOL_SPRAY, 27, 81 }, { TOOL_SPRAY, 31, 93 },
167 
168 { TOOL_CIRCLE, 3, -1 }, { TOOL_CIRCLE, 5, -1 }, { TOOL_CIRCLE, 7, -1 },
169 { TOOL_CIRCLE, 9, -1 }, { TOOL_CIRCLE, 13, -1 }, { TOOL_CIRCLE, 17, -1 },
170 { TOOL_CIRCLE, 21, -1 }, { TOOL_CIRCLE, 25, -1 }, { TOOL_CIRCLE, 31, -1 },
171 
172 { TOOL_SQUARE, 1, -1 }, { TOOL_SQUARE, 2, -1 }, { TOOL_SQUARE, 3, -1 },
173 { TOOL_SQUARE, 4, -1 }, { TOOL_SQUARE, 8, -1 }, { TOOL_SQUARE, 12, -1 },
174 { TOOL_SQUARE, 16, -1 }, { TOOL_SQUARE, 24, -1 }, { TOOL_SQUARE, 32, -1 },
175 
176 { TOOL_SLASH, 3, -1 }, { TOOL_SLASH, 5, -1 }, { TOOL_SLASH, 7, -1 },
177 { TOOL_SLASH, 9, -1 }, { TOOL_SLASH, 13, -1 }, { TOOL_SLASH, 17, -1 },
178 { TOOL_SLASH, 21, -1 }, { TOOL_SLASH, 25, -1 }, { TOOL_SLASH, 31, -1 },
179 
180 { TOOL_BACKSLASH, 3, -1 }, { TOOL_BACKSLASH, 5, -1 }, { TOOL_BACKSLASH, 7, -1 },
181 { TOOL_BACKSLASH, 9, -1 }, { TOOL_BACKSLASH, 13, -1 }, { TOOL_BACKSLASH, 17, -1 },
182 { TOOL_BACKSLASH, 21, -1 }, { TOOL_BACKSLASH, 25, -1 }, { TOOL_BACKSLASH, 31, -1 },
183 
184 { TOOL_VERTICAL, 3, -1 }, { TOOL_VERTICAL, 5, -1 }, { TOOL_VERTICAL, 7, -1 },
185 { TOOL_VERTICAL, 9, -1 }, { TOOL_VERTICAL, 13, -1 }, { TOOL_VERTICAL, 17, -1 },
186 { TOOL_VERTICAL, 21, -1 }, { TOOL_VERTICAL, 25, -1 }, { TOOL_VERTICAL, 31, -1 },
187 
188 { TOOL_HORIZONTAL, 3, -1 }, { TOOL_HORIZONTAL, 5, -1 }, { TOOL_HORIZONTAL, 7, -1 },
189 { TOOL_HORIZONTAL, 9, -1 }, { TOOL_HORIZONTAL, 13, -1 }, { TOOL_HORIZONTAL, 17, -1 },
190 { TOOL_HORIZONTAL, 21, -1 }, { TOOL_HORIZONTAL, 25, -1 }, { TOOL_HORIZONTAL, 31, -1 },
191 
192 };
193 
194 int mem_pal_def_i = 256;		// Items in default palette
195 
196 png_color mem_pal_def[256]={		// Default palette entries for new image
197 /// All RGB in 3 bits per channel. i.e. 0..7 - multiply by 255/7 for full RGB ..
198 /// .. or: int lookup[8] = {0, 36, 73, 109, 146, 182, 219, 255};
199 
200 /// Primary colours = 8
201 
202 {0,0,0}, {7,0,0}, {0,7,0}, {7,7,0}, {0,0,7}, {7,0,7}, {0,7,7}, {7,7,7},
203 
204 /// Primary fades to black: 7 x 6 = 42
205 
206 {6,6,6}, {5,5,5}, {4,4,4}, {3,3,3}, {2,2,2}, {1,1,1},
207 {6,0,0}, {5,0,0}, {4,0,0}, {3,0,0}, {2,0,0}, {1,0,0},
208 {0,6,0}, {0,5,0}, {0,4,0}, {0,3,0}, {0,2,0}, {0,1,0},
209 {6,6,0}, {5,5,0}, {4,4,0}, {3,3,0}, {2,2,0}, {1,1,0},
210 {0,0,6}, {0,0,5}, {0,0,4}, {0,0,3}, {0,0,2}, {0,0,1},
211 {6,0,6}, {5,0,5}, {4,0,4}, {3,0,3}, {2,0,2}, {1,0,1},
212 {0,6,6}, {0,5,5}, {0,4,4}, {0,3,3}, {0,2,2}, {0,1,1},
213 
214 /// Shading triangles: 6 x 21 = 126
215 /// RED
216 {7,6,6}, {6,5,5}, {5,4,4}, {4,3,3}, {3,2,2}, {2,1,1},
217 {7,5,5}, {6,4,4}, {5,3,3}, {4,2,2}, {3,1,1},
218 {7,4,4}, {6,3,3}, {5,2,2}, {4,1,1},
219 {7,3,3}, {6,2,2}, {5,1,1},
220 {7,2,2}, {6,1,1},
221 {7,1,1},
222 
223 /// GREEN
224 {6,7,6}, {5,6,5}, {4,5,4}, {3,4,3}, {2,3,2}, {1,2,1},
225 {5,7,5}, {4,6,4}, {3,5,3}, {2,4,2}, {1,3,1},
226 {4,7,4}, {3,6,3}, {2,5,2}, {1,4,1},
227 {3,7,3}, {2,6,2}, {1,5,1},
228 {2,7,2}, {1,6,1},
229 {1,7,1},
230 
231 /// BLUE
232 {6,6,7}, {5,5,6}, {4,4,5}, {3,3,4}, {2,2,3}, {1,1,2},
233 {5,5,7}, {4,4,6}, {3,3,5}, {2,2,4}, {1,1,3},
234 {4,4,7}, {3,3,6}, {2,2,5}, {1,1,4},
235 {3,3,7}, {2,2,6}, {1,1,5},
236 {2,2,7}, {1,1,6},
237 {1,1,7},
238 
239 /// YELLOW (red + green)
240 {7,7,6}, {6,6,5}, {5,5,4}, {4,4,3}, {3,3,2}, {2,2,1},
241 {7,7,5}, {6,6,4}, {5,5,3}, {4,4,2}, {3,3,1},
242 {7,7,4}, {6,6,3}, {5,5,2}, {4,4,1},
243 {7,7,3}, {6,6,2}, {5,5,1},
244 {7,7,2}, {6,6,1},
245 {7,7,1},
246 
247 /// MAGENTA (red + blue)
248 {7,6,7}, {6,5,6}, {5,4,5}, {4,3,4}, {3,2,3}, {2,1,2},
249 {7,5,7}, {6,4,6}, {5,3,5}, {4,2,4}, {3,1,3},
250 {7,4,7}, {6,3,6}, {5,2,5}, {4,1,4},
251 {7,3,7}, {6,2,6}, {5,1,5},
252 {7,2,7}, {6,1,6},
253 {7,1,7},
254 
255 /// CYAN (blue + green)
256 {6,7,7}, {5,6,6}, {4,5,5}, {3,4,4}, {2,3,3}, {1,2,2},
257 {5,7,7}, {4,6,6}, {3,5,5}, {2,4,4}, {1,3,3},
258 {4,7,7}, {3,6,6}, {2,5,5}, {1,4,4},
259 {3,7,7}, {2,6,6}, {1,5,5},
260 {2,7,7}, {1,6,6},
261 {1,7,7},
262 
263 
264 /// Scales: 11 x 6 = 66
265 
266 /// RGB
267 {7,6,5}, {6,5,4}, {5,4,3}, {4,3,2}, {3,2,1}, {2,1,0},
268 {7,5,4}, {6,4,3}, {5,3,2}, {4,2,1}, {3,1,0},
269 
270 /// RBG
271 {7,5,6}, {6,4,5}, {5,3,4}, {4,2,3}, {3,1,2}, {2,0,1},
272 {7,4,5}, {6,3,4}, {5,2,3}, {4,1,2}, {3,0,1},
273 
274 /// BRG
275 {6,5,7}, {5,4,6}, {4,3,5}, {3,2,4}, {2,1,3}, {1,0,2},
276 {5,4,7}, {4,3,6}, {3,2,5}, {2,1,4}, {1,0,3},
277 
278 /// BGR
279 {5,6,7}, {4,5,6}, {3,4,5}, {2,3,4}, {1,2,3}, {0,1,2},
280 {4,5,7}, {3,4,6}, {2,3,5}, {1,2,4}, {0,1,3},
281 
282 /// GBR
283 {5,7,6}, {4,6,5}, {3,5,4}, {2,4,3}, {1,3,2}, {0,2,1},
284 {4,7,5}, {3,6,4}, {2,5,3}, {1,4,2}, {0,3,1},
285 
286 /// GRB
287 {6,7,5}, {5,6,4}, {4,5,3}, {3,4,2}, {2,3,1}, {1,2,0},
288 {5,7,4}, {4,6,3}, {3,5,2}, {2,4,1}, {1,3,0},
289 
290 /// Misc
291 {7,5,0}, {6,4,0}, {5,3,0}, {4,2,0},		// Oranges
292 {7,0,5}, {6,0,4}, {5,0,3}, {4,0,2},		// Red Pink
293 {0,5,7}, {0,4,6}, {0,3,5}, {0,2,4},		// Blues
294 {0,0,0}, {0,0,0}
295 
296 /// End: Primary (8) + Fades (42) + Shades (126) + Scales (66) + Misc (14) = 256
297 };
298 
299 /// FONT FOR PALETTE WINDOW
300 
301 #define B8(A,B,C,D,E,F,G,H) (A|B<<1|C<<2|D<<3|E<<4|F<<5|G<<6|H<<7)
302 
303 static unsigned char mem_cross[PALETTE_CROSS_H] = {
304 	B8( 1,1,0,0,0,0,1,1 ),
305 	B8( 1,1,1,0,0,1,1,1 ),
306 	B8( 0,1,1,1,1,1,1,0 ),
307 	B8( 0,0,1,1,1,1,0,0 ),
308 	B8( 0,0,1,1,1,1,0,0 ),
309 	B8( 0,1,1,1,1,1,1,0 ),
310 	B8( 1,1,1,0,0,1,1,1 ),
311 	B8( 1,1,0,0,0,0,1,1 )
312 };
313 
314 #include "graphics/xbm_n7x7.xbm"
315 #if (PALETTE_DIGIT_W != xbm_n7x7_width) || (PALETTE_DIGIT_H * 10 != xbm_n7x7_height)
316 #error "Mismatched palette-window font"
317 #endif
318 
319 /* While a number of unwieldy allocation APIs is provided by GLib, it's better
320  * to do it the right way once, than constantly invent workarounds - WJ */
321 
322 #define WJMEM_DEFINCR 16384
323 #define WJMEM_RESERVED 64
324 #define WJMEM_DEFSIZE (WJMEM_DEFINCR - WJMEM_RESERVED)
325 
wjmemnew(int minsize,int incr)326 wjmem *wjmemnew(int minsize, int incr)
327 {
328 	wjmem *mem;
329 
330 	if (incr <= 0) incr = WJMEM_DEFINCR;
331 	if (minsize <= (int)sizeof(wjmem)) minsize = WJMEM_DEFSIZE;
332 	mem = calloc(1, minsize);
333 	if (mem)
334 	{
335 		mem->block = (char *)mem;
336 		mem->here = sizeof(wjmem);
337 		mem->size = mem->minsize = minsize;
338 		mem->incr = incr;
339 	}
340 	return (mem);
341 }
342 
wjmemfree(wjmem * mem)343 void wjmemfree(wjmem *mem)
344 {
345 	char *this, *next;
346 
347 	if (!mem) return;
348 	for (this = mem->block; this != (char *)mem; this = next)
349 	{
350 		next = *(char **)this;
351 		free(this);
352 	}
353 	free(mem);
354 }
355 
wjmalloc(wjmem * mem,int size,int align)356 void *wjmalloc(wjmem *mem, int size, int align)
357 {
358 	char *dest;
359 	unsigned int sz, ds;
360 
361 	align += !align; // 0 -> 1
362 	dest = mem->block + mem->here;
363 	dest = ALIGNED(dest, align);
364 	ds = dest - mem->block + size;
365 	if (ds > mem->size)
366 	{
367 		sz = mem->minsize;
368 		ds = sizeof(char *) + align + size;
369 		if (sz < ds)
370 		{
371 			ds += WJMEM_RESERVED + mem->incr - 1;
372 			sz = ds - ds % mem->incr - WJMEM_RESERVED;
373 		}
374 		dest = calloc(1, sz);
375 		if (!dest) return (NULL);
376 		*(char **)dest = mem->block;
377 		mem->block = dest;
378 		mem->size = sz;
379 		dest += sizeof(char *);
380 		dest = ALIGNED(dest, align);
381 		ds = dest - mem->block + size;
382 	}
383 	mem->here = ds;
384 	return ((void *)dest);
385 }
386 
387 /* Simple doubling allocator */
388 
getmemx2(memx2 * mem,size_t length)389 size_t getmemx2(memx2 *mem, size_t length)
390 {
391 	size_t s = mem->size - mem->here;
392 
393 	if (length > s)
394 	{
395 		size_t l = mem->here + length, l2 = mem->size * 2;
396 		unsigned char *tmp = NULL;
397 
398 		if ((l2 > l) && (l2 <= MEMX2_MAX)) tmp = realloc(mem->buf, l2);
399 		if (!tmp && (l <= MEMX2_MAX)) tmp = realloc(mem->buf, l2 = l);
400 		if (!tmp) return (s);
401 		mem->buf = tmp;
402 		mem->size = l2;
403 	}
404 	return (length);
405 }
406 
addstr(memx2 * mem,char * s,int bk)407 void addstr(memx2 *mem, char *s, int bk)
408 {
409 	int l;
410 
411 	if ((l = getmemx2(mem, strlen(s) + 1)))
412 	{
413 		memcpy(mem->buf + mem->here, s, l);
414 		mem->buf[(l += mem->here) - 1] = '\0';
415 		mem->here = l - bk;
416 	}
417 }
418 
addchars(memx2 * mem,int c,int l)419 void addchars(memx2 *mem, int c, int l)
420 {
421 	l = getmemx2(mem, l);
422 	memset(mem->buf + mem->here, c, l);
423 	mem->here += l;
424 }
425 
426 /* Calculate optimal number of objects in a memory chunk */
objcount(unsigned int n,unsigned int size,unsigned int hsize)427 static inline unsigned int objcount(unsigned int n, unsigned int size,
428 	unsigned int hsize)
429 {
430 	n = nextpow2(n * size + hsize + WJMEM_RESERVED);
431 	if (n < WJMEM_DEFINCR) n = WJMEM_DEFINCR;
432 	return ((n - hsize - WJMEM_RESERVED) / size);
433 }
434 
newchunk(memchunks * mem)435 static void *newchunk(memchunks *mem)
436 {
437 	void *node;
438 
439 	if ((node = mem->freelist))
440 	{
441 		mem->freelist = *(void **)node;
442 		*(void **)node = NULL; // Clear
443 	}
444 	else
445 	{
446 		if (!mem->freecnt)
447 		{
448 			unsigned int n = objcount(mem->n, mem->size, 0);
449 			node = calloc(n, mem->size);
450 			if (!node) return (NULL);
451 			mem->datastore = node;
452 			mem->freecnt = n;
453 		}
454 		/* Datastores are never freed, so pointer is movable */
455 		node = mem->datastore;
456 		mem->datastore += mem->size;
457 		mem->freecnt--;
458 	}
459 	return (node);
460 }
461 
freechunk(memchunks * mem,void * chunk)462 static inline void freechunk(memchunks *mem, void *chunk)
463 {
464 	*(void **)chunk = mem->freelist;
465 	mem->freelist = chunk;
466 }
467 
468 char MEM_NONE_[1]; /* Nothing is located here :-) */
469 
470 /* This allocates several memory chunks in one block - making it one single
471  * point of allocation failure, and needing just a single free() later on.
472  * On Windows, allocations aren't guaranteed to be double-aligned, so
473  * MA_ALIGN_DOUBLE flag is necessary there unless no chunks contain doubles. */
multialloc(int flags,void * ptr,int size,...)474 void *multialloc(int flags, void *ptr, int size, ...)
475 {
476 	va_list args;
477 	void *res;
478 	char *tmp;
479 	size_t tsz, sz = size, align = 0;
480 
481 
482 	if ((flags & MA_ALIGN_MASK) == MA_ALIGN_DOUBLE)
483 		align = sizeof(double) - 1;
484 
485 	va_start(args, size);
486 	while (va_arg(args, void *))
487 	{
488 		sz = (sz + align) & ~align;
489 		sz += va_arg(args, int);
490 	}
491 	va_end(args);
492 	if (!sz && (flags & MA_FLAG_NONE)) return (MEM_NONE);
493 	if (align) sz += align + 1;
494 	tmp = res = calloc(1, sz);
495 	if (res)
496 	{
497 		tmp = ALIGNED(tmp, align + 1);
498 		sz = 0; tsz = size;
499 		va_start(args, size);
500 		while (TRUE)
501 		{
502 			if (tsz || !(flags & MA_SKIP_ZEROSIZE))
503 				*(void **)ptr = (void *)(tmp + sz);
504 
505 			if (!(ptr = va_arg(args, void *))) break;
506 
507 			sz = (sz + tsz + align) & ~align;
508 			tsz = va_arg(args, int);
509 		}
510 		va_end(args);
511 	}
512 	return (res);
513 }
514 
frameset_realloc(frameset * fset)515 static int frameset_realloc(frameset *fset)
516 {
517 	image_frame *tmp;
518 	int n;
519 
520 	/* Next power of 2 */
521 	n = nextpow2(fset->cnt);
522 	if (n < FRAMES_MIN) n = FRAMES_MIN;
523 	if (n == fset->max) return (TRUE);
524 	tmp = realloc(fset->frames, n * sizeof(image_frame));
525 	if (!tmp) return (FALSE);
526 	fset->frames = tmp;
527 	fset->max = n;
528 	fset->size = 0; // Recalculate it later
529 	return (TRUE);
530 }
531 
532 /* Add one more frame to a frameset */
mem_add_frame(frameset * fset,int w,int h,int bpp,int cmask,png_color * pal)533 int mem_add_frame(frameset *fset, int w, int h, int bpp, int cmask, png_color *pal)
534 {
535 	image_frame *frm;
536 	unsigned char *res;
537 	size_t l, sz = (size_t)w * h;
538 	int i;
539 
540 	/* Extend frames array if necessary */
541 	if (fset->cnt >= fset->max)
542 	{
543 		if ((fset->cnt >= FRAMES_MAX) || !frameset_realloc(fset))
544 			return (FALSE);
545 	}
546 
547 	/* Initialize the frame */
548 	frm = fset->frames + fset->cnt;
549 	memset(frm, 0, sizeof(image_frame));
550 	frm->width = w;
551 	frm->height = h;
552 	frm->bpp = bpp;
553 
554 	/* Allocate channels */
555 	l = sz * bpp;
556 	res = MEM_NONE;
557 	for (i = CHN_IMAGE; res && (i < NUM_CHANNELS); i++)
558 	{
559 		if (cmask & CMASK_FOR(i))
560 			res = frm->img[i] = malloc(l);
561 		l = sz;
562 	}
563 
564 	/* Allocate palette if it differs from default */
565 	if (res && pal && (!fset->pal || memcmp(fset->pal, pal, SIZEOF_PALETTE)))
566 	{
567 		res = malloc(SIZEOF_PALETTE);
568 		if (res)
569 		{
570 			/* Set as default if first frame and no default yet */
571 			if (!fset->cnt && !fset->pal) fset->pal = (void *)res;
572 			else frm->pal = (void *)res;
573 			mem_pal_copy(res, pal);
574 		}
575 	}
576 
577 	if (!res) /* Not enough memory */
578 	{
579 		while (--i >= 0) free(frm->img[i]);
580 		return (FALSE);
581 	}
582 
583 	fset->cnt++;
584 	fset->size = 0; // Recalculate it later
585 	return (TRUE);
586 }
587 
588 /* Remove specified frame from a frameset */
mem_remove_frame(frameset * fset,int frame)589 void mem_remove_frame(frameset *fset, int frame)
590 {
591 	image_frame *tmp;
592 	int l = fset->cnt;
593 
594 	if (frame >= l) return;
595 	tmp = fset->frames + frame;
596 	mem_free_chanlist(tmp->img);
597 	free(tmp->pal);
598 	memmove(tmp, tmp + 1, (--l - frame) * sizeof(image_frame));
599 	fset->cnt = l;
600 // !!! Like with layers, you switch to another frame before deleting current one
601 	if (fset->cur > frame) fset->cur--;
602 	/* Reduce array size if 2/3+ empty */
603 	if ((l * 3 <= fset->max) && (fset->max > FRAMES_MIN))
604 		frameset_realloc(fset);
605 	fset->size = 0; // Recalculate it later
606 }
607 
608 /* Empty a frameset */
mem_free_frames(frameset * fset)609 void mem_free_frames(frameset *fset)
610 {
611 	image_frame *frm;
612 	int i;
613 
614 	if (fset->frames)
615 	{
616 		for (i = 0 , frm = fset->frames; i < fset->cnt; i++ , frm++)
617 		{
618 			mem_free_chanlist(frm->img);
619 			free(frm->pal);
620 		}
621 		free(fset->frames);
622 	}
623 	free(fset->pal);
624 	memset(fset, 0, sizeof(frameset));
625 }
626 
627 /* Set initial state of image variables */
init_istate(image_state * state,image_info * image)628 void init_istate(image_state *state, image_info *image)
629 {
630 	memset(state->prot_mask, 0, 256);	/* Clear all mask info */
631 	state->prot = 0;
632 	state->col_[0] = 1;
633 	state->col_[1] = 0;
634 	state->col_24[0] = image->pal[1];
635 	state->col_24[1] = image->pal[0];
636 	state->tool_pat = 0;
637 	state->tool_pat_B = 0;
638 }
639 
640 /* Add a new undo data node */
undo_add_data(undo_item * undo,int type,void * ptr)641 static int undo_add_data(undo_item *undo, int type, void *ptr)
642 {
643 	undo_data *node;
644 	unsigned int tmap = 1 << type;
645 
646 
647 	/* Reuse existing node */
648 	if ((node = undo->dataptr))
649 	{
650 		if (node->map & tmap) goto fail; // Prevent duplication
651 		tmap |= node->map;
652 	}
653 	/* Allocate a new node */
654 	else if (!(node = newchunk(&undo_datastore))) goto fail;
655 	node->map = tmap;
656 	node->store[type] = ptr;
657 	undo->dataptr = node;
658 	return (TRUE);
659 
660 fail:	/* Cannot store - delete the data right now */
661 	if (tmap & UD_FREE_MASK) free(ptr);
662 	return (FALSE);
663 }
664 
665 /* Free an undo data block, and delete its data */
undo_free_data(undo_item * undo)666 static void undo_free_data(undo_item *undo)
667 {
668 	undo_data *tmp;
669 	unsigned int tmap;
670 	int i;
671 
672 	if (!(tmp = undo->dataptr)) return;
673 	for (tmap = tmp->map & UD_FREE_MASK, i = 0; tmap; tmap >>= 1 , i++)
674 		if (tmap & 1) free(tmp->store[i]);
675 	freechunk(&undo_datastore, tmp);
676 	undo->dataptr = NULL;
677 }
678 
679 /* Swap undo data - move current set out, and replace by incoming set */
undo_swap_data(undo_item * outp)680 static void undo_swap_data(undo_item *outp)
681 {
682 	undo_data *tmp = outp->dataptr;
683 	unsigned int tmap;
684 
685 	outp->dataptr = NULL;
686 	if (mem_tempfiles) undo_add_data(outp, UD_TEMPFILES, mem_tempfiles);
687 	mem_tempfiles = NULL;
688 // !!! Other unconditionally outgoing stuff goes here
689 
690 	if (!tmp) return;
691 	tmap = tmp->map;
692 	if (tmap & (1 << UD_FILENAME))
693 	{
694 		undo_add_data(outp, UD_FILENAME, mem_filename);
695 		mem_filename = tmp->store[UD_FILENAME];
696 	}
697 	if (tmap & (1 << UD_TEMPFILES)) mem_tempfiles = tmp->store[UD_TEMPFILES];
698 // !!! All stuff (swappable or incoming) goes here
699 
700 	/* Release the incoming node */
701 	freechunk(&undo_datastore, tmp);
702 }
703 
704 /* Change layer's filename
705  * Note: calling this with non-empty redo, for example when saving to a new
706  * name, will "reparent" its frames from the old filename to the new one - WJ */
mem_replace_filename(int layer,char * fname)707 void mem_replace_filename(int layer, char *fname)
708 {
709 	image_info *image = &mem_image;
710 	undo_stack *undo;
711 	char *name;
712 
713 	if (layer != layer_selected) image = &layer_table[layer].image->image_;
714 	name = image->filename;
715 	if (fname && !fname[0]) fname = NULL; // Empty name is no name
716 
717 	/* Do nothing if "replacing" name by itself */
718 	if (fname && name ? !strcmp(fname, name) : fname == name) return;
719 
720 	/* !!! Make a copy of new filename while the old filename still exists,
721 	 * because the new pointer must differ from the old one - WJ */
722 	if (fname) fname = strdup(fname);
723 
724 	/* Store the old filename in _previous_ undo frame if possible */
725 	undo = &image->undo_;
726 	if (undo->done) undo_add_data(undo->items[(undo->pointer ?
727 		undo->pointer : undo->max) - 1], UD_FILENAME, name);
728 	else free(name);
729 
730 	/* Replace filename, and clear tempfiles too while we're at it */
731 	image->filename = fname;
732 	image->tempfiles = NULL;
733 }
734 
735 /* Label file's frames in current layer as changed */
mem_file_modified(char * fname)736 void mem_file_modified(char *fname)
737 {
738 	char *name;
739 	undo_item *undo;
740 	int i, j, k, l, changed;
741 
742 	l = mem_undo_done;
743 	for (k = -1; k <= 1; k += 2)
744 	{
745 		name = mem_filename;
746 		changed = name && !strcmp(name, fname) ? ~UF_ORIG : ~0;
747 		for (i = 1; i <= l; i++)
748 		{
749 			j = (mem_undo_max + mem_undo_pointer + i * k) % mem_undo_max;
750 			undo = mem_undo_im_[j];
751 			if (undo->dataptr && (undo->dataptr->map & (1 << UD_FILENAME)))
752 			{
753 				name = undo->dataptr->store[UD_FILENAME];
754 				changed = name && !strcmp(name, fname) ? ~UF_ORIG : ~0;
755 			}
756 			undo->flags &= changed;
757 		}
758 		l = mem_undo_redo;
759 	}
760 }
761 
762 /* Create new undo stack of a given depth, and put default frame onto it */
init_undo(undo_stack * ustack,int depth)763 int init_undo(undo_stack *ustack, int depth)
764 {
765 	if ((ustack->items = calloc(depth, sizeof(undo_item *))) &&
766 		(ustack->items[0] = newchunk(&undo_items)))
767 	{
768 		ustack->max = depth;
769 		ustack->pointer = ustack->done = ustack->redo = 0;
770 		ustack->size = 0;
771 		return (TRUE);
772 	}
773 	free(ustack->items);
774 	return (FALSE);
775 }
776 
777 /* Copy image state into current undo frame */
update_undo(image_info * image)778 void update_undo(image_info *image)
779 {
780 	undo_item *undo = image->undo_.items[image->undo_.pointer];
781 
782 /* !!! If system is unable to allocate 768 bytes, may as well die by SIGSEGV
783  * !!! right here, and not hobble along till GUI does the dying - WJ */
784 	if (!undo->pal_) undo->pal_ = malloc(SIZEOF_PALETTE);
785 	mem_pal_copy(undo->pal_, image->pal);
786 
787 	memcpy(undo->img, image->img, sizeof(chanlist));
788 	undo->dataptr = NULL;
789 	undo->cols = image->cols;
790 	undo->trans = image->trans;
791 	undo->bpp = image->bpp;
792 	undo->width = image->width;
793 	undo->height = image->height;
794 	undo->flags = image->changed ? 0 : UF_ORIG;
795 }
796 
mem_free_chanlist(chanlist img)797 void mem_free_chanlist(chanlist img)
798 {
799 	int i;
800 
801 	for (i = 0; i < NUM_CHANNELS; i++)
802 	{
803 		if (!img[i]) continue;
804 		if (img[i] != MEM_NONE) free(img[i]);
805 	}
806 }
807 
undo_free_x(undo_item ** undo_)808 static size_t undo_free_x(undo_item **undo_)
809 {
810 	undo_item *undo = *undo_;
811 	size_t j;
812 
813 	if (!undo) return (0);
814 	j = undo->size;
815 	undo_free_data(undo);
816 	free(undo->pal_);
817 	mem_free_chanlist(undo->img);
818 	memset(undo, 0, sizeof(undo_item));
819 	freechunk(&undo_items, undo);
820 	*undo_ = NULL;
821 	return (j);
822 }
823 
824 /* This resizes an in-use undo stack
825  * !!! Both old and new depths must be nonzero */
resize_undo(undo_stack * ustack,int depth)826 static int resize_undo(undo_stack *ustack, int depth)
827 {
828 	undo_stack nstack;
829 	int i, j, k, undo, redo, ptr, uptr, udepth, trim;
830 
831 	if (!init_undo(&nstack, depth)) return (FALSE);
832 	undo_free_x(nstack.items); // Drop default item
833 
834 	undo = ustack->done;
835 	redo = ustack->redo;
836 	if ((trim = undo + redo + 1 > depth))
837 	{
838 		i = (depth - 1) / 2;
839 		if (undo < i) redo = depth - undo - 1;
840 		else
841 		{
842 			if (redo > i) redo = i;
843 			undo = depth - redo - 1;
844 		}
845 	}
846 	uptr = ptr = ustack->pointer;
847 	if (ptr >= depth) ptr = 0;
848 	udepth = ustack->max;
849 	for (i = -undo; i <= redo; i++)
850 	{
851 		j = (uptr + i + udepth) % udepth;
852 		k = (ptr + i + depth) % depth;
853 		nstack.items[k] = ustack->items[j];
854 		ustack->items[j] = NULL;
855 	}
856 	nstack.pointer = ptr;
857 	nstack.done = undo;
858 	nstack.redo = redo;
859 	if (trim)
860 	{
861 		for (i = 0; i < udepth; i++)
862 			undo_free_x(ustack->items + i);
863 	}
864 	free(ustack->items);
865 	*ustack = nstack;
866 	return (TRUE);
867 }
868 
869 /* Resize all undo stacks */
update_undo_depth()870 void update_undo_depth()
871 {
872 	image_info *image;
873 	int l;
874 
875 	mem_undo_depth = mem_undo_depth <= MIN_UNDO ? MIN_UNDO :
876 		mem_undo_depth >= MAX_UNDO ? MAX_UNDO : mem_undo_depth | 1;
877 	for (l = 0; l <= layers_total; l++)
878 	{
879 		image = l == layer_selected ? &mem_image :
880 			&layer_table[l].image->image_;
881 		if (image->undo_.max == mem_undo_depth) continue;
882 		resize_undo(&image->undo_, mem_undo_depth);
883 	}
884 }
885 
886 /* Clear/remove image data */
mem_free_image(image_info * image,int mode)887 void mem_free_image(image_info *image, int mode)
888 {
889 	int i, j = image->undo_.max, p = image->undo_.pointer;
890 
891 	/* Delete current image (don't rely on undo frame being up to date) */
892 	if (mode & FREE_IMAGE)
893 	{
894 		mem_free_chanlist(image->img);
895 		memset(image->img, 0, sizeof(chanlist));
896 		image->width = image->height = 0;
897 
898 		free(image->filename);
899 		image->filename = image->tempfiles = NULL;
900 	}
901 
902 	/* Delete undo frames if any */
903 	image->undo_.pointer = image->undo_.done = image->undo_.redo = 0;
904 	if (!image->undo_.items) return;
905 	memset(image->undo_.items[p]->img, 0, sizeof(chanlist)); // Already freed
906 	for (i = 0; i < j; i++) undo_free_x(image->undo_.items + i);
907 
908 	/* Delete undo stack if finalizing */
909 	if (mode & FREE_UNDO)
910 	{
911 		free(image->undo_.items);
912 		image->undo_.items = NULL;
913 		image->undo_.max = 0;
914 	}
915 	/* Otherwise, allocate default frame */
916 	else image->undo_.items[0] = newchunk(&undo_items);
917 }
918 
919 /* Allocate new image data */
920 // !!! Does NOT copy palette in copy mode, as it may be invalid
mem_alloc_image(int mode,image_info * image,int w,int h,int bpp,int cmask,image_info * src)921 int mem_alloc_image(int mode, image_info *image, int w, int h, int bpp,
922 	int cmask, image_info *src)
923 {
924 	unsigned char *res;
925 	size_t l, sz;
926 	int i;
927 
928 	if (mode & AI_CLEAR) memset(image, 0, sizeof(image_info));
929 	else
930 	{
931 		memset(image->img, 0, sizeof(chanlist));
932 		image->filename = image->tempfiles = NULL; /* Paranoia */
933 		image->changed = 0;
934 	}
935 
936 	if (mode & AI_COPY)
937 	{
938 		if (src->filename && !(image->filename = strdup(src->filename)))
939 			return (FALSE);
940 		image->tempfiles = src->tempfiles;
941 		image->changed = src->changed;
942 
943 		w = src->width;
944 		h = src->height;
945 		bpp = src->bpp;
946 		cmask = cmask_from(src->img);
947 	}
948 
949 	image->width = w;
950 	image->height = h;
951 	image->bpp = bpp;
952 
953 	if (!cmask) return (TRUE); /* Empty block requested */
954 
955 	sz = (size_t)w * h;
956 	l = sz * bpp;
957 	res = MEM_NONE;
958 	for (i = CHN_IMAGE; res && (i < NUM_CHANNELS); i++)
959 	{
960 		if (cmask & CMASK_FOR(i)) res = image->img[i] = malloc(l);
961 		l = sz;
962 	}
963 	if (res && image->undo_.items)
964 	{
965 		undo_item *undo = image->undo_.items[image->undo_.pointer];
966 		if (!undo->pal_) res = (void *)(undo->pal_ = malloc(SIZEOF_PALETTE));
967 	}
968 	if (!res) /* Not enough memory */
969 	{
970 		free(image->filename);
971 		image->filename = NULL;
972 		while (--i >= 0) free(image->img[i]);
973 		memset(image->img, 0, sizeof(chanlist));
974 		return (FALSE);
975 	}
976 
977 	l = sz * bpp;
978 	if (mode & AI_COPY) /* Clone */
979 	{
980 		for (i = CHN_IMAGE; i < NUM_CHANNELS; i++)
981 		{
982 			if (image->img[i]) memcpy(image->img[i], src->img[i], l);
983 			l = sz;
984 		}
985 	}
986 	else if (!(mode & AI_NOINIT)) /* Init */
987 	{
988 		for (i = CHN_IMAGE; i < NUM_CHANNELS; i++)
989 		{
990 			if (image->img[i]) memset(image->img[i], channel_fill[i], l);
991 			l = sz;
992 		}
993 	}
994 
995 	return (TRUE);
996 }
997 
998 /* Allocate space for new image, removing old if needed */
mem_new(int width,int height,int bpp,int cmask)999 int mem_new( int width, int height, int bpp, int cmask )
1000 {
1001 	int res;
1002 
1003 	mem_free_image(&mem_image, FREE_IMAGE);
1004 	res = mem_alloc_image(0, &mem_image, width, height, bpp, cmask, NULL);
1005 	if (!res) /* Not enough memory */
1006 	{
1007 		// 8x8 is bound to work!
1008 		mem_alloc_image(0, &mem_image, 8, 8, bpp, CMASK_IMAGE, NULL);
1009 	}
1010 	mem_image.trans = -1;
1011 
1012 // !!! If palette isn't set up before mem_new(), undo frame will get wrong one
1013 // !!! (not that it affects anything at this time)
1014 	update_undo(&mem_image);
1015 	mem_channel = CHN_IMAGE;
1016 	mem_xbm_hot_x = mem_xbm_hot_y = -1;
1017 
1018 	return (!res);
1019 }
1020 
cmask_from(chanlist img)1021 int cmask_from(chanlist img)
1022 {
1023 	int i, j, k = 1;
1024 
1025 	for (i = j = 0; i < NUM_CHANNELS; i++ , k += k)
1026 		if (img[i]) j |= k;
1027 	return (j);
1028 }
1029 
1030 /* Allocate new clipboard, removing or preserving old as needed */
mem_clip_new(int width,int height,int bpp,int cmask,chanlist backup)1031 int mem_clip_new(int width, int height, int bpp, int cmask, chanlist backup)
1032 {
1033 	int res;
1034 
1035 
1036 	/* Text flag defaults to cleared */
1037 	text_paste = 0;
1038 
1039 	/* Clear everything if no backup needed */
1040 	if (!backup)
1041 	{
1042 		mem_free_image(&mem_clip, FREE_ALL);
1043 		mem_clip_paletted = 0;
1044 	}
1045 
1046 	/* Backup current contents */
1047 	else memcpy(backup, mem_clip.img, sizeof(chanlist));
1048 
1049 	/* Allocate new frame */
1050 	res = mem_alloc_image(AI_NOINIT, &mem_clip, width, height, bpp, cmask, NULL);
1051 
1052 	/* Remove backup if allocation failed */
1053 	if (!res && backup)
1054 	{
1055 		mem_free_chanlist(backup);
1056 		mem_clip_paletted = 0;
1057 	}
1058 
1059 	return (!res);
1060 }
1061 
1062 /* Get address of previous channel data (or current if none) */
mem_undo_previous(int channel)1063 unsigned char *mem_undo_previous(int channel)
1064 {
1065 	undo_item *undo;
1066 	unsigned char *res;
1067 
1068 	undo = mem_undo_im_[(mem_undo_pointer ? mem_undo_pointer : mem_undo_max) - 1];
1069 	if (!undo || !(res = undo->img[channel]) || (res == MEM_NONE) ||
1070 		(undo->flags & UF_TILED))
1071 		res = mem_img[channel];	// No usable undo so use current
1072 	return (res);
1073 }
1074 
lose_oldest(undo_stack * ustack)1075 static size_t lose_oldest(undo_stack *ustack)	// Lose the oldest undo image
1076 {
1077 	int idx;
1078 
1079 	if (ustack->redo > ustack->done) idx = ustack->redo--;
1080 	else if (ustack->done) idx = ustack->max - ustack->done--;
1081 	else return (0);
1082 /* !!! mem_try_malloc() may call this on an unsized undo stack - but it
1083  * !!! doesn't need valid sizes anyway - WJ */
1084 	return (undo_free_x(ustack->items + (ustack->pointer + idx) % ustack->max));
1085 }
1086 
1087 /* Convert tile bitmap row into a set of spans (skip/copy), terminated by
1088  * a zero-length copy span; return copied length */
mem_undo_spans(int * spans,unsigned char * tmap,int width,int bpp)1089 static int mem_undo_spans(int *spans, unsigned char *tmap, int width, int bpp)
1090 {
1091 	int bt = 0, bw = 0, tl = 0, l = 0, ll = bpp * TILE_SIZE;
1092 
1093 	while (width > 0)
1094 	{
1095 		if ((bw >>= 1) < 2) bw = 0x100 + *tmap++;
1096 		if (bt ^ (bw & 1))
1097 		{
1098 			*spans++ = tl * ll;
1099 			tl = 0;
1100 		}
1101 		tl++;
1102 		l += (bt = bw & 1) * ll;
1103 		width -= TILE_SIZE;
1104 	}
1105 	width *= bpp;
1106 	*spans++ = tl * ll + width;
1107 	l += bt * width;
1108 	spans[0] = spans[bt] = 0;
1109 	return (l);
1110 }
1111 
1112 /* Endianness-aware byte shifts */
1113 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1114 #define SHIFTUP(X,N) (X) <<= ((N) << 3)
1115 #define SHIFTDN(X,N) (X) >>= ((N) << 3)
1116 #else /* G_BYTE_ORDER == G_BIG_ENDIAN */
1117 #define SHIFTUP(X,N) (X) >>= ((N) << 3)
1118 #define SHIFTDN(X,N) (X) <<= ((N) << 3)
1119 #endif
1120 
1121 /* Register-sized unsigned integer - redefine if this isn't it */
1122 #include <stdint.h>
1123 #define R_INT uintptr_t
1124 
1125 /* Integer-at-a-time byte array comparison function; its efficiency depends on
1126  * both arrays aligned, or misaligned, the same - which is natural for channel
1127  * strips when geometry and position match - WJ */
tile_row_compare(unsigned char * src,unsigned char * dest,int w,int h,unsigned char * buf)1128 static int tile_row_compare(unsigned char *src, unsigned char *dest,
1129 	int w, int h, unsigned char *buf)
1130 {
1131 	const int amask = sizeof(R_INT) - 1;
1132 	int l = w * h, mc = (w + TILE_SIZE - 1) >> TILE_SHIFT, nc = 0;
1133 
1134 	/* Long enough & identically aligned - use fast path */
1135 	if ((w > sizeof(R_INT)) && (l > sizeof(R_INT) * 4) &&
1136 		(((int)src & amask) == ((int)dest & amask)))
1137 	{
1138 		R_INT v, vm, vt1, vt2, *isrc, *idest;
1139 		int i, k, t, x, d0, d1, il;
1140 
1141 		/* Given that loose ends, if any, belong to tiles too, we
1142 		 * simply leave them for later - maybe there won't be need */
1143 		d0 = (((int)src ^ amask) + 1) & amask;
1144 		d1 = (int)(src + l) & amask;
1145 		isrc = (R_INT *)(src + d0);
1146 		idest = (R_INT *)(dest + d0);
1147 		il = (l - d0 - d1) / sizeof(v);
1148 		i = 0;
1149 		while (TRUE)
1150 		{
1151 			/* Fast comparison loop - damn GCC's guts for not
1152 			 * allocating it on registers without heavy wizardry */
1153 			{
1154 				int wi = il - i;
1155 				R_INT *wsrc = isrc + i, *wdest = idest + i;
1156 				while (TRUE)
1157 				{
1158 					if (wi-- <= 0) goto done;
1159 					if (*wsrc != *wdest) break;
1160 					++wsrc; ++wdest;
1161 				}
1162 				t = (unsigned char *)wsrc - src;
1163 			}
1164 			k = (unsigned int)t % w;
1165 			x = TILE_SIZE - (k & (TILE_SIZE - 1));
1166 			if (k + x > w) x = w - k;
1167 			k >>= TILE_SHIFT;
1168 
1169 			/* Value overlaps two or three tiles */
1170 			while (x < sizeof(v))
1171 			{
1172 				v = *(R_INT *)(src + t) ^ *(R_INT *)(dest + t);
1173 tile2:				vm = ~0UL;
1174 				SHIFTUP(vm, x);
1175 				x += sizeof(v);
1176 				if (!(vm &= v)) break;
1177 				x -= sizeof(v);
1178 
1179 				/* Farther tile(s) differ */
1180 				if ((v != vm) && !buf[k]) /* First one differs too */
1181 				{
1182 					buf[k] = 1;
1183 					if (++nc >= mc) x = l; /* Done is done */
1184 				}
1185 				if (++k + 1 == mc) /* May be 3 tiles */
1186 				{
1187 					x += w & (TILE_SIZE - 1);
1188 					if (x >= sizeof(v)) break;
1189 					v = vm;
1190 					goto tile2;
1191 				}
1192 				x += TILE_SIZE;
1193 				if (k == mc) k = 0; /* Row wrap */
1194 				break;
1195 			}
1196 			i = (t + x - d0) / sizeof(v);
1197 			if (buf[k]) continue;
1198 			buf[k] = 1;
1199 			if (++nc >= mc) break;
1200 		}
1201 done:
1202 		/* Compare the ends - using the fact that memory blocks
1203 		 * *must* be aligned at least that much */
1204 		if (d1 && !buf[mc - 1])
1205 		{
1206 			vt2 = isrc[il] ^ idest[il];
1207 			SHIFTUP(vt2, sizeof(vt2) - d1);
1208 			if (vt2) ++nc , buf[mc - 1] = 1;
1209 		}
1210 		if (d0 && !buf[0])
1211 		{
1212 			vt1 = *(isrc - 1) ^ *(idest - 1);
1213 			SHIFTDN(vt1, d0);
1214 			if (vt1) ++nc , buf[0] = 1;
1215 		}
1216 	}
1217 	/* Misaligned - use slow path */
1218 	else
1219 	{
1220 		int i, k, x;
1221 
1222 		for (i = 0; i < l; i++)
1223 		{
1224 			if (src[i] != dest[i])
1225 			{
1226 				k = (unsigned int)i % w;
1227 				x = TILE_SIZE - (k & (TILE_SIZE - 1));
1228 				if (k + x > w) x = w - k;
1229 				i += x;
1230 				k >>= TILE_SHIFT;
1231 				if (buf[k]) continue;
1232 				buf[k] = 1;
1233 				if (++nc >= mc) break;
1234 			}
1235 		}
1236 	}
1237 	return (nc);
1238 }
1239 
1240 /* Convert undo frame to tiled representation */
mem_undo_tile(undo_item * undo)1241 static void mem_undo_tile(undo_item *undo)
1242 {
1243 	unsigned char buf[((MAX_WIDTH + TILE_SIZE - 1) / TILE_SIZE) * 3];
1244 	unsigned char *tstrip, tmap[MAX_TILEMAP], *tmp = NULL;
1245 	int spans[(MAX_WIDTH + TILE_SIZE - 1) / TILE_SIZE + 3];
1246 	size_t sz, area = 0, msize = 0;
1247 	int i, j, k, nt, dw, cc, bpp;
1248 	int h, nc, bw, tw, tsz, nstrips, ntiles = 0;
1249 
1250 
1251 	undo->flags |= UF_FLAT; /* Not tiled by default */
1252 
1253 	/* Not tileable if too small */
1254 	if (mem_width + mem_height < TILE_SIZE * 3) return;
1255 
1256 	/* Not tileable if different geometry */
1257 	if ((undo->width != mem_width) || (undo->height != mem_height) ||
1258 		(undo->bpp != mem_img_bpp)) return;
1259 
1260 	for (i = nc = 0; i < NUM_CHANNELS; i++)
1261 	{
1262 		/* Not tileable if different set of channels */
1263 		if (!!undo->img[i] ^ !!mem_img[i]) return;
1264 		if (undo->img[i] && mem_img[i] &&
1265 			(undo->img[i] != MEM_NONE)) nc |= 1 << i;
1266 	}
1267 	/* Not tileable if no matching channels */
1268 	if (!nc) return;
1269 
1270 	/* Build tilemap */
1271 	nstrips = (mem_height + TILE_SIZE - 1) / TILE_SIZE;
1272 	dw = (TILE_SIZE - 1) & ~(mem_width - 1);
1273 	bw = (mem_width + TILE_SIZE - 1) / TILE_SIZE;
1274 	tw = (bw + 7) >> 3; tsz = tw * nstrips;
1275 	memset(tmap, 0, tsz);
1276 	for (i = 0 , tstrip = tmap; i < mem_height; i += TILE_SIZE , tstrip += tw)
1277 	{
1278 		h = mem_height - i;
1279 		if (h > TILE_SIZE) h = TILE_SIZE;
1280 
1281 		/* Compare strip of image */
1282 		memset(buf, 0, bw * 3);
1283 		for (cc = 0; nc >= 1 << cc; cc++)
1284 		{
1285 			unsigned char *src, *dest;
1286 			int j, k, j2, w;
1287 
1288 			if (!(nc & 1 << cc)) continue;
1289 			bpp = BPP(cc);
1290 			w = mem_width * bpp;
1291 			k = i * w;
1292 			src = undo->img[cc] + k;
1293 			dest = mem_img[cc] + k;
1294 			if (!tile_row_compare(src, dest, w, h, buf)) continue;
1295 			if (bpp == 1) continue;
1296 			/* 3 bpp happen only in image channel, which goes first;
1297 			 * so we can postprocess the results to match 1 bpp */
1298 			for (j = j2 = 0; j < bw; j++ , j2 += 3)
1299 				buf[j] = buf[j2] | buf[j2 + 1] | buf[j2 + 2];
1300 		}
1301 		/* Fill tilemap row */
1302 		for (j = nt = 0; j < bw; j++)
1303 		{
1304 			nt += (k = buf[j]);
1305 			tstrip[j >> 3] |= k << (j & 7);
1306 		}
1307 		ntiles += nt;
1308 		area += (nt * TILE_SIZE - buf[bw - 1] * dw) * h;
1309 	}
1310 
1311 	/* Not tileable if tilemap cannot fit in space gained */
1312 	sz = (size_t)mem_width * mem_height;
1313 	bpp = (nc & CMASK_IMAGE ? mem_img_bpp : 1);
1314 	if ((sz - area) * bpp <= tsz) return;
1315 
1316 	/* Implement tiling */
1317 	sz = (size_t)mem_width * mem_height;
1318 	for (cc = 0; nc >= 1 << cc; cc++)
1319 	{
1320 		unsigned char *src, *dest, *blk;
1321 		size_t l;
1322 		int i;
1323 
1324 		if (!(nc & 1 << cc)) continue;
1325 		if (!ntiles) /* Channels unchanged - free the memory */
1326 		{
1327 			free(undo->img[cc]);
1328 			undo->img[cc] = MEM_NONE;
1329 			continue;
1330 		}
1331 
1332 		/* Try to reduce memory fragmentation - allocate small blocks
1333 		 * anew when possible, instead of carving up huge ones */
1334 		src = blk = undo->img[cc];
1335 		bpp = BPP(cc);
1336 		l = area * bpp + (tmp ? 0 : tsz);
1337 		if (l * 3 <= sz * bpp) /* Small enough */
1338 		{
1339 			blk = malloc(l);
1340 			/* Use original chunk if cannot get new one */
1341 			if (!blk) blk = src;
1342 		}
1343 		dest = blk;
1344 
1345 		/* Compress channel */
1346 		for (i = 0; i < nstrips; i++)
1347 		{
1348 			int j, k, *span;
1349 
1350 			mem_undo_spans(spans, tmap + tw * i, mem_width, bpp);
1351 			k = mem_height - i * TILE_SIZE;
1352 			if (k > TILE_SIZE) k = TILE_SIZE;
1353 			for (j = 0; j < k; j++)
1354 			{
1355 				span = spans;
1356 				while (TRUE)
1357 				{
1358 					src += *span++;
1359 					if (!*span) break;
1360 					if (dest != src) memmove(dest, src, *span);
1361 					src += *span; dest += *span++;
1362 				}
1363 			}
1364 		}
1365 
1366 		/* Resize or free memory block */
1367 		if (blk == undo->img[cc]) /* Resize old */
1368 		{
1369 			dest = realloc(undo->img[cc], l);
1370 			/* Leave chunk alone if resizing failed */
1371 			if (!dest) l = sz * bpp;
1372 			else undo->img[cc] = dest;
1373 		}
1374 		else /* Replace with new */
1375 		{
1376 			free(undo->img[cc]);
1377 			undo->img[cc] = blk;
1378 		}
1379 		msize += l + 32;
1380 
1381 		/* Place tilemap in first chunk */
1382 		if (!tmp) tmp = undo->img[cc] + area * bpp;
1383 	}
1384 
1385 	/* Re-label as tiled and store tilemap, if there *are* tiles */
1386 	if (msize)
1387 	{
1388 		undo->flags ^= UF_FLAT | UF_TILED;
1389 		undo->tileptr = tmp;
1390 		memcpy(tmp, tmap, tsz);
1391 	}
1392 
1393 	if (undo->pal_) msize += SIZEOF_PALETTE + 32;
1394 	undo->size = msize;
1395 	undo->flags |= UF_SIZED;
1396 }
1397 
1398 /* Compress last undo frame */
mem_undo_prepare()1399 void mem_undo_prepare()
1400 {
1401 	undo_item *undo;
1402 
1403 	if (!mem_undo_done) return;
1404 	undo = mem_undo_im_[(mem_undo_pointer ? mem_undo_pointer : mem_undo_max) - 1];
1405 
1406 	/* Already processed? */
1407 	if (undo->flags & (UF_TILED | UF_FLAT)) return;
1408 
1409 	/* Cull palette if unchanged */
1410 	if (undo->pal_ && !memcmp(undo->pal_, mem_pal, SIZEOF_PALETTE))
1411 	{
1412 		/* Free new block, reuse old */
1413 		free(mem_undo_im_[mem_undo_pointer]->pal_);
1414 		mem_undo_im_[mem_undo_pointer]->pal_ = undo->pal_;
1415 		undo->pal_ = NULL;
1416 	}
1417 	/* Tile image */
1418 	mem_undo_tile(undo);
1419 }
1420 
mem_undo_size(undo_stack * ustack)1421 static size_t mem_undo_size(undo_stack *ustack)
1422 {
1423 	undo_item *undo;
1424 	size_t k, l, total = 0;
1425 	int i, j, bpp, umax = ustack->max;
1426 
1427 	for (i = 0; i < umax; i++)
1428 	{
1429 		/* Anything there? */
1430 		if (!(undo = ustack->items[i])) continue;
1431 		/* Not empty and not yet scanned */
1432 		if (undo->width && !(undo->flags & UF_SIZED))
1433 		{
1434 			k = (size_t)undo->width * undo->height;
1435 			bpp = undo->bpp;
1436 			for (j = l = 0; j < NUM_CHANNELS; j++)
1437 			{
1438 				if (undo->img[j] && (undo->img[j] != MEM_NONE))
1439 					l += k * bpp + 32;
1440 				bpp = 1;
1441 			}
1442 			if (undo->pal_) l += SIZEOF_PALETTE + 32;
1443 			undo->size = l;
1444 			undo->flags |= UF_SIZED;
1445 		}
1446 		total += undo->size;
1447 	}
1448 
1449 	return (total);
1450 }
1451 
1452 /* Add up sizes of all layers other than current */
mem_undo_lsize()1453 static size_t mem_undo_lsize()
1454 {
1455 	undo_stack *ustack;
1456 	size_t total = 0;
1457 	int l;
1458 
1459 	for (l = 0; l <= layers_total; l++)
1460 	{
1461 		if (l == layer_selected) continue;
1462 		ustack = &layer_table[l].image->image_.undo_;
1463 // !!! This relies on layer_table items already processed by update_undo()
1464 		if (!ustack->size) ustack->size = mem_undo_size(ustack);
1465 		total += ustack->size;
1466 	}
1467 
1468 	return (total);
1469 }
1470 
1471 /* Free requested amount of undo space */
mem_undo_space(size_t mem_req)1472 static int mem_undo_space(size_t mem_req)
1473 {
1474 	undo_stack *heap[MAX_LAYERS + 2], *wp, *hp;
1475 	size_t mem_lim, mem_max = (size_t)mem_undo_limit * (1024 * 1024);
1476 	int i, l, l2, h, csz = mem_undo_common * layers_total;
1477 
1478 	/* Layer mem limit including common area */
1479 	mem_lim = mem_max * (csz * 0.01 + 1) / (layers_total + 1);
1480 
1481 	/* Fail if hopeless */
1482 	if (mem_req > mem_lim) return (mem_req - mem_lim);
1483 
1484 	/* Layer mem limit exceeded - drop oldest */
1485 	mem_req += mem_undo_size(&mem_image.undo_);
1486 	while (mem_req > mem_lim)
1487 	{
1488 		if (!mem_undo_done) return (mem_req - mem_lim);
1489 		mem_req -= lose_oldest(&mem_image.undo_);
1490 	}
1491 	/* All done if no common area */
1492 	if (!csz) return (0);
1493 
1494 	mem_req += mem_undo_lsize();
1495 	if (mem_req <= mem_max) return (0); // No need to trim other layers yet
1496 	mem_lim -= mem_max * (mem_undo_common * 0.01); // Reserved space per layer
1497 
1498 	/* Build heap of undo stacks */
1499 	for (i = h = 0; i <= layers_total; i++)
1500 	{
1501 		// Skip current layer
1502 		if (i == layer_selected) continue;
1503 		wp = &layer_table[i].image->image_.undo_;
1504 		// Skip layers without extra frames
1505 		if (!(wp->done + wp->redo)) continue;
1506 		// Skip layers under the memory limit
1507 		if (wp->size <= mem_lim) continue;
1508 		// Put undo stack onto heap
1509 		for (l = ++h; l > 1; l = l2)
1510 		{
1511 			l2 = l >> 1;
1512 			if ((hp = heap[l2])->size >= wp->size) break;
1513 			heap[l] = hp;
1514 		}
1515 		heap[l] = wp;
1516 	}
1517 
1518 	/* Drop frames of greediest layers */
1519 	while (h > 0)
1520 	{
1521 		size_t mem_nx = h > 1 ? heap[2]->size : 0;
1522 		if ((h > 2) && (heap[3]->size > mem_nx)) mem_nx = heap[3]->size;
1523 		/* Drop frames */
1524 		wp = heap[1];
1525 		while (TRUE)
1526 		{
1527 			size_t res = lose_oldest(wp);
1528 			wp->size -= res; // Maintain undo stack size
1529 			mem_req -= res;
1530 			if (mem_req <= mem_max) return (0);
1531 			if (!(wp->done + wp->redo) || (wp->size <= mem_lim))
1532 				wp = heap[h--];
1533 			else if (wp->size >= mem_nx) continue;
1534 			break;
1535 		}
1536 		/* Reheap layer */
1537 		mem_nx = wp->size;
1538 		for (l = 1; (l2 = l + l) <= h; l = l2)
1539 		{
1540 			if ((l2 < h) && (heap[l2]->size < heap[l2 + 1]->size)) l2++;
1541 			if (mem_nx >= (hp = heap[l2])->size) break;
1542 			heap[l] = hp;
1543 		}
1544 		heap[l] = wp;
1545 	}
1546 
1547 	return (0);
1548 }
1549 
1550 /* Try to allocate a memory block, releasing undo frames if needed */
mem_try_malloc(size_t size)1551 void *mem_try_malloc(size_t size)
1552 {
1553 	void *ptr;
1554 
1555 	while (!((ptr = malloc(size))))
1556 	{
1557 // !!! Hardcoded to work with mem_image for now
1558 		if (!mem_undo_done) return (NULL);
1559 		lose_oldest(&mem_image.undo_);
1560 	}
1561 	return (ptr);
1562 }
1563 
undo_next_core(int mode,int new_width,int new_height,int new_bpp,int cmask)1564 int undo_next_core(int mode, int new_width, int new_height, int new_bpp, int cmask)
1565 {
1566 	png_color *newpal;
1567 	undo_item *undo;
1568 	unsigned char *img;
1569 	void *tempfiles = mem_tempfiles;
1570 	chanlist holder, frame;
1571 	size_t mem_req, mem_lim, wh;
1572 	int i, j, k, need_frame;
1573 
1574 
1575 	if (pen_down && (mode & UC_PENDOWN)) return (0);
1576 	pen_down = mode & UC_PENDOWN ? 1 : 0;
1577 
1578 	/* Fill undo frame */
1579 	update_undo(&mem_image);
1580 
1581 	/* Postpone change notify if nothing will be done without new frame */
1582 	need_frame = mode & (UC_CREATE | UC_NOCOPY | UC_GETMEM);
1583 	if (!need_frame) notify_changed();
1584 
1585 	/* Release redo data */
1586 	if (mem_undo_redo)
1587 	{
1588 		k = mem_undo_pointer;
1589 		for (i = 0; i < mem_undo_redo; i++)
1590 		{
1591 			k = (k + 1) % mem_undo_max;
1592 			undo_free_x(mem_undo_im_ + k);
1593 		}
1594 		mem_undo_redo = 0;
1595 	}
1596 
1597 	/* Let cumulative updates stack */
1598 	if (mode & UC_ACCUM)
1599 	{
1600 		int i = (mem_undo_pointer ? mem_undo_pointer : mem_undo_max) - 1;
1601 		if (mem_undo_done && (mem_undo_im_[i]->flags & UF_ACCUM))
1602 			return (0);
1603 		mem_undo_im_[mem_undo_pointer]->flags |= UF_ACCUM;
1604 	}
1605 
1606 	/* Compress last undo frame */
1607 	mem_undo_prepare();
1608 
1609 	/* Calculate memory requirements */
1610 	mem_req = SIZEOF_PALETTE + 32;
1611 	wh = (size_t)new_width * new_height;
1612 	if (!(mode & UC_DELETE))
1613 	{
1614 		for (i = j = 0; i < NUM_CHANNELS; i++)
1615 		{
1616 			if ((cmask & (1 << i)) && (mem_img[i] ||
1617 				(mode & (UC_CREATE | UC_RESET)))) j++;
1618 		}
1619 		if (cmask & CMASK_IMAGE) j += new_bpp - 1;
1620 		mem_req += (wh + 32) * j;
1621 // !!! Must be after update_undo() to get used memory right
1622 		if ((mem_undo_fail = mem_undo_space(mem_req))) return (2);
1623 	}
1624 	if (mode & UC_GETMEM) return (0); // Enough memory was freed
1625 
1626 	/* Ensure a new frame */
1627 	undo = newchunk(&undo_items);
1628 	if (!undo) return (1);
1629 	freechunk(&undo_items, undo); // It'll be waiting in the freelist
1630 
1631 	/* Prepare outgoing frame */
1632 	undo = mem_undo_im_[mem_undo_pointer];
1633 	memcpy(frame, undo->img, sizeof(chanlist));
1634 	if (!(mode & UC_RESET)) for (i = 0; i < NUM_CHANNELS; i++)
1635 		if (frame[i] && !(cmask & (1 << i))) frame[i] = MEM_NONE;
1636 
1637 	/* Allocate new palette */
1638 	newpal = mem_try_malloc(SIZEOF_PALETTE);
1639 	if (!newpal) return (1);
1640 
1641 	/* Duplicate affected channels */
1642 	for (i = 0; i < NUM_CHANNELS; i++)
1643 	{
1644 		holder[i] = img = mem_img[i];
1645 		if (!(cmask & (1 << i)))
1646 		{
1647 			if (mode & UC_RESET) holder[i] = NULL;
1648 			continue;
1649 		}
1650 		if (mode & UC_DELETE)
1651 		{
1652 			holder[i] = NULL;
1653 			continue;
1654 		}
1655 		if (!img && !(mode & (UC_CREATE | UC_RESET))) continue;
1656 		mem_lim = i == CHN_IMAGE ? wh * new_bpp : wh;
1657 		img = mem_try_malloc(mem_lim);
1658 		if (!img) /* Release memory and fail */
1659 		{
1660 			free(newpal);
1661 			for (j = 0; j < i; j++)
1662 				if (holder[j] != mem_img[j]) free(holder[j]);
1663 			return (1);
1664 		}
1665 		holder[i] = img;
1666 		/* Copy */
1667 		if (!frame[i] || (mode & UC_NOCOPY)) continue;
1668 		memcpy(img, frame[i], mem_lim);
1669 	}
1670 
1671 	/* Next undo step */
1672 	mem_undo_pointer = (mem_undo_pointer + 1) % mem_undo_max;
1673 	if (mem_undo_done >= mem_undo_max - 1)
1674 		undo_free_x(mem_undo_im_ + mem_undo_pointer);
1675 	else mem_undo_done++;
1676 	mem_undo_im_[mem_undo_pointer] = newchunk(&undo_items); // Cannot fail
1677 
1678 	/* Commit */
1679 	if (tempfiles) undo_add_data(undo, UD_TEMPFILES, tempfiles);
1680 	memcpy(undo->img, frame, sizeof(chanlist));
1681 	mem_undo_im_[mem_undo_pointer]->pal_ = newpal;
1682 	memcpy(mem_img, holder, sizeof(chanlist));
1683 	mem_width = new_width;
1684 	mem_height = new_height;
1685 	mem_img_bpp = new_bpp;
1686 
1687 	/* Do postponed change notify, now that new frame is created */
1688 	if (need_frame) notify_changed();
1689 
1690 	update_undo(&mem_image);
1691 	return (0);
1692 }
1693 
1694 // Call this after a draw event but before any changes to image
mem_undo_next(int mode)1695 void mem_undo_next(int mode)
1696 {
1697 	int cmask = CMASK_ALL, wmode = 0;
1698 
1699 	switch (mode)
1700 	{
1701 	case UNDO_TRANS: /* Transparent colour change (cumulative) */
1702 		wmode = UC_ACCUM;
1703 		/* Fallthrough */
1704 	case UNDO_PAL: /* Palette changes */
1705 		cmask = CMASK_NONE;
1706 		break;
1707 	case UNDO_XPAL: /* Palette and indexed image changes */
1708 		cmask = mem_img_bpp == 1 ? CMASK_IMAGE : CMASK_NONE;
1709 		break;
1710 	case UNDO_COL: /* Palette and/or RGB image changes */
1711 		cmask = mem_img_bpp == 3 ? CMASK_IMAGE : CMASK_NONE;
1712 		break;
1713 	case UNDO_TOOL: /* Continuous drawing */
1714 		wmode = UC_PENDOWN;
1715 	case UNDO_DRAW: /* Changes to current channel / RGBA */
1716 		cmask = (mem_channel == CHN_IMAGE) && RGBA_mode ?
1717 			CMASK_RGBA : CMASK_CURR;
1718 		break;
1719 	case UNDO_INV: /* "Invert" operation */
1720 		if ((mem_channel == CHN_IMAGE) && (mem_img_bpp == 1))
1721 			cmask = CMASK_NONE;
1722 		else cmask = CMASK_CURR;
1723 		break;
1724 	case UNDO_XFORM: /* Changes to all channels */
1725 		cmask = CMASK_ALL;
1726 		break;
1727 	case UNDO_FILT: /* Changes to current channel */
1728 		cmask = CMASK_CURR;
1729 		break;
1730 	case UNDO_PASTE: /* Paste to current channel / RGBA */
1731 		wmode = UC_PENDOWN;	/* !!! Workaround for move-with-RMB-pressed */
1732 		cmask = (mem_channel == CHN_IMAGE) && !channel_dis[CHN_ALPHA] &&
1733 			(mem_clip_alpha || RGBA_mode) ? CMASK_RGBA : CMASK_CURR;
1734 		break;
1735 	}
1736 	undo_next_core(wmode, mem_width, mem_height, mem_img_bpp, cmask);
1737 }
1738 
1739 /* Swap image & undo tiles; in process, normal order translates to reverse and
1740  * vice versa - in order to do it in same memory with minimum extra copies */
mem_undo_tile_swap(undo_item * undo,int redo)1741 static void mem_undo_tile_swap(undo_item *undo, int redo)
1742 {
1743 	unsigned char buf[MAX_WIDTH * 3], *tmap, *src, *dest;
1744 	int spans[(MAX_WIDTH + TILE_SIZE - 1) / TILE_SIZE + 3];
1745 	int i, l, h, cc, nw, bpp, w;
1746 
1747 	nw = ((mem_width + TILE_SIZE - 1) / TILE_SIZE + 7) >> 3;
1748 	for (cc = 0; cc < NUM_CHANNELS; cc++)
1749 	{
1750 		if (!undo->img[cc] || (undo->img[cc] == MEM_NONE))
1751 			continue;
1752 		tmap = undo->tileptr;
1753 		bpp = BPP(cc);
1754 		w = mem_width * bpp;
1755 		src = undo->img[cc];
1756 		for (i = 0; i < mem_height; i += TILE_SIZE , tmap += nw)
1757 		{
1758 			int j, j1, dj;
1759 
1760 			if (!(l = mem_undo_spans(spans, tmap, mem_width, bpp)))
1761 				continue;
1762 			dest = mem_img[cc] + w * i;
1763 			h = mem_height - i;
1764 			if (h > TILE_SIZE) h = TILE_SIZE;
1765 
1766 			/* First row stored after last in redo frames */
1767 			if (!redo) j = 0 , j1 = h , dj = 1;
1768 			else
1769 			{
1770 				j = h - 1; j1 = dj = -1;
1771 				memcpy(buf, src + j * l, l);
1772 			}
1773 			/* Process undo normally, and redo backwards */
1774 			for (; j != j1; j += dj)
1775 			{
1776 				unsigned char *ts, *td, *tm;
1777 				int *span = spans;
1778 
1779 				td = dest + j * w;
1780 				tm = ts = src + j * l;
1781 				*(redo ? &ts : &tm) = j ? tm - l : buf;
1782 				while (TRUE)
1783 				{
1784 					td += *span++;
1785 					if (!*span) break;
1786 					memcpy(tm, td, *span);
1787 					memcpy(td, ts, *span);
1788 					tm += *span;
1789 					ts += *span; td += *span++;
1790 				}
1791 			}
1792 			src += h * l;
1793 			if (!redo) memcpy(src - l, buf, l);
1794 		}
1795 	}
1796 }
1797 
mem_undo_swap(undo_item * prev,int redo)1798 static void mem_undo_swap(undo_item *prev, int redo)
1799 {
1800 	undo_item tmp = *prev;
1801 	png_color pal[256];
1802 	int i;
1803 
1804 	if (prev->flags & UF_TILED)
1805 	{
1806 		mem_undo_tile_swap(prev, redo);
1807 		prev->flags &= ~UF_ORIG;
1808 	}
1809 	else
1810 	{
1811 		for (i = 0; i < NUM_CHANNELS; i++)
1812 		{
1813 			if (prev->img[i] != MEM_NONE)
1814 			{
1815 				prev->img[i] = mem_img[i];
1816 				mem_img[i] = tmp.img[i];
1817 			}
1818 		}
1819 		/* !!! If more flags need preserving, add them to mask */
1820 		prev->flags = (prev->flags & UF_ACCUM) | UF_FLAT;
1821 	}
1822 
1823 	if (prev->pal_)
1824 	{
1825 		mem_pal_copy(pal, mem_pal);
1826 		mem_pal_copy(mem_pal, prev->pal_);
1827 		mem_pal_copy(prev->pal_, pal);
1828 	}
1829 
1830 	undo_swap_data(prev);
1831 
1832 	prev->width = mem_width;
1833 	prev->height = mem_height;
1834 	prev->bpp = mem_img_bpp;
1835 	prev->cols = mem_cols;
1836 	prev->trans = mem_xpm_trans;
1837 	if (!mem_changed) prev->flags |= UF_ORIG;
1838 
1839 	mem_width = tmp.width;
1840 	mem_height = tmp.height;
1841 	mem_img_bpp = tmp.bpp;
1842 	mem_cols = tmp.cols;
1843 	mem_xpm_trans = tmp.trans;
1844 	mem_changed = !(tmp.flags & UF_ORIG);
1845 }
1846 
mem_do_undo(int redo)1847 void mem_do_undo(int redo)
1848 {
1849 	undo_item *curr, *prev;
1850 	int i, j;
1851 
1852 	/* Compress last undo frame */
1853 	mem_undo_prepare();
1854 
1855 	if ((redo ? mem_undo_redo : mem_undo_done) > 0 )
1856 	{
1857 		j = redo ? 1 : -1;
1858 		i = (mem_undo_pointer + j + mem_undo_max) % mem_undo_max;
1859 
1860 		/* Swap data */
1861 		curr = mem_undo_im_[mem_undo_pointer];
1862 		prev = mem_undo_im_[i];
1863 		mem_undo_swap(prev, redo);
1864 
1865 		/* Swap frames */
1866 		mem_undo_im_[mem_undo_pointer] = prev;
1867 		mem_undo_im_[i] = curr;
1868 		mem_undo_pointer = i;
1869 		mem_undo_done += j;
1870 		mem_undo_redo -= j;
1871 
1872 		/* Update current */
1873 		update_undo(&mem_image);
1874 	}
1875 	pen_down = 0;
1876 }
1877 
1878 /* Return the number of bytes used in image + undo */
mem_used()1879 size_t mem_used()
1880 {
1881 	update_undo(&mem_image);
1882 	return mem_undo_size(&mem_image.undo_);
1883 }
1884 
1885 /* Return the number of bytes used in image + undo in all layers */
mem_used_layers()1886 size_t mem_used_layers()
1887 {
1888 	return (mem_used() + mem_undo_lsize());
1889 }
1890 
1891 /* Fast approximate atan2() function, returning result in degrees. This code is
1892  * approximately 2x faster than using libm on P4/Linux, and 6x on Windows.
1893  * Absolute error is below 0.0003 degrees, which means 1/10 of a pixel in worst
1894  * possible case. - WJ */
1895 
1896 #define ATANNUM 128
1897 static float ATAN[2 * ATANNUM + 2];
1898 
atan360(int x,int y)1899 double atan360(int x, int y)
1900 {
1901 	double d;
1902 	int xa, ya, n;
1903 
1904 	if (!(x | y)) return (0.0);
1905 	xa = abs(x); ya = abs(y);
1906 	d = ya < xa ? (double)ya / (double)xa : 2.0 - (double)xa / (double)ya;
1907 	d *= ATANNUM;
1908 	n = d;
1909 	d = ATAN[n] + (ATAN[n + 1] - ATAN[n]) * (d - n);
1910 
1911 	if (x < 0) d = 180.0 - d;
1912 	return (y >= 0 ? d : 360.0 - d);
1913 }
1914 
make_ATAN()1915 static void make_ATAN()
1916 {
1917 	int i;
1918 
1919 	for (i = 0; i <= ATANNUM; i++)
1920 		ATAN[2 * ATANNUM - i] = 90.0 -
1921 			(ATAN[i] = atan(i * (1.0 / ATANNUM)) * (180.0 / M_PI));
1922 	ATAN[2 * ATANNUM + 1] = 90.0;
1923 }
1924 
load_def_palette(char * name)1925 int load_def_palette(char *name)
1926 {
1927 	int i;
1928 
1929 	if (!name[0]) return (FALSE); // Useless
1930 	i = detect_palette_format(name);
1931 	if (i > FT_NONE) return (load_image(name, FS_PALETTE_DEF, i) == 1);
1932 	return (FALSE);
1933 }
1934 
load_def_patterns(char * name)1935 int load_def_patterns(char *name)
1936 {
1937 	int i;
1938 
1939 	if (!name[0]) return (FALSE); // Useless
1940 	i = detect_image_format(name);
1941 	if ((i > FT_NONE) && (file_formats[i].flags & FF_IDX))
1942 		return (load_image(name, FS_PATTERN_LOAD, i) == 1);
1943 	return (FALSE);
1944 }
1945 
mem_init()1946 void mem_init()					// Initialise memory
1947 {
1948 	static const unsigned char lookup[8] =
1949 		{ 0, 36, 73, 109, 146, 182, 219, 255 };
1950 	unsigned char *dest;
1951 	char txt[64];
1952 	int i, j, ix, iy, bs, bf, bt;
1953 
1954 
1955 	make_ATAN();
1956 
1957 	for (i = 0; i < 256; i++)	// Load up normal palette defaults
1958 	{
1959 		mem_pal_def[i].red = lookup[mem_pal_def[i].red];
1960 		mem_pal_def[i].green = lookup[mem_pal_def[i].green];
1961 		mem_pal_def[i].blue = lookup[mem_pal_def[i].blue];
1962 	}
1963 
1964 	load_def_palette(inifile_get(DEFAULT_PAL_INI, ""));
1965 	load_def_patterns(inifile_get(DEFAULT_PAT_INI, ""));
1966 
1967 	/* Init editor settings */
1968 	mem_channel = CHN_IMAGE;
1969 	mem_icx = mem_icy = 0.5;
1970 	mem_xbm_hot_x = mem_xbm_hot_y = -1;
1971 	mem_col_A = 1;
1972 	mem_col_B = 0;
1973 
1974 	/* Set up default undo stack */
1975 	mem_undo_depth = mem_undo_depth <= MIN_UNDO ? MIN_UNDO :
1976 		mem_undo_depth >= MAX_UNDO ? MAX_UNDO : mem_undo_depth | 1;
1977 	if (!init_undo(&mem_image.undo_, mem_undo_depth))
1978 	{
1979 		memory_errors(1);
1980 		exit(0);
1981 	}
1982 
1983 	// Create brush presets
1984 
1985 	mem_cols = mem_pal_def_i;
1986 	mem_pal_copy( mem_pal, mem_pal_def );
1987 	if (mem_new(PATCH_WIDTH, PATCH_HEIGHT, 3, CMASK_IMAGE))	// Not enough memory!
1988 	{
1989 		memory_errors(1);
1990 		exit(0);
1991 	}
1992 	mem_mask_setv(NULL, -1, FALSE);
1993 
1994 	mem_col_A24.red = 255;
1995 	mem_col_A24.green = 255;
1996 	mem_col_A24.blue = 255;
1997 	mem_col_B24.red = 0;
1998 	mem_col_B24.green = 0;
1999 	mem_col_B24.blue = 0;
2000 
2001 	j = mem_width * mem_height;
2002 	dest = mem_img[CHN_IMAGE];
2003 	for (i = 0; i < j; i++)
2004 	{
2005 		*dest++ = mem_col_B24.red;
2006 		*dest++ = mem_col_B24.green;
2007 		*dest++ = mem_col_B24.blue;
2008 	}
2009 
2010 	mem_pat_update();
2011 
2012 	for (i = 0; i < NUM_BRUSHES; i++)		// Draw each brush
2013 	{
2014 		ix = BRUSH_CELL / 2 + BRUSH_CELL * (i % BRUSH_GRID_W);
2015 		iy = BRUSH_CELL / 2 + BRUSH_CELL * (i / BRUSH_GRID_W);
2016 		bt = mem_brush_list[i][0];
2017 		bs = mem_brush_list[i][1];
2018 		bf = mem_brush_list[i][2];
2019 
2020 		switch (bt)
2021 		{
2022 		case TOOL_SQUARE:
2023 			f_rectangle(ix - bs / 2, iy - bs / 2, bs, bs); break;
2024 		case TOOL_CIRCLE:
2025 			f_circle(ix, iy, bs); break;
2026 		case TOOL_VERTICAL:
2027 			f_rectangle(ix, iy - bs / 2, 1, bs); break;
2028 		case TOOL_HORIZONTAL:
2029 			f_rectangle(ix - bs / 2, iy, bs, 1); break;
2030 		case TOOL_SLASH:
2031 			for (j = 0; j < bs; j++)
2032 				put_pixel(ix - bs / 2 + j, iy + bs / 2 - j);
2033 			break;
2034 		case TOOL_BACKSLASH:
2035 			for (j = 0; j < bs; j++)
2036 				put_pixel(ix + bs / 2 - j, iy + bs / 2 - j);
2037 			break;
2038 		case TOOL_SPRAY:
2039 			for (j = 0; j < bf * 3; j++)
2040 				put_pixel(ix - bs / 2 + rand() % bs,
2041 					iy - bs / 2 + rand() % bs);
2042 			break;
2043 		}
2044 	}
2045 
2046 	j = PATCH_WIDTH * PATCH_HEIGHT * 3;
2047 	memcpy(mem_brushes, mem_img[CHN_IMAGE], j);	// Store image for later use
2048 	memset(mem_img[CHN_IMAGE], 0, j);	// Clear so user doesn't see it upon load fail
2049 
2050 	mem_set_brush(36);		// Initial brush
2051 
2052 	for ( i=0; i<NUM_CHANNELS; i++ )
2053 	{
2054 		for ( j=0; j<4; j++ )
2055 		{
2056 			sprintf(txt, "overlay%i%i", i, j);
2057 			if ( j<3 )
2058 			{
2059 				channel_rgb[i][j] = inifile_get_gint32(txt, channel_rgb[i][j] );
2060 			}
2061 			else	channel_opacity[i] = inifile_get_gint32(txt, channel_opacity[i] );
2062 		}
2063 	}
2064 
2065 	/* Preset gradients */
2066 	for (i = 0; i < NUM_CHANNELS; i++)
2067 	{
2068 		grad_info *grad = gradient + i;
2069 
2070 		grad->gmode = GRAD_MODE_LINEAR;
2071 		grad->rmode = GRAD_BOUND_STOP;
2072 		grad_update(grad);
2073 	}
2074 	for (i = 0; i <= NUM_CHANNELS; i++)
2075 	{
2076 		graddata[i].gtype = GRAD_TYPE_RGB;
2077 		graddata[i].otype = GRAD_TYPE_CONST;
2078 	}
2079 	grad_def_update(-1);
2080 	for (i = 0; i <= NUM_CHANNELS; i++)
2081 		gmap_setup(graddata + i, gradbytes, i);
2082 }
2083 
mem_swap_cols(int redraw)2084 void mem_swap_cols(int redraw)
2085 {
2086 	int oc, flags;
2087 	png_color o24;
2088 
2089 	if (pattern_B)
2090 	{
2091 		oc = mem_tool_pat;
2092 		mem_tool_pat = mem_tool_pat_B;
2093 		mem_tool_pat_B = oc;
2094 	}
2095 	if (mem_channel != CHN_IMAGE)
2096 	{
2097 		oc = channel_col_A[mem_channel];
2098 		channel_col_A[mem_channel] = channel_col_B[mem_channel];
2099 		channel_col_B[mem_channel] = oc;
2100 		flags = redraw ? UPD_GRAD : CF_GRAD;
2101 	}
2102 	else
2103 	{
2104 		oc = mem_col_A;
2105 		mem_col_A = mem_col_B;
2106 		mem_col_B = oc;
2107 
2108 		o24 = mem_col_A24;
2109 		mem_col_A24 = mem_col_B24;
2110 		mem_col_B24 = o24;
2111 
2112 		if (RGBA_mode)
2113 		{
2114 			oc = channel_col_A[CHN_ALPHA];
2115 			channel_col_A[CHN_ALPHA] = channel_col_B[CHN_ALPHA];
2116 			channel_col_B[CHN_ALPHA] = oc;
2117 		}
2118 		flags = redraw ? UPD_AB : CF_AB | CF_GRAD;
2119 	}
2120 	update_stuff(flags);
2121 }
2122 
mem_set_trans(int trans)2123 void mem_set_trans(int trans)
2124 {
2125 	if (trans == mem_xpm_trans) return;
2126 	mem_undo_next(UNDO_TRANS);
2127 	mem_xpm_trans = trans;
2128 	update_stuff(UPD_TRANS);
2129 }
2130 
repaint_swatch(int index)2131 static void repaint_swatch(int index)		// Update a palette colour swatch
2132 {
2133 	static const int ll[3] = { PALETTE_SWATCH_X, PALETTE_SWATCH_W,
2134 		PALETTE_WIDTH - PALETTE_CROSS_X };
2135 	unsigned char *tr, *tmp;
2136 	int i, j, k, n, d, c = PNG_2_INT(mem_pal[index]);
2137 	int cc[4] = { mem_pal_ab_c, c, mem_pal_ab_c, mem_pal_id_c };
2138 
2139 	/* Unhighlight background if not A or B */
2140 	if ((index ^ mem_col_A) | (c ^ PNG_2_INT(mem_col_A24))) cc[0] = 0;
2141 	if ((index ^ mem_col_B) | (c ^ PNG_2_INT(mem_col_B24))) cc[2] = 0;
2142 
2143 	tr = mem_pals + index * PALETTE_SWATCH_H * PALETTE_W3 +
2144 		PALETTE_SWATCH_Y * PALETTE_W3;
2145 
2146 	/* Draw color & background */
2147 	tmp = tr;
2148 	for (n = 0; n < 3; n++)
2149 	{
2150 		c = cc[n]; j = ll[n];
2151 		for (i = 0; i < j; i++ , tmp += 3)
2152 		{
2153 			tmp[0] = INT_2_R(c);
2154 			tmp[1] = INT_2_G(c);
2155 			tmp[2] = INT_2_B(c);
2156 		}
2157 	}
2158 	for (i = 1; i < PALETTE_SWATCH_H; i++)
2159 		memcpy(tr + i * PALETTE_W3, tr, PALETTE_W3);
2160 
2161 	/* Draw index */
2162 	cc[1] = mem_pal_id_c;
2163 	tmp = tr + PALETTE_INDEX_DY * PALETTE_W3 + PALETTE_INDEX_X * 3;
2164 	for (d = 100; d; d /= 10 , tmp += (PALETTE_DIGIT_W + 1) * 3)
2165 	{
2166 		if ((index < d) && (d > 1)) continue;
2167 		n = ((index / d) % 10) * PALETTE_DIGIT_H;
2168 		for (i = 0; i < PALETTE_DIGIT_H; i++)
2169 		{
2170 			k = xbm_n7x7_bits[n + i];
2171 			for (j = 0; j < PALETTE_DIGIT_W; j++ , k >>= 1 , tmp += 3)
2172 			{
2173 				c = cc[k & 1];
2174 				tmp[0] = INT_2_R(c);
2175 				tmp[1] = INT_2_G(c);
2176 				tmp[2] = INT_2_B(c);
2177 			}
2178 			tmp += PALETTE_W3 - PALETTE_DIGIT_W * 3;
2179 		}
2180 		tmp -= PALETTE_DIGIT_H * PALETTE_W3;
2181 	}
2182 
2183 	/* Draw protection mask cross */
2184 	if (!mem_prot_mask[index]) return;
2185 	tmp = tr + PALETTE_CROSS_DY * PALETTE_W3 +
2186 		(PALETTE_CROSS_X + PALETTE_CROSS_DX) * 3;
2187 	for (i = 0; i < PALETTE_CROSS_H; i++)
2188 	{
2189 		k = mem_cross[i];
2190 		for (j = 0; j < PALETTE_CROSS_W; j++ , k >>= 1 , tmp += 3)
2191 		{
2192 			c = cc[(k & 1) + 2];
2193 			tmp[0] = INT_2_R(c);
2194 			tmp[1] = INT_2_G(c);
2195 			tmp[2] = INT_2_B(c);
2196 		}
2197 		tmp += PALETTE_W3 - PALETTE_CROSS_W * 3;
2198 	}
2199 }
2200 
mem_pal_init()2201 void mem_pal_init()			// Redraw whole palette
2202 {
2203 	int i;
2204 
2205 	memset(mem_pals, 0, PALETTE_WIDTH * PALETTE_HEIGHT * 3);
2206 	for (i = 0; i < mem_cols; i++) repaint_swatch(i);
2207 }
2208 
mem_pal_load_def()2209 void mem_pal_load_def()					// Load default palette
2210 {
2211 	mem_pal_copy( mem_pal, mem_pal_def );
2212 	mem_cols = mem_pal_def_i;
2213 }
2214 
2215 #define RGB_PROT_MAX 256
2216 /* The 16:8 split is optimal for up to 768 colors, then 17:7 etc */
2217 typedef struct {
2218 	short nb[0x10000 / 32];
2219 	uint32_t rg[0x10000 / 32], b[RGB_PROT_MAX * 0x100 / 32];
2220 } rgb_prot;
2221 
2222 static rgb_prot mem_prot_map;
2223 
mem_mask_init()2224 void mem_mask_init()		// Initialise RGB protection bitmaps
2225 {
2226 	int i, j, n, v, rgb[RGB_PROT_MAX];
2227 
2228 	memset(&mem_prot_map, 0, sizeof(mem_prot_map));
2229 	for (i = n = 0; i < mem_cols; i++)
2230 	{
2231 		if (!mem_prot_mask[i]) continue;
2232 		rgb[n++] = v = PNG_2_INT(mem_pal[i]);
2233 		v >>= 8;
2234 		mem_prot_map.rg[v >> 5] |= 1U << (v & 0x1F);
2235 	}
2236 	mem_prot = n;
2237 	if (!n) return;
2238 	for (i = v = 0; i < 0x10000 / 32 - 1; i++)
2239 		mem_prot_map.nb[i + 1] = v += bitcount(mem_prot_map.rg[i]);
2240 	for (i = 0; i < n; i++)
2241 	{
2242 		unsigned u;
2243 		v = rgb[i] >> 8;
2244 		u = (1U << (v & 0x1F)) - 1;
2245 		v >>= 5;
2246 		j = mem_prot_map.nb[v] + bitcount(u & mem_prot_map.rg[v]);
2247 		v = rgb[i] & 0xFF;
2248 		mem_prot_map.b[j * (0x100 >> 5) + (v >> 5)] |= 1U << (v & 0x1F);
2249 	}
2250 }
2251 
mem_mask_test(int rgb)2252 static inline int mem_mask_test(int rgb)
2253 {
2254 	int v = rgb >> 8;
2255 	unsigned u = 1U << (v & 0x1F), w = mem_prot_map.rg[v >> 5];
2256 
2257 	if (u &= w)
2258 	{
2259 		v = mem_prot_map.nb[v >> 5] + bitcount((u - 1) & w);
2260 		rgb &= 0xFF;
2261 		u = mem_prot_map.b[v * (0x100 >> 5) + (rgb >> 5)] >> (rgb & 0x1F);
2262 	}
2263 	return (u & 1);
2264 }
2265 
mem_mask_setv(int * what,int n,int state)2266 void mem_mask_setv(int *what, int n, int state)
2267 {
2268 	state = state ? 255 : 0;
2269 	if (what)
2270 	{
2271 		while (n-- > 0)
2272 		{
2273 			int i = *what++;
2274 			if ((i >= 0) && (i < mem_cols)) mem_prot_mask[i] = state;
2275 		}
2276 	}
2277 	else if (n < 0) memset(mem_prot_mask, state, 256);
2278 	else if (n < mem_cols) mem_prot_mask[n] = state;
2279 	mem_mask_init();
2280 }
2281 
mem_get_histogram(int channel)2282 void mem_get_histogram(int channel)	// Calculate how many of each colour index is on the canvas
2283 {
2284 	int i, j = mem_width * mem_height;
2285 	unsigned char *img = mem_img[channel];
2286 
2287 	memset(mem_histogram, 0, sizeof(mem_histogram));
2288 
2289 	for (i = 0; i < j; i++) mem_histogram[*img++]++;
2290 }
2291 
2292 typedef struct {
2293 	int last_gamma, last_br, last_co, last_ps;
2294 	unsigned char gamma_table[256], bc_table[256], ps_table[256];
2295 } transform_cache;
2296 
do_transform(int start,int step,int cnt,unsigned char * mask,unsigned char * imgr,unsigned char * img0,int m0)2297 void do_transform(int start, int step, int cnt, unsigned char *mask,
2298 	unsigned char *imgr, unsigned char *img0, int m0)
2299 {
2300 	static const int ixx[7] = {0, 1, 2, 0, 1, 2, 0};
2301 	static unsigned char fmask = 255;
2302 	static transform_cache tc[2];
2303 	int do_gamma, do_bc, /*do_sa,*/ do_ps;
2304 	unsigned char rgb[3];
2305 	int br, co, sa;
2306 	int dH, sH, tH, ix0, ix1, ix2, c0, c1, c2, dc = 0, ops = 0;
2307 	int j, mstep, r, g, b;
2308 	transform_cache *tp = tc;
2309 	transform_state *mp = mem_bcsp;
2310 
2311 	if (m0 > 255) tp++ , mp++; // Brush mode
2312 
2313 	if (!mp->allow[0]) ops |= 0xFF;
2314 	if (!mp->allow[1]) ops |= 0xFF00;
2315 	if (!mp->allow[2]) ops |= 0xFF0000;
2316 
2317 	br = mp->bcsp[0] * 256;
2318 	co = mp->bcsp[1];
2319 	if (co > 0) co *= 3;
2320 	co += 100;
2321 	co = (256 * co) / 100;
2322 	sa = (256 * mp->bcsp[2]) / 100;
2323 	dH = sH = mp->bcsp[5];
2324 
2325 	// Map bitwise to truncated
2326 	do_ps = mp->pmode ? mp->bcsp[3] : 1 << mp->bcsp[3];
2327 	// Disable if 1:1, else separate truncated from rounded
2328 	if (do_ps &= 255) do_ps += (mp->pmode > 1) << 8;
2329 
2330 	do_gamma = mp->bcsp[4] - 100;
2331 	do_bc = br | (co - 256);
2332 //	do_sa = sa - 255;
2333 
2334 	/* Prepare posterize table */
2335 	if (do_ps && (do_ps != tp->last_ps))
2336 	{
2337 		int mul = do_ps & 255, div = 256, add = 0, div2 = mul - 1;
2338 		int i, j;
2339 
2340 		tp->last_ps = do_ps;
2341 		if (do_ps > 255) // Rounded
2342 		{
2343 			mul += mul - 2;
2344 			div = 255 * 2;
2345 			add = 255;
2346 		}
2347 		for (i = 0; i < 256; i++)
2348 		{
2349 			j = (i * mul + add) / div;
2350 			tp->ps_table[i] = (j * 255 * 2 + div2) / (div2 + div2);
2351 		}
2352 	}
2353 	/* Prepare gamma table */
2354 	if (do_gamma && (do_gamma != tp->last_gamma))
2355 	{
2356 		double w;
2357 		int i;
2358 
2359 		tp->last_gamma = do_gamma;
2360 		w = 100.0 / (double)(do_gamma + 100);
2361 		for (i = 0; i < 256; i++)
2362 		{
2363 			tp->gamma_table[i] = rint(255.0 * pow((double)i / 255.0, w));
2364 		}
2365 	}
2366 	/* Prepare brightness-contrast table */
2367 	if (do_bc && ((br ^ tp->last_br) | (co ^ tp->last_co)))
2368 	{
2369 		int i, j;
2370 
2371 		tp->last_br = br; tp->last_co = co;
2372 		for (i = 0; i < 256; i++)
2373 		{
2374 			j = ((i + i - 255) * co + (255 * 256)) / 2 + br;
2375 			tp->bc_table[i] = j < 0 ? 0 : j > (255 * 256) ? 255 : j >> 8;
2376 		}
2377 	}
2378 	if (dH)
2379 	{
2380 		if (dH < 0) dH += 1530;
2381 		dc = (dH / 510) * 2; dH -= dc * 255;
2382 		if ((sH = dH > 255))
2383 		{
2384 			dH = 510 - dH;
2385 			dc = dc < 4 ? dc + 2 : 0;
2386 		}
2387 	}
2388 	ix0 = ixx[dc]; ix1 = ixx[dc + 1]; ix2 = ixx[dc + 2];
2389 
2390 	/* Use fake mask if no real one provided */
2391 	if (!mask) mask = &fmask , mstep = 0;
2392 	else mask += start - step , mstep = step;
2393 
2394 	start *= 3; step *= 3; // Step by triples
2395 	img0 += start - step;
2396 	imgr += start - step;
2397 	while (cnt-- > 0)
2398 	{
2399 		img0 += step; imgr += step; mask += mstep;
2400 		if (*mask == (unsigned char)m0) continue;
2401 		rgb[0] = img0[0];
2402 		rgb[1] = img0[1];
2403 		rgb[2] = img0[2];
2404 		/* If we do gamma transform */
2405 		if (do_gamma)
2406 		{
2407 			rgb[0] = tp->gamma_table[rgb[0]];
2408 			rgb[1] = tp->gamma_table[rgb[1]];
2409 			rgb[2] = tp->gamma_table[rgb[2]];
2410 		}
2411 		/* If we do hue transform & colour has a hue */
2412 		if (dH && ((rgb[0] ^ rgb[1]) | (rgb[0] ^ rgb[2])))
2413 		{
2414 			/* Min. component */
2415 			c2 = dc;
2416 			if (rgb[ix2] < rgb[ix0]) c2++;
2417 			if (rgb[ixx[c2]] >= rgb[ixx[c2 + 1]]) c2++;
2418 			/* Actual indices */
2419 			c2 = ixx[c2];
2420 			c0 = ixx[c2 + 1];
2421 			c1 = ixx[c2 + 2];
2422 
2423 			/* Max. component & edge dir */
2424 			if ((tH = rgb[c0] <= rgb[c1]))
2425 			{
2426 				c0 = ixx[c2 + 2];
2427 				c1 = ixx[c2 + 1];
2428 			}
2429 			/* Do adjustment */
2430 			j = dH * (rgb[c0] - rgb[c2]) + 127; /* Round up (?) */
2431 			j = (j + (j >> 8) + 1) >> 8;
2432 			r = rgb[c0]; g = rgb[c1]; b = rgb[c2];
2433 			if (tH ^ sH) /* Falling edge */
2434 			{
2435 				rgb[c1] = r = g > j + b ? g - j : b;
2436 				rgb[c2] += j + r - g;
2437 			}
2438 			else /* Rising edge */
2439 			{
2440 				rgb[c1] = b = g < r - j ? g + j : r;
2441 				rgb[c0] -= j + g - b;
2442 			}
2443 		}
2444 		r = rgb[ix0];
2445 		g = rgb[ix1];
2446 		b = rgb[ix2];
2447 		/* If we do brightness/contrast transform */
2448 		if (do_bc)
2449 		{
2450 			r = tp->bc_table[r];
2451 			g = tp->bc_table[g];
2452 			b = tp->bc_table[b];
2453 		}
2454 		/* If we do saturation transform */
2455 		if (sa)
2456 		{
2457 			j = (299 * r + 587 * g + 114 * b) / 1000;
2458 			r = r * 256 + (r - j) * sa;
2459 			r = r < 0 ? 0 : r > (255 * 256) ? 255 : r >> 8;
2460 			g = g * 256 + (g - j) * sa;
2461 			g = g < 0 ? 0 : g > (255 * 256) ? 255 : g >> 8;
2462 			b = b * 256 + (b - j) * sa;
2463 			b = b < 0 ? 0 : b > (255 * 256) ? 255 : b >> 8;
2464 		}
2465 		/* If we do posterize transform */
2466 		if (do_ps)
2467 		{
2468 			r = tp->ps_table[r];
2469 			g = tp->ps_table[g];
2470 			b = tp->ps_table[b];
2471 		}
2472 		/* If we do channel masking */
2473 		if (ops)
2474 		{
2475 			r ^= (r ^ img0[0]) & ops;
2476 			g ^= (g ^ img0[1]) & (ops >> 8);
2477 			b ^= (b ^ img0[2]) & (ops >> 16);
2478 		}
2479 		imgr[0] = r;
2480 		imgr[1] = g;
2481 		imgr[2] = b;
2482 	}
2483 }
2484 
2485 static unsigned char pal_dupes[256];
2486 
scan_duplicates()2487 int scan_duplicates()	// Find duplicate palette colours, return number found
2488 {
2489 	int i, j, c, found, pmap[256];
2490 
2491 	for (i = 0; i < mem_cols; i++)
2492 		pmap[i] = PNG_2_INT(mem_pal[i]);
2493 	/* Transparent color is different from any normal one */
2494 	if (mem_xpm_trans >= 0) pmap[mem_xpm_trans] = -1;
2495 
2496 	for (found = 0 , i = mem_cols - 1; i >= 0; i--)
2497 	{
2498 		c = pmap[i];
2499 		for (j = 0; pmap[j] != c; j++);
2500 		pal_dupes[i] = j;
2501 		found += i != j;
2502 	}
2503 
2504 	return (found);
2505 }
2506 
remove_duplicates()2507 void remove_duplicates()	// Remove duplicate palette colours - call AFTER scan_duplicates
2508 {
2509 	do_xlate(pal_dupes, mem_img[CHN_IMAGE], mem_width * mem_height);
2510 }
2511 
mem_remove_unused_check()2512 int mem_remove_unused_check()
2513 {
2514 	int i, found = 0;
2515 
2516 	mem_get_histogram(CHN_IMAGE);
2517 	for (i = 0; i < mem_cols; i++)
2518 		if (!mem_histogram[i]) found++;
2519 
2520 	if (!found) return 0;	// All palette colours are used on the canvas
2521 	// Leave at least one colour even if canvas is 0x0
2522 	return (mem_cols > found ? found : mem_cols - 1);
2523 }
2524 
mem_remove_unused()2525 int mem_remove_unused()
2526 {
2527 	unsigned char conv[256];
2528 	int i, j, found = mem_remove_unused_check();
2529 
2530 	if (found <= 0) return (0);
2531 
2532 	conv[0] = 0; // Ensure this works even with empty histogram
2533 	for (i = j = 0; i < 256; i++)	// Create conversion table
2534 	{
2535 		if (mem_histogram[i])
2536 		{
2537 			mem_pal[j] = mem_pal[i];
2538 			conv[i] = j++;
2539 		}
2540 	}
2541 
2542 	// Re-adjust transparent colour index if it exists
2543 	mem_xpm_trans = (mem_xpm_trans < 0) || !mem_histogram[mem_xpm_trans] ?
2544 		-1 : conv[mem_xpm_trans];
2545 
2546 	do_xlate(conv, mem_img[CHN_IMAGE], mem_width * mem_height);
2547 
2548 	mem_cols -= found;
2549 
2550 	return found;
2551 }
2552 
2553 // Generate black-to-white palette
mem_bw_pal(png_color * pal,int i1,int i2)2554 void mem_bw_pal(png_color *pal, int i1, int i2)
2555 {
2556 	int i, j, step = i2 > i1 ? 1 : -1, d = abs(i2 - i1);
2557 
2558 	if (!d) return;
2559 	for (i = i1 , j = d , d += d; i != i2 + step; i += step , j += 255 * 2)
2560 	{
2561 		pal[i].red = pal[i].green = pal[i].blue = j / d;
2562 	}
2563 }
2564 
transform_pal(png_color * pal1,png_color * pal2,int p1,int p2)2565 void transform_pal(png_color *pal1, png_color *pal2, int p1, int p2)
2566 {
2567 	int l = p2 - p1 + 1;
2568 	unsigned char tmp[256 * 3];
2569 
2570 	pal2rgb(tmp, pal2 + p1, l, 0);
2571 	do_transform(0, 1, l, NULL, tmp, tmp, 0);
2572 	rgb2pal(pal1 + p1, tmp, l);
2573 }
2574 
set_zoom_centre(int x,int y)2575 void set_zoom_centre( int x, int y )
2576 {
2577 	IF_IN_RANGE( x, y )
2578 	{
2579 		mem_icx = ((float) x ) / mem_width;
2580 		mem_icy = ((float) y ) / mem_height;
2581 		mem_ics = 1;
2582 	}
2583 }
2584 
2585 // Convert image to RGB
do_convert_rgb(int start,int step,int cnt,unsigned char * dest,unsigned char * src,png_color * pal)2586 void do_convert_rgb(int start, int step, int cnt, unsigned char *dest,
2587 	unsigned char *src, png_color *pal)
2588 {
2589 	dest += start * 3;
2590 	src += start;
2591 	while (cnt-- > 0)
2592 	{
2593 		png_color *col = pal + *src;
2594 		dest[0] = col->red;
2595 		dest[1] = col->green;
2596 		dest[2] = col->blue;
2597 		dest += step * 3; src += step;
2598 	}
2599 }
2600 
2601 /* With 16-bit rg[], would be a little bit more compact (24K vs 26K) */
2602 typedef struct {
2603 	uint32_t rg[0x10000 / 32], b[256 * (0x100 / 32)];
2604 	unsigned char rgx[0x10000 / 32], vx[256 * 32];
2605 	int nv, nb;
2606 } rgb_256_map;
2607 
2608 // Convert RGB image to Indexed Palette
mem_convert_indexed(unsigned char * dest,unsigned char * src,int cnt,int cols,png_color * pal)2609 int mem_convert_indexed(unsigned char *dest, unsigned char *src, int cnt,
2610 	int cols, png_color *pal)
2611 {
2612 	rgb_256_map m;
2613 	unsigned char bx[256 * (0x100 / 32)], idx[256];
2614 	int i, j, k, l, n, v, vn, pix;
2615 
2616 	/* Put palette into bitmap */
2617 	memset(&m, 0, sizeof(m));
2618 	for (i = 0; i < cols; i++)
2619 	{
2620 		pix = PNG_2_INT(pal[i]);
2621 		k = pix & 0xFF;
2622 		n = (pix >> 8) & 0x1F;
2623 		v = pix >> (8 + 5);
2624 		/* Insert into tiers */
2625 		if (!m.rg[v]) m.rgx[v] = m.nv++;
2626 		vn = m.rgx[v] * 32 + n;
2627 		if (!((m.rg[v] >> n) & 1))
2628 			m.vx[vn] = m.nb++ , m.rg[v] |= 1U << n;
2629 		m.b[m.vx[vn] * 8 + (k >> 5)] |= 1U << (k & 0x1F);
2630 	}
2631 	/* Calculate bitcounts */
2632 	for (i = j = 0; i < sizeof(bx); i++)
2633 	{
2634 		bx[i] = j;
2635 		j += bitcount(m.b[i]);
2636 	}
2637 	/* Prepare mapping */
2638 	for (i = 0; i < cols; i++)
2639 	{
2640 		pix = PNG_2_INT(pal[i]);
2641 		k = pix & 0xFF;
2642 		n = (pix >> 8) & 0x1F;
2643 		v = pix >> (8 + 5);
2644 		/* Locate in bitmap */
2645 		vn = m.rgx[v] * 32 + n;
2646 		j = m.vx[vn] * 8 + (k >> 5);
2647 		j = bx[j] + bitcount(m.b[j] & ((1U << (k & 0x1F)) - 1));
2648 		/* Remember the palette slot for the location */
2649 		idx[j] = i;
2650 	}
2651 
2652 	for (i = 0; i < cnt; i++)
2653 	{
2654 		pix = MEM_2_INT(src, 0);
2655 		k = pix & 0xFF;
2656 		n = (pix >> 8) & 0x1F;
2657 		v = pix >> (8 + 5);
2658 		/* Test presence on both tiers at once: if the 1st is unset,
2659 		 * the 2nd simply defaults to block #0 */
2660 		vn = m.rgx[v] * 32 + n;
2661 		l = m.vx[vn] * 8 + (k >> 5);
2662 		if (!((m.rg[v] >> n) & 1 & (m.b[l] >> (k & 0x1F))))
2663 			return (1);	// No index found - BAD ERROR!!
2664 		/* Get index */
2665 		l = bx[l] + bitcount(m.b[l] & ((1U << (k & 0x1F)) - 1));
2666 		/* Map to palette */
2667 		*dest++ = idx[l];
2668 		src += 3;
2669 	}
2670 
2671 	return (0);
2672 }
2673 
2674 /* Max-Min quantization algorithm - good for preserving saturated colors,
2675  * and because of that, bad when used without dithering - WJ */
2676 
2677 #define HISTSIZE (64 * 64 * 64)
maxminquan(unsigned char * inbuf,int width,int height,int quant_to,png_color * userpal)2678 int maxminquan(unsigned char *inbuf, int width, int height, int quant_to,
2679 	png_color *userpal)
2680 {
2681 	int i, j, k, ii, r, g, b, dr, dg, db, l = width * height, *hist;
2682 
2683 	/* Allocate histogram */
2684 	hist = calloc(1, HISTSIZE * sizeof(int));
2685 	if (!hist) return (-1);
2686 
2687 	/* Fill histogram */
2688 	for (i = 0; i < l; i++)
2689 	{
2690 		++hist[((inbuf[0] & 0xFC) << 10) + ((inbuf[1] & 0xFC) << 4) +
2691 			(inbuf[2] >> 2)];
2692 		inbuf += 3;
2693 	}
2694 
2695 	/* Find the most frequent color */
2696 	j = k = -1;
2697 	for (i = 0; i < HISTSIZE; i++)
2698 	{
2699 		if (hist[i] <= k) continue;
2700 		j = i; k = hist[i];
2701 	}
2702 
2703 	/* Make it first */
2704 	userpal[0].red = r = j >> 12;
2705 	userpal[0].green = g = (j >> 6) & 0x3F;
2706 	userpal[0].blue = b = j & 0x3F;
2707 
2708 	/* Find distances from all others to it */
2709 	if (quant_to > 1)
2710 	{
2711 		for (i = 0; i < HISTSIZE; i++)
2712 		{
2713 			if (!hist[i]) continue;
2714 			dr = (i >> 12) - r;
2715 			dg = ((i >> 6) & 0x3F) - g;
2716 			db = (i & 0x3F) - b;
2717 			hist[i] = dr * dr + dg * dg + db * db;
2718 		}
2719 	}
2720 
2721 	/* Add more colors */
2722 	for (ii = 1; ii < quant_to; ii++)
2723 	{
2724 		/* Find farthest color */
2725 		j = -1;
2726 		for (i = k = 0; i < HISTSIZE; i++)
2727 		{
2728 			if (hist[i] <= k) continue;
2729 			j = i; k = hist[i];
2730 		}
2731 		/* No more colors? */
2732 		if (j < 0) break;
2733 
2734 		/* Store into palette */
2735 		userpal[ii].red = r = j >> 12;
2736 		userpal[ii].green = g = (j >> 6) & 0x3F;
2737 		userpal[ii].blue = b = j & 0x3F;
2738 
2739 		/* Update distances */
2740 		for (i = 0; i < HISTSIZE; i++)
2741 		{
2742 			if (!hist[i]) continue;
2743 			dr = (i >> 12) - r;
2744 			dg = ((i >> 6) & 0x3F) - g;
2745 			db = (i & 0x3F) - b;
2746 			k = dr * dr + dg * dg + db * db;
2747 			if (k < hist[i]) hist[i] = k;
2748 		}
2749 	}
2750 
2751 	/* Upconvert colors */
2752 	for (i = 0; i < ii; i++)
2753 	{
2754 		userpal[i].red = (userpal[i].red << 2) + (userpal[i].red >> 4);
2755 		userpal[i].green = (userpal[i].green << 2) + (userpal[i].green >> 4);
2756 		userpal[i].blue = (userpal[i].blue << 2) + (userpal[i].blue >> 4);
2757 	}
2758 
2759 	/* Clear empty slots */
2760 	for (i = ii; i < quant_to; i++)
2761 		userpal[i].red = userpal[i].green = userpal[i].blue = 0;
2762 
2763 	free(hist);
2764 	return (0);
2765 }
2766 
2767 /* Pairwise Nearest Neighbor quantization algorithm - minimizes mean square
2768  * error measure; time used is proportional to number of bins squared - WJ */
2769 
2770 typedef struct {
2771 	double rc, gc, bc, err;
2772 	int cnt;
2773 	unsigned short nn, fw, bk, tm, mtm;
2774 } pnnbin;
2775 
find_nn(pnnbin * bins,int idx)2776 static void find_nn(pnnbin *bins, int idx)
2777 {
2778 	pnnbin *bin1, *bin2;
2779 	int i, nn = 0;
2780 	double n1, wr, wg, wb, err = 1e100;
2781 
2782 	bin1 = bins + idx;
2783 	n1 = bin1->cnt;
2784 	wr = bin1->rc;
2785 	wg = bin1->gc;
2786 	wb = bin1->bc;
2787 	for (i = bin1->fw; i; i = bin2->fw)
2788 	{
2789 		double nerr, n2;
2790 
2791 		bin2 = bins + i;
2792 		nerr = (bin2->rc - wr) * (bin2->rc - wr) +
2793 			(bin2->gc - wg) * (bin2->gc - wg) +
2794 			(bin2->bc - wb) * (bin2->bc - wb);
2795 		n2 = bin2->cnt;
2796 		nerr *= (n1 * n2) / (n1 + n2);
2797 		if (nerr >= err) continue;
2798 		err = nerr;
2799 		nn = i;
2800 	}
2801 	bin1->err = err;
2802 	bin1->nn = nn;
2803 }
2804 
pnnquan(unsigned char * inbuf,int width,int height,int quant_to,png_color * userpal)2805 int pnnquan(unsigned char *inbuf, int width, int height, int quant_to,
2806 	png_color *userpal)
2807 {
2808 	unsigned short heap[32769];
2809 	pnnbin *bins, *tb, *nb;
2810 	double d, err, n1, n2;
2811 	int i, j, k, l, l2, h, b1, maxbins, extbins, res = 1;
2812 
2813 
2814 	heap[0] = 0; // Empty
2815 	bins = calloc(32768, sizeof(pnnbin));
2816 	if (!bins) return (-1);
2817 
2818 	progress_init(_("Quantize Pass 1"), 1);
2819 
2820 	/* Build histogram */
2821 	k = width * height;
2822 	for (i = 0; i < k; i++ , inbuf += 3)
2823 	{
2824 // !!! Can throw gamma correction in here, but what to do about perceptual
2825 // !!! nonuniformity then?
2826 		j = ((inbuf[0] & 0xF8) << 7) + ((inbuf[1] & 0xF8) << 2) +
2827 			(inbuf[2] >> 3);
2828 		tb = bins + j;
2829 		tb->rc += inbuf[0]; tb->gc += inbuf[1]; tb->bc += inbuf[2];
2830 		tb->cnt++;
2831 	}
2832 
2833 	/* Cluster nonempty bins at one end of array */
2834 	tb = bins;
2835 	for (i = 0; i < 32768; i++)
2836 	{
2837 		if (!bins[i].cnt) continue;
2838 		*tb = bins[i];
2839 		d = 1.0 / (double)tb->cnt;
2840 		tb->rc *= d; tb->gc *= d; tb->bc *= d;
2841 		if (quan_sqrt) tb->cnt = sqrt(tb->cnt);
2842 		tb++;
2843 	}
2844 	maxbins = tb - bins;
2845 	for (i = 0; i < maxbins - 1; i++)
2846 	{
2847 		bins[i].fw = i + 1;
2848 		bins[i + 1].bk = i;
2849 	}
2850 // !!! Already zeroed out by calloc()
2851 //	bins[0].bk = bins[i].fw = 0;
2852 
2853 	/* Initialize nearest neighbors and build heap of them */
2854 	for (i = 0; i < maxbins; i++)
2855 	{
2856 		if (((i * 50) % maxbins >= maxbins - 50))
2857 			if (progress_update((float)i / maxbins)) goto quit;
2858 
2859 		find_nn(bins, i);
2860 		/* Push slot on heap */
2861 		err = bins[i].err;
2862 		for (l = ++heap[0]; l > 1; l = l2)
2863 		{
2864 			l2 = l >> 1;
2865 			if (bins[h = heap[l2]].err <= err) break;
2866 			heap[l] = h;
2867 		}
2868 		heap[l] = i;
2869 	}
2870 
2871 	progress_end();
2872 	progress_init(_("Quantize Pass 2"), 1);
2873 
2874 	/* Merge bins which increase error the least */
2875 	extbins = maxbins - quant_to;
2876 	for (i = 0; i < extbins; )
2877 	{
2878 		if (((i * 50) % extbins >= extbins - 50))
2879 			if (progress_update((float)i / extbins)) goto quit;
2880 
2881 		/* Use heap to find which bins to merge */
2882 		while (TRUE)
2883 		{
2884 			tb = bins + (b1 = heap[1]); /* One with least error */
2885 			/* Is stored error up to date? */
2886 			if ((tb->tm >= tb->mtm) &&
2887 				(bins[tb->nn].mtm <= tb->tm)) break;
2888 			if (tb->mtm == 0xFFFF) /* Deleted node */
2889 				b1 = heap[1] = heap[heap[0]--];
2890 			else /* Too old error value */
2891 			{
2892 				find_nn(bins, b1);
2893 				tb->tm = i;
2894 			}
2895 			/* Push slot down */
2896 			err = bins[b1].err;
2897 			for (l = 1; (l2 = l + l) <= heap[0]; l = l2)
2898 			{
2899 				if ((l2 < heap[0]) && (bins[heap[l2]].err >
2900 					bins[heap[l2 + 1]].err)) l2++;
2901 				if (err <= bins[h = heap[l2]].err) break;
2902 				heap[l] = h;
2903 			}
2904 			heap[l] = b1;
2905 		}
2906 
2907 		/* Do a merge */
2908 		nb = bins + tb->nn;
2909 		n1 = tb->cnt;
2910 		n2 = nb->cnt;
2911 		d = 1.0 / (n1 + n2);
2912 		tb->rc = d * rint(n1 * tb->rc + n2 * nb->rc);
2913 		tb->gc = d * rint(n1 * tb->gc + n2 * nb->gc);
2914 		tb->bc = d * rint(n1 * tb->bc + n2 * nb->bc);
2915 		tb->cnt += nb->cnt;
2916 		tb->mtm = ++i;
2917 
2918 		/* Unchain deleted bin */
2919 		bins[nb->bk].fw = nb->fw;
2920 		bins[nb->fw].bk = nb->bk;
2921 		nb->mtm = 0xFFFF;
2922 	}
2923 
2924 	/* Fill palette */
2925 	i = j = 0;
2926 	while (TRUE)
2927 	{
2928 		userpal[j].red = rint(bins[i].rc);
2929 		userpal[j].green = rint(bins[i].gc);
2930 		userpal[j++].blue = rint(bins[i].bc);
2931 		if (!(i = bins[i].fw)) break;
2932 	}
2933 
2934 	/* Clear empty slots */
2935 	for (; j < quant_to; j++)
2936 		userpal[j].red = userpal[j].green = userpal[j].blue = 0;
2937 	res = 0;
2938 
2939 quit:	progress_end();
2940 	free(bins);
2941 	return (res);
2942 }
2943 
2944 /* Distance functions for 3 distance measures */
2945 
2946 #if defined(__GNUC__) && defined(__i386__)
2947 #define REGPARM2 __attribute__ ((regparm (2)))
2948 #else
2949 #define REGPARM2
2950 #endif
2951 
2952 typedef double REGPARM2 (*distance_func)(const double *v0, const double *v1);
2953 
distance_linf(const double * v0,const double * v1)2954 static double REGPARM2 distance_linf(const double *v0, const double *v1)
2955 {
2956 	double td, td2;
2957 
2958 	td = fabs(v0[0] - v1[0]);
2959 	td2 = fabs(v0[1] - v1[1]);
2960 	if (td < td2) td = td2;
2961 	td2 = fabs(v0[2] - v1[2]);
2962 	if (td < td2) td = td2;
2963 	return (td);
2964 }
2965 
distance_l1(const double * v0,const double * v1)2966 static double REGPARM2 distance_l1(const double *v0, const double *v1)
2967 {
2968 	return (fabs(v0[0] - v1[0]) + fabs(v0[1] - v1[1]) + fabs(v0[2] - v1[2]));
2969 }
2970 
distance_l2(const double * v0,const double * v1)2971 static double REGPARM2 distance_l2(const double *v0, const double *v1)
2972 {
2973 	return (sqrt((v0[0] - v1[0]) * (v0[0] - v1[0]) +
2974 		(v0[1] - v1[1]) * (v0[1] - v1[1]) +
2975 		(v0[2] - v1[2]) * (v0[2] - v1[2])));
2976 }
2977 
2978 static const distance_func distance_3d[NUM_DISTANCES] = {
2979 	distance_linf, distance_l1, distance_l2
2980 };
2981 
2982 /* Dithering works with 6-bit colours, because hardware VGA palette is 6-bit,
2983  * and any kind of dithering is imprecise by definition anyway - WJ */
2984 
2985 typedef struct {
2986 	double xyz256[768], gamma[256 * 2], lin[256 * 2];
2987 	int cspace, cdist, ncols;
2988 	guint32 xcmap[64 * 64 * 2 + 128 * 2]; /* Cache bitmap */
2989 	guint32 lcmap[64 * 64 * 2]; /* Extension bitmap */
2990 	unsigned char cmap[64 * 64 * 64 + 128 * 64]; /* Index cache */
2991 } ctable;
2992 
2993 static ctable *ctp;
2994 
2995 /* !!! Beware of GCC misoptimizing this! The two functions below is the result
2996  * of much trial and error, and hopefully not VERY brittle; but still, after any
2997  * modification to them, compare the performance to what it was before - WJ */
2998 
find_nearest(int col[3],int n)2999 static int find_nearest(int col[3], int n)
3000 {
3001 	/* !!! Stack misalignment is a very real issue here */
3002 	unsigned char tmp_[4 * sizeof(double)];
3003 	double *tmp = ALIGNED(tmp_, sizeof(double));
3004 
3005 
3006 	/* Prepare colour coords */
3007 	switch (ctp->cspace)
3008 	{
3009 	default:
3010 	case CSPACE_RGB:
3011 		tmp[0] = ctp->lin[n + col[0]];
3012 		tmp[1] = ctp->lin[n + col[1]];
3013 		tmp[2] = ctp->lin[n + col[2]];
3014 		break;
3015 	case CSPACE_SRGB:
3016 		tmp[0] = ctp->gamma[n + col[0]];
3017 		tmp[1] = ctp->gamma[n + col[1]];
3018 		tmp[2] = ctp->gamma[n + col[2]];
3019 		break;
3020 	case CSPACE_LXN:
3021 		rgb2LXN(tmp, ctp->gamma[n + col[0]], ctp->gamma[n + col[1]],
3022 			ctp->gamma[n + col[2]]);
3023 		break;
3024 	}
3025 
3026 	/* Find nearest colour */
3027 	{
3028 		const distance_func dist = distance_3d[ctp->cdist];
3029 		double d = 1000000000.0, td, *xyz = ctp->xyz256;
3030 		int i, j, l = ctp->ncols;
3031 
3032 		for (i = j = 0; i < l; i++)
3033 		{
3034 			td = dist(tmp, xyz + i * 3);
3035 			if (td < d) j = i , d = td;
3036 		}
3037 		return (j);
3038 	}
3039 }
3040 
lookup_srgb(double * srgb)3041 static int lookup_srgb(double *srgb)
3042 {
3043 	int k, n = 0, col[3];
3044 
3045 	/* Convert to 8-bit RGB coords */
3046 	col[0] = UNGAMMA256(srgb[0]);
3047 	col[1] = UNGAMMA256(srgb[1]);
3048 	col[2] = UNGAMMA256(srgb[2]);
3049 
3050 	/* Check if there is extended precision */
3051 	k = ((col[0] & 0xFC) << 10) + ((col[1] & 0xFC) << 4) + (col[2] >> 2);
3052 	if (ctp->lcmap[k >> 5] & (1U << (k & 31))) k = 64 * 64 * 64 +
3053 		ctp->cmap[k] * 64 + ((col[0] & 3) << 4) +
3054 		((col[1] & 3) << 2) + (col[2] & 3);
3055 	else n = 256; /* Use posterized values for 6-bit part */
3056 
3057 	/* Use colour cache if possible */
3058 	if (!(ctp->xcmap[k >> 5] & (1U << (k & 31))))
3059 	{
3060 		ctp->xcmap[k >> 5] |= 1U << (k & 31);
3061 		ctp->cmap[k] = find_nearest(col, n);
3062 	}
3063 
3064 	return (ctp->cmap[k]);
3065 }
3066 
3067 // !!! No support for transparency yet !!!
3068 /* Damping functions roughly resemble old GIMP's behaviour, but may need some
3069  * tuning because linear sRGB is just too different from normal RGB */
mem_dither(unsigned char * old,int ncols,short * dither,int cspace,int dist,int limit,int selc,int serpent,int rgb8b,double emult)3070 int mem_dither(unsigned char *old, int ncols, short *dither, int cspace,
3071 	int dist, int limit, int selc, int serpent, int rgb8b, double emult)
3072 {
3073 	int i, j, k, l, kk, j0, j1, dj, rlen, col0, col1, progress;
3074 	unsigned char *ddata, *src, *dest;
3075 	double *row0, *row1, *row2, *tmp;
3076 	double err, intd, extd, *gamma6, *lin6;
3077 	double tc0[3], tc1[3], color0[3], color1[3];
3078 	double fdiv = 0, gamut[6] = {1, 1, 1, 0, 0, 0};
3079 
3080 	/* Allocate working space */
3081 	rlen = (mem_width + 4) * 3 * sizeof(double);
3082 	ddata = multialloc(MA_ALIGN_DOUBLE,
3083 		&row0, rlen,
3084 		&row1, rlen,
3085 		&row2, rlen,
3086 		&ctp, sizeof(ctable),
3087 		NULL);
3088 	if (!ddata) return (1);
3089 
3090 	if ((progress = mem_width * mem_height > 1000000))
3091 		progress_init(_("Converting to Indexed Palette"), 0);
3092 
3093 	/* Preprocess palette to find whether to extend precision and where */
3094 	for (i = 0; i < ncols; i++)
3095 	{
3096 		j = ((mem_pal[i].red & 0xFC) << 10) +
3097 			((mem_pal[i].green & 0xFC) << 4) +
3098 			(mem_pal[i].blue >> 2);
3099 		if (!(l = ctp->cmap[j]))
3100 		{
3101 			ctp->cmap[j] = l = i + 1;
3102 			ctp->xcmap[l * 4 + 2] = j;
3103 		}
3104 		k = ((mem_pal[i].red & 3) << 4) +
3105 			((mem_pal[i].green & 3) << 2) +
3106 			(mem_pal[i].blue & 3);
3107 		ctp->xcmap[l * 4 + (k & 1)] |= 1U << (k >> 1);
3108 	}
3109 	memset(ctp->cmap, 0, 64 * 64 * 64);
3110 	for (k = 0 , i = 4; i < 256 * 4; i += 4)
3111 	{
3112 		guint32 v = ctp->xcmap[i] | ctp->xcmap[i + 1];
3113 		/* Are 2+ colors there somewhere? */
3114 		if (!((v & (v - 1)) | (ctp->xcmap[i] & ctp->xcmap[i + 1])))
3115 			continue;
3116 		rgb8b = TRUE; /* Force 8-bit precision */
3117 		j = ctp->xcmap[i + 2];
3118 		ctp->lcmap[j >> 5] |= 1U << (j & 31);
3119 		ctp->cmap[j] = k++;
3120 	}
3121 	memset(ctp->xcmap, 0, 257 * 4 * sizeof(guint32));
3122 
3123 	/* Prepare tables */
3124 	for (i = 0; i < 256; i++)
3125 	{
3126 		j = (i & 0xFC) + (i >> 6);
3127 		ctp->gamma[i] = gamma256[i];
3128 		ctp->gamma[i + 256] = gamma256[j];
3129 		ctp->lin[i] = i * (1.0 / 255.0);
3130 		ctp->lin[i + 256] = j * (1.0 / 255.0);
3131 	}
3132 	/* Keep all 8 bits of input or posterize to 6 bits? */
3133 	i = rgb8b ? 0 : 256;
3134 	gamma6 = ctp->gamma + i; lin6 = ctp->lin + i;
3135 	tmp = ctp->xyz256;
3136 	for (i = 0; i < ncols; i++ , tmp += 3)
3137 	{
3138 		/* Update gamut limits */
3139 		tmp[0] = gamma6[mem_pal[i].red];
3140 		tmp[1] = gamma6[mem_pal[i].green];
3141 		tmp[2] = gamma6[mem_pal[i].blue];
3142 		for (j = 0; j < 3; j++)
3143 		{
3144 			if (tmp[j] < gamut[j]) gamut[j] = tmp[j];
3145 			if (tmp[j] > gamut[j + 3]) gamut[j + 3] = tmp[j];
3146 		}
3147 		/* Store colour coords */
3148 		switch (cspace)
3149 		{
3150 		default:
3151 		case CSPACE_RGB:
3152 			tmp[0] = lin6[mem_pal[i].red];
3153 			tmp[1] = lin6[mem_pal[i].green];
3154 			tmp[2] = lin6[mem_pal[i].blue];
3155 			break;
3156 		case CSPACE_SRGB:
3157 			break; /* Done already */
3158 		case CSPACE_LXN:
3159 			rgb2LXN(tmp, tmp[0], tmp[1], tmp[2]);
3160 			break;
3161 		}
3162 	}
3163 	ctp->cspace = cspace; ctp->cdist = dist; ctp->ncols = ncols;
3164 	serpent = serpent ? 0 : 2;
3165 	if (dither) fdiv = 1.0 / *dither++;
3166 
3167 	/* Process image */
3168 	for (i = 0; i < mem_height; i++)
3169 	{
3170 		src = old + i * mem_width * 3;
3171 		dest = mem_img[CHN_IMAGE] + i * mem_width;
3172 		memset(row2, 0, rlen);
3173 		if (serpent ^= 1)
3174 		{
3175 			j0 = 0; j1 = mem_width * 3; dj = 1;
3176 		}
3177 		else
3178 		{
3179 			j0 = (mem_width - 1) * 3; j1 = -3; dj = -1;
3180 			dest += mem_width - 1;
3181 		}
3182 		for (j = j0; j != j1; j += dj * 3)
3183 		{
3184 			for (k = 0; k < 3; k++)
3185 			{
3186 				/* Posterize to 6 bits as natural for palette */
3187 				color0[k] = gamma6[src[j + k]];
3188 				/* Add in error, maybe limiting it */
3189 				err = row0[j + k + 6];
3190 				if (limit == 1) /* To half of SRGB range */
3191 				{
3192 					err = err < -0.5 ? -0.5 :
3193 						err > 0.5 ? 0.5 : err;
3194 				}
3195 				else if (limit == 2) /* To 1/4, with damping */
3196 				{
3197 					err = err < -0.1 ? (err < -0.4 ?
3198 						-0.25 : 0.5 * err - 0.05) :
3199 						err > 0.1 ? (err > 0.4 ?
3200 						0.25 : 0.5 * err + 0.05) : err;
3201 				}
3202 				color1[k] = color0[k] + err;
3203 				/* Limit result to palette gamut */
3204 				if (color1[k] < gamut[k]) color1[k] = gamut[k];
3205 				if (color1[k] > gamut[k + 3]) color1[k] = gamut[k + 3];
3206 			}
3207 			/* Output best colour */
3208 			col1 = lookup_srgb(color1);
3209 			*dest = col1;
3210 			dest += dj;
3211 			if (!dither) continue;
3212 			/* Evaluate new error */
3213 			tc1[0] = gamma6[mem_pal[col1].red];
3214 			tc1[1] = gamma6[mem_pal[col1].green];
3215 			tc1[2] = gamma6[mem_pal[col1].blue];
3216 			if (selc) /* Selective error damping */
3217 			{
3218 				col0 = lookup_srgb(color0);
3219 				tc0[0] = gamma6[mem_pal[col0].red];
3220 				tc0[1] = gamma6[mem_pal[col0].green];
3221 				tc0[2] = gamma6[mem_pal[col0].blue];
3222 				/* Split error the obvious way */
3223 				if (!(selc & 1) && (col0 == col1))
3224 				{
3225 					color1[0] = (color1[0] - color0[0]) * emult +
3226 						color0[0] - tc0[0];
3227 					color1[1] = (color1[1] - color0[1]) * emult +
3228 						color0[1] - tc0[1];
3229 					color1[2] = (color1[2] - color0[2]) * emult +
3230 						color0[2] - tc0[2];
3231 				}
3232 				/* Weigh component errors separately */
3233 				else if (selc < 3)
3234 				{
3235 					for (k = 0; k < 3; k++)
3236 					{
3237 						intd = fabs(color0[k] - tc0[k]);
3238 						extd = fabs(color0[k] - color1[k]);
3239 						if (intd + extd == 0.0) err = 1.0;
3240 						else err = (intd + emult * extd) / (intd + extd);
3241 						color1[k] = err * (color1[k] - tc1[k]);
3242 					}
3243 				}
3244 				/* Weigh errors by vector length */
3245 				else
3246 				{
3247 					intd = sqrt((color0[0] - tc0[0]) * (color0[0] - tc0[0]) +
3248 						(color0[1] - tc0[1]) * (color0[1] - tc0[1]) +
3249 						(color0[2] - tc0[2]) * (color0[2] - tc0[2]));
3250 					extd = sqrt((color0[0] - color1[0]) * (color0[0] - color1[0]) +
3251 						(color0[1] - color1[1]) * (color0[1] - color1[1]) +
3252 						(color0[2] - color1[2]) * (color0[2] - color1[2]));
3253 					if (intd + extd == 0.0) err = 1.0;
3254 					else err = (intd + emult * extd) / (intd + extd);
3255 					color1[0] = err * (color1[0] - tc1[0]);
3256 					color1[1] = err * (color1[1] - tc1[1]);
3257 					color1[2] = err * (color1[2] - tc1[2]);
3258 				}
3259 			}
3260 			else /* Indiscriminate error damping */
3261 			{
3262 				color1[0] = (color1[0] - tc1[0]) * emult;
3263 				color1[1] = (color1[1] - tc1[1]) * emult;
3264 				color1[2] = (color1[2] - tc1[2]) * emult;
3265 			}
3266 			/* Distribute the error */
3267 			color1[0] *= fdiv;
3268 			color1[1] *= fdiv;
3269 			color1[2] *= fdiv;
3270 			for (k = 0; k < 5; k++)
3271 			{
3272 				kk = j + (k - 2) * dj * 3 + 6;
3273 				for (l = 0; l < 3; l++ , kk++)
3274 				{
3275 					row0[kk] += color1[l] * dither[k];
3276 					row1[kk] += color1[l] * dither[k + 5];
3277 					row2[kk] += color1[l] * dither[k + 10];
3278 				}
3279 			}
3280 		}
3281 		tmp = row0; row0 = row1; row1 = row2; row2 = tmp;
3282 		if (progress && (i * 10) % mem_height >= mem_height - 10)
3283 			progress_update((float)(i + 1) / mem_height);
3284 	}
3285 
3286 	if (progress) progress_end();
3287 	free(ddata);
3288 	return (0);
3289 }
3290 
3291 /* Dumb (but fast) Floyd-Steinberg dithering in RGB space, loosely based on
3292  * Dennis Lee's dithering implementation from dl3quant.c, in turn based on
3293  * dithering code from the IJG's jpeg library - WJ */
mem_dumb_dither(unsigned char * old,unsigned char * new,png_color * pal,int width,int height,int ncols,int dither)3294 int mem_dumb_dither(unsigned char *old, unsigned char *new, png_color *pal,
3295 	int width, int height, int ncols, int dither)
3296 {
3297 	unsigned short cols[32768], sqrtb[512], *sqr;
3298 	short limtb[512], *lim, fr[3] = {0, 0, 0};
3299 	short *rows = NULL, *row0 = fr, *row1 = fr;
3300 	unsigned char clamp[768], *src, *dest;
3301 	int i, j, k, j0, dj, dj3, r, g, b, rlen, serpent = 2;
3302 
3303 	/* Allocate working space */
3304 	rlen = (width + 2) * 3;
3305 	if (dither)
3306 	{
3307 		rows = calloc(rlen * 2, sizeof(short));
3308 		if (!rows) return (1);
3309 		serpent = 0;
3310 	}
3311 
3312 	/* Color cache, squares table, clamp table */
3313 	memset(cols, 0, sizeof(cols));
3314 	sqr = sqrtb + 256;
3315 	for (i = -255; i < 256; i++) sqr[i] = i * i;
3316 	memset(clamp, 0, 256);
3317 	memset(clamp + 512, 255, 256);
3318 	for (i = 0; i < 256; i++) clamp[i + 256] = i;
3319 
3320 	/* Error limiter table, Dennis Lee's way */
3321 #define ERR_LIM 20
3322 	lim = limtb + 256;
3323 	for (i = 0; i < ERR_LIM; i++)
3324 		lim[i] = i , lim[-i] = -i;
3325 	for (; i < 256; i++)
3326 		lim[i] = ERR_LIM , lim[-i] = -ERR_LIM;
3327 #undef ERR_LIM
3328 
3329 	/* Process image */
3330 	for (i = 0; i < height; i++)
3331 	{
3332 		src = old + i * width * 3;
3333 		dest = new + i * width;
3334 		if (serpent ^= 1)
3335 		{
3336 			j0 = 0; dj = 1;
3337 		}
3338 		else
3339 		{
3340 			j0 = (width - 1) * 3; dj = -1;
3341 			dest += width - 1;
3342 		}
3343 		if (dither)
3344 		{
3345 			row0 = row1 = rows + 3;
3346 			*(serpent ? &row1 : &row0) += rlen;
3347 			memset(row1 - 3, 0, rlen * sizeof(short));
3348 			src += j0; row0 += j0; row1 += j0;
3349 		}
3350 		dj3 = dj * 3;
3351 		for (j = 0; j < width; j++ , src += dj3 , dest += dj)
3352 		{
3353 			r = clamp[src[0] + ((row0[0] + 0x1008) >> 4)];
3354 			g = clamp[src[1] + ((row0[1] + 0x1008) >> 4)];
3355 			b = clamp[src[2] + ((row0[2] + 0x1008) >> 4)];
3356 			k = ((r & 0xF8) << 7) + ((g & 0xF8) << 2) + (b >> 3);
3357 			if (!cols[k]) /* Find nearest color in RGB */
3358 			{
3359 				int i, j, n = 0, l = 1000000;
3360 
3361 /* Searching for color nearest to first color in cell, instead of to cell
3362  * itself, looks like a bug, but works like a feature - makes FS dither less
3363  * prone to patterning. This trick I learned from Dennis Lee's code - WJ */
3364 				for (i = 0; i < ncols; i++)
3365 				{
3366 					j = sqr[r - pal[i].red] +
3367 						sqr[g - pal[i].green] +
3368 						sqr[b - pal[i].blue];
3369 					if (j >= l) continue;
3370 					l = j; n = i;
3371 				}
3372 				cols[k] = n + 1;
3373 			}
3374 			*dest = k = cols[k] - 1;
3375 			if (!dither) continue;
3376 
3377 			r = lim[r - pal[k].red];
3378 			g = lim[g - pal[k].green];
3379 			b = lim[b - pal[k].blue];
3380 			k = r + r;
3381 			row1[0 + dj3] += r;
3382 			row1[0 - dj3] += (r += k);
3383 			row1[0 + 0  ] += (r += k);
3384 			row0[0 + dj3] += r + k;
3385 			k = g + g;
3386 			row1[1 + dj3] += g;
3387 			row1[1 - dj3] += (g += k);
3388 			row1[1 + 0  ] += (g += k);
3389 			row0[1 + dj3] += g + k;
3390 			k = b + b;
3391 			row1[2 + dj3] += b;
3392 			row1[2 - dj3] += (b += k);
3393 			row1[2 + 0  ] += (b += k);
3394 			row0[2 + dj3] += b + k;
3395 			row0 += dj3; row1 += dj3;
3396 		}
3397 	}
3398 
3399 	free(rows);
3400 	return (0);
3401 }
3402 
mem_find_dither(int red,int green,int blue)3403 void mem_find_dither(int red, int green, int blue)
3404 {
3405 	int pat = 4, dp = 3;
3406 	int i, ix1, ix2, pn, tpn, pp2 = pat * pat * 2;
3407 	double r, g, b, r1, g1, b1, dr0, dg0, db0, dr, dg, db;
3408 	double l, l2, tl, t;
3409 
3410 	r = gamma256[red];
3411 	g = gamma256[green];
3412 	b = gamma256[blue];
3413 	l = 16.0; ix1 = 0;
3414 
3415 	for (i = 0; i < mem_cols; i++)
3416 	{
3417 		dr = r - gamma256[mem_pal[i].red];
3418 		dg = g - gamma256[mem_pal[i].green];
3419 		db = b - gamma256[mem_pal[i].blue];
3420 		tl = dr * dr + dg * dg + db * db;
3421 		if (tl >= l) continue;
3422 		l = tl;
3423 		ix1 = i;
3424 	}
3425 
3426 	r1 = gamma256[mem_pal[ix1].red];
3427 	g1 = gamma256[mem_pal[ix1].green];
3428 	b1 = gamma256[mem_pal[ix1].blue];
3429 	dr0 = r - r1;
3430 	dg0 = g - g1;
3431 	db0 = b - b1;
3432 
3433 	l2 = l; ix2 = ix1; pn = 0;
3434 
3435 	for (i = 0; i < mem_cols; i++)
3436 	{
3437 		if (i == ix1) continue;
3438 		dr = gamma256[mem_pal[i].red] - r1;
3439 		dg = gamma256[mem_pal[i].green] - g1;
3440 		db = gamma256[mem_pal[i].blue] - b1;
3441 		t = pp2 * (dr0 * dr + dg0 * dg + db0 * db) /
3442 			(dr * dr + dg * dg + db * db);
3443 		if ((t <= dp) || (t >= pp2 - dp)) continue;
3444 		t = (tpn = rint(0.5 * t)) / (double)(pp2 >> 1);
3445 		dr = dr * t - dr0;
3446 		dg = dg * t - dg0;
3447 		db = db * t - db0;
3448 		tl = dr * dr + dg * dg + db * db;
3449 		if (tl >= l2) continue;
3450 		l2 = tl;
3451 		ix2 = i;
3452 		pn = tpn;
3453 	}
3454 
3455 	mem_col_A = ix1;
3456 	mem_col_B = ix2;
3457 /* !!! A mix with less than half of nearest color cannot be better than it, so
3458  * !!! patterns less dense than 50:50 won't be needed */
3459 	mem_tool_pat = -pn; /* pn*4 for 8x8 */
3460 	if (pattern_B) mem_tool_pat_B = pn - 16; /* pat**2 */
3461 
3462 	mem_col_A24 = mem_pal[mem_col_A];
3463 	mem_col_B24 = mem_pal[mem_col_B];
3464 }
3465 
mem_quantize(unsigned char * old_mem_image,int target_cols,int type)3466 int mem_quantize( unsigned char *old_mem_image, int target_cols, int type )
3467 	// type = 1:flat, 2:dither, 3:scatter
3468 {
3469 	unsigned char *new_img = mem_img[CHN_IMAGE];
3470 	int i, j, k;//, res=0;
3471 	int closest[3][2];
3472 	png_color pcol;
3473 
3474 	j = mem_width * mem_height;
3475 
3476 	progress_init(_("Converting to Indexed Palette"),1);
3477 
3478 	for ( j=0; j<mem_height; j++ )		// Convert RGB to indexed
3479 	{
3480 		if ( j%16 == 0)
3481 			if (progress_update( ((float) j)/(mem_height) )) break;
3482 		for ( i=0; i<mem_width; i++ )
3483 		{
3484 			pcol.red = old_mem_image[ 3*(i + mem_width*j) ];
3485 			pcol.green = old_mem_image[ 1 + 3*(i + mem_width*j) ];
3486 			pcol.blue = old_mem_image[ 2 + 3*(i + mem_width*j) ];
3487 
3488 			closest[0][0] = 0;		// 1st Closest palette item to pixel
3489 			closest[1][0] = 100000000;
3490 			closest[0][1] = 0;		// 2nd Closest palette item to pixel
3491 			closest[1][1] = 100000000;
3492 			for ( k=0; k<target_cols; k++ )
3493 			{
3494 				closest[2][0] = abs( pcol.red - mem_pal[k].red ) +
3495 					abs( pcol.green - mem_pal[k].green ) +
3496 					abs( pcol.blue - mem_pal[k].blue );
3497 				if ( closest[2][0] < closest[1][0] )
3498 				{
3499 					closest[0][1] = closest[0][0];
3500 					closest[1][1] = closest[1][0];
3501 					closest[0][0] = k;
3502 					closest[1][0] = closest[2][0];
3503 				}
3504 				else
3505 				{
3506 					if ( closest[2][0] < closest[1][1] )
3507 					{
3508 						closest[0][1] = k;
3509 						closest[1][1] = closest[2][0];
3510 					}
3511 				}
3512 			}
3513 			if ( type == 1 ) k = closest[0][0];		// Flat conversion
3514 			else
3515 			{
3516 				if ( closest[1][1] == 100000000 ) closest[1][0] = 0;
3517 				if ( closest[1][0] == 0 ) k = closest[0][0];
3518 				else
3519 				{
3520 				  if ( type == 2 )			// Dithered
3521 				  {
3522 //				  	if ( closest[1][1]/2 >= closest[1][0] )
3523 				  	if ( closest[1][1]*.67 < (closest[1][1] - closest[1][0]) )
3524 						k = closest[0][0];
3525 					else
3526 					{
3527 					  	if ( closest[0][0] > closest[0][1] )
3528 							k = closest[0][ (i+j) % 2 ];
3529 						else
3530 							k = closest[0][ (i+j+1) % 2 ];
3531 					}
3532 				  }
3533 				  if ( type == 3 )			// Scattered
3534 				  {
3535 				    if ( (rand() % (closest[1][1] + closest[1][0])) <= closest[1][1] )
3536 						k = closest[0][0];
3537 				    else	k = closest[0][1];
3538 				  }
3539 				}
3540 			}
3541 			*new_img++ = k;
3542 		}
3543 	}
3544 	progress_end();
3545 
3546 	return 0;
3547 }
3548 
3549 /* Linear brightness for palette color */
pal2B(png_color * c)3550 double pal2B(png_color *c)
3551 {
3552 	return (rgb2B(gamma256[c->red], gamma256[c->green], gamma256[c->blue]));
3553 }
3554 
3555 /* Convert image to greyscale */
mem_greyscale(int gcor)3556 void mem_greyscale(int gcor)
3557 {
3558 	unsigned char *mask, *img = mem_img[CHN_IMAGE];
3559 	int i, j, k, v, ch;
3560 
3561 	mask = malloc(mem_width);
3562 	if (!mask)
3563 	{
3564 		memory_errors(1);
3565 		return;
3566 	}
3567 	if (mem_img_bpp == 1)
3568 	{
3569 		for (i = 0; i < 256; i++)
3570 		{
3571 			if (gcor) /* Gamma correction + Helmholtz-Kohlrausch effect */
3572 			{
3573 				v = UNGAMMA256(pal2B(mem_pal + i));
3574 			}
3575 			else /* Usual braindead formula */
3576 			{
3577 				v = (299 * mem_pal[i].red +
3578 					587 * mem_pal[i].green +
3579 					114 * mem_pal[i].blue + 500) / 1000;
3580 			}
3581 			mem_pal[i].red = v;
3582 			mem_pal[i].green = v;
3583 			mem_pal[i].blue = v;
3584 		}
3585 	}
3586 	else
3587 	{
3588 		ch = mem_channel;
3589 		mem_channel = CHN_IMAGE;
3590 		for (i = 0; i < mem_height; i++)
3591 		{
3592 			row_protected(0, i, mem_width, mask);
3593 			for (j = 0; j < mem_width; j++)
3594 			if (paint_gamma && mask[j] && (mask[j] != 255))
3595 			{
3596 				double d, d0, d1, d2, m;
3597 				m = 1.0 - mask[j] / 255.0;
3598 				d0 = gamma256[img[0]];
3599 				d1 = gamma256[img[1]];
3600 				d2 = gamma256[img[2]];
3601 				/* Gamma + H-K effect / Usual */
3602 				d = gcor ? rgb2B(d0, d1, d2) :
3603 					gamma256[(299 * img[0] + 587 * img[1] +
3604 					114 * img[2] + 500) / 1000];
3605 				d0 += (d - d0) * m;
3606 				d1 += (d - d1) * m;
3607 				d2 += (d - d2) * m;
3608 				*img++ = UNGAMMA256(d0);
3609 				*img++ = UNGAMMA256(d1);
3610 				*img++ = UNGAMMA256(d2);
3611 			}
3612 			else
3613 			{
3614 				/* Gamma + H-K effect / Usual */
3615 				v = gcor ? UNGAMMA256(rgb2B(gamma256[img[0]],
3616 					gamma256[img[1]], gamma256[img[2]])) :
3617 					(299 * img[0] + 587 * img[1] +
3618 					114 * img[2] + 500) / 1000;
3619 				v *= 255 - mask[j];
3620 				k = *img * mask[j] + v;
3621 				*img++ = (k + (k >> 8) + 1) >> 8;
3622 				k = *img * mask[j] + v;
3623 				*img++ = (k + (k >> 8) + 1) >> 8;
3624 				k = *img * mask[j] + v;
3625 				*img++ = (k + (k >> 8) + 1) >> 8;
3626 			}
3627 		}
3628 		mem_channel = ch;
3629 	}
3630 	free(mask);
3631 }
3632 
3633 /* Valid for x=0..5, which is enough here */
3634 #define MOD3(x) ((((x) * 5 + 1) >> 2) & 3)
3635 
3636 /* Nonclassical HSV: H is 0..6, S is 0..1, V is 0..255 */
rgb2hsv(unsigned char * rgb,double * hsv)3637 void rgb2hsv(unsigned char *rgb, double *hsv)
3638 {
3639 	int c0, c1, c2;
3640 
3641 	if (!((rgb[0] ^ rgb[1]) | (rgb[0] ^ rgb[2])))
3642 	{
3643 		hsv[0] = hsv[1] = 0.0;
3644 		hsv[2] = rgb[0];
3645 		return;
3646 	}
3647 	c2 = rgb[2] < rgb[0] ? 1 : 0;
3648 	if (rgb[c2] >= rgb[c2 + 1]) c2++;
3649 	c0 = MOD3(c2 + 1);
3650 	c1 = (c2 + c0) ^ 3;
3651 	hsv[2] = rgb[c0] > rgb[c1] ? rgb[c0] : rgb[c1];
3652 	hsv[1] = hsv[2] - rgb[c2];
3653 	hsv[0] = c0 * 2 + 1 + (rgb[c1] - rgb[c0]) / hsv[1];
3654 	hsv[1] /= hsv[2];
3655 }
3656 
hsv2rgb(unsigned char * rgb,double * hsv)3657 void hsv2rgb(unsigned char *rgb, double *hsv)
3658 {
3659 	double h0, h1, h2;
3660 	int i;
3661 
3662 	h2 = hsv[2] * 2;
3663 	h1 = h2 * (1.0 - hsv[1]);
3664 	i = hsv[0];
3665 	h0 = (hsv[0] - i) * (h2 - h1);
3666 	if (i & 1) h2 -= h0 , h0 += h2;
3667 	else h0 += h1;
3668 	i >>= 1;
3669 	rgb[i] = ((int)h2 + 1) >> 1;
3670 	rgb[MOD3(i + 1)] = ((int)h0 + 1) >> 1;
3671 	rgb[MOD3(i + 2)] = ((int)h1 + 1) >> 1;
3672 }
3673 
rgb_hsl(int t,png_color col)3674 static double rgb_hsl(int t, png_color col)
3675 {
3676 	double hsv[3];
3677 	unsigned char rgb[3] = {col.red, col.green, col.blue};
3678 
3679 	if (t == 2) return (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]);
3680 	rgb2hsv(rgb, hsv);
3681 	return (hsv[t]);
3682 }
3683 
mem_pal_index_move(int c1,int c2)3684 void mem_pal_index_move( int c1, int c2 )	// Move index c1 to c2 and shuffle in between up/down
3685 {
3686 	png_color temp;
3687 	int i, j;
3688 
3689 	if (c1 == c2) return;
3690 
3691 	j = c1 < c2 ? 1 : -1;
3692 	temp = mem_pal[c1];
3693 	for (i = c1; i != c2; i += j) mem_pal[i] = mem_pal[i + j];
3694 	mem_pal[c2] = temp;
3695 }
3696 
mem_canvas_index_move(int c1,int c2)3697 void mem_canvas_index_move( int c1, int c2 )	// Similar to palette item move but reworks canvas pixels
3698 {
3699 	unsigned char table[256];
3700 	int i;
3701 
3702 	if (c1 == c2) return;
3703 
3704 	for (i = 0; i < 256; i++)
3705 	{
3706 		table[i] = i + (i > c2) - (i > c1);
3707 	}
3708 	table[c1] = c2;
3709 	table[c2] += (c1 > c2);
3710 
3711 	// Remap transparent color
3712 	if (mem_xpm_trans >= 0) mem_xpm_trans = table[mem_xpm_trans];
3713 
3714 	// Change pixel index to new palette
3715 	if (mem_img_bpp == 1) do_xlate(table, mem_img[CHN_IMAGE],
3716 		mem_width * mem_height);
3717 }
3718 
mem_pal_sort(int a,int i1,int i2,int rev)3719 void mem_pal_sort( int a, int i1, int i2, int rev )		// Sort colours in palette
3720 {
3721 	int tab0[256], tab1[256], tmp, i, j;
3722 	png_color old_pal[256];
3723 	unsigned char map[256];
3724 	double lxnA[3], lxn[3];
3725 
3726 	if ( i2 == i1 || i1>mem_cols || i2>mem_cols ) return;
3727 	if ( i2 < i1 )
3728 	{
3729 		i = i1;
3730 		i1 = i2;
3731 		i2 = i;
3732 	}
3733 
3734 	if (a == 4) get_lxn(lxnA, PNG_2_INT(mem_col_A24));
3735 	if (a == 9) mem_get_histogram(CHN_IMAGE);
3736 
3737 	for (i = 0; i < 256; i++)
3738 		tab0[i] = i;
3739 	for (i = i1; i <= i2; i++)
3740 	{
3741 		switch (a)
3742 		{
3743 		/* Hue */
3744 		case 0: tab1[i] = rint(1024 * rgb_hsl(0, mem_pal[i]));
3745 			break;
3746 		/* Saturation */
3747 		case 1: tab1[i] = rint(1024 * rgb_hsl(1, mem_pal[i]));
3748 			break;
3749 		/* Luminance */
3750 		case 2: tab1[i] = rint(1024 * rgb_hsl(2, mem_pal[i]));
3751 			break;
3752 		/* Brightness */
3753 		case 3: tab1[i] = rint(1024 * pal2B(mem_pal + i));
3754 			break;
3755 		/* Distance to A */
3756 		case 4: get_lxn(lxn, PNG_2_INT(mem_pal[i]));
3757 			tab1[i] = rint(1024 * ((lxn[0] - lxnA[0]) *
3758 				(lxn[0] - lxnA[0]) + (lxn[1] - lxnA[1]) *
3759 				(lxn[1] - lxnA[1]) + (lxn[2] - lxnA[2]) *
3760 				(lxn[2] - lxnA[2])));
3761 			break;
3762 		/* Red */
3763 		case 5: tab1[i] = mem_pal[i].red;
3764 			break;
3765 		/* Green */
3766 		case 6: tab1[i] = mem_pal[i].green;
3767 			break;
3768 		/* Blue */
3769 		case 7: tab1[i] = mem_pal[i].blue;
3770 			break;
3771 		/* Projection on A->B */
3772 		case 8: tab1[i] = mem_pal[i].red * (mem_col_B24.red - mem_col_A24.red) +
3773 				mem_pal[i].green * (mem_col_B24.green - mem_col_A24.green) +
3774 				mem_pal[i].blue * (mem_col_B24.blue - mem_col_A24.blue);
3775 			break;
3776 		/* Frequency */
3777 		case 9: tab1[i] = mem_histogram[i];
3778 			break;
3779 		}
3780 	}
3781 
3782 	rev = rev ? 1 : 0;
3783 	for ( j=i2; j>i1; j-- )			// The venerable bubble sort
3784 		for ( i=i1; i<j; i++ )
3785 		{
3786 			if (tab1[i + 1 - rev] < tab1[i + rev])
3787 			{
3788 				tmp = tab0[i];
3789 				tab0[i] = tab0[i + 1];
3790 				tab0[i + 1] = tmp;
3791 
3792 				tmp = tab1[i];
3793 				tab1[i] = tab1[i + 1];
3794 				tab1[i + 1] = tmp;
3795 			}
3796 		}
3797 
3798 	mem_pal_copy(old_pal, mem_pal);
3799 	for (i = 0; i < 256; i++)
3800 	{
3801 		mem_pal[i] = old_pal[tab0[i]];
3802 		map[tab0[i]] = i;
3803 	}
3804 	if (mem_xpm_trans >= 0) mem_xpm_trans = map[mem_xpm_trans];
3805 
3806 	if (mem_img_bpp != 1) return;
3807 
3808 	// Adjust canvas pixels if in indexed palette mode
3809 	do_xlate(map, mem_img[CHN_IMAGE], mem_width * mem_height);
3810 	/* Modify A & B */
3811 	mem_col_A = map[mem_col_A];
3812 	mem_col_B = map[mem_col_B];
3813 }
3814 
mem_invert()3815 void mem_invert()			// Invert the palette
3816 {
3817 	int i, j;
3818 	png_color *col = mem_pal;
3819 	unsigned char *img;
3820 
3821 	if ((mem_channel == CHN_IMAGE) && (mem_img_bpp == 1))
3822 	{
3823 		for ( i=0; i<256; i++ )
3824 		{
3825 			col->red = 255 - col->red;
3826 			col->green = 255 - col->green;
3827 			col->blue = 255 - col->blue;
3828 			col++;
3829 		}
3830 	}
3831 	else
3832 	{
3833 		unsigned char *mask = calloc(1, mem_width);
3834 
3835 		j = mem_width * mem_height;
3836 		if (mem_channel == CHN_IMAGE) j *= 3;
3837 		img = mem_img[mem_channel];
3838 		for (i = 0; i < j; i++)
3839 		{
3840 			*img++ ^= 255;
3841 		}
3842 		if (mask)
3843 		{
3844 			mask_merge(mem_undo_previous(mem_channel), mem_channel, mask);
3845 			free(mask);
3846 		}
3847 	}
3848 }
3849 
mem_normalize()3850 void mem_normalize()		// Normalize contrast in image or palette
3851 {
3852 	unsigned char map[256], *img = NULL;
3853 	png_color *col;
3854 	int i, uninit_(j), k, k0, k1;
3855 
3856 	memset(map, 0, 256);
3857 	if ((mem_channel == CHN_IMAGE) && (mem_img_bpp == 1))
3858 	{
3859 		for (i = 0 , col = mem_pal; i < mem_cols; i++ , col++)
3860 		{
3861 			map[col->red] = 1;
3862 			map[col->green] = 1;
3863 			map[col->blue] = 1;
3864 		}
3865 	}
3866 	else
3867 	{
3868 		j = mem_width * mem_height;
3869 		if (mem_channel == CHN_IMAGE) j *= 3;
3870 		img = mem_img[mem_channel];
3871 		for (i = 0; i < j; i++) map[img[i]] = 1;
3872 	}
3873 
3874 	/* Range */
3875 	for (i = 0; (i < 255) && !map[i]; i++);
3876 	k0 = k1 = i;
3877 	for (; i < 256; i++) if (map[i]) k1 = i;
3878 	/* Table */
3879 	map[k0] = k0; // Default
3880 	k = k1 - k0;
3881 	if (k) for (i = k0; i <= k1; i++) map[i] = 255 * (i - k0) / k;
3882 
3883 	if (img)
3884 	{
3885 		unsigned char *mask = calloc(1, mem_width);
3886 
3887 		do_xlate(map, img, j);
3888 		if (mask)
3889 		{
3890 			mask_merge(mem_undo_previous(mem_channel), mem_channel, mask);
3891 			free(mask);
3892 		}
3893 	}
3894 	else
3895 	{
3896 		for (i = 0 , col = mem_pal; i < mem_cols; i++ , col++)
3897 		{
3898 			col->red = map[col->red];
3899 			col->green = map[col->green];
3900 			col->blue = map[col->blue];
3901 		}
3902 	}
3903 }
3904 
mem_prepare_map(unsigned char * map,int how)3905 void mem_prepare_map(unsigned char *map, int how)
3906 {
3907 	int i, n, wrk[3];
3908 
3909 	memset(map, 0, 768); // Init
3910 	/* Greyscale */
3911 	if (how == MAP_GREY) for (i = 0; i < 256; i++ , map += 3)
3912 		map[0] = map[1] = map[2] = i;
3913 	/* Gradient */
3914 	else if (how == MAP_GRAD) for (i = 0; i < 256; i++ , map += 3)
3915 	{
3916 		if (!grad_value(wrk, CHN_IMAGE, i / 255.0)) continue;
3917 		map[0] = wrk[0] >> 8;
3918 		map[1] = wrk[1] >> 8;
3919 		map[2] = wrk[2] >> 8;
3920 	}
3921 	/* Palette */
3922 	else if (how == MAP_PAL) pal2rgb(map, mem_pal, mem_cols, 0);
3923 	/* Clipboard */
3924 	else if (how == MAP_CLIP)
3925 	{
3926 		n = mem_clip_w * mem_clip_h;
3927 		if (n > 256) n = 256;
3928 		if (mem_clip_bpp == 3) memcpy(map, mem_clipboard, n * 3);
3929 		else do_convert_rgb(0, 1, n, map, mem_clipboard, mem_pal);
3930 	}
3931 }
3932 
mem_remap_rgb(unsigned char * map,int what)3933 void mem_remap_rgb(unsigned char *map, int what) // Remap V/R/G/B to color
3934 {
3935 	unsigned char *w, *img = mem_img[CHN_IMAGE];
3936 	int cnt = mem_width * mem_height;
3937 
3938 	/* Value */
3939 	if (!what) while (cnt-- > 0)
3940 	{
3941 		int n = img[0] > img[1] ? img[0] : img[1];
3942 		n = n > img[2] ? n : img[2];
3943 		w = map + n * 3;
3944 		*img++ = w[0];
3945 		*img++ = w[1];
3946 		*img++ = w[2];
3947 	}
3948 	/* R/G/B */
3949 	else while (cnt-- > 0)
3950 	{
3951 		w = map + img[what - 1] * 3;
3952 		*img++ = w[0];
3953 		*img++ = w[1];
3954 		*img++ = w[2];
3955 	}
3956 
3957 	w = calloc(1, mem_width);
3958 	if (w)
3959 	{
3960 		mask_merge(mem_undo_previous(CHN_IMAGE), CHN_IMAGE, w);
3961 		free(w);
3962 	}
3963 }
3964 
3965 /* Expand palette to RGB triples, pad with 0 if needed */
pal2rgb(unsigned char * rgb,png_color * pal,int cnt,int len)3966 void pal2rgb(unsigned char *rgb, png_color *pal, int cnt, int len)
3967 {
3968 	len -= cnt;
3969 	while (cnt-- > 0)
3970 	{
3971 		rgb[0] = pal->red;
3972 		rgb[1] = pal->green;
3973 		rgb[2] = pal->blue;
3974 		rgb += 3; pal++;
3975 	}
3976 	if (len > 0) memset(rgb, 0, len * 3);
3977 }
3978 
3979 /* Pack RGB triples into palette */
rgb2pal(png_color * pal,unsigned char * rgb,int cnt)3980 void rgb2pal(png_color *pal, unsigned char *rgb, int cnt)
3981 {
3982 	while (cnt-- > 0)
3983 	{
3984 		pal->red = rgb[0];
3985 		pal->green = rgb[1];
3986 		pal->blue = rgb[2];
3987 		pal++; rgb += 3;
3988 	}
3989 }
3990 
3991 /* !!! The rectangles here exclude bottom & right border */
clip(int * rxy,int x0,int y0,int x1,int y1,const int * vxy)3992 int clip(int *rxy, int x0, int y0, int x1, int y1, const int *vxy)
3993 {
3994 	rxy[0] = x0 < vxy[0] ? vxy[0] : x0;
3995 	rxy[1] = y0 < vxy[1] ? vxy[1] : y0;
3996 	rxy[2] = x1 > vxy[2] ? vxy[2] : x1;
3997 	rxy[3] = y1 > vxy[3] ? vxy[3] : y1;
3998 	return ((rxy[2] > rxy[0]) && (rxy[3] > rxy[1]));
3999 }
4000 
4001 /* Intersect outer & inner rectangle, write out 1 to 5 rectangles the outer one
4002  * separates into, return number of outer rectangles */
clip4(int * rect04,int xo,int yo,int wo,int ho,int xi,int yi,int wi,int hi)4003 int clip4(int *rect04, int xo, int yo, int wo, int ho, int xi, int yi, int wi, int hi)
4004 {
4005 	int *p = rect04 + 4;
4006 	int xo1 = xo + wo, yo1 = yo + ho, xi1 = xi + wi, yi1 = yi + hi;
4007 
4008 	// Whole outer rectangle
4009 	p[0] = xo; p[1] = yo; p[2] = wo; p[3] = ho;
4010 	// No intersection
4011 	if ((xi >= xo1) || (yi >= yo1) || (xo >= xi1) || (yo >= yi1))
4012 	{
4013 		rect04[0] = xi; rect04[1] = yi; rect04[2] = rect04[3] = 0;
4014 		return (1);
4015 	}
4016 	if (yi > yo) // Top rectangle
4017 		p[3] = yi - yo , p += 4;
4018 	else yi = yo;
4019 	if (yi1 < yo1) // Bottom rectangle
4020 		*p++ = xo , *p++ = yi1 , *p++ = wo , *p++ = yo1 - yi1;
4021 	else yi1 = yo1;
4022 	hi = yi1 - yi;
4023 	if (xi > xo) // Left rectangle
4024 		*p++ = xo , *p++ = yi , *p++ = xi - xo , *p++ = hi;
4025 	else xi = xo;
4026 	if (xi1 < xo1) // Right rectangle
4027 		*p++ = xi1 , *p++ = yi , *p++ = xo1 - xi1 , *p++ = hi;
4028 	else xi1 = xo1;
4029 	wi = xi1 - xi;
4030 	// Clipped inner rectangle
4031 	rect04[0] = xi; rect04[1] = yi; rect04[2] = wi; rect04[3] = hi;
4032 
4033 	// Number of outer rectangles
4034 	return ((p - rect04 - 4) >> 2);
4035 }
4036 
xy_span(int * rxy,int scale,int yf)4037 int xy_span(int *rxy, int scale, int yf)
4038 {
4039 	return (floor_div(rxy[2 + yf] - 1, scale) - floor_div(rxy[yf], scale) + 1);
4040 }
4041 
xy_origin(int * rxy,int * vxy,int x,int y)4042 void xy_origin(int *rxy, int *vxy, int x, int y)
4043 {
4044 	rxy[0] = vxy[0] - x;
4045 	rxy[1] = vxy[1] - y;
4046 	rxy[2] = vxy[2] - x;
4047 	rxy[3] = vxy[3] - y;
4048 }
4049 
line_init(linedata line,int x0,int y0,int x1,int y1)4050 void line_init(linedata line, int x0, int y0, int x1, int y1)
4051 {
4052 	int i;
4053 	line[0] = x0;
4054 	line[1] = y0;
4055 	line[4] = (x1 - x0) * (line[6] = line[8] = x1 - x0 < 0 ? -1 : 1);
4056 	line[5] = (y1 - y0) * (line[7] = line[9] = y1 - y0 < 0 ? -1 : 1);
4057 	i = line[4] >= line[5]; /* More horizontal? */
4058 	line[2] = line[3] = line[5 - i];
4059 	line[4] = 2 * line[4 + i];
4060 	line[5] = 2 * line[2];
4061 	line[6 + i] = 0;
4062 }
4063 
line_step(linedata line)4064 int line_step(linedata line)
4065 {
4066 	line[3] -= line[4];
4067 	if (line[3] <= 0)
4068 	{
4069 		line[3] += line[5];
4070 		line[0] += line[8];
4071 		line[1] += line[9];
4072 	}
4073 	else
4074 	{
4075 		line[0] += line[6];
4076 		line[1] += line[7];
4077 	}
4078 	return (--line[2]);
4079 }
4080 
line_nudge(linedata line,int x,int y)4081 void line_nudge(linedata line, int x, int y)
4082 {
4083 	while ((line[0] != x) && (line[1] != y) && (line[2] >= 0))
4084 		line_step(line);
4085 }
4086 
4087 /* !!! The clipping rectangle here includes both borders */
line_clip(linedata line,const int * vxy,int * step)4088 int line_clip(linedata line, const int *vxy, int *step)
4089 {
4090 	int vh = !line[6], hv = vh ^ 1, hs = line[8 + vh], vs = line[8 + hv];
4091 	int dh = hs < 0, dv = vs < 0, l4 = line[4], steps[2];
4092 	int i, j, dx, dy;
4093 
4094 	for (i = 1; 1;)
4095 	{
4096 		dx = (vxy[(dh ^ i) * 2 + vh] - line[vh]) * hs + i;
4097 		if (dx < 0) dx = 0;
4098 		if (l4)
4099 		{
4100 			dy = (vxy[(dv ^ i) * 2 + hv] - line[hv]) * vs + i;
4101 			if (dy < 0) dy = 0;
4102 			dy = (line[5] * (dy - 1) + line[3] + l4 - 1) / l4;
4103 			if ((dy > dx) ^ i) dx = dy;
4104 		}
4105 		steps[i] = dx;
4106 		if (!i--) break;
4107 	}
4108 
4109 	if (line[5]) // Makes no sense for a single point
4110 	{
4111 		/* Too short? */
4112 		if ((line[2] -= dx) < 0) return (line[2]);
4113 		dy = (j = l4 * dx + line[5] - line[3]) / line[5];
4114 		line[vh] += hs * dx; line[hv] += vs * dy;
4115 		line[3] = line[5] * (dy + 1) - j;
4116 	}
4117 	/* Misses the rectangle? */
4118 	if ((line[0] < vxy[0]) || (line[0] > vxy[2]) ||
4119 		(line[1] < vxy[1]) || (line[1] > vxy[3])) return (line[2] = -1);
4120 	*step = dx;
4121 	j = steps[1] - dx - 1;
4122 	if (j < line[2]) line[2] = j;
4123 	return (line[2]);
4124 }
4125 
line_flip(linedata line)4126 void line_flip(linedata line)
4127 {
4128 	int l, d2;
4129 
4130 	if (!line[2]) return; // Single point
4131 	l = line[4] * line[2] + line[5] - line[3];
4132 	d2 = l / line[5];
4133 	line[3] = l - d2 * line[5] + 1;
4134 	line[0] += line[2] * line[6] + d2 * (line[8] - line[6]);
4135 	line[1] += line[2] * line[7] + d2 * (line[9] - line[7]);
4136 	line[6] *= -1; line[7] *= -1;
4137 	line[8] *= -1; line[9] *= -1;
4138 }
4139 
4140 /* Produce a horizontal segment from two connected lines */
twoline_segment(int * xx,linedata line1,linedata line2)4141 static void twoline_segment(int *xx, linedata line1, linedata line2)
4142 {
4143 	xx[0] = xx[1] = line1[0];
4144 	while (TRUE)
4145 	{
4146 		if (!line1[7]) /* Segments longer than 1 pixel */
4147 		{
4148 			while ((line1[2] > 0) && (line1[3] > line1[4]))
4149 				line_step(line1);
4150 		}
4151 		if (xx[0] > line1[0]) xx[0] = line1[0];
4152 		if (xx[1] < line1[0]) xx[1] = line1[0];
4153 		if ((line1[2] > 0) || (line2[2] < 0)) break;
4154 		memcpy(line1, line2, sizeof(linedata));
4155 		line2[2] = -1;
4156 		if (xx[0] > line1[0]) xx[0] = line1[0];
4157 		if (xx[1] < line1[0]) xx[1] = line1[0];
4158 	}
4159 }
4160 
sline(int x1,int y1,int x2,int y2)4161 void sline( int x1, int y1, int x2, int y2 )		// Draw single thickness straight line
4162 {
4163 	linedata line;
4164 
4165 	line_init(line, x1, y1, x2, y2);
4166 	for (; line[2] >= 0; line_step(line))
4167 	{
4168 		IF_IN_RANGE(line[0], line[1]) put_pixel(line[0], line[1]);
4169 	}
4170 }
4171 
4172 void circle_line(int x0, int y0, int dx, int dy, int thick);
4173 
tline(int x1,int y1,int x2,int y2,int size)4174 void tline( int x1, int y1, int x2, int y2, int size )		// Draw size thickness straight line
4175 {
4176 	linedata line;
4177 	int xdo, ydo, todo;
4178 
4179 	xdo = abs(x2 - x1);
4180 	ydo = abs(y2 - y1);
4181 	todo = xdo > ydo ? xdo : ydo;
4182 	if (todo < 2) return;	// The 1st and last points are done by calling procedure
4183 
4184 	if (size < 2) /* One pixel wide */
4185 	{
4186 		sline(x1, y1, x2, y2);
4187 		return;
4188 	}
4189 
4190 	/* Draw middle segment */
4191 	circle_line(x1, y1, x2 - x1, y2 - y1, size);
4192 
4193 	/* Add four more circles to cover all odd points */
4194 	if (!xdo || !ydo || (xdo == ydo)) return; /* Not needed */
4195 	line_init(line, x1, y1, x2, y2);
4196 	line_nudge(line, x1 + line[8] - 2 * line[6],
4197 		y1 + line[9] - 2 * line[7]); /* Jump to first diagonal step */
4198 	f_circle(line[0], line[1], size);
4199 	f_circle(line[0] - line[8], line[1] - line[9], size);
4200 	line_nudge(line, x2, y2); /* Jump to last diagonal step */
4201 	f_circle(line[0], line[1], size);
4202 	f_circle(line[0] - line[8], line[1] - line[9], size);
4203 }
4204 
4205 /* Draw whatever is bounded by two pairs of lines */
draw_quad(linedata line1,linedata line2,linedata line3,linedata line4)4206 void draw_quad(linedata line1, linedata line2, linedata line3, linedata line4)
4207 {
4208 	int x1, x2, y1, xx[4];
4209 	for (; line1[2] >= 0; line_step(line1) , line_step(line3))
4210 	{
4211 		y1 = line1[1];
4212 		twoline_segment(xx + 0, line1, line2);
4213 		twoline_segment(xx + 2, line3, line4);
4214 		if ((y1 < 0) || (y1 >= mem_height)) continue;
4215 		if (xx[0] > xx[2]) xx[0] = xx[2];
4216 		if (xx[1] < xx[3]) xx[1] = xx[3];
4217 		x1 = xx[0] < 0 ? 0 : xx[0];
4218 		x2 = xx[1] >= mem_width ? mem_width - 1 : xx[1];
4219 		put_pixel_row(x1, y1, x2 - x1 + 1, NULL);
4220 	}
4221 }
4222 
4223 /* Draw general parallelogram */
g_para(int x1,int y1,int x2,int y2,int xv,int yv)4224 void g_para( int x1, int y1, int x2, int y2, int xv, int yv )
4225 {
4226 	linedata line1, line2, line3, line4;
4227 	int i, j, x[2] = {x1, x2}, y[2] = {y1, y2};
4228 
4229 	j = (y1 < y2) ^ (yv < 0); i = j ^ 1;
4230 	line_init(line1, x[i], y[i], x[i] + xv, y[i] + yv);
4231 	line_init(line2, x[i] + xv, y[i] + yv, x[j] + xv, y[j] + yv);
4232 	line_init(line3, x[i], y[i], x[j], y[j]);
4233 	line_init(line4, x[j], y[j], x[j] + xv, y[j] + yv);
4234 	draw_quad(line1, line2, line3, line4);
4235 }
4236 
4237 /* Shapeburst engine */
4238 
4239 int sb_dist = DIST_L1;
4240 int sb_rect[4];
4241 static void *sb_mem;
4242 static unsigned short *sb_buf;
4243 static uint32_t *sb_buf2;
4244 
put_pixel_sb(int x,int y)4245 static void put_pixel_sb(int x, int y)
4246 {
4247 	int j, x1, y1;
4248 
4249 	x1 = x - sb_rect[0];
4250 	y1 = y - sb_rect[1];
4251 	if ((x1 < 0) || (x1 >= sb_rect[2]) || (y1 < 0) || (y1 >= sb_rect[3]))
4252 		return;
4253 
4254 	j = pixel_protected(x, y);
4255 	if (IS_INDEXED ? j : j == 255) return;
4256 
4257 	if (!sb_buf2) sb_buf[y1 * sb_rect[2] + x1] = 0xFFFF;
4258 	else sb_buf2[y1 * sb_rect[2] + x1] = 0xFFFF;
4259 }
4260 
4261 static void mask_select(unsigned char *mask, unsigned char *xsel, int l);
4262 
put_pixel_row_sb(int x,int y,int len,unsigned char * xsel)4263 static void put_pixel_row_sb(int x, int y, int len, unsigned char *xsel)
4264 {
4265 	unsigned char mask[ROW_BUFLEN];
4266 	int x1, y1, sb_ofs, offset, use_mask, masked;
4267 
4268 
4269 	if ((len <= 0) || (x + len <= sb_rect[0])) return;
4270 	x1 = x - sb_rect[0];
4271 	y1 = y - sb_rect[1];
4272 	if ((x1 >= sb_rect[2]) || (y1 < 0) || (y1 >= sb_rect[3]))
4273 		return;
4274 	if (x1 + len > sb_rect[2]) len = sb_rect[2] - x1; // Clip right side
4275 	if (x1 < 0) x -= x1 , len += x1 , xsel -= x1 , x1 = 0; // Clip left side
4276 
4277 	sb_ofs = y1 * sb_rect[2] + x1;
4278 	offset = x + mem_width * y;
4279 	masked = IS_INDEXED ? 1 : 255;
4280 	use_mask = (mem_channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK];
4281 
4282 	while (TRUE)
4283 	{
4284 		int i, l = len <= ROW_BUFLEN ? len : ROW_BUFLEN;
4285 
4286 		prep_mask(0, 1, l, mask,
4287 			use_mask ? mem_img[CHN_MASK] + offset : NULL,
4288 			mem_img[CHN_IMAGE] + offset * mem_img_bpp);
4289 
4290 		if (xsel)
4291 		{
4292 			mask_select(mask, xsel, l);
4293 			xsel += l;
4294 		}
4295 
4296 		for (i = 0; i < l; i++)
4297 		{
4298 			if (mask[i] >= masked) continue;
4299 			if (!sb_buf2) sb_buf[sb_ofs + i] = 0xFFFF;
4300 			else sb_buf2[sb_ofs + i] = 0xFFFF;
4301 		}
4302 
4303 		if (!(len -= l)) return;
4304 		sb_ofs += l;
4305 		offset += l;
4306 	}
4307 }
4308 
4309 /* Distance transform of binary image map, using L1 or Linf distance metric */
shapeburst()4310 static int shapeburst()
4311 {
4312 	unsigned short *r0, *dmap = sb_buf;
4313 	int i, j, k, l, dx, dy, maxd = 0, w = sb_rect[2], h = sb_rect[3];
4314 
4315 
4316 	/* Calculate distance */
4317 	r0 = dmap; dx = 1; dy = w; /* Forward pass */
4318 	while (TRUE)
4319 	{
4320 		/* First row */
4321 		for (i = 0; i < w; i++ , r0 += dx) if (*r0) *r0 = 1;
4322 		/* Other rows */
4323 		for (j = 1; j < h; j++)
4324 		{
4325 			/* 1st pixel */
4326 			if (*r0) *r0 = 1; r0 += dx;
4327 			/* Other pixels */
4328 			for (i = w - 1; i > 0; i-- , r0 += dx)
4329 			{
4330 				/* L1 */
4331 				k = *(r0 - dx); l = *(r0 - dy);
4332 				if (k > l) k = l;
4333 				if (*r0 > k) *r0 = k + 1;
4334 				if (sb_dist != DIST_LINF) continue;
4335 				/* Linf */
4336 				k = *(r0 - dy - dx); l = *(r0 - dy + dx);
4337 				if (k > l) k = l;
4338 				if (*r0 > k) *r0 = k + 1;
4339 			}
4340 		}
4341 		if (dx < 0) break; /* Both passes done */
4342 		r0 = dmap + w * h - 1; dx = -1; dy = -w; /* Backward pass */
4343 	}
4344 
4345 	/* Find largest */
4346 	r0 = dmap;
4347 	for (k = w * h; k; k-- , r0++) if (maxd < *r0) maxd = *r0;
4348 	return (maxd);
4349 }
4350 
4351 /* Meijster algorithm for squared Euclidean distance transform */
4352 
4353 typedef struct {
4354 	int x, e, v, w;
4355 } par_data;
4356 
dist_pass1(int w,int h,uint32_t * dmap)4357 static void dist_pass1(int w, int h, uint32_t *dmap)
4358 {
4359 	uint32_t m, *r0;
4360 	int i, j, dy;
4361 
4362 
4363 	/* Calculate distance by column */
4364 	r0 = dmap; dy = w; /* Forward pass */
4365 	while (TRUE)
4366 	{
4367 		/* First row */
4368 		for (i = 0; i < w; i++) if (r0[i]) r0[i] = 1;
4369 		/* Other rows */
4370 		for (j = 1; j < h; j++)
4371 		{
4372 			r0 += dy;
4373 			for (i = 0; i < w; i++)
4374 			{
4375 				m = r0[i - dy];
4376 				if (r0[i] > m) r0[i] = m + 1;
4377 			}
4378 		}
4379 		if (dy < 0) return; /* Both passes done */
4380 		dy = -dy; /* Backward pass */
4381 	}
4382 }
4383 
dist_pass2_e2(int w,int h,uint32_t * dmap,par_data * pb)4384 static int dist_pass2_e2(int w, int h, uint32_t *dmap, par_data *pb)
4385 {
4386 	par_data *pn;
4387 	int x, y, mx = 0;
4388 
4389 	for (y = 0; y < h; y++ , dmap += w)
4390 	{
4391 		/* Left border */
4392 		pn = pb;
4393 		pn->x = -1;
4394 		pn->e = pn->v = 0;
4395 		pn->w = 1; /* v + x^2 */
4396 		/* Find envelope */
4397 		for (x = 0; ; x++)
4398 		{
4399 			int k = 0, v2 = 0;
4400 
4401 			if (x < w) v2 = dmap[x] * dmap[x];
4402 			else if (x > w) break;
4403 
4404 			while (((x - pn->e) * (x - pn->e) + v2) < pn->w)
4405 				if (--pn - pb < 0) break;
4406 			if (pn - pb >= 0) /* Find intersection */
4407 			{
4408 				/* 1 + Sep(s[q], u) */
4409 				k = (x * x + v2 - pn->x * pn->x - pn->v) /
4410 					((x - pn->x) * 2) + 1;
4411 				if (k >= w) continue; // Not inside
4412 			}
4413 
4414 			/* Add a segment */
4415 			pn++;
4416 			pn->x = x;
4417 			pn->v = v2;
4418 			pn->e = k;
4419 			pn->w = (x - k) * (x - k) + v2;
4420 		}
4421 
4422 		/* Fill up squared distances */
4423 // !!! Also possible to run left to right, by using _next_ slot's "e"
4424 // (only then need one extra slot allocated, and set pn[1].e=w every time)
4425 // (but then, may loop to e, and only then check if this e >= w)
4426 		for (x = w - 1; x >= 0; x--)
4427 		{
4428 			int l = pn->v + (x - pn->x) * (x - pn->x);
4429 			if (mx < l) mx = l; // Finding the max
4430 			dmap[x] = l;
4431 			if (x == pn->e) pn--;
4432 		}
4433 	}
4434 
4435 	return (mx);
4436 }
4437 
4438 /* Euclidean (L2 metric) distance transform of binary image map */
shapeburst_m()4439 static int shapeburst_m()
4440 {
4441 	int maxd, w = sb_rect[2], h = sb_rect[3];
4442 
4443 	dist_pass1(w, h, sb_buf2);
4444 	maxd = dist_pass2_e2(w, h, sb_buf2, sb_mem);
4445 	return (ceil(sqrt(maxd)));
4446 }
4447 
init_sb()4448 int init_sb()
4449 {
4450 	int l = sb_rect[2] + 3, wh = sb_rect[2] * sb_rect[3];
4451 
4452 	if (sb_dist != DIST_L2) /* Use simple distance algorithm */
4453 		sb_mem = sb_buf = calloc(wh, sizeof(unsigned short));
4454 	/* Use squared Euclidean distance */
4455 	else if ((sb_mem = calloc(1, l * sizeof(par_data) + wh * sizeof(uint32_t))))
4456 	{
4457 		/* Pointer to uint32 array */
4458 		sb_buf2 = (void *)((par_data *)sb_mem + l);
4459 	}
4460 	if (!sb_mem)
4461 	{
4462 		memory_errors(1);
4463 		return (FALSE);
4464 	}
4465 	put_pixel = put_pixel_sb;
4466 	put_pixel_row = put_pixel_row_sb;
4467 	return (TRUE);
4468 }
4469 
4470 /* Mask, if present, must be sb_rect[] sized */
render_sb(unsigned char * mask)4471 void render_sb(unsigned char *mask)
4472 {
4473 	grad_info svgrad, *grad = gradient + mem_channel;
4474 	int i, maxd;
4475 
4476 	if (!sb_mem) return; /* Uninitialized */
4477 	put_pixel = put_pixel_def;
4478 	put_pixel_row = put_pixel_row_def;
4479 	maxd = sb_dist != DIST_L2 ? shapeburst() : shapeburst_m();
4480 	if (maxd) /* Have something to draw */
4481 	{
4482 		svgrad = *grad;
4483 		grad->gmode = GRAD_MODE_BURST;
4484 		if (!grad->len) grad->len = maxd - (maxd > 1);
4485 		grad_update(grad);
4486 
4487 		for (i = 0; i < sb_rect[3]; i++)
4488 			put_pixel_row(sb_rect[0], sb_rect[1] + i, sb_rect[2],
4489 				mask ? mask + sb_rect[2] * i : NULL);
4490 
4491 		*grad = svgrad;
4492 	}
4493 	free(sb_mem);
4494 	sb_buf2 = sb_mem = sb_buf = NULL;
4495 }
4496 
4497 /*
4498  * This flood fill algorithm processes image in quadtree order, and thus has
4499  * guaranteed upper bound on memory consumption, of order O(width + height).
4500  * This implementation takes O(max(width, height)) for simplicity - X and Y
4501  * bitmaps are interleaved.
4502  * (C) Dmitry Groshev
4503  */
4504 
4505 #define QLEVELS 11
4506 #define QMINSIZE 32
4507 #define QMINLEVEL 5
4508 
4509 /*
4510  * Level bitmaps are ordered from nearest to farthest, with cells interleaved
4511  * in the following order: Left-Y Right-Y Top-X Bottom-X.
4512  * Pixel bitmap is packed by Y, not by X: byte[x, y / 8] |= 1 << (y % 8)
4513  */
4514 
wjfloodfill(int x,int y,int col,unsigned char * bmap)4515 static int wjfloodfill(int x, int y, int col, unsigned char *bmap)
4516 {
4517 	short nearq[QMINSIZE * QMINSIZE * 2];
4518 	/* QMINSIZE bits per cell */
4519 	guint32 tmap, lmap[(MAX_DIM >> QMINLEVEL) * 12 + QLEVELS * 4], maps[4];
4520 	int borders[4] = {0, mem_width, 0, mem_height};
4521 	int corners[4], coords[4], slots[4];
4522 	int i, j, k, tx, ty, fmode = 0, imgc = 0, lastr[3], thisr[3];
4523 	int lmax, ntail, bidx = 0, bbit = 0;
4524 	double lastc[3], thisc[3], dist2, mdist2 = flood_step * flood_step;
4525 	csel_info *flood_data = NULL;
4526 	char *tmp = NULL;
4527 
4528 	/* Init */
4529 	if ((x < 0) || (x >= mem_width) || (y < 0) || (y >= mem_height) ||
4530 		(get_pixel(x, y) != col) || (pixel_protected(x, y) == 255))
4531 		return (FALSE);
4532 	/* Exact limits are less, but it's too complicated */
4533 	lmax = mem_width > mem_height ? mem_width : mem_height;
4534 	lmax = (lmax >> QMINLEVEL) * 12 + QLEVELS * 4;
4535 	memset(lmap, 0, lmax * sizeof(*lmap));
4536 
4537 	/* Start drawing */
4538 	if (bmap) bmap[(y >> 3) * mem_width + x] |= 1 << (y & 7);
4539 	else
4540 	{
4541 		put_pixel(x, y);
4542 		if (get_pixel(x, y) == col) return (FALSE); /* Can't draw */
4543 	}
4544 
4545 	/* Configure fuzzy flood fill */
4546 	if (flood_step && ((mem_channel == CHN_IMAGE) || flood_img))
4547 	{
4548 		if (flood_slide) fmode = flood_cube ? 2 : 3;
4549 		else flood_data = ALIGN(tmp = calloc(1, sizeof(csel_info) + sizeof(double)));
4550 		if (flood_data)
4551 		{
4552 			flood_data->center = get_pixel_RGB(x, y);
4553 			flood_data->range = flood_step;
4554 			flood_data->mode = flood_cube ? 2 : 0;
4555 /* !!! Alpha isn't tested yet !!! */
4556 			csel_reset(flood_data);
4557 			fmode = 1;
4558 		}
4559 	}
4560 	/* Configure by-image flood fill */
4561 	else if (!flood_step && flood_img && (mem_channel != CHN_IMAGE))
4562 	{
4563 		imgc = get_pixel_img(x, y);
4564 		fmode = -1;
4565 	}
4566 
4567 	/* Set up initial area */
4568 	corners[0] = x & ~(QMINSIZE - 1);
4569 	corners[2] = y & ~(QMINSIZE - 1);
4570 	nearq[0] = x; nearq[1] = y; ntail = 2;
4571 
4572 	while (1)
4573 	{
4574 		corners[1] = corners[0] + QMINSIZE;
4575 		corners[3] = corners[2] + QMINSIZE;
4576 
4577 		for (i = 0; i < 4; i++)
4578 		{
4579 			int j, k, i2 = (i >> 1) ^ 1;
4580 			int wx = corners[i2 + i2], wy = corners[i];
4581 
4582 			/* Locate map slots */
4583 			j = ((unsigned)(wy & ~(wy - 1)) - 1) >> QMINLEVEL; // Level mask
4584 			j += j; k = (wx >> QMINLEVEL) & (j + 1);
4585 			slots[i] = k = (j + k) * 4 + i;
4586 
4587 			/* Prefill near queue */
4588 			if (k >= lmax) continue; // Outside image
4589 			k ^= 1; tmap = lmap[k]; lmap[k] = 0;
4590 			for (wy -= i & 1; tmap; wx++ , tmap >>= 1)
4591 			{
4592 				if (!(tmap & 1)) continue;
4593 				nearq[ntail++ + i2] = wx;
4594 				nearq[ntail++ - i2] = wy;
4595 			}
4596 		}
4597 
4598 		/* Clear the side bitmaps */
4599 		maps[0] = maps[1] = maps[2] = maps[3] = 0;
4600 //		memset(maps, 0, sizeof(maps));
4601 
4602 		/* Process near points */
4603 		while (ntail)
4604 		{
4605 			/* Unqueue last x & y */
4606 			coords[2] = y = nearq[--ntail];
4607 			coords[0] = x = nearq[--ntail];
4608 			if (fmode > 1)
4609 			{
4610 				k = get_pixel_RGB(x, y);
4611 				if (fmode == 3) get_lxn(lastc, k);
4612 				else
4613 				{
4614 					lastr[0] = INT_2_R(k);
4615 					lastr[1] = INT_2_G(k);
4616 					lastr[2] = INT_2_B(k);
4617 				}
4618 			}
4619 			for (i = 0; i < 4; i++)
4620 			{
4621 				coords[1] = x;
4622 				coords[3] = y;
4623 				coords[(i & 2) + 1] += ((i + i) & 2) - 1;
4624 				/* Is pixel valid? */
4625 				if (coords[i] == borders[i]) continue;
4626 				tx = coords[1];
4627 				ty = coords[3];
4628 				if (bmap)
4629 				{
4630 					bidx = (ty >> 3) * mem_width + tx;
4631 					bbit = 1 << (ty & 7);
4632 					if (bmap[bidx] & bbit) continue;
4633 				}
4634 				/* Sliding mode */
4635 				switch (fmode)
4636 				{
4637 				case 3: /* Sliding L*X*N* */
4638 					get_lxn(thisc, get_pixel_RGB(tx, ty));
4639 					dist2 = (thisc[0] - lastc[0]) * (thisc[0] - lastc[0]) +
4640 						(thisc[1] - lastc[1]) * (thisc[1] - lastc[1]) +
4641 						(thisc[2] - lastc[2]) * (thisc[2] - lastc[2]);
4642 					if (dist2 > mdist2) continue;
4643 					break;
4644 				case 2: /* Sliding RGB */
4645 					k = get_pixel_RGB(tx, ty);
4646 					thisr[0] = INT_2_R(k);
4647 					thisr[1] = INT_2_G(k);
4648 					thisr[2] = INT_2_B(k);
4649 					if ((abs(thisr[0] - lastr[0]) > flood_step) ||
4650 						(abs(thisr[1] - lastr[1]) > flood_step) ||
4651 						(abs(thisr[2] - lastr[2]) > flood_step))
4652 						continue;
4653 					break;
4654 				case 1: /* Centered mode */
4655 					if (!csel_scan(ty * mem_width + tx, 1, 1,
4656 						NULL, mem_img[CHN_IMAGE], flood_data))
4657 						continue;
4658 					break;
4659 				case 0: /* Normal mode */
4660 					if (get_pixel(tx, ty) != col) continue;
4661 					break;
4662 				default: /* (-1) - By-image mode */
4663 					if (get_pixel_img(tx, ty) != imgc) continue;
4664 					break;
4665 				}
4666 				/* Is pixel writable? */
4667 				if (bmap)
4668 				{
4669 					if (pixel_protected(tx, ty) == 255)
4670 						continue;
4671 					bmap[bidx] |= bbit;
4672 				}
4673 				else
4674 				{
4675 					put_pixel(tx, ty);
4676 					if (get_pixel(tx, ty) == col) continue;
4677 				}
4678 				/* Near queue */
4679 //				if (coords[i] != corners[i])
4680 				if (coords[i] & (QMINSIZE - 1))
4681 				{
4682 					nearq[ntail++] = tx;
4683 					nearq[ntail++] = ty;
4684 					continue;
4685 				}
4686 				/* Far map */
4687 				j = coords[(i & 2) ^ 3] & (QMINSIZE - 1);
4688 				maps[i] |= 1U << j;
4689 			}
4690 		}
4691 
4692 		/* Store maps */
4693 		for (i = 0; i < 4; i++)
4694 		{
4695 			/* !!! Condition prevents out-of-bounds access */
4696 			if (maps[i]) lmap[slots[i]] |= maps[i];
4697 		}
4698 
4699 		/* Find what else remains */
4700 		for (i = 0; (i < lmax) && !lmap[i]; i++);
4701 		if (i >= lmax) break; // All done
4702 
4703 		/* Determine where that happens to be */
4704 		j = ((i >> 2) + 2) << QMINLEVEL;
4705 		k = nextpow2(j) >> 1; // MSB
4706 		x = (k >> 1) + ((i & 1) << QMINLEVEL) - QMINSIZE;
4707 		y = j - k;
4708 		i &= 2;
4709 		corners[i] = (corners[i] & ~(k - 1)) + x;
4710 		i ^= 2;
4711 		corners[i] = (corners[i] & ~(k - 1)) + y;
4712 	}
4713 	free(tmp);
4714 	return (TRUE);
4715 }
4716 
4717 /* Determine Y-packed bitmap boundaries */
bitmap_bounds(int * rect,unsigned char * pat)4718 static int bitmap_bounds(int *rect, unsigned char *pat)
4719 {
4720 	unsigned char u, c, buf[MAX_WIDTH];
4721 	int n, x, y, y0, y1, w = rect[2], h = (rect[3] + 7) >> 3;
4722 
4723 
4724 	/* Scan */
4725 	memset(buf, 0, w);
4726 	for (y0 = y1 = y = 0; y < h; y++)
4727 	{
4728 		for (u = x = 0; x < w; x++)
4729 			u |= c = *pat++ , buf[x] |= c;
4730 		if (!u) continue;
4731 		y1 = (y << 8) + u;
4732 		if (!y0) y0 = y1;
4733 	}
4734 	if (!y0) return (0); // Empty
4735 
4736 	/* Analyze */
4737 	for (y = (y0 >> 8) * 8; !(y0 & 1); y++ , y0 >>= 1);
4738 	rect[1] += n = y;
4739 	for (y = (y1 >> 8) * 8 + 7; !(y1 & 0x80); y-- , y1 <<= 1);
4740 	rect[3] = y -= n - 1; // h
4741 	for (x = 0; !buf[x]; x++);
4742 	rect[0] += n = x;
4743 	for (x = w - 1; !buf[x]; x--);
4744 	rect[2] = x -= n - 1; // w
4745 
4746 	return (x * y);
4747 }
4748 
4749 /* Try drawing on a pixel */
try_pixel(int x,int y)4750 int try_pixel(int x, int y)
4751 {
4752 	unsigned char uninit_(ab), ib[3], *img, *uninit_(alpha);
4753 	int res, bpp = MEM_BPP, ofs = x + mem_width * y, op = mem_undo_opacity;
4754 
4755 	img = mem_img[mem_channel] + ofs * bpp;
4756 	memcpy(ib, img, bpp);
4757 	if (mem_img[CHN_ALPHA]) ab = *(alpha = mem_img[CHN_ALPHA] + ofs);
4758 
4759 	mem_undo_opacity = FALSE; // No prepared undo frame
4760 	put_pixel_def(x, y);
4761 	mem_undo_opacity = op;
4762 
4763 	res = memcmp(ib, img, bpp);
4764 	memcpy(img, ib, bpp);
4765 	if (mem_img[CHN_ALPHA])
4766 	{
4767 		res |= *alpha ^ ab;
4768 		*alpha = ab;
4769 	}
4770 	return (res);
4771 }
4772 
4773 /* Flood fill - may use temporary area (1 bit per pixel) */
flood_fill(int x,int y,unsigned int target)4774 int flood_fill(int x, int y, unsigned int target)
4775 {
4776 	unsigned char *pat, *buf, *temp;
4777 	int i, j, l, sb, res = FALSE;
4778 
4779 	/* Regular fill? */
4780 	if (!mem_gradient && !(mem_blend && blend_src) && !mem_tool_pat &&
4781 		!flood_step && (!flood_img || (mem_channel == CHN_IMAGE)))
4782 	{
4783 		/* Try modifying the first pixel */
4784 		if (!try_pixel(x, y)) return (FALSE);
4785 		spot_undo(UNDO_TOOL);
4786 		return (wjfloodfill(x, y, target, NULL));
4787 	}
4788 
4789 	/* Patterned or fuzzy fill - use bitmap */
4790 	buf = calloc((mem_height + 7 + 8) >> 3, mem_width);
4791 	if (!buf)
4792 	{
4793 		memory_errors(1);
4794 		return (FALSE);
4795 	}
4796 	pat = buf + mem_width;
4797 	while (wjfloodfill(x, y, target, pat))
4798 	{
4799 		/* Shapeburst - setup rendering backbuffer */
4800 		sb = STROKE_GRADIENT;
4801 		if (sb)
4802 		{
4803 			sb_rect[0] = sb_rect[1] = 0;
4804 			sb_rect[2] = mem_width;
4805 			sb_rect[3] = mem_height;
4806 			l = bitmap_bounds(sb_rect, pat);
4807 			if (!l) break; /* Nothing to draw */
4808 			if (!init_sb()) break; /* Not enough memory */
4809 		}
4810 
4811 		res = TRUE;
4812 		spot_undo(UNDO_TOOL);
4813 		for (i = 0; i < mem_height; i++)
4814 		{
4815 			unsigned u, f = 1 << (i & 7);
4816 
4817 			temp = pat + (i >> 3) * mem_width;
4818 			for (u = j = 0; j < mem_width; j++)
4819 				u |= buf[j] = (0x10000 - (temp[j] & f)) >> 8;
4820 			if (!u) continue; // Avoid wasting time on empty rows
4821 			put_pixel_row(0, i, mem_width, buf);
4822 		}
4823 
4824 		if (sb) render_sb(NULL); /* Finalize */
4825 
4826 		break;
4827 	}
4828 	free(buf);
4829 	return (res);
4830 }
4831 
4832 
f_rectangle(int x,int y,int w,int h)4833 void f_rectangle(int x, int y, int w, int h)	// Draw a filled rectangle
4834 {
4835 	w += x; h += y;
4836 	if (x < 0) x = 0;
4837 	if (y < 0) y = 0;
4838 	if (w > mem_width) w = mem_width;
4839 	if (h > mem_height) h = mem_height;
4840 	w -= x;
4841 
4842 	/* !!! Test is oversimplified and is overkill, see rec_continuous() */
4843 	if ((tool_type == TOOL_CLONE) && (clone_dy < 0))
4844 	{
4845 		while (--h >= y) put_pixel_row(x, h, w, NULL);
4846 		return;
4847 	}
4848 
4849 	for (; y < h; y++) put_pixel_row(x, y, w, NULL);
4850 }
4851 
4852 /*
4853  * This code uses midpoint ellipse algorithm modified for uncentered ellipses,
4854  * with floating-point arithmetics to prevent overflows. (C) Dmitry Groshev
4855  */
trace_ellipse(int w,int h,int * left,int * right)4856 static void trace_ellipse(int w, int h, int *left, int *right)
4857 {
4858 	int dx, dy;
4859 	double err, stx, sty, w2, h2;
4860 
4861 	if (left[0] > w) left[0] = w;
4862 	if (right[0] < w) right[0] = w;
4863 
4864 	if (h <= 1) return; /* Too small */
4865 
4866 	h2 = h * h;
4867 	w2 = w * w;
4868 	dx = w & 1;
4869 	dy = h;
4870 	stx = h2 * dx;
4871 	sty = w2 * dy;
4872 	err = h2 * (dx * 5 + 4) + w2 * (1 - h - h);
4873 
4874 	while (1) /* Have to force first step */
4875 	{
4876 		if (left[dy >> 1] > dx) left[dy >> 1] = dx;
4877 		if (right[dy >> 1] < dx) right[dy >> 1] = dx;
4878 		if (err >= 0.0)
4879 		{
4880 			dy -= 2;
4881 			sty -= w2 + w2;
4882 			err -= 4.0 * sty;
4883 		}
4884 		dx += 2;
4885 		stx += h2 + h2;
4886 		err += 4.0 * (h2 + stx);
4887 		if ((dy < 2) || (stx >= sty)) break;
4888 	}
4889 
4890 	err += 3.0 * (w2 - h2) - 2.0 * (stx + sty);
4891 
4892 	while (dy > 1)
4893 	{
4894 		if (left[dy >> 1] > dx) left[dy >> 1] = dx;
4895 		if (right[dy >> 1] < dx) right[dy >> 1] = dx;
4896 		if (err < 0.0)
4897 		{
4898 			dx += 2;
4899 			stx += h2 + h2;
4900 			err += 4.0 * stx;
4901 		}
4902 		dy -= 2;
4903 		sty -= w2 + w2;
4904 		err += 4.0 * (w2 - sty);
4905 	}
4906 
4907 	/* For too-flat ellipses */
4908 	if (left[1] > dx) left[1] = dx;
4909 	if (right[1] < w - 2) right[1] = w - 2;
4910 }
4911 
wjellipse(int xs,int ys,int w,int h,int type,int thick)4912 static void wjellipse(int xs, int ys, int w, int h, int type, int thick)
4913 {
4914 	int i, j, k, dx0, dx1, dy, *left, *right;
4915 
4916 	/* Prepare */
4917 	ys += ys + --h;
4918 	xs += xs + --w;
4919 	k = type ? w + 1 : w & 1;
4920 	j = h / 2 + 1;
4921 	left = malloc(2 * j * sizeof(int));
4922 	if (!left) return;
4923 	right = left + j;
4924 	for (i = 0; i < j; i++)
4925 	{
4926 		left[i] = k;
4927 		right[i] = 0;
4928 	}
4929 
4930 	/* Plot outer */
4931 	trace_ellipse(w, h, left, right);
4932 
4933 	/* Plot inner */
4934 	if (type && (thick > 1))
4935 	{
4936 		int i, j, k;
4937 
4938 		/* Determine possible height */
4939 		thick += thick - 2;
4940 		for (i = h; i >= 0; i -= 2)
4941 		{
4942 			if (left[i >> 1] > thick + 1) break;
4943 		}
4944 		i = i >= h - thick ? h - thick : i + 2;
4945 
4946 		/* Determine possible width */
4947 		j = left[thick >> 1];
4948 		if (j > w - thick) j = w - thick;
4949 		if (j < 2) i = h & 1;
4950 
4951 		/* Do the plotting */
4952 		for (k = i >> 1; k <= h >> 1; k++) left[k] = w & 1;
4953 		if (i > 1) trace_ellipse(j, i, left, right);
4954 	}
4955 
4956 	/* Draw result */
4957 	for (dy = h & 1; dy <= h; dy += 2)
4958 	{
4959 		int y0 = ys - dy, y1 = ys + dy;
4960 
4961 		if (y1 < 0) continue;
4962 		if (y0 < 0) y0 = y1;
4963 		y0 >>= 1; y1 >>= 1;
4964 		if (y0 >= mem_height) continue;
4965 
4966 		dx0 = right[dy >> 1];
4967 		dx1 = left[dy >> 1];
4968 		if (dx1 <= 1) dx1 = -dx0; // Merge two spans
4969 		while (TRUE)
4970 		{
4971 			int x0 = xs - dx0, x1 = xs - dx1;
4972 
4973 			if ((x1 >= 0) && (x0 < mem_width * 2))
4974 			{
4975 				x0 >>= 1; x1 >>= 1;
4976 				if (x0 < 0) x0 = 0;
4977 				if (++x1 > mem_width) x1 = mem_width;
4978 				x1 -= x0;
4979 				put_pixel_row(x0, y0, x1, NULL);
4980 				if (y1 != y0) put_pixel_row(x0, y1, x1, NULL);
4981 			}
4982 			if (dx1 <= 0) break;
4983 			x1 = -dx0; dx0 = -dx1; dx1 = x1;
4984 		}
4985 	}
4986 
4987 	free(left);
4988 }
4989 
4990 /* Thickness 0 means filled */
mem_ellipse(int x1,int y1,int x2,int y2,int thick)4991 void mem_ellipse(int x1, int y1, int x2, int y2, int thick)
4992 {
4993 	int xs, ys, xl, yl, sb = FALSE;
4994 
4995 	xs = x1 < x2 ? x1 : x2;
4996 	ys = y1 < y2 ? y1 : y2;
4997 	xl = abs(x2 - x1) + 1;
4998 	yl = abs(y2 - y1) + 1;
4999 
5000 	/* Shapeburst mode */
5001 	if (STROKE_GRADIENT)
5002 	{
5003 		sb_rect[0] = xs; sb_rect[1] = ys;
5004 		sb_rect[2] = xl; sb_rect[3] = yl;
5005 		sb = init_sb();
5006 	}
5007 
5008 	/* Draw rectangle instead if too small */
5009 	if ((xl <= 2) || (yl <= 2)) f_rectangle(xs, ys, xl, yl);
5010 	else wjellipse(xs, ys, xl, yl, thick && (thick * 2 < xl) &&
5011 		(thick * 2 < yl), thick);
5012 
5013 	if (sb) render_sb(NULL);
5014 }
5015 
5016 static int circ_r, circ_trace[128];
5017 
retrace_circle(int r)5018 static void retrace_circle(int r)
5019 {
5020 	int sz, left[128];
5021 
5022 	circ_r = r--;
5023 	sz = ((r >> 1) + 1) * sizeof(int);
5024 	memset(left, 0, sz);
5025 	memset(circ_trace, 0, sz);
5026 	trace_ellipse(r, r, left, circ_trace);
5027 }
5028 
f_circle(int x,int y,int r)5029 void f_circle( int x, int y, int r )				// Draw a filled circle
5030 {
5031 	int i, x0, x1, y0, y1, r1 = r - 1, half = r1 & 1;
5032 
5033 	/* Prepare & cache circle contour */
5034 	if (circ_r != r) retrace_circle(r);
5035 
5036 	/* Draw result */
5037 	for (i = half; i <= r1; i += 2)
5038 	{
5039 		y0 = y - ((i + half) >> 1);
5040 		y1 = y + ((i - half) >> 1);
5041 		if ((y0 >= mem_height) || (y1 < 0)) continue;
5042 
5043 		x0 = x - ((circ_trace[i >> 1] + half) >> 1);
5044 		x1 = x + ((circ_trace[i >> 1] - half) >> 1) + 1;
5045 		if (x0 < 0) x0 = 0;
5046 		if (x1 > mem_width) x1 = mem_width;
5047 		x1 -= x0;
5048 		if (y0 >= 0) put_pixel_row(x0, y0, x1, NULL);
5049 		if ((y1 != y0) && (y1 < mem_height)) put_pixel_row(x0, y1, x1, NULL);
5050 	}
5051 }
5052 
find_tangent(int dx,int dy)5053 static int find_tangent(int dx, int dy)
5054 {
5055 	int i, j = 0, yy = (circ_r + 1) & 1, d, dist = 0;
5056 
5057 	dx = abs(dx); dy = abs(dy);
5058 	for (i = 0; i < (circ_r + 1) >> 1; i++)
5059 	{
5060 		d = (i + i + yy) * dy + circ_trace[i] * dx;
5061 		if (d < dist) continue;
5062 		dist = d;
5063 		j = i;
5064 	}
5065 	return (j);
5066 }
5067 
5068 /* Draw line as if traced by circle brush */
circle_line(int x0,int y0,int dx,int dy,int thick)5069 void circle_line(int x0, int y0, int dx, int dy, int thick)
5070 {
5071 	int n, ix, iy, xx[2], yy[2], dt = (thick + 1) & 1;
5072 
5073 	if (circ_r != thick) retrace_circle(thick);
5074 	n = find_tangent(dx, dy);
5075 	ix = dx >= 0 ? 0 : 1;
5076 	iy = dy >= 0 ? 0 : 1;
5077 	xx[ix] = x0 - n - dt;
5078 	xx[ix ^ 1] = x0 + n;
5079 	yy[iy] = y0 + ((circ_trace[n] - dt) >> 1);
5080 	yy[iy ^ 1] = y0 - ((circ_trace[n] + dt) >> 1);
5081 
5082 	g_para(xx[0], yy[0], xx[1], yy[1], dx, dy);
5083 }
5084 
mem_flip_v(char * mem,char * tmp,int w,int h,int bpp)5085 void mem_flip_v(char *mem, char *tmp, int w, int h, int bpp)
5086 {
5087 	unsigned char *src, *dest;
5088 	int i, k;
5089 
5090 	k = w * bpp;
5091 	src = mem;
5092 	dest = mem + (h - 1) * k;
5093 	h /= 2;
5094 
5095 	for (i = 0; i < h; i++)
5096 	{
5097 		memcpy(tmp, src, k);
5098 		memcpy(src, dest, k);
5099 		memcpy(dest, tmp, k);
5100 		src += k;
5101 		dest -= k;
5102 	}
5103 }
5104 
mem_flip_h(char * mem,int w,int h,int bpp)5105 void mem_flip_h( char *mem, int w, int h, int bpp )
5106 {
5107 	unsigned char tmp, *src, *dest;
5108 	int i, j, k;
5109 
5110 	k = w * bpp;
5111 	w /= 2;
5112 	for (i = 0; i < h; i++)
5113 	{
5114 		src = mem + i * k;
5115 		dest = src + k - bpp;
5116 		if (bpp == 1)
5117 		{
5118 			for (j = 0; j < w; j++)
5119 			{
5120 				tmp = *src;
5121 				*src++ = *dest;
5122 				*dest-- = tmp;
5123 			}
5124 		}
5125 		else
5126 		{
5127 			for (j = 0; j < w; j++)
5128 			{
5129 				tmp = src[0];
5130 				src[0] = dest[0];
5131 				dest[0] = tmp;
5132 				tmp = src[1];
5133 				src[1] = dest[1];
5134 				dest[1] = tmp;
5135 				tmp = src[2];
5136 				src[2] = dest[2];
5137 				dest[2] = tmp;
5138 				src += 3;
5139 				dest -= 3;
5140 			}
5141 		}
5142 	}
5143 }
5144 
mem_bacteria(int val)5145 void mem_bacteria( int val )			// Apply bacteria effect val times the canvas area
5146 {						// Ode to 1994 and my Acorn A3000
5147 	int i, j, x, y, w = mem_width-2, h = mem_height-2, tot = w*h, np, cancel;
5148 	unsigned int pixy;
5149 	unsigned char *img;
5150 
5151 	while ( tot > PROGRESS_LIM )	// Ensure the user gets a regular opportunity to cancel
5152 	{
5153 		tot /= 2;
5154 		val *= 2;
5155 	}
5156 
5157 	cancel = (w * h * val > PROGRESS_LIM);
5158 	if (cancel) progress_init(_("Bacteria Effect"), 1);
5159 
5160 	for ( i=0; i<val; i++ )
5161 	{
5162 		if (cancel && ((i * 20) % val >= val - 20))
5163 			if (progress_update((float)i / val)) break;
5164 
5165 		for ( j=0; j<tot; j++ )
5166 		{
5167 			x = rand() % w;
5168 			y = rand() % h;
5169 			img = mem_img[CHN_IMAGE] + x + mem_width * y;
5170 			pixy = img[0] + img[1] + img[2];
5171 			img += mem_width;
5172 			pixy += img[0] + img[1] + img[2];
5173 			img += mem_width;
5174 			pixy += img[0] + img[1] + img[2];
5175 			np = ((pixy + pixy + 9) / 18 + 1) % mem_cols;
5176 			*(img - mem_width + 1) = (unsigned char)np;
5177 		}
5178 	}
5179 	if (cancel) progress_end();
5180 }
5181 
mem_rotate(char * new,char * old,int old_w,int old_h,int dir,int bpp)5182 void mem_rotate( char *new, char *old, int old_w, int old_h, int dir, int bpp )
5183 {
5184 	unsigned char *src;
5185 	int i, j, k, l, flag;
5186 
5187 	flag = (old_w * old_h > PROGRESS_LIM * 4);
5188 	j = old_w * bpp;
5189 	l = dir ? -bpp : bpp;
5190 	k = -old_w * l;
5191 	old += dir ? j - bpp: (old_h - 1) * j;
5192 
5193 	if (flag) progress_init(_("Rotating"), 1);
5194 	for (i = 0; i < old_w; i++)
5195 	{
5196 		if (flag && ((i * 5) % old_w >= old_w - 5))
5197 				progress_update((float)i / old_w);
5198 		src = old;
5199 		if (bpp == 1)
5200 		{
5201 			for (j = 0; j < old_h; j++)
5202 			{
5203 				*new++ = *src;
5204 				src += k;
5205 			}
5206 		}
5207 		else
5208 		{
5209 			for (j = 0; j < old_h; j++)
5210 			{
5211 				*new++ = src[0];
5212 				*new++ = src[1];
5213 				*new++ = src[2];
5214 				src += k;
5215 			}
5216 		}
5217 		old += l;
5218 	}
5219 	if (flag) progress_end();
5220 }
5221 
mem_sel_rot(int dir)5222 int mem_sel_rot( int dir )			// Rotate clipboard 90 degrees
5223 {
5224 	unsigned char *buf = NULL;
5225 	int i, j = mem_clip_w * mem_clip_h, bpp = mem_clip_bpp;
5226 
5227 	for (i = 0; i < NUM_CHANNELS; i++ , bpp = 1)
5228 	{
5229 		if (!mem_clip.img[i]) continue;
5230 		buf = malloc(j * bpp);
5231 		if (!buf) break;	// Not enough memory
5232 		mem_rotate(buf, mem_clip.img[i], mem_clip_w, mem_clip_h, dir, bpp);
5233 		free(mem_clip.img[i]);
5234 		mem_clip.img[i] = buf;
5235 	}
5236 
5237 	/* Don't leave a mix of rotated and unrotated channels */
5238 	if (!buf && i) mem_free_image(&mem_clip, FREE_ALL);
5239 	if (!buf) return (1);
5240 
5241 	i = mem_clip_w;
5242 	mem_clip_w = mem_clip_h;		// Flip geometry
5243 	mem_clip_h = i;
5244 
5245 	return (0);
5246 }
5247 
5248 /* Clear the channels */
mem_clear_img(chanlist img,int w,int h,int bpp)5249 static void mem_clear_img(chanlist img, int w, int h, int bpp)
5250 {
5251 	int i, j, k, l = w * h;
5252 
5253 	if (!img[CHN_IMAGE]); // !!! Here, image channel CAN be absent
5254 	else if (bpp == 3)
5255 	{
5256 		unsigned char *tmp = img[CHN_IMAGE];
5257 		tmp[0] = mem_col_A24.red;
5258 		tmp[1] = mem_col_A24.green;
5259 		tmp[2] = mem_col_A24.blue;
5260 		j = l * 3;
5261 		for (i = 3; i < j; i++) tmp[i] = tmp[i - 3];
5262 	}
5263 	else memset(img[CHN_IMAGE], mem_col_A, l);
5264 
5265 	for (k = CHN_IMAGE + 1; k < NUM_CHANNELS; k++)
5266 		if (img[k]) memset(img[k], 0, l);
5267 }
5268 
mem_rotate_free_real(chanlist old_img,chanlist new_img,int ow,int oh,int nw,int nh,int bpp,double angle,int mode,int gcor,int dis_a,int silent)5269 void mem_rotate_free_real(chanlist old_img, chanlist new_img, int ow, int oh,
5270 	int nw, int nh, int bpp, double angle, int mode, int gcor, int dis_a,
5271 	int silent)
5272 {
5273 	unsigned char *src, *dest, *alpha, A_rgb[3];
5274 	unsigned char *pix1, *pix2, *pix3, *pix4;
5275 	int nx, ny, ox, oy, cc;
5276 	double rangle = (M_PI / 180.0) * angle;	// Radians
5277 	double s1, s2, c1, c2;			// Trig values
5278 	double cx0, cy0, cx1, cy1;
5279 	double x00, y00, x0y, y0y;		// Quick look up values
5280 	double fox, foy, k1, k2, k3, k4;	// Pixel weights
5281 	double aa1, aa2, aa3, aa4, aa;
5282 	double rr, gg, bb;
5283 	double tw, th, ta, ca, sa, sca, csa, Y00, Y0h, Yw0, Ywh, X00, Xwh;
5284 
5285 	c2 = cos(rangle);
5286 	s2 = sin(rangle);
5287 	c1 = -s2;
5288 	s1 = c2;
5289 
5290 	/* Centerpoints, including half-pixel offsets */
5291 	cx0 = (ow - 1) / 2.0;
5292 	cy0 = (oh - 1) / 2.0;
5293 	cx1 = (nw - 1) / 2.0;
5294 	cy1 = (nh - 1) / 2.0;
5295 
5296 	x00 = cx0 - cx1 * s1 - cy1 * s2;
5297 	y00 = cy0 - cx1 * c1 - cy1 * c2;
5298 	A_rgb[0] = mem_col_A24.red;
5299 	A_rgb[1] = mem_col_A24.green;
5300 	A_rgb[2] = mem_col_A24.blue;
5301 
5302 	/* Prepare clipping rectangle */
5303 	tw = 0.5 * (ow + (mode ? 1 : 0));
5304 	th = 0.5 * (oh + (mode ? 1 : 0));
5305 	ta = M_PI * (angle / 180.0 - floor(angle / 180.0));
5306 	ca = cos(ta); sa = sin(ta);
5307 	sca = ca ? sa / ca : 0.0;
5308 	csa = sa ? ca / sa : 0.0;
5309 	Y00 = cy1 - th * ca - tw * sa;
5310 	Y0h = cy1 + th * ca - tw * sa;
5311 	Yw0 = cy1 - th * ca + tw * sa;
5312 	Ywh = cy1 + th * ca + tw * sa;
5313 	X00 = cx1 - tw * ca + th * sa;
5314 	Xwh = cx1 + tw * ca - th * sa;
5315 
5316 	mem_clear_img(new_img, nw, nh, bpp); /* Clear the channels */
5317 
5318 	for (ny = 0; ny < nh; ny++)
5319 	{
5320 		int xl, xm;
5321 		if (!silent && ((ny * 10) % nh >= nh - 10))
5322 			progress_update((float)ny / nh);
5323 
5324 		/* Clip this row */
5325 		if (ny < Y0h) xl = ceil(X00 + (Y00 - ny) * sca);
5326 		else if (ny < Ywh) xl = ceil(Xwh + (ny - Ywh) * csa);
5327 		else /* if (ny < Yw0) */ xl = ceil(Xwh + (Ywh - ny) * sca);
5328 		if (ny < Y00) xm = ceil(X00 + (Y00 - ny) * sca);
5329 		else if (ny < Yw0) xm = ceil(X00 + (ny - Y00) * csa);
5330 		else /* if (ny < Ywh) */ xm = ceil(Xwh + (Ywh - ny) * sca);
5331 		if (xl < 0) xl = 0;
5332 		if (--xm >= nw) xm = nw - 1;
5333 
5334 		x0y = ny * s2 + x00;
5335 		y0y = ny * c2 + y00;
5336 		for (cc = 0; cc < NUM_CHANNELS; cc++)
5337 		{
5338 			if (!new_img[cc]) continue;
5339 			/* RGB nearest neighbour */
5340 			if (!mode && (cc == CHN_IMAGE) && (bpp == 3))
5341 			{
5342 				dest = new_img[CHN_IMAGE] + (ny * nw + xl) * 3;
5343 				for (nx = xl; nx <= xm; nx++ , dest += 3)
5344 				{
5345 					WJ_ROUND(ox, nx * s1 + x0y);
5346 					WJ_ROUND(oy, nx * c1 + y0y);
5347 					src = old_img[CHN_IMAGE] +
5348 						(oy * ow + ox) * 3;
5349 					dest[0] = src[0];
5350 					dest[1] = src[1];
5351 					dest[2] = src[2];
5352 				}
5353 				continue;
5354 			}
5355 			/* One-bpp nearest neighbour */
5356 			if (!mode)
5357 			{
5358 				dest = new_img[cc] + ny * nw + xl;
5359 				for (nx = xl; nx <= xm; nx++)
5360 				{
5361 					WJ_ROUND(ox, nx * s1 + x0y);
5362 					WJ_ROUND(oy, nx * c1 + y0y);
5363 					*dest++ = old_img[cc][oy * ow + ox];
5364 				}
5365 				continue;
5366 			}
5367 			/* RGB/RGBA bilinear */
5368 			if (cc == CHN_IMAGE)
5369 			{
5370 				alpha = NULL;
5371 				if (new_img[CHN_ALPHA] && !dis_a)
5372 					alpha = new_img[CHN_ALPHA] + ny * nw + xl;
5373 				dest = new_img[CHN_IMAGE] + (ny * nw + xl) * 3;
5374 				for (nx = xl; nx <= xm; nx++ , dest += 3)
5375 				{
5376 					fox = nx * s1 + x0y;
5377 					foy = nx * c1 + y0y;
5378 					/* floor() is *SLOW* on Win32 - avoiding... */
5379 					ox = (int)(fox + 2.0) - 2;
5380 					oy = (int)(foy + 2.0) - 2;
5381 					fox -= ox;
5382 					foy -= oy;
5383 					k4 = fox * foy;
5384 					k3 = foy - k4;
5385 					k2 = fox - k4;
5386 					k1 = 1.0 - fox - foy + k4;
5387 					pix1 = old_img[CHN_IMAGE] + (oy * ow + ox) * 3;
5388 					pix2 = pix1 + 3;
5389 					pix3 = pix1 + ow * 3;
5390 					pix4 = pix3 + 3;
5391 					if (ox > ow - 2) pix2 = pix4 = A_rgb;
5392 					else if (ox < 0) pix1 = pix3 = A_rgb;
5393 					if (oy > oh - 2) pix3 = pix4 = A_rgb;
5394 					else if (oy < 0) pix1 = pix2 = A_rgb;
5395 					if (alpha)
5396 					{
5397 						aa1 = aa2 = aa3 = aa4 = 0.0;
5398 						src = old_img[CHN_ALPHA] + oy * ow + ox;
5399 						if (pix1 != A_rgb) aa1 = src[0] * k1;
5400 						if (pix2 != A_rgb) aa2 = src[1] * k2;
5401 						if (pix3 != A_rgb) aa3 = src[ow] * k3;
5402 						if (pix4 != A_rgb) aa4 = src[ow + 1] * k4;
5403 						aa = aa1 + aa2 + aa3 + aa4;
5404 						if ((*alpha++ = rint(aa)))
5405 						{
5406 							aa = 1.0 / aa;
5407 							k1 = aa1 * aa;
5408 							k2 = aa2 * aa;
5409 							k3 = aa3 * aa;
5410 							k4 = aa4 * aa;
5411 						}
5412 					}
5413 					if (gcor) /* Gamma-correct */
5414 					{
5415 						rr = gamma256[pix1[0]] * k1 +
5416 							gamma256[pix2[0]] * k2 +
5417 							gamma256[pix3[0]] * k3 +
5418 							gamma256[pix4[0]] * k4;
5419 						gg = gamma256[pix1[1]] * k1 +
5420 							gamma256[pix2[1]] * k2 +
5421 							gamma256[pix3[1]] * k3 +
5422 							gamma256[pix4[1]] * k4;
5423 						bb = gamma256[pix1[2]] * k1 +
5424 							gamma256[pix2[2]] * k2 +
5425 							gamma256[pix3[2]] * k3 +
5426 							gamma256[pix4[2]] * k4;
5427 						dest[0] = UNGAMMA256(rr);
5428 						dest[1] = UNGAMMA256(gg);
5429 						dest[2] = UNGAMMA256(bb);
5430 					}
5431 					else /* Leave as is */
5432 					{
5433 						rr = pix1[0] * k1 + pix2[0] * k2 +
5434 							pix3[0] * k3 + pix4[0] * k4;
5435 						gg = pix1[1] * k1 + pix2[1] * k2 +
5436 							pix3[1] * k3 + pix4[1] * k4;
5437 						bb = pix1[2] * k1 + pix2[2] * k2 +
5438 							pix3[2] * k3 + pix4[2] * k4;
5439 						dest[0] = rint(rr);
5440 						dest[1] = rint(gg);
5441 						dest[2] = rint(bb);
5442 					}
5443 				}
5444 				continue;
5445 			}
5446 			/* Alpha channel already done... maybe */
5447 			if ((cc == CHN_ALPHA) && !dis_a)
5448 				continue;
5449 			/* Utility channel bilinear */
5450 			dest = new_img[cc] + ny * nw + xl;
5451 			for (nx = xl; nx <= xm; nx++)
5452 			{
5453 				fox = nx * s1 + x0y;
5454 				foy = nx * c1 + y0y;
5455 				/* floor() is *SLOW* on Win32 - avoiding... */
5456 				ox = (int)(fox + 2.0) - 2;
5457 				oy = (int)(foy + 2.0) - 2;
5458 				fox -= ox;
5459 				foy -= oy;
5460 				k4 = fox * foy;
5461 				k3 = foy - k4;
5462 				k2 = fox - k4;
5463 				k1 = 1.0 - fox - foy + k4;
5464 				src = old_img[cc] + oy * ow + ox;
5465 				aa1 = aa2 = aa3 = aa4 = 0.0;
5466 				if (ox < ow - 1)
5467 				{
5468 					if (oy < oh - 1) aa4 = src[ow + 1] * k4;
5469 					if (oy >= 0) aa2 = src[1] * k2;
5470 				}
5471 				if (ox >= 0)
5472 				{
5473 					if (oy < oh - 1) aa3 = src[ow] * k3;
5474 					if (oy >= 0) aa1 = src[0] * k1;
5475 				}
5476 				*dest++ = rint(aa1 + aa2 + aa3 + aa4);
5477 			}
5478 		}
5479 	}
5480 }
5481 
5482 #define PIX_ADD (127.0 / 128.0) /* Include all _visibly_ altered pixels */
5483 
mem_rotate_geometry(int ow,int oh,double angle,int * nw,int * nh)5484 void mem_rotate_geometry(int ow, int oh, double angle, int *nw, int *nh)
5485 				// Get new image geometry of rotation. angle = degrees
5486 {
5487 	int dx, dy;
5488 	double rangle = (M_PI / 180.0) * angle,	// Radians
5489 		s2, c2;				// Trig values
5490 
5491 
5492 	c2 = fabs(cos(rangle));
5493 	s2 = fabs(sin(rangle));
5494 
5495 	/* Preserve original centering */
5496 	dx = ow & 1; dy = oh & 1;
5497 	/* Exchange Y with X when rotated Y is nearer to old X */
5498 	if ((dx ^ dy) && (c2 < s2)) dx ^= 1 , dy ^= 1;
5499 	*nw = 2 * (int)(0.5 * (ow * c2 + oh * s2 - dx) + PIX_ADD) + dx;
5500 	*nh = 2 * (int)(0.5 * (oh * c2 + ow * s2 - dy) + PIX_ADD) + dy;
5501 }
5502 
5503 // Rotate canvas or clipboard by any angle (degrees)
mem_rotate_free(double angle,int type,int gcor,int clipboard)5504 int mem_rotate_free(double angle, int type, int gcor, int clipboard)
5505 {
5506 	chanlist old_img, new_img;
5507 	int ow, oh, nw, nh, res, rot_bpp;
5508 
5509 
5510 	if (clipboard)
5511 	{
5512 		if (!mem_clipboard) return (-1);	// Nothing to rotate
5513 		ow = mem_clip_w;
5514 		oh = mem_clip_h;
5515 		rot_bpp = mem_clip_bpp;
5516 	}
5517 	else
5518 	{
5519 		ow = mem_width;
5520 		oh = mem_height;
5521 		rot_bpp = mem_img_bpp;
5522 	}
5523 
5524 	mem_rotate_geometry(ow, oh, angle, &nw, &nh);
5525 
5526 	if ( nw>MAX_WIDTH || nh>MAX_HEIGHT ) return -5;		// If new image is too big return -5
5527 
5528 	if (!clipboard)
5529 	{
5530 		memcpy(old_img, mem_img, sizeof(chanlist));
5531 		res = undo_next_core(UC_NOCOPY, nw, nh, mem_img_bpp, CMASK_ALL);
5532 		if (res) return (res);		// No undo space
5533 		memcpy(new_img, mem_img, sizeof(chanlist));
5534 		progress_init(_("Free Rotation"), 0);
5535 	}
5536 	else
5537 	{
5538 		/* Note:  even if the original clipboard doesn't have a mask,
5539 		 * the rotation will need one to chop off the corners of
5540 		 * a rotated rectangle. */
5541 		if (!mem_clip_mask && mem_clip_mask_init(255))
5542 			return (1);	// Not enough memory
5543 
5544 		res = mem_clip_new(nw, nh, mem_clip_bpp,
5545 			cmask_from(mem_clip.img), old_img);
5546 		if (res) return (1);	// Not enough memory
5547 		memcpy(new_img, mem_clip.img, sizeof(chanlist));
5548 	}
5549 
5550 	if ( rot_bpp == 1 ) type = FALSE;
5551 	mem_rotate_free_real(old_img, new_img, ow, oh, nw, nh, rot_bpp, angle, type,
5552 		gcor, channel_dis[CHN_ALPHA] && !clipboard, clipboard);
5553 	if (!clipboard) progress_end();
5554 
5555 	/* Lose old unwanted clipboard */
5556 	if (clipboard) mem_free_chanlist(old_img);
5557 
5558 	return 0;
5559 }
5560 
mem_image_rot(int dir)5561 int mem_image_rot( int dir )					// Rotate image 90 degrees
5562 {
5563 	chanlist old_img;
5564 	int i, ow = mem_width, oh = mem_height;
5565 
5566 	memcpy(old_img, mem_img, sizeof(chanlist));
5567 	i = undo_next_core(UC_NOCOPY, oh, ow, mem_img_bpp, CMASK_ALL);
5568 	if (i) return (i);			// Not enough memory
5569 
5570 	for (i = 0; i < NUM_CHANNELS; i++)
5571 	{
5572 		if (!mem_img[i]) continue;
5573 		mem_rotate(mem_img[i], old_img[i], ow, oh, dir, BPP(i));
5574 	}
5575 	mem_undo_prepare();
5576 	return 0;
5577 }
5578 
5579 
5580 
5581 ///	Code for scaling contributed by Dmitry Groshev, January 2006
5582 ///	Multicore support added by Dmitry Groshev, November 2010
5583 
5584 typedef struct {
5585 	float *k;
5586 	int idx;
5587 } fstep;
5588 
Cubic(double x,double A)5589 static double Cubic(double x, double A)
5590 {
5591 	if (x < -1.5) return (0.0);
5592 	else if (x < -0.5) return (A * (-1.0 / 8.0) * (((x * 8.0 + 28.0) * x +
5593 		30.0) * x + 9.0));
5594 	else if (x < 0.5) return (0.5 * (((-4.0 * A - 4.0) * x * x + A + 3.0) *
5595 		x + 1.0));
5596 	else if (x < 1.5) return (A * (-1.0 / 8.0) * (((x * 8.0 - 28.0) * x +
5597 		30.0) * x - 9.0) + 1.0);
5598 	else return (1.0);
5599 }
5600 
BH1(double x)5601 static double BH1(double x)
5602 {
5603 	if (x < 1e-7) return (1.0);
5604 	return ((sin(M_PI * x) / (M_PI * x)) * (0.42323 +
5605 		0.49755 * cos(x * (M_PI * 2.0 / 6.0)) +
5606 		0.07922 * cos(x * (M_PI * 4.0 / 6.0))));
5607 }
5608 
BH(double x)5609 static double BH(double x)
5610 {
5611 	double y = 0.0, xx = fabs(x);
5612 
5613 	if (xx < 2.5)
5614 	{
5615 		y = BH1(xx + 0.5);
5616 		if (xx < 1.5) y += BH1(xx + 1.5);
5617 		if (xx < 0.5) y += BH1(xx + 2.5);
5618 	}
5619 	return (x > 0.0 ? 1.0 - y : y);
5620 }
5621 
5622 static const double Aarray[4] = {-0.5, -2.0 / 3.0, -0.75, -1.0};
5623 
5624 /* !!! Filter as a whole must be perfectly symmetric, and "idx" of step 0
5625  * must be <= 0; these natural properties are relied on when allocating and
5626  * extending horizontal temp arrays for BOUND_TILE mode.
5627  * 2 extra steps at end hold end pointer & index, and terminating NULL. */
make_filter(int l0,int l1,int type,int sharp,int bound)5628 static fstep *make_filter(int l0, int l1, int type, int sharp, int bound)
5629 {
5630 	fstep *res, *buf;
5631 	__typeof__(*res->k) *kp;
5632 	double x, y, basept, scale;
5633 	double A = 0.0, kk = 1.0, sum;
5634 	int i, j, k, ix, j0, fwidth, delta, k0 = 0;
5635 
5636 
5637 	/* Untransformed bilinear is useless for reduction */
5638 	if (type == 1) sharp = TRUE;
5639 
5640 	/* 1:1 transform is special */
5641 	if (l1 == l0) type = 0;
5642 
5643 	switch (type)
5644 	{
5645 	case 1:	fwidth = 2; /* Bilinear / Area-mapping */
5646 		break;
5647 	case 2:	case 3: case 4: case 5:	/* Bicubic, all flavors */
5648 		fwidth = 4;
5649 		A = Aarray[type - 2];
5650 		break;
5651 	case 6:	fwidth = 6; /* Blackman-Harris windowed sinc */
5652 		break;
5653 	default: /* 1:1 */
5654 		fwidth = 0;
5655 		break;
5656 	}
5657 	type *= 2;
5658 
5659 	scale = (double)l1 / (double)l0;
5660 	/* !!! fwidth is rational (l1 denominator) to prevent rounding errors */
5661 	if (l1 < l0)
5662 	{
5663 		kk = scale;
5664 		fwidth *= l0;
5665 		if (sharp) fwidth += l1 - l0 , type++;
5666 	}
5667 	else fwidth *= l1;
5668 
5669 	buf = multialloc(MA_ALIGN_DOUBLE, &res, (l1 + 2) * sizeof(*res),
5670 		&kp, (fwidth + l1) * sizeof(*res->k), NULL);
5671 	if (!buf) return (NULL);
5672 	res = buf; /* No need to double-align the index array */
5673 
5674 	/* To correct scale-shift */
5675 	delta = l0 - l1;	// 2*l1 denominator
5676 
5677 	for (i = l1 , l1 *= 2; i > 0; i-- , buf++ , delta += l0 * 2)
5678 	{
5679 		basept = delta / (double)l1;
5680 		j = j0 = ceil_div(delta - fwidth, l1);
5681 		k = k0 = (delta + fwidth) / l1 + 1;
5682 		if (j0 < 0) j0 = 0;
5683 		if (k0 > l0) k0 = l0;
5684 		/* If filter doesn't cover source from end to end, tiling will
5685 		 * require physical copying */
5686 		if ((bound == BOUND_TILE) && (k0 - j0 < l0))
5687 			k0 = k , j0 = j;
5688 		buf->idx = j0;
5689 		buf->k = kp;
5690 		kp += k0 - j0;
5691 		sum = 0.0;
5692 		for (; j < k; j++)
5693 		{
5694 			ix = j;
5695 			if ((j < j0) || (j >= k0))
5696 			{
5697 				if (bound == BOUND_VOID) continue;
5698 				if (bound == BOUND_TILE)
5699 				{
5700 					if (ix < 0) ix = k0 - (-ix % k0);
5701 					ix %= k0;
5702 				}
5703 				else if (k0 == 1) ix = 0;
5704 				else
5705 				{
5706 					ix = abs(ix) % (k0 + k0 - 2);
5707 					if (ix >= k0) ix = k0 + k0 - 2 - ix;
5708 				}
5709 			}
5710 			ix -= j0;
5711 			x = fabs(((double)j - basept) * kk);
5712 			switch (type)
5713 			{
5714 			case 0: /* 1:1 */
5715 			case 2: /* Bilinear */
5716 				y = 1.0 - x;
5717 				break;
5718 			case 3: /* Area mapping */
5719 				if (x <= 0.5 - scale / 2.0) y = 1.0;
5720 				else y = 0.5 - (x - 0.5) / scale;
5721 				break;
5722 			case 4: case 6: case 8: case 10: /* Bicubic */
5723 				if (x < 1.0) y = ((A + 2.0) * x - (A + 3)) * x * x + 1.0;
5724 				else y = A * (((x - 5.0) * x + 8.0) * x - 4.0);
5725 				break;
5726 			case 5: case 7: case 9: case 11: /* Sharpened bicubic */
5727 				y = Cubic(x + scale * 0.5, A) - Cubic(x - scale * 0.5, A);
5728 				break;
5729 			case 12: /* Blackman-Harris */
5730 				y = BH1(x);
5731 				break;
5732 			case 13: /* Sharpened Blackman-Harris */
5733 				y = BH(x + scale * 0.5) - BH(x - scale * 0.5);
5734 				break;
5735 			default: /* Bug */
5736 				y = 0;
5737 				break;
5738 			}
5739 			buf->k[ix] += y;
5740 			sum += y;
5741 		}
5742 		/* Normalize */
5743 		if ((sum != 0.0) && (sum != 1.0))
5744 		{
5745 			__typeof__(*kp) *tp = buf->k;
5746 			sum = 1.0 / sum;
5747 			while (tp != kp) *tp++ *= sum;
5748 		}
5749 	}
5750 	/* Finalize */
5751 	buf->idx = k0; // The rightmost extent
5752 	buf->k = kp;
5753 
5754 	return (res);
5755 }
5756 
5757 typedef struct {
5758 	int tmask, gcor, progress;
5759 	int ow, oh, nw, nh, bpp;
5760 	unsigned char **src, **dest;
5761 	double *rgb;
5762 	fstep *hfilter, *vfilter;
5763 	threaddata *tdata; // For simplicity
5764 } scale_context;
5765 
clear_scale(scale_context * ctx)5766 static void clear_scale(scale_context *ctx)
5767 {
5768 	free(ctx->hfilter);
5769 	free(ctx->vfilter);
5770 	free(ctx->tdata);
5771 }
5772 
prepare_scale(scale_context * ctx,int type,int sharp,int bound)5773 static int prepare_scale(scale_context *ctx, int type, int sharp, int bound)
5774 {
5775 	ctx->hfilter = ctx->vfilter = NULL;
5776 	ctx->tdata = NULL;
5777 
5778 	/* We don't use threading for NN */
5779 	if (!type || (ctx->bpp == 1)) return (TRUE);
5780 
5781 	if ((ctx->hfilter = make_filter(ctx->ow, ctx->nw, type, sharp, bound)) &&
5782 		(ctx->vfilter = make_filter(ctx->oh, ctx->nh, type, sharp, bound)))
5783 	{
5784 		int l = (ctx->ow - ctx->hfilter[0].idx * 2) * sizeof(double);
5785 		if ((ctx->tdata = talloc(MA_ALIGN_DOUBLE,
5786 			image_threads(ctx->nw, ctx->nh), ctx, sizeof(*ctx),
5787 			NULL,
5788 			// !!! No space for RGBAS for now
5789 			&ctx->rgb, l * (ctx->tmask ? 7 : 3),
5790 			NULL))) return (TRUE);
5791 	}
5792 
5793 	clear_scale(ctx);
5794 	return (FALSE);
5795 }
5796 
tile_extend(double * temp,int w,int l)5797 static void tile_extend(double *temp, int w, int l)
5798 {
5799 	memcpy(temp - l, temp + w - l, l * sizeof(*temp));
5800 	memcpy(temp + w, temp, l * sizeof(*temp));
5801 }
5802 
5803 typedef void REGPARM2 (*istore_func)(unsigned char *img, const double *sum);
5804 
istore_gc(unsigned char * img,const double * sum)5805 static void REGPARM2 istore_gc(unsigned char *img, const double *sum)
5806 {
5807 	/* Reverse gamma correction */
5808 	img[0] = UNGAMMA256X(sum[0]);
5809 	img[1] = UNGAMMA256X(sum[1]);
5810 	img[2] = UNGAMMA256X(sum[2]);
5811 }
5812 
istore_3(unsigned char * img,const double * sum)5813 static void REGPARM2 istore_3(unsigned char *img, const double *sum)
5814 {
5815 	int j = (int)rint(sum[0]);
5816 	img[0] = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5817 	j = (int)rint(sum[1]);
5818 	img[1] = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5819 	j = (int)rint(sum[2]);
5820 	img[2] = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5821 }
5822 
istore_1(unsigned char * img,const double * sum)5823 static void REGPARM2 istore_1(unsigned char *img, const double *sum)
5824 {
5825 	int j = (int)rint(sum[0]);
5826 	img[0] = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5827 }
5828 
5829 /* !!! Once again, beware of GCC misoptimization! The two functions below
5830  * should not be both inlineable at once, otherwise poor code wasting both
5831  * time and space will be produced - WJ */
5832 
scale_row(fstep * tmpy,fstep * hfilter,double * work_area,int bpp,int gc,int ow,int oh,int nw,int i,unsigned char * src,unsigned char * dest)5833 static void scale_row(fstep *tmpy, fstep *hfilter, double *work_area,
5834 	int bpp, int gc, int ow, int oh, int nw, int i,
5835 	unsigned char *src, unsigned char *dest)
5836 {
5837 	/* !!! Protect from possible stack misalignment */
5838 	unsigned char sum_[4 * sizeof(double)];
5839 	double *sum = ALIGNED(sum_, sizeof(double));
5840 	istore_func istore;
5841 	unsigned char *img;
5842 	fstep *tmpx;
5843 	__typeof__(*tmpy->k) *kp = tmpy->k - tmpy->idx;
5844 	int j, y, h = tmpy[1].k - kp, ll = hfilter[0].idx;
5845 
5846 
5847 	work_area -= ll * bpp;
5848 	ow *= bpp;
5849 	memset(work_area, 0, ow * sizeof(double));
5850 	/* Build one vertically-scaled row */
5851 	for (y = tmpy->idx; y < h; y++)
5852 	{
5853 		const double tk = kp[y];
5854 		double *wrk = work_area;
5855 		/* Only simple tiling isn't built into filter */
5856 		img = src + ((y + oh) % oh) * ow;
5857 		if (gc) /* Gamma-correct */
5858 		{
5859 			for (j = 0; j < ow; j++)
5860 				*wrk++ += gamma256[*img++] * tk;
5861 		}
5862 		else /* Leave as is */
5863 		{
5864 			for (j = 0; j < ow; j++)
5865 				*wrk++ += *img++ * tk;
5866 		}
5867 	}
5868 	tile_extend(work_area, ow, -ll * bpp);
5869 	/* Scale it horizontally */
5870 	istore = gc ? istore_gc : bpp == 1 ? istore_1 : istore_3;
5871 	img = dest + i * nw * bpp;
5872 	for (tmpx = hfilter; tmpx[1].k; tmpx++ , img += bpp)
5873 	{
5874 		__typeof__(*tmpx->k) *tp, *kp = tmpx[1].k;
5875 		double *wrk = work_area + tmpx->idx * bpp;
5876 		double sum0, sum1, sum2;
5877 
5878 		sum0 = sum1 = sum2 = 0.0;
5879 		tp = tmpx->k;
5880 		while (tp != kp)
5881 		{
5882 			const double kk = *tp++;
5883 			sum0 += *wrk++ * kk;
5884 			if (bpp == 1) continue;
5885 			sum1 += *wrk++ * kk;
5886 			sum2 += *wrk++ * kk;
5887 		}
5888 		sum[0] = sum0; sum[1] = sum1; sum[2] = sum2;
5889 		istore(img, sum);
5890 	}
5891 }
5892 
scale_rgba(fstep * tmpy,fstep * hfilter,double * work_area,int bpp,int gc,int ow,int oh,int nw,int i,unsigned char * src,unsigned char * dest,unsigned char * srca,unsigned char * dsta)5893 static void scale_rgba(fstep *tmpy, fstep *hfilter, double *work_area,
5894 	int bpp, int gc, int ow, int oh, int nw, int i,
5895 	unsigned char *src, unsigned char *dest,
5896 	unsigned char *srca, unsigned char *dsta)
5897 {
5898 	/* !!! Protect from possible stack misalignment */
5899 	unsigned char sum_[4 * sizeof(double)];
5900 	double *sum = ALIGNED(sum_, sizeof(double));
5901 	istore_func istore;
5902 	unsigned char *img, *imga;
5903 	fstep *tmpx;
5904 	__typeof__(*tmpy->k) *kp = tmpy->k - tmpy->idx;
5905 	int j, y, h = tmpy[1].k - kp, ll = hfilter[0].idx;
5906 	double *wrka = work_area + ow * 6 - ll * 13;
5907 
5908 
5909 	work_area -= ll * 6;
5910 	memset(work_area, 0, (ow - ll) * 7 * sizeof(double));
5911 	for (y = tmpy->idx; y < h; y++)
5912 	{
5913 		double *wrk = work_area;
5914 		unsigned char *img, *imga;
5915 		int ix = (y + oh) % oh;
5916 
5917 		img = src + ix * ow * 3;
5918 		imga = srca + ix * ow;
5919 		if (gc) /* Gamma-correct */
5920 		{
5921 			const double tk = kp[y];
5922 			for (j = 0; j < ow; j++)
5923 			{
5924 				const double kk = imga[j] * tk;
5925 				double tv;
5926 
5927 				wrka[j] += kk;
5928 				wrk[0] += (tv = gamma256[img[0]]) * tk;
5929 				wrk[3] += tv * kk;
5930 				wrk[1] += (tv = gamma256[img[1]]) * tk;
5931 				wrk[4] += tv * kk;
5932 				wrk[2] += (tv = gamma256[img[2]]) * tk;
5933 				wrk[5] += tv * kk;
5934 				wrk += 6; img += 3;
5935 			}
5936 		}
5937 		else /* Leave as is */
5938 		{
5939 			const double tk = kp[y];
5940 			for (j = 0; j < ow; j++)
5941 			{
5942 				const double kk = imga[j] * tk;
5943 				double tv;
5944 
5945 				wrka[j] += kk;
5946 				wrk[0] += (tv = img[0]) * tk;
5947 				wrk[3] += tv * kk;
5948 				wrk[1] += (tv = img[1]) * tk;
5949 				wrk[4] += tv * kk;
5950 				wrk[2] += (tv = img[2]) * tk;
5951 				wrk[5] += tv * kk;
5952 				wrk += 6; img += 3;
5953 			}
5954 		}
5955 	}
5956 	tile_extend(work_area, ow * 6, -ll * 6);
5957 	tile_extend(wrka, ow, -ll);
5958 	/* Scale it horizontally */
5959 	istore = gc ? istore_gc : bpp == 1 ? istore_1 : istore_3;
5960 	img = dest + i * nw * 3;
5961 	imga = dsta + i * nw;
5962 	for (tmpx = hfilter; tmpx[1].k; tmpx++)
5963 	{
5964 		__typeof__(*tmpx->k) *tp, *kp = tmpx[1].k;
5965 		double *wrk;
5966 		double sum0, sum1, sum2, mult;
5967 
5968 		sum0 = 0.0;
5969 		wrk = wrka + tmpx->idx;
5970 		tp = tmpx->k;
5971 		while (tp != kp) sum0 += *wrk++ * *tp++;
5972 		j = (int)rint(sum0);
5973 		*imga = j < 0 ? 0 : j > 0xFF ? 0xFF : j;
5974 		wrk = work_area + tmpx->idx * 6;
5975 		mult = 1.0;
5976 		if (*imga++)
5977 		{
5978 			wrk += 3;
5979 			mult /= sum0;
5980 		}
5981 		sum0 = sum1 = sum2 = 0.0;
5982 		tp = tmpx->k;
5983 		while (tp != kp)
5984 		{
5985 			const double kk = *tp++;
5986 			sum0 += wrk[0] * kk;
5987 			sum1 += wrk[1] * kk;
5988 			sum2 += wrk[2] * kk;
5989 			wrk += 6;
5990 		}
5991 		sum[0] = sum0 * mult; sum[1] = sum1 * mult; sum[2] = sum2 * mult;
5992 		istore(img, sum);
5993 		img += 3;
5994 	}
5995 }
5996 
do_scale(tcb * thread)5997 static void do_scale(tcb *thread)
5998 {
5999 	scale_context ctx = *(scale_context *)thread->data;
6000 	fstep *tmpy;
6001 	int i, ii, cc, cnt = thread->nsteps;
6002 
6003 
6004 	/* For each destination line */
6005 	for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
6006 	{
6007 		tmpy = ctx.vfilter + i;
6008 		if (ctx.dest[CHN_IMAGE]) // Chanlist may contain, e.g., only mask
6009 		{
6010 			(ctx.tmask == CMASK_NONE ? (__typeof__(&scale_rgba))scale_row :
6011 				scale_rgba)(tmpy, ctx.hfilter, ctx.rgb,
6012 				3, ctx.gcor, ctx.ow, ctx.oh, ctx.nw, i,
6013 				ctx.src[CHN_IMAGE], ctx.dest[CHN_IMAGE],
6014 				ctx.src[CHN_ALPHA], ctx.dest[CHN_ALPHA]);
6015 		}
6016 
6017 		for (cc = CHN_IMAGE + 1; cc < NUM_CHANNELS; cc++)
6018 		{
6019 			if (ctx.dest[cc] && !(ctx.tmask & CMASK_FOR(cc)))
6020 				scale_row(tmpy, ctx.hfilter, ctx.rgb,
6021 					1, FALSE, ctx.ow, ctx.oh, ctx.nw, i,
6022 					ctx.src[cc], ctx.dest[cc]);
6023 		}
6024 
6025 		if (ctx.progress && thread_step(thread, ii + 1, cnt, 10)) break;
6026 	}
6027 	thread_done(thread);
6028 }
6029 
do_scale_nn(chanlist old_img,chanlist neo_img,int img_bpp,int type,int ow,int oh,int nw,int nh,int gcor,int progress)6030 static void do_scale_nn(chanlist old_img, chanlist neo_img, int img_bpp,
6031 	int type, int ow, int oh, int nw, int nh, int gcor, int progress)
6032 {
6033 	char *src, *dest;
6034 	int i, j, oi, oj, cc, bpp;
6035 	double scalex, scaley, deltax, deltay;
6036 
6037 
6038 	scalex = (double)ow / (double)nw;
6039 	scaley = (double)oh / (double)nh;
6040 	deltax = 0.5 * scalex - 0.5;
6041 	deltay = 0.5 * scaley - 0.5;
6042 
6043 	for (j = 0; j < nh; j++)
6044 	{
6045 		for (cc = 0 , bpp = img_bpp; cc < NUM_CHANNELS; cc++ , bpp = 1)
6046 		{
6047 			if (!neo_img[cc]) continue;
6048 			dest = neo_img[cc] + nw * j * bpp;
6049 			WJ_ROUND(oj, scaley * j + deltay);
6050 			src = old_img[cc] + ow * oj * bpp;
6051 			for (i = 0; i < nw; i++)
6052 			{
6053 				WJ_ROUND(oi, scalex * i + deltax);
6054 				oi *= bpp;
6055 				*dest++ = src[oi];
6056 				if (bpp == 1) continue;
6057 				*dest++ = src[oi + 1];
6058 				*dest++ = src[oi + 2];
6059 			}
6060 		}
6061 		if (progress && ((j * 10) % nh >= nh - 10))
6062 			progress_update((float)(j + 1) / nh);
6063 	}
6064 }
6065 
6066 
mem_image_scale_real(chanlist old_img,int ow,int oh,int bpp,chanlist new_img,int nw,int nh,int type,int gcor,int sharp)6067 int mem_image_scale_real(chanlist old_img, int ow, int oh, int bpp,
6068 	chanlist new_img, int nw, int nh, int type, int gcor, int sharp)
6069 {
6070 	scale_context ctx;
6071 
6072 	ctx.tmask = CMASK_NONE;
6073 	ctx.gcor = gcor;
6074 	ctx.progress = FALSE;
6075 	ctx.ow = ow;
6076 	ctx.oh = oh;
6077 	ctx.nw = nw;
6078 	ctx.nh = nh;
6079 	ctx.bpp = bpp;
6080 	ctx.src = old_img;
6081 	ctx.dest = new_img;
6082 
6083 	if (!prepare_scale(&ctx, type, sharp, BOUND_MIRROR))
6084 		return (1);	// Not enough memory
6085 
6086 	if (type && (bpp == 3))
6087 		launch_threads(do_scale, ctx.tdata, NULL, nh);
6088 	else do_scale_nn(old_img, new_img, bpp, type, ow, oh, nw, nh, gcor, FALSE);
6089 
6090 	return (0);
6091 }
6092 
mem_image_scale(int nw,int nh,int type,int gcor,int sharp,int bound)6093 int mem_image_scale(int nw, int nh, int type, int gcor, int sharp, int bound)	// Scale image
6094 {
6095 	scale_context ctx;
6096 	chanlist old_img;
6097 	int res;
6098 
6099 	memcpy(old_img, mem_img, sizeof(chanlist));
6100 	nw = nw < 1 ? 1 : nw > MAX_WIDTH ? MAX_WIDTH : nw;
6101 	nh = nh < 1 ? 1 : nh > MAX_HEIGHT ? MAX_HEIGHT : nh;
6102 
6103 	ctx.tmask = mem_img[CHN_ALPHA] && !channel_dis[CHN_ALPHA] ? CMASK_RGBA : CMASK_NONE;
6104 	ctx.gcor = gcor;
6105 	ctx.progress = TRUE;
6106 	ctx.ow = mem_width;
6107 	ctx.oh = mem_height;
6108 	ctx.nw = nw;
6109 	ctx.nh = nh;
6110 	ctx.bpp = mem_img_bpp;
6111 	ctx.src = old_img;
6112 	ctx.dest = mem_img;
6113 
6114 	if (!prepare_scale(&ctx, type, sharp, bound))
6115 		return (1);	// Not enough memory
6116 
6117 	if (!(res = undo_next_core(UC_NOCOPY, nw, nh, mem_img_bpp, CMASK_ALL)))
6118 	{
6119 		progress_init(_("Scaling Image"), 0);
6120 		if (type && (mem_img_bpp == 3))
6121 			launch_threads(do_scale, ctx.tdata, NULL, mem_height);
6122 		else do_scale_nn(old_img, mem_img, mem_img_bpp, type,
6123 			ctx.ow, ctx.oh, nw, nh, gcor, TRUE);
6124 		progress_end();
6125 	}
6126 
6127 	clear_scale(&ctx);
6128 	return (res);
6129 }
6130 
6131 
6132 
mem_isometrics(int type)6133 int mem_isometrics(int type)
6134 {
6135 	unsigned char *wrk, *src, *dest, *fill;
6136 	int i, j, k, l, cc, step, bpp, ow = mem_width, oh = mem_height;
6137 
6138 	if ( type<2 )
6139 	{
6140 		if ( (oh + (ow-1)/2) > MAX_HEIGHT ) return -5;
6141 		i = mem_image_resize(ow, oh + (ow-1)/2, 0, 0, 0);
6142 	}
6143 	if ( type>1 )
6144 	{
6145 		if ( (ow+oh-1) > MAX_WIDTH ) return -5;
6146 		i = mem_image_resize(ow + oh - 1, oh, 0, 0, 0);
6147 	}
6148 
6149 	if (i) return (i);
6150 
6151 	for (cc = 0; cc < NUM_CHANNELS; cc++)
6152 	{
6153 		if (!mem_img[cc]) continue;
6154 		bpp = BPP(cc);
6155 		if ( type < 2 )		// Left/Right side down
6156 		{
6157 			fill = mem_img[cc] + (mem_height - 1) * ow * bpp;
6158 			step = ow * bpp;
6159 			if (type) step = -step;
6160 			else fill += (2 - (ow & 1)) * bpp;
6161 			for (i = mem_height - 1; i >= 0; i--)
6162 			{
6163 				k = i + i + 2;
6164 				if (k > ow) k = ow;
6165 				l = k;
6166 				j = 0;
6167 				dest = mem_img[cc] + i * ow * bpp;
6168 				src = dest - step;
6169 				if (!type)
6170 				{
6171 					j = ow - k;
6172 					dest += j * bpp;
6173 					src += (j - ow * ((ow - j - 1) >> 1)) * bpp;
6174 					j = j ? 0 : ow & 1;
6175 					k += j;
6176 					if (j) src += step;
6177 				}
6178 				for (; j < k; j++)
6179 				{
6180 					if (!(j & 1)) src += step;
6181 					*dest++ = *src++;
6182 					if (bpp == 1) continue;
6183 					*dest++ = *src++;
6184 					*dest++ = *src++;
6185 				}
6186 				if (l < ow)
6187 				{
6188 					if (!type) dest = mem_img[cc] + i * ow * bpp;
6189 					memcpy(dest, fill, (ow - l) * bpp);
6190 				}
6191 			}
6192 		}
6193 		else			// Top/Bottom side right
6194 		{
6195 			step = mem_width * bpp;
6196 			fill = mem_img[cc] + ow * bpp;
6197 			k = (oh - 1) * mem_width * bpp;
6198 			if (type == 2)
6199 			{
6200 				fill += k;
6201 				step = -step;
6202 			}
6203 			wrk = fill + step - 1;
6204 			k = ow * bpp;
6205 			for (i = 1; i < oh; i++)
6206 			{
6207 				src = wrk;
6208 				dest = wrk + i * bpp;
6209 				for (j = 0; j < k; j++)
6210 					*dest-- = *src--;
6211 				memcpy(src + 1, fill, i * bpp);
6212 				wrk += step;
6213 			}
6214 		}
6215 	}
6216 
6217 	return 0;
6218 }
6219 
6220 /* Modes: 0 - clear, 1 - tile, 2 - mirror tile */
mem_image_resize(int nw,int nh,int ox,int oy,int mode)6221 int mem_image_resize(int nw, int nh, int ox, int oy, int mode)
6222 {
6223 	chanlist old_img;
6224 	char *src, *dest;
6225 	int i, h, ow = mem_width, oh = mem_height, hmode = mode;
6226 	int res, hstep, vstep, vstep2 = 0, oxo = 0, oyo = 0, nxo = 0, nyo = 0;
6227 	int rspan1 = 0, span1 = 0, rspan2 = 0, span2 = 0, rep = 0, tail = 0;
6228 
6229 	nw = nw < 1 ? 1 : nw > MAX_WIDTH ? MAX_WIDTH : nw;
6230 	nh = nh < 1 ? 1 : nh > MAX_HEIGHT ? MAX_HEIGHT : nh;
6231 
6232 	memcpy(old_img, mem_img, sizeof(chanlist));
6233 	res = undo_next_core(UC_NOCOPY, nw, nh, mem_img_bpp, CMASK_ALL);
6234 	if (res) return (res);			// Not enough memory
6235 
6236 	/* Special mode for simplest, one-piece-covering case */
6237 	if ((ox <= 0) && (nw - ox <= ow)) hmode = -1;
6238 	if ((oy <= 0) && (nh - oy <= oh)) mode = -1;
6239 
6240 	/* Clear */
6241 	if (!mode || !hmode)
6242 	{
6243 		int i, l, cc;
6244 
6245 		l = nw * nh;
6246 		for (cc = 0; cc < NUM_CHANNELS; cc++)
6247 		{
6248 			if (!mem_img[cc]) continue;
6249 			dest = mem_img[cc];
6250 			if ((cc != CHN_IMAGE) || (mem_img_bpp == 1))
6251 			{
6252 				memset(dest, cc == CHN_IMAGE ? mem_col_A : 0, l);
6253 				continue;
6254 			}
6255 			for (i = 0; i < l; i++)	// Background is current colour A
6256 			{
6257 				*dest++ = mem_col_A24.red;
6258 				*dest++ = mem_col_A24.green;
6259 				*dest++ = mem_col_A24.blue;
6260 			}
6261 		}
6262 		/* All done if source out of bounds */
6263 		if ((ox >= nw) || (ox + ow <= 0) || (oy >= nh) ||
6264 			(oy + oh <= 0)) return (0);
6265 	}
6266 
6267 	/* Tiled vertically */
6268 	if (mode > 0)
6269 	{
6270 		/* No mirror when height < 3 */
6271 		if (oh < 3) mode = 1;
6272 		/* Period length */
6273 		if (mode == 2) vstep = 2 * (vstep2 = oh - 1);
6274 		else vstep = oh;
6275 		/* Normalize offset */
6276 		oyo = oy <= 0 ? -oy % vstep : vstep - 1 - (oy - 1) % vstep;
6277 		h = nh;
6278 	}
6279 	/* Single vertical span */
6280 	else
6281 	{
6282 		/* No periodicity */
6283 		vstep = nh + oh;
6284 		/* Normalize offset */
6285 		if (oy < 0) oyo = -oy;
6286 		else nyo = oy;
6287 		h = oh + oy;
6288 		if (h > nh) h = nh;
6289 	}
6290 
6291 	/* Tiled horizontally */
6292 	if (hmode > 0)
6293 	{
6294 		/* No mirror when width < 3 */
6295 		if (ow < 3) hmode = 1;
6296 		/* Period length */
6297 		if (hmode == 2) hstep = ow + ow - 2;
6298 		else hstep = ow;
6299 		/* Normalize offset */
6300 		oxo = ox <= 0 ? -ox % hstep : hstep - 1 - (ox - 1) % hstep;
6301 		/* Single direct span? */
6302 		if ((oxo <= 0) && (oxo + ow >= nw)) hmode = -1;
6303 		if (hmode == 2) /* Mirror tiling */
6304 		{
6305 			if (oxo < ow - 1) span1 = ow - 1 - oxo;
6306 			res = nw - span1;
6307 			rspan1 = hstep - oxo - span1;
6308 			if (rspan1 > res) rspan1 = res;
6309 			span2 = (res = res - rspan1);
6310 			if (span2 > ow - 1 - span1) span2 = ow - 1 - span1;
6311 			rspan2 = res - span2;
6312 			if (rspan2 > ow - 1 - rspan1) rspan2 = ow - 1 - rspan1;
6313 		}
6314 		else /* Normal tiling */
6315 		{
6316 			span1 = ow - oxo;
6317 			span2 = nw - span1;
6318 			if (span2 > oxo) span2 = oxo;
6319 		}
6320 		rep = nw / hstep;
6321 		if (rep) tail = nw % hstep;
6322 	}
6323 	/* Single horizontal span */
6324 	else
6325 	{
6326 		/* No periodicity */
6327 		hstep = nw;
6328 		/* Normalize offset */
6329 		if (ox < 0) oxo = -ox;
6330 		else nxo = ox;
6331 		/* First direct span */
6332 		span1 = nw - nxo;
6333 		if (span1 > ow - oxo) span1 = ow - oxo;
6334 	}
6335 
6336 	/* Row loop */
6337 	for (i = nyo; i < h; i++)
6338 	{
6339 		int j, k, l, bpp, cc;
6340 
6341 		/* Main period */
6342 		k = i - vstep;
6343 		/* Mirror period */
6344 		if ((k < 0) && (vstep2 > 1)) k = i - ((i + oyo) % vstep2) * 2;
6345 		/* The row is there - copy it */
6346 		if ((k >= 0) && (k < i))
6347 		{
6348 			for (cc = 0; cc < NUM_CHANNELS; cc++)
6349 			{
6350 				if (!mem_img[cc]) continue;
6351 				l = nw * BPP(cc);
6352 				src = mem_img[cc] + k * l;
6353 				dest = mem_img[cc] + i * l;
6354 				memcpy(dest, src, l);
6355 			}
6356 			continue;
6357 		}
6358 		/* First encounter - have to build the row anew */
6359 		k = (i - nyo + oyo) % vstep;
6360 		if (k >= oh) k = vstep - k;
6361 		for (cc = 0; cc < NUM_CHANNELS; cc++)
6362 		{
6363 			if (!mem_img[cc]) continue;
6364 			bpp = BPP(cc);
6365 			dest = mem_img[cc] + (i * nw + nxo) * bpp;
6366 			/* First direct span */
6367 			if (span1)
6368 			{
6369 				src = old_img[cc] + (k * ow + oxo) * bpp;
6370 				memcpy(dest, src, span1 * bpp);
6371 				if (hmode < 1) continue; /* Single-span mode */
6372 				dest += span1 * bpp;
6373 			}
6374 			/* First reverse span */
6375 			if (rspan1)
6376 			{
6377 				src = old_img[cc] + (k * ow + hstep - oxo -
6378 					span1) * bpp;
6379 				for (j = 0; j < rspan1; j++ , src -= bpp)
6380 				{
6381 					*dest++ = src[0];
6382 					if (bpp == 1) continue;
6383 					*dest++ = src[1];
6384 					*dest++ = src[2];
6385 				}
6386 			}
6387 			/* Second direct span */
6388 			if (span2)
6389 			{
6390 				src = old_img[cc] + k * ow * bpp;
6391 				memcpy(dest, src, span2 * bpp);
6392 				dest += span2 * bpp;
6393 			}
6394 			/* Second reverse span */
6395 			if (rspan2)
6396 			{
6397 				src = old_img[cc] + (k * ow + ow - 1) * bpp;
6398 				for (j = 0; j < rspan2; j++ , src -= bpp)
6399 				{
6400 					*dest++ = src[0];
6401 					if (bpp == 1) continue;
6402 					*dest++ = src[1];
6403 					*dest++ = src[2];
6404 				}
6405 			}
6406 			/* Repeats */
6407 			if (rep)
6408 			{
6409 				src = mem_img[cc] + i * nw * bpp;
6410 				l = hstep * bpp;
6411 				for (j = 1; j < rep; j++)
6412 				{
6413 					memcpy(dest, src, l);
6414 					dest += l;
6415 				}
6416 				memcpy(dest, src, tail * bpp);
6417 			}
6418 		}
6419 	}
6420 	mem_undo_prepare();
6421 
6422 	return (0);
6423 }
6424 
6425 /* Threshold channel values */
mem_threshold(unsigned char * img,int len,int level)6426 void mem_threshold(unsigned char *img, int len, int level)
6427 {
6428 	if (!img) return; /* Paranoia */
6429 	level += 0xFFFF;
6430 	for (; len; len-- , img++)
6431 		*img = (level - *img) >> 8;
6432 }
6433 
6434 /* Industrial-grade thresholding */
do_xhold(int start,int step,int cnt,unsigned char * mask,unsigned char * imgr,unsigned char * img0)6435 void do_xhold(int start, int step, int cnt, unsigned char *mask,
6436 	unsigned char *imgr, unsigned char *img0)
6437 {
6438 	unsigned char lo = mem_ts.lo, hi = mem_ts.hi;
6439 	int n, mstep = step, bpp = MEM_BPP;
6440 
6441 	mask += start - step;
6442 	start *= bpp; step *= bpp;
6443 	img0 += start - step;
6444 	imgr += start - step;
6445 	if ((bpp > 1) && (mem_ts.mode <= XHOLD_MIN)) /* By max or min */
6446 	{
6447 		int m = mem_ts.mode; // 0 for max, 1 for min
6448 
6449 		while (cnt-- > 0)
6450 		{
6451 			img0 += step; imgr += step; mask += mstep;
6452 			if (*mask == 255) continue;
6453 			n = (img0[0] > img0[1]) ^ m ? img0[0] : img0[1];
6454 			n = (n > img0[2]) ^ m ? n : img0[2];
6455 			imgr[0] = imgr[1] = imgr[2] =
6456 				((0xFFFF + lo - n) & (0xFFFF - hi + n)) >> 8;
6457 		}
6458 	}
6459 	else /* By R/G/B/value */
6460 	{
6461 		unsigned char mx = 255;
6462 
6463 		if (bpp > 1) img0 += mem_ts.mode - XHOLD_RED;
6464 		else if (mem_channel == CHN_IMAGE) mx = mem_cols - 1;
6465 
6466 		while (cnt-- > 0)
6467 		{
6468 			img0 += step; imgr += step; mask += mstep;
6469 			if (*mask == 255) continue;
6470 			n = *img0;
6471 			imgr[0] = n = mx &
6472 				(((0xFFFF + lo - n) & (0xFFFF - hi + n)) >> 8);
6473 			if (bpp == 1) continue;
6474 			imgr[1] = imgr[2] = n;
6475 		}
6476 	}
6477 }
6478 
6479 /* Only supports BPP = 1 and 3 */
mem_demultiply(unsigned char * img,unsigned char * alpha,int len,int bpp)6480 void mem_demultiply(unsigned char *img, unsigned char *alpha, int len, int bpp)
6481 {
6482 	int i, k;
6483 	double d;
6484 
6485 	for (i = 0; i < len; i++ , img += bpp)
6486 	{
6487 		if (!alpha[i]) continue;
6488 		d = 255.0 / (double)alpha[i];
6489 		k = rint(d * img[0]);
6490 		img[0] = k > 255 ? 255 : k;
6491 		if (bpp == 1) continue;
6492 		k = rint(d * img[1]);
6493 		img[1] = k > 255 ? 255 : k;
6494 		k = rint(d * img[2]);
6495 		img[2] = k > 255 ? 255 : k;
6496 	}
6497 }
6498 
6499 /* Build value rescaling table */
set_xlate_n(unsigned char * xlat,int n)6500 void set_xlate_n(unsigned char *xlat, int n)
6501 {
6502 	int i, j, m;
6503 
6504 	for (i = 0 , j = n , m = n + n; i <= n; i++ , j += 255 * 2)
6505 		xlat[i] = j / m;
6506 }
6507 
6508 /* Check if byte array is all one value */
is_filled(unsigned char * data,unsigned char val,int len)6509 int is_filled(unsigned char *data, unsigned char val, int len)
6510 {
6511 	len++;
6512 	while (--len && (*data++ == val));
6513 	return (!len);
6514 }
6515 
get_pixel(int x,int y)6516 int get_pixel( int x, int y )	/* Mixed */
6517 {
6518 	x = mem_width * y + x;
6519 	if ((mem_channel != CHN_IMAGE) || (mem_img_bpp == 1))
6520 		return (mem_img[mem_channel][x]);
6521 	x *= 3;
6522 	return (MEM_2_INT(mem_img[CHN_IMAGE], x));
6523 }
6524 
get_pixel_RGB(int x,int y)6525 int get_pixel_RGB( int x, int y )	/* RGB */
6526 {
6527 	x = mem_width * y + x;
6528 	if (mem_img_bpp == 1)
6529 		return (PNG_2_INT(mem_pal[mem_img[CHN_IMAGE][x]]));
6530 	x *= 3;
6531 	return (MEM_2_INT(mem_img[CHN_IMAGE], x));
6532 }
6533 
get_pixel_img(int x,int y)6534 int get_pixel_img( int x, int y )	/* RGB or indexed */
6535 {
6536 	x = mem_width * y + x;
6537 	if (mem_img_bpp == 1) return (mem_img[CHN_IMAGE][x]);
6538 	x *= 3;
6539 	return (MEM_2_INT(mem_img[CHN_IMAGE], x));
6540 }
6541 
mem_protected_RGB(int intcol)6542 int mem_protected_RGB(int intcol)		// Is this intcol in bitmap?
6543 {
6544 	return (mem_mask_test(intcol) * 255);
6545 }
6546 
pixel_protected(int x,int y)6547 int pixel_protected(int x, int y)
6548 {
6549 	int offset = y * mem_width + x;
6550 
6551 	if (mem_unmask) return (0);
6552 
6553 	/* Colour protection */
6554 	if (mem_img_bpp == 1)
6555 	{
6556 		if (mem_prot_mask[mem_img[CHN_IMAGE][offset]]) return (255);
6557 	}
6558 	else
6559 	{
6560 		if (mem_prot && mem_protected_RGB(MEM_2_INT(mem_img[CHN_IMAGE],
6561 			offset * 3))) return (255);
6562 	}
6563 
6564 	/* Colour selectivity */
6565 	if (mem_cselect && csel_scan(offset, 1, 1, NULL, mem_img[CHN_IMAGE], csel_data))
6566 		return (255);
6567 
6568 	/* Mask channel */
6569 	if ((mem_channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK])
6570 		return (mem_img[CHN_MASK][offset]);
6571 
6572 	return (0);
6573 }
6574 
prep_mask(int start,int step,int cnt,unsigned char * mask,unsigned char * mask0,unsigned char * img0)6575 void prep_mask(int start, int step, int cnt, unsigned char *mask,
6576 	unsigned char *mask0, unsigned char *img0)
6577 {
6578 	int i, j;
6579 
6580 	j = start + step * (cnt - 1) + 1;
6581 
6582 	if (mem_unmask)
6583 	{
6584 		memset(mask, 0, j);
6585 		return;
6586 	}
6587 
6588 	/* Clear mask or copy mask channel into it */
6589 	if (mask0) memcpy(mask, mask0, j);
6590 	else memset(mask, 0, j);
6591 
6592 	/* Add colour protection to it */
6593 	if (mem_img_bpp == 1)
6594 	{
6595 		for (i = start; i < j; i += step)
6596 		{
6597 			mask[i] |= mem_prot_mask[img0[i]];
6598 		}
6599 	}
6600 	else if (mem_prot)
6601 	{
6602 		for (i = start; i < j; i += step)
6603 		{
6604 			mask[i] |= mem_protected_RGB(MEM_2_INT(img0, i * 3));
6605 		}
6606 	}
6607 
6608 	/* Add colour selectivity to it */
6609 	if (mem_cselect) csel_scan(start, step, cnt, mask, img0, csel_data);
6610 }
6611 
6612 /* Prepare mask array - for each pixel >0 if masked, 0 if not */
row_protected(int x,int y,int len,unsigned char * mask)6613 void row_protected(int x, int y, int len, unsigned char *mask)
6614 {
6615 	unsigned char *mask0 = NULL;
6616 	int ofs = y * mem_width + x;
6617 
6618 	/* Clear mask or copy mask channel into it */
6619 	if ((mem_channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK])
6620 		mask0 = mem_img[CHN_MASK] + ofs;
6621 
6622 	prep_mask(0, 1, len, mask, mask0, mem_img[CHN_IMAGE] + ofs * mem_img_bpp);
6623 }
6624 
6625 /* Make code not compile if it cannot work */
6626 typedef char Too_Many_Blend_Modes[2 * (BLEND_NMODES <= BLEND_MMASK + 1) - 1];
6627 
blend_pixels(int start,int step,int cnt,const unsigned char * mask,unsigned char * imgr,unsigned char * img0,unsigned char * img,int bpp,int mode)6628 static void blend_pixels(int start, int step, int cnt, const unsigned char *mask,
6629 	unsigned char *imgr, unsigned char *img0, unsigned char *img,
6630 	int bpp, int mode)
6631 {
6632 	static const unsigned char hhsv[8] = {
6633 		0x24, /* 0, 1, 2 = #0: B..M */
6634 		0x06, /* 2, 1, 0 = #1: M+..R- */
6635 		0x24, /* 0, 1, 2 = #2: B..M alt */
6636 		0x21, /* 1, 0, 2 = #3: C+..B- */
6637 		0x12, /* 2, 0, 1 = #4: G..C */
6638 		0x18, /* 0, 2, 1 = #5: Y+..G- */
6639 		0x09, /* 1, 2, 0 = #6: R..Y */
6640 		0x49  /* 1, 2, 0, 1 = #7: W */ };
6641 #define HHSV(X,N) (((X) >> ((N) * 2)) & 3)
6642 	const unsigned char *new, *old;
6643 	int j, step3, mx, uninit_(nhex), uninit_(ohex);
6644 
6645 
6646 	/* Backward transfer? */
6647 	if (mode & BLEND_REVERSE) new = img0 , old = img;
6648 	else new = img , old = img0;
6649 	mx = mode & BLENDF_IDX ? mem_cols - 1 : 255;
6650 	mode &= BLEND_MMASK;
6651 	if (bpp == 1) mode += BLEND_NMODES;
6652 
6653 	j = start - step;
6654 	mask += j;
6655 	j *= bpp;
6656 	step3 = step * bpp;
6657 	new += j; old += j;
6658 	while (cnt-- > 0)
6659 	{
6660 		unsigned char *dest;
6661 		int j0, j1, j2;
6662 
6663 		old += step3; new += step3; mask += step; j += step3;
6664 		if (!*mask) continue;
6665 
6666 		dest = imgr + j;
6667 
6668 		if (mode < BLEND_1BPP)
6669 		{
6670 			nhex = hhsv[(((0x200 + new[0]) - new[1]) ^
6671 				((0x400 + new[1]) - new[2]) ^
6672 				((0x100 + new[2]) - new[0])) >> 8];
6673 			ohex = hhsv[(((0x200 + old[0]) - old[1]) ^
6674 				((0x400 + old[1]) - old[2]) ^
6675 				((0x100 + old[2]) - old[0])) >> 8];
6676 		}
6677 
6678 		switch (mode)
6679 		{
6680 		case BLEND_HUE: /* HS* Hue */
6681 		{
6682 			int i;
6683 			unsigned char os, ov, ns;
6684 
6685 			ov = old[HHSV(ohex, 2)];
6686 
6687 			if (nhex & 0x40) /* New is white */
6688 			{
6689 				dest[0] = dest[1] = dest[2] = ov;
6690 				break;
6691 			}
6692 
6693 			os = old[HHSV(ohex, 1)];
6694 			ns = new[HHSV(nhex, 1)];
6695 
6696 			i = new[HHSV(nhex, 2)] - ns;
6697 			dest[HHSV(nhex, 0)] = (i + (ov - os) * 2 *
6698 				(new[HHSV(nhex, 0)] - ns)) / (i + i) + os;
6699 			dest[HHSV(nhex, 1)] = os;
6700 			dest[HHSV(nhex, 2)] = ov;
6701 			break;
6702 		}
6703 		case BLEND_SAT: /* HSV Saturation */
6704 		{
6705 			int i;
6706 			unsigned char ov, os, ns, nv;
6707 
6708 			if (ohex & 0x40) /* Old is white - leave it so */
6709 			{
6710 				dest[0] = old[0]; dest[1] = old[1]; dest[2] = old[2];
6711 				break;
6712 			}
6713 
6714 			ov = old[HHSV(ohex, 2)];
6715 
6716 			if (nhex & 0x40) /* New is white */
6717 			{
6718 				dest[0] = dest[1] = dest[2] = ov;
6719 				break;
6720 			}
6721 
6722 			os = old[HHSV(ohex, 1)];
6723 
6724 			nv = new[HHSV(nhex, 2)];
6725 			ns = (new[HHSV(nhex, 1)] * ov * 2 + nv) / (nv + nv);
6726 
6727 			i = ov - os;
6728 			dest[HHSV(ohex, 0)] = (i + (ov - ns) * 2 *
6729 				(old[HHSV(ohex, 0)] - os)) / (i + i) + ns;
6730 			dest[HHSV(ohex, 1)] = ns;
6731 			dest[HHSV(ohex, 2)] = ov;
6732 			break;
6733 		}
6734 		case BLEND_VALUE: /* HSV Value */
6735 		{
6736 			unsigned char ov, nv;
6737 
6738 			nv = new[HHSV(nhex, 2)];
6739 
6740 			if (ohex & 0x40) /* Old is white */
6741 			{
6742 				dest[0] = dest[1] = dest[2] = nv;
6743 				break;
6744 			}
6745 
6746 			ov = old[HHSV(ohex, 2)];
6747 
6748 			dest[HHSV(ohex, 0)] =
6749 				(old[HHSV(ohex, 0)] * nv * 2 + ov) / (ov + ov);
6750 			dest[HHSV(ohex, 1)] =
6751 				(old[HHSV(ohex, 1)] * nv * 2 + ov) / (ov + ov);
6752 			dest[HHSV(ohex, 2)] = nv;
6753 			break;
6754 		}
6755 		case BLEND_COLOR: /* HSL Hue + Saturation */
6756 		{
6757 			int x0, x1, y0, y1, vsy1, vs1y;
6758 			unsigned char os, ov;
6759 
6760 			os = old[HHSV(ohex, 1)];
6761 			ov = old[HHSV(ohex, 2)];
6762 			x0 = os + ov;
6763 
6764 			/* New is white */
6765 			if (nhex & 0x40)
6766 			{
6767 				dest[0] = dest[1] = dest[2] = (x0 + 1) >> 1;
6768 				break;
6769 			}
6770 
6771 			x1 = new[HHSV(nhex, 2)] + new[HHSV(nhex, 1)];
6772 
6773 			y1 = x1 > 255 ? 510 - x1 : x1;
6774 			vs1y = (x0 + 1) * y1;
6775 			y0 = x0 > 255 ? 510 - x0 : x0;
6776 			vsy1 = (new[HHSV(nhex, 2)] - new[HHSV(nhex, 1)]) * y0;
6777 			y1 += y1;
6778 
6779 			dest[HHSV(nhex, 0)] =
6780 				(vs1y + (new[HHSV(nhex, 0)] * 2 - x1) * y0) / y1;
6781 			dest[HHSV(nhex, 1)] = (vs1y - vsy1) / y1;
6782 			dest[HHSV(nhex, 2)] = (vs1y + vsy1) / y1;
6783 			break;
6784 		}
6785 		case BLEND_SATPP: /* Perceived saturation */
6786 		{
6787 			int i, xyz = (new[0] + new[1] + new[2]) / 3;
6788 
6789 			i = old[0] + new[0] - xyz;
6790 			dest[0] = i < 0 ? 0 : i > 255 ? 255 : i;
6791 			i = old[1] + new[1] - xyz;
6792 			dest[1] = i < 0 ? 0 : i > 255 ? 255 : i;
6793 			i = old[2] + new[2] - xyz;
6794 			dest[2] = i < 0 ? 0 : i > 255 ? 255 : i;
6795 			break;
6796 		}
6797 		case BLEND_SCREEN: // ~mult(~old, ~new)
6798 			j1 = (old[1] + new[1]) * 255 - old[1] * new[1];
6799 			dest[1] = (j1 + (j1 >> 8) + 1) >> 8;
6800 			j2 = (old[2] + new[2]) * 255 - old[2] * new[2];
6801 			dest[2] = (j2 + (j2 >> 8) + 1) >> 8;
6802 		case BLEND_SCREEN + BLEND_NMODES:
6803 			j0 = (old[0] + new[0]) * 255 - old[0] * new[0];
6804 			dest[0] = (j0 + (j0 >> 8) + 1) >> 8;
6805 			break;
6806 		case BLEND_MULT:
6807 			j1 = old[1] * new[1];
6808 			dest[1] = (j1 + (j1 >> 8) + 1) >> 8;
6809 			j2 = old[2] * new[2];
6810 			dest[2] = (j2 + (j2 >> 8) + 1) >> 8;
6811 		case BLEND_MULT + BLEND_NMODES:
6812 			j0 = old[0] * new[0];
6813 			dest[0] = (j0 + (j0 >> 8) + 1) >> 8;
6814 			break;
6815 		case BLEND_BURN: // ~div(~old, new)
6816 			j1 = ((unsigned char)~old[1] << 8) / (new[1] + 1);
6817 			dest[1] = 255 - j1 >= 0 ? 255 - j1 : 0;
6818 			j2 = ((unsigned char)~old[2] << 8) / (new[2] + 1);
6819 			dest[2] = 255 - j2 >= 0 ? 255 - j2 : 0;
6820 		case BLEND_BURN + BLEND_NMODES:
6821 			j0 = ((unsigned char)~old[0] << 8) / (new[0] + 1);
6822 			dest[0] = 255 - j0 >= 0 ? 255 - j0 : 0;
6823 			break;
6824 		case BLEND_DODGE: // div(old, ~new)
6825 			j1 = (old[1] << 8) / ((unsigned char)~new[1] + 1);
6826 			dest[1] = j1 < 255 ? j1 : 255;
6827 			j2 = (old[2] << 8) / ((unsigned char)~new[2] + 1);
6828 			dest[2] = j2 < 255 ? j2 : 255;
6829 		case BLEND_DODGE + BLEND_NMODES:
6830 			j0 = (old[0] << 8) / ((unsigned char)~new[0] + 1);
6831 			dest[0] = j0 < 255 ? j0 : 255;
6832 			break;
6833 		case BLEND_DIV:
6834 			j1 = (old[1] << 8) / (new[1] + 1);
6835 			dest[1] = j1 < 255 ? j1 : 255;
6836 			j2 = (old[2] << 8) / (new[2] + 1);
6837 			dest[2] = j2 < 255 ? j2 : 255;
6838 		case BLEND_DIV + BLEND_NMODES:
6839 			j0 = (old[0] << 8) / (new[0] + 1);
6840 			dest[0] = j0 < 255 ? j0 : 255;
6841 			break;
6842 		case BLEND_HLIGHT:
6843 			j1 = old[1] * new[1] * 2;
6844 			if (new[1] >= 128)
6845 				j1 = (old[1] + new[1]) * (255 * 2) - (255 * 255) - j1;
6846 			dest[1] = (j1 + (j1 >> 8) + 1) >> 8;
6847 			j2 = old[2] * new[2] * 2;
6848 			if (new[2] >= 128)
6849 				j2 = (old[2] + new[2]) * (255 * 2) - (255 * 255) - j2;
6850 			dest[2] = (j2 + (j2 >> 8) + 1) >> 8;
6851 		case BLEND_HLIGHT + BLEND_NMODES:
6852 			j0 = old[0] * new[0] * 2;
6853 			if (new[0] >= 128)
6854 				j0 = (old[0] + new[0]) * (255 * 2) - (255 * 255) - j0;
6855 			dest[0] = (j0 + (j0 >> 8) + 1) >> 8;
6856 			break;
6857 		case BLEND_SLIGHT:
6858 // !!! This formula is equivalent to one used in Pegtop XFader and GIMP,
6859 // !!! and differs from one used by Photoshop and PhotoPaint
6860 			j1 = old[1] * ((255 * 255) - (unsigned char)~old[1] *
6861 				(255 - (new[1] << 1)));
6862 			// Precise division by 255^2
6863 			j1 += j1 >> 7;
6864 			dest[1] = (j1 + ((j1 * 3 + 0x480) >> 16)) >> 16;
6865 			j2 = old[2] * ((255 * 255) - (unsigned char)~old[2] *
6866 				(255 - (new[2] << 1)));
6867 			j2 += j2 >> 7;
6868 			dest[2] = (j2 + ((j2 * 3 + 0x480) >> 16)) >> 16;
6869 		case BLEND_SLIGHT + BLEND_NMODES:
6870 			j0 = old[0] * ((255 * 255) - (unsigned char)~old[0] *
6871 				(255 - (new[0] << 1)));
6872 			j0 += j0 >> 7;
6873 			dest[0] = (j0 + ((j0 * 3 + 0x480) >> 16)) >> 16;
6874 			break;
6875 // "Negation" : ~BLEND_DIFF(~old, new)
6876 		case BLEND_DIFF:
6877 			dest[1] = abs(old[1] - new[1]);
6878 			dest[2] = abs(old[2] - new[2]);
6879 		case BLEND_DIFF + BLEND_NMODES:
6880 			dest[0] = abs(old[0] - new[0]);
6881 			break;
6882 		case BLEND_DARK:
6883 			dest[1] = old[1] < new[1] ? old[1] : new[1];
6884 			dest[2] = old[2] < new[2] ? old[2] : new[2];
6885 		case BLEND_DARK + BLEND_NMODES:
6886 			dest[0] = old[0] < new[0] ? old[0] : new[0];
6887 			break;
6888 		case BLEND_LIGHT:
6889 			dest[1] = old[1] > new[1] ? old[1] : new[1];
6890 			dest[2] = old[2] > new[2] ? old[2] : new[2];
6891 		case BLEND_LIGHT + BLEND_NMODES:
6892 			dest[0] = old[0] > new[0] ? old[0] : new[0];
6893 			break;
6894 		case BLEND_GRAINX:
6895 			j1 = old[1] - new[1] + 128;
6896 			dest[1] = j1 < 0 ? 0 : j1 > 255 ? 255 : j1;
6897 			j2 = old[2] - new[2] + 128;
6898 			dest[2] = j2 < 0 ? 0 : j2 > 255 ? 255 : j2;
6899 		case BLEND_GRAINX + BLEND_NMODES:
6900 			j0 = old[0] - new[0] + 128;
6901 			dest[0] = j0 < 0 ? 0 : j0 > 255 ? 255 : j0;
6902 			break;
6903 		case BLEND_GRAINM:
6904 			j1 = old[1] + new[1] - 128;
6905 			dest[1] = j1 < 0 ? 0 : j1 > 255 ? 255 : j1;
6906 			j2 = old[2] + new[2] - 128;
6907 			dest[2] = j2 < 0 ? 0 : j2 > 255 ? 255 : j2;
6908 		case BLEND_GRAINM + BLEND_NMODES:
6909 			j0 = old[0] + new[0] - 128;
6910 			dest[0] = j0 < 0 ? 0 : j0 > 255 ? 255 : j0;
6911 			break;
6912 		case BLEND_XHOLD:
6913 			dest[1] = (0xFFFF + new[1] - old[1]) >> 8;
6914 			dest[2] = (0xFFFF + new[2] - old[2]) >> 8;
6915 		case BLEND_XHOLD + BLEND_NMODES:
6916 			/* For indexed, upper limit is last palette index */
6917 			dest[0] = mx & ((0xFFFF + new[0] - old[0]) >> 8);
6918 			break;
6919 // Photoshop's "Linear light" is equivalent to XFader's "Stamp" with swapped A&B
6920 		default: /* RGB mode applied to 1bpp */
6921 			dest[0] = img0[j];
6922  			break;
6923 		}
6924 	}
6925 #undef HHSV
6926 }
6927 
put_pixel_def(int x,int y)6928 void put_pixel_def(int x, int y)	/* Combined */
6929 {
6930 	unsigned char *src, *ti, *old_image, *old_alpha = NULL;
6931 	unsigned char fmask, opacity = 255, cset[NUM_CHANNELS + 3];
6932 	int i, j, offset, idx, bpp, op = tool_opacity;
6933 
6934 
6935 	idx = IS_INDEXED;
6936 	j = pixel_protected(x, y);
6937 	if (idx ? j : j == 255) return;
6938 	bpp = MEM_BPP;
6939 	ti = cset + (bpp == 3 ? 0 : mem_channel + 3);
6940 
6941 	old_image = mem_undo_opacity ? mem_undo_previous(mem_channel) :
6942 		mem_img[mem_channel];
6943 	if ((mem_channel == CHN_IMAGE) && RGBA_mode)
6944 		old_alpha = mem_undo_opacity ? mem_undo_previous(CHN_ALPHA) :
6945 			mem_img[CHN_ALPHA];
6946 
6947 	offset = x + mem_width * y;
6948 
6949 	if (mem_gradient) /* Gradient mode - ask for one pixel */
6950 	{
6951 		fmask = 0; // Fake mask on input
6952 		grad_pixels(0, 1, 1, x, y, &fmask, &fmask, ti,
6953 			cset + CHN_ALPHA + 3);
6954 		if (!(op = fmask)) return;
6955 	}
6956 	else if (mem_blend && blend_src) /* Source mode - copy from layer */
6957 	{
6958 		cset[CHN_ALPHA + 3] = channel_col_A[CHN_ALPHA]; // Fake alpha
6959 		if ((blend_src == SRC_IMAGE) || // Same layer
6960 			(blend_src == SRC_LAYER + layer_selected))
6961 		{
6962 			if (bpp == 3) goto set3;
6963 			cset[mem_channel + 3] = old_image[offset];
6964 			goto seta;
6965 		}
6966 		else // Other layer
6967 		{
6968 			layer_node *t = layer_table + blend_src - SRC_LAYER;
6969 			image_info *img = &t->image->image_;
6970 			int u, w;
6971 
6972 			src = img->img[mem_channel];
6973 			if (!src) return; // Nothing here
6974 			w = img->width;
6975 			u = floor_mod(y - t->y, img->height) * w +
6976 				floor_mod(x - t->x, w);
6977 
6978 			if (mem_channel == CHN_IMAGE)
6979 			{
6980 				if (img->bpp > bpp) return; // Incompatible
6981 				if (img->bpp < bpp)
6982 				{
6983 					png_color *p = img->pal + src[u];
6984 					cset[0] = p->red;
6985 					cset[1] = p->green;
6986 					cset[2] = p->blue;
6987 				}
6988 				else if (bpp == 3)
6989 				{
6990 					src += u * 3;
6991 					cset[0] = src[0];
6992 					cset[1] = src[1];
6993 					cset[2] = src[2];
6994 				}
6995 				else cset[CHN_IMAGE + 3] = src[u];
6996 			}
6997 			else cset[mem_channel + 3] = src[u];
6998 			if ((src = img->img[CHN_ALPHA]))
6999 				cset[CHN_ALPHA + 3] = src[u];
7000 		}
7001 	}
7002 	/* Transform mode - copy from dest */
7003 	else if (mem_blend && (blend_mode & BLEND_XFORM) && (bpp == 3))
7004 	{
7005 set3:		src = old_image + offset * 3;
7006 		cset[0] = src[0];
7007 		cset[1] = src[1];
7008 		cset[2] = src[2];
7009 seta:		if (old_alpha) cset[CHN_ALPHA + 3] = old_alpha[offset];
7010 	}
7011 	else /* Default mode - init from pattern */
7012 	{
7013 		i = ((x & 7) + 8 * (y & 7));
7014 		cset[mem_channel + 3] = channel_col_[mem_pattern[i]][mem_channel];
7015 		cset[CHN_ALPHA + 3] = channel_col_[mem_pattern[i]][CHN_ALPHA];
7016 		cset[CHN_IMAGE + 3] = mem_col_pat[i]; /* !!! This must be last! */
7017 		i *= 3;
7018 		cset[0] = mem_col_pat24[i + 0];
7019 		cset[1] = mem_col_pat24[i + 1];
7020 		cset[2] = mem_col_pat24[i + 2];
7021 	}
7022 
7023 	if (!idx) // No use for opacity with indexed images
7024 	{
7025 		j = (255 - j) * op;
7026 		opacity = (j + (j >> 8) + 1) >> 8;
7027 	}
7028 
7029 	/* Coupled alpha channel */
7030 	if (old_alpha && mem_img[CHN_ALPHA])
7031 	{
7032 		unsigned char newc = cset[CHN_ALPHA + 3];
7033 
7034 		if (opacity < 255)
7035 		{
7036 			unsigned char oldc = old_alpha[offset];
7037 			int j = oldc * 255 + (newc - oldc) * opacity;
7038 
7039 			if (j && !channel_dis[CHN_ALPHA])
7040 				opacity = (255 * opacity * newc) / j;
7041 			newc = (j + (j >> 8) + 1) >> 8;
7042 		}
7043 		mem_img[CHN_ALPHA][offset] = newc;
7044 	}
7045 
7046 	offset *= bpp;
7047 	process_img(0, 1, 1, &opacity,
7048 		mem_img[mem_channel] + offset, old_image + offset, ti,
7049 		ti, bpp, 0);
7050 }
7051 
7052 /* Repeat pattern in buffer */
pattern_rep(unsigned char * dest,unsigned char * src,int ofs,int rep,int len,int bpp)7053 static void pattern_rep(unsigned char *dest, unsigned char *src,
7054 	int ofs, int rep, int len, int bpp)
7055 {
7056 	int l1;
7057 
7058 	ofs *= bpp; rep *= bpp; len *= bpp;
7059 	l1 = rep - ofs;
7060 	if (l1 > len) l1 = len;
7061 	memcpy(dest, src + ofs, l1);
7062 	if (!(len -= l1)) return;
7063 	dest += l1;
7064 	if ((len -= rep) > 0)
7065 	{
7066 		memcpy(dest, src, rep);
7067 		src = dest;
7068 		dest += rep;
7069 		while ((len -= rep) > 0)
7070 		{
7071 			memcpy(dest, src, rep);
7072 			dest += rep;
7073 			rep += rep;
7074 		}
7075 	}
7076 	memcpy(dest, src, len + rep);
7077 }
7078 
7079 /* Merge mask with selection */
mask_select(unsigned char * mask,unsigned char * xsel,int l)7080 static void mask_select(unsigned char *mask, unsigned char *xsel, int l)
7081 {
7082 	int i, j, k;
7083 
7084 	for (i = 0; i < l; i++)
7085 	{
7086 		k = mask[i] * (j = xsel[i]);
7087 		mask[i] = ((k + (k >> 8) + 1) >> 8) + 255 - j;
7088 	}
7089 }
7090 
7091 enum {
7092 	PP_DEF = 0,	// Default (pattern)
7093 	PP_OFS,		// Offset
7094 	PP_BUF,		// Buffer
7095 	PP_GRAD,	// Gradient
7096 	PP_LR,		// Layer
7097 	PP_L2R,		// Indexed layer to RGB
7098 	PP_LBUF		// Buffered layer
7099 };
7100 
7101 /* Faster function for large brushes and fills */
put_pixel_row_def(int x,int y,int len,unsigned char * xsel)7102 void put_pixel_row_def(int x, int y, int len, unsigned char *xsel)
7103 {
7104 	unsigned char tmp_image[ROW_BUFLEN * 3], mask[ROW_BUFLEN],
7105 		tmp_alpha[ROW_BUFLEN], tmp_opacity[ROW_BUFLEN],
7106 		*source_image = tmp_image, *source_alpha = NULL,
7107 		*source_opacity = NULL;
7108 	unsigned char *old_image, *old_alpha, *srcp, src1[8];
7109 	image_info *img = NULL;
7110 	int offset, use_mask, bpp, idx, uninit_(cx), cy, d = 0, s = ROW_BUFLEN;
7111 	int mode = PP_DEF;
7112 
7113 
7114 	if (len <= 0) return;
7115 
7116 	old_image = mem_undo_opacity ? mem_undo_previous(mem_channel) :
7117 		mem_img[mem_channel];
7118 	old_alpha = mem_undo_opacity ? mem_undo_previous(CHN_ALPHA) :
7119 		mem_img[CHN_ALPHA];
7120 
7121 	bpp = MEM_BPP; idx = IS_INDEXED;
7122 	use_mask = (mem_channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK];
7123 	if ((mem_channel == CHN_IMAGE) && RGBA_mode && mem_img[CHN_ALPHA])
7124 		source_alpha = tmp_alpha;
7125 
7126 	if (tool_type == TOOL_CLONE) /* Clone mode */
7127 	{
7128 		cy = y + clone_dy;
7129 		if ((cy < 0) || (cy >= mem_height)) return;
7130 		cx = x + clone_dx;
7131 		if (cx + len > mem_width) len = mem_width - cx;
7132 		if (cx < 0) len += cx , x -= cx;
7133 		if (len <= 0) return;
7134 		d = clone_dx + clone_dy * mem_width;
7135 		mode = PP_OFS; // Use offset
7136 		if (!clone_dy && (old_image == mem_img[mem_channel]))
7137 		{
7138 			mode = PP_BUF; // Use buffering
7139 			// Backward step in the rare case of unbufferable overlap
7140 			if ((clone_dx < 0) && (clone_dx > -len) && (len > ROW_BUFLEN))
7141 				x += len - ROW_BUFLEN , s = -ROW_BUFLEN;
7142 		}
7143 	}
7144 	else if (mem_gradient) mode = PP_GRAD; /* Gradient mode */
7145 	else if (mem_blend && blend_src) /* Source mode */
7146 	{
7147 		if ((blend_src == SRC_IMAGE) || // Same layer - use offset
7148 			(blend_src == SRC_LAYER + layer_selected)) mode = PP_OFS;
7149 		else // From other layer
7150 		{
7151 			layer_node *t = layer_table + blend_src - SRC_LAYER;
7152 			int u, w;
7153 
7154 			img = &t->image->image_;
7155 			if (!img->img[mem_channel]) return; // Nothing here
7156 
7157 			mode = PP_LR;
7158 			if (mem_channel == CHN_IMAGE)
7159 			{
7160 				if (img->bpp > bpp) return; // Incompatible
7161 				if (img->bpp < bpp) mode = PP_L2R; // Idx to RGB
7162 			}
7163 
7164 			w = img->width;
7165 			cx = floor_mod(x - t->x, w);
7166 			d = floor_mod(y - t->y, img->height) * w;
7167 			u = len;
7168 
7169 			if ((len > w) && (w <= ROW_BUFLEN / 2)) // Buffered repeat
7170 			{
7171 				u += cx;
7172 				if (u > ROW_BUFLEN) u = ROW_BUFLEN;
7173 
7174 				if (mode == PP_LR) memcpy(tmp_image,
7175 					img->img[mem_channel] + d * bpp, w * bpp);
7176 				else do_convert_rgb(0, 1, w, tmp_image,
7177 					img->img[CHN_IMAGE] + d, img->pal);
7178 				pattern_rep(tmp_image + w * bpp, tmp_image,
7179 					0, w, u - w, bpp);
7180 
7181 				if (source_alpha && img->img[CHN_ALPHA])
7182 					pattern_rep(tmp_alpha, img->img[CHN_ALPHA] + d,
7183 						0, w, u, 1);
7184 
7185 				mode = PP_LBUF;
7186 			}
7187 
7188 			/* Fake alpha */
7189 			if (source_alpha && !img->img[CHN_ALPHA])
7190 				memset(tmp_alpha, channel_col_A[CHN_ALPHA],
7191 					u > ROW_BUFLEN ? ROW_BUFLEN : u);
7192 		}
7193 	}
7194 	/* Transform mode - use offset */
7195 	else if (mem_blend && (blend_mode & BLEND_XFORM) && (bpp == 3)) mode = PP_OFS;
7196 // !!! This depends on buffer length being a multiple of pattern length
7197 	else /* Default mode - init buffer(s) from pattern */
7198 	{
7199 		int i, dy = 8 * (y & 7), l = len <= ROW_BUFLEN ? len : ROW_BUFLEN;
7200 
7201 		srcp = mem_pattern + dy;
7202 		if (source_alpha)
7203 		{
7204 			for (i = 0; i < 8; i++)
7205 				src1[i] = channel_col_[srcp[i]][CHN_ALPHA];
7206 			pattern_rep(tmp_alpha, src1, x & 7, 8, l, 1);
7207 		}
7208 		if (mem_channel != CHN_IMAGE)
7209 		{
7210 			for (i = 0; i < 8; i++)
7211 				src1[i] = channel_col_[srcp[i]][mem_channel];
7212 			srcp = src1;
7213 		}
7214 		else srcp = idx ? mem_col_pat + dy : mem_col_pat24 + dy * 3;
7215 		pattern_rep(tmp_image, srcp, x & 7, 8, l, bpp);
7216 	}
7217 
7218 	offset = x + mem_width * y;
7219 	idx ^= 1; // 0 if indexed, now
7220 	while (TRUE)
7221 	{
7222 		int l = len <= ROW_BUFLEN ? len : ROW_BUFLEN;
7223 
7224 		/* Offset mode */
7225 		if (mode == PP_OFS)
7226 		{
7227 			source_image = old_image + (offset + d) * bpp;
7228 			if (source_alpha) source_alpha = old_alpha + offset + d;
7229 		}
7230 		/* Buffered mode */
7231 		if (mode == PP_BUF)
7232 		{
7233 			memcpy(tmp_image, old_image + (offset + d) * bpp, l * bpp);
7234 			if (source_alpha)
7235 				memcpy(tmp_alpha, old_alpha + offset + d, l);
7236 		}
7237 		/* Layer mode, direct */
7238 		if ((mode == PP_LR) || (mode == PP_L2R))
7239 		{
7240 			int w = img->width;
7241 			if (l + cx > w) l = w - cx;
7242 			if (mode == PP_L2R) do_convert_rgb(0, 1, l, tmp_image,
7243 				img->img[CHN_IMAGE] + d + cx, img->pal);
7244 			else source_image = img->img[mem_channel] + (d + cx) * bpp;
7245 			if (source_alpha && img->img[CHN_ALPHA])
7246 				source_alpha = img->img[CHN_ALPHA] + d + cx;
7247 			cx = (cx + l) % w;
7248 			s = l;
7249 		}
7250 		/* Layer mode, buffered */
7251 		if (mode == PP_LBUF)
7252 		{
7253 			if (l + cx > ROW_BUFLEN) l = ROW_BUFLEN - cx;
7254 			source_image = tmp_image + cx * bpp;
7255 			if (source_alpha) source_alpha = tmp_alpha + cx;
7256 			cx = (cx + l) % img->width;
7257 			s = l;
7258 		}
7259 		/* Buffers stay unchanged for default mode */
7260 
7261 		/* Mask */
7262 		prep_mask(0, 1, l, mask,
7263 			use_mask ? mem_img[CHN_MASK] + offset : NULL,
7264 			mem_img[CHN_IMAGE] + offset * mem_img_bpp);
7265 
7266 		if (xsel)
7267 		{
7268 			mask_select(mask, xsel, l);
7269 			xsel += l;
7270 		}
7271 
7272 		/* Gradient mode */
7273 		if (mode == PP_GRAD) grad_pixels(0, 1, l, x, y, mask,
7274 			source_opacity = tmp_opacity, tmp_image, source_alpha);
7275 
7276 		process_mask(0, 1, l, mask,
7277 			mem_img[CHN_ALPHA] + offset,
7278 			old_alpha + offset, source_alpha, source_opacity,
7279 			idx * tool_opacity, channel_dis[CHN_ALPHA]);
7280 		process_img(0, 1, l, mask,
7281 			mem_img[mem_channel] + offset * bpp,
7282 			old_image + offset * bpp, source_image,
7283 			tmp_image, bpp, 0);
7284 
7285 		if ((len -= l) <= 0) return;
7286 		x += s;
7287 		offset += s;
7288 	}
7289 }
7290 
process_mask(int start,int step,int cnt,unsigned char * mask,unsigned char * alphar,unsigned char * alpha0,unsigned char * alpha,unsigned char * trans,int opacity,int noalpha)7291 void process_mask(int start, int step, int cnt, unsigned char *mask,
7292 	unsigned char *alphar, unsigned char *alpha0, unsigned char *alpha,
7293 	unsigned char *trans, int opacity, int noalpha)
7294 {
7295 	unsigned char *xalpha = NULL;
7296 	int i, j, k;
7297 
7298 	/* Use alpha as selection when pasting RGBA to RGB */
7299 	if (alpha && !alphar)
7300 	{
7301 		*(trans ? &xalpha : &trans) = alpha;
7302 		alpha = NULL;
7303 	}
7304 
7305 	i = start - step;
7306 	/* Opacity mode */
7307 	if (opacity)
7308 	{
7309 		while (cnt-- > 0)
7310 		{
7311 			unsigned char newc, oldc;
7312 
7313 			i += step;
7314 			k = (255 - mask[i]) * opacity;
7315 			if (!k)
7316 			{
7317 				mask[i] = 0;
7318 				continue;
7319 			}
7320 			k = (k + (k >> 8) + 1) >> 8;
7321 
7322 			if (trans) /* Have transparency mask */
7323 			{
7324 				if (xalpha) /* Have two :-) */
7325 				{
7326 					k *= xalpha[i];
7327 					k = (k + (k >> 8) + 1) >> 8;
7328 				}
7329 				k *= trans[i];
7330 				k = (k + (k >> 8) + 1) >> 8;
7331 			}
7332 			mask[i] = k;
7333 
7334 			if (!alpha || !k) continue;
7335 			/* Have coupled alpha channel - process it */
7336 			newc = alpha[i];
7337 			oldc = alpha0[i];
7338 			j = oldc * 255 + (newc - oldc) * k;
7339 			alphar[i] = (j + (j >> 8) + 1) >> 8;
7340 			if (noalpha) continue;
7341 			if (j) mask[i] = (255 * k * newc) / j;
7342 		}
7343 	}
7344 
7345 	/* Indexed mode - set mask to on-off */
7346 	else
7347 	{
7348 		while (cnt-- > 0)
7349 		{
7350 			i += step;
7351 			k = mask[i];
7352 			if (trans)
7353 			{
7354 				unsigned char oldc = trans[i];
7355 				if (xalpha) oldc &= xalpha[i];
7356 				k |= oldc ^ 255;
7357 			}
7358 			mask[i] = k = k ? 0 : 255;
7359 			if (!alpha || !k) continue;
7360 			/* Have coupled alpha channel - process it */
7361 			alphar[i] = alpha[i];
7362 		}
7363 	}
7364 }
7365 
process_img(int start,int step,int cnt,unsigned char * mask,unsigned char * imgr,unsigned char * img0,unsigned char * img,unsigned char * xbuf,int bpp,int blend)7366 void process_img(int start, int step, int cnt, unsigned char *mask,
7367 	unsigned char *imgr, unsigned char *img0, unsigned char *img,
7368 	unsigned char *xbuf, int bpp, int blend)
7369 {
7370 	int opm = 0;
7371 
7372 	/* Calculate drawing mode */
7373 	if (!(blend & BLENDF_SET))
7374 	{
7375 		blend = mem_blend ? blend_mode : 0;
7376 		if (tint_mode[0]) blend |= tint_mode[1] ^ (tint_mode[2] < 2) ?
7377 			BLENDF_TINTM : BLENDF_TINT;
7378 		if (IS_INDEXED) blend |= BLENDF_IDX;
7379 	}
7380 	if (blend & BLENDF_INVM) opm = 255;
7381 
7382 	/* Apply blend mode's transform parts */
7383 	// !!! Both calls ignore BLENDF_INVM, as are never combined with it
7384 	if ((blend & BLEND_XFORM) && (bpp == 3))
7385 	{
7386 		do_transform(start, step, cnt, mask, xbuf, img, 256);
7387 		img = xbuf;
7388 	}
7389 	if (blend & BLEND_MMASK)
7390 	{
7391 		blend_pixels(start, step, cnt, mask, xbuf, img0, img, bpp, blend);
7392 		img = xbuf;
7393 	}
7394 
7395 	/* Indexed image or utility channel */
7396 	if (bpp < 3)
7397 	{
7398 		unsigned char newc, oldc;
7399 		int i, j, mx = blend & BLENDF_IDX ? mem_cols - 1 : 255;
7400 
7401 		for (i = start; cnt-- > 0; i += step)
7402 		{
7403 			j = mask[i] ^ opm;
7404 			if (!j) continue;
7405 			newc = img[i];
7406 			oldc = img0[i];
7407 
7408 			if (!(blend & (BLENDF_TINTM | BLENDF_TINT))); // Do nothing
7409 			else if (blend & BLENDF_TINTM) newc = oldc + newc < mx ?
7410 				oldc + newc : mx;
7411 			else newc = oldc > newc ? oldc - newc : 0;
7412 
7413 			if (j < 255)
7414 			{
7415 				j = oldc * 255 + (newc - oldc) * j;
7416 				newc = (j + (j >> 8) + 1) >> 8;
7417 			}
7418 			imgr[i] = newc;
7419 		}
7420 	}
7421 
7422 	/* RGB image */
7423 	else
7424 	{
7425 		int ops = (blend >> BLEND_RGBSHIFT) & 7;
7426 		unsigned char r, g, b, nrgb[3];
7427 		int j, opacity;
7428 
7429 		/* Make mask */
7430 		ops = (ops + (ops >> 1) * 0xFE + (ops >> 2) * 0xFE00) * 0xFF;
7431 
7432 		img0 += (start - step) * 3;
7433 		img += (start - step) * 3;
7434 		imgr += (start - step) * 3;
7435 		mask += start - step;
7436 		while (cnt-- > 0)
7437 		{
7438 			img0 += step * 3; img += step * 3; imgr += step * 3;
7439 			mask += step;
7440 			opacity = *mask ^ opm;
7441 			if (!opacity) continue;
7442 			nrgb[0] = img[0];
7443 			nrgb[1] = img[1];
7444 			nrgb[2] = img[2];
7445 
7446 /* !!! On x86, register pressure here is too large already, so rereading img0
7447  * is preferable to lengthening r/g/b's living ranges - WJ */
7448 			if (blend & (BLENDF_TINTM | BLENDF_TINT))
7449 			{
7450 				r = img0[0];
7451 				g = img0[1];
7452 				b = img0[2];
7453 				if (blend & BLENDF_TINTM)
7454 				{
7455 					nrgb[0] = r > 255 - nrgb[0] ? 255 : r + nrgb[0];
7456 					nrgb[1] = g > 255 - nrgb[1] ? 255 : g + nrgb[1];
7457 					nrgb[2] = b > 255 - nrgb[2] ? 255 : b + nrgb[2];
7458 				}
7459 				else
7460 				{
7461 					nrgb[0] = r > nrgb[0] ? r - nrgb[0] : 0;
7462 					nrgb[1] = g > nrgb[1] ? g - nrgb[1] : 0;
7463 					nrgb[2] = b > nrgb[2] ? b - nrgb[2] : 0;
7464 				}
7465 			}
7466 
7467 			if (opacity == 255);
7468 			else if (paint_gamma)
7469 			{
7470 				double r, g, b, o = opacity / 255.0;
7471 
7472 				r = gamma256[img0[0]];
7473 				r += (gamma256[nrgb[0]] - r) * o;
7474 				g = gamma256[img0[1]];
7475 				g += (gamma256[nrgb[1]] - g) * o;
7476 				b = gamma256[img0[2]];
7477 				b += (gamma256[nrgb[2]] - b) * o;
7478 				nrgb[0] = UNGAMMA256(r);
7479 				nrgb[1] = UNGAMMA256(g);
7480 				nrgb[2] = UNGAMMA256(b);
7481 			}
7482 			else
7483 			{
7484 				r = img0[0];
7485 				g = img0[1];
7486 				b = img0[2];
7487 				j = r * 255 + (nrgb[0] - r) * opacity;
7488 				nrgb[0] = (j + (j >> 8) + 1) >> 8;
7489 				j = g * 255 + (nrgb[1] - g) * opacity;
7490 				nrgb[1] = (j + (j >> 8) + 1) >> 8;
7491 				j = b * 255 + (nrgb[2] - b) * opacity;
7492 				nrgb[2] = (j + (j >> 8) + 1) >> 8;
7493 			}
7494 
7495 			if (ops)
7496 			{
7497 				nrgb[0] ^= (nrgb[0] ^ img0[0]) & ops;
7498 				nrgb[1] ^= (nrgb[1] ^ img0[1]) & (ops >> 8);
7499 				nrgb[2] ^= (nrgb[2] ^ img0[2]) & (ops >> 16);
7500 			}
7501 
7502 			imgr[0] = nrgb[0];
7503 			imgr[1] = nrgb[1];
7504 			imgr[2] = nrgb[2];
7505 		}
7506 	}
7507 }
7508 
7509 /* !!! This assumes dest area lies entirely within src, its bpp matches src's
7510  * current channel bpp, and it has alpha channel only if src has it too */
copy_area(image_info * dest,image_info * src,int x,int y)7511 void copy_area(image_info *dest, image_info *src, int x, int y)
7512 {
7513 	int w = dest->width, h = dest->height, bpp = dest->bpp, ww = src->width;
7514 	int i, ofs, delta, len;
7515 
7516 	/* Current channel */
7517 	ofs = (y * ww + x) * bpp;
7518 	delta = 0;
7519 	len = w * bpp;
7520 	for (i = 0; i < h; i++)
7521 	{
7522 		memcpy(dest->img[CHN_IMAGE] + delta, src->img[mem_channel] + ofs, len);
7523 		ofs += ww * bpp;
7524 		delta += len;
7525 	}
7526 
7527 	/* Alpha channel */
7528 	if (!dest->img[CHN_ALPHA]) return;
7529 	ofs = y * ww + x;
7530 	delta = 0;
7531 	for (i = 0; i < h; i++)
7532 	{
7533 		memcpy(dest->img[CHN_ALPHA] + delta, src->img[CHN_ALPHA] + ofs, w);
7534 		ofs += ww;
7535 		delta += w;
7536 	}
7537 }
7538 
mem_count_all_cols()7539 int mem_count_all_cols()				// Count all colours - Using main image
7540 {
7541 	return mem_count_all_cols_real(mem_img[CHN_IMAGE], mem_width, mem_height);
7542 }
7543 
mem_count_all_cols_real(unsigned char * im,int w,int h)7544 int mem_count_all_cols_real(unsigned char *im, int w, int h)	// Count all colours - very memory greedy
7545 {
7546 	guint32 *tab;
7547 	int i, j, k, ix;
7548 
7549 	j = 0x80000;
7550 	tab = calloc(j, sizeof(guint32));	// HUGE colour cube
7551 	if (!tab) return -1;			// Not enough memory Mr Greedy ;-)
7552 
7553 	k = w * h;
7554 	for (i = 0; i < k; i++)			// Scan each pixel
7555 	{
7556 		ix = (im[0] >> 5) + (im[1] << 3) + (im[2] << 11);
7557 		tab[ix] |= 1U << (im[0] & 31);
7558 		im += 3;
7559 	}
7560 
7561 	// Count each colour
7562 	for (i = k = 0; i < j; i++) k += bitcount(tab[i]);
7563 
7564 	free(tab);
7565 
7566 	return k;
7567 }
7568 
mem_cols_used(png_color * pal)7569 int mem_cols_used(png_color *pal)	// Count and collect colours used in main RGB image
7570 {
7571 	if ( mem_img_bpp == 1 ) return -1;			// RGB only
7572 
7573 	return (mem_cols_used_real(mem_img[CHN_IMAGE], mem_width, mem_height, pal));
7574 }
7575 
mem_cols_used_real(unsigned char * im,int w,int h,png_color * pal)7576 int mem_cols_used_real(unsigned char *im, int w, int h, png_color *pal)
7577 			// Count and collect up to 256 colours used in RGB chunk
7578 {
7579 	rgb_256_map m;
7580 	int i, j = w * h, k, l, n, v, vn, res, pix;
7581 
7582 	memset(&m, 0, sizeof(m));
7583 	for (i = res = 0; i < j; i++ , im += 3) // Skim all pixels
7584 	{
7585 		pix = MEM_2_INT(im, 0);
7586 		k = pix & 0xFF;
7587 		n = (pix >> 8) & 0x1F;
7588 		v = pix >> (8 + 5);
7589 		/* Test presence on both tiers at once: if the 1st is unset,
7590 		 * the 2nd simply defaults to block #0 */
7591 		vn = m.rgx[v] * 32 + n;
7592 		l = m.vx[vn] * 8 + (k >> 5);
7593 		if ((m.rg[v] >> n) & 1 & (m.b[l] >> (k & 0x1F)))
7594 			continue;
7595 		/* New color - stop if too many */
7596 		if (++res > 256) break;
7597 		/* Insert into tiers */
7598 		if (!m.rg[v]) m.rgx[v] = m.nv++;
7599 		vn = m.rgx[v] * 32 + n;
7600 		if (!((m.rg[v] >> n) & 1))
7601 			m.vx[vn] = m.nb++ , m.rg[v] |= 1U << n;
7602 		l = m.vx[vn] * 8 + (k >> 5);
7603 		m.b[l] |= 1U << (k & 0x1F);
7604 		/* Add to palette */
7605 		if (!pal) continue;
7606 		pal->red = im[0];
7607 		pal->green = im[1];
7608 		pal->blue = im[2];
7609 		pal++;
7610 	}
7611 	return (res);
7612 }
7613 
7614 
7615 ////	EFFECTS
7616 
dist(int n1,int n2)7617 static inline double dist(int n1, int n2)
7618 {
7619 	return (sqrt(n1 * n1 + n2 * n2));
7620 }
7621 
do_effect(int type,int param)7622 void do_effect(int type, int param)
7623 {
7624 	unsigned char *src, *dest, *tmp, *mask, *buf;
7625 	int i, j, uninit_(k), k1, k2, bpp, ll, dxp1, dxm1, dyp1, dym1;
7626 	int op, md, ms;
7627 	double blur = (double)param / 200.0;
7628 
7629 	bpp = MEM_BPP;
7630 	ll = mem_width * bpp;
7631 	ms = bpp == 3 ? 1 : 4;
7632 
7633 	src = mem_undo_previous(mem_channel);
7634 	mask = malloc(mem_width * (bpp + 1));
7635 	if (!mask)
7636 	{
7637 		memory_errors(1);
7638 		return;
7639 	}
7640 	buf = mask + mem_width;
7641 
7642 	progress_init(_("Applying Effect"), 1);
7643 
7644 	for (i = 0; i < mem_height; i++)
7645 	{
7646 		row_protected(0, i, mem_width, tmp = mask);
7647 		dyp1 = i < mem_height - 1 ? ll : -ll;
7648 		dym1 = i ? -ll : ll;
7649 		dest = buf;
7650 		for (md = j = 0; j < ll; j++ , src++ , dest++)
7651 		{
7652 			op = *tmp;
7653 			/* One step for 1 or 3 bytes */
7654 			md += ms + (md >> 1);
7655 			tmp += md >> 2;
7656 			md &= 3;
7657 			if (op == 255) continue;
7658 			dxp1 = j < ll - bpp ? bpp : -bpp;
7659 			dxm1 = j >= bpp ? -bpp : bpp;
7660 			switch (type)
7661 			{
7662 			case FX_EDGE: /* Edge detect */
7663 				k = *src;
7664 				k = abs(k - src[dym1]) + abs(k - src[dyp1]) +
7665 					abs(k - src[dxm1]) + abs(k - src[dxp1]);
7666 				k += k >> 1;
7667 				break;
7668 			case FX_EMBOSS: /* Emboss */
7669 				k = src[dym1] + src[dxm1] +
7670 					src[dxm1 + dym1] + src[dxp1 + dym1];
7671 				k = k / 4 - *src + 127;
7672 				break;
7673 			case FX_SHARPEN: /* Edge sharpen */
7674 				k = src[dym1] + src[dyp1] +
7675 					src[dxm1] + src[dxp1] - 4 * src[0];
7676 				k = *src - blur * k;
7677 				break;
7678 			case FX_SOFTEN: /* Edge soften */
7679 				k = src[dym1] + src[dyp1] +
7680 					src[dxm1] + src[dxp1] - 4 * src[0];
7681 				k = *src + (5 * k) / (125 - param);
7682 				break;
7683 			case FX_SOBEL: /* Another edge detector */
7684 				k = dist((src[dxp1] - src[dxm1]) * 2 +
7685 					src[dym1 + dxp1] - src[dym1 + dxm1] +
7686 					src[dyp1 + dxp1] - src[dyp1 + dxm1],
7687 					(src[dyp1] - src[dym1]) * 2 +
7688 					src[dyp1 + dxm1] + src[dyp1 + dxp1] -
7689 					src[dym1 + dxm1] - src[dym1 + dxp1]);
7690 				break;
7691 			case FX_PREWITT: /* Yet another edge detector */
7692 /* Actually, the filter kernel used is "Robinson"; what is attributable to
7693  * Prewitt is "compass filtering", which can be done with other filter
7694  * kernels too - WJ */
7695 			case FX_KIRSCH: /* Compass detector with another kernel */
7696 /* Optimized compass detection algorithm: I calculate three values (compass,
7697  * plus and minus) and then mix them according to filter type - WJ */
7698 				k = 0;
7699 				k1 = src[dyp1 + dxm1] - src[dxp1];
7700 				if (k < k1) k = k1;
7701 				k1 += src[dyp1] - src[dym1 + dxp1];
7702 				if (k < k1) k = k1;
7703 				k1 += src[dyp1 + dxp1] - src[dym1];
7704 				if (k < k1) k = k1;
7705 				k1 += src[dxp1] - src[dym1 + dxm1];
7706 				if (k < k1) k = k1;
7707 				k1 += src[dym1 + dxp1] - src[dxm1];
7708 				if (k < k1) k = k1;
7709 				k1 += src[dym1] - src[dyp1 + dxm1];
7710 				if (k < k1) k = k1;
7711 				k1 += src[dym1 + dxm1] - src[dyp1];
7712 				if (k < k1) k = k1;
7713 				k1 = src[dym1 + dxm1] + src[dym1] + src[dym1 + dxp1] +
7714 					src[dxm1] + src[dxp1];
7715 				k2 = src[dyp1 + dxm1] + src[dyp1] + src[dyp1 + dxp1];
7716 				if (type == FX_PREWITT)
7717 					k = k * 2 + k1 - k2 - src[0] * 2;
7718 				else /* if (type == FX_KIRSCH) */
7719 					k = (k * 8 + k1 * 3 - k2 * 5) / 4;
7720 					// Division is for equalizing weight of edge
7721 				break;
7722 			case FX_GRADIENT: /* Still another edge detector */
7723 				k = 4.0 * dist(src[dxp1] - src[0],
7724 					src[dyp1] - src[0]);
7725 				break;
7726 			case FX_ROBERTS: /* One more edge detector */
7727 				k = 4.0 * dist(src[dyp1 + dxp1] - src[0],
7728 					src[dxp1] - src[dyp1]);
7729 				break;
7730 			case FX_LAPLACE: /* The last edge detector... I hope */
7731 				k = src[dym1 + dxm1] + src[dym1] + src[dym1 + dxp1] +
7732 					src[dxm1] - 8 * src[0] + src[dxp1] +
7733 					src[dyp1 + dxm1] + src[dyp1] + src[dyp1 + dxp1];
7734 				break;
7735 			case FX_MORPHEDGE: /* Morphological edge detection */
7736 			case FX_ERODE: /* Greyscale erosion */
7737 				k = src[0];
7738 				if (k > src[dym1 + dxm1]) k = src[dym1 + dxm1];
7739 				if (k > src[dym1]) k = src[dym1];
7740 				if (k > src[dym1 + dxp1]) k = src[dym1 + dxp1];
7741 				if (k > src[dxm1]) k = src[dxm1];
7742 				if (k > src[dxp1]) k = src[dxp1];
7743 				if (k > src[dyp1 + dxm1]) k = src[dyp1 + dxm1];
7744 				if (k > src[dyp1]) k = src[dyp1];
7745 				if (k > src[dyp1 + dxp1]) k = src[dyp1 + dxp1];
7746 				if (type == FX_MORPHEDGE)
7747 					k = (src[0] - k) * 2;
7748 				break;
7749 			case FX_DILATE: /* Greyscale dilation */
7750 				k = src[0];
7751 				if (k < src[dym1 + dxm1]) k = src[dym1 + dxm1];
7752 				if (k < src[dym1]) k = src[dym1];
7753 				if (k < src[dym1 + dxp1]) k = src[dym1 + dxp1];
7754 				if (k < src[dxm1]) k = src[dxm1];
7755 				if (k < src[dxp1]) k = src[dxp1];
7756 				if (k < src[dyp1 + dxm1]) k = src[dyp1 + dxm1];
7757 				if (k < src[dyp1]) k = src[dyp1];
7758 				if (k < src[dyp1 + dxp1]) k = src[dyp1 + dxp1];
7759 				break;
7760 			}
7761 			*dest = k < 0 ? 0 : k > 0xFF ? 0xFF : k;
7762 		}
7763 		dest = mem_img[mem_channel] + i * ll;
7764 		process_img(0, 1, mem_width, mask, dest, dest, buf,
7765 			NULL, bpp, BLENDF_SET | BLENDF_INVM);
7766 		if ((i * 10) % mem_height >= mem_height - 10)
7767 			if (progress_update((float)(i + 1) / mem_height)) break;
7768 	}
7769 	free(mask);
7770 	progress_end();
7771 }
7772 
7773 /* Apply vertical filter */
vert_gauss(unsigned char * chan,int w,int h,int y,double * temp,double * gaussY,int lenY,int gcor)7774 static void vert_gauss(unsigned char *chan, int w, int h, int y, double *temp,
7775 	double *gaussY, int lenY, int gcor)
7776 {
7777 	unsigned char *src0, *src1;
7778 	double gv = gaussY[0];
7779 	int j, k, mh2 = h > 1 ? h + h - 2 : 1;
7780 
7781 	src0 = chan + y * w;
7782 	if (gcor) /* Gamma-correct RGB values */
7783 	{
7784 		for (j = 0; j < w; j++) temp[j] = gamma256[src0[j]] * gv;
7785 	}
7786 	else /* Leave RGB values as they were */
7787 	{
7788 		for (j = 0; j < w; j++) temp[j] = src0[j] * gv;
7789 	}
7790 	for (j = 1; j < lenY; j++)
7791 	{
7792 		double gv = gaussY[j];
7793 
7794 		k = (y + j) % mh2;
7795 		if (k >= h) k = mh2 - k;
7796 		src0 = chan + k * w;
7797 		k = abs(y - j) % mh2;
7798 		if (k >= h) k = mh2 - k;
7799 		src1 = chan + k * w;
7800 		if (gcor) /* Gamma-correct */
7801 		{
7802 			for (k = 0; k < w; k++)
7803 			{
7804 				temp[k] += (gamma256[src0[k]] +
7805 					gamma256[src1[k]]) * gv;
7806 			}
7807 		}
7808 		else /* Leave alone */
7809 		{
7810 			for (k = 0; k < w; k++)
7811 			{
7812 				temp[k] += (src0[k] + src1[k]) * gv;
7813 			}
7814 		}
7815 	}
7816 }
7817 
7818 typedef struct {
7819 	double *gaussX, *gaussY, *temp;
7820 	unsigned char *mask;
7821 	int *idx;
7822 	int lenX, lenY;
7823 	int channel, gcor;
7824 	// For unsharp mask
7825 	int threshold;
7826 	double amount;
7827 } gaussd;
7828 
7829 /* Extend horizontal array, using precomputed indices */
gauss_extend(gaussd * gd,double * temp,int w,int bpp)7830 static void gauss_extend(gaussd *gd, double *temp, int w, int bpp)
7831 {
7832 	double *dest, *src;
7833 	int i, l = gd->lenX - 1, *tp = gd->idx;
7834 
7835 	dest = temp - l * bpp;
7836 	while (TRUE)
7837 	{
7838 		for (i = 0; i < l; i++ , dest += bpp)
7839 		{
7840 			src = temp + *tp++ * bpp;
7841 			dest[0] = src[0];
7842 			if (bpp == 1) continue;
7843 			dest[1] = src[1];
7844 			dest[2] = src[2];
7845 		}
7846 		if (dest != temp) break; // "w * bpp" is definitely nonzero
7847 		dest += w * bpp;
7848 	}
7849 }
7850 
7851 /* Apply RGB horizontal filter */
hor_gauss3(double * temp,int w,double * gaussX,int lenX,unsigned char * mask)7852 static void hor_gauss3(double *temp, int w, double *gaussX, int lenX,
7853 	unsigned char *mask)
7854 {
7855 	int j, jj, k, x1, x2;
7856 	double sum0, sum1, sum2;
7857 
7858 	for (j = jj = 0; jj < w; jj++ , j += 3)
7859 	{
7860 		if (mask[jj] == 255) continue;
7861 		sum0 = temp[j] * gaussX[0];
7862 		sum1 = temp[j + 1] * gaussX[0];
7863 		sum2 = temp[j + 2] * gaussX[0];
7864 		x1 = x2 = j;
7865 		for (k = 1; k < lenX; k++)
7866 		{
7867 			double gv = gaussX[k];
7868 			x1 -= 3; x2 += 3;
7869 			sum0 += (temp[x1] + temp[x2]) * gv;
7870 			sum1 += (temp[x1 + 1] + temp[x2 + 1]) * gv;
7871 			sum2 += (temp[x1 + 2] + temp[x2 + 2]) * gv;
7872 		}
7873 		temp[x1] = sum0;
7874 		temp[x1 + 1] = sum1;
7875 		temp[x1 + 2] = sum2;
7876 	}
7877 }
7878 
7879 // !!! Will need extra checks if used for out-of-range values
pack_row3(unsigned char * dest,const double * src,int w,int gcor,unsigned char * mask)7880 static void pack_row3(unsigned char *dest, const double *src, int w, int gcor,
7881 	unsigned char *mask)
7882 {
7883 	int j, jj, uninit_(k0), uninit_(k1), uninit_(k2), m;
7884 	double sum0, sum1, sum2, mm;
7885 
7886 	for (j = jj = 0; jj < w; jj++ , j += 3)
7887 	{
7888 		if (mask[jj] == 255) continue;
7889 		sum0 = src[j];
7890 		sum1 = src[j + 1];
7891 		sum2 = src[j + 2];
7892 		if (!gcor) /* Simply round to nearest */
7893 		{
7894 			k0 = rint(sum0);
7895 			k1 = rint(sum1);
7896 			k2 = rint(sum2);
7897 		}
7898 		m = mask[jj];
7899 		if (paint_gamma && m) /* Gamma corrected mask blend */
7900 		{
7901 			if (!gcor) // RGB to linear
7902 			{
7903 				sum0 = gamma256[k0];
7904 				sum1 = gamma256[k1];
7905 				sum2 = gamma256[k2];
7906 			}
7907 			mm = m / 255.0;
7908 			sum0 += (gamma256[dest[j + 0]] - sum0) * mm;
7909 			sum1 += (gamma256[dest[j + 1]] - sum1) * mm;
7910 			sum2 += (gamma256[dest[j + 2]] - sum2) * mm;
7911 			m = 0;
7912 			goto ungamma;
7913 		}
7914 		if (gcor) /* Reverse gamma correction */
7915 		{
7916 ungamma:		k0 = UNGAMMA256(sum0);
7917 			k1 = UNGAMMA256(sum1);
7918 			k2 = UNGAMMA256(sum2);
7919 		}
7920 		k0 = k0 * 255 + (dest[j] - k0) * m;
7921 		dest[j] = (k0 + (k0 >> 8) + 1) >> 8;
7922 		k1 = k1 * 255 + (dest[j + 1] - k1) * m;
7923 		dest[j + 1] = (k1 + (k1 >> 8) + 1) >> 8;
7924 		k2 = k2 * 255 + (dest[j + 2] - k2) * m;
7925 		dest[j + 2] = (k2 + (k2 >> 8) + 1) >> 8;
7926 	}
7927 }
7928 
7929 /* Most-used variables are local to inner blocks to shorten their live ranges -
7930  * otherwise stupid compilers might allocate them to memory */
gauss_filter(tcb * thread)7931 static void gauss_filter(tcb *thread)
7932 {
7933 	gaussd *gd = thread->data;
7934 	int lenX = gd->lenX, gcor = gd->gcor, channel = gd->channel;
7935 	int i, ii, cnt, wid, bpp;
7936 	double sum, *temp, *gaussX = gd->gaussX;
7937 	unsigned char *chan, *dest, *mask = gd->mask;
7938 
7939 	cnt = thread->nsteps;
7940 	bpp = BPP(channel);
7941 	wid = mem_width * bpp;
7942 	chan = mem_undo_previous(channel);
7943 	temp = gd->temp + (lenX - 1) * bpp;
7944 	for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
7945 	{
7946 		vert_gauss(chan, wid, mem_height, i, temp, gd->gaussY, gd->lenY, gcor);
7947 		gauss_extend(gd, temp, mem_width, bpp);
7948 		row_protected(0, i, mem_width, mask);
7949 		dest = mem_img[channel] + i * wid;
7950 		if (bpp == 3) /* Run 3-bpp horizontal filter */
7951 		{
7952 			hor_gauss3(temp, mem_width, gaussX, lenX, mask);
7953 			pack_row3(dest, gd->temp, mem_width, gcor, mask);
7954 		}
7955 		else /* Run 1-bpp horizontal filter - no gamma here */
7956 		{
7957 			int j, k, k0;
7958 
7959 			for (j = 0; j < mem_width; j++)
7960 			{
7961 				if (mask[j] == 255) continue;
7962 				sum = temp[j] * gaussX[0];
7963 				for (k = 1; k < lenX; k++)
7964 				{
7965 					sum += (temp[j - k] + temp[j + k]) * gaussX[k];
7966 				}
7967 				k0 = rint(sum);
7968 				k0 = k0 * 255 + (dest[j] - k0) * mask[j];
7969 				dest[j] = (k0 + (k0 >> 8) + 1) >> 8;
7970 			}
7971 		}
7972 		if (thread_step(thread, ii + 1, cnt, 10)) break;
7973 	}
7974 	thread_done(thread);
7975 }
7976 
7977 /* The inner loops are coded the way they are because one must spell everything
7978  * out for dumb compiler to get acceptable code out of it */
gauss_filter_rgba(tcb * thread)7979 static void gauss_filter_rgba(tcb *thread)
7980 {
7981 	gaussd *gd = thread->data;
7982 	int i, ii, cnt, mh2, lenX = gd->lenX, lenY = gd->lenY, gcor = gd->gcor;
7983 	double sum, sum1, sum2, mult, *temp, *tmpa, *atmp, *src, *gaussX, *gaussY;
7984 	unsigned char *chan, *dest, *alpha, *dsta, *mask = gd->mask;
7985 
7986 	cnt = thread->nsteps;
7987 	chan = mem_undo_previous(CHN_IMAGE);
7988 	alpha = mem_undo_previous(CHN_ALPHA);
7989 	gaussX = gd->gaussX;
7990 	gaussY = gd->gaussY;
7991 	temp = gd->temp + (lenX - 1) * 3;
7992 	mh2 = mem_height > 1 ? 2 * mem_height - 2 : 1;
7993 
7994 	/* Set up the main row buffer and process the image */
7995 	tmpa = temp + mem_width * 3 + (lenX - 1) * (3 + 3);
7996 	atmp = tmpa + mem_width * 3 + (lenX - 1) * (3 + 1);
7997 	for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
7998 	{
7999 		/* Apply vertical filter */
8000 		{
8001 			unsigned char *srcc, *src0, *src1;
8002 			unsigned char *alff, *alf0, *alf1;
8003 			int j, k;
8004 
8005 			alff = alpha + i * mem_width;
8006 			srcc = chan + i * mem_width * 3;
8007 			if (gcor) /* Gamma correct */
8008 			{
8009 				double gk = gaussY[0];
8010 				int j, jj;
8011 
8012 				for (j = jj = 0; j < mem_width; j++)
8013 				{
8014 					double ak, tv;
8015 
8016 					atmp[j] = ak = alff[j] * gk;
8017 					temp[jj] = (tv = gamma256[srcc[jj]]) * gk;
8018 					tmpa[jj++] = tv * ak;
8019 					temp[jj] = (tv = gamma256[srcc[jj]]) * gk;
8020 					tmpa[jj++] = tv * ak;
8021 					temp[jj] = (tv = gamma256[srcc[jj]]) * gk;
8022 					tmpa[jj++] = tv * ak;
8023 				}
8024 			}
8025 			else /* Use as is */
8026 			{
8027 				double gk = gaussY[0];
8028 				int j, jj;
8029 
8030 				for (j = jj = 0; j < mem_width; j++)
8031 				{
8032 					double ak, tv;
8033 
8034 					atmp[j] = ak = alff[j] * gk;
8035 					temp[jj] = (tv = srcc[jj]) * gk;
8036 					tmpa[jj++] = tv * ak;
8037 					temp[jj] = (tv = srcc[jj]) * gk;
8038 					tmpa[jj++] = tv * ak;
8039 					temp[jj] = (tv = srcc[jj]) * gk;
8040 					tmpa[jj++] = tv * ak;
8041 				}
8042 			}
8043 			for (j = 1; j < lenY; j++)
8044 			{
8045 				double gk = gaussY[j];
8046 
8047 				k = (i + j) % mh2;
8048 				if (k >= mem_height) k = mh2 - k;
8049 				alf0 = alpha + k * mem_width;
8050 				src0 = chan + k * mem_width * 3;
8051 				k = abs(i - j) % mh2;
8052 				if (k >= mem_height) k = mh2 - k;
8053 				alf1 = alpha + k * mem_width;
8054 				src1 = chan + k * mem_width * 3;
8055 				if (gcor) /* Gamma correct */
8056 				{
8057 					int k, kk;
8058 
8059 					for (k = kk = 0; k < mem_width; k++)
8060 					{
8061 						double ak0, ak1, tv0, tv1;
8062 
8063 						ak0 = alf0[k] * gk;
8064 						ak1 = alf1[k] * gk;
8065 						atmp[k] += ak0 + ak1;
8066 						tv0 = gamma256[src0[kk]];
8067 						tv1 = gamma256[src1[kk]];
8068 						temp[kk] += (tv0 + tv1) * gk;
8069 						tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8070 						tv0 = gamma256[src0[kk]];
8071 						tv1 = gamma256[src1[kk]];
8072 						temp[kk] += (tv0 + tv1) * gk;
8073 						tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8074 						tv0 = gamma256[src0[kk]];
8075 						tv1 = gamma256[src1[kk]];
8076 						temp[kk] += (tv0 + tv1) * gk;
8077 						tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8078 					}
8079 				}
8080 				else /* Use as is */
8081 				{
8082 					int k, kk;
8083 
8084 					for (k = kk = 0; k < mem_width; k++)
8085 					{
8086 						double ak0, ak1, tv0, tv1;
8087 
8088 						ak0 = alf0[k] * gk;
8089 						ak1 = alf1[k] * gk;
8090 						atmp[k] += ak0 + ak1;
8091 						tv0 = src0[kk];
8092 						tv1 = src1[kk];
8093 						temp[kk] += (tv0 + tv1) * gk;
8094 						tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8095 						tv0 = src0[kk];
8096 						tv1 = src1[kk];
8097 						temp[kk] += (tv0 + tv1) * gk;
8098 						tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8099 						tv0 = src0[kk];
8100 						tv1 = src1[kk];
8101 						temp[kk] += (tv0 + tv1) * gk;
8102 						tmpa[kk++] += tv0 * ak0 + tv1 * ak1;
8103 					}
8104 				}
8105 			}
8106 		}
8107 		gauss_extend(gd, temp, mem_width, 3);
8108 		gauss_extend(gd, tmpa, mem_width, 3);
8109 		gauss_extend(gd, atmp, mem_width, 1);
8110 		row_protected(0, i, mem_width, mask);
8111 		dest = mem_img[CHN_IMAGE] + i * mem_width * 3;
8112 		dsta = mem_img[CHN_ALPHA] + i * mem_width;
8113 		/* Horizontal RGBA filter */
8114 		{
8115 			int j, jj, k, kk, x1, x2;
8116 
8117 			for (j = jj = 0; j < mem_width; j++ , jj += 3)
8118 			{
8119 				if (mask[j] == 255) continue;
8120 
8121 				sum = atmp[j] * gaussX[0];
8122 				for (k = 1; k < lenX; k++)
8123 				{
8124 					sum += (atmp[j - k] + atmp[j + k]) * gaussX[k];
8125 				}
8126 				k = rint(sum);
8127 				src = temp;
8128 				mult = 1.0;
8129 				if (k)
8130 				{
8131 					src = tmpa;
8132 					mult /= sum;
8133 				}
8134 				kk = mask[j];
8135 				k = k * 255 + (dsta[j] - k) * kk;
8136 				if (k) mask[j] = (255 * kk * dsta[j]) / k;
8137 				dsta[j] = (k + (k >> 8) + 1) >> 8;
8138 
8139 				sum = src[jj] * gaussX[0];
8140 				sum1 = src[jj + 1] * gaussX[0];
8141 				sum2 = src[jj + 2] * gaussX[0];
8142 				x1 = x2 = jj;
8143 				for (k = 1; k < lenX; k++)
8144 				{
8145 					double gv = gaussX[k];
8146 					x1 -= 3; x2 += 3;
8147 					sum += (src[x1] + src[x2]) * gv;
8148 					sum1 += (src[x1 + 1] + src[x2 + 1]) * gv;
8149 					sum2 += (src[x1 + 2] + src[x2 + 2]) * gv;
8150 				}
8151 				temp[x1] = sum * mult;
8152 				temp[x1 + 1] = sum1 * mult;
8153 				temp[x1 + 2] = sum2 * mult;
8154 			}
8155 			pack_row3(dest, gd->temp, mem_width, gcor, mask);
8156 		}
8157 		if (thread_step(thread, ii + 1, cnt, 10)) break;
8158 	}
8159 	thread_done(thread);
8160 }
8161 
8162 /* Modes: 0 - normal, 1 - RGBA, 2 - DoG */
init_gauss(gaussd * gd,double radiusX,double radiusY,int mode)8163 static threaddata *init_gauss(gaussd *gd, double radiusX, double radiusY, int mode)
8164 {
8165 	threaddata *tdata;
8166 	int i, j, k, l, lenX, lenY, w, bpp = MEM_BPP;
8167 	double sum, exkX, exkY, *gauss;
8168 
8169 
8170 	/* Cutoff point is where gaussian becomes < 1/255 */
8171 	gd->lenX = lenX = ceil(radiusX) + 2;
8172 	gd->lenY = lenY = ceil(radiusY) + 2;
8173 	exkX = -log(255.0) / ((radiusX + 1.0) * (radiusX + 1.0));
8174 	exkY = -log(255.0) / ((radiusY + 1.0) * (radiusY + 1.0));
8175 
8176 	/* Allocate memory */
8177 	if (mode == 1) i = 7;			/* Extra linebuffer for RGBA */
8178 	else if (mode == 2) i = bpp + bpp;	/* Extra buffer in DoG mode */
8179 	else i = bpp;
8180 	l = 2 * (lenX - 1);
8181 	w = mem_width + l;
8182 
8183 	tdata = talloc(MA_ALIGN_DOUBLE,
8184 		image_threads(mem_width, mem_height),
8185 		gd, sizeof(gaussd),
8186 		&gd->gaussX, lenX * sizeof(double),
8187 		&gd->gaussY, lenY * sizeof(double),
8188 		&gd->idx, l * sizeof(int),
8189 		NULL,
8190 		&gd->temp, i * w * sizeof(double),
8191 		&gd->mask, mem_width,
8192 		NULL);
8193 	if (!tdata) return (NULL);
8194 
8195 	/* Prepare filters */
8196 	j = lenX; gauss = gd->gaussX;
8197 	while (1)
8198 	{
8199 		sum = gauss[0] = 1.0;
8200 		for (i = 1; i < j; i++)
8201 		{
8202 			sum += 2.0 * (gauss[i] = exp((double)(i * i) * exkX));
8203 		}
8204 		sum = 1.0 / sum;
8205 		for (i = 0; i < j; i++)
8206 		{
8207 			gauss[i] *= sum;
8208 		}
8209 		if (gauss != gd->gaussX) break;
8210 		exkX = exkY; j = lenY; gauss = gd->gaussY;
8211 	}
8212 
8213 	/* Prepare horizontal indices, assuming mirror boundary */
8214 	if (mem_width > 1) // Else, good already (zeroed out)
8215 	{
8216 		int *idx = gd->idx + lenX - 1; // To simplify indexing
8217 
8218 		k = 2 * mem_width - 2;
8219 		for (i = 1; i < lenX; i++)
8220 		{
8221 			j = i % k;
8222 			idx[-i] = j < mem_width ? j : k - j;
8223 			j = (mem_width + i - 1) % k;
8224 			idx[i - 1] = j < mem_width ? j : k - j;
8225 
8226 		}
8227 	}
8228 	return (tdata);
8229 }
8230 
8231 /* Gaussian blur */
mem_gauss(double radiusX,double radiusY,int gcor)8232 void mem_gauss(double radiusX, double radiusY, int gcor)
8233 {
8234 	gaussd gd;
8235 	threaddata *tdata;
8236 	int rgba, rgbb;
8237 
8238 	/* RGBA or not? */
8239 	rgba = (mem_channel == CHN_IMAGE) && mem_img[CHN_ALPHA] && RGBA_mode;
8240 	rgbb = rgba && !channel_dis[CHN_ALPHA];
8241 
8242 	/* Create arrays */
8243 	if (mem_channel != CHN_IMAGE) gcor = FALSE;
8244 	gd.gcor = gcor;
8245 	gd.channel = mem_channel;
8246 	tdata = init_gauss(&gd, radiusX, radiusY, rgbb);
8247 	if (!tdata)
8248 	{
8249 		memory_errors(1);
8250 		return;
8251 	}
8252 
8253 	progress_init(_("Gaussian Blur"), 1);
8254 	if (rgbb) /* Coupled RGBA */
8255 		launch_threads(gauss_filter_rgba, tdata, NULL, mem_height);
8256 	else /* One channel, or maybe two */
8257 	{
8258 		launch_threads(gauss_filter, tdata, NULL, mem_height);
8259 		if (rgba) /* Need to process alpha too */
8260 		{
8261 #ifdef U_THREADS
8262 			int i, j = tdata->count;
8263 
8264 			for (i = 0; i < j; i++)
8265 			{
8266 				gaussd *gp = tdata->threads[i]->data;
8267 				gp->channel = CHN_ALPHA;
8268 				gp->gcor = FALSE;
8269 			}
8270 #else
8271 			gaussd *gp = tdata->threads[0]->data;
8272 			gp->channel = CHN_ALPHA;
8273 			gp->gcor = FALSE;
8274 #endif
8275 			launch_threads(gauss_filter, tdata, NULL, mem_height);
8276 		}
8277 	}
8278 	progress_end();
8279 	free(tdata);
8280 }
8281 
unsharp_filter(tcb * thread)8282 static void unsharp_filter(tcb *thread)
8283 {
8284 	gaussd *gd = thread->data;
8285 	int lenX = gd->lenX, threshold = gd->threshold, channel = gd->channel;
8286 	int i, ii, cnt, wid, bpp, gcor = gd->gcor;
8287 	double *temp, *gaussX = gd->gaussX, *gt = gd->temp;
8288 	double sum, amount = gd->amount, u = gcor ? 1.0 : 255.0;
8289 	unsigned char *chan, *dest, *mask = gd->mask;
8290 
8291 	cnt = thread->nsteps;
8292 	bpp = BPP(channel);
8293 	wid = mem_width * bpp;
8294 	chan = mem_undo_previous(channel);
8295 	temp = gd->temp + (lenX - 1) * bpp;
8296 	for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
8297 	{
8298 		vert_gauss(chan, wid, mem_height, i, temp, gd->gaussY, gd->lenY, gcor);
8299 		gauss_extend(gd, temp, mem_width, bpp);
8300 		row_protected(0, i, mem_width, mask);
8301 		dest = mem_img[channel] + i * wid;
8302 		if (bpp == 3) /* Run 3-bpp horizontal filter */
8303 		{
8304 			int j, jj, k, k1, k2;
8305 
8306 			hor_gauss3(temp, mem_width, gaussX, lenX, mask);
8307 			/* Threshold to mask */
8308 			if (threshold) for (j = jj = 0; jj < mem_width; jj++ , j += 3)
8309 			{
8310 				if (mask[jj] == 255) continue;
8311 				if (gcor) /* Reverse gamma correction */
8312 				{
8313 					k = UNGAMMA256(gt[j]);
8314 					k1 = UNGAMMA256(gt[j + 1]);
8315 					k2 = UNGAMMA256(gt[j + 2]);
8316 				}
8317 				else /* Simply round to nearest */
8318 				{
8319 					k = rint(gt[j]);
8320 					k1 = rint(gt[j + 1]);
8321 					k2 = rint(gt[j + 2]);
8322 				}
8323 	/* !!! GIMP has an apparent bug which I won't reproduce - so mtPaint's
8324 	 * threshold value means _actual_ difference, not half of it - WJ */
8325 				if ((abs(k - dest[j]) < threshold) &&
8326 					(abs(k1 - dest[j + 1]) < threshold) &&
8327 					(abs(k2 - dest[j + 2]) < threshold))
8328 					mask[jj] = 255;
8329 			}
8330 
8331 			/* !!! Mask is ignored here - but this pass takes about
8332 			 * 25% time at worst, and masking adds 5% time at best;
8333 			 * so the common case of no mask is optimized for - WJ */
8334 			k = mem_width * 3;
8335 			for (j = 0; j < k; j++)
8336 			{
8337 				sum = gcor ? gamma256[dest[j]] : dest[j];
8338 				sum += amount * (sum - gt[j]);
8339 				/* Limit values, for pack_row3() cannot */
8340 				gt[j] = sum < 0.0 ? 0.0 : sum > u ? u : sum;
8341 			}
8342 
8343 			pack_row3(dest, gt, mem_width, gcor, mask);
8344 		}
8345 		else /* Run 1-bpp horizontal filter - no gamma here */
8346 		{
8347 			int j, k;
8348 
8349 			for (j = 0; j < mem_width; j++)
8350 			{
8351 				if (mask[j] == 255) continue;
8352 				sum = temp[j] * gaussX[0];
8353 				for (k = 1; k < lenX; k++)
8354 				{
8355 					sum += (temp[j - k] + temp[j + k]) * gaussX[k];
8356 				}
8357 				k = rint(sum);
8358 				/* Threshold */
8359 				/* !!! Same non-bug as above */
8360 				if (abs(k - dest[j]) < threshold) continue;
8361 				/* Combine values */
8362 				k = rint(dest[j] + amount * (dest[j] - sum));
8363 				k = k < 0 ? 0 : k > 255 ? 255 : k;
8364 				/* Store the result */
8365 				k = k * 255 + (dest[j] - k) * mask[j];
8366 				dest[j] = (k + (k >> 8) + 1) >> 8;
8367 			}
8368 		}
8369 		if (thread_step(thread, ii + 1, cnt, 10)) break;
8370 	}
8371 	thread_done(thread);
8372 }
8373 
8374 /* Unsharp mask */
mem_unsharp(double radius,double amount,int threshold,int gcor)8375 void mem_unsharp(double radius, double amount, int threshold, int gcor)
8376 {
8377 	gaussd gd;
8378 	threaddata *tdata;
8379 
8380 	/* Create arrays */
8381 	if (mem_channel != CHN_IMAGE) gcor = 0;
8382 	gd.gcor = gcor;
8383 	gd.channel = mem_channel;
8384 	gd.amount = amount;
8385 	gd.threshold = threshold;
8386 // !!! No RGBA mode for now
8387 	tdata = init_gauss(&gd, radius, radius, 0);
8388 	if (!tdata)
8389 	{
8390 		memory_errors(1);
8391 		return;
8392 	}
8393 	/* Run filter */
8394 	launch_threads(unsharp_filter, tdata, _("Unsharp Mask"), mem_height);
8395 	free(tdata);
8396 }
8397 
8398 /* Retroactive masking - by blending with undo frame */
mask_merge(unsigned char * old,int channel,unsigned char * mask)8399 void mask_merge(unsigned char *old, int channel, unsigned char *mask)
8400 {
8401 	chanlist tlist;
8402 	unsigned char *dest, *mask0 = NULL;
8403 	int i, ofs, bpp = BPP(channel);
8404 
8405 	memcpy(tlist, mem_img, sizeof(chanlist));
8406 	tlist[channel] = old;
8407 
8408 	/* Clear mask or copy mask channel into it */
8409 	if ((channel <= CHN_ALPHA) && mem_img[CHN_MASK] && !channel_dis[CHN_MASK])
8410 		mask0 = tlist[CHN_MASK];
8411 
8412 	for (i = 0; i < mem_height; i++)
8413 	{
8414 		ofs = i * mem_width;
8415 		prep_mask(0, 1, mem_width, mask, mask0 ? mask0 + ofs : NULL,
8416 			tlist[CHN_IMAGE] + ofs * mem_img_bpp);
8417 		dest = mem_img[channel] + ofs * bpp;
8418 		process_img(0, 1, mem_width, mask, dest, dest, old + ofs * bpp,
8419 			NULL, bpp, BLENDF_SET);
8420 	}
8421 }
8422 
dog_filter(tcb * thread)8423 static void dog_filter(tcb *thread)
8424 {
8425 	gaussd *gd = thread->data;
8426 	int channel = gd->channel, bpp = BPP(channel), wid = mem_width * bpp;
8427 	int i, ii, cnt, gcor = gd->gcor;
8428 	int lenW = gd->lenX, lenN = gd->lenY;
8429 	double sum, sum1, sum2, *tmp1, *tmp2;
8430 	double *gaussW = gd->gaussX, *gaussN = gd->gaussY;
8431 	unsigned char *chan, *dest;
8432 
8433 	cnt = thread->nsteps;
8434 	chan = mem_undo_previous(channel);
8435 	tmp1 = gd->temp + (lenW - 1) * bpp;
8436 	tmp2 = tmp1 + wid + (lenW - 1) * bpp * 2;
8437 	for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
8438 	{
8439 		vert_gauss(chan, wid, mem_height, i, tmp1, gaussW, lenW, gcor);
8440 		vert_gauss(chan, wid, mem_height, i, tmp2, gaussN, lenN, gcor);
8441 		gauss_extend(gd, tmp1, mem_width, bpp);
8442 		gauss_extend(gd, tmp2, mem_width, bpp);
8443 		dest = mem_img[channel] + i * wid;
8444 		if (bpp == 3) /* Run 3-bpp horizontal filter */
8445 		{
8446 			int j, jj, k, k1, k2;
8447 
8448 			for (j = jj = 0; jj < mem_width; jj++ , j += 3)
8449 			{
8450 				int x1, x2, x3, x4;
8451 
8452 				sum = tmp1[j] * gaussW[0] - tmp2[j] * gaussN[0];
8453 				sum1 = tmp1[j + 1] * gaussW[0] - tmp2[j + 1] * gaussN[0];
8454 				sum2 = tmp1[j + 2] * gaussW[0] - tmp2[j + 2] * gaussN[0];
8455 				x1 = x2 = j;
8456 				for (k = 1; k < lenW; k++)
8457 				{
8458 					double gv = gaussW[k];
8459 					x1 -= 3; x2 += 3;
8460 					sum += (tmp1[x1] + tmp1[x2]) * gv;
8461 					sum1 += (tmp1[x1 + 1] + tmp1[x2 + 1]) * gv;
8462 					sum2 += (tmp1[x1 + 2] + tmp1[x2 + 2]) * gv;
8463 				}
8464 				x3 = x4 = j;
8465 				for (k = 1; k < lenN; k++)
8466 				{
8467 					double gv = gaussN[k];
8468 					x3 -= 3; x4 += 3;
8469 					sum -= (tmp2[x3] + tmp2[x4]) * gv;
8470 					sum1 -= (tmp2[x3 + 1] + tmp2[x4 + 1]) * gv;
8471 					sum2 -= (tmp2[x3 + 2] + tmp2[x4 + 2]) * gv;
8472 				}
8473 				if (gcor)
8474 				{
8475 #if 1 /* Reverse gamma - but does it make sense? */
8476 					k = UNGAMMA256X(sum);
8477 					k1 = UNGAMMA256X(sum1);
8478 					k2 = UNGAMMA256X(sum2);
8479 #else /* Let values remain linear */
8480 					k = rint(sum * 255.0);
8481 					k = k < 0 ? 0 : k;
8482 					k1 = rint(sum1 * 255.0);
8483 					k1 = k1 < 0 ? 0 : k1;
8484 					k2 = rint(sum2 * 255.0);
8485 					k2 = k2 < 0 ? 0 : k2;
8486 #endif
8487 				}
8488 				else
8489 				{
8490 					k = rint(sum);
8491 					k = k < 0 ? 0 : k;
8492 					k1 = rint(sum1);
8493 					k1 = k1 < 0 ? 0 : k1;
8494 					k2 = rint(sum2);
8495 					k2 = k2 < 0 ? 0 : k2;
8496 				}
8497 				/* Store the result */
8498 				dest[j] = k;
8499 				dest[j + 1] = k1;
8500 				dest[j + 2] = k2;
8501 			}
8502 		}
8503 		else /* Run 1-bpp horizontal filter - no gamma here */
8504 		{
8505 			int j, k;
8506 
8507 			for (j = 0; j < mem_width; j++)
8508 			{
8509 				sum = tmp1[j] * gaussW[0] - tmp2[j] * gaussN[0];
8510 				for (k = 1; k < lenW; k++)
8511 				{
8512 					sum += (tmp1[j - k] + tmp1[j + k]) * gaussW[k];
8513 				}
8514 				for (k = 1; k < lenN; k++)
8515 				{
8516 					sum -= (tmp2[j - k] + tmp2[j + k]) * gaussN[k];
8517 				}
8518 				k = rint(sum);
8519 				dest[j] = k < 0 ? 0 : k;
8520 			}
8521 		}
8522 		if (thread_step(thread, ii + 1, cnt, 10)) break;
8523 	}
8524 	thread_done(thread);
8525 }
8526 
8527 /* Difference of Gaussians */
mem_dog(double radiusW,double radiusN,int norm,int gcor)8528 void mem_dog(double radiusW, double radiusN, int norm, int gcor)
8529 {
8530 	gaussd gd;
8531 	threaddata *tdata;
8532 
8533 	/* Create arrays */
8534 	if (mem_channel != CHN_IMAGE) gcor = 0;
8535 	gd.gcor = gcor;
8536 	gd.channel = mem_channel;
8537 // !!! No RGBA mode for ever - DoG mode instead
8538 	tdata = init_gauss(&gd, radiusW, radiusN, 2);
8539 	if (!tdata)
8540 	{
8541 		memory_errors(1);
8542 		return;
8543 	}
8544 
8545 	/* Run filter */
8546 	progress_init(_("Difference of Gaussians"), 1);
8547 	launch_threads(dog_filter, tdata, NULL, mem_height);
8548 
8549 	/* Normalize values (expand to full 0..255) */
8550 	while (norm)
8551 	{
8552 		unsigned char *tmp, xtb[256];
8553 		double d;
8554 		int i, l, mx = 0;
8555 
8556 		l = mem_height * mem_width * BPP(mem_channel);
8557 		tmp = mem_img[mem_channel];
8558 		for (i = l; i; i-- , tmp++)
8559 			if (*tmp > mx) mx = *tmp;
8560 
8561 		if (!mx) break;
8562 		d = 255.0 / (double)mx;
8563 		for (i = 0; i <= mx; i++) xtb[i] = rint(i * d);
8564 
8565 		tmp = mem_img[mem_channel];
8566 		for (i = l; i; i-- , tmp++) *tmp = xtb[*tmp];
8567 
8568 		break;
8569 	}
8570 
8571 	/* Mask-merge with prior picture */
8572 	mask_merge(mem_undo_previous(mem_channel), mem_channel, gd.mask);
8573 
8574 	progress_end();
8575 	free(tdata);
8576 }
8577 
8578 
8579 /* !!! Kuwahara-Nagao filter's radius is limited to 255, to use byte offsets */
8580 typedef struct {
8581 	int *idx;	// Index array
8582 	double *rs;	// Sum of gamma-corrected RGB if using gamma
8583 	int *avg;	// Sum of pixel values (for average)
8584 	int *dis;	// Sum of pixel values squared (for variance)
8585 	unsigned char *min;	// Offset to minimum-variance square
8586 	double r2i;	// 1/r^2 to multiply things with
8587 	int w, r;	// Row width & filter radius
8588 	int gcor;	// Gamma correction toggle
8589 	int l, rl;	// Row array lengths
8590 } kuwahara_info;
8591 
8592 /* This function uses running sums, which gives x87 FPU's "precision jitter"
8593  * a chance to accumulate; to avoid, reduced-precision gamma is used - WJ */
kuwahara_row(unsigned char * src,int base,int add,kuwahara_info * info)8594 static void kuwahara_row(unsigned char *src, int base, int add, kuwahara_info *info)
8595 {
8596 	double rs0 = 0.0, rs1 = 0.0, rs2 = 0.0;
8597 	int avg[3] = { 0, 0, 0 }, dis[3] = { 0, 0, 0 };
8598 	int i, w, r = info->r, gc = info->gcor, *idx = info->idx;
8599 
8600 	w = info->w + r++;
8601 	for (i = -r; i < w; i++)
8602 	{
8603 		unsigned char *tvv;
8604 		int tv, i3, *iavg, *idis;
8605 
8606 		tvv = src + idx[i];
8607 		avg[0] += (tv = tvv[0]);
8608 		dis[0] += tv * tv;
8609 		avg[1] += (tv = tvv[1]);
8610 		dis[1] += tv * tv;
8611 		avg[2] += (tv = tvv[2]);
8612 		dis[2] += tv * tv;
8613 		if (gc)
8614 		{
8615 			rs0 += Fgamma256[tvv[0]];
8616 			rs1 += Fgamma256[tvv[1]];
8617 			rs2 += Fgamma256[tvv[2]];
8618 		}
8619 		if (i < 0) continue;
8620 
8621 		tvv = src + idx[i - r];
8622 		avg[0] -= (tv = tvv[0]);
8623 		dis[0] -= tv * tv;
8624 		avg[1] -= (tv = tvv[1]);
8625 		dis[1] -= tv * tv;
8626 		avg[2] -= (tv = tvv[2]);
8627 		dis[2] -= tv * tv;
8628 		i3 = (base + i) * 3;
8629 		iavg = info->avg + i3;
8630 		idis = info->dis + i3;
8631 		if (add)
8632 		{
8633 			iavg[0] += avg[0];
8634 			iavg[1] += avg[1];
8635 			iavg[2] += avg[2];
8636 			idis[0] += dis[0];
8637 			idis[1] += dis[1];
8638 			idis[2] += dis[2];
8639 		}
8640 		else
8641 		{
8642 			iavg[0] -= avg[0];
8643 			iavg[1] -= avg[1];
8644 			iavg[2] -= avg[2];
8645 			idis[0] -= dis[0];
8646 			idis[1] -= dis[1];
8647 			idis[2] -= dis[2];
8648 		}
8649 		if (gc)
8650 		{
8651 			double *irs = info->rs + i3;
8652 
8653 			rs0 -= Fgamma256[tvv[0]];
8654 			rs1 -= Fgamma256[tvv[1]];
8655 			rs2 -= Fgamma256[tvv[2]];
8656 			if (add)
8657 			{
8658 				irs[0] += rs0;
8659 				irs[1] += rs1;
8660 				irs[2] += rs2;
8661 			}
8662 			else
8663 			{
8664 				irs[0] -= rs0;
8665 				irs[1] -= rs1;
8666 				irs[2] -= rs2;
8667 			}
8668 		}
8669 	}
8670 }
8671 
kuwahara_copy(int dest,int src,kuwahara_info * info)8672 static void kuwahara_copy(int dest, int src, kuwahara_info *info)
8673 {
8674 	src *= 3; dest *= 3;
8675 	memcpy(info->rs + dest, info->rs + src, info->rl * 3 * sizeof(double));
8676 	memcpy(info->avg + dest, info->avg + src, info->l * 3 * sizeof(int));
8677 	memcpy(info->dis + dest, info->dis + src, info->l * 3 * sizeof(int));
8678 }
8679 
kuwahara_square(int idx,kuwahara_info * info)8680 static double kuwahara_square(int idx, kuwahara_info *info)
8681 {
8682 	double r2i = info->r2i;
8683 	int *dp = info->dis + idx * 3, *ap = info->avg + idx * 3;
8684 	// !!! Multiplication is done this way to avoid integer overflow
8685 	return (dp[0] + dp[1] + dp[2] - ((r2i * ap[0]) * ap[0] +
8686 		(r2i * ap[1]) * ap[1] + (r2i * ap[2]) * ap[2]));
8687 }
8688 
8689 /* For each X, locate the square with minimum variance & store its offset */
kuwahara_min(int base,kuwahara_info * info)8690 static void kuwahara_min(int base, kuwahara_info *info)
8691 {
8692 	double da[256];
8693 	int i, j, j1, w = info->w, r = info->r, min = -1;
8694 
8695 	for (i = 0; i < r; i++) da[i] = kuwahara_square(base + i, info);
8696 	for (i = 0; i < w; i++)
8697 	{
8698 		j1 = (i + r) & 255;
8699 		da[j1] = kuwahara_square(base + (i + r), info);
8700 		if (min > i) // Old minimum still valid
8701 		{
8702 			if (da[j1] <= da[min & 255]) min = i + r;
8703 		}
8704 		else // Forced to find a new one
8705 		{
8706 			min = i;
8707 			for (j = 1; j <= r; j++)
8708 				if (da[(i + j) & 255] <= da[min & 255])
8709 					min = i + j;
8710 		}
8711 		info->min[base + i] = min - i;
8712 	}
8713 }
8714 
8715 /* Replace each pixel in image row by nearest color in 3x3 Kuwahara'ed region */
kuwahara_detailed(unsigned char * buf,unsigned char * mask,unsigned char * dest,int y,int gcor)8716 static void kuwahara_detailed(unsigned char *buf, unsigned char *mask,
8717 	unsigned char *dest, int y, int gcor)
8718 {
8719 	unsigned char *tmp;
8720 	int l, w = mem_width * 3;
8721 #define REGION_SIZE 9
8722 	int steps[REGION_SIZE] = { 3, 3, w, 3, 3, w, 3, 3, w };
8723 
8724 #if 0 /* Make scanning order the same as with flat image */
8725 	l = (y + 2) % 3;
8726 	buf += (w + 6) * l;
8727 	steps [8 - 3 * l] -= (w + 6) * 3;
8728 #endif
8729 
8730 	row_protected(0, y, mem_width, mask);
8731 	tmp = mem_img[CHN_IMAGE] + y * w;
8732 	for (l = 0; l < mem_width; l++ , tmp += 3 , dest += 3)
8733 	{
8734 		unsigned char *tb, *found;
8735 		int rr, gg, bb, op = *mask++;
8736 
8737 		if (op == 255) continue;
8738 		/* Find the nearest color pixel */
8739 		rr = tmp[0]; gg = tmp[1]; bb = tmp[2];
8740 		found = tb = buf + l * 3;
8741 		if (gcor) // Gamma corrected
8742 		{
8743 			double d, r2, g2, b2;
8744 			int i;
8745 
8746 			d = 100.0; // More than 3*1.0^2
8747 			r2 = gamma256[rr];
8748 			g2 = gamma256[gg];
8749 			b2 = gamma256[bb];
8750 			for (i = 0; i < REGION_SIZE; tb += steps[i++])
8751 			{
8752 				double d2, dr, dg, db;
8753 
8754 				dr = gamma256[tb[0]] - r2;
8755 				dg = gamma256[tb[1]] - g2;
8756 				db = gamma256[tb[2]] - b2;
8757 				d2 = dr * dr + dg * dg + db * db;
8758 				if (d2 >= d) continue;
8759 				found = tb; d = d2;
8760 			}
8761 		}
8762 		else // Raw RGB
8763 		{
8764 			int i, d, d2;
8765 
8766 			d = 1000000; // More than 3*255^2
8767 			for (i = 0; i < REGION_SIZE; tb += steps[i++])
8768 			{
8769 				d2 = (rr - tb[0]) * (rr - tb[0]) +
8770 					(gg - tb[1]) * (gg - tb[1]) +
8771 					(bb - tb[2]) * (bb - tb[2]);
8772 				if (d2 >= d) continue;
8773 				found = tb; d = d2;
8774 			}
8775 		}
8776 		dest[0] = found[0];
8777 		dest[1] = found[1];
8778 		dest[2] = found[2];
8779 	}
8780 #undef REGION_SIZE
8781 }
8782 
8783 /* Convert virtual row to row index (mirror boundary) */
idx2row(int idx)8784 static int idx2row(int idx)
8785 {
8786 	int j, k;
8787 
8788 	if (mem_height == 1) return (0);
8789 	k = mem_height + mem_height - 2;
8790 	j = abs(idx) % k;
8791 	if (j >= mem_height) j = k - j;
8792 	return (j);
8793 }
8794 
8795 /* RGB only - cannot be generalized without speed loss */
mem_kuwahara(int r,int gcor,int detail)8796 void mem_kuwahara(int r, int gcor, int detail)
8797 {
8798 	kuwahara_info info;
8799 	unsigned char *mem, *src, *buf, *mask, *tmp, *timg, *tx;
8800 	int i, j, k, l, ir, len, rl, r1 = r + 1;
8801 	int w = mem_width * 3, wbuf = w + 3 * 2, ch = mem_channel;
8802 	double r2i = 1.0 / (double)(r1 * r1);
8803 
8804 
8805 	if (mem_img_bpp != 3) return; // Sanity check
8806 
8807 	len = mem_width + r + r + 1;
8808 	info.l = l = mem_width + r;
8809 	info.rl = rl = gcor ? l : 0;
8810 	mem = multialloc(MA_ALIGN_DOUBLE,
8811 		&info.rs, rl * r1 * 3 * sizeof(double),
8812 		&info.avg, l * r1 * 3 * sizeof(int),
8813 		&info.dis, l * r1 * 3 * sizeof(int),
8814 		&info.idx, len * sizeof(int),
8815 		&info.min, l * r1,
8816 		&mask, mem_width,
8817 		&timg, wbuf * 3,
8818 		NULL);
8819 	if (!mem)
8820 	{
8821 		memory_errors(1);
8822 		return;
8823 	}
8824 	info.r2i = r2i; info.w = mem_width; info.r = r; info.gcor = gcor;
8825 
8826 	progress_init(_("Kuwahara-Nagao Filter"), 1);
8827 	info.idx += r1;
8828 	if (mem_width > 1) // All indices remain zero otherwise
8829 	{
8830 		k = mem_width + mem_width - 2;
8831 		for (i = -(r + 1); i < mem_width + r; i++)
8832 		{
8833 			j = abs(i) % k;
8834 			if (j >= mem_width) j = k - j;
8835 			info.idx[i] = j * 3;
8836 		}
8837 	}
8838 
8839 	mem_channel = CHN_IMAGE; // For row_protected()
8840 	src = mem_undo_previous(CHN_IMAGE);
8841 	/* Initialize the bottom sum */
8842 	for (i = -r; i <= 0; i++)
8843 		kuwahara_row(src + idx2row(i) * w, 0, TRUE, &info);
8844 	kuwahara_min(0, &info);
8845 	/* Initialize the rest of sums */
8846 	for (i = 1; i <= r; i++)
8847 	{
8848 		int j = l * i;
8849 		kuwahara_copy(j, j - l, &info);
8850 		kuwahara_row(src + idx2row(i - r1) * w, j, FALSE, &info);
8851 		kuwahara_row(src + idx2row(i) * w, j, TRUE, &info);
8852 		kuwahara_min(j, &info);
8853 	}
8854 	/* Actually process image */
8855 	ir = i = 0;
8856 	while (TRUE)
8857 	{
8858 		int j, k, jp;
8859 
8860 		if ((i * 10) % mem_height >= mem_height - 10)
8861 			if (progress_update((float)(i + 1) / mem_height)) break;
8862 
8863 		/* Process a pixel row */
8864 		if (!detail) row_protected(0, i, mem_width, mask);
8865 		tmp = buf = timg + wbuf * (i % 3);
8866 		for (j = 0; j < mem_width; j++)
8867 		{
8868 			double dis;
8869 			int jj, jk;
8870 
8871 			tmp += 3;
8872 			if (!detail && (mask[j] == 255)) continue;
8873 			/* Select minimum variance square from covered rows */
8874 			jj = j + l;
8875 			jk = j + info.min[j];
8876 			dis = kuwahara_square(jk, &info);
8877 // !!! Only the all-or-nothing mode for now - weighted mode not implemented yet
8878 			for (k = 1; k < r1; k++ , jj += l)
8879 			{
8880 				int jv = jj + info.min[jj];
8881 				double dv = kuwahara_square(jv, &info);
8882 				if (dv < dis) jk = jv , dis = dv;
8883 			}
8884 			/* Calculate & store new RGB */
8885 			jk *= 3;
8886 			if (gcor)
8887 			{
8888 				double *wr = info.rs + jk;
8889 				tmp[0] = UNGAMMA256(wr[0] * r2i);
8890 				tmp[1] = UNGAMMA256(wr[1] * r2i);
8891 				tmp[2] = UNGAMMA256(wr[2] * r2i);
8892 			}
8893 			else
8894 			{
8895 				int *ar = info.avg + jk;
8896 				tmp[0] = rint(*ar++ * r2i);
8897 				tmp[1] = rint(*ar++ * r2i);
8898 				tmp[2] = rint(*ar * r2i);
8899 			}
8900 		}
8901 
8902 		if (detail)
8903 		{
8904 			/* Copy-extend the row on both ends */
8905 			memcpy(buf, buf + 3, 3);
8906 			memcpy(tmp + 3, tmp, 3);
8907 			/* Copy-extend the top row */
8908 			if (!i) memcpy(timg + wbuf * 2, buf, wbuf);
8909 			else /* Build and mask-merge the previous row */
8910 			{
8911 				// Overwrite outgoing pixels of outgoing row
8912 				tx = timg + wbuf * ((i + 1) % 3);
8913 				kuwahara_detailed(timg, mask, tx, i - 1, gcor);
8914 				tmp = mem_img[CHN_IMAGE] + (i - 1) * w;
8915 				process_img(0, 1, mem_width, mask, tmp, tmp, tx,
8916 					NULL, 3, BLENDF_SET | BLENDF_INVM);
8917 			}
8918 		}
8919 		else
8920 		{
8921 			/* Mask-merge current row */
8922 			tmp = mem_img[CHN_IMAGE] + i * w;
8923 			process_img(0, 1, mem_width, mask, tmp, tmp, buf + 3,
8924 				NULL, 3, BLENDF_SET | BLENDF_INVM);
8925 		}
8926 
8927 		if (++i < mem_height)
8928 		{
8929 			/* Update sums for a new row */
8930 			jp = ir * l;
8931 			kuwahara_copy(jp, ((ir + r) % r1) * l, &info);
8932 			kuwahara_row(src + idx2row(i - 1) * w, jp, FALSE, &info);
8933 			kuwahara_row(src + idx2row(i + r) * w, jp, TRUE, &info);
8934 			kuwahara_min(jp, &info);
8935 			ir = (ir + 1) % r1;
8936 			continue;
8937 		}
8938 
8939 		if (detail)
8940 		{
8941 			/* Copy-extend the bottom row */
8942 			memcpy(timg + wbuf * (i % 3), buf, wbuf);
8943 			/* Build and mask-merge it */
8944 			kuwahara_detailed(timg, mask, timg, i - 1, gcor);
8945 			tmp = mem_img[CHN_IMAGE] + (i - 1) * w;
8946 			process_img(0, 1, mem_width, mask, tmp, tmp, timg,
8947 				NULL, 3, BLENDF_SET | BLENDF_INVM);
8948 		}
8949 		break;
8950 	}
8951 
8952 	mem_channel = ch;
8953 
8954 	progress_end();
8955 	free(mem);
8956 }
8957 
8958 ///	CLIPBOARD MASK
8959 
mem_clip_mask_init(unsigned char val)8960 int mem_clip_mask_init(unsigned char val)		// Initialise the clipboard mask
8961 {
8962 	int j = mem_clip_w*mem_clip_h;
8963 
8964 	if (mem_clipboard) mem_clip_mask_clear();	// Remove old mask
8965 
8966 	mem_clip_mask = malloc(j);
8967 	if (!mem_clip_mask) return 1;			// Not able to allocate memory
8968 
8969 	memset(mem_clip_mask, val, j);		// Start with fully opaque/clear mask
8970 
8971 	return 0;
8972 }
8973 
mem_mask_colors(unsigned char * mask,unsigned char * img,unsigned char v,int width,int height,int bpp,int col0,int col1)8974 void mem_mask_colors(unsigned char *mask, unsigned char *img, unsigned char v,
8975 	int width, int height, int bpp, int col0, int col1)
8976 {
8977 	int i, j = width * height, k;
8978 
8979 	if (bpp == 1)
8980 	{
8981 		for (i = 0; i < j; i++)
8982 		{
8983 			if ((img[i] == col0) || (img[i] == col1)) mask[i] = v;
8984 		}
8985 	}
8986 	else
8987 	{
8988 		for (i = 0; i < j; i++ , img += 3)
8989 		{
8990 			k = MEM_2_INT(img, 0);
8991 			if ((k == col0) || (k == col1)) mask[i] = v;
8992 		}
8993 	}
8994 }
8995 
mem_clip_mask_set(unsigned char val)8996 void mem_clip_mask_set(unsigned char val)		// (un)Mask colours A and B on the clipboard
8997 {
8998 	int aa, bb;
8999 
9000 	if (mem_clip_bpp == 1) /* Indexed/utility */
9001 	{
9002 		if (mem_channel == CHN_IMAGE)
9003 		{
9004 			aa = mem_col_A;
9005 			bb = mem_col_B;
9006 		}
9007 		else
9008 		{
9009 			aa = channel_col_A[mem_channel];
9010 			bb = channel_col_B[mem_channel];
9011 		}
9012 	}
9013 	else /* RGB */
9014 	{
9015 		aa = PNG_2_INT(mem_col_A24);
9016 		bb = PNG_2_INT(mem_col_B24);
9017 	}
9018 	mem_mask_colors(mem_clip_mask, mem_clipboard, val,
9019 		mem_clip_w, mem_clip_h, mem_clip_bpp, aa, bb);
9020 }
9021 
mem_clip_mask_clear()9022 void mem_clip_mask_clear()		// Clear/remove the clipboard mask
9023 {
9024 	free(mem_clip_mask);
9025 	mem_clip_mask = NULL;
9026 }
9027 
9028 /*
9029  * Extract alpha information from RGB image - alpha if pixel is in colour
9030  * scale of A->B. Return 0 if OK, 1 otherwise
9031  */
mem_scale_alpha(unsigned char * img,unsigned char * alpha,int width,int height,int mode)9032 int mem_scale_alpha(unsigned char *img, unsigned char *alpha,
9033 	int width, int height, int mode)
9034 {
9035 	int i, j = width * height, AA[3], BB[3], DD[6], chan, c1, c2, dc1, dc2;
9036 	double p0, p1, p2, dchan, KK[6];
9037 
9038 	if (!img || !alpha) return (1);
9039 
9040 	AA[0] = mem_col_A24.red;
9041 	AA[1] = mem_col_A24.green;
9042 	AA[2] = mem_col_A24.blue;
9043 	BB[0] = mem_col_B24.red;
9044 	BB[1] = mem_col_B24.green;
9045 	BB[2] = mem_col_B24.blue;
9046 	for (i = 0; i < 3; i++)
9047 	{
9048 		if (AA[i] < BB[i])
9049 		{
9050 			DD[i] = AA[i];
9051 			DD[i + 3] = BB[i];
9052 		}
9053 		else
9054 		{
9055 			DD[i] = BB[i];
9056 			DD[i + 3] = AA[i];
9057 		}
9058 	}
9059 
9060 	chan = 0;	// Find the channel with the widest range - gives most accurate result later
9061 	if (DD[4] - DD[1] > DD[3] - DD[0]) chan = 1;
9062 	if (DD[5] - DD[2] > DD[chan + 3] - DD[chan]) chan = 2;
9063 
9064 	if (AA[chan] == BB[chan])	/* if A == B then work GIMP-like way */
9065 	{
9066 		for (i = 0; i < 3; i++)
9067 		{
9068 			KK[i] = AA[i] ? 255.0 / AA[i] : 1.0;
9069 			KK[i + 3] = AA[i] < 255 ? -255.0 / (255 - AA[i]) : 0.0;
9070 		}
9071 
9072 		for (i = 0; i < j; i++ , alpha++ , img += 3)
9073 		{
9074 			/* Already semi-opaque so don't touch */
9075 			if (*alpha != 255) continue;
9076 
9077 			/* Evaluate the three possible alphas */
9078 			p0 = (AA[0] - img[0]) * (img[0] <= AA[0] ? KK[0] : KK[3]);
9079 			p1 = (AA[1] - img[1]) * (img[1] <= AA[1] ? KK[1] : KK[4]);
9080 			p2 = (AA[2] - img[2]) * (img[2] <= AA[2] ? KK[2] : KK[5]);
9081 			if (p0 < p1) p0 = p1;
9082 			if (p0 < p2) p0 = p2;
9083 
9084 			/* Set alpha */
9085 			*alpha = rint(p0);
9086 
9087 			/* Demultiply image if this is alpha and nonzero */
9088 			if (!mode) continue;
9089 			dchan = p0 ? 255.0 / p0 : 0.0;
9090 			img[0] = rint((img[0] - AA[0]) * dchan) + AA[0];
9091 			img[1] = rint((img[1] - AA[1]) * dchan) + AA[1];
9092 			img[2] = rint((img[2] - AA[2]) * dchan) + AA[2];
9093 		}
9094 	}
9095 	else	/* Limit processing to A->B scale */
9096 	{
9097 		dchan = 1.0 / (BB[chan] - AA[chan]);
9098 		c1 = 1 ^ (chan & 1);
9099 		c2 = 2 ^ (chan & 2);
9100 		dc1 = BB[c1] - AA[c1];
9101 		dc2 = BB[c2] - AA[c2];
9102 
9103 		for (i = 0; i < j; i++ , alpha++ , img += 3)
9104 		{
9105 			/* Already semi-opaque so don't touch */
9106 			if (*alpha != 255) continue;
9107 			/* Ensure pixel lies between A and B for each channel */
9108 			if ((img[0] < DD[0]) || (img[0] > DD[3])) continue;
9109 			if ((img[1] < DD[1]) || (img[1] > DD[4])) continue;
9110 			if ((img[2] < DD[2]) || (img[2] > DD[5])) continue;
9111 
9112 			p0 = (img[chan] - AA[chan]) * dchan;
9113 
9114 			/* Check delta for all channels is roughly the same ...
9115 			 * ... if it isn't, ignore this pixel as its not in A->B scale
9116 			 */
9117 			if (abs(AA[c1] + (int)rint(p0 * dc1) - img[c1]) > 2) continue;
9118 			if (abs(AA[c2] + (int)rint(p0 * dc2) - img[c2]) > 2) continue;
9119 
9120 			/* Pixel is a shade of A/B so set alpha */
9121 			*alpha = (int)rint(p0 * 255) ^ 255;
9122 
9123 			/* Demultiply image if this is alpha */
9124 			if (!mode) continue;
9125 			img[0] = AA[0];
9126 			img[1] = AA[1];
9127 			img[2] = AA[2];
9128 		}
9129 	}
9130 
9131 	return 0;
9132 }
9133 
mem_smudge(int ox,int oy,int nx,int ny)9134 void mem_smudge(int ox, int oy, int nx, int ny)
9135 {
9136 	unsigned char mask[256], img[256 * 2 * 3], alf[256 * 2];
9137 	unsigned char *src, *dest, *srca = NULL, *dsta = NULL;
9138 	int ax, ay, bx, by, w, h;
9139 	int xv = nx - ox, yv = ny - oy;		// Vector
9140 	int i, j, delta, delta1, bpp;
9141 	int y0, y1, dy, opw, op2, cpf, mode;
9142 
9143 
9144 	if (tool_opacity < 2) return;
9145 
9146 	/* Clip source and dest areas to image bounds */
9147 	ax = ox - tool_size / 2;
9148 	bx = ax + tool_size;
9149 	if (ax < 0) ax = 0;
9150 	if (ax + xv < 0) ax = -xv;
9151 	if (bx > mem_width) bx = mem_width;
9152 	if (bx + xv > mem_width) bx = mem_width - xv;
9153 	w = bx - ax;
9154 
9155 	ay = oy - tool_size / 2;
9156 	by = ay + tool_size;
9157 	if (ay < 0) ay = 0;
9158 	if (ay + yv < 0) ay = -yv;
9159 	if (by > mem_height) by = mem_height;
9160 	if (by + yv > mem_height) by = mem_height - yv;
9161 	h = by - ay;
9162 
9163 	if ((w < 1) || (h < 1)) return;
9164 
9165 /* !!! I modified this tool action somewhat - White Jaguar */
9166 	mode = smudge_mode && mem_undo_opacity;
9167 	if (mode) src = mem_undo_previous(mem_channel);
9168 	else src = mem_img[mem_channel];
9169 	dest = mem_img[mem_channel];
9170 	if ((mem_channel == CHN_IMAGE) && RGBA_mode && mem_img[CHN_ALPHA])
9171 	{
9172 		if (mode) srca = mem_undo_previous(CHN_ALPHA);
9173 		else srca = mem_img[CHN_ALPHA];
9174 		dsta = mem_img[CHN_ALPHA];
9175 	}
9176 	bpp = MEM_BPP;
9177 	delta1 = yv * mem_width + xv;
9178 	delta = delta1 * bpp;
9179 
9180 	/* Copy source if destination overwrites it */
9181 	cpf = (src == dest) && !yv && (xv > 0) && (w > xv);
9182 	/* Set up Y pass to prevent overwriting source */
9183 	if ((src == dest) && (yv > 0) && (h > yv))
9184 		y0 = ay + h - 1 , y1 = ay - 1 , dy = -1; // Bottom to top
9185 	else y0 = ay , y1 = ay + h , dy = 1; // Top to bottom
9186 
9187 	for (j = y0; j != y1; j += dy)	// Blend old area with new area
9188 	{
9189 		unsigned char *ts, *td, *tsa = NULL, *tda = NULL;
9190 		int offs = j * mem_width + ax;
9191 
9192 		row_protected(ax + xv, j + yv, w, mask);
9193 		ts = src + offs * bpp;
9194 		td = dest + offs * bpp + delta;
9195 		if (cpf)
9196 		{
9197 			memcpy(img, ts, w * bpp + delta);
9198 			ts = img;
9199 		}
9200 		if (dsta)
9201 		{
9202 			tsa = srca + offs;
9203 			tda = dsta + offs + delta1;
9204 			if (cpf)
9205 			{
9206 				memcpy(alf, tsa, w + delta1);
9207 				tsa = alf;
9208 			}
9209 		}
9210 
9211 		for (i = 0; i < w; i++ , ts += bpp , td += bpp)
9212 		{
9213 			int k = mask[i], k0, k1, k2;
9214 
9215 			opw = (255 - k) * (tool_opacity >> 1);
9216 			opw = (opw + (opw >> 8) + 1) >> 8;
9217 			if (!opw) continue;
9218 			if (tda)
9219 			{
9220 				int k = tsa[i + delta1];
9221 				k = k * 255 + (tsa[i] - k) * opw + 127;
9222 				tda[i] = (k + (k >> 8) + 1) >> 8;
9223 				if (k && !channel_dis[CHN_ALPHA])
9224 					opw = (255 * opw * tsa[i]) / k;
9225 			}
9226 			op2 = 255 - opw;
9227 			k0 = ts[0] * opw + ts[delta] * op2 + 127;
9228 			td[0] = (k0 + (k0 >> 8) + 1) >> 8;
9229 			if (bpp == 1) continue;
9230 			k1 = ts[1] * opw + ts[delta + 1] * op2 + 127;
9231 			td[1] = (k1 + (k1 >> 8) + 1) >> 8;
9232 			k2 = ts[2] * opw + ts[delta + 2] * op2 + 127;
9233 			td[2] = (k2 + (k2 >> 8) + 1) >> 8;
9234 		}
9235 	}
9236 }
9237 
9238 ///	GRADIENTS
9239 
9240 /* Evaluate channel gradient at coordinate, return opacity
9241  * Coordinate 0 is center of 1st pixel, 1 center of last
9242  * Scale of return values is 0x0000..0xFF00 (NOT 0xFFFF) */
grad_value(int * dest,int slot,double x)9243 int grad_value(int *dest, int slot, double x)
9244 {
9245 	int i, k, len, op;
9246 	unsigned char *gdata, *gmap;
9247 	grad_map *gradmap;
9248 	double xx, hsv[6];
9249 
9250 	/* Gradient slot (first RGB, then 1-bpp channels) */
9251 	gradmap = graddata + slot;
9252 
9253 	/* Get opacity */
9254 	gdata = gradmap->op; gmap = gradmap->opmap; len = gradmap->oplen;
9255 	xx = (gradmap->orev ? 1.0 - x : x) * (len - 1);
9256 	i = xx;
9257 	if (i > len - 2) i = len - 2;
9258 	k = gmap[i] == GRAD_TYPE_CONST ? 0 : (int)((xx - i) * 0x10000 + 0.5);
9259 	op = (gdata[i] << 8) + ((k * (gdata[i + 1] - gdata[i]) + 127) >> 8);
9260 	if (!op) return (0); /* Stop if zero opacity */
9261 
9262 	/* Get channel value */
9263 	gdata = gradmap->vs; gmap = gradmap->vsmap; len = gradmap->vslen;
9264 	xx = (gradmap->grev ? 1.0 - x : x) * (len - 1);
9265 	i = xx;
9266 	if (i > len - 2) i = len - 2;
9267 	k = gmap[i] == GRAD_TYPE_CONST ? 0 : (int)((xx - i) * 0x10000 + 0.5);
9268 	if (!slot) /* RGB */
9269 	{
9270 		unsigned char *gslot = gdata + i * 3;
9271 		int j3 = 0;
9272 
9273 		switch (gmap[i])
9274 		{
9275 		case GRAD_TYPE_BK_HSV: /* Backward HSV interpolation */
9276 			j3 = 3;
9277 		case GRAD_TYPE_HSV: /* HSV interpolation */
9278 			/* Convert */
9279 			rgb2hsv(gslot + 0, hsv + 0);
9280 			rgb2hsv(gslot + 3, hsv + 3);
9281 			/* Grey has no hue */
9282 			if (hsv[1] == 0.0) hsv[0] = hsv[3];
9283 			if (hsv[4] == 0.0) hsv[3] = hsv[0];
9284 			/* Prevent wraparound */
9285 			if (hsv[j3] > hsv[j3 ^ 3]) hsv[j3] -= 6.0;
9286 			/* Interpolate */
9287 			hsv[0] += (xx - i) * (hsv[3] - hsv[0]);
9288 			hsv[1] += (xx - i) * (hsv[4] - hsv[1]);
9289 			hsv[2] += (xx - i) * (hsv[5] - hsv[2]);
9290 			/* Convert back */
9291 			hsv[2] *= 512;
9292 			hsv[1] = hsv[2] * (1.0 - hsv[1]);
9293 			if (hsv[0] < 0.0) hsv[0] += 6.0;
9294 			j3 = hsv[0];
9295 			hsv[0] = (hsv[0] - j3) * (hsv[2] - hsv[1]);
9296 			if (j3 & 1) { hsv[2] -= hsv[0]; hsv[0] += hsv[2]; }
9297 			else hsv[0] += hsv[1];
9298 			j3 >>= 1;
9299 			dest[j3] = ((int)hsv[2] + 1) >> 1;
9300 			dest[MOD3(j3 + 1)] = ((int)hsv[0] + 1) >> 1;
9301 			dest[MOD3(j3 + 2)] = ((int)hsv[1] + 1) >> 1;
9302 			break;
9303 		case GRAD_TYPE_SRGB: /* sRGB interpolation */
9304 			dest[0] = ungamma65281(gamma256[gslot[0]] + (xx - i) *
9305 				(gamma256[gslot[3]] - gamma256[gslot[0]]));
9306 			dest[1] = ungamma65281(gamma256[gslot[1]] + (xx - i) *
9307 				(gamma256[gslot[4]] - gamma256[gslot[1]]));
9308 			dest[2] = ungamma65281(gamma256[gslot[2]] + (xx - i) *
9309 				(gamma256[gslot[5]] - gamma256[gslot[2]]));
9310 			break;
9311 		default: /* RGB interpolation */
9312 			dest[0] = (gslot[0] << 8) +
9313 				((k * (gslot[3] - gslot[0]) + 127) >> 8);
9314 			dest[1] = (gslot[1] << 8) +
9315 				((k * (gslot[4] - gslot[1]) + 127) >> 8);
9316 			dest[2] = (gslot[2] << 8) +
9317 				((k * (gslot[5] - gslot[2]) + 127) >> 8);
9318 			break;
9319 		}
9320 	}
9321 	else if (slot == CHN_IMAGE + 1) /* Indexed */
9322 	{
9323 		dest[0] = gdata[i];
9324 		dest[1] = gdata[i + ((k + 0xFFFF) >> 16)];
9325 		dest[CHN_IMAGE + 3] = (k + 127) >> 8;
9326 	}
9327 	else /* Utility */
9328 	{
9329 		dest[slot + 2] = (gdata[i] << 8) +
9330 			((k * (gdata[i + 1] - gdata[i]) + 127) >> 8);
9331 	}
9332 
9333 	return (op);
9334 }
9335 
9336 /* Evaluate (coupled) alpha gradient at coordinate */
grad_alpha(int * dest,double x)9337 static void grad_alpha(int *dest, double x)
9338 {
9339 	int i, k, len;
9340 	unsigned char *gdata, *gmap;
9341 	grad_map *gradmap;
9342 	double xx;
9343 
9344 	/* Get coupled alpha */
9345 	gradmap = graddata + CHN_ALPHA + 1;
9346 	gdata = gradmap->vs; gmap = gradmap->vsmap; len = gradmap->vslen;
9347 	xx = (gradmap->grev ? 1.0 - x : x) * (len - 1);
9348 	i = xx;
9349 	if (i > len - 2) i = len - 2;
9350 	k = gmap[i] == GRAD_TYPE_CONST ? 0 : (int)((xx - i) * 0x10000 + 0.5);
9351 	dest[CHN_ALPHA + 3] = (gdata[i] << 8) +
9352 		((k * (gdata[i + 1] - gdata[i]) + 127) >> 8);
9353 }
9354 
9355 /* Evaluate gradient at a sequence of points */
9356 /* !!! For now, works only in (slower) exact mode */
grad_pixels(int start,int step,int cnt,int x,int y,unsigned char * mask,unsigned char * op0,unsigned char * img0,unsigned char * alpha0)9357 void grad_pixels(int start, int step, int cnt, int x, int y, unsigned char *mask,
9358 	unsigned char *op0, unsigned char *img0, unsigned char *alpha0)
9359 {
9360 	grad_info *grad = gradient + mem_channel;
9361 	unsigned char *dest;
9362 	int i, mmask, dither, op, slot, wrk[NUM_CHANNELS + 3];
9363 	double dist, len1, l2;
9364 
9365 
9366 	if (!RGBA_mode) alpha0 = NULL;
9367 	mmask = IS_INDEXED ? 1 : 255; /* On/off opacity */
9368 	slot = mem_channel + ((0x81 + mem_channel + mem_channel - mem_img_bpp) >> 7);
9369 
9370 	cnt = start + step * cnt; x += start;
9371 	for (i = start; i < cnt; op0[i] = op , x += step , i += step)
9372 	{
9373 		op = 0;
9374 		if (mask[i] >= mmask) continue;
9375 
9376 		/* Disabled because of unusable settings? */
9377 		if (grad->wmode == GRAD_MODE_NONE) continue;
9378 
9379 		/* Distance for gradient mode */
9380 		if (grad->status == GRAD_NONE)
9381 		{
9382 			/* Stroke gradient */
9383 			if (grad->wmode != GRAD_MODE_BURST) dist = grad_path +
9384 				(x - grad_x0) * grad->xv + (y - grad_y0) * grad->yv;
9385 			/* Shapeburst gradient */
9386 			else if (!sb_buf2)
9387 			{
9388 				int n = sb_buf[(y - sb_rect[1]) * sb_rect[2] +
9389 					(x - sb_rect[0])] - 1;
9390 				if (n < 0) continue;
9391 				dist = n;
9392 			}
9393 			else
9394 			{
9395 				int n = sb_buf2[(y - sb_rect[1]) * sb_rect[2] +
9396 					(x - sb_rect[0])];
9397 				if (!n) continue;
9398 				dist = sqrt(n) - 1.0;
9399 			}
9400 		}
9401 		else
9402 		{
9403 			int dx = x - grad->xy[0], dy = y - grad->xy[1];
9404 
9405 			switch (grad->wmode)
9406 			{
9407 			default:
9408 			case GRAD_MODE_LINEAR:	/* Linear/bilinear gradient */
9409 			case GRAD_MODE_BILINEAR:
9410 				dist = dx * grad->xv + dy * grad->yv;
9411 				if (grad->wmode == GRAD_MODE_LINEAR) break;
9412 				dist = fabs(dist); /* Bilinear */
9413 				break;
9414 			case GRAD_MODE_RADIAL:	/* Radial gradient */
9415 				dist = sqrt(dx * dx + dy * dy);
9416 				break;
9417 			case GRAD_MODE_SQUARE:	/* Square gradient */
9418 				/* !!! Here is code duplication with linear/
9419 				 * bilinear path - but merged paths actually
9420 				 * LOSE in both time and space, at least
9421 				 * with GCC - WJ */
9422 				dist = fabs(dx * grad->xv + dy * grad->yv) +
9423 					fabs(dx * grad->yv - dy * grad->xv);
9424 				break;
9425 			case GRAD_MODE_ANGULAR:	/* Angular/conical gradient */
9426 			case GRAD_MODE_CONICAL:
9427 				dist = atan360(dx, dy) - grad->wa;
9428 				if (dist < 0.0) dist += 360.0;
9429 				if (grad->wmode == GRAD_MODE_ANGULAR) break;
9430 				if (dist >= 180.0) dist = 360.0 - dist;
9431 				break;
9432 			}
9433 		}
9434 		dist -= grad->ofs;
9435 
9436 		/* Apply repeat mode */
9437 		len1 = grad->wrep;
9438 		switch (grad->wrmode)
9439 		{
9440 		case GRAD_BOUND_MIRROR: /* Mirror repeat */
9441 			l2 = len1 + len1;
9442 			dist -= l2 * (int)(dist * grad->wil2);
9443 			if (dist < 0.0) dist += l2;
9444 			if (dist > len1) dist = l2 - dist;
9445 			break;
9446 		case GRAD_BOUND_REPEAT: /* Repeat */
9447 			l2 = len1 + 1.0; /* Repeat period is 1 pixel longer */
9448 			dist -= l2 * (int)((dist + 0.5) * grad->wil2);
9449 			if (dist < -0.5) dist += l2;
9450 			break;
9451 		case GRAD_BOUND_REP_A: /* Angular repeat */
9452 			dist -= len1 * (int)(dist * grad->wil2);
9453 			if (dist < 0.0) dist += len1;
9454 			break;
9455 		case GRAD_BOUND_STOP: /* Nothing is outside bounds */
9456 			if ((dist < -0.5) || (dist >= len1 + 0.5)) continue;
9457 			break;
9458 		case GRAD_BOUND_STOP_A: /* Nothing is outside angle */
9459 			if ((dist < 0.0) || (dist > len1)) continue;
9460 			break;
9461 		case GRAD_BOUND_LEVEL: /* Constant extension */
9462 		default:
9463 			break;
9464 		}
9465 
9466 		/* Rescale to 0..1, enforce boundaries */
9467 		dist = dist <= 0.0 ? 0.0 : dist >= len1 ? 1.0 : dist * grad->wil1;
9468 
9469 		/* Value from Bayer dither matrix */
9470 		dither = BAYER(x, y);
9471 
9472 		/* Get gradient */
9473 		wrk[CHN_IMAGE + 3] = 0;
9474 		op = (grad_value(wrk, slot, dist) + dither) >> 8;
9475 		if (!op) continue;
9476 
9477 		if (mem_channel == CHN_IMAGE)
9478 		{
9479 			if (alpha0)
9480 			{
9481 				grad_alpha(wrk, dist);
9482 				alpha0[i] = (wrk[CHN_ALPHA + 3] + dither) >> 8;
9483 			}
9484 			if (mem_img_bpp == 3)
9485 			{
9486 				dest = img0 + i * 3;
9487 				dest[0] = (wrk[0] + dither) >> 8;
9488 				dest[1] = (wrk[1] + dither) >> 8;
9489 				dest[2] = (wrk[2] + dither) >> 8;
9490 			}
9491 			else
9492 			{
9493 				img0[i] = (unsigned char)wrk[(wrk[CHN_IMAGE + 3] +
9494 					dither) >> 8];
9495 				op = 255;
9496 			}
9497 		}
9498 		else img0[i] = (wrk[mem_channel + 3] + dither) >> 8;
9499 	}
9500 }
9501 
9502 /* Reevaluate gradient placement functions */
grad_update(grad_info * grad)9503 void grad_update(grad_info *grad)
9504 {
9505 	double len, len1, l2;
9506 	int dx = grad->xy[2] - grad->xy[0], dy = grad->xy[3] - grad->xy[1];
9507 
9508 	/* Distance for gradient mode */
9509 	grad->wmode = grad->gmode;
9510 	len = grad->len;
9511 	while (1)
9512 	{
9513 		 /* Stroke gradient */
9514 		if (grad->status == GRAD_NONE)
9515 		{
9516 			if (!len) len = grad->rep + grad->ofs;
9517 			if (len <= 0.0) grad->wmode = GRAD_MODE_NONE;
9518 			break;
9519 		}
9520 
9521 		/* Placement length */
9522 		l2 = sqrt(dx * dx + dy * dy);
9523 		if (l2 == 0.0)
9524 		{
9525 			grad->wmode = GRAD_MODE_RADIAL;
9526 			break;
9527 		}
9528 		grad->xv = dx / l2;
9529 		grad->yv = dy / l2;
9530 		grad->wa = atan360(dx, dy);
9531 		if (!len) len = grad->wmode == GRAD_MODE_ANGULAR ? 360.0 :
9532 			grad->wmode == GRAD_MODE_CONICAL ? 180.0 : l2;
9533 		break;
9534 	}
9535 
9536 	/* Base length (one repeat) */
9537 	len1 = grad->rep > 0 ? grad->rep : len - grad->ofs;
9538 	if (len1 < 1.0) len1 = 1.0;
9539 	grad->wrep = len1;
9540 	grad->wil1 = 1.0 / len1;
9541 
9542 	/* Inverse period */
9543 	l2 = 1.0;
9544 	grad->wrmode = grad->rmode;
9545 	if (grad->rmode == GRAD_BOUND_MIRROR) /* Mirror repeat */
9546 		l2 = len1 + len1;
9547 	else if (grad->rmode == GRAD_BOUND_REPEAT) /* Repeat */
9548 		l2 = len1 + 1.0;
9549 	/* Angular distance is in degrees, not pixels */
9550 	if ((grad->wmode == GRAD_MODE_ANGULAR) ||
9551 		(grad->wmode == GRAD_MODE_CONICAL))
9552 	{
9553 		if (grad->rmode == GRAD_BOUND_REPEAT)
9554 			grad->wrmode = GRAD_BOUND_REP_A , l2 = len1;
9555 		else if (grad->rmode == GRAD_BOUND_STOP)
9556 			grad->wrmode = GRAD_BOUND_STOP_A;
9557 	}
9558 	grad->wil2 = 1.0 / l2;
9559 }
9560 
9561 static unsigned char grad_def[4 + 8 + NUM_CHANNELS * 4];
9562 
9563 /* Setup gradient mapping */
gmap_setup(grad_map * gmap,grad_store gstore,int slot)9564 void gmap_setup(grad_map *gmap, grad_store gstore, int slot)
9565 {
9566 	unsigned char *data, *map;
9567 
9568 	data = grad_def + (slot ? 8 + slot * 4 : 4);
9569 	map = grad_def + 10 + slot * 4;
9570 	gmap->vslen = 2;
9571 	if (gmap->gtype == GRAD_TYPE_CUSTOM)
9572 	{
9573 		gmap->vs = gstore + GRAD_CUSTOM_DATA(slot);
9574 		gmap->vsmap = gstore + GRAD_CUSTOM_DMAP(slot);
9575 		if (gmap->cvslen > 1) gmap->vslen = gmap->cvslen;
9576 		else
9577 		{
9578 			memcpy(gmap->vs, data, slot ? 2 : 6);
9579 			gmap->vsmap[0] = map[0];
9580 		}
9581 	}
9582 	else
9583 	{
9584 		gmap->vs = data;
9585 		gmap->vsmap = map;
9586 		grad_def[10 + slot * 4] = (unsigned char)gmap->gtype;
9587 	}
9588 
9589 	gmap->oplen = 2;
9590 	if (gmap->otype == GRAD_TYPE_CUSTOM)
9591 	{
9592 		gmap->op = gstore + GRAD_CUSTOM_OPAC(slot);
9593 		gmap->opmap = gstore + GRAD_CUSTOM_OMAP(slot);
9594 		if (gmap->coplen > 1) gmap->oplen = gmap->coplen;
9595 		else
9596 		{
9597 			gmap->op[0] = grad_def[0];
9598 			gmap->op[1] = grad_def[1];
9599 			gmap->opmap[0] = grad_def[2];
9600 		}
9601 	}
9602 	else
9603 	{
9604 		gmap->op = grad_def;
9605 		gmap->opmap = grad_def + 2;
9606 		grad_def[2] = gmap->otype;
9607 	}
9608 }
9609 
9610 /* Store default gradient */
grad_def_update(int slot)9611 void grad_def_update(int slot)
9612 {
9613 	grad_map *gradmap;
9614 
9615 	/* Gradient slot (first RGB, then 1-bpp channels) */
9616 	if (slot < 0) slot = mem_channel + ((0x81 + mem_channel + mem_channel -
9617 		mem_img_bpp) >> 7);
9618 	gradmap = graddata + slot;
9619 
9620 	grad_def[0] = tool_opacity;
9621 	/* !!! As there's only 1 tool_opacity, use 0 for 2nd point */
9622 	grad_def[1] = 0;
9623 	grad_def[2] = gradmap->otype;
9624 
9625 	grad_def[10 + slot * 4] = gradmap->gtype;
9626 	if (slot)
9627 	{
9628 		grad_def[8 + slot * 4] = channel_col_A[slot - 1];
9629 		grad_def[9 + slot * 4] = channel_col_B[slot - 1];
9630 		grad_def[12] = mem_col_A;
9631 		grad_def[13] = mem_col_B;
9632 	}
9633 	else
9634 	{
9635 		grad_def[4] = mem_col_A24.red;
9636 		grad_def[5] = mem_col_A24.green;
9637 		grad_def[6] = mem_col_A24.blue;
9638 		grad_def[7] = mem_col_B24.red;
9639 		grad_def[8] = mem_col_B24.green;
9640 		grad_def[9] = mem_col_B24.blue;
9641 	}
9642 
9643 	gradmap = graddata + CHN_ALPHA + 1;
9644 	grad_def[12 + CHN_ALPHA * 4] = channel_col_A[CHN_ALPHA];
9645 	grad_def[13 + CHN_ALPHA * 4] = channel_col_B[CHN_ALPHA];
9646 	grad_def[14 + CHN_ALPHA * 4] = gradmap->gtype;
9647 }
9648 
9649 /* Convert to RGB & blend indexed/indexed+alpha for preview */
blend_indexed(int start,int step,int cnt,unsigned char * rgb,unsigned char * img0,unsigned char * img,unsigned char * alpha0,unsigned char * alpha,int opacity)9650 void blend_indexed(int start, int step, int cnt, unsigned char *rgb,
9651 	unsigned char *img0, unsigned char *img,
9652 	unsigned char *alpha0, unsigned char *alpha, int opacity)
9653 {
9654 	png_color *col, *col0;
9655 	int i, j, k, i3;
9656 
9657 	for (i = start; cnt-- > 0; i += step)
9658 	{
9659 		j = opacity;
9660 		if (alpha)
9661 		{
9662 			if (alpha[i])
9663 			{
9664 				if (alpha0[i]) /* Opaque both */
9665 					alpha[i] = 255;
9666 				else /* Opaque new */
9667 				{
9668 					alpha[i] = opacity;
9669 					j = 255;
9670 				}
9671 			}
9672 			else if (alpha0[i]) /* Opaque old */
9673 			{
9674 				alpha[i] = opacity ^ 255;
9675 				j = 0;
9676 			}
9677 			else /* Transparent both */
9678 			{
9679 				alpha[i] = 0;
9680 				continue;
9681 			}
9682 		}
9683 		col = mem_pal + img[i];
9684 		col0 = mem_pal + img0[i];
9685 		i3 = i * 3;
9686 		k = col0->red * 255 + j * (col->red - col0->red);
9687 		rgb[i3 + 0] = (k + (k >> 8) + 1) >> 8;
9688 		k = col0->green * 255 + j * (col->green - col0->green);
9689 		rgb[i3 + 1] = (k + (k >> 8) + 1) >> 8;
9690 		k = col0->blue * 255 + j * (col->blue - col0->blue);
9691 		rgb[i3 + 2] = (k + (k >> 8) + 1) >> 8;
9692 	}
9693 }
9694 
grad_point(double * xyz,int cspace,int idx)9695 static void grad_point(double *xyz, int cspace, int idx)
9696 {
9697 	int wrk[NUM_CHANNELS + 3];
9698 
9699 	grad_value(wrk, 0, idx * (1.0 / 4096.0));
9700 	switch (cspace)
9701 	{
9702 	default:
9703 	case CSPACE_RGB:
9704 		xyz[0] = wrk[0] * (1.0 / 256.0);
9705 		xyz[1] = wrk[1] * (1.0 / 256.0);
9706 		xyz[2] = wrk[2] * (1.0 / 256.0);
9707 		break;
9708 	case CSPACE_LXN:
9709 	case CSPACE_SRGB:
9710 		xyz[0] = gamma65281(wrk[0]);
9711 		xyz[1] = gamma65281(wrk[1]);
9712 		xyz[2] = gamma65281(wrk[2]);
9713 		if (cspace == CSPACE_LXN) rgb2LXN(xyz, xyz[0], xyz[1], xyz[2]);
9714 		break;
9715 	}
9716 }
9717 
mem_pick_gradient(unsigned char * buf,int cspace,int mode)9718 int mem_pick_gradient(unsigned char *buf, int cspace, int mode)
9719 {
9720 	grad_map oldgr;
9721 	double pal[256 * 3], near[256 * 3], dist[256], len[256], lastc[3];
9722 	unsigned char *tb = buf;
9723 	int i, j, k, l;
9724 
9725 	/* Set up new RGB gradient */
9726 	oldgr = graddata[0];
9727 	memset(graddata, 0, sizeof(grad_map));
9728 	graddata[0].gtype = mode;
9729 	graddata[0].otype = GRAD_TYPE_CONST;
9730 	graddata[0].grev = graddata[0].orev = FALSE;
9731 	grad_def_update(0);
9732 	gmap_setup(graddata, gradbytes, 0);
9733 
9734 	/* Map palette to colorspace, and init point/distance/position */
9735 	grad_point(lastc, cspace, 0);
9736 	for (i = 0; i < mem_cols; i++)
9737 	{
9738 		double *tmp = pal + i * 3;
9739 
9740 		switch (cspace)
9741 		{
9742 		default:
9743 		case CSPACE_RGB:
9744 			tmp[0] = mem_pal[i].red;
9745 			tmp[1] = mem_pal[i].green;
9746 			tmp[2] = mem_pal[i].blue;
9747 			break;
9748 		case CSPACE_SRGB:
9749 			tmp[0] = gamma256[mem_pal[i].red];
9750 			tmp[1] = gamma256[mem_pal[i].green];
9751 			tmp[2] = gamma256[mem_pal[i].blue];
9752 			break;
9753 		case CSPACE_LXN:
9754 			get_lxn(tmp, PNG_2_INT(mem_pal[i]));
9755 			break;
9756 		}
9757 		dist[i] = (tmp[0] - lastc[0]) * (tmp[0] - lastc[0]) +
9758 			(tmp[1] - lastc[1]) * (tmp[1] - lastc[1]) +
9759 			(tmp[2] - lastc[2]) * (tmp[2] - lastc[2]);
9760 		memcpy(near + i * 3, lastc, sizeof(lastc));
9761 	}
9762 	memset(len, 0, sizeof(len));
9763 
9764 	/* Find nearest point on gradient curve for each palette color */
9765 	for (i = 1; i < 4096; i++)
9766 	{
9767 		double thisc[3], dx, dy, dz, l2;
9768 
9769 		grad_point(thisc, cspace, i);
9770 		dx = thisc[0] - lastc[0];
9771 		dy = thisc[1] - lastc[1];
9772 		dz = thisc[2] - lastc[2];
9773 		l2 = dx * dx + dy * dy + dz * dz;
9774 		if (l2 == 0.0) continue;
9775 		for (j = 0; j < mem_cols; j++)
9776 		{
9777 			double a, d, newc[3], *tmp = pal + j * 3;
9778 			a = ((tmp[0] - lastc[0]) * dx + (tmp[1] - lastc[1]) * dy +
9779 				(tmp[2] - lastc[2]) * dz) / l2;
9780 			a = a < 0.0 ? 0.0 : a > 1.0 ? 1.0 : a;
9781 			newc[0] = lastc[0] + a * dx;
9782 			newc[1] = lastc[1] + a * dy;
9783 			newc[2] = lastc[2] + a * dz;
9784 			d = (tmp[0] - newc[0]) * (tmp[0] - newc[0]) +
9785 				(tmp[1] - newc[1]) * (tmp[1] - newc[1]) +
9786 				(tmp[2] - newc[2]) * (tmp[2] - newc[2]);
9787 			if (d >= dist[j]) continue;
9788 			dist[j] = d; // Distance from the curve
9789 			len[j] = a + i; // Position along the curve
9790 			memcpy(near + j * 3, newc, sizeof(newc)); // Point
9791 		}
9792 		memcpy(lastc, thisc, sizeof(thisc));
9793 	}
9794 
9795 	/* Include gradient's second end */
9796 	grad_point(lastc, cspace, 4096);
9797 	for (i = 0; i < mem_cols; i++)
9798 	{
9799 		double d, *tmp = pal + i * 3;
9800 		d = (tmp[0] - lastc[0]) * (tmp[0] - lastc[0]) +
9801 			(tmp[1] - lastc[1]) * (tmp[1] - lastc[1]) +
9802 			(tmp[2] - lastc[2]) * (tmp[2] - lastc[2]);
9803 		if (d >= dist[i]) continue;
9804 		dist[i] = d;
9805 		len[i] = 4096.0;
9806 		memcpy(near + i * 3, lastc, sizeof(lastc));
9807 	}
9808 
9809 	/* Restore old RGB gradient */
9810 	graddata[0] = oldgr;
9811 	grad_def_update(-1);
9812 	gmap_setup(graddata, gradbytes, 0);
9813 
9814 	/* Pick colors with *uncontested* nearest points */
9815 	scan_duplicates(); // Need to avoid duplicated colors
9816 	for (i = 0; i < mem_cols; i++)
9817 	{
9818 		double d, d0, *tmp, *xyz;
9819 
9820 		if (pal_dupes[i] != i) continue;
9821 		*tb++ = i; // Add to result set by default
9822 		d0 = dist[i];
9823 		xyz = near + i * 3;
9824 		for (j = 0 , tmp = pal; j < mem_cols; j++ , tmp += 3)
9825 		{
9826 			if (pal_dupes[j] == i) continue;
9827 			tmp = pal + j * 3;
9828 			d = (tmp[0] - xyz[0]) * (tmp[0] - xyz[0]) +
9829 				(tmp[1] - xyz[1]) * (tmp[1] - xyz[1]) +
9830 				(tmp[2] - xyz[2]) * (tmp[2] - xyz[2]);
9831 			if (d <= d0)
9832 			{
9833 				tb--; // Fail - remove this color
9834 				break;
9835 			}
9836 		}
9837 	}
9838 
9839 	/* Bubble-sort the result set by position */
9840 	l = tb - buf;
9841 	for (i = l - 1; i > 0; i--)
9842 	for (j = 0; j < i; j++)
9843 	{
9844 		k = buf[j + 1];
9845 		if (len[buf[j]] > len[k])
9846 		{
9847 			buf[j + 1] = buf[j];
9848 			buf[j] = k;
9849 		}
9850 	}
9851 
9852 	/* Return number of colors in result set */
9853 	return (l);
9854 }
9855 
9856 ///	SKEW ENGINE
9857 
9858 #define FILT_MAX 6 /* Must be no less than largest filter width */
9859 
make_skew_filter(double ** filt,int ** dcc,int * fw,int len,double shift,double skew,int type)9860 static void *make_skew_filter(double **filt, int **dcc, int *fw,
9861 	int len, double shift, double skew, int type)
9862 {
9863 	void *tmp;
9864 	double x, y, x0, dy, fw2, sum, A = 0.0, *fdata;
9865 	int i, j, k, y0, fwidth = 0, *ofdata;
9866 
9867 	// Use NN "filter" for integer shifts
9868 	if ((fabs(skew - rint(skew)) < 1e-10) &&
9869 		(fabs(shift - rint(shift)) < 1e-10)) type = 0;
9870 
9871 	switch (type)
9872 	{
9873 	case 0: fwidth = 1; /* Nearest neighbor */
9874 		break;
9875 	case 1:	fwidth = 2; /* Bilinear */
9876 		break;
9877 	case 2:	case 3: case 4: case 5:	/* Bicubic, all flavors */
9878 		fwidth = 4;
9879 		A = Aarray[type - 2];
9880 		break;
9881 	case 6:	fwidth = 6; /* Blackman-Harris windowed sinc */
9882 		break;
9883 	}
9884 
9885 	*filt = NULL; *dcc = NULL; *fw = fwidth;
9886 	tmp = multialloc(MA_ALIGN_DOUBLE, filt, len * fwidth * sizeof(double),
9887 		dcc, len * sizeof(int), NULL);
9888 	if (!tmp) return (NULL);
9889 	fdata = *filt; ofdata = *dcc;
9890 
9891 	/* Generate filter */
9892 	fw2 = fwidth >> 1;
9893 	x0 = 0.5 * (len - 1);
9894 	for (i = 0; i < len; i++)
9895 	{
9896 		/* As mapping is dest-to-src, shifts are negative */
9897 		dy = (x0 - i) * skew - shift;
9898 		/* Specialcase NN filter, for simplicity */
9899 		if (!type)
9900 		{
9901 			WJ_FLOOR(*ofdata++, dy + 0.5);
9902 			*fdata++ = 1.0;
9903 			continue;
9904 		}
9905 		/* Build regular filters*/
9906 		dy -= (*ofdata++ = y0 = ceil(dy - fw2)); // Mirrored offset
9907 		sum = 0.0;
9908 		for (j = 0; j < fwidth; j++ , dy -= 1.0)
9909 		{
9910 			x = fabs(dy);
9911 			y = 0;
9912 			switch (type)
9913 			{
9914 			case 1: /* Bilinear */
9915 				y = 1.0 - x;
9916 				break;
9917 			case 2: case 3: case 4: case 5: /* Bicubic */
9918 				if (x < 1.0) y = ((A + 2.0) * x - (A + 3)) * x * x + 1.0;
9919 				else y = A * (((x - 5.0) * x + 8.0) * x - 4.0);
9920 				break;
9921 			case 6: /* Blackman-Harris */
9922 				y = BH1(x);
9923 				break;
9924 			}
9925 			sum += (fdata[j] = y);
9926 		}
9927 		/* Normalization pass */
9928 		sum = 1.0 / sum;
9929 		for (k = 0; k < fwidth; k++) *fdata++ *= sum;
9930 	}
9931 	return (tmp);
9932 }
9933 
skew_fill_rgba(double * buf,double * filler,unsigned char * src,unsigned char * srca,int y0,int ow,int xl,int xr,int x0l,int x0r,int xfsz,double * xfilt,int * dxx,int * dyy,int gcor)9934 static void skew_fill_rgba(double *buf, double *filler,
9935 	unsigned char *src, unsigned char *srca,
9936 	int y0, int ow, int xl, int xr, int x0l, int x0r,
9937 	int xfsz, double *xfilt, int *dxx, int *dyy, int gcor)
9938 {
9939 	double *dest, *tmp;
9940 	int j, k, l;
9941 
9942 	/* Initialize dest buffer */
9943 	k = x0l < xl ? x0l : xl;
9944 	l = (x0r > xr ? x0r : xr) - k - 1;
9945 	if (l < 0) return; // Nothing to do
9946 	tmp = buf + k * 7;
9947 	memcpy(tmp, filler, sizeof(double) * 7);
9948 	for (tmp += 7 , l *= 7; l > 0; tmp++ , l--) *tmp = *(tmp - 7);
9949 
9950 	/* Collect pixels */
9951 	dest = buf + xl * 7;
9952 	for (j = xl; j < xr; j++ , dest += 7)
9953 	{
9954 		unsigned char *img, *alpha;
9955 		double *filt, acc = 0.0;
9956 		int x, y, x1, ofs;
9957 
9958 		/* Get location */
9959 		y = y0 + dyy[j];
9960 		x = j + dxx[y];
9961 		x1 = x + xfsz;
9962 		filt = xfilt - x + y * xfsz;
9963 
9964 		/* Accumulate empty space */
9965 		while (x1 > ow) acc += filt[--x1];
9966 		while (x < 0) acc += filt[x++];
9967 
9968 		/* Setup source & dest */
9969 		ofs = y * ow + x;
9970 		img = src + ofs * 3;
9971 		alpha = srca + ofs;
9972 // !!! Maybe use temp vars for accumulators - but will it make a difference?
9973 		dest[0] *= acc;
9974 		dest[1] *= acc;
9975 		dest[2] *= acc;
9976 
9977 		/* Accumulate image data */
9978 		filt += x;
9979 		for (; x < x1; x++ , img += 3)
9980 		{
9981 			double rr, gg, bb, aa, fv;
9982 
9983 			fv = *filt++;
9984 			if (gcor)
9985 			{
9986 				rr = gamma256[img[0]] * fv;
9987 				gg = gamma256[img[1]] * fv;
9988 				bb = gamma256[img[2]] * fv;
9989 			}
9990 			else
9991 			{
9992 				rr = img[0] * fv;
9993 				gg = img[1] * fv;
9994 				bb = img[2] * fv;
9995 			}
9996 			dest[6] += (aa = *alpha++) * fv;
9997 			dest[0] += rr;
9998 			dest[1] += gg;
9999 			dest[2] += bb;
10000 			dest[3] += rr * aa;
10001 			dest[4] += gg * aa;
10002 			dest[5] += bb * aa;
10003 		}
10004 	}
10005 }
10006 
skew_fill_rgb(double * buf,double * filler,unsigned char * src,unsigned char * srca,int y0,int ow,int xl,int xr,int x0l,int x0r,int xfsz,double * xfilt,int * dxx,int * dyy,int gcor)10007 static void skew_fill_rgb(double *buf, double *filler,
10008 	unsigned char *src, unsigned char *srca,
10009 	int y0, int ow, int xl, int xr, int x0l, int x0r,
10010 	int xfsz, double *xfilt, int *dxx, int *dyy, int gcor)
10011 {
10012 	double *dest, *tmp;
10013 	int j, k, l;
10014 
10015 	/* Initialize dest buffer */
10016 	k = x0l < xl ? x0l : xl;
10017 	l = (x0r > xr ? x0r : xr) - k - 1;
10018 	if (l < 0) return; // Nothing to do
10019 	tmp = buf + k * 3;
10020 	memcpy(tmp, filler, sizeof(double) * 3);
10021 	for (tmp += 3 , l *= 3; l > 0; tmp++ , l--) *tmp = *(tmp - 3);
10022 
10023 	/* Collect pixels */
10024 	dest = buf + xl * 3;
10025 	for (j = xl; j < xr; j++ , dest += 3)
10026 	{
10027 		unsigned char *img;
10028 		double *filt, acc = 0.0;
10029 		double rv, gv, bv;
10030 		int x, y, x1;
10031 
10032 		/* Get location */
10033 		y = y0 + dyy[j];
10034 		x = j + dxx[y];
10035 		x1 = x + xfsz;
10036 		filt = xfilt - x + y * xfsz;
10037 
10038 		/* Accumulate empty space */
10039 		while (x1 > ow) acc += filt[--x1];
10040 		while (x < 0) acc += filt[x++];
10041 
10042 		/* Setup source & dest */
10043 		img = src + (y * ow + x) * 3;
10044 		rv = dest[0] * acc;
10045 		gv = dest[1] * acc;
10046 		bv = dest[2] * acc;
10047 
10048 		/* Accumulate image data */
10049 		filt += x;
10050 		for (; x < x1; x++ , img += 3)
10051 		{
10052 			double fv = *filt++;
10053 			if (gcor)
10054 			{
10055 				rv += gamma256[img[0]] * fv;
10056 				gv += gamma256[img[1]] * fv;
10057 				bv += gamma256[img[2]] * fv;
10058 			}
10059 			else
10060 			{
10061 				rv += img[0] * fv;
10062 				gv += img[1] * fv;
10063 				bv += img[2] * fv;
10064 			}
10065 		}
10066 		dest[0] = rv;
10067 		dest[1] = gv;
10068 		dest[2] = bv;
10069 	}
10070 }
10071 
skew_fill_util(double * buf,double * filler,unsigned char * src,unsigned char * srca,int y0,int ow,int xl,int xr,int x0l,int x0r,int xfsz,double * xfilt,int * dxx,int * dyy,int gcor)10072 static void skew_fill_util(double *buf, double *filler,
10073 	unsigned char *src, unsigned char *srca,
10074 	int y0, int ow, int xl, int xr, int x0l, int x0r,
10075 	int xfsz, double *xfilt, int *dxx, int *dyy, int gcor)
10076 {
10077 	double *dest;
10078 	int j, k, l;
10079 
10080 	/* Initialize dest buffer */
10081 	k = x0l < xl ? x0l : xl;
10082 	l = (x0r > xr ? x0r : xr) - k;
10083 	if (l <= 0) return; // Nothing to do
10084 	memset(buf + k, 0, l * sizeof(double));
10085 
10086 	/* Collect pixels */
10087 	dest = buf + xl * 3;
10088 	for (j = xl; j < xr; j++)
10089 	{
10090 		unsigned char *img;
10091 		double *filt, sum;
10092 		int x, y, x1;
10093 
10094 		/* Get location */
10095 		y = y0 + dyy[j];
10096 		x = j + dxx[y];
10097 		x1 = x + xfsz;
10098 		filt = xfilt - x + y * xfsz;
10099 
10100 		/* Skip empty space */
10101 		while (x1 > ow) x1--;
10102 		while (x < 0) x++;
10103 
10104 		/* Setup source */
10105 		img = src + y * ow + x;
10106 
10107 		/* Accumulate image data */
10108 		filt += x; sum = 0.0;
10109 		for (; x < x1; x++) sum += *img++ * *filt++;
10110 		*dest++ = sum;
10111 	}
10112 }
10113 
10114 /* !!! This works, after a fashion - but remains 2.5 times slower than a smooth
10115  * free-rotate if using 6-tap filter, or 1.5 times if using 2-tap one. Which,
10116  * while still being several times faster than anything else, is rather bad
10117  * for a high-quality tool like mtPaint. Needs improvement. - WJ */
mem_skew_filt(chanlist old_img,chanlist new_img,int ow,int oh,int nw,int nh,double xskew,double yskew,int mode,int gcor,int dis_a,int silent)10118 static void mem_skew_filt(chanlist old_img, chanlist new_img, int ow, int oh,
10119 	int nw, int nh, double xskew, double yskew, int mode, int gcor,
10120 	int dis_a, int silent)
10121 {
10122 	void *xmem, *ymem, *tmem;
10123 	double *xfilt, *yfilt, *wbuf, *rbuf;
10124 	int *dxx, *dyy;
10125 	double x0, y0, d, Kh, Kv, XX[4], YY[4], filler[7];
10126 	int i, cc, /*fw2, fh2,*/ xfsz, yfsz, wbsz, rgba, step, ny, nr;
10127 
10128 
10129 	/* Create temp data */
10130 	step = (rgba = new_img[CHN_ALPHA] && !dis_a) ? 7 : 3;
10131 	xmem = make_skew_filter(&xfilt, &dxx, &xfsz, oh, (nw - ow) * 0.5, xskew, mode);
10132 	ymem = make_skew_filter(&yfilt, &dyy, &yfsz, nw, (nh - oh) * 0.5, yskew, mode);
10133 //	fw2 = xfsz >> 1; fh2 = yfsz >> 1;
10134 
10135 	wbsz = nw * step;
10136 	tmem = multialloc(MA_ALIGN_DOUBLE, &wbuf, wbsz * yfsz * sizeof(double),
10137 		&rbuf, wbsz * sizeof(double), NULL);
10138 	if (!xmem || !ymem || !tmem) goto fail;
10139 	x0 = 0.5 * (nw - 1); y0 = 0.5 * (nh - 1);
10140 
10141 	/* Calculate clipping parallelogram's corners */
10142 	// To avoid corner cases, we add an extra pixel to original dimensions
10143 	XX[1] = XX[3] = (XX[0] = XX[2] = 0.5 * (nw - ow) - 1) + ow + 1;
10144 	YY[2] = YY[3] = (YY[0] = YY[1] = 0.5 * (nh - oh) - 1) + oh + 1;
10145 	for (i = 0; i < 4; i++)
10146 	{
10147 		XX[i] += (YY[i] - y0) * xskew;
10148 		YY[i] += (XX[i] - x0) * yskew;
10149 	}
10150 	d = 1.0 + xskew * yskew;
10151 	Kv = d ? xskew / d : 0.0; // for left & right
10152 	Kh = yskew ? 1.0 / yskew : 0.0; // for top & bottom
10153 
10154 	/* Init filler */
10155 	memset(filler, 0, sizeof(filler));
10156 	if (gcor)
10157 	{
10158 		filler[0] = gamma256[mem_col_A24.red];
10159 		filler[1] = gamma256[mem_col_A24.green];
10160 		filler[2] = gamma256[mem_col_A24.blue];
10161 	}
10162 	else
10163 	{
10164 		filler[0] = mem_col_A24.red;
10165 		filler[1] = mem_col_A24.green;
10166 		filler[2] = mem_col_A24.blue;
10167 	}
10168 
10169 	/* Process image channels */
10170 	for (nr = cc = 0; cc < NUM_CHANNELS; cc++) nr += !!new_img[cc];
10171 	nr = (nr - rgba) * (nh + yfsz - 1);
10172 	for (ny = cc = 0; cc < NUM_CHANNELS; cc++)
10173 	{
10174 		int ring_l[FILT_MAX], ring_r[FILT_MAX];
10175 		int i, idx, bpp = cc == CHN_IMAGE ? step : 1;
10176 
10177 		if (!new_img[cc]) continue;
10178 		/* Alpha already processed for RGBA */
10179 		if ((cc == CHN_ALPHA) && rgba) continue;
10180 
10181 		/* Init border rings to all-filled */
10182 		for (i = 0; i < yfsz; i++) ring_l[i] = 0 , ring_r[i] = nw;
10183 
10184 		/* Row loop */
10185 		for (i = 1 - yfsz , idx = 0; i < nh; i++ , ++idx >= yfsz ? idx = 0 : 0)
10186 		{
10187 			double *filt0, *thatbuf, *thisbuf = wbuf + idx * wbsz;
10188 			int j, k, y0, xl, xr, len, ofs, lfx = -xfsz;
10189 
10190 			if (!silent && ((++ny * 10) % nr >= nr - 10))
10191 				progress_update((float)ny / nr);
10192 
10193 			/* Locate source row */
10194 			y0 = i + yfsz - 1; // Effective Y offset
10195 
10196 			/* !!! A reliable equation for pixel-precise clipping
10197 			 * of source rows stubbornly refuses to be found, so
10198 			 * a brute-force approach is used instead - WJ */
10199 			xl = 0; xr = nw;
10200 			for (; xl < xr; xl++) // Skip empty pixels on the left
10201 			{
10202 				int j = y0 + dyy[xl];
10203 				if ((j < 0) || (j >= oh)) continue;
10204 				j = xl + dxx[j];
10205 				if ((j <= lfx) || (j >= ow)) continue;
10206 				break;
10207 			}
10208 			for (; xl < xr; xr--) // Same on the right
10209 			{
10210 				int j = y0 + dyy[xr - 1];
10211 				if ((j < 0) || (j >= oh)) continue;
10212 				j = xr - 1 + dxx[j];
10213 				if ((j <= lfx) || (j >= ow)) continue;
10214 				break;
10215 			}
10216 			if (xl >= xr) xl = xr = ring_r[idx];
10217 
10218 			/* Read in a new row */
10219 			(cc != CHN_IMAGE ? skew_fill_util : rgba ?
10220 				skew_fill_rgba : skew_fill_rgb)(thisbuf,
10221 				filler, old_img[cc], old_img[CHN_ALPHA],
10222 				y0, ow, xl, xr, ring_l[idx], ring_r[idx],
10223 				xfsz, xfilt, dxx, dyy, gcor);
10224 
10225 			if (xl >= xr) xl = nw , xr = 0;
10226 			ring_l[idx] = xl;
10227 			ring_r[idx] = xr;
10228 
10229 			if (i < 0) continue; // Initialization phase
10230 
10231 			/* Clip target row */
10232 			if (i <= YY[0]) xl = ceil(XX[0] + (i - YY[0]) * Kh);
10233 			else if (i <= YY[2]) xl = ceil(XX[2] + (i - YY[2]) * Kv);
10234 			else /* if (i <= YY[3]) */ xl = ceil(XX[2] + (i - YY[2]) * Kh);
10235 			if (i <= YY[1]) xr = ceil(XX[1] + (i - YY[1]) * Kh);
10236 			else if (i <= YY[3]) xr = ceil(XX[3] + (i - YY[3]) * Kv);
10237 			else /* if (i <= YY[2]) */ xr = ceil(XX[3] + (i - YY[3]) * Kh);
10238 			if (xl < 0) xl = 0;
10239 			if (xr > nw) xr = nw; // Right boundary is exclusive
10240 
10241 			/* Run vertical filter over the row buffers */
10242 			thisbuf = rbuf + xl * bpp;
10243 			thatbuf = wbuf + xl * bpp;
10244 			len = xr - xl;
10245 			if (len <= 0); // Do nothing
10246 			else if (yfsz == 1) // Just copy
10247 				memcpy(thisbuf, thatbuf, len * bpp * sizeof(double));
10248 			else // Apply filter
10249 			{
10250 				memset(thisbuf, 0, len * bpp * sizeof(double));
10251 				filt0 = yfilt + xl * yfsz;
10252 				for (j = 0 , k = idx; j < yfsz; j++)
10253 				{
10254 					double *dsrc, *ddest = thisbuf, *filt = filt0++;
10255 					int l = len;
10256 
10257 					if (++k >= yfsz) k = 0;
10258 					dsrc = thatbuf + k * wbsz;
10259 					while (l-- > 0)
10260 					{
10261 						double kk = *filt;
10262 						filt += yfsz;
10263 						*ddest++ += *dsrc++ * kk;
10264 						if (bpp < 3) continue;
10265 						*ddest++ += *dsrc++ * kk;
10266 						*ddest++ += *dsrc++ * kk;
10267 						if (bpp == 3) continue;
10268 						*ddest++ += *dsrc++ * kk;
10269 						*ddest++ += *dsrc++ * kk;
10270 						*ddest++ += *dsrc++ * kk;
10271 						*ddest++ += *dsrc++ * kk;
10272 					}
10273 				}
10274 			}
10275 
10276 			/* Write out results */
10277 			ofs = i * nw + xl;
10278 			if (cc == CHN_IMAGE) // RGB and RGBA
10279 			{
10280 				double *dsrc = thisbuf;
10281 				unsigned char *dest, *dsta;
10282 				int l = len, n = step;
10283 
10284 				dest = new_img[CHN_IMAGE] + ofs * 3;
10285 				dsta = rgba ? new_img[CHN_ALPHA] + ofs : NULL;
10286 				while (l-- > 0)
10287 				{
10288 					double rr, gg, bb, aa;
10289 					int a;
10290 
10291 					if (dsta && (a = rint(aa = dsrc[6]) ,
10292 						*dsta++ = a < 0 ? 0 :
10293 						a > 0xFF ? 0xFF : a))
10294 					{
10295 						aa = 1.0 / aa;
10296 						rr = dsrc[3] * aa;
10297 						gg = dsrc[4] * aa;
10298 						bb = dsrc[5] * aa;
10299 					}
10300 					else
10301 					{
10302 						rr = dsrc[0];
10303 						gg = dsrc[1];
10304 						bb = dsrc[2];
10305 					}
10306 					if (gcor)
10307 					{
10308 						dest[0] = UNGAMMA256X(rr);
10309 						dest[1] = UNGAMMA256X(gg);
10310 						dest[2] = UNGAMMA256X(bb);
10311 					}
10312 					else
10313 					{
10314 						int r, g, b;
10315 						r = rint(rr);
10316 						dest[0] = r < 0 ? 0 : r > 0xFF ? 0xFF : r;
10317 						g = rint(gg);
10318 						dest[1] = g < 0 ? 0 : g > 0xFF ? 0xFF : g;
10319 						b = rint(bb);
10320 						dest[2] = b < 0 ? 0 : b > 0xFF ? 0xFF : b;
10321 					}
10322 					dsrc += n; dest += 3;
10323 				}
10324 			}
10325 			else // Utility channel
10326 			{
10327 				double *dsrc = thisbuf;
10328 				unsigned char *dest = new_img[cc] + ofs;
10329 				int l = len, n;
10330 
10331 				while (l-- > 0)
10332 				{
10333 					n = rint(*dsrc++);
10334 					*dest++ = n < 0 ? 0 : n > 0xFF ? 0xFF : n;
10335 				}
10336 			}
10337 		}
10338 	}
10339 
10340 fail:	free(xmem);
10341 	free(ymem);
10342 	free(tmem);
10343 }
10344 
mem_skew_nn(chanlist old_img,chanlist new_img,int ow,int oh,int nw,int nh,int bpp,double xskew,double yskew,int silent)10345 static void mem_skew_nn(chanlist old_img, chanlist new_img, int ow, int oh,
10346 	int nw, int nh, int bpp, double xskew, double yskew, int silent)
10347 {
10348 	double x0, y0, d, Kh, Kv, XX[4], YY[4];
10349 	int i, ny;
10350 
10351 	/* Calculate clipping parallelogram's corners */
10352 	x0 = 0.5 * (nw - 1); y0 = 0.5 * (nh - 1);
10353 	XX[1] = XX[3] = (XX[0] = XX[2] = 0.5 * (nw - ow - 1)) + ow;
10354 	YY[2] = YY[3] = (YY[0] = YY[1] = 0.5 * (nh - oh - 1)) + oh;
10355 	for (i = 0; i < 4; i++)
10356 	{
10357 		XX[i] += (YY[i] - y0) * xskew;
10358 		YY[i] += (XX[i] - x0) * yskew;
10359 	}
10360 	d = 1.0 + xskew * yskew;
10361 	Kv = d ? xskew / d : 0.0; // for left & right
10362 	Kh = yskew ? 1.0 / yskew : 0.0; // for top & bottom
10363 
10364 	/* Process image row by row */
10365 	for (ny = 0; ny < nh; ny++)
10366 	{
10367 		int cc, xl, xr;
10368 
10369 		if (!silent && ((ny * 10) % nh >= nh - 10))
10370 			progress_update((float)ny / nh);
10371 
10372 		/* Clip row */
10373 		if (ny <= YY[0]) xl = ceil(XX[0] + (ny - YY[0]) * Kh);
10374 		else if (ny <= YY[2]) xl = ceil(XX[2] + (ny - YY[2]) * Kv);
10375 		else /* if (ny <= YY[3]) */ xl = ceil(XX[2] + (ny - YY[2]) * Kh);
10376 		if (ny <= YY[1]) xr = ceil(XX[1] + (ny - YY[1]) * Kh);
10377 		else if (ny <= YY[3]) xr = ceil(XX[3] + (ny - YY[3]) * Kv);
10378 		else /* if (ny <= YY[2]) */ xr = ceil(XX[3] + (ny - YY[3]) * Kh);
10379 		if (xl < 0) xl = 0;
10380 		if (xr > nw) xr = nw; // Right boundary is exclusive
10381 
10382 		for (cc = 0; cc < NUM_CHANNELS; cc++)
10383 		{
10384 			unsigned char *src, *dest;
10385 			double x0y, y0y;
10386 			int nx, ox, oy;
10387 
10388 			if (!new_img[cc]) continue;
10389 
10390 			x0y = 0.5 * (ow - 1) - x0 * d + (y0 - ny) * xskew;
10391 			y0y = x0 * yskew - 0.5 * (nh - oh) + ny;
10392 
10393 			/* RGB nearest neighbour */
10394 			if ((cc == CHN_IMAGE) && (bpp == 3))
10395 			{
10396 				dest = new_img[CHN_IMAGE] + (ny * nw + xl) * 3;
10397 				for (nx = xl; nx < xr; nx++ , dest += 3)
10398 				{
10399 // !!! Later, try reimplementing these calculations in row-then-column way -
10400 // !!! while less theoretically precise, it might cause less jitter, and better
10401 // !!! match what other skew-transform code does - WJ
10402 					WJ_ROUND(ox, x0y + nx * d);
10403 					WJ_ROUND(oy, y0y - nx * yskew);
10404 					src = old_img[CHN_IMAGE] +
10405 						(oy * ow + ox) * 3;
10406 					dest[0] = src[0];
10407 					dest[1] = src[1];
10408 					dest[2] = src[2];
10409 				}
10410 			}
10411 			/* One-bpp nearest neighbour */
10412 			else
10413 			{
10414 				dest = new_img[cc] + ny * nw + xl;
10415 				for (nx = xl; nx < xr; nx++)
10416 				{
10417 					WJ_ROUND(ox, x0y + nx * d);
10418 					WJ_ROUND(oy, y0y - nx * yskew);
10419 					*dest++ = old_img[cc][oy * ow + ox];
10420 				}
10421 			}
10422 		}
10423 	}
10424 }
10425 
10426 /* Skew geometry calculation is far nastier than same for rotation, and worse,
10427  * the approaches don't quite match in case of 3-skew rotation - WJ */
mem_skew_geometry(int ow,int oh,double xskew,double yskew,int rotation,int * nw,int * nh)10428 static void mem_skew_geometry(int ow, int oh, double xskew, double yskew,
10429 	int rotation, int *nw, int *nh)
10430 {
10431 	double nww, nhh, ax, ay;
10432 	int dx, dy, dx0, dy0;
10433 
10434 
10435 	/* Select new centering */
10436 	dx0 = ow & 1; dy0 = oh & 1;
10437 	/* Pure skew */
10438 	if (!rotation)
10439 	{
10440 		/* For certain skew factors, when the other dimension is even,
10441 		 * rows/columns nearest to axis fit the pixel grid better if
10442 		 * skew dimension is realigned to offset them half a pixel */
10443 		dx = dy0 ? dx0 : dx0 ^ ((int)(fabs(xskew) + 0.5) & 1);
10444 		dy = dx ? dy0 : dy0 ^ ((int)(fabs(yskew) + 0.5) & 1);
10445 	}
10446 	/* Rotation for 45 degrees or less */
10447 	else if (fabs(yskew) <= M_SQRT1_2) dx = dx0 , dy = dy0;
10448 	/* Rotation for more than 45 degrees */
10449 	else
10450 	{
10451 		// Height gets to be odd - do width realign now
10452 		if (dx0) dx = dy0;
10453 		// Leave width realign till 3rd pass
10454 		else if (dy0) dx = 0;
10455 		// Let double realign happen when possible & useful
10456 		else dx = (int)(fabs(xskew) + 0.5) & 1;
10457 		dy = dx0;
10458 	}
10459 
10460 	/* Calculate theoretical dimensions */
10461 	ax = fabs(xskew); ay = fabs(yskew);
10462 	nww = ow + oh * ax;
10463 	if (xskew * yskew >= 0) nhh = nww * ay + oh;
10464 	else if (ax * ay > 1) nhh = nww * ay - oh;
10465 	else nhh = (ow - oh * ax) * ay + oh;
10466 	/* Convert to actual pixel dimensions */
10467 	*nw = 2 * (int)(0.5 * (nww - dx) + PIX_ADD) + dx;
10468 	*nh = 2 * (int)(0.5 * (nhh - dy) + PIX_ADD) + dy;
10469 }
10470 
10471 // Skew canvas in one or two directions (X then Y)
10472 // !!! Later, extend to handle skew+shift in both directions, too
mem_skew(double xskew,double yskew,int type,int gcor)10473 int mem_skew(double xskew, double yskew, int type, int gcor)
10474 {
10475 	chanlist old_img, new_img;
10476 	int ow, oh, nw, nh, res, bpp;
10477 
10478 	ow = mem_width;
10479 	oh = mem_height;
10480 	bpp = mem_img_bpp;
10481 
10482 	mem_skew_geometry(ow, oh, xskew, yskew, FALSE, &nw, &nh);
10483 
10484 	if ((nw > MAX_WIDTH) || (nh > MAX_HEIGHT)) return (-5);
10485 
10486 	memcpy(old_img, mem_img, sizeof(chanlist));
10487 	res = undo_next_core(UC_NOCOPY, nw, nh, bpp, CMASK_ALL);
10488 	if (res) return (res);		// No undo space
10489 	memcpy(new_img, mem_img, sizeof(chanlist));
10490 	progress_init(_("Skew"), 0);
10491 
10492 	mem_clear_img(new_img, nw, nh, bpp);
10493 	if (!type || (mem_img_bpp == 1)) mem_skew_nn(old_img, new_img,
10494 		ow, oh, nw, nh, bpp, xskew, yskew, FALSE);
10495 	else mem_skew_filt(old_img, new_img, ow, oh, nw, nh, xskew, yskew,
10496 		type, gcor, channel_dis[CHN_ALPHA], FALSE);
10497 
10498 	progress_end();
10499 
10500 	return (0);
10501 }
10502 
10503 // Get average of utility channel pixels in an area
average_channel(unsigned char * src,int iw,int * vxy)10504 int average_channel(unsigned char *src, int iw, int *vxy)
10505 {
10506 	unsigned char *tmp;
10507 	unsigned int nn, wh;
10508 	int i, j, x, y, w, h;
10509 
10510 	w = vxy[2] - (x = vxy[0]);
10511 	h = vxy[3] - (y = vxy[1]);
10512 	src += y * iw + x;
10513 
10514 	/* Average area */
10515 	for (nn = i = 0; i < h; i++)
10516 	{
10517 		tmp = src + i * iw;
10518 		for (j = w; j--; nn += *tmp++);
10519 	}
10520 	wh = w * h;
10521 	return ((nn + (wh >> 1)) / wh);
10522 }
10523 
10524 // Get gamma-corrected average of RGB/RGBA pixels in an area
average_pixels(unsigned char * rgb,unsigned char * alpha,int iw,int * vxy)10525 int average_pixels(unsigned char *rgb, unsigned char *alpha, int iw, int *vxy)
10526 {
10527 	unsigned char *tmp, *tma;
10528 	double rr, gg, bb, dd;
10529 	int i, j, k, x, y, w, h;
10530 
10531 	w = vxy[2] - (x = vxy[0]);
10532 	h = vxy[3] - (y = vxy[1]);
10533 	rgb += (y * iw + x) * 3;
10534 	if (alpha) alpha += y * iw + x;
10535 
10536 	/* Average (gamma corrected) area */
10537 	rr = gg = bb = dd = 0.0;
10538 	for (i = 0; i < h; i++)
10539 	{
10540 		tmp = rgb + i * iw * 3;
10541 		if (alpha)
10542 		{
10543 			tma = alpha + i * iw;
10544 			for (j = 0; j < w; j++ , tmp += 3)
10545 			{
10546 				dd += k = *tma++;
10547 				rr += k * gamma256[tmp[0]];
10548 				gg += k * gamma256[tmp[1]];
10549 				bb += k * gamma256[tmp[2]];
10550 			}
10551 		}
10552 		else
10553 		{
10554 			dd += w;
10555 			for (j = 0; j < w; j++ , tmp += 3)
10556 			{
10557 				rr += gamma256[tmp[0]];
10558 				gg += gamma256[tmp[1]];
10559 				bb += gamma256[tmp[2]];
10560 			}
10561 		}
10562 	}
10563 	dd = 1.0 / dd;
10564 	rr *= dd; gg *= dd; bb *= dd;
10565 	return (RGB_2_INT(UNGAMMA256(rr), UNGAMMA256(gg), UNGAMMA256(bb)));
10566 }
10567 
10568 // Convert a row of pixels to any of 3 colorspaces
mem_convert_row(double * dest,unsigned char * src,int l,int cspace)10569 static void mem_convert_row(double *dest, unsigned char *src, int l, int cspace)
10570 {
10571 	if (cspace == CSPACE_LXN)
10572 	{
10573 		while (l-- > 0)
10574 		{
10575 			get_lxn(dest, MEM_2_INT(src, 0));
10576 			dest += 3; src += 3;
10577 		}
10578 	}
10579 	else if (cspace == CSPACE_SRGB)
10580 	{
10581 		l *= 3;
10582 		while (l-- > 0) *dest++ = gamma256[*src++];
10583 	}
10584 	else /* if (cspace == CSPACE_RGB) */
10585 	{
10586 		l *= 3;
10587 		while (l-- > 0) *dest++ = *src++;
10588 	}
10589 }
10590 
10591 ///	SEGMENTATION
10592 
10593 /*
10594  * This code implements a 4-way variation of the segmentation algorithm
10595  * described in:
10596  * Pedro F. Felzenszwalb, "Efficient Graph-Based Image Segmentation"
10597  */
10598 
cmp_edge(const void * v1,const void * v2)10599 static int cmp_edge(const void *v1, const void *v2)
10600 {
10601 	float f1 = ((seg_edge *)v1)->diff, f2 = ((seg_edge *)v2)->diff;
10602 	return (f1 < f2 ? -1 : f1 != f2 ? f1 > f2 :
10603 		((seg_edge *)v1)->which - ((seg_edge *)v2)->which);
10604 }
10605 
seg_find(seg_pixel * pix,int n)10606 static inline int seg_find(seg_pixel *pix, int n)
10607 {
10608 	unsigned int i, j;
10609 
10610 	for (i = n; i != (j = pix[i].group); i = j);
10611 	return (pix[n].group = i);
10612 }
10613 
seg_join(seg_pixel * pix,int a,int b)10614 static inline int seg_join(seg_pixel *pix, int a, int b)
10615 {
10616 	seg_pixel *ca = pix + a, *cb = pix + b;
10617 
10618 	if (ca->rank > cb->rank)
10619 	{
10620 		ca->cnt += cb->cnt;
10621 		return (cb->group = a);
10622 	}
10623 	cb->cnt += ca->cnt;
10624 	cb->rank += (ca->rank == cb->rank);
10625 	return (ca->group = b);
10626 }
10627 
mem_seg_prepare(seg_state * s,unsigned char * img,int w,int h,int flags,int cspace,int dist)10628 seg_state *mem_seg_prepare(seg_state *s, unsigned char *img, int w, int h,
10629 	int flags, int cspace, int dist)
10630 {
10631 	static const unsigned char dist_scales[NUM_CSPACES] = { 1, 255, 1 };
10632 	seg_edge *e;
10633 	double mult, *row0, *row1, *rows[2];
10634 	int i, j, k, l, bsz, sz = w * h;
10635 
10636 
10637 	// !!! Will need a longer int type (and twice the memory) otherwise
10638 	if (sz > (INT_MAX >> 1) + 1) return (NULL);
10639 
10640 	/* 3 buffers will be sharing space */
10641 	bsz = w * 3 * 2 * sizeof(double);
10642 	l = sz * sizeof(seg_pixel);
10643 	if (l > bsz) bsz = l;
10644 
10645 	if (!s) // Reuse existing allocation if possible
10646 	{ /* Allocation is HUGE, but no way to make do with smaller one - WJ */
10647 		void *v[3];
10648 
10649 		s = multialloc(MA_ALIGN_DOUBLE,
10650 			v, sizeof(seg_state), // Dummy pointer (header struct)
10651 			v + 1, bsz, // Row buffers/pixel nodes
10652 			v + 2, sz * 2 * sizeof(seg_edge), // Pixel connections
10653 			NULL);
10654 		if (!s) return (NULL);
10655 		s->pix = v[1];
10656 		s->edges = v[2];
10657 		s->w = w;
10658 		s->h = h;
10659 	}
10660 	rows[0] = (void *)s->pix; // 1st row buffer
10661 	rows[1] = rows[0] + w * 3; // 2nd row buffer
10662 	s->phase = 0; // Struct is to be refilled
10663 
10664 	if (flags & SEG_PROGRESS) progress_init(_("Segmentation Pass 1"), 1);
10665 
10666 	/* Compute color distances, fill connections buffer */
10667 	l = w * 3;
10668 	mult = dist_scales[cspace]; // Make all colorspaces use similar scale
10669 	for (i = 0 , e = s->edges; i < h; i++)
10670 	{
10671 		k = i * w;
10672 		mem_convert_row(row1 = rows[i & 1], img + k * 3, w, cspace);
10673 		/* Right vertices for this row */
10674 		for (j = 3 , k *= 2; j < l; j += 3 , k += 2 , e++)
10675 		{
10676 			e->which = k;
10677 			e->diff = mult * distance_3d[dist](row1 + j - 3, row1 + j);
10678 		}
10679 		if (!i) continue;
10680 		/* Bottom vertices for previous row */
10681 		k = (i - 1) * w * 2 + 1;
10682 		row0 = rows[~i & 1];
10683 		for (j = 0; j < l; j += 3 , k += 2 , e++)
10684 		{
10685 			e->which = k;
10686 			e->diff = mult * distance_3d[dist](row0 + j, row1 + j);
10687 		}
10688 		if ((flags & SEG_PROGRESS) && ((i * 20) % h >= h - 20))
10689 			if (progress_update((0.9 * i) / h)) goto quit;
10690 	}
10691 
10692 	/* Sort connections, smallest distances first */
10693 	s->cnt = e - s->edges;
10694 	qsort(s->edges, s->cnt, sizeof(seg_edge), cmp_edge);
10695 
10696 	s->phase = 1;
10697 
10698 quit:	if (flags & SEG_PROGRESS) progress_end();
10699 
10700 	return (s);
10701 }
10702 
mem_seg_process_chunk(int start,int cnt,seg_state * s)10703 int mem_seg_process_chunk(int start, int cnt, seg_state *s)
10704 {
10705 	seg_edge *edge;
10706 	seg_pixel *cp, *pix = s->pix;
10707 	double threshold = s->threshold;
10708 	int minrank = s->minrank, minsize = s->minsize;
10709 	int sz = s->w * s->h, w1[2] = { 1, s->w };
10710 	int i, ix, pass;
10711 
10712 	/* Initialize pixel nodes */
10713 	if (!start)
10714 	{
10715 		for (i = 0 , cp = pix; i < sz; i++ , cp++)
10716 		{
10717 			cp->group = i;
10718 			cp->cnt = 1;
10719 			cp->rank = 0;
10720 			cp->threshold = threshold;
10721 		}
10722 	}
10723 
10724 	/* Setup loop range */
10725 	pass = start / s->cnt;
10726 	i = start % s->cnt;
10727 	cnt += i;
10728 
10729 	for (; pass < 3; pass++)
10730 	{
10731 		ix = cnt < s->cnt ? cnt : s->cnt;
10732 		edge = s->edges + i;
10733 		for (; i < ix; i++ , edge++)
10734 		{
10735 			float dist;
10736 			int j, k, idx;
10737 
10738 			/* Get the original pixel */
10739 			dist = edge->diff;
10740 			idx = edge->which;
10741 			j = idx >> 1;
10742 			/* Get the neighboring pixel's index */
10743 			k = j + w1[idx & 1];
10744 			/* Get segment anchors */
10745 			j = seg_find(pix, j);
10746 			k = seg_find(pix, k);
10747 			if (j == k) continue;
10748 			/* Merge segments if difference is small enough in pass 0,
10749 			 * one of segments is too low rank in pass 1, or is too
10750 			 * small in pass 2 */
10751 			if (!pass ? ((dist <= pix[j].threshold) &&
10752 					(dist <= pix[k].threshold)) :
10753 				pass == 1 ? ((pix[j].rank < minrank) ||
10754 					(pix[k].rank < minrank)) :
10755 				((pix[j].cnt < minsize) || (pix[k].cnt < minsize)))
10756 			{
10757 				seg_pixel *cp = pix + seg_join(pix, j, k);
10758 				cp->threshold = dist + threshold / cp->cnt;
10759 			}
10760 		}
10761 		/* Pass not yet completed - return progress */
10762 		if (cnt < s->cnt) return (pass * s->cnt + cnt);
10763 		cnt -= s->cnt;
10764 		i = 0;
10765 		pass += !pass && !minrank; // Maybe skip pass 1
10766 		pass += pass && (minsize <= (1 << minrank)); // Maybe skip pass 2
10767 	}
10768 
10769 	/* Normalize groups */
10770 	for (i = 0; i < sz; i++) seg_find(pix, i);
10771 
10772 	/* All done */
10773 	s->phase |= 2;
10774 	return (s->cnt * 3);
10775 }
10776 
mem_seg_process(seg_state * s)10777 int mem_seg_process(seg_state *s)
10778 {
10779 	int i, n, cnt = s->cnt * 3;
10780 
10781 
10782 	if (s->w * s->h < 1024 * 1024)
10783 	{
10784 		/* Run silently */
10785 		mem_seg_process_chunk(0, cnt, s);
10786 		return (TRUE);
10787 	}
10788 
10789 	/* Show progress */
10790 	n = (cnt + 19) / 20;
10791 	progress_init(_("Segmentation Pass 2"), 1);
10792 	for (i = 0; s->phase < 2; i = mem_seg_process_chunk(i, n, s))
10793  		if (progress_update((float)i / cnt)) break;
10794 	progress_end();
10795 	return (s->phase >= 2);
10796 }
10797 
10798 /* This produces for one row 2 difference bits per pixel: left & up; if called
10799  * with segmentation still in progress, will show oversegmentation */
mem_seg_scan(unsigned char * dest,int y,int x,int w,int zoom,const seg_state * s)10800 void mem_seg_scan(unsigned char *dest, int y, int x, int w, int zoom,
10801 	const seg_state *s)
10802 {
10803 	int i, j, k, l, ofs, dy;
10804 	seg_pixel *pix = s->pix;
10805 
10806 	memset(dest, 0, (w + 3) >> 2);
10807 	ofs = (y * s->w + x) * zoom;
10808 	dy = y ? s->w * zoom : 0; // No up neighbors for Y=0
10809 	j = pix[ofs + (!x - 1) * zoom].group; // No left neighbor for X=0
10810 	for (i = 0; i < w; i++ , j = k , ofs += zoom)
10811 	{
10812 		k = pix[ofs].group , l = pix[ofs - dy].group;
10813 		dest[i >> 2] |= ((j != k) * 2 + (k != l)) << ((i + i) & 6);
10814 	}
10815 }
10816 
10817 /* Draw segments in unique colors */
mem_seg_render(unsigned char * img,const seg_state * s)10818 void mem_seg_render(unsigned char *img, const seg_state *s)
10819 {
10820 	int i, k, l, sz = s->w * s->h;
10821 	seg_pixel *pix = s->pix;
10822 
10823 	for (i = l = 0; i < sz; i++)
10824 	{
10825 		int j, k, r, g, b;
10826 
10827 		if (pix[i].group != i) continue; // Only new groups
10828 		k = l++;
10829 		/* Transform index to most distinct RGB color */
10830 		for (j = r = g = b = 0; j < 8; j++)
10831 		{
10832 			r += r + (k & 1); k >>= 1;
10833 			g += g + (k & 1); k >>= 1;
10834 			b += b + (k & 1); k >>= 1;
10835 		}
10836 		pix[i].cnt = RGB_2_INT(r, g, b);
10837 	}
10838 
10839 	for (i = 0; i < sz; i++ , img += 3)
10840 	{
10841 		k = pix[pix[i].group].cnt;
10842 		img[0] = INT_2_R(k);
10843 		img[1] = INT_2_G(k);
10844 		img[2] = INT_2_B(k);
10845 	}
10846 }
10847 
10848 #define FRACTAL_DIM 1.25
10849 //#define FRACTAL_THR 20 /* dragban2.jpg */
10850 #define FRACTAL_THR 15 /* dragban2.jpg after K-N */
10851 #define THRESHOLD_MULT 20.0
10852 
10853 /* Estimate contour length by fractal dimension, use the difference value found
10854  * this way as threshold's base value */
mem_seg_threshold(seg_state * s)10855 double mem_seg_threshold(seg_state *s)
10856 {
10857 	int k = s->cnt - FRACTAL_THR * pow(s->cnt, 0.5 * FRACTAL_DIM);
10858 	while (!s->edges[k].diff && (k < s->cnt - 1)) k++;
10859 	return (s->edges[k].diff ? s->edges[k].diff * THRESHOLD_MULT : 1.0);
10860 }
10861 
10862 #undef FRACTAL_DIM
10863 #undef FRACTAL_THR
10864 #undef THRESHOLD_MULT
10865 
10866 /// NOISE
10867 
10868 /*
10869  * This code implements classical Perlin noise, with the added tweak that nodes
10870  * of every octave are offset against all the others, so that you won't observe
10871  * N successively smaller copies of same thing over one another at the upper left
10872  */
10873 
10874 static uint32_t ran_seed[2];
10875 
ran_init(uint32_t seed)10876 void ran_init(uint32_t seed)
10877 {
10878 	ran_seed[1] = (ran_seed[0] = seed ^ 0xC0FFEE) * 0x10450405 + 1;
10879 }
10880 
10881 #define ROL(V,N) (((V) << (N)) | (V) >> (32 - (N)))
10882 
10883 /* xoroshiro64** 1.0 PRNG */
ran()10884 uint32_t ran()
10885 {
10886 	uint32_t r, s0 = ran_seed[0], s1 = ran_seed[1];
10887 
10888 	r = s0 * 0x9E3779BB;
10889 	r = ROL(r, 5) * 5;
10890 	s1 ^= s0;
10891 	ran_seed[0] = ROL(s0, 26) ^ s1 ^ (s1 << 9);
10892 	ran_seed[1] = ROL(s1, 13);
10893 	return (r);
10894 }
10895 
10896 static struct {
10897 	int xstep, ystep, lvl;
10898 	float grad[256 * 2];
10899 	unsigned char p[256], map[768];
10900 } perlin_info;
10901 
init_perlin(int seed,int xstep,int ystep,int lvl,int maptype)10902 void init_perlin(int seed, int xstep, int ystep, int lvl, int maptype)
10903 {
10904 	float *fp = perlin_info.grad;
10905 	int i, j;
10906 
10907 	mem_prepare_map(perlin_info.map, maptype);
10908 
10909 	perlin_info.xstep = xstep;
10910 	perlin_info.ystep = ystep;
10911 
10912 	/* Limit lvl to max of log2(xstep,ystep) */
10913 	i = nlog2(xstep);
10914 	j = nlog2(ystep);
10915 	if (i < j) i = j;
10916 	i += !i; // Allow for useless setup of 1/1
10917 	if (lvl > i) lvl = i;
10918 	perlin_info.lvl = lvl;
10919 
10920 	ran_init(seed);
10921 
10922 	/* Random gradient vectors, equidistributed on unit circle */
10923 	for (i = 0; i < 256; i++)
10924 	{
10925 		double a = (2 * M_PI / 0x1000000) * (int)(ran() >> 8); // 24 random bits
10926 		*fp++ = sin(a);
10927 		*fp++ = cos(a);
10928 	}
10929 	/* Permutation table */
10930 	for (i = 0; i < 256; i++) perlin_info.p[i] = i;
10931 	for (i = 0; i < 255; i++)
10932 	{
10933 		unsigned char v = perlin_info.p[i];
10934 		int n = ran() % (256 - i) + i;
10935 		perlin_info.p[i] = perlin_info.p[n];
10936 		perlin_info.p[n] = v;
10937 	}
10938 }
10939 
do_perlin(int start,int step,int cnt,unsigned char * mask,unsigned char * imgr,int x,int y)10940 void do_perlin(int start, int step, int cnt, unsigned char *mask,
10941 	unsigned char *imgr, int x, int y)
10942 {
10943 	double sum, tx, ty, yb, d, dx, dy, sc, wyy[8], ybb[8];
10944 	int i, k, lvl, a, b, yp0[8], yp1[8], mstep = step, bpp = MEM_BPP;
10945 
10946 	/* Y-dependent values stay same for whole row */
10947 	dy = 0;
10948 	ty = (double)y / perlin_info.ystep;
10949 	for (lvl = 0; lvl < perlin_info.lvl; lvl++)
10950 	{
10951 		yb = ty + dy;
10952 		ybb[lvl] = yb -= (b = (int)yb);
10953 		wyy[lvl] = ((yb * 6.0 - 15.0) * yb + 10.0) * yb * yb * yb;
10954 		k = perlin_info.p[lvl] * lvl;
10955 		yp0[lvl] = perlin_info.p[(b + k) & 255];
10956 		yp1[lvl] = perlin_info.p[(b + 1 + k) & 255];
10957 		ty *= 2;
10958 		dy = 0.5; // Dealign levels' anchor grid
10959 	}
10960 
10961 	/* Normalization factor */
10962 	i = 1 << perlin_info.lvl;
10963 	sc = 255 * i / (M_SQRT2 * 2 * (i - 1));
10964 
10965 	x += start - step;
10966 	start *= bpp; step *= bpp;
10967 	imgr += start - step;
10968 
10969 	while (cnt-- > 0)
10970 	{
10971 		imgr += step; x += mstep;
10972 		if (mask[x] == 255) continue;
10973 		sum = dx = 0;
10974 		tx = (double)x / perlin_info.xstep;
10975 		d = 1;
10976 		for (lvl = 0; lvl < perlin_info.lvl; lvl++)
10977 		{
10978 			float *xp0, *xp1, *xp2, *xp3;
10979 			double xa, yb, wx, wy, dd, dd1;
10980 
10981 			xa = tx + dx;
10982 			xa -= (a = (int)xa);
10983 			wx = ((xa * 6.0 - 15.0) * xa + 10.0) * xa * xa * xa;
10984 			yb = ybb[lvl];
10985 			wy = wyy[lvl];
10986 			a += perlin_info.p[lvl] * lvl;
10987 			b = a + yp0[lvl];
10988 			xp0 = perlin_info.grad + perlin_info.p[b & 255] * 2;
10989 			dd = xp0[0] * xa + xp0[1] * yb;
10990 			xp1 = perlin_info.grad + perlin_info.p[(b + 1) & 255] * 2;
10991 			dd += wx * (xp1[0] * (xa - 1) + xp1[1] * yb - dd);
10992 			b = a + yp1[lvl];
10993 			xp2 = perlin_info.grad + perlin_info.p[b & 255] * 2;
10994 			dd1 = xp2[0] * xa + xp2[1] * (yb - 1);
10995 			xp3 = perlin_info.grad + perlin_info.p[(b + 1) & 255] * 2;
10996 			dd1 += wx * (xp3[0] * (xa - 1) + xp3[1] * (yb - 1) - dd1);
10997 			sum += (dd + (dd1 - dd) * wy) * d;
10998 			tx += tx;
10999 			d *= 0.5;
11000 			dx = 0.5; // Dealign levels' anchor grid
11001 		}
11002 		k = rint(sum * sc + 0.5 * 255.0);
11003 		if (bpp == 1) *imgr = k;
11004 		else
11005 		{
11006 			k *= 3;
11007 			imgr[0] = perlin_info.map[k + 0];
11008 			imgr[1] = perlin_info.map[k + 1];
11009 			imgr[2] = perlin_info.map[k + 2];
11010 		}
11011 	}
11012 }
11013 
11014 typedef struct {
11015 	unsigned char *buf, *mask;
11016 } noised;
11017 
perlin_noise(tcb * thread)11018 static void perlin_noise(tcb *thread)
11019 {
11020 	noised *nd = thread->data;
11021 	unsigned char *dest, *buf = nd->buf, *mask = nd->mask;
11022 	int i, ii, cnt = thread->nsteps, bpp = MEM_BPP;
11023 
11024 	for (i = thread->step0 , ii = 0; ii < cnt; i++ , ii++)
11025 	{
11026 		row_protected(0, i, mem_width, mask);
11027 		do_perlin(0, 1, mem_width, mask, buf, 0, i);
11028 		dest = mem_img[mem_channel] + i * mem_width * bpp;
11029 		process_img(0, 1, mem_width, mask, dest, dest, buf,
11030 			NULL, bpp, BLENDF_SET | BLENDF_INVM);
11031 		if (thread_step(thread, ii + 1, cnt, 10)) break;
11032 	}
11033 	thread_done(thread);
11034 }
11035 
mem_perlin()11036 void mem_perlin()
11037 {
11038 	noised nd;
11039 	threaddata *tdata;
11040 
11041 	tdata = talloc(MA_ALIGN_DEFAULT,
11042 		image_threads(mem_width, mem_height),
11043 		&nd, sizeof(nd),
11044 		NULL,
11045 		&nd.buf, mem_width * MEM_BPP,
11046 		&nd.mask, mem_width,
11047 		NULL);
11048 	if (!tdata)
11049 	{
11050 		memory_errors(1);
11051 		return;
11052 	}
11053 	launch_threads(perlin_noise, tdata, _("Solid Noise"), mem_height);
11054 	free(tdata);
11055 }
11056