From 37f89dca4967856b0b780fdfa68b30296968be61 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Fri, 10 May 2002 14:55:53 +0200 Subject: Separated the actual DVB hardware OSD implementation from the abstract OSD interface --- osdbase.c | 482 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 482 insertions(+) create mode 100644 osdbase.c (limited to 'osdbase.c') diff --git a/osdbase.c b/osdbase.c new file mode 100644 index 00000000..31e86def --- /dev/null +++ b/osdbase.c @@ -0,0 +1,482 @@ +/* + * osdbase.c: Basic interface to the On Screen Display + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: osdbase.c 1.1 2002/05/10 14:55:53 kls Exp $ + */ + +#include "osdbase.h" +#include +#include +#include +#include +#include "tools.h" + +// --- cPalette -------------------------------------------------------------- + +cPalette::cPalette(int Bpp) +{ + maxColors = 1 << Bpp; + numColors = 0; + full = false; +} + +int cPalette::Index(eDvbColor Color) +{ +#if __BYTE_ORDER == __BIG_ENDIAN + Color = eDvbColor(((Color & 0xFF) << 24) | ((Color & 0xFF00) << 8) | ((Color & 0xFF0000) >> 8) | ((Color & 0xFF000000) >> 24)); +#endif + for (int i = 0; i < numColors; i++) { + if (color[i] == Color) { + used[i] = true; + return i; + } + } + if (!full) { + if (numColors < maxColors) { + color[numColors++] = Color; + used[numColors - 1] = true; + fetched[numColors - 1] = false; + return numColors - 1; + } + for (int i = maxColors; --i >= 0; ) { + if (!used[i]) { + color[i] = Color; + used[i] = true; + fetched[i] = false; + return i; + } + } + esyslog(LOG_ERR, "ERROR: too many different colors used in palette"); + full = true; + } + return 0; +} + +void cPalette::Reset(void) +{ + for (int i = 0; i < numColors; i++) + used[i] = false; + full = false; +} + +const eDvbColor *cPalette::Colors(int &FirstColor, int &LastColor) +{ + for (FirstColor = 0; FirstColor < numColors; FirstColor++) { + if (!fetched[FirstColor]) { + for (LastColor = FirstColor; LastColor < numColors && !fetched[LastColor]; LastColor++) + fetched[LastColor] = true; + LastColor--; // the loop ended one past the last one! + return &color[FirstColor]; + } + } + return NULL; +} + +void cPalette::Take(const cPalette &Palette, tIndexes *Indexes) +{ + for (int i = 0; i < Palette.numColors; i++) { + if (Palette.used[i]) { + int n = Index(Palette.color[i]); + if (Indexes) + (*Indexes)[i] = n; + } + } +} + +// --- cBitmap --------------------------------------------------------------- + +cBitmap::cBitmap(int Width, int Height, int Bpp, bool ClearWithBackground) +:cPalette(Bpp) +{ + width = Width; + height = Height; + clearWithBackground = ClearWithBackground; + bitmap = NULL; + fontType = fontOsd; + font = NULL; + if (width > 0 && height > 0) { + bitmap = new char[width * height]; + if (bitmap) { + Clean(); + memset(bitmap, 0x00, width * height); + SetFont(fontOsd); + } + else + esyslog(LOG_ERR, "ERROR: can't allocate bitmap!"); + } + else + esyslog(LOG_ERR, "ERROR: illegal bitmap parameters (%d, %d)!", width, height); +} + +cBitmap::~cBitmap() +{ + delete font; + delete bitmap; +} + +eDvbFont cBitmap::SetFont(eDvbFont Font) +{ + eDvbFont oldFont = fontType; + if (fontType != Font || !font) { + delete font; + font = new cFont(Font); + fontType = Font; + } + return oldFont; +} + +bool cBitmap::Dirty(int &x1, int &y1, int &x2, int &y2) +{ + if (dirtyX2 >= 0) { + //XXX Workaround: apparently the bitmap sent to the driver always has to be a multiple + //XXX of 8 bits wide, and (dx * dy) also has to be a multiple of 8. + //TODO Fix driver (should be able to handle any size bitmaps!) + while ((dirtyX1 > 0 || dirtyX2 < width - 1) && ((dirtyX2 - dirtyX1) & 7) != 7) { + if (dirtyX2 < width - 1) + dirtyX2++; + else if (dirtyX1 > 0) + dirtyX1--; + } + //XXX "... / 2" <==> Bpp??? + while ((dirtyY1 > 0 || dirtyY2 < height - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { + if (dirtyY2 < height - 1) + dirtyY2++; + else if (dirtyY1 > 0) + dirtyY1--; + } + while ((dirtyX1 > 0 || dirtyX2 < width - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) { + if (dirtyX2 < width - 1) + dirtyX2++; + else if (dirtyX1 > 0) + dirtyX1--; + } + x1 = dirtyX1; + y1 = dirtyY1; + x2 = dirtyX2; + y2 = dirtyY2; + return true; + } + return false; +} + +void cBitmap::Clean(void) +{ + dirtyX1 = width; + dirtyY1 = height; + dirtyX2 = -1; + dirtyY2 = -1; +} + +void cBitmap::SetIndex(int x, int y, char Index) +{ + if (bitmap) { + if (0 <= x && x < width && 0 <= y && y < height) { + if (bitmap[width * y + x] != Index) { + bitmap[width * y + x] = Index; + if (dirtyX1 > x) dirtyX1 = x; + if (dirtyY1 > y) dirtyY1 = y; + if (dirtyX2 < x) dirtyX2 = x; + if (dirtyY2 < y) dirtyY2 = y; + } + } + } +} + +void cBitmap::SetPixel(int x, int y, eDvbColor Color) +{ + SetIndex(x, y, Index(Color)); +} + +void cBitmap::SetBitmap(int x, int y, const cBitmap &Bitmap) +{ + if (bitmap && Bitmap.bitmap) { + tIndexes Indexes; + Take(Bitmap, &Indexes); + for (int ix = 0; ix < Bitmap.width; ix++) { + for (int iy = 0; iy < Bitmap.height; iy++) + SetIndex(x + ix, y + iy, Indexes[Bitmap.bitmap[Bitmap.width * iy + ix]]); + } + } +} + +int cBitmap::Width(unsigned char c) +{ + return font ? font->Width(c) : -1; +} + +int cBitmap::Width(const char *s) +{ + return font ? font->Width(s) : -1; +} + +void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) +{ + if (bitmap) { + char fg = Index(ColorFg); + char bg = Index(ColorBg); + int h = font->Height(s); + while (s && *s) { + const cFont::tCharData *CharData = font->CharData(*s++); + if (int(x + CharData->width) > width) + break; + for (int row = 0; row < h; row++) { + cFont::tPixelData PixelData = CharData->lines[row]; + for (int col = CharData->width; col-- > 0; ) { + SetIndex(x + col, y + row, (PixelData & 1) ? fg : bg); + PixelData >>= 1; + } + } + x += CharData->width; + } + } +} + +void cBitmap::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) +{ + if (bitmap) { + char c = Index(Color); + for (int y = y1; y <= y2; y++) + for (int x = x1; x <= x2; x++) + SetIndex(x, y, c); + } +} + +void cBitmap::Clear(void) +{ + Reset(); + if (clearWithBackground) + Fill(0, 0, width - 1, height - 1, clrBackground); +} + +const char *cBitmap::Data(int x, int y) +{ + return &bitmap[y * width + x]; +} + +// --- cWindow --------------------------------------------------------------- + +cWindow::cWindow(int Handle, int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled) +:cBitmap(w, h, Bpp, ClearWithBackground) +{ + handle = Handle; + x0 = x; + y0 = y; + bpp = Bpp; + tiled = Tiled; + shown = false; +} + +bool cWindow::Contains(int x, int y) +{ + x -= x0; + y -= y0; + return x >= 0 && y >= 0 && x < width && y < height; +} + +void cWindow::Relocate(int x, int y) +{ + x0 = x; + y0 = y; +} + +void cWindow::Fill(int x1, int y1, int x2, int y2, eDvbColor Color) +{ + if (tiled) { + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + } + cBitmap::Fill(x1, y1, x2, y2, Color); +} + +void cWindow::SetBitmap(int x, int y, const cBitmap &Bitmap) +{ + if (tiled) { + x -= x0; + y -= y0; + } + cBitmap::SetBitmap(x, y, Bitmap); +} + +void cWindow::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) +{ + if (tiled) { + x -= x0; + y -= y0; + } + cBitmap::Text(x, y, s, ColorFg, ColorBg); +} + +const char *cWindow::Data(int x, int y) +{ + return cBitmap::Data(x, y); +} + +// --- cOsd ------------------------------------------------------------------ + +cOsd::cOsd(int x, int y) +{ + numWindows = 0; + x0 = x; + y0 = y; +} + +cOsd::~cOsd() +{ + for (int i = 0; i < numWindows; i++) + delete window[i]; +} + +tWindowHandle cOsd::Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled) +{ + if (numWindows < MAXNUMWINDOWS) { + if (x >= 0 && y >= 0 && w > 0 && h > 0 && (Bpp == 1 || Bpp == 2 || Bpp == 4 || Bpp == 8)) { + if ((w & 0x03) != 0) { + w += 4 - (w & 0x03); + esyslog(LOG_ERR, "ERROR: OSD window width must be a multiple of 4 - increasing to %d", w); + } + cWindow *win = new cWindow(numWindows, x, y, w, h, Bpp, ClearWithBackground, Tiled); + if (OpenWindow(win)) { + window[win->Handle()] = win; + numWindows++; + return win->Handle(); + } + else + delete win; + } + else + esyslog(LOG_ERR, "ERROR: illegal OSD parameters"); + } + else + esyslog(LOG_ERR, "ERROR: too many OSD windows"); + return -1; +} + +void cOsd::AddColor(eDvbColor Color, tWindowHandle Window) +{ + cWindow *w = GetWindow(Window); + if (w) { + w->Index(Color); + w->Reset(); + } +} + +cWindow *cOsd::GetWindow(int x, int y) +{ + for (int i = 0; i < numWindows; i++) { + if (window[i]->Tiled() && window[i]->Contains(x, y)) + return window[i]; + } + return NULL; +} + +cWindow *cOsd::GetWindow(tWindowHandle Window) +{ + if (0 <= Window && Window < numWindows) + return window[Window]; + if (Window == LAST_CREATED_WINDOW && numWindows > 0) + return window[numWindows - 1]; + return NULL; +} + +void cOsd::Flush(void) +{ + for (int i = 0; i < numWindows; i++) { + CommitWindow(window[i]); + window[i]->Clean(); + } + // Showing the windows in a separate loop to avoid seeing them come up one after another + for (int i = 0; i < numWindows; i++) { + if (!window[i]->Shown()) + ShowWindow(window[i]); + } +} + +void cOsd::Clear(tWindowHandle Window) +{ + if (Window == ALL_TILED_WINDOWS || Window == ALL_WINDOWS) { + for (int i = 0; i < numWindows; i++) + if (Window == ALL_WINDOWS || window[i]->Tiled()) + window[i]->Clear(); + } + else { + cWindow *w = GetWindow(Window); + if (w) + w->Clear(); + } +} + +void cOsd::Fill(int x1, int y1, int x2, int y2, eDvbColor Color, tWindowHandle Window) +{ + cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x1, y1) : GetWindow(Window); + if (w) + w->Fill(x1, y1, x2, y2, Color); +} + +void cOsd::SetBitmap(int x, int y, const cBitmap &Bitmap, tWindowHandle Window) +{ + cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x, y) : GetWindow(Window); + if (w) + w->SetBitmap(x, y, Bitmap); +} + +int cOsd::Width(unsigned char c) +{ + return numWindows ? window[0]->Width(c) : 0; +} + +int cOsd::Width(const char *s) +{ + return numWindows ? window[0]->Width(s) : 0; +} + +eDvbFont cOsd::SetFont(eDvbFont Font) +{ + eDvbFont oldFont = Font; + for (int i = 0; i < numWindows; i++) + oldFont = window[i]->SetFont(Font); + return oldFont; +} + +void cOsd::Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground, tWindowHandle Window) +{ + cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x, y) : GetWindow(Window); + if (w) + w->Text(x, y, s, ColorFg, ColorBg); +} + +void cOsd::Relocate(tWindowHandle Window, int x, int y, int NewWidth, int NewHeight) +{ + cWindow *w = GetWindow(Window); + if (w) { + if (NewWidth > 0 && NewHeight > 0) { + if ((NewWidth & 0x03) != 0) { + NewWidth += 4 - (NewWidth & 0x03); + esyslog(LOG_ERR, "ERROR: OSD window width must be a multiple of 4 - increasing to %d", NewWidth); + } + CloseWindow(w); + cWindow *NewWindow = new cWindow(w->Handle(), x, y, NewWidth, NewHeight, w->Bpp(), w->ClearWithBackground(), w->Tiled()); + window[w->Handle()] = NewWindow; + delete w; + OpenWindow(NewWindow); + } + else { + MoveWindow(w, x, y); + w->Relocate(x, y); + } + } +} + +void cOsd::Hide(tWindowHandle Window) +{ + HideWindow(GetWindow(Window), true); +} + +void cOsd::Show(tWindowHandle Window) +{ + HideWindow(GetWindow(Window), false); +} -- cgit v1.2.3