1 
2 /*
3  *  Diverse Bristol audio routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 3 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include <stdio.h>
23 #include <math.h>
24 
25 #include "brightonX11.h"
26 
27 /*
28  * This is for some basic profiling of some of the routines, needed to optimise
29  * the codebase.
30  */
31 #define STATS
32 //#define STATS2
33 #ifdef STATS
34 #include <sys/time.h>
35 struct timeval tstart, tend;
36 #endif
37 
38 #include "brightoninternals.h"
39 
40 #define SQRT_TAB_SIZE 128
41 double sqrttab[SQRT_TAB_SIZE][SQRT_TAB_SIZE];
42 extern int cacheInsertColor(unsigned short, unsigned short, unsigned short, int);
43 
44 void
initSqrtTab()45 initSqrtTab()
46 {
47 	int i, j;
48 
49 	for (j = 0 ; j < SQRT_TAB_SIZE; j++)
50 	{
51 		for (i = 0 ; i < SQRT_TAB_SIZE; i++)
52 		{
53 			if ((sqrttab[i][j] = sqrt((double) (i * i + j * j))) == 0)
54 				sqrttab[i][j] = 0.0001;
55 		}
56 	}
57 }
58 
59 int
brightonInitBitmap(brightonBitmap * bitmap,int value)60 brightonInitBitmap(brightonBitmap *bitmap, int value)
61 {
62 	register int pindex, total = bitmap->width * bitmap->height;
63 
64 	for (pindex = 0; pindex < total; pindex++)
65 		bitmap->pixels[pindex] = value;
66 
67 	return(0);
68 }
69 
70 /*
71  * This is dead slow.
72  */
73 int
brightonWorldChanged(brightonWindow * bwin,int width,int height)74 brightonWorldChanged(brightonWindow *bwin, int width, int height)
75 {
76 	if (bwin->flags & BRIGHTON_DEBUG)
77 		printf("brightonWorldChanged(%i %i %i %i) %i %i\n",
78 			width, height,
79 			bwin->width, bwin->height,
80 			bwin->template->width, bwin->template->height);
81 
82 	/*
83 	 * We need to maintain aspect ratio. First take the new width, and build
84 	 * a corresponding height. If the height is outside the realms of the
85 	 * display then do the reverse. If, however, the width and height are
86 	 * within a reasonable amount of the desired aspect ratio, just use
87 	 * them.
88 	 *
89 	 * 110908 - FR 2243291 - Add an option to override the checks for aspect
90 	 * ratio. Required by some window managers to prevent permanant redrawing
91 	 * of the window however it results in some pretty gruesome images if the
92 	 * ratio is not a reasonable approximation of the original.
93 	 *
94 	 * There is some pretty ugly resizing stuff here. Going to propose the app
95 	 * will lose aspect ratio as resizing takes place, then on Focus change
96 	 * events it will see if aspect should be maintained and do a single resize
97 	 * at that point.
98 	 */
99 	if (bwin->flags & BRIGHTON_DEBUG)
100 		printf("%i %i, %i %i\n", width, height, bwin->width, bwin->height);
101 
102 	if (bwin->height != height)
103 		bwin->flags |= _BRIGHTON_SET_HEIGHT;
104 
105 	/* This is the KDE Postage Stamp fix */
106 	if ((height < 30) || (width < 50))
107 	{
108 		brightonRequestResize(bwin,
109 			bwin->template->width, bwin->template->height);
110 		return(0);
111 	}
112 
113 	bwin->width = width;
114 	bwin->height = height;
115 
116 	brightonFreeBitmap(bwin, bwin->canvas);
117 	brightonFreeBitmap(bwin, bwin->render);
118 	brightonFreeBitmap(bwin, bwin->dlayer);
119 	brightonFreeBitmap(bwin, bwin->slayer);
120 	brightonFreeBitmap(bwin, bwin->tlayer);
121 	brightonFreeBitmap(bwin, bwin->mlayer);
122 
123 	bwin->canvas = brightonCreateNamedBitmap(bwin, bwin->width, bwin->height,
124 		"canvas");
125 	bwin->dlayer = brightonCreateNamedBitmap(bwin, bwin->width, bwin->height,
126 		"dlayer");
127 	bwin->slayer = brightonCreateNamedBitmap(bwin, bwin->width, bwin->height,
128 		"slayer");
129 	bwin->tlayer = brightonCreateNamedBitmap(bwin, bwin->width, bwin->height,
130 		"tlayer");
131 	bwin->mlayer = brightonCreateNamedBitmap(bwin, bwin->width, bwin->height,
132 		"mlayer");
133 	bwin->render = brightonCreateNamedBitmap(bwin, bwin->width, bwin->height,
134 		"render");
135 
136 	if (bwin->display->flags & BRIGHTON_ANTIALIAS_3)
137 	{
138 		brightonFreeBitmap(bwin, bwin->renderalias);
139 		bwin->renderalias
140 			= brightonCreateBitmap(bwin, bwin->width, bwin->height);
141 	}
142 
143 	if (bwin->opacity == 0)
144 		bwin->opacity = 0.5f;
145 
146 	/*
147 	 * Our device and shadow layer need to be initialised with -1
148 	 */
149 	brightonInitBitmap(bwin->dlayer, -1);
150 	brightonInitBitmap(bwin->slayer, -1);
151 	brightonInitBitmap(bwin->tlayer, -1);
152 	brightonInitBitmap(bwin->mlayer, -1);
153 
154 	//placebox(bwin, bwin->mlayer, 100, 100, 100, 200);
155 
156 	bwin->lightX = -1000;
157 	bwin->lightY = -1000;
158 	bwin->lightH = 3000;
159 	bwin->lightI = 0.95;
160 
161 	/*
162 	 * We now have a configured size. We need to render the surface onto the
163 	 * window background, and render the image if we have any configured
164 	 * blueprints. These are rendered onto our canvas.
165 	 */
166 	if (bwin->app->flags & BRIGHTON_STRETCH)
167 		brightonStretch(bwin, bwin->surface, bwin->canvas, 0, 0,
168 			bwin->width, bwin->height, bwin->app->flags);
169 	else
170 		brightonTesselate(bwin, bwin->surface, bwin->canvas, 0, 0,
171 			bwin->width, bwin->height, bwin->app->flags);
172 
173 	if ((bwin->display->flags & BRIGHTON_ANTIALIAS_5)
174 		|| (bwin->display->flags & BRIGHTON_ANTIALIAS_3))
175 		brightonStretchAlias(bwin, bwin->image, bwin->canvas, 0, 0,
176 			bwin->width, bwin->height, 0.8);
177 	else
178 		brightonStretch(bwin, bwin->image, bwin->canvas, 0, 0,
179 			bwin->width, bwin->height, 0);
180 
181 	brightonRender(bwin, bwin->canvas, bwin->render, 0, 0,
182 		bwin->width, bwin->height, 0);
183 
184 	bwin->flags |= BRIGHTON_NO_DRAW;
185 
186 	if  (bwin->app)
187 	{
188 		int panel;
189 		brightonEvent event;
190 
191 		for (panel = 0; panel < bwin->app->nresources; panel++)
192 		{
193 			/*
194 			 * We need to configure the device to resize itself
195 			 */
196 			event.command = BRIGHTON_RESIZE;
197 			event.x = (int) bwin->app->resources[panel].x
198 				* bwin->width / 1000;
199 			event.y = (int) bwin->app->resources[panel].y
200 				* bwin->height / 1000;
201 			event.w = (int) bwin->app->resources[panel].width
202 				* bwin->width / 1000;
203 			event.h = (int) bwin->app->resources[panel].height
204 				* bwin->height / 1000;
205 
206 			bwin->app->resources[panel].configure(bwin,
207 				&bwin->app->resources[panel], &event);
208 		}
209 	}
210 
211 	bwin->flags &= ~BRIGHTON_NO_DRAW;
212 
213 	brightonRePlace(bwin);
214 
215 	brightonFinalRender(bwin, 0, 0, bwin->width, bwin->height);
216 
217 	/*
218 	 * Call the application to see if it wants to alter anything after the
219 	 * world changed.
220 	 */
221 	if (bwin->template->configure)
222 		bwin->template->configure(bwin);
223 
224 	return(0);
225 }
226 
227 int
brightonColorQuality(brightonWindow * bwin,int quality)228 brightonColorQuality(brightonWindow *bwin, int quality)
229 {
230 	if ((bwin->quality = quality) < 2)
231 		bwin->quality = 2;
232 	else if (bwin->quality > 8)
233 		bwin->quality = 8;
234 
235 	return(0);
236 }
237 
238 int
brightonOpacity(brightonWindow * bwin,float opacity)239 brightonOpacity(brightonWindow *bwin, float opacity)
240 {
241 	if ((bwin->opacity = opacity) < 0.01f)
242 		bwin->opacity = 0.01f;
243 	else if (bwin->opacity > 1.0f)
244 		bwin->opacity = 1.0f;
245 
246 	return(0);
247 }
248 
249 void
brightonLogo(brightonWindow * bwin)250 brightonLogo(brightonWindow *bwin)
251 {
252 	bwin->flags |= BRIGHTON_NO_LOGO;
253 }
254 
255 static int
antialias(brightonWindow * bwin,brightonBitmap * b,int x,int y,float primary)256 antialias(brightonWindow *bwin, brightonBitmap *b, int x, int y, float primary)
257 {
258 	register int nr, ng, nb, dy, color = 0, cpre, cnext, pindex, cpy, cny;
259 	register brightonPalette *palette = bwin->display->palette;
260 	float secondary;
261 
262 	if ((primary <= 0) || (primary > 1.0))
263 		return(color);
264 
265 	if ((x == 0) || (x >= bwin->width - 1)
266 		|| (y == 0) || (y >= bwin->height - 1))
267 		return(0);
268 
269 	dy = x + y * bwin->width;
270 
271 	cpy = b->pixels[x + (y - 1) * bwin->width];
272 	cny = b->pixels[x + (y + 1) * bwin->width];
273 	cpre = b->pixels[dy - 1];
274 	color = b->pixels[dy];
275 	cnext = b->pixels[dy + 1];
276 
277 
278 	/*
279 	 * Generally the palette for any color C will be specified as
280 	 *
281 	 *	C * aa + (4C * (1 - n)/4)
282 	 *
283 	 * This would work if aa was a floating point from 0 to 1.0. To do this
284 	 * requires two options, one of which is a flag to state that we are doing
285 	 * either texture or full image antialiasing and the value we want to use.
286 	 *
287 	 * For now we have a couple of values for each and they use predefined
288 	 * levels. As the value tends to one the antialiasing lessens, ie, we take
289 	 * more of the target pixel and less smoothing from the surrounding ones.
290 	 * This is counter intuitive in my opinion, I think the smoothing should
291 	 * increase as this value does, hence we will make it reciprocal.
292 	 *
293 	 * Values greater that 0.5 are actually counter productive, reducing the
294 	 * definition of the target pixel to the benefit of the surrounding ones.
295 	 */
296 	secondary = (1.0 - primary) / 4.0;
297 
298 	nr = (int) ( ((float) palette[color].red) * primary
299 		+ ((float) (palette[cpy].red + palette[cny].red
300 		+ palette[cpre].red + palette[cnext].red)) * secondary);
301 	ng = (int) ( ((float) palette[color].green) * primary
302 		+ ((float) (palette[cpy].green + palette[cny].green
303 		+ palette[cpre].green + palette[cnext].green)) * secondary);
304 	nb = (int) ( ((float) palette[color].blue) * primary
305 		+ ((float) (palette[cpy].blue + palette[cny].blue
306 		+ palette[cpre].blue + palette[cnext].blue)) * secondary);
307 
308 	/*
309 	 * We want to be flexible on matches otherwise we use excessive colors and
310 	 * slow the GUI down
311 	 */
312 	if ((pindex = brightonFindColor(palette, bwin->cmap_size,
313 		nr, ng, nb, bwin->quality)) >= 0)
314 	{
315 		palette[pindex].uses++;
316 		return(pindex);
317 	}
318 
319 	/*
320 	 * If we have no free colors, then palette[0] is the default
321 	 */
322 	if ((pindex = brightonFindFreeColor(palette, bwin->cmap_size)) < 0)
323 		return(0);
324 
325 	palette[pindex].red =  nr;
326 	palette[pindex].green = ng;
327 	palette[pindex].blue = nb;
328 	palette[pindex].uses++;
329 
330 	palette[pindex].flags &= ~BRIGHTON_INACTIVE_COLOR;
331 	palette[pindex].uses++;
332 
333 	/*
334 	 * Set up the cache.
335 	 */
336 	cacheInsertColor(nr, ng, nb, pindex);
337 
338 	return(pindex);
339 }
340 
341 static void
brightonAliasArea(brightonWindow * bwin,int x,int y,int width,int height)342 brightonAliasArea(brightonWindow *bwin, int x, int y, int width, int height)
343 {
344 	register int i, j, dy, aa = 1;
345 	register int *dest;
346 
347 	if (bwin->renderalias == NULL)
348 		bwin->renderalias
349 			= brightonCreateBitmap(bwin, bwin->width, bwin->height);
350 
351 	dest = bwin->renderalias->pixels;
352 
353 	aa = bwin->display->flags & BRIGHTON_ANTIALIAS_3? 1:2;
354 
355 	if (y == 0)
356 	{
357 		y += 1;
358 		height -= 1;
359 	}
360 	if (x == 0)
361 	{
362 		x += 1;
363 		width -= 1;
364 	}
365 
366 	for (j = y; j < (y + height); j++)
367 	{
368 		if (j >= (bwin->height - 1))
369 			break;
370 
371 		dy = j * bwin->width;
372 
373 		for (i = x; i < (x + width); i++)
374 		{
375 			if (i >= (bwin->width - 1))
376 				break;
377 
378 			dest[i + dy] = antialias(bwin, bwin->render, i, j, bwin->antialias);
379 		}
380 	}
381 }
382 
383 static int
makeMonoChrome(brightonWindow * bwin,int dest)384 makeMonoChrome(brightonWindow *bwin, int dest)
385 {
386 	register int r, g, b;
387 	register int pindex;
388 	register brightonPalette *palette = bwin->display->palette;
389 
390 	r = palette[dest].red;
391 	g = palette[dest].green;
392 	b = palette[dest].blue;
393 
394 	/*
395 	 * Greyscale tests.
396 	 *	1 is average,
397 	 *	2 is min
398 	 *	3 is max
399 	 */
400 	switch (bwin->grayscale) {
401 		case 1:
402 			r = (r + g + b) / 3;
403 			g = b = r;
404 			break;
405 		case 2:
406 			r = (r + g + b) / 6;
407 			g = b = r;
408 			break;
409 		case 3:
410 			r = (r + g + b) / 12;
411 			g = b = r;
412 			break;
413 		case 4:
414 		    if (r < g) {
415    				r = r < b? r:b;
416 			} else {
417 				r = g < b? g:b;
418 			}
419 			g = b = r;
420 			break;
421 		case 5:
422 		    if (r > g) {
423    				r = r > b? r:b;
424 			} else {
425 				r = g > b? g:b;
426 			}
427 			g = b = r;
428 			break;
429 	}
430 
431 	/*
432 	 * We want to be flexible on matches otherwise we use excessive colors and
433 	 * slow the GUI down
434 	 */
435 	if ((pindex = brightonFindColor(palette, bwin->cmap_size,
436 		r, g, b, bwin->quality - 2)) >= 0)
437 	{
438 		palette[pindex].uses++;
439 		return(pindex);
440 	}
441 
442 	/*
443 	 * If we have no free colors, then palette[0] is the default
444 	 */
445 	if ((pindex = brightonFindFreeColor(palette, bwin->cmap_size)) < 0)
446 		return(0);
447 
448 	palette[pindex].red =  r;
449 	palette[pindex].green = g;
450 	palette[pindex].blue = b;
451 	palette[pindex].uses++;
452 
453 	palette[pindex].flags &= ~BRIGHTON_INACTIVE_COLOR;
454 	palette[pindex].uses++;
455 
456 	cacheInsertColor(r, g, b, pindex);
457 
458 	return(pindex);
459 }
460 
461 static int
makeTransparent(brightonWindow * bwin,int dest,int tlayer,float opacity)462 makeTransparent(brightonWindow *bwin, int dest, int tlayer, float opacity)
463 {
464 	register int nr, ng, nb;
465 	register int pindex;
466 	register brightonPalette *palette = bwin->display->palette;
467 
468 	if (opacity >= 0.99)
469 		return(tlayer);
470 
471 	/*
472 	 * Take the color selections between the two values, the more opaque the
473 	 * greater the more of the selected value will be taken from the top patch
474 	 * layer.
475 	 */
476 	nr = (int) (
477 		(((float) (palette[dest].red)) * (1.0f - opacity))
478 		+ (((float) (palette[tlayer].red)) * opacity));
479 	ng = (int) (
480 		(((float) (palette[dest].green)) * (1.0f - opacity))
481 		+ (((float) (palette[tlayer].green)) * opacity));
482 	nb = (int) (
483 		(((float) (palette[dest].blue)) * (1.0f - opacity))
484 		+ (((float) (palette[tlayer].blue)) * opacity));
485 
486 	/*
487 	 * We want to be flexible on matches otherwise we use excessive colors and
488 	 * slow the GUI down
489 	 */
490 	if ((pindex = brightonFindColor(palette, bwin->cmap_size,
491 		nr, ng, nb, bwin->quality - 2)) >= 0)
492 	{
493 		palette[pindex].uses++;
494 		return(pindex);
495 	}
496 
497 	/*
498 	 * If we have no free colors, then palette[0] is the default
499 	 */
500 	if ((pindex = brightonFindFreeColor(palette, bwin->cmap_size)) < 0)
501 		return(0);
502 
503 	palette[pindex].red =  nr;
504 	palette[pindex].green = ng;
505 	palette[pindex].blue = nb;
506 	palette[pindex].uses++;
507 
508 	palette[pindex].flags &= ~BRIGHTON_INACTIVE_COLOR;
509 	palette[pindex].uses++;
510 
511 	cacheInsertColor(nr, ng, nb, pindex);
512 
513 	return(pindex);
514 }
515 
516 static int
makeMenuPixel(brightonWindow * bwin,int x,int y,int dy)517 makeMenuPixel(brightonWindow *bwin, int x, int y, int dy)
518 {
519 	int nr, ng, nb;
520 	int cpy = bwin->render->pixels[x + (y - 1) * bwin->width];
521 	int cny = bwin->render->pixels[x + (y + 1) * bwin->width];
522 	int cpre = bwin->render->pixels[dy - 1];
523 	int color = bwin->render->pixels[dy];
524 	int cnext = bwin->render->pixels[dy + 1];
525 	brightonPalette *palette = bwin->display->palette;
526 
527 	/*
528 	 * This takes a pixel and does the following options as a single call:
529 	 *
530 	 *	dest[i + dy] = antialias(bwin, bwin->render, i, j, 0.05);
531 	 *	dest[i + dy] = makeMonoChrome(bwin, dest[i + dy]);
532 	 *	dest[i + dy] = makeTransparent(bwin, dest[i + dy], menu[index],
533 	 *		bwin->opacity);
534 	 *
535 	 * These routines were called separately however that had two negative
536 	 * side	effects:
537 	 *
538 	 *	1. Creates excess colours as each routine will request new brighton
539 	 *		colours that may never actually be rendered but are cached.
540 	 *	2. Has the overhead of 3 subroutine calls per pixel.
541 	 *
542 	 * The code may need to be put into brightonMenu.c
543 	 */
544 	if ((x == 0) || (x >= bwin->width - 1)
545 		|| (y == 0) || (y == bwin->height - 1))
546 		return(0);
547 
548 	/*
549 	 * Antialias the color:
550 	 */
551 	nr = (int) (((float) palette[color].red) * 0.08
552 		+ ((float) (palette[cpy].red + palette[cny].red
553 		+ palette[cpre].red + palette[cnext].red)) * 0.23);
554 	ng = (int) (((float) palette[color].green) * 0.08
555 		+ ((float) (palette[cpy].green + palette[cny].green
556 		+ palette[cpre].green + palette[cnext].green)) * 0.23);
557 	nb = (int) (((float) palette[color].blue) * 0.08
558 		+ ((float) (palette[cpy].blue + palette[cny].blue
559 		+ palette[cpre].blue + palette[cnext].blue)) * 0.23);
560 
561 	/*
562 	 * Make monochrome based on selected algorithm, failing any match it will
563 	 * not be grayscaled:
564 	 */
565 	switch (bwin->grayscale) {
566 		case 1:
567 			nr = (nr + ng + nb) / 3;
568 			ng = nb = nr;
569 			break;
570 		case 2:
571 			nr = (nr + ng + nb) / 6;
572 			ng = nb = nr;
573 			break;
574 		case 3:
575 			nr = (nr + ng + nb) / 12;
576 			ng = nb = nr;
577 			break;
578 		case 4:
579 		    if (nr < ng)
580    				nr = nr < nb? nr:nb;
581 			else
582 				nr = ng < nb? ng:nb;
583 			ng = nb = nr;
584 			break;
585 		case 5:
586 		    if (nr > ng)
587    				nr = nr > nb? nr:nb;
588 			else
589 				nr = ng > nb? ng:nb;
590 			ng = nb = nr;
591 			break;
592 	}
593 
594 	/*
595 	 * Make it transparent to the menu layer
596 	 */
597 	nr = (int) (
598 		(((float) nr) * (1.0f - bwin->opacity))
599 		+ (((float) (palette[bwin->mlayer->pixels[dy]].red)) * bwin->opacity));
600 	ng = (int) (
601 		(((float) ng) * (1.0f - bwin->opacity))
602 		+ (((float) (palette[bwin->mlayer->pixels[dy]].green)) * bwin->opacity));
603 	nb = (int) (
604 		(((float) nb) * (1.0f - bwin->opacity))
605 		+ (((float) (palette[bwin->mlayer->pixels[dy]].blue)) * bwin->opacity));
606 
607 	/*
608 	 * We want to be flexible on matches otherwise we use excessive colors and
609 	 * slow the GUI down
610 	 */
611 	if ((color = brightonFindColor(palette, bwin->cmap_size,
612 		nr, ng, nb, bwin->quality - 2)) >= 0)
613 	{
614 		palette[color].uses++;
615 		return(color);
616 	}
617 
618 	/*
619 	 * If we have no free colors, then palette[0] is the default
620 	 */
621 	if ((color = brightonFindFreeColor(palette, bwin->cmap_size)) < 0)
622 		return(0);
623 
624 	palette[color].red =  nr;
625 	palette[color].green = ng;
626 	palette[color].blue = nb;
627 	palette[color].uses++;
628 
629 	palette[color].flags &= ~BRIGHTON_INACTIVE_COLOR;
630 	palette[color].uses++;
631 
632 	cacheInsertColor(nr, ng, nb, color);
633 
634 	return(color);
635 }
636 
637 /*
638  * This is the final render algorithm.
639  * It will take the window canvas, device layer and shadow layer at a given
640  * offset, put them all onto the rendering plane, and update our screen
641  * interface library.
642  */
643 
644 #ifdef STATS
645 int
statFunction(int op,char * operation)646 statFunction(int op, char *operation)
647 {
648 	if (op == 0) {
649 		gettimeofday(&tstart, 0);
650 	} else {
651 		time_t delta;
652 
653 		gettimeofday(&tend, 0);
654 		/*
655 		 * I hate this calculation.
656 		 *
657 		 * If seconds are the same then take the difference of the micros.
658 		 * If seconds are not the same then diff secs - 1 blah blah blah
659 		 */
660 		delta = (tend.tv_sec - tstart.tv_sec) * 1000000
661 			- tstart.tv_usec + tend.tv_usec;
662 
663 		printf("%16s: %7i us\n", operation, (int) delta);
664 	}
665 	return(0);
666 }
667 #endif
668 
669 static int lock = 0;
670 
671 int
brightonDoFinalRender(brightonWindow * bwin,register int x,register int y,register int width,register int height)672 brightonDoFinalRender(brightonWindow *bwin,
673 register int x, register int y, register int width, register int height)
674 {
675 	register int i, j, dy, pindex, aa;
676 	register int *src;
677 	register int *dest;
678 	register int *device;
679 	register int *shadow;
680 	register int *top;
681 	register int *menu;
682 	int count = 40;
683 
684 #ifdef STATS2
685 	statFunction(0, "Brighton");
686 #endif
687 
688 	while (lock)
689 	{
690 		usleep(25000);
691 		if (--count == 0)
692 			lock = 0;
693 	}
694 
695 	lock = 1;
696 
697 	if (bwin == NULL)
698 		return(lock = 0);
699 
700 	if (bwin->canvas)
701 		src = bwin->canvas->pixels;
702 	else
703 		return(lock = 0);
704 
705 	if (bwin->render)
706 		dest = bwin->render->pixels;
707 	else
708 		return(lock = 0);
709 
710 	device = bwin->dlayer->pixels;
711 	shadow = bwin->slayer->pixels;
712 	top = bwin->tlayer->pixels;
713 	menu = bwin->mlayer->pixels;
714 
715 	if ((width < 0) || (height < 0))
716 		return(lock = 0);
717 
718 	aa = bwin->display->flags & (BRIGHTON_ANTIALIAS_1 | BRIGHTON_ANTIALIAS_2);
719 
720 	for (j = y; j < (y + height); j++)
721 	{
722 		if (j >= bwin->height)
723 			break;
724 
725 		dy = j * bwin->width;
726 
727 		for (i = x; i < (x + width); i++)
728 		{
729 			if (i >= bwin->width)
730 				break;
731 
732 			/*pindex = i + j * bwin->width; */
733 			pindex = i + dy;
734 
735 			/*
736 			 * We have 3 layers, the topmost device layer, the middle shadow
737 			 * layer, and the lower canvas. The colors from each layer are
738 			 * moved into the render layer in order of priority. Where any
739 			 * layer has a negative brightonColor reference it is passed over
740 			 * to a lower plane. Other planes may be introduced at a later date
741 			 * as other features are incorporated.
742 			 *
743 			 * Adding another layer initially for patch cabling. We should
744 			 * consider adding the top layer last and allow it to act as a
745 			 * transparancy, but that is non trivial since we are not dealing
746 			 * with colors, but with pixel identifiers. FFS. Done.
747 			 *
748 			 * FS: We should paint in the pixel as if the transparency were
749 			 * not there, then, if we have a color in the transparency then we
750 			 * will paint it in with opacity.
751 			 *
752 			 * Going to try and add in some 'smoothing', or antialiasing of the
753 			 * rendering. Start with some trivial stuff - horizontal. Finally
754 			 * implemented a trivial LR/TB antialiasing. Will extend it to use
755 			 * a sandwiched bitmap since otherwise there are issues with how
756 			 * devices are rendered - they are not antialiased as they appear
757 			 * in a separate layer. The results are actualy quite nice, the
758 			 * textures and blueprints get smoothed and the devices stand out
759 			 * as more than real. Optional total smoothing is also possible.
760 			 */
761 			if (device[pindex] >= 0)
762 				dest[i + dy] = device[pindex];
763 			else if (shadow[pindex] >= 0)
764 				dest[i + dy] = shadow[pindex];
765 			else if (aa &&
766 					((i > 0) && (i < bwin->width - 1)) &&
767 					((j > 0) && (j < bwin->height - 1)))
768 				dest[i + dy] = antialias(bwin, bwin->canvas, i, j,
769 					bwin->antialias);
770 			else
771 				dest[i + dy] = src[pindex];
772 
773 			if (top[pindex] >= 0)
774 				dest[i + dy] =
775 					makeTransparent(bwin, dest[i + dy], top[pindex],
776 						bwin->opacity);
777 
778 			/*
779 			 * Now look for floating or other menus. These should generally be
780 			 * on top as not to be obscured by devices or patch cables.
781 			 */
782 			if (menu[pindex] >= 0) {
783 				/*
784 				 * So, we have to do something. I would initially suggest that
785 				 * the existing image be greyscaled, blurred, made transparent
786 				 * to the color in the menu layer.
787 				 *
788 				 * This should be put into a separate subroutine since calling
789 				 * each operation individually means our internal colormap gets
790 				 * filled with entries that are not used. This does not put any
791 				 * greater load on the windowing system but will increase our
792 				 * color cache lookup depth and hence lower lookup rate.
793 				dest[i + dy] = antialias(bwin, bwin->render, i, j, 0.05);
794 				dest[i + dy] = makeMonoChrome(bwin, dest[i + dy]);
795 				dest[i + dy] = makeTransparent(bwin, dest[i + dy], menu[pindex],
796 						bwin->opacity);
797 				 */
798 				dest[i + dy] = makeMenuPixel(bwin, i, j, i + dy);
799 			}
800 		}
801 	}
802 
803 #ifdef STATS2
804 	statFunction(1, "Brighton");
805 	statFunction(0, "Library");
806 #endif
807 
808 	/*
809 	 * The third levels of antialias is to re-alias the whole image rather
810 	 * than just the backgrounds. This only works if we have already been
811 	 * given the renderAlias image.
812 	 */
813 	if (bwin->display->flags & (BRIGHTON_ANTIALIAS_3|BRIGHTON_ANTIALIAS_4))
814 	{
815 		brightonAliasArea(bwin, x, y, width, height);
816 		BDrawArea(bwin->display, bwin->renderalias, x, y, width, height, x, y);
817 	} else
818 		/*
819 		 * Finally call the B library, of which currently only one version, the
820 		 * B11 interface to X11.
821 		 */
822 		BDrawArea(bwin->display, bwin->render, x, y, width, height, x, y);
823 
824 #ifdef STATS2
825 	statFunction(1, "Library");
826 #endif
827 	return(lock = 0);
828 }
829 
830 int
brightonFinalRender(brightonWindow * bwin,register int x,register int y,register int width,register int height)831 brightonFinalRender(brightonWindow *bwin,
832 register int x, register int y, register int width, register int height)
833 {
834 	/*
835 	 * Speed up on resizing - prevent excess redraws since we will have to
836 	 * scan the whole lot again anyway
837 	 */
838 	if (bwin->flags & BRIGHTON_NO_DRAW)
839 		return(0);
840 
841 /*	if (bwin->flags & BRIGHTON_BUSY) */
842 /*		return(0); */
843 
844 /*	bwin->flags |= BRIGHTON_BUSY; */
845 
846 	brightonDoFinalRender(bwin, x, y, width, height);
847 
848 /*	bwin->flags &= ~BRIGHTON_BUSY; */
849 
850 	return(0);
851 }
852 
853 /*
854  * A tesselation algorithm, takes a bitmap and tiles it onto the specified area.
855  */
856 int
brightonTesselate(register brightonWindow * bwin,register brightonBitmap * src,register brightonBitmap * dest,register int x,register int y,register int width,register int height,int direction)857 brightonTesselate(register brightonWindow *bwin, register brightonBitmap *src,
858 register brightonBitmap *dest, register int x, register int y,
859 register int width, register int height, int direction)
860 {
861 	register int i, j, dy, w, h;
862 	register int *pixels;
863 
864 	if ((src == 0) || (dest == 0))
865 		return(0);
866 
867 /*printf("brightonTesselate()\n"); */
868 
869 	pixels = src->pixels;
870 
871 	for (j = 0; j < height; j += src->height)
872 	{
873 		if (((j + y) >= dest->height) || (j >= height))
874 			break;
875 
876 		dy = (j + y) * dest->width;
877 
878 		/*
879 		 * Bounds check for reduction of last image to be rendered.
880 		 */
881 		if (j + src->height >= height)
882 			h = height - j;
883 		else
884 			h = src->height;
885 
886 		for (i = 0; i < width; i += src->width)
887 		{
888 			if (((i + x) >= dest->width) || (i >= width))
889 				break;
890 
891 			if (i + src->width >= width)
892 				w = width - i;
893 			else
894 				w = src->width;
895 
896 			brightonRender(bwin, src, dest, i + x, j + y, w, h, direction);
897 		}
898 	}
899 	return(0);
900 }
901 
902 /*
903  * This is a render algorithm. Takes a bitmap and copies it to the
904  * brightonBitmap area. We should do some bounds checking first?
905  */
906 int
brightonRender(register brightonWindow * bwin,register brightonBitmap * src,register brightonBitmap * dest,register int x,register int y,register int width,register int height,int direction)907 brightonRender(register brightonWindow *bwin, register brightonBitmap *src,
908 register brightonBitmap *dest, register int x, register int y,
909 register int width, register int height, int direction)
910 {
911 	register int i, j, dy;
912 	register int *pixels;
913 
914 	if ((src == 0) || (dest == 0) || (dest == src))
915 		return(0);
916 
917 /*printf("	render %i %i %i %i, %i %i, %i %i %x\n", x, y, width, height, */
918 /*src->width, src->height, dest->width, dest->height, src->pixels); */
919 /*printf("bitmap \"%s\" uses = %i\n", src->name, src->uses); */
920 
921 	pixels = src->pixels;
922 
923 	for (j = 0; j < height; j++)
924 	{
925 		if (((j + y) >= dest->height) || (j >= height))
926 			break;
927 
928 		dy = (j + y) * dest->width + x;
929 
930 		for (i = 0; i < width; i++)
931 		{
932 			if (((i + x) >= dest->width) || (i >= width))
933 				break;
934 
935 			if (isblue(i + j * src->width, bwin->display->palette, pixels))
936 				continue;
937 
938 			dest->pixels[i + dy] = src->pixels[i + j * src->width];
939 		}
940 	}
941 	return(0);
942 }
943 
944 #define round(x) x - ((float) ((int) x)) >= 0.5? x, x + 1;
945 
946 static int
brightonround(float x)947 brightonround(float x)
948 {
949 	int ix = x;
950 	float fx = ix;
951 
952 	if (x - fx >= 0.5)
953 		return(ix + 1);
954 
955 	return(ix);
956 }
957 
958 /*
959  * This is a scaling render algorithm. Takes a bitmap and speads it across
960  * the brightonWindow canvas area with interpolative antialiasing. It is only
961  * really intended for blueprints as they are the only ones that are not easily
962  * interpolated.
963  */
964 void
brightonStretchAlias(register brightonWindow * bwin,brightonBitmap * src,register brightonBitmap * dest,register int x,register int y,register int width,register int height,float primary)965 brightonStretchAlias(register brightonWindow *bwin, brightonBitmap *src,
966 register brightonBitmap *dest, register int x, register int y,
967 register int width, register int height, float primary)
968 {
969 	register float i, j, fx, fy, px, py;
970 	register int ix, iy, ng, nb, nr, pindex;
971 	register int c, n, s, e, w;
972 	register brightonPalette *palette = bwin->display->palette;
973 	register int *pixels;
974 	register int *scratch;
975 
976 	if ((src == 0) || (dest == 0) || (src == dest))
977 		return;
978 
979 /*
980 printf("	stretchAlias %i %i %i %i, %i %i: p %f\n", x, y, width, height,
981 src->width, src->height, primary);
982 */
983 
984 	pixels = src->pixels;
985 
986 	/*
987 	 * Do not support rendering outside of the panel area, excepting where we
988 	 * go over outer edges.
989 	 */
990 	if ((x < 0) || (x >= bwin->width) || (y < 0) || (y >= bwin->height))
991 		return;
992 
993 	/*
994 	 * Scratch should be allocated and only reallocated if it inceases in size
995 	 * which is a fairly easy enhancement.
996 	 */
997 	scratch = (int *) brightonmalloc(sizeof(int) * dest->width * dest->height);
998 	bcopy(dest->pixels, scratch, sizeof(int) * dest->width * dest->height);
999 
1000 	/*
1001 	 * We now have the test bitmap, and it should have generated a palette.
1002 	 * render the bits onto our background, and copy it over.
1003 	 */
1004 	for (j = y; j <= (y + height); j++)
1005 	{
1006 		fy = (j - y) * ((float) src->height) / ((float) height);
1007 		iy = fy;
1008 
1009 		if ((iy = fy) >= src->height)
1010 			break;
1011 
1012 		if ((fy -= iy) < 0.5)
1013 			py = fy;
1014 		else
1015 			py = 1.0 - fy;
1016 
1017 		for (i = x; i <= (x + width - 1); i++)
1018 		{
1019 			/*
1020 			 * Take the x relative index into the source bitmap. These are
1021 			 * relative since they are floating points that will eventually
1022 			 * specify the depth of antialiasing.
1023 			 *
1024 			 * We take a floating point index and an integer, one for the
1025 			 * bitmap index and the float for the eventual alias munging.
1026 			 */
1027 			fx = (i - x) * ((float) src->width) / ((float) width);
1028 			if ((ix = fx) >= src->width)
1029 				break;
1030 
1031 			/*
1032 			 * Set pixel. Since we are using brightonBitmaps we do not have to
1033 			 * go around using X library calls to set the pixel states.
1034 			 *
1035 			 * We may want to put in here isblue then destpixel;continue;
1036 			 */
1037 			if (isblue(ix + iy * src->width, palette, pixels))
1038 				c = scratch[(int) (i + j * dest->width)];
1039 			else
1040 				c = pixels[ix + iy * src->width];
1041 			if (c >= bwin->cmap_size) c = 1;
1042 
1043 			if (c < 0)
1044 				continue;
1045 
1046 			if (iy <= 0) {
1047 				n = c;
1048 			} else {
1049 				if (isblue(ix + (iy - 1) * src->width, palette, pixels))
1050 					n = scratch[(int) (i + (j - 1) * dest->width)];
1051 				else
1052 					n = pixels[ix + (iy - 1) * src->width];
1053 				if ((n < 0) || (n >= bwin->cmap_size)) continue;
1054 			}
1055 
1056 			if ((iy >= src->height - 1) || (j >= dest->height - 1))
1057 				s = c;
1058 			else {
1059 				if (isblue(ix + (iy + 1) * src->width, palette, pixels))
1060 					s = scratch[(int) (i + (j + 1) * dest->width)];
1061 				else
1062 					s = pixels[ix + (iy + 1) * src->width];
1063 				if ((s < 0) || (s >= bwin->cmap_size)) continue;
1064 			}
1065 
1066 			if (ix >= src->width - 1)
1067 				e = c;
1068 			else {
1069 				if (isblue(ix + 1 + iy * src->width, palette, pixels))
1070 					e = scratch[(int) (i + j * dest->width)];
1071 				else
1072 					e = pixels[ix + 1 + iy * src->width];
1073 				if ((e < 0) || (e >= bwin->cmap_size)) continue;
1074 			}
1075 
1076 			if (ix <= 0)
1077 				w = c;
1078 			else {
1079 				if (isblue(ix - 1 + iy * src->width, palette, pixels))
1080 					w = scratch[(int) (i - 1 + j * dest->width)];
1081 				else
1082 					w = pixels[ix - 1 + iy * src->width];
1083 				if ((w < 0) || (w >= bwin->cmap_size)) continue;
1084 			}
1085 
1086 			/*
1087 			 * We now have centre plus north/south/east/west. We could go for
1088 			 * more compasspoints but that will do for now.
1089 			 *
1090 			 * We want to give most weight to the real current pixel and the
1091 			 * remainder to the n/s/e/w components.
1092 			 *
1093 			 * Primary = 0.8
1094 			 * Secondary = (0.999 - 0.8) / 4;
1095 			 *
1096 			 * So, each secondary sums to 0.05 of itself but that is split
1097 			 * between dx and dy respectively.
1098 			 *
1099 			 * primary: 0.5 + (1.0 - (fx - ix))
1100 			 * secondary: (1.0 - primary) * 0.25;
1101 			 * c: primary * c;
1102 			 * n: (1.0 - (fy - iy)) * secondary * n
1103 			 * s: (fy - iy) * secondary * s
1104 			 * w: (1.0 - (fx - ix)) * secondary * w
1105 			 * e: (fx - ix) * secondary * e
1106 printf("(%f, %f) (%f, %f) (%i, %i): %i %i %i %i %i\n", i, j, fx, fy, ix, iy,
1107 c, n, s, e, w);
1108 printf("%f %i: %f\n", fy, iy, (fy - iy));
1109 printf("%f %f: %f %i, %f %i\n",  px, py, fx, ix, fy, iy);
1110 			 */
1111 			if ((fx -= ix) < 0.5)
1112 				px = fx;
1113 			else
1114 				px = 1.0 - fx;
1115 
1116 			nr = (int) (((float) palette[c].red) * (py + px)
1117 				+ ((float) palette[n].red) * (1.0 - fy) * (0.5 - py)
1118 				+ ((float) palette[s].red) * fy * (0.5 - py)
1119 				+ ((float) palette[w].red) * (1.0 - fx) * (0.5 - px)
1120 				+ ((float) palette[e].red) * fx * (0.5 - px));
1121 
1122 			ng = (int) (((float) palette[c].green) * (py + px)
1123 				+ ((float) palette[n].green) * (1.0 - fy) * (0.5 - py)
1124 				+ ((float) palette[s].green) * fy * (0.5 - py)
1125 				+ ((float) palette[w].green) * (1.0 - fx) * (0.5 - px)
1126 				+ ((float) palette[e].green) * fx * (0.5 - px));
1127 
1128 			nb = (int) (((float) palette[c].blue) * (py + px)
1129 				+ ((float) palette[n].blue) * (1.0 - fy) * (0.5 - py)
1130 				+ ((float) palette[s].blue) * fy * (0.5 - py)
1131 				+ ((float) palette[w].blue) * (1.0 - fx) * (0.5 - px)
1132 				+ ((float) palette[e].blue) * fx * (0.5 - px));
1133 
1134 			/*
1135 			 * We want to be flexible on matches otherwise we use excessive
1136 			 * colors and slow the GUI down
1137 			 */
1138 			if ((pindex = brightonFindColor(palette, bwin->cmap_size,
1139 				nr, ng, nb, bwin->quality)) >= 0)
1140 			{
1141 				palette[pindex].uses++;
1142 				dest->pixels[(int) (i + j * dest->width)] = pindex;
1143 				continue;
1144 			}
1145 
1146 			/*
1147 			 * If we have no free colors, then palette[0] is the default
1148 			 */
1149 			if ((pindex = brightonFindFreeColor(palette, bwin->cmap_size)) < 0)
1150 				continue;
1151 
1152 			palette[pindex].red =  nr;
1153 			palette[pindex].green = ng;
1154 			palette[pindex].blue = nb;
1155 			palette[pindex].uses++;
1156 
1157 			palette[pindex].flags &= ~BRIGHTON_INACTIVE_COLOR;
1158 			palette[pindex].uses++;
1159 
1160 			/*
1161 			 * Set up the cache.
1162 			 */
1163 			cacheInsertColor(nr, ng, nb, pindex);
1164 			dest->pixels[(int) (i + j * dest->width)] = pindex;
1165 		}
1166 	}
1167 
1168 	brightonfree(scratch);
1169 }
1170 
1171 /*
1172  * This is a scaling render algorithm. Takes a bitmap and speads it across
1173  * the brightonWindow canvas area. We should do some bounds checking first.
1174  */
1175 void
brightonStretch(register brightonWindow * bwin,brightonBitmap * src,register brightonBitmap * dest,register int x,register int y,register int width,register int height,int flags)1176 brightonStretch(register brightonWindow *bwin, brightonBitmap *src,
1177 register brightonBitmap *dest, register int x, register int y,
1178 register int width, register int height, int flags)
1179 {
1180 	register float i, j, x1 = 0;
1181 	register int y1 = 0, ix1;
1182 	register brightonPalette *palette = bwin->display->palette;
1183 	register int *pixels;
1184 
1185 	if ((src == 0) || (dest == 0) || (src == dest))
1186 		return;
1187 
1188 /*printf("	stretch %i %i %i %i, %i %i: flags %x\n", x, y, width, height, */
1189 /*src->width, src->height, flags); */
1190 
1191 	if ((pixels = src->pixels) == NULL)
1192 		return;
1193 
1194 	/*
1195 	 * Do not support rendering outside of the panel area, excepting where we
1196 	 * go over outer edges.
1197 	 */
1198 	if ((x < 0) || (x >= bwin->width) || (y < 0) || (y >= bwin->height))
1199 		return;
1200 
1201 	/*
1202 	 * We now have the test bitmap, and it should have generated a palette.
1203 	 * render the bits onto our background, and copy it over.
1204 	 */
1205 	for (i = y; i < (y + height); i++)
1206 	{
1207 		switch (flags & BRIGHTON_DIRECTION_MASK) {
1208 			default:
1209 			/* Default case and reverse take same values here */
1210 			case BRIGHTON_REVERSE:
1211 				y1 = (int) ((i - y) * src->height / height) * src->width;
1212 				break;
1213 			case BRIGHTON_VERTICAL:
1214 				y1 = (i - y) / height * src->width;
1215 				break;
1216 			case (BRIGHTON_VERTICAL|BRIGHTON_REVERSE):
1217 				if (flags & BRIGHTON_HALF_REVERSE)
1218 				{
1219 					y1 = (i - y) / height * src->width;
1220 					if (y1 < src->width / 2)
1221 						y1 += src->width / 2;
1222 					else
1223 						y1 -= src->width / 2;
1224 				} else {
1225 					y1 = src->width - (i - y) / height * src->width;
1226 				}
1227 				break;
1228 		}
1229 
1230 		for (j = x; j < (x + width); j++)
1231 		{
1232 			switch (flags & BRIGHTON_DIRECTION_MASK) {
1233 				default:
1234 				/* Default case and reverse take same values here */
1235 				case 0:
1236 					x1 = y1 + (j - x) * src->width / width;
1237 					break;
1238 				case BRIGHTON_REVERSE:
1239 					/*
1240 					 * This is for button operations, and is only "half"
1241 					 * reversed. We should make this a rendering option?
1242 					 */
1243 					if (flags & BRIGHTON_HALF_REVERSE)
1244 					{
1245 						x1 = (j - x) / width * src->width;
1246 						if (x1 < src->width / 2)
1247 							x1 += y1 + src->width / 2;
1248 						else
1249 							x1 += y1 - src->width / 2;
1250 
1251 						if (x1 >= src->width * src->height)
1252 							x1 = src->width * src->height - 1;
1253 					} else {
1254 						x1 = y1 + src->width - (j - x) * src->width / width;
1255 					}
1256 					break;
1257 				case BRIGHTON_VERTICAL:
1258 				case (BRIGHTON_VERTICAL|BRIGHTON_REVERSE):
1259 					x1 = y1
1260 						+ (int) ((j - x) * src->height / width) * src->width;
1261 					break;
1262 			}
1263 
1264 			ix1 = x1;
1265 
1266 			/*
1267 			 * Set pixel. Since we are using brightonBitmaps we do not have to
1268 			 * go around using X library calls to set the pixel states.
1269 			 */
1270 			if (!isblue(ix1, palette, pixels))
1271 				dest->pixels[(int) (i * dest->width + j)] = src->pixels[ix1];
1272 				/*
1273 				dest->pixels[(int) (i * dest->width + j)] = src->pixels[ix1];
1274 				 * What I want to do here is take my source pixel and give it
1275 				 * some antialias. This should only be done if neighbouring
1276 				 * pixels are blue - primarily device edges and blueprints.
1277 				 *
1278 				 * The cheapest way to do this is just paint my pixel, then
1279 				 * temper it from 4 neighbors.
1280 
1281 				if (i <= 0)
1282 					n = src->pixels[ix1];
1283 				else
1284 					n = dest->pixels[(int) ((i - 1) * dest->width + j)];
1285 
1286 				if (i >= dest->height - 1)
1287 					s = src->pixels[ix1];
1288 				else
1289 					s = dest->pixels[(int) ((i + 1) * dest->width + j)];
1290 
1291 				if (j <= 0)
1292 					w = src->pixels[ix1];
1293 				else
1294 					w = dest->pixels[(int) (i * dest->width + j - 1)];
1295 
1296 				if (j >= dest->width - 1)
1297 					e = src->pixels[ix1];
1298 				else
1299 					e = dest->pixels[(int) (i * dest->width + j + 1)];
1300 				 */
1301 		}
1302 	}
1303 }
1304 
1305 /*
1306  * This is not a true alpha layer in a bitmap. The function is similar, it
1307  * allows for fading bitmaps in and out.
1308  */
1309 void
brightonAlphaLayer(register brightonWindow * bwin,register brightonBitmap * src,register brightonBitmap * dest,register int dx,register int dy,register int width,register int height,register double rotation)1310 brightonAlphaLayer(register brightonWindow *bwin, register brightonBitmap *src,
1311 register brightonBitmap *dest, register int dx, register int dy,
1312 register int width, register int height, register double rotation)
1313 {
1314 	register int py, px, dp, sp, red, green, blue;
1315 	register int i, j, ty, pindex;
1316 	register brightonPalette *palette = bwin->display->palette;
1317 	register float factor;
1318 
1319 /*printf("brightonAlphaLayer()\n"); */
1320 
1321 	for (py = 0; py < height; py+=1)
1322 	{
1323 		j = py * src->height / height;
1324 
1325 		if (py >= dest->height)
1326 			break;
1327 
1328 		ty = (dy + py) * dest->width + dx;
1329 
1330 		for (px = 0; px < width; px++)
1331 		{
1332 			i = px * src->width / width;
1333 
1334 			if ((dp = dest->pixels[ty + px]) < 0)
1335 				continue;
1336 
1337 			sp = src->pixels[i + j * src->width];
1338 
1339 /*			if ((palette[sp].red == 0) */
1340 /*				&& (palette[sp].green == 0) */
1341 /*				&& (palette[sp].blue == 0xff)) */
1342 			if (isblue(i + j * src->width, palette, src->pixels))
1343 				continue;
1344 
1345 			/*
1346 			 * The coloring wants to be white, but as the alpha layer gets
1347 			 * dimmer, the value tends back to the original:
1348 			 *
1349 			 * factor = (255 - palette[sp].red) / 255;
1350 			 * red = 255 * factor + palette[dp].red * (1.0 - factor);
1351 			 *
1352 			red = 255 - ((255 - palette[sp].red) * palette[dp].red / 255);
1353 			green = 255 - ((255 - palette[sp].green) * palette[dp].green / 255);
1354 			blue = 255 - ((255 - palette[sp].blue) * palette[dp].blue / 255);
1355 			red = (palette[dp].red + palette[sp].red) / 2;
1356 			green = (palette[dp].green + palette[sp].green) / 2;
1357 			blue = (palette[dp].blue + palette[sp].blue) / 2;
1358 			red = 65535 * factor + palette[dp].red * (1.0 - factor);
1359 			green = 65535 * factor + palette[dp].green * (1.0 - factor);
1360 			blue = 65535 * factor + palette[dp].blue * (1.0 - factor);
1361 			 *
1362 			 * This works as a pure alpha layer scaling to white, I would
1363 			 * prefer the ability to add shadow.
1364 			 */
1365 			if ((factor = ((float) palette[sp].red) / 65535.0) > 0.5)
1366 			{
1367 				red = palette[dp].red
1368 					+ (65535 - palette[dp].red) * (factor - 0.5) * 2;
1369 				green = palette[dp].green
1370 					+ (65535 - palette[dp].green) * (factor - 0.5) * 2;
1371 				blue = palette[dp].blue
1372 					+ (65535 - palette[dp].blue) * (factor - 0.5) * 2;
1373 			} else {
1374 				red = palette[dp].red * factor * 2;
1375 				green = palette[dp].green * factor * 2;
1376 				blue = palette[dp].blue * factor * 2;
1377 			}
1378 
1379 			if ((pindex = brightonFindColor(palette, bwin->cmap_size,
1380 				red, green, blue, bwin->quality))
1381 				>= 0)
1382 			{
1383 				palette[pindex].uses++;
1384 				dest->pixels[ty + px] = pindex;
1385 				continue;
1386 			}
1387 
1388 			/*
1389 			 * If we have no free colors, then palette[0] is the default
1390 			 */
1391 			if ((pindex = brightonFindFreeColor(palette, bwin->cmap_size)) < 0)
1392 			{
1393 				pindex = 0;
1394 				dest->pixels[ty + px] = pindex;
1395 				continue;
1396 			}
1397 
1398 			palette[pindex].red = red;
1399 			palette[pindex].green = green;
1400 			palette[pindex].blue = blue;
1401 			palette[pindex].uses++;
1402 
1403 			palette[pindex].flags &= ~BRIGHTON_INACTIVE_COLOR;
1404 			palette[pindex].uses++;
1405 
1406 			cacheInsertColor(red, green, blue, pindex);
1407 
1408 			dest->pixels[ty + px] = pindex;
1409 		}
1410 	}
1411 }
1412 
1413 double roll = 0;
1414 double rinc = 0.04;
1415 
1416 /*
1417  * This could do with some XDrawPoints() optimisation as well.
1418  */
1419 int
brightonRotate(register brightonWindow * bwin,register brightonBitmap * src,register brightonBitmap * dest,register int dx,register int dy,register int width,register int height,register double rotation)1420 brightonRotate(register brightonWindow *bwin, register brightonBitmap *src,
1421 register brightonBitmap *dest, register int dx, register int dy,
1422 register int width, register int height, register double rotation)
1423 {
1424 	register int py, px;
1425 	register double i, j;
1426 	register int adjx, adjy, natx, naty;
1427 	register double r, ho2, angle;
1428 	register int x, y;
1429 	register brightonPalette *palette = bwin->display->palette;
1430 	register int *pixels;
1431 
1432 /*printf("brightonRotate(%i, %i, %i, %i)\n", */
1433 /*dx, dy, src->width, src->height); */
1434 
1435 	if ((src == 0) || (dest == 0))
1436 		return(0);
1437 
1438 	pixels = src->pixels;
1439 	ho2 = src->height / 2;
1440 	/*
1441 	 * Do not support rendering outside of the panel area, excepting where we
1442 	 * go over outer edges.
1443 	 */
1444 	if ((dx < 0) || (dx >= bwin->width) || (dy < 0) || (dy >= bwin->height))
1445 	{
1446 		printf("bounds fail\n");
1447 		return(0);
1448 	}
1449 
1450 	if (width & 0x01)
1451 		width--;
1452 	if (height & 0x01)
1453 		height--;
1454 
1455 	/*
1456 	 * This is for 'wobble' on the pot cap as it rotates.
1457 	 */
1458 	if ((roll += rinc) > 0.3)
1459 		rinc = -rinc;
1460 	else if (roll < 0)
1461 	{
1462 		rinc = -rinc;
1463 		roll = 0;
1464 	}
1465 
1466 	/*
1467 	 * We now have the test bitmap, and it should have generated a palette.
1468 	 * render the bits onto our background, and copy it over.
1469 	 */
1470 	for (py = 0; py < height; py+=1)
1471 	{
1472 		j = py * src->height / height;
1473 		naty = j - ho2;
1474 
1475 		if (py >= dest->height)
1476 			break;
1477 
1478 		for (px = 0; px < width; px++)
1479 		{
1480 			i = px * src->width / width;
1481 			natx = i - ho2;
1482 
1483 			if ((r = sqrttab[natx < 0?-natx:natx][naty < 0?-naty: naty]) > ho2)
1484 				continue;
1485 
1486 			/*
1487 			 * Rotate this point, and then put them back into native coords.
1488 			 * We need our own rounding algorithm - otherwise we get truncation.
1489 			 */
1490 			if (r < src->istatic) {
1491 				/*
1492 				 * Want to do something here to make the centre 'wobble'
1493 				x = brightonround(natx + ho2);
1494 				y = brightonround(naty + ho2);
1495 				 */
1496 				/*
1497 				 * Take the angle of this point to the origin.
1498 				 */
1499 				if (naty < 0.0) {
1500 					/*angle = asin(natx / r) + rotation; */
1501 					angle = asin(natx / r) + 2*M_PI - roll;
1502 					adjx = r * sin(angle);
1503 					adjy = -r * cos(angle);
1504 				} else {
1505 					/*angle = -asin(natx / r) + M_PI; */
1506 					angle = -asin(natx / r) + 2*M_PI - roll;
1507 					adjx = -r * sin(angle);
1508 					adjy = r * cos(angle);
1509 				}
1510 				x = brightonround(adjx + ho2);
1511 				y = brightonround(adjy + ho2);
1512 
1513 				/*x = brightonround(natx + ho2); */
1514 				/*y = brightonround(naty + ho2); */
1515 			} else if (r < src->ostatic) {
1516 				/*
1517 				 * Take the angle of this point to the origin.
1518 				 */
1519 				if (naty < 0.0) {
1520 					angle = asin(natx / r) + rotation;
1521 					adjx = r * sin(angle);
1522 					adjy = -r * cos(angle);
1523 				} else {
1524 					angle = -asin(natx / r) + rotation;
1525 					adjx = -r * sin(angle);
1526 					adjy = r * cos(angle);
1527 				}
1528 				x = brightonround(adjx + ho2);
1529 				y = brightonround(adjy + ho2);
1530 			} else {
1531 				x = brightonround(natx + ho2);
1532 				y = brightonround(naty + ho2);
1533 			}
1534 
1535 			if ((x < 0) || (x >= src->height) || (y < 0) || (y >= src->height))
1536 				continue;
1537 
1538 			if (!isblue(x + y * src->width, palette, src->pixels))
1539 				dest->pixels[(int) (((dy + py) * dest->width) + dx + px)]
1540 					= src->pixels[(int) (y * src->width + x)];
1541 		}
1542 	}
1543 	return(0);
1544 }
1545 
1546