1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
|
/*************************************************************** -*- c++ -*-
* Copyright (c) 2005 by Udo Richter *
* Copyright (c) 2021 by Peter Bieringer (extenions) *
* *
* display.c - Actual implementation of OSD display variants and *
* Display:: namespace that encapsulates a single cDisplay. *
* *
* 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. *
* *
***************************************************************************/
#include <strings.h>
#include <vdr/config.h>
#include <vdr/skins.h>
#include "setup.h"
#include "display.h"
#include "txtfont.h"
#include "logging.h"
// Static variables of Display:: namespace
Display::Mode Display::mode=Display::Full;
cDisplay *Display::display=NULL;
void Display::SetMode(Display::Mode NewMode, tColor clrBackground) {
// Background is optional and default predefined in display.h
int hChars = 40;
int vLines = TT_DISPLAY_LINES;
int OSDwidth;
int OSDheight;
int OSDleftFrame = 0;
int OSDrightFrame = 0;
int OSDtopFrame = 0;
int OSDbottomFrame = 0;
int x0 = cOsd::OsdLeft(); // start with general OSD offset
int y0 = cOsd::OsdTop(); // start with general OSD offset
// (re-)set display mode.
if (display!=NULL && NewMode==mode) return; // No change, nothing to do
// calculate from percentage and OSD maximum
OSDwidth = (cOsd::OsdWidth() * TTSETUPPRESET(Width) ) / 100;
OSDheight = (cOsd::OsdHeight() * TTSETUPPRESET(Height)) / 100;
// align with hChars/vLines
if ((OSDwidth % hChars) > 0) OSDwidth = (OSDwidth / hChars) * hChars;
if ((OSDheight % vLines) > 0) OSDheight = (OSDheight / vLines) * vLines;
if (TTSETUPPRESET(Width) < 100) {
if (TTSETUPPRESET(Left) > 0) {
// check offset not exceeding maximum possible
if ((TTSETUPPRESET(Width) + TTSETUPPRESET(Left)) > 100) {
// shift to maximum
x0 += cOsd::OsdWidth() - OSDwidth;
} else {
// add configured offset
x0 += (cOsd::OsdWidth() * TTSETUPPRESET(Left)) / 100;
// add 50% of alignment offset to center proper
x0 += ((cOsd::OsdWidth() * TTSETUPPRESET(Width)) / 100 - OSDwidth) / 2;
};
};
if (TTSETUPPRESET(Frame) > 0) {
OSDleftFrame = TTSETUPPRESET(Frame);
OSDrightFrame = TTSETUPPRESET(Frame);
x0 -= OSDleftFrame;
if (x0 < cOsd::OsdLeft()) {
OSDleftFrame += x0 - cOsd::OsdLeft();
x0 = cOsd::OsdLeft();
};
if (OSDleftFrame < 0) OSDleftFrame = 0;
if (x0 + OSDwidth + OSDrightFrame + OSDleftFrame > cOsd::OsdWidth() + cOsd::OsdLeft()) {
// limit right frame instead drawing out-of-area
OSDrightFrame = cOsd::OsdWidth() - OSDwidth - x0 - OSDleftFrame + cOsd::OsdLeft();
if (OSDrightFrame < 0) OSDrightFrame = 0;
};
};
} else {
// horizontal center with black frame left/right
OSDleftFrame = (cOsd::OsdWidth() - OSDwidth) / 2;
OSDrightFrame = cOsd::OsdWidth() - OSDwidth - OSDleftFrame;
if ((OSDleftFrame > 0) && (OSDleftFrame > TTSETUPPRESET(Frame))) {
x0 += OSDleftFrame - TTSETUPPRESET(Frame);
OSDleftFrame = TTSETUPPRESET(Frame);
};
if ((OSDrightFrame > 0) && (OSDrightFrame > TTSETUPPRESET(Frame))) {
OSDrightFrame = TTSETUPPRESET(Frame);
};
};
if (TTSETUPPRESET(Height) < 100) {
if (TTSETUPPRESET(Top) > 0) {
// check offset not exceeding maximum possible
if ((TTSETUPPRESET(Height) + TTSETUPPRESET(Top)) > 100) {
// shift to maximum
y0 += cOsd::OsdHeight() - OSDheight;
} else {
// add configured offset
y0 += (cOsd::OsdHeight() * TTSETUPPRESET(Top)) / 100;
// add 50% of alignment offset to center proper
y0 += ((cOsd::OsdHeight() * TTSETUPPRESET(Height)) / 100 - OSDheight) / 2;
};
};
if (TTSETUPPRESET(Frame) > 0) {
OSDtopFrame = TTSETUPPRESET(Frame);
OSDbottomFrame = TTSETUPPRESET(Frame);
y0 -= OSDtopFrame;
if (y0 < cOsd::OsdTop()) {
OSDtopFrame += y0 - cOsd::OsdTop();
y0 = cOsd::OsdTop();
};
if (OSDtopFrame < 0) OSDtopFrame = 0;
if (y0 + OSDheight + OSDtopFrame + OSDbottomFrame > cOsd::OsdHeight() + cOsd::OsdTop()) {
// limit bottom frame instead drawing out-of-area
OSDbottomFrame = cOsd::OsdHeight() - OSDheight - y0 - OSDtopFrame + cOsd::OsdTop();
if (OSDbottomFrame < 0) OSDbottomFrame = 0;
};
};
} else {
// vertical center with black frame top/bottom
OSDtopFrame = (cOsd::OsdHeight() - OSDheight) / 2;
OSDbottomFrame = cOsd::OsdHeight() - OSDheight - OSDtopFrame;
if ((OSDtopFrame > 0) && (OSDtopFrame > TTSETUPPRESET(Frame))) {
y0 += OSDtopFrame - TTSETUPPRESET(Frame);
OSDtopFrame = TTSETUPPRESET(Frame);
};
if ((OSDbottomFrame > 0) && (OSDbottomFrame > TTSETUPPRESET(Frame))) {
OSDbottomFrame = TTSETUPPRESET(Frame);
};
};
DEBUG_OT_AREA("osdteletext: OSD area calculated by percent values: OL=%d OT=%d OW=%d OH=%d OwP=%d%% OhP=%d%% OlP=%d%% OtP=%d%% OfPx=%d lineMode24=%d => x0=%d y0=%d Ow=%d Oh=%d OlF=%d OrF=%d OtF=%d ObF=%d"
, cOsd::OsdLeft(), cOsd::OsdTop(), cOsd::OsdWidth(), cOsd::OsdHeight()
, TTSETUPPRESET(Width), TTSETUPPRESET(Height), TTSETUPPRESET(Left), TTSETUPPRESET(Top)
, TTSETUPPRESET(Frame)
, ttSetup.lineMode24
, x0, y0
, OSDwidth, OSDheight
, OSDleftFrame, OSDrightFrame
, OSDtopFrame, OSDbottomFrame
);
switch (NewMode) {
case Display::Full:
// Need to re-initialize *display:
DEBUG_OT_DBFC("osdteletext: OSD 'full' Full->reinit display");
Delete();
// Try 32BPP display first:
display=new cDisplay32BPP(x0,y0,OSDwidth,OSDheight,OSDleftFrame,OSDrightFrame,OSDtopFrame,OSDbottomFrame,clrBackground);
break;
case Display::HalfUpper:
// Shortcut to switch from HalfUpper to HalfLower:
if (mode==Display::HalfLower) {
DEBUG_OT_DBFC("osdteletext: OSD 'half' shortcut HalfUpper->HalfLower");
// keep instance.
((cDisplay32BPPHalf*)display)->SetZoom(cDisplay::Zoom_Upper);
((cDisplay32BPPHalf*)display)->SetUpper(true);
((cDisplay32BPPHalf*)display)->SetTop(false);
break;
}
// Need to re-initialize *display:
DEBUG_OT_DBFC("osdteletext: OSD 'half' HalfUpper->reinit display");
Delete();
display=new cDisplay32BPPHalf(x0,y0,OSDwidth,OSDheight,OSDleftFrame,OSDrightFrame,OSDtopFrame,OSDbottomFrame,true,false,clrBackground);
((cDisplay32BPPHalf*)display)->SetZoom(cDisplay::Zoom_Upper);
break;
case Display::HalfUpperTop:
// Shortcut to switch from HalfUpperTop to HalfLowerTop:
if (mode==Display::HalfLowerTop) {
// keep instance.
((cDisplay32BPPHalf*)display)->SetZoom(cDisplay::Zoom_Upper);
((cDisplay32BPPHalf*)display)->SetUpper(true);
((cDisplay32BPPHalf*)display)->SetTop(true);
break;
}
// Need to re-initialize *display:
DEBUG_OT_DBFC("osdteletext: OSD 'half' HalfUpperTop->reinit display");
Delete();
display=new cDisplay32BPPHalf(x0,y0,OSDwidth,OSDheight,OSDleftFrame,OSDrightFrame,OSDtopFrame,OSDbottomFrame,true,true,clrBackground);
((cDisplay32BPPHalf*)display)->SetZoom(cDisplay::Zoom_Upper);
break;
case Display::HalfLower:
// Shortcut to switch from HalfUpper to HalfLower:
if (mode==Display::HalfUpper) {
DEBUG_OT_DBFC("osdteletext: OSD 'half' shortcut HalfLower->HalfUpper");
// keep instance.
((cDisplay32BPPHalf*)display)->SetZoom(cDisplay::Zoom_Lower);
((cDisplay32BPPHalf*)display)->SetUpper(false);
((cDisplay32BPPHalf*)display)->SetTop(false);
break;
}
// Need to re-initialize *display:
DEBUG_OT_DBFC("osdteletext: OSD 'half' HalfLower->reinit display");
Delete();
display=new cDisplay32BPPHalf(x0,y0,OSDwidth,OSDheight,OSDleftFrame,OSDrightFrame,OSDtopFrame,OSDbottomFrame,false,false,clrBackground);
((cDisplay32BPPHalf*)display)->SetZoom(cDisplay::Zoom_Lower);
break;
case Display::HalfLowerTop:
// Shortcut to switch from HalfUpperTop to HalfLowerTop:
if (mode==Display::HalfUpperTop) {
DEBUG_OT_DBFC("osdteletext: OSD 'half' shortcut HalfUpperTop->HalfLowerTop");
// keep instance.
((cDisplay32BPPHalf*)display)->SetZoom(cDisplay::Zoom_Lower);
((cDisplay32BPPHalf*)display)->SetUpper(false);
((cDisplay32BPPHalf*)display)->SetTop(true);
break;
}
// Need to re-initialize *display:
DEBUG_OT_DBFC("osdteletext: OSD 'half' HalfLowerTop->reinit display");
Delete();
display=new cDisplay32BPPHalf(x0,y0,OSDwidth,OSDheight,OSDleftFrame,OSDrightFrame,OSDtopFrame,OSDbottomFrame,false,true,clrBackground);
((cDisplay32BPPHalf*)display)->SetZoom(cDisplay::Zoom_Lower);
break;
}
mode=NewMode;
// If display is invalid, clean up immediately:
if (!display->Valid()) Delete();
}
void Display::ShowUpperHalf() {
// Enforce upper half of screen to be visible
if (GetZoom()==cDisplay::Zoom_Lower)
SetZoom(cDisplay::Zoom_Upper);
if (mode==HalfLower)
SetMode(HalfUpper);
}
cDisplay32BPP::cDisplay32BPP(int x0, int y0, int width, int height, int leftFrame, int rightFrame, int topFrame, int bottomFrame, tColor clrBackground)
: cDisplay(width,height) {
// 32BPP display for True Color OSD providers
osd = cOsdProvider::NewOsd(x0, y0);
if (!osd) return;
Background = clrBackground;
width=(width+1)&~1;
// Width has to end on byte boundary, so round up
int bpp = 32;
if (ttSetup.colorMode4bpp == true) {
bpp = 4;
dsyslog("osdteletext: OSD config forced to bpp=%d", bpp);
};
tArea Areas[] = { { 0, 0, width - 1 + leftFrame + rightFrame, height - 1 + topFrame + bottomFrame, bpp } };
if (bpp == 32 && (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk)) {
bpp = 8;
Areas[0].bpp = 8;
DEBUG_OT_AREA("osdteletext: OSD is not providing TrueColor, fallback to bpp=%d", bpp);
}
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) {
DELETENULL(osd);
esyslog("osdteletext: can't create requested OSD area with x0=%d y0=%d width=%d height=%d bpp=%d osdPreset=%d", x0, y0, width, height, bpp
, ttSetup.osdPreset
);
Skins.Message(mtError, "OSD-Teletext can't request OSD area, check plugin settings");
return;
}
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
setOutputWidth(width);
setOutputHeight(Height);
setLeftFrame(leftFrame);
setRightFrame(rightFrame);
setTopFrame(topFrame);
setBottomFrame(bottomFrame);
isyslog("osdteletext: OSD area successful requested with x0=%d y0=%d width=%d height=%d bpp=%d lF=%d rF=%d tF=%d bF=%d bg=0x%08x osdPreset=%d"
, x0, y0, width, height, bpp
, leftFrame, rightFrame, topFrame, bottomFrame
, clrBackground
, ttSetup.osdPreset
);
InitScaler();
CleanDisplay();
Dirty=true;
DirtyAll=true;
}
cDisplay32BPPHalf::cDisplay32BPPHalf(int x0, int y0, int width, int height, int leftFrame, int rightFrame, int topFrame, int bottomFrame, bool upper, bool top, tColor clrBackground)
: cDisplay(width,height), leftFrame(leftFrame)
, rightFrame(rightFrame), topFrame(topFrame), bottomFrame(bottomFrame)
, Upper(upper), Top(top), OsdX0(x0), OsdY0(y0)
{
osd=NULL;
Background = clrBackground;
// Redirect all real init work to method
InitOSD();
}
void cDisplay32BPPHalf::InitOSD() {
delete osd;
int x0 = OsdX0;
int height = Height / 2; // half heigth
int vLines = TT_DISPLAY_LINES;
if ((height % vLines) > 0) height = (height / vLines) * vLines; // alignment
int y0 = OsdY0;
if (!Top)
y0 += Height - height; // calculate y-offset
osd = cOsdProvider::NewOsd(x0, y0);
if (!osd) return;
int width=(Width+1)&~1; // Width has to end on byte boundary, so round up
int bpp = 32;
if (ttSetup.colorMode4bpp == true) {
bpp = 4;
dsyslog("osdteletext: OSD config forced to bpp=%d", bpp);
};
tArea Areas[] = { { 0, 0, width - 1 + leftFrame + rightFrame, height - 1 + topFrame + bottomFrame, bpp } };
if (bpp == 32 && (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk)) {
bpp = 8;
Areas[0].bpp = 8;
DEBUG_OT_AREA("osdteletext: OSD is not providing TrueColor, fallback to bpp=%d", bpp);
}
if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) {
DELETENULL(osd);
esyslog("osdteletext: can't create requested OSD 'half' area with x0=%d y0=%d width=%d height=%d bpp=%d", x0, y0, width, height, bpp);
Skins.Message(mtError, "OSD-Teletext can't request OSD 'half' area, check plugin settings");
return;
}
/*
// Try full-size area first
while (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) {
// Out of memory, so shrink
if (Upper) {
// Move up lower border
Areas[0].y2=Areas[0].y2-1;
} else {
// Move down upper border
Areas[0].y1=Areas[0].y1+1;
}
if (Areas[0].y1>Areas[0].y2) {
// Area is empty, fail miserably
DELETENULL(osd);
return;
}
}
// Add some backup
// CanHandleAreas is not accurate enough
if (Upper) {
Areas[0].y2=Areas[0].y2-10;
} else {
Areas[0].y1=Areas[0].y1+10;
}
*/
osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
isyslog("osdteletext: OSD 'half' area successful requested x0=%d y0=%d width=%d height=%d bpp=%d lF=%d rF=%d tF=%d bF=%d Upper=%s Top=%s"
, x0, y0, width, height, bpp
, leftFrame, rightFrame, topFrame, bottomFrame
, (Upper == true) ? "yes" : "no"
, (Top == true) ? "yes" : "no"
);
setOutputWidth(width);
setOutputHeight(height);
setLeftFrame(leftFrame);
setRightFrame(rightFrame);
setTopFrame(topFrame);
setBottomFrame(bottomFrame);
InitScaler();
// In case we switched on the fly, do a full redraw
CleanDisplay();
Dirty=true;
DirtyAll=true;
Flush();
}
// vim: ts=4 sw=4 et
|