vdr 2.6.4
osd.c
Go to the documentation of this file.
1/*
2 * osd.c: Abstract On Screen Display layer
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * $Id: osd.c 4.11 2020/12/18 23:02:47 kls Exp $
8 */
9
10#include "osd.h"
11#include <math.h>
12#include <stdlib.h>
13#include <sys/ioctl.h>
14#include <sys/stat.h>
15#include <sys/unistd.h>
16#include "device.h"
17#include "tools.h"
18
19tColor HsvToColor(double H, double S, double V)
20{
21 if (S > 0) {
22 H /= 60;
23 int i = floor(H);
24 double f = H - i;
25 double p = V * (1 - S);
26 double q = V * (1 - S * f);
27 double t = V * (1 - S * (1 - f));
28 switch (i) {
29 case 0: return RgbToColor(V, t, p);
30 case 1: return RgbToColor(q, V, p);
31 case 2: return RgbToColor(p, V, t);
32 case 3: return RgbToColor(p, q, V);
33 case 4: return RgbToColor(t, p, V);
34 default: return RgbToColor(V, p, q);
35 }
36 }
37 else { // greyscale
38 uint8_t n = V * 0xFF;
39 return RgbToColor(n, n, n);
40 }
41}
42
43tColor RgbShade(tColor Color, double Factor)
44{
45 double f = fabs(constrain(Factor, -1.0, 1.0));
46 double w = Factor > 0 ? f * 0xFF : 0;
47 return (Color & 0xFF000000) |
48 (min(0xFF, int((1 - f) * ((Color >> 16) & 0xFF) + w + 0.5)) << 16) |
49 (min(0xFF, int((1 - f) * ((Color >> 8) & 0xFF) + w + 0.5)) << 8) |
50 (min(0xFF, int((1 - f) * ( Color & 0xFF) + w + 0.5)) );
51}
52
53#define USE_ALPHA_LUT
54#ifdef USE_ALPHA_LUT
55// Alpha blending with lookup table (by Reinhard Nissl <rnissl@gmx.de>)
56// A little slower (138 %) on fast machines than the implementation below and faster
57// on slow machines (79 %), but requires some 318KB of RAM for the lookup table.
58static uint16_t AlphaLutFactors[255][256][2];
59static uint8_t AlphaLutAlpha[255][256];
60
62public:
64 {
65 for (int alphaA = 0; alphaA < 255; alphaA++) {
66 int range = (alphaA == 255 ? 255 : 254);
67 for (int alphaB = 0; alphaB < 256; alphaB++) {
68 int alphaO_x_range = 255 * alphaA + alphaB * (range - alphaA);
69 if (!alphaO_x_range)
70 alphaO_x_range++;
71 int factorA = (256 * 255 * alphaA + alphaO_x_range / 2) / alphaO_x_range;
72 int factorB = (256 * alphaB * (range - alphaA) + alphaO_x_range / 2) / alphaO_x_range;
73 AlphaLutFactors[alphaA][alphaB][0] = factorA;
74 AlphaLutFactors[alphaA][alphaB][1] = factorB;
75 AlphaLutAlpha[alphaA][alphaB] = alphaO_x_range / range;
76 }
77 }
78 }
80
81tColor AlphaBlend(tColor ColorFg, tColor ColorBg, uint8_t AlphaLayer)
82{
83 tColor Alpha = (ColorFg & 0xFF000000) >> 24;
84 Alpha *= AlphaLayer;
85 Alpha >>= 8;
86 uint16_t *lut = &AlphaLutFactors[Alpha][(ColorBg & 0xFF000000) >> 24][0];
87 return (tColor)((AlphaLutAlpha[Alpha][(ColorBg & 0xFF000000) >> 24] << 24)
88 | (((((ColorFg & 0x00FF00FF) * lut[0] + (ColorBg & 0x00FF00FF) * lut[1])) & 0xFF00FF00)
89 | ((((ColorFg & 0x0000FF00) * lut[0] + (ColorBg & 0x0000FF00) * lut[1])) & 0x00FF0000)) >> 8);
90}
91#else
92// Alpha blending without lookup table.
93// Also works fast, but doesn't return the theoretically correct result.
94// It's "good enough", though.
95static tColor Multiply(tColor Color, uint8_t Alpha)
96{
97 tColor RB = (Color & 0x00FF00FF) * Alpha;
98 RB = ((RB + ((RB >> 8) & 0x00FF00FF) + 0x00800080) >> 8) & 0x00FF00FF;
99 tColor AG = ((Color >> 8) & 0x00FF00FF) * Alpha;
100 AG = ((AG + ((AG >> 8) & 0x00FF00FF) + 0x00800080)) & 0xFF00FF00;
101 return AG | RB;
102}
103
104tColor AlphaBlend(tColor ColorFg, tColor ColorBg, uint8_t AlphaLayer)
105{
106 tColor Alpha = (ColorFg & 0xFF000000) >> 24;
107 if (AlphaLayer < ALPHA_OPAQUE) {
108 Alpha *= AlphaLayer;
109 Alpha = ((Alpha + ((Alpha >> 8) & 0x000000FF) + 0x00000080) >> 8) & 0x000000FF;
110 }
111 return Multiply(ColorFg, Alpha) + Multiply(ColorBg, 255 - Alpha);
112}
113#endif
114
115// --- cPalette --------------------------------------------------------------
116
118{
119 SetBpp(Bpp);
121}
122
124{
125}
126
127void cPalette::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
128{
129 if (FixedColors >= MAXNUMCOLORS || BlendColors == 0)
131 else {
132 int ColorsForBlending = MAXNUMCOLORS - FixedColors;
133 int ColorsPerBlend = ColorsForBlending / BlendColors + 2; // +2 = the full foreground and background colors, which are among the fixed colors
134 antiAliasGranularity = double(MAXNUMCOLORS - 1) / (ColorsPerBlend - 1);
135 }
136}
137
139{
140 numColors = 0;
141 modified = false;
142}
143
145{
146 // Check if color is already defined:
147 for (int i = 0; i < numColors; i++) {
148 if (color[i] == Color)
149 return i;
150 }
151 // No exact color, try a close one:
152 int i = ClosestColor(Color, 4);
153 if (i >= 0)
154 return i;
155 // No close one, try to define a new one:
156 if (numColors < maxColors) {
157 color[numColors++] = Color;
158 modified = true;
159 return numColors - 1;
160 }
161 // Out of colors, so any close color must do:
162 return ClosestColor(Color);
163}
164
165void cPalette::SetBpp(int Bpp)
166{
167 bpp = Bpp;
168 maxColors = 1 << bpp;
169 Reset();
170}
171
172void cPalette::SetColor(int Index, tColor Color)
173{
174 if (Index < maxColors) {
175 if (numColors <= Index) {
176 numColors = Index + 1;
177 modified = true;
178 }
179 else
180 modified |= color[Index] != Color;
181 color[Index] = Color;
182 }
183}
184
185const tColor *cPalette::Colors(int &NumColors) const
186{
187 NumColors = numColors;
188 return numColors ? color : NULL;
189}
190
191void cPalette::Take(const cPalette &Palette, tIndexes *Indexes, tColor ColorFg, tColor ColorBg)
192{
193 for (int i = 0; i < Palette.numColors; i++) {
194 tColor Color = Palette.color[i];
195 if (ColorFg || ColorBg) {
196 switch (i) {
197 case 0: Color = ColorBg; break;
198 case 1: Color = ColorFg; break;
199 default: ;
200 }
201 }
202 int n = Index(Color);
203 if (Indexes)
204 (*Indexes)[i] = n;
205 }
206}
207
208void cPalette::Replace(const cPalette &Palette)
209{
210 for (int i = 0; i < Palette.numColors; i++)
211 SetColor(i, Palette.color[i]);
212 numColors = Palette.numColors;
214}
215
216tColor cPalette::Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) const
217{
218 if (antiAliasGranularity > 0)
219 Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity);
220 int Af = (ColorFg & 0xFF000000) >> 24;
221 int Rf = (ColorFg & 0x00FF0000) >> 16;
222 int Gf = (ColorFg & 0x0000FF00) >> 8;
223 int Bf = (ColorFg & 0x000000FF);
224 int Ab = (ColorBg & 0xFF000000) >> 24;
225 int Rb = (ColorBg & 0x00FF0000) >> 16;
226 int Gb = (ColorBg & 0x0000FF00) >> 8;
227 int Bb = (ColorBg & 0x000000FF);
228 int A = (Ab + (Af - Ab) * Level / 0xFF) & 0xFF;
229 int R = (Rb + (Rf - Rb) * Level / 0xFF) & 0xFF;
230 int G = (Gb + (Gf - Gb) * Level / 0xFF) & 0xFF;
231 int B = (Bb + (Bf - Bb) * Level / 0xFF) & 0xFF;
232 return (A << 24) | (R << 16) | (G << 8) | B;
233}
234
235int cPalette::ClosestColor(tColor Color, int MaxDiff) const
236{
237 int n = 0;
238 int d = INT_MAX;
239 int A1 = (Color & 0xFF000000) >> 24;
240 int R1 = (Color & 0x00FF0000) >> 16;
241 int G1 = (Color & 0x0000FF00) >> 8;
242 int B1 = (Color & 0x000000FF);
243 for (int i = 0; i < numColors && d > 0; i++) {
244 int A2 = (color[i] & 0xFF000000) >> 24;
245 int R2 = (color[i] & 0x00FF0000) >> 16;
246 int G2 = (color[i] & 0x0000FF00) >> 8;
247 int B2 = (color[i] & 0x000000FF);
248 int diff = 0;
249 if (A1 || A2) // fully transparent colors are considered equal
250 diff = (abs(A1 - A2) << 1) + (abs(R1 - R2) << 1) + (abs(G1 - G2) << 1) + (abs(B1 - B2) << 1);
251 if (diff < d) {
252 d = diff;
253 n = i;
254 }
255 }
256 return d <= MaxDiff ? n : -1;
257}
258
259// --- cBitmap ---------------------------------------------------------------
260
261cBitmap::cBitmap(int Width, int Height, int Bpp, int X0, int Y0)
262:cPalette(Bpp)
263{
264 bitmap = NULL;
265 x0 = X0;
266 y0 = Y0;
267 width = height = 0;
269}
270
271cBitmap::cBitmap(const char *FileName)
272{
273 bitmap = NULL;
274 x0 = 0;
275 y0 = 0;
276 width = height = 0;
277 LoadXpm(FileName);
278}
279
280cBitmap::cBitmap(const char *const Xpm[])
281{
282 bitmap = NULL;
283 x0 = 0;
284 y0 = 0;
285 width = height = 0;
286 SetXpm(Xpm);
287}
288
290{
291 free(bitmap);
292}
293
294void cBitmap::SetSize(int Width, int Height)
295{
296 if (bitmap && Width == width && Height == height)
297 return;
298 width = Width;
299 height = Height;
300 free(bitmap);
301 bitmap = NULL;
302 dirtyX1 = 0;
303 dirtyY1 = 0;
304 dirtyX2 = width - 1;
305 dirtyY2 = height - 1;
306 if (width > 0 && height > 0) {
308 if (bitmap)
309 memset(bitmap, 0x00, width * height);
310 else
311 esyslog("ERROR: can't allocate bitmap!");
312 }
313 else
314 esyslog("ERROR: invalid bitmap parameters (%d, %d)!", width, height);
315}
316
317bool cBitmap::Contains(int x, int y) const
318{
319 x -= x0;
320 y -= y0;
321 return 0 <= x && x < width && 0 <= y && y < height;
322}
323
324bool cBitmap::Covers(int x1, int y1, int x2, int y2) const
325{
326 x1 -= x0;
327 y1 -= y0;
328 x2 -= x0;
329 y2 -= y0;
330 return x1 <= 0 && y1 <= 0 && x2 >= width - 1 && y2 >= height - 1;
331}
332
333bool cBitmap::Intersects(int x1, int y1, int x2, int y2) const
334{
335 x1 -= x0;
336 y1 -= y0;
337 x2 -= x0;
338 y2 -= y0;
339 return !(x2 < 0 || x1 >= width || y2 < 0 || y1 >= height);
340}
341
342bool cBitmap::Dirty(int &x1, int &y1, int &x2, int &y2)
343{
344 if (dirtyX2 >= 0) {
345 x1 = dirtyX1;
346 y1 = dirtyY1;
347 x2 = dirtyX2;
348 y2 = dirtyY2;
349 return true;
350 }
351 return false;
352}
353
355{
356 dirtyX1 = width;
357 dirtyY1 = height;
358 dirtyX2 = -1;
359 dirtyY2 = -1;
360}
361
362bool cBitmap::LoadXpm(const char *FileName)
363{
364 bool Result = false;
365 FILE *f = fopen(FileName, "r");
366 if (f) {
367 char **Xpm = NULL;
368 bool isXpm = false;
369 int lines = 0;
370 int index = 0;
371 char *s;
372 cReadLine ReadLine;
373 while ((s = ReadLine.Read(f)) != NULL) {
374 s = skipspace(s);
375 if (!isXpm) {
376 if (strcmp(s, "/* XPM */") != 0) {
377 esyslog("ERROR: invalid header in XPM file '%s'", FileName);
378 break;
379 }
380 isXpm = true;
381 }
382 else if (*s++ == '"') {
383 if (!lines) {
384 int w, h, n, c;
385 if (4 != sscanf(s, "%d %d %d %d", &w, &h, &n, &c)) {
386 esyslog("ERROR: faulty 'values' line in XPM file '%s'", FileName);
387 isXpm = false;
388 break;
389 }
390 lines = h + n + 1;
391 Xpm = MALLOC(char *, lines);
392 memset(Xpm, 0, lines * sizeof(char*));
393 }
394 char *q = strchr(s, '"');
395 if (!q) {
396 esyslog("ERROR: missing quotes in XPM file '%s'", FileName);
397 isXpm = false;
398 break;
399 }
400 *q = 0;
401 if (index < lines)
402 Xpm[index++] = strdup(s);
403 else {
404 esyslog("ERROR: too many lines in XPM file '%s'", FileName);
405 isXpm = false;
406 break;
407 }
408 }
409 }
410 if (isXpm) {
411 if (index == lines)
412 Result = SetXpm(Xpm);
413 else
414 esyslog("ERROR: too few lines in XPM file '%s'", FileName);
415 }
416 if (Xpm) {
417 for (int i = 0; i < index; i++)
418 free(Xpm[i]);
419 }
420 free(Xpm);
421 fclose(f);
422 }
423 else
424 esyslog("ERROR: can't open XPM file '%s'", FileName);
425 return Result;
426}
427
428bool cBitmap::SetXpm(const char *const Xpm[], bool IgnoreNone)
429{
430 if (!Xpm)
431 return false;
432 const char *const *p = Xpm;
433 int w, h, n, c;
434 if (4 != sscanf(*p, "%d %d %d %d", &w, &h, &n, &c)) {
435 esyslog("ERROR: faulty 'values' line in XPM: '%s'", *p);
436 return false;
437 }
438 if (n > MAXNUMCOLORS) {
439 esyslog("ERROR: too many colors in XPM: %d", n);
440 return false;
441 }
442 int b = 0;
443 while (1 << (1 << b) < (IgnoreNone ? n - 1 : n))
444 b++;
445 SetBpp(1 << b);
446 SetSize(w, h);
447 int NoneColorIndex = MAXNUMCOLORS;
448 for (int i = 0; i < n; i++) {
449 const char *s = *++p;
450 if (int(strlen(s)) < c) {
451 esyslog("ERROR: faulty 'colors' line in XPM: '%s'", s);
452 return false;
453 }
454 s = skipspace(s + c);
455 if (*s != 'c') {
456 esyslog("ERROR: unknown color key in XPM: '%c'", *s);
457 return false;
458 }
459 s = skipspace(s + 1);
460 if (strcasecmp(s, "none") == 0) {
461 NoneColorIndex = i;
462 if (!IgnoreNone)
464 continue;
465 }
466 if (*s != '#') {
467 esyslog("ERROR: unknown color code in XPM: '%c'", *s);
468 return false;
469 }
470 tColor color = strtoul(++s, NULL, 16) | 0xFF000000;
471 SetColor((IgnoreNone && i > NoneColorIndex) ? i - 1 : i, color);
472 }
473 for (int y = 0; y < h; y++) {
474 const char *s = *++p;
475 if (int(strlen(s)) != w * c) {
476 esyslog("ERROR: faulty pixel line in XPM: %d '%s'", y, s);
477 return false;
478 }
479 for (int x = 0; x < w; x++) {
480 for (int i = 0; i <= n; i++) {
481 if (i == n) {
482 esyslog("ERROR: undefined pixel color in XPM: %d %d '%s'", x, y, s);
483 return false;
484 }
485 if (strncmp(Xpm[i + 1], s, c) == 0) {
486 if (i == NoneColorIndex)
487 NoneColorIndex = MAXNUMCOLORS;
488 SetIndex(x, y, (IgnoreNone && i > NoneColorIndex) ? i - 1 : i);
489 break;
490 }
491 }
492 s += c;
493 }
494 }
495 if (NoneColorIndex < MAXNUMCOLORS && !IgnoreNone)
496 return SetXpm(Xpm, true);
497 return true;
498}
499
500void cBitmap::SetIndex(int x, int y, tIndex Index)
501{
502 if (bitmap) {
503 if (0 <= x && x < width && 0 <= y && y < height) {
504 if (bitmap[width * y + x] != Index) {
505 bitmap[width * y + x] = Index;
506 if (dirtyX1 > x) dirtyX1 = x;
507 if (dirtyY1 > y) dirtyY1 = y;
508 if (dirtyX2 < x) dirtyX2 = x;
509 if (dirtyY2 < y) dirtyY2 = y;
510 }
511 }
512 }
513}
514
516{
517 if (bitmap) {
518 memset(bitmap, Index, width * height);
519 dirtyX1 = 0;
520 dirtyY1 = 0;
521 dirtyX2 = width - 1;
522 dirtyY2 = height - 1;
523 }
524}
525
526void cBitmap::DrawPixel(int x, int y, tColor Color)
527{
528 x -= x0;
529 y -= y0;
530 SetIndex(x, y, Index(Color));
531}
532
533void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
534{
535 if (bitmap && Bitmap.bitmap && Intersects(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) {
536 if (Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1))
537 Reset();
538 x -= x0;
539 y -= y0;
540 if (ReplacePalette && Covers(x + x0, y + y0, x + x0 + Bitmap.Width() - 1, y + y0 + Bitmap.Height() - 1)) {
541 Replace(Bitmap);
542 for (int ix = 0; ix < Bitmap.width; ix++) {
543 for (int iy = 0; iy < Bitmap.height; iy++) {
544 if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0)
545 SetIndex(x + ix, y + iy, Bitmap.bitmap[Bitmap.width * iy + ix]);
546 }
547 }
548 }
549 else {
550 tIndexes Indexes;
551 Take(Bitmap, &Indexes, ColorFg, ColorBg);
552 for (int ix = 0; ix < Bitmap.width; ix++) {
553 for (int iy = 0; iy < Bitmap.height; iy++) {
554 if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0)
555 SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]);
556 }
557 }
558 }
559 }
560}
561
562void cBitmap::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
563{
564 if (bitmap) {
565 int w = Font->Width(s);
566 int h = Font->Height();
567 int limit = 0;
568 int cw = Width ? Width : w;
569 int ch = Height ? Height : h;
570 if (!Intersects(x, y, x + cw - 1, y + ch - 1))
571 return;
572 if (ColorBg != clrTransparent)
573 DrawRectangle(x, y, x + cw - 1, y + ch - 1, ColorBg);
574 if (Width || Height) {
575 limit = x + cw - x0;
576 if (Width) {
577 if ((Alignment & taLeft) != 0) {
578 if ((Alignment & taBorder) != 0)
579 x += max(h / TEXT_ALIGN_BORDER, 1);
580 }
581 else if ((Alignment & taRight) != 0) {
582 if (w < Width)
583 x += Width - w;
584 if ((Alignment & taBorder) != 0)
585 x -= max(h / TEXT_ALIGN_BORDER, 1);
586 }
587 else { // taCentered
588 if (w < Width)
589 x += (Width - w) / 2;
590 }
591 }
592 if (Height) {
593 if ((Alignment & taTop) != 0)
594 ;
595 else if ((Alignment & taBottom) != 0) {
596 if (h < Height)
597 y += Height - h;
598 }
599 else { // taCentered
600 if (h < Height)
601 y += (Height - h) / 2;
602 }
603 }
604 }
605 x -= x0;
606 y -= y0;
607 Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
608 }
609}
610
611void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
612{
613 if (bitmap && Intersects(x1, y1, x2, y2)) {
614 if (Covers(x1, y1, x2, y2))
615 Reset();
616 x1 -= x0;
617 y1 -= y0;
618 x2 -= x0;
619 y2 -= y0;
620 x1 = max(x1, 0);
621 y1 = max(y1, 0);
622 x2 = min(x2, width - 1);
623 y2 = min(y2, height - 1);
624 tIndex c = Index(Color);
625 for (int y = y1; y <= y2; y++) {
626 for (int x = x1; x <= x2; x++)
627 SetIndex(x, y, c);
628 }
629 }
630}
631
632void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
633{
634 if (!Intersects(x1, y1, x2, y2))
635 return;
636 // Algorithm based on https://dai.fmph.uniba.sk/upload/0/01/Ellipse.pdf
637 int rx = x2 - x1;
638 int ry = y2 - y1;
639 int cx = (x1 + x2) / 2;
640 int cy = (y1 + y2) / 2;
641 switch (abs(Quadrants)) {
642 case 0: rx /= 2; ry /= 2; break;
643 case 1: cx = x1; cy = y2; break;
644 case 2: cx = x2; cy = y2; break;
645 case 3: cx = x2; cy = y1; break;
646 case 4: cx = x1; cy = y1; break;
647 case 5: cx = x1; ry /= 2; break;
648 case 6: cy = y2; rx /= 2; break;
649 case 7: cx = x2; ry /= 2; break;
650 case 8: cy = y1; rx /= 2; break;
651 default: ;
652 }
653 int TwoASquare = max(1, 2 * rx * rx);
654 int TwoBSquare = max(1, 2 * ry * ry);
655 int x = rx;
656 int y = 0;
657 int XChange = ry * ry * (1 - 2 * rx);
658 int YChange = rx * rx;
659 int EllipseError = 0;
660 int StoppingX = TwoBSquare * rx;
661 int StoppingY = 0;
662 while (StoppingX >= StoppingY) {
663 switch (Quadrants) {
664 case 5: DrawRectangle(cx, cy + y, cx + x, cy + y, Color); // no break
665 case 1: DrawRectangle(cx, cy - y, cx + x, cy - y, Color); break;
666 case 7: DrawRectangle(cx - x, cy + y, cx, cy + y, Color); // no break
667 case 2: DrawRectangle(cx - x, cy - y, cx, cy - y, Color); break;
668 case 3: DrawRectangle(cx - x, cy + y, cx, cy + y, Color); break;
669 case 4: DrawRectangle(cx, cy + y, cx + x, cy + y, Color); break;
670 case 0:
671 case 6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, Color); if (Quadrants == 6) break;
672 case 8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, Color); break;
673 case -1: DrawRectangle(cx + x, cy - y, x2, cy - y, Color); break;
674 case -2: DrawRectangle(x1, cy - y, cx - x, cy - y, Color); break;
675 case -3: DrawRectangle(x1, cy + y, cx - x, cy + y, Color); break;
676 case -4: DrawRectangle(cx + x, cy + y, x2, cy + y, Color); break;
677 default: ;
678 }
679 y++;
680 StoppingY += TwoASquare;
681 EllipseError += YChange;
682 YChange += TwoASquare;
683 if (2 * EllipseError + XChange > 0) {
684 x--;
685 StoppingX -= TwoBSquare;
686 EllipseError += XChange;
687 XChange += TwoBSquare;
688 }
689 }
690 x = 0;
691 y = ry;
692 XChange = ry * ry;
693 YChange = rx * rx * (1 - 2 * ry);
694 EllipseError = 0;
695 StoppingX = 0;
696 StoppingY = TwoASquare * ry;
697 while (StoppingX <= StoppingY) {
698 switch (Quadrants) {
699 case 5: DrawRectangle(cx, cy + y, cx + x, cy + y, Color); // no break
700 case 1: DrawRectangle(cx, cy - y, cx + x, cy - y, Color); break;
701 case 7: DrawRectangle(cx - x, cy + y, cx, cy + y, Color); // no break
702 case 2: DrawRectangle(cx - x, cy - y, cx, cy - y, Color); break;
703 case 3: DrawRectangle(cx - x, cy + y, cx, cy + y, Color); break;
704 case 4: DrawRectangle(cx, cy + y, cx + x, cy + y, Color); break;
705 case 0:
706 case 6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, Color); if (Quadrants == 6) break;
707 case 8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, Color); break;
708 case -1: DrawRectangle(cx + x, cy - y, x2, cy - y, Color); break;
709 case -2: DrawRectangle(x1, cy - y, cx - x, cy - y, Color); break;
710 case -3: DrawRectangle(x1, cy + y, cx - x, cy + y, Color); break;
711 case -4: DrawRectangle(cx + x, cy + y, x2, cy + y, Color); break;
712 default: ;
713 }
714 x++;
715 StoppingX += TwoBSquare;
716 EllipseError += XChange;
717 XChange += TwoBSquare;
718 if (2 * EllipseError + YChange > 0) {
719 y--;
720 StoppingY -= TwoASquare;
721 EllipseError += YChange;
722 YChange += TwoASquare;
723 }
724 }
725}
726
727void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
728{
729 if (!Intersects(x1, y1, x2, y2))
730 return;
731 bool upper = Type & 0x01;
732 bool falling = Type & 0x02;
733 bool vertical = Type & 0x04;
734 if (vertical) {
735 for (int y = y1; y <= y2; y++) {
736 double c = cos((y - y1) * M_PI / (y2 - y1 + 1));
737 if (falling)
738 c = -c;
739 int x = int((x2 - x1 + 1) * c / 2);
740 if (upper && !falling || !upper && falling)
741 DrawRectangle(x1, y, (x1 + x2) / 2 + x, y, Color);
742 else
743 DrawRectangle((x1 + x2) / 2 + x, y, x2, y, Color);
744 }
745 }
746 else {
747 for (int x = x1; x <= x2; x++) {
748 double c = cos((x - x1) * M_PI / (x2 - x1 + 1));
749 if (falling)
750 c = -c;
751 int y = int((y2 - y1 + 1) * c / 2);
752 if (upper)
753 DrawRectangle(x, y1, x, (y1 + y2) / 2 + y, Color);
754 else
755 DrawRectangle(x, (y1 + y2) / 2 + y, x, y2, Color);
756 }
757 }
758}
759
760const tIndex *cBitmap::Data(int x, int y) const
761{
762 return &bitmap[y * width + x];
763}
764
765void cBitmap::ReduceBpp(const cPalette &Palette)
766{
767 int NewBpp = Palette.Bpp();
768 if (Bpp() == 4 && NewBpp == 2) {
769 for (int i = width * height; i--; ) {
770 tIndex p = bitmap[i];
771 bitmap[i] = (p >> 2) | ((p & 0x03) != 0);
772 }
773 }
774 else if (Bpp() == 8) {
775 if (NewBpp == 2) {
776 for (int i = width * height; i--; ) {
777 tIndex p = bitmap[i];
778 bitmap[i] = (p >> 6) | ((p & 0x30) != 0);
779 }
780 }
781 else if (NewBpp == 4) {
782 for (int i = width * height; i--; ) {
783 tIndex p = bitmap[i];
784 bitmap[i] = p >> 4;
785 }
786 }
787 else
788 return;
789 }
790 else
791 return;
792 SetBpp(NewBpp);
793 Replace(Palette);
794}
795
796void cBitmap::ShrinkBpp(int NewBpp)
797{
798 int NumOldColors;
799 const tColor *Colors = this->Colors(NumOldColors);
800 if (Colors) {
801 // Find the most frequently used colors and create a map table:
802 int Used[MAXNUMCOLORS] = { 0 };
803 int Map[MAXNUMCOLORS] = { 0 };
804 for (int i = width * height; i--; )
805 Used[bitmap[i]]++;
806 int MaxNewColors = (NewBpp == 4) ? 16 : 4;
807 cPalette NewPalette(NewBpp);
808 for (int i = 0; i < MaxNewColors; i++) {
809 int Max = 0;
810 int Index = -1;
811 for (int n = 0; n < NumOldColors; n++) {
812 if (Used[n] > Max) {
813 Max = Used[n];
814 Index = n;
815 }
816 }
817 if (Index >= 0) {
818 Used[Index] = 0;
819 Map[Index] = i;
820 NewPalette.SetColor(i, Colors[Index]);
821 }
822 else
823 break;
824 }
825 // Complete the map table for all other colors (will be set to closest match):
826 for (int n = 0; n < NumOldColors; n++) {
827 if (Used[n])
828 Map[n] = NewPalette.Index(Colors[n]);
829 }
830 // Do the actual index mapping:
831 for (int i = width * height; i--; )
832 bitmap[i] = Map[bitmap[i]];
833 SetBpp(NewBpp);
834 Replace(NewPalette);
835 }
836}
837
838cBitmap *cBitmap::Scaled(double FactorX, double FactorY, bool AntiAlias) const
839{
840 // Fixed point scaling code based on www.inversereality.org/files/bitmapscaling.pdf
841 // by deltener@mindtremors.com
842 int w = max(1, int(round(Width() * FactorX)));
843 int h = max(1, int(round(Height() * FactorY)));
844 cBitmap *b = new cBitmap(w, h, Bpp(), X0(), Y0());
845 int RatioX = (Width() << 16) / b->Width();
846 int RatioY = (Height() << 16) / b->Height();
847 if (!AntiAlias || FactorX <= 1.0 && FactorY <= 1.0) {
848 // Downscaling - no anti-aliasing:
849 b->Replace(*this); // copy palette
850 tIndex *DestRow = b->bitmap;
851 int SourceY = 0;
852 for (int y = 0; y < b->Height(); y++) {
853 int SourceX = 0;
854 tIndex *SourceRow = bitmap + (SourceY >> 16) * Width();
855 tIndex *Dest = DestRow;
856 for (int x = 0; x < b->Width(); x++) {
857 *Dest++ = SourceRow[SourceX >> 16];
858 SourceX += RatioX;
859 }
860 SourceY += RatioY;
861 DestRow += b->Width();
862 }
863 }
864 else {
865 // Upscaling - anti-aliasing:
866 b->SetBpp(8);
867 b->Replace(*this); // copy palette (must be done *after* SetBpp()!)
868 int SourceY = 0;
869 for (int y = 0; y < b->Height(); y++) {
870 int SourceX = 0;
871 int sy = min(SourceY >> 16, Height() - 2);
872 uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF);
873 for (int x = 0; x < b->Width(); x++) {
874 int sx = min(SourceX >> 16, Width() - 2);
875 uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF);
876 tColor c1 = b->Blend(GetColor(sx, sy), GetColor(sx + 1, sy), BlendX);
877 tColor c2 = b->Blend(GetColor(sx, sy + 1), GetColor(sx + 1, sy + 1), BlendX);
878 tColor c3 = b->Blend(c1, c2, BlendY);
879 b->DrawPixel(x + X0(), y + Y0(), c3);
880 SourceX += RatioX;
881 }
882 SourceY += RatioY;
883 }
884 }
885 return b;
886}
887
888// --- cRect -----------------------------------------------------------------
889
890const cRect cRect::Null;
891
892void cRect::Grow(int Dx, int Dy)
893{
894 point.Shift(-Dx, -Dy);
895 size.Grow(Dx, Dy);
896}
897
898bool cRect::Contains(const cPoint &Point) const
899{
900 return Left() <= Point.X() &&
901 Top() <= Point.Y() &&
902 Right() >= Point.X() &&
903 Bottom() >= Point.Y();
904}
905
906bool cRect::Contains(const cRect &Rect) const
907{
908 return Left() <= Rect.Left() &&
909 Top() <= Rect.Top() &&
910 Right() >= Rect.Right() &&
911 Bottom() >= Rect.Bottom();
912}
913
914bool cRect::Intersects(const cRect &Rect) const
915{
916 return !(Left() > Rect.Right() ||
917 Top() > Rect.Bottom() ||
918 Right() < Rect.Left() ||
919 Bottom() < Rect.Top());
920}
921
923{
924 cRect r;
925 if (!IsEmpty() && !Rect.IsEmpty()) {
926 r.SetLeft(max(Left(), Rect.Left()));
927 r.SetTop(max(Top(), Rect.Top()));
928 r.SetRight(min(Right(), Rect.Right()));
929 r.SetBottom(min(Bottom(), Rect.Bottom()));
930 }
931 return r;
932}
933
934void cRect::Combine(const cRect &Rect)
935{
936 if (IsEmpty())
937 *this = Rect;
938 if (Rect.IsEmpty())
939 return;
940 // must set right/bottom *before* top/left!
941 SetRight(max(Right(), Rect.Right()));
942 SetBottom(max(Bottom(), Rect.Bottom()));
943 SetLeft(min(Left(), Rect.Left()));
944 SetTop(min(Top(), Rect.Top()));
945}
946
947void cRect::Combine(const cPoint &Point)
948{
949 if (IsEmpty())
950 Set(Point.X(), Point.Y(), 1, 1);
951 // must set right/bottom *before* top/left!
952 SetRight(max(Right(), Point.X()));
953 SetBottom(max(Bottom(), Point.Y()));
954 SetLeft(min(Left(), Point.X()));
955 SetTop(min(Top(), Point.Y()));
956}
957
958// --- cPixmap ---------------------------------------------------------------
959
961
963{
964 layer = -1;
966 tile = false;
967}
968
969cPixmap::cPixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
970{
971 layer = Layer;
972 if (layer >= MAXPIXMAPLAYERS) {
974 esyslog("ERROR: pixmap layer %d limited to %d", Layer, layer);
975 }
977 if (!DrawPort.IsEmpty())
979 else {
981 drawPort.SetPoint(0, 0);
982 }
984 tile = false;
985}
986
988{
989 if (layer >= 0)
991}
992
994{
995 if (layer >= 0 && viewPort.Contains(Point))
996 dirtyViewPort.Combine(Point);
997}
998
1000{
1002 if (tile)
1004 else
1006}
1007
1009{
1010 if (drawPort.Contains(Point)) {
1011 dirtyDrawPort.Combine(Point);
1012 if (tile)
1014 else
1016 }
1017}
1018
1020{
1022}
1023
1024void cPixmap::SetLayer(int Layer)
1025{
1026 Lock();
1027 if (Layer >= MAXPIXMAPLAYERS) {
1028 esyslog("ERROR: pixmap layer %d limited to %d", Layer, MAXPIXMAPLAYERS - 1);
1029 Layer = MAXPIXMAPLAYERS - 1;
1030 }
1031 // The sequence here is important, because the view port is only marked as dirty
1032 // if the layer is >= 0:
1033 if (layer >= 0) {
1034 MarkViewPortDirty(viewPort); // the pixmap is visible and may or may not become invisible
1035 layer = Layer;
1036 }
1037 else if (Layer >= 0) {
1038 layer = Layer;
1039 MarkViewPortDirty(viewPort); // the pixmap was invisible and has become visible
1040 }
1041 else
1042 layer = Layer; // the pixmap was invisible and remains so
1043 Unlock();
1044}
1045
1046void cPixmap::SetAlpha(int Alpha)
1047{
1048 Lock();
1050 if (Alpha != alpha) {
1052 alpha = Alpha;
1053 }
1054 Unlock();
1055}
1056
1057void cPixmap::SetTile(bool Tile)
1058{
1059 Lock();
1060 if (Tile != tile) {
1061 if (drawPort.Point() != cPoint(0, 0) || drawPort.Width() < viewPort.Width() || drawPort.Height() < viewPort.Height())
1063 tile = Tile;
1064 }
1065 Unlock();
1066}
1067
1069{
1070 Lock();
1071 if (Rect != viewPort) {
1072 if (tile)
1074 else
1076 viewPort = Rect;
1077 if (tile)
1079 else
1081 }
1082 Unlock();
1083}
1084
1085void cPixmap::SetDrawPortPoint(const cPoint &Point, bool Dirty)
1086{
1087 Lock();
1088 if (Point != drawPort.Point()) {
1089 if (Dirty) {
1090 if (tile)
1092 else
1094 }
1095 drawPort.SetPoint(Point);
1096 if (Dirty && !tile)
1098 }
1099 Unlock();
1100}
1101
1102// --- cImage ----------------------------------------------------------------
1103
1105{
1106 data = NULL;
1107}
1108
1110{
1111 size = Image.Size();
1112 int l = size.Width() * size.Height();
1113 data = MALLOC(tColor, l);
1114 memcpy(data, Image.Data(), l * sizeof(tColor));
1115}
1116
1117cImage::cImage(const cSize &Size, const tColor *Data)
1118{
1119 size = Size;
1120 int l = size.Width() * size.Height();
1121 data = MALLOC(tColor, l);
1122 if (Data)
1123 memcpy(data, Data, l * sizeof(tColor));
1124}
1125
1127{
1128 free(data);
1129}
1130
1132{
1133 memset(data, 0x00, Width() * Height() * sizeof(tColor));
1134}
1135
1137{
1138 for (int i = Width() * Height() - 1; i >= 0; i--)
1139 data[i] = Color;
1140}
1141
1142// --- cPixmapMemory ---------------------------------------------------------
1143
1145{
1146 data = NULL;
1147 panning = false;
1148}
1149
1150cPixmapMemory::cPixmapMemory(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1151:cPixmap(Layer, ViewPort, DrawPort)
1152{
1153 data = MALLOC(tColor, this->DrawPort().Width() * this->DrawPort().Height());
1154 panning = false;
1155}
1156
1158{
1159 free(data);
1160}
1161
1163{
1164 Lock();
1165 memset(data, 0x00, DrawPort().Width() * DrawPort().Height() * sizeof(tColor));
1167 Unlock();
1168}
1169
1171{
1172 Lock();
1173 for (int i = DrawPort().Width() * DrawPort().Height() - 1; i >= 0; i--)
1174 data[i] = Color;
1176 Unlock();
1177}
1178
1179void cPixmap::DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
1180{
1181 if (Pixmap->Tile() && (Pixmap->DrawPort().Point() != cPoint(0, 0) || Pixmap->DrawPort().Size() < Pixmap->ViewPort().Size())) {
1182 cPoint t0 = Pixmap->DrawPort().Point().Shifted(Pixmap->ViewPort().Point()); // the origin of the draw port in absolute OSD coordinates
1183 // Find the top/leftmost location where the draw port touches the view port:
1184 while (t0.X() > Pixmap->ViewPort().Left())
1185 t0.Shift(-Pixmap->DrawPort().Width(), 0);
1186 while (t0.Y() > Pixmap->ViewPort().Top())
1187 t0.Shift(0, -Pixmap->DrawPort().Height());
1188 cPoint t = t0;
1189 while (t.Y() <= Pixmap->ViewPort().Bottom()) {
1190 while (t.X() <= Pixmap->ViewPort().Right()) {
1191 cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1192 Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1193 cPoint Delta = Source.Point() - t;
1194 Source.SetPoint(t); // Source is now where the pixmap's data shall be drawn
1195 Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1196 Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1197 if (!Source.IsEmpty()) {
1198 cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1199 Source.Shift(Delta); // Source is now back at the pixmap's draw port location, still in absolute OSD coordinates
1200 Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's view port again
1201 Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1202 if (Pixmap->Layer() == 0)
1203 Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1204 else
1205 Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1206 }
1207 t.Shift(Pixmap->DrawPort().Width(), 0); // increase one draw port width to the right
1208 }
1209 t.SetX(t0.X()); // go back to the leftmost position
1210 t.Shift(0, Pixmap->DrawPort().Height()); // increase one draw port height down
1211 }
1212 }
1213 else {
1214 cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1215 Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1216 Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1217 Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1218 if (!Source.IsEmpty()) {
1219 cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1220 Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's draw port again
1221 Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1222 if (Pixmap->Layer() == 0)
1223 Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1224 else
1225 Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1226 }
1227 }
1228}
1229
1230void cPixmapMemory::DrawImage(const cPoint &Point, const cImage &Image)
1231{
1232 Lock();
1233 cRect r = cRect(Point, Image.Size()).Intersected(DrawPort().Size());
1234 if (!r.IsEmpty()) {
1235 int ws = Image.Size().Width();
1236 int wd = DrawPort().Width();
1237 int w = r.Width() * sizeof(tColor);
1238 const tColor *ps = Image.Data();
1239 if (Point.Y() < 0)
1240 ps -= Point.Y() * ws;
1241 if (Point.X() < 0)
1242 ps -= Point.X();
1243 tColor *pd = data + wd * r.Top() + r.Left();
1244 for (int y = r.Height(); y-- > 0; ) {
1245 memcpy(pd, ps, w);
1246 ps += ws;
1247 pd += wd;
1248 }
1250 }
1251 Unlock();
1252}
1253
1254void cPixmapMemory::DrawImage(const cPoint &Point, int ImageHandle)
1255{
1256 Lock();
1257 if (const cImage *Image = cOsdProvider::GetImageData(ImageHandle))
1258 DrawImage(Point, *Image);
1259 Unlock();
1260}
1261
1262void cPixmapMemory::DrawPixel(const cPoint &Point, tColor Color)
1263{
1264 Lock();
1265 if (DrawPort().Size().Contains(Point)) {
1266 int p = Point.Y() * DrawPort().Width() + Point.X();
1267 if (Layer() == 0 && !IS_OPAQUE(Color))
1268 data[p] = AlphaBlend(Color, data[p]);
1269 else
1270 data[p] = Color;
1271 MarkDrawPortDirty(Point);
1272 }
1273 Unlock();
1274}
1275
1276void cPixmapMemory::DrawBlendedPixel(const cPoint &Point, tColor Color, uint8_t Alpha)
1277{
1278 Lock();
1279 if (DrawPort().Size().Contains(Point)) {
1280 int p = Point.Y() * DrawPort().Width() + Point.X();
1281 if (Alpha != ALPHA_OPAQUE) {
1282 if (Color == clrTransparent)
1283 data[p] = (data[p] & 0x00FFFFFF) | ((((data[p] >> 24) * (255 - Alpha)) << 16) & 0xFF000000);
1284 else
1285 data[p] = AlphaBlend(Color, data[p], Alpha);
1286 }
1287 else
1288 data[p] = Color;
1289 MarkDrawPortDirty(Point);
1290 }
1291 Unlock();
1292}
1293
1294void cPixmapMemory::DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay)
1295{
1296 Lock();
1297 cRect r = cRect(Point, cSize(Bitmap.Width(), Bitmap.Height())).Intersected(DrawPort().Size());
1298 if (!r.IsEmpty()) {
1299 bool UseColors = ColorFg || ColorBg;
1300 int wd = DrawPort().Width();
1301 tColor *pd = data + wd * r.Top() + r.Left();
1302 for (int y = r.Top(); y <= r.Bottom(); y++) {
1303 tColor *cd = pd;
1304 for (int x = r.Left(); x <= r.Right(); x++) {
1305 tIndex Index = *Bitmap.Data(x - Point.X(), y - Point.Y());
1306 if (Index || !Overlay) {
1307 if (UseColors)
1308 *cd = Index ? ColorFg : ColorBg;
1309 else
1310 *cd = Bitmap.Color(Index);
1311 }
1312 cd++;
1313 }
1314 pd += wd;
1315 }
1317 }
1318 Unlock();
1319}
1320
1321void cPixmapMemory::DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
1322{
1323 Lock();
1324 int x = Point.X();
1325 int y = Point.Y();
1326 int w = Font->Width(s);
1327 int h = Font->Height();
1328 int limit = 0;
1329 int cw = Width ? Width : w;
1330 int ch = Height ? Height : h;
1331 cRect r(x, y, cw, ch);
1332 if (ColorBg != clrTransparent)
1333 DrawRectangle(r, ColorBg);
1334 if (Width || Height) {
1335 limit = x + cw;
1336 if (Width) {
1337 if ((Alignment & taLeft) != 0) {
1338 if ((Alignment & taBorder) != 0)
1339 x += max(h / TEXT_ALIGN_BORDER, 1);
1340 }
1341 else if ((Alignment & taRight) != 0) {
1342 if (w < Width)
1343 x += Width - w;
1344 if ((Alignment & taBorder) != 0)
1345 x -= max(h / TEXT_ALIGN_BORDER, 1);
1346 }
1347 else { // taCentered
1348 if (w < Width)
1349 x += (Width - w) / 2;
1350 }
1351 }
1352 if (Height) {
1353 if ((Alignment & taTop) != 0)
1354 ;
1355 else if ((Alignment & taBottom) != 0) {
1356 if (h < Height)
1357 y += Height - h;
1358 }
1359 else { // taCentered
1360 if (h < Height)
1361 y += (Height - h) / 2;
1362 }
1363 }
1364 }
1365 Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
1367 Unlock();
1368}
1369
1371{
1372 Lock();
1373 cRect r = Rect.Intersected(DrawPort().Size());
1374 if (!r.IsEmpty()) {
1375 int wd = DrawPort().Width();
1376 int w = r.Width() * sizeof(tColor);
1377 tColor *ps = NULL;
1378 tColor *pd = data + wd * r.Top() + r.Left();
1379 for (int y = r.Height(); y-- > 0; ) {
1380 if (ps)
1381 memcpy(pd, ps, w); // all other lines are copied fast from the first one
1382 else {
1383 // explicitly fill the first line:
1384 tColor *cd = ps = pd;
1385 for (int x = r.Width(); x-- > 0; ) {
1386 *cd = Color;
1387 cd++;
1388 }
1389 }
1390 pd += wd;
1391 }
1393 }
1394 Unlock();
1395}
1396
1397void cPixmapMemory::DrawEllipse(const cRect &Rect, tColor Color, int Quadrants)
1398{
1399 Lock();
1400 // Algorithm based on https://dai.fmph.uniba.sk/upload/0/01/Ellipse.pdf
1401 int x1 = Rect.Left();
1402 int y1 = Rect.Top();
1403 int x2 = Rect.Right();
1404 int y2 = Rect.Bottom();
1405 int rx = x2 - x1;
1406 int ry = y2 - y1;
1407 int ax = rx & 0x01; // alignment to make semi-circles match rectangles of same size
1408 int ay = ry & 0x01;
1409 int cx = (x1 + x2) / 2;
1410 int cy = (y1 + y2) / 2;
1411 switch (abs(Quadrants)) {
1412 case 0: rx /= 2; ry /= 2; break;
1413 case 1: cx = x1; cy = y2; break;
1414 case 2: cx = x2; cy = y2; break;
1415 case 3: cx = x2; cy = y1; break;
1416 case 4: cx = x1; cy = y1; break;
1417 case 5: cx = x1; ry /= 2; break;
1418 case 6: cy = y2; rx /= 2; break;
1419 case 7: cx = x2; ry /= 2; break;
1420 case 8: cy = y1; rx /= 2; break;
1421 default: ;
1422 }
1423 int TwoASquare = max(1, 2 * rx * rx);
1424 int TwoBSquare = max(1, 2 * ry * ry);
1425 int x = rx;
1426 int y = 0;
1427 int XChange = ry * ry * (1 - 2 * rx);
1428 int YChange = rx * rx;
1429 int EllipseError = 0;
1430 int StoppingX = TwoBSquare * rx;
1431 int StoppingY = 0;
1432 int Delta = 0;
1433 bool AntiAliased = Setup.AntiAlias;
1434 while (StoppingX >= StoppingY) {
1435 if (!AntiAliased) {
1436 switch (Quadrants) {
1437 case 5: DrawRectangle(cRect(cx, cy + y + ay, x + 1, 1), Color); // no break
1438 case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1439 case 7: DrawRectangle(cRect(cx - x, cy + y + ay, x + 1, 1), Color); // no break
1440 case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1441 case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1442 case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1443 case 0:
1444 case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + ax + 1, 1), Color); if (Quadrants == 6) break;
1445 case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + ax + 1, 1), Color); break;
1446 case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1447 case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1448 case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1449 case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1450 default: ;
1451 }
1452 }
1453 else {
1454 uint8_t intensity = abs(255 * (long int)EllipseError / XChange);
1455 if (EllipseError >= 0) {
1456 intensity = 255 - intensity;
1457 Delta = 0;
1458 }
1459 else
1460 Delta = 1;
1461 switch (Quadrants) {
1462 case 5: DrawRectangle( cRect( cx, cy + y + ay, x + Delta, 1), Color);
1463 DrawBlendedPixel(cPoint(cx + x + Delta, cy + y + ay), Color, intensity);
1464 // no break
1465 case 1: DrawRectangle( cRect( cx, cy - y, x + Delta, 1), Color);
1466 DrawBlendedPixel(cPoint(cx + x + Delta, cy - y), Color, intensity);
1467 break;
1468 case 7: DrawRectangle( cRect( cx - x + 1 - Delta, cy + ay + y, x + Delta, 1), Color);
1469 DrawBlendedPixel(cPoint(cx - x - Delta, cy + ay + y), Color, intensity);
1470 // no break
1471 case 2: DrawRectangle( cRect( cx - x + 1 - Delta, cy - y, x + Delta, 1), Color);
1472 DrawBlendedPixel(cPoint(cx - x - Delta, cy - y), Color, intensity);
1473 break;
1474 case 3: DrawRectangle( cRect( cx - x + 1 - Delta, cy + y, x + Delta, 1), Color);
1475 DrawBlendedPixel(cPoint(cx - x - Delta, cy + y), Color, intensity);
1476 break;
1477 case 4: DrawRectangle( cRect( cx, cy + y, x + Delta, 1), Color);
1478 DrawBlendedPixel(cPoint(cx + x + Delta, cy + y), Color, intensity);
1479 break;
1480 case 0:
1481 case 6: DrawRectangle( cRect( cx - x - Delta + 1, cy - y, 2 * (x + Delta) + ax - 1, 1), Color);
1482 DrawBlendedPixel(cPoint(cx - x - Delta, cy - y), Color, intensity);
1483 DrawBlendedPixel(cPoint(cx + x + Delta + ax, cy - y), Color, intensity);
1484 if (Quadrants == 6)
1485 break;
1486 case 8: DrawRectangle( cRect( cx - x - Delta + 1, cy + y, 2 * (x + Delta) + ax - 1 , 1), Color);
1487 DrawBlendedPixel(cPoint(cx - x - Delta, cy + y), Color, intensity);
1488 DrawBlendedPixel(cPoint(cx + x + Delta + ax, cy + y), Color, intensity);
1489 break;
1490 case -1: DrawRectangle( cRect( cx + x + 1 + Delta, cy - y, rx - (x + Delta), 1), Color);
1491 DrawBlendedPixel(cPoint(cx + x + Delta, cy - y), Color, 255-intensity);
1492 break;
1493 case -2: DrawRectangle( cRect( x1, cy - y, rx - x - Delta, 1), Color);
1494 DrawBlendedPixel(cPoint(cx - x - Delta, cy - y), Color, 255-intensity);
1495 break;
1496 case -3: DrawRectangle( cRect( x1, cy + y, rx - x - Delta, 1), Color);
1497 DrawBlendedPixel(cPoint(cx - x - Delta, cy + y), Color, 255-intensity);
1498 break;
1499 case -4: DrawRectangle( cRect( cx + x + 1 + Delta, cy + y, rx - x - Delta, 1), Color);
1500 DrawBlendedPixel(cPoint(cx + x + Delta, cy + y), Color, 255-intensity);
1501 break;
1502 default: ;
1503 }
1504 }
1505 y++;
1506 StoppingY += TwoASquare;
1507 EllipseError += YChange;
1508 YChange += TwoASquare;
1509 if (2 * EllipseError + XChange > 0) {
1510 x--;
1511 StoppingX -= TwoBSquare;
1512 EllipseError += XChange;
1513 XChange += TwoBSquare;
1514 }
1515 }
1516 int ymax = y - 1;
1517 x = 0;
1518 y = ry;
1519 XChange = ry * ry;
1520 YChange = rx * rx * (1 - 2 * ry);
1521 EllipseError = 0;
1522 StoppingX = 0;
1523 StoppingY = TwoASquare * ry;
1524 while (StoppingX <= StoppingY) {
1525 if (!AntiAliased) {
1526 switch (Quadrants) {
1527 case 5: DrawRectangle(cRect(cx, cy + y + ay, x + 1, 1), Color); // no break
1528 case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1529 case 7: DrawRectangle(cRect(cx - x, cy + y + ay, x + 1, 1), Color); // no break
1530 case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1531 case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1532 case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1533 case 0:
1534 case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + ax + 1, 1), Color); if (Quadrants == 6) break;
1535 case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + ax + 1, 1), Color); break;
1536 case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1537 case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1538 case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1539 case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1540 default: ;
1541 }
1542 }
1543 else {
1544 uint8_t intensity = abs(255 * (long int)EllipseError / YChange);
1545 if (EllipseError >= 0) {
1546 intensity = 255 - intensity;
1547 Delta = 1;
1548 }
1549 else
1550 Delta = 0;
1551 switch (Quadrants) {
1552 case 5: DrawRectangle( cRect( cx + x, cy + ay + 1 + ymax, 1, y - ymax - Delta), Color);
1553 DrawBlendedPixel(cPoint(cx + x, cy + ay + y + 1 - Delta), Color, intensity);
1554 // no break
1555 case 1: DrawRectangle( cRect( cx + x, cy - y + Delta, 1, y - ymax - Delta), Color);
1556 DrawBlendedPixel(cPoint(cx + x, cy - y - 1 + Delta), Color, intensity);
1557 break;
1558 case 7: DrawRectangle( cRect( cx - x, cy + ay + 1 + ymax, 1, y - ymax - Delta), Color);
1559 DrawBlendedPixel(cPoint(cx - x, cy + ay + y + 1 - Delta), Color, intensity);
1560 // no break
1561 case 2: DrawRectangle( cRect( cx - x, cy - y + Delta, 1, y - ymax - Delta), Color);
1562 DrawBlendedPixel(cPoint(cx - x, cy - y - 1 + Delta), Color, intensity);
1563 break;
1564 case 3: DrawRectangle( cRect( cx - x, cy + 1 + ymax, 1, y - ymax - Delta), Color);
1565 DrawBlendedPixel(cPoint(cx - x, cy + y + 1 - Delta), Color, intensity);
1566 break;
1567 case 4: DrawRectangle( cRect( cx + x, cy + 1 + ymax, 1, y - ymax - Delta), Color);
1568 DrawBlendedPixel(cPoint(cx + x, cy + y + 1 - Delta), Color, intensity);
1569 break;
1570 case 0:
1571 case 6: DrawRectangle( cRect( cx + x + ax, cy - y + Delta, 1, y - ymax - Delta), Color);
1572 DrawRectangle( cRect( cx - x, cy - y + Delta, 1, y - ymax - Delta), Color);
1573 DrawBlendedPixel(cPoint(cx - x, cy - y + Delta - 1), Color, intensity);
1574 DrawBlendedPixel(cPoint(cx + x + ax, cy - y + Delta - 1), Color, intensity);
1575 if (Quadrants == 6)
1576 break;
1577 case 8: DrawRectangle( cRect( cx - x, cy + 1 + ymax, 1, y - ymax - Delta), Color);
1578 DrawRectangle( cRect( cx + x + ax, cy + 1 + ymax, 1, y - ymax - Delta), Color);
1579 DrawBlendedPixel(cPoint(cx - x, cy + y + 1 - Delta), Color, intensity);
1580 DrawBlendedPixel(cPoint(cx + x + ax, cy + y + 1 - Delta), Color, intensity);
1581 break;
1582 case -1: DrawRectangle( cRect( cx + x, cy - ry, 1, ry - y - 1 + Delta), Color);
1583 DrawBlendedPixel(cPoint(cx + x, cy - y - 1 + Delta), Color, 255-intensity);
1584 break;
1585 case -2: DrawRectangle( cRect( cx - x, cy - ry, 1, ry - y - 1 + Delta), Color);
1586 DrawBlendedPixel(cPoint(cx - x, cy - y - 1 + Delta), Color, 255-intensity);
1587 break;
1588 case -3: DrawRectangle( cRect( cx - x, cy + y + 2 - Delta, 1, ry - y - 1 + Delta), Color);
1589 DrawBlendedPixel(cPoint(cx - x, cy + y + 1 - Delta), Color, 255-intensity);
1590 break;
1591 case -4: DrawRectangle( cRect( cx + x, cy + y + 2 - Delta, 1, ry - y - 1 + Delta), Color);
1592 DrawBlendedPixel(cPoint(cx + x, cy + y + 1 - Delta), Color, 255-intensity);
1593 break;
1594 default: ;
1595 }
1596 }
1597 x++;
1598 StoppingX += TwoBSquare;
1599 EllipseError += XChange;
1600 XChange += TwoBSquare;
1601 if (2 * EllipseError + YChange > 0) {
1602 y--;
1603 StoppingY -= TwoASquare;
1604 EllipseError += YChange;
1605 YChange += TwoASquare;
1606 }
1607 }
1608 if (AntiAliased && Quadrants < 0 ) {
1609 switch (Quadrants) {
1610 case -1: DrawRectangle(cRect(cx + x, cy - ry, rx - x + 1, ry - y), Color); break;
1611 case -2: DrawRectangle(cRect(x1, cy - ry, rx - x + 1, ry - y), Color); break;
1612 case -3: DrawRectangle(cRect(x1, cy + y + 1, rx - x + 1, ry - y), Color); break;
1613 case -4: DrawRectangle(cRect(cx + x, cy + y + 1, rx - x + 1, ry - y), Color); break;
1614 default: ;
1615 }
1616 }
1617 MarkDrawPortDirty(Rect);
1618 Unlock();
1619}
1620
1621void cPixmapMemory::DrawSlope(const cRect &Rect, tColor Color, int Type)
1622{
1623 //TODO also simplify cBitmap::DrawSlope()
1624 Lock();
1625 bool upper = Type & 0x01;
1626 bool falling = Type & 0x02;
1627 bool vertical = Type & 0x04;
1628 int x1 = Rect.Left();
1629 int y1 = Rect.Top();
1630 int x2 = Rect.Right();
1631 int y2 = Rect.Bottom();
1632 int w = Rect.Width();
1633 int h = Rect.Height();
1634 bool AntiAliased = Setup.AntiAlias;
1635 uint8_t intensity = 0;
1636
1637 if (vertical) {
1638 if (upper)
1639 DrawRectangle(cRect(x1, y1, w, 1), Color);
1640 else
1641 DrawRectangle(cRect(x1, y2, w, 1), Color);
1642 for (int y = 1; y <= (y2 - y1) / 2; y++) {
1643 double c = cos(y * M_PI / (y2 - y1));
1644 if (AntiAliased) {
1645 double wc = (w * c + (w & 1)) / 2;
1646 intensity = 255 * fabs(wc - floor(wc));
1647 }
1648 if (falling)
1649 c = -c;
1650 int x = (x1 + x2 + w * c + 1) / 2;
1651 if (upper && !falling || !upper && falling) {
1652 if (AntiAliased) {
1653 DrawRectangle(cRect(x1, y1 + y, x - x1, 1), Color);
1654 DrawBlendedPixel(cPoint(x, y1 + y), Color, upper ? intensity : 255 - intensity);
1655 DrawRectangle(cRect(x1, y2 - y, x2 - x, 1), Color);
1656 DrawBlendedPixel(cPoint(x1 + x2 - x, y2 - y), Color, upper ? 255 - intensity : intensity);
1657 }
1658 else {
1659 DrawRectangle(cRect(x1, y1 + y, x - x1 + 1, 1), Color);
1660 DrawRectangle(cRect(x1, y2 - y, x2 - x + 1, 1), Color);
1661 }
1662 }
1663 else {
1664 if (AntiAliased) {
1665 DrawRectangle(cRect(x + 1, y1 + y, x2 - x, 1), Color);
1666 DrawBlendedPixel(cPoint(x, y1 + y), Color, falling ? intensity : 255 - intensity);
1667 DrawRectangle(cRect(x1 + x2 - x + 1, y2 - y, x - x1, 1), Color);
1668 DrawBlendedPixel(cPoint(x1 + x2 - x, y2 - y), Color, falling ? 255 - intensity : intensity);
1669 }
1670 else {
1671 DrawRectangle(cRect(x, y1 + y, x2 - x + 1, 1), Color);
1672 DrawRectangle(cRect(x1 + x2 - x, y2 - y, x - x1 + 1, 1), Color);
1673 }
1674 }
1675 }
1676 }
1677 else {
1678 if ((upper && !falling) || (!upper && falling))
1679 DrawRectangle(cRect(x1, y1, 1, h), Color);
1680 else
1681 DrawRectangle(cRect(x2, y1, 1, h), Color);
1682 for (int x = 1; x <= (x2 - x1) / 2; x++) {
1683 double c = cos(x * M_PI / (x2 - x1));
1684 if (AntiAliased) {
1685 double hc = (h * c + (h & 1)) / 2;
1686 intensity = 255 * fabs(hc - floor(hc));
1687 }
1688 if (falling)
1689 c = -c;
1690 int y = (y1 + y2 + h * c + 1) / 2;
1691 if (upper) {
1692 if (AntiAliased) {
1693 DrawRectangle(cRect(x1 + x, y1, 1, y - y1), Color);
1694 DrawBlendedPixel(cPoint(x1 + x, y), Color, falling ? 255 - intensity : intensity);
1695 DrawRectangle(cRect(x2 - x, y1, 1, y2 - y), Color);
1696 DrawBlendedPixel(cPoint(x2 - x, y1 + y2 - y), Color, falling ? intensity : 255 - intensity);
1697 }
1698 else {
1699 DrawRectangle(cRect(x1 + x, y1, 1, y - y1 + 1), Color);
1700 DrawRectangle(cRect(x2 - x, y1, 1, y2 - y + 1), Color);
1701 }
1702 }
1703 else {
1704 if (AntiAliased) {
1705 DrawRectangle(cRect(x1 + x, y + 1, 1, y2 - y), Color);
1706 DrawBlendedPixel(cPoint(x1 + x, y), Color, falling ? intensity : 255 - intensity);
1707 DrawRectangle(cRect(x2 - x, y1 + y2 - y + 1, 1, y - y1), Color);
1708 DrawBlendedPixel(cPoint(x2 - x, y1 + y2 - y), Color, falling ? 255 - intensity : intensity);
1709 }
1710 else {
1711 DrawRectangle(cRect(x1 + x, y, 1, y2 - y + 1), Color);
1712 DrawRectangle(cRect(x2 - x, y1 + y2 - y, 1, y - y1 + 1), Color);
1713 }
1714 }
1715 }
1716 }
1717 MarkDrawPortDirty(Rect);
1718 Unlock();
1719}
1720
1721void cPixmapMemory::Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1722{
1723 Lock();
1724 if (Pixmap->Alpha() != ALPHA_TRANSPARENT) {
1725 if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1726 cRect s = Source.Intersected(Pixmap->DrawPort().Size());
1727 if (!s.IsEmpty()) {
1728 cPoint v = Dest - Source.Point();
1729 cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1730 if (!d.IsEmpty()) {
1731 s = d.Shifted(-v);
1732 int a = pm->Alpha();
1733 int ws = pm->DrawPort().Width();
1734 int wd = DrawPort().Width();
1735 const tColor *ps = pm->data + ws * s.Top() + s.Left();
1736 tColor *pd = data + wd * d.Top() + d.Left();
1737 for (int y = d.Height(); y-- > 0; ) {
1738 const tColor *cs = ps;
1739 tColor *cd = pd;
1740 for (int x = d.Width(); x-- > 0; ) {
1741 *cd = AlphaBlend(*cs, *cd, a);
1742 cs++;
1743 cd++;
1744 }
1745 ps += ws;
1746 pd += wd;
1747 }
1749 }
1750 }
1751 }
1752 }
1753 Unlock();
1754}
1755
1756void cPixmapMemory::Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1757{
1758 Lock();
1759 if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1760 cRect s = Source.Intersected(pm->DrawPort().Size());
1761 if (!s.IsEmpty()) {
1762 cPoint v = Dest - Source.Point();
1763 cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1764 if (!d.IsEmpty()) {
1765 s = d.Shifted(-v);
1766 int ws = pm->DrawPort().Width();
1767 int wd = DrawPort().Width();
1768 int w = d.Width() * sizeof(tColor);
1769 const tColor *ps = pm->data + ws * s.Top() + s.Left();
1770 tColor *pd = data + wd * d.Top() + d.Left();
1771 for (int y = d.Height(); y-- > 0; ) {
1772 memcpy(pd, ps, w);
1773 ps += ws;
1774 pd += wd;
1775 }
1777 }
1778 }
1779 }
1780 Unlock();
1781}
1782
1783void cPixmapMemory::Scroll(const cPoint &Dest, const cRect &Source)
1784{
1785 Lock();
1786 cRect s;
1787 if (&Source == &cRect::Null)
1788 s = DrawPort().Shifted(-DrawPort().Point());
1789 else
1790 s = Source.Intersected(DrawPort().Size());
1791 if (!s.IsEmpty()) {
1792 cPoint v = Dest - Source.Point();
1793 cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1794 if (!d.IsEmpty()) {
1795 s = d.Shifted(-v);
1796 if (d.Point() != s.Point()) {
1797 int ws = DrawPort().Width();
1798 int wd = ws;
1799 int w = d.Width() * sizeof(tColor);
1800 const tColor *ps = data + ws * s.Top() + s.Left();
1801 tColor *pd = data + wd * d.Top() + d.Left();
1802 for (int y = d.Height(); y-- > 0; ) {
1803 memmove(pd, ps, w); // source and destination might overlap!
1804 ps += ws;
1805 pd += wd;
1806 }
1807 if (panning)
1808 SetDrawPortPoint(DrawPort().Point().Shifted(s.Point() - d.Point()), false);
1809 else
1811 }
1812 }
1813 }
1814 Unlock();
1815}
1816
1817void cPixmapMemory::Pan(const cPoint &Dest, const cRect &Source)
1818{
1819 Lock();
1820 panning = true;
1821 Scroll(Dest, Source);
1822 panning = false;
1823 Unlock();
1824}
1825
1826// --- cOsd ------------------------------------------------------------------
1827
1828static const char *OsdErrorTexts[] = {
1829 "ok",
1830 "too many areas",
1831 "too many colors",
1832 "bpp not supported",
1833 "areas overlap",
1834 "wrong alignment",
1835 "out of memory",
1836 "wrong area size",
1837 "unknown",
1838 };
1839
1840int cOsd::osdLeft = 0;
1841int cOsd::osdTop = 0;
1842int cOsd::osdWidth = 0;
1843int cOsd::osdHeight = 0;
1844cSize cOsd::maxPixmapSize(INT_MAX, INT_MAX);
1847
1848cOsd::cOsd(int Left, int Top, uint Level)
1849{
1850 cMutexLock MutexLock(&mutex);
1851 isTrueColor = false;
1852 savedBitmap = NULL;
1853 numBitmaps = 0;
1854 savedPixmap = NULL;
1855 left = Left;
1856 top = Top;
1857 width = height = 0;
1858 level = Level;
1859 active = false;
1860 for (int i = 0; i < Osds.Size(); i++) {
1861 if (Osds[i]->level > level) {
1862 Osds.Insert(this, i);
1863 return;
1864 }
1865 }
1866 Osds.Append(this);
1867}
1868
1870{
1871 cMutexLock MutexLock(&mutex);
1872 for (int i = 0; i < numBitmaps; i++)
1873 delete bitmaps[i];
1874 delete savedBitmap;
1875 delete savedPixmap;
1876 for (int i = 0; i < pixmaps.Size(); i++)
1877 delete pixmaps[i];
1878 for (int i = 0; i < Osds.Size(); i++) {
1879 if (Osds[i] == this) {
1880 Osds.Remove(i);
1881 if (Osds.Size())
1882 Osds[0]->SetActive(true);
1883 break;
1884 }
1885 }
1886}
1887
1888void cOsd::SetOsdPosition(int Left, int Top, int Width, int Height)
1889{
1890 osdLeft = Left;
1891 osdTop = Top;
1894}
1895
1896void cOsd::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
1897{
1898 if (isTrueColor)
1899 return;
1900 for (int i = 0; i < numBitmaps; i++)
1901 bitmaps[i]->SetAntiAliasGranularity(FixedColors, BlendColors);
1902}
1903
1905{
1906 return Area < numBitmaps ? (isTrueColor ? bitmaps[0] : bitmaps[Area]) : NULL;
1907}
1908
1909const cSize &cOsd::MaxPixmapSize(void) const
1910{
1911 return maxPixmapSize;
1912}
1913
1914cPixmap *cOsd::CreatePixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1915{
1916 if (isTrueColor) {
1918 cPixmap *Pixmap = new cPixmapMemory(Layer, ViewPort, DrawPort);
1919 if (AddPixmap(Pixmap))
1920 return Pixmap;
1921 delete Pixmap;
1922 }
1923 return NULL;
1924}
1925
1927{
1928 if (Pixmap) {
1930 for (int i = 1; i < pixmaps.Size(); i++) { // begin at 1 - don't let the background pixmap be destroyed!
1931 if (pixmaps[i] == Pixmap) {
1932 if (Pixmap->Layer() >= 0)
1933 pixmaps[0]->MarkViewPortDirty(Pixmap->ViewPort());
1934 delete Pixmap;
1935 pixmaps[i] = NULL;
1936 return;
1937 }
1938 }
1939 esyslog("ERROR: attempt to destroy an unregistered pixmap");
1940 }
1941}
1942
1944{
1945 if (Pixmap) {
1947 for (int i = 0; i < pixmaps.Size(); i++) {
1948 if (!pixmaps[i])
1949 return pixmaps[i] = Pixmap;
1950 }
1951 pixmaps.Append(Pixmap);
1952 }
1953 return Pixmap;
1954}
1955
1957{
1958 cPixmap *Pixmap = NULL;
1959 if (isTrueColor) {
1961 // Collect overlapping dirty rectangles:
1962 cRect d;
1963 for (int i = 0; i < pixmaps.Size(); i++) {
1964 if (cPixmap *pm = pixmaps[i]) {
1965 if (!pm->DirtyViewPort().IsEmpty()) {
1966 if (d.IsEmpty() || d.Intersects(pm->DirtyViewPort())) {
1967 d.Combine(pm->DirtyViewPort());
1968 pm->SetClean();
1969 }
1970 }
1971 }
1972 }
1973 if (!d.IsEmpty()) {
1974//#define DebugDirty
1975#ifdef DebugDirty
1976 static cRect OldDirty;
1977 cRect NewDirty = d;
1978 d.Combine(OldDirty);
1979 OldDirty = NewDirty;
1980#endif
1981 Pixmap = CreatePixmap(-1, d);
1982 if (Pixmap) {
1983 Pixmap->Clear();
1984 // Render the individual pixmaps into the resulting pixmap:
1985 for (int Layer = 0; Layer < MAXPIXMAPLAYERS; Layer++) {
1986 for (int i = 0; i < pixmaps.Size(); i++) {
1987 if (cPixmap *pm = pixmaps[i]) {
1988 if (pm->Layer() == Layer)
1989 Pixmap->DrawPixmap(pm, d);
1990 }
1991 }
1992 }
1993#ifdef DebugDirty
1994 cPixmapMemory DirtyIndicator(7, NewDirty);
1995 static tColor DirtyIndicatorColors[] = { 0x7FFFFF00, 0x7F00FFFF };
1996 static int DirtyIndicatorIndex = 0;
1997 DirtyIndicator.Fill(DirtyIndicatorColors[DirtyIndicatorIndex]);
1998 DirtyIndicatorIndex = 1 - DirtyIndicatorIndex;
1999 Pixmap->Render(&DirtyIndicator, DirtyIndicator.DrawPort(), DirtyIndicator.ViewPort().Point().Shifted(-Pixmap->ViewPort().Point()));
2000#endif
2001 }
2002 }
2003 }
2004 return Pixmap;
2005}
2006
2007eOsdError cOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
2008{
2009 if (NumAreas > MAXOSDAREAS)
2010 return oeTooManyAreas;
2011 eOsdError Result = oeOk;
2012 for (int i = 0; i < NumAreas; i++) {
2013 if (Areas[i].x1 > Areas[i].x2 || Areas[i].y1 > Areas[i].y2 || Areas[i].x1 < 0 || Areas[i].y1 < 0)
2014 return oeWrongAlignment;
2015 for (int j = i + 1; j < NumAreas; j++) {
2016 if (Areas[i].Intersects(Areas[j])) {
2017 Result = oeAreasOverlap;
2018 break;
2019 }
2020 }
2021 if (Areas[i].bpp == 32) {
2022 if (NumAreas > 1)
2023 return oeTooManyAreas;
2024 }
2025 }
2026 return Result;
2027}
2028
2029eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas)
2030{
2031 eOsdError Result = CanHandleAreas(Areas, NumAreas);
2032 if (Result == oeOk) {
2033 while (numBitmaps)
2034 delete bitmaps[--numBitmaps];
2035 for (int i = 0; i < pixmaps.Size(); i++) {
2036 delete pixmaps[i];
2037 pixmaps[i] = NULL;
2038 }
2039 width = height = 0;
2040 isTrueColor = NumAreas == 1 && Areas[0].bpp == 32;
2041 if (isTrueColor) {
2042 width = Areas[0].x2 - Areas[0].x1 + 1;
2043 height = Areas[0].y2 - Areas[0].y1 + 1;
2044 cPixmap *Pixmap = CreatePixmap(0, cRect(Areas[0].x1, Areas[0].y1, width, height));
2045 if (Pixmap)
2046 Pixmap->Clear();
2047 else
2048 Result = oeOutOfMemory;
2049 bitmaps[numBitmaps++] = new cBitmap(10, 10, 8); // dummy bitmap for GetBitmap()
2050 }
2051 else {
2052 for (int i = 0; i < NumAreas; i++) {
2053 bitmaps[numBitmaps++] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1);
2054 width = max(width, Areas[i].x2 + 1);
2055 height = max(height, Areas[i].y2 + 1);
2056 }
2057 }
2058 }
2059 else
2060 esyslog("ERROR: cOsd::SetAreas returned %d (%s)", Result, Result < oeUnknown ? OsdErrorTexts[Result] : OsdErrorTexts[oeUnknown]);
2061 return Result;
2062}
2063
2064void cOsd::SaveRegion(int x1, int y1, int x2, int y2)
2065{
2066 if (isTrueColor) {
2067 delete savedPixmap;
2068 cRect r(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
2069 savedPixmap = new cPixmapMemory(0, r);
2070 savedPixmap->Copy(pixmaps[0], r, cPoint(0, 0));
2071 }
2072 else {
2073 delete savedBitmap;
2074 savedBitmap = new cBitmap(x2 - x1 + 1, y2 - y1 + 1, 8, x1, y1);
2075 for (int i = 0; i < numBitmaps; i++)
2076 savedBitmap->DrawBitmap(bitmaps[i]->X0(), bitmaps[i]->Y0(), *bitmaps[i]);
2077 }
2078}
2079
2081{
2082 if (isTrueColor) {
2083 if (savedPixmap) {
2085 delete savedPixmap;
2086 savedPixmap = NULL;
2087 }
2088 }
2089 else {
2090 if (savedBitmap) {
2092 delete savedBitmap;
2093 savedBitmap = NULL;
2094 }
2095 }
2096}
2097
2098eOsdError cOsd::SetPalette(const cPalette &Palette, int Area)
2099{
2100 if (isTrueColor)
2101 return oeOk;
2102 if (Area < numBitmaps) {
2103 bitmaps[Area]->Take(Palette);
2104 return oeOk;
2105 }
2106 return oeUnknown;
2107}
2108
2109void cOsd::DrawImage(const cPoint &Point, const cImage &Image)
2110{
2111 if (isTrueColor)
2112 pixmaps[0]->DrawImage(Point, Image);
2113}
2114
2115void cOsd::DrawImage(const cPoint &Point, int ImageHandle)
2116{
2117 if (isTrueColor)
2118 pixmaps[0]->DrawImage(Point, ImageHandle);
2119}
2120
2121void cOsd::DrawPixel(int x, int y, tColor Color)
2122{
2123 if (isTrueColor)
2124 pixmaps[0]->DrawPixel(cPoint(x, y), Color);
2125 else {
2126 for (int i = 0; i < numBitmaps; i++)
2127 bitmaps[i]->DrawPixel(x, y, Color);
2128 }
2129}
2130
2131void cOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
2132{
2133 if (isTrueColor)
2134 pixmaps[0]->DrawBitmap(cPoint(x, y), Bitmap, ColorFg, ColorBg, Overlay);
2135 else {
2136 for (int i = 0; i < numBitmaps; i++)
2137 bitmaps[i]->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg, ReplacePalette, Overlay);
2138 }
2139}
2140
2141void cOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
2142{
2143 const cBitmap *b = &Bitmap;
2144 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0))
2145 b = b->Scaled(FactorX, FactorY, AntiAlias);
2146 DrawBitmap(x, y, *b);
2147 if (b != &Bitmap)
2148 delete b;
2149}
2150
2151void cOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
2152{
2153 if (isTrueColor)
2154 pixmaps[0]->DrawText(cPoint(x, y), s, ColorFg, ColorBg, Font, Width, Height, Alignment);
2155 else {
2156 for (int i = 0; i < numBitmaps; i++)
2157 bitmaps[i]->DrawText(x, y, s, ColorFg, ColorBg, Font, Width, Height, Alignment);
2158 }
2159}
2160
2161void cOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
2162{
2163 if (isTrueColor)
2164 pixmaps[0]->DrawRectangle(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color);
2165 else {
2166 for (int i = 0; i < numBitmaps; i++)
2167 bitmaps[i]->DrawRectangle(x1, y1, x2, y2, Color);
2168 }
2169}
2170
2171void cOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
2172{
2173 if (isTrueColor)
2174 pixmaps[0]->DrawEllipse(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Quadrants);
2175 else {
2176 for (int i = 0; i < numBitmaps; i++)
2177 bitmaps[i]->DrawEllipse(x1, y1, x2, y2, Color, Quadrants);
2178 }
2179}
2180
2181void cOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
2182{
2183 if (isTrueColor)
2184 pixmaps[0]->DrawSlope(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Type);
2185 else {
2186 for (int i = 0; i < numBitmaps; i++)
2187 bitmaps[i]->DrawSlope(x1, y1, x2, y2, Color, Type);
2188 }
2189}
2190
2191void cOsd::Flush(void)
2192{
2193}
2194
2195// --- cOsdProvider ----------------------------------------------------------
2196
2200double cOsdProvider::oldAspect = 1.0;
2203
2205{
2206 delete osdProvider;
2207 osdProvider = this;
2208}
2209
2211{
2212 osdProvider = NULL;
2213}
2214
2215cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level)
2216{
2217 cMutexLock MutexLock(&cOsd::mutex);
2218 if (Level == OSD_LEVEL_DEFAULT && cOsd::IsOpen())
2219 esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
2220 else if (osdProvider) {
2221 cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL;
2222 cOsd *Osd = osdProvider->CreateOsd(Left, Top, Level);
2223 if (Osd == cOsd::Osds[0]) {
2224 if (ActiveOsd)
2225 ActiveOsd->SetActive(false);
2226 Osd->SetActive(true);
2227 }
2228 return Osd;
2229 }
2230 else
2231 esyslog("ERROR: no OSD provider available - using dummy OSD!");
2232 return new cOsd(Left, Top, 999); // create a dummy cOsd, so that access won't result in a segfault
2233}
2234
2236{
2237 int Width;
2238 int Height;
2239 double Aspect;
2240 cMutexLock MutexLock(&cOsd::mutex);
2241 cDevice::PrimaryDevice()->GetOsdSize(Width, Height, Aspect);
2242 if (Width != oldWidth || Height != oldHeight || !DoubleEqual(Aspect, oldAspect) || Force) {
2243 Setup.OSDLeft = int(round(Width * Setup.OSDLeftP));
2244 Setup.OSDTop = int(round(Height * Setup.OSDTopP));
2245 Setup.OSDWidth = min(Width - Setup.OSDLeft, int(round(Width * Setup.OSDWidthP))) & ~0x07; // OSD width must be a multiple of 8
2246 Setup.OSDHeight = min(Height - Setup.OSDTop, int(round(Height * Setup.OSDHeightP)));
2247 Setup.OSDAspect = Aspect;
2248 Setup.FontOsdSize = int(round(Height * Setup.FontOsdSizeP));
2249 Setup.FontFixSize = int(round(Height * Setup.FontFixSizeP));
2250 Setup.FontSmlSize = int(round(Height * Setup.FontSmlSizeP));
2254 oldWidth = Width;
2255 oldHeight = Height;
2256 oldAspect = Aspect;
2257 dsyslog("OSD size changed to %dx%d @ %g", Width, Height, Aspect);
2258 osdState++;
2259 }
2260}
2261
2263{
2264 cMutexLock MutexLock(&cOsd::mutex);
2265 bool Result = osdState != State;
2266 State = osdState;
2267 return Result;
2268}
2269
2271{
2272 if (osdProvider) {
2274 }
2275 else
2276 esyslog("ERROR: no OSD provider available in call to SupportsTrueColor()");
2277 return false;
2278}
2279
2281{
2283 for (int i = 1; i < MAXOSDIMAGES; i++) {
2284 if (!images[i]) {
2285 images[i] = new cImage(Image);
2286 return i;
2287 }
2288 }
2289 return 0;
2290}
2291
2292void cOsdProvider::DropImageData(int ImageHandle)
2293{
2295 if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES) {
2296 delete images[ImageHandle];
2297 images[ImageHandle] = NULL;
2298 }
2299}
2300
2301const cImage *cOsdProvider::GetImageData(int ImageHandle)
2302{
2304 if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES)
2305 return images[ImageHandle];
2306 return NULL;
2307}
2308
2310{
2311 if (osdProvider)
2312 return osdProvider->StoreImageData(Image);
2313 return 0;
2314}
2315
2316void cOsdProvider::DropImage(int ImageHandle)
2317{
2318 if (osdProvider)
2319 osdProvider->DropImageData(ImageHandle);
2320}
2321
2323{
2324 delete osdProvider;
2325 osdProvider = NULL;
2326}
2327
2328// --- cTextScroller ---------------------------------------------------------
2329
2331{
2332 osd = NULL;
2333 left = top = width = height = 0;
2334 font = NULL;
2335 colorFg = 0;
2336 colorBg = 0;
2337 offset = 0;
2338 shown = 0;
2339}
2340
2341cTextScroller::cTextScroller(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2342{
2343 Set(Osd, Left, Top, Width, Height, Text, Font, ColorFg, ColorBg);
2344}
2345
2346void cTextScroller::Set(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2347{
2348 osd = Osd;
2349 left = Left;
2350 top = Top;
2351 width = Width;
2352 height = Height;
2353 font = Font;
2354 colorFg = ColorFg;
2355 colorBg = ColorBg;
2356 offset = 0;
2357 textWrapper.Set(Text, Font, Width);
2358 shown = min(Total(), height / font->Height());
2359 height = shown * font->Height(); // sets height to the actually used height, which may be less than Height
2360 DrawText();
2361}
2362
2364{
2365 osd = NULL; // just makes sure it won't draw anything
2366}
2367
2369{
2370 if (osd) {
2371 for (int i = 0; i < shown; i++)
2373 }
2374}
2375
2376void cTextScroller::Scroll(bool Up, bool Page)
2377{
2378 if (Up) {
2379 if (CanScrollUp()) {
2380 offset -= Page ? shown : 1;
2381 if (offset < 0)
2382 offset = 0;
2383 DrawText();
2384 }
2385 }
2386 else {
2387 if (CanScrollDown()) {
2388 offset += Page ? shown : 1;
2389 if (offset + shown > Total())
2390 offset = Total() - shown;
2391 DrawText();
2392 }
2393 }
2394}
Definition osd.h:169
int y0
Definition osd.h:172
void ShrinkBpp(int NewBpp)
Shrinks the color depth of the bitmap to NewBpp by keeping only the 2^NewBpp most frequently used col...
Definition osd.c:796
int dirtyY2
Definition osd.h:174
int width
Definition osd.h:173
void ReduceBpp(const cPalette &Palette)
Reduces the color depth of the bitmap to that of the given Palette.
Definition osd.c:765
int Height(void) const
Definition osd.h:189
int height
Definition osd.h:173
bool Dirty(int &x1, int &y1, int &x2, int &y2)
Tells whether there is a dirty area and returns the bounding rectangle of that area (relative to the ...
Definition osd.c:342
cBitmap * Scaled(double FactorX, double FactorY, bool AntiAlias=false) const
Creates a copy of this bitmap, scaled by the given factors.
Definition osd.c:838
int X0(void) const
Definition osd.h:186
void DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
Draws a "slope" into the rectangle defined by the upper left (x1, y1) and lower right (x2,...
Definition osd.c:727
tColor GetColor(int x, int y) const
Returns the color at the given coordinates.
Definition osd.h:277
bool Contains(int x, int y) const
Returns true if this bitmap contains the point (x, y).
Definition osd.c:317
void SetIndex(int x, int y, tIndex Index)
Sets the index at the given coordinates to Index.
Definition osd.c:500
void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
Draws a filled rectangle defined by the upper left (x1, y1) and lower right (x2, y2) corners with the...
Definition osd.c:611
void DrawPixel(int x, int y, tColor Color)
Sets the pixel at the given coordinates to the given Color, which is a full 32 bit ARGB value.
Definition osd.c:526
bool Covers(int x1, int y1, int x2, int y2) const
Returns true if the rectangle defined by the given coordinates completely covers this bitmap.
Definition osd.c:324
void Clean(void)
Marks the dirty area as clean.
Definition osd.c:354
int dirtyX1
Definition osd.h:174
tIndex * bitmap
Definition osd.h:171
void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg=0, tColor ColorBg=0, bool ReplacePalette=false, bool Overlay=false)
Sets the pixels in this bitmap with the data from the given Bitmap, putting the upper left corner of ...
Definition osd.c:533
void SetSize(int Width, int Height)
Sets the size of this bitmap to the given values.
Definition osd.c:294
void Fill(tIndex Index)
Fills the bitmap data with the given Index.
Definition osd.c:515
int dirtyX2
Definition osd.h:174
int dirtyY1
Definition osd.h:174
void DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width=0, int Height=0, int Alignment=taDefault)
Draws the given string at coordinates (x, y) with the given foreground and background color and font.
Definition osd.c:562
bool SetXpm(const char *const Xpm[], bool IgnoreNone=false)
Sets this bitmap to the given XPM data.
Definition osd.c:428
void DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants=0)
Draws a filled ellipse defined by the upper left (x1, y1) and lower right (x2, y2) corners with the g...
Definition osd.c:632
bool LoadXpm(const char *FileName)
Calls SetXpm() with the data from the file FileName.
Definition osd.c:362
virtual ~cBitmap()
Definition osd.c:289
cBitmap(int Width, int Height, int Bpp, int X0=0, int Y0=0)
Creates a bitmap with the given Width, Height and color depth (Bpp).
Definition osd.c:261
bool Intersects(int x1, int y1, int x2, int y2) const
Returns true if the rectangle defined by the given coordinates intersects with this bitmap.
Definition osd.c:333
int Y0(void) const
Definition osd.h:187
int x0
Definition osd.h:172
int Width(void) const
Definition osd.h:188
const tIndex * Data(int x, int y) const
Returns the address of the index byte at the given coordinates.
Definition osd.c:760
virtual int Width(void) const
Returns the original character width as requested when the font was created, or 0 if the default widt...
Definition skincurses.c:23
virtual int Height(void) const
Returns the height of this font in pixel (all characters have the same height).
Definition skincurses.c:26
virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const
Draws the given text into the Bitmap at position (x, y) with the given colors.
Definition skincurses.c:27
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:148
virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect)
Returns the Width, Height and PixelAspect ratio the OSD should use to best fit the resolution of the ...
Definition device.c:532
Definition font.h:37
virtual int Height(void) const =0
Returns the height of this font in pixel (all characters have the same height).
static void SetFont(eDvbFont Font, const char *Name, int CharHeight)
< Draws the given text into the Pixmap at position (x, y) with the given colors.
Definition font.c:406
Definition osd.h:419
int Height(void) const
Definition osd.h:436
const tColor * Data(void) const
Definition osd.h:437
int Width(void) const
Definition osd.h:435
cImage(void)
Definition osd.c:1104
tColor * data
Definition osd.h:422
const cSize & Size(void) const
Definition osd.h:434
virtual ~cImage()
Definition osd.c:1126
cSize size
Definition osd.h:421
void Clear(void)
Clears the image data by setting all pixels to be fully transparent.
Definition osd.c:1131
void Fill(tColor Color)
Fills the image data with the given Color.
Definition osd.c:1136
cInitAlphaLut(void)
Definition osd.c:63
static int oldHeight
Definition osd.h:969
static int oldWidth
Definition osd.h:968
virtual bool ProvidesTrueColor(void)
Returns true if this OSD provider is able to handle a true color OSD.
Definition osd.h:977
static cImage * images[MAXOSDIMAGES]
Definition osd.h:971
static double oldAspect
Definition osd.h:970
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition osd.c:2262
static void DropImage(int ImageHandle)
Drops the image referenced by the given ImageHandle.
Definition osd.c:2316
virtual ~cOsdProvider()
Definition osd.c:2210
virtual int StoreImageData(const cImage &Image)
Copies the given Image and returns a handle for later reference.
Definition osd.c:2280
virtual cOsd * CreateOsd(int Left, int Top, uint Level)=0
Returns a pointer to a newly created cOsd object, which will be located at the given coordinates.
virtual void DropImageData(int ImageHandle)
Drops the image data referenced by ImageHandle.
Definition osd.c:2292
static cOsdProvider * osdProvider
Definition osd.h:967
static int osdState
Definition osd.h:972
static int StoreImage(const cImage &Image)
Stores the given Image for later use with DrawImage() on an OSD or pixmap.
Definition osd.c:2309
cOsdProvider(void)
Definition osd.c:2204
static void Shutdown(void)
Shuts down the OSD provider facility by deleting the current OSD provider.
Definition osd.c:2322
static void UpdateOsdSize(bool Force=false)
Inquires the actual size of the video display and adjusts the OSD and font sizes accordingly.
Definition osd.c:2235
static const cImage * GetImageData(int ImageHandle)
Gets the image data referenced by ImageHandle.
Definition osd.c:2301
static bool SupportsTrueColor(void)
Returns true if the current OSD provider is able to handle a true color OSD.
Definition osd.c:2270
static cOsd * NewOsd(int Left, int Top, uint Level=OSD_LEVEL_DEFAULT)
Returns a pointer to a newly created cOsd object, which will be located at the given coordinates.
Definition osd.c:2215
The cOsd class is the interface to the "On Screen Display".
Definition osd.h:729
int numBitmaps
Definition osd.h:739
cOsd(int Left, int Top, uint Level)
Initializes the OSD with the given coordinates.
Definition osd.c:1848
virtual eOsdError SetPalette(const cPalette &Palette, int Area)
Sets the Palette for the given Area (the first area is numbered 0).
Definition osd.c:2098
uint level
Definition osd.h:743
virtual const cSize & MaxPixmapSize(void) const
Returns the maximum possible size of a pixmap this OSD can create.
Definition osd.c:1909
int top
Definition osd.h:742
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image on this OSD at the given Point.
Definition osd.c:2109
static int osdHeight
Definition osd.h:732
virtual void SetActive(bool On)
Sets this OSD to be the active one.
Definition osd.h:767
int Width(void)
Definition osd.h:820
bool isTrueColor
Definition osd.h:736
cVector< cPixmap * > pixmaps
Definition osd.h:741
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas)
Sets the sub-areas to the given areas.
Definition osd.c:2029
virtual void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg=0, tColor ColorBg=0, bool ReplacePalette=false, bool Overlay=false)
Sets the pixels in the OSD with the data from the given Bitmap, putting the upper left corner of the ...
Definition osd.c:2131
virtual void DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants=0)
Draws a filled ellipse defined by the upper left (x1, y1) and lower right (x2, y2) corners with the g...
Definition osd.c:2171
cBitmap * GetBitmap(int Area)
Returns a pointer to the bitmap for the given Area, or NULL if no such bitmap exists.
Definition osd.c:1904
virtual void DestroyPixmap(cPixmap *Pixmap)
Destroys the given Pixmap, which has previously been created by a call to CreatePixmap().
Definition osd.c:1926
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
Allows the system to optimize utilization of the limited color palette entries when generating blende...
Definition osd.c:1896
virtual void DrawPixel(int x, int y, tColor Color)
Sets the pixel at the given coordinates to the given Color, which is a full 32 bit ARGB value.
Definition osd.c:2121
bool active
Definition osd.h:744
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas)
Checks whether the OSD can display the given set of sub-areas.
Definition osd.c:2007
static int osdWidth
Definition osd.h:732
cPixmap * AddPixmap(cPixmap *Pixmap)
Adds the given Pixmap to the list of currently active pixmaps in this OSD.
Definition osd.c:1943
cPixmap * RenderPixmaps(void)
Renders the dirty part of all pixmaps into a resulting pixmap that shall be displayed on the OSD.
Definition osd.c:1956
static int osdLeft
Definition osd.h:732
virtual cPixmap * CreatePixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort=cRect::Null)
Creates a new true color pixmap on this OSD (see cPixmap for details).
Definition osd.c:1914
static void SetOsdPosition(int Left, int Top, int Width, int Height)
Sets the position and size of the OSD to the given values.
Definition osd.c:1888
virtual void SaveRegion(int x1, int y1, int x2, int y2)
Saves the region defined by the given coordinates for later restoration through RestoreRegion().
Definition osd.c:2064
virtual void DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias=false)
Sets the pixels in the OSD with the data from the given Bitmap, putting the upper left corner of the ...
Definition osd.c:2141
virtual void Flush(void)
Actually commits all data to the OSD hardware.
Definition osd.c:2191
virtual void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
Draws a filled rectangle defined by the upper left (x1, y1) and lower right (x2, y2) corners with the...
Definition osd.c:2161
int Left(void)
Definition osd.h:818
cBitmap * bitmaps[MAXOSDAREAS]
Definition osd.h:738
virtual void DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
Draws a "slope" into the rectangle defined by the upper left (x1, y1) and lower right (x2,...
Definition osd.c:2181
static cMutex mutex
Definition osd.h:735
int left
Definition osd.h:742
cPixmapMemory * savedPixmap
Definition osd.h:740
int height
Definition osd.h:742
static int osdTop
Definition osd.h:732
int Top(void)
Definition osd.h:819
virtual void RestoreRegion(void)
Restores the region previously saved by a call to SaveRegion().
Definition osd.c:2080
static cVector< cOsd * > Osds
Definition osd.h:733
cBitmap * savedBitmap
Definition osd.h:737
static cSize maxPixmapSize
Definition osd.h:734
virtual ~cOsd()
Shuts down the OSD.
Definition osd.c:1869
int width
Definition osd.h:742
int Height(void)
Definition osd.h:821
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition osd.h:813
virtual void DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width=0, int Height=0, int Alignment=taDefault)
Draws the given string at coordinates (x, y) with the given foreground and background color and font.
Definition osd.c:2151
Definition osd.h:88
tColor Color(int Index) const
Returns the color at the given Index.
Definition osd.h:119
tColor Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) const
Determines a color that consists of a linear blend between ColorFg and ColorBg.
Definition osd.c:216
void Reset(void)
Resets the palette, making it contain no colors.
Definition osd.c:138
void Replace(const cPalette &Palette)
Replaces the colors of this palette with the colors from the given palette.
Definition osd.c:208
const tColor * Colors(int &NumColors) const
Returns a pointer to the complete color table and stores the number of valid entries in NumColors.
Definition osd.c:185
int maxColors
Definition osd.h:92
virtual ~cPalette()
Definition osd.c:123
bool modified
Definition osd.h:93
tIndex tIndexes[MAXNUMCOLORS]
Definition osd.h:96
int bpp
Definition osd.h:91
void SetBpp(int Bpp)
Sets the color depth of this palette to the given value.
Definition osd.c:165
void SetColor(int Index, tColor Color)
Sets the palette entry at Index to Color.
Definition osd.c:172
tColor color[MAXNUMCOLORS]
Definition osd.h:90
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
Allows the system to optimize utilization of the limited color palette entries when generating blende...
Definition osd.c:127
int Index(tColor Color)
Returns the index of the given Color (the first color has index 0).
Definition osd.c:144
int ClosestColor(tColor Color, int MaxDiff=INT_MAX) const
Returns the index of a color in this palette that is closest to the given Color.
Definition osd.c:235
int numColors
Definition osd.h:92
cPalette(int Bpp=8)
Initializes the palette with the given color depth.
Definition osd.c:117
double antiAliasGranularity
Definition osd.h:94
int Bpp(void) const
Definition osd.h:111
void Take(const cPalette &Palette, tIndexes *Indexes=NULL, tColor ColorFg=0, tColor ColorBg=0)
Takes the colors from the given Palette and adds them to this palette, using existing entries if poss...
Definition osd.c:191
virtual void Pan(const cPoint &Dest, const cRect &Source=cRect::Null)
Does the same as Scroll(), but also shifts the draw port accordingly, so that the view port doesn't g...
Definition osd.c:1817
virtual void Scroll(const cPoint &Dest, const cRect &Source=cRect::Null)
Scrolls the data in the pixmap's draw port to the given Dest point.
Definition osd.c:1783
virtual void Clear(void)
Clears the pixmap's draw port by setting all pixels to be fully transparent.
Definition osd.c:1162
bool panning
Definition osd.h:693
virtual void Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
Copies the part of the given Pixmap covered by Source into this pixmap at location Dest.
Definition osd.c:1756
cPixmapMemory(void)
Definition osd.c:1144
virtual ~cPixmapMemory()
Definition osd.c:1157
virtual void Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
Renders the part of the given Pixmap covered by Source into this pixmap at location Dest.
Definition osd.c:1721
virtual void DrawBlendedPixel(const cPoint &Point, tColor Color, uint8_t AlphaLayer=ALPHA_OPAQUE)
Like DrawPixel(), but with an additional AlphaLayer, and works on any pixmap, not only the background...
Definition osd.c:1276
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type)
Draws a "slope" with the given Color into the given rectangle.
Definition osd.c:1621
virtual void DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg=0, tColor ColorBg=0, bool Overlay=false)
Sets the pixels in the OSD with the data from the given Bitmap, putting the upper left corner of the ...
Definition osd.c:1294
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image into this pixmap at the given Point.
Definition osd.c:1230
virtual void DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width=0, int Height=0, int Alignment=taDefault)
Draws the given string at Point with the given foreground and background color and font.
Definition osd.c:1321
virtual void Fill(tColor Color)
Fills the pixmap's draw port with the given Color.
Definition osd.c:1170
virtual void DrawEllipse(const cRect &Rect, tColor Color, int Quadrants=0)
Draws a filled ellipse with the given Color that fits into the given rectangle.
Definition osd.c:1397
tColor * data
Definition osd.h:692
virtual void DrawPixel(const cPoint &Point, tColor Color)
Sets the pixel at the given Point to the given Color, which is a full 32 bit ARGB value.
Definition osd.c:1262
virtual void DrawRectangle(const cRect &Rect, tColor Color)
Draws a filled rectangle with the given Color.
Definition osd.c:1370
Definition osd.h:454
virtual void DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
Draws the Dirty part of the given Pixmap into this pixmap.
Definition osd.c:1179
bool Tile(void) const
Definition osd.h:538
const cRect & DrawPort(void) const
Returns the pixmap's draw port, which is relative to the view port.
Definition osd.h:543
int alpha
Definition osd.h:460
virtual void SetViewPort(const cRect &Rect)
Sets the pixmap's view port to the given Rect.
Definition osd.c:1068
cPixmap(void)
Definition osd.c:962
static void Unlock(void)
Definition osd.h:535
virtual void Clear(void)=0
Clears the pixmap's draw port by setting all pixels to be fully transparent.
void MarkViewPortDirty(const cRect &Rect)
Marks the given rectangle of the view port of this pixmap as dirty.
Definition osd.c:987
cRect dirtyDrawPort
Definition osd.h:465
cRect viewPort
Definition osd.h:462
const cRect & ViewPort(void) const
Returns the pixmap's view port, which is relative to the OSD's origin.
Definition osd.h:539
int Alpha(void) const
Definition osd.h:537
virtual void SetDrawPortPoint(const cPoint &Point, bool Dirty=true)
Sets the pixmap's draw port to the given Point.
Definition osd.c:1085
static void Lock(void)
All public member functions of cPixmap set locks as necessary to make sure they are thread-safe (unle...
Definition osd.h:529
static cMutex mutex
Definition osd.h:458
virtual void SetLayer(int Layer)
Sets the layer of this pixmap to the given value.
Definition osd.c:1024
void MarkDrawPortDirty(const cRect &Rect)
Marks the given rectangle of the draw port of this pixmap as dirty.
Definition osd.c:999
void SetClean(void)
Resets the "dirty" rectangles of this pixmap.
Definition osd.c:1019
virtual void Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)=0
Copies the part of the given Pixmap covered by Source into this pixmap at location Dest.
bool tile
Definition osd.h:461
cRect dirtyViewPort
Definition osd.h:464
virtual void Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)=0
Renders the part of the given Pixmap covered by Source into this pixmap at location Dest.
virtual void SetAlpha(int Alpha)
Sets the alpha value of this pixmap to the given value.
Definition osd.c:1046
int layer
Definition osd.h:459
cRect drawPort
Definition osd.h:463
virtual void SetTile(bool Tile)
Sets the tile property of this pixmap to the given value.
Definition osd.c:1057
int Layer(void) const
Definition osd.h:536
Definition osd.h:306
int Y(void) const
Definition osd.h:319
int X(void) const
Definition osd.h:318
void SetX(int X)
Definition osd.h:320
cPoint Shifted(int Dx, int Dy) const
Definition osd.h:326
void Shift(int Dx, int Dy)
Definition osd.h:324
char * Read(FILE *f)
Definition tools.c:1481
Definition osd.h:352
static const cRect Null
Definition osd.h:357
void Combine(const cRect &Rect)
Combines this rectangle with the given Rect.
Definition osd.c:934
int Top(void) const
Definition osd.h:370
cSize size
Definition osd.h:355
const cPoint & Point(void) const
Definition osd.h:373
bool Intersects(const cRect &Rect) const
Returns true if this rectangle intersects with Rect.
Definition osd.c:914
bool Contains(const cPoint &Point) const
Returns true if this rectangle contains Point.
Definition osd.c:898
void SetPoint(int X, int Y)
Definition osd.h:377
cRect Intersected(const cRect &Rect) const
Returns the intersection of this rectangle and the given Rect.
Definition osd.c:922
int Height(void) const
Definition osd.h:368
int Left(void) const
Definition osd.h:369
int Bottom(void) const
Definition osd.h:372
void SetRight(int Right)
Definition osd.h:387
void Grow(int Dx, int Dy)
Grows the rectangle by the given number of pixels in either direction.
Definition osd.c:892
int Right(void) const
Definition osd.h:371
void SetTop(int Top)
Definition osd.h:386
void SetLeft(int Left)
Definition osd.h:385
cRect Shifted(int Dx, int Dy) const
Definition osd.h:391
void SetBottom(int Bottom)
Definition osd.h:388
cPoint point
Definition osd.h:354
void Shift(int Dx, int Dy)
Definition osd.h:389
int Width(void) const
Definition osd.h:367
const cSize & Size(void) const
Definition osd.h:374
bool IsEmpty(void) const
Returns true if this rectangle is empty.
Definition osd.h:415
void Set(int X, int Y, int Width, int Height)
Definition osd.h:375
int AntiAlias
Definition config.h:334
int FontFixSize
Definition config.h:343
int OSDHeight
Definition config.h:330
double OSDAspect
Definition config.h:331
double OSDWidthP
Definition config.h:329
double OSDHeightP
Definition config.h:329
double FontOsdSizeP
Definition config.h:338
int FontOsdSize
Definition config.h:341
int FontSmlSize
Definition config.h:342
int OSDTop
Definition config.h:330
double FontFixSizeP
Definition config.h:340
double OSDLeftP
Definition config.h:329
double FontSmlSizeP
Definition config.h:339
int OSDLeft
Definition config.h:330
char FontOsd[MAXFONTNAME]
Definition config.h:335
int OSDWidth
Definition config.h:330
char FontSml[MAXFONTNAME]
Definition config.h:336
double OSDTopP
Definition config.h:329
char FontFix[MAXFONTNAME]
Definition config.h:337
Definition osd.h:330
void Grow(int Dw, int Dh)
Definition osd.h:348
int Height(void) const
Definition osd.h:342
int Width(void) const
Definition osd.h:341
int Height(void)
Definition osd.h:1051
tColor colorBg
Definition osd.h:1039
int Left(void)
Definition osd.h:1048
void DrawText(void)
Definition osd.c:2368
int shown
Definition osd.h:1040
int Total(void)
Definition osd.h:1052
int height
Definition osd.h:1037
cTextWrapper textWrapper
Definition osd.h:1041
const cFont * font
Definition osd.h:1038
cTextScroller(void)
Definition osd.c:2330
void Scroll(bool Up, bool Page)
Definition osd.c:2376
int Top(void)
Definition osd.h:1049
void Set(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
Definition osd.c:2346
void Reset(void)
Definition osd.c:2363
tColor colorFg
Definition osd.h:1039
int width
Definition osd.h:1037
cOsd * osd
Definition osd.h:1036
bool CanScrollDown(void)
Definition osd.h:1057
int offset
Definition osd.h:1040
int Width(void)
Definition osd.h:1050
bool CanScrollUp(void)
Definition osd.h:1056
const char * GetLine(int Line)
Returns the given Line. The first line is numbered 0.
Definition font.c:638
void Set(const char *Text, const cFont *Font, int Width)
Wraps the Text to make it fit into the area defined by the given Width when displayed with the given ...
Definition font.c:566
int Size(void) const
Definition tools.h:764
virtual void Insert(T Data, int Before=0)
Definition tools.h:765
virtual void Append(T Data)
Definition tools.h:784
virtual void Remove(int Index)
Definition tools.h:798
cSetup Setup
Definition config.c:372
#define MINOSDHEIGHT
Definition config.h:63
#define MINOSDWIDTH
Definition config.h:61
#define MAXOSDWIDTH
Definition config.h:62
#define MAXOSDHEIGHT
Definition config.h:64
@ fontOsd
Definition font.h:22
@ fontFix
Definition font.h:23
uint32_t tColor
Definition font.h:30
static uint16_t AlphaLutFactors[255][256][2]
Definition osd.c:58
tColor AlphaBlend(tColor ColorFg, tColor ColorBg, uint8_t AlphaLayer)
Definition osd.c:81
tColor RgbShade(tColor Color, double Factor)
Returns a brighter (Factor > 0) or darker (Factor < 0) version of the given Color.
Definition osd.c:43
class cInitAlphaLut InitAlphaLut
static uint8_t AlphaLutAlpha[255][256]
Definition osd.c:59
static const char * OsdErrorTexts[]
Definition osd.c:1828
tColor HsvToColor(double H, double S, double V)
Converts the given Hue (0..360), Saturation (0..1) and Value (0..1) to an RGB tColor value.
Definition osd.c:19
#define ALPHA_TRANSPARENT
Definition osd.h:25
#define ALPHA_OPAQUE
Definition osd.h:26
tColor AlphaBlend(tColor ColorFg, tColor ColorBg, uint8_t AlphaLayer=ALPHA_OPAQUE)
Definition osd.c:81
@ taBorder
Definition osd.h:163
@ taTop
Definition osd.h:161
@ taBottom
Definition osd.h:162
@ taRight
Definition osd.h:160
@ taLeft
Definition osd.h:159
#define MAXNUMCOLORS
Definition osd.h:24
#define MAXPIXMAPLAYERS
Definition osd.h:452
eOsdError
Definition osd.h:44
@ oeUnknown
Definition osd.h:52
@ oeTooManyAreas
Definition osd.h:45
@ oeAreasOverlap
Definition osd.h:48
@ oeOutOfMemory
Definition osd.h:50
@ oeWrongAlignment
Definition osd.h:49
@ oeOk
Definition osd.h:44
tColor RgbToColor(uint8_t R, uint8_t G, uint8_t B)
Definition osd.h:63
#define OSD_LEVEL_DEFAULT
Definition osd.h:21
@ clrTransparent
Definition osd.h:32
#define LOCK_PIXMAPS
Definition osd.h:685
#define MAXOSDAREAS
Definition osd.h:716
#define TEXT_ALIGN_BORDER
Definition osd.h:28
#define MAXOSDIMAGES
Definition osd.h:962
#define IS_OPAQUE(c)
Definition osd.h:27
uint32_t tColor
Definition osd.h:55
uint8_t tIndex
Definition osd.h:56
static const cCursesFont Font
Definition skincurses.c:31
Definition osd.h:298
int bpp
Definition osd.h:300
int x2
Definition osd.h:299
int y1
Definition osd.h:299
int x1
Definition osd.h:299
int y2
Definition osd.h:299
T constrain(T v, T l, T h)
Definition tools.h:70
#define dsyslog(a...)
Definition tools.h:37
#define MALLOC(type, size)
Definition tools.h:47
char * skipspace(const char *s)
Definition tools.h:241
bool DoubleEqual(double a, double b)
Definition tools.h:97
T min(T a, T b)
Definition tools.h:63
T max(T a, T b)
Definition tools.h:64
#define esyslog(a...)
Definition tools.h:35