1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Implemented support for TrueColor OSD

This commit is contained in:
Klaus Schmidinger 2011-02-20 15:12:56 +01:00
parent 343071cc6a
commit 6c7089afd2
11 changed files with 2135 additions and 85 deletions

View File

@ -1260,6 +1260,8 @@ Reinhard Nissl <rnissl@gmx.de>
for implementing cDeviceHook
for implementing cDevice::GetCurrentlyTunedTransponder()
for fixing DDS detection for HD resolution subtitles
for some valuable input during development of the TrueColor OSD, help with
debugging, and an implementation of the AlphaBlend() function.
Richard Robson <richard_robson@beeb.net>
for reporting freezing replay if a timer starts while in Transfer Mode from the

16
HISTORY
View File

@ -6481,7 +6481,7 @@ Video Disk Recorder Revision History
from Osama Alrawab). See INSTALL for information on how to turn this on.
- Added Arabian language texts (thanks to Osama Alrawab).
2010-12-29: Version 1.7.17
2011-02-20: Version 1.7.17
- Updated the Estonian OSD texts (thanks to Arthur Konovalov).
- Fixed following symbolic links in RemoveFileOrDir() (cont'd) (thanks to
@ -6519,3 +6519,17 @@ Video Disk Recorder Revision History
recording is started that has a frame rate other than the default.
- The include path to the freetype2 header files is now retrieved via a call to
'pkg-config --cflags freetype2' (suggested by Andreas Oberritter).
- The OSD now has full TrueColor support. There can be several "pixmaps" that can
be overlayed with alpha blending. All existing skins should work out of the box
with the TrueColor OSD - the only exception being cOsd::GetBitmap(). Since the
TrueColor OSD doesn't use bitmaps, this function will return a dummy bitmap, which
may not be what the plugin expects. As long as this bitmap is only used for setting
the palette, there is no problem. However, any other operations on this bitmap will
have no effect. See the description of the cPixmap functions in osd.h for details
about the new functionalities.
The "ST:TNG Panels" skin has been enhanced to automatically use the TrueColor OSD
if available.
The "osddemo" plugin has been extended to show some of the possibilities of the
TrueColor OSD if it is run on a system that actually provides TrueColor support.
Thanks to Reinhard Nissl for some valuable input, help with debugging, and an
implementation of the AlphaBlend() function.

View File

@ -21,3 +21,7 @@ VDR Plugin 'osddemo' Revision History
2008-04-13: Version 0.1.3
- Fixed setting the OSD level (thanks to Wolfgang Rohdewald).
2011-02-20: Version 0.2.0
- Added support for TrueColor OSD.

View File

@ -19,4 +19,11 @@ Demonstration of how a plugin can have its very own OSD setup.
It's a very primitive game that opens a small window in which the
user can draw lines with the Up, Down, Left and Right buttons.
The color buttons are used to switch color.
On a VDR system with TrueColor support it displays some of the
possibilities available with the TrueColor OSD. Once the "Animation"
pixmap is displayed, it can be moved around with the Up, Down, Left
and Right buttons. The Red button turns off the "Tiled Pixmaps"
display, and the Green button toggles the color display.
Press Ok to close the window.

View File

@ -3,12 +3,13 @@
*
* See the README file for copyright information and how to reach the author.
*
* $Id: osddemo.c 2.1 2008/04/13 12:59:57 kls Exp $
* $Id: osddemo.c 2.2 2011/02/20 15:06:18 kls Exp $
*/
#include <vdr/osd.h>
#include <vdr/plugin.h>
static const char *VERSION = "0.1.3";
static const char *VERSION = "0.2.0";
static const char *DESCRIPTION = "Demo of arbitrary OSD setup";
static const char *MAINMENUENTRY = "Osd Demo";
@ -22,7 +23,7 @@ private:
tColor color;
public:
cLineGame(void);
~cLineGame();
virtual ~cLineGame();
virtual void Show(void);
virtual eOSState ProcessKey(eKeys Key);
};
@ -73,6 +74,364 @@ eOSState cLineGame::ProcessKey(eKeys Key)
return state;
}
// --- cTrueColorDemo --------------------------------------------------------
class cTrueColorDemo : public cOsdObject, public cThread {
private:
cOsd *osd;
cPoint cursor;
cRect cursorLimits;
bool clockwise;
cPixmap *destroyablePixmap;
cPixmap *toggleablePixmap;
virtual void Action(void);
cPixmap *CreateTextPixmap(const char *s, int Line, int Layer, tColor ColorFg, tColor ColorBg, const cFont *Font = NULL);
public:
cTrueColorDemo(void);
virtual ~cTrueColorDemo();
virtual void Show(void);
virtual eOSState ProcessKey(eKeys Key);
};
cTrueColorDemo::cTrueColorDemo(void)
{
osd = NULL;
clockwise = true;
destroyablePixmap = NULL;
toggleablePixmap = NULL;
}
cTrueColorDemo::~cTrueColorDemo()
{
delete osd;
}
cPixmap *cTrueColorDemo::CreateTextPixmap(const char *s, int Line, int Layer, tColor ColorFg, tColor ColorBg, const cFont *Font)
{
if (!Font)
Font = cFont::GetFont(fontOsd);
const int h = Font->Height(s);
int w = Font->Width(s);
cPixmap *Pixmap = osd->CreatePixmap(Layer, cRect((osd->Width() - w) / 2, Line, w, h));
if (Pixmap) {
Pixmap->Clear();
Pixmap->SetAlpha(0);
Pixmap->DrawText(cPoint(0, 0), s, ColorFg, ColorBg, Font);
}
return Pixmap;
}
void cTrueColorDemo::Action(void)
{
cPixmap *FadeInPixmap = NULL;
cPixmap *FadeOutPixmap = NULL;
cPixmap *MovePixmap = NULL;
cPixmap *NextPixmap = NULL;
cPixmap *TilePixmap = NULL;
cPixmap *ScrollPixmap = NULL;
cPixmap *AnimPixmap = NULL;
int FrameTime = 40; // ms
int FadeTime = 1000; // ms
int MoveTime = 4000; // ms
int TileTime = 6000; // ms
int ScrollWaitTime = 1000; // ms
int ScrollLineTime = 200; // ms
int ScrollTotalTime = 8000; // ms
uint64_t Start = 0;
uint64_t ScrollStartTime = 0;
int ScrollLineNumber = 0;
cPoint MoveStart, MoveEnd;
cPoint TileStart, TileEnd;
cPoint ScrollStart, ScrollEnd;
int Line = osd->Height() / 20;
int StartLine = Line;
cPoint OldCursor;
int State = 0;
while (Running()) {
cPixmap::Lock();
bool Animated = false;
uint64_t Now = cTimeMs::Now();
if (FadeInPixmap) {
double t = min(double(Now - Start) / FadeTime, 1.0);
int Alpha = t * ALPHA_OPAQUE;
FadeInPixmap->SetAlpha(Alpha);
if (t >= 1)
FadeInPixmap = NULL;
Animated = true;
}
if (FadeOutPixmap) {
double t = min(double(Now - Start) / FadeTime, 1.0);
int Alpha = ALPHA_OPAQUE - t * ALPHA_OPAQUE;
FadeOutPixmap->SetAlpha(Alpha);
if (t >= 1)
FadeOutPixmap = NULL;
Animated = true;
}
if (MovePixmap) {
double t = min(double(Now - Start) / MoveTime, 1.0);
int x = MoveStart.X() + t * (MoveEnd.X() - MoveStart.X());
int y = MoveStart.Y() + t * (MoveEnd.Y() - MoveStart.Y());
cRect r = MovePixmap->ViewPort();
r.SetPoint(x, y);
MovePixmap->SetViewPort(r);
if (t >= 1)
MovePixmap = NULL;
Animated = true;
}
if (TilePixmap) {
double t = min(double(Now - Start) / TileTime, 1.0);
int x = TileStart.X() + t * (TileEnd.X() - TileStart.X());
int y = TileStart.Y() + t * (TileEnd.Y() - TileStart.Y());
TilePixmap->SetDrawPortPoint(cPoint(x, y));
if (t >= 1) {
destroyablePixmap = TilePixmap;
TilePixmap = NULL;
}
Animated = true;
}
if (ScrollPixmap) {
if (int(Now - Start) > ScrollWaitTime) {
if (ScrollStartTime) {
double t = min(double(Now - ScrollStartTime) / ScrollLineTime, 1.0);
int x = ScrollStart.X() + t * (ScrollEnd.X() - ScrollStart.X());
int y = ScrollStart.Y() + t * (ScrollEnd.Y() - ScrollStart.Y());
ScrollPixmap->SetDrawPortPoint(cPoint(x, y));
if (t >= 1) {
if (int(Now - Start) < ScrollTotalTime) {
cRect r = ScrollPixmap->DrawPort();
r.SetPoint(-r.X(), -r.Y());
ScrollPixmap->Pan(cPoint(0, 0), r);
const cFont *Font = cFont::GetFont(fontOsd);
cString s = cString::sprintf("Line %d", ++ScrollLineNumber);
ScrollPixmap->DrawRectangle(cRect(0, ScrollPixmap->ViewPort().Height(), ScrollPixmap->DrawPort().Width(), ScrollPixmap->DrawPort().Height()), clrTransparent);
ScrollPixmap->DrawText(cPoint(0, ScrollPixmap->ViewPort().Height()), s, clrYellow, clrTransparent, Font);
ScrollStartTime = Now;
}
else {
FadeOutPixmap = ScrollPixmap;
ScrollPixmap = NULL;
Start = cTimeMs::Now();
}
}
}
else
ScrollStartTime = Now;
}
Animated = true;
}
if (AnimPixmap) {
int d = AnimPixmap->ViewPort().Height();
if (clockwise)
d = -d;
cPoint p = AnimPixmap->DrawPort().Point().Shifted(0, d);
if (clockwise && p.Y() <= -AnimPixmap->DrawPort().Height())
p.SetY(0);
else if (!clockwise && p.Y() > 0)
p.SetY(-(AnimPixmap->DrawPort().Height() - AnimPixmap->ViewPort().Height()));
AnimPixmap->SetDrawPortPoint(p);
}
if (!Animated) {
switch (State) {
case 0: {
if (cFont *Font = cFont::CreateFont(DefaultFontOsd, osd->Height() / 10)) {
FadeInPixmap = CreateTextPixmap("VDR", Line, 1, clrYellow, clrTransparent, Font);
if (FadeInPixmap)
Line += FadeInPixmap->DrawPort().Height();
delete Font;
Start = cTimeMs::Now();
}
State++;
}
break;
case 1: {
FadeInPixmap = CreateTextPixmap("Video Disk Recorder", Line, 3, clrYellow, clrTransparent);
if (FadeInPixmap)
Line += FadeInPixmap->DrawPort().Height();
Start = cTimeMs::Now();
State++;
}
break;
case 2: {
FadeInPixmap = CreateTextPixmap("True Color OSD Demo", Line, 1, clrYellow, clrTransparent);
if (FadeInPixmap)
Line += FadeInPixmap->DrawPort().Height();
Start = cTimeMs::Now();
State++;
}
break;
case 3: {
if (cFont *Font = cFont::CreateFont(DefaultFontOsd, osd->Height() / 10)) {
NextPixmap = CreateTextPixmap("Millions of colors", Line, 1, clrYellow, clrTransparent, Font);
if (NextPixmap) {
FadeInPixmap = NextPixmap;
}
Start = cTimeMs::Now();
StartLine = Line;
Line += NextPixmap->DrawPort().Height();
}
State++;
}
break;
case 4: {
Line += osd->Height() / 10;
int w = osd->Width() / 2;
int h = osd->Height() - Line - osd->Height() / 10;
cImage Image(cSize(w, h));
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++)
Image.SetPixel(cPoint(x, y), HsvToColor(360 * double(x) / w, 1 - double(y) / h, 1) | 0xDF000000);
}
if (cPixmap *Pixmap = osd->CreatePixmap(2, cRect((osd->Width() - w) / 2, Line, w, h))) {
Pixmap->DrawImage(cPoint(0, 0), Image);
toggleablePixmap = Pixmap;
}
State++;
}
break;
case 5: {
if (NextPixmap) {
MovePixmap = NextPixmap;
MoveStart = MovePixmap->ViewPort().Point();
MoveEnd.Set(osd->Width() - MovePixmap->ViewPort().Width(), osd->Height() - MovePixmap->ViewPort().Height());
Start = cTimeMs::Now();
}
State++;
}
break;
case 6: {
TilePixmap = CreateTextPixmap("Tiled Pixmaps", StartLine, 1, clrRed, clrWhite);
if (TilePixmap) {
TilePixmap->SetViewPort(TilePixmap->ViewPort().Grown(TilePixmap->DrawPort().Width(), TilePixmap->DrawPort().Height()));
TilePixmap->SetAlpha(200);
TilePixmap->SetTile(true);
TileStart = TilePixmap->DrawPort().Point();
TileEnd = TileStart.Shifted(TilePixmap->ViewPort().Width(), TilePixmap->ViewPort().Height());
MovePixmap = TilePixmap;
MoveStart = MovePixmap->ViewPort().Point();
MoveEnd.Set(10, osd->Height() - MovePixmap->ViewPort().Height() - 10);
Start = cTimeMs::Now();
}
State++;
}
break;
case 7: {
const cFont *Font = cFont::GetFont(fontOsd);
const char *Text = "Scrolling Pixmaps";
int w = Font->Width(Text);
int h = Font->Height();
if (cPixmap *Pixmap = osd->CreatePixmap(2, cRect((osd->Width() - w) / 2, StartLine, w, 2 * h), cRect(0, 0, w, 3 * h))) {
Pixmap->Clear();
Pixmap->DrawText(cPoint(0, 0), Text, clrYellow, clrTransparent, Font);
cString s = cString::sprintf("Line %d", ++ScrollLineNumber);
Pixmap->DrawText(cPoint(0, Pixmap->ViewPort().Height()), s, clrYellow, clrTransparent, Font);
ScrollPixmap = Pixmap;
ScrollStart.Set(0, 0);
ScrollEnd.Set(0, -h);
Start = cTimeMs::Now();
}
State++;
}
break;
case 8: {
const cFont *Font = cFont::GetFont(fontSml);
const char *Text = "Animation";
const int Size = Font->Width(Text) + 10;
const int NumDots = 12;
const int AnimFrames = NumDots;
AnimPixmap = osd->CreatePixmap(3, cRect((osd->Width() - Size) / 2, StartLine, Size, Size), cRect(0, 0, Size, Size * AnimFrames));
if (AnimPixmap) {
AnimPixmap->SetAlpha(0);
AnimPixmap->Clear();
const int Diameter = Size / 5;
int xc = Size / 2 - Diameter / 2;
for (int Frame = 0; Frame < AnimFrames; Frame++) {
AnimPixmap->DrawEllipse(cRect(0, Frame * Size, Size, Size), 0xDDFFFFFF);
int yc = Frame * Size + Size / 2 - Diameter / 2;
int Color = 0xFF;
int Delta = Color / NumDots / 3;
for (int a = 0; a < NumDots; a++) {
double t = 2 * M_PI * (Frame + a) / NumDots;
int x = xc + ((Size - Diameter) / 2 - 5) * cos(t);
int y = yc + ((Size - Diameter) / 2 - 5) * sin(t);
AnimPixmap->DrawEllipse(cRect(x, y, Diameter, Diameter), ArgbToColor(0xFF, Color, Color, Color));
Color -= Delta;
}
AnimPixmap->DrawText(cPoint(0, Frame * Size), "Animation", clrBlack, clrTransparent, cFont::GetFont(fontSml), Size, Size, taCenter);
}
FadeInPixmap = AnimPixmap;
LOCK_THREAD;
OldCursor = cursor = AnimPixmap->ViewPort().Point();
cursorLimits.Set(0, 0, osd->Width(), osd->Height());
cursorLimits.SetRight(cursorLimits.Right() - Size);
cursorLimits.SetBottom(cursorLimits.Bottom() - Size);
cursorLimits.Grow(-10, -10);
Start = cTimeMs::Now();
}
State++;
}
break;
case 9: {
LOCK_THREAD;
if (cursor != OldCursor) {
MovePixmap = AnimPixmap;
MoveStart = MovePixmap->ViewPort().Point();
MoveEnd = OldCursor = cursor;
MoveTime = 500;
Start = cTimeMs::Now();
}
}
break;
}
}
osd->Flush();
cPixmap::Unlock();
int Delta = cTimeMs::Now() - Now;
if (Delta < FrameTime)
cCondWait::SleepMs(FrameTime - Delta);
}
}
void cTrueColorDemo::Show(void)
{
osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop(), 50);
if (osd) {
tArea Area = { 0, 0, cOsd::OsdWidth() - 1, cOsd::OsdHeight() - 1, 32 };
if (osd->SetAreas(&Area, 1) == oeOk) {
osd->DrawRectangle(0, 0, osd->Width() -1 , osd->Height() - 1, clrGray50);
osd->Flush();
Start();
}
}
}
eOSState cTrueColorDemo::ProcessKey(eKeys Key)
{
eOSState state = cOsdObject::ProcessKey(Key);
if (state == osUnknown) {
LOCK_PIXMAPS;
LOCK_THREAD;
const int d = 80;
switch (Key & ~k_Repeat) {
case kUp: cursor.SetY(max(cursorLimits.Top(), cursor.Y() - d)); clockwise = false; break;
case kDown: cursor.SetY(min(cursorLimits.Bottom(), cursor.Y() + d)); clockwise = true; break;
case kLeft: cursor.SetX(max(cursorLimits.Left(), cursor.X() - d)); clockwise = false; break;
case kRight: cursor.SetX(min(cursorLimits.Right(), cursor.X() + d)); clockwise = true; break;
case kRed: if (destroyablePixmap) {
osd->DestroyPixmap(destroyablePixmap);
destroyablePixmap = NULL;
}
break;
case kGreen: if (toggleablePixmap)
toggleablePixmap->SetLayer(-toggleablePixmap->Layer());
break;
case kOk: return osEnd;
default: return state;
}
state = osContinue;
}
return state;
}
// --- cPluginOsddemo --------------------------------------------------------
class cPluginOsddemo : public cPlugin {
@ -131,6 +490,8 @@ void cPluginOsddemo::Housekeeping(void)
cOsdObject *cPluginOsddemo::MainMenuAction(void)
{
// Perform the action when selected from the main VDR menu.
if (cOsdProvider::SupportsTrueColor())
return new cTrueColorDemo;
return new cLineGame;
}

View File

@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
* $Id: skincurses.c 2.4 2010/02/28 12:50:13 kls Exp $
* $Id: skincurses.c 2.5 2011/01/04 08:52:03 kls Exp $
*/
#include <ncurses.h>
@ -23,6 +23,7 @@ public:
virtual int Width(const char *s) const { return s ? Utf8StrLen(s) : 0; }
virtual int Height(void) const { return 1; }
virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
};
static const cCursesFont Font;

60
font.c
View File

@ -6,7 +6,7 @@
*
* BiDi support by Osama Alrawab <alrawab@hotmail.com> @2008 Tripoli-Libya.
*
* $Id: font.c 2.5 2010/09/19 11:49:19 kls Exp $
* $Id: font.c 2.6 2011/02/20 14:15:38 kls Exp $
*/
#include "font.h"
@ -118,6 +118,7 @@ public:
virtual int Width(const char *s) const;
virtual int Height(void) const { return height; }
virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const;
virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const;
};
cFreetypeFont::cFreetypeFont(const char *Name, int CharHeight, int CharWidth)
@ -329,6 +330,62 @@ void cFreetypeFont::DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColo
}
}
void cFreetypeFont::DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const
{
if (s && height) { // checking height to make sure we actually have a valid font
#ifdef BIDI
cString bs = Bidi(s);
s = bs;
#endif
bool AntiAliased = Setup.AntiAlias;
bool TransparentBackground = ColorBg == clrTransparent;
uint prevSym = 0;
while (*s) {
int sl = Utf8CharLen(s);
uint sym = Utf8CharGet(s, sl);
s += sl;
cGlyph *g = Glyph(sym, AntiAliased);
if (!g)
continue;
int kerning = Kerning(g, prevSym);
prevSym = sym;
uchar *buffer = g->Bitmap();
int symWidth = g->Width();
if (Width && x + symWidth + g->Left() + kerning - 1 > Width)
break; // we don't draw partial characters
if (x + symWidth + g->Left() + kerning > 0) {
for (int row = 0; row < g->Rows(); row++) {
for (int pitch = 0; pitch < g->Pitch(); pitch++) {
uchar bt = *(buffer + (row * g->Pitch() + pitch));
if (AntiAliased) {
if (bt > 0x00) {
tColor bg;
if (bt == 0xFF || TransparentBackground)
bg = ColorFg;
else {
bg = AlphaBlend(ColorFg, ColorBg, bt);
bt = ALPHA_OPAQUE;
}
Pixmap->DrawPixel(cPoint(x + pitch + g->Left() + kerning, y + row + (height - Bottom() - g->Top())), bg, bt);
}
}
else { //monochrome rendering
for (int col = 0; col < 8 && col + pitch * 8 <= symWidth; col++) {
if (bt & 0x80)
Pixmap->DrawPixel(cPoint(x + col + pitch * 8 + g->Left() + kerning, y + row + (height - Bottom() - g->Top())), ColorFg);
bt <<= 1;
}
}
}
}
}
x += g->AdvanceX() + kerning;
if (x > Pixmap->DrawPort().Width() - 1)
break;
}
}
}
// --- cDummyFont ------------------------------------------------------------
// A dummy font, in case there are no fonts installed:
@ -339,6 +396,7 @@ public:
virtual int Width(const char *s) const { return 50; }
virtual int Height(void) const { return 20; }
virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}
virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {};
};
// --- cFont -----------------------------------------------------------------

8
font.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: font.h 2.4 2010/09/19 11:48:37 kls Exp $
* $Id: font.h 2.5 2011/01/14 16:22:03 kls Exp $
*/
#ifndef __FONT_H
@ -26,6 +26,7 @@ enum eDvbFont {
};
class cBitmap;
class cPixmap;
typedef uint32_t tColor; // see also osd.h
typedef uint8_t tIndex;
@ -54,6 +55,9 @@ public:
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.
///< The text will not exceed the given Width (if > 0), and will end with a complete character.
virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}; // not "pure", so that existing implementations still compile
///< Draws the given text into the Pixmap at position (x, y) with the given colors.
///< The text will not exceed the given Width (if > 0), and will end with a complete character.
static void SetFont(eDvbFont Font, const char *Name, int CharHeight);
///< Sets the given Font to use the font data according to Name (see CreateFont())
///< and make its characters CharHeight pixels high.
@ -81,7 +85,7 @@ public:
///< of the actual font file.
///< Returns true if any font names were found.
static cString GetFontFileName(const char *FontName);
///< Retruns the actual font file name for the given FontName.
///< Returns the actual font file name for the given FontName.
#ifdef BIDI
static cString Bidi(const char *Ltr);
///< Converts any "right-to-left" parts in the "left-to-right" string Ltr

1098
osd.c

File diff suppressed because it is too large Load Diff

534
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.h 2.5 2010/01/17 13:23:50 kls Exp $
* $Id: osd.h 2.6 2011/02/20 14:52:17 kls Exp $
*/
#ifndef __OSD_H
@ -15,12 +15,15 @@
#include <stdint.h>
#include "config.h"
#include "font.h"
#include "thread.h"
#include "tools.h"
#define OSD_LEVEL_DEFAULT 0
#define OSD_LEVEL_SUBTITLES 10
#define MAXNUMCOLORS 256
#define ALPHA_TRANSPARENT 0x00
#define ALPHA_OPAQUE 0xFF
enum {
//AARRGGBB
@ -50,6 +53,28 @@ enum eOsdError { oeOk, // see also OsdErrorTexts in osd.c
typedef uint32_t tColor; // see also font.h
typedef uint8_t tIndex;
inline tColor ArgbToColor(uint8_t A, uint8_t R, uint8_t G, uint8_t B)
{
return (tColor(A) << 24) | (tColor(R) << 16) | (tColor(G) << 8) | B;
}
inline tColor RgbToColor(uint8_t R, uint8_t G, uint8_t B)
{
return (tColor(R) << 16) | (tColor(G) << 8) | B;
}
inline tColor RgbToColor(double R, double G, double B)
{
return RgbToColor(uint8_t(0xFF * R), uint8_t(0xFF * G), uint8_t(0xFF * B));
}
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. The alpha value of the result is 0x00, so
///< the caller may need to set it accordingly.
tColor AlphaBlend(tColor ColorFg, tColor ColorBg, tColor AlphaLayer = ALPHA_OPAQUE);
class cPalette {
private:
tColor color[MAXNUMCOLORS];
@ -257,16 +282,424 @@ struct tArea {
bool Intersects(const tArea &Area) const { return !(x2 < Area.x1 || x1 > Area.x2 || y2 < Area.y1 || y1 > Area.y2); }
};
class cPoint {
private:
int x;
int y;
public:
cPoint(void) { x = y = 0; }
cPoint(int X, int Y) { x = X; y = Y; }
cPoint(const cPoint &Point) { x = Point.X(); y = Point.Y(); }
bool operator==(const cPoint &Point) const { return x == Point.X() && y == Point.Y(); }
bool operator!=(const cPoint &Point) const { return !(*this == Point); }
cPoint operator-(void) const { return cPoint(-x, -y); }
cPoint operator-(const cPoint &Point) const { return cPoint(x - Point.X(), y - Point.Y()); }
int X(void) const { return x; }
int Y(void) const { return y; }
void SetX(int X) { x = X; }
void SetY(int Y) { y = Y; }
void Set(int X, int Y) { x = X; y = Y; }
void Set(const cPoint &Point) { x = Point.X(); y = Point.Y(); }
void Shift(int Dx, int Dy) { x += Dx; y += Dy; }
void Shift(const cPoint &Dp) { x += Dp.X(); y += Dp.Y(); }
cPoint Shifted(int Dx, int Dy) const { cPoint p(*this); p.Shift(Dx, Dy); return p; }
cPoint Shifted(const cPoint &Dp) const { cPoint p(*this); p.Shift(Dp); return p; }
};
class cSize {
private:
int width;
int height;
public:
cSize(void) { width = height = 0; }
cSize(int Width, int Height) { width = Width; height = Height; }
cSize(const cSize &Size) { width = Size.Width(); height = Size.Height(); }
bool operator==(const cSize &Size) const { return width == Size.Width() && height == Size.Height(); }
bool operator!=(const cSize &Size) const { return !(*this == Size); }
bool operator<(const cSize &Size) const { return width < Size.Width() && height < Size.Height(); }
int Width(void) const { return width; }
int Height(void) const { return height; }
void SetWidth(int Width) { width = Width; }
void SetHeight(int Height) { height = Height; }
void Set(int Width, int Height) { width = Width; height = Height; }
void Set(const cSize &Size) { width = Size.Width(); height = Size.Height(); }
bool Contains(const cPoint &Point) const { return 0 <= Point.X() && 0 <= Point.Y() && Point.X() < width && Point.Y() < height; }
void Grow(int Dw, int Dh) { width += 2 * Dw; height += 2 * Dh; }
cSize Grown(int Dw, int Dh) const { cSize s(*this); s.Grow(Dw, Dh); return s; }
};
class cRect {
private:
cPoint point;
cSize size;
public:
static const cRect Null;
cRect(void): point(0, 0), size(0, 0) {}
cRect(int X, int Y, int Width, int Height): point(X, Y), size(Width, Height) {}
cRect(const cPoint &Point, const cSize &Size): point(Point), size(Size) {}
cRect(const cSize &Size): point(0, 0), size(Size) {}
cRect(const cRect &Rect): point(Rect.Point()), size(Rect.Size()) {}
bool operator==(const cRect &Rect) const { return point == Rect.Point() && size == Rect.Size(); }
bool operator!=(const cRect &Rect) const { return !(*this == Rect); }
int X(void) const { return point.X(); }
int Y(void) const { return point.Y(); }
int Width(void) const { return size.Width(); }
int Height(void) const { return size.Height(); }
int Left(void) const { return X(); }
int Top(void) const { return Y(); }
int Right(void) const { return X() + Width() - 1; }
int Bottom(void) const { return Y() + Height() - 1; }
const cPoint &Point(void) const { return point; }
const cSize &Size(void) const { return size; }
void Set(int X, int Y, int Width, int Height) { point.Set(X, Y); size.Set(Width, Height); }
void Set(cPoint Point, cSize Size) { point.Set(Point); size.Set(Size); }
void SetPoint(int X, int Y) { point.Set(X, Y); }
void SetPoint(const cPoint &Point) { point.Set(Point); }
void SetSize(int Width, int Height) { size.Set(Width, Height); }
void SetSize(const cSize &Size) { size.Set(Size); }
void SetX(int X) { point.SetX(X); }
void SetY(int Y) { point.SetY(Y); }
void SetWidth(int Width) { size.SetWidth(Width); }
void SetHeight(int Height) { size.SetHeight(Height); }
void SetLeft(int Left) { SetWidth(Width() + X() - Left); SetX(Left); }
void SetTop(int Top) { SetHeight(Height() + Y() - Top); SetY(Top); }
void SetRight(int Right) { SetWidth(Right - X() + 1); }
void SetBottom(int Bottom) { SetHeight(Bottom - Y() + 1); }
void Shift(int Dx, int Dy) { point.Shift(Dx, Dy); }
void Shift(const cPoint &Dp) { point.Shift(Dp); }
cRect Shifted(int Dx, int Dy) const { cRect r(*this); r.Shift(Dx, Dy); return r; }
cRect Shifted(const cPoint &Dp) const { cRect r(*this); r.Shift(Dp); return r; }
void Grow(int Dx, int Dy);
///< Grows the rectangle by the given number of pixels in either direction.
///< A negative value will shrink the rectangle.
cRect Grown(int Dw, int Dh) const { cRect r(*this); r.Grow(Dw, Dh); return r; }
bool Contains(const cPoint &Point) const;
///< Returns true if this rectangle contains Point.
bool Contains(const cRect &Rect) const;
///< Returns true if this rectangle completely contains Rect.
bool Intersects(const cRect &Rect) const;
///< Returns true if this rectangle intersects with Rect.
cRect Intersected(const cRect &Rect) const;
///< Returns the intersection of this rectangle and the given Rect.
void Combine(const cRect &Rect);
///< Combines this rectangle with the given Rect.
cRect Combined(const cRect &Rect) const { cRect r(*this); r.Combine(Rect); return r; }
///< Returns the surrounding rectangle that contains this rectangle and the
///< given Rect.
void Combine(const cPoint &Point);
///< Combines this rectangle with the given Point.
cRect Combined(const cPoint &Point) const { cRect r(*this); r.Combine(Point); return r; }
///< Returns the surrounding rectangle that contains this rectangle and the
///< given Point.
bool IsEmpty(void) const { return Width() <= 0 || Height() <= 0; }
///< Returns true if this rectangle is empty.
};
class cImage {
private:
cSize size;
tColor *data;
public:
cImage(void);
cImage(const cImage &Image);
cImage(const cSize &Size, const tColor *Data = NULL);
///< Creates an image with the given Size and allocates the necessary memory
///< to copy the pixels pointed to by Data, which is a sequence of
///< (Size.Width() * Size.Height()) tColor values.
///< If Data is NULL, the allocated memory is not initialized.
///< The alpha value of the Image's pixels is taken into account, so it has to be
///< greater than 0 for the image to be visible.
virtual ~cImage();
const cSize &Size(void) const { return size; }
int Width(void) const { return size.Width(); }
int Height(void) const { return size.Height(); }
const tColor *Data(void) const { return data; }
tColor GetPixel(const cPoint &Point) const { return data[size.Width() * Point.Y() + Point.X()]; }
///< Returns the pixel value at the given Point.
///< For performance reasons there is no range check here, so the caller
///< must make sure that the Point is within the images size.
void SetPixel(const cPoint &Point, tColor Color) { data[size.Width() * Point.Y() + Point.X()] = Color; }
///< Sets the pixel at the given Point to Color.
///< For performance reasons there is no range check here, so the caller
///< must make sure that the Point is within the images size.
void Clear(void);
///< Clears the image data by setting all pixels to be fully transparent.
void Fill(tColor Color);
///< Fills the image data with the given Color.
};
#define MAXPIXMAPLAYERS 8
class cPixmap {
friend class cOsd;
friend class cPixmapMutexLock;
private:
static cMutex mutex;
int layer;
int alpha;
bool tile;
cRect viewPort;
cRect drawPort;
cRect dirtyViewPort;
cRect dirtyDrawPort;
protected:
virtual ~cPixmap() {}
void MarkViewPortDirty(const cRect &Rect);
///< Marks the given rectangle of the view port of this pixmap as dirty.
///< Rect is combined with the existing dirtyViewPort rectangle.
///< The coordinates of Rect are given in absolute OSD values.
void MarkViewPortDirty(const cPoint &Point);
///< Marks the given point of the view port of this pixmap as dirty.
///< Point is combined with the existing dirtyViewPort rectangle.
///< The coordinates of Point are given in absolute OSD values.
void MarkDrawPortDirty(const cRect &Rect);
///< Marks the given rectangle of the draw port of this pixmap as dirty.
///< Rect is combined with the existing dirtyDrawPort rectangle.
///< The coordinates of Rect are relative to the pixmap's draw port.
///< If Rect extends into the currently visible view port of this pixmap,
///< MarkViewPortDirty() is called with the appropriate value.
void MarkDrawPortDirty(const cPoint &Point);
///< Marks the given point of the draw port of this pixmap as dirty.
///< Point is combined with the existing dirtyDrawPort rectangle.
///< The coordinates of Point are relative to the pixmap's draw port.
///< If Point is within the currently visible view port of this pixmap,
///< MarkViewPortDirty() is called with the appropriate value.
virtual void DrawPixmap(const cPixmap *Pixmap, const cRect &Dirty, bool Opaque);
///< Draws the Dirty part of the given Pixmap into this pixmap. If Opaque
///< is true, the Pixmap is copied, otherwise it is rendered into this
///< pixmap. This function is used only to implement the tile handling
///< in the final rendering to the OSD.
public:
cPixmap(void);
cPixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort = cRect::Null);
///< Creates a pixmap in the given Layer. When rendering the final OSD, pixmaps
///< are handled in ascending order of their individual layer. This is
///< important if pixmaps overlap each other. The one with the highest layer is
///< rendered last. The actual value of Layer doesn't matter, it is only used
///< for defining the rendering sequence. If Layer is less than zero, this
///< pixmap will not be rendered into the final OSD (it can be activated by a
///< later call to SetLayer()). The value 0 is reserved for the background
///< pixmap and shall not be used otherwise. If there are several pixmaps with
///< the same value of Layer, their rendering sequence within that layer is
///< undefined.
///< I order to allow devices that can handle only a limited number of layers,
///< the Layer parameters must be less than 8 (MAXPIXMAPLAYERS).
///< ViewPort defines the rectangle in which this pixmap will be rendered on
///< the OSD. If no DrawPort ist given, it defaults to the same size as the
///< ViewPort, with its upper left corner set to (0, 0).
///< All drawing operations will be executed relative to the origin of the
///< DrawPort rectangle, and will be clipped to the size of this rectangle.
///< The DrawPort may have a different size than the ViewPort. If it is smaller
///< than the ViewPort, the rest of the ViewPort is treated as fully transparent
///< (unless this is a tiled pixmap, in which case the DrawPort is repeated
///< horizontally and vertically to fill the entire ViewPort). If the DrawPort
///< is larger than the ViewPort, only that portion of the DrawPort that
///< intersects with the ViewPort will be visible on the OSD.
///< The drawing area of a newly created cPixmap is not initialized and may
///< contain random data.
static void Lock(void) { mutex.Lock(); }
///< All member functions of cPixmap set locks as necessary to make sure
///< they are thread-safe. If several cPixmap member functions need to be
///< called in a row, the caller must surround these calls with proper
///< Lock()/Unlock() calls. See the LOCK_PIXMAPS macro for a convenient
///< way of doing this.
static void Unlock(void) { mutex.Unlock(); }
int Layer(void) const { return layer; }
int Alpha(void) const { return alpha; }
bool Tile(void) const { return tile; }
const cRect &ViewPort(void) const { return viewPort; }
///< Returns the pixmap's view port, which is relative to the OSD's origin.
const cRect &DrawPort(void) const { return drawPort; }
///< Returns the pixmap's draw port, which is relative to the view port.
const cRect &DirtyViewPort(void) const { return dirtyViewPort; }
///< Returns the "dirty" rectangle this pixmap causes on the OSD. This is the
///< surrounding rectangle around all pixels that have been modified since the
///< last time this pixmap has been rendered to the OSD. The rectangle is
///< relative to the OSD's origin.
const cRect &DirtyDrawPort(void) const { return dirtyDrawPort; }
///< Returns the "dirty" rectangle in the draw port of this this pixmap. This is
///< the surrounding rectangle around all pixels that have been modified since the
///< last time this pixmap has been rendered to the OSD. The rectangle is
///< relative to the draw port's origin.
void SetClean(void);
///< Resets the "dirty" rectangles of this pixmap.
virtual void SetLayer(int Layer);
///< Sets the layer of this pixmap to the given value.
///< If the new layer is greater than zero, the pixmap will be visible.
///< If it is less than zero, it will be invisible.
///< A value of 0 will be silently ignored.
///< If a derived class reimplements this function, it needs to call the base
///< class function.
virtual void SetAlpha(int Alpha);
///< Sets the alpha value of this pixmap to the given value.
///< Alpha is limited to the range 0 (fully transparent) to 255 (fully opaque).
///< If a derived class reimplements this function, it needs to call the base
///< class function.
virtual void SetTile(bool Tile);
///< Sets the tile property of this pixmap to the given value. If Tile is true,
///< the pixmaps data will be repeated horizontally and vertically if necessary
///< to fill the entire view port.
///< If a derived class reimplements this function, it needs to call the base
///< class function.
virtual void SetViewPort(const cRect &Rect);
///< Sets the pixmap's view port to the given Rect.
///< If a derived class reimplements this function, it needs to call the base
///< class function.
virtual void SetDrawPortPoint(const cPoint &Point, bool Dirty = true);
///< Sets the pixmap's draw port to the given Point.
///< Only the origin point of the draw port can be modified, its size is fixed.
///< By default, setting a new draw port point results in marking the relevant
///< part of the view port as "drity". If Dirty is set to false, the view port
///< will not be marked as dirty. This is mainly used to implement the Pan()
///< function.
///< If a derived class reimplements this function, it needs to call the base
///< class function.
virtual void Clear(void) = 0;
///< Clears the pixmap's draw port by setting all pixels to be fully transparent.
///< A derived class must call Lock()/Unlock().
virtual void Fill(tColor Color) = 0;
///< Fills the pixmap's draw port with the given Color.
///< A derived class must call Lock()/Unlock().
virtual void DrawImage(const cPoint &Point, const cImage &Image) = 0;
///< Draws the given Image into this pixmap at the given Point.
virtual void DrawImage(const cPoint &Point, int ImageHandle) = 0;
///< Draws the image referenced by the given ImageHandle into this pixmap at
///< the given Point. ImageHandle must be a value that has previously been
///< returned by a call to cOsdProvider::StoreImage(). If ImageHandle
///< has an invalid value, nothing happens.
virtual void DrawPixel(const cPoint &Point, tColor Color, tColor Alpha = ALPHA_OPAQUE) = 0;
///< Sets the pixel at the given Point to the given Color, which is
///< a full 32 bit ARGB value. If the alpha value of Color is not 0xFF
///< (fully opaque), the pixel is alpha blended with the existing color
///< at the given position in this pixmap. If Alpha is less than
///< ALPHA_OPAQUE, the alpha value of Color will be reduced accordingly.
virtual void DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool Overlay = false) = 0;
///< Sets the pixels in the OSD with the data from the given
///< Bitmap, putting the upper left corner of the Bitmap at Point.
///< If ColorFg or ColorBg is given, the first palette entry of the Bitmap
///< will be mapped to ColorBg and the second palette entry will be mapped to
///< ColorFg (palette indexes are defined so that 0 is the background and
///< 1 is the foreground color).
///< If Overlay is true, any pixel in Bitmap that has color index 0 will
///< not overwrite the corresponding pixel in the target area.
///< This function is mainly for compatibility with skins or plugins that
///< draw bitmaps onto the OSD.
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) = 0;
///< Draws the given string at Point with the given foreground
///< and background color and font. If Width and Height are given, the text
///< will be drawn into a rectangle with the given size and the given
///< Alignment (default is top-left). If ColorBg is clrTransparent, no
///< background pixels will be drawn, which allows drawing "transparent" text.
virtual void DrawRectangle(const cRect &Rect, tColor Color) = 0;
///< Draws a filled rectangle with the given Color.
virtual void DrawEllipse(const cRect &Rect, tColor Color, int Quadrants = 0) = 0;
///< Draws a filled ellipse with the given Color that fits into the given
///< rectangle. Quadrants controls which parts of the ellipse are actually drawn:
///< 0 draws the entire ellipse
///< 1..4 draws only the first, second, third or fourth quadrant, respectively
///< 5..8 draws the right, top, left or bottom half, respectively
///< -1..-8 draws the inverted part of the given quadrant(s)
///< If Quadrants is not 0, the coordinates are those of the actual area, not
///< the full circle!
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type) = 0;
///< Draws a "slope" with the given Color into the given rectangle.
///< Type controls the direction of the slope and which side of it will be drawn:
///< 0: horizontal, rising, lower
///< 1: horizontal, rising, upper
///< 2: horizontal, falling, lower
///< 3: horizontal, falling, upper
///< 4: vertical, rising, lower
///< 5: vertical, rising, upper
///< 6: vertical, falling, lower
///< 7: vertical, falling, upper
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. The Source rectangle is relative to the given Pixmap's draw port.
///< The Pixmap's alpha value is to be used when rendering.
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. The Source rectangle is relative to the given Pixmap's draw port.
///< The data from Pixmap is copied as is, no alpha handling of any kind takes
///< place.
virtual void Scroll(const cPoint &Dest, const cRect &Source = cRect::Null) = 0;
///< Scrolls the data in the pixmap's draw port to the given Dest point.
///< If Source is given, only the data within that rectangle is scrolled.
///< Source and Dest are relative to this pixmap's draw port.
virtual void Pan(const cPoint &Dest, const cRect &Source = cRect::Null) = 0;
///< Does the same as Scroll(), but also shifts the draw port accordingly,
///< so that the view port doesn't get dirty if the scrolled rectangle
///< covers the entire view port. This may be of advantage if, e.g.,
///< there is a draw port that holds, say, 11 lines of text, while the
///< view port displays only 10 lines. By Pan()'ing the draw port up one
///< line, an new bottom line can be written into the draw port (without
///< being seen through the view port), and later the draw port can be
///< shifted smoothly, resulting in a smooth scrolling.
///< It is the caller's responsibility to make sure that Source and Dest
///< are given in such a way that the view port will not get dirty. No
///< check is done whether this condition actually holds true.
};
class cPixmapMutexLock : public cMutexLock {
public:
cPixmapMutexLock(void): cMutexLock(&cPixmap::mutex) {}
};
#define LOCK_PIXMAPS cPixmapMutexLock PixmapMutexLock
// cPixmapMemory is an implementation of cPixmap that uses an array of tColor
// values to store the pixmap.
class cPixmapMemory : public cPixmap {
private:
tColor *data;
bool panning;
public:
cPixmapMemory(void);
cPixmapMemory(int Layer, const cRect &ViewPort, const cRect &DrawPort = cRect::Null);
virtual ~cPixmapMemory();
const uint8_t *Data(void) { return (uint8_t *)data; }
virtual void Clear(void);
virtual void Fill(tColor Color);
virtual void DrawImage(const cPoint &Point, const cImage &Image);
virtual void DrawImage(const cPoint &Point, int ImageHandle);
virtual void DrawPixel(const cPoint &Point, tColor Color, tColor Alpha = ALPHA_OPAQUE);
virtual void DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool Overlay = false);
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);
virtual void DrawRectangle(const cRect &Rect, tColor Color);
virtual void DrawEllipse(const cRect &Rect, tColor Color, int Quadrants = 0);
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type);
virtual void Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest);
virtual void Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest);
virtual void Scroll(const cPoint &Dest, const cRect &Source = cRect::Null);
virtual void Pan(const cPoint &Dest, const cRect &Source = cRect::Null);
};
#define MAXOSDAREAS 16
#define MAXOSDPIXMAPS 64
/// The cOsd class is the interface to the "On Screen Display".
/// An actual output device needs to derive from this class and implement
/// the functionality necessary to display the OSD on the TV screen.
/// If the actual OSD supports "True Color", it can either let VDR do
/// all the rendering by calling RenderPixmaps() ("raw mode"), or it can
/// reimplement all necessary cPixmap functions and do the rendering
/// itself ("high level mode").
/// If an OSD provides a "high level mode", it shall also provide a "raw mode"
/// in order to verify proper operation. The plugin that impements the OSD
/// shall offer a configuration switch in its setup.
class cOsd {
friend class cOsdProvider;
private:
static int osdLeft, osdTop, osdWidth, osdHeight;
static cVector<cOsd *> Osds;
cBitmap *savedRegion;
bool isTrueColor;
cBitmap *savedBitmap;
cBitmap *bitmaps[MAXOSDAREAS];
int numBitmaps;
cPixmapMemory *savedPixmap;
cPixmap *pixmaps[MAXOSDPIXMAPS];
int numPixmaps;
int left, top, width, height;
uint level;
bool active;
@ -295,6 +728,32 @@ protected:
virtual void SetActive(bool On) { active = On; }
///< Sets this OSD to be the active one.
///< A derived class must call cOsd::SetActive(On).
const cPixmap * const *Pixmaps(void) { return pixmaps; }
///< Returns the list of currently active pixmaps in this OSD.
int NumPixmaps(void) { return numPixmaps; }
///< Returns the number of currently active pixmaps in this OSD.
cPixmap *AddPixmap(cPixmap *Pixmap);
///< Adds the given Pixmap to the list of currently active pixmaps in this OSD.
///< Returns Pixmap if the operation was successful, or NULL if the maximum
///< number of pixmaps has been exceeded.
///< A derived class that implements its own cPixmap class must call AddPixmap()
///< in order to add a newly created pixmap to the OSD's list of pixmaps.
cPixmapMemory *RenderPixmaps(void);
///< Renders the dirty part of all pixmaps into a resulting pixmap that
///< shall be displayed on the OSD. The returned pixmap's view port is
///< set to the location of the rectangle on the OSD that needs to be
///< refreshed; its draw port's origin is at (0, 0), and it has the same
///< size as the view port.
///< If there are several non-overlapping dirty rectangles from different pixmaps,
///< they are returned separately in order to avoid re-rendering large parts
///< of the OSD that haven't changed at all. The caller must therefore call
///< RenderPixmaps() repeatedly until it returns NULL, and display the returned
///< parts of the OSD at their appropriate locations. During this entire
///< operation the caller must hold a lock on the cPixmap mutex (for instance
///< by putting a LOCK_PIXMAPS into the scope of the operation).
///< If there are no dirty pixmaps, or if this is not a true color OSD,
///< this function returns NULL.
///< The caller must delete the returned pixmap after use.
public:
virtual ~cOsd();
///< Shuts down the OSD.
@ -309,6 +768,9 @@ public:
///< screen.
static int IsOpen(void) { return Osds.Size() && Osds[0]->level == OSD_LEVEL_DEFAULT; }
///< Returns true if there is currently a level 0 OSD open.
bool IsTrueColor(void) const { return isTrueColor; }
///< Returns 'true' if this is a true color OSD (providing full 32 bit color
///< depth).
int Left(void) { return left; }
int Top(void) { return top; }
int Width(void) { return width; }
@ -323,9 +785,33 @@ public:
///< a single color combination, and may not be able to serve all
///< requested colors. By default the palette assumes there will be
///< 10 fixed colors and 10 color combinations.
///< If this is a true color OSD, this function does nothing.
cBitmap *GetBitmap(int Area);
///< Returns a pointer to the bitmap for the given Area, or NULL if no
///< such bitmap exists.
///< If this is a true color OSD, a pointer to a dummy bitmap with 8bpp
///< is returned. This is done so that skins that call this function
///< in order to preset the bitmap's palette won't crash.
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).
///< The caller must not delete the returned object, it will be deleted when
///< the OSD is deleted. DestroyPixmap() can be called if a pixmap shall be
///< destroyed before the OSD is deleted.
///< If this is not a true color OSD, this function returns NULL.
virtual void DestroyPixmap(cPixmap *Pixmap);
///< Destroys the given Pixmap, which has previously been created by a call to
///< CreatePixmap(). When the OSD is deleted, all pixmaps are destroyed
///< automatically. So this function only needs to be used if a pixmap shall
///< be destroyed while the OSD is still being used.
virtual void DrawImage(const cPoint &Point, const cImage &Image);
///< Draws the given Image on this OSD at the given Point.
///< If this is not a true color OSD, this function does nothing.
virtual void DrawImage(const cPoint &Point, int ImageHandle);
///< Draws the image referenced by the given ImageHandle on this OSD at
///< the given Point. ImageHandle must be a value that has previously been
///< returned by a call to cOsdProvider::StoreImage(). If ImageHandle
///< has an invalid value, nothing happens.
///< If this is not a true color OSD, this function does nothing.
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
///< Checks whether the OSD can display the given set of sub-areas.
///< The return value indicates whether a call to SetAreas() with this
@ -343,6 +829,9 @@ public:
///< are part of the rectangle that surrounds a given drawing operation
///< will be drawn into, with the proper offsets.
///< A new call overwrites any previous settings
///< To set up a true color OSD, exactly one area must be requested, with
///< its coordinates set to the full area the OSD shall cover, and the
///< bpp value set to 32.
virtual void SaveRegion(int x1, int y1, int x2, int y2);
///< Saves the region defined by the given coordinates for later restoration
///< through RestoreRegion(). Only one saved region can be active at any
@ -352,6 +841,7 @@ public:
///< If SaveRegion() has not been called before, nothing will happen.
virtual eOsdError SetPalette(const cPalette &Palette, int Area);
///< Sets the Palette for the given Area (the first area is numbered 0).
///< If this is a true color OSD, nothing happens and oeOk is returned.
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.
@ -368,6 +858,7 @@ public:
///< area shall have its palette replaced with the one from Bitmap.
///< If Overlay is true, any pixel in Bitmap that has color index 0 will
///< not overwrite the corresponding pixel in the target area.
///< If this is a true color OSD, ReplacePalette has no meaning.
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. If Width and Height are given, the text
@ -401,18 +892,40 @@ public:
///< 7: vertical, falling, upper
virtual void Flush(void);
///< Actually commits all data to the OSD hardware.
///< Flush() should return as soon as possible.
};
#define MAXOSDIMAGES 64
class cOsdProvider {
friend class cPixmapMemory;
private:
static cOsdProvider *osdProvider;
static int oldWidth;
static int oldHeight;
static double oldAspect;
static cImage *images[MAXOSDIMAGES];
protected:
virtual cOsd *CreateOsd(int Left, int Top, uint Level) = 0;
///< Returns a pointer to a newly created cOsd object, which will be located
///< at the given coordinates.
virtual bool ProvidesTrueColor(void) { return false; }
///< Returns true if this OSD provider is able to handle a true color OSD.
virtual int StoreImageData(const cImage &Image);
///< Copies the given Image and returns a handle for later reference.
///< A derived class can implement its own image storing mechanism by
///< reimplementing this function as well as DropImageData().
///< The base class implementation simply copies the image data to allow
///< plugins to always use this interface, no matter if the actual device
///< provides support for storing image data or not. The handles returned
///< by the default implementation are positive integers. A derived class
///< might want to use negative integers as handles, so that it can fall
///< back to using the base class image storing mechanism if, e.g., it runs
///< out of memory.
virtual void DropImageData(int ImageHandle);
///< Drops the image data referenced by ImageHandle.
static const cImage *GetImageData(int ImageHandle);
///< Gets the image data referenced by ImageHandle.
public:
cOsdProvider(void);
//XXX maybe parameter to make this one "sticky"??? (frame-buffer etc.)
@ -427,7 +940,22 @@ public:
///< Inquires the actual size of the video display and adjusts the OSD and
///< font sizes accordingly. If Force is true, all settings are recalculated,
///< even if the video resolution hasn't changed since the last call to
///< this funtion.
///< this function.
static bool SupportsTrueColor(void);
///< Returns true if the current OSD provider is able to handle a true color OSD.
static int StoreImage(const cImage &Image);
///< Stores the given Image for later use with DrawImage() on an OSD or
///< pixmap. The returned number is a handle that must be used when
///< referencing this image in a call to DrawImage() or DropImage().
///< The image data is copied, so any later changes to Image will have
///< no effect on the stored image.
///< A derived class may be able to copy frequently used images to some
///< space where they can be retrieved faster than using a cImage in each call.
///< If this is not a true color OSD, or if the image data can't be stored for
///< any reason, this function returns 0 and nothing is stored.
static void DropImage(int ImageHandle);
///< Drops the image referenced by the given ImageHandle. If ImageHandle
///< has an invalid value, nothing happens.
static void Shutdown(void);
///< Shuts down the OSD provider facility by deleting the current OSD provider.
};

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: skinsttng.c 2.6 2010/11/07 15:10:08 kls Exp $
* $Id: skinsttng.c 2.7 2011/02/20 13:02:49 kls Exp $
*/
// Star Trek: The Next Generation® is a registered trademark of Paramount Pictures
@ -182,12 +182,17 @@ cSkinSTTNGDisplayChannel::cSkinSTTNGDisplayChannel(bool WithInfo)
int yt = (y0 + y1) / 2;
int yb = (y6 + y7) / 2;
osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + (Setup.ChannelInfoPos ? 0 : cOsd::OsdHeight() - y7));
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 8 } };
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 32 } }; // TrueColor
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 4 } };
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 8 } }; // 256 colors
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 4 } }; // 16 colors
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}
}
osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, Theme.Color(clrBackground));
osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
@ -220,12 +225,17 @@ cSkinSTTNGDisplayChannel::cSkinSTTNGDisplayChannel(bool WithInfo)
y0 = 0;
y1 = lineHeight;
osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + (Setup.ChannelInfoPos ? 0 : cOsd::OsdHeight() - y1));
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } };
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 32 } }; // TrueColor
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 4 } };
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } }; // 256 colors
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 4 } }; // 16 colors
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}
}
osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, clrTransparent);
osd->DrawEllipse (x0, y0, x1 - 1, y1 - 1, frameColor, 7);
@ -397,21 +407,26 @@ cSkinSTTNGDisplayMenu::cSkinSTTNGDisplayMenu(void)
int yt = (y0 + y1) / 2;
int yb = (y6 + y7) / 2;
osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop());
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 8 } };
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 32 } }; // TrueColor
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } };
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 8 } }; // 256 colors
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 },
{ x0, y3, x3 - 1, y4 - 1, 1 },
{ x3, y3, x4 - 1, y4 - 1, 2 },
{ x4, y3, x7 - 1, y4 - 1, 2 },
{ x0, y4, x7 - 1, y7 - 1, 4 }
};
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } }; // 16 colors
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 }, // 2..16 colors
{ x0, y3, x3 - 1, y4 - 1, 1 },
{ x3, y3, x4 - 1, y4 - 1, 2 },
{ x4, y3, x7 - 1, y4 - 1, 2 },
{ x0, y4, x7 - 1, y7 - 1, 4 }
};
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}
}
}
osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, Theme.Color(clrBackground));
@ -754,12 +769,17 @@ cSkinSTTNGDisplayReplay::cSkinSTTNGDisplayReplay(bool ModeOnly)
int yt = (y0 + y1) / 2;
int yb = (y6 + y7) / 2;
osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y7);
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 8 } };
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 32 } }; // TrueColor
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 4 } };
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 8 } }; // 256 colors
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { 0, 0, x7 - 1, y7 - 1, 4 } }; // 16 colors
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}
}
osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, ModeOnly ? clrTransparent : Theme.Color(clrBackground));
if (!ModeOnly) {
@ -888,12 +908,17 @@ cSkinSTTNGDisplayVolume::cSkinSTTNGDisplayVolume(void)
y0 = 0;
y1 = lineHeight;
osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y1);
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } };
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 32 } }; // TrueColor
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 4 } };
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } }; // 256 colors
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 4 } }; // 16 colors
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}
}
osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, clrTransparent);
osd->DrawEllipse (x0, y0, x1 - 1, y1 - 1, frameColor, 7);
@ -1003,21 +1028,26 @@ cSkinSTTNGDisplayTracks::cSkinSTTNGDisplayTracks(const char *Title, int NumTrack
int yt = (y0 + y1) / 2;
int yb = (y6 + y7) / 2;
osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y7);
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 8 } };
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 32 } }; // TrueColor
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } };
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 8 } }; // 256 colors
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 },
{ x0, y3, x3 - 1, y4 - 1, 1 },
{ x3, y3, x4 - 1, y4 - 1, 2 },
{ x4, y3, x7 - 1, y4 - 1, 2 },
{ x0, y4, x7 - 1, y7 - 1, 4 }
};
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } }; // 16 colors
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 }, // 2..16 colors
{ x0, y3, x3 - 1, y4 - 1, 1 },
{ x3, y3, x4 - 1, y4 - 1, 2 },
{ x4, y3, x7 - 1, y4 - 1, 2 },
{ x0, y4, x7 - 1, y7 - 1, 4 }
};
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}
}
}
osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, Theme.Color(clrBackground));
@ -1131,12 +1161,17 @@ cSkinSTTNGDisplayMessage::cSkinSTTNGDisplayMessage(void)
y0 = 0;
y1 = lineHeight;
osd = cOsdProvider::NewOsd(cOsd::OsdLeft(), cOsd::OsdTop() + cOsd::OsdHeight() - y1);
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } };
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 32 } }; // TrueColor
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 2 } };
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 8 } }; // 256 colors
if (Setup.AntiAlias && osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
else {
tArea Areas[] = { { x0, y0, x7 - 1, y1 - 1, 2 } }; // 4 colors
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
}
}
osd->DrawRectangle(x0, y0, x7 - 1, y1 - 1, clrTransparent);
osd->DrawEllipse (x0, y0, x1 - 1, y1 - 1, frameColor, 7);