vdr  2.4.1
osd.c
Go to the documentation of this file.
1 /*
2  * osd.c: Abstract On Screen Display layer
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: osd.c 4.5.1.1 2019/05/24 21:30:20 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 http://homepage.smc.edu/kennedy_john/BELIPSE.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() * sizeof(tColor);
1113  data = MALLOC(tColor, l);
1114  memcpy(data, Image.Data(), l);
1115 }
1116 
1117 cImage::cImage(const cSize &Size, const tColor *Data)
1118 {
1119  size = Size;
1120  int l = size.Width() * size.Height() * sizeof(tColor);
1121  data = MALLOC(tColor, l);
1122  if (Data)
1123  memcpy(data, Data, l);
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 // --- cPixmapMemory ---------------------------------------------------------
1143 
1145 {
1146  data = NULL;
1147  panning = false;
1148 }
1149 
1150 cPixmapMemory::cPixmapMemory(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1151 :cPixmap(Layer, ViewPort, DrawPort)
1152 {
1153  data = MALLOC(tColor, this->DrawPort().Width() * this->DrawPort().Height());
1154  panning = false;
1155 }
1156 
1158 {
1159  free(data);
1160 }
1161 
1163 {
1164  Lock();
1165  memset(data, 0x00, DrawPort().Width() * DrawPort().Height() * sizeof(tColor));
1167  Unlock();
1168 }
1169 
1171 {
1172  Lock();
1173  for (int i = DrawPort().Width() * DrawPort().Height() - 1; i >= 0; i--)
1174  data[i] = Color;
1176  Unlock();
1177 }
1178 
1179 void cPixmap::DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
1180 {
1181  if (Pixmap->Tile() && (Pixmap->DrawPort().Point() != cPoint(0, 0) || Pixmap->DrawPort().Size() < Pixmap->ViewPort().Size())) {
1182  cPoint t0 = Pixmap->DrawPort().Point().Shifted(Pixmap->ViewPort().Point()); // the origin of the draw port in absolute OSD coordinates
1183  // Find the top/leftmost location where the draw port touches the view port:
1184  while (t0.X() > Pixmap->ViewPort().Left())
1185  t0.Shift(-Pixmap->DrawPort().Width(), 0);
1186  while (t0.Y() > Pixmap->ViewPort().Top())
1187  t0.Shift(0, -Pixmap->DrawPort().Height());
1188  cPoint t = t0;
1189  while (t.Y() <= Pixmap->ViewPort().Bottom()) {
1190  while (t.X() <= Pixmap->ViewPort().Right()) {
1191  cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1192  Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1193  cPoint Delta = Source.Point() - t;
1194  Source.SetPoint(t); // Source is now where the pixmap's data shall be drawn
1195  Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1196  Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1197  if (!Source.IsEmpty()) {
1198  cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1199  Source.Shift(Delta); // Source is now back at the pixmap's draw port location, still in absolute OSD coordinates
1200  Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's view port again
1201  Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1202  if (Pixmap->Layer() == 0)
1203  Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1204  else
1205  Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1206  }
1207  t.Shift(Pixmap->DrawPort().Width(), 0); // increase one draw port width to the right
1208  }
1209  t.SetX(t0.X()); // go back to the leftmost position
1210  t.Shift(0, Pixmap->DrawPort().Height()); // increase one draw port height down
1211  }
1212  }
1213  else {
1214  cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1215  Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1216  Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1217  Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1218  if (!Source.IsEmpty()) {
1219  cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1220  Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's draw port again
1221  Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1222  if (Pixmap->Layer() == 0)
1223  Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1224  else
1225  Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1226  }
1227  }
1228 }
1229 
1230 void cPixmapMemory::DrawImage(const cPoint &Point, const cImage &Image)
1231 {
1232  Lock();
1233  cRect r = cRect(Point, Image.Size()).Intersected(DrawPort().Size());
1234  if (!r.IsEmpty()) {
1235  int ws = Image.Size().Width();
1236  int wd = DrawPort().Width();
1237  int w = r.Width() * sizeof(tColor);
1238  const tColor *ps = Image.Data();
1239  if (Point.Y() < 0)
1240  ps -= Point.Y() * ws;
1241  if (Point.X() < 0)
1242  ps -= Point.X();
1243  tColor *pd = data + wd * r.Top() + r.Left();
1244  for (int y = r.Height(); y-- > 0; ) {
1245  memcpy(pd, ps, w);
1246  ps += ws;
1247  pd += wd;
1248  }
1249  MarkDrawPortDirty(r);
1250  }
1251  Unlock();
1252 }
1253 
1254 void cPixmapMemory::DrawImage(const cPoint &Point, int ImageHandle)
1255 {
1256  Lock();
1257  if (const cImage *Image = cOsdProvider::GetImageData(ImageHandle))
1258  DrawImage(Point, *Image);
1259  Unlock();
1260 }
1261 
1262 void cPixmapMemory::DrawPixel(const cPoint &Point, tColor Color)
1263 {
1264  Lock();
1265  if (DrawPort().Size().Contains(Point)) {
1266  int p = Point.Y() * DrawPort().Width() + Point.X();
1267  if (Layer() == 0 && !IS_OPAQUE(Color))
1268  data[p] = AlphaBlend(Color, data[p]);
1269  else
1270  data[p] = Color;
1271  MarkDrawPortDirty(Point);
1272  }
1273  Unlock();
1274 }
1275 
1276 void cPixmapMemory::DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay)
1277 {
1278  Lock();
1279  cRect r = cRect(Point, cSize(Bitmap.Width(), Bitmap.Height())).Intersected(DrawPort().Size());
1280  if (!r.IsEmpty()) {
1281  bool UseColors = ColorFg || ColorBg;
1282  int wd = DrawPort().Width();
1283  tColor *pd = data + wd * r.Top() + r.Left();
1284  for (int y = r.Top(); y <= r.Bottom(); y++) {
1285  tColor *cd = pd;
1286  for (int x = r.Left(); x <= r.Right(); x++) {
1287  tIndex Index = *Bitmap.Data(x - Point.X(), y - Point.Y());
1288  if (Index || !Overlay) {
1289  if (UseColors)
1290  *cd = Index ? ColorFg : ColorBg;
1291  else
1292  *cd = Bitmap.Color(Index);
1293  }
1294  cd++;
1295  }
1296  pd += wd;
1297  }
1298  MarkDrawPortDirty(r);
1299  }
1300  Unlock();
1301 }
1302 
1303 void cPixmapMemory::DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
1304 {
1305  Lock();
1306  int x = Point.X();
1307  int y = Point.Y();
1308  int w = Font->Width(s);
1309  int h = Font->Height();
1310  int limit = 0;
1311  int cw = Width ? Width : w;
1312  int ch = Height ? Height : h;
1313  cRect r(x, y, cw, ch);
1314  if (ColorBg != clrTransparent)
1315  DrawRectangle(r, ColorBg);
1316  if (Width || Height) {
1317  limit = x + cw;
1318  if (Width) {
1319  if ((Alignment & taLeft) != 0) {
1320  if ((Alignment & taBorder) != 0)
1321  x += max(h / TEXT_ALIGN_BORDER, 1);
1322  }
1323  else if ((Alignment & taRight) != 0) {
1324  if (w < Width)
1325  x += Width - w;
1326  if ((Alignment & taBorder) != 0)
1327  x -= max(h / TEXT_ALIGN_BORDER, 1);
1328  }
1329  else { // taCentered
1330  if (w < Width)
1331  x += (Width - w) / 2;
1332  }
1333  }
1334  if (Height) {
1335  if ((Alignment & taTop) != 0)
1336  ;
1337  else if ((Alignment & taBottom) != 0) {
1338  if (h < Height)
1339  y += Height - h;
1340  }
1341  else { // taCentered
1342  if (h < Height)
1343  y += (Height - h) / 2;
1344  }
1345  }
1346  }
1347  Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
1348  MarkDrawPortDirty(r);
1349  Unlock();
1350 }
1351 
1353 {
1354  Lock();
1355  cRect r = Rect.Intersected(DrawPort().Size());
1356  if (!r.IsEmpty()) {
1357  int wd = DrawPort().Width();
1358  int w = r.Width() * sizeof(tColor);
1359  tColor *ps = NULL;
1360  tColor *pd = data + wd * r.Top() + r.Left();
1361  for (int y = r.Height(); y-- > 0; ) {
1362  if (ps)
1363  memcpy(pd, ps, w); // all other lines are copied fast from the first one
1364  else {
1365  // explicitly fill the first line:
1366  tColor *cd = ps = pd;
1367  for (int x = r.Width(); x-- > 0; ) {
1368  *cd = Color;
1369  cd++;
1370  }
1371  }
1372  pd += wd;
1373  }
1374  MarkDrawPortDirty(r);
1375  }
1376  Unlock();
1377 }
1378 
1379 void cPixmapMemory::DrawEllipse(const cRect &Rect, tColor Color, int Quadrants)
1380 {
1381 //TODO use anti-aliasing?
1382 //TODO fix alignment
1383  Lock();
1384  // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF
1385  int x1 = Rect.Left();
1386  int y1 = Rect.Top();
1387  int x2 = Rect.Right();
1388  int y2 = Rect.Bottom();
1389  int rx = x2 - x1;
1390  int ry = y2 - y1;
1391  int cx = (x1 + x2) / 2;
1392  int cy = (y1 + y2) / 2;
1393  switch (abs(Quadrants)) {
1394  case 0: rx /= 2; ry /= 2; break;
1395  case 1: cx = x1; cy = y2; break;
1396  case 2: cx = x2; cy = y2; break;
1397  case 3: cx = x2; cy = y1; break;
1398  case 4: cx = x1; cy = y1; break;
1399  case 5: cx = x1; ry /= 2; break;
1400  case 6: cy = y2; rx /= 2; break;
1401  case 7: cx = x2; ry /= 2; break;
1402  case 8: cy = y1; rx /= 2; break;
1403  default: ;
1404  }
1405  int TwoASquare = max(1, 2 * rx * rx);
1406  int TwoBSquare = max(1, 2 * ry * ry);
1407  int x = rx;
1408  int y = 0;
1409  int XChange = ry * ry * (1 - 2 * rx);
1410  int YChange = rx * rx;
1411  int EllipseError = 0;
1412  int StoppingX = TwoBSquare * rx;
1413  int StoppingY = 0;
1414  while (StoppingX >= StoppingY) {
1415  switch (Quadrants) {
1416  case 5: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); // no break
1417  case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1418  case 7: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); // no break
1419  case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1420  case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1421  case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1422  case 0:
1423  case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + 1, 1), Color); if (Quadrants == 6) break;
1424  case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + 1, 1), Color); break;
1425  case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1426  case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1427  case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1428  case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1429  default: ;
1430  }
1431  y++;
1432  StoppingY += TwoASquare;
1433  EllipseError += YChange;
1434  YChange += TwoASquare;
1435  if (2 * EllipseError + XChange > 0) {
1436  x--;
1437  StoppingX -= TwoBSquare;
1438  EllipseError += XChange;
1439  XChange += TwoBSquare;
1440  }
1441  }
1442  x = 0;
1443  y = ry;
1444  XChange = ry * ry;
1445  YChange = rx * rx * (1 - 2 * ry);
1446  EllipseError = 0;
1447  StoppingX = 0;
1448  StoppingY = TwoASquare * ry;
1449  while (StoppingX <= StoppingY) {
1450  switch (Quadrants) {
1451  case 5: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); // no break
1452  case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1453  case 7: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); // no break
1454  case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1455  case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1456  case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1457  case 0:
1458  case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + 1, 1), Color); if (Quadrants == 6) break;
1459  case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + 1, 1), Color); break;
1460  case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1461  case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1462  case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1463  case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1464  default: ;
1465  }
1466  x++;
1467  StoppingX += TwoBSquare;
1468  EllipseError += XChange;
1469  XChange += TwoBSquare;
1470  if (2 * EllipseError + YChange > 0) {
1471  y--;
1472  StoppingY -= TwoASquare;
1473  EllipseError += YChange;
1474  YChange += TwoASquare;
1475  }
1476  }
1477  MarkDrawPortDirty(Rect);
1478  Unlock();
1479 }
1480 
1481 void cPixmapMemory::DrawSlope(const cRect &Rect, tColor Color, int Type)
1482 {
1483  //TODO anti-aliasing?
1484  //TODO also simplify cBitmap::DrawSlope()
1485  Lock();
1486  bool upper = Type & 0x01;
1487  bool falling = Type & 0x02;
1488  bool vertical = Type & 0x04;
1489  int x1 = Rect.Left();
1490  int y1 = Rect.Top();
1491  int x2 = Rect.Right();
1492  int y2 = Rect.Bottom();
1493  int w = Rect.Width();
1494  int h = Rect.Height();
1495  if (vertical) {
1496  for (int y = y1; y <= y2; y++) {
1497  double c = cos((y - y1) * M_PI / h);
1498  if (falling)
1499  c = -c;
1500  int x = (x1 + x2) / 2 + int(w * c / 2);
1501  if (upper && !falling || !upper && falling)
1502  DrawRectangle(cRect(x1, y, x - x1 + 1, 1), Color);
1503  else
1504  DrawRectangle(cRect(x, y, x2 - x + 1, 1), Color);
1505  }
1506  }
1507  else {
1508  for (int x = x1; x <= x2; x++) {
1509  double c = cos((x - x1) * M_PI / w);
1510  if (falling)
1511  c = -c;
1512  int y = (y1 + y2) / 2 + int(h * c / 2);
1513  if (upper)
1514  DrawRectangle(cRect(x, y1, 1, y - y1 + 1), Color);
1515  else
1516  DrawRectangle(cRect(x, y, 1, y2 - y + 1), Color);
1517  }
1518  }
1519  MarkDrawPortDirty(Rect);
1520  Unlock();
1521 }
1522 
1523 void cPixmapMemory::Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1524 {
1525  Lock();
1526  if (Pixmap->Alpha() != ALPHA_TRANSPARENT) {
1527  if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1528  cRect s = Source.Intersected(Pixmap->DrawPort().Size());
1529  if (!s.IsEmpty()) {
1530  cPoint v = Dest - Source.Point();
1531  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1532  if (!d.IsEmpty()) {
1533  s = d.Shifted(-v);
1534  int a = pm->Alpha();
1535  int ws = pm->DrawPort().Width();
1536  int wd = DrawPort().Width();
1537  const tColor *ps = pm->data + ws * s.Top() + s.Left();
1538  tColor *pd = data + wd * d.Top() + d.Left();
1539  for (int y = d.Height(); y-- > 0; ) {
1540  const tColor *cs = ps;
1541  tColor *cd = pd;
1542  for (int x = d.Width(); x-- > 0; ) {
1543  *cd = AlphaBlend(*cs, *cd, a);
1544  cs++;
1545  cd++;
1546  }
1547  ps += ws;
1548  pd += wd;
1549  }
1550  MarkDrawPortDirty(d);
1551  }
1552  }
1553  }
1554  }
1555  Unlock();
1556 }
1557 
1558 void cPixmapMemory::Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1559 {
1560  Lock();
1561  if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1562  cRect s = Source.Intersected(pm->DrawPort().Size());
1563  if (!s.IsEmpty()) {
1564  cPoint v = Dest - Source.Point();
1565  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1566  if (!d.IsEmpty()) {
1567  s = d.Shifted(-v);
1568  int ws = pm->DrawPort().Width();
1569  int wd = DrawPort().Width();
1570  int w = d.Width() * sizeof(tColor);
1571  const tColor *ps = pm->data + ws * s.Top() + s.Left();
1572  tColor *pd = data + wd * d.Top() + d.Left();
1573  for (int y = d.Height(); y-- > 0; ) {
1574  memcpy(pd, ps, w);
1575  ps += ws;
1576  pd += wd;
1577  }
1578  MarkDrawPortDirty(d);
1579  }
1580  }
1581  }
1582  Unlock();
1583 }
1584 
1585 void cPixmapMemory::Scroll(const cPoint &Dest, const cRect &Source)
1586 {
1587  Lock();
1588  cRect s;
1589  if (&Source == &cRect::Null)
1590  s = DrawPort().Shifted(-DrawPort().Point());
1591  else
1592  s = Source.Intersected(DrawPort().Size());
1593  if (!s.IsEmpty()) {
1594  cPoint v = Dest - Source.Point();
1595  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1596  if (!d.IsEmpty()) {
1597  s = d.Shifted(-v);
1598  if (d.Point() != s.Point()) {
1599  int ws = DrawPort().Width();
1600  int wd = ws;
1601  int w = d.Width() * sizeof(tColor);
1602  const tColor *ps = data + ws * s.Top() + s.Left();
1603  tColor *pd = data + wd * d.Top() + d.Left();
1604  for (int y = d.Height(); y-- > 0; ) {
1605  memmove(pd, ps, w); // source and destination might overlap!
1606  ps += ws;
1607  pd += wd;
1608  }
1609  if (panning)
1610  SetDrawPortPoint(DrawPort().Point().Shifted(s.Point() - d.Point()), false);
1611  else
1612  MarkDrawPortDirty(d);
1613  }
1614  }
1615  }
1616  Unlock();
1617 }
1618 
1619 void cPixmapMemory::Pan(const cPoint &Dest, const cRect &Source)
1620 {
1621  Lock();
1622  panning = true;
1623  Scroll(Dest, Source);
1624  panning = false;
1625  Unlock();
1626 }
1627 
1628 // --- cOsd ------------------------------------------------------------------
1629 
1630 static const char *OsdErrorTexts[] = {
1631  "ok",
1632  "too many areas",
1633  "too many colors",
1634  "bpp not supported",
1635  "areas overlap",
1636  "wrong alignment",
1637  "out of memory",
1638  "wrong area size",
1639  "unknown",
1640  };
1641 
1642 int cOsd::osdLeft = 0;
1643 int cOsd::osdTop = 0;
1644 int cOsd::osdWidth = 0;
1645 int cOsd::osdHeight = 0;
1646 cSize cOsd::maxPixmapSize(INT_MAX, INT_MAX);
1649 
1650 cOsd::cOsd(int Left, int Top, uint Level)
1651 {
1652  cMutexLock MutexLock(&mutex);
1653  isTrueColor = false;
1654  savedBitmap = NULL;
1655  numBitmaps = 0;
1656  savedPixmap = NULL;
1657  left = Left;
1658  top = Top;
1659  width = height = 0;
1660  level = Level;
1661  active = false;
1662  for (int i = 0; i < Osds.Size(); i++) {
1663  if (Osds[i]->level > level) {
1664  Osds.Insert(this, i);
1665  return;
1666  }
1667  }
1668  Osds.Append(this);
1669 }
1670 
1672 {
1673  cMutexLock MutexLock(&mutex);
1674  for (int i = 0; i < numBitmaps; i++)
1675  delete bitmaps[i];
1676  delete savedBitmap;
1677  delete savedPixmap;
1678  for (int i = 0; i < pixmaps.Size(); i++)
1679  delete pixmaps[i];
1680  for (int i = 0; i < Osds.Size(); i++) {
1681  if (Osds[i] == this) {
1682  Osds.Remove(i);
1683  if (Osds.Size())
1684  Osds[0]->SetActive(true);
1685  break;
1686  }
1687  }
1688 }
1689 
1690 void cOsd::SetOsdPosition(int Left, int Top, int Width, int Height)
1691 {
1692  osdLeft = Left;
1693  osdTop = Top;
1696 }
1697 
1698 void cOsd::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
1699 {
1700  if (isTrueColor)
1701  return;
1702  for (int i = 0; i < numBitmaps; i++)
1703  bitmaps[i]->SetAntiAliasGranularity(FixedColors, BlendColors);
1704 }
1705 
1707 {
1708  return Area < numBitmaps ? (isTrueColor ? bitmaps[0] : bitmaps[Area]) : NULL;
1709 }
1710 
1711 const cSize &cOsd::MaxPixmapSize(void) const
1712 {
1713  return maxPixmapSize;
1714 }
1715 
1716 cPixmap *cOsd::CreatePixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1717 {
1718  if (isTrueColor) {
1719  LOCK_PIXMAPS;
1720  cPixmap *Pixmap = new cPixmapMemory(Layer, ViewPort, DrawPort);
1721  if (AddPixmap(Pixmap))
1722  return Pixmap;
1723  delete Pixmap;
1724  }
1725  return NULL;
1726 }
1727 
1729 {
1730  if (Pixmap) {
1731  LOCK_PIXMAPS;
1732  for (int i = 1; i < pixmaps.Size(); i++) { // begin at 1 - don't let the background pixmap be destroyed!
1733  if (pixmaps[i] == Pixmap) {
1734  if (Pixmap->Layer() >= 0)
1735  pixmaps[0]->MarkViewPortDirty(Pixmap->ViewPort());
1736  delete Pixmap;
1737  pixmaps[i] = NULL;
1738  return;
1739  }
1740  }
1741  esyslog("ERROR: attempt to destroy an unregistered pixmap");
1742  }
1743 }
1744 
1746 {
1747  if (Pixmap) {
1748  LOCK_PIXMAPS;
1749  for (int i = 0; i < pixmaps.Size(); i++) {
1750  if (!pixmaps[i])
1751  return pixmaps[i] = Pixmap;
1752  }
1753  pixmaps.Append(Pixmap);
1754  }
1755  return Pixmap;
1756 }
1757 
1759 {
1760  cPixmap *Pixmap = NULL;
1761  if (isTrueColor) {
1762  LOCK_PIXMAPS;
1763  // Collect overlapping dirty rectangles:
1764  cRect d;
1765  for (int i = 0; i < pixmaps.Size(); i++) {
1766  if (cPixmap *pm = pixmaps[i]) {
1767  if (!pm->DirtyViewPort().IsEmpty()) {
1768  if (d.IsEmpty() || d.Intersects(pm->DirtyViewPort())) {
1769  d.Combine(pm->DirtyViewPort());
1770  pm->SetClean();
1771  }
1772  }
1773  }
1774  }
1775  if (!d.IsEmpty()) {
1776 //#define DebugDirty
1777 #ifdef DebugDirty
1778  static cRect OldDirty;
1779  cRect NewDirty = d;
1780  d.Combine(OldDirty);
1781  OldDirty = NewDirty;
1782 #endif
1783  Pixmap = CreatePixmap(-1, d);
1784  if (Pixmap) {
1785  Pixmap->Clear();
1786  // Render the individual pixmaps into the resulting pixmap:
1787  for (int Layer = 0; Layer < MAXPIXMAPLAYERS; Layer++) {
1788  for (int i = 0; i < pixmaps.Size(); i++) {
1789  if (cPixmap *pm = pixmaps[i]) {
1790  if (pm->Layer() == Layer)
1791  Pixmap->DrawPixmap(pm, d);
1792  }
1793  }
1794  }
1795 #ifdef DebugDirty
1796  cPixmapMemory DirtyIndicator(7, NewDirty);
1797  static tColor DirtyIndicatorColors[] = { 0x7FFFFF00, 0x7F00FFFF };
1798  static int DirtyIndicatorIndex = 0;
1799  DirtyIndicator.Fill(DirtyIndicatorColors[DirtyIndicatorIndex]);
1800  DirtyIndicatorIndex = 1 - DirtyIndicatorIndex;
1801  Pixmap->Render(&DirtyIndicator, DirtyIndicator.DrawPort(), DirtyIndicator.ViewPort().Point().Shifted(-Pixmap->ViewPort().Point()));
1802 #endif
1803  }
1804  }
1805  }
1806  return Pixmap;
1807 }
1808 
1809 eOsdError cOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
1810 {
1811  if (NumAreas > MAXOSDAREAS)
1812  return oeTooManyAreas;
1813  eOsdError Result = oeOk;
1814  for (int i = 0; i < NumAreas; i++) {
1815  if (Areas[i].x1 > Areas[i].x2 || Areas[i].y1 > Areas[i].y2 || Areas[i].x1 < 0 || Areas[i].y1 < 0)
1816  return oeWrongAlignment;
1817  for (int j = i + 1; j < NumAreas; j++) {
1818  if (Areas[i].Intersects(Areas[j])) {
1819  Result = oeAreasOverlap;
1820  break;
1821  }
1822  }
1823  if (Areas[i].bpp == 32) {
1824  if (NumAreas > 1)
1825  return oeTooManyAreas;
1826  }
1827  }
1828  return Result;
1829 }
1830 
1831 eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas)
1832 {
1833  eOsdError Result = CanHandleAreas(Areas, NumAreas);
1834  if (Result == oeOk) {
1835  while (numBitmaps)
1836  delete bitmaps[--numBitmaps];
1837  for (int i = 0; i < pixmaps.Size(); i++) {
1838  delete pixmaps[i];
1839  pixmaps[i] = NULL;
1840  }
1841  width = height = 0;
1842  isTrueColor = NumAreas == 1 && Areas[0].bpp == 32;
1843  if (isTrueColor) {
1844  width = Areas[0].x2 - Areas[0].x1 + 1;
1845  height = Areas[0].y2 - Areas[0].y1 + 1;
1846  cPixmap *Pixmap = CreatePixmap(0, cRect(Areas[0].x1, Areas[0].y1, width, height));
1847  if (Pixmap)
1848  Pixmap->Clear();
1849  else
1850  Result = oeOutOfMemory;
1851  bitmaps[numBitmaps++] = new cBitmap(10, 10, 8); // dummy bitmap for GetBitmap()
1852  }
1853  else {
1854  for (int i = 0; i < NumAreas; i++) {
1855  bitmaps[numBitmaps++] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1);
1856  width = max(width, Areas[i].x2 + 1);
1857  height = max(height, Areas[i].y2 + 1);
1858  }
1859  }
1860  }
1861  else
1862  esyslog("ERROR: cOsd::SetAreas returned %d (%s)", Result, Result < oeUnknown ? OsdErrorTexts[Result] : OsdErrorTexts[oeUnknown]);
1863  return Result;
1864 }
1865 
1866 void cOsd::SaveRegion(int x1, int y1, int x2, int y2)
1867 {
1868  if (isTrueColor) {
1869  delete savedPixmap;
1870  cRect r(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
1871  savedPixmap = new cPixmapMemory(0, r);
1872  savedPixmap->Copy(pixmaps[0], r, cPoint(0, 0));
1873  }
1874  else {
1875  delete savedBitmap;
1876  savedBitmap = new cBitmap(x2 - x1 + 1, y2 - y1 + 1, 8, x1, y1);
1877  for (int i = 0; i < numBitmaps; i++)
1878  savedBitmap->DrawBitmap(bitmaps[i]->X0(), bitmaps[i]->Y0(), *bitmaps[i]);
1879  }
1880 }
1881 
1883 {
1884  if (isTrueColor) {
1885  if (savedPixmap) {
1887  delete savedPixmap;
1888  savedPixmap = NULL;
1889  }
1890  }
1891  else {
1892  if (savedBitmap) {
1894  delete savedBitmap;
1895  savedBitmap = NULL;
1896  }
1897  }
1898 }
1899 
1900 eOsdError cOsd::SetPalette(const cPalette &Palette, int Area)
1901 {
1902  if (isTrueColor)
1903  return oeOk;
1904  if (Area < numBitmaps) {
1905  bitmaps[Area]->Take(Palette);
1906  return oeOk;
1907  }
1908  return oeUnknown;
1909 }
1910 
1911 void cOsd::DrawImage(const cPoint &Point, const cImage &Image)
1912 {
1913  if (isTrueColor)
1914  pixmaps[0]->DrawImage(Point, Image);
1915 }
1916 
1917 void cOsd::DrawImage(const cPoint &Point, int ImageHandle)
1918 {
1919  if (isTrueColor)
1920  pixmaps[0]->DrawImage(Point, ImageHandle);
1921 }
1922 
1923 void cOsd::DrawPixel(int x, int y, tColor Color)
1924 {
1925  if (isTrueColor)
1926  pixmaps[0]->DrawPixel(cPoint(x, y), Color);
1927  else {
1928  for (int i = 0; i < numBitmaps; i++)
1929  bitmaps[i]->DrawPixel(x, y, Color);
1930  }
1931 }
1932 
1933 void cOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
1934 {
1935  if (isTrueColor)
1936  pixmaps[0]->DrawBitmap(cPoint(x, y), Bitmap, ColorFg, ColorBg, Overlay);
1937  else {
1938  for (int i = 0; i < numBitmaps; i++)
1939  bitmaps[i]->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg, ReplacePalette, Overlay);
1940  }
1941 }
1942 
1943 void cOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
1944 {
1945  const cBitmap *b = &Bitmap;
1946  if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0))
1947  b = b->Scaled(FactorX, FactorY, AntiAlias);
1948  DrawBitmap(x, y, *b);
1949  if (b != &Bitmap)
1950  delete b;
1951 }
1952 
1953 void cOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
1954 {
1955  if (isTrueColor)
1956  pixmaps[0]->DrawText(cPoint(x, y), s, ColorFg, ColorBg, Font, Width, Height, Alignment);
1957  else {
1958  for (int i = 0; i < numBitmaps; i++)
1959  bitmaps[i]->DrawText(x, y, s, ColorFg, ColorBg, Font, Width, Height, Alignment);
1960  }
1961 }
1962 
1963 void cOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
1964 {
1965  if (isTrueColor)
1966  pixmaps[0]->DrawRectangle(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color);
1967  else {
1968  for (int i = 0; i < numBitmaps; i++)
1969  bitmaps[i]->DrawRectangle(x1, y1, x2, y2, Color);
1970  }
1971 }
1972 
1973 void cOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
1974 {
1975  if (isTrueColor)
1976  pixmaps[0]->DrawEllipse(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Quadrants);
1977  else {
1978  for (int i = 0; i < numBitmaps; i++)
1979  bitmaps[i]->DrawEllipse(x1, y1, x2, y2, Color, Quadrants);
1980  }
1981 }
1982 
1983 void cOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
1984 {
1985  if (isTrueColor)
1986  pixmaps[0]->DrawSlope(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Type);
1987  else {
1988  for (int i = 0; i < numBitmaps; i++)
1989  bitmaps[i]->DrawSlope(x1, y1, x2, y2, Color, Type);
1990  }
1991 }
1992 
1993 void cOsd::Flush(void)
1994 {
1995 }
1996 
1997 // --- cOsdProvider ----------------------------------------------------------
1998 
2000 int cOsdProvider::oldWidth = 0;
2001 int cOsdProvider::oldHeight = 0;
2002 double cOsdProvider::oldAspect = 1.0;
2004 int cOsdProvider::osdState = 0;
2005 
2007 {
2008  delete osdProvider;
2009  osdProvider = this;
2010 }
2011 
2013 {
2014  osdProvider = NULL;
2015 }
2016 
2017 cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level)
2018 {
2019  cMutexLock MutexLock(&cOsd::mutex);
2020  if (Level == OSD_LEVEL_DEFAULT && cOsd::IsOpen())
2021  esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
2022  else if (osdProvider) {
2023  cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL;
2024  cOsd *Osd = osdProvider->CreateOsd(Left, Top, Level);
2025  if (Osd == cOsd::Osds[0]) {
2026  if (ActiveOsd)
2027  ActiveOsd->SetActive(false);
2028  Osd->SetActive(true);
2029  }
2030  return Osd;
2031  }
2032  else
2033  esyslog("ERROR: no OSD provider available - using dummy OSD!");
2034  return new cOsd(Left, Top, 999); // create a dummy cOsd, so that access won't result in a segfault
2035 }
2036 
2038 {
2039  int Width;
2040  int Height;
2041  double Aspect;
2042  cMutexLock MutexLock(&cOsd::mutex);
2043  cDevice::PrimaryDevice()->GetOsdSize(Width, Height, Aspect);
2044  if (Width != oldWidth || Height != oldHeight || !DoubleEqual(Aspect, oldAspect) || Force) {
2045  Setup.OSDLeft = int(round(Width * Setup.OSDLeftP));
2046  Setup.OSDTop = int(round(Height * Setup.OSDTopP));
2047  Setup.OSDWidth = min(Width - Setup.OSDLeft, int(round(Width * Setup.OSDWidthP))) & ~0x07; // OSD width must be a multiple of 8
2048  Setup.OSDHeight = min(Height - Setup.OSDTop, int(round(Height * Setup.OSDHeightP)));
2049  Setup.OSDAspect = Aspect;
2050  Setup.FontOsdSize = int(round(Height * Setup.FontOsdSizeP));
2051  Setup.FontFixSize = int(round(Height * Setup.FontFixSizeP));
2052  Setup.FontSmlSize = int(round(Height * Setup.FontSmlSizeP));
2056  oldWidth = Width;
2057  oldHeight = Height;
2058  oldAspect = Aspect;
2059  dsyslog("OSD size changed to %dx%d @ %g", Width, Height, Aspect);
2060  osdState++;
2061  }
2062 }
2063 
2065 {
2066  cMutexLock MutexLock(&cOsd::mutex);
2067  bool Result = osdState != State;
2068  State = osdState;
2069  return Result;
2070 }
2071 
2073 {
2074  if (osdProvider) {
2075  return osdProvider->ProvidesTrueColor();
2076  }
2077  else
2078  esyslog("ERROR: no OSD provider available in call to SupportsTrueColor()");
2079  return false;
2080 }
2081 
2083 {
2084  LOCK_PIXMAPS;
2085  for (int i = 1; i < MAXOSDIMAGES; i++) {
2086  if (!images[i]) {
2087  images[i] = new cImage(Image);
2088  return i;
2089  }
2090  }
2091  return 0;
2092 }
2093 
2094 void cOsdProvider::DropImageData(int ImageHandle)
2095 {
2096  LOCK_PIXMAPS;
2097  if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES) {
2098  delete images[ImageHandle];
2099  images[ImageHandle] = NULL;
2100  }
2101 }
2102 
2103 const cImage *cOsdProvider::GetImageData(int ImageHandle)
2104 {
2105  LOCK_PIXMAPS;
2106  if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES)
2107  return images[ImageHandle];
2108  return NULL;
2109 }
2110 
2112 {
2113  if (osdProvider)
2114  return osdProvider->StoreImageData(Image);
2115  return 0;
2116 }
2117 
2118 void cOsdProvider::DropImage(int ImageHandle)
2119 {
2120  if (osdProvider)
2121  osdProvider->DropImageData(ImageHandle);
2122 }
2123 
2125 {
2126  delete osdProvider;
2127  osdProvider = NULL;
2128 }
2129 
2130 // --- cTextScroller ---------------------------------------------------------
2131 
2133 {
2134  osd = NULL;
2135  left = top = width = height = 0;
2136  font = NULL;
2137  colorFg = 0;
2138  colorBg = 0;
2139  offset = 0;
2140  shown = 0;
2141 }
2142 
2143 cTextScroller::cTextScroller(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2144 {
2145  Set(Osd, Left, Top, Width, Height, Text, Font, ColorFg, ColorBg);
2146 }
2147 
2148 void cTextScroller::Set(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2149 {
2150  osd = Osd;
2151  left = Left;
2152  top = Top;
2153  width = Width;
2154  height = Height;
2155  font = Font;
2156  colorFg = ColorFg;
2157  colorBg = ColorBg;
2158  offset = 0;
2159  textWrapper.Set(Text, Font, Width);
2160  shown = min(Total(), height / font->Height());
2161  height = shown * font->Height(); // sets height to the actually used height, which may be less than Height
2162  DrawText();
2163 }
2164 
2166 {
2167  osd = NULL; // just makes sure it won't draw anything
2168 }
2169 
2171 {
2172  if (osd) {
2173  for (int i = 0; i < shown; i++)
2175  }
2176 }
2177 
2178 void cTextScroller::Scroll(bool Up, bool Page)
2179 {
2180  if (Up) {
2181  if (CanScrollUp()) {
2182  offset -= Page ? shown : 1;
2183  if (offset < 0)
2184  offset = 0;
2185  DrawText();
2186  }
2187  }
2188  else {
2189  if (CanScrollDown()) {
2190  offset += Page ? shown : 1;
2191  if (offset + shown > Total())
2192  offset = Total() - shown;
2193  DrawText();
2194  }
2195  }
2196 }
cBitmap::Data
const tIndex * Data(int x, int y) const
Returns the address of the index byte at the given coordinates.
Definition: osd.c:760
cPalette::bpp
int bpp
Definition: osd.h:91
cTextScroller::top
int top
Definition: osd.h:1038
cBitmap::~cBitmap
virtual ~cBitmap()
Definition: osd.c:289
cPixmap::viewPort
cRect viewPort
Definition: osd.h:462
cImage::size
cSize size
Definition: osd.h:421
cSize::Grow
void Grow(int Dw, int Dh)
Definition: osd.h:348
cPixmap::mutex
static cMutex mutex
Definition: osd.h:458
cOsd::Osds
static cVector< cOsd * > Osds
Definition: osd.h:728
cPalette::Bpp
int Bpp(void) const
Definition: osd.h:111
cRect::Height
int Height(void) const
Definition: osd.h:368
cBitmap::DrawSlope
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
cPoint::Shifted
cPoint Shifted(int Dx, int Dy) const
Definition: osd.h:326
cBitmap::dirtyY1
int dirtyY1
Definition: osd.h:174
cReadLine
Definition: tools.h:383
cPixmapMemory::DrawEllipse
virtual void DrawEllipse(const cRect &Rect, tColor Color, int Quadrants=0)
Draws a filled ellipse with the given Color that fits into the given rectangle.
Definition: osd.c:1379
cPixmap::drawPort
cRect drawPort
Definition: osd.h:463
cOsd::~cOsd
virtual ~cOsd()
Shuts down the OSD.
Definition: osd.c:1671
cOsdProvider::NewOsd
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:2017
cSize
Definition: osd.h:330
tColor
uint32_t tColor
Definition: font.h:29
cPixmapMemory::Clear
virtual void Clear(void)
Clears the pixmap's draw port by setting all pixels to be fully transparent.
Definition: osd.c:1162
cOsdProvider::images
static cImage * images[MAXOSDIMAGES]
Definition: osd.h:972
cOsd::savedPixmap
cPixmapMemory * savedPixmap
Definition: osd.h:735
cBitmap::SetIndex
void SetIndex(int x, int y, tIndex Index)
Sets the index at the given coordinates to Index.
Definition: osd.c:500
cBitmap::SetSize
void SetSize(int Width, int Height)
Sets the size of this bitmap to the given values.
Definition: osd.c:294
cOsdProvider::SupportsTrueColor
static bool SupportsTrueColor(void)
Returns true if the current OSD provider is able to handle a true color OSD.
Definition: osd.c:2072
cSetup::OSDLeft
int OSDLeft
Definition: config.h:323
cBitmap::dirtyX1
int dirtyX1
Definition: osd.h:174
cSize::Width
int Width(void) const
Definition: osd.h:341
cRect::size
cSize size
Definition: osd.h:355
oeOk
@ oeOk
Definition: osd.h:44
tIndex
uint8_t tIndex
Definition: font.h:31
cPixmap::Clear
virtual void Clear(void)=0
Clears the pixmap's draw port by setting all pixels to be fully transparent.
cRect::IsEmpty
bool IsEmpty(void) const
Returns true if this rectangle is empty.
Definition: osd.h:415
cSetup::OSDWidth
int OSDWidth
Definition: config.h:323
cBitmap::GetColor
tColor GetColor(int x, int y) const
Returns the color at the given coordinates.
Definition: osd.h:277
cRect::Size
const cSize & Size(void) const
Definition: osd.h:374
MAXOSDHEIGHT
#define MAXOSDHEIGHT
Definition: config.h:57
cOsd::width
int width
Definition: osd.h:737
cPixmap::Copy
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.
cBitmap::Fill
void Fill(tIndex Index)
Fills the bitmap data with the given Index.
Definition: osd.c:515
cPixmap::SetDrawPortPoint
virtual void SetDrawPortPoint(const cPoint &Point, bool Dirty=true)
Sets the pixmap's draw port to the given Point.
Definition: osd.c:1085
cPixmap::SetLayer
virtual void SetLayer(int Layer)
Sets the layer of this pixmap to the given value.
Definition: osd.c:1024
cFont::SetFont
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:405
cOsd::DrawPixel
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:1923
cTextScroller::CanScrollUp
bool CanScrollUp(void)
Definition: osd.h:1057
cTextScroller::left
int left
Definition: osd.h:1038
taRight
@ taRight
Definition: osd.h:160
cImage::Height
int Height(void) const
Definition: osd.h:436
cBitmap::DrawEllipse
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
cTextWrapper::GetLine
const char * GetLine(int Line)
Returns the given Line. The first line is numbered 0.
Definition: font.c:635
tArea::x2
int x2
Definition: osd.h:299
cOsd::osdWidth
static int osdWidth
Definition: osd.h:727
cPalette::Color
tColor Color(int Index) const
Returns the color at the given Index.
Definition: osd.h:119
cPixmapMemory::Scroll
virtual void Scroll(const cPoint &Dest, const cRect &Source=cRect::Null)
Scrolls the data in the pixmap's draw port to the given Dest point.
Definition: osd.c:1585
cOsd
The cOsd class is the interface to the "On Screen Display".
Definition: osd.h:724
cRect::Left
int Left(void) const
Definition: osd.h:369
cBitmap::Width
int Width(void) const
Definition: osd.h:188
cTextScroller::osd
cOsd * osd
Definition: osd.h:1037
cOsdProvider::oldAspect
static double oldAspect
Definition: osd.h:971
cPixmap::Alpha
int Alpha(void) const
Definition: osd.h:537
cOsd::maxPixmapSize
static cSize maxPixmapSize
Definition: osd.h:729
cRect::Width
int Width(void) const
Definition: osd.h:367
cPixmap::SetAlpha
virtual void SetAlpha(int Alpha)
Sets the alpha value of this pixmap to the given value.
Definition: osd.c:1046
cPixmapMemory::Pan
virtual void Pan(const cPoint &Dest, const cRect &Source=cRect::Null)
Does the same as Scroll(), but also shifts the draw port accordingly, so that the view port doesn't g...
Definition: osd.c:1619
constrain
T constrain(T v, T l, T h)
Definition: tools.h:68
RgbShade
tColor RgbShade(tColor Color, double Factor)
Returns a brighter (Factor > 0) or darker (Factor < 0) version of the given Color.
Definition: osd.c:43
cSetup::OSDTopP
double OSDTopP
Definition: config.h:322
cRect::SetTop
void SetTop(int Top)
Definition: osd.h:386
cOsd::CreatePixmap
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:1716
cOsd::savedBitmap
cBitmap * savedBitmap
Definition: osd.h:732
osd.h
cPixmap::SetClean
void SetClean(void)
Resets the "dirty" rectangles of this pixmap.
Definition: osd.c:1019
cBitmap::Scaled
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
cBitmap::DrawRectangle
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
cPoint::SetX
void SetX(int X)
Definition: osd.h:320
cSetup::FontOsdSize
int FontOsdSize
Definition: config.h:334
ALPHA_OPAQUE
#define ALPHA_OPAQUE
Definition: osd.h:26
cPixmap::SetViewPort
virtual void SetViewPort(const cRect &Rect)
Sets the pixmap's view port to the given Rect.
Definition: osd.c:1068
cSetup::OSDWidthP
double OSDWidthP
Definition: config.h:322
cTextScroller::height
int height
Definition: osd.h:1038
taBottom
@ taBottom
Definition: osd.h:162
taBorder
@ taBorder
Definition: osd.h:163
cBitmap::DrawText
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
cRect::Right
int Right(void) const
Definition: osd.h:371
cFont
Definition: font.h:37
cPalette
Definition: osd.h:88
cOsdProvider::UpdateOsdSize
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:2037
cPixmapMemory::panning
bool panning
Definition: osd.h:689
cPixmapMemory::cPixmapMemory
cPixmapMemory(void)
Definition: osd.c:1144
cTextScroller::Width
int Width(void)
Definition: osd.h:1051
cSetup::FontFix
char FontFix[MAXFONTNAME]
Definition: config.h:330
cOsd::SaveRegion
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:1866
cOsd::DestroyPixmap
virtual void DestroyPixmap(cPixmap *Pixmap)
Destroys the given Pixmap, which has previously been created by a call to CreatePixmap().
Definition: osd.c:1728
cMutexLock
Definition: thread.h:141
OsdErrorTexts
static const char * OsdErrorTexts[]
Definition: osd.c:1630
MAXNUMCOLORS
#define MAXNUMCOLORS
Definition: osd.h:24
cBitmap::bitmap
tIndex * bitmap
Definition: osd.h:171
cPalette::Reset
void Reset(void)
Resets the palette, making it contain no colors.
Definition: osd.c:138
cOsd::bitmaps
cBitmap * bitmaps[MAXOSDAREAS]
Definition: osd.h:733
AlphaBlend
tColor AlphaBlend(tColor ColorFg, tColor ColorBg, uint8_t AlphaLayer)
Definition: osd.c:81
cOsdProvider::CreateOsd
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.
tArea::bpp
int bpp
Definition: osd.h:300
cImage
Definition: osd.h:419
Setup
cSetup Setup
Definition: config.c:372
cDevice::PrimaryDevice
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:146
device.h
cBitmap::dirtyX2
int dirtyX2
Definition: osd.h:174
cPalette::antiAliasGranularity
double antiAliasGranularity
Definition: osd.h:94
cOsd::IsOpen
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition: osd.h:814
RgbToColor
tColor RgbToColor(uint8_t R, uint8_t G, uint8_t B)
Definition: osd.h:63
cTextScroller::Top
int Top(void)
Definition: osd.h:1050
cBitmap::x0
int x0
Definition: osd.h:172
cOsd::osdTop
static int osdTop
Definition: osd.h:727
cOsd::DrawImage
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image on this OSD at the given Point.
Definition: osd.c:1911
cPixmapMemory::data
tColor * data
Definition: osd.h:688
cBitmap::LoadXpm
bool LoadXpm(const char *FileName)
Calls SetXpm() with the data from the file FileName.
Definition: osd.c:362
cCursesFont::Width
virtual int Width(void) const
Returns the original character width as requested when the font was created, or 0 if the default widt...
Definition: skincurses.c:24
cVector< cOsd * >
cBitmap::Intersects
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
fontFix
@ fontFix
Definition: font.h:23
cRect::Combine
void Combine(const cRect &Rect)
Combines this rectangle with the given Rect.
Definition: osd.c:934
cOsd::DrawEllipse
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:1973
cTextScroller::shown
int shown
Definition: osd.h:1041
cOsdProvider::oldHeight
static int oldHeight
Definition: osd.h:970
oeTooManyAreas
@ oeTooManyAreas
Definition: osd.h:45
taLeft
@ taLeft
Definition: osd.h:159
cPixmapMemory::Copy
virtual void Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
Copies the part of the given Pixmap covered by Source into this pixmap at location Dest.
Definition: osd.c:1558
cSetup::FontFixSize
int FontFixSize
Definition: config.h:336
cMutex
Definition: thread.h:67
cPalette::SetBpp
void SetBpp(int Bpp)
Sets the color depth of this palette to the given value.
Definition: osd.c:165
AlphaLutAlpha
static uint8_t AlphaLutAlpha[255][256]
Definition: osd.c:59
cPixmap::Layer
int Layer(void) const
Definition: osd.h:536
cPalette::Colors
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
DoubleEqual
bool DoubleEqual(double a, double b)
Definition: tools.h:95
cBitmap::cBitmap
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
cOsdProvider::~cOsdProvider
virtual ~cOsdProvider()
Definition: osd.c:2012
cBitmap::Clean
void Clean(void)
Marks the dirty area as clean.
Definition: osd.c:354
cOsd::RestoreRegion
virtual void RestoreRegion(void)
Restores the region previously saved by a call to SaveRegion().
Definition: osd.c:1882
cTextScroller::Scroll
void Scroll(bool Up, bool Page)
Definition: osd.c:2178
cSetup::FontSml
char FontSml[MAXFONTNAME]
Definition: config.h:329
cPoint
Definition: osd.h:306
oeWrongAlignment
@ oeWrongAlignment
Definition: osd.h:49
cRect::Point
const cPoint & Point(void) const
Definition: osd.h:373
cImage::data
tColor * data
Definition: osd.h:422
MAXOSDWIDTH
#define MAXOSDWIDTH
Definition: config.h:55
cOsd::DrawSlope
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:1983
cOsd::osdLeft
static int osdLeft
Definition: osd.h:727
cPalette::cPalette
cPalette(int Bpp=8)
Initializes the palette with the given color depth.
Definition: osd.c:117
cOsdProvider::Shutdown
static void Shutdown(void)
Shuts down the OSD provider facility by deleting the current OSD provider.
Definition: osd.c:2124
cTextScroller::Set
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:2148
cImage::~cImage
virtual ~cImage()
Definition: osd.c:1126
cBitmap
Definition: osd.h:169
tArea::x1
int x1
Definition: osd.h:299
cRect::Contains
bool Contains(const cPoint &Point) const
Returns true if this rectangle contains Point.
Definition: osd.c:898
cPixmapMemory::Fill
virtual void Fill(tColor Color)
Fills the pixmap's draw port with the given Color.
Definition: osd.c:1170
cPixmapMemory::DrawPixel
virtual void DrawPixel(const cPoint &Point, tColor Color)
Sets the pixel at the given Point to the given Color, which is a full 32 bit ARGB value.
Definition: osd.c:1262
cOsdProvider::StoreImage
static int StoreImage(const cImage &Image)
Stores the given Image for later use with DrawImage() on an OSD or pixmap.
Definition: osd.c:2111
cBitmap::Contains
bool Contains(int x, int y) const
Returns true if this bitmap contains the point (x, y).
Definition: osd.c:317
cPixmap::Unlock
static void Unlock(void)
Definition: osd.h:535
cSetup::OSDHeight
int OSDHeight
Definition: config.h:323
cPixmap::Tile
bool Tile(void) const
Definition: osd.h:538
cImage::Clear
void Clear(void)
Clears the image data by setting all pixels to be fully transparent.
Definition: osd.c:1131
MAXPIXMAPLAYERS
#define MAXPIXMAPLAYERS
Definition: osd.h:452
cRect::SetPoint
void SetPoint(int X, int Y)
Definition: osd.h:377
cFont::Height
virtual int Height(void) const =0
Returns the height of this font in pixel (all characters have the same height).
cRect::Set
void Set(int X, int Y, int Width, int Height)
Definition: osd.h:375
cOsd::MaxPixmapSize
virtual const cSize & MaxPixmapSize(void) const
Returns the maximum possible size of a pixmap this OSD can create.
Definition: osd.c:1711
cOsd::GetBitmap
cBitmap * GetBitmap(int Area)
Returns a pointer to the bitmap for the given Area, or NULL if no such bitmap exists.
Definition: osd.c:1706
cOsd::SetActive
virtual void SetActive(bool On)
Sets this OSD to be the active one.
Definition: osd.h:762
oeOutOfMemory
@ oeOutOfMemory
Definition: osd.h:50
cRect::Grow
void Grow(int Dx, int Dy)
Grows the rectangle by the given number of pixels in either direction.
Definition: osd.c:892
cTextScroller::font
const cFont * font
Definition: osd.h:1039
cBitmap::X0
int X0(void) const
Definition: osd.h:186
cOsd::RenderPixmaps
cPixmap * RenderPixmaps(void)
Renders the dirty part of all pixmaps into a resulting pixmap that shall be displayed on the OSD.
Definition: osd.c:1758
cPixmap::DrawPixmap
virtual void DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
Draws the Dirty part of the given Pixmap into this pixmap.
Definition: osd.c:1179
cOsd::level
uint level
Definition: osd.h:738
cTextScroller::Total
int Total(void)
Definition: osd.h:1053
cCursesFont::DrawText
virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const
Draws the given text into the Bitmap at position (x, y) with the given colors.
Definition: skincurses.c:28
cPixmapMemory::Render
virtual void Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
Renders the part of the given Pixmap covered by Source into this pixmap at location Dest.
Definition: osd.c:1523
cVector::Remove
virtual void Remove(int Index)
Definition: tools.h:751
tArea
Definition: osd.h:298
cImage::Data
const tColor * Data(void) const
Definition: osd.h:437
cRect::Intersected
cRect Intersected(const cRect &Rect) const
Returns the intersection of this rectangle and the given Rect.
Definition: osd.c:922
cPoint::X
int X(void) const
Definition: osd.h:318
cBitmap::y0
int y0
Definition: osd.h:172
clrTransparent
@ clrTransparent
Definition: osd.h:32
cOsd::height
int height
Definition: osd.h:737
cOsd::osdHeight
static int osdHeight
Definition: osd.h:727
cRect::Shifted
cRect Shifted(int Dx, int Dy) const
Definition: osd.h:391
cPixmapMemory::DrawText
virtual void DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width=0, int Height=0, int Alignment=taDefault)
Draws the given string at Point with the given foreground and background color and font.
Definition: osd.c:1303
cPixmap::tile
bool tile
Definition: osd.h:461
cPixmapMemory
Definition: osd.h:686
cRect::Bottom
int Bottom(void) const
Definition: osd.h:372
cVector::Size
int Size(void) const
Definition: tools.h:717
cSetup::OSDAspect
double OSDAspect
Definition: config.h:324
cPixmapMemory::DrawImage
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image into this pixmap at the given Point.
Definition: osd.c:1230
cRect::SetBottom
void SetBottom(int Bottom)
Definition: osd.h:388
cPixmap
Definition: osd.h:454
cRect::SetLeft
void SetLeft(int Left)
Definition: osd.h:385
cOsd::isTrueColor
bool isTrueColor
Definition: osd.h:731
cPalette::SetColor
void SetColor(int Index, tColor Color)
Sets the palette entry at Index to Color.
Definition: osd.c:172
cOsd::Top
int Top(void)
Definition: osd.h:820
cOsd::cOsd
cOsd(int Left, int Top, uint Level)
Initializes the OSD with the given coordinates.
Definition: osd.c:1650
cPalette::Take
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
cPoint::Shift
void Shift(int Dx, int Dy)
Definition: osd.h:324
cBitmap::DrawBitmap
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
cRect::SetRight
void SetRight(int Right)
Definition: osd.h:387
cBitmap::Covers
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
cTextScroller::colorFg
tColor colorFg
Definition: osd.h:1040
cRect::Top
int Top(void) const
Definition: osd.h:370
cOsd::SetAntiAliasGranularity
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
Allows the system to optimize utilization of the limited color palette entries when generating blende...
Definition: osd.c:1698
cOsd::active
bool active
Definition: osd.h:739
cOsd::Left
int Left(void)
Definition: osd.h:819
cOsd::DrawRectangle
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:1963
cImage::Size
const cSize & Size(void) const
Definition: osd.h:434
dsyslog
#define dsyslog(a...)
Definition: tools.h:37
cSetup::FontOsdSizeP
double FontOsdSizeP
Definition: config.h:331
cImage::Fill
void Fill(tColor Color)
Fills the image data with the given Color.
Definition: osd.c:1136
cInitAlphaLut::cInitAlphaLut
cInitAlphaLut(void)
Definition: osd.c:63
cOsd::numBitmaps
int numBitmaps
Definition: osd.h:734
cOsdProvider::OsdSizeChanged
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition: osd.c:2064
InitAlphaLut
class cInitAlphaLut InitAlphaLut
cDevice::GetOsdSize
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:521
cPalette::ClosestColor
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
cPalette::maxColors
int maxColors
Definition: osd.h:92
HsvToColor
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
cBitmap::width
int width
Definition: osd.h:173
cTextScroller::cTextScroller
cTextScroller(void)
Definition: osd.c:2132
MALLOC
#define MALLOC(type, size)
Definition: tools.h:47
TEXT_ALIGN_BORDER
#define TEXT_ALIGN_BORDER
Definition: osd.h:28
MINOSDHEIGHT
#define MINOSDHEIGHT
Definition: config.h:56
cRect::Null
static const cRect Null
Definition: osd.h:357
cTextScroller::DrawText
void DrawText(void)
Definition: osd.c:2170
cPixmap::MarkDrawPortDirty
void MarkDrawPortDirty(const cRect &Rect)
Marks the given rectangle of the draw port of this pixmap as dirty.
Definition: osd.c:999
cOsdProvider::ProvidesTrueColor
virtual bool ProvidesTrueColor(void)
Returns true if this OSD provider is able to handle a true color OSD.
Definition: osd.h:978
cSetup::FontSmlSize
int FontSmlSize
Definition: config.h:335
cBitmap::dirtyY2
int dirtyY2
Definition: osd.h:174
cBitmap::SetXpm
bool SetXpm(const char *const Xpm[], bool IgnoreNone=false)
Sets this bitmap to the given XPM data.
Definition: osd.c:428
cBitmap::Y0
int Y0(void) const
Definition: osd.h:187
cPalette::Blend
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
skipspace
char * skipspace(const char *s)
Definition: tools.h:209
cOsd::SetAreas
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas)
Sets the sub-areas to the given areas.
Definition: osd.c:1831
cPixmapMemory::DrawRectangle
virtual void DrawRectangle(const cRect &Rect, tColor Color)
Draws a filled rectangle with the given Color.
Definition: osd.c:1352
cRect::point
cPoint point
Definition: osd.h:354
cPixmapMemory::~cPixmapMemory
virtual ~cPixmapMemory()
Definition: osd.c:1157
cOsdProvider::StoreImageData
virtual int StoreImageData(const cImage &Image)
Copies the given Image and returns a handle for later reference.
Definition: osd.c:2082
cTextScroller::Height
int Height(void)
Definition: osd.h:1052
cOsdProvider::DropImageData
virtual void DropImageData(int ImageHandle)
Drops the image data referenced by ImageHandle.
Definition: osd.c:2094
cPixmap::ViewPort
const cRect & ViewPort(void) const
Returns the pixmap's view port, which is relative to the OSD's origin.
Definition: osd.h:539
cSetup::OSDTop
int OSDTop
Definition: config.h:323
cInitAlphaLut
Definition: osd.c:61
cOsd::left
int left
Definition: osd.h:737
fontOsd
@ fontOsd
Definition: font.h:22
cBitmap::ReduceBpp
void ReduceBpp(const cPalette &Palette)
Reduces the color depth of the bitmap to that of the given Palette.
Definition: osd.c:765
cOsdProvider::cOsdProvider
cOsdProvider(void)
Definition: osd.c:2006
AlphaLutFactors
static uint16_t AlphaLutFactors[255][256][2]
Definition: osd.c:58
cBitmap::Dirty
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
cOsdProvider
Definition: osd.h:965
taTop
@ taTop
Definition: osd.h:161
cVector::Insert
virtual void Insert(T Data, int Before=0)
Definition: tools.h:718
cImage::Width
int Width(void) const
Definition: osd.h:435
cImage::cImage
cImage(void)
Definition: osd.c:1104
cRect::Shift
void Shift(int Dx, int Dy)
Definition: osd.h:389
MAXOSDAREAS
#define MAXOSDAREAS
Definition: osd.h:711
MAXOSDIMAGES
#define MAXOSDIMAGES
Definition: osd.h:963
cPixmapMemory::DrawSlope
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type)
Draws a "slope" with the given Color into the given rectangle.
Definition: osd.c:1481
cTextScroller::offset
int offset
Definition: osd.h:1041
cPalette::~cPalette
virtual ~cPalette()
Definition: osd.c:123
cTextScroller::colorBg
tColor colorBg
Definition: osd.h:1040
cPixmap::DrawPort
const cRect & DrawPort(void) const
Returns the pixmap's draw port, which is relative to the view port.
Definition: osd.h:543
cPixmap::Lock
static void Lock(void)
All public member functions of cPixmap set locks as necessary to make sure they are thread-safe (unle...
Definition: osd.h:529
OSD_LEVEL_DEFAULT
#define OSD_LEVEL_DEFAULT
Definition: osd.h:21
cOsd::DrawScaledBitmap
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:1943
cPalette::color
tColor color[MAXNUMCOLORS]
Definition: osd.h:90
max
T max(T a, T b)
Definition: tools.h:60
cOsd::Height
int Height(void)
Definition: osd.h:822
cSize::Height
int Height(void) const
Definition: osd.h:342
cOsd::DrawBitmap
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:1933
MINOSDWIDTH
#define MINOSDWIDTH
Definition: config.h:54
cOsdProvider::osdState
static int osdState
Definition: osd.h:973
cBitmap::Height
int Height(void) const
Definition: osd.h:189
ALPHA_TRANSPARENT
#define ALPHA_TRANSPARENT
Definition: osd.h:25
cOsd::SetOsdPosition
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:1690
cPixmap::alpha
int alpha
Definition: osd.h:460
cPixmapMemory::DrawBitmap
virtual void DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg=0, tColor ColorBg=0, bool Overlay=false)
Sets the pixels in the OSD with the data from the given Bitmap, putting the upper left corner of the ...
Definition: osd.c:1276
LOCK_PIXMAPS
#define LOCK_PIXMAPS
Definition: osd.h:681
cOsd::pixmaps
cVector< cPixmap * > pixmaps
Definition: osd.h:736
cOsd::CanHandleAreas
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas)
Checks whether the OSD can display the given set of sub-areas.
Definition: osd.c:1809
cTextScroller::textWrapper
cTextWrapper textWrapper
Definition: osd.h:1042
cOsd::DrawText
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:1953
cReadLine::Read
char * Read(FILE *f)
Definition: tools.c:1459
cOsd::SetPalette
virtual eOsdError SetPalette(const cPalette &Palette, int Area)
Sets the Palette for the given Area (the first area is numbered 0).
Definition: osd.c:1900
cPalette::tIndexes
tIndex tIndexes[MAXNUMCOLORS]
Definition: osd.h:96
cPixmap::layer
int layer
Definition: osd.h:459
min
T min(T a, T b)
Definition: tools.h:59
cTextScroller::Reset
void Reset(void)
Definition: osd.c:2165
cVector::Append
virtual void Append(T Data)
Definition: tools.h:737
tArea::y1
int y1
Definition: osd.h:299
cPixmap::Render
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.
cSetup::OSDHeightP
double OSDHeightP
Definition: config.h:322
cOsdProvider::osdProvider
static cOsdProvider * osdProvider
Definition: osd.h:968
tools.h
cPixmap::dirtyDrawPort
cRect dirtyDrawPort
Definition: osd.h:465
cPixmap::dirtyViewPort
cRect dirtyViewPort
Definition: osd.h:464
cTextScroller::Left
int Left(void)
Definition: osd.h:1049
cPalette::Index
int Index(tColor Color)
Returns the index of the given Color (the first color has index 0).
Definition: osd.c:144
cOsd::mutex
static cMutex mutex
Definition: osd.h:730
IS_OPAQUE
#define IS_OPAQUE(c)
Definition: osd.h:27
cRect::Intersects
bool Intersects(const cRect &Rect) const
Returns true if this rectangle intersects with Rect.
Definition: osd.c:914
oeUnknown
@ oeUnknown
Definition: osd.h:52
cCursesFont::Height
virtual int Height(void) const
Returns the height of this font in pixel (all characters have the same height).
Definition: skincurses.c:27
cPalette::Replace
void Replace(const cPalette &Palette)
Replaces the colors of this palette with the colors from the given palette.
Definition: osd.c:208
cPixmap::SetTile
virtual void SetTile(bool Tile)
Sets the tile property of this pixmap to the given value.
Definition: osd.c:1057
cOsd::Flush
virtual void Flush(void)
Actually commits all data to the OSD hardware.
Definition: osd.c:1993
cOsd::Width
int Width(void)
Definition: osd.h:821
cTextScroller::width
int width
Definition: osd.h:1038
cOsd::AddPixmap
cPixmap * AddPixmap(cPixmap *Pixmap)
Adds the given Pixmap to the list of currently active pixmaps in this OSD.
Definition: osd.c:1745
oeAreasOverlap
@ oeAreasOverlap
Definition: osd.h:48
cSetup::FontOsd
char FontOsd[MAXFONTNAME]
Definition: config.h:328
esyslog
#define esyslog(a...)
Definition: tools.h:35
eOsdError
eOsdError
Definition: osd.h:44
cBitmap::height
int height
Definition: osd.h:173
Font
static const cCursesFont Font
Definition: skincurses.c:32
cTextScroller::CanScrollDown
bool CanScrollDown(void)
Definition: osd.h:1058
cPalette::numColors
int numColors
Definition: osd.h:92
cSetup::FontFixSizeP
double FontFixSizeP
Definition: config.h:333
cPoint::Y
int Y(void) const
Definition: osd.h:319
cPalette::modified
bool modified
Definition: osd.h:93
cSetup::OSDLeftP
double OSDLeftP
Definition: config.h:322
cOsd::top
int top
Definition: osd.h:737
cPixmap::cPixmap
cPixmap(void)
Definition: osd.c:962
tArea::y2
int y2
Definition: osd.h:299
cRect
Definition: osd.h:352
cBitmap::ShrinkBpp
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
cOsdProvider::oldWidth
static int oldWidth
Definition: osd.h:969
cTextWrapper::Set
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:563
cOsdProvider::GetImageData
static const cImage * GetImageData(int ImageHandle)
Gets the image data referenced by ImageHandle.
Definition: osd.c:2103
cPalette::SetAntiAliasGranularity
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
cOsdProvider::DropImage
static void DropImage(int ImageHandle)
Drops the image referenced by the given ImageHandle.
Definition: osd.c:2118
cPixmap::MarkViewPortDirty
void MarkViewPortDirty(const cRect &Rect)
Marks the given rectangle of the view port of this pixmap as dirty.
Definition: osd.c:987
cSetup::FontSmlSizeP
double FontSmlSizeP
Definition: config.h:332
cBitmap::DrawPixel
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