vdr  2.7.6
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 
19 tColor 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 
43 tColor 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.
58 static uint16_t AlphaLutFactors[255][256][2];
59 static uint8_t AlphaLutAlpha[255][256];
60 
62 public:
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 
81 tColor 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.
95 static 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 
104 tColor 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);
120  SetAntiAliasGranularity(10, 10);
121 }
122 
124 {
125 }
126 
127 void 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 
138 void cPalette::Reset(void)
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 
165 void cPalette::SetBpp(int Bpp)
166 {
167  bpp = Bpp;
168  maxColors = 1 << bpp;
169  Reset();
170 }
171 
172 void 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 
185 const tColor *cPalette::Colors(int &NumColors) const
186 {
187  NumColors = numColors;
188  return numColors ? color : NULL;
189 }
190 
191 void 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 
208 void 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 
216 tColor 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 
235 int 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 
261 cBitmap::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;
268  SetSize(Width, Height);
269 }
270 
271 cBitmap::cBitmap(const char *FileName)
272 {
273  bitmap = NULL;
274  x0 = 0;
275  y0 = 0;
276  width = height = 0;
277  LoadXpm(FileName);
278 }
279 
280 cBitmap::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 
294 void 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 
317 bool 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 
324 bool 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 
333 bool 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 
342 bool 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 
354 void cBitmap::Clean(void)
355 {
356  dirtyX1 = width;
357  dirtyY1 = height;
358  dirtyX2 = -1;
359  dirtyY2 = -1;
360 }
361 
362 bool 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 
428 bool 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 
500 void 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 
526 void cBitmap::DrawPixel(int x, int y, tColor Color)
527 {
528  x -= x0;
529  y -= y0;
530  SetIndex(x, y, Index(Color));
531 }
532 
533 void 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 
562 void 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 
611 void 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 
632 void 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 
727 void 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 
760 const tIndex *cBitmap::Data(int x, int y) const
761 {
762  return &bitmap[y * width + x];
763 }
764 
765 void 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 
796 void 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 
838 cBitmap *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 
890 const cRect cRect::Null;
891 
892 void cRect::Grow(int Dx, int Dy)
893 {
894  point.Shift(-Dx, -Dy);
895  size.Grow(Dx, Dy);
896 }
897 
898 bool 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 
906 bool 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 
914 bool 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 
922 cRect cRect::Intersected(const cRect &Rect) const
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 
934 void 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 
947 void 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 
969 cPixmap::cPixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
970 {
971  layer = Layer;
972  if (layer >= MAXPIXMAPLAYERS) {
973  layer = MAXPIXMAPLAYERS - 1;
974  esyslog("ERROR: pixmap layer %d limited to %d", Layer, layer);
975  }
976  viewPort = ViewPort;
977  if (!DrawPort.IsEmpty())
978  drawPort = DrawPort;
979  else {
980  drawPort = viewPort;
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 
1024 void 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 
1046 void cPixmap::SetAlpha(int Alpha)
1047 {
1048  Lock();
1050  if (Alpha != alpha) {
1052  alpha = Alpha;
1053  }
1054  Unlock();
1055 }
1056 
1057 void 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 
1068 void cPixmap::SetViewPort(const cRect &Rect)
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 
1085 void 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 
1109 cImage::cImage(const cImage &Image)
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 
1117 cImage::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 
1131 void cImage::Clear(void)
1132 {
1133  memset(data, 0x00, Width() * Height() * sizeof(tColor));
1134 }
1135 
1137 {
1138  for (int i = Width() * Height() - 1; i >= 0; i--)
1139  data[i] = Color;
1140 }
1141 
1142 cImage *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 
1193 cPixmapMemory::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 
1222 void 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 
1273 void 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  }
1292  MarkDrawPortDirty(r);
1293  }
1294  Unlock();
1295 }
1296 
1297 void 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 
1305 void 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 
1317 void 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 
1325 void 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 
1339 void 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 
1357 void 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  }
1379  MarkDrawPortDirty(r);
1380  }
1381  Unlock();
1382 }
1383 
1384 void 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);
1429  MarkDrawPortDirty(r);
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  }
1455  MarkDrawPortDirty(r);
1456  }
1457  Unlock();
1458 }
1459 
1460 void 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 
1684 void 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 
1784 void 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  }
1811  MarkDrawPortDirty(d);
1812  }
1813  }
1814  }
1815  }
1816  Unlock();
1817 }
1818 
1819 void 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  }
1839  MarkDrawPortDirty(d);
1840  }
1841  }
1842  }
1843  Unlock();
1844 }
1845 
1846 void 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
1873  MarkDrawPortDirty(d);
1874  }
1875  }
1876  }
1877  Unlock();
1878 }
1879 
1880 void 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 
1891 static 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 
1903 int cOsd::osdLeft = 0;
1904 int cOsd::osdTop = 0;
1905 int cOsd::osdWidth = 0;
1906 int cOsd::osdHeight = 0;
1907 cSize cOsd::maxPixmapSize(INT_MAX, INT_MAX);
1910 
1911 cOsd::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 
1951 void cOsd::SetOsdPosition(int Left, int Top, int Width, int Height)
1952 {
1953  osdLeft = Left;
1954  osdTop = Top;
1957 }
1958 
1959 void 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 
1972 const cSize &cOsd::MaxPixmapSize(void) const
1973 {
1974  return maxPixmapSize;
1975 }
1976 
1977 cPixmap *cOsd::CreatePixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1978 {
1979  if (isTrueColor) {
1980  LOCK_PIXMAPS;
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) {
1992  LOCK_PIXMAPS;
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) {
2009  LOCK_PIXMAPS;
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) {
2023  LOCK_PIXMAPS;
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 
2070 eOsdError 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 
2092 eOsdError 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 
2127 void 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 
2161 eOsdError 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 
2172 void cOsd::DrawImage(const cPoint &Point, const cImage &Image)
2173 {
2174  if (isTrueColor)
2175  pixmaps[0]->DrawImage(Point, Image);
2176 }
2177 
2178 void cOsd::DrawImage(const cPoint &Point, int ImageHandle)
2179 {
2180  if (isTrueColor)
2181  pixmaps[0]->DrawImage(Point, ImageHandle);
2182 }
2183 
2184 void 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 
2190 void 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 
2196 void 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 
2206 void 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 
2216 void 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 
2226 void 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 
2236 void 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 
2246 void 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 
2256 void 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 
2266 void cOsd::Flush(void)
2267 {
2268 }
2269 
2270 // --- cOsdProvider ----------------------------------------------------------
2271 
2273 int cOsdProvider::oldWidth = 0;
2274 int cOsdProvider::oldHeight = 0;
2275 double cOsdProvider::oldAspect = 1.0;
2277 int cOsdProvider::osdState = 0;
2278 
2280 {
2281  delete osdProvider;
2282  osdProvider = this;
2283 }
2284 
2286 {
2287  osdProvider = NULL;
2288 }
2289 
2290 cOsd *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) {
2348  return osdProvider->ProvidesTrueColor();
2349  }
2350  else
2351  esyslog("ERROR: no OSD provider available in call to SupportsTrueColor()");
2352  return false;
2353 }
2354 
2356 {
2357  LOCK_PIXMAPS;
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 
2367 void cOsdProvider::DropImageData(int ImageHandle)
2368 {
2369  LOCK_PIXMAPS;
2370  if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES) {
2371  delete images[ImageHandle];
2372  images[ImageHandle] = NULL;
2373  }
2374 }
2375 
2376 const cImage *cOsdProvider::GetImageData(int ImageHandle)
2377 {
2378  LOCK_PIXMAPS;
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 
2391 void 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 
2416 cTextScroller::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 
2421 void 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 
2451 void 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
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
virtual ~cBitmap() override
Definition: osd.c:289
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 override
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 override
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 override
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 cSize & Size(void) const
Definition: osd.h:434
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
virtual ~cImage()
Definition: osd.c:1126
cSize size
Definition: osd.h:421
const tColor * Data(void) const
Definition: osd.h:437
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
Definition: thread.h:67
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:1008
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 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
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.
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
tIndex tIndexes[MAXNUMCOLORS]
Definition: osd.h:96
int bpp
Definition: osd.h:91
void SetBpp(int Bpp)
Sets the color depth of this palette to the given value.
Definition: osd.c:165
void SetColor(int Index, tColor Color)
Sets the palette entry at Index to Color.
Definition: osd.c:172
tColor color[MAXNUMCOLORS]
Definition: osd.h:90
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
Allows the system to optimize utilization of the limited color palette entries when generating blende...
Definition: osd.c:127
int Index(tColor Color)
Returns the index of the given Color (the first color has index 0).
Definition: osd.c:144
int ClosestColor(tColor Color, int MaxDiff=INT_MAX) const
Returns the index of a color in this palette that is closest to the given Color.
Definition: osd.c:235
int numColors
Definition: osd.h:92
cPalette(int Bpp=8)
Initializes the palette with the given color depth.
Definition: osd.c:117
double antiAliasGranularity
Definition: osd.h:94
int Bpp(void) const
Definition: osd.h:111
void Take(const cPalette &Palette, tIndexes *Indexes=NULL, tColor ColorFg=0, tColor ColorBg=0)
Takes the colors from the given Palette and adds them to this palette, using existing entries if poss...
Definition: osd.c:191
virtual void DrawRectangle(const cRect &Rect, tColor Color) override
Draws a filled rectangle with the given Color.
Definition: osd.c:1433
virtual void Clear(void) override
Clears the pixmap's draw port by setting all pixels to be fully transparent.
Definition: osd.c:1205
virtual void Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest) override
Copies the part of the given Pixmap covered by Source into this pixmap at location Dest.
Definition: osd.c:1819
virtual void Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest) override
Renders the part of the given Pixmap covered by Source into this pixmap at location Dest.
Definition: osd.c:1784
virtual void DrawEllipse(const cRect &Rect, tColor Color, int Quadrants=0) override
Draws a filled ellipse with the given Color that fits into the given rectangle.
Definition: osd.c:1460
virtual void Scroll(const cPoint &Dest, const cRect &Source=cRect::Null) override
Scrolls the data in the pixmap's draw port to the given Dest point.
Definition: osd.c:1846
bool panning
Definition: osd.h:715
virtual void DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg=0, tColor ColorBg=0, bool Overlay=false) override
Sets the pixels in the OSD with the data from the given Bitmap, putting the upper left corner of the ...
Definition: osd.c:1357
cPixmapMemory(void)
Definition: osd.c:1187
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) override
Draws the given string at Point with the given foreground and background color and font.
Definition: osd.c:1384
virtual void Fill(tColor Color) override
Fills the pixmap's draw port with the given Color.
Definition: osd.c:1213
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type) override
Draws a "slope" with the given Color into the given rectangle.
Definition: osd.c:1684
virtual void DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias=false) override
Definition: osd.c:1305
tColor * data
Definition: osd.h:714
virtual void DrawBlendedPixel(const cPoint &Point, tColor Color, uint8_t AlphaLayer=ALPHA_OPAQUE) override
Like DrawPixel(), but with an additional AlphaLayer, and works on any pixmap, not only the background...
Definition: osd.c:1339
virtual void DrawImage(const cPoint &Point, const cImage &Image) override
Draws the given Image into this pixmap at the given Point.
Definition: osd.c:1273
virtual void Pan(const cPoint &Dest, const cRect &Source=cRect::Null) override
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 DrawPixel(const cPoint &Point, tColor Color) override
Draws the image referenced by the given ImageHandle into this pixmap at the given Point and scales it...
Definition: osd.c:1325
virtual ~cPixmapMemory() override
Definition: osd.c:1200
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
const cRect & DrawPort(void) const
Returns the pixmap's draw port, which is relative to the view port.
Definition: osd.h:548
bool Tile(void) const
Definition: osd.h:543
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
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
const cRect & ViewPort(void) const
Returns the pixmap's view port, which is relative to the OSD's origin.
Definition: osd.h:544
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:1527
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
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
const cSize & Size(void) const
Definition: osd.h:374
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 cPoint & Point(void) const
Definition: osd.h:373
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:344
int FontFixSize
Definition: config.h:353
int OSDHeight
Definition: config.h:340
double OSDAspect
Definition: config.h:341
double OSDWidthP
Definition: config.h:339
double OSDHeightP
Definition: config.h:339
double FontOsdSizeP
Definition: config.h:348
int FontOsdSize
Definition: config.h:351
int FontSmlSize
Definition: config.h:352
int OSDTop
Definition: config.h:340
double FontFixSizeP
Definition: config.h:350
double OSDLeftP
Definition: config.h:339
double FontSmlSizeP
Definition: config.h:349
int OSDLeft
Definition: config.h:340
char FontOsd[MAXFONTNAME]
Definition: config.h:345
int OSDWidth
Definition: config.h:340
char FontSml[MAXFONTNAME]
Definition: config.h:346
double OSDTopP
Definition: config.h:339
char FontFix[MAXFONTNAME]
Definition: config.h:347
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 left
Definition: osd.h:1074
int width
Definition: osd.h:1074
cOsd * osd
Definition: osd.h:1073
int top
Definition: osd.h:1074
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:65
#define MINOSDWIDTH
Definition: config.h:63
#define MAXOSDWIDTH
Definition: config.h:64
#define MAXOSDHEIGHT
Definition: config.h:66
@ fontOsd
Definition: font.h:22
@ fontFix
Definition: font.h:23
uint32_t tColor
Definition: font.h:29
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
@ 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
char * skipspace(const char *s)
Definition: tools.h:244
#define dsyslog(a...)
Definition: tools.h:37
#define MALLOC(type, size)
Definition: tools.h:47
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