vdr 2.7.3
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 5.2 2024/01/18 12:04:57 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
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
1142cImage *cImage::Scaled(double FactorX, double FactorY, bool AntiAlias) const
1143{
1144 int w = max(1, int(round(Width() * FactorX)));
1145 int h = max(1, int(round(Height() * FactorY)));
1146 cImage *i = new cImage(cSize(w, h));
1147 int RatioX = (Width() << 16) / i->Width();
1148 int RatioY = (Height() << 16) / i->Height();
1149
1150 if (!AntiAlias || FactorX <= 1.0 && FactorY <= 1.0) {
1151 // Downscaling - no anti-aliasing:
1152 int SourceY = 0;
1153 for (int y = 0; y < i->Height(); y++) {
1154 int SourceX = 0;
1155 for (int x = 0; x < i->Width(); x++) {
1156 tColor c1 = GetPixel(cPoint(SourceX >> 16, SourceY >> 16));
1157 i->SetPixel(cPoint(x, y), c1);
1158 SourceX += RatioX;
1159 }
1160 SourceY += RatioY;
1161 }
1162 }
1163 else {
1164 // Upscaling - anti-aliasing:
1165 int SourceY = 0;
1166 for (int y = 0; y < i->Height(); y++) {
1167 int SourceX = 0;
1168 int sy = min(SourceY >> 16, Height() - 2);
1169 uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF);
1170 for (int x = 0; x < i->Width(); x++) {
1171 int sx = min(SourceX >> 16, Width() - 2);
1172 uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF);
1173 tColor c1 = AlphaBlend(GetPixel(cPoint(sx, sy)), GetPixel(cPoint(sx + 1, sy)), BlendX);
1174 tColor c2 = AlphaBlend(GetPixel(cPoint(sx, sy + 1)), GetPixel(cPoint(sx + 1, sy + 1)), BlendX);
1175 tColor c3 = AlphaBlend(c1, c2, BlendY);
1176 i->SetPixel(cPoint(x, y), c3);
1177 SourceX += RatioX;
1178 }
1179 SourceY += RatioY;
1180 }
1181 }
1182 return i;
1183}
1184
1185// --- cPixmapMemory ---------------------------------------------------------
1186
1188{
1189 data = NULL;
1190 panning = false;
1191}
1192
1193cPixmapMemory::cPixmapMemory(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1194:cPixmap(Layer, ViewPort, DrawPort)
1195{
1196 data = MALLOC(tColor, this->DrawPort().Width() * this->DrawPort().Height());
1197 panning = false;
1198}
1199
1201{
1202 free(data);
1203}
1204
1206{
1207 Lock();
1208 memset(data, 0x00, DrawPort().Width() * DrawPort().Height() * sizeof(tColor));
1210 Unlock();
1211}
1212
1214{
1215 Lock();
1216 for (int i = DrawPort().Width() * DrawPort().Height() - 1; i >= 0; i--)
1217 data[i] = Color;
1219 Unlock();
1220}
1221
1222void cPixmap::DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
1223{
1224 if (Pixmap->Tile() && (Pixmap->DrawPort().Point() != cPoint(0, 0) || Pixmap->DrawPort().Size() < Pixmap->ViewPort().Size())) {
1225 cPoint t0 = Pixmap->DrawPort().Point().Shifted(Pixmap->ViewPort().Point()); // the origin of the draw port in absolute OSD coordinates
1226 // Find the top/leftmost location where the draw port touches the view port:
1227 while (t0.X() > Pixmap->ViewPort().Left())
1228 t0.Shift(-Pixmap->DrawPort().Width(), 0);
1229 while (t0.Y() > Pixmap->ViewPort().Top())
1230 t0.Shift(0, -Pixmap->DrawPort().Height());
1231 cPoint t = t0;
1232 while (t.Y() <= Pixmap->ViewPort().Bottom()) {
1233 while (t.X() <= Pixmap->ViewPort().Right()) {
1234 cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1235 Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1236 cPoint Delta = Source.Point() - t;
1237 Source.SetPoint(t); // Source is now where the pixmap's data shall be drawn
1238 Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1239 Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1240 if (!Source.IsEmpty()) {
1241 cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1242 Source.Shift(Delta); // Source is now back at the pixmap's draw port location, still in absolute OSD coordinates
1243 Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's view port again
1244 Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1245 if (Pixmap->Layer() == 0)
1246 Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1247 else
1248 Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1249 }
1250 t.Shift(Pixmap->DrawPort().Width(), 0); // increase one draw port width to the right
1251 }
1252 t.SetX(t0.X()); // go back to the leftmost position
1253 t.Shift(0, Pixmap->DrawPort().Height()); // increase one draw port height down
1254 }
1255 }
1256 else {
1257 cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1258 Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1259 Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1260 Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1261 if (!Source.IsEmpty()) {
1262 cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1263 Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's draw port again
1264 Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1265 if (Pixmap->Layer() == 0)
1266 Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1267 else
1268 Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1269 }
1270 }
1271}
1272
1273void cPixmapMemory::DrawImage(const cPoint &Point, const cImage &Image)
1274{
1275 Lock();
1276 cRect r = cRect(Point, Image.Size()).Intersected(DrawPort().Size());
1277 if (!r.IsEmpty()) {
1278 int ws = Image.Size().Width();
1279 int wd = DrawPort().Width();
1280 int w = r.Width() * sizeof(tColor);
1281 const tColor *ps = Image.Data();
1282 if (Point.Y() < 0)
1283 ps -= Point.Y() * ws;
1284 if (Point.X() < 0)
1285 ps -= Point.X();
1286 tColor *pd = data + wd * r.Top() + r.Left();
1287 for (int y = r.Height(); y-- > 0; ) {
1288 memcpy(pd, ps, w);
1289 ps += ws;
1290 pd += wd;
1291 }
1293 }
1294 Unlock();
1295}
1296
1297void cPixmapMemory::DrawImage(const cPoint &Point, int ImageHandle)
1298{
1299 Lock();
1300 if (const cImage *Image = cOsdProvider::GetImageData(ImageHandle))
1301 DrawImage(Point, *Image);
1302 Unlock();
1303}
1304
1305void cPixmapMemory::DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias)
1306{
1307 Lock();
1308 const cImage *i = &Image;
1309 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0))
1310 i = i->Scaled(FactorX, FactorY, AntiAlias);
1311 DrawImage(Point, *i);
1312 if (i != &Image)
1313 delete i;
1314 Unlock();
1315}
1316
1317void cPixmapMemory::DrawScaledImage(const cPoint &Point, int ImageHandle, double FactorX, double FactorY, bool AntiAlias)
1318{
1319 Lock();
1320 if (const cImage *Image = cOsdProvider::GetImageData(ImageHandle))
1321 DrawScaledImage(Point, *Image, FactorX, FactorY, AntiAlias);
1322 Unlock();
1323}
1324
1325void cPixmapMemory::DrawPixel(const cPoint &Point, tColor Color)
1326{
1327 Lock();
1328 if (DrawPort().Size().Contains(Point)) {
1329 int p = Point.Y() * DrawPort().Width() + Point.X();
1330 if (Layer() == 0 && !IS_OPAQUE(Color))
1331 data[p] = AlphaBlend(Color, data[p]);
1332 else
1333 data[p] = Color;
1334 MarkDrawPortDirty(Point);
1335 }
1336 Unlock();
1337}
1338
1339void cPixmapMemory::DrawBlendedPixel(const cPoint &Point, tColor Color, uint8_t Alpha)
1340{
1341 Lock();
1342 if (DrawPort().Size().Contains(Point)) {
1343 int p = Point.Y() * DrawPort().Width() + Point.X();
1344 if (Alpha != ALPHA_OPAQUE) {
1345 if (Color == clrTransparent)
1346 data[p] = (data[p] & 0x00FFFFFF) | ((((data[p] >> 24) * (255 - Alpha)) << 16) & 0xFF000000);
1347 else
1348 data[p] = AlphaBlend(Color, data[p], Alpha);
1349 }
1350 else
1351 data[p] = Color;
1352 MarkDrawPortDirty(Point);
1353 }
1354 Unlock();
1355}
1356
1357void cPixmapMemory::DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay)
1358{
1359 Lock();
1360 cRect r = cRect(Point, cSize(Bitmap.Width(), Bitmap.Height())).Intersected(DrawPort().Size());
1361 if (!r.IsEmpty()) {
1362 bool UseColors = ColorFg || ColorBg;
1363 int wd = DrawPort().Width();
1364 tColor *pd = data + wd * r.Top() + r.Left();
1365 for (int y = r.Top(); y <= r.Bottom(); y++) {
1366 tColor *cd = pd;
1367 for (int x = r.Left(); x <= r.Right(); x++) {
1368 tIndex Index = *Bitmap.Data(x - Point.X(), y - Point.Y());
1369 if (Index || !Overlay) {
1370 if (UseColors)
1371 *cd = Index ? ColorFg : ColorBg;
1372 else
1373 *cd = Bitmap.Color(Index);
1374 }
1375 cd++;
1376 }
1377 pd += wd;
1378 }
1380 }
1381 Unlock();
1382}
1383
1384void cPixmapMemory::DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
1385{
1386 Lock();
1387 int x = Point.X();
1388 int y = Point.Y();
1389 int w = Font->Width(s);
1390 int h = Font->Height();
1391 int limit = 0;
1392 int cw = Width ? Width : w;
1393 int ch = Height ? Height : h;
1394 cRect r(x, y, cw, ch);
1395 if (ColorBg != clrTransparent)
1396 DrawRectangle(r, ColorBg);
1397 if (Width || Height) {
1398 limit = x + cw;
1399 if (Width) {
1400 if ((Alignment & taLeft) != 0) {
1401 if ((Alignment & taBorder) != 0)
1402 x += max(h / TEXT_ALIGN_BORDER, 1);
1403 }
1404 else if ((Alignment & taRight) != 0) {
1405 if (w < Width)
1406 x += Width - w;
1407 if ((Alignment & taBorder) != 0)
1408 x -= max(h / TEXT_ALIGN_BORDER, 1);
1409 }
1410 else { // taCentered
1411 if (w < Width)
1412 x += (Width - w) / 2;
1413 }
1414 }
1415 if (Height) {
1416 if ((Alignment & taTop) != 0)
1417 ;
1418 else if ((Alignment & taBottom) != 0) {
1419 if (h < Height)
1420 y += Height - h;
1421 }
1422 else { // taCentered
1423 if (h < Height)
1424 y += (Height - h) / 2;
1425 }
1426 }
1427 }
1428 Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
1430 Unlock();
1431}
1432
1434{
1435 Lock();
1436 cRect r = Rect.Intersected(DrawPort().Size());
1437 if (!r.IsEmpty()) {
1438 int wd = DrawPort().Width();
1439 int w = r.Width() * sizeof(tColor);
1440 tColor *ps = NULL;
1441 tColor *pd = data + wd * r.Top() + r.Left();
1442 for (int y = r.Height(); y-- > 0; ) {
1443 if (ps)
1444 memcpy(pd, ps, w); // all other lines are copied fast from the first one
1445 else {
1446 // explicitly fill the first line:
1447 tColor *cd = ps = pd;
1448 for (int x = r.Width(); x-- > 0; ) {
1449 *cd = Color;
1450 cd++;
1451 }
1452 }
1453 pd += wd;
1454 }
1456 }
1457 Unlock();
1458}
1459
1460void cPixmapMemory::DrawEllipse(const cRect &Rect, tColor Color, int Quadrants)
1461{
1462 Lock();
1463 // Algorithm based on https://dai.fmph.uniba.sk/upload/0/01/Ellipse.pdf
1464 int x1 = Rect.Left();
1465 int y1 = Rect.Top();
1466 int x2 = Rect.Right();
1467 int y2 = Rect.Bottom();
1468 int rx = x2 - x1;
1469 int ry = y2 - y1;
1470 int ax = rx & 0x01; // alignment to make semi-circles match rectangles of same size
1471 int ay = ry & 0x01;
1472 int cx = (x1 + x2) / 2;
1473 int cy = (y1 + y2) / 2;
1474 switch (abs(Quadrants)) {
1475 case 0: rx /= 2; ry /= 2; break;
1476 case 1: cx = x1; cy = y2; break;
1477 case 2: cx = x2; cy = y2; break;
1478 case 3: cx = x2; cy = y1; break;
1479 case 4: cx = x1; cy = y1; break;
1480 case 5: cx = x1; ry /= 2; break;
1481 case 6: cy = y2; rx /= 2; break;
1482 case 7: cx = x2; ry /= 2; break;
1483 case 8: cy = y1; rx /= 2; break;
1484 default: ;
1485 }
1486 int TwoASquare = max(1, 2 * rx * rx);
1487 int TwoBSquare = max(1, 2 * ry * ry);
1488 int x = rx;
1489 int y = 0;
1490 int XChange = ry * ry * (1 - 2 * rx);
1491 int YChange = rx * rx;
1492 int EllipseError = 0;
1493 int StoppingX = TwoBSquare * rx;
1494 int StoppingY = 0;
1495 int Delta = 0;
1496 bool AntiAliased = Setup.AntiAlias;
1497 while (StoppingX >= StoppingY) {
1498 if (!AntiAliased) {
1499 switch (Quadrants) {
1500 case 5: DrawRectangle(cRect(cx, cy + y + ay, x + 1, 1), Color); // no break
1501 case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1502 case 7: DrawRectangle(cRect(cx - x, cy + y + ay, x + 1, 1), Color); // no break
1503 case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1504 case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1505 case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1506 case 0:
1507 case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + ax + 1, 1), Color); if (Quadrants == 6) break;
1508 case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + ax + 1, 1), Color); break;
1509 case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1510 case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1511 case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1512 case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1513 default: ;
1514 }
1515 }
1516 else {
1517 uint8_t intensity = abs(255 * (long int)EllipseError / XChange);
1518 if (EllipseError >= 0) {
1519 intensity = 255 - intensity;
1520 Delta = 0;
1521 }
1522 else
1523 Delta = 1;
1524 switch (Quadrants) {
1525 case 5: DrawRectangle( cRect( cx, cy + y + ay, x + Delta, 1), Color);
1526 DrawBlendedPixel(cPoint(cx + x + Delta, cy + y + ay), Color, intensity);
1527 // no break
1528 case 1: DrawRectangle( cRect( cx, cy - y, x + Delta, 1), Color);
1529 DrawBlendedPixel(cPoint(cx + x + Delta, cy - y), Color, intensity);
1530 break;
1531 case 7: DrawRectangle( cRect( cx - x + 1 - Delta, cy + ay + y, x + Delta, 1), Color);
1532 DrawBlendedPixel(cPoint(cx - x - Delta, cy + ay + y), Color, intensity);
1533 // no break
1534 case 2: DrawRectangle( cRect( cx - x + 1 - Delta, cy - y, x + Delta, 1), Color);
1535 DrawBlendedPixel(cPoint(cx - x - Delta, cy - y), Color, intensity);
1536 break;
1537 case 3: DrawRectangle( cRect( cx - x + 1 - Delta, cy + y, x + Delta, 1), Color);
1538 DrawBlendedPixel(cPoint(cx - x - Delta, cy + y), Color, intensity);
1539 break;
1540 case 4: DrawRectangle( cRect( cx, cy + y, x + Delta, 1), Color);
1541 DrawBlendedPixel(cPoint(cx + x + Delta, cy + y), Color, intensity);
1542 break;
1543 case 0:
1544 case 6: DrawRectangle( cRect( cx - x - Delta + 1, cy - y, 2 * (x + Delta) + ax - 1, 1), Color);
1545 DrawBlendedPixel(cPoint(cx - x - Delta, cy - y), Color, intensity);
1546 DrawBlendedPixel(cPoint(cx + x + Delta + ax, cy - y), Color, intensity);
1547 if (Quadrants == 6)
1548 break;
1549 case 8: DrawRectangle( cRect( cx - x - Delta + 1, cy + y, 2 * (x + Delta) + ax - 1 , 1), Color);
1550 DrawBlendedPixel(cPoint(cx - x - Delta, cy + y), Color, intensity);
1551 DrawBlendedPixel(cPoint(cx + x + Delta + ax, cy + y), Color, intensity);
1552 break;
1553 case -1: DrawRectangle( cRect( cx + x + 1 + Delta, cy - y, rx - (x + Delta), 1), Color);
1554 DrawBlendedPixel(cPoint(cx + x + Delta, cy - y), Color, 255-intensity);
1555 break;
1556 case -2: DrawRectangle( cRect( x1, cy - y, rx - x - Delta, 1), Color);
1557 DrawBlendedPixel(cPoint(cx - x - Delta, cy - y), Color, 255-intensity);
1558 break;
1559 case -3: DrawRectangle( cRect( x1, cy + y, rx - x - Delta, 1), Color);
1560 DrawBlendedPixel(cPoint(cx - x - Delta, cy + y), Color, 255-intensity);
1561 break;
1562 case -4: DrawRectangle( cRect( cx + x + 1 + Delta, cy + y, rx - x - Delta, 1), Color);
1563 DrawBlendedPixel(cPoint(cx + x + Delta, cy + y), Color, 255-intensity);
1564 break;
1565 default: ;
1566 }
1567 }
1568 y++;
1569 StoppingY += TwoASquare;
1570 EllipseError += YChange;
1571 YChange += TwoASquare;
1572 if (2 * EllipseError + XChange > 0) {
1573 x--;
1574 StoppingX -= TwoBSquare;
1575 EllipseError += XChange;
1576 XChange += TwoBSquare;
1577 }
1578 }
1579 int ymax = y - 1;
1580 x = 0;
1581 y = ry;
1582 XChange = ry * ry;
1583 YChange = rx * rx * (1 - 2 * ry);
1584 EllipseError = 0;
1585 StoppingX = 0;
1586 StoppingY = TwoASquare * ry;
1587 while (StoppingX <= StoppingY) {
1588 if (!AntiAliased) {
1589 switch (Quadrants) {
1590 case 5: DrawRectangle(cRect(cx, cy + y + ay, x + 1, 1), Color); // no break
1591 case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1592 case 7: DrawRectangle(cRect(cx - x, cy + y + ay, x + 1, 1), Color); // no break
1593 case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1594 case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1595 case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1596 case 0:
1597 case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + ax + 1, 1), Color); if (Quadrants == 6) break;
1598 case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + ax + 1, 1), Color); break;
1599 case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1600 case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1601 case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1602 case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1603 default: ;
1604 }
1605 }
1606 else {
1607 uint8_t intensity = abs(255 * (long int)EllipseError / YChange);
1608 if (EllipseError >= 0) {
1609 intensity = 255 - intensity;
1610 Delta = 1;
1611 }
1612 else
1613 Delta = 0;
1614 switch (Quadrants) {
1615 case 5: DrawRectangle( cRect( cx + x, cy + ay + 1 + ymax, 1, y - ymax - Delta), Color);
1616 DrawBlendedPixel(cPoint(cx + x, cy + ay + y + 1 - Delta), Color, intensity);
1617 // no break
1618 case 1: DrawRectangle( cRect( cx + x, cy - y + Delta, 1, y - ymax - Delta), Color);
1619 DrawBlendedPixel(cPoint(cx + x, cy - y - 1 + Delta), Color, intensity);
1620 break;
1621 case 7: DrawRectangle( cRect( cx - x, cy + ay + 1 + ymax, 1, y - ymax - Delta), Color);
1622 DrawBlendedPixel(cPoint(cx - x, cy + ay + y + 1 - Delta), Color, intensity);
1623 // no break
1624 case 2: DrawRectangle( cRect( cx - x, cy - y + Delta, 1, y - ymax - Delta), Color);
1625 DrawBlendedPixel(cPoint(cx - x, cy - y - 1 + Delta), Color, intensity);
1626 break;
1627 case 3: DrawRectangle( cRect( cx - x, cy + 1 + ymax, 1, y - ymax - Delta), Color);
1628 DrawBlendedPixel(cPoint(cx - x, cy + y + 1 - Delta), Color, intensity);
1629 break;
1630 case 4: DrawRectangle( cRect( cx + x, cy + 1 + ymax, 1, y - ymax - Delta), Color);
1631 DrawBlendedPixel(cPoint(cx + x, cy + y + 1 - Delta), Color, intensity);
1632 break;
1633 case 0:
1634 case 6: DrawRectangle( cRect( cx + x + ax, cy - y + Delta, 1, y - ymax - Delta), Color);
1635 DrawRectangle( cRect( cx - x, cy - y + Delta, 1, y - ymax - Delta), Color);
1636 DrawBlendedPixel(cPoint(cx - x, cy - y + Delta - 1), Color, intensity);
1637 DrawBlendedPixel(cPoint(cx + x + ax, cy - y + Delta - 1), Color, intensity);
1638 if (Quadrants == 6)
1639 break;
1640 case 8: DrawRectangle( cRect( cx - x, cy + 1 + ymax, 1, y - ymax - Delta), Color);
1641 DrawRectangle( cRect( cx + x + ax, cy + 1 + ymax, 1, y - ymax - Delta), Color);
1642 DrawBlendedPixel(cPoint(cx - x, cy + y + 1 - Delta), Color, intensity);
1643 DrawBlendedPixel(cPoint(cx + x + ax, cy + y + 1 - Delta), Color, intensity);
1644 break;
1645 case -1: DrawRectangle( cRect( cx + x, cy - ry, 1, ry - y - 1 + Delta), Color);
1646 DrawBlendedPixel(cPoint(cx + x, cy - y - 1 + Delta), Color, 255-intensity);
1647 break;
1648 case -2: DrawRectangle( cRect( cx - x, cy - ry, 1, ry - y - 1 + Delta), Color);
1649 DrawBlendedPixel(cPoint(cx - x, cy - y - 1 + Delta), Color, 255-intensity);
1650 break;
1651 case -3: DrawRectangle( cRect( cx - x, cy + y + 2 - Delta, 1, ry - y - 1 + Delta), Color);
1652 DrawBlendedPixel(cPoint(cx - x, cy + y + 1 - Delta), Color, 255-intensity);
1653 break;
1654 case -4: DrawRectangle( cRect( cx + x, cy + y + 2 - Delta, 1, ry - y - 1 + Delta), Color);
1655 DrawBlendedPixel(cPoint(cx + x, cy + y + 1 - Delta), Color, 255-intensity);
1656 break;
1657 default: ;
1658 }
1659 }
1660 x++;
1661 StoppingX += TwoBSquare;
1662 EllipseError += XChange;
1663 XChange += TwoBSquare;
1664 if (2 * EllipseError + YChange > 0) {
1665 y--;
1666 StoppingY -= TwoASquare;
1667 EllipseError += YChange;
1668 YChange += TwoASquare;
1669 }
1670 }
1671 if (AntiAliased && Quadrants < 0 ) {
1672 switch (Quadrants) {
1673 case -1: DrawRectangle(cRect(cx + x, cy - ry, rx - x + 1, ry - y), Color); break;
1674 case -2: DrawRectangle(cRect(x1, cy - ry, rx - x + 1, ry - y), Color); break;
1675 case -3: DrawRectangle(cRect(x1, cy + y + 1, rx - x + 1, ry - y), Color); break;
1676 case -4: DrawRectangle(cRect(cx + x, cy + y + 1, rx - x + 1, ry - y), Color); break;
1677 default: ;
1678 }
1679 }
1680 MarkDrawPortDirty(Rect);
1681 Unlock();
1682}
1683
1684void cPixmapMemory::DrawSlope(const cRect &Rect, tColor Color, int Type)
1685{
1686 //TODO also simplify cBitmap::DrawSlope()
1687 Lock();
1688 bool upper = Type & 0x01;
1689 bool falling = Type & 0x02;
1690 bool vertical = Type & 0x04;
1691 int x1 = Rect.Left();
1692 int y1 = Rect.Top();
1693 int x2 = Rect.Right();
1694 int y2 = Rect.Bottom();
1695 int w = Rect.Width();
1696 int h = Rect.Height();
1697 bool AntiAliased = Setup.AntiAlias;
1698 uint8_t intensity = 0;
1699
1700 if (vertical) {
1701 if (upper)
1702 DrawRectangle(cRect(x1, y1, w, 1), Color);
1703 else
1704 DrawRectangle(cRect(x1, y2, w, 1), Color);
1705 for (int y = 1; y <= (y2 - y1) / 2; y++) {
1706 double c = cos(y * M_PI / (y2 - y1));
1707 if (AntiAliased) {
1708 double wc = (w * c + (w & 1)) / 2;
1709 intensity = 255 * fabs(wc - floor(wc));
1710 }
1711 if (falling)
1712 c = -c;
1713 int x = (x1 + x2 + w * c + 1) / 2;
1714 if (upper && !falling || !upper && falling) {
1715 if (AntiAliased) {
1716 DrawRectangle(cRect(x1, y1 + y, x - x1, 1), Color);
1717 DrawBlendedPixel(cPoint(x, y1 + y), Color, upper ? intensity : 255 - intensity);
1718 DrawRectangle(cRect(x1, y2 - y, x2 - x, 1), Color);
1719 DrawBlendedPixel(cPoint(x1 + x2 - x, y2 - y), Color, upper ? 255 - intensity : intensity);
1720 }
1721 else {
1722 DrawRectangle(cRect(x1, y1 + y, x - x1 + 1, 1), Color);
1723 DrawRectangle(cRect(x1, y2 - y, x2 - x + 1, 1), Color);
1724 }
1725 }
1726 else {
1727 if (AntiAliased) {
1728 DrawRectangle(cRect(x + 1, y1 + y, x2 - x, 1), Color);
1729 DrawBlendedPixel(cPoint(x, y1 + y), Color, falling ? intensity : 255 - intensity);
1730 DrawRectangle(cRect(x1 + x2 - x + 1, y2 - y, x - x1, 1), Color);
1731 DrawBlendedPixel(cPoint(x1 + x2 - x, y2 - y), Color, falling ? 255 - intensity : intensity);
1732 }
1733 else {
1734 DrawRectangle(cRect(x, y1 + y, x2 - x + 1, 1), Color);
1735 DrawRectangle(cRect(x1 + x2 - x, y2 - y, x - x1 + 1, 1), Color);
1736 }
1737 }
1738 }
1739 }
1740 else {
1741 if ((upper && !falling) || (!upper && falling))
1742 DrawRectangle(cRect(x1, y1, 1, h), Color);
1743 else
1744 DrawRectangle(cRect(x2, y1, 1, h), Color);
1745 for (int x = 1; x <= (x2 - x1) / 2; x++) {
1746 double c = cos(x * M_PI / (x2 - x1));
1747 if (AntiAliased) {
1748 double hc = (h * c + (h & 1)) / 2;
1749 intensity = 255 * fabs(hc - floor(hc));
1750 }
1751 if (falling)
1752 c = -c;
1753 int y = (y1 + y2 + h * c + 1) / 2;
1754 if (upper) {
1755 if (AntiAliased) {
1756 DrawRectangle(cRect(x1 + x, y1, 1, y - y1), Color);
1757 DrawBlendedPixel(cPoint(x1 + x, y), Color, falling ? 255 - intensity : intensity);
1758 DrawRectangle(cRect(x2 - x, y1, 1, y2 - y), Color);
1759 DrawBlendedPixel(cPoint(x2 - x, y1 + y2 - y), Color, falling ? intensity : 255 - intensity);
1760 }
1761 else {
1762 DrawRectangle(cRect(x1 + x, y1, 1, y - y1 + 1), Color);
1763 DrawRectangle(cRect(x2 - x, y1, 1, y2 - y + 1), Color);
1764 }
1765 }
1766 else {
1767 if (AntiAliased) {
1768 DrawRectangle(cRect(x1 + x, y + 1, 1, y2 - y), Color);
1769 DrawBlendedPixel(cPoint(x1 + x, y), Color, falling ? intensity : 255 - intensity);
1770 DrawRectangle(cRect(x2 - x, y1 + y2 - y + 1, 1, y - y1), Color);
1771 DrawBlendedPixel(cPoint(x2 - x, y1 + y2 - y), Color, falling ? 255 - intensity : intensity);
1772 }
1773 else {
1774 DrawRectangle(cRect(x1 + x, y, 1, y2 - y + 1), Color);
1775 DrawRectangle(cRect(x2 - x, y1 + y2 - y, 1, y - y1 + 1), Color);
1776 }
1777 }
1778 }
1779 }
1780 MarkDrawPortDirty(Rect);
1781 Unlock();
1782}
1783
1784void cPixmapMemory::Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1785{
1786 Lock();
1787 if (Pixmap->Alpha() != ALPHA_TRANSPARENT) {
1788 if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1789 cRect s = Source.Intersected(Pixmap->DrawPort().Size());
1790 if (!s.IsEmpty()) {
1791 cPoint v = Dest - Source.Point();
1792 cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1793 if (!d.IsEmpty()) {
1794 s = d.Shifted(-v);
1795 int a = pm->Alpha();
1796 int ws = pm->DrawPort().Width();
1797 int wd = DrawPort().Width();
1798 const tColor *ps = pm->data + ws * s.Top() + s.Left();
1799 tColor *pd = data + wd * d.Top() + d.Left();
1800 for (int y = d.Height(); y-- > 0; ) {
1801 const tColor *cs = ps;
1802 tColor *cd = pd;
1803 for (int x = d.Width(); x-- > 0; ) {
1804 *cd = AlphaBlend(*cs, *cd, a);
1805 cs++;
1806 cd++;
1807 }
1808 ps += ws;
1809 pd += wd;
1810 }
1812 }
1813 }
1814 }
1815 }
1816 Unlock();
1817}
1818
1819void cPixmapMemory::Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1820{
1821 Lock();
1822 if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1823 cRect s = Source.Intersected(pm->DrawPort().Size());
1824 if (!s.IsEmpty()) {
1825 cPoint v = Dest - Source.Point();
1826 cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1827 if (!d.IsEmpty()) {
1828 s = d.Shifted(-v);
1829 int ws = pm->DrawPort().Width();
1830 int wd = DrawPort().Width();
1831 int w = d.Width() * sizeof(tColor);
1832 const tColor *ps = pm->data + ws * s.Top() + s.Left();
1833 tColor *pd = data + wd * d.Top() + d.Left();
1834 for (int y = d.Height(); y-- > 0; ) {
1835 memcpy(pd, ps, w);
1836 ps += ws;
1837 pd += wd;
1838 }
1840 }
1841 }
1842 }
1843 Unlock();
1844}
1845
1846void cPixmapMemory::Scroll(const cPoint &Dest, const cRect &Source)
1847{
1848 Lock();
1849 cRect s;
1850 if (&Source == &cRect::Null)
1851 s = DrawPort().Shifted(-DrawPort().Point());
1852 else
1853 s = Source.Intersected(DrawPort().Size());
1854 if (!s.IsEmpty()) {
1855 cPoint v = Dest - Source.Point();
1856 cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1857 if (!d.IsEmpty()) {
1858 s = d.Shifted(-v);
1859 if (d.Point() != s.Point()) {
1860 int ws = DrawPort().Width();
1861 int wd = ws;
1862 int w = d.Width() * sizeof(tColor);
1863 const tColor *ps = data + ws * s.Top() + s.Left();
1864 tColor *pd = data + wd * d.Top() + d.Left();
1865 for (int y = d.Height(); y-- > 0; ) {
1866 memmove(pd, ps, w); // source and destination might overlap!
1867 ps += ws;
1868 pd += wd;
1869 }
1870 if (panning)
1871 SetDrawPortPoint(DrawPort().Point().Shifted(s.Point() - d.Point()), false);
1872 else
1874 }
1875 }
1876 }
1877 Unlock();
1878}
1879
1880void cPixmapMemory::Pan(const cPoint &Dest, const cRect &Source)
1881{
1882 Lock();
1883 panning = true;
1884 Scroll(Dest, Source);
1885 panning = false;
1886 Unlock();
1887}
1888
1889// --- cOsd ------------------------------------------------------------------
1890
1891static const char *OsdErrorTexts[] = {
1892 "ok",
1893 "too many areas",
1894 "too many colors",
1895 "bpp not supported",
1896 "areas overlap",
1897 "wrong alignment",
1898 "out of memory",
1899 "wrong area size",
1900 "unknown",
1901 };
1902
1903int cOsd::osdLeft = 0;
1904int cOsd::osdTop = 0;
1905int cOsd::osdWidth = 0;
1906int cOsd::osdHeight = 0;
1907cSize cOsd::maxPixmapSize(INT_MAX, INT_MAX);
1910
1911cOsd::cOsd(int Left, int Top, uint Level)
1912{
1913 cMutexLock MutexLock(&mutex);
1914 isTrueColor = false;
1915 savedBitmap = NULL;
1916 numBitmaps = 0;
1917 savedPixmap = NULL;
1918 left = Left;
1919 top = Top;
1920 width = height = 0;
1921 level = Level;
1922 active = false;
1923 for (int i = 0; i < Osds.Size(); i++) {
1924 if (Osds[i]->level > level) {
1925 Osds.Insert(this, i);
1926 return;
1927 }
1928 }
1929 Osds.Append(this);
1930}
1931
1933{
1934 cMutexLock MutexLock(&mutex);
1935 for (int i = 0; i < numBitmaps; i++)
1936 delete bitmaps[i];
1937 delete savedBitmap;
1938 delete savedPixmap;
1939 for (int i = 0; i < pixmaps.Size(); i++)
1940 delete pixmaps[i];
1941 for (int i = 0; i < Osds.Size(); i++) {
1942 if (Osds[i] == this) {
1943 Osds.Remove(i);
1944 if (Osds.Size())
1945 Osds[0]->SetActive(true);
1946 break;
1947 }
1948 }
1949}
1950
1951void cOsd::SetOsdPosition(int Left, int Top, int Width, int Height)
1952{
1953 osdLeft = Left;
1954 osdTop = Top;
1957}
1958
1959void cOsd::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
1960{
1961 if (isTrueColor)
1962 return;
1963 for (int i = 0; i < numBitmaps; i++)
1964 bitmaps[i]->SetAntiAliasGranularity(FixedColors, BlendColors);
1965}
1966
1968{
1969 return Area < numBitmaps ? (isTrueColor ? bitmaps[0] : bitmaps[Area]) : NULL;
1970}
1971
1972const cSize &cOsd::MaxPixmapSize(void) const
1973{
1974 return maxPixmapSize;
1975}
1976
1977cPixmap *cOsd::CreatePixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1978{
1979 if (isTrueColor) {
1981 cPixmap *Pixmap = new cPixmapMemory(Layer, ViewPort, DrawPort);
1982 if (AddPixmap(Pixmap))
1983 return Pixmap;
1984 delete Pixmap;
1985 }
1986 return NULL;
1987}
1988
1990{
1991 if (Pixmap) {
1993 for (int i = 1; i < pixmaps.Size(); i++) { // begin at 1 - don't let the background pixmap be destroyed!
1994 if (pixmaps[i] == Pixmap) {
1995 if (Pixmap->Layer() >= 0)
1996 pixmaps[0]->MarkViewPortDirty(Pixmap->ViewPort());
1997 delete Pixmap;
1998 pixmaps[i] = NULL;
1999 return;
2000 }
2001 }
2002 esyslog("ERROR: attempt to destroy an unregistered pixmap");
2003 }
2004}
2005
2007{
2008 if (Pixmap) {
2010 for (int i = 0; i < pixmaps.Size(); i++) {
2011 if (!pixmaps[i])
2012 return pixmaps[i] = Pixmap;
2013 }
2014 pixmaps.Append(Pixmap);
2015 }
2016 return Pixmap;
2017}
2018
2020{
2021 cPixmap *Pixmap = NULL;
2022 if (isTrueColor) {
2024 // Collect overlapping dirty rectangles:
2025 cRect d;
2026 for (int i = 0; i < pixmaps.Size(); i++) {
2027 if (cPixmap *pm = pixmaps[i]) {
2028 if (!pm->DirtyViewPort().IsEmpty()) {
2029 if (d.IsEmpty() || d.Intersects(pm->DirtyViewPort())) {
2030 d.Combine(pm->DirtyViewPort());
2031 pm->SetClean();
2032 }
2033 }
2034 }
2035 }
2036 if (!d.IsEmpty()) {
2037//#define DebugDirty
2038#ifdef DebugDirty
2039 static cRect OldDirty;
2040 cRect NewDirty = d;
2041 d.Combine(OldDirty);
2042 OldDirty = NewDirty;
2043#endif
2044 Pixmap = CreatePixmap(-1, d);
2045 if (Pixmap) {
2046 Pixmap->Clear();
2047 // Render the individual pixmaps into the resulting pixmap:
2048 for (int Layer = 0; Layer < MAXPIXMAPLAYERS; Layer++) {
2049 for (int i = 0; i < pixmaps.Size(); i++) {
2050 if (cPixmap *pm = pixmaps[i]) {
2051 if (pm->Layer() == Layer)
2052 Pixmap->DrawPixmap(pm, d);
2053 }
2054 }
2055 }
2056#ifdef DebugDirty
2057 cPixmapMemory DirtyIndicator(7, NewDirty);
2058 static tColor DirtyIndicatorColors[] = { 0x7FFFFF00, 0x7F00FFFF };
2059 static int DirtyIndicatorIndex = 0;
2060 DirtyIndicator.Fill(DirtyIndicatorColors[DirtyIndicatorIndex]);
2061 DirtyIndicatorIndex = 1 - DirtyIndicatorIndex;
2062 Pixmap->Render(&DirtyIndicator, DirtyIndicator.DrawPort(), DirtyIndicator.ViewPort().Point().Shifted(-Pixmap->ViewPort().Point()));
2063#endif
2064 }
2065 }
2066 }
2067 return Pixmap;
2068}
2069
2070eOsdError cOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
2071{
2072 if (NumAreas > MAXOSDAREAS)
2073 return oeTooManyAreas;
2074 eOsdError Result = oeOk;
2075 for (int i = 0; i < NumAreas; i++) {
2076 if (Areas[i].x1 > Areas[i].x2 || Areas[i].y1 > Areas[i].y2 || Areas[i].x1 < 0 || Areas[i].y1 < 0)
2077 return oeWrongAlignment;
2078 for (int j = i + 1; j < NumAreas; j++) {
2079 if (Areas[i].Intersects(Areas[j])) {
2080 Result = oeAreasOverlap;
2081 break;
2082 }
2083 }
2084 if (Areas[i].bpp == 32) {
2085 if (NumAreas > 1)
2086 return oeTooManyAreas;
2087 }
2088 }
2089 return Result;
2090}
2091
2092eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas)
2093{
2094 eOsdError Result = CanHandleAreas(Areas, NumAreas);
2095 if (Result == oeOk) {
2096 while (numBitmaps)
2097 delete bitmaps[--numBitmaps];
2098 for (int i = 0; i < pixmaps.Size(); i++) {
2099 delete pixmaps[i];
2100 pixmaps[i] = NULL;
2101 }
2102 width = height = 0;
2103 isTrueColor = NumAreas == 1 && Areas[0].bpp == 32;
2104 if (isTrueColor) {
2105 width = Areas[0].x2 - Areas[0].x1 + 1;
2106 height = Areas[0].y2 - Areas[0].y1 + 1;
2107 cPixmap *Pixmap = CreatePixmap(0, cRect(Areas[0].x1, Areas[0].y1, width, height));
2108 if (Pixmap)
2109 Pixmap->Clear();
2110 else
2111 Result = oeOutOfMemory;
2112 bitmaps[numBitmaps++] = new cBitmap(10, 10, 8); // dummy bitmap for GetBitmap()
2113 }
2114 else {
2115 for (int i = 0; i < NumAreas; i++) {
2116 bitmaps[numBitmaps++] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1);
2117 width = max(width, Areas[i].x2 + 1);
2118 height = max(height, Areas[i].y2 + 1);
2119 }
2120 }
2121 }
2122 else
2123 esyslog("ERROR: cOsd::SetAreas returned %d (%s)", Result, Result < oeUnknown ? OsdErrorTexts[Result] : OsdErrorTexts[oeUnknown]);
2124 return Result;
2125}
2126
2127void cOsd::SaveRegion(int x1, int y1, int x2, int y2)
2128{
2129 if (isTrueColor) {
2130 delete savedPixmap;
2131 cRect r(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
2132 savedPixmap = new cPixmapMemory(0, r);
2133 savedPixmap->Copy(pixmaps[0], r, cPoint(0, 0));
2134 }
2135 else {
2136 delete savedBitmap;
2137 savedBitmap = new cBitmap(x2 - x1 + 1, y2 - y1 + 1, 8, x1, y1);
2138 for (int i = 0; i < numBitmaps; i++)
2139 savedBitmap->DrawBitmap(bitmaps[i]->X0(), bitmaps[i]->Y0(), *bitmaps[i]);
2140 }
2141}
2142
2144{
2145 if (isTrueColor) {
2146 if (savedPixmap) {
2148 delete savedPixmap;
2149 savedPixmap = NULL;
2150 }
2151 }
2152 else {
2153 if (savedBitmap) {
2155 delete savedBitmap;
2156 savedBitmap = NULL;
2157 }
2158 }
2159}
2160
2161eOsdError cOsd::SetPalette(const cPalette &Palette, int Area)
2162{
2163 if (isTrueColor)
2164 return oeOk;
2165 if (Area < numBitmaps) {
2166 bitmaps[Area]->Take(Palette);
2167 return oeOk;
2168 }
2169 return oeUnknown;
2170}
2171
2172void cOsd::DrawImage(const cPoint &Point, const cImage &Image)
2173{
2174 if (isTrueColor)
2175 pixmaps[0]->DrawImage(Point, Image);
2176}
2177
2178void cOsd::DrawImage(const cPoint &Point, int ImageHandle)
2179{
2180 if (isTrueColor)
2181 pixmaps[0]->DrawImage(Point, ImageHandle);
2182}
2183
2184void cOsd::DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias)
2185{
2186 if (isTrueColor)
2187 pixmaps[0]->DrawScaledImage(Point, Image, FactorX, FactorY, AntiAlias);
2188}
2189
2190void cOsd::DrawScaledImage(const cPoint &Point, int ImageHandle, double FactorX, double FactorY, bool AntiAlias)
2191{
2192 if (isTrueColor)
2193 pixmaps[0]->DrawScaledImage(Point, ImageHandle, FactorX, FactorY, AntiAlias);
2194}
2195
2196void cOsd::DrawPixel(int x, int y, tColor Color)
2197{
2198 if (isTrueColor)
2199 pixmaps[0]->DrawPixel(cPoint(x, y), Color);
2200 else {
2201 for (int i = 0; i < numBitmaps; i++)
2202 bitmaps[i]->DrawPixel(x, y, Color);
2203 }
2204}
2205
2206void cOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
2207{
2208 if (isTrueColor)
2209 pixmaps[0]->DrawBitmap(cPoint(x, y), Bitmap, ColorFg, ColorBg, Overlay);
2210 else {
2211 for (int i = 0; i < numBitmaps; i++)
2212 bitmaps[i]->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg, ReplacePalette, Overlay);
2213 }
2214}
2215
2216void cOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
2217{
2218 const cBitmap *b = &Bitmap;
2219 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0))
2220 b = b->Scaled(FactorX, FactorY, AntiAlias);
2221 DrawBitmap(x, y, *b);
2222 if (b != &Bitmap)
2223 delete b;
2224}
2225
2226void cOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
2227{
2228 if (isTrueColor)
2229 pixmaps[0]->DrawText(cPoint(x, y), s, ColorFg, ColorBg, Font, Width, Height, Alignment);
2230 else {
2231 for (int i = 0; i < numBitmaps; i++)
2232 bitmaps[i]->DrawText(x, y, s, ColorFg, ColorBg, Font, Width, Height, Alignment);
2233 }
2234}
2235
2236void cOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
2237{
2238 if (isTrueColor)
2239 pixmaps[0]->DrawRectangle(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color);
2240 else {
2241 for (int i = 0; i < numBitmaps; i++)
2242 bitmaps[i]->DrawRectangle(x1, y1, x2, y2, Color);
2243 }
2244}
2245
2246void cOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
2247{
2248 if (isTrueColor)
2249 pixmaps[0]->DrawEllipse(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Quadrants);
2250 else {
2251 for (int i = 0; i < numBitmaps; i++)
2252 bitmaps[i]->DrawEllipse(x1, y1, x2, y2, Color, Quadrants);
2253 }
2254}
2255
2256void cOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
2257{
2258 if (isTrueColor)
2259 pixmaps[0]->DrawSlope(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Type);
2260 else {
2261 for (int i = 0; i < numBitmaps; i++)
2262 bitmaps[i]->DrawSlope(x1, y1, x2, y2, Color, Type);
2263 }
2264}
2265
2266void cOsd::Flush(void)
2267{
2268}
2269
2270// --- cOsdProvider ----------------------------------------------------------
2271
2275double cOsdProvider::oldAspect = 1.0;
2278
2280{
2281 delete osdProvider;
2282 osdProvider = this;
2283}
2284
2286{
2287 osdProvider = NULL;
2288}
2289
2290cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level)
2291{
2292 cMutexLock MutexLock(&cOsd::mutex);
2293 if (Level == OSD_LEVEL_DEFAULT && cOsd::IsOpen())
2294 esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
2295 else if (osdProvider) {
2296 cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL;
2297 cOsd *Osd = osdProvider->CreateOsd(Left, Top, Level);
2298 if (Osd == cOsd::Osds[0]) {
2299 if (ActiveOsd)
2300 ActiveOsd->SetActive(false);
2301 Osd->SetActive(true);
2302 }
2303 return Osd;
2304 }
2305 else
2306 isyslog("no OSD provider available - using dummy OSD!");
2307 return new cOsd(Left, Top, 999); // create a dummy cOsd, so that access won't result in a segfault
2308}
2309
2311{
2312 int Width;
2313 int Height;
2314 double Aspect;
2315 cMutexLock MutexLock(&cOsd::mutex);
2316 cDevice::PrimaryDevice()->GetOsdSize(Width, Height, Aspect);
2317 if (Width != oldWidth || Height != oldHeight || !DoubleEqual(Aspect, oldAspect) || Force) {
2318 Setup.OSDLeft = int(round(Width * Setup.OSDLeftP));
2319 Setup.OSDTop = int(round(Height * Setup.OSDTopP));
2320 Setup.OSDWidth = min(Width - Setup.OSDLeft, int(round(Width * Setup.OSDWidthP))) & ~0x07; // OSD width must be a multiple of 8
2321 Setup.OSDHeight = min(Height - Setup.OSDTop, int(round(Height * Setup.OSDHeightP)));
2322 Setup.OSDAspect = Aspect;
2323 Setup.FontOsdSize = int(round(Height * Setup.FontOsdSizeP));
2324 Setup.FontFixSize = int(round(Height * Setup.FontFixSizeP));
2325 Setup.FontSmlSize = int(round(Height * Setup.FontSmlSizeP));
2329 oldWidth = Width;
2330 oldHeight = Height;
2331 oldAspect = Aspect;
2332 dsyslog("OSD size changed to %dx%d @ %g", Width, Height, Aspect);
2333 osdState++;
2334 }
2335}
2336
2338{
2339 cMutexLock MutexLock(&cOsd::mutex);
2340 bool Result = osdState != State;
2341 State = osdState;
2342 return Result;
2343}
2344
2346{
2347 if (osdProvider) {
2349 }
2350 else
2351 esyslog("ERROR: no OSD provider available in call to SupportsTrueColor()");
2352 return false;
2353}
2354
2356{
2358 for (int i = 1; i < MAXOSDIMAGES; i++) {
2359 if (!images[i]) {
2360 images[i] = new cImage(Image);
2361 return i;
2362 }
2363 }
2364 return 0;
2365}
2366
2367void cOsdProvider::DropImageData(int ImageHandle)
2368{
2370 if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES) {
2371 delete images[ImageHandle];
2372 images[ImageHandle] = NULL;
2373 }
2374}
2375
2376const cImage *cOsdProvider::GetImageData(int ImageHandle)
2377{
2379 if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES)
2380 return images[ImageHandle];
2381 return NULL;
2382}
2383
2385{
2386 if (osdProvider)
2387 return osdProvider->StoreImageData(Image);
2388 return 0;
2389}
2390
2391void cOsdProvider::DropImage(int ImageHandle)
2392{
2393 if (osdProvider)
2394 osdProvider->DropImageData(ImageHandle);
2395}
2396
2398{
2399 delete osdProvider;
2400 osdProvider = NULL;
2401}
2402
2403// --- cTextScroller ---------------------------------------------------------
2404
2406{
2407 osd = NULL;
2408 left = top = width = height = 0;
2409 font = NULL;
2410 colorFg = 0;
2411 colorBg = 0;
2412 offset = 0;
2413 shown = 0;
2414}
2415
2416cTextScroller::cTextScroller(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2417{
2418 Set(Osd, Left, Top, Width, Height, Text, Font, ColorFg, ColorBg);
2419}
2420
2421void cTextScroller::Set(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2422{
2423 osd = Osd;
2424 left = Left;
2425 top = Top;
2426 width = Width;
2427 height = Height;
2428 font = Font;
2429 colorFg = ColorFg;
2430 colorBg = ColorBg;
2431 offset = 0;
2432 textWrapper.Set(Text, Font, Width);
2433 shown = min(Total(), height / font->Height());
2434 height = shown * font->Height(); // sets height to the actually used height, which may be less than Height
2435 DrawText();
2436}
2437
2439{
2440 osd = NULL; // just makes sure it won't draw anything
2441}
2442
2444{
2445 if (osd) {
2446 for (int i = 0; i < shown; i++)
2448 }
2449}
2450
2451void cTextScroller::Scroll(bool Up, bool Page)
2452{
2453 if (Up) {
2454 if (CanScrollUp()) {
2455 offset -= Page ? shown : 1;
2456 if (offset < 0)
2457 offset = 0;
2458 DrawText();
2459 }
2460 }
2461 else {
2462 if (CanScrollDown()) {
2463 offset += Page ? shown : 1;
2464 if (offset + shown > Total())
2465 offset = Total() - shown;
2466 DrawText();
2467 }
2468 }
2469}
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:540
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
void SetPixel(const cPoint &Point, tColor Color)
Sets the pixel at the given Point to Color.
Definition osd.h:442
const cSize & Size(void) const
Definition osd.h:434
virtual ~cImage()
Definition osd.c:1126
cSize size
Definition osd.h:421
cImage * Scaled(double FactorX, double FactorY, bool AntiAlias=false) const
Creates a copy of this image, scaled by the given factors.
Definition osd.c:1142
tColor GetPixel(const cPoint &Point) const
Returns the pixel value at the given Point.
Definition osd.h:438
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:1006
static int oldWidth
Definition osd.h:1005
virtual bool ProvidesTrueColor(void)
Returns true if this OSD provider is able to handle a true color OSD.
Definition osd.h:1014
static cImage * images[MAXOSDIMAGES]
Definition osd.h:2276
static double oldAspect
Definition osd.h:1007
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition osd.c:2337
static void DropImage(int ImageHandle)
Drops the image referenced by the given ImageHandle.
Definition osd.c:2391
virtual ~cOsdProvider()
Definition osd.c:2285
virtual int StoreImageData(const cImage &Image)
Copies the given Image and returns a handle for later reference.
Definition osd.c:2355
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:2367
static cOsdProvider * osdProvider
Definition osd.h:1004
static int osdState
Definition osd.h:1009
static int StoreImage(const cImage &Image)
Stores the given Image for later use with DrawImage() on an OSD or pixmap.
Definition osd.c:2384
cOsdProvider(void)
Definition osd.c:2279
static void Shutdown(void)
Shuts down the OSD provider facility by deleting the current OSD provider.
Definition osd.c:2397
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:2310
static const cImage * GetImageData(int ImageHandle)
Gets the image data referenced by ImageHandle.
Definition osd.c:2376
static bool SupportsTrueColor(void)
Returns true if the current OSD provider is able to handle a true color OSD.
Definition osd.c:2345
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:2290
The cOsd class is the interface to the "On Screen Display".
Definition osd.h:753
int numBitmaps
Definition osd.h:763
cOsd(int Left, int Top, uint Level)
Initializes the OSD with the given coordinates.
Definition osd.c:1911
virtual eOsdError SetPalette(const cPalette &Palette, int Area)
Sets the Palette for the given Area (the first area is numbered 0).
Definition osd.c:2161
uint level
Definition osd.h:767
virtual const cSize & MaxPixmapSize(void) const
Returns the maximum possible size of a pixmap this OSD can create.
Definition osd.c:1972
int top
Definition osd.h:766
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image on this OSD at the given Point.
Definition osd.c:2172
static int osdHeight
Definition osd.h:756
virtual void SetActive(bool On)
Sets this OSD to be the active one.
Definition osd.h:791
int Width(void)
Definition osd.h:844
bool isTrueColor
Definition osd.h:760
cVector< cPixmap * > pixmaps
Definition osd.h:765
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas)
Sets the sub-areas to the given areas.
Definition osd.c:2092
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:2206
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:2246
cBitmap * GetBitmap(int Area)
Returns a pointer to the bitmap for the given Area, or NULL if no such bitmap exists.
Definition osd.c:1967
virtual void DestroyPixmap(cPixmap *Pixmap)
Destroys the given Pixmap, which has previously been created by a call to CreatePixmap().
Definition osd.c:1989
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
Allows the system to optimize utilization of the limited color palette entries when generating blende...
Definition osd.c:1959
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:2196
bool active
Definition osd.h:768
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas)
Checks whether the OSD can display the given set of sub-areas.
Definition osd.c:2070
static int osdWidth
Definition osd.h:756
cPixmap * AddPixmap(cPixmap *Pixmap)
Adds the given Pixmap to the list of currently active pixmaps in this OSD.
Definition osd.c:2006
cPixmap * RenderPixmaps(void)
Renders the dirty part of all pixmaps into a resulting pixmap that shall be displayed on the OSD.
Definition osd.c:2019
static int osdLeft
Definition osd.h:756
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:1977
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:1951
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:2127
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:2216
virtual void Flush(void)
Actually commits all data to the OSD hardware.
Definition osd.c:2266
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:2236
int Left(void)
Definition osd.h:842
cBitmap * bitmaps[MAXOSDAREAS]
Definition osd.h:762
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:2256
static cMutex mutex
Definition osd.h:759
int left
Definition osd.h:766
cPixmapMemory * savedPixmap
Definition osd.h:764
int height
Definition osd.h:766
static int osdTop
Definition osd.h:756
int Top(void)
Definition osd.h:843
virtual void RestoreRegion(void)
Restores the region previously saved by a call to SaveRegion().
Definition osd.c:2143
static cVector< cOsd * > Osds
Definition osd.h:757
cBitmap * savedBitmap
Definition osd.h:761
static cSize maxPixmapSize
Definition osd.h:758
virtual ~cOsd()
Shuts down the OSD.
Definition osd.c:1932
virtual void DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias=false)
Draws the given Image on this OSD at the given Point and scales it.
Definition osd.c:2184
int width
Definition osd.h:766
int Height(void)
Definition osd.h:845
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition osd.h:837
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:2226
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
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
tIndex tIndexes[MAXNUMCOLORS]
Definition osd.h:96
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 DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias=false)
Definition osd.c:1305
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:1880
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:1846
virtual void Clear(void)
Clears the pixmap's draw port by setting all pixels to be fully transparent.
Definition osd.c:1205
bool panning
Definition osd.h:715
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:1819
cPixmapMemory(void)
Definition osd.c:1187
virtual ~cPixmapMemory()
Definition osd.c:1200
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:1784
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:1339
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type)
Draws a "slope" with the given Color into the given rectangle.
Definition osd.c:1684
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:1357
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image into this pixmap at the given Point.
Definition osd.c:1273
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:1384
virtual void Fill(tColor Color)
Fills the pixmap's draw port with the given Color.
Definition osd.c:1213
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:1460
tColor * data
Definition osd.h:714
virtual void DrawPixel(const cPoint &Point, tColor Color)
Draws the image referenced by the given ImageHandle into this pixmap at the given Point and scales it...
Definition osd.c:1325
virtual void DrawRectangle(const cRect &Rect, tColor Color)
Draws a filled rectangle with the given Color.
Definition osd.c:1433
Definition osd.h:459
virtual void DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
Draws the Dirty part of the given Pixmap into this pixmap.
Definition osd.c:1222
bool Tile(void) const
Definition osd.h:543
const cRect & DrawPort(void) const
Returns the pixmap's draw port, which is relative to the view port.
Definition osd.h:548
int alpha
Definition osd.h:465
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:540
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:470
cRect viewPort
Definition osd.h:467
const cRect & ViewPort(void) const
Returns the pixmap's view port, which is relative to the OSD's origin.
Definition osd.h:544
int Alpha(void) const
Definition osd.h:542
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:534
static cMutex mutex
Definition osd.h:463
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:466
cRect dirtyViewPort
Definition osd.h:469
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:464
cRect drawPort
Definition osd.h:468
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:541
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:1520
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:1088
tColor colorBg
Definition osd.h:1076
int Left(void)
Definition osd.h:1085
void DrawText(void)
Definition osd.c:2443
int shown
Definition osd.h:1077
int Total(void)
Definition osd.h:1089
int height
Definition osd.h:1074
cTextWrapper textWrapper
Definition osd.h:1078
const cFont * font
Definition osd.h:1075
cTextScroller(void)
Definition osd.c:2405
void Scroll(bool Up, bool Page)
Definition osd.c:2451
int Top(void)
Definition osd.h:1086
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:2421
void Reset(void)
Definition osd.c:2438
tColor colorFg
Definition osd.h:1076
int width
Definition osd.h:1074
cOsd * osd
Definition osd.h:1073
bool CanScrollDown(void)
Definition osd.h:1094
int offset
Definition osd.h:1077
int Width(void)
Definition osd.h:1087
bool CanScrollUp(void)
Definition osd.h:1093
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:754
virtual void Insert(T Data, int Before=0)
Definition tools.h:755
virtual void Append(T Data)
Definition tools.h:774
virtual void Remove(int Index)
Definition tools.h:788
cSetup Setup
Definition config.c:372
#define MINOSDHEIGHT
Definition config.h:61
#define MINOSDWIDTH
Definition config.h:59
#define MAXOSDWIDTH
Definition config.h:60
#define MAXOSDHEIGHT
Definition config.h:62
@ fontOsd
Definition font.h:22
@ fontFix
Definition font.h:23
uint32_t tColor
Definition font.h:30
uint8_t tIndex
Definition font.h:31
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:1891
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:457
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:707
#define MAXOSDAREAS
Definition osd.h:740
#define TEXT_ALIGN_BORDER
Definition osd.h:28
#define MAXOSDIMAGES
Definition osd.h:999
#define IS_OPAQUE(c)
Definition osd.h:27
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:244
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
#define isyslog(a...)
Definition tools.h:36