vdr  2.0.6
osd.c
Go to the documentation of this file.
1 /*
2  * osd.c: Abstract On Screen Display layer
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: osd.c 2.38.1.1 2013/05/18 12:41:48 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  }
79  } InitAlphaLut;
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 
515 void cBitmap::DrawPixel(int x, int y, tColor Color)
516 {
517  x -= x0;
518  y -= y0;
519  SetIndex(x, y, Index(Color));
520 }
521 
522 void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
523 {
524  if (bitmap && Bitmap.bitmap && Intersects(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) {
525  if (Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1))
526  Reset();
527  x -= x0;
528  y -= y0;
529  if (ReplacePalette && Covers(x + x0, y + y0, x + x0 + Bitmap.Width() - 1, y + y0 + Bitmap.Height() - 1)) {
530  Replace(Bitmap);
531  for (int ix = 0; ix < Bitmap.width; ix++) {
532  for (int iy = 0; iy < Bitmap.height; iy++) {
533  if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0)
534  SetIndex(x + ix, y + iy, Bitmap.bitmap[Bitmap.width * iy + ix]);
535  }
536  }
537  }
538  else {
539  tIndexes Indexes;
540  Take(Bitmap, &Indexes, ColorFg, ColorBg);
541  for (int ix = 0; ix < Bitmap.width; ix++) {
542  for (int iy = 0; iy < Bitmap.height; iy++) {
543  if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0)
544  SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]);
545  }
546  }
547  }
548  }
549 }
550 
551 void cBitmap::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
552 {
553  if (bitmap) {
554  int w = Font->Width(s);
555  int h = Font->Height();
556  int limit = 0;
557  int cw = Width ? Width : w;
558  int ch = Height ? Height : h;
559  if (!Intersects(x, y, x + cw - 1, y + ch - 1))
560  return;
561  if (ColorBg != clrTransparent)
562  DrawRectangle(x, y, x + cw - 1, y + ch - 1, ColorBg);
563  if (Width || Height) {
564  limit = x + cw - x0;
565  if (Width) {
566  if ((Alignment & taLeft) != 0) {
567  if ((Alignment & taBorder) != 0)
568  x += max(h / TEXT_ALIGN_BORDER, 1);
569  }
570  else if ((Alignment & taRight) != 0) {
571  if (w < Width)
572  x += Width - w;
573  if ((Alignment & taBorder) != 0)
574  x -= max(h / TEXT_ALIGN_BORDER, 1);
575  }
576  else { // taCentered
577  if (w < Width)
578  x += (Width - w) / 2;
579  }
580  }
581  if (Height) {
582  if ((Alignment & taTop) != 0)
583  ;
584  else if ((Alignment & taBottom) != 0) {
585  if (h < Height)
586  y += Height - h;
587  }
588  else { // taCentered
589  if (h < Height)
590  y += (Height - h) / 2;
591  }
592  }
593  }
594  x -= x0;
595  y -= y0;
596  Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
597  }
598 }
599 
600 void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
601 {
602  if (bitmap && Intersects(x1, y1, x2, y2)) {
603  if (Covers(x1, y1, x2, y2))
604  Reset();
605  x1 -= x0;
606  y1 -= y0;
607  x2 -= x0;
608  y2 -= y0;
609  x1 = max(x1, 0);
610  y1 = max(y1, 0);
611  x2 = min(x2, width - 1);
612  y2 = min(y2, height - 1);
613  tIndex c = Index(Color);
614  for (int y = y1; y <= y2; y++) {
615  for (int x = x1; x <= x2; x++)
616  SetIndex(x, y, c);
617  }
618  }
619 }
620 
621 void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
622 {
623  if (!Intersects(x1, y1, x2, y2))
624  return;
625  // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF
626  int rx = x2 - x1;
627  int ry = y2 - y1;
628  int cx = (x1 + x2) / 2;
629  int cy = (y1 + y2) / 2;
630  switch (abs(Quadrants)) {
631  case 0: rx /= 2; ry /= 2; break;
632  case 1: cx = x1; cy = y2; break;
633  case 2: cx = x2; cy = y2; break;
634  case 3: cx = x2; cy = y1; break;
635  case 4: cx = x1; cy = y1; break;
636  case 5: cx = x1; ry /= 2; break;
637  case 6: cy = y2; rx /= 2; break;
638  case 7: cx = x2; ry /= 2; break;
639  case 8: cy = y1; rx /= 2; break;
640  default: ;
641  }
642  int TwoASquare = max(1, 2 * rx * rx);
643  int TwoBSquare = max(1, 2 * ry * ry);
644  int x = rx;
645  int y = 0;
646  int XChange = ry * ry * (1 - 2 * rx);
647  int YChange = rx * rx;
648  int EllipseError = 0;
649  int StoppingX = TwoBSquare * rx;
650  int StoppingY = 0;
651  while (StoppingX >= StoppingY) {
652  switch (Quadrants) {
653  case 5: DrawRectangle(cx, cy + y, cx + x, cy + y, Color); // no break
654  case 1: DrawRectangle(cx, cy - y, cx + x, cy - y, Color); break;
655  case 7: DrawRectangle(cx - x, cy + y, cx, cy + y, Color); // no break
656  case 2: DrawRectangle(cx - x, cy - y, cx, cy - y, Color); break;
657  case 3: DrawRectangle(cx - x, cy + y, cx, cy + y, Color); break;
658  case 4: DrawRectangle(cx, cy + y, cx + x, cy + y, Color); break;
659  case 0:
660  case 6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, Color); if (Quadrants == 6) break;
661  case 8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, Color); break;
662  case -1: DrawRectangle(cx + x, cy - y, x2, cy - y, Color); break;
663  case -2: DrawRectangle(x1, cy - y, cx - x, cy - y, Color); break;
664  case -3: DrawRectangle(x1, cy + y, cx - x, cy + y, Color); break;
665  case -4: DrawRectangle(cx + x, cy + y, x2, cy + y, Color); break;
666  default: ;
667  }
668  y++;
669  StoppingY += TwoASquare;
670  EllipseError += YChange;
671  YChange += TwoASquare;
672  if (2 * EllipseError + XChange > 0) {
673  x--;
674  StoppingX -= TwoBSquare;
675  EllipseError += XChange;
676  XChange += TwoBSquare;
677  }
678  }
679  x = 0;
680  y = ry;
681  XChange = ry * ry;
682  YChange = rx * rx * (1 - 2 * ry);
683  EllipseError = 0;
684  StoppingX = 0;
685  StoppingY = TwoASquare * ry;
686  while (StoppingX <= StoppingY) {
687  switch (Quadrants) {
688  case 5: DrawRectangle(cx, cy + y, cx + x, cy + y, Color); // no break
689  case 1: DrawRectangle(cx, cy - y, cx + x, cy - y, Color); break;
690  case 7: DrawRectangle(cx - x, cy + y, cx, cy + y, Color); // no break
691  case 2: DrawRectangle(cx - x, cy - y, cx, cy - y, Color); break;
692  case 3: DrawRectangle(cx - x, cy + y, cx, cy + y, Color); break;
693  case 4: DrawRectangle(cx, cy + y, cx + x, cy + y, Color); break;
694  case 0:
695  case 6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, Color); if (Quadrants == 6) break;
696  case 8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, Color); break;
697  case -1: DrawRectangle(cx + x, cy - y, x2, cy - y, Color); break;
698  case -2: DrawRectangle(x1, cy - y, cx - x, cy - y, Color); break;
699  case -3: DrawRectangle(x1, cy + y, cx - x, cy + y, Color); break;
700  case -4: DrawRectangle(cx + x, cy + y, x2, cy + y, Color); break;
701  default: ;
702  }
703  x++;
704  StoppingX += TwoBSquare;
705  EllipseError += XChange;
706  XChange += TwoBSquare;
707  if (2 * EllipseError + YChange > 0) {
708  y--;
709  StoppingY -= TwoASquare;
710  EllipseError += YChange;
711  YChange += TwoASquare;
712  }
713  }
714 }
715 
716 void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
717 {
718  if (!Intersects(x1, y1, x2, y2))
719  return;
720  bool upper = Type & 0x01;
721  bool falling = Type & 0x02;
722  bool vertical = Type & 0x04;
723  if (vertical) {
724  for (int y = y1; y <= y2; y++) {
725  double c = cos((y - y1) * M_PI / (y2 - y1 + 1));
726  if (falling)
727  c = -c;
728  int x = int((x2 - x1 + 1) * c / 2);
729  if (upper && !falling || !upper && falling)
730  DrawRectangle(x1, y, (x1 + x2) / 2 + x, y, Color);
731  else
732  DrawRectangle((x1 + x2) / 2 + x, y, x2, y, Color);
733  }
734  }
735  else {
736  for (int x = x1; x <= x2; x++) {
737  double c = cos((x - x1) * M_PI / (x2 - x1 + 1));
738  if (falling)
739  c = -c;
740  int y = int((y2 - y1 + 1) * c / 2);
741  if (upper)
742  DrawRectangle(x, y1, x, (y1 + y2) / 2 + y, Color);
743  else
744  DrawRectangle(x, (y1 + y2) / 2 + y, x, y2, Color);
745  }
746  }
747 }
748 
749 const tIndex *cBitmap::Data(int x, int y) const
750 {
751  return &bitmap[y * width + x];
752 }
753 
754 void cBitmap::ReduceBpp(const cPalette &Palette)
755 {
756  int NewBpp = Palette.Bpp();
757  if (Bpp() == 4 && NewBpp == 2) {
758  for (int i = width * height; i--; ) {
759  tIndex p = bitmap[i];
760  bitmap[i] = (p >> 2) | ((p & 0x03) != 0);
761  }
762  }
763  else if (Bpp() == 8) {
764  if (NewBpp == 2) {
765  for (int i = width * height; i--; ) {
766  tIndex p = bitmap[i];
767  bitmap[i] = (p >> 6) | ((p & 0x30) != 0);
768  }
769  }
770  else if (NewBpp == 4) {
771  for (int i = width * height; i--; ) {
772  tIndex p = bitmap[i];
773  bitmap[i] = p >> 4;
774  }
775  }
776  else
777  return;
778  }
779  else
780  return;
781  SetBpp(NewBpp);
782  Replace(Palette);
783 }
784 
785 void cBitmap::ShrinkBpp(int NewBpp)
786 {
787  int NumOldColors;
788  const tColor *Colors = this->Colors(NumOldColors);
789  if (Colors) {
790  // Find the most frequently used colors and create a map table:
791  int Used[MAXNUMCOLORS] = { 0 };
792  int Map[MAXNUMCOLORS] = { 0 };
793  for (int i = width * height; i--; )
794  Used[bitmap[i]]++;
795  int MaxNewColors = (NewBpp == 4) ? 16 : 4;
796  cPalette NewPalette(NewBpp);
797  for (int i = 0; i < MaxNewColors; i++) {
798  int Max = 0;
799  int Index = -1;
800  for (int n = 0; n < NumOldColors; n++) {
801  if (Used[n] > Max) {
802  Max = Used[n];
803  Index = n;
804  }
805  }
806  if (Index >= 0) {
807  Used[Index] = 0;
808  Map[Index] = i;
809  NewPalette.SetColor(i, Colors[Index]);
810  }
811  else
812  break;
813  }
814  // Complete the map table for all other colors (will be set to closest match):
815  for (int n = 0; n < NumOldColors; n++) {
816  if (Used[n])
817  Map[n] = NewPalette.Index(Colors[n]);
818  }
819  // Do the actual index mapping:
820  for (int i = width * height; i--; )
821  bitmap[i] = Map[bitmap[i]];
822  SetBpp(NewBpp);
823  Replace(NewPalette);
824  }
825 }
826 
827 cBitmap *cBitmap::Scaled(double FactorX, double FactorY, bool AntiAlias)
828 {
829  // Fixed point scaling code based on www.inversereality.org/files/bitmapscaling.pdf
830  // by deltener@mindtremors.com
831  cBitmap *b = new cBitmap(int(round(Width() * FactorX)), int(round(Height() * FactorY)), Bpp(), X0(), Y0());
832  int RatioX = (Width() << 16) / b->Width();
833  int RatioY = (Height() << 16) / b->Height();
834  if (!AntiAlias || FactorX <= 1.0 && FactorY <= 1.0) {
835  // Downscaling - no anti-aliasing:
836  b->Replace(*this); // copy palette
837  tIndex *DestRow = b->bitmap;
838  int SourceY = 0;
839  for (int y = 0; y < b->Height(); y++) {
840  int SourceX = 0;
841  tIndex *SourceRow = bitmap + (SourceY >> 16) * Width();
842  tIndex *Dest = DestRow;
843  for (int x = 0; x < b->Width(); x++) {
844  *Dest++ = SourceRow[SourceX >> 16];
845  SourceX += RatioX;
846  }
847  SourceY += RatioY;
848  DestRow += b->Width();
849  }
850  }
851  else {
852  // Upscaling - anti-aliasing:
853  b->SetBpp(8);
854  b->Replace(*this); // copy palette (must be done *after* SetBpp()!)
855  int SourceY = 0;
856  for (int y = 0; y < b->Height(); y++) {
857  int SourceX = 0;
858  int sy = min(SourceY >> 16, Height() - 2);
859  uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF);
860  for (int x = 0; x < b->Width(); x++) {
861  int sx = min(SourceX >> 16, Width() - 2);
862  uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF);
863  tColor c1 = b->Blend(GetColor(sx, sy), GetColor(sx + 1, sy), BlendX);
864  tColor c2 = b->Blend(GetColor(sx, sy + 1), GetColor(sx + 1, sy + 1), BlendX);
865  tColor c3 = b->Blend(c1, c2, BlendY);
866  b->DrawPixel(x + X0(), y + Y0(), c3);
867  SourceX += RatioX;
868  }
869  SourceY += RatioY;
870  }
871  }
872  return b;
873 }
874 
875 // --- cRect -----------------------------------------------------------------
876 
877 const cRect cRect::Null;
878 
879 void cRect::Grow(int Dx, int Dy)
880 {
881  point.Shift(-Dx, -Dy);
882  size.Grow(Dx, Dy);
883 }
884 
885 bool cRect::Contains(const cPoint &Point) const
886 {
887  return Left() <= Point.X() &&
888  Top() <= Point.Y() &&
889  Right() >= Point.X() &&
890  Bottom() >= Point.Y();
891 }
892 
893 bool cRect::Contains(const cRect &Rect) const
894 {
895  return Left() <= Rect.Left() &&
896  Top() <= Rect.Top() &&
897  Right() >= Rect.Right() &&
898  Bottom() >= Rect.Bottom();
899 }
900 
901 bool cRect::Intersects(const cRect &Rect) const
902 {
903  return !(Left() > Rect.Right() ||
904  Top() > Rect.Bottom() ||
905  Right() < Rect.Left() ||
906  Bottom() < Rect.Top());
907 }
908 
909 cRect cRect::Intersected(const cRect &Rect) const
910 {
911  cRect r;
912  if (!IsEmpty() && !Rect.IsEmpty()) {
913  r.SetLeft(max(Left(), Rect.Left()));
914  r.SetTop(max(Top(), Rect.Top()));
915  r.SetRight(min(Right(), Rect.Right()));
916  r.SetBottom(min(Bottom(), Rect.Bottom()));
917  }
918  return r;
919 }
920 
921 void cRect::Combine(const cRect &Rect)
922 {
923  if (IsEmpty())
924  *this = Rect;
925  if (Rect.IsEmpty())
926  return;
927  // must set right/bottom *before* top/left!
928  SetRight(max(Right(), Rect.Right()));
929  SetBottom(max(Bottom(), Rect.Bottom()));
930  SetLeft(min(Left(), Rect.Left()));
931  SetTop(min(Top(), Rect.Top()));
932 }
933 
934 void cRect::Combine(const cPoint &Point)
935 {
936  if (IsEmpty())
937  Set(Point.X(), Point.Y(), 1, 1);
938  // must set right/bottom *before* top/left!
939  SetRight(max(Right(), Point.X()));
940  SetBottom(max(Bottom(), Point.Y()));
941  SetLeft(min(Left(), Point.X()));
942  SetTop(min(Top(), Point.Y()));
943 }
944 
945 // --- cPixmap ---------------------------------------------------------------
946 
948 
950 {
951  layer = -1;
953  tile = false;
954 }
955 
956 cPixmap::cPixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
957 {
958  layer = Layer;
959  if (layer >= MAXPIXMAPLAYERS) {
960  layer = MAXPIXMAPLAYERS - 1;
961  esyslog("ERROR: pixmap layer %d limited to %d", Layer, layer);
962  }
963  viewPort = ViewPort;
964  if (!DrawPort.IsEmpty())
965  drawPort = DrawPort;
966  else {
967  drawPort = viewPort;
968  drawPort.SetPoint(0, 0);
969  }
971  tile = false;
972 }
973 
975 {
977 }
978 
980 {
981  if (viewPort.Contains(Point))
982  dirtyViewPort.Combine(Point);
983 }
984 
986 {
988  if (tile)
990  else
992 }
993 
995 {
996  if (drawPort.Contains(Point)) {
997  dirtyDrawPort.Combine(Point);
998  if (tile)
1000  else
1002  }
1003 }
1004 
1006 {
1008 }
1009 
1010 void cPixmap::SetLayer(int Layer)
1011 {
1012  Lock();
1013  if (Layer >= MAXPIXMAPLAYERS) {
1014  esyslog("ERROR: pixmap layer %d limited to %d", Layer, MAXPIXMAPLAYERS - 1);
1015  Layer = MAXPIXMAPLAYERS - 1;
1016  }
1017  if (Layer != layer) {
1018  if (Layer > 0 || layer > 0)
1020  layer = Layer;
1021  }
1022  Unlock();
1023 }
1024 
1025 void cPixmap::SetAlpha(int Alpha)
1026 {
1027  Lock();
1028  Alpha = constrain(Alpha, ALPHA_TRANSPARENT, ALPHA_OPAQUE);
1029  if (Alpha != alpha) {
1031  alpha = Alpha;
1032  }
1033  Unlock();
1034 }
1035 
1036 void cPixmap::SetTile(bool Tile)
1037 {
1038  Lock();
1039  if (Tile != tile) {
1040  if (drawPort.Point() != cPoint(0, 0) || drawPort.Width() < viewPort.Width() || drawPort.Height() < viewPort.Height())
1042  tile = Tile;
1043  }
1044  Unlock();
1045 }
1046 
1047 void cPixmap::SetViewPort(const cRect &Rect)
1048 {
1049  Lock();
1050  if (Rect != viewPort) {
1051  if (tile)
1053  else
1055  viewPort = Rect;
1056  if (tile)
1058  else
1060  }
1061  Unlock();
1062 }
1063 
1064 void cPixmap::SetDrawPortPoint(const cPoint &Point, bool Dirty)
1065 {
1066  Lock();
1067  if (Point != drawPort.Point()) {
1068  if (Dirty) {
1069  if (tile)
1071  else
1073  }
1074  drawPort.SetPoint(Point);
1075  if (Dirty && !tile)
1077  }
1078  Unlock();
1079 }
1080 
1081 // --- cImage ----------------------------------------------------------------
1082 
1084 {
1085  data = NULL;
1086 }
1087 
1088 cImage::cImage(const cImage &Image)
1089 {
1090  size = Image.Size();
1091  int l = size.Width() * size.Height() * sizeof(tColor);
1092  data = MALLOC(tColor, l);
1093  memcpy(data, Image.Data(), l);
1094 }
1095 
1096 cImage::cImage(const cSize &Size, const tColor *Data)
1097 {
1098  size = Size;
1099  int l = size.Width() * size.Height() * sizeof(tColor);
1100  data = MALLOC(tColor, l);
1101  if (Data)
1102  memcpy(data, Data, l);
1103 }
1104 
1106 {
1107  free(data);
1108 }
1109 
1110 void cImage::Clear(void)
1111 {
1112  memset(data, 0x00, Width() * Height() * sizeof(tColor));
1113 }
1114 
1116 {
1117  for (int i = Width() * Height() - 1; i >= 0; i--)
1118  data[i] = Color;
1119 }
1120 
1121 // --- cPixmapMemory ---------------------------------------------------------
1122 
1124 {
1125  data = NULL;
1126  panning = false;
1127 }
1128 
1129 cPixmapMemory::cPixmapMemory(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1130 :cPixmap(Layer, ViewPort, DrawPort)
1131 {
1132  data = MALLOC(tColor, this->DrawPort().Width() * this->DrawPort().Height());
1133 }
1134 
1136 {
1137  free(data);
1138 }
1139 
1141 {
1142  Lock();
1143  memset(data, 0x00, DrawPort().Width() * DrawPort().Height() * sizeof(tColor));
1145  Unlock();
1146 }
1147 
1149 {
1150  Lock();
1151  for (int i = DrawPort().Width() * DrawPort().Height() - 1; i >= 0; i--)
1152  data[i] = Color;
1154  Unlock();
1155 }
1156 
1157 void cPixmap::DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
1158 {
1159  if (Pixmap->Tile() && (Pixmap->DrawPort().Point() != cPoint(0, 0) || Pixmap->DrawPort().Size() < Pixmap->ViewPort().Size())) {
1160  cPoint t0 = Pixmap->DrawPort().Point().Shifted(Pixmap->ViewPort().Point()); // the origin of the draw port in absolute OSD coordinates
1161  // Find the top/leftmost location where the draw port touches the view port:
1162  while (t0.X() > Pixmap->ViewPort().Left())
1163  t0.Shift(-Pixmap->DrawPort().Width(), 0);
1164  while (t0.Y() > Pixmap->ViewPort().Top())
1165  t0.Shift(0, -Pixmap->DrawPort().Height());
1166  cPoint t = t0;;
1167  while (t.Y() <= Pixmap->ViewPort().Bottom()) {
1168  while (t.X() <= Pixmap->ViewPort().Right()) {
1169  cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1170  Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1171  cPoint Delta = Source.Point() - t;
1172  Source.SetPoint(t); // Source is now where the pixmap's data shall be drawn
1173  Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1174  Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1175  if (!Source.IsEmpty()) {
1176  cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1177  Source.Shift(Delta); // Source is now back at the pixmap's draw port location, still in absolute OSD coordinates
1178  Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's view port again
1179  Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1180  if (Pixmap->Layer() == 0)
1181  Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1182  else
1183  Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1184  }
1185  t.Shift(Pixmap->DrawPort().Width(), 0); // increase one draw port width to the right
1186  }
1187  t.SetX(t0.X()); // go back to the leftmost position
1188  t.Shift(0, Pixmap->DrawPort().Height()); // increase one draw port height down
1189  }
1190  }
1191  else {
1192  cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1193  Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1194  Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1195  Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1196  if (!Source.IsEmpty()) {
1197  cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1198  Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's draw port again
1199  Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1200  if (Pixmap->Layer() == 0)
1201  Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1202  else
1203  Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1204  }
1205  }
1206 }
1207 
1208 void cPixmapMemory::DrawImage(const cPoint &Point, const cImage &Image)
1209 {
1210  Lock();
1211  cRect r = cRect(Point, Image.Size()).Intersected(DrawPort().Size());
1212  if (!r.IsEmpty()) {
1213  int ws = Image.Size().Width();
1214  int wd = DrawPort().Width();
1215  int w = r.Width() * sizeof(tColor);
1216  const tColor *ps = Image.Data();
1217  if (Point.Y() < 0)
1218  ps -= Point.Y() * ws;
1219  if (Point.X() < 0)
1220  ps -= Point.X();
1221  tColor *pd = data + wd * r.Top() + r.Left();
1222  for (int y = r.Height(); y-- > 0; ) {
1223  memcpy(pd, ps, w);
1224  ps += ws;
1225  pd += wd;
1226  }
1227  MarkDrawPortDirty(r);
1228  }
1229  Unlock();
1230 }
1231 
1232 void cPixmapMemory::DrawImage(const cPoint &Point, int ImageHandle)
1233 {
1234  Lock();
1235  if (const cImage *Image = cOsdProvider::GetImageData(ImageHandle))
1236  DrawImage(Point, *Image);
1237  Unlock();
1238 }
1239 
1240 void cPixmapMemory::DrawPixel(const cPoint &Point, tColor Color)
1241 {
1242  Lock();
1243  if (DrawPort().Size().Contains(Point)) {
1244  int p = Point.Y() * DrawPort().Width() + Point.X();
1245  if (Layer() == 0 && !IS_OPAQUE(Color))
1246  data[p] = AlphaBlend(Color, data[p]);
1247  else
1248  data[p] = Color;
1249  MarkDrawPortDirty(Point);
1250  }
1251  Unlock();
1252 }
1253 
1254 void cPixmapMemory::DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay)
1255 {
1256  Lock();
1257  cRect r = cRect(Point, cSize(Bitmap.Width(), Bitmap.Height())).Intersected(DrawPort().Size());
1258  if (!r.IsEmpty()) {
1259  bool UseColors = ColorFg || ColorBg;
1260  int wd = DrawPort().Width();
1261  tColor *pd = data + wd * r.Top() + r.Left();
1262  for (int y = r.Top(); y <= r.Bottom(); y++) {
1263  tColor *cd = pd;
1264  for (int x = r.Left(); x <= r.Right(); x++) {
1265  tIndex Index = *Bitmap.Data(x - Point.X(), y - Point.Y());
1266  if (Index || !Overlay) {
1267  if (UseColors)
1268  *cd = Index ? ColorFg : ColorBg;
1269  else
1270  *cd = Bitmap.Color(Index);
1271  }
1272  cd++;
1273  }
1274  pd += wd;
1275  }
1276  MarkDrawPortDirty(r);
1277  }
1278  Unlock();
1279 }
1280 
1281 void cPixmapMemory::DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
1282 {
1283  Lock();
1284  int x = Point.X();
1285  int y = Point.Y();
1286  int w = Font->Width(s);
1287  int h = Font->Height();
1288  int limit = 0;
1289  int cw = Width ? Width : w;
1290  int ch = Height ? Height : h;
1291  cRect r(x, y, cw, ch);
1292  if (ColorBg != clrTransparent)
1293  DrawRectangle(r, ColorBg);
1294  if (Width || Height) {
1295  limit = x + cw;
1296  if (Width) {
1297  if ((Alignment & taLeft) != 0) {
1298  if ((Alignment & taBorder) != 0)
1299  x += max(h / TEXT_ALIGN_BORDER, 1);
1300  }
1301  else if ((Alignment & taRight) != 0) {
1302  if (w < Width)
1303  x += Width - w;
1304  if ((Alignment & taBorder) != 0)
1305  x -= max(h / TEXT_ALIGN_BORDER, 1);
1306  }
1307  else { // taCentered
1308  if (w < Width)
1309  x += (Width - w) / 2;
1310  }
1311  }
1312  if (Height) {
1313  if ((Alignment & taTop) != 0)
1314  ;
1315  else if ((Alignment & taBottom) != 0) {
1316  if (h < Height)
1317  y += Height - h;
1318  }
1319  else { // taCentered
1320  if (h < Height)
1321  y += (Height - h) / 2;
1322  }
1323  }
1324  }
1325  Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
1326  MarkDrawPortDirty(r);
1327  Unlock();
1328 }
1329 
1331 {
1332  Lock();
1333  cRect r = Rect.Intersected(DrawPort().Size());
1334  if (!r.IsEmpty()) {
1335  int wd = DrawPort().Width();
1336  int w = r.Width() * sizeof(tColor);
1337  tColor *ps = NULL;
1338  tColor *pd = data + wd * r.Top() + r.Left();
1339  for (int y = r.Height(); y-- > 0; ) {
1340  if (ps)
1341  memcpy(pd, ps, w); // all other lines are copied fast from the first one
1342  else {
1343  // explicitly fill the first line:
1344  tColor *cd = ps = pd;
1345  for (int x = r.Width(); x-- > 0; ) {
1346  *cd = Color;
1347  cd++;
1348  }
1349  }
1350  pd += wd;
1351  }
1352  MarkDrawPortDirty(r);
1353  }
1354  Unlock();
1355 }
1356 
1357 void cPixmapMemory::DrawEllipse(const cRect &Rect, tColor Color, int Quadrants)
1358 {
1359 //TODO use anti-aliasing?
1360 //TODO fix alignment
1361  Lock();
1362  // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF
1363  int x1 = Rect.Left();
1364  int y1 = Rect.Top();
1365  int x2 = Rect.Right();
1366  int y2 = Rect.Bottom();
1367  int rx = x2 - x1;
1368  int ry = y2 - y1;
1369  int cx = (x1 + x2) / 2;
1370  int cy = (y1 + y2) / 2;
1371  switch (abs(Quadrants)) {
1372  case 0: rx /= 2; ry /= 2; break;
1373  case 1: cx = x1; cy = y2; break;
1374  case 2: cx = x2; cy = y2; break;
1375  case 3: cx = x2; cy = y1; break;
1376  case 4: cx = x1; cy = y1; break;
1377  case 5: cx = x1; ry /= 2; break;
1378  case 6: cy = y2; rx /= 2; break;
1379  case 7: cx = x2; ry /= 2; break;
1380  case 8: cy = y1; rx /= 2; break;
1381  default: ;
1382  }
1383  int TwoASquare = max(1, 2 * rx * rx);
1384  int TwoBSquare = max(1, 2 * ry * ry);
1385  int x = rx;
1386  int y = 0;
1387  int XChange = ry * ry * (1 - 2 * rx);
1388  int YChange = rx * rx;
1389  int EllipseError = 0;
1390  int StoppingX = TwoBSquare * rx;
1391  int StoppingY = 0;
1392  while (StoppingX >= StoppingY) {
1393  switch (Quadrants) {
1394  case 5: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); // no break
1395  case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1396  case 7: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); // no break
1397  case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1398  case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1399  case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1400  case 0:
1401  case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + 1, 1), Color); if (Quadrants == 6) break;
1402  case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + 1, 1), Color); break;
1403  case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1404  case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1405  case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1406  case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1407  default: ;
1408  }
1409  y++;
1410  StoppingY += TwoASquare;
1411  EllipseError += YChange;
1412  YChange += TwoASquare;
1413  if (2 * EllipseError + XChange > 0) {
1414  x--;
1415  StoppingX -= TwoBSquare;
1416  EllipseError += XChange;
1417  XChange += TwoBSquare;
1418  }
1419  }
1420  x = 0;
1421  y = ry;
1422  XChange = ry * ry;
1423  YChange = rx * rx * (1 - 2 * ry);
1424  EllipseError = 0;
1425  StoppingX = 0;
1426  StoppingY = TwoASquare * ry;
1427  while (StoppingX <= StoppingY) {
1428  switch (Quadrants) {
1429  case 5: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); // no break
1430  case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1431  case 7: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); // no break
1432  case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1433  case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1434  case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1435  case 0:
1436  case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + 1, 1), Color); if (Quadrants == 6) break;
1437  case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + 1, 1), Color); break;
1438  case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1439  case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1440  case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1441  case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1442  default: ;
1443  }
1444  x++;
1445  StoppingX += TwoBSquare;
1446  EllipseError += XChange;
1447  XChange += TwoBSquare;
1448  if (2 * EllipseError + YChange > 0) {
1449  y--;
1450  StoppingY -= TwoASquare;
1451  EllipseError += YChange;
1452  YChange += TwoASquare;
1453  }
1454  }
1455  MarkDrawPortDirty(Rect);
1456  Unlock();
1457 }
1458 
1459 void cPixmapMemory::DrawSlope(const cRect &Rect, tColor Color, int Type)
1460 {
1461  //TODO anti-aliasing?
1462  //TODO also simplify cBitmap::DrawSlope()
1463  Lock();
1464  bool upper = Type & 0x01;
1465  bool falling = Type & 0x02;
1466  bool vertical = Type & 0x04;
1467  int x1 = Rect.Left();
1468  int y1 = Rect.Top();
1469  int x2 = Rect.Right();
1470  int y2 = Rect.Bottom();
1471  int w = Rect.Width();
1472  int h = Rect.Height();
1473  if (vertical) {
1474  for (int y = y1; y <= y2; y++) {
1475  double c = cos((y - y1) * M_PI / h);
1476  if (falling)
1477  c = -c;
1478  int x = (x1 + x2) / 2 + int(w * c / 2);
1479  if (upper && !falling || !upper && falling)
1480  DrawRectangle(cRect(x1, y, x - x1 + 1, 1), Color);
1481  else
1482  DrawRectangle(cRect(x, y, x2 - x + 1, 1), Color);
1483  }
1484  }
1485  else {
1486  for (int x = x1; x <= x2; x++) {
1487  double c = cos((x - x1) * M_PI / w);
1488  if (falling)
1489  c = -c;
1490  int y = (y1 + y2) / 2 + int(h * c / 2);
1491  if (upper)
1492  DrawRectangle(cRect(x, y1, 1, y - y1 + 1), Color);
1493  else
1494  DrawRectangle(cRect(x, y, 1, y2 - y + 1), Color);
1495  }
1496  }
1497  MarkDrawPortDirty(Rect);
1498  Unlock();
1499 }
1500 
1501 void cPixmapMemory::Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1502 {
1503  Lock();
1504  if (Pixmap->Alpha() != ALPHA_TRANSPARENT) {
1505  if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1506  cRect s = Source.Intersected(Pixmap->DrawPort().Size());
1507  if (!s.IsEmpty()) {
1508  cPoint v = Dest - Source.Point();
1509  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1510  if (!d.IsEmpty()) {
1511  s = d.Shifted(-v);
1512  int a = pm->Alpha();
1513  int ws = pm->DrawPort().Width();
1514  int wd = DrawPort().Width();
1515  const tColor *ps = pm->data + ws * s.Top() + s.Left();
1516  tColor *pd = data + wd * d.Top() + d.Left();
1517  for (int y = d.Height(); y-- > 0; ) {
1518  const tColor *cs = ps;
1519  tColor *cd = pd;
1520  for (int x = d.Width(); x-- > 0; ) {
1521  *cd = AlphaBlend(*cs, *cd, a);
1522  cs++;
1523  cd++;
1524  }
1525  ps += ws;
1526  pd += wd;
1527  }
1528  MarkDrawPortDirty(d);
1529  }
1530  }
1531  }
1532  }
1533  Unlock();
1534 }
1535 
1536 void cPixmapMemory::Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1537 {
1538  Lock();
1539  if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1540  cRect s = Source.Intersected(pm->DrawPort().Size());
1541  if (!s.IsEmpty()) {
1542  cPoint v = Dest - Source.Point();
1543  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1544  if (!d.IsEmpty()) {
1545  s = d.Shifted(-v);
1546  int ws = pm->DrawPort().Width();
1547  int wd = DrawPort().Width();
1548  int w = d.Width() * sizeof(tColor);
1549  const tColor *ps = pm->data + ws * s.Top() + s.Left();
1550  tColor *pd = data + wd * d.Top() + d.Left();
1551  for (int y = d.Height(); y-- > 0; ) {
1552  memcpy(pd, ps, w);
1553  ps += ws;
1554  pd += wd;
1555  }
1556  MarkDrawPortDirty(d);
1557  }
1558  }
1559  }
1560  Unlock();
1561 }
1562 
1563 void cPixmapMemory::Scroll(const cPoint &Dest, const cRect &Source)
1564 {
1565  Lock();
1566  cRect s;
1567  if (&Source == &cRect::Null)
1568  s = DrawPort().Shifted(-DrawPort().Point());
1569  else
1570  s = Source.Intersected(DrawPort().Size());
1571  if (!s.IsEmpty()) {
1572  cPoint v = Dest - Source.Point();
1573  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1574  if (!d.IsEmpty()) {
1575  s = d.Shifted(-v);
1576  if (d.Point() != s.Point()) {
1577  int ws = DrawPort().Width();
1578  int wd = ws;
1579  int w = d.Width() * sizeof(tColor);
1580  const tColor *ps = data + ws * s.Top() + s.Left();
1581  tColor *pd = data + wd * d.Top() + d.Left();
1582  for (int y = d.Height(); y-- > 0; ) {
1583  memmove(pd, ps, w); // source and destination might overlap!
1584  ps += ws;
1585  pd += wd;
1586  }
1587  if (panning)
1588  SetDrawPortPoint(DrawPort().Point().Shifted(s.Point() - d.Point()), false);
1589  else
1590  MarkDrawPortDirty(d);
1591  }
1592  }
1593  }
1594  Unlock();
1595 }
1596 
1597 void cPixmapMemory::Pan(const cPoint &Dest, const cRect &Source)
1598 {
1599  Lock();
1600  panning = true;
1601  Scroll(Dest, Source);
1602  panning = false;
1603  Unlock();
1604 }
1605 
1606 // --- cOsd ------------------------------------------------------------------
1607 
1608 static const char *OsdErrorTexts[] = {
1609  "ok",
1610  "too many areas",
1611  "too many colors",
1612  "bpp not supported",
1613  "areas overlap",
1614  "wrong alignment",
1615  "out of memory",
1616  "wrong area size",
1617  "unknown",
1618  };
1619 
1620 int cOsd::osdLeft = 0;
1621 int cOsd::osdTop = 0;
1622 int cOsd::osdWidth = 0;
1623 int cOsd::osdHeight = 0;
1626 
1627 cOsd::cOsd(int Left, int Top, uint Level)
1628 {
1629  cMutexLock MutexLock(&mutex);
1630  isTrueColor = false;
1631  savedBitmap = NULL;
1632  numBitmaps = 0;
1633  savedPixmap = NULL;
1634  left = Left;
1635  top = Top;
1636  width = height = 0;
1637  level = Level;
1638  active = false;
1639  for (int i = 0; i < Osds.Size(); i++) {
1640  if (Osds[i]->level > level) {
1641  Osds.Insert(this, i);
1642  return;
1643  }
1644  }
1645  Osds.Append(this);
1646 }
1647 
1649 {
1650  cMutexLock MutexLock(&mutex);
1651  for (int i = 0; i < numBitmaps; i++)
1652  delete bitmaps[i];
1653  delete savedBitmap;
1654  delete savedPixmap;
1655  for (int i = 0; i < pixmaps.Size(); i++)
1656  delete pixmaps[i];
1657  for (int i = 0; i < Osds.Size(); i++) {
1658  if (Osds[i] == this) {
1659  Osds.Remove(i);
1660  if (Osds.Size())
1661  Osds[0]->SetActive(true);
1662  break;
1663  }
1664  }
1665 }
1666 
1667 void cOsd::SetOsdPosition(int Left, int Top, int Width, int Height)
1668 {
1669  osdLeft = Left;
1670  osdTop = Top;
1673 }
1674 
1675 void cOsd::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
1676 {
1677  if (isTrueColor)
1678  return;
1679  for (int i = 0; i < numBitmaps; i++)
1680  bitmaps[i]->SetAntiAliasGranularity(FixedColors, BlendColors);
1681 }
1682 
1684 {
1685  return Area < numBitmaps ? (isTrueColor ? bitmaps[0] : bitmaps[Area]) : NULL;
1686 }
1687 
1688 cPixmap *cOsd::CreatePixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1689 {
1690  if (isTrueColor) {
1691  LOCK_PIXMAPS;
1692  cPixmap *Pixmap = new cPixmapMemory(Layer, ViewPort, DrawPort);
1693  if (AddPixmap(Pixmap))
1694  return Pixmap;
1695  delete Pixmap;
1696  }
1697  return NULL;
1698 }
1699 
1701 {
1702  if (Pixmap) {
1703  LOCK_PIXMAPS;
1704  for (int i = 1; i < pixmaps.Size(); i++) { // begin at 1 - don't let the background pixmap be destroyed!
1705  if (pixmaps[i] == Pixmap) {
1706  pixmaps[0]->MarkViewPortDirty(Pixmap->ViewPort());
1707  delete Pixmap;
1708  pixmaps[i] = NULL;
1709  return;
1710  }
1711  }
1712  esyslog("ERROR: attempt to destroy an unregistered pixmap");
1713  }
1714 }
1715 
1717 {
1718  if (Pixmap) {
1719  LOCK_PIXMAPS;
1720  for (int i = 0; i < pixmaps.Size(); i++) {
1721  if (!pixmaps[i])
1722  return pixmaps[i] = Pixmap;
1723  }
1724  pixmaps.Append(Pixmap);
1725  }
1726  return Pixmap;
1727 }
1728 
1730 {
1731  cPixmapMemory *Pixmap = NULL;
1732  if (isTrueColor) {
1733  LOCK_PIXMAPS;
1734  // Collect overlapping dirty rectangles:
1735  cRect d;
1736  for (int i = 0; i < pixmaps.Size(); i++) {
1737  if (cPixmap *pm = pixmaps[i]) {
1738  if (!pm->DirtyViewPort().IsEmpty()) {
1739  if (d.IsEmpty() || d.Intersects(pm->DirtyViewPort())) {
1740  d.Combine(pm->DirtyViewPort());
1741  pm->SetClean();
1742  }
1743  }
1744  }
1745  }
1746  if (!d.IsEmpty()) {
1747 //#define DebugDirty
1748 #ifdef DebugDirty
1749  static cRect OldDirty;
1750  cRect NewDirty = d;
1751  d.Combine(OldDirty);
1752  OldDirty = NewDirty;
1753 #endif
1754  Pixmap = new cPixmapMemory(0, d);
1755  Pixmap->Clear();
1756  // Render the individual pixmaps into the resulting pixmap:
1757  for (int Layer = 0; Layer < MAXPIXMAPLAYERS; Layer++) {
1758  for (int i = 0; i < pixmaps.Size(); i++) {
1759  if (cPixmap *pm = pixmaps[i]) {
1760  if (pm->Layer() == Layer)
1761  Pixmap->DrawPixmap(pm, d);
1762  }
1763  }
1764  }
1765 #ifdef DebugDirty
1766  cPixmapMemory DirtyIndicator(7, NewDirty);
1767  static tColor DirtyIndicatorColors[] = { 0x7FFFFF00, 0x7F00FFFF };
1768  static int DirtyIndicatorIndex = 0;
1769  DirtyIndicator.Fill(DirtyIndicatorColors[DirtyIndicatorIndex]);
1770  DirtyIndicatorIndex = 1 - DirtyIndicatorIndex;
1771  Pixmap->Render(&DirtyIndicator, DirtyIndicator.DrawPort(), DirtyIndicator.ViewPort().Point().Shifted(-Pixmap->ViewPort().Point()));
1772 #endif
1773  }
1774  }
1775  return Pixmap;
1776 }
1777 
1778 eOsdError cOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
1779 {
1780  if (NumAreas > MAXOSDAREAS)
1781  return oeTooManyAreas;
1782  eOsdError Result = oeOk;
1783  for (int i = 0; i < NumAreas; i++) {
1784  if (Areas[i].x1 > Areas[i].x2 || Areas[i].y1 > Areas[i].y2 || Areas[i].x1 < 0 || Areas[i].y1 < 0)
1785  return oeWrongAlignment;
1786  for (int j = i + 1; j < NumAreas; j++) {
1787  if (Areas[i].Intersects(Areas[j])) {
1788  Result = oeAreasOverlap;
1789  break;
1790  }
1791  }
1792  if (Areas[i].bpp == 32) {
1793  if (NumAreas > 1)
1794  return oeTooManyAreas;
1795  }
1796  }
1797  return Result;
1798 }
1799 
1800 eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas)
1801 {
1802  eOsdError Result = CanHandleAreas(Areas, NumAreas);
1803  if (Result == oeOk) {
1804  while (numBitmaps)
1805  delete bitmaps[--numBitmaps];
1806  for (int i = 0; i < pixmaps.Size(); i++) {
1807  delete pixmaps[i];
1808  pixmaps[i] = NULL;
1809  }
1810  width = height = 0;
1811  isTrueColor = NumAreas == 1 && Areas[0].bpp == 32;
1812  if (isTrueColor) {
1813  width = Areas[0].x2 - Areas[0].x1 + 1;
1814  height = Areas[0].y2 - Areas[0].y1 + 1;
1815  cPixmap *Pixmap = CreatePixmap(0, cRect(Areas[0].x1, Areas[0].y1, width, height));
1816  Pixmap->Clear();
1817  bitmaps[numBitmaps++] = new cBitmap(10, 10, 8); // dummy bitmap for GetBitmap()
1818  }
1819  else {
1820  for (int i = 0; i < NumAreas; i++) {
1821  bitmaps[numBitmaps++] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1);
1822  width = max(width, Areas[i].x2 + 1);
1823  height = max(height, Areas[i].y2 + 1);
1824  }
1825  }
1826  }
1827  else
1828  esyslog("ERROR: cOsd::SetAreas returned %d (%s)", Result, Result < oeUnknown ? OsdErrorTexts[Result] : OsdErrorTexts[oeUnknown]);
1829  return Result;
1830 }
1831 
1832 void cOsd::SaveRegion(int x1, int y1, int x2, int y2)
1833 {
1834  if (isTrueColor) {
1835  delete savedPixmap;
1836  cRect r(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
1837  savedPixmap = new cPixmapMemory(0, r);
1838  savedPixmap->Copy(pixmaps[0], r, cPoint(0, 0));
1839  }
1840  else {
1841  delete savedBitmap;
1842  savedBitmap = new cBitmap(x2 - x1 + 1, y2 - y1 + 1, 8, x1, y1);
1843  for (int i = 0; i < numBitmaps; i++)
1844  savedBitmap->DrawBitmap(bitmaps[i]->X0(), bitmaps[i]->Y0(), *bitmaps[i]);
1845  }
1846 }
1847 
1849 {
1850  if (isTrueColor) {
1851  if (savedPixmap) {
1853  delete savedPixmap;
1854  savedPixmap = NULL;
1855  }
1856  }
1857  else {
1858  if (savedBitmap) {
1860  delete savedBitmap;
1861  savedBitmap = NULL;
1862  }
1863  }
1864 }
1865 
1866 eOsdError cOsd::SetPalette(const cPalette &Palette, int Area)
1867 {
1868  if (isTrueColor)
1869  return oeOk;
1870  if (Area < numBitmaps) {
1871  bitmaps[Area]->Take(Palette);
1872  return oeOk;
1873  }
1874  return oeUnknown;
1875 }
1876 
1877 void cOsd::DrawImage(const cPoint &Point, const cImage &Image)
1878 {
1879  if (isTrueColor)
1880  pixmaps[0]->DrawImage(Point, Image);
1881 }
1882 
1883 void cOsd::DrawImage(const cPoint &Point, int ImageHandle)
1884 {
1885  if (isTrueColor)
1886  pixmaps[0]->DrawImage(Point, ImageHandle);
1887 }
1888 
1889 void cOsd::DrawPixel(int x, int y, tColor Color)
1890 {
1891  if (isTrueColor)
1892  pixmaps[0]->DrawPixel(cPoint(x, y), Color);
1893  else {
1894  for (int i = 0; i < numBitmaps; i++)
1895  bitmaps[i]->DrawPixel(x, y, Color);
1896  }
1897 }
1898 
1899 void cOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
1900 {
1901  if (isTrueColor)
1902  pixmaps[0]->DrawBitmap(cPoint(x, y), Bitmap, ColorFg, ColorBg, Overlay);
1903  else {
1904  for (int i = 0; i < numBitmaps; i++)
1905  bitmaps[i]->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg, ReplacePalette, Overlay);
1906  }
1907 }
1908 
1909 void cOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
1910 {
1911  if (isTrueColor)
1912  pixmaps[0]->DrawText(cPoint(x, y), s, ColorFg, ColorBg, Font, Width, Height, Alignment);
1913  else {
1914  for (int i = 0; i < numBitmaps; i++)
1915  bitmaps[i]->DrawText(x, y, s, ColorFg, ColorBg, Font, Width, Height, Alignment);
1916  }
1917 }
1918 
1919 void cOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
1920 {
1921  if (isTrueColor)
1922  pixmaps[0]->DrawRectangle(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color);
1923  else {
1924  for (int i = 0; i < numBitmaps; i++)
1925  bitmaps[i]->DrawRectangle(x1, y1, x2, y2, Color);
1926  }
1927 }
1928 
1929 void cOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
1930 {
1931  if (isTrueColor)
1932  pixmaps[0]->DrawEllipse(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Quadrants);
1933  else {
1934  for (int i = 0; i < numBitmaps; i++)
1935  bitmaps[i]->DrawEllipse(x1, y1, x2, y2, Color, Quadrants);
1936  }
1937 }
1938 
1939 void cOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
1940 {
1941  if (isTrueColor)
1942  pixmaps[0]->DrawSlope(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Type);
1943  else {
1944  for (int i = 0; i < numBitmaps; i++)
1945  bitmaps[i]->DrawSlope(x1, y1, x2, y2, Color, Type);
1946  }
1947 }
1948 
1949 void cOsd::Flush(void)
1950 {
1951 }
1952 
1953 // --- cOsdProvider ----------------------------------------------------------
1954 
1956 int cOsdProvider::oldWidth = 0;
1957 int cOsdProvider::oldHeight = 0;
1958 double cOsdProvider::oldAspect = 1.0;
1960 
1962 {
1963  delete osdProvider;
1964  osdProvider = this;
1965 }
1966 
1968 {
1969  osdProvider = NULL;
1970 }
1971 
1972 cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level)
1973 {
1974  cMutexLock MutexLock(&cOsd::mutex);
1975  if (Level == OSD_LEVEL_DEFAULT && cOsd::IsOpen())
1976  esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
1977  else if (osdProvider) {
1978  cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL;
1979  cOsd *Osd = osdProvider->CreateOsd(Left, Top, Level);
1980  if (Osd == cOsd::Osds[0]) {
1981  if (ActiveOsd)
1982  ActiveOsd->SetActive(false);
1983  Osd->SetActive(true);
1984  }
1985  return Osd;
1986  }
1987  else
1988  esyslog("ERROR: no OSD provider available - using dummy OSD!");
1989  return new cOsd(Left, Top, 999); // create a dummy cOsd, so that access won't result in a segfault
1990 }
1991 
1993 {
1994  int Width;
1995  int Height;
1996  double Aspect;
1997  cDevice::PrimaryDevice()->GetOsdSize(Width, Height, Aspect);
1998  if (Width != oldWidth || Height != oldHeight || !DoubleEqual(Aspect, oldAspect) || Force) {
1999  Setup.OSDLeft = int(round(Width * Setup.OSDLeftP));
2000  Setup.OSDTop = int(round(Height * Setup.OSDTopP));
2001  Setup.OSDWidth = int(round(Width * Setup.OSDWidthP)) & ~0x07; // OSD width must be a multiple of 8
2002  Setup.OSDHeight = int(round(Height * Setup.OSDHeightP));
2003  Setup.OSDAspect = Aspect;
2004  Setup.FontOsdSize = int(round(Height * Setup.FontOsdSizeP));
2005  Setup.FontFixSize = int(round(Height * Setup.FontFixSizeP));
2006  Setup.FontSmlSize = int(round(Height * Setup.FontSmlSizeP));
2010  oldWidth = Width;
2011  oldHeight = Height;
2012  oldAspect = Aspect;
2013  dsyslog("OSD size changed to %dx%d @ %g", Width, Height, Aspect);
2014  }
2015 }
2016 
2018 {
2019  if (osdProvider) {
2020  return osdProvider->ProvidesTrueColor();
2021  }
2022  else
2023  esyslog("ERROR: no OSD provider available in call to SupportsTrueColor()");
2024  return false;
2025 }
2026 
2028 {
2029  LOCK_PIXMAPS;
2030  for (int i = 1; i < MAXOSDIMAGES; i++) {
2031  if (!images[i]) {
2032  images[i] = new cImage(Image);
2033  return i;
2034  }
2035  }
2036  return 0;
2037 }
2038 
2039 void cOsdProvider::DropImageData(int ImageHandle)
2040 {
2041  LOCK_PIXMAPS;
2042  if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES) {
2043  delete images[ImageHandle];
2044  images[ImageHandle] = NULL;
2045  }
2046 }
2047 
2048 const cImage *cOsdProvider::GetImageData(int ImageHandle)
2049 {
2050  LOCK_PIXMAPS;
2051  if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES)
2052  return images[ImageHandle];
2053  return NULL;
2054 }
2055 
2057 {
2058  if (osdProvider)
2059  return osdProvider->StoreImageData(Image);
2060  return 0;
2061 }
2062 
2063 void cOsdProvider::DropImage(int ImageHandle)
2064 {
2065  if (osdProvider)
2066  osdProvider->DropImageData(ImageHandle);
2067 }
2068 
2070 {
2071  delete osdProvider;
2072  osdProvider = NULL;
2073 }
2074 
2075 // --- cTextScroller ---------------------------------------------------------
2076 
2078 {
2079  osd = NULL;
2080  left = top = width = height = 0;
2081  font = NULL;
2082  colorFg = 0;
2083  colorBg = 0;
2084  offset = 0;
2085  shown = 0;
2086 }
2087 
2088 cTextScroller::cTextScroller(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2089 {
2090  Set(Osd, Left, Top, Width, Height, Text, Font, ColorFg, ColorBg);
2091 }
2092 
2093 void cTextScroller::Set(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2094 {
2095  osd = Osd;
2096  left = Left;
2097  top = Top;
2098  width = Width;
2099  height = Height;
2100  font = Font;
2101  colorFg = ColorFg;
2102  colorBg = ColorBg;
2103  offset = 0;
2104  textWrapper.Set(Text, Font, Width);
2105  shown = min(Total(), height / font->Height());
2106  height = shown * font->Height(); // sets height to the actually used height, which may be less than Height
2107  DrawText();
2108 }
2109 
2111 {
2112  osd = NULL; // just makes sure it won't draw anything
2113 }
2114 
2116 {
2117  if (osd) {
2118  for (int i = 0; i < shown; i++)
2120  }
2121 }
2122 
2123 void cTextScroller::Scroll(bool Up, bool Page)
2124 {
2125  if (Up) {
2126  if (CanScrollUp()) {
2127  offset -= Page ? shown : 1;
2128  if (offset < 0)
2129  offset = 0;
2130  DrawText();
2131  }
2132  }
2133  else {
2134  if (CanScrollDown()) {
2135  offset += Page ? shown : 1;
2136  if (offset + shown > Total())
2137  offset = Total() - shown;
2138  DrawText();
2139  }
2140  }
2141 }
cRect dirtyDrawPort
Definition: osd.h:461
int height
Definition: osd.h:999
void ReduceBpp(const cPalette &Palette)
Reduces the color depth of the bitmap to that of the given Palette.
Definition: osd.c:754
int y2
Definition: osd.h:295
cOsdProvider(void)
Definition: osd.c:1961
int maxColors
Definition: osd.h:92
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:1597
int y0
Definition: osd.h:172
double OSDHeightP
Definition: config.h:313
cPixmapMemory(void)
Definition: osd.c:1123
cSize size
Definition: osd.h:351
int width
Definition: osd.h:999
cOsd * osd
Definition: osd.h:998
static uint8_t AlphaLutAlpha[255][256]
Definition: osd.c:59
int Height(void) const
Definition: osd.h:432
static int oldHeight
Definition: osd.h:938
void SetTop(int Top)
Definition: osd.h:382
Definition: osd.h:450
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
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:1254
bool Covers(int x1, int y1, int x2, int y2) const
Returns true if the rectangle defined by the given coordinates completely covers this bitmap...
Definition: osd.c:324
void 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:522
int height
Definition: osd.h:173
#define dsyslog(a...)
Definition: tools.h:36
Definition: font.h:23
double OSDWidthP
Definition: config.h:313
static cImage * images[MAXOSDIMAGES]
Definition: osd.h:940
virtual void SetViewPort(const cRect &Rect)
Sets the pixmap's view port to the given Rect.
Definition: osd.c:1047
void Shift(int Dx, int Dy)
Definition: osd.h:320
void Clean(void)
Marks the dirty area as clean.
Definition: osd.c:354
void Reset(void)
Resets the palette, making it contain no colors.
Definition: osd.c:138
int left
Definition: osd.h:999
static cOsdProvider * osdProvider
Definition: osd.h:936
int dirtyY1
Definition: osd.h:174
double FontFixSizeP
Definition: config.h:324
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:1563
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas)
Sets the sub-areas to the given areas.
Definition: osd.c:1800
virtual void SetActive(bool On)
Sets this OSD to be the active one.
Definition: osd.h:753
virtual ~cPalette()
Definition: osd.c:123
static const cImage * GetImageData(int ImageHandle)
Gets the image data referenced by ImageHandle.
Definition: osd.c:2048
static const char * OsdErrorTexts[]
Definition: osd.c:1608
#define MAXOSDWIDTH
Definition: config.h:57
double FontOsdSizeP
Definition: config.h:322
static int osdLeft
Definition: osd.h:719
bool SetXpm(const char *const Xpm[], bool IgnoreNone=false)
Sets this bitmap to the given XPM data.
Definition: osd.c:428
cTextScroller(void)
Definition: osd.c:2077
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:1240
int x1
Definition: osd.h:295
Definition: osd.h:163
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:1667
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:1536
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
cRect drawPort
Definition: osd.h:459
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:1899
int Alpha(void) const
Definition: osd.h:529
int numBitmaps
Definition: osd.h:725
tIndex * bitmap
Definition: osd.h:171
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:400
const cRect & DrawPort(void) const
Returns the pixmap's draw port, which is relative to the view port.
Definition: osd.h:535
Definition: osd.h:415
int Index(tColor Color)
Returns the index of the given Color (the first color has index 0).
Definition: osd.c:144
virtual void Append(T Data)
Definition: tools.h:545
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:1929
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:2093
cVector< cPixmap * > pixmaps
Definition: osd.h:727
int bpp
Definition: osd.h:91
bool tile
Definition: osd.h:457
cPixmap(void)
Definition: osd.c:949
bool isTrueColor
Definition: osd.h:722
int Width(void) const
Definition: osd.h:363
int dirtyX1
Definition: osd.h:174
tIndex tIndexes[MAXNUMCOLORS]
Definition: osd.h:96
int X(void) const
Definition: osd.h:314
cBitmap * Scaled(double FactorX, double FactorY, bool AntiAlias=false)
Creates a copy of this bitmap, scaled by the given factors.
Definition: osd.c:827
#define esyslog(a...)
Definition: tools.h:34
#define MAXOSDIMAGES
Definition: osd.h:931
bool IsEmpty(void) const
Returns true if this rectangle is empty.
Definition: osd.h:411
int FontFixSize
Definition: config.h:327
int bpp
Definition: osd.h:296
void MarkViewPortDirty(const cRect &Rect)
Marks the given rectangle of the view port of this pixmap as dirty.
Definition: osd.c:974
char FontSml[MAXFONTNAME]
Definition: config.h:320
Definition: osd.h:302
T max(T a, T b)
Definition: tools.h:55
virtual void SetDrawPortPoint(const cPoint &Point, bool Dirty=true)
Sets the pixmap's draw port to the given Point.
Definition: osd.c:1064
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:621
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:1919
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
int OSDTop
Definition: config.h:314
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:445
virtual int StoreImageData(const cImage &Image)
Copies the given Image and returns a handle for later reference.
Definition: osd.c:2027
virtual eOsdError SetPalette(const cPalette &Palette, int Area)
Sets the Palette for the given Area (the first area is numbered 0).
Definition: osd.c:1866
static double oldAspect
Definition: osd.h:939
cPixmapMemory * RenderPixmaps(void)
Renders the dirty part of all pixmaps into a resulting pixmap that shall be displayed on the OSD...
Definition: osd.c:1729
T min(T a, T b)
Definition: tools.h:54
virtual void Fill(tColor Color)
Fills the pixmap's draw port with the given Color.
Definition: osd.c:1148
int Height(void) const
Definition: osd.h:338
int top
Definition: osd.h:999
int shown
Definition: osd.h:1002
virtual void SetAlpha(int Alpha)
Sets the alpha value of this pixmap to the given value.
Definition: osd.c:1025
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:551
int Bpp(void) const
Definition: osd.h:111
char * Read(FILE *f)
Definition: tools.c:1329
virtual void Flush(void)
Actually commits all data to the OSD hardware.
Definition: osd.c:1949
#define LOCK_PIXMAPS
Definition: osd.h:673
bool active
Definition: osd.h:730
#define MALLOC(type, size)
Definition: tools.h:46
static cMutex mutex
Definition: osd.h:454
Definition: osd.h:169
void Scroll(bool Up, bool Page)
Definition: osd.c:2123
int Width(void) const
Definition: osd.h:188
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:521
cPixmap * AddPixmap(cPixmap *Pixmap)
Adds the given Pixmap to the list of currently active pixmaps in this OSD.
Definition: osd.c:1716
int Height(void)
Definition: osd.h:1013
const cRect & ViewPort(void) const
Returns the pixmap's view port, which is relative to the OSD's origin.
Definition: osd.h:531
void SetSize(int Width, int Height)
Sets the size of this bitmap to the given values.
Definition: osd.c:294
virtual void Remove(int Index)
Definition: tools.h:551
cBitmap * savedBitmap
Definition: osd.h:723
void SetX(int X)
Definition: osd.h:316
Definition: osd.h:161
#define MINOSDHEIGHT
Definition: config.h:58
void Combine(const cRect &Rect)
Combines this rectangle with the given Rect.
Definition: osd.c:921
cRect Shifted(int Dx, int Dy) const
Definition: osd.h:387
tColor color[MAXNUMCOLORS]
Definition: osd.h:90
void SetPoint(int X, int Y)
Definition: osd.h:373
virtual int Height(void) const =0
Returns the height of this font in pixel (all characters have the same height).
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...
int Top(void)
Definition: osd.h:796
void Replace(const cPalette &Palette)
Replaces the colors of this palette with the colors from the given palette.
Definition: osd.c:208
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
static cMutex mutex
Definition: osd.h:721
bool LoadXpm(const char *FileName)
Calls SetXpm() with the data from the file FileName.
Definition: osd.c:362
virtual void Insert(T Data, int Before=0)
Definition: tools.h:534
const cSize & Size(void) const
Definition: osd.h:370
Definition: font.h:22
T constrain(T v, T l, T h)
Definition: tools.h:60
#define MINOSDWIDTH
Definition: config.h:56
bool Tile(void) const
Definition: osd.h:530
class cInitAlphaLut InitAlphaLut
virtual void DestroyPixmap(cPixmap *Pixmap)
Destroys the given Pixmap, which has previously been created by a call to CreatePixmap().
Definition: osd.c:1700
int width
Definition: osd.h:728
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:558
double antiAliasGranularity
Definition: osd.h:94
int numColors
Definition: osd.h:92
static cVector< cOsd * > Osds
Definition: osd.h:720
int Height(void) const
Definition: osd.h:189
bool Intersects(int x1, int y1, int x2, int y2) const
Returns true if the rectangle defined by the given coordinates intersects with this bitmap...
Definition: osd.c:333
virtual void DrawRectangle(const cRect &Rect, tColor Color)
Draws a filled rectangle with the given Color.
Definition: osd.c:1330
#define MAXOSDHEIGHT
Definition: config.h:59
Definition: osd.h:162
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas)
Checks whether the OSD can display the given set of sub-areas.
Definition: osd.c:1778
double OSDLeftP
Definition: config.h:313
Definition: osd.h:348
virtual ~cOsdProvider()
Definition: osd.c:1967
const tColor * Data(void) const
Definition: osd.h:433
char FontOsd[MAXFONTNAME]
Definition: config.h:319
void SetBottom(int Bottom)
Definition: osd.h:384
cRect viewPort
Definition: osd.h:458
virtual ~cOsd()
Shuts down the OSD.
Definition: osd.c:1648
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:515
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:716
void SetLeft(int Left)
Definition: osd.h:381
#define MAXOSDAREAS
Definition: osd.h:703
void Set(int X, int Y, int Width, int Height)
Definition: osd.h:371
bool Contains(const cPoint &Point) const
Returns true if this rectangle contains Point.
Definition: osd.c:885
int x2
Definition: osd.h:295
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:600
tColor RgbShade(tColor Color, double Factor)
Returns a brighter (Factor > 0) or darker (Factor < 0) version of the given Color.
Definition: osd.c:43
tColor AlphaBlend(tColor ColorFg, tColor ColorBg, uint8_t AlphaLayer)
Definition: osd.c:81
cPoint point
Definition: osd.h:350
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:1992
bool Contains(int x, int y) const
Returns true if this bitmap contains the point (x, y).
Definition: osd.c:317
const cFont * font
Definition: osd.h:1000
static const cCursesFont Font
Definition: skincurses.c:30
cRect Intersected(const cRect &Rect) const
Returns the intersection of this rectangle and the given Rect.
Definition: osd.c:909
int Left(void) const
Definition: osd.h:365
tColor colorFg
Definition: osd.h:1001
The cOsd class is the interface to the "On Screen Display".
Definition: osd.h:716
int Top(void)
Definition: osd.h:1011
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...
Definition: osd.h:326
void SetClean(void)
Resets the "dirty" rectangles of this pixmap.
Definition: osd.c:1005
cSetup Setup
Definition: config.c:373
tColor RgbToColor(uint8_t R, uint8_t G, uint8_t B)
Definition: osd.h:63
int Width(void) const
Definition: osd.h:337
bool panning
Definition: osd.h:681
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image into this pixmap at the given Point.
Definition: osd.c:1208
tColor * data
Definition: osd.h:418
static int osdTop
Definition: osd.h:719
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition: osd.h:790
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:1909
int OSDLeft
Definition: config.h:314
Definition: thread.h:63
void Clear(void)
Clears the image data by setting all pixels to be fully transparent.
Definition: osd.c:1110
static const cRect Null
Definition: osd.h:353
int Width(void) const
Definition: osd.h:431
int Size(void) const
Definition: tools.h:533
int Right(void) const
Definition: osd.h:367
void DrawText(void)
Definition: osd.c:2115
virtual void SetTile(bool Tile)
Sets the tile property of this pixmap to the given value.
Definition: osd.c:1036
const cPoint & Point(void) const
Definition: osd.h:369
int x0
Definition: osd.h:172
void SetColor(int Index, tColor Color)
Sets the palette entry at Index to Color.
Definition: osd.c:172
bool CanScrollUp(void)
Definition: osd.h:1018
int dirtyX2
Definition: osd.h:174
void Grow(int Dx, int Dy)
Grows the rectangle by the given number of pixels in either direction.
Definition: osd.c:879
int offset
Definition: osd.h:1002
int Height(void)
Definition: osd.h:798
virtual ~cImage()
Definition: osd.c:1105
virtual void DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
Draws the Dirty part of the given Pixmap into this pixmap.
Definition: osd.c:1157
int Y0(void) const
Definition: osd.h:187
#define IS_OPAQUE(c)
Definition: osd.h:27
void SetRight(int Right)
Definition: osd.h:383
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:785
int Left(void)
Definition: osd.h:1010
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:1688
const char * GetLine(int Line)
Returns the given Line. The first line is numbered 0.
Definition: font.c:630
const tIndex * Data(int x, int y) const
Returns the address of the index byte at the given coordinates.
Definition: osd.c:749
const cSize & Size(void) const
Definition: osd.h:430
#define TEXT_ALIGN_BORDER
Definition: osd.h:28
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:1281
#define MAXNUMCOLORS
Definition: osd.h:24
static bool SupportsTrueColor(void)
Returns true if the current OSD provider is able to handle a true color OSD.
Definition: osd.c:2017
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:1501
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type)
Draws a "slope" with the given Color into the given rectangle.
Definition: osd.c:1459
int Height(void) const
Definition: osd.h:364
void Shift(int Dx, int Dy)
Definition: osd.h:385
int y1
Definition: osd.h:295
char FontFix[MAXFONTNAME]
Definition: config.h:321
virtual void Clear(void)
Clears the pixmap's draw port by setting all pixels to be fully transparent.
Definition: osd.c:1140
Definition: osd.h:88
void Reset(void)
Definition: osd.c:2110
virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const =0
Draws the given text into the Bitmap at position (x, y) with the given colors.
Definition: osd.h:294
#define OSD_LEVEL_DEFAULT
Definition: osd.h:21
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:132
int Width(void)
Definition: osd.h:797
eOsdError
Definition: osd.h:44
Definition: osd.h:159
cBitmap * bitmaps[MAXOSDAREAS]
Definition: osd.h:724
double OSDAspect
Definition: config.h:315
int alpha
Definition: osd.h:456
int Left(void)
Definition: osd.h:795
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:1889
char * skipspace(const char *s)
Definition: tools.h:194
virtual bool ProvidesTrueColor(void)
Returns true if this OSD provider is able to handle a true color OSD.
Definition: osd.h:945
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image on this OSD at the given Point.
Definition: osd.c:1877
int Width(void)
Definition: osd.h:1012
#define ALPHA_TRANSPARENT
Definition: osd.h:25
int height
Definition: osd.h:728
double FontSmlSizeP
Definition: config.h:323
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
static int osdHeight
Definition: osd.h:719
virtual ~cPixmapMemory()
Definition: osd.c:1135
cPixmapMemory * savedPixmap
Definition: osd.h:726
void MarkDrawPortDirty(const cRect &Rect)
Marks the given rectangle of the draw port of this pixmap as dirty.
Definition: osd.c:985
cSize size
Definition: osd.h:417
bool modified
Definition: osd.h:93
int top
Definition: osd.h:728
int FontOsdSize
Definition: config.h:325
int Y(void) const
Definition: osd.h:315
static int oldWidth
Definition: osd.h:937
Definition: osd.h:44
Definition: osd.h:160
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
tColor Color(int Index) const
Returns the color at the given Index.
Definition: osd.h:119
virtual int Width(uint c) const =0
Returns the width of the given character in pixel.
tColor GetColor(int x, int y) const
Returns the color at the given coordinates.
Definition: osd.h:273
static int StoreImage(const cImage &Image)
Stores the given Image for later use with DrawImage() on an OSD or pixmap.
Definition: osd.c:2056
int Bottom(void) const
Definition: osd.h:368
void Take(const cPalette &Palette, tIndexes *Indexes=NULL, tColor ColorFg=0, tColor ColorBg=0)
Takes the colors from the given Palette and adds them to this palette, using existing entries if poss...
Definition: osd.c:191
virtual void SetLayer(int Layer)
Sets the layer of this pixmap to the given value.
Definition: osd.c:1010
void Fill(tColor Color)
Fills the image data with the given Color.
Definition: osd.c:1115
cOsd(int Left, int Top, uint Level)
Initializes the OSD with the given coordinates.
Definition: osd.c:1627
virtual void RestoreRegion(void)
Restores the region previously saved by a call to SaveRegion().
Definition: osd.c:1848
virtual void Clear(void)=0
Clears the pixmap's draw port by setting all pixels to be fully transparent.
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:1357
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
Allows the system to optimize utilization of the limited color palette entries when generating blende...
Definition: osd.c:1675
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:1939
uint level
Definition: osd.h:729
bool DoubleEqual(double a, double b)
Definition: tools.h:85
void Grow(int Dw, int Dh)
Definition: osd.h:344
static void Unlock(void)
Definition: osd.h:527
void SetBpp(int Bpp)
Sets the color depth of this palette to the given value.
Definition: osd.c:165
int left
Definition: osd.h:728
int OSDHeight
Definition: config.h:314
int FontSmlSize
Definition: config.h:326
int X0(void) const
Definition: osd.h:186
virtual void DropImageData(int ImageHandle)
Drops the image data referenced by ImageHandle.
Definition: osd.c:2039
virtual ~cBitmap()
Definition: osd.c:289
int OSDWidth
Definition: config.h:314
uint8_t tIndex
Definition: font.h:31
static void DropImage(int ImageHandle)
Drops the image referenced by the given ImageHandle.
Definition: osd.c:2063
int Layer(void) const
Definition: osd.h:528
cPoint Shifted(int Dx, int Dy) const
Definition: osd.h:322
cImage(void)
Definition: osd.c:1083
cPalette(int Bpp=8)
Initializes the palette with the given color depth.
Definition: osd.c:117
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
Definition: osd.h:52
#define MAXPIXMAPLAYERS
Definition: osd.h:448
tColor colorBg
Definition: osd.h:1001
tColor * data
Definition: osd.h:680
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:1832
void SetIndex(int x, int y, tIndex Index)
Sets the index at the given coordinates to Index.
Definition: osd.c:500
cBitmap * GetBitmap(int Area)
Returns a pointer to the bitmap for the given Area, or NULL if no such bitmap exists.
Definition: osd.c:1683
cRect dirtyViewPort
Definition: osd.h:460
cInitAlphaLut(void)
Definition: osd.c:63
bool Intersects(const cRect &Rect) const
Returns true if this rectangle intersects with Rect.
Definition: osd.c:901
Definition: font.h:37
int Top(void) const
Definition: osd.h:366
static void Shutdown(void)
Shuts down the OSD provider facility by deleting the current OSD provider.
Definition: osd.c:2069
static uint16_t AlphaLutFactors[255][256][2]
Definition: osd.c:58
int width
Definition: osd.h:173
int layer
Definition: osd.h:455
cTextWrapper textWrapper
Definition: osd.h:1003
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...
#define ALPHA_OPAQUE
Definition: osd.h:26
static int osdWidth
Definition: osd.h:719
uint32_t tColor
Definition: font.h:29
bool CanScrollDown(void)
Definition: osd.h:1019
double OSDTopP
Definition: config.h:313
int dirtyY2
Definition: osd.h:174
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:1972
int Total(void)
Definition: osd.h:1014