vdr-plugin-softhddevice-drm-gles 1.5.9-20e15de
openglosd.cpp
Go to the documentation of this file.
1
25#include <algorithm>
26#include <cinttypes>
27#include <cstdio>
28#include <cstdlib>
29#include <vector>
30
31#ifdef GRIDPOINTS
32#include <string>
33#endif
34
35#include <sys/ioctl.h>
36
37#include <GLES2/gl2.h>
38#include <glm/glm.hpp>
39#include <glm/gtc/matrix_transform.hpp>
40#include <glm/gtc/type_ptr.hpp>
41
42#include <vdr/osd.h>
43
44#include "logger.h"
45#include "misc.h"
46#include "openglosd.h"
47#include "openglshader.h"
48#include "softhddevice.h"
49#include "videorender.h"
50
51// This maybe useful for skin developing and marks the rects of the single draws
52#ifdef GRIDPOINTS
53#define GRIDPOINTSTEXT 1
54#define GRIDRECT 1
55#define GRIDTEXT 0
56#define GRIDPOINTSIZE 3
57#define GRIDPOINTOFFSET 4
58#define GRIDPOINTSTXTSIZE 14
59#define GRIDPOINTBG clrTransparent
60#define GRIDPOINTCLR 0xFFFF0000
61#endif
62
63/****************************************************************************************
64 * Helpers
65 ***************************************************************************************/
66static void ConvertColor(const GLint &colARGB, glm::vec4 &col) {
67 col.a = ((colARGB & 0xFF000000) >> 24) / 255.0;
68 col.r = ((colARGB & 0x00FF0000) >> 16) / 255.0;
69 col.g = ((colARGB & 0x0000FF00) >> 8 ) / 255.0;
70 col.b = ((colARGB & 0x000000FF) ) / 255.0;
71}
72
73/****************************************************************************************
74 * cOglShader
75 ***************************************************************************************/
77
79{
80 GL_CHECK(glUseProgram(m_id));
81}
82
84{
85 const char *vertexCode = NULL;
86 const char *fragmentCode = NULL;
87
88 m_type = type;
89 switch (m_type) {
90 case stRect:
91 vertexCode = rectVertexShader;
92 fragmentCode = rectFragmentShader;
93 break;
94 case stTexture:
95 vertexCode = textureVertexShader;
96 fragmentCode = textureFragmentShader;
97 break;
98 case stTextureSwapBR:
99 vertexCode = textureVertexShader;
100 fragmentCode = textureFragmentShaderSwapBR;
101 break;
102 case stText:
103 vertexCode = textVertexShader;
104 fragmentCode = textFragmentShader;
105 break;
106 default:
107 LOGERROR("openglosd: %s: unknown shader type", __FUNCTION__);
108 break;
109 }
110
111 if (vertexCode == NULL || fragmentCode == NULL) {
112 LOGERROR("openglosd: %s: error reading shader", __FUNCTION__);
113 return false;
114 }
115
116 if (!Compile(vertexCode, fragmentCode)) {
117 LOGERROR("openglosd: %s: error compiling shader", __FUNCTION__);
118 return false;
119 }
120
121 return true;
122}
123
124void cOglShader::SetFloat(const GLchar *name, GLfloat value)
125{
126 GL_CHECK(glUniform1f(glGetUniformLocation(m_id, name), value));
127}
128
129void cOglShader::SetInteger(const GLchar *name, GLint value)
130{
131 GL_CHECK(glUniform1i(glGetUniformLocation(m_id, name), value));
132}
133
134void cOglShader::SetVector2f(const GLchar *name, GLfloat x, GLfloat y)
135{
136 GL_CHECK(glUniform2f(glGetUniformLocation(m_id, name), x, y));
137}
138
139void cOglShader::SetVector3f(const GLchar *name, GLfloat x, GLfloat y, GLfloat z)
140{
141 GL_CHECK(glUniform3f(glGetUniformLocation(m_id, name), x, y, z));
142}
143
144void cOglShader::SetVector4f(const GLchar *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
145{
146 GL_CHECK(glUniform4f(glGetUniformLocation(m_id, name), x, y, z, w));
147}
148
149void cOglShader::SetMatrix4(const GLchar *name, const glm::mat4 &matrix)
150{
151 GL_CHECK(glUniformMatrix4fv(glGetUniformLocation(m_id, name), 1, GL_FALSE, glm::value_ptr(matrix)));
152}
153
154bool cOglShader::Compile(const char *vertexCode, const char *fragmentCode)
155{
156 GLuint sVertex, sFragment;
157
158 // vertex shader
159 GL_CHECK(sVertex = glCreateShader(GL_VERTEX_SHADER));
160 GL_CHECK(glShaderSource(sVertex, 1, &vertexCode, NULL));
161 GL_CHECK(glCompileShader(sVertex));
162 if (!CheckCompileErrors(sVertex))
163 return false;
164
165 // fragment shader
166 GL_CHECK(sFragment = glCreateShader(GL_FRAGMENT_SHADER));
167 GL_CHECK(glShaderSource(sFragment, 1, &fragmentCode, NULL));
168 GL_CHECK(glCompileShader(sFragment));
169 if (!CheckCompileErrors(sFragment))
170 return false;
171
172 // link program
173 GL_CHECK(m_id = glCreateProgram());
174 GL_CHECK(glAttachShader(m_id, sVertex));
175 GL_CHECK(glAttachShader(m_id, sFragment));
176 GL_CHECK(glBindAttribLocation(m_id, 0, "position"));
177 GL_CHECK(glBindAttribLocation(m_id, 1, "texCoords"));
178 GL_CHECK(glLinkProgram(m_id));
179 if (!CheckCompileErrors(m_id, true))
180 return false;
181
182 // delete the shaders as they're linked into our program now and no longer necessary
183 GL_CHECK(glDeleteShader(sVertex));
184 GL_CHECK(glDeleteShader(sFragment));
185 return true;
186}
187
188bool cOglShader::CheckCompileErrors(GLuint object, bool program) {
189 GLint success;
190 GLchar infoLog[1024];
191 if (!program) {
192 GL_CHECK(glGetShaderiv(object, GL_COMPILE_STATUS, &success));
193 if (!success) {
194 GL_CHECK(glGetShaderInfoLog(object, 1024, NULL, infoLog));
195 LOGERROR("openglosd: %s: Compile-time error: Type: %d - %s", __FUNCTION__, m_type, infoLog);
196 return false;
197 }
198 } else {
199 GL_CHECK(glGetProgramiv(object, GL_LINK_STATUS, &success));
200 if (!success) {
201 GL_CHECK(glGetProgramInfoLog(object, 1024, NULL, infoLog));
202 LOGERROR("openglosd: %s: Link-time error: Type: %d - %s", __FUNCTION__, m_type, infoLog);
203 return false;
204 }
205 }
206 return true;
207}
208
209#define KERNING_UNKNOWN (-10000)
210/****************************************************************************************
211 * cOglGlyph
212 ***************************************************************************************/
213cOglGlyph::cOglGlyph(FT_ULong charCode, FT_BitmapGlyph ftGlyph)
214 : m_charCode(charCode),
215 m_bearingLeft(ftGlyph->left),
216 m_bearingTop(ftGlyph->top),
217 m_width(ftGlyph->bitmap.width),
218 m_height(ftGlyph->bitmap.rows),
219 m_pBuffer(ftGlyph->bitmap.buffer),
220 m_advanceX(ftGlyph->root.advance.x >> 16) // value in 1/2^16 pixel
221{
222}
223
225{
226 if (m_texture)
227 GL_CHECK(glDeleteTextures(1, &m_texture));
228}
229
230int cOglGlyph::GetKerningCache(FT_ULong prevSym)
231{
232 for (int i = m_pKerningCache.Size(); --i > 0; ) {
233 if (m_pKerningCache[i].prevSym == prevSym)
234 return m_pKerningCache[i].kerning;
235 }
236 return KERNING_UNKNOWN;
237}
238
239void cOglGlyph::SetKerningCache(FT_ULong prevSym, int kerning)
240{
241 m_pKerningCache.Append(tKerning(prevSym, kerning));
242}
243
245{
246 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture));
247}
248
250{
251 // Disable byte-alignment restriction
252 GL_CHECK(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
253 GL_CHECK(glGenTextures(1, &m_texture));
254 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture));
255
256 GL_CHECK(glTexImage2D(
257 GL_TEXTURE_2D,
258 0,
259 GL_LUMINANCE,
260 m_width,
261 m_height,
262 0,
263 GL_LUMINANCE,
264 GL_UNSIGNED_BYTE,
266 ));
267
268 // Set texture options
269 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
270 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
271 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
272 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
273 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
274 GL_CHECK(glPixelStorei(GL_UNPACK_ALIGNMENT, 4));
275}
276
277/****************************************************************************************
278 * cOglFontAtlas
279 ***************************************************************************************/
280cOglFontAtlas::cOglFontAtlas(FT_Face face, int height)
281{
282 int maxAtlasWidth;
283 GL_CHECK(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxAtlasWidth));
284
285 FT_Set_Pixel_Sizes(face, 0, height);
286 FT_GlyphSlot g = face->glyph;
287
288 int rowW = 0;
289 int rowH = 0;
290
291 // Find the minimum size for the texture holding all visible ASCII characters
292 for (int i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
293 if (FT_Load_Char(face, i, FT_LOAD_NO_BITMAP)) {
294 LOGDEBUG2(L_OPENGL, "openglosd: %s: Loading char %d failed!", __FUNCTION__, i);
295 continue;
296 }
297
298 // do some glyph manipulation
299 FT_Glyph ftGlyph;
300 FT_Stroker stroker;
301 if (FT_Stroker_New(g->library, &stroker)) {
302 LOGERROR("openglosd: %s: FT_Stroker_New error!", __FUNCTION__);
303 return;
304 }
305
306 float outlineWidth = 0.25f;
307 FT_Stroker_Set(stroker, (int)(outlineWidth * 64),
308 FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
309
310 if (FT_Get_Glyph(g, &ftGlyph)) {
311 LOGERROR("openglosd: %s: FT_Get_Glyph error!", __FUNCTION__);
312 return;
313 }
314
315 if (FT_Glyph_StrokeBorder(&ftGlyph, stroker, 0, 1)) {
316 LOGERROR("openglosd: %s: FT_Glyph_StrokeBoder error!", __FUNCTION__);
317 return;
318 }
319
320 FT_Stroker_Done(stroker);
321
322 if (FT_Glyph_To_Bitmap(&ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
323 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap error!", __FUNCTION__);
324 return;
325 }
326
327 FT_BitmapGlyph bGlyph = (FT_BitmapGlyph)ftGlyph;
328
329 if (rowW + bGlyph->bitmap.width + 1 >= (unsigned int)maxAtlasWidth) {
330 m_width = std::max(m_width, rowW);
331 m_height += rowH;
332 rowW = 0;
333 rowH = 0;
334 }
335 rowW += bGlyph->bitmap.width + 1;
336 rowH = std::max(rowH, (int)bGlyph->bitmap.rows);
337
338 FT_Done_Glyph(ftGlyph);
339 }
340
341 m_width = std::max(m_width, rowW);
342 m_height += rowH;
343
344 // Create a texture that will be used to hold all ASCII glyphs
345 GL_CHECK(glGenTextures(1, &m_texture));
346 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture));
347 LOGDEBUG2(L_OPENGL, "openglosd: %s: Try creating font atlas texture with w %d h %d (max %d)", __FUNCTION__, m_width, m_height, maxAtlasWidth);
348
349 GL_CHECK(glTexImage2D(
350 GL_TEXTURE_2D,
351 0,
352 GL_LUMINANCE,
353 m_width,
354 m_height,
355 0,
356 GL_LUMINANCE,
357 GL_UNSIGNED_BYTE,
358 0
359 ));
360
361 GL_CHECK(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
362 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
363 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
364 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
365 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
366
367 int offsetX = 0;
368 int offsetY = 0;
369
370 rowH = 0;
371
372 // Now do the real upload
373 for (FT_ULong i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
374 if (FT_Load_Char(face, i, FT_LOAD_NO_BITMAP)) {
375 LOGWARNING("openglosd: %s: Loading char %c failed!", __FUNCTION__, i);
376 continue;
377 }
378
379 // do some glyph manipulation
380 FT_Glyph ftGlyph;
381 FT_Stroker stroker;
382 if (FT_Stroker_New(g->library, &stroker)) {
383 LOGERROR("openglosd: %s: FT_Stroker_New error!", __FUNCTION__);
384 return;
385 }
386
387 float outlineWidth = 0.25f;
388 FT_Stroker_Set(stroker, (int)(outlineWidth * 64),
389 FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
390
391 if (FT_Get_Glyph(g, &ftGlyph)) {
392 LOGERROR("openglosd: %s: FT_Get_Glyph error!", __FUNCTION__);
393 return;
394 }
395
396 if (FT_Glyph_StrokeBorder(&ftGlyph, stroker, 0, 1)) {
397 LOGERROR("openglosd: %s: FT_Glyph_StrokeBoder error!", __FUNCTION__);
398 return;
399 }
400
401 FT_Stroker_Done(stroker);
402
403 if (FT_Glyph_To_Bitmap(&ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
404 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap error!", __FUNCTION__);
405 return;
406 }
407 FT_BitmapGlyph bGlyph = (FT_BitmapGlyph)ftGlyph;
408
409 // pushing the glyphs to the texture
410 if (offsetX + bGlyph->bitmap.width + 1 >= (unsigned int)maxAtlasWidth) {
411 offsetY += rowH;
412 rowH = 0;
413 offsetX = 0;
414 }
415
416 GL_CHECK(glTexSubImage2D(
417 GL_TEXTURE_2D,
418 0,
419 offsetX,
420 offsetY,
421 bGlyph->bitmap.width,
422 bGlyph->bitmap.rows,
423 GL_LUMINANCE,
424 GL_UNSIGNED_BYTE,
425 bGlyph->bitmap.buffer
426 ));
427
428 m_pGlyph[i - MIN_CHARCODE] = new cOglAtlasGlyph(i, bGlyph, offsetX / (float)m_width, offsetY / (float)m_height);
429 rowH = std::max(rowH, (int)bGlyph->bitmap.rows);
430 offsetX += bGlyph->bitmap.width + 1;
431
432 FT_Done_Glyph(ftGlyph);
433 }
434
435 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
436 LOGDEBUG2(L_OPENGL, "openglosd: %s: Created a %d x %d (%d kB) FontAtlas for fontsize %d, rowH %d, rowW %d",
437 __FUNCTION__, m_width, m_height, m_width * m_height / 1024, height, rowH, rowW);
438}
439
441 if (m_texture)
442 GL_CHECK(glDeleteTextures(1, &m_texture));
443
444 for (FT_ULong i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
445 if (m_pGlyph[i - MIN_CHARCODE]) {
446 delete m_pGlyph[i - MIN_CHARCODE];
447 m_pGlyph[i - MIN_CHARCODE] = nullptr;
448 }
449 }
450}
451
453 if (sym < MIN_CHARCODE || sym > MAX_CHARCODE)
454 return nullptr;
455
456 return m_pGlyph[sym - MIN_CHARCODE];
457}
458
460 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture));
461}
462
463/****************************************************************************************
464 * cOglFont
465 ***************************************************************************************/
466FT_Library cOglFont::s_ftLib = 0;
467cList<cOglFont> *cOglFont::s_pFonts = 0;
468bool cOglFont::s_initiated = false;
469
470cOglFont::cOglFont(const char *fontName, int charHeight)
471 : m_name(fontName),
472 m_size(charHeight)
473{
474 int error = FT_New_Face(s_ftLib, m_name, 0, &m_face);
475 if (error)
476 LOGERROR("openglosd: %s: failed to open %s!", __FUNCTION__, *m_name);
477
478 FT_ULong charcode;
479 FT_UInt gindex;
480 int count = 0;
481 int minIndex = 0;
482 int maxIndex = 0;
483
484 charcode = FT_Get_First_Char(m_face, &gindex);
485 minIndex = gindex;
486 maxIndex = gindex;
487 while (gindex != 0) {
488 count++;
489 charcode = FT_Get_Next_Char(m_face, charcode, &gindex);
490 minIndex = std::min(minIndex, (int)gindex);
491 maxIndex = std::max(maxIndex, (int)gindex);
492 }
493
494 FT_Set_Char_Size(m_face, 0, m_size * 64, 0, 0);
495 m_height = (m_face->size->metrics.ascender - m_face->size->metrics.descender + 63) / 64;
496 m_bottom = abs((m_face->size->metrics.descender - 63) / 64);
498 LOGDEBUG2(L_OPENGL, "openglosd: %s: Created new font: %s (%d) height: %d, bottom: %d - %d chars (%d - %d)", __FUNCTION__, m_name, m_size, m_height, m_bottom, count, minIndex, maxIndex);
499}
500
502{
503 delete m_pAtlas;
504 FT_Done_Face(m_face);
505}
506
507cOglFont *cOglFont::Get(const char *name, int charHeight)
508{
509 if (!s_pFonts)
510 Init();
511
512 cOglFont *font;
513 for (font = s_pFonts->First(); font; font = s_pFonts->Next(font))
514 if (!strcmp(font->Name(), name) && charHeight == font->Size()) {
515 return font;
516 }
517 font = new cOglFont(name, charHeight);
518 s_pFonts->Add(font);
519
520 return font;
521}
522
524{
525 if (FT_Init_FreeType(&s_ftLib)) {
526 LOGERROR("openglosd: %s: failed to initialize FreeType library!", __FUNCTION__);
527 return;
528 }
529 s_pFonts = new cList<cOglFont>;
530 s_initiated = true;
531}
532
534{
535 if (!s_initiated)
536 return;
537 delete s_pFonts;
538 s_pFonts = 0;
539 if (s_ftLib && FT_Done_FreeType(s_ftLib))
540 LOGERROR("openglosd: %s: failed to deinitialize FreeType library!", __FUNCTION__);
541
542 s_ftLib = 0;
543}
544
545cOglGlyph* cOglFont::Glyph(FT_ULong charCode) const
546{
547 // Non-breaking space:
548 if (charCode == 0xA0)
549 charCode = 0x20;
550
551 // Lookup in cache:
552 for (cOglGlyph *g = m_glyphCache.First(); g; g = m_glyphCache.Next(g)) {
553 if (g->CharCode() == charCode) {
554 return g;
555 }
556 }
557
558 FT_UInt glyphIndex = FT_Get_Char_Index(m_face, charCode);
559
560 FT_Int32 loadFlags = FT_LOAD_NO_BITMAP;
561 // Load glyph image into the slot (erase previous one):
562 int error = FT_Load_Glyph(m_face, glyphIndex, loadFlags);
563 if (error) {
564 LOGERROR("openglosd: %s: FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
565 return NULL;
566 }
567
568 FT_Glyph ftGlyph;
569 FT_Stroker stroker;
570 error = FT_Stroker_New(s_ftLib, &stroker);
571 if (error) {
572 LOGERROR("openglosd: %s: FT_Stroker_New FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
573 return NULL;
574 }
575 float outlineWidth = 0.25f;
576 FT_Stroker_Set(stroker, (int)(outlineWidth * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
577
578 error = FT_Get_Glyph(m_face->glyph, &ftGlyph);
579 if (error) {
580 LOGERROR("openglosd: %s: FT_Get_Glyph FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
581 return NULL;
582 }
583
584 error = FT_Glyph_StrokeBorder(&ftGlyph, stroker, 0, 1);
585 if (error) {
586 LOGERROR("openglosd: %s: FT_Glyph_StrokeBorder FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
587 return NULL;
588 }
589 FT_Stroker_Done(stroker);
590
591 error = FT_Glyph_To_Bitmap(&ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1);
592 if (error) {
593 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
594 return NULL;
595 }
596
597 cOglGlyph *glyph = new cOglGlyph(charCode, (FT_BitmapGlyph)ftGlyph);
598 glyph->LoadTexture();
599 m_glyphCache.Add(glyph);
600 FT_Done_Glyph(ftGlyph);
601
602 return glyph;
603}
604
605int cOglFont::Kerning(cOglGlyph *glyph, FT_ULong prevSym) const
606{
607 int kerning = 0;
608 if (glyph && prevSym) {
609 kerning = glyph->GetKerningCache(prevSym);
610 if (kerning == KERNING_UNKNOWN) {
611 FT_Vector delta;
612 FT_UInt glyphIndex = FT_Get_Char_Index(m_face, glyph->CharCode());
613 FT_UInt glyphIndexPrev = FT_Get_Char_Index(m_face, prevSym);
614 FT_Get_Kerning(m_face, glyphIndexPrev, glyphIndex, FT_KERNING_DEFAULT, &delta);
615 kerning = delta.x / 64;
616 glyph->SetKerningCache(prevSym, kerning);
617 }
618 }
619
620 return kerning;
621}
622
623/****************************************************************************************
624 * cOglFb
625 ***************************************************************************************/
626cOglFb::cOglFb(GLint width, GLint height, GLint viewPortWidth, GLint viewPortHeight)
627 : m_width(width),
628 m_height(height),
629 m_viewPortWidth(viewPortWidth),
630 m_viewPortHeight(viewPortHeight)
631{
633 m_scrollable = true;
634}
635
637{
638 if (m_texture)
639 GL_CHECK(glDeleteTextures(1, &m_texture));
640 if (m_framebuffer)
641 GL_CHECK(glDeleteFramebuffers(1, &m_framebuffer));
642}
643
644bool cOglFb::Init(void)
645{
646 GL_CHECK(glGenTextures(1, &m_texture));
647 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture));
648 GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
649 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
650 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
651 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
652 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
653 GL_CHECK(glGenFramebuffers(1, &m_framebuffer));
654 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer));
655
656 GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0));
657
658 GLenum fbstatus;
659 GL_CHECK(fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER));
660 if (fbstatus != GL_FRAMEBUFFER_COMPLETE) {
661 LOGERROR("openglosd: %s: Framebuffer is not complete!", __FUNCTION__);
662 return false;
663 }
664
665 m_initiated = true;
666 return true;
667}
668
669void cOglFb::Bind(void)
670{
671 if (!m_initiated)
672 Init();
673 GL_CHECK(glViewport(0, 0, m_width, m_height));
674 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer));
675}
676
678{
679 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
680 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
681}
682
684{
685 if (!m_initiated)
686 return false;
687 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture));
688 return true;
689}
690
691/****************************************************************************************
692 * cOglOutputFb
693 ***************************************************************************************/
695{
696 GL_CHECK(glGenTextures(1, &m_texture));
697 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_texture));
698 GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
699 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
700 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
701 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
702 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
703 GL_CHECK(glGenFramebuffers(1, &m_framebuffer));
704 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer));
705
706 GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0));
707
708 GLenum fbstatus;
709 GL_CHECK(fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER));
710 if (fbstatus != GL_FRAMEBUFFER_COMPLETE) {
711 LOGERROR("openglosd: %s: Framebuffer is not complete!", __FUNCTION__);
712 return false;
713 }
714
715 m_initiated = true;
716 return true;
717}
718
720{
721 GL_CHECK(glFinish());
722 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
723 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
724}
725
726/****************************************************************************************
727 * cOglVb
728 ***************************************************************************************/
730
731bool cOglVb::Init(void)
732{
733 switch (m_type) {
734 case vbTexture: // Texture VBO definition
735 m_sizeVertex1 = 2;
736 m_sizeVertex2 = 2;
737 m_numVertices = 6;
738 m_drawMode = GL_TRIANGLES;
740 break;
741 case vbTextureSwapBR: // Texture VBO definition, BR swapped
742 m_sizeVertex1 = 2;
743 m_sizeVertex2 = 2;
744 m_numVertices = 6;
745 m_drawMode = GL_TRIANGLES;
747 break;
748 case vbRect: // Rectangle VBO definition
749 m_sizeVertex1 = 2;
750 m_sizeVertex2 = 0;
751 m_numVertices = 4;
752 m_drawMode = GL_TRIANGLE_FAN;
754 break;
755 case vbEllipse: // Ellipse VBO definition
756 m_sizeVertex1 = 2;
757 m_sizeVertex2 = 0;
758 m_numVertices = 182;
759 m_drawMode = GL_TRIANGLE_FAN;
761 break;
762 case vbSlope: // Slope VBO definition
763 m_sizeVertex1 = 2;
764 m_sizeVertex2 = 0;
765 m_numVertices = 102;
766 m_drawMode = GL_TRIANGLE_FAN;
768 break;
769 case vbText: // Text VBO definition
770 m_sizeVertex1 = 2;
771 m_sizeVertex2 = 2;
772 m_numVertices = 6;
773 m_drawMode = GL_TRIANGLES;
775 break;
776 default:
777 break;
778 }
779
780 GL_CHECK(glGenBuffers(1, &m_vbo));
781 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_vbo));
782
783 GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (m_sizeVertex1 + m_sizeVertex2) * m_numVertices, NULL, GL_DYNAMIC_DRAW));
784
785 GL_CHECK(glEnableVertexAttribArray(m_positionLoc));
786 GL_CHECK(glVertexAttribPointer(m_positionLoc, m_sizeVertex1, GL_FLOAT, GL_FALSE, (m_sizeVertex1 + m_sizeVertex2) * sizeof(GLfloat), (GLvoid*)0));
787 if (m_sizeVertex2 > 0) {
788 GL_CHECK(glEnableVertexAttribArray(m_texCoordsLoc));
789 GL_CHECK(glVertexAttribPointer(m_texCoordsLoc, m_sizeVertex2, GL_FLOAT, GL_FALSE, (m_sizeVertex1 + m_sizeVertex2) * sizeof(GLfloat), (GLvoid*)(m_sizeVertex1 * sizeof(GLfloat))));
790 }
791
792 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
793
794 return true;
795}
796
797void cOglVb::Bind(void)
798{
799 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_vbo));
800 GL_CHECK(glEnableVertexAttribArray(m_positionLoc));
801 GL_CHECK(glVertexAttribPointer(m_positionLoc, m_sizeVertex1, GL_FLOAT, GL_FALSE, (m_sizeVertex1 + m_sizeVertex2) * sizeof(GLfloat), (GLvoid*)0));
802 if (m_sizeVertex2 > 0) {
803 GL_CHECK(glEnableVertexAttribArray(m_texCoordsLoc));
804 GL_CHECK(glVertexAttribPointer(m_texCoordsLoc, m_sizeVertex2, GL_FLOAT, GL_FALSE, (m_sizeVertex1 + m_sizeVertex2) * sizeof(GLfloat), (GLvoid*)(m_sizeVertex1 * sizeof(GLfloat))));
805 }
806}
807
809{
810 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
811}
812
814{
815 Shaders[m_shader]->Use();
816}
817
819{
820 GL_CHECK(glEnable(GL_BLEND));
821 GL_CHECK(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
822}
823
825{
826 GL_CHECK(glDisable(GL_BLEND));
827}
828
829void cOglVb::SetShaderColor(GLint color)
830{
831 glm::vec4 col;
832 ConvertColor(color, col);
833 Shaders[m_shader]->SetVector4f("inColor", col.r, col.g, col.b, col.a);
834}
835
837{
838 glm::vec4 col;
839 ConvertColor(color, col);
840 Shaders[m_shader]->SetVector4f("bColor", col.r, col.g, col.b, col.a);
841}
842
844{
845 Shaders[m_shader]->SetInteger("screenTexture", value);
846}
847
848void cOglVb::SetShaderAlpha(GLint alpha)
849{
850 Shaders[m_shader]->SetVector4f("alpha", 1.0f, 1.0f, 1.0f, (GLfloat)(alpha) / 255.0f);
851}
852
853void cOglVb::SetShaderProjectionMatrix(GLint width, GLint height)
854{
855 glm::mat4 projection = glm::ortho(0.0f, (GLfloat)width, (GLfloat)height, 0.0f, -1.0f, 1.0f);
856 Shaders[m_shader]->SetMatrix4("projection", projection);
857}
858
859void cOglVb::SetVertexSubData(GLfloat *vertices, int count)
860{
861 if (count == 0)
862 count = m_numVertices;
863 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_vbo));
864 GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * (m_sizeVertex1 + m_sizeVertex2) * count, vertices));
865 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
866}
867
868void cOglVb::SetVertexData(GLfloat *vertices, int count)
869{
870 if (count == 0)
871 count = m_numVertices;
872 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_vbo));
873 GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (m_sizeVertex1 + m_sizeVertex2) * count, vertices, GL_DYNAMIC_DRAW));
874 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
875}
876
877void cOglVb::DrawArrays(int count)
878{
879 if (count == 0)
880 count = m_numVertices;
881 GL_CHECK(glDrawArrays(m_drawMode, 0, count));
882}
883
884/****************************************************************************************
885 * cOpenGLCmd
886 ***************************************************************************************/
887
888//------------------ cOglCmdInitOutputFb --------------------
890{
891 bool ok = m_pOutputFramebuffer->Init();
893 return ok;
894}
895
896//------------------ cOglCmdInitFb --------------------------
898{
899 bool ok = m_pFramebuffer->Init();
901 if (m_wait)
902 m_wait->Signal();
903 return ok;
904}
905
906//------------------ cOglCmdDeleteFb ------------------------
908{
909 GL_CHECK(glFinish());
910 if (m_pFramebuffer)
911 delete m_pFramebuffer;
912 return true;
913}
914
915//------------------ cOglCmdRenderFbToBufferFb --------------
917{
918 GLfloat x1 = m_x; // left
919 GLfloat y1 = m_y; // top
920 GLfloat x2 = m_x + m_pFramebuffer->ViewportWidth(); // right
921 GLfloat y2 = m_y + m_pFramebuffer->ViewportHeight(); // bottom
922
923 GLfloat texX1 = m_drawPortX / (GLfloat)m_pFramebuffer->Width();
924 GLfloat texX2 = texX1 + 1.0f;
925 GLfloat texY1 = m_drawPortY / (GLfloat)m_pFramebuffer->Height();
926 GLfloat texY2 = texY1 + 1.0f;
927
928 if (m_pFramebuffer->Scrollable()) {
929 GLfloat pageHeight = (GLfloat)m_pFramebuffer->ViewportHeight() / (GLfloat)m_pFramebuffer->Height();
930 texX1 = abs(m_drawPortX) / (GLfloat)m_pFramebuffer->Width();
931 texY1 = 1.0f - pageHeight - abs(m_drawPortY) / (GLfloat)m_pFramebuffer->Height();
932 texX2 = texX1 + (GLfloat)m_pFramebuffer->ViewportWidth() / (GLfloat)m_pFramebuffer->Width();
933 texY2 = texY1 + pageHeight;
934 }
935
936 GLfloat quadVertices[] = {
937 // Pos // TexCoords
938 x1, y1, texX1, texY2, // left top
939 x1, y2, texX1, texY1, // left bottom
940 x2, y2, texX2, texY1, // right bottom
941
942 x1, y1, texX1, texY2, // left top
943 x2, y2, texX2, texY1, // right bottom
944 x2, y1, texX2, texY2 // right top
945 };
946
951
952 m_pBuffer->Bind();
954 return false;
955 if (!m_alphablending)
958 GL_CHECK(glEnable(GL_SCISSOR_TEST));
962 GL_CHECK(glDisable(GL_SCISSOR_TEST));
964
965 if (!m_alphablending)
967 m_pBuffer->Unbind();
968
969 return true;
970}
971
972//------------------ cOglCmdCopyBufferToOutputFb ------------
974{
975 GLfloat x1 = m_x;
976 GLfloat y1 = m_y;
977 GLfloat x2 = m_x + (GLfloat)m_pFramebuffer->Width();
978 GLfloat y2 = m_y + (GLfloat)m_pFramebuffer->Height();
979
980 GLfloat texX1 = 0.0f;
981 GLfloat texX2 = 1.0f;
982 GLfloat texY1 = 1.0f;
983 GLfloat texY2 = 0.0f;
984
985 GLfloat quadVertices[] = {
986 // Pos // TexCoords
987 x1, y1, texX1, texY1, //left top
988 x1, y2, texX1, texY2, //left bottom
989 x2, y2, texX2, texY2, //right bottom
990
991 x1, y1, texX1, texY1, //left top
992 x2, y2, texX2, texY2, //right bottom
993 x2, y1, texX2, texY1 //right top
994 };
995
1000
1002 GL_CHECK(glViewport(0, 0, m_pOutputFramebuffer->Width(), m_pOutputFramebuffer->Height()));
1004 return false;
1005
1010
1011 GL_CHECK(glFinish());
1012 // eglSwapBuffers and gbm_surface_lock_front_buffer in OsdDrawARGB()
1013 if (m_active)
1015 else
1017
1019
1020 return true;
1021}
1022
1023//------------------ cOglCmdFill ----------------------------
1025{
1026 glm::vec4 col;
1027 ConvertColor(m_color, col);
1029 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1030 GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
1032
1033 return true;
1034}
1035
1036//------------------ cOglCmdBufferFill ----------------------
1038{
1039 glm::vec4 col;
1040 ConvertColor(m_color, col);
1041 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1042 GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
1043
1044 return true;
1045}
1046
1047//------------------ cOglCmdDrawRectangle -------------------
1049{
1050 if (m_width <= 0 || m_height <= 0)
1051 return false;
1052
1053 GLfloat x1 = m_x;
1054 GLfloat y1 = m_y;
1055 GLfloat x2 = m_x + m_width;
1056 GLfloat y2 = m_y + m_height;
1057
1058 GLfloat vertices[] = {
1059 x1, y1, // left top
1060 x2, y1, // right top
1061 x2, y2, // right bottom
1062 x1, y2 // left bottom
1063 };
1064
1068
1077
1078 return true;
1079}
1080
1081//------------------ cOglCmdDrawEllipse ---------------------
1082// quadrants:
1083// 0 draws the entire ellipse
1084// 1..4 draws only the first, second, third or fourth quadrant, respectively
1085// 5..8 draws the right, top, left or bottom half, respectively
1086// -1..-4 draws the inverted part of the given quadrant
1087//-----------------------------------------------------------
1089{
1090 if (m_width <= 0 || m_height <= 0)
1091 return false;
1092
1093 int numVertices = 0;
1094 GLfloat *vertices = NULL;
1095
1096 switch (m_quadrants) {
1097 case 0:
1098 vertices = CreateVerticesFull(numVertices);
1099 break;
1100 case 1:
1101 case 2:
1102 case 3:
1103 case 4:
1104 case -1:
1105 case -2:
1106 case -3:
1107 case -4:
1108 vertices = CreateVerticesQuadrant(numVertices);
1109 break;
1110 case 5:
1111 case 6:
1112 case 7:
1113 case 8:
1114 vertices = CreateVerticesHalf(numVertices);
1115 break;
1116 default:
1117 break;
1118 }
1119
1123
1124 // not antialiased
1128 VertexBuffers[vbEllipse]->SetVertexSubData(vertices, numVertices);
1129 VertexBuffers[vbEllipse]->DrawArrays(numVertices);
1133
1134 delete[] vertices;
1135 return true;
1136}
1137
1139{
1140 int size = 364;
1141 numVertices = size/2;
1142 GLfloat radiusX = (GLfloat)m_width / 2;
1143 GLfloat radiusY = (GLfloat)m_height / 2;
1144 GLfloat *vertices = new GLfloat[size];
1145 vertices[0] = m_x + radiusX;
1146 vertices[1] = m_y + radiusY;
1147 for (int i=0; i <= 180; i++) {
1148 vertices[2 * i + 2] = m_x + radiusX + (GLfloat)cos(2 * i * M_PI / 180.0f) * radiusX;
1149 vertices[2 * i + 3] = m_y + radiusY - (GLfloat)sin(2 * i * M_PI / 180.0f) * radiusY;
1150 }
1151 return vertices;
1152}
1153
1155{
1156 int size = 94;
1157 numVertices = size / 2;
1158 GLfloat radiusX = (GLfloat)m_width;
1159 GLfloat radiusY = (GLfloat)m_height;
1160 GLint transX = 0;
1161 GLint transY = 0;
1162 GLint startAngle = 0;
1163 GLfloat *vertices = new GLfloat[size];
1164 switch (m_quadrants) {
1165 case 1:
1166 vertices[0] = m_x;
1167 vertices[1] = m_y + m_height;
1168 transY = radiusY;
1169 break;
1170 case 2:
1171 vertices[0] = m_x + m_width;
1172 vertices[1] = m_y + m_height;
1173 transX = radiusX;
1174 transY = radiusY;
1175 startAngle = 90;
1176 break;
1177 case 3:
1178 vertices[0] = m_x + m_width;
1179 vertices[1] = m_y;
1180 transX = radiusX;
1181 startAngle = 180;
1182 break;
1183 case 4:
1184 vertices[0] = m_x;
1185 vertices[1] = m_y;
1186 startAngle = 270;
1187 break;
1188 case -1:
1189 vertices[0] = m_x + m_width;
1190 vertices[1] = m_y;
1191 transY = radiusY;
1192 break;
1193 case -2:
1194 vertices[0] = m_x;
1195 vertices[1] = m_y;
1196 transX = radiusX;
1197 transY = radiusY;
1198 startAngle = 90;
1199 break;
1200 case -3:
1201 vertices[0] = m_x;
1202 vertices[1] = m_y + m_height;
1203 transX = radiusX;
1204 startAngle = 180;
1205 break;
1206 case -4:
1207 vertices[0] = m_x + m_width;
1208 vertices[1] = m_y + m_height;
1209 startAngle = 270;
1210 break;
1211 default:
1212 break;
1213 }
1214 for (int i = 0; i <= 45; i++) {
1215 vertices[2 * i + 2] = m_x + transX + (GLfloat)cos((2 * i + startAngle) * M_PI / 180.0f) * radiusX;
1216 vertices[2 * i + 3] = m_y + transY - (GLfloat)sin((2 * i + startAngle) * M_PI / 180.0f) * radiusY;
1217 }
1218 return vertices;
1219}
1220
1222{
1223 int size = 184;
1224 numVertices = size / 2;
1225 GLfloat radiusX = 0.0f;
1226 GLfloat radiusY = 0.0f;
1227 GLint transX = 0;
1228 GLint transY = 0;
1229 GLint startAngle = 0;
1230 GLfloat *vertices = new GLfloat[size];
1231 switch (m_quadrants) {
1232 case 5:
1233 radiusX = (GLfloat)m_width;
1234 radiusY = (GLfloat)m_height / 2;
1235 vertices[0] = m_x;
1236 vertices[1] = m_y + radiusY;
1237 startAngle = 270;
1238 transY = radiusY;
1239 break;
1240 case 6:
1241 radiusX = (GLfloat)m_width / 2;
1242 radiusY = (GLfloat)m_height;
1243 vertices[0] = m_x + radiusX;
1244 vertices[1] = m_y + radiusY;
1245 startAngle = 0;
1246 transX = radiusX;
1247 transY = radiusY;
1248 break;
1249 case 7:
1250 radiusX = (GLfloat)m_width;
1251 radiusY = (GLfloat)m_height / 2;
1252 vertices[0] = m_x + radiusX;
1253 vertices[1] = m_y + radiusY;
1254 startAngle = 90;
1255 transX = radiusX;
1256 transY = radiusY;
1257 break;
1258 case 8:
1259 radiusX = (GLfloat)m_width / 2;
1260 radiusY = (GLfloat)m_height;
1261 vertices[0] = m_x + radiusX;
1262 vertices[1] = m_y;
1263 startAngle = 180;
1264 transX = radiusX;
1265 break;
1266 default:
1267 break;
1268 }
1269 for (int i=0; i <= 90; i++) {
1270 vertices[2 * i + 2] = m_x + transX + (GLfloat)cos((2 * i + startAngle) * M_PI / 180.0f) * radiusX;
1271 vertices[2 * i + 3] = m_y + transY - (GLfloat)sin((2 * i + startAngle) * M_PI / 180.0f) * radiusY;
1272 }
1273 return vertices;
1274}
1275
1276//------------------ cOglCmdDrawSlope -----------------------
1277// type:
1278// 0: horizontal, rising, lower
1279// 1: horizontal, rising, upper
1280// 2: horizontal, falling, lower
1281// 3: horizontal, falling, upper
1282// 4: vertical, rising, lower
1283// 5: vertical, rising, upper
1284// 6: vertical, falling, lower
1285// 7: vertical, falling, upper
1286//-----------------------------------------------------------
1288{
1289 if (m_width <= 0 || m_height <= 0)
1290 return false;
1291
1292 bool falling = m_type & 0x02;
1293 bool vertical = m_type & 0x04;
1294
1295 int steps = 100;
1296 if (m_width < 100)
1297 steps = 25;
1298 int numVertices = steps + 2;
1299 GLfloat *vertices = new GLfloat[numVertices * 2];
1300
1301 switch (m_type) {
1302 case 0:
1303 case 4:
1304 vertices[0] = (GLfloat)(m_x + m_width);
1305 vertices[1] = (GLfloat)(m_y + m_height);
1306 break;
1307 case 1:
1308 case 5:
1309 vertices[0] = (GLfloat)m_x;
1310 vertices[1] = (GLfloat)m_y;
1311 break;
1312 case 2:
1313 case 6:
1314 vertices[0] = (GLfloat)m_x;
1315 vertices[1] = (GLfloat)(m_y + m_height);
1316 break;
1317 case 3:
1318 case 7:
1319 vertices[0] = (GLfloat)(m_x + m_width);
1320 vertices[1] = (GLfloat)m_y;
1321 break;
1322 default:
1323 vertices[0] = (GLfloat)(m_x);
1324 vertices[1] = (GLfloat)(m_y);
1325 break;
1326 }
1327
1328 for (int i = 0; i <= steps; i++) {
1329 GLfloat c = cos(i * M_PI / steps);
1330 if (falling)
1331 c = -c;
1332 if (vertical) {
1333 vertices[2 * i + 2] = (GLfloat)m_x + (GLfloat)m_width / 2.0f + (GLfloat)m_width * c / 2.0f;
1334 vertices[2 * i + 3] = (GLfloat)m_y + (GLfloat)i * ((GLfloat)m_height) / steps ;
1335 } else {
1336 vertices[2 * i + 2] = (GLfloat)m_x + (GLfloat)i * ((GLfloat)m_width) / steps ;
1337 vertices[2 * i + 3] = (GLfloat)m_y + (GLfloat)m_height / 2.0f + (GLfloat)m_height * c / 2.0f;
1338 }
1339 }
1340
1344
1345 // not antialiased
1349 VertexBuffers[vbSlope]->SetVertexSubData(vertices, numVertices);
1350 VertexBuffers[vbSlope]->DrawArrays(numVertices);
1354
1355 delete[] vertices;
1356 return true;
1357}
1358
1359//------------------ cOglCmdDrawText ------------------------
1361{
1363 if (!f)
1364 return false;
1365
1366 if (!m_length)
1367 return false;
1368
1372
1375
1376 int xGlyph = m_x;
1377 int yGlyph = m_y;
1378 int fontHeight = f->Height();
1379 int bottom = f->Bottom();
1380 FT_ULong sym = 0;
1381 FT_ULong prevSym = 0;
1382 int kerning = 0;
1383
1384 // Check, if we only have symbols, which are in our atlas
1385 int unknown_char = 0;
1386 for (int i = 0; m_pSymbols[i]; i++) {
1387 if ((m_pSymbols[i] < MIN_CHARCODE) || (m_pSymbols[i] > MAX_CHARCODE)) {
1388 if (m_pSymbols[i]) {
1389 unknown_char = m_pSymbols[i];
1390 break;
1391 }
1392 }
1393 }
1394
1395 if (!unknown_char) {
1396 cOglFontAtlas *fa = f->Atlas();
1397 std::vector<GLfloat> vertices;
1398 vertices.reserve( 4 * 6 * m_length);
1399
1400 for (int i = 0; m_pSymbols[i]; i++) {
1401 sym = m_pSymbols[i];
1402
1403 cOglAtlasGlyph *g;
1404 // Get the glyph from the font atlas for ASCII code MIN_CHARCODE-MAX_CHARCODE
1405 g = fa->GetGlyph(sym);
1406
1407 if (!g) {
1408 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1409 continue;
1410 }
1411
1412 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1413 break;
1414
1415 kerning = f->Kerning(g, prevSym);
1416 prevSym = sym;
1417
1418 GLfloat x2 = xGlyph + kerning + g->BearingLeft();
1419 GLfloat y2 = m_y + (fontHeight - bottom - g->BearingTop()); //top
1420 GLfloat w = g->Width();
1421 GLfloat h = g->Height();
1422
1423 vertices.push_back(x2);
1424 vertices.push_back(y2);
1425 vertices.push_back(g->OffsetX());
1426 vertices.push_back(g->OffsetY());
1427
1428 vertices.push_back(x2 + w);
1429 vertices.push_back(y2);
1430 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1431 vertices.push_back(g->OffsetY());
1432
1433 vertices.push_back(x2);
1434 vertices.push_back(y2 + h);
1435 vertices.push_back(g->OffsetX());
1436 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1437
1438 vertices.push_back(x2 + w);
1439 vertices.push_back(y2);
1440 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1441 vertices.push_back(g->OffsetY());
1442
1443 vertices.push_back(x2);
1444 vertices.push_back(y2 + h);
1445 vertices.push_back(g->OffsetX());
1446 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1447
1448 vertices.push_back(x2 + w);
1449 vertices.push_back(y2 + h);
1450 vertices.push_back(g->OffsetX() + g->Width() / (float)fa->Width());
1451 vertices.push_back(g->OffsetY() + g->Height() / (float)fa->Height());
1452
1453 xGlyph += kerning + g->AdvanceX();
1454 yGlyph += kerning + g->AdvanceY();
1455
1456
1457 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1458 break;
1459 }
1460
1461 fa->BindTexture();
1462 VertexBuffers[vbText]->SetVertexData(vertices.data(), (vertices.size() / 4));
1463 VertexBuffers[vbText]->DrawArrays(vertices.size() / 4);
1464 } else {
1465 LOGDEBUG2(L_OPENGL, "openglosd: %s: char %d is not on the texture atlas, use single draw", __FUNCTION__, unknown_char);
1466 for (int i = 0; m_pSymbols[i]; i++) {
1467 sym = m_pSymbols[i];
1468 cOglGlyph *g = f->Glyph(sym);
1469 if (!g) {
1470 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1471 continue;
1472 }
1473
1474 if ( m_limitX && xGlyph + g->AdvanceX() > m_limitX )
1475 break;
1476
1477 kerning = f->Kerning(g, prevSym);
1478 prevSym = sym;
1479
1480 GLfloat x1 = xGlyph + kerning + g->BearingLeft(); // left
1481 GLfloat y1 = m_y + (fontHeight - bottom - g->BearingTop()); // top
1482 GLfloat x2 = x1 + g->Width(); // right
1483 GLfloat y2 = y1 + g->Height(); // bottom
1484
1485 GLfloat vertices[] = {
1486 x1, y2, 0.0, 1.0, // left bottom
1487 x1, y1, 0.0, 0.0, // left top
1488 x2, y1, 1.0, 0.0, // right top
1489
1490 x1, y2, 0.0, 1.0, // left bottom
1491 x2, y1, 1.0, 0.0, // right top
1492 x2, y2, 1.0, 1.0 // right bottom
1493 };
1494
1495 g->BindTexture();
1498
1499 xGlyph += kerning + g->AdvanceX();
1500
1501 if ( xGlyph > m_pFramebuffer->Width() - 1 )
1502 break;
1503 }
1504 }
1505
1506 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
1509 return true;
1510}
1511
1512//------------------ cOglCmdDrawImage -----------------------
1514{
1515 if (m_width <= 0 || m_height <= 0)
1516 return false;
1517
1518 GLuint texture;
1519 GL_CHECK(glGenTextures(1, &texture));
1520 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
1521 GL_CHECK(glTexImage2D(
1522 GL_TEXTURE_2D,
1523 0,
1524 GL_RGBA,
1525 m_width,
1526 m_height,
1527 0,
1528 GL_RGBA,
1529 GL_UNSIGNED_BYTE,
1530 m_argb
1531 ));
1532 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
1533 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
1534 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
1535 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
1536 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
1537
1538 GLfloat x1 = m_x; // left
1539 GLfloat y1 = m_y; // top
1540 GLfloat x2 = m_x + m_width * m_scaleX; // right
1541 GLfloat y2 = m_y + m_height * m_scaleY; // bottom
1542
1543 GLfloat quadVertices[] = {
1544 x1, y2, 0.0, 1.0, // left bottom
1545 x1, y1, 0.0, 0.0, // left top
1546 x2, y1, 1.0, 0.0, // right top
1547
1548 x1, y2, 0.0, 1.0, // left bottom
1549 x2, y1, 1.0, 0.0, // right top
1550 x2, y2, 1.0, 1.0 // right bottom
1551 };
1552
1557
1559 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
1560 if (m_overlay)
1566 if (m_overlay)
1569 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
1570 GL_CHECK(glDeleteTextures(1, &texture));
1571
1572 return true;
1573}
1574
1575//------------------ cOglCmdDrawTexture ---------------------
1577{
1578 if (m_pImageRef->width <= 0 || m_pImageRef->height <= 0)
1579 return false;
1580
1581 GLfloat x1 = m_x; // top
1582 GLfloat y1 = m_y; // left
1583 GLfloat x2 = m_x + m_pImageRef->width * m_scaleX; // right
1584 GLfloat y2 = m_y + m_pImageRef->height * m_scaleY; // bottom
1585
1586 GLfloat quadVertices[] = {
1587 // Pos // TexCoords
1588 x1, y1, 0.0f, 0.0f, // left bottom
1589 x1, y2, 0.0f, 1.0f, // left top
1590 x2, y2, 1.0f, 1.0f, // right top
1591
1592 x1, y1, 0.0f, 0.0f, // left bottom
1593 x2, y2, 1.0f, 1.0f, // right top
1594 x2, y1, 1.0f, 0.0f // right bottom
1595 };
1596
1601
1603 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_pImageRef->texture));
1609
1610 return true;
1611}
1612
1613//------------------ cOglCmdStoreImage ----------------------
1615 GL_CHECK(glGenTextures(1, &m_pImageRef->texture));
1616 GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_pImageRef->texture));
1617 GL_CHECK(glTexImage2D(
1618 GL_TEXTURE_2D,
1619 0,
1620 GL_RGBA,
1621 m_pImageRef->width,
1622 m_pImageRef->height,
1623 0,
1624 GL_RGBA,
1625 GL_UNSIGNED_BYTE,
1626 m_pData
1627 ));
1628 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
1629 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
1630 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
1631 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
1632 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
1633 return true;
1634}
1635
1636//------------------ cOglCmdDropImage -----------------------
1638 if (m_pImageRef->texture != GL_NONE)
1639 GL_CHECK(glDeleteTextures(1, &m_pImageRef->texture));
1640 m_pWait->Signal();
1641 return true;
1642}
1643
1644/******************************************************************************
1645 * cOglThread
1646 *****************************************************************************/
1647cOglThread::cOglThread(cCondWait *startWait, int maxCacheSize, cSoftHdDevice *device)
1648 : cThread("oglThread"),
1649 m_startWait(startWait),
1650 m_maxCacheSize(maxCacheSize * 1024 * 1024),
1651 m_pRender(device->Render())
1652{
1653 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1654 m_imageCache[i].used = false;
1655 m_imageCache[i].texture = GL_NONE;
1656 m_imageCache[i].width = 0;
1657 m_imageCache[i].height = 0;
1658 }
1659
1660 Start();
1661}
1662
1664{
1665 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
1666 if (m_imageCache[i].used) {
1667 DropImageData(i);
1668 }
1669 }
1670 Cancel(2);
1671 m_stalled = false;
1672}
1673
1675{
1676 while (m_stalled)
1677 cCondWait::SleepMs(10);
1678
1679 bool doSignal = false;
1680 Lock();
1681 if (m_commands.size() == 0)
1682 doSignal = true;
1683 m_commands.push(cmd);
1684 Unlock();
1685
1686 if (m_commands.size() > OGL_CMDQUEUE_SIZE) {
1687 m_stalled = true;
1688 }
1689
1690 if (doSignal || m_stalled)
1691 m_wait.Signal();
1692}
1693
1694int cOglThread::StoreImage(const cImage &image)
1695{
1696 if (!m_maxCacheSize) {
1697 LOGERROR("openglosd: %s: cannot store image, no cache set", __FUNCTION__);
1698 return 0;
1699 }
1700
1701 if (image.Width() > m_maxTextureSize || image.Height() > m_maxTextureSize) {
1702 LOGERROR("openglosd: %s: cannot store image of %dpx x %dpx (maximum size is %dpx x %dpx) - falling back to cOsdProvider::StoreImageData()",
1703 __FUNCTION__, image.Width(), image.Height(), m_maxTextureSize, m_maxTextureSize);
1704 return 0;
1705 }
1706
1707 int imgSize = image.Width() * image.Height();
1708 int newMemUsed = imgSize * sizeof(tColor) + m_memCached;
1709 if (newMemUsed > m_maxCacheSize) {
1710 float cachedMB = m_memCached / 1024.0f / 1024.0f;
1711 float maxMB = m_maxCacheSize / 1024.0f / 1024.0f;
1712 LOGERROR("openglosd: %s: Maximum size for GPU cache reached. Used: %.2fMB Max: %.2fMB", __FUNCTION__, cachedMB, maxMB);
1713 return 0;
1714 }
1715
1716 int slot = GetFreeSlot();
1717 if (!slot)
1718 return 0;
1719
1720 tColor *argb = MALLOC(tColor, imgSize);
1721 if (!argb) {
1722 LOGERROR("openglosd: %s: memory allocation of %d kb for OSD image failed", __FUNCTION__, (int)(imgSize * sizeof(tColor) / 1024));
1723 ClearSlot(slot);
1724 slot = 0;
1725 return 0;
1726 }
1727
1728 memcpy(argb, image.Data(), sizeof(tColor) * imgSize);
1729
1730 sOglImage *imageRef = GetImageRef(slot);
1731 imageRef->width = image.Width();
1732 imageRef->height = image.Height();
1733 DoCmd(new cOglCmdStoreImage(imageRef, argb));
1734
1735 cTimeMs timer(5000);
1736 while (imageRef->used && imageRef->texture == 0 && !timer.TimedOut())
1737 cCondWait::SleepMs(2);
1738
1739 if (imageRef->texture == GL_NONE) {
1740 LOGERROR("openglosd: %s: failed to store OSD image texture! (%s)", __FUNCTION__, timer.TimedOut() ? "timed out" : "allocation failed");
1741 DropImageData(slot);
1742 slot = 0;
1743 }
1744
1745 m_memCached += imgSize * sizeof(tColor);
1746
1747 return slot;
1748}
1749
1751{
1752 Lock();
1753 int slot = 0;
1754 for (int i = 0; i < OGL_MAX_OSDIMAGES && !slot; i++) {
1755 if (!m_imageCache[i].used) {
1756 m_imageCache[i].used = true;
1757 slot = -i - 1;
1758 }
1759 }
1760 Unlock();
1761 return slot;
1762}
1763
1765{
1766 int i = -slot - 1;
1767 if (i >= 0 && i < OGL_MAX_OSDIMAGES) {
1768 Lock();
1769 m_imageCache[i].used = false;
1770 m_imageCache[i].texture = GL_NONE;
1771 m_imageCache[i].width = 0;
1772 m_imageCache[i].height = 0;
1773 Unlock();
1774 }
1775}
1776
1777sOglImage *cOglThread::GetImageRef(int slot)
1778{
1779 int i = -slot - 1;
1780 if (0 <= i && i < OGL_MAX_OSDIMAGES)
1781 return &m_imageCache[i];
1782 return 0;
1783}
1784
1785void cOglThread::DropImageData(int imageHandle)
1786{
1787 sOglImage *imageRef = GetImageRef(imageHandle);
1788 if (!imageRef)
1789 return;
1790 int imgSize = imageRef->width * imageRef->height * sizeof(tColor);
1791 m_memCached -= imgSize;
1792 cCondWait dropWait;
1793 DoCmd(new cOglCmdDropImage(imageRef, &dropWait));
1794 dropWait.Wait();
1795 ClearSlot(imageHandle);
1796}
1797
1799{
1800 if (!InitOpenGL()) {
1801 LOGERROR("openglosd: %s: Could not initiate OpenGL context", __FUNCTION__);
1802 Cleanup();
1803 m_startWait->Signal();
1804 return;
1805 }
1806
1807 if (!InitShaders()) {
1808 LOGERROR("openglosd: %s: Could not initiate shaders", __FUNCTION__);
1809 Cleanup();
1810 m_startWait->Signal();
1811 return;
1812 }
1813
1814 if (!InitVertexBuffers()) {
1815 LOGERROR("openglosd: %s: Vertex Buffers NOT initialized", __FUNCTION__);
1816 Cleanup();
1817 m_startWait->Signal();
1818 return;
1819 }
1820
1821 GL_CHECK(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize));
1822 LOGDEBUG2(L_OPENGL, "openglosd: %s: Maximum Pixmap size: %dx%dpx", __FUNCTION__, m_maxTextureSize, m_maxTextureSize);
1823
1824 //now Thread is ready to do his job
1825 m_startWait->Signal();
1826 m_stalled = false;
1827
1828 LOGINFO("OpenGL context initialized");
1829
1830 uint64_t startFlush = 0;
1831 uint64_t endFlush = 0;
1832 bool timeReset = false;
1833
1834 while(Running()) {
1835 if (m_commands.empty()) {
1836 m_wait.Wait(20);
1837 continue;
1838 }
1839
1840 Lock();
1841 cOglCmd* cmd = m_commands.front();
1842 m_commands.pop();
1843 Unlock();
1844
1845 uint64_t start = cTimeMs::Now();
1846 if (strcmp(cmd->Description(), "InitFramebuffer") == 0 || timeReset) {
1847 startFlush = cTimeMs::Now();
1848 timeReset = false;
1849 }
1850
1851 cmd->Execute();
1852 LOGDEBUG2(L_OPENGL_TIME_ALL, "openglosd: %s: \"%-*s\", %dms, %d commands left, time %" PRIu64 "",
1853 __FUNCTION__, 15, cmd->Description(), (int)(cTimeMs::Now() - start), (int)(m_commands.size()), cTimeMs::Now());
1854
1855 if (strcmp(cmd->Description(), "Copy buffer to OutputFramebuffer") == 0) {
1856 endFlush = cTimeMs::Now();
1857 timeReset = true;
1858 LOGDEBUG2(L_OPENGL_TIME, "openglosd: %s: OSD Flush %dms, time %" PRIu64 "", __FUNCTION__, (int)(endFlush - startFlush), cTimeMs::Now());
1859 }
1860 delete cmd;
1861 if (m_stalled && m_commands.size() < OGL_CMDQUEUE_SIZE / 2)
1862 m_stalled = false;
1863 }
1864
1865 LOGDEBUG2(L_OPENGL, "openglosd: %s: Cleaning up OpenGL stuff", __FUNCTION__);
1866 Cleanup();
1867 LOGDEBUG2(L_OPENGL, "openglosd: %s: OpenGL worker thread ended", __FUNCTION__);
1868}
1869
1871{
1872 EGL_CHECK(eglMakeCurrent(m_pRender->EglDisplay(), m_pRender->EglSurface(), m_pRender->EglSurface(), m_pRender->EglContext()));
1873}
1874
1876{
1877 EGL_CHECK(eglMakeCurrent(m_pRender->EglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1878}
1879
1881{
1882 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context", __FUNCTION__);
1883
1884 // Wait for the EGL context to be created
1885 while(!m_pRender->GlInitiated()) {
1886 LOGDEBUG2(L_OPENGL, "openglosd: %s: wait for EGL context", __FUNCTION__);
1887 usleep(20000);
1888 }
1889
1890 eglAcquireContext(); // eglMakeCurrent with new eglSurface
1891
1892 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Version: \"%s\"", glGetString(GL_VERSION)));
1893 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Vendor: \"%s\"", glGetString(GL_VENDOR)));
1894 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Extensions: \"%s\"", glGetString(GL_EXTENSIONS)));
1895 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Renderer: \"%s\"", glGetString(GL_RENDERER)));
1896
1898 GL_CHECK(glDisable(GL_DEPTH_TEST));
1899 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context done", __FUNCTION__);
1900
1901 return true;
1902}
1903
1905{
1906 for (int i = 0; i < stCount; i++) {
1907 cOglShader *shader = new cOglShader();
1908 if (!shader->Load((eShaderType)i))
1909 return false;
1910 Shaders[i] = shader;
1911 }
1912 LOGDEBUG2(L_OPENGL, "openglosd: %s: Shaders initialized", __FUNCTION__);
1913
1914 return true;
1915}
1916
1918{
1919 for (int i = 0; i < stCount; i++)
1920 delete Shaders[i];
1921}
1922
1924{
1925 for (int i = 0; i < vbCount; i++) {
1926 cOglVb *vb = new cOglVb(i);
1927 if (!vb->Init())
1928 return false;
1929 VertexBuffers[i] = vb;
1930 }
1931 LOGDEBUG2(L_OPENGL, "openglosd: %s: Vertex buffers initialized", __FUNCTION__);
1932
1933 return true;
1934}
1935
1937{
1938 for (int i=0; i < vbCount; i++) {
1939 delete VertexBuffers[i];
1940 }
1941}
1942
1951
1952/******************************************************************************
1953 * cOglPixmap
1954 *****************************************************************************/
1955cOglPixmap::cOglPixmap(std::shared_ptr<cOglThread> oglThread, int layer, const cRect &viewPort, const cRect &drawPort)
1956 : cPixmap(layer, viewPort, drawPort),
1957 m_pOglThread(oglThread)
1958{
1959 int width = drawPort.IsEmpty() ? viewPort.Width() : drawPort.Width();
1960 int height = drawPort.IsEmpty() ? viewPort.Height() : drawPort.Height();
1961
1962 if (width > m_pOglThread->MaxTextureSize() || height > m_pOglThread->MaxTextureSize()) {
1963 LOGWARNING("openglosd: %s: cannot allocate pixmap of %dpx x %dpx, clipped to %dpx x %dpx!", __FUNCTION__,
1964 width, height, std::min(width, m_pOglThread->MaxTextureSize()), std::min(height, m_pOglThread->MaxTextureSize()));
1965 width = std::min(width, m_pOglThread->MaxTextureSize());
1966 height = std::min(height, m_pOglThread->MaxTextureSize());
1967 }
1968
1969 m_pFramebuffer = new cOglFb(width, height, viewPort.Width(), viewPort.Height());
1970
1971#ifdef GRIDPOINTS
1972 // Creates a tiny font with height GRIDPOINTSTXTSIZE
1973 m_pTinyfont = cFont::CreateFont(Setup.FontOsd, GRIDPOINTSTXTSIZE);
1974#endif
1975}
1976
1978{
1979 if (!m_pOglThread->Active())
1980 return;
1981
1983#ifdef GRIDPOINTS
1984 delete m_pTinyfont;
1985#endif
1986}
1987
1988void cOglPixmap::MarkViewPortDirty(const cRect &rect)
1989{
1990 cPixmap::MarkViewPortDirty(rect);
1991 SetDirty();
1992}
1993
1995{
1996 cPixmap::SetClean();
1997 SetDirty(false);
1998}
1999
2001{
2002 cPixmap::SetLayer(layer);
2003 SetDirty();
2004}
2005
2007{
2008 alpha = constrain(alpha, ALPHA_TRANSPARENT, ALPHA_OPAQUE);
2009 if (alpha != cPixmap::Alpha()) {
2010 cPixmap::SetAlpha(alpha);
2011 SetDirty();
2012 }
2013}
2014
2015void cOglPixmap::SetTile(bool tile)
2016{
2017 cPixmap::SetTile(tile);
2018 SetDirty();
2019}
2020
2021void cOglPixmap::SetViewPort(const cRect &rect)
2022{
2023 cPixmap::SetViewPort(rect);
2024 SetDirty();
2025}
2026
2027void cOglPixmap::SetDrawPortPoint(const cPoint &point, bool dirty)
2028{
2029 cPixmap::SetDrawPortPoint(point, dirty);
2030 if (dirty)
2031 SetDirty();
2032}
2033
2035{
2036 if (!m_pOglThread->Active())
2037 return;
2038
2039 LOCK_PIXMAPS;
2040 m_pOglThread->DoCmd(new cOglCmdFill(m_pFramebuffer, clrTransparent));
2041 SetDirty();
2042 MarkDrawPortDirty(DrawPort());
2043}
2044
2045void cOglPixmap::Fill(tColor color)
2046{
2047 if (!m_pOglThread->Active())
2048 return;
2049
2050 LOCK_PIXMAPS;
2051 m_pOglThread->DoCmd(new cOglCmdFill(m_pFramebuffer, color));
2052 SetDirty();
2053 MarkDrawPortDirty(DrawPort());
2054}
2055
2056void cOglPixmap::DrawImage(const cPoint &point, const cImage &image)
2057{
2058 DrawScaledImage(point, image);
2059}
2060
2061void cOglPixmap::DrawImage(const cPoint &point, int imageHandle)
2062{
2063 DrawScaledImage(point, imageHandle);
2064}
2065
2066void cOglPixmap::DrawScaledImage(const cPoint &point, const cImage &image, double factorX, double factorY, __attribute__ ((unused)) bool antiAlias)
2067{
2068 if (!m_pOglThread->Active())
2069 return;
2070
2071 tColor *argb = MALLOC(tColor, image.Width() * image.Height());
2072 if (!argb)
2073 return;
2074 memcpy(argb, image.Data(), sizeof(tColor) * image.Width() * image.Height());
2075
2076 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, image.Width(), image.Height(), point.X(), point.Y(), true, factorX, factorY));
2077#ifdef GRIDRECT
2078 DrawGridRect(cRect(point.X(), point.Y(), image.Width() * factorX, image.Height() * factorY), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, m_pTinyfont);
2079#endif
2080 SetDirty();
2081 MarkDrawPortDirty(cRect(point, cSize(image.Width() * factorX, image.Height() * factorY)).Intersected(DrawPort().Size()));
2082}
2083
2084void cOglPixmap::DrawScaledImage(const cPoint &point, int imageHandle, double factorX, double factorY, __attribute__ ((unused)) bool antiAlias)
2085{
2086 if (!m_pOglThread->Active())
2087 return;
2088
2089 if (imageHandle < 0 && m_pOglThread->GetImageRef(imageHandle)) {
2090 sOglImage *img = m_pOglThread->GetImageRef(imageHandle);
2091 m_pOglThread->DoCmd(new cOglCmdDrawTexture(m_pFramebuffer, img, point.X(), point.Y(), factorX, factorY));
2092#ifdef GRIDRECT
2093 DrawGridRect(cRect(point.X(), point.Y(), img->width * factorX, img->height * factorY), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, m_pTinyfont);
2094#endif
2095 SetDirty();
2096 MarkDrawPortDirty(cRect(point, cSize(img->width * factorX, img->height * factorY)).Intersected(DrawPort().Size()));
2097 }
2098}
2099
2100void cOglPixmap::DrawPixel(const cPoint &point, tColor color)
2101{
2102 cRect r(point.X(), point.Y(), 1, 1);
2103 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), color));
2104#ifdef GRIDRECT
2105 DrawGridRect(cRect(r.X(), r.Y(), 0, 0), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, m_pTinyfont);
2106#endif
2107 SetDirty();
2108 MarkDrawPortDirty(r);
2109}
2110
2111void cOglPixmap::DrawBitmap(const cPoint &point, const cBitmap &bitmap, tColor colorFg, tColor colorBg, bool overlay)
2112{
2113 if (!m_pOglThread->Active())
2114 return;
2115
2116 LOCK_PIXMAPS;
2117 bool specialColors = colorFg || colorBg;
2118 tColor *argb = MALLOC(tColor, bitmap.Width() * bitmap.Height());
2119 if (!argb)
2120 return;
2121
2122 tColor *p = argb;
2123 for (int py = 0; py < bitmap.Height(); py++)
2124 for (int px = 0; px < bitmap.Width(); px++) {
2125 tIndex index = *bitmap.Data(px, py);
2126 *p++ = (!index && overlay) ? clrTransparent :
2127 (specialColors ? (index == 0 ? colorBg : index == 1 ? colorFg :
2128 bitmap.Color(index)) : bitmap.Color(index));
2129 }
2130
2131 m_pOglThread->DoCmd(new cOglCmdDrawImage(m_pFramebuffer, argb, bitmap.Width(), bitmap.Height(), point.X(), point.Y(), true));
2132#ifdef GRIDRECT
2133 DrawGridRect(cRect(point.X(), point.Y(), bitmap.Width(), bitmap.Height()), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, m_pTinyfont);
2134#endif
2135
2136 SetDirty();
2137 MarkDrawPortDirty(cRect(cPoint(point.X(), point.Y()), cSize(bitmap.Width(), bitmap.Height())).Intersected(DrawPort().Size()));
2138}
2139
2140void cOglPixmap::DrawText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2141{
2142 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, false);
2143}
2144
2145#ifdef GRIDPOINTS
2146void cOglPixmap::DrawGridText(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment)
2147{
2148 DrawTextInternal(point, s, colorFg, colorBg, font, width, height, alignment, true);
2149}
2150#endif
2151
2152void cOglPixmap::DrawTextInternal(const cPoint &point, const char *s, tColor colorFg, tColor colorBg, const cFont *font, int width, int height, int alignment, bool isGridText)
2153{
2154 if (!m_pOglThread->Active())
2155 return;
2156
2157 LOCK_PIXMAPS;
2158 int len = s ? Utf8StrLen(s) : 0;
2159 unsigned int *symbols = MALLOC(unsigned int, len + 1);
2160 if (!symbols)
2161 return;
2162
2163 if (len)
2164 Utf8ToArray(s, symbols, len + 1);
2165 else
2166 symbols[0] = 0;
2167
2168 int x = point.X();
2169 int y = point.Y();
2170 int w = font->Width(s);
2171 int h = font->Height();
2172 int limitX = 0;
2173 int cw = width ? width : w;
2174 int ch = height ? height : h;
2175
2176 // workaround for messages in SkinElchiHD
2177 if (width > ViewPort().Width() && !x && !isGridText)
2178 x = ViewPort().Width() - w;
2179
2180 cRect r(x, y, cw, ch);
2181
2182 if (colorBg != clrTransparent)
2183 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, r.X(), r.Y(), r.Width(), r.Height(), colorBg));
2184
2185 if (width || height)
2186 limitX = x + cw;
2187
2188 if (width) {
2189 if ((alignment & taLeft) != 0) {
2190 if ((alignment & taBorder) != 0)
2191 x += std::max(h / TEXT_ALIGN_BORDER, 1);
2192 } else if ((alignment & taRight) != 0) {
2193 if (w < width)
2194 x += width - w;
2195 if ((alignment & taBorder) != 0)
2196 x -= std::max(h / TEXT_ALIGN_BORDER, 1);
2197 } else { // taCentered
2198 if (w < width)
2199 x += (width - w) / 2;
2200 }
2201 }
2202
2203 if (height) {
2204 if ((alignment & taTop) != 0)
2205 ;
2206 else if ((alignment & taBottom) != 0) {
2207 if (h < height)
2208 y += height - h;
2209 } else { // taCentered
2210 if (h < height)
2211 y += (height - h) / 2;
2212 }
2213 }
2214
2215 m_pOglThread->DoCmd(new cOglCmdDrawText(m_pFramebuffer, x, y, symbols, limitX, font->FontName(), font->Size(), colorFg, len));
2216
2217#ifdef GRIDTEXT
2218 if (!isGridText)
2219 DrawGridRect(cRect(x, y, cw, ch), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, m_pTinyfont);
2220#endif
2221
2222 SetDirty();
2223 MarkDrawPortDirty(r);
2224}
2225
2226void cOglPixmap::DrawRectangle(const cRect &rect, tColor color)
2227{
2228 if (!m_pOglThread->Active())
2229 return;
2230
2231 LOCK_PIXMAPS;
2232 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color));
2233#ifdef GRIDRECT
2234 DrawGridRect(rect, GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, m_pTinyfont);
2235#endif
2236
2237 SetDirty();
2238 MarkDrawPortDirty(rect);
2239}
2240
2241void cOglPixmap::DrawEllipse(const cRect &rect, tColor color, int quadrants)
2242{
2243 if (!m_pOglThread->Active())
2244 return;
2245
2246 LOCK_PIXMAPS;
2247 m_pOglThread->DoCmd(new cOglCmdDrawEllipse(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, quadrants));
2248#ifdef GRIDRECT
2249 DrawGridRect(rect, GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, m_pTinyfont);
2250#endif
2251
2252 SetDirty();
2253 MarkDrawPortDirty(rect);
2254}
2255
2256void cOglPixmap::DrawSlope(const cRect &rect, tColor color, int type)
2257{
2258 if (!m_pOglThread->Active())
2259 return;
2260
2261 LOCK_PIXMAPS;
2262 m_pOglThread->DoCmd(new cOglCmdDrawSlope(m_pFramebuffer, rect.X(), rect.Y(), rect.Width(), rect.Height(), color, type));
2263#ifdef GRIDRECT
2264 DrawGridRect(rect, GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, m_pTinyfont);
2265#endif
2266
2267 SetDirty();
2268 MarkDrawPortDirty(rect);
2269}
2270
2271void cOglPixmap::Render(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2272{
2273 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, pixmap->ViewPort().X(), source.X(), dest.X());
2274}
2275
2276void cOglPixmap::Copy(const cPixmap *pixmap, const cRect &source, const cPoint &dest)
2277{
2278 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, pixmap->ViewPort().X(), source.X(), dest.X());
2279}
2280
2281void cOglPixmap::Scroll(const cPoint &dest, const cRect &source)
2282{
2283 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, source.X(), dest.X());
2284}
2285
2286void cOglPixmap::Pan(const cPoint &dest, const cRect &source)
2287{
2288 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, source.X(), dest.X());
2289}
2290
2291#ifdef GRIDPOINTS
2292void cOglPixmap::DrawGridRect(const cRect &rect, int offset, int size, tColor clr, tColor bg, const cFont *font)
2293{
2294 int x1 = rect.X() + offset;
2295 int x2 = rect.X() + rect.Width() + offset;
2296 int y1 = rect.Y();
2297 int y2 = rect.Y() + rect.Height();
2298 char p1[10];
2299 char p2[10];
2300 char p3[10];
2301 char p4[10];
2302 sprintf(p1, "%d.%d", x1, y1);
2303 sprintf(p2, "%d.%d", x2, y1);
2304 sprintf(p3, "%d.%d", x1, y2);
2305 sprintf(p4, "%d.%d", x2, y2);
2306
2307 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y1, size, size, clr));
2308#ifdef GRIDPOINTSTEXT
2309 DrawGridText(cPoint(x1, y1), p1, clr, bg, font);
2310#endif
2311 if (Rect.Width() && Rect.Height()) {
2312 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y1, size, size, clr));
2313 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x1, y2, size, size, clr));
2314 m_pOglThread->DoCmd(new cOglCmdDrawRectangle(m_pFramebuffer, x2, y2, size, size, clr));
2315#ifdef GRIDPOINTSTEXT
2316 DrawGridText(cPoint(x2, y1), p2, clr, bg, font);
2317 DrawGridText(cPoint(x1, y2), p3, clr, bg, font);
2318 DrawGridText(cPoint(x2, y2), p4, clr, bg, font);
2319#endif
2320 }
2321}
2322#endif
2323
2324/******************************************************************************
2325 * cOglOsd
2326 *****************************************************************************/
2328
2329cOglOsd::cOglOsd(int left, int top, uint level, std::shared_ptr<cOglThread> oglThread, cSoftHdDevice *device)
2330 : cOsd(left, top, level),
2331 m_pOglThread(oglThread),
2332 m_isSubtitleOsd(level == 10 ? true : false),
2333 m_pDevice(device)
2334{
2335 int osdWidth = 0;
2336 int osdHeight = 0;
2337 double pixelAspect;
2338 m_pDevice->GetOsdSize(osdWidth, osdHeight, pixelAspect);
2339 LOGDEBUG2(L_OSD, "openglosd: %s: New Osd %p osdLeft %d osdTop %d screenWidth %d screenHeight %d", __FUNCTION__, this, left, top, osdWidth, osdHeight);
2340
2341 m_maxPixmapSize.Set(m_pOglThread->MaxTextureSize(), m_pOglThread->MaxTextureSize());
2342
2343 if (!OutputFramebuffer) {
2344 OutputFramebuffer = new cOglOutputFb(osdWidth, osdHeight);
2346 }
2347}
2348
2350{
2351 if (!m_pOglThread->Active() || !Active() || !m_pBufferFramebuffer)
2352 return;
2353
2354 LOGDEBUG2(L_OSD, "openglosd: %s: Delete Osd %p", __FUNCTION__, this);
2355 m_pOglThread->DoCmd(new cOglCmdFill(m_pBufferFramebuffer, clrTransparent));
2356
2357 SetActive(false); // OsdClose() is done in cOglCmdCopyBufferToOutputFb()
2360}
2361
2362eOsdError cOglOsd::SetAreas(const tArea *areas, int numAreas)
2363{
2364 cRect r;
2365 if (numAreas > 1)
2366 m_isSubtitleOsd = true;
2367 for (int i = 0; i < numAreas; i++)
2368 r.Combine(cRect(areas[i].x1, areas[i].y1, areas[i].Width(), areas[i].Height()));
2369
2370 tArea area = { r.Left(), r.Top(), r.Right(), r.Bottom(), 32 };
2371
2372 // now we know the actual osd size, create double buffer frame buffer
2376 }
2377 m_pBufferFramebuffer = new cOglFb(r.Width(), r.Height(), r.Width(), r.Height());
2378 cCondWait initiated;
2379 m_pOglThread->DoCmd(new cOglCmdInitFb(m_pBufferFramebuffer, &initiated));
2380 initiated.Wait();
2381
2382 return cOsd::SetAreas(&area, 1);
2383}
2384
2385cPixmap *cOglOsd::CreatePixmap(int layer, const cRect &viewPort, const cRect &drawPort)
2386{
2387 if (!m_pOglThread->Active())
2388 return NULL;
2389
2390 LOCK_PIXMAPS;
2391 cOglPixmap *p = new cOglPixmap(m_pOglThread, layer, viewPort, drawPort);
2392 if (cOsd::AddPixmap(p)) {
2393 // find a free slot
2394 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2395 if (!m_pOglPixmaps[i])
2396 return m_pOglPixmaps[i] = p;
2397 }
2398 m_pOglPixmaps.Append(p);
2399 return p;
2400 }
2401 delete p;
2402
2403 return NULL;
2404}
2405
2406void cOglOsd::DestroyPixmap(cPixmap *Pixmap)
2407{
2408 if (!m_pOglThread->Active())
2409 return;
2410 if (!Pixmap)
2411 return;
2412
2413 LOCK_PIXMAPS;
2414 int start = 1;
2415 if (m_isSubtitleOsd)
2416 start = 0;
2417 for (int i = start; i < m_pOglPixmaps.Size(); i++) {
2418 if (m_pOglPixmaps[i] == Pixmap) {
2419 if (Pixmap->Layer() >= 0)
2420 m_pOglPixmaps[0]->MarkViewPortDirty(m_pOglPixmaps[i]->ViewPort());
2421
2422 m_pOglPixmaps[i] = NULL;
2423 if (i)
2424 cOsd::DestroyPixmap(Pixmap);
2425
2426 return;
2427 }
2428 }
2429}
2430
2432{
2433 if (!m_pOglThread->Active() || !Active())
2434 return;
2435
2436 LOGDEBUG2(L_OSD, "openglosd: %s: Flush Osd %p", __FUNCTION__, this);
2437 LOCK_PIXMAPS;
2438 // check for dirty areas
2439 m_pDirtyViewport.Set(0, 0, 0, 0);
2440 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2441 if (m_pOglPixmaps[i] && m_pOglPixmaps[i]->IsDirty()) {
2442 if (m_isSubtitleOsd)
2443 m_pDirtyViewport.Combine(m_pOglPixmaps[i]->DirtyViewPort().Size());
2444 else
2445 m_pDirtyViewport.Combine(m_pOglPixmaps[i]->DirtyViewPort());
2446
2447 m_pOglPixmaps[i]->SetClean();
2448 }
2449 }
2450
2451 if (m_pDirtyViewport.IsEmpty())
2452 return;
2453
2454 // clear private buffer within the dirty area
2456 m_pDirtyViewport.X(),
2457 m_pDirtyViewport.Y(),
2459 m_pDirtyViewport.Height(),
2460 clrTransparent));
2461
2462 // render pixmap textures blended to private buffer
2463 for (int layer = 0; layer < MAXPIXMAPLAYERS; layer++) {
2464 for (int i = 0; i < m_pOglPixmaps.Size(); i++) {
2465 if (!m_pOglPixmaps[i])
2466 continue;
2467
2468 if (m_pOglPixmaps[i]->Layer () != layer)
2469 continue;
2470
2471 if (m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort().Size()))
2472 continue;
2473
2474 if (!m_isSubtitleOsd && !m_pDirtyViewport.Intersects(m_pOglPixmaps[i]->ViewPort()))
2475 continue;
2476
2477 bool alphablending = layer == 0 ? false : true; // decide wether to render (with alpha) or copy a pixmap
2478 m_pOglThread->DoCmd(new cOglCmdRenderFbToBufferFb(m_pOglPixmaps[i]->Framebuffer(),
2480 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().X(),
2481 m_isSubtitleOsd ? 0 : m_pOglPixmaps[i]->ViewPort().Y(),
2482 m_pOglPixmaps[i]->Alpha(),
2483 m_pOglPixmaps[i]->DrawPort().X(),
2484 m_pOglPixmaps[i]->DrawPort().Y(),
2485 m_pDirtyViewport.X(),
2486 m_pDirtyViewport.Top(),
2487 m_pDirtyViewport.Width(),
2488 m_pDirtyViewport.Height(),
2489 alphablending,
2490 m_pDevice));
2491 }
2492 }
2493 // copy the private buffer to output framebuffer
2494 m_pOglThread->DoCmd(new cOglCmdBufferFill(OutputFramebuffer, clrTransparent));
2495
2497 Left() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().X() : 0),
2498 Top() + (m_isSubtitleOsd ? m_pOglPixmaps[0]->ViewPort().Y() : 0), 1, m_pDevice));
2499}
2500
2501void cOglOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias)
2502{
2503 if (!m_pOglPixmaps[0])
2504 return;
2505
2506 std::unique_ptr<cBitmap> scaledBitmap;
2507 const cBitmap *b = &Bitmap;
2508
2509 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0)) {
2510 scaledBitmap.reset(Bitmap.Scaled(FactorX, FactorY, AntiAlias));
2511 b = scaledBitmap.get();
2512 }
2513
2514 int xNew = x;
2515 int yNew = y;
2516
2517 const cRect &viewport = m_pOglPixmaps[0]->ViewPort();
2518 if (m_isSubtitleOsd && (x >= viewport.X()))
2519 xNew -= viewport.X();
2520 if (m_isSubtitleOsd && (y >= viewport.Y()))
2521 yNew -= viewport.Y();
2522
2523 m_pOglPixmaps[0]->DrawBitmap(cPoint(xNew, yNew), *b);
2524}
float OffsetY(void) const
Definition openglosd.h:156
int AdvanceY(void)
Definition openglosd.h:154
float OffsetX(void) const
Definition openglosd.h:155
virtual bool Execute(void)
cOglOutputFb * m_pOutputFramebuffer
Definition openglosd.h:429
virtual bool Execute(void)
cSoftHdDevice * m_pDevice
Definition openglosd.h:433
virtual bool Execute(void)
GLfloat * CreateVerticesFull(int &)
GLfloat * CreateVerticesHalf(int &)
GLfloat * CreateVerticesQuadrant(int &)
virtual bool Execute(void)
virtual bool Execute(void)
tColor * m_argb
Definition openglosd.h:571
virtual bool Execute(void)
virtual bool Execute(void)
cString m_fontName
Definition openglosd.h:548
unsigned int * m_pSymbols
Definition openglosd.h:550
virtual bool Execute(void)
virtual bool Execute(void)
sOglImage * m_pImageRef
Definition openglosd.h:593
sOglImage * m_pImageRef
Definition openglosd.h:625
cCondWait * m_pWait
Definition openglosd.h:626
virtual bool Execute(void)
GLint m_color
Definition openglosd.h:446
virtual bool Execute(void)
virtual bool Execute(void)
cCondWait * m_wait
Definition openglosd.h:366
cOglOutputFb * m_pOutputFramebuffer
Definition openglosd.h:353
virtual bool Execute(void)
virtual bool Execute(void)
sOglImage * m_pImageRef
Definition openglosd.h:610
virtual bool Execute(void)
cOglFb * m_pFramebuffer
Definition openglosd.h:340
virtual bool Execute(void)=0
virtual const char * Description(void)=0
GLint m_width
Definition openglosd.h:252
GLuint m_framebuffer
Definition openglosd.h:254
virtual void Unbind(void)
GLint ViewportHeight(void)
Definition openglosd.h:249
GLuint m_texture
Definition openglosd.h:255
void Bind(void)
GLint m_viewPortWidth
Definition openglosd.h:256
GLint Height(void)
Definition openglosd.h:246
cOglFb(GLint, GLint, GLint, GLint)
virtual ~cOglFb(void)
GLint ViewportWidth(void)
Definition openglosd.h:248
GLint Width(void)
Definition openglosd.h:245
bool m_scrollable
Definition openglosd.h:257
bool Scrollable(void)
Definition openglosd.h:247
GLint m_height
Definition openglosd.h:252
bool BindTexture(void)
GLint m_viewPortHeight
Definition openglosd.h:256
virtual bool Init(void)
bool m_initiated
Definition openglosd.h:251
GLuint m_texture
Definition openglosd.h:187
cOglFontAtlas(FT_Face, int)
int Width(void) const
Definition openglosd.h:184
cOglAtlasGlyph * GetGlyph(int) const
virtual ~cOglFontAtlas(void)
int Height(void) const
Definition openglosd.h:183
void BindTexture(void)
cOglAtlasGlyph * m_pGlyph[MAX_CHARCODE - MIN_CHARCODE+1]
Definition openglosd.h:190
int Height(void)
Definition openglosd.h:208
int m_size
Definition openglosd.h:217
cString m_name
Definition openglosd.h:216
static void Cleanup(void)
cOglFont(const char *, int)
cOglFontAtlas * Atlas(void)
Definition openglosd.h:203
cOglGlyph * Glyph(FT_ULong) const
int Bottom(void)
Definition openglosd.h:207
static void Init(void)
static cOglFont * Get(const char *, int)
virtual ~cOglFont(void)
FT_Face m_face
Definition openglosd.h:220
int Size(void)
Definition openglosd.h:206
cOglFontAtlas * m_pAtlas
Definition openglosd.h:222
int Kerning(cOglGlyph *glyph, FT_ULong prevSym) const
cList< cOglGlyph > m_glyphCache
Definition openglosd.h:221
int m_bottom
Definition openglosd.h:219
int m_height
Definition openglosd.h:218
static bool s_initiated
Definition openglosd.h:212
static FT_Library s_ftLib
Definition openglosd.h:213
const char * Name(void)
Definition openglosd.h:205
static cList< cOglFont > * s_pFonts
Definition openglosd.h:214
int AdvanceX(void)
Definition openglosd.h:110
void BindTexture(void)
GLuint m_texture
Definition openglosd.h:137
cOglGlyph(FT_ULong, FT_BitmapGlyph)
void LoadTexture(void)
unsigned char * m_pBuffer
Definition openglosd.h:134
int BearingTop(void) const
Definition openglosd.h:112
void SetKerningCache(FT_ULong, int)
int Height(void) const
Definition openglosd.h:114
virtual ~cOglGlyph()
int BearingLeft(void) const
Definition openglosd.h:111
int Width(void) const
Definition openglosd.h:113
FT_ULong CharCode(void)
Definition openglosd.h:109
int GetKerningCache(FT_ULong)
int m_height
Definition openglosd.h:133
cVector< tKerning > m_pKerningCache
Definition openglosd.h:136
int m_width
Definition openglosd.h:132
virtual ~cOglOsd()
std::shared_ptr< cOglThread > m_pOglThread
pointer to thread, which executes the commands
Definition openglosd.h:753
bool m_isSubtitleOsd
true, if this is a subtitle osd
Definition openglosd.h:755
cSoftHdDevice * m_pDevice
pointer to cSofthdDevice
Definition openglosd.h:758
cOglFb * m_pBufferFramebuffer
all pixmaps are composed onto this framebuffer after each other, before this one is blit onto the OSD...
Definition openglosd.h:751
static cOglOutputFb * OutputFramebuffer
main OSD output framebuffer - this keeps our finished "OSD" (one per OSD)
Definition openglosd.h:749
virtual void Flush(void)
virtual eOsdError SetAreas(const tArea *, int)
cRect m_pDirtyViewport
the dirty viewport
Definition openglosd.h:757
virtual void DrawScaledBitmap(int, int, const cBitmap &, double, double, bool AntiAlias=false)
virtual cPixmap * CreatePixmap(int, const cRect &, const cRect &DrawPort=cRect::Null)
cVector< cOglPixmap * > m_pOglPixmaps
array of pixmaps
Definition openglosd.h:754
cOglOsd(int, int, uint, std::shared_ptr< cOglThread >, cSoftHdDevice *)
cSize m_maxPixmapSize
maximum allowed size of a pixmap (depends on the maximum OpenGL texture size)
Definition openglosd.h:756
virtual void DestroyPixmap(cPixmap *)
GLuint m_framebuffer
Definition openglosd.h:273
virtual void Unbind(void)
GLuint m_texture
Definition openglosd.h:274
virtual bool Init(void)
virtual void Clear(void)
virtual void SetClean(void)
virtual void DrawRectangle(const cRect &, tColor)
virtual void Pan(const cPoint &, const cRect &Source=cRect::Null)
virtual void DrawPixel(const cPoint &, tColor)
void DrawTextInternal(const cPoint &, const char *, tColor, tColor, const cFont *, int Width=0, int Height=0, int Alignment=taDefault, bool isGridText=false)
virtual void DrawImage(const cPoint &, const cImage &)
virtual ~cOglPixmap(void)
cOglPixmap(std::shared_ptr< cOglThread >, int, const cRect &, const cRect &DrawPort=cRect::Null)
virtual void DrawSlope(const cRect &, tColor, int)
virtual void DrawText(const cPoint &, const char *, tColor, tColor, const cFont *, int Width=0, int Height=0, int Alignment=taDefault)
cOglFb * m_pFramebuffer
everything is drawn onto this framebuffer (one per pixmap)
Definition openglosd.h:719
std::shared_ptr< cOglThread > m_pOglThread
Definition openglosd.h:720
virtual void SetTile(bool)
virtual void SetDirty(bool dirty=true)
Definition openglosd.h:694
virtual void MarkViewPortDirty(const cRect &)
virtual void Scroll(const cPoint &, const cRect &Source=cRect::Null)
virtual void SetLayer(int)
virtual void Fill(tColor)
virtual void SetDrawPortPoint(const cPoint &, bool Dirty=true)
virtual void DrawBitmap(const cPoint &, const cBitmap &, tColor ColorFg=0, tColor ColorBg=0, bool Overlay=false)
virtual void Render(const cPixmap *, const cRect &, const cPoint &)
virtual void Copy(const cPixmap *, const cRect &, const cPoint &)
virtual void DrawEllipse(const cRect &, tColor, int Quadrants=0)
virtual void SetAlpha(int)
virtual void DrawScaledImage(const cPoint &, const cImage &, double FactorX=1.0f, double FactorY=1.0f, bool AntiAlias=false)
virtual void SetViewPort(const cRect &)
bool CheckCompileErrors(GLuint, bool program=false)
void SetMatrix4(const GLchar *, const glm::mat4 &)
void SetVector4f(const GLchar *, GLfloat, GLfloat, GLfloat, GLfloat)
void Use(void)
Definition openglosd.cpp:78
void SetFloat(const GLchar *, GLfloat)
void SetInteger(const GLchar *, GLint)
GLuint m_id
Definition openglosd.h:92
void SetVector3f(const GLchar *, GLfloat, GLfloat, GLfloat)
bool Load(eShaderType)
Definition openglosd.cpp:83
eShaderType m_type
Definition openglosd.h:91
bool Compile(const char *, const char *)
void SetVector2f(const GLchar *, GLfloat, GLfloat)
long m_memCached
Definition openglosd.h:663
void DoCmd(cOglCmd *)
long m_maxCacheSize
Definition openglosd.h:664
bool InitOpenGL(void)
bool InitVertexBuffers(void)
bool m_stalled
Definition openglosd.h:659
void eglReleaseContext(void)
sOglImage m_imageCache[OGL_MAX_OSDIMAGES]
Definition openglosd.h:662
int GetFreeSlot(void)
void Stop(void)
bool InitShaders(void)
cCondWait * m_startWait
Definition openglosd.h:657
cOglThread(cCondWait *startWait, int maxCacheSize, cSoftHdDevice *device)
cCondWait m_wait
Definition openglosd.h:658
void DropImageData(int)
void Cleanup(void)
void DeleteShaders(void)
virtual void Action(void)
void ClearSlot(int slot)
int StoreImage(const cImage &)
cVideoRender * m_pRender
Definition openglosd.h:665
sOglImage * GetImageRef(int)
GLint m_maxTextureSize
Definition openglosd.h:661
void DeleteVertexBuffers(void)
std::queue< cOglCmd * > m_commands
Definition openglosd.h:660
void eglAcquireContext(void)
int m_sizeVertex2
Definition openglosd.h:320
GLuint m_positionLoc
Definition openglosd.h:317
void EnableBlending(void)
eVertexBufferType m_type
Definition openglosd.h:313
int m_sizeVertex1
Definition openglosd.h:319
int m_numVertices
Definition openglosd.h:321
eShaderType m_shader
Definition openglosd.h:314
void SetShaderColor(GLint)
GLuint m_texCoordsLoc
Definition openglosd.h:318
void SetShaderTexture(GLint)
void DisableBlending(void)
void SetVertexSubData(GLfloat *, int count=0)
void Bind(void)
void SetShaderProjectionMatrix(GLint, GLint)
void SetVertexData(GLfloat *, int count=0)
void DrawArrays(int count=0)
void ActivateShader(void)
GLuint m_vbo
Definition openglosd.h:316
void SetShaderAlpha(GLint)
bool Init(void)
void Unbind(void)
void SetShaderBorderColor(GLint)
GLuint m_drawMode
Definition openglosd.h:322
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD pixmap.
virtual void GetOsdSize(int &, int &, double &)
Returns the width, height and aspect ratio the OSD.
void OsdClose(void)
Close the OSD.
Logger class header file.
#define LOGDEBUG2
Definition logger.h:45
#define L_OPENGL_TIME_ALL
Definition logger.h:64
#define LOGERROR
Definition logger.h:41
#define L_OPENGL_TIME
Definition logger.h:63
#define LOGWARNING
Definition logger.h:42
#define L_OPENGL
Definition logger.h:62
#define LOGINFO
Definition logger.h:43
#define L_OSD
Definition logger.h:56
Misc function header file.
static cOglVb * VertexBuffers[vbCount]
static void ConvertColor(const GLint &colARGB, glm::vec4 &col)
Definition openglosd.cpp:66
#define KERNING_UNKNOWN
static cOglShader * Shaders[stCount]
Definition openglosd.cpp:76
Osd class - hardware accelerated (OpenGL/ES) - header file.
#define OGL_MAX_OSDIMAGES
Definition openglosd.h:639
const char * message
Definition openglosd.h:40
#define MIN_CHARCODE
Definition openglosd.h:175
const struct @0 FT_Errors[]
int code
Definition openglosd.h:39
eShaderType
Definition openglosd.h:68
@ stText
Definition openglosd.h:72
@ stCount
Definition openglosd.h:73
@ stTextureSwapBR
Definition openglosd.h:71
@ stRect
Definition openglosd.h:69
@ stTexture
Definition openglosd.h:70
@ vbSlope
Definition openglosd.h:285
@ vbCount
Definition openglosd.h:289
@ vbText
Definition openglosd.h:288
@ vbTexture
Definition openglosd.h:286
@ vbEllipse
Definition openglosd.h:284
@ vbRect
Definition openglosd.h:283
@ vbTextureSwapBR
Definition openglosd.h:287
#define MAX_CHARCODE
Definition openglosd.h:176
#define OGL_CMDQUEUE_SIZE
Definition openglosd.h:640
Shader definitions for OpenGL osd class.
const char * textureFragmentShaderSwapBR
In difference to the textureFragmentShader this one does a blue/red color component swap.
const char * rectVertexShader
const char * textureFragmentShader
const char * rectFragmentShader
const char * textFragmentShader
const char * textureVertexShader
const char * textVertexShader
Device class header file.
Rendering class header file.