diff options
author | Tobias Grimm <tobias@e-tobi.loc> | 2008-12-02 21:00:33 +0100 |
---|---|---|
committer | Tobias Grimm <tobias@e-tobi.loc> | 2008-12-02 21:00:33 +0100 |
commit | b451fdb5a36c0f749d63d53165cdf4e84a8f476a (patch) | |
tree | aa3b6548ea52ef133028098c8fbaebbe47ed8a5d /displaybase.c | |
download | vdr-plugin-osdteletext-b451fdb5a36c0f749d63d53165cdf4e84a8f476a.tar.gz vdr-plugin-osdteletext-b451fdb5a36c0f749d63d53165cdf4e84a8f476a.tar.bz2 |
Initial commit of version 0.5.1v0.5.1release/v0.5.1
Diffstat (limited to 'displaybase.c')
-rw-r--r-- | displaybase.c | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/displaybase.c b/displaybase.c new file mode 100644 index 0000000..b46fa25 --- /dev/null +++ b/displaybase.c @@ -0,0 +1,507 @@ +/*************************************************************************** + * * + * displaybase.c - Base class for rendering a teletext cRenderPage to * + * an actual VDR OSD. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * Changelog: * + * 2005-03 initial version (c) Udo Richter * + * * + ***************************************************************************/ + +#include <strings.h> +#include <time.h> +#include "displaybase.h" +#include "txtfont.h" + + +cDisplay::cDisplay(int width, int height) { + Concealed=false; + Blinked=false; + FlushLock=0; + Zoom=Zoom_Off; + osd=NULL; + ScaleX=1; + ScaleY=1; + OffsetX=0; + OffsetY=0; + Width=width; + Height=height; + Background=clrGray50; + Boxed=false; + + MessageX=0; + MessageY=0; + MessageW=0; + MessageH=0; + MessageFont=cFont::GetFont(fontSml); +} + +cDisplay::~cDisplay() { + if (osd) delete osd; + osd=NULL; +} + +void cDisplay::InitScaler() { + // Set up the scaling factors. Also do zoom mode by + // scaling differently. + + if (!osd) return; + + int height=Height-6; + int width=Width-6; + OffsetX=3; + OffsetY=3; + + switch (Zoom) { + case Zoom_Upper: + height=height*2; + break; + case Zoom_Lower: + OffsetY=OffsetY-height; + height=height*2; + break; + default:; + } + + ScaleX=(480<<16)/width; + ScaleY=(250<<16)/height; +} + +void cDisplay::InitPalette() { + cBitmap *bm; + if (!osd) return; + + int Area=0; + while ((bm=osd->GetBitmap(Area))) { + enumTeletextColor c; + + bm->Reset(); + // reset palette + + for (c=ttcFirst;c<=ttcLast;c++) bm->Index(GetColorRGB(c,Area)); + // Announce all palette colors in defined order + + int x1,y1,x2,y2; + if (!bm->Dirty(x1,y1,x2,y2)) { + // force bitmap dirty to update palette + bm->SetIndex(bm->X0(),bm->Y0(),*bm->Data(bm->X0(),bm->Y0())); + // otherwise palette change wont be displayed on flush + } + + Area++; + } +} + +bool cDisplay::SetBlink(bool blink) { + int x,y; + bool Change=false; + + if (blink==Blinked) return false; + + // touch all blinking chars + for (y=0;y<25;y++) { + for (x=0;x<40;x++) { + if (Page[x][y].GetBlink()) { + Page[x][y].SetDirty(true); + Change=true; + } + } + } + Blinked=blink; + if (Change) Dirty=true; + + Flush(); + + return Change; +} + +bool cDisplay::SetConceal(bool conceal) { + int x,y; + bool Change=false; + + if (conceal==Concealed) return false; + + // touch all concealed chars + for (y=0;y<25;y++) { + for (x=0;x<40;x++) { + if (Page[x][y].GetConceal()) { + Page[x][y].SetDirty(true); + Change=true; + } + } + } + Concealed=conceal; + if (Change) Dirty=true; + + Flush(); + + return Change; +} + +void cDisplay::SetZoom(enumZoom zoom) { + + if (!osd) return; + if (Zoom==zoom) return; + Zoom=zoom; + + // Re-initialize scaler to let zoom take effect + InitScaler(); + + // Clear screen - mainly clear border + CleanDisplay(); + + Flush(); +} + +void cDisplay::SetBackgroundColor(tColor c) { + Background=c; + InitPalette(); + CleanDisplay(); + Flush(); +} + +void cDisplay::CleanDisplay() { + cBitmap *bm; + enumTeletextColor bgc=(Boxed)?(ttcTransparent):(ttcBlack); + int Area=0; + while ((bm=osd->GetBitmap(Area))) { + // Draw rect in two steps to avoid zapping palette + bm->DrawRectangle(bm->X0(), bm->Y0() , bm->X0()+bm->Width()-1, bm->Y0() , bm->Color(GetColorIndex(bgc,Area))); + bm->DrawRectangle(bm->X0(), bm->Y0()+1, bm->X0()+bm->Width()-1, bm->Y0()+bm->Height()-1, bm->Color(GetColorIndex(bgc,Area))); + // Yes, this *is* stupid. + // Otherwise, ttcTransparent would shift into 0 index of palette, + // causing palette re-organization and flicker on page change + Area++; + } + + // repaint all + Dirty=true; + DirtyAll=true; +} + + +tColor cDisplay::GetColorRGB(enumTeletextColor ttc, int Area) { + switch (ttc) { + case ttcBlack: return Background; + case ttcRed: return clrRed; + case ttcGreen: return clrGreen; + case ttcYellow: return clrYellow; + case ttcBlue: return clrBlue; + case ttcMagenta: return clrMagenta; + case ttcCyan: return clrCyan; + case ttcWhite: return clrWhite; + case ttcTransparent: return clrTransparent; + default: return Background; + } +} + +tColor cDisplay::GetColorRGBAlternate(enumTeletextColor ttc, int Area) { + return GetColorRGB(ttc,Area); +} + +void cDisplay::RenderTeletextCode(unsigned char *PageCode) { + // Interprete teletext code referenced by PageCode + // and draw the whole page content into OSD. + // PageCode must be a 40*24+12 bytes buffer + + #ifdef timingdebug + cTime t; + t.Start(); + #endif + + HoldFlush(); + + cRenderPage::ReadTeletextHeader(PageCode); + + if (!Boxed && (Flags&0x60)!=0) { + Boxed=true; + CleanDisplay(); + } else if (Boxed && (Flags&0x60)==0) { + Boxed=false; + CleanDisplay(); + } + + cRenderPage::RenderTeletextCode(PageCode+12); + + #ifdef timingdebug + t.Stop("Render Teletext"); + #endif + + ReleaseFlush(); +} + + + +void cDisplay::DrawDisplay() { + int x,y; + int cnt=0; + + if (!IsDirty()) return; + // nothing to do + + #ifdef timingdebug + cTime t; + t.Start(); + #endif + + for (y=0;y<25;y++) { + for (x=0;x<40;x++) { + if (IsDirty(x,y)) { + // Need to draw char to osd + cnt++; + cTeletextChar c=Page[x][y]; + c.SetDirty(false); + if ((Blinked && c.GetBlink()) || (Concealed && c.GetConceal())) { + c.SetChar(0x20); + c.SetCharset(CHARSET_LATIN_G0_DE); + } + DrawChar(x,y,c); + Page[x][y]=c; + } + } + } + #ifdef timingdebug + t.Stop("Draw Display"); + #endif + + Dirty=false; + DirtyAll=false; +} + + +inline bool IsPureChar(unsigned int *bitmap) { + // Check if character is pure foreground or + // pure background color + int i; + if (bitmap[0]==0x0000) { + for (i=1;i<10;i++) { + if (bitmap[i]!=0x0000) return false; + } + } else if (bitmap[0]==0xfff0) { + for (i=1;i<10;i++) { + if (bitmap[i]!=0xfff0) return false; + } + } else { + return false; + } + return true; +} + + + +void cDisplay::DrawChar(int x, int y, cTeletextChar c) { + unsigned int buffer[10]; + unsigned int *charmap; + cBitmap *bm; + + // Get character face: + charmap=GetFontChar(c,buffer); + if (!charmap) { + // invalid - clear buffer + bzero(&buffer,sizeof buffer); + charmap=buffer; + } + + // Get colors + enumTeletextColor ttfg=c.GetFGColor(); + enumTeletextColor ttbg=c.GetBGColor(); + + if (c.GetBoxedOut()) { + ttbg=ttcTransparent; + ttfg=ttcTransparent; + } + + // Virtual box area of the character + cBox box; + box.SetToCharacter(x,y); + + // OSD top left pixel of char + cVirtualCoordinate TopLeft; + TopLeft.VirtualToPixel(this,box.XMin,box.YMin); + // This pixel overlaps the box, but may be almost outside. + + // Move in OSD pixel units until we are inside the box + while (TopLeft.VirtX<box.XMin) TopLeft.IncPixelX(this); + while (TopLeft.VirtY<box.YMin) TopLeft.IncPixelY(this); + + // Move through all areas + int Area=0; + while ((bm=osd->GetBitmap(Area))) { + cVirtualCoordinate BMTopLeft=TopLeft; + + // Correct for bitmap offset + BMTopLeft.OsdX-=bm->X0(); + BMTopLeft.OsdY-=bm->Y0(); + + // Map color to local + int fg=GetColorIndex(ttfg,Area); + int bg=GetColorIndex(ttbg,Area); + if (ttfg!=ttbg && fg==bg && !IsPureChar(charmap)) { + // Color collision + bg=GetColorIndexAlternate(ttbg,Area); + } + + // Now draw the character. Start at the top left corner, and walk + // through all pixels on OSD. To speed up, keep one pointer to OSD pixel + // and one to virtual box coordinates, and move them together. + + cVirtualCoordinate p=BMTopLeft; + while (p.VirtY<=box.YMax) { + // run through OSD lines + + // OSD line in this bitmap? + if (0<=p.OsdY && p.OsdY<bm->Height()) { + // bits for this line + int bitline; + bitline=charmap[(p.VirtY-box.YMin)>>16]; + + p.OsdX=BMTopLeft.OsdX; + p.VirtX=BMTopLeft.VirtX; + while (p.VirtX<=box.XMax) { + // run through line pixels + + // pixel insied this bitmap? + if (0<=p.OsdX && p.OsdX<bm->Width()) { + // pixel offset in bitline: + int bit=(p.VirtX-box.XMin)>>16; + + if (bitline&(0x8000>>bit)) { + bm->SetIndex(p.OsdX,p.OsdY,fg); + } else { + bm->SetIndex(p.OsdX,p.OsdY,bg); + } + } + p.IncPixelX(this); + } + } + p.IncPixelY(this); + } + Area++; + } +} + +void cDisplay::DrawText(int x, int y, const char *text, int len) { + // Copy text to teletext page + + cTeletextChar c; + c.SetFGColor(ttcWhite); + c.SetBGColor(ttcBlack); + c.SetCharset(CHARSET_LATIN_G0); + + // Copy chars up to len or null char + while (len>0 && *text!=0x00) { + c.SetChar(*text); + SetChar(x,y,c); + text++; + x++; + len--; + } + + // Fill remaining chars with spaces + c.SetChar(' '); + while (len>0) { + SetChar(x,y,c); + x++; + len--; + } + // .. and display + Flush(); +} + +void cDisplay::DrawClock() { + char text[9]; + time_t t=time(0); + struct tm loct; + + localtime_r(&t, &loct); + sprintf(text, "%02d:%02d:%02d", loct.tm_hour, loct.tm_min, loct.tm_sec); + + DrawText(32,0,text,8); +} + +void cDisplay::DrawMessage(const char *txt) { + const int border=5; + cBitmap *bm; + + if (!osd) return; + + HoldFlush(); + // Hold flush until done + + ClearMessage(); + // Make sure old message is gone + + if (IsDirty()) DrawDisplay(); + // Make sure all characters are out, so we can draw on top + + int w=MessageFont->Width(txt)+4*border; + int h=MessageFont->Height(txt)+4*border; + int x=(Width-w)/2; + int y=(Height-h)/2; + + int Area=0; + while ((bm=osd->GetBitmap(Area))) { + // Walk through all OSD areas + + // Get local color mapping + tColor fg=bm->Color(GetColorIndex(ttcWhite,Area)); + tColor bg=bm->Color(GetColorIndex(ttcBlack,Area)); + if (fg==bg) bg=bm->Color(GetColorIndexAlternate(ttcBlack,Area)); + + // Draw framed box + osd->DrawRectangle(x ,y ,x+w-1 ,y+border-1 ,fg); + osd->DrawRectangle(x ,y+h-border,x+w-1 ,y+h-1 ,fg); + osd->DrawRectangle(x ,y ,x+border-1 ,y+h-1 ,fg); + osd->DrawRectangle(x+w-border,y ,x+w-1 ,y+h-1 ,fg); + osd->DrawRectangle(x+border ,y+border ,x+w-border-1,y+h-border-1,bg); + + // Draw text + osd->DrawText(x+2*border,y+2*border,txt, fg, bg, MessageFont); + + Area++; + } + + // Remember box + MessageW=w; + MessageH=h; + MessageX=x; + MessageY=y; + + // And flush all changes + ReleaseFlush(); +} + +void cDisplay::ClearMessage() { + if (!osd) return; + if (MessageW==0 || MessageH==0) return; + + // map OSD pixel to virtual coordinate, use center of pixel + int x0=(MessageX-OffsetX)*ScaleX+ScaleX/2; + int y0=(MessageY-OffsetY)*ScaleY+ScaleY/2; + int x1=(MessageX+MessageW-1-OffsetX)*ScaleX+ScaleX/2; + int y1=(MessageY+MessageH-1-OffsetY)*ScaleY+ScaleY/2; + + // map to character + x0=x0/(12<<16); + y0=y0/(10<<16); + x1=(x1+(12<<16)-1)/(12<<16); + y1=(y1+(10<<16)-1)/(10<<16); + + for (int x=x0;x<=x1;x++) { + for (int y=y0;y<=y1;y++) { + MakeDirty(x,y); + } + } + + MessageW=0; + MessageH=0; + + Flush(); +} + + |