vdr  2.2.0
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 3.5 2015/02/11 09:48:02 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)
130  antiAliasGranularity = MAXNUMCOLORS - 1;
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;
213  antiAliasGranularity = Palette.antiAliasGranularity;
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 
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  cBitmap *b = new cBitmap(int(round(Width() * FactorX)), int(round(Height() * FactorY)), Bpp(), X0(), Y0());
843  int RatioX = (Width() << 16) / b->Width();
844  int RatioY = (Height() << 16) / b->Height();
845  if (!AntiAlias || FactorX <= 1.0 && FactorY <= 1.0) {
846  // Downscaling - no anti-aliasing:
847  b->Replace(*this); // copy palette
848  tIndex *DestRow = b->bitmap;
849  int SourceY = 0;
850  for (int y = 0; y < b->Height(); y++) {
851  int SourceX = 0;
852  tIndex *SourceRow = bitmap + (SourceY >> 16) * Width();
853  tIndex *Dest = DestRow;
854  for (int x = 0; x < b->Width(); x++) {
855  *Dest++ = SourceRow[SourceX >> 16];
856  SourceX += RatioX;
857  }
858  SourceY += RatioY;
859  DestRow += b->Width();
860  }
861  }
862  else {
863  // Upscaling - anti-aliasing:
864  b->SetBpp(8);
865  b->Replace(*this); // copy palette (must be done *after* SetBpp()!)
866  int SourceY = 0;
867  for (int y = 0; y < b->Height(); y++) {
868  int SourceX = 0;
869  int sy = min(SourceY >> 16, Height() - 2);
870  uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF);
871  for (int x = 0; x < b->Width(); x++) {
872  int sx = min(SourceX >> 16, Width() - 2);
873  uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF);
874  tColor c1 = b->Blend(GetColor(sx, sy), GetColor(sx + 1, sy), BlendX);
875  tColor c2 = b->Blend(GetColor(sx, sy + 1), GetColor(sx + 1, sy + 1), BlendX);
876  tColor c3 = b->Blend(c1, c2, BlendY);
877  b->DrawPixel(x + X0(), y + Y0(), c3);
878  SourceX += RatioX;
879  }
880  SourceY += RatioY;
881  }
882  }
883  return b;
884 }
885 
886 // --- cRect -----------------------------------------------------------------
887 
888 const cRect cRect::Null;
889 
890 void cRect::Grow(int Dx, int Dy)
891 {
892  point.Shift(-Dx, -Dy);
893  size.Grow(Dx, Dy);
894 }
895 
896 bool cRect::Contains(const cPoint &Point) const
897 {
898  return Left() <= Point.X() &&
899  Top() <= Point.Y() &&
900  Right() >= Point.X() &&
901  Bottom() >= Point.Y();
902 }
903 
904 bool cRect::Contains(const cRect &Rect) const
905 {
906  return Left() <= Rect.Left() &&
907  Top() <= Rect.Top() &&
908  Right() >= Rect.Right() &&
909  Bottom() >= Rect.Bottom();
910 }
911 
912 bool cRect::Intersects(const cRect &Rect) const
913 {
914  return !(Left() > Rect.Right() ||
915  Top() > Rect.Bottom() ||
916  Right() < Rect.Left() ||
917  Bottom() < Rect.Top());
918 }
919 
920 cRect cRect::Intersected(const cRect &Rect) const
921 {
922  cRect r;
923  if (!IsEmpty() && !Rect.IsEmpty()) {
924  r.SetLeft(max(Left(), Rect.Left()));
925  r.SetTop(max(Top(), Rect.Top()));
926  r.SetRight(min(Right(), Rect.Right()));
927  r.SetBottom(min(Bottom(), Rect.Bottom()));
928  }
929  return r;
930 }
931 
932 void cRect::Combine(const cRect &Rect)
933 {
934  if (IsEmpty())
935  *this = Rect;
936  if (Rect.IsEmpty())
937  return;
938  // must set right/bottom *before* top/left!
939  SetRight(max(Right(), Rect.Right()));
940  SetBottom(max(Bottom(), Rect.Bottom()));
941  SetLeft(min(Left(), Rect.Left()));
942  SetTop(min(Top(), Rect.Top()));
943 }
944 
945 void cRect::Combine(const cPoint &Point)
946 {
947  if (IsEmpty())
948  Set(Point.X(), Point.Y(), 1, 1);
949  // must set right/bottom *before* top/left!
950  SetRight(max(Right(), Point.X()));
951  SetBottom(max(Bottom(), Point.Y()));
952  SetLeft(min(Left(), Point.X()));
953  SetTop(min(Top(), Point.Y()));
954 }
955 
956 // --- cPixmap ---------------------------------------------------------------
957 
959 
961 {
962  layer = -1;
963  alpha = ALPHA_OPAQUE;
964  tile = false;
965 }
966 
967 cPixmap::cPixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
968 {
969  layer = Layer;
970  if (layer >= MAXPIXMAPLAYERS) {
971  layer = MAXPIXMAPLAYERS - 1;
972  esyslog("ERROR: pixmap layer %d limited to %d", Layer, layer);
973  }
974  viewPort = ViewPort;
975  if (!DrawPort.IsEmpty())
976  drawPort = DrawPort;
977  else {
978  drawPort = viewPort;
979  drawPort.SetPoint(0, 0);
980  }
981  alpha = ALPHA_OPAQUE;
982  tile = false;
983 }
984 
986 {
987  if (layer >= 0)
988  dirtyViewPort.Combine(Rect.Intersected(viewPort));
989 }
990 
992 {
993  if (layer >= 0 && viewPort.Contains(Point))
994  dirtyViewPort.Combine(Point);
995 }
996 
998 {
999  dirtyDrawPort.Combine(Rect.Intersected(drawPort));
1000  if (tile)
1001  MarkViewPortDirty(viewPort);
1002  else
1003  MarkViewPortDirty(Rect.Shifted(viewPort.Point()));
1004 }
1005 
1007 {
1008  if (drawPort.Contains(Point)) {
1009  dirtyDrawPort.Combine(Point);
1010  if (tile)
1011  MarkViewPortDirty(viewPort);
1012  else
1013  MarkViewPortDirty(Point.Shifted(viewPort.Point()));
1014  }
1015 }
1016 
1018 {
1019  dirtyViewPort = dirtyDrawPort = cRect();
1020 }
1021 
1022 void cPixmap::SetLayer(int Layer)
1023 {
1024  Lock();
1025  if (Layer >= MAXPIXMAPLAYERS) {
1026  esyslog("ERROR: pixmap layer %d limited to %d", Layer, MAXPIXMAPLAYERS - 1);
1027  Layer = MAXPIXMAPLAYERS - 1;
1028  }
1029  // The sequence here is important, because the view port is only marked as dirty
1030  // if the layer is >= 0:
1031  if (layer >= 0) {
1032  MarkViewPortDirty(viewPort); // the pixmap is visible and may or may not become invisible
1033  layer = Layer;
1034  }
1035  else if (Layer >= 0) {
1036  layer = Layer;
1037  MarkViewPortDirty(viewPort); // the pixmap was invisible and has become visible
1038  }
1039  else
1040  layer = Layer; // the pixmap was invisible and remains so
1041  Unlock();
1042 }
1043 
1044 void cPixmap::SetAlpha(int Alpha)
1045 {
1046  Lock();
1047  Alpha = constrain(Alpha, ALPHA_TRANSPARENT, ALPHA_OPAQUE);
1048  if (Alpha != alpha) {
1049  MarkViewPortDirty(viewPort);
1050  alpha = Alpha;
1051  }
1052  Unlock();
1053 }
1054 
1055 void cPixmap::SetTile(bool Tile)
1056 {
1057  Lock();
1058  if (Tile != tile) {
1059  if (drawPort.Point() != cPoint(0, 0) || drawPort.Width() < viewPort.Width() || drawPort.Height() < viewPort.Height())
1060  MarkViewPortDirty(viewPort);
1061  tile = Tile;
1062  }
1063  Unlock();
1064 }
1065 
1066 void cPixmap::SetViewPort(const cRect &Rect)
1067 {
1068  Lock();
1069  if (Rect != viewPort) {
1070  if (tile)
1071  MarkViewPortDirty(viewPort);
1072  else
1073  MarkViewPortDirty(drawPort.Shifted(viewPort.Point()));
1074  viewPort = Rect;
1075  if (tile)
1076  MarkViewPortDirty(viewPort);
1077  else
1078  MarkViewPortDirty(drawPort.Shifted(viewPort.Point()));
1079  }
1080  Unlock();
1081 }
1082 
1083 void cPixmap::SetDrawPortPoint(const cPoint &Point, bool Dirty)
1084 {
1085  Lock();
1086  if (Point != drawPort.Point()) {
1087  if (Dirty) {
1088  if (tile)
1089  MarkViewPortDirty(viewPort);
1090  else
1091  MarkViewPortDirty(drawPort.Shifted(viewPort.Point()));
1092  }
1093  drawPort.SetPoint(Point);
1094  if (Dirty && !tile)
1095  MarkViewPortDirty(drawPort.Shifted(viewPort.Point()));
1096  }
1097  Unlock();
1098 }
1099 
1100 // --- cImage ----------------------------------------------------------------
1101 
1103 {
1104  data = NULL;
1105 }
1106 
1107 cImage::cImage(const cImage &Image)
1108 {
1109  size = Image.Size();
1110  int l = size.Width() * size.Height() * sizeof(tColor);
1111  data = MALLOC(tColor, l);
1112  memcpy(data, Image.Data(), l);
1113 }
1114 
1115 cImage::cImage(const cSize &Size, const tColor *Data)
1116 {
1117  size = Size;
1118  int l = size.Width() * size.Height() * sizeof(tColor);
1119  data = MALLOC(tColor, l);
1120  if (Data)
1121  memcpy(data, Data, l);
1122 }
1123 
1125 {
1126  free(data);
1127 }
1128 
1129 void cImage::Clear(void)
1130 {
1131  memset(data, 0x00, Width() * Height() * sizeof(tColor));
1132 }
1133 
1135 {
1136  for (int i = Width() * Height() - 1; i >= 0; i--)
1137  data[i] = Color;
1138 }
1139 
1140 // --- cPixmapMemory ---------------------------------------------------------
1141 
1143 {
1144  data = NULL;
1145  panning = false;
1146 }
1147 
1148 cPixmapMemory::cPixmapMemory(int Layer, const cRect &ViewPort, const cRect &DrawPort)
1149 :cPixmap(Layer, ViewPort, DrawPort)
1150 {
1151  data = MALLOC(tColor, this->DrawPort().Width() * this->DrawPort().Height());
1152  panning = false;
1153 }
1154 
1156 {
1157  free(data);
1158 }
1159 
1161 {
1162  Lock();
1163  memset(data, 0x00, DrawPort().Width() * DrawPort().Height() * sizeof(tColor));
1165  Unlock();
1166 }
1167 
1169 {
1170  Lock();
1171  for (int i = DrawPort().Width() * DrawPort().Height() - 1; i >= 0; i--)
1172  data[i] = Color;
1174  Unlock();
1175 }
1176 
1177 void cPixmap::DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
1178 {
1179  if (Pixmap->Tile() && (Pixmap->DrawPort().Point() != cPoint(0, 0) || Pixmap->DrawPort().Size() < Pixmap->ViewPort().Size())) {
1180  cPoint t0 = Pixmap->DrawPort().Point().Shifted(Pixmap->ViewPort().Point()); // the origin of the draw port in absolute OSD coordinates
1181  // Find the top/leftmost location where the draw port touches the view port:
1182  while (t0.X() > Pixmap->ViewPort().Left())
1183  t0.Shift(-Pixmap->DrawPort().Width(), 0);
1184  while (t0.Y() > Pixmap->ViewPort().Top())
1185  t0.Shift(0, -Pixmap->DrawPort().Height());
1186  cPoint t = t0;;
1187  while (t.Y() <= Pixmap->ViewPort().Bottom()) {
1188  while (t.X() <= Pixmap->ViewPort().Right()) {
1189  cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1190  Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1191  cPoint Delta = Source.Point() - t;
1192  Source.SetPoint(t); // Source is now where the pixmap's data shall be drawn
1193  Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1194  Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1195  if (!Source.IsEmpty()) {
1196  cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1197  Source.Shift(Delta); // Source is now back at the pixmap's draw port location, still in absolute OSD coordinates
1198  Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's view 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  t.Shift(Pixmap->DrawPort().Width(), 0); // increase one draw port width to the right
1206  }
1207  t.SetX(t0.X()); // go back to the leftmost position
1208  t.Shift(0, Pixmap->DrawPort().Height()); // increase one draw port height down
1209  }
1210  }
1211  else {
1212  cRect Source = Pixmap->DrawPort(); // assume the entire pixmap needs to be rendered
1213  Source.Shift(Pixmap->ViewPort().Point()); // Source is now in absolute OSD coordinates
1214  Source = Source.Intersected(Pixmap->ViewPort()); // Source is now limited to the pixmap's view port
1215  Source = Source.Intersected(Dirty); // Source is now limited to the actual dirty rectangle
1216  if (!Source.IsEmpty()) {
1217  cPoint Dest = Source.Point().Shifted(-ViewPort().Point()); // remember the destination point
1218  Source.Shift(-Pixmap->ViewPort().Point()); // Source is now relative to the pixmap's draw port again
1219  Source.Shift(-Pixmap->DrawPort().Point()); // Source is now relative to the pixmap's data
1220  if (Pixmap->Layer() == 0)
1221  Copy(Pixmap, Source, Dest); // this is the "background" pixmap
1222  else
1223  Render(Pixmap, Source, Dest); // all others are alpha blended over the background
1224  }
1225  }
1226 }
1227 
1228 void cPixmapMemory::DrawImage(const cPoint &Point, const cImage &Image)
1229 {
1230  Lock();
1231  cRect r = cRect(Point, Image.Size()).Intersected(DrawPort().Size());
1232  if (!r.IsEmpty()) {
1233  int ws = Image.Size().Width();
1234  int wd = DrawPort().Width();
1235  int w = r.Width() * sizeof(tColor);
1236  const tColor *ps = Image.Data();
1237  if (Point.Y() < 0)
1238  ps -= Point.Y() * ws;
1239  if (Point.X() < 0)
1240  ps -= Point.X();
1241  tColor *pd = data + wd * r.Top() + r.Left();
1242  for (int y = r.Height(); y-- > 0; ) {
1243  memcpy(pd, ps, w);
1244  ps += ws;
1245  pd += wd;
1246  }
1247  MarkDrawPortDirty(r);
1248  }
1249  Unlock();
1250 }
1251 
1252 void cPixmapMemory::DrawImage(const cPoint &Point, int ImageHandle)
1253 {
1254  Lock();
1255  if (const cImage *Image = cOsdProvider::GetImageData(ImageHandle))
1256  DrawImage(Point, *Image);
1257  Unlock();
1258 }
1259 
1260 void cPixmapMemory::DrawPixel(const cPoint &Point, tColor Color)
1261 {
1262  Lock();
1263  if (DrawPort().Size().Contains(Point)) {
1264  int p = Point.Y() * DrawPort().Width() + Point.X();
1265  if (Layer() == 0 && !IS_OPAQUE(Color))
1266  data[p] = AlphaBlend(Color, data[p]);
1267  else
1268  data[p] = Color;
1269  MarkDrawPortDirty(Point);
1270  }
1271  Unlock();
1272 }
1273 
1274 void cPixmapMemory::DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay)
1275 {
1276  Lock();
1277  cRect r = cRect(Point, cSize(Bitmap.Width(), Bitmap.Height())).Intersected(DrawPort().Size());
1278  if (!r.IsEmpty()) {
1279  bool UseColors = ColorFg || ColorBg;
1280  int wd = DrawPort().Width();
1281  tColor *pd = data + wd * r.Top() + r.Left();
1282  for (int y = r.Top(); y <= r.Bottom(); y++) {
1283  tColor *cd = pd;
1284  for (int x = r.Left(); x <= r.Right(); x++) {
1285  tIndex Index = *Bitmap.Data(x - Point.X(), y - Point.Y());
1286  if (Index || !Overlay) {
1287  if (UseColors)
1288  *cd = Index ? ColorFg : ColorBg;
1289  else
1290  *cd = Bitmap.Color(Index);
1291  }
1292  cd++;
1293  }
1294  pd += wd;
1295  }
1296  MarkDrawPortDirty(r);
1297  }
1298  Unlock();
1299 }
1300 
1301 void cPixmapMemory::DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
1302 {
1303  Lock();
1304  int x = Point.X();
1305  int y = Point.Y();
1306  int w = Font->Width(s);
1307  int h = Font->Height();
1308  int limit = 0;
1309  int cw = Width ? Width : w;
1310  int ch = Height ? Height : h;
1311  cRect r(x, y, cw, ch);
1312  if (ColorBg != clrTransparent)
1313  DrawRectangle(r, ColorBg);
1314  if (Width || Height) {
1315  limit = x + cw;
1316  if (Width) {
1317  if ((Alignment & taLeft) != 0) {
1318  if ((Alignment & taBorder) != 0)
1319  x += max(h / TEXT_ALIGN_BORDER, 1);
1320  }
1321  else if ((Alignment & taRight) != 0) {
1322  if (w < Width)
1323  x += Width - w;
1324  if ((Alignment & taBorder) != 0)
1325  x -= max(h / TEXT_ALIGN_BORDER, 1);
1326  }
1327  else { // taCentered
1328  if (w < Width)
1329  x += (Width - w) / 2;
1330  }
1331  }
1332  if (Height) {
1333  if ((Alignment & taTop) != 0)
1334  ;
1335  else if ((Alignment & taBottom) != 0) {
1336  if (h < Height)
1337  y += Height - h;
1338  }
1339  else { // taCentered
1340  if (h < Height)
1341  y += (Height - h) / 2;
1342  }
1343  }
1344  }
1345  Font->DrawText(this, x, y, s, ColorFg, ColorBg, limit);
1346  MarkDrawPortDirty(r);
1347  Unlock();
1348 }
1349 
1351 {
1352  Lock();
1353  cRect r = Rect.Intersected(DrawPort().Size());
1354  if (!r.IsEmpty()) {
1355  int wd = DrawPort().Width();
1356  int w = r.Width() * sizeof(tColor);
1357  tColor *ps = NULL;
1358  tColor *pd = data + wd * r.Top() + r.Left();
1359  for (int y = r.Height(); y-- > 0; ) {
1360  if (ps)
1361  memcpy(pd, ps, w); // all other lines are copied fast from the first one
1362  else {
1363  // explicitly fill the first line:
1364  tColor *cd = ps = pd;
1365  for (int x = r.Width(); x-- > 0; ) {
1366  *cd = Color;
1367  cd++;
1368  }
1369  }
1370  pd += wd;
1371  }
1372  MarkDrawPortDirty(r);
1373  }
1374  Unlock();
1375 }
1376 
1377 void cPixmapMemory::DrawEllipse(const cRect &Rect, tColor Color, int Quadrants)
1378 {
1379 //TODO use anti-aliasing?
1380 //TODO fix alignment
1381  Lock();
1382  // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF
1383  int x1 = Rect.Left();
1384  int y1 = Rect.Top();
1385  int x2 = Rect.Right();
1386  int y2 = Rect.Bottom();
1387  int rx = x2 - x1;
1388  int ry = y2 - y1;
1389  int cx = (x1 + x2) / 2;
1390  int cy = (y1 + y2) / 2;
1391  switch (abs(Quadrants)) {
1392  case 0: rx /= 2; ry /= 2; break;
1393  case 1: cx = x1; cy = y2; break;
1394  case 2: cx = x2; cy = y2; break;
1395  case 3: cx = x2; cy = y1; break;
1396  case 4: cx = x1; cy = y1; break;
1397  case 5: cx = x1; ry /= 2; break;
1398  case 6: cy = y2; rx /= 2; break;
1399  case 7: cx = x2; ry /= 2; break;
1400  case 8: cy = y1; rx /= 2; break;
1401  default: ;
1402  }
1403  int TwoASquare = max(1, 2 * rx * rx);
1404  int TwoBSquare = max(1, 2 * ry * ry);
1405  int x = rx;
1406  int y = 0;
1407  int XChange = ry * ry * (1 - 2 * rx);
1408  int YChange = rx * rx;
1409  int EllipseError = 0;
1410  int StoppingX = TwoBSquare * rx;
1411  int StoppingY = 0;
1412  while (StoppingX >= StoppingY) {
1413  switch (Quadrants) {
1414  case 5: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); // no break
1415  case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1416  case 7: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); // no break
1417  case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1418  case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1419  case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1420  case 0:
1421  case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + 1, 1), Color); if (Quadrants == 6) break;
1422  case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + 1, 1), Color); break;
1423  case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1424  case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1425  case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1426  case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1427  default: ;
1428  }
1429  y++;
1430  StoppingY += TwoASquare;
1431  EllipseError += YChange;
1432  YChange += TwoASquare;
1433  if (2 * EllipseError + XChange > 0) {
1434  x--;
1435  StoppingX -= TwoBSquare;
1436  EllipseError += XChange;
1437  XChange += TwoBSquare;
1438  }
1439  }
1440  x = 0;
1441  y = ry;
1442  XChange = ry * ry;
1443  YChange = rx * rx * (1 - 2 * ry);
1444  EllipseError = 0;
1445  StoppingX = 0;
1446  StoppingY = TwoASquare * ry;
1447  while (StoppingX <= StoppingY) {
1448  switch (Quadrants) {
1449  case 5: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); // no break
1450  case 1: DrawRectangle(cRect(cx, cy - y, x + 1, 1), Color); break;
1451  case 7: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); // no break
1452  case 2: DrawRectangle(cRect(cx - x, cy - y, x + 1, 1), Color); break;
1453  case 3: DrawRectangle(cRect(cx - x, cy + y, x + 1, 1), Color); break;
1454  case 4: DrawRectangle(cRect(cx, cy + y, x + 1, 1), Color); break;
1455  case 0:
1456  case 6: DrawRectangle(cRect(cx - x, cy - y, 2 * x + 1, 1), Color); if (Quadrants == 6) break;
1457  case 8: DrawRectangle(cRect(cx - x, cy + y, 2 * x + 1, 1), Color); break;
1458  case -1: DrawRectangle(cRect(cx + x, cy - y, rx - x + 1, 1), Color); break;
1459  case -2: DrawRectangle(cRect(x1, cy - y, cx - x - x1 + 1, 1), Color); break;
1460  case -3: DrawRectangle(cRect(x1, cy + y, cx - x - x1 + 1, 1), Color); break;
1461  case -4: DrawRectangle(cRect(cx + x, cy + y, rx - x + 1, 1), Color); break;
1462  default: ;
1463  }
1464  x++;
1465  StoppingX += TwoBSquare;
1466  EllipseError += XChange;
1467  XChange += TwoBSquare;
1468  if (2 * EllipseError + YChange > 0) {
1469  y--;
1470  StoppingY -= TwoASquare;
1471  EllipseError += YChange;
1472  YChange += TwoASquare;
1473  }
1474  }
1475  MarkDrawPortDirty(Rect);
1476  Unlock();
1477 }
1478 
1479 void cPixmapMemory::DrawSlope(const cRect &Rect, tColor Color, int Type)
1480 {
1481  //TODO anti-aliasing?
1482  //TODO also simplify cBitmap::DrawSlope()
1483  Lock();
1484  bool upper = Type & 0x01;
1485  bool falling = Type & 0x02;
1486  bool vertical = Type & 0x04;
1487  int x1 = Rect.Left();
1488  int y1 = Rect.Top();
1489  int x2 = Rect.Right();
1490  int y2 = Rect.Bottom();
1491  int w = Rect.Width();
1492  int h = Rect.Height();
1493  if (vertical) {
1494  for (int y = y1; y <= y2; y++) {
1495  double c = cos((y - y1) * M_PI / h);
1496  if (falling)
1497  c = -c;
1498  int x = (x1 + x2) / 2 + int(w * c / 2);
1499  if (upper && !falling || !upper && falling)
1500  DrawRectangle(cRect(x1, y, x - x1 + 1, 1), Color);
1501  else
1502  DrawRectangle(cRect(x, y, x2 - x + 1, 1), Color);
1503  }
1504  }
1505  else {
1506  for (int x = x1; x <= x2; x++) {
1507  double c = cos((x - x1) * M_PI / w);
1508  if (falling)
1509  c = -c;
1510  int y = (y1 + y2) / 2 + int(h * c / 2);
1511  if (upper)
1512  DrawRectangle(cRect(x, y1, 1, y - y1 + 1), Color);
1513  else
1514  DrawRectangle(cRect(x, y, 1, y2 - y + 1), Color);
1515  }
1516  }
1517  MarkDrawPortDirty(Rect);
1518  Unlock();
1519 }
1520 
1521 void cPixmapMemory::Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1522 {
1523  Lock();
1524  if (Pixmap->Alpha() != ALPHA_TRANSPARENT) {
1525  if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1526  cRect s = Source.Intersected(Pixmap->DrawPort().Size());
1527  if (!s.IsEmpty()) {
1528  cPoint v = Dest - Source.Point();
1529  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1530  if (!d.IsEmpty()) {
1531  s = d.Shifted(-v);
1532  int a = pm->Alpha();
1533  int ws = pm->DrawPort().Width();
1534  int wd = DrawPort().Width();
1535  const tColor *ps = pm->data + ws * s.Top() + s.Left();
1536  tColor *pd = data + wd * d.Top() + d.Left();
1537  for (int y = d.Height(); y-- > 0; ) {
1538  const tColor *cs = ps;
1539  tColor *cd = pd;
1540  for (int x = d.Width(); x-- > 0; ) {
1541  *cd = AlphaBlend(*cs, *cd, a);
1542  cs++;
1543  cd++;
1544  }
1545  ps += ws;
1546  pd += wd;
1547  }
1548  MarkDrawPortDirty(d);
1549  }
1550  }
1551  }
1552  }
1553  Unlock();
1554 }
1555 
1556 void cPixmapMemory::Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
1557 {
1558  Lock();
1559  if (const cPixmapMemory *pm = dynamic_cast<const cPixmapMemory *>(Pixmap)) {
1560  cRect s = Source.Intersected(pm->DrawPort().Size());
1561  if (!s.IsEmpty()) {
1562  cPoint v = Dest - Source.Point();
1563  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1564  if (!d.IsEmpty()) {
1565  s = d.Shifted(-v);
1566  int ws = pm->DrawPort().Width();
1567  int wd = DrawPort().Width();
1568  int w = d.Width() * sizeof(tColor);
1569  const tColor *ps = pm->data + ws * s.Top() + s.Left();
1570  tColor *pd = data + wd * d.Top() + d.Left();
1571  for (int y = d.Height(); y-- > 0; ) {
1572  memcpy(pd, ps, w);
1573  ps += ws;
1574  pd += wd;
1575  }
1576  MarkDrawPortDirty(d);
1577  }
1578  }
1579  }
1580  Unlock();
1581 }
1582 
1583 void cPixmapMemory::Scroll(const cPoint &Dest, const cRect &Source)
1584 {
1585  Lock();
1586  cRect s;
1587  if (&Source == &cRect::Null)
1588  s = DrawPort().Shifted(-DrawPort().Point());
1589  else
1590  s = Source.Intersected(DrawPort().Size());
1591  if (!s.IsEmpty()) {
1592  cPoint v = Dest - Source.Point();
1593  cRect d = s.Shifted(v).Intersected(DrawPort().Size());
1594  if (!d.IsEmpty()) {
1595  s = d.Shifted(-v);
1596  if (d.Point() != s.Point()) {
1597  int ws = DrawPort().Width();
1598  int wd = ws;
1599  int w = d.Width() * sizeof(tColor);
1600  const tColor *ps = data + ws * s.Top() + s.Left();
1601  tColor *pd = data + wd * d.Top() + d.Left();
1602  for (int y = d.Height(); y-- > 0; ) {
1603  memmove(pd, ps, w); // source and destination might overlap!
1604  ps += ws;
1605  pd += wd;
1606  }
1607  if (panning)
1608  SetDrawPortPoint(DrawPort().Point().Shifted(s.Point() - d.Point()), false);
1609  else
1610  MarkDrawPortDirty(d);
1611  }
1612  }
1613  }
1614  Unlock();
1615 }
1616 
1617 void cPixmapMemory::Pan(const cPoint &Dest, const cRect &Source)
1618 {
1619  Lock();
1620  panning = true;
1621  Scroll(Dest, Source);
1622  panning = false;
1623  Unlock();
1624 }
1625 
1626 // --- cOsd ------------------------------------------------------------------
1627 
1628 static const char *OsdErrorTexts[] = {
1629  "ok",
1630  "too many areas",
1631  "too many colors",
1632  "bpp not supported",
1633  "areas overlap",
1634  "wrong alignment",
1635  "out of memory",
1636  "wrong area size",
1637  "unknown",
1638  };
1639 
1640 int cOsd::osdLeft = 0;
1641 int cOsd::osdTop = 0;
1642 int cOsd::osdWidth = 0;
1643 int cOsd::osdHeight = 0;
1646 
1647 cOsd::cOsd(int Left, int Top, uint Level)
1648 {
1649  cMutexLock MutexLock(&mutex);
1650  isTrueColor = false;
1651  savedBitmap = NULL;
1652  numBitmaps = 0;
1653  savedPixmap = NULL;
1654  left = Left;
1655  top = Top;
1656  width = height = 0;
1657  level = Level;
1658  active = false;
1659  for (int i = 0; i < Osds.Size(); i++) {
1660  if (Osds[i]->level > level) {
1661  Osds.Insert(this, i);
1662  return;
1663  }
1664  }
1665  Osds.Append(this);
1666 }
1667 
1669 {
1670  cMutexLock MutexLock(&mutex);
1671  for (int i = 0; i < numBitmaps; i++)
1672  delete bitmaps[i];
1673  delete savedBitmap;
1674  delete savedPixmap;
1675  for (int i = 0; i < pixmaps.Size(); i++)
1676  delete pixmaps[i];
1677  for (int i = 0; i < Osds.Size(); i++) {
1678  if (Osds[i] == this) {
1679  Osds.Remove(i);
1680  if (Osds.Size())
1681  Osds[0]->SetActive(true);
1682  break;
1683  }
1684  }
1685 }
1686 
1687 void cOsd::SetOsdPosition(int Left, int Top, int Width, int Height)
1688 {
1689  osdLeft = Left;
1690  osdTop = Top;
1691  osdWidth = constrain(Width, MINOSDWIDTH, MAXOSDWIDTH);
1692  osdHeight = constrain(Height, MINOSDHEIGHT, MAXOSDHEIGHT);
1693 }
1694 
1695 void cOsd::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
1696 {
1697  if (isTrueColor)
1698  return;
1699  for (int i = 0; i < numBitmaps; i++)
1700  bitmaps[i]->SetAntiAliasGranularity(FixedColors, BlendColors);
1701 }
1702 
1704 {
1705  return Area < numBitmaps ? (isTrueColor ? bitmaps[0] : bitmaps[Area]) : NULL;
1706 }
1707 
1709 {
1710  if (isTrueColor) {
1711  LOCK_PIXMAPS;
1712  cPixmap *Pixmap = new cPixmapMemory(Layer, ViewPort, DrawPort);
1713  if (AddPixmap(Pixmap))
1714  return Pixmap;
1715  delete Pixmap;
1716  }
1717  return NULL;
1718 }
1719 
1721 {
1722  if (Pixmap) {
1723  LOCK_PIXMAPS;
1724  for (int i = 1; i < pixmaps.Size(); i++) { // begin at 1 - don't let the background pixmap be destroyed!
1725  if (pixmaps[i] == Pixmap) {
1726  if (Pixmap->Layer() >= 0)
1727  pixmaps[0]->MarkViewPortDirty(Pixmap->ViewPort());
1728  delete Pixmap;
1729  pixmaps[i] = NULL;
1730  return;
1731  }
1732  }
1733  esyslog("ERROR: attempt to destroy an unregistered pixmap");
1734  }
1735 }
1736 
1738 {
1739  if (Pixmap) {
1740  LOCK_PIXMAPS;
1741  for (int i = 0; i < pixmaps.Size(); i++) {
1742  if (!pixmaps[i])
1743  return pixmaps[i] = Pixmap;
1744  }
1745  pixmaps.Append(Pixmap);
1746  }
1747  return Pixmap;
1748 }
1749 
1751 {
1752  cPixmap *Pixmap = NULL;
1753  if (isTrueColor) {
1754  LOCK_PIXMAPS;
1755  // Collect overlapping dirty rectangles:
1756  cRect d;
1757  for (int i = 0; i < pixmaps.Size(); i++) {
1758  if (cPixmap *pm = pixmaps[i]) {
1759  if (!pm->DirtyViewPort().IsEmpty()) {
1760  if (d.IsEmpty() || d.Intersects(pm->DirtyViewPort())) {
1761  d.Combine(pm->DirtyViewPort());
1762  pm->SetClean();
1763  }
1764  }
1765  }
1766  }
1767  if (!d.IsEmpty()) {
1768 //#define DebugDirty
1769 #ifdef DebugDirty
1770  static cRect OldDirty;
1771  cRect NewDirty = d;
1772  d.Combine(OldDirty);
1773  OldDirty = NewDirty;
1774 #endif
1775  Pixmap = CreatePixmap(-1, d);
1776  if (Pixmap) {
1777  Pixmap->Clear();
1778  // Render the individual pixmaps into the resulting pixmap:
1779  for (int Layer = 0; Layer < MAXPIXMAPLAYERS; Layer++) {
1780  for (int i = 0; i < pixmaps.Size(); i++) {
1781  if (cPixmap *pm = pixmaps[i]) {
1782  if (pm->Layer() == Layer)
1783  Pixmap->DrawPixmap(pm, d);
1784  }
1785  }
1786  }
1787 #ifdef DebugDirty
1788  cPixmapMemory DirtyIndicator(7, NewDirty);
1789  static tColor DirtyIndicatorColors[] = { 0x7FFFFF00, 0x7F00FFFF };
1790  static int DirtyIndicatorIndex = 0;
1791  DirtyIndicator.Fill(DirtyIndicatorColors[DirtyIndicatorIndex]);
1792  DirtyIndicatorIndex = 1 - DirtyIndicatorIndex;
1793  Pixmap->Render(&DirtyIndicator, DirtyIndicator.DrawPort(), DirtyIndicator.ViewPort().Point().Shifted(-Pixmap->ViewPort().Point()));
1794 #endif
1795  }
1796  }
1797  }
1798  return Pixmap;
1799 }
1800 
1801 eOsdError cOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
1802 {
1803  if (NumAreas > MAXOSDAREAS)
1804  return oeTooManyAreas;
1805  eOsdError Result = oeOk;
1806  for (int i = 0; i < NumAreas; i++) {
1807  if (Areas[i].x1 > Areas[i].x2 || Areas[i].y1 > Areas[i].y2 || Areas[i].x1 < 0 || Areas[i].y1 < 0)
1808  return oeWrongAlignment;
1809  for (int j = i + 1; j < NumAreas; j++) {
1810  if (Areas[i].Intersects(Areas[j])) {
1811  Result = oeAreasOverlap;
1812  break;
1813  }
1814  }
1815  if (Areas[i].bpp == 32) {
1816  if (NumAreas > 1)
1817  return oeTooManyAreas;
1818  }
1819  }
1820  return Result;
1821 }
1822 
1823 eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas)
1824 {
1825  eOsdError Result = CanHandleAreas(Areas, NumAreas);
1826  if (Result == oeOk) {
1827  while (numBitmaps)
1828  delete bitmaps[--numBitmaps];
1829  for (int i = 0; i < pixmaps.Size(); i++) {
1830  delete pixmaps[i];
1831  pixmaps[i] = NULL;
1832  }
1833  width = height = 0;
1834  isTrueColor = NumAreas == 1 && Areas[0].bpp == 32;
1835  if (isTrueColor) {
1836  width = Areas[0].x2 - Areas[0].x1 + 1;
1837  height = Areas[0].y2 - Areas[0].y1 + 1;
1838  cPixmap *Pixmap = CreatePixmap(0, cRect(Areas[0].x1, Areas[0].y1, width, height));
1839  Pixmap->Clear();
1840  bitmaps[numBitmaps++] = new cBitmap(10, 10, 8); // dummy bitmap for GetBitmap()
1841  }
1842  else {
1843  for (int i = 0; i < NumAreas; i++) {
1844  bitmaps[numBitmaps++] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1);
1845  width = max(width, Areas[i].x2 + 1);
1846  height = max(height, Areas[i].y2 + 1);
1847  }
1848  }
1849  }
1850  else
1851  esyslog("ERROR: cOsd::SetAreas returned %d (%s)", Result, Result < oeUnknown ? OsdErrorTexts[Result] : OsdErrorTexts[oeUnknown]);
1852  return Result;
1853 }
1854 
1855 void cOsd::SaveRegion(int x1, int y1, int x2, int y2)
1856 {
1857  if (isTrueColor) {
1858  delete savedPixmap;
1859  cRect r(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
1860  savedPixmap = new cPixmapMemory(0, r);
1861  savedPixmap->Copy(pixmaps[0], r, cPoint(0, 0));
1862  }
1863  else {
1864  delete savedBitmap;
1865  savedBitmap = new cBitmap(x2 - x1 + 1, y2 - y1 + 1, 8, x1, y1);
1866  for (int i = 0; i < numBitmaps; i++)
1867  savedBitmap->DrawBitmap(bitmaps[i]->X0(), bitmaps[i]->Y0(), *bitmaps[i]);
1868  }
1869 }
1870 
1872 {
1873  if (isTrueColor) {
1874  if (savedPixmap) {
1875  pixmaps[0]->Copy(savedPixmap, savedPixmap->DrawPort(), savedPixmap->ViewPort().Point());
1876  delete savedPixmap;
1877  savedPixmap = NULL;
1878  }
1879  }
1880  else {
1881  if (savedBitmap) {
1882  DrawBitmap(savedBitmap->X0(), savedBitmap->Y0(), *savedBitmap);
1883  delete savedBitmap;
1884  savedBitmap = NULL;
1885  }
1886  }
1887 }
1888 
1889 eOsdError cOsd::SetPalette(const cPalette &Palette, int Area)
1890 {
1891  if (isTrueColor)
1892  return oeOk;
1893  if (Area < numBitmaps) {
1894  bitmaps[Area]->Take(Palette);
1895  return oeOk;
1896  }
1897  return oeUnknown;
1898 }
1899 
1900 void cOsd::DrawImage(const cPoint &Point, const cImage &Image)
1901 {
1902  if (isTrueColor)
1903  pixmaps[0]->DrawImage(Point, Image);
1904 }
1905 
1906 void cOsd::DrawImage(const cPoint &Point, int ImageHandle)
1907 {
1908  if (isTrueColor)
1909  pixmaps[0]->DrawImage(Point, ImageHandle);
1910 }
1911 
1912 void cOsd::DrawPixel(int x, int y, tColor Color)
1913 {
1914  if (isTrueColor)
1915  pixmaps[0]->DrawPixel(cPoint(x, y), Color);
1916  else {
1917  for (int i = 0; i < numBitmaps; i++)
1918  bitmaps[i]->DrawPixel(x, y, Color);
1919  }
1920 }
1921 
1922 void cOsd::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay)
1923 {
1924  if (isTrueColor)
1925  pixmaps[0]->DrawBitmap(cPoint(x, y), Bitmap, ColorFg, ColorBg, Overlay);
1926  else {
1927  for (int i = 0; i < numBitmaps; i++)
1928  bitmaps[i]->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg, ReplacePalette, Overlay);
1929  }
1930 }
1931 
1932 void cOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
1933 {
1934  const cBitmap *b = &Bitmap;
1935  if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0))
1936  b = b->Scaled(FactorX, FactorY, AntiAlias);
1937  DrawBitmap(x, y, *b);
1938  if (b != &Bitmap)
1939  delete b;
1940 }
1941 
1942 void cOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment)
1943 {
1944  if (isTrueColor)
1945  pixmaps[0]->DrawText(cPoint(x, y), s, ColorFg, ColorBg, Font, Width, Height, Alignment);
1946  else {
1947  for (int i = 0; i < numBitmaps; i++)
1948  bitmaps[i]->DrawText(x, y, s, ColorFg, ColorBg, Font, Width, Height, Alignment);
1949  }
1950 }
1951 
1952 void cOsd::DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
1953 {
1954  if (isTrueColor)
1955  pixmaps[0]->DrawRectangle(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color);
1956  else {
1957  for (int i = 0; i < numBitmaps; i++)
1958  bitmaps[i]->DrawRectangle(x1, y1, x2, y2, Color);
1959  }
1960 }
1961 
1962 void cOsd::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
1963 {
1964  if (isTrueColor)
1965  pixmaps[0]->DrawEllipse(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Quadrants);
1966  else {
1967  for (int i = 0; i < numBitmaps; i++)
1968  bitmaps[i]->DrawEllipse(x1, y1, x2, y2, Color, Quadrants);
1969  }
1970 }
1971 
1972 void cOsd::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type)
1973 {
1974  if (isTrueColor)
1975  pixmaps[0]->DrawSlope(cRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1), Color, Type);
1976  else {
1977  for (int i = 0; i < numBitmaps; i++)
1978  bitmaps[i]->DrawSlope(x1, y1, x2, y2, Color, Type);
1979  }
1980 }
1981 
1982 void cOsd::Flush(void)
1983 {
1984 }
1985 
1986 // --- cOsdProvider ----------------------------------------------------------
1987 
1989 int cOsdProvider::oldWidth = 0;
1990 int cOsdProvider::oldHeight = 0;
1991 double cOsdProvider::oldAspect = 1.0;
1993 int cOsdProvider::osdState = 0;
1994 
1996 {
1997  delete osdProvider;
1998  osdProvider = this;
1999 }
2000 
2002 {
2003  osdProvider = NULL;
2004 }
2005 
2006 cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level)
2007 {
2008  cMutexLock MutexLock(&cOsd::mutex);
2009  if (Level == OSD_LEVEL_DEFAULT && cOsd::IsOpen())
2010  esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
2011  else if (osdProvider) {
2012  cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL;
2013  cOsd *Osd = osdProvider->CreateOsd(Left, Top, Level);
2014  if (Osd == cOsd::Osds[0]) {
2015  if (ActiveOsd)
2016  ActiveOsd->SetActive(false);
2017  Osd->SetActive(true);
2018  }
2019  return Osd;
2020  }
2021  else
2022  esyslog("ERROR: no OSD provider available - using dummy OSD!");
2023  return new cOsd(Left, Top, 999); // create a dummy cOsd, so that access won't result in a segfault
2024 }
2025 
2027 {
2028  int Width;
2029  int Height;
2030  double Aspect;
2031  cMutexLock MutexLock(&cOsd::mutex);
2032  cDevice::PrimaryDevice()->GetOsdSize(Width, Height, Aspect);
2033  if (Width != oldWidth || Height != oldHeight || !DoubleEqual(Aspect, oldAspect) || Force) {
2034  Setup.OSDLeft = int(round(Width * Setup.OSDLeftP));
2035  Setup.OSDTop = int(round(Height * Setup.OSDTopP));
2036  Setup.OSDWidth = int(round(Width * Setup.OSDWidthP)) & ~0x07; // OSD width must be a multiple of 8
2037  Setup.OSDHeight = int(round(Height * Setup.OSDHeightP));
2038  Setup.OSDAspect = Aspect;
2039  Setup.FontOsdSize = int(round(Height * Setup.FontOsdSizeP));
2040  Setup.FontFixSize = int(round(Height * Setup.FontFixSizeP));
2041  Setup.FontSmlSize = int(round(Height * Setup.FontSmlSizeP));
2045  oldWidth = Width;
2046  oldHeight = Height;
2047  oldAspect = Aspect;
2048  dsyslog("OSD size changed to %dx%d @ %g", Width, Height, Aspect);
2049  osdState++;
2050  }
2051 }
2052 
2054 {
2055  cMutexLock MutexLock(&cOsd::mutex);
2056  bool Result = osdState != State;
2057  State = osdState;
2058  return Result;
2059 }
2060 
2062 {
2063  if (osdProvider) {
2064  return osdProvider->ProvidesTrueColor();
2065  }
2066  else
2067  esyslog("ERROR: no OSD provider available in call to SupportsTrueColor()");
2068  return false;
2069 }
2070 
2072 {
2073  LOCK_PIXMAPS;
2074  for (int i = 1; i < MAXOSDIMAGES; i++) {
2075  if (!images[i]) {
2076  images[i] = new cImage(Image);
2077  return i;
2078  }
2079  }
2080  return 0;
2081 }
2082 
2083 void cOsdProvider::DropImageData(int ImageHandle)
2084 {
2085  LOCK_PIXMAPS;
2086  if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES) {
2087  delete images[ImageHandle];
2088  images[ImageHandle] = NULL;
2089  }
2090 }
2091 
2092 const cImage *cOsdProvider::GetImageData(int ImageHandle)
2093 {
2094  LOCK_PIXMAPS;
2095  if (0 < ImageHandle && ImageHandle < MAXOSDIMAGES)
2096  return images[ImageHandle];
2097  return NULL;
2098 }
2099 
2101 {
2102  if (osdProvider)
2103  return osdProvider->StoreImageData(Image);
2104  return 0;
2105 }
2106 
2107 void cOsdProvider::DropImage(int ImageHandle)
2108 {
2109  if (osdProvider)
2110  osdProvider->DropImageData(ImageHandle);
2111 }
2112 
2114 {
2115  delete osdProvider;
2116  osdProvider = NULL;
2117 }
2118 
2119 // --- cTextScroller ---------------------------------------------------------
2120 
2122 {
2123  osd = NULL;
2124  left = top = width = height = 0;
2125  font = NULL;
2126  colorFg = 0;
2127  colorBg = 0;
2128  offset = 0;
2129  shown = 0;
2130 }
2131 
2132 cTextScroller::cTextScroller(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2133 {
2134  Set(Osd, Left, Top, Width, Height, Text, Font, ColorFg, ColorBg);
2135 }
2136 
2137 void cTextScroller::Set(cOsd *Osd, int Left, int Top, int Width, int Height, const char *Text, const cFont *Font, tColor ColorFg, tColor ColorBg)
2138 {
2139  osd = Osd;
2140  left = Left;
2141  top = Top;
2142  width = Width;
2143  height = Height;
2144  font = Font;
2145  colorFg = ColorFg;
2146  colorBg = ColorBg;
2147  offset = 0;
2148  textWrapper.Set(Text, Font, Width);
2149  shown = min(Total(), height / font->Height());
2150  height = shown * font->Height(); // sets height to the actually used height, which may be less than Height
2151  DrawText();
2152 }
2153 
2155 {
2156  osd = NULL; // just makes sure it won't draw anything
2157 }
2158 
2160 {
2161  if (osd) {
2162  for (int i = 0; i < shown; i++)
2163  osd->DrawText(left, top + i * font->Height(), textWrapper.GetLine(offset + i), colorFg, colorBg, font, width);
2164  }
2165 }
2166 
2167 void cTextScroller::Scroll(bool Up, bool Page)
2168 {
2169  if (Up) {
2170  if (CanScrollUp()) {
2171  offset -= Page ? shown : 1;
2172  if (offset < 0)
2173  offset = 0;
2174  DrawText();
2175  }
2176  }
2177  else {
2178  if (CanScrollDown()) {
2179  offset += Page ? shown : 1;
2180  if (offset + shown > Total())
2181  offset = Total() - shown;
2182  DrawText();
2183  }
2184  }
2185 }
void ReduceBpp(const cPalette &Palette)
Reduces the color depth of the bitmap to that of the given Palette.
Definition: osd.c:765
int y2
Definition: osd.h:299
cOsdProvider(void)
Definition: osd.c:1995
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&#39;t g...
Definition: osd.c:1617
int y0
Definition: osd.h:172
double OSDHeightP
Definition: config.h:318
cPixmapMemory(void)
Definition: osd.c:1142
static int osdState
Definition: osd.h:956
static uint8_t AlphaLutAlpha[255][256]
Definition: osd.c:59
static int oldHeight
Definition: osd.h:953
void SetTop(int Top)
Definition: osd.h:386
Definition: osd.h:454
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:1274
void Fill(tIndex Index)
Fills the bitmap data with the given Index.
Definition: osd.c:515
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:533
int height
Definition: osd.h:173
#define dsyslog(a...)
Definition: tools.h:36
Definition: font.h:23
double OSDWidthP
Definition: config.h:318
static cImage * images[MAXOSDIMAGES]
Definition: osd.h:955
virtual void SetViewPort(const cRect &Rect)
Sets the pixmap&#39;s view port to the given Rect.
Definition: osd.c:1066
void Shift(int Dx, int Dy)
Definition: osd.h:324
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
static cOsdProvider * osdProvider
Definition: osd.h:951
int dirtyY1
Definition: osd.h:174
double FontFixSizeP
Definition: config.h:329
virtual void Scroll(const cPoint &Dest, const cRect &Source=cRect::Null)
Scrolls the data in the pixmap&#39;s draw port to the given Dest point.
Definition: osd.c:1583
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas)
Sets the sub-areas to the given areas.
Definition: osd.c:1823
virtual void SetActive(bool On)
Sets this OSD to be the active one.
Definition: osd.h:757
virtual ~cPalette()
Definition: osd.c:123
static const cImage * GetImageData(int ImageHandle)
Gets the image data referenced by ImageHandle.
Definition: osd.c:2092
static const char * OsdErrorTexts[]
Definition: osd.c:1628
#define MAXOSDWIDTH
Definition: config.h:55
double FontOsdSizeP
Definition: config.h:327
static int osdLeft
Definition: osd.h:723
bool SetXpm(const char *const Xpm[], bool IgnoreNone=false)
Sets this bitmap to the given XPM data.
Definition: osd.c:428
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:1932
cTextScroller(void)
Definition: osd.c:2121
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:1260
int x1
Definition: osd.h:299
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:1687
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:1556
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
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:1922
int Alpha(void) const
Definition: osd.h:533
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&#39;s draw port, which is relative to the view port.
Definition: osd.h:539
Definition: osd.h:419
int Index(tColor Color)
Returns the index of the given Color (the first color has index 0).
Definition: osd.c:144
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:1962
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:2137
cPixmap(void)
Definition: osd.c:960
int Width(void) const
Definition: osd.h:367
int dirtyX1
Definition: osd.h:174
tIndex tIndexes[MAXNUMCOLORS]
Definition: osd.h:96
int X(void) const
Definition: osd.h:318
#define esyslog(a...)
Definition: tools.h:34
#define MAXOSDIMAGES
Definition: osd.h:946
bool IsEmpty(void) const
Returns true if this rectangle is empty.
Definition: osd.h:415
int FontFixSize
Definition: config.h:332
int bpp
Definition: osd.h:300
void MarkViewPortDirty(const cRect &Rect)
Marks the given rectangle of the view port of this pixmap as dirty.
Definition: osd.c:985
char FontSml[MAXFONTNAME]
Definition: config.h:325
Definition: osd.h:306
T max(T a, T b)
Definition: tools.h:55
virtual void SetDrawPortPoint(const cPoint &Point, bool Dirty=true)
Sets the pixmap&#39;s draw port to the given Point.
Definition: osd.c:1083
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
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:1952
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:319
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:442
virtual int StoreImageData(const cImage &Image)
Copies the given Image and returns a handle for later reference.
Definition: osd.c:2071
virtual eOsdError SetPalette(const cPalette &Palette, int Area)
Sets the Palette for the given Area (the first area is numbered 0).
Definition: osd.c:1889
static double oldAspect
Definition: osd.h:954
T min(T a, T b)
Definition: tools.h:54
virtual void Fill(tColor Color)
Fills the pixmap&#39;s draw port with the given Color.
Definition: osd.c:1168
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition: osd.c:2053
virtual void SetAlpha(int Alpha)
Sets the alpha value of this pixmap to the given value.
Definition: osd.c:1044
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
int Bpp(void) const
Definition: osd.h:111
char * Read(FILE *f)
Definition: tools.c:1398
virtual void Flush(void)
Actually commits all data to the OSD hardware.
Definition: osd.c:1982
#define LOCK_PIXMAPS
Definition: osd.h:677
#define MALLOC(type, size)
Definition: tools.h:46
static cMutex mutex
Definition: osd.h:458
Definition: osd.h:169
void Scroll(bool Up, bool Page)
Definition: osd.c:2167
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:525
cPixmap * AddPixmap(cPixmap *Pixmap)
Adds the given Pixmap to the list of currently active pixmaps in this OSD.
Definition: osd.c:1737
const cRect & ViewPort(void) const
Returns the pixmap&#39;s view port, which is relative to the OSD&#39;s origin.
Definition: osd.h:535
void SetSize(int Width, int Height)
Sets the size of this bitmap to the given values.
Definition: osd.c:294
void SetX(int X)
Definition: osd.h:320
Definition: osd.h:161
#define MINOSDHEIGHT
Definition: config.h:56
void Combine(const cRect &Rect)
Combines this rectangle with the given Rect.
Definition: osd.c:932
cRect Shifted(int Dx, int Dy) const
Definition: osd.h:391
tColor color[MAXNUMCOLORS]
Definition: osd.h:90
void SetPoint(int X, int Y)
Definition: osd.h:377
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:725
bool LoadXpm(const char *FileName)
Calls SetXpm() with the data from the file FileName.
Definition: osd.c:362
const cSize & Size(void) const
Definition: osd.h:374
Definition: font.h:22
T constrain(T v, T l, T h)
Definition: tools.h:60
#define MINOSDWIDTH
Definition: config.h:54
bool Tile(void) const
Definition: osd.h:534
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:1720
double antiAliasGranularity
Definition: osd.h:94
int numColors
Definition: osd.h:92
static cVector< cOsd * > Osds
Definition: osd.h:724
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:1350
#define IS_OPAQUE(c)
Definition: osd.h:27
#define MAXOSDHEIGHT
Definition: config.h:57
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:1801
double OSDLeftP
Definition: config.h:318
Definition: osd.h:352
virtual ~cOsdProvider()
Definition: osd.c:2001
const tColor * Data(void) const
Definition: osd.h:437
char FontOsd[MAXFONTNAME]
Definition: config.h:324
void SetBottom(int Bottom)
Definition: osd.h:388
virtual ~cOsd()
Shuts down the OSD.
Definition: osd.c:1668
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
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
void SetLeft(int Left)
Definition: osd.h:385
#define MAXOSDAREAS
Definition: osd.h:707
bool Contains(const cPoint &Point) const
Returns true if this rectangle contains Point.
Definition: osd.c:896
int x2
Definition: osd.h:299
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
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
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:2026
bool Contains(int x, int y) const
Returns true if this bitmap contains the point (x, y).
Definition: osd.c:317
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:920
int Left(void) const
Definition: osd.h:369
The cOsd class is the interface to the "On Screen Display".
Definition: osd.h:720
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:330
void SetClean(void)
Resets the "dirty" rectangles of this pixmap.
Definition: osd.c:1017
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:341
bool panning
Definition: osd.h:685
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image into this pixmap at the given Point.
Definition: osd.c:1228
static int osdTop
Definition: osd.h:723
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition: osd.h:795
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:1942
int OSDLeft
Definition: config.h:319
Definition: thread.h:63
void Clear(void)
Clears the image data by setting all pixels to be fully transparent.
Definition: osd.c:1129
static const cRect Null
Definition: osd.h:357
int Size(void) const
Definition: tools.h:551
int Right(void) const
Definition: osd.h:371
void DrawText(void)
Definition: osd.c:2159
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
virtual void SetTile(bool Tile)
Sets the tile property of this pixmap to the given value.
Definition: osd.c:1055
const cPoint & Point(void) const
Definition: osd.h:373
int x0
Definition: osd.h:172
void SetColor(int Index, tColor Color)
Sets the palette entry at Index to Color.
Definition: osd.c:172
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:890
virtual ~cImage()
Definition: osd.c:1124
virtual void DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty)
Draws the Dirty part of the given Pixmap into this pixmap.
Definition: osd.c:1177
int Y0(void) const
Definition: osd.h:187
void SetRight(int Right)
Definition: osd.h:387
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
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:1708
const tIndex * Data(int x, int y) const
Returns the address of the index byte at the given coordinates.
Definition: osd.c:760
const cSize & Size(void) const
Definition: osd.h:434
#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:1301
#define MAXNUMCOLORS
Definition: osd.h:24
friend class cOsd
Definition: osd.h:455
static bool SupportsTrueColor(void)
Returns true if the current OSD provider is able to handle a true color OSD.
Definition: osd.c:2061
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:1521
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type)
Draws a "slope" with the given Color into the given rectangle.
Definition: osd.c:1479
int Height(void) const
Definition: osd.h:368
void Shift(int Dx, int Dy)
Definition: osd.h:389
int y1
Definition: osd.h:299
char FontFix[MAXFONTNAME]
Definition: config.h:326
virtual void Clear(void)
Clears the pixmap&#39;s draw port by setting all pixels to be fully transparent.
Definition: osd.c:1160
Definition: osd.h:88
void Reset(void)
Definition: osd.c:2154
Definition: osd.h:298
#define OSD_LEVEL_DEFAULT
Definition: osd.h:21
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:137
virtual int Width(uint c) const =0
Returns the width of the given character in pixel.
eOsdError
Definition: osd.h:44
Definition: osd.h:159
double OSDAspect
Definition: config.h:320
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:1912
char * skipspace(const char *s)
Definition: tools.h:200
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Draws the given Image on this OSD at the given Point.
Definition: osd.c:1900
#define ALPHA_TRANSPARENT
Definition: osd.h:25
double FontSmlSizeP
Definition: config.h:328
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:723
virtual ~cPixmapMemory()
Definition: osd.c:1155
void MarkDrawPortDirty(const cRect &Rect)
Marks the given rectangle of the draw port of this pixmap as dirty.
Definition: osd.c:997
int FontOsdSize
Definition: config.h:330
int Y(void) const
Definition: osd.h:319
static int oldWidth
Definition: osd.h:952
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
tColor GetColor(int x, int y) const
Returns the color at the given coordinates.
Definition: osd.h:277
static int StoreImage(const cImage &Image)
Stores the given Image for later use with DrawImage() on an OSD or pixmap.
Definition: osd.c:2100
int Bottom(void) const
Definition: osd.h:372
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:1022
void Fill(tColor Color)
Fills the image data with the given Color.
Definition: osd.c:1134
cOsd(int Left, int Top, uint Level)
Initializes the OSD with the given coordinates.
Definition: osd.c:1647
virtual int Height(void) const =0
Returns the height of this font in pixel (all characters have the same height).
virtual void RestoreRegion(void)
Restores the region previously saved by a call to SaveRegion().
Definition: osd.c:1871
virtual void Clear(void)=0
Clears the pixmap&#39;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:1377
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
Allows the system to optimize utilization of the limited color palette entries when generating blende...
Definition: osd.c:1695
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:1972
bool DoubleEqual(double a, double b)
Definition: tools.h:87
static void Unlock(void)
Definition: osd.h:531
void SetBpp(int Bpp)
Sets the color depth of this palette to the given value.
Definition: osd.c:165
int OSDHeight
Definition: config.h:319
int FontSmlSize
Definition: config.h:331
int X0(void) const
Definition: osd.h:186
virtual void DropImageData(int ImageHandle)
Drops the image data referenced by ImageHandle.
Definition: osd.c:2083
virtual ~cBitmap()
Definition: osd.c:289
int OSDWidth
Definition: config.h:319
uint8_t tIndex
Definition: font.h:31
static void DropImage(int ImageHandle)
Drops the image referenced by the given ImageHandle.
Definition: osd.c:2107
int Layer(void) const
Definition: osd.h:532
cPoint Shifted(int Dx, int Dy) const
Definition: osd.h:326
cImage(void)
Definition: osd.c:1102
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:452
tColor * data
Definition: osd.h:684
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:1855
cPixmap * RenderPixmaps(void)
Renders the dirty part of all pixmaps into a resulting pixmap that shall be displayed on the OSD...
Definition: osd.c:1750
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:1703
cInitAlphaLut(void)
Definition: osd.c:63
bool Intersects(const cRect &Rect) const
Returns true if this rectangle intersects with Rect.
Definition: osd.c:912
Definition: font.h:37
int Top(void) const
Definition: osd.h:370
static void Shutdown(void)
Shuts down the OSD provider facility by deleting the current OSD provider.
Definition: osd.c:2113
static uint16_t AlphaLutFactors[255][256][2]
Definition: osd.c:58
int width
Definition: osd.h:173
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.
#define ALPHA_OPAQUE
Definition: osd.h:26
static int osdWidth
Definition: osd.h:723
uint32_t tColor
Definition: font.h:29
double OSDTopP
Definition: config.h:318
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:2006