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