vdr-plugin-softhddevice-drm-gles 1.4.0
openglosd.cpp
Go to the documentation of this file.
1
25#define __STL_CONFIG_H
26#include <algorithm>
27#include "openglosd.h"
28#include "glhelpers.h"
29#include <inttypes.h>
30#include <assert.h>
31#include <stdio.h>
32#include <stdlib.h>
33#ifdef GRIDPOINTS
34#include <string>
35#endif
36#include <vector>
37#include <sys/ioctl.h>
38
39#include "logger.h"
40
41#ifdef WRITE_PNG
42#include <png.h>
43#endif
44
45// This is needed for the GLES2 GL_CLAMP_TO_BORDER workaround
46#define BORDERCOLOR 0x00000000
47
48// This maybe useful for skin developing
49#ifdef GRIDPOINTS
50#define GRIDPOINTSTEXT 1
51#define GRIDRECT 1
52#define GRIDTEXT 0
53#define GRIDPOINTSIZE 3
54#define GRIDPOINTOFFSET 4
55#define GRIDPOINTSTXTSIZE 14
56#define GRIDPOINTBG clrTransparent
57#define GRIDPOINTCLR 0xFFFF0000
58#endif
59
60/****************************************************************************************
61* Helpers
62****************************************************************************************/
63#ifdef WRITE_PNG
64static int writeImage(char* filename, int width, int height, void *buffer, char* title)
65{
66 int code;
67 FILE *fp;
68 png_structp png_ptr;
69 png_infop info_ptr;
70
71 // Open file for writing (binary mode)
72 fp = fopen(filename, "wb");
73 if (fp == NULL) {
74 LOGERROR("WritePng: Could not open file %s for writing", filename);
75 code = 1;
76 goto finalise;
77 }
78
79 // Initialize write structure
80 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
81 if (png_ptr == NULL) {
82 LOGERROR("WritePng: Could not allocate write struct");
83 code = 1;
84 goto finalise;
85 }
86
87 // Initialize info structure
88 info_ptr = png_create_info_struct(png_ptr);
89 if (info_ptr == NULL) {
90 LOGERROR("WritePng: Could not allocate info struct");
91 code = 1;
92 goto finalise;
93 }
94
95 // Setup Exception handling
96 if (setjmp(png_jmpbuf(png_ptr))) {
97 LOGERROR("WritePng: Error during png creation");
98 code = 1;
99 goto finalise;
100 }
101
102 png_init_io(png_ptr, fp);
103
104 // Write header (8 bit colour depth)
105 png_set_IHDR(png_ptr, info_ptr, width, height,
106 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
107 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
108
109 // Set title
110 if (title != NULL) {
111 png_text title_text;
112 title_text.compression = PNG_TEXT_COMPRESSION_NONE;
113 title_text.key = strdup("Title");
114 title_text.text = title;
115 png_set_text(png_ptr, info_ptr, &title_text, 1);
116 }
117
118 png_write_info(png_ptr, info_ptr);
119
120 // Write image data
121 int i;
122 for (i = height - 1; i >= 0; i--) {
123 png_write_row(png_ptr, (png_bytep)buffer + i * width * 4);
124 }
125
126 // End write
127 png_write_end(png_ptr, NULL);
128
129 code = 0;
130finalise:
131 if (fp != NULL) fclose(fp);
132 if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
133 if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
134
135 return code;
136}
137#endif
138
139#ifdef WRITE_PNG
140static void writePng(int x, int y, int w, int h, bool oFb) {
141 GL_CHECK(glFinish());
142 GLubyte result[w * h * 4];
143 static int scr_nr = 0;
144 char filename[40];
145
146 GLenum fbstatus;
147 GL_CHECK(fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER));
148 if(fbstatus != GL_FRAMEBUFFER_COMPLETE)
149 LOGERROR("WritePng: Framebuffer is not complete! %d", fbstatus);
150
151 GL_CHECK(glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, &result));
152 if (oFb) {
153 snprintf(filename, sizeof(filename), "/tmp/%03doFb.png", scr_nr++);
154 } else {
155 snprintf(filename, sizeof(filename), "/tmp/%03dbFb.png", scr_nr++);
156 }
157 writeImage(filename, w, h, &result, strdup("osd"));
158}
159#endif
160
161void ConvertColor(const GLint &colARGB, glm::vec4 &col) {
162 col.a = ((colARGB & 0xFF000000) >> 24) / 255.0;
163 col.r = ((colARGB & 0x00FF0000) >> 16) / 255.0;
164 col.g = ((colARGB & 0x0000FF00) >> 8 ) / 255.0;
165 col.b = ((colARGB & 0x000000FF) ) / 255.0;
166}
167
168/****************************************************************************************
169* cShader
170****************************************************************************************/
171const char *rectVertexShader =
172"#version 100 \n\
173\
174attribute vec2 position; \
175varying vec4 rectCol; \
176uniform vec4 inColor; \
177uniform mat4 projection; \
178\
179void main() \
180{ \
181 gl_Position = projection * vec4(position.x, position.y, 0.0, 1.0); \
182 rectCol = inColor; \
183} \
184";
185
187"#version 100 \n\
188precision mediump float; \
189varying vec4 rectCol; \
190\
191void main() \
192{ \
193 gl_FragColor = rectCol; \
194} \
195";
196
198"#version 100 \n\
199\
200attribute vec2 position; \
201attribute vec2 texCoords; \
202\
203varying vec2 TexCoords; \
204varying vec4 alphaValue;\
205varying vec4 bColorValue;\
206\
207uniform vec4 bColor; \
208uniform mat4 projection; \
209uniform vec4 alpha; \
210\
211void main() \
212{ \
213 gl_Position = projection * vec4(position.x, position.y, 0.0, 1.0); \
214 TexCoords = texCoords; \
215 alphaValue = alpha; \
216 bColorValue = bColor; \
217} \
218";
219
221"#version 100 \n\
222precision mediump float; \
223varying vec2 TexCoords; \
224varying vec4 alphaValue; \
225varying vec4 bColorValue; \
226\
227uniform sampler2D screenTexture; \
228\
229float clamp_to_border_factor (vec2 coords) \
230{ \
231 bvec2 out1 = greaterThan (coords, vec2 (1,1)); \
232 bvec2 out2 = lessThan (coords, vec2 (0,0)); \
233 bool do_clamp = (any (out1) || any (out2)); \
234 return float (!do_clamp); \
235} \
236\
237void main() \
238{ \
239 vec4 color = texture2D(screenTexture, TexCoords) * alphaValue; \
240 float f = clamp_to_border_factor (TexCoords); \
241 gl_FragColor = mix (bColorValue, color, f); \
242} \
243";
244
246"#version 100 \n\
247precision mediump float; \
248varying vec2 TexCoords; \
249varying vec4 alphaValue; \
250varying vec4 bColorValue; \
251\
252uniform sampler2D screenTexture; \
253\
254float clamp_to_border_factor (vec2 coords) \
255{ \
256 bvec2 out1 = greaterThan (coords, vec2 (1,1)); \
257 bvec2 out2 = lessThan (coords, vec2 (0,0)); \
258 bool do_clamp = (any (out1) || any (out2)); \
259 return float (!do_clamp); \
260} \
261\
262void main() \
263{ \
264 vec4 color = texture2D(screenTexture, TexCoords) * alphaValue; \
265 vec4 color_swapped = vec4(color.b, color.g, color.r, color.a); \
266 float f = clamp_to_border_factor (TexCoords); \
267 gl_FragColor = mix (bColorValue, color_swapped, f); \
268} \
269";
270
271const char *textVertexShader =
272"#version 100 \n\
273\
274attribute vec2 position; \
275attribute vec2 texCoords; \
276\
277varying vec2 TexCoords; \
278varying vec4 textColor; \
279\
280uniform mat4 projection; \
281uniform vec4 inColor; \
282\
283void main() \
284{ \
285 gl_Position = projection * vec4(position.x, position.y, 0.0, 1.0); \
286 TexCoords = texCoords; \
287 textColor = inColor; \
288} \
289";
290
292"#version 100 \n\
293precision mediump float; \
294varying vec2 TexCoords; \
295varying vec4 textColor; \
296\
297uniform sampler2D glyphTexture; \
298\
299void main() \
300{ \
301 vec4 sampled = vec4(1.0, 1.0, 1.0, texture2D(glyphTexture, TexCoords).r); \
302 gl_FragColor = textColor * sampled; \
303} \
304";
305
307
308void cShader::Use(void) {
309 GL_CHECK(glUseProgram(id));
310}
311
313 this->type = type;
314
315 const char *vertexCode = NULL;
316 const char *fragmentCode = NULL;
317
318 switch (type) {
319 case stRect:
320 vertexCode = rectVertexShader;
321 fragmentCode = rectFragmentShader;
322 break;
323 case stTexture:
324 vertexCode = textureVertexShader;
325 fragmentCode = textureFragmentShader;
326 break;
327 case stTextureSwapBR:
328 vertexCode = textureVertexShader;
329 fragmentCode = textureFragmentShaderSwapBR;
330 break;
331 case stText:
332 vertexCode = textVertexShader;
333 fragmentCode = textFragmentShader;
334 break;
335 default:
336 LOGERROR("openglosd: %s: unknown shader type", __FUNCTION__);
337 break;
338 }
339
340 if (vertexCode == NULL || fragmentCode == NULL) {
341 LOGERROR("openglosd: %s: error reading shader", __FUNCTION__);
342 return false;
343 }
344
345 if (!Compile(vertexCode, fragmentCode)) {
346 LOGERROR("openglosd: %s: error compiling shader", __FUNCTION__);
347 return false;
348 }
349 return true;
350}
351
352void cShader::SetFloat(const GLchar *name, GLfloat value) {
353 GL_CHECK(glUniform1f(glGetUniformLocation(id, name), value));
354}
355
356void cShader::SetInteger(const GLchar *name, GLint value) {
357 GL_CHECK(glUniform1i(glGetUniformLocation(id, name), value));
358}
359
360void cShader::SetVector2f(const GLchar *name, GLfloat x, GLfloat y) {
361 GL_CHECK(glUniform2f(glGetUniformLocation(id, name), x, y));
362}
363
364void cShader::SetVector3f(const GLchar *name, GLfloat x, GLfloat y, GLfloat z) {
365 GL_CHECK(glUniform3f(glGetUniformLocation(id, name), x, y, z));
366}
367
368void cShader::SetVector4f(const GLchar *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
369 GL_CHECK(glUniform4f(glGetUniformLocation(id, name), x, y, z, w));
370}
371
372void cShader::SetMatrix4(const GLchar *name, const glm::mat4 &matrix) {
373 GL_CHECK(glUniformMatrix4fv(glGetUniformLocation(id, name), 1, GL_FALSE, glm::value_ptr(matrix)));
374}
375
376bool cShader::Compile(const char *vertexCode, const char *fragmentCode) {
377 GLuint sVertex, sFragment;
378 // Vertex Shader
379 GL_CHECK(sVertex = glCreateShader(GL_VERTEX_SHADER));
380 GL_CHECK(glShaderSource(sVertex, 1, &vertexCode, NULL));
381 GL_CHECK(glCompileShader(sVertex));
382 if (!CheckCompileErrors(sVertex))
383 return false;
384 // Fragment Shader
385 GL_CHECK(sFragment = glCreateShader(GL_FRAGMENT_SHADER));
386 GL_CHECK(glShaderSource(sFragment, 1, &fragmentCode, NULL));
387 GL_CHECK(glCompileShader(sFragment));
388 if (!CheckCompileErrors(sFragment))
389 return false;
390 // link Program
391 GL_CHECK(id = glCreateProgram());
392 GL_CHECK(glAttachShader(id, sVertex));
393 GL_CHECK(glAttachShader(id, sFragment));
394 GL_CHECK(glBindAttribLocation(id, 0, "position"));
395 GL_CHECK(glBindAttribLocation(id, 1, "texCoords"));
396 GL_CHECK(glLinkProgram(id));
397 if (!CheckCompileErrors(id, true))
398 return false;
399 // Delete the shaders as they're linked into our program now and no longer necessery
400 GL_CHECK(glDeleteShader(sVertex));
401 GL_CHECK(glDeleteShader(sFragment));
402 return true;
403}
404
405bool cShader::CheckCompileErrors(GLuint object, bool program) {
406 GLint success;
407 GLchar infoLog[1024];
408 if (!program) {
409 GL_CHECK(glGetShaderiv(object, GL_COMPILE_STATUS, &success));
410 if (!success) {
411 GL_CHECK(glGetShaderInfoLog(object, 1024, NULL, infoLog));
412 LOGERROR("openglosd: %s: Compile-time error: Type: %d - %s", __FUNCTION__, type, infoLog);
413 return false;
414 }
415 } else {
416 GL_CHECK(glGetProgramiv(object, GL_LINK_STATUS, &success));
417 if (!success) {
418 GL_CHECK(glGetProgramInfoLog(object, 1024, NULL, infoLog));
419 LOGERROR("openglosd: %s: Link-time error: Type: %d - %s", __FUNCTION__, type, infoLog);
420 return false;
421 }
422 }
423 return true;
424}
425
426#define KERNING_UNKNOWN (-10000)
427/****************************************************************************************
428* cOglGlyph
429****************************************************************************************/
430cOglGlyph::cOglGlyph(FT_ULong charCode, FT_BitmapGlyph ftGlyph) {
431 this->charCode = charCode;
432 bearingLeft = ftGlyph->left;
433 bearingTop = ftGlyph->top;
434 width = ftGlyph->bitmap.width;
435 height = ftGlyph->bitmap.rows;
436 advanceX = ftGlyph->root.advance.x >> 16; //value in 1/2^16 pixel
437 LoadTexture(ftGlyph);
438}
439
441 if (texture)
442 GL_CHECK(glDeleteTextures(1, &texture));
443}
444
445int cOglGlyph::GetKerningCache(FT_ULong prevSym) {
446 for (int i = kerningCache.Size(); --i > 0; ) {
447 if (kerningCache[i].prevSym == prevSym)
448 return kerningCache[i].kerning;
449 }
450 return KERNING_UNKNOWN;
451}
452
453void cOglGlyph::SetKerningCache(FT_ULong prevSym, int kerning) {
454 kerningCache.Append(tKerning(prevSym, kerning));
455}
456
458 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
459}
460
461void cOglGlyph::LoadTexture(FT_BitmapGlyph ftGlyph) {
462 // Disable byte-alignment restriction
463 GL_CHECK(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
464 GL_CHECK(glGenTextures(1, &texture));
465 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
466
467 GL_CHECK(glTexImage2D(
468 GL_TEXTURE_2D,
469 0,
470 GL_LUMINANCE,
471 ftGlyph->bitmap.width,
472 ftGlyph->bitmap.rows,
473 0,
474 GL_LUMINANCE,
475 GL_UNSIGNED_BYTE,
476 ftGlyph->bitmap.buffer
477 ));
478
479 // Set texture options
480 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
481 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
482 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
483 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
484 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
485 GL_CHECK(glPixelStorei(GL_UNPACK_ALIGNMENT, 4));
486}
487
488
489/****************************************************************************************
490* cOglAtlasGlyph
491****************************************************************************************/
492cOglAtlasGlyph::cOglAtlasGlyph(FT_ULong charCode, float advanceX, float advanceY,
493 float width, float height,
494 float bearingLeft, float bearingTop,
495 float xoffset, float yoffset) {
496 this->charCode = charCode;
497 this->bearingLeft = bearingLeft;
498 this->bearingTop = bearingTop;
499 this->width = width;
500 this->height = height;
501 this->advanceX = advanceX; //value in 1/2^16 pixel
502 this->advanceY = advanceY; //value in 1/2^16 pixel
503 this->xoffset = xoffset;
504 this->yoffset = yoffset;
505}
506
508
509}
510
511int cOglAtlasGlyph::GetKerningCache(FT_ULong prevSym) {
512 for (int i = kerningCache.Size(); --i > 0; ) {
513 if (kerningCache[i].prevSym == prevSym)
514 return kerningCache[i].kerning;
515 }
516 return KERNING_UNKNOWN;
517}
518
519void cOglAtlasGlyph::SetKerningCache(FT_ULong prevSym, int kerning) {
520 kerningCache.Append(tKerning(prevSym, kerning));
521}
522
523/****************************************************************************************
524* cOglFontAtlas
525****************************************************************************************/
526cOglFontAtlas::cOglFontAtlas(FT_Face face, int height) {
527 this->fontheight = height;
528 int max_atlas_width;
529 GL_CHECK(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_atlas_width));
530
531 FT_Set_Pixel_Sizes(face, 0, height);
532 FT_GlyphSlot g = face->glyph;
533
534 int roww = 0;
535 int rowh = 0;
536 w = 0;
537 h = 0;
538
539 /* Find the minimum size for the texture holding all visible ASCII characters */
540 for (int i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
541 if (FT_Load_Char(face, i, FT_LOAD_NO_BITMAP)) {
542 LOGDEBUG2(L_OPENGL, "openglosd: %s: Loading char %d failed!", __FUNCTION__, i);
543 continue;
544 }
545
546 // do some glyph manipulation
547 FT_Glyph ftGlyph;
548 FT_Stroker stroker;
549 if (FT_Stroker_New(g->library, &stroker)) {
550 LOGERROR("openglosd: %s: FT_Stroker_New error!", __FUNCTION__);
551 return;
552 }
553
554 float outlineWidth = 0.25f;
555 FT_Stroker_Set(stroker, (int)(outlineWidth * 64),
556 FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
557
558 if (FT_Get_Glyph(g, &ftGlyph)) {
559 LOGERROR("openglosd: %s: FT_Get_Glyph error!", __FUNCTION__);
560 return;
561 }
562
563 if (FT_Glyph_StrokeBorder(&ftGlyph, stroker, 0, 1)) {
564 LOGERROR("openglosd: %s: FT_Glyph_StrokeBoder error!", __FUNCTION__);
565 return;
566 }
567
568 FT_Stroker_Done(stroker);
569
570 if (FT_Glyph_To_Bitmap(&ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
571 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap error!", __FUNCTION__);
572 return;
573 }
574
575 FT_BitmapGlyph bGlyph = (FT_BitmapGlyph)ftGlyph;
576
577 if (roww + bGlyph->bitmap.width + 1 >= (unsigned int)max_atlas_width) {
578 w = std::max(w, roww);
579 h += rowh;
580 roww = 0;
581 rowh = 0;
582 }
583 roww += bGlyph->bitmap.width + 1;
584 rowh = std::max(rowh, (int)bGlyph->bitmap.rows);
585
586 FT_Done_Glyph(ftGlyph);
587 }
588
589 w = std::max(w, roww);
590 h += rowh;
591
592 /* Create a texture that will be used to hold all ASCII glyphs */
593 GL_CHECK(glGenTextures(1, &tex));
594 GL_CHECK(glBindTexture(GL_TEXTURE_2D, tex));
595 LOGDEBUG2(L_OPENGL, "openglosd: %s: Try creating font atlas texture with w %d h %d (max %d)", __FUNCTION__, w, h, max_atlas_width);
596
597 GL_CHECK(glTexImage2D(
598 GL_TEXTURE_2D,
599 0,
600 GL_LUMINANCE,
601 w,
602 h,
603 0,
604 GL_LUMINANCE,
605 GL_UNSIGNED_BYTE,
606 0
607 ));
608
609 GL_CHECK(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
610 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
611 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
612 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
613 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
614
615 int ox = 0;
616 int oy = 0;
617
618 rowh = 0;
619
620 // Now do the real upload
621 for (FT_ULong i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
622 if (FT_Load_Char(face, i, FT_LOAD_NO_BITMAP)) {
623 LOGWARNING("openglosd: %s: Loading char %c failed!", __FUNCTION__, i);
624 continue;
625 }
626
627 // do some glyph manipulation
628 FT_Glyph ftGlyph;
629 FT_Stroker stroker;
630 if (FT_Stroker_New(g->library, &stroker)) {
631 LOGERROR("openglosd: %s: FT_Stroker_New error!", __FUNCTION__);
632 return;
633 }
634
635 float outlineWidth = 0.25f;
636 FT_Stroker_Set(stroker, (int)(outlineWidth * 64),
637 FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
638
639 if (FT_Get_Glyph(g, &ftGlyph)) {
640 LOGERROR("openglosd: %s: FT_Get_Glyph error!", __FUNCTION__);
641 return;
642 }
643
644 if (FT_Glyph_StrokeBorder(&ftGlyph, stroker, 0, 1)) {
645 LOGERROR("openglosd: %s: FT_Glyph_StrokeBoder error!", __FUNCTION__);
646 return;
647 }
648
649 FT_Stroker_Done(stroker);
650
651 if (FT_Glyph_To_Bitmap(&ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
652 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap error!", __FUNCTION__);
653 return;
654 }
655 FT_BitmapGlyph bGlyph = (FT_BitmapGlyph)ftGlyph;
656
657 // pushing the glyphs to the texture
658 if (ox + bGlyph->bitmap.width + 1 >= (unsigned int)max_atlas_width) {
659 oy += rowh;
660 rowh = 0;
661 ox = 0;
662 }
663
664 GL_CHECK(glTexSubImage2D(
665 GL_TEXTURE_2D,
666 0,
667 ox,
668 oy,
669 bGlyph->bitmap.width,
670 bGlyph->bitmap.rows,
671 GL_LUMINANCE,
672 GL_UNSIGNED_BYTE,
673 bGlyph->bitmap.buffer
674 ));
675
676 float ax = bGlyph->root.advance.x >> 16; // AdvanceX
677 float ay = bGlyph->root.advance.y >> 16; // AdvanceX
678 float bw = bGlyph->bitmap.width; // Width
679 float bh = bGlyph->bitmap.rows; // Height
680 float bl = bGlyph->left; // BearingLeft
681 float bt = bGlyph->top; // BearingTop
682 float tx = ox / (float)w;
683 float ty = oy / (float)h;
684
685 Glyph[i - MIN_CHARCODE] = new cOglAtlasGlyph(i, ax, ay, bw, bh, bl, bt, tx, ty);
686 rowh = std::max(rowh, (int)bGlyph->bitmap.rows);
687 ox += bGlyph->bitmap.width + 1;
688
689 FT_Done_Glyph(ftGlyph);
690 }
691
692 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
693 LOGDEBUG2(L_OPENGL, "openglosd: %s: Created a %d x %d (%d kB) FontAtlas for fontsize %d, rowh %d, roww %d", __FUNCTION__, w, h, w * h / 1024, height, rowh, roww);
694}
695
697 if (tex)
698 GL_CHECK(glDeleteTextures(1, &tex));
699
700 for (FT_ULong i = MIN_CHARCODE; i <= MAX_CHARCODE; i++) {
701 if (Glyph[i - MIN_CHARCODE]) {
702 delete Glyph[i - MIN_CHARCODE];
703 Glyph[i - MIN_CHARCODE] = nullptr;
704 }
705 }
706}
707
709 if (sym < MIN_CHARCODE || sym > MAX_CHARCODE)
710 return nullptr;
711
712 return Glyph[sym - MIN_CHARCODE];
713}
714
716 GL_CHECK(glBindTexture(GL_TEXTURE_2D, tex));
717}
718
719/****************************************************************************************
720* cOglFont
721****************************************************************************************/
722FT_Library cOglFont::ftLib = 0;
723cList<cOglFont> *cOglFont::fonts = 0;
724bool cOglFont::initiated = false;
725
726cOglFont::cOglFont(const char *fontName, int charHeight) : name(fontName) {
727 size = charHeight;
728 height = 0;
729 bottom = 0;
730
731 int error = FT_New_Face(ftLib, fontName, 0, &face);
732 if (error)
733 LOGERROR("openglosd: %s: failed to open %s!", __FUNCTION__, *name);
734
735 FT_ULong charcode;
736 FT_UInt gindex;
737 int count = 0;
738 int min_index = 0;
739 int max_index = 0;
740
741 charcode = FT_Get_First_Char(face, &gindex);
742 min_index = gindex;
743 max_index = gindex;
744 while (gindex != 0) {
745 count++;
746 charcode = FT_Get_Next_Char(face, charcode, &gindex);
747 min_index = std::min(min_index, (int)gindex);
748 max_index = std::max(max_index, (int)gindex);
749 }
750
751 FT_Set_Char_Size(face, 0, charHeight * 64, 0, 0);
752 height = (face->size->metrics.ascender - face->size->metrics.descender + 63) / 64;
753 bottom = abs((face->size->metrics.descender - 63) / 64);
754 this->atlas = new cOglFontAtlas(face, charHeight);
755 LOGDEBUG2(L_OPENGL, "openglosd: %s: Created new font: %s (%d) height: %d, bottom: %d - %d chars (%d - %d)", __FUNCTION__, fontName, charHeight, height, bottom, count, min_index, max_index);
756}
757
759 delete atlas;
760 FT_Done_Face(face);
761}
762
763cOglFont *cOglFont::Get(const char *name, int charHeight) {
764 if (!fonts)
765 Init();
766
767 cOglFont *font;
768 for (font = fonts->First(); font; font = fonts->Next(font))
769 if (!strcmp(font->Name(), name) && charHeight == font->Size()) {
770 return font;
771 }
772 font = new cOglFont(name, charHeight);
773 fonts->Add(font);
774 return font;
775}
776
777void cOglFont::Init(void) {
778 if (FT_Init_FreeType(&ftLib)) {
779 LOGERROR("openglosd: %s: failed to initialize FreeType library!", __FUNCTION__);
780 return;
781 }
782 fonts = new cList<cOglFont>;
783 initiated = true;
784}
785
787 if (!initiated)
788 return;
789 delete fonts;
790 fonts = 0;
791 if (ftLib && FT_Done_FreeType(ftLib))
792 LOGERROR("openglosd: %s: failed to deinitialize FreeType library!", __FUNCTION__);
793
794 ftLib = 0;
795}
796
797cOglGlyph* cOglFont::Glyph(FT_ULong charCode) const {
798 // Non-breaking space:
799 if (charCode == 0xA0)
800 charCode = 0x20;
801
802 // Lookup in cache:
803 for (cOglGlyph *g = glyphCache.First(); g; g = glyphCache.Next(g)) {
804 if (g->CharCode() == charCode) {
805 return g;
806 }
807 }
808
809 FT_UInt glyph_index = FT_Get_Char_Index(face, charCode);
810
811 FT_Int32 loadFlags = FT_LOAD_NO_BITMAP;
812 // Load glyph image into the slot (erase previous one):
813 int error = FT_Load_Glyph(face, glyph_index, loadFlags);
814 if (error) {
815 LOGERROR("openglosd: %s: FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
816 return NULL;
817 }
818
819 FT_Glyph ftGlyph;
820 FT_Stroker stroker;
821 error = FT_Stroker_New( ftLib, &stroker );
822 if (error) {
823 LOGERROR("openglosd: %s: FT_Stroker_New FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
824 return NULL;
825 }
826 float outlineWidth = 0.25f;
827 FT_Stroker_Set(stroker,
828 (int)(outlineWidth * 64),
829 FT_STROKER_LINECAP_ROUND,
830 FT_STROKER_LINEJOIN_ROUND,
831 0);
832
833
834 error = FT_Get_Glyph(face->glyph, &ftGlyph);
835 if (error) {
836 LOGERROR("openglosd: %s: FT_Get_Glyph FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
837 return NULL;
838 }
839
840 error = FT_Glyph_StrokeBorder( &ftGlyph, stroker, 0, 1 );
841 if ( error ) {
842 LOGERROR("openglosd: %s: FT_Glyph_StrokeBorder FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
843 return NULL;
844 }
845 FT_Stroker_Done(stroker);
846
847 error = FT_Glyph_To_Bitmap( &ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1);
848 if (error) {
849 LOGERROR("openglosd: %s: FT_Glyph_To_Bitmap FT_Error (0x%02x) : %s", __FUNCTION__, FT_Errors[error].code, FT_Errors[error].message);
850 return NULL;
851 }
852
853 cOglGlyph *Glyph = new cOglGlyph(charCode, (FT_BitmapGlyph)ftGlyph);
854 glyphCache.Add(Glyph);
855 FT_Done_Glyph(ftGlyph);
856
857 return Glyph;
858}
859
860int cOglFont::Kerning(cOglGlyph *glyph, FT_ULong prevSym) const {
861 int kerning = 0;
862 if (glyph && prevSym) {
863 kerning = glyph->GetKerningCache(prevSym);
864 if (kerning == KERNING_UNKNOWN) {
865 FT_Vector delta;
866 FT_UInt glyph_index = FT_Get_Char_Index(face, glyph->CharCode());
867 FT_UInt glyph_index_prev = FT_Get_Char_Index(face, prevSym);
868 FT_Get_Kerning(face, glyph_index_prev, glyph_index, FT_KERNING_DEFAULT, &delta);
869 kerning = delta.x / 64;
870 glyph->SetKerningCache(prevSym, kerning);
871 }
872 }
873 return kerning;
874}
875
876int cOglFont::AtlasKerning(cOglAtlasGlyph *glyph, FT_ULong prevSym) const {
877 int kerning = 0;
878 if (glyph && prevSym) {
879 kerning = glyph->GetKerningCache(prevSym);
880 if (kerning == KERNING_UNKNOWN) {
881 FT_Vector delta;
882 FT_UInt glyph_index = FT_Get_Char_Index(face, glyph->CharCode());
883 FT_UInt glyph_index_prev = FT_Get_Char_Index(face, prevSym);
884 FT_Get_Kerning(face, glyph_index_prev, glyph_index, FT_KERNING_DEFAULT, &delta);
885 kerning = delta.x / 64;
886 glyph->SetKerningCache(prevSym, kerning);
887 }
888 }
889 return kerning;
890}
891
892/****************************************************************************************
893* cOglFb
894****************************************************************************************/
895cOglFb::cOglFb(GLint width, GLint height, GLint viewPortWidth, GLint viewPortHeight) {
896 initiated = false;
897 fb = 0;
898 texture = 0;
899 this->width = width;
900 this->height = height;
901 this->viewPortWidth = viewPortWidth;
902 this->viewPortHeight = viewPortHeight;
904 scrollable = true;
905 else
906 scrollable = false;
907}
908
910 if (texture)
911 GL_CHECK(glDeleteTextures(1, &texture));
912 if (fb)
913 GL_CHECK(glDeleteFramebuffers(1, &fb));
914}
915
916bool cOglFb::Init(void) {
917 initiated = true;
918 GL_CHECK(glGenTextures(1, &texture));
919 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
920 GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
921 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
922 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
923 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
924 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
925 GL_CHECK(glGenFramebuffers(1, &fb));
926 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fb));
927
928 GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0));
929
930 GLenum fbstatus;
931 GL_CHECK(fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER));
932 if(fbstatus != GL_FRAMEBUFFER_COMPLETE) {
933 LOGERROR("openglosd: %s: Framebuffer is not complete!", __FUNCTION__);
934 return false;
935 }
936 return true;
937}
938
939void cOglFb::Bind(void) {
940 if (!initiated)
941 Init();
942 GL_CHECK(glViewport(0, 0, width, height));
943 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fb));
944}
945
947 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fb));
948}
949
951 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fb));
952}
953
954void cOglFb::Unbind(void) {
955 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
956 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
957}
958
960 if (!initiated)
961 return false;
962 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
963 return true;
964}
965
966
967/****************************************************************************************
968* cOglOutputFb
969****************************************************************************************/
970cOglOutputFb::cOglOutputFb(GLint width, GLint height) : cOglFb(width, height, width, height) {
971 initiated = false;
972 this->width = width;
973 this->height = height;
974 fb = 0;
975 texture = 0;
976}
977
979 if (texture)
980 GL_CHECK(glDeleteTextures(1, &texture));
981 if (fb)
982 GL_CHECK(glDeleteFramebuffers(1, &fb));
983}
984
986 initiated = true;
987 GL_CHECK(glGenTextures(1, &texture));
988 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
989 GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
990 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
991 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
992 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
993 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
994 GL_CHECK(glGenFramebuffers(1, &fb));
995 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fb));
996
997 GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0));
998
999 GLenum fbstatus;
1000 GL_CHECK(fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER));
1001 if(fbstatus != GL_FRAMEBUFFER_COMPLETE) {
1002 LOGERROR("openglosd: %s: Framebuffer is not complete (%d)!", __FUNCTION__, fbstatus);
1003 return false;
1004 }
1005
1006 return true;
1007}
1008
1010 if (!initiated)
1011 Init();
1012 GL_CHECK(glViewport(0, 0, width, height));
1013 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fb));
1014}
1015
1017 GL_CHECK(glFinish()); //??
1018 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
1019 GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
1020}
1021
1022/****************************************************************************************
1023* cOglVb
1024****************************************************************************************/
1026
1028 this->type = (eVertexBufferType)type;
1029 positionLoc = 0;
1030 texCoordsLoc = 1;
1031 vbo = 0;
1032 sizeVertex1 = 0;
1033 sizeVertex2 = 0;
1034 numVertices = 0;
1035 drawMode = 0;
1036}
1037
1039}
1040
1041bool cOglVb::Init(void) {
1042
1043 if (type == vbTexture) {
1044 //Texture VBO definition
1045 sizeVertex1 = 2;
1046 sizeVertex2 = 2;
1047 numVertices = 6;
1048 drawMode = GL_TRIANGLES;
1049 shader = stTexture;
1050 } else if (type == vbTextureSwapBR) {
1051 //Texture VBO definition, BR swapped
1052 sizeVertex1 = 2;
1053 sizeVertex2 = 2;
1054 numVertices = 6;
1055 drawMode = GL_TRIANGLES;
1057 } else if (type == vbRect) {
1058 //Rectangle VBO definition
1059 sizeVertex1 = 2;
1060 sizeVertex2 = 0;
1061 numVertices = 4;
1062 drawMode = GL_TRIANGLE_FAN;
1063 shader = stRect;
1064 } else if (type == vbEllipse) {
1065 //Ellipse VBO definition
1066 sizeVertex1 = 2;
1067 sizeVertex2 = 0;
1068 numVertices = 182;
1069 drawMode = GL_TRIANGLE_FAN;
1070 shader = stRect;
1071 } else if (type == vbSlope) {
1072 //Slope VBO definition
1073 sizeVertex1 = 2;
1074 sizeVertex2 = 0;
1075 numVertices = 102;
1076 drawMode = GL_TRIANGLE_FAN;
1077 shader = stRect;
1078 } else if (type == vbText) {
1079 //Text VBO definition
1080 sizeVertex1 = 2;
1081 sizeVertex2 = 2;
1082 numVertices = 6;
1083 drawMode = GL_TRIANGLES;
1084 shader = stText;
1085 }
1086
1087 GL_CHECK(glGenBuffers(1, &vbo));
1088 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vbo));
1089
1090 GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (sizeVertex1 + sizeVertex2) * numVertices, NULL, GL_DYNAMIC_DRAW));
1091
1092 GL_CHECK(glEnableVertexAttribArray(positionLoc));
1093 GL_CHECK(glVertexAttribPointer(positionLoc, sizeVertex1, GL_FLOAT, GL_FALSE, (sizeVertex1 + sizeVertex2) * sizeof(GLfloat), (GLvoid*)0));
1094 if (sizeVertex2 > 0) {
1095 GL_CHECK(glEnableVertexAttribArray(texCoordsLoc));
1096 GL_CHECK(glVertexAttribPointer(texCoordsLoc, sizeVertex2, GL_FLOAT, GL_FALSE, (sizeVertex1 + sizeVertex2) * sizeof(GLfloat), (GLvoid*)(sizeVertex1 * sizeof(GLfloat))));
1097 }
1098
1099 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
1100
1101 return true;
1102}
1103
1104void cOglVb::Bind(void) {
1105 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vbo));
1106 GL_CHECK(glEnableVertexAttribArray(positionLoc));
1107 GL_CHECK(glVertexAttribPointer(positionLoc, sizeVertex1, GL_FLOAT, GL_FALSE, (sizeVertex1 + sizeVertex2) * sizeof(GLfloat), (GLvoid*)0));
1108 if (sizeVertex2 > 0) {
1109 GL_CHECK(glEnableVertexAttribArray(texCoordsLoc));
1110 GL_CHECK(glVertexAttribPointer(texCoordsLoc, sizeVertex2, GL_FLOAT, GL_FALSE, (sizeVertex1 + sizeVertex2) * sizeof(GLfloat), (GLvoid*)(sizeVertex1 * sizeof(GLfloat))));
1111 }
1112}
1113
1114void cOglVb::Unbind(void) {
1115 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
1116}
1117
1119 Shaders[shader]->Use();
1120}
1121
1123 GL_CHECK(glEnable(GL_BLEND));
1124 GL_CHECK(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
1125}
1126
1128 GL_CHECK(glDisable(GL_BLEND));
1129}
1130
1131void cOglVb::SetShaderColor(GLint color) {
1132 glm::vec4 col;
1133 ConvertColor(color, col);
1134 Shaders[shader]->SetVector4f("inColor", col.r, col.g, col.b, col.a);
1135}
1136
1138 glm::vec4 col;
1139 ConvertColor(color, col);
1140 Shaders[shader]->SetVector4f("bColor", col.r, col.g, col.b, col.a);
1141}
1142
1143void cOglVb::SetShaderTexture(GLint value) {
1144 Shaders[shader]->SetInteger("screenTexture", value);
1145}
1146
1147void cOglVb::SetShaderAlpha(GLint alpha) {
1148 Shaders[shader]->SetVector4f("alpha", 1.0f, 1.0f, 1.0f, (GLfloat)(alpha) / 255.0f);
1149}
1150
1151void cOglVb::SetShaderProjectionMatrix(GLint width, GLint height) {
1152 glm::mat4 projection = glm::ortho(0.0f, (GLfloat)width, (GLfloat)height, 0.0f, -1.0f, 1.0f);
1153 Shaders[shader]->SetMatrix4("projection", projection);
1154}
1155
1156void cOglVb::SetVertexSubData(GLfloat *vertices, int count) {
1157 if (count == 0)
1158 count = numVertices;
1159 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vbo));
1160 GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * (sizeVertex1 + sizeVertex2) * count, vertices));
1161 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
1162}
1163
1164void cOglVb::SetVertexData(GLfloat *vertices, int count) {
1165 if (count == 0)
1166 count = numVertices;
1167 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, vbo));
1168 GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * (sizeVertex1 + sizeVertex2) * count, vertices, GL_DYNAMIC_DRAW));
1169 GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
1170}
1171
1172void cOglVb::DrawArrays(int count) {
1173 if (count == 0)
1174 count = numVertices;
1175 GL_CHECK(glDrawArrays(drawMode, 0, count));
1176}
1177
1178/****************************************************************************************
1179* cOpenGLCmd
1180****************************************************************************************/
1181//------------------ cOglCmdInitOutputFb --------------------
1183 this->oFb = oFb;
1184}
1185
1187 bool ok = oFb->Init();
1188 oFb->Unbind();
1189 return ok;
1190}
1191
1192//------------------ cOglCmdInitFb --------------------
1193cOglCmdInitFb::cOglCmdInitFb(cOglFb *fb, cCondWait *wait) : cOglCmd(fb) {
1194 this->wait = wait;
1195}
1196
1198 bool ok = fb->Init();
1199 fb->Unbind();
1200 if (wait)
1201 wait->Signal();
1202 return ok;
1203}
1204
1205//------------------ cOglCmdDeleteFb --------------------
1207}
1208
1210 GL_CHECK(glFinish());
1211 if (fb)
1212 delete fb;
1213 return true;
1214}
1215
1216//------------------ cOglCmdRenderFbToBufferFb --------------------
1217cOglCmdRenderFbToBufferFb::cOglCmdRenderFbToBufferFb(cOglFb *fb, cOglFb *buffer, GLint x, GLint y, GLint transparency, GLint drawPortX, GLint drawPortY, GLint dirtyX, GLint dirtyTop, GLint dirtyWidth, GLint dirtyHeight, bool alphablending, cSoftHdDevice *device) : cOglCmd(fb) {
1218 this->dirtyX = dirtyX;
1219 this->dirtyTop = dirtyTop;
1220 this->dirtyWidth = dirtyWidth;
1221 this->dirtyHeight = dirtyHeight;
1222 this->buffer = buffer;
1223 this->x = (GLfloat)x;
1224 this->y = (GLfloat)y;
1225 this->drawPortX = (GLfloat)drawPortX;
1226 this->drawPortY = (GLfloat)drawPortY;
1227 this->transparency = (alphablending ? transparency : ALPHA_OPAQUE);
1228 this->bcolor = BORDERCOLOR;
1229 this->alphablending = alphablending;
1230 Device = device;
1231}
1232
1234 GLfloat x2 = x + fb->ViewportWidth(); //right
1235 GLfloat y2 = y + fb->ViewportHeight(); //bottom
1236
1237 GLfloat texX1 = drawPortX / (GLfloat)fb->Width();
1238 GLfloat texX2 = texX1 + 1.0f;
1239 GLfloat texY1 = drawPortY / (GLfloat)fb->Height();
1240 GLfloat texY2 = texY1 + 1.0f;
1241
1242 if (fb->Scrollable()) {
1243 GLfloat pageHeight = (GLfloat)fb->ViewportHeight() / (GLfloat)fb->Height();
1244 texX1 = abs(drawPortX) / (GLfloat)fb->Width();
1245 texY1 = 1.0f - pageHeight - abs(drawPortY) / (GLfloat)fb->Height();
1246 texX2 = texX1 + (GLfloat)fb->ViewportWidth() / (GLfloat)fb->Width();
1247 texY2 = texY1 + pageHeight;
1248 }
1249
1250 GLfloat quadVertices[] = {
1251 // Pos // TexCoords
1252 x , y , texX1, texY2, //left top
1253 x , y2, texX1, texY1, //left bottom
1254 x2, y2, texX2, texY1, //right bottom
1255
1256 x , y , texX1, texY2, //left top
1257 x2, y2, texX2, texY1, //right bottom
1258 x2, y , texX2, texY2 //right top
1259 };
1260
1265
1266 buffer->Bind();
1267 if (!fb->BindTexture())
1268 return false;
1269 if (!alphablending)
1272 GL_CHECK(glEnable(GL_SCISSOR_TEST));
1276 GL_CHECK(glDisable(GL_SCISSOR_TEST));
1278
1279#ifdef WRITE_PNG
1280 // Read back bFb framebuffer
1281// if (Device->WritePngs())
1282// writePng(0, 0, buffer->Width(), buffer->Height(), false);
1283#endif
1284 if (!alphablending)
1286 buffer->Unbind();
1287
1288 return true;
1289}
1290
1291//------------------ cOglCmdCopyBufferToOutputFb --------------------
1293 this->oFb = oFb;
1294 this->x = (GLfloat)x;
1295 this->y = (GLfloat)y;
1296 this->bcolor = BORDERCOLOR;
1297 this->active = active;
1298 Device = device;
1299 this->Render = render;
1300}
1301
1303 GLfloat x2 = x + (GLfloat)fb->Width();
1304 GLfloat y2 = y + (GLfloat)fb->Height();
1305
1306 GLfloat texX1 = 0.0f;
1307 GLfloat texX2 = 1.0f;
1308 GLfloat texY1 = 1.0f;
1309 GLfloat texY2 = 0.0f;
1310
1311 GLfloat quadVertices[] = {
1312 // Pos // TexCoords
1313 x , y , texX1, texY1, //left top
1314 x , y2, texX1, texY2, //left bottom
1315 x2, y2, texX2, texY2, //right bottom
1316
1317 x , y , texX1, texY1, //left top
1318 x2, y2, texX2, texY2, //right bottom
1319 x2, y , texX2, texY1 //right top
1320 };
1321
1326
1327 oFb->Bind();
1328 GL_CHECK(glViewport(0, 0, oFb->Width(), oFb->Height()));
1329 if (!fb->BindTexture())
1330 return false;
1331
1336
1337 GL_CHECK(glFinish());
1338 // eglSwapBuffers and gbm_surface_lock_front_buffer in OsdDrawARGB()
1339 if (active)
1340 Device->OsdDrawARGB(0, 0, oFb->Width(), oFb->Height(), 0, 0, 0, 0);
1341 else
1342 Device->OsdClose();
1343
1344#ifdef WRITE_PNG
1345 // Read back oFb framebuffer
1346 if (Device->WritePngs())
1347 writePng(0, 0, oFb->Width(), oFb->Height(), true);
1348#endif
1349 oFb->Unbind();
1350
1351 return true;
1352}
1353
1354//------------------ cOglCmdFill --------------------
1355cOglCmdFill::cOglCmdFill(cOglFb *fb, GLint color) : cOglCmd(fb) {
1356 this->color = color;
1357}
1358
1360 glm::vec4 col;
1361 ConvertColor(color, col);
1362 fb->Bind();
1363 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1364 GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
1365 fb->Unbind();
1366 return true;
1367}
1368
1369//------------------ cOglCmdBufferFill --------------------
1371 this->color = color;
1372}
1373
1375 glm::vec4 col;
1376 ConvertColor(color, col);
1377 GL_CHECK(glClearColor(col.r, col.g, col.b, col.a));
1378 GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
1379 return true;
1380}
1381
1382//------------------ cOglCmdDrawRectangle --------------------
1383cOglCmdDrawRectangle::cOglCmdDrawRectangle( cOglFb *fb, GLint x, GLint y, GLint width, GLint height, GLint color) : cOglCmd(fb) {
1384 this->x = x;
1385 this->y = y;
1386 this->width = width;
1387 this->height = height;
1388 this->color = color;
1389}
1390
1392 if (width <= 0 || height <= 0)
1393 return false;
1394
1395 GLfloat x1 = x;
1396 GLfloat y1 = y;
1397 GLfloat x2 = x + width;
1398 GLfloat y2 = y + height;
1399
1400 GLfloat vertices[] = {
1401 x1, y1, //left top
1402 x2, y1, //right top
1403 x2, y2, //right bottom
1404 x1, y2 //left bottom
1405 };
1406
1410
1411 fb->Bind();
1418 fb->Unbind();
1419
1420 return true;
1421}
1422
1423//------------------ cOglCmdDrawEllipse --------------------
1429cOglCmdDrawEllipse::cOglCmdDrawEllipse( cOglFb *fb, GLint x, GLint y, GLint width, GLint height, GLint color, GLint quadrants) : cOglCmd(fb) {
1430 this->x = x;
1431 this->y = y;
1432 this->width = width;
1433 this->height = height;
1434 this->color = color;
1435 this->quadrants = quadrants;
1436}
1437
1439 if (width <= 0 || height <= 0)
1440 return false;
1441
1442 int numVertices = 0;
1443 GLfloat *vertices = NULL;
1444
1445 switch (quadrants) {
1446 case 0:
1447 vertices = CreateVerticesFull(numVertices);
1448 break;
1449 case 1: case 2: case 3: case 4: case -1: case -2: case -3: case -4:
1450 vertices = CreateVerticesQuadrant(numVertices);
1451 break;
1452 case 5: case 6: case 7: case 8:
1453 vertices = CreateVerticesHalf(numVertices);
1454 break;
1455 default:
1456 break;
1457 }
1458
1462
1463 //not antialiased
1464 fb->Bind();
1467 VertexBuffers[vbEllipse]->SetVertexSubData(vertices, numVertices);
1468 VertexBuffers[vbEllipse]->DrawArrays(numVertices);
1471 fb->Unbind();
1472
1473 delete[] vertices;
1474 return true;
1475}
1476
1477GLfloat *cOglCmdDrawEllipse::CreateVerticesFull(int &numVertices) {
1478 int size = 364;
1479 numVertices = size/2;
1480 GLfloat radiusX = (GLfloat)width/2;
1481 GLfloat radiusY = (GLfloat)height/2;
1482 GLfloat *vertices = new GLfloat[size];
1483 vertices[0] = x + radiusX;
1484 vertices[1] = y + radiusY;
1485 for (int i=0; i <= 180; i++) {
1486 vertices[2*i+2] = x + radiusX + (GLfloat)cos(2*i * M_PI / 180.0f)*radiusX;
1487 vertices[2*i+3] = y + radiusY - (GLfloat)sin(2*i * M_PI / 180.0f)*radiusY;
1488 }
1489 return vertices;
1490}
1491
1493 int size = 94;
1494 numVertices = size/2;
1495 GLfloat radiusX = (GLfloat)width;
1496 GLfloat radiusY = (GLfloat)height;
1497 GLint transX = 0;
1498 GLint transY = 0;
1499 GLint startAngle = 0;
1500 GLfloat *vertices = new GLfloat[size];
1501 switch (quadrants) {
1502 case 1:
1503 vertices[0] = x;
1504 vertices[1] = y + height;
1505 transY = radiusY;
1506 break;
1507 case 2:
1508 vertices[0] = x + width;
1509 vertices[1] = y + height;
1510 transX = radiusX;
1511 transY = radiusY;
1512 startAngle = 90;
1513 break;
1514 case 3:
1515 vertices[0] = x + width;
1516 vertices[1] = y;
1517 transX = radiusX;
1518 startAngle = 180;
1519 break;
1520 case 4:
1521 vertices[0] = x;
1522 vertices[1] = y;
1523 startAngle = 270;
1524 break;
1525 case -1:
1526 vertices[0] = x + width;
1527 vertices[1] = y;
1528 transY = radiusY;
1529 break;
1530 case -2:
1531 vertices[0] = x;
1532 vertices[1] = y;
1533 transX = radiusX;
1534 transY = radiusY;
1535 startAngle = 90;
1536 break;
1537 case -3:
1538 vertices[0] = x;
1539 vertices[1] = y + height;
1540 transX = radiusX;
1541 startAngle = 180;
1542 break;
1543 case -4:
1544 vertices[0] = x + width;
1545 vertices[1] = y + height;
1546 startAngle = 270;
1547 break;
1548 default:
1549 break;
1550 }
1551 for (int i=0; i <= 45; i++) {
1552 vertices[2*i+2] = x + transX + (GLfloat)cos((2*i + startAngle) * M_PI / 180.0f)*radiusX;
1553 vertices[2*i+3] = y + transY - (GLfloat)sin((2*i + startAngle) * M_PI / 180.0f)*radiusY;
1554 }
1555 return vertices;
1556}
1557
1558GLfloat *cOglCmdDrawEllipse::CreateVerticesHalf(int &numVertices) {
1559 int size = 184;
1560 numVertices = size/2;
1561 GLfloat radiusX = 0.0f;
1562 GLfloat radiusY = 0.0f;
1563 GLint transX = 0;
1564 GLint transY = 0;
1565 GLint startAngle = 0;
1566 GLfloat *vertices = new GLfloat[size];
1567 switch (quadrants) {
1568 case 5:
1569 radiusX = (GLfloat)width;
1570 radiusY = (GLfloat)height/2;
1571 vertices[0] = x;
1572 vertices[1] = y + radiusY;
1573 startAngle = 270;
1574 transY = radiusY;
1575 break;
1576 case 6:
1577 radiusX = (GLfloat)width/2;
1578 radiusY = (GLfloat)height;
1579 vertices[0] = x + radiusX;
1580 vertices[1] = y + radiusY;
1581 startAngle = 0;
1582 transX = radiusX;
1583 transY = radiusY;
1584 break;
1585 case 7:
1586 radiusX = (GLfloat)width;
1587 radiusY = (GLfloat)height/2;
1588 vertices[0] = x + radiusX;
1589 vertices[1] = y + radiusY;
1590 startAngle = 90;
1591 transX = radiusX;
1592 transY = radiusY;
1593 break;
1594 case 8:
1595 radiusX = (GLfloat)width/2;
1596 radiusY = (GLfloat)height;
1597 vertices[0] = x + radiusX;
1598 vertices[1] = y;
1599 startAngle = 180;
1600 transX = radiusX;
1601 break;
1602 default:
1603 break;
1604 }
1605 for (int i=0; i <= 90; i++) {
1606 vertices[2*i+2] = x + transX + (GLfloat)cos((2*i + startAngle) * M_PI / 180.0f)*radiusX;
1607 vertices[2*i+3] = y + transY - (GLfloat)sin((2*i + startAngle) * M_PI / 180.0f)*radiusY;
1608 }
1609 return vertices;
1610}
1611
1612//------------------ cOglCmdDrawSlope --------------------
1622cOglCmdDrawSlope::cOglCmdDrawSlope( cOglFb *fb, GLint x, GLint y, GLint width, GLint height, GLint color, GLint type) : cOglCmd(fb) {
1623 this->x = x;
1624 this->y = y;
1625 this->width = width;
1626 this->height = height;
1627 this->color = color;
1628 this->type = type;
1629}
1630
1632 if (width <= 0 || height <= 0)
1633 return false;
1634
1635 bool falling = type & 0x02;
1636 bool vertical = type & 0x04;
1637
1638 int steps = 100;
1639 if (width < 100)
1640 steps = 25;
1641 int numVertices = steps + 2;
1642 GLfloat *vertices = new GLfloat[numVertices*2];
1643
1644 switch (type) {
1645 case 0: case 4:
1646 vertices[0] = (GLfloat)(x + width);
1647 vertices[1] = (GLfloat)(y + height);
1648 break;
1649 case 1: case 5:
1650 vertices[0] = (GLfloat)x;
1651 vertices[1] = (GLfloat)y;
1652 break;
1653 case 2: case 6:
1654 vertices[0] = (GLfloat)x;
1655 vertices[1] = (GLfloat)(y + height);
1656 break;
1657 case 3: case 7:
1658 vertices[0] = (GLfloat)(x + width);
1659 vertices[1] = (GLfloat)y;
1660 break;
1661 default:
1662 vertices[0] = (GLfloat)(x);
1663 vertices[1] = (GLfloat)(y);
1664 break;
1665 }
1666
1667 for (int i = 0; i <= steps; i++) {
1668 GLfloat c = cos(i * M_PI / steps);
1669 if (falling)
1670 c = -c;
1671 if (vertical) {
1672 vertices[2*i+2] = (GLfloat)x + (GLfloat)width / 2.0f + (GLfloat)width * c / 2.0f;
1673 vertices[2*i+3] = (GLfloat)y + (GLfloat)i * ((GLfloat)height) / steps ;
1674 } else {
1675 vertices[2*i+2] = (GLfloat)x + (GLfloat)i * ((GLfloat)width) / steps ;
1676 vertices[2*i+3] = (GLfloat)y + (GLfloat)height / 2.0f + (GLfloat)height * c / 2.0f;
1677 }
1678 }
1679
1683
1684 //not antialiased
1685 fb->Bind();
1688 VertexBuffers[vbSlope]->SetVertexSubData(vertices, numVertices);
1689 VertexBuffers[vbSlope]->DrawArrays(numVertices);
1692 fb->Unbind();
1693
1694 delete[] vertices;
1695 return true;
1696}
1697
1698//------------------ cOglCmdDrawText --------------------
1699cOglCmdDrawText::cOglCmdDrawText(cOglFb *fb, GLint x, GLint y, unsigned int *symbols, GLint limitX,
1700 const char *name, int fontSize, tColor colorText, int length) : cOglCmd(fb), fontName(name) {
1701 this->x = x;
1702 this->y = y;
1703 this->limitX = limitX;
1704 this->colorText = colorText;
1705 this->fontSize = fontSize;
1706 this->symbols = symbols;
1707 this->fontName = name;
1708 this->length = length;
1709}
1710
1712 free(symbols);
1713}
1714
1717 if (!f)
1718 return false;
1719
1720 if (!length)
1721 return false;
1722
1726
1727 fb->Bind();
1729
1730 int xGlyph = x;
1731 int yGlyph = y;
1732 int fontHeight = f->Height();
1733 int bottom = f->Bottom();
1734 FT_ULong sym = 0;
1735 FT_ULong prevSym = 0;
1736 int kerning = 0;
1737
1738 // Check, if we only have symbols, which are in our atlas
1739 int unknown_char = 0;
1740 for (int i = 0; symbols[i]; i++) {
1741 if ((symbols[i] < MIN_CHARCODE) || (symbols[i] > MAX_CHARCODE)) {
1742 if (symbols[i]) {
1743 unknown_char = symbols[i];
1744 break;
1745 }
1746 }
1747 }
1748
1749 if (!unknown_char) {
1750 cOglFontAtlas *fa = f->Atlas();
1751 std::vector<GLfloat> vertices;
1752 vertices.reserve( 4 * 6 * length);
1753
1754 for (int i = 0; symbols[i]; i++) {
1755 sym = symbols[i];
1756
1757 cOglAtlasGlyph *g;
1758 // Get the glyph from the font atlas for ASCII code MIN_CHARCODE-MAX_CHARCODE
1759 g = fa->GetGlyph(sym);
1760
1761 if (!g) {
1762 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1763 continue;
1764 }
1765
1766 if ( limitX && xGlyph + g->AdvanceX() > limitX )
1767 break;
1768
1769 kerning = f->AtlasKerning(g, prevSym);
1770 prevSym = sym;
1771
1772 GLfloat x2 = xGlyph + kerning + g->BearingLeft();
1773 GLfloat y2 = y + (fontHeight - bottom - g->BearingTop()); //top
1774 GLfloat w = g->Width();
1775 GLfloat h = g->Height();
1776
1777 vertices.push_back(x2);
1778 vertices.push_back(y2);
1779 vertices.push_back(g->XOffset());
1780 vertices.push_back(g->YOffset());
1781
1782 vertices.push_back(x2 + w);
1783 vertices.push_back(y2);
1784 vertices.push_back(g->XOffset() + g->Width() / (float)fa->Width());
1785 vertices.push_back(g->YOffset());
1786
1787 vertices.push_back(x2);
1788 vertices.push_back(y2 + h);
1789 vertices.push_back(g->XOffset());
1790 vertices.push_back(g->YOffset() + g->Height() / (float)fa->Height());
1791
1792 vertices.push_back(x2 + w);
1793 vertices.push_back(y2);
1794 vertices.push_back(g->XOffset() + g->Width() / (float)fa->Width());
1795 vertices.push_back(g->YOffset());
1796
1797 vertices.push_back(x2);
1798 vertices.push_back(y2 + h);
1799 vertices.push_back(g->XOffset());
1800 vertices.push_back(g->YOffset() + g->Height() / (float)fa->Height());
1801
1802 vertices.push_back(x2 + w);
1803 vertices.push_back(y2 + h);
1804 vertices.push_back(g->XOffset() + g->Width() / (float)fa->Width());
1805 vertices.push_back(g->YOffset() + g->Height() / (float)fa->Height());
1806
1807 xGlyph += kerning + g->AdvanceX();
1808 yGlyph += kerning + g->AdvanceY();
1809
1810
1811 if ( xGlyph > fb->Width() - 1 )
1812 break;
1813 }
1814
1815 fa->BindTexture();
1816 VertexBuffers[vbText]->SetVertexData(vertices.data(), (vertices.size() / 4));
1817 VertexBuffers[vbText]->DrawArrays(vertices.size() / 4);
1818 } else {
1819 LOGDEBUG2(L_OPENGL, "openglosd: %s: char %d is not on the texture atlas, use single draw", __FUNCTION__, unknown_char);
1820 for (int i = 0; symbols[i]; i++) {
1821 sym = symbols[i];
1822 cOglGlyph *g = f->Glyph(sym);
1823 if (!g) {
1824 LOGWARNING("openglosd: %s: could not load glyph %lx", __FUNCTION__, sym);
1825 continue;
1826 }
1827
1828 if ( limitX && xGlyph + g->AdvanceX() > limitX )
1829 break;
1830
1831 kerning = f->Kerning(g, prevSym);
1832 prevSym = sym;
1833
1834 GLfloat x1 = xGlyph + kerning + g->BearingLeft(); //left
1835 GLfloat y1 = y + (fontHeight - bottom - g->BearingTop()); //top
1836 GLfloat x2 = x1 + g->Width(); //right
1837 GLfloat y2 = y1 + g->Height(); //bottom
1838
1839 GLfloat vertices[] = {
1840 x1, y2, 0.0, 1.0, // left bottom
1841 x1, y1, 0.0, 0.0, // left top
1842 x2, y1, 1.0, 0.0, // right top
1843
1844 x1, y2, 0.0, 1.0, // left bottom
1845 x2, y1, 1.0, 0.0, // right top
1846 x2, y2, 1.0, 1.0 // right bottom
1847 };
1848
1849 g->BindTexture();
1852
1853 xGlyph += kerning + g->AdvanceX();
1854
1855 if ( xGlyph > fb->Width() - 1 )
1856 break;
1857 }
1858 }
1859
1860 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
1862 fb->Unbind();
1863 return true;
1864}
1865
1866//------------------ cOglCmdDrawImage --------------------
1867cOglCmdDrawImage::cOglCmdDrawImage(cOglFb *fb, tColor *argb, GLint width, GLint height, GLint x, GLint y, bool overlay, double scaleX, double scaleY): cOglCmd(fb) {
1868 this->argb = argb;
1869 this->x = x;
1870 this->y = y;
1871 this->width = width;
1872 this->height = height;
1873 this->overlay = overlay;
1874 this->scaleX = scaleX;
1875 this->scaleY = scaleY;
1876 this->bcolor = BORDERCOLOR;
1877}
1878
1880 free(argb);
1881}
1882
1884 if (width <= 0 || height <= 0)
1885 return false;
1886
1887 GLuint texture;
1888 GL_CHECK(glGenTextures(1, &texture));
1889 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
1890 GL_CHECK(glTexImage2D(
1891 GL_TEXTURE_2D,
1892 0,
1893 GL_RGBA,
1894 width,
1895 height,
1896 0,
1897 GL_RGBA,
1898 GL_UNSIGNED_BYTE,
1899 argb
1900 ));
1901 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
1902 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
1903 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
1904 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
1905 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
1906
1907 GLfloat x1 = x; //left
1908 GLfloat y1 = y; //top
1909 GLfloat x2 = x + width * scaleX; //right
1910 GLfloat y2 = y + height * scaleY; //bottom
1911
1912 GLfloat quadVertices[] = {
1913 x1, y2, 0.0, 1.0, // left bottom
1914 x1, y1, 0.0, 0.0, // left top
1915 x2, y1, 1.0, 0.0, // right top
1916
1917 x1, y2, 0.0, 1.0, // left bottom
1918 x2, y1, 1.0, 0.0, // right top
1919 x2, y2, 1.0, 1.0 // right bottom
1920 };
1921
1926
1927 fb->Bind();
1928 GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
1929 if (overlay)
1935 if (overlay)
1937 fb->Unbind();
1938 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
1939 GL_CHECK(glDeleteTextures(1, &texture));
1940
1941 return true;
1942}
1943
1944//------------------ cOglCmdDrawTexture --------------------
1945cOglCmdDrawTexture::cOglCmdDrawTexture(cOglFb *fb, sOglImage *imageRef, GLint x, GLint y, double scaleX, double scaleY): cOglCmd(fb) {
1946 this->imageRef = imageRef;
1947 this->x = x;
1948 this->y = y;
1949 this->scaleX = scaleX;
1950 this->scaleY = scaleY;
1951 this->bcolor = BORDERCOLOR;
1952}
1953
1955 if (imageRef->width <= 0 || imageRef->height <= 0)
1956 return false;
1957
1958 GLfloat x1 = x; //top
1959 GLfloat y1 = y; //left
1960 GLfloat x2 = x + imageRef->width * scaleX; //right
1961 GLfloat y2 = y + imageRef->height * scaleY; //bottom
1962
1963 GLfloat quadVertices[] = {
1964 // Pos // TexCoords
1965 x1, y1, 0.0f, 0.0f, //left bottom
1966 x1, y2, 0.0f, 1.0f, //left top
1967 x2, y2, 1.0f, 1.0f, //right top
1968
1969 x1, y1, 0.0f, 0.0f, //left bottom
1970 x2, y2, 1.0f, 1.0f, //right top
1971 x2, y1, 1.0f, 0.0f //right bottom
1972 };
1973
1978
1979 fb->Bind();
1980 GL_CHECK(glBindTexture(GL_TEXTURE_2D, imageRef->texture));
1985 fb->Unbind();
1986
1987 return true;
1988}
1989
1990
1991//------------------ cOglCmdStoreImage --------------------
1992cOglCmdStoreImage::cOglCmdStoreImage(sOglImage *imageRef, tColor *argb) : cOglCmd(NULL) {
1993 this->imageRef = imageRef;
1994 data = argb;
1995}
1996
1998 free(data);
1999}
2000
2002 GL_CHECK(glGenTextures(1, &imageRef->texture));
2003 GL_CHECK(glBindTexture(GL_TEXTURE_2D, imageRef->texture));
2004 GL_CHECK(glTexImage2D(
2005 GL_TEXTURE_2D,
2006 0,
2007 GL_RGBA,
2008 imageRef->width,
2009 imageRef->height,
2010 0,
2011 GL_RGBA,
2012 GL_UNSIGNED_BYTE,
2013 data
2014 ));
2015 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
2016 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
2017 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2018 GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2019 GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
2020 return true;
2021}
2022
2023//------------------ cOglCmdDropImage --------------------
2024cOglCmdDropImage::cOglCmdDropImage(sOglImage *imageRef, cCondWait *wait) : cOglCmd(NULL) {
2025 this->imageRef = imageRef;
2026 this->wait = wait;
2027}
2028
2030 if (imageRef->texture != GL_NONE)
2031 GL_CHECK(glDeleteTextures(1, &imageRef->texture));
2032 wait->Signal();
2033 return true;
2034}
2035
2036/******************************************************************************
2037* cOglThread
2038******************************************************************************/
2039cOglThread::cOglThread(cCondWait *startWait, int maxCacheSize, cSoftHdDevice *device) : cThread("oglThread") {
2040 stalled = false;
2041 memCached = 0;
2042 this->maxCacheSize = maxCacheSize * 1024 * 1024;
2043 this->startWait = startWait;
2044 this->Render = device->Render();
2045 wait = new cCondWait();
2046 maxTextureSize = 0;
2047 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
2048 imageCache[i].used = false;
2049 imageCache[i].texture = GL_NONE;
2050 imageCache[i].width = 0;
2051 imageCache[i].height = 0;
2052 }
2053
2054 Start();
2055}
2056
2058 delete wait;
2059 wait = NULL;
2060}
2061
2063 for (int i = 0; i < OGL_MAX_OSDIMAGES; i++) {
2064 if (imageCache[i].used) {
2065 DropImageData(i);
2066 }
2067 }
2068 Cancel(2);
2069 stalled = false;
2070}
2071
2073 while (stalled)
2074 cCondWait::SleepMs(10);
2075
2076 bool doSignal = false;
2077 Lock();
2078 if (commands.size() == 0)
2079 doSignal = true;
2080 commands.push(cmd);
2081 Unlock();
2082
2083 if (commands.size() > OGL_CMDQUEUE_SIZE) {
2084 stalled = true;
2085 }
2086
2087 if (doSignal || stalled)
2088 wait->Signal();
2089}
2090
2091int cOglThread::StoreImage(const cImage &image) {
2092 if (!maxCacheSize) {
2093 LOGERROR("openglosd: %s: cannot store image, no cache set", __FUNCTION__);
2094 return 0;
2095 }
2096
2097 if (image.Width() > maxTextureSize || image.Height() > maxTextureSize) {
2098 LOGERROR("openglosd: %s: cannot store image of %dpx x %dpx "
2099 "(maximum size is %dpx x %dpx) - falling back to "
2100 "cOsdProvider::StoreImageData()", __FUNCTION__,
2101 image.Width(), image.Height(),
2103 return 0;
2104 }
2105
2106 int imgSize = image.Width() * image.Height();
2107 int newMemUsed = imgSize * sizeof(tColor) + memCached;
2108 if (newMemUsed > maxCacheSize) {
2109 float cachedMB = memCached / 1024.0f / 1024.0f;
2110 float maxMB = maxCacheSize / 1024.0f / 1024.0f;
2111 LOGERROR("openglosd: %s: Maximum size for GPU cache reached. Used: %.2fMB Max: %.2fMB", __FUNCTION__, cachedMB, maxMB);
2112 return 0;
2113 }
2114
2115 int slot = GetFreeSlot();
2116 if (!slot)
2117 return 0;
2118
2119 tColor *argb = MALLOC(tColor, imgSize);
2120 if (!argb) {
2121 LOGERROR("openglosd: %s: memory allocation of %d kb for OSD image failed", __FUNCTION__, (int)(imgSize * sizeof(tColor) / 1024));
2122 ClearSlot(slot);
2123 slot = 0;
2124 return 0;
2125 }
2126
2127 memcpy(argb, image.Data(), sizeof(tColor) * imgSize);
2128
2129 sOglImage *imageRef = GetImageRef(slot);
2130 imageRef->width = image.Width();
2131 imageRef->height = image.Height();
2132 DoCmd(new cOglCmdStoreImage(imageRef, argb));
2133
2134 cTimeMs timer(5000);
2135 while (imageRef->used && imageRef->texture == 0 && !timer.TimedOut())
2136 cCondWait::SleepMs(2);
2137
2138 if (imageRef->texture == GL_NONE) {
2139 LOGERROR("openglosd: %s: failed to store OSD image texture! (%s)", __FUNCTION__, timer.TimedOut() ? "timed out" : "allocation failed");
2140 DropImageData(slot);
2141 slot = 0;
2142 }
2143
2144 memCached += imgSize * sizeof(tColor);
2145 return slot;
2146}
2147
2149 Lock();
2150 int slot = 0;
2151 for (int i = 0; i < OGL_MAX_OSDIMAGES && !slot; i++) {
2152 if (!imageCache[i].used) {
2153 imageCache[i].used = true;
2154 slot = -i - 1;
2155 }
2156 }
2157 Unlock();
2158 return slot;
2159}
2160
2162 int i = -slot - 1;
2163 if (i >= 0 && i < OGL_MAX_OSDIMAGES) {
2164 Lock();
2165 imageCache[i].used = false;
2166 imageCache[i].texture = GL_NONE;
2167 imageCache[i].width = 0;
2168 imageCache[i].height = 0;
2169 Unlock();
2170 }
2171}
2172
2173sOglImage *cOglThread::GetImageRef(int slot) {
2174 int i = -slot - 1;
2175 if (0 <= i && i < OGL_MAX_OSDIMAGES)
2176 return &imageCache[i];
2177 return 0;
2178}
2179
2180void cOglThread::DropImageData(int imageHandle) {
2181 sOglImage *imageRef = GetImageRef(imageHandle);
2182 if (!imageRef)
2183 return;
2184 int imgSize = imageRef->width * imageRef->height * sizeof(tColor);
2185 memCached -= imgSize;
2186 cCondWait dropWait;
2187 DoCmd(new cOglCmdDropImage(imageRef, &dropWait));
2188 dropWait.Wait();
2189 ClearSlot(imageHandle);
2190}
2191
2193 if (!InitOpenGL()) {
2194 LOGERROR("openglosd: %s: Could not initiate OpenGL context", __FUNCTION__);
2195 Cleanup();
2196 startWait->Signal();
2197 return;
2198 }
2199
2200 if (!InitShaders()) {
2201 LOGERROR("openglosd: %s: Could not initiate shaders", __FUNCTION__);
2202 Cleanup();
2203 startWait->Signal();
2204 return;
2205 }
2206
2207 if (!InitVertexBuffers()) {
2208 LOGERROR("openglosd: %s: Vertex Buffers NOT initialized", __FUNCTION__);
2209 Cleanup();
2210 startWait->Signal();
2211 return;
2212 }
2213
2214 GL_CHECK(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize));
2215 LOGDEBUG2(L_OPENGL, "openglosd: %s: Maximum Pixmap size: %dx%dpx", __FUNCTION__, maxTextureSize, maxTextureSize);
2216
2217 //now Thread is ready to do his job
2218 startWait->Signal();
2219 stalled = false;
2220
2221 LOGINFO("OpenGL context initialized");
2222
2223 uint64_t start_flush = 0;
2224 uint64_t end_flush = 0;
2225 int time_reset = 0;
2226
2227 while(Running()) {
2228
2229 if (commands.empty()) {
2230 wait->Wait(20);
2231 continue;
2232 }
2233
2234 Lock();
2235 cOglCmd* cmd = commands.front();
2236 commands.pop();
2237 Unlock();
2238
2239 uint64_t start = cTimeMs::Now();
2240 if (strcmp(cmd->Description(), "InitFramebuffer") == 0 || time_reset) {
2241 start_flush = cTimeMs::Now();
2242 time_reset = 0;
2243 }
2244
2245 cmd->Execute();
2246 LOGDEBUG2(L_OPENGL_TIME_ALL, "openglosd: %s: \"%-*s\", %dms, %d commands left, time %" PRIu64 "", __FUNCTION__, 15, cmd->Description(), (int)(cTimeMs::Now() - start), (int)(commands.size()), cTimeMs::Now());
2247
2248 if (strcmp(cmd->Description(), "Copy buffer to OutputFramebuffer") == 0) {
2249 end_flush = cTimeMs::Now();
2250 time_reset = 1;
2251 LOGDEBUG2(L_OPENGL_TIME, "openglosd: %s: OSD Flush %dms, time %" PRIu64 "", __FUNCTION__, (int)(end_flush - start_flush), cTimeMs::Now());
2252 }
2253 delete cmd;
2254 if (stalled && commands.size() < OGL_CMDQUEUE_SIZE / 2)
2255 stalled = false;
2256 }
2257
2258 LOGDEBUG2(L_OPENGL, "openglosd: %s: Cleaning up OpenGL stuff", __FUNCTION__);
2259 Cleanup();
2260 LOGDEBUG2(L_OPENGL, "openglosd: %s: OpenGL worker thread ended", __FUNCTION__);
2261}
2262
2264{
2265 EGL_CHECK(eglMakeCurrent(Render->EglDisplay(), Render->EglSurface(), Render->EglSurface(), Render->EglContext()));
2266}
2267
2269{
2270 EGL_CHECK(eglMakeCurrent(Render->EglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2271}
2272
2274 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context", __FUNCTION__);
2275
2276 // Wait for the EGL context to be created
2277 while(!Render->GlInitiated()) {
2278 LOGDEBUG2(L_OPENGL, "openglosd: %s: wait for EGL context", __FUNCTION__);
2279 usleep(20000);
2280 }
2281
2282 eglAcquireContext(); /* eglMakeCurrent with new eglSurface */
2283
2284 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Version: \"%s\"", glGetString(GL_VERSION)));
2285 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Vendor: \"%s\"", glGetString(GL_VENDOR)));
2286 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Extensions: \"%s\"", glGetString(GL_EXTENSIONS)));
2287 GL_CHECK(LOGDEBUG2(L_OPENGL, " GL Renderer: \"%s\"", glGetString(GL_RENDERER)));
2288
2290 GL_CHECK(glDisable(GL_DEPTH_TEST));
2291 LOGDEBUG2(L_OPENGL, "openglosd: %s: Init OpenGL context done", __FUNCTION__);
2292 return true;
2293}
2294
2296 for (int i=0; i < stCount; i++) {
2297 cShader *shader = new cShader();
2298 if (!shader->Load((eShaderType)i))
2299 return false;
2300 Shaders[i] = shader;
2301 }
2302 LOGDEBUG2(L_OPENGL, "openglosd: %s: Shaders initialized", __FUNCTION__);
2303 return true;
2304}
2305
2307 for (int i=0; i < stCount; i++)
2308 delete Shaders[i];
2309}
2310
2312 for (int i=0; i < vbCount; i++) {
2313 cOglVb *vb = new cOglVb(i);
2314 if (!vb->Init())
2315 return false;
2316 VertexBuffers[i] = vb;
2317 }
2318 LOGDEBUG2(L_OPENGL, "openglosd: %s: Vertex buffers initialized", __FUNCTION__);
2319 return true;
2320}
2321
2323 for (int i=0; i < vbCount; i++) {
2324 delete VertexBuffers[i];
2325 }
2326}
2327
2330 delete cOglOsd::oFb;
2331 cOglOsd::oFb = NULL;
2332 DeleteShaders();
2334}
2335
2336/****************************************************************************************
2337* cOglPixmap
2338****************************************************************************************/
2339
2340cOglPixmap::cOglPixmap(std::shared_ptr<cOglThread> oglThread, int Layer, const cRect &ViewPort, const cRect &DrawPort) : cPixmap(Layer, ViewPort, DrawPort) {
2341 this->oglThread = oglThread;
2342 int width = DrawPort.IsEmpty() ? ViewPort.Width() : DrawPort.Width();
2343 int height = DrawPort.IsEmpty() ? ViewPort.Height() : DrawPort.Height();
2344
2345 if (width > oglThread->MaxTextureSize() || height > oglThread->MaxTextureSize()) {
2346 LOGWARNING("openglosd: %s: cannot allocate pixmap of %dpx x %dpx, clipped to %dpx x %dpx!", __FUNCTION__,
2347 width, height, std::min(width, oglThread->MaxTextureSize()), std::min(height, oglThread->MaxTextureSize()));
2348 width = std::min(width, oglThread->MaxTextureSize());
2349 height = std::min(height, oglThread->MaxTextureSize());
2350 }
2351
2352 fb = new cOglFb(width, height, ViewPort.Width(), ViewPort.Height());
2353 dirty = true;
2354
2355#ifdef GRIDPOINTS
2356 // Creates a tiny font with height GRIDPOINTSTXTSIZE
2357 tinyfont = cFont::CreateFont(Setup.FontOsd, GRIDPOINTSTXTSIZE);
2358#endif
2359}
2360
2362 if (!oglThread->Active())
2363 return;
2364 oglThread->DoCmd(new cOglCmdDeleteFb(fb));
2365#ifdef GRIDPOINTS
2366 delete tinyfont;
2367#endif
2368}
2369
2370void cOglPixmap::MarkViewPortDirty(const cRect &Rect) {
2371 cPixmap::MarkViewPortDirty(Rect);
2372 SetDirty();
2373}
2374
2376 cPixmap::SetClean();
2377 SetDirty(false);
2378}
2379
2380void cOglPixmap::SetLayer(int Layer) {
2381 cPixmap::SetLayer(Layer);
2382 SetDirty();
2383}
2384
2385void cOglPixmap::SetAlpha(int Alpha) {
2386 Alpha = constrain(Alpha, ALPHA_TRANSPARENT, ALPHA_OPAQUE);
2387 if (Alpha != cPixmap::Alpha()) {
2388 cPixmap::SetAlpha(Alpha);
2389 SetDirty();
2390 }
2391}
2392
2393void cOglPixmap::SetTile(bool Tile) {
2394 cPixmap::SetTile(Tile);
2395 SetDirty();
2396}
2397
2398void cOglPixmap::SetViewPort(const cRect &Rect) {
2399 cPixmap::SetViewPort(Rect);
2400 SetDirty();
2401}
2402
2403void cOglPixmap::SetDrawPortPoint(const cPoint &Point, bool Dirty) {
2404 cPixmap::SetDrawPortPoint(Point, Dirty);
2405 if (Dirty)
2406 SetDirty();
2407}
2408
2410 if (!oglThread->Active())
2411 return;
2412 LOCK_PIXMAPS;
2413 oglThread->DoCmd(new cOglCmdFill(fb, clrTransparent));
2414 SetDirty();
2415 MarkDrawPortDirty(DrawPort());
2416}
2417
2418void cOglPixmap::Fill(tColor Color) {
2419 if (!oglThread->Active())
2420 return;
2421 LOCK_PIXMAPS;
2422 oglThread->DoCmd(new cOglCmdFill(fb, Color));
2423 SetDirty();
2424 MarkDrawPortDirty(DrawPort());
2425}
2426
2427void cOglPixmap::DrawImage(const cPoint &Point, const cImage &Image) {
2428 DrawScaledImage(Point, Image);
2429}
2430
2431void cOglPixmap::DrawImage(const cPoint &Point, int ImageHandle) {
2432 DrawScaledImage(Point, ImageHandle);
2433}
2434
2435void cOglPixmap::DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, __attribute__ ((unused)) bool AntiAlias) {
2436 if (!oglThread->Active())
2437 return;
2438 tColor *argb = MALLOC(tColor, Image.Width() * Image.Height());
2439 if (!argb)
2440 return;
2441 memcpy(argb, Image.Data(), sizeof(tColor) * Image.Width() * Image.Height());
2442
2443 oglThread->DoCmd(new cOglCmdDrawImage(fb, argb, Image.Width(), Image.Height(), Point.X(), Point.Y(), true, FactorX, FactorY));
2444#ifdef GRIDRECT
2445 DrawGridRect(cRect(Point.X(), Point.Y(), Image.Width() * FactorX, Image.Height() * FactorY), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, tinyfont);
2446#endif
2447 SetDirty();
2448 MarkDrawPortDirty(cRect(Point, cSize(Image.Width() * FactorX, Image.Height() * FactorY)).Intersected(DrawPort().Size()));
2449}
2450
2451void cOglPixmap::DrawScaledImage(const cPoint &Point, int ImageHandle, double FactorX, double FactorY, __attribute__ ((unused)) bool AntiAlias) {
2452 if (!oglThread->Active())
2453 return;
2454 if (ImageHandle < 0 && oglThread->GetImageRef(ImageHandle)) {
2455 sOglImage *img = oglThread->GetImageRef(ImageHandle);
2456 oglThread->DoCmd(new cOglCmdDrawTexture(fb, img, Point.X(), Point.Y(), FactorX, FactorY));
2457#ifdef GRIDRECT
2458 DrawGridRect(cRect(Point.X(), Point.Y(), img->width * FactorX, img->height * FactorY), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, tinyfont);
2459#endif
2460 SetDirty();
2461 MarkDrawPortDirty(cRect(Point, cSize(img->width * FactorX, img->height * FactorY)).Intersected(DrawPort().Size()));
2462 }
2463}
2464
2465void cOglPixmap::DrawPixel(const cPoint &Point, tColor Color) {
2466 cRect r(Point.X(), Point.Y(), 1, 1);
2467 oglThread->DoCmd(new cOglCmdDrawRectangle(fb, r.X(), r.Y(), r.Width(), r.Height(), Color));
2468#ifdef GRIDRECT
2469 DrawGridRect(cRect(r.X(), r.Y(), 0, 0), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, tinyfont);
2470#endif
2471 SetDirty();
2472 MarkDrawPortDirty(r);
2473}
2474
2475void cOglPixmap::DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay) {
2476 if (!oglThread->Active())
2477 return;
2478 LOCK_PIXMAPS;
2479 bool specialColors = ColorFg || ColorBg;
2480 tColor *argb = MALLOC(tColor, Bitmap.Width() * Bitmap.Height());
2481 if (!argb)
2482 return;
2483
2484 tColor *p = argb;
2485 for (int py = 0; py < Bitmap.Height(); py++)
2486 for (int px = 0; px < Bitmap.Width(); px++) {
2487 tIndex index = *Bitmap.Data(px, py);
2488 *p++ = (!index && Overlay) ? clrTransparent : (specialColors ?
2489 (index == 0 ? ColorBg : index == 1 ? ColorFg :
2490 Bitmap.Color(index)) : Bitmap.Color(index));
2491 }
2492
2493 oglThread->DoCmd(new cOglCmdDrawImage(fb, argb, Bitmap.Width(), Bitmap.Height(), Point.X(), Point.Y(), true));
2494#ifdef GRIDRECT
2495 DrawGridRect(cRect(Point.X(), Point.Y(), Bitmap.Width(), Bitmap.Height()), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, tinyfont);
2496#endif
2497
2498 SetDirty();
2499 MarkDrawPortDirty(cRect(cPoint(Point.X(), Point.Y()), cSize(Bitmap.Width(), Bitmap.Height())).Intersected(DrawPort().Size()));
2500}
2501
2502void cOglPixmap::DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) {
2503 if (!oglThread->Active())
2504 return;
2505 LOCK_PIXMAPS;
2506 int len = s ? Utf8StrLen(s) : 0;
2507 unsigned int *symbols = MALLOC(unsigned int, len + 1);
2508 if (!symbols)
2509 return;
2510
2511 if (len)
2512 Utf8ToArray(s, symbols, len + 1);
2513 else
2514 symbols[0] = 0;
2515
2516 int x = Point.X();
2517 int y = Point.Y();
2518 int w = Font->Width(s);
2519 int h = Font->Height();
2520 int limitX = 0;
2521 int cw = Width ? Width : w;
2522 int ch = Height ? Height : h;
2523
2524 // workaround for messages in SkinElchiHD
2525 if (Width > ViewPort().Width() && !x)
2526 x = ViewPort().Width() - w;
2527
2528 cRect r(x, y, cw, ch);
2529
2530 if (ColorBg != clrTransparent)
2531 oglThread->DoCmd(new cOglCmdDrawRectangle(fb, r.X(), r.Y(), r.Width(), r.Height(), ColorBg));
2532
2533 if (Width || Height) {
2534 limitX = x + cw;
2535 if (Width) {
2536 if ((Alignment & taLeft) != 0) {
2537 if ((Alignment & taBorder) != 0)
2538 x += std::max(h / TEXT_ALIGN_BORDER, 1);
2539 } else if ((Alignment & taRight) != 0) {
2540 if (w < Width)
2541 x += Width - w;
2542 if ((Alignment & taBorder) != 0)
2543 x -= std::max(h / TEXT_ALIGN_BORDER, 1);
2544 } else { // taCentered
2545 if (w < Width)
2546 x += (Width - w) / 2;
2547 }
2548 }
2549
2550 if (Height) {
2551 if ((Alignment & taTop) != 0)
2552 ;
2553 else if ((Alignment & taBottom) != 0) {
2554 if (h < Height)
2555 y += Height - h;
2556 } else { // taCentered
2557 if (h < Height)
2558 y += (Height - h) / 2;
2559 }
2560 }
2561 }
2562 oglThread->DoCmd(new cOglCmdDrawText(fb, x, y, symbols, limitX, Font->FontName(), Font->Size(), ColorFg, len));
2563
2564#ifdef GRIDTEXT
2565 DrawGridRect(cRect(x, y, cw, ch), GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, tinyfont);
2566#endif
2567
2568 SetDirty();
2569 MarkDrawPortDirty(r);
2570}
2571
2572void cOglPixmap::DrawRectangle(const cRect &Rect, tColor Color) {
2573 if (!oglThread->Active())
2574 return;
2575
2576 LOCK_PIXMAPS;
2577 oglThread->DoCmd(new cOglCmdDrawRectangle(fb, Rect.X(), Rect.Y(), Rect.Width(), Rect.Height(), Color));
2578#ifdef GRIDRECT
2579 DrawGridRect(Rect, GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, tinyfont);
2580#endif
2581
2582 SetDirty();
2583 MarkDrawPortDirty(Rect);
2584}
2585
2586void cOglPixmap::DrawEllipse(const cRect &Rect, tColor Color, int Quadrants) {
2587 if (!oglThread->Active())
2588 return;
2589
2590 LOCK_PIXMAPS;
2591 oglThread->DoCmd(new cOglCmdDrawEllipse(fb, Rect.X(), Rect.Y(), Rect.Width(), Rect.Height(), Color, Quadrants));
2592#ifdef GRIDRECT
2593 DrawGridRect(Rect, GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, tinyfont);
2594#endif
2595
2596 SetDirty();
2597 MarkDrawPortDirty(Rect);
2598}
2599
2600void cOglPixmap::DrawSlope(const cRect &Rect, tColor Color, int Type) {
2601 if (!oglThread->Active())
2602 return;
2603
2604 LOCK_PIXMAPS;
2605 oglThread->DoCmd(new cOglCmdDrawSlope(fb, Rect.X(), Rect.Y(), Rect.Width(), Rect.Height(), Color, Type));
2606#ifdef GRIDRECT
2607 DrawGridRect(Rect, GRIDPOINTOFFSET, GRIDPOINTSIZE, GRIDPOINTCLR, GRIDPOINTBG, tinyfont);
2608#endif
2609
2610 SetDirty();
2611 MarkDrawPortDirty(Rect);
2612}
2613
2614void cOglPixmap::Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest) {
2615 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, Pixmap->ViewPort().X(), Source.X(), Dest.X());
2616}
2617
2618void cOglPixmap::Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest) {
2619 LOGWARNING("openglosd: %s: %d %d %d not implemented in OpenGl OSD", __FUNCTION__, Pixmap->ViewPort().X(), Source.X(), Dest.X());
2620}
2621
2622void cOglPixmap::Scroll(const cPoint &Dest, const cRect &Source) {
2623 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, Source.X(), Dest.X());
2624}
2625
2626void cOglPixmap::Pan(const cPoint &Dest, const cRect &Source) {
2627 LOGWARNING("openglosd: %s: %d %d not implemented in OpenGl OSD", __FUNCTION__, Source.X(), Dest.X());
2628}
2629
2630#ifdef GRIDPOINTS
2631void cOglPixmap::DrawGridText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) {
2632 if (!oglThread->Active())
2633 return;
2634 LOCK_PIXMAPS;
2635 int len = s ? Utf8StrLen(s) : 0;
2636 unsigned int *symbols = MALLOC(unsigned int, len + 1);
2637 if (!symbols)
2638 return;
2639
2640 if (len)
2641 Utf8ToArray(s, symbols, len + 1);
2642 else
2643 symbols[0] = 0;
2644
2645 int x = Point.X();
2646 int y = Point.Y();
2647 int w = Font->Width(s);
2648 int h = Font->Height();
2649 int limitX = 0;
2650 int cw = Width ? Width : w;
2651 int ch = Height ? Height : h;
2652
2653 cRect r(x, y, cw, ch);
2654
2655 if (ColorBg != clrTransparent)
2656 oglThread->DoCmd(new cOglCmdDrawRectangle(fb, r.X(), r.Y(), r.Width(), r.Height(), ColorBg));
2657
2658 if (Width || Height) {
2659 limitX = x + cw;
2660 if (Width) {
2661 if ((Alignment & taLeft) != 0) {
2662 if ((Alignment & taBorder) != 0)
2663 x += std::max(h / TEXT_ALIGN_BORDER, 1);
2664 } else if ((Alignment & taRight) != 0) {
2665 if (w < Width)
2666 x += Width - w;
2667 if ((Alignment & taBorder) != 0)
2668 x -= std::max(h / TEXT_ALIGN_BORDER, 1);
2669 } else { // taCentered
2670 if (w < Width)
2671 x += (Width - w) / 2;
2672 }
2673 }
2674
2675 if (Height) {
2676 if ((Alignment & taTop) != 0)
2677 ;
2678 else if ((Alignment & taBottom) != 0) {
2679 if (h < Height)
2680 y += Height - h;
2681 } else { // taCentered
2682 if (h < Height)
2683 y += (Height - h) / 2;
2684 }
2685 }
2686 }
2687 oglThread->DoCmd(new cOglCmdDrawText(fb, x, y, symbols, limitX, Font->FontName(), Font->Size(), ColorFg, len));
2688
2689 SetDirty();
2690 MarkDrawPortDirty(r);
2691}
2692
2693void cOglPixmap::DrawGridRect(const cRect &Rect, int offset, int size, tColor clr, tColor bg, const cFont *font) {
2694 int x1 = Rect.X() + offset;
2695 int x2 = Rect.X() + Rect.Width() + offset;
2696 int y1 = Rect.Y();
2697 int y2 = Rect.Y() + Rect.Height();
2698 char p1[10];
2699 char p2[10];
2700 char p3[10];
2701 char p4[10];
2702 sprintf(p1, "%d.%d", x1, y1);
2703 sprintf(p2, "%d.%d", x2, y1);
2704 sprintf(p3, "%d.%d", x1, y2);
2705 sprintf(p4, "%d.%d", x2, y2);
2706
2707 oglThread->DoCmd(new cOglCmdDrawRectangle(fb, x1, y1, size, size, clr));
2708#ifdef GRIDPOINTSTEXT
2709 this->DrawGridText(cPoint(x1, y1), p1, clr, bg, font);
2710#endif
2711 if (Rect.Width() && Rect.Height()) {
2712 oglThread->DoCmd(new cOglCmdDrawRectangle(fb, x2, y1, size, size, clr));
2713 oglThread->DoCmd(new cOglCmdDrawRectangle(fb, x1, y2, size, size, clr));
2714 oglThread->DoCmd(new cOglCmdDrawRectangle(fb, x2, y2, size, size, clr));
2715#ifdef GRIDPOINTSTEXT
2716 this->DrawGridText(cPoint(x2, y1), p2, clr, bg, font);
2717 this->DrawGridText(cPoint(x1, y2), p3, clr, bg, font);
2718 this->DrawGridText(cPoint(x2, y2), p4, clr, bg, font);
2719#endif
2720 }
2721}
2722#endif
2723
2724/******************************************************************************
2725* cOglOsd
2726******************************************************************************/
2728
2729cOglOsd::cOglOsd(int Left, int Top, uint Level, std::shared_ptr<cOglThread> oglThread, cSoftHdDevice *device) : cOsd(Left, Top, Level) {
2730 this->Device = device;
2731 this->oglThread = oglThread;
2732 this->Render = Device->Render();
2733 bFb = NULL;
2734 if (Level == 10)
2735 isSubtitleOsd = true;
2736 else
2737 isSubtitleOsd = false;
2738 int osdWidth = 0;
2739 int osdHeight = 0;
2740 double pixel_aspect;
2741 dirtyViewport = new cRect();
2742
2743 Device->GetOsdSize(osdWidth, osdHeight, pixel_aspect);
2744 LOGDEBUG2(L_OSD, "openglosd: %s: New Osd %p osdLeft %d osdTop %d screenWidth %d screenHeight %d", __FUNCTION__, this, Left, Top, osdWidth, osdHeight);
2745
2746 maxPixmapSize.Set(oglThread->MaxTextureSize(), oglThread->MaxTextureSize());
2747
2748 if (!oFb) {
2749 oFb = new cOglOutputFb(osdWidth, osdHeight);
2750 oglThread->DoCmd(new cOglCmdInitOutputFb(oFb));
2751 }
2752}
2753
2755 if (!oglThread->Active() || !Active() || !bFb) {
2756 delete dirtyViewport;
2757 return;
2758 }
2759
2760 LOGDEBUG2(L_OSD, "openglosd: %s: Delete Osd %p", __FUNCTION__, this);
2761 oglThread->DoCmd(new cOglCmdFill(bFb, clrTransparent));
2762
2763 SetActive(false); // OsdClose() in cOglCmdCopyBufferToOutputFb()
2764 oglThread->DoCmd(new cOglCmdCopyBufferToOutputFb(bFb, oFb, Left(), Top(), 0, Device, Render));
2765 oglThread->DoCmd(new cOglCmdDeleteFb(bFb));
2766 delete dirtyViewport;
2767}
2768
2769const cSize &cOglOsd::MaxPixmapSize(void) const {
2770 return maxPixmapSize;
2771}
2772
2773eOsdError cOglOsd::SetAreas(const tArea *Areas, int NumAreas) {
2774 cRect r;
2775 if (NumAreas > 1)
2776 isSubtitleOsd = true;
2777 for (int i = 0; i < NumAreas; i++)
2778 r.Combine(cRect(Areas[i].x1, Areas[i].y1, Areas[i].Width(), Areas[i].Height()));
2779
2780 tArea area = { r.Left(), r.Top(), r.Right(), r.Bottom(), 32 };
2781
2782 //now we know the actual osd size, create double buffer frame buffer
2783 if (bFb) {
2784 oglThread->DoCmd(new cOglCmdDeleteFb(bFb));
2786 }
2787 bFb = new cOglFb(r.Width(), r.Height(), r.Width(), r.Height());
2788 cCondWait initiated;
2789 oglThread->DoCmd(new cOglCmdInitFb(bFb, &initiated));
2790 initiated.Wait();
2791
2792 return cOsd::SetAreas(&area, 1);
2793}
2794
2795cPixmap *cOglOsd::CreatePixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort) {
2796 if (!oglThread->Active())
2797 return NULL;
2798 LOCK_PIXMAPS;
2799
2800 cOglPixmap *p = new cOglPixmap(oglThread, Layer, ViewPort, DrawPort);
2801
2802 if (cOsd::AddPixmap(p)) {
2803 //find free slot
2804 for (int i = 0; i < oglPixmaps.Size(); i++)
2805 if (!oglPixmaps[i])
2806 return oglPixmaps[i] = p;
2807 //append at end
2808 oglPixmaps.Append(p);
2809 return p;
2810 }
2811 delete p;
2812 return NULL;
2813}
2814
2815void cOglOsd::DestroyPixmap(cPixmap *Pixmap) {
2816 if (!oglThread->Active())
2817 return;
2818 if (!Pixmap)
2819 return;
2820 LOCK_PIXMAPS;
2821 int start = 1;
2822 if (isSubtitleOsd)
2823 start = 0;
2824 for (int i = start; i < oglPixmaps.Size(); i++) {
2825 if (oglPixmaps[i] == Pixmap) {
2826 if (Pixmap->Layer() >= 0)
2827 oglPixmaps[0]->MarkViewPortDirty(oglPixmaps[i]->ViewPort());
2828 oglPixmaps[i] = NULL;
2829 if (i)
2830 cOsd::DestroyPixmap(Pixmap);
2831 return;
2832 }
2833 }
2834}
2835
2836void cOglOsd::Flush(void) {
2837 if (!oglThread->Active() || !Active())
2838 return;
2839
2840 LOGDEBUG2(L_OSD, "openglosd: %s: Flush Osd %p", __FUNCTION__, this);
2841 LOCK_PIXMAPS;
2842 // check for dirty areas
2843 dirtyViewport->Set(0, 0, 0, 0);
2844 for (int i = 0; i < oglPixmaps.Size(); i++) {
2845 if (oglPixmaps[i] && oglPixmaps[i]->IsDirty()) {
2846 if (isSubtitleOsd) {
2847 dirtyViewport->Combine(oglPixmaps[i]->DirtyViewPort().Size());
2848 } else {
2849 dirtyViewport->Combine(oglPixmaps[i]->DirtyViewPort());
2850 }
2851 oglPixmaps[i]->SetClean();
2852 }
2853 }
2854
2855 if (dirtyViewport->IsEmpty())
2856 return;
2857
2858 // clear buffer within the dirty area
2860 dirtyViewport->X(),
2861 dirtyViewport->Y(),
2862 dirtyViewport->Width(),
2863 dirtyViewport->Height(),
2864 clrTransparent));
2865
2866 //render pixmap textures blended to buffer
2867 for (int layer = 0; layer < MAXPIXMAPLAYERS; layer++) {
2868 for (int i = 0; i < oglPixmaps.Size(); i++) {
2869 if (!oglPixmaps[i])
2870 continue;
2871
2872 if (oglPixmaps[i]->Layer () != layer)
2873 continue;
2874
2875 if (isSubtitleOsd && !dirtyViewport->Intersects(oglPixmaps[i]->ViewPort().Size()))
2876 continue;
2877
2878 if (!isSubtitleOsd && !dirtyViewport->Intersects(oglPixmaps[i]->ViewPort()))
2879 continue;
2880
2881 bool alphablending = layer == 0 ? false : true; // Decide wether to render (with alpha) or copy a pixmap
2882 oglThread->DoCmd(new cOglCmdRenderFbToBufferFb( oglPixmaps[i]->Fb(),
2883 bFb,
2884 isSubtitleOsd ? 0 : oglPixmaps[i]->ViewPort().X(),
2885 isSubtitleOsd ? 0 : oglPixmaps[i]->ViewPort().Y(),
2886 oglPixmaps[i]->Alpha(),
2887 oglPixmaps[i]->DrawPort().X(),
2888 oglPixmaps[i]->DrawPort().Y(),
2889 dirtyViewport->X(),
2890 dirtyViewport->Top(),
2891 dirtyViewport->Width(),
2892 dirtyViewport->Height(),
2893 alphablending,
2894 Device));
2895 }
2896 }
2897 //copy buffer to output framebuffer
2898 oglThread->DoCmd(new cOglCmdBufferFill(oFb, clrTransparent));
2899
2901 Left() + (isSubtitleOsd ? oglPixmaps[0]->ViewPort().X() : 0),
2902 Top() + (isSubtitleOsd ? oglPixmaps[0]->ViewPort().Y() : 0), 1, Device, Render));
2903}
2904
2905void cOglOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias) {
2906 if (!oglPixmaps[0])
2907 return;
2908
2909 std::unique_ptr<cBitmap> scaledBitmap;
2910 const cBitmap *b = &Bitmap;
2911
2912 if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0)) {
2913 scaledBitmap.reset(Bitmap.Scaled(FactorX, FactorY, AntiAlias));
2914 b = scaledBitmap.get();
2915 }
2916
2917 int xNew = x;
2918 int yNew = y;
2919
2920 const cRect &viewport = oglPixmaps[0]->ViewPort();
2921 if (isSubtitleOsd && (x >= viewport.X()))
2922 xNew -= viewport.X();
2923 if (isSubtitleOsd && (y >= viewport.Y()))
2924 yNew -= viewport.Y();
2925
2926 oglPixmaps[0]->DrawBitmap(cPoint(xNew, yNew), *b);
2927}
int BearingTop(void) const
Definition: openglosd.h:193
FT_ULong CharCode(void)
Definition: openglosd.h:189
int Width(void) const
Definition: openglosd.h:194
void SetKerningCache(FT_ULong prevSym, int kerning)
Definition: openglosd.cpp:519
cVector< tKerning > kerningCache
Definition: openglosd.h:185
int AdvanceY(void)
Definition: openglosd.h:191
int BearingLeft(void) const
Definition: openglosd.h:192
int GetKerningCache(FT_ULong prevSym)
Definition: openglosd.cpp:511
float YOffset(void) const
Definition: openglosd.h:197
FT_ULong charCode
Definition: openglosd.h:176
cOglAtlasGlyph(FT_ULong charCode, float advanceX, float advanceY, float width, float height, float bearingLeft, float bearingTop, float xoffset, float yoffset)
Definition: openglosd.cpp:492
float XOffset(void) const
Definition: openglosd.h:196
virtual ~cOglAtlasGlyph()
Definition: openglosd.cpp:507
int Height(void) const
Definition: openglosd.h:195
int AdvanceX(void)
Definition: openglosd.h:190
cOglCmdBufferFill(cOglFb *fb, GLint color)
Definition: openglosd.cpp:1370
virtual bool Execute(void)
Definition: openglosd.cpp:1374
cOglCmdCopyBufferToOutputFb(cOglFb *fb, cOglOutputFb *oFb, GLint x, GLint y, int active, cSoftHdDevice *device, cVideoRender *render)
Definition: openglosd.cpp:1292
cSoftHdDevice * Device
Definition: openglosd.h:413
virtual bool Execute(void)
Definition: openglosd.cpp:1302
virtual bool Execute(void)
Definition: openglosd.cpp:1209
cOglCmdDeleteFb(cOglFb *fb)
Definition: openglosd.cpp:1206
GLfloat * CreateVerticesFull(int &numVertices)
Definition: openglosd.cpp:1477
GLfloat * CreateVerticesQuadrant(int &numVertices)
Definition: openglosd.cpp:1492
virtual bool Execute(void)
Definition: openglosd.cpp:1438
GLfloat * CreateVerticesHalf(int &numVertices)
Definition: openglosd.cpp:1558
cOglCmdDrawEllipse(cOglFb *fb, GLint x, GLint y, GLint width, GLint height, GLint color, GLint quadrants)
quadrants: 0 draws the entire ellipse 1..4 draws only the first, second, third or fourth quadrant,...
Definition: openglosd.cpp:1429
virtual bool Execute(void)
Definition: openglosd.cpp:1883
cOglCmdDrawImage(cOglFb *fb, tColor *argb, GLint width, GLint height, GLint x, GLint y, bool overlay=true, double scaleX=1.0f, double scaleY=1.0f)
Definition: openglosd.cpp:1867
virtual ~cOglCmdDrawImage(void)
Definition: openglosd.cpp:1879
GLfloat scaleY
Definition: openglosd.h:504
GLfloat scaleX
Definition: openglosd.h:504
tColor * argb
Definition: openglosd.h:501
virtual bool Execute(void)
Definition: openglosd.cpp:1391
cOglCmdDrawRectangle(cOglFb *fb, GLint x, GLint y, GLint width, GLint height, GLint color)
Definition: openglosd.cpp:1383
virtual bool Execute(void)
Definition: openglosd.cpp:1631
cOglCmdDrawSlope(cOglFb *fb, GLint x, GLint y, GLint width, GLint height, GLint color, GLint type)
type: 0: horizontal, rising, lower 1: horizontal, rising, upper 2: horizontal, falling,...
Definition: openglosd.cpp:1622
cOglCmdDrawText(cOglFb *fb, GLint x, GLint y, unsigned int *symbols, GLint limitX, const char *name, int fontSize, tColor colorText, int length)
Definition: openglosd.cpp:1699
cString fontName
Definition: openglosd.h:489
unsigned int * symbols
Definition: openglosd.h:491
virtual bool Execute(void)
Definition: openglosd.cpp:1715
virtual ~cOglCmdDrawText(void)
Definition: openglosd.cpp:1711
virtual bool Execute(void)
Definition: openglosd.cpp:1954
cOglCmdDrawTexture(cOglFb *fb, sOglImage *imageRef, GLint x, GLint y, double scaleX=1.0f, double scaleY=1.0f)
Definition: openglosd.cpp:1945
sOglImage * imageRef
Definition: openglosd.h:515
sOglImage * imageRef
Definition: openglosd.h:539
cOglCmdDropImage(sOglImage *imageRef, cCondWait *wait)
Definition: openglosd.cpp:2024
virtual bool Execute(void)
Definition: openglosd.cpp:2029
cCondWait * wait
Definition: openglosd.h:540
cOglCmdFill(cOglFb *fb, GLint color)
Definition: openglosd.cpp:1355
GLint color
Definition: openglosd.h:424
virtual bool Execute(void)
Definition: openglosd.cpp:1359
virtual bool Execute(void)
Definition: openglosd.cpp:1197
cOglCmdInitFb(cOglFb *fb, cCondWait *wait=NULL)
Definition: openglosd.cpp:1193
cCondWait * wait
Definition: openglosd.h:371
cOglCmdInitOutputFb(cOglOutputFb *oFb)
Definition: openglosd.cpp:1182
cOglOutputFb * oFb
Definition: openglosd.h:361
virtual bool Execute(void)
Definition: openglosd.cpp:1186
virtual bool Execute(void)
Definition: openglosd.cpp:1233
cOglCmdRenderFbToBufferFb(cOglFb *fb, cOglFb *buffer, GLint x, GLint y, GLint transparency, GLint drawPortX, GLint drawPortY, GLint dirtyX, GLint dirtyTop, GLint dirtyWidth, GLint dirtyHeight, bool alphablending, cSoftHdDevice *device)
Definition: openglosd.cpp:1217
cSoftHdDevice * Device
Definition: openglosd.h:399
virtual bool Execute(void)
Definition: openglosd.cpp:2001
sOglImage * imageRef
Definition: openglosd.h:528
cOglCmdStoreImage(sOglImage *imageRef, tColor *argb)
Definition: openglosd.cpp:1992
virtual ~cOglCmdStoreImage(void)
Definition: openglosd.cpp:1997
virtual bool Execute(void)=0
cOglFb * fb
Definition: openglosd.h:351
virtual const char * Description(void)=0
virtual void Unbind(void)
Definition: openglosd.cpp:954
GLint viewPortHeight
Definition: openglosd.h:265
GLint ViewportHeight(void)
Definition: openglosd.h:282
GLint height
Definition: openglosd.h:264
void Bind(void)
Definition: openglosd.cpp:939
GLint Height(void)
Definition: openglosd.h:279
GLint width
Definition: openglosd.h:264
virtual void BindWrite(void)
Definition: openglosd.cpp:950
virtual ~cOglFb(void)
Definition: openglosd.cpp:909
GLint ViewportWidth(void)
Definition: openglosd.h:281
GLint Width(void)
Definition: openglosd.h:278
bool Scrollable(void)
Definition: openglosd.h:280
bool initiated
Definition: openglosd.h:261
bool scrollable
Definition: openglosd.h:266
GLuint fb
Definition: openglosd.h:262
GLint viewPortWidth
Definition: openglosd.h:265
bool BindTexture(void)
Definition: openglosd.cpp:959
void BindRead(void)
Definition: openglosd.cpp:946
cOglFb(GLint width, GLint height, GLint viewPortWidth, GLint viewPortHeight)
Definition: openglosd.cpp:895
virtual bool Init(void)
Definition: openglosd.cpp:916
GLuint texture
Definition: openglosd.h:263
GLuint tex
Definition: openglosd.h:209
cOglAtlasGlyph * GetGlyph(int sym) const
Definition: openglosd.cpp:708
int Width(void) const
Definition: openglosd.h:220
virtual ~cOglFontAtlas(void)
Definition: openglosd.cpp:696
cOglAtlasGlyph * Glyph[MAX_CHARCODE - MIN_CHARCODE+1]
Definition: openglosd.h:213
int Height(void) const
Definition: openglosd.h:219
void BindTexture(void)
Definition: openglosd.cpp:715
cOglFontAtlas(FT_Face face, int height)
Definition: openglosd.cpp:526
int Height(void)
Definition: openglosd.h:249
static cList< cOglFont > * fonts
Definition: openglosd.h:236
static void Cleanup(void)
Definition: openglosd.cpp:786
cOglFontAtlas * Atlas(void)
Definition: openglosd.h:244
int Bottom(void)
Definition: openglosd.h:248
static void Init(void)
Definition: openglosd.cpp:777
cOglFontAtlas * atlas
Definition: openglosd.h:240
int size
Definition: openglosd.h:231
FT_Face face
Definition: openglosd.h:235
static cOglFont * Get(const char *name, int charHeight)
Definition: openglosd.cpp:763
virtual ~cOglFont(void)
Definition: openglosd.cpp:758
int Size(void)
Definition: openglosd.h:247
cList< cOglGlyph > glyphCache
Definition: openglosd.h:237
int Kerning(cOglGlyph *glyph, FT_ULong prevSym) const
Definition: openglosd.cpp:860
int bottom
Definition: openglosd.h:233
cOglFont(const char *fontName, int charHeight)
Definition: openglosd.cpp:726
int AtlasKerning(cOglAtlasGlyph *glyph, FT_ULong prevSym) const
Definition: openglosd.cpp:876
cOglGlyph * Glyph(FT_ULong charCode) const
Definition: openglosd.cpp:797
static FT_Library ftLib
Definition: openglosd.h:234
static bool initiated
Definition: openglosd.h:229
cString name
Definition: openglosd.h:230
int height
Definition: openglosd.h:232
const char * Name(void)
Definition: openglosd.h:246
int AdvanceX(void)
Definition: openglosd.h:152
void BindTexture(void)
Definition: openglosd.cpp:457
void SetKerningCache(FT_ULong prevSym, int kerning)
Definition: openglosd.cpp:453
FT_ULong charCode
Definition: openglosd.h:139
GLuint texture
Definition: openglosd.h:146
int width
Definition: openglosd.h:142
int BearingTop(void) const
Definition: openglosd.h:154
int bearingTop
Definition: openglosd.h:141
int advanceX
Definition: openglosd.h:144
void LoadTexture(FT_BitmapGlyph ftGlyph)
Definition: openglosd.cpp:461
int Height(void) const
Definition: openglosd.h:156
virtual ~cOglGlyph()
Definition: openglosd.cpp:440
int height
Definition: openglosd.h:143
int BearingLeft(void) const
Definition: openglosd.h:153
int bearingLeft
Definition: openglosd.h:140
int Width(void) const
Definition: openglosd.h:155
FT_ULong CharCode(void)
Definition: openglosd.h:151
cOglGlyph(FT_ULong charCode, FT_BitmapGlyph ftGlyph)
Definition: openglosd.cpp:430
cVector< tKerning > kerningCache
Definition: openglosd.h:145
int GetKerningCache(FT_ULong prevSym)
Definition: openglosd.cpp:445
virtual ~cOglOsd()
Definition: openglosd.cpp:2754
static cOglOutputFb * oFb
Definition: openglosd.h:657
virtual cPixmap * CreatePixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort=cRect::Null)
Definition: openglosd.cpp:2795
cOglOsd(int Left, int Top, uint Level, std::shared_ptr< cOglThread > oglThread, cSoftHdDevice *device)
Definition: openglosd.cpp:2729
std::shared_ptr< cOglThread > oglThread
Definition: openglosd.h:640
cOglFb * bFb
Definition: openglosd.h:639
virtual void Flush(void)
Definition: openglosd.cpp:2836
cSize maxPixmapSize
Definition: openglosd.h:643
bool isSubtitleOsd
Definition: openglosd.h:642
cSoftHdDevice * Device
Definition: openglosd.h:645
virtual void DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double FactorX, double FactorY, bool AntiAlias=false)
Definition: openglosd.cpp:2905
cRect * dirtyViewport
Definition: openglosd.h:644
virtual const cSize & MaxPixmapSize(void) const
Definition: openglosd.cpp:2769
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas)
Definition: openglosd.cpp:2773
cVideoRender * Render
Definition: openglosd.h:646
virtual void DestroyPixmap(cPixmap *Pixmap)
Definition: openglosd.cpp:2815
cVector< cOglPixmap * > oglPixmaps
Definition: openglosd.h:641
virtual ~cOglOutputFb(void)
Definition: openglosd.cpp:978
virtual void Unbind(void)
Definition: openglosd.cpp:1016
GLuint texture
Definition: openglosd.h:293
virtual bool Init(void)
Definition: openglosd.cpp:985
cOglOutputFb(GLint width, GLint height)
Definition: openglosd.cpp:970
GLuint fb
Definition: openglosd.h:292
virtual void BindWrite(void)
Definition: openglosd.cpp:1009
virtual void DrawImage(const cPoint &Point, const cImage &Image)
Definition: openglosd.cpp:2427
virtual void DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX=1.0f, double FactorY=1.0f, bool AntiAlias=false)
virtual void Clear(void)
Definition: openglosd.cpp:2409
virtual void SetClean(void)
Definition: openglosd.cpp:2375
virtual void Fill(tColor Color)
Definition: openglosd.cpp:2418
bool dirty
Definition: openglosd.h:595
virtual void Render(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
Definition: openglosd.cpp:2614
virtual void SetAlpha(int Alpha)
Definition: openglosd.cpp:2385
virtual void MarkViewPortDirty(const cRect &Rect)
Definition: openglosd.cpp:2370
virtual void Copy(const cPixmap *Pixmap, const cRect &Source, const cPoint &Dest)
Definition: openglosd.cpp:2618
virtual ~cOglPixmap(void)
Definition: openglosd.cpp:2361
virtual void SetDrawPortPoint(const cPoint &Point, bool Dirty=true)
Definition: openglosd.cpp:2403
virtual void DrawEllipse(const cRect &Rect, tColor Color, int Quadrants=0)
Definition: openglosd.cpp:2586
virtual void SetViewPort(const cRect &Rect)
Definition: openglosd.cpp:2398
virtual void Scroll(const cPoint &Dest, const cRect &Source=cRect::Null)
Definition: openglosd.cpp:2622
virtual void SetDirty(bool dirty=true)
Definition: openglosd.h:608
cOglPixmap(std::shared_ptr< cOglThread > oglThread, int Layer, const cRect &ViewPort, const cRect &DrawPort=cRect::Null)
Definition: openglosd.cpp:2340
virtual void Pan(const cPoint &Dest, const cRect &Source=cRect::Null)
Definition: openglosd.cpp:2626
virtual void DrawRectangle(const cRect &Rect, tColor Color)
Definition: openglosd.cpp:2572
virtual void DrawSlope(const cRect &Rect, tColor Color, int Type)
Definition: openglosd.cpp:2600
virtual void DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width=0, int Height=0, int Alignment=taDefault)
Definition: openglosd.cpp:2502
virtual void DrawPixel(const cPoint &Point, tColor Color)
Definition: openglosd.cpp:2465
std::shared_ptr< cOglThread > oglThread
Definition: openglosd.h:594
virtual void DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg=0, tColor ColorBg=0, bool Overlay=false)
Definition: openglosd.cpp:2475
virtual void SetLayer(int Layer)
Definition: openglosd.cpp:2380
virtual void SetTile(bool Tile)
Definition: openglosd.cpp:2393
cOglFb * fb
Definition: openglosd.h:593
std::queue< cOglCmd * > commands
Definition: openglosd.h:559
long maxCacheSize
Definition: openglosd.h:563
long memCached
Definition: openglosd.h:562
int StoreImage(const cImage &image)
Definition: openglosd.cpp:2091
cVideoRender * Render
Definition: openglosd.h:574
sOglImage * GetImageRef(int slot)
Definition: openglosd.cpp:2173
bool InitOpenGL(void)
Definition: openglosd.cpp:2273
bool InitVertexBuffers(void)
Definition: openglosd.cpp:2311
GLint maxTextureSize
Definition: openglosd.h:560
void eglReleaseContext(void)
Definition: openglosd.cpp:2268
sOglImage imageCache[OGL_MAX_OSDIMAGES]
Definition: openglosd.h:561
int GetFreeSlot(void)
Definition: openglosd.cpp:2148
cCondWait * startWait
Definition: openglosd.h:556
void Stop(void)
Definition: openglosd.cpp:2062
bool InitShaders(void)
Definition: openglosd.cpp:2295
virtual ~cOglThread()
Definition: openglosd.cpp:2057
cOglThread(cCondWait *startWait, int maxCacheSize, cSoftHdDevice *device)
Definition: openglosd.cpp:2039
void Cleanup(void)
Definition: openglosd.cpp:2328
void DeleteShaders(void)
Definition: openglosd.cpp:2306
bool stalled
Definition: openglosd.h:558
virtual void Action(void)
Definition: openglosd.cpp:2192
cCondWait * wait
Definition: openglosd.h:557
void ClearSlot(int slot)
Definition: openglosd.cpp:2161
void DoCmd(cOglCmd *cmd)
Definition: openglosd.cpp:2072
void DropImageData(int imageHandle)
Definition: openglosd.cpp:2180
void DeleteVertexBuffers(void)
Definition: openglosd.cpp:2322
void eglAcquireContext(void)
Definition: openglosd.cpp:2263
GLuint texCoordsLoc
Definition: openglosd.h:322
int sizeVertex1
Definition: openglosd.h:323
void EnableBlending(void)
Definition: openglosd.cpp:1122
void SetVertexSubData(GLfloat *vertices, int count=0)
Definition: openglosd.cpp:1156
void SetShaderProjectionMatrix(GLint width, GLint height)
Definition: openglosd.cpp:1151
void SetShaderTexture(GLint value)
Definition: openglosd.cpp:1143
int numVertices
Definition: openglosd.h:325
void SetShaderColor(GLint color)
Definition: openglosd.cpp:1131
void DisableBlending(void)
Definition: openglosd.cpp:1127
GLuint positionLoc
Definition: openglosd.h:321
void Bind(void)
Definition: openglosd.cpp:1104
void SetShaderBorderColor(GLint bcolor)
Definition: openglosd.cpp:1137
eShaderType shader
Definition: openglosd.h:318
void DrawArrays(int count=0)
Definition: openglosd.cpp:1172
void SetShaderAlpha(GLint alpha)
Definition: openglosd.cpp:1147
void ActivateShader(void)
Definition: openglosd.cpp:1118
void SetVertexData(GLfloat *vertices, int count=0)
Definition: openglosd.cpp:1164
GLuint vbo
Definition: openglosd.h:320
bool Init(void)
Definition: openglosd.cpp:1041
GLuint drawMode
Definition: openglosd.h:326
eVertexBufferType type
Definition: openglosd.h:317
cOglVb(int type)
Definition: openglosd.cpp:1027
void Unbind(void)
Definition: openglosd.cpp:1114
int sizeVertex2
Definition: openglosd.h:324
virtual ~cOglVb(void)
Definition: openglosd.cpp:1038
void SetMatrix4(const GLchar *name, const glm::mat4 &matrix)
Definition: openglosd.cpp:372
void Use(void)
Definition: openglosd.cpp:308
void SetInteger(const GLchar *name, GLint value)
Definition: openglosd.cpp:356
void SetVector2f(const GLchar *name, GLfloat x, GLfloat y)
Definition: openglosd.cpp:360
void SetFloat(const GLchar *name, GLfloat value)
Definition: openglosd.cpp:352
bool Compile(const char *vertexCode, const char *fragmentCode)
Definition: openglosd.cpp:376
void SetVector3f(const GLchar *name, GLfloat x, GLfloat y, GLfloat z)
Definition: openglosd.cpp:364
bool CheckCompileErrors(GLuint object, bool program=false)
Definition: openglosd.cpp:405
eShaderType type
Definition: openglosd.h:108
void SetVector4f(const GLchar *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
Definition: openglosd.cpp:368
bool Load(eShaderType type)
Definition: openglosd.cpp:312
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.
cVideoRender * Render(void)
Definition: softhddevice.h:176
void OsdClose(void)
Close the OSD.
cVideoRender - Video render class
Definition: videorender.h:122
Some helper functions for GL.
#define GL_CHECK(stmt)
Definition: glhelpers.h:55
#define EGL_CHECK(stmt)
Definition: glhelpers.h:60
Logger class header file.
#define LOGDEBUG2
Definition: logger.h:50
#define L_OPENGL_TIME_ALL
Definition: logger.h:69
#define LOGERROR
Definition: logger.h:46
#define L_OPENGL_TIME
Definition: logger.h:68
#define LOGWARNING
Definition: logger.h:47
#define L_OPENGL
Definition: logger.h:67
#define LOGINFO
Definition: logger.h:48
#define L_OSD
Definition: logger.h:61
#define BORDERCOLOR
Definition: openglosd.cpp:46
void ConvertColor(const GLint &colARGB, glm::vec4 &col)
Definition: openglosd.cpp:161
const char * textureFragmentShaderSwapBR
Definition: openglosd.cpp:245
const char * rectVertexShader
Definition: openglosd.cpp:171
static cOglVb * VertexBuffers[vbCount]
Definition: openglosd.cpp:1025
const char * textureFragmentShader
Definition: openglosd.cpp:220
const char * rectFragmentShader
Definition: openglosd.cpp:186
const char * textFragmentShader
Definition: openglosd.cpp:291
static cShader * Shaders[stCount]
Definition: openglosd.cpp:306
const char * textureVertexShader
Definition: openglosd.cpp:197
#define KERNING_UNKNOWN
Definition: openglosd.cpp:426
const char * textVertexShader
Definition: openglosd.cpp:271
Osd class - hardware accelerated (OpenGL/ES) - header file.
#define OGL_MAX_OSDIMAGES
Definition: openglosd.h:551
const char * message
Definition: openglosd.h:59
#define MIN_CHARCODE
Definition: openglosd.h:205
const struct @0 FT_Errors[]
int code
Definition: openglosd.h:58
eShaderType
Definition: openglosd.h:98
@ stText
Definition: openglosd.h:102
@ stCount
Definition: openglosd.h:103
@ stTextureSwapBR
Definition: openglosd.h:101
@ stRect
Definition: openglosd.h:99
@ stTexture
Definition: openglosd.h:100
eVertexBufferType
Definition: openglosd.h:305
@ vbSlope
Definition: openglosd.h:308
@ vbCount
Definition: openglosd.h:312
@ vbText
Definition: openglosd.h:311
@ vbTexture
Definition: openglosd.h:309
@ vbEllipse
Definition: openglosd.h:307
@ vbRect
Definition: openglosd.h:306
@ vbTextureSwapBR
Definition: openglosd.h:310
#define MAX_CHARCODE
Definition: openglosd.h:206
#define OGL_CMDQUEUE_SIZE
Definition: openglosd.h:552