]> git.vomp.tv Git - vompclient.git/blob - osdopenvg.cc
Roll OsdOpenVG::haveOpenVGResponse into putOpenVGCommand
[vompclient.git] / osdopenvg.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>  // really?
21 #include <chrono>
22 #include <sys/syscall.h>
23 #include <fontconfig/fontconfig.h>
24 #include <math.h>
25 #include <bcm_host.h>
26
27 #include "videoomx.h"
28 #include "surface.h"
29 #include "message.h"
30 #include "messagequeue.h"
31 #include "teletxt/txtfont.h"
32
33 #include "osdopenvg.h"
34
35 #define EXTERNALPICTURE(name, fname, fileextension)  extern uint8_t name ## _data[]  asm("_binary_other_"#fname"_"#fileextension"_start"); \
36                                                                                                          extern uint8_t name ## _data_end[]  asm("_binary_other_"#fname"_"#fileextension"_end");
37
38 EXTERNAL_PICTS
39
40 #undef EXTERNALPICTURE
41
42 #define  BACKBUFFER_WIDTH 1280
43 #define  BACKBUFFER_HEIGHT 720
44
45 OsdOpenVG::OsdOpenVG()
46 {
47   vgmutex.lock();
48   taskmutex.lock();
49   lastrendertime = getTimeMS();
50
51   const char* fontname = "Droid Sans:style=Regular";
52   cur_fontname = static_cast<char*>(malloc(strlen(fontname) + 1));
53   strcpy(cur_fontname, fontname);
54
55 #define EXTERNALPICTURE(name, fname, fileextension) static_artwork_begin[sa_ ## name]=name ## _data;
56
57   EXTERNAL_PICTS
58
59 #undef EXTERNALPICTURE
60 #define EXTERNALPICTURE(name, fname, fileextension) static_artwork_end[sa_ ## name]=name ## _data_end;
61
62   EXTERNAL_PICTS
63
64 #undef EXTERNALPICTURE
65 }
66
67 OsdOpenVG::~OsdOpenVG()
68 {
69   if (initted) shutdown();
70
71   if (cur_fontname) free(cur_fontname);
72
73   if (freetype_inited) FT_Done_Face(ft_face);
74
75   // I think the following is broken as it is, but also possibly it shouldn't be free()ing the memory
76   // pointed at anyway, so it's correctly not working?!
77
78   if (!fontnames.size())
79   {
80     std::vector<char*>::iterator itty = fontnames.begin();
81
82     while (itty != fontnames.end())
83     {
84       free(*itty);
85       itty++;
86     }
87   }
88
89   // end
90
91
92   if (fontnames_keys.size())
93   {
94     std::vector<char*>::iterator itty = fontnames_keys.begin();
95
96     while (itty != fontnames_keys.end())
97     {
98       free(*itty);
99       itty++;
100     }
101   }
102
103   vgmutex.unlock();
104   taskmutex.unlock();
105 }
106
107 int OsdOpenVG::init()
108 {
109   if (initted) return 0;
110
111   reader.init();
112
113   //First get connection to egl
114   egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
115   if (egl_display == EGL_NO_DISPLAY)
116   {
117     Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x", eglGetError());
118     vgmutex.unlock();
119     return 0;
120   }
121
122   if (eglInitialize(egl_display, NULL, NULL) == EGL_FALSE)
123   {
124     Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x", eglGetError());
125     vgmutex.unlock();
126     return 0;
127   }
128
129   const char* query_str = eglQueryString(egl_display, EGL_CLIENT_APIS);
130
131   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
132   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x", eglGetError());
133
134   query_str = eglQueryString(egl_display, EGL_EXTENSIONS);
135
136   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
137   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x", eglGetError());
138
139   if (eglBindAPI(EGL_OPENVG_API) == EGL_FALSE)
140   {
141     Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api failed! %x", eglGetError());
142     vgmutex.unlock();
143     return 0;
144   }
145
146   const EGLint attributs[] =
147   {
148     EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
149     EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
150     EGL_CONFORMANT, EGL_OPENVG_BIT,
151     EGL_NONE
152   }; // Here, we might have to select the resolution!
153
154   EGLint number;
155
156   if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number) == EGL_FALSE)
157   {
158     Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x", eglGetError());
159     vgmutex.unlock();
160     return 0;
161   }
162
163   egl_context = eglCreateContext(egl_display, egl_ourconfig, NULL, NULL);
164
165   if (egl_context == EGL_NO_CONTEXT)
166   {
167     Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x", eglGetError());
168     vgmutex.unlock();
169     return 0;
170   }
171
172   // warning broadcom specific, get display size!
173   display_width = display_height = 0;
174
175   if (graphics_get_display_size(0, &display_width, &display_height) < 0)
176   {
177     Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");
178     vgmutex.unlock();
179     return 0;
180   }
181
182   Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ", display_width, display_height);
183   VC_RECT_T dst_rect = {0, 0, (int32_t)display_width, (int32_t)display_height};
184   VC_RECT_T src_rect = {0, 0, BACKBUFFER_WIDTH << 16, BACKBUFFER_HEIGHT << 16};
185   VC_RECT_T src_rect_bg = {0, 0, 16 << 16, 16 << 16};
186   //   VC_RECT_T src_rect_im={0,0,16,16};
187
188   uint32_t back_image_ptr;
189   bcm_backres = vc_dispmanx_resource_create(VC_IMAGE_RGBX32, 16, 16, &back_image_ptr);
190
191   updateBackgroundColor(DrawStyle::WALLPAPER);
192
193   DISPMANX_UPDATE_HANDLE_T  bcm_update;
194   bcm_display = vc_dispmanx_display_open(0);
195   bcm_update = vc_dispmanx_update_start(0);
196   bcm_element = vc_dispmanx_element_add(bcm_update, bcm_display,
197                                         2, &dst_rect, 0,
198                                         &src_rect, DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T) 0);
199
200
201   bcm_background = vc_dispmanx_element_add(bcm_update, bcm_display,
202                    0, &dst_rect, bcm_backres,
203                    &src_rect_bg, DISPMANX_PROTECTION_NONE, 0, 0, (DISPMANX_TRANSFORM_T) 0);
204
205   vc_dispmanx_update_submit_sync(bcm_update);
206
207   static EGL_DISPMANX_WINDOW_T nativewindow;
208   nativewindow.element = bcm_element;
209   nativewindow.height = BACKBUFFER_HEIGHT;
210   nativewindow.width = BACKBUFFER_WIDTH;
211
212   egl_surface = eglCreateWindowSurface(egl_display, egl_ourconfig, &nativewindow, NULL);
213   if (egl_surface == EGL_NO_SURFACE)
214   {
215     Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");
216     vgmutex.unlock();
217     return 0;
218   }
219
220   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current in1%d", syscall(SYS_gettid));
221
222   if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) == EGL_FALSE)
223   {
224     Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");
225     vgmutex.unlock();
226     return 0;
227   }
228
229   // Test stuff
230
231   query_str = reinterpret_cast<const char*>(vgGetString(VG_VERSION));
232
233   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
234   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x", vgGetError());
235
236   query_str = reinterpret_cast<const char*>(vgGetString(VG_VENDOR));
237
238   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
239   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x", vgGetError());
240
241   query_str = reinterpret_cast<const char*>(vgGetString(VG_RENDERER));
242
243   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
244   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x", vgGetError());
245
246   query_str = reinterpret_cast<const char*>(vgGetString(VG_EXTENSIONS));
247
248   if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
249   else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x", vgGetError());
250
251   aspect_correction = ((float)BACKBUFFER_HEIGHT) / 576.f / (((float)BACKBUFFER_WIDTH) / 720.f);
252   initPaths();
253
254   if (!fontnames.size())
255   {
256     //inspired by and copied from vdr's code
257     FcInit();
258     FcObjectSet* objset = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
259     FcPattern* pattern = FcPatternCreate();
260     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
261     FcFontSet* fonts = FcFontList(NULL, pattern, objset);
262
263     for (int i = 0; i < fonts->nfont; i++)
264     {
265       char* s = (char*)FcNameUnparse(fonts->fonts[i]);
266
267       if (s)
268       {
269         char* c = strchr(s, ':');
270
271         if (c)
272         {
273           char* s2 = strchr(c + 1, ',');
274
275           if (s2) *s2 = 0;
276         }
277
278         char* p = strchr(s, ',');
279
280         if (p)
281         {
282           if (!c) *p = 0;
283           else memmove(p, c, strlen(c) + 1);
284         }
285
286         char* key = (char*)malloc(strlen(s) + 1);
287         strcpy(key, s);
288         fontnames_keys.push_back(key);
289         char* s2 = strstr(s, "style=");
290
291         if (s2)
292         {
293           memmove(s2, s2 + 6, strlen(s2 + 6) + 1);
294         }
295
296         fontnames.push_back(s);
297       }
298     }
299
300     FcFontSetDestroy(fonts);
301     FcPatternDestroy(pattern);
302     FcObjectSetDestroy(objset);
303   }
304
305   if (!loadFont(false))
306   {
307     return 0;
308   }
309
310   vgttfont = vgCreateFont(0);
311   vgttpaint = vgCreatePaint();
312   vgSetParameteri( vgttpaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
313   vgSetColor(vgttpaint, 0xffffffff);
314
315   eglSwapInterval(egl_display, 1);
316
317   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out 1%d", syscall(SYS_gettid));
318   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
319   //Now we will create the Screen
320   initted = true; // must set this here or create surface won't work
321
322   /*if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init  stuff
323     return 0;
324   }*/
325
326   threadStart();
327   taskmutex.unlock();
328   vgmutex.unlock();
329
330 #ifdef PICTURE_DECODER_OMX
331   imageomx = new ImageOMX(&reader);
332   reader.addDecoder(imageomx);
333 #endif
334
335   return 1;
336 }
337
338 void OsdOpenVG::updateBackgroundColor(DrawStyle bg)
339 {
340   unsigned int color[16 * 16];
341
342   if (!bcm_backres) return;
343
344   VC_RECT_T src_rect_im = {0, 0, 16, 16};
345
346   if (bg.ft != DrawStyle::GradientLinear)
347   {
348     bg.grad_col[0] = bg;
349   }
350
351   //memset(color,0xFF,sizeof(unsigned int)*4*8);
352   for (int j = 0; j < 16; j++)
353   {
354     int helpr = (((15 - j) * bg.red) + (j * bg.grad_col[0].red)) / 15;
355     int helpb = (((15 - j) * bg.blue) + (j * bg.grad_col[0].blue)) / 15;
356     int helpg = (((15 - j) * bg.green) + (j * bg.grad_col[0].green)) / 15;
357     //unsigned int cur_col=help | (help<< 8)  | (help<< 16)  | (0xFF<< 24);
358     unsigned int cur_col = helpr  | (helpg << (8))  | (helpb << (16))  | (0xFF << (24));
359
360     for (int i = 0; i < 16; i++)
361     {
362       color[i + 16 * j] = cur_col;
363     }
364   }
365
366   vc_dispmanx_resource_write_data(bcm_backres, VC_IMAGE_RGBX32, 16 * 4, color, &src_rect_im);
367 }
368
369 void OsdOpenVG::getScreenSize(int& width, int& height)
370 {
371   width = BACKBUFFER_WIDTH;
372   height = BACKBUFFER_HEIGHT;
373 }
374
375 void OsdOpenVG::getRealScreenSize(int& width, int& height)
376 {
377   width = display_width;
378   height = display_height;
379 }
380
381 bool OsdOpenVG::screenShot(void* buffer, int width, int height, bool osd /*include osd*/)
382 {
383   if (!initted) return false;
384
385   if (!buffer) return false;
386
387   DISPMANX_RESOURCE_HANDLE_T res;
388   DISPMANX_DISPLAY_HANDLE_T display;
389
390   uint32_t image_ptr;
391   VC_RECT_T rect;
392   res = vc_dispmanx_resource_create(VC_IMAGE_RGBA32, width, height, &image_ptr);
393   display = vc_dispmanx_display_open(0);
394
395   if (!osd)
396   {
397     vc_dispmanx_snapshot(display, res,
398                          static_cast<DISPMANX_TRANSFORM_T>(DISPMANX_SNAPSHOT_NO_RGB | DISPMANX_SNAPSHOT_FILL/*|DISPMANX_SNAPSHOT_PACK*/));
399   }
400   else
401   {
402     vc_dispmanx_snapshot(display, res,
403                          static_cast<DISPMANX_TRANSFORM_T>(DISPMANX_SNAPSHOT_FILL));
404   }
405
406   vc_dispmanx_rect_set(&rect, 0, 0, width, height);
407   vc_dispmanx_resource_read_data(res, &rect, buffer, width * 4);
408   vc_dispmanx_resource_delete(res);
409   vc_dispmanx_display_close(display);
410   return true;
411 }
412
413 void OsdOpenVG::initPaths()
414 {
415   VGPath current;
416   current = vgCreatePath(VG_PATH_FORMAT_STANDARD,
417                          VG_PATH_DATATYPE_F, 1.f, 0.f,
418                          0, 0, VG_PATH_CAPABILITY_ALL);
419
420   vguLine(current, 0.f, 0.f, 1.f, 0.f);
421   // HorzLine
422   std_paths[PIHorzLine] = current;
423
424   current = vgCreatePath(VG_PATH_FORMAT_STANDARD,
425                          VG_PATH_DATATYPE_F, 1.f, 0.f,
426                          0, 0, VG_PATH_CAPABILITY_ALL);
427   vguLine(current, 0.f, 0.f, 0.f, 1.f);
428   // VertLine
429   std_paths[PIVertLine] = current;
430
431   current = vgCreatePath(VG_PATH_FORMAT_STANDARD,
432                          VG_PATH_DATATYPE_F, 1.f, 0.f,
433                          0, 0, VG_PATH_CAPABILITY_ALL);
434   //vguRect(current,0.f,0.f,1.f,1.f);
435   vguRect(current, 0.f, 0.f, 1.f, 1.f);
436   // Rectabgle
437   std_paths[PIRectangle] = current;
438
439   current = vgCreatePath(VG_PATH_FORMAT_STANDARD,
440                          VG_PATH_DATATYPE_F, 1.f, 0.f,
441                          0, 0, 0);
442   vguEllipse(current, 0.f, 0.f, 1.f, 1.f);
443   // Point
444   std_paths[PIPoint] = current;
445 }
446
447 void OsdOpenVG::destroyPaths()
448 {
449   vgDestroyPath(std_paths[PIHorzLine]);
450   vgDestroyPath(std_paths[PIVertLine]);
451   vgDestroyPath(std_paths[PIRectangle]);
452   vgDestroyPath(std_paths[PIPoint]);
453 }
454
455 int OsdOpenVG::stopUpdate()
456 {
457   threadStop();
458   processTasks();
459   return 1;
460 }
461
462 /*
463 void OsdOpenVG::purgeAllReferences()
464 {
465         images_ref.clear();
466         drawstyleHandlesRefCounts.clear(); // remove all references
467
468
469         map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
470         while (mitty!=monobitmaps.end()) {
471                 vgDestroyImage((VGImage)(*mitty).second);
472                 mitty++;
473         }
474         monobitmaps.clear();
475
476         / *map<string,ImageIndex>::iterator jitty=jpegs.begin();
477         while (jitty!=jpegs.end()) {
478                 vgDestroyImage((VGImage)(*jitty).second);
479                 jitty++;
480         }
481         jpegs.clear();* /
482
483         map<TVMediaInfo,ImageIndex>::iterator titty=tvmedias.begin();
484         while (titty!=tvmedias.end()) {
485                 vgDestroyImage((VGImage)(*titty).second);
486                 titty++;
487         }
488         tvmedias.clear();
489
490         map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=drawstyleHandles.begin();
491         while (sitty!=drawstyleHandles.end()) {
492                 vgDestroyPaint((VGPaint)(*sitty).second);
493                 sitty++;
494         }
495         drawstyleHandles.clear();
496
497 }*/
498
499 int OsdOpenVG::shutdown()
500 {
501   reader.shutdown();
502
503 #ifdef PICTURE_DECODER_OMX
504   if (imageomx) reader.removeDecoder(imageomx);
505   imageomx = NULL;
506 #endif
507
508   if (!initted) return 0;
509
510   initted = false;
511   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1");
512   threadStop();
513   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1a");
514
515   //(((VideoOMX*)Video::getInstance())->shutdownUsingOSDObjects());
516   if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) == EGL_FALSE)
517   {
518     Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in shutdown %x", eglGetError());
519   }
520
521   if (eglBindAPI(EGL_OPENVG_API) == EGL_FALSE)
522   {
523     Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api thread failed! %x", eglGetError());
524   }
525
526   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark2");
527   processTasks();
528   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark3");
529
530   taskmutex.lock();
531   vgmutex.lock();
532
533   //purgeAllReferences();
534
535   vgDestroyFont(vgfont);
536   vgDestroyFont(vgttfont);
537   vgDestroyPaint(vgttpaint);
538   destroyPaths();
539   float colclear[] = {0.8f, 0.8f, 0.8f, 1.f};
540   vgSetfv(VG_CLEAR_COLOR, 4, colclear);
541   vgClear(0, 0, BACKBUFFER_WIDTH, BACKBUFFER_HEIGHT);
542   eglSwapBuffers(egl_display, egl_surface);
543   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out final");
544   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
545
546   if (eglDestroySurface(egl_display, egl_surface) == EGL_FALSE)
547   {
548     Log::getInstance()->log("OSD", Log::ERR, "eglDestroySurface failed %x", eglGetError());
549   }
550
551   if (eglDestroyContext(egl_display, egl_context) == EGL_FALSE)
552   {
553     Log::getInstance()->log("OSD", Log::ERR, "eglDestroyContext failed %x", eglGetError());
554   }
555
556   if (eglTerminate(egl_display ) == EGL_FALSE)
557   {
558     Log::getInstance()->log("OSD", Log::ERR, "eglTerminate failed %x", eglGetError());
559   }
560
561   DISPMANX_UPDATE_HANDLE_T  bcm_update;
562   bcm_update = vc_dispmanx_update_start(0);
563
564   vc_dispmanx_element_remove(bcm_update, bcm_element);
565   vc_dispmanx_element_remove(bcm_update, bcm_background);
566   vc_dispmanx_update_submit_sync(bcm_update);
567   vc_dispmanx_resource_delete(bcm_backres);
568   bcm_backres = 0;
569   vc_dispmanx_display_close(bcm_display);
570   return 1;
571 }
572
573 void OsdOpenVG::threadMethod()
574 {
575   // We have to claim the egl context for this thread
576   Log::getInstance()->log("OSD", Log::NOTICE, "Entering drawing thread");
577
578   if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) == EGL_FALSE)
579   {
580     Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %x", eglGetError());
581     return;
582   }
583
584   if (eglBindAPI(EGL_OPENVG_API) == EGL_FALSE)
585   {
586     Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api thread failed! %x", eglGetError());
587     return;
588   }
589
590   int ts;
591
592   while (true)
593   {
594     ts = 1;
595
596     if (initted)
597     {
598       long long time1 = getTimeMS();
599
600       if ((time1 - lastrendertime) > 200)  //5 fps for OSD updates are enough, avoids tearing
601       {
602         #if DEV
603         dumpStyles();
604         #endif
605
606         InternalRendering();
607         lastrendertime = getTimeMS();
608
609         ts = 10;
610       }
611       else
612       {
613         ts = time1 - lastrendertime;
614       }
615
616       if (processTasks()) ts = 0;
617     }
618
619     if (!threadIsActive())
620     {
621       if (eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ) == EGL_FALSE)
622       {
623         Log::getInstance()->log("OSD", Log::WARN, "Making egl Current out thread failed");
624       }
625
626       threadCheckExit();
627     }
628
629     if (ts != 0)
630     {
631       struct timespec target_time;
632       clock_gettime(CLOCK_REALTIME, &target_time);
633       target_time.tv_nsec += 1000000LL * ts;
634
635       if (target_time.tv_nsec > 999999999)
636       {
637         target_time.tv_nsec -= 1000000000L;
638         target_time.tv_sec += 1;
639       }
640
641       threadLock();
642       threadWaitForSignalTimed(&target_time);
643       threadUnlock();
644     }
645   }
646
647   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
648 }
649
650 void OsdOpenVG::InternalRendering()
651 {
652   vgmutex.lock();
653   Colour bg = DrawStyle::WALLPAPER;
654   float colclear[] = {1.f, 1.0f, 1.f, 1.f};
655
656   if (bg.alpha == 0) colclear[3] = 0.f;
657
658   vgSetfv(VG_CLEAR_COLOR, 4, colclear);
659   vgClear(0, 0, BACKBUFFER_WIDTH, BACKBUFFER_HEIGHT);
660   vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
661
662   drawSurfaces(); //iterate through and draws all commands
663
664   //Show it to the user!
665   eglSwapBuffers(egl_display, egl_surface);
666   vgmutex.unlock();
667 }
668
669 /*font stuff*/
670
671 float OsdOpenVG::getFontHeight()
672 {
673   return font_height; //dummy
674 }
675
676 float OsdOpenVG::getCharWidth(wchar_t c)
677 {
678   if (c < 256) return byte_char_width[c];
679
680   unsigned int glyph_index = FT_Get_Char_Index(ft_face, c);
681   return font_exp_x[glyph_index];
682 }
683
684 unsigned int OsdOpenVG::loadTTchar(cTeletextChar c)
685 {
686   unsigned int glyph_index = c.getGlyphIndex();
687
688   if (tt_font_chars.find(glyph_index) != tt_font_chars.end())
689   {
690     return glyph_index;
691   }
692
693   unsigned int buffer[10];
694   const VGfloat glyphOrigin[] = { 0.f, 0.f };
695   const VGfloat escapement[] = { 12.f, 0.f };
696   unsigned int* charmap = GetFontChar(c, buffer);
697
698   if (!charmap) return 0; //invalid char
699
700   for (int i = 0; i < 10; i++)
701   {
702     buffer[i] = charmap[i] >> 4;
703   }
704
705   VGImage handle = vgCreateImage(
706                      VG_A_8,
707                      12,
708                      10,
709                      VG_IMAGE_QUALITY_NONANTIALIASED | VG_IMAGE_QUALITY_FASTER
710                      | VG_IMAGE_QUALITY_BETTER);
711   vgImageSubData(handle, buffer, 4, VG_A_1, 0, 0, 12, 10);
712   vgSetGlyphToImage(
713     vgttfont,
714     glyph_index,
715     handle, const_cast<VGfloat*>(glyphOrigin), const_cast<VGfloat*>(escapement));
716   vgDestroyImage(handle);
717   tt_font_chars[glyph_index] = 1;
718
719   return glyph_index;
720 }
721
722 int OsdOpenVG::getFontNames(const char*** names, const char*** names_keys)
723 {
724   *names = const_cast<const char**>(&(fontnames[0]));
725   *names_keys = const_cast<const char**>(&(fontnames_keys[0]));
726   return fontnames.size();
727 }
728
729 void OsdOpenVG::setFont(const char* fontname)
730 {
731   if (strcmp(fontname, cur_fontname))
732   {
733     // new font!
734     if (cur_fontname) free(cur_fontname);
735
736     cur_fontname = static_cast<char*>(malloc(strlen(fontname) + 1));
737     strcpy(cur_fontname, fontname);
738
739     struct OpenVGCommand comm;
740     comm.task = OVGreplacefont;
741     putOpenVGCommand(comm, false);
742   }
743 }
744
745 int OsdOpenVG::loadFont(bool newfont)
746 {
747   int error;
748   float font_size = 16.f;
749
750   if (!freetype_inited)
751   {
752     error = FT_Init_FreeType(&ft_library);
753
754     if (error)
755     {
756       Log::getInstance()->log("OSD", Log::WARN, "Could not load freetype %x", error);
757       return 0;
758     }
759   }
760
761   if (!freetype_inited || newfont)
762   {
763     //first get the filename algorith extracted from vdr by Klaus Schmidinger
764     FcInit();
765     FcPattern* pattern = FcNameParse(reinterpret_cast<FcChar8*>(cur_fontname));
766     FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
767     FcConfigSubstitute(NULL, pattern, FcMatchPattern);
768     FcDefaultSubstitute(pattern);
769     FcResult fres;
770     FcFontSet* fonts = FcFontSort(NULL, pattern, FcFalse, NULL, &fres);
771     FcChar8* filename = NULL;
772
773     if (fonts)
774     {
775       for (int i = 0; i < fonts->nfont; i++)
776       {
777         FcBool canscale;
778         FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &canscale);
779
780         if (canscale)
781         {
782           FcPatternGetString(fonts->fonts[i], FC_FILE, 0, &filename);
783           break;
784         }
785       }
786
787       FcFontSetDestroy(fonts);
788     }
789     else
790     {
791       Log::getInstance()->log("OSD", Log::CRIT, "Could not locate a font! Abort!");
792       return 0;
793     }
794
795     FcPatternDestroy(pattern);
796
797     Log::getInstance()->log("OSD", Log::NOTICE, "Load Font %s: %s", cur_fontname, filename);
798     // second load the font
799     FT_Face new_ft_face;
800     error = FT_New_Face(ft_library, reinterpret_cast<const char*>(filename), 0, &new_ft_face);
801
802     if (error)
803     {
804       Log::getInstance()->log("OSD", Log::WARN, "Could not load font face %x %s", error, filename);
805       return 0;
806     }
807
808     error = FT_Set_Char_Size(new_ft_face, 0, font_size * 256, 0, 0 /*dpi*/);
809
810     if (error)
811     {
812       FT_Done_Face(new_ft_face);
813       Log::getInstance()->log("OSD", Log::WARN, "Could not set  face size %x", error);
814       return 0;
815     }
816
817     FT_Face old_ft_face = ft_face; // do it thread safe
818     ft_face = new_ft_face;
819
820     if (freetype_inited) FT_Done_Face(old_ft_face);//
821
822     freetype_inited = true;
823   }
824
825   vgfont = vgCreateFont(0);
826   FT_ULong cur_char;
827   FT_UInt glyph;
828   font_height = ft_face->size->metrics.height / 256.f;
829   cur_char = FT_Get_First_Char(ft_face, &glyph);
830   std::vector<VGubyte> segments;
831   std::vector<VGfloat> coord;
832   segments.reserve(256);
833   coord.reserve(1024);
834
835   //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph test %d %x %x %d",cur_char,font_data_end,font_data,glyph);
836   while (glyph != 0)
837   {
838     error = FT_Load_Glyph(ft_face, glyph, FT_LOAD_DEFAULT);
839
840     if (error)
841     {
842       cur_char = FT_Get_Next_Char(ft_face, cur_char, &glyph);
843       Log::getInstance()->log("OSD", Log::WARN, "Could not load glyph %x %c", error);
844       continue;
845     }
846
847     VGPath path;
848     FT_Outline ot = ft_face->glyph->outline;
849     segments.clear();
850     coord.clear();
851
852     if (ot.n_contours == 0)
853     {
854       path = VG_INVALID_HANDLE;
855     }
856     else
857     {
858       path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
859                           1.0f, 0.f, 0, 0, VG_PATH_CAPABILITY_ALL);
860
861       /* convert glyph */
862       FT_Vector* pt = ot.points;
863       const char* tags = ot.tags;
864       const short* cont = ot.contours;
865       short n_cont = ot.n_contours;
866
867       //short n_point=ot.n_points;
868       //short last_cont=0;
869       for (short point = 0; n_cont != 0; cont++, n_cont--)
870       {
871         short next_cont = *cont + 1;
872         bool first = true;
873         char last_tag = 0;
874         short first_point = point;
875
876         //Log::getInstance()->log("OSD", Log::DEBUG, "runs %d",*cont);
877         for (; point < next_cont; point++)
878         {
879           char tag = tags[point];
880           FT_Vector fpoint = pt[point];
881
882           //    Log::getInstance()->log("OSD", Log::DEBUG, "tag %d point %d %d: %d %d",tag,fpoint.x,fpoint.y,point,n_point);
883           if (first)
884           {
885             segments.push_back(VG_MOVE_TO);
886             first = false;
887           }
888           else if (tag & 0x1)    //on curve
889           {
890             if (last_tag & 0x1)
891             {
892               segments.push_back(VG_LINE_TO);
893             }
894             else if (last_tag & 0x2)
895             {
896               segments.push_back(VG_CUBIC_TO);
897             }
898             else
899             {
900               segments.push_back(VG_QUAD_TO);
901             }
902
903           }
904           else
905           {
906             if (!(tag & 0x2))
907             {
908               if (!(last_tag & 0x1))
909               {
910                 segments.push_back(VG_QUAD_TO);
911                 int coord_size = coord.size();
912                 VGfloat x = (coord[coord_size - 2] + ((float)fpoint.x) / 256.f) * 0.5f * aspect_correction;
913                 VGfloat y = (coord[coord_size - 1] + (font_size - ((float)fpoint.y) / 256.f)) * 0.5f;
914                 coord.push_back(x);
915                 coord.push_back(y);
916               }
917             }
918           }
919
920           last_tag = tag;
921           coord.push_back(((float)fpoint.x)*aspect_correction / 256.);
922           coord.push_back(font_size - ((float)fpoint.y) / 256.);
923           //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph coord %d %d %g %g",fpoint.x,fpoint.y,coord[coord.size()-2],coord[coord.size()-1]);
924         }
925
926         if (!(last_tag & 0x1))
927         {
928           if (last_tag & 0x2)
929           {
930             segments.push_back(VG_CUBIC_TO);
931           }
932           else
933           {
934             segments.push_back(VG_QUAD_TO);
935           }
936
937           coord.push_back(((float)pt[first_point].x)*aspect_correction / 256.);
938           coord.push_back(font_size - ((float)pt[first_point].y) / 256.);
939         }
940
941         //segments.push_back(VG_CLOSE_PATH);
942       }
943
944       vgAppendPathData(path, segments.size(), &segments[0], &coord[0]);
945       /*        for (int m=0;m<segments.size();m++) {
946                 int n=0;
947                 switch (segments[m])
948                 {
949                 case VG_MOVE_TO:
950                         Log::getInstance()->log("OSD", Log::DEBUG, "Move To %g %g",coord[n],coord[n+1]);n+=2; break;
951                 case VG_LINE_TO:
952                         Log::getInstance()->log("OSD", Log::DEBUG, "Line To %g %g",coord[n],coord[n+1]);n+=2; break;
953                 case VG_CUBIC_TO:
954                         Log::getInstance()->log("OSD", Log::DEBUG, "Cubic To %g %g %g %g %g %g",coord[n],coord[n+1],coord[n+2],coord[n+3],coord[n+4],coord[n+5]);n+=6; break;
955                 case VG_QUAD_TO:
956                         Log::getInstance()->log("OSD", Log::DEBUG, "Quad To %g %g %g %g",coord[n],coord[n+1],coord[n+2],coord[n+3]);n+=4; break;
957                 case VG_CLOSE_PATH:
958                         Log::getInstance()->log("OSD", Log::DEBUG, "Close Path"); break;
959                 }
960
961         }*/
962       //vguRect(path,0.f,0.f,1.f,1.f);
963       //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph %d %x",segments.size(),vgGetError());
964     }
965
966     VGfloat ori[] = {0.f, 0.f};
967     VGfloat esp[] = {ft_face->glyph->advance.x / 256.f * aspect_correction, ft_face->glyph->advance.y / 256.f};
968     font_exp_x[glyph] = ft_face->glyph->advance.x / 256.f * aspect_correction; //recalculate
969
970     vgSetGlyphToPath(vgfont, glyph, path, VG_FALSE, ori, esp);
971
972     //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph %d %d %x",path,glyph,vgGetError());
973     if (path != VG_INVALID_HANDLE)
974     {
975       vgDestroyPath(path);
976     }
977
978     cur_char = FT_Get_Next_Char(ft_face, cur_char, &glyph);
979   }
980
981   for (int i = 0; i < 256; i++)
982   {
983     unsigned int glyph_index = FT_Get_Char_Index(ft_face, i);
984     byte_char_width[i] = font_exp_x[glyph_index];
985   }
986
987   return 1;
988 }
989
990 void OsdOpenVG::drawSetTrans(SurfaceInfo& sc)
991 {
992   vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
993   vgLoadIdentity();
994   vgScale(((float)BACKBUFFER_WIDTH) / 720.f, -((float)BACKBUFFER_HEIGHT) / 576.f);
995   vgTranslate(0.f + sc.x, -576.f + sc.y);
996
997   vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
998   vgLoadIdentity();
999   vgScale(((float)BACKBUFFER_WIDTH) / 720.f, -((float)BACKBUFFER_HEIGHT) / 576.f);
1000   vgTranslate(0.f + sc.x, -576.f + sc.y);
1001
1002   vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
1003   vgLoadIdentity();
1004   vgScale(((float)BACKBUFFER_WIDTH) / 720.f, -((float)BACKBUFFER_HEIGHT) / 576.f);
1005   vgTranslate(0.f + sc.x, -576.f + sc.y);
1006   clip_shift_x = sc.x;
1007   clip_shift_y = sc.y;
1008
1009   //vgTranslate(0.f+sc.x,576.f-sc.y);
1010   //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Translate %g %g",sc.x,sc.y);
1011 }
1012
1013 void OsdOpenVG::executeDrawCommand(SVGCommand& command)
1014 {
1015   VGfloat save_matrix[9];
1016   VGfloat save_matrix2[9];
1017
1018   switch (command.instr)
1019   {
1020     case DrawPath:
1021     {
1022       vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
1023       //        VGuint rgba;
1024       //        rgba = vgGetColor((VGPaint) command.handle);
1025       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Path %d %x %g %g %g %g",command.handle,command.target.path_index,command.x,command.y,command.w,command.h);
1026       //vgSeti(VG_FILL_RULE,);
1027
1028       vgGetMatrix(save_matrix);
1029       vgSetPaint(static_cast<VGPaint>(command.handle), VG_FILL_PATH);
1030       vgSetPaint(static_cast<VGPaint>(command.handle), VG_STROKE_PATH);
1031       vgTranslate(command.x, command.y);
1032       vgScale(command.w, command.h);
1033       vgDrawPath(std_paths[command.target.path_index], VG_FILL_PATH);
1034       vgLoadMatrix(save_matrix);
1035       break;
1036     }
1037     case DrawImage:
1038     {
1039       vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
1040       vgGetMatrix(save_matrix);
1041       VGfloat imagewidth = vgGetParameteri((VGImage) command.target.image, VG_IMAGE_WIDTH);
1042       VGfloat imageheight = vgGetParameteri((VGImage) command.target.image, VG_IMAGE_HEIGHT);
1043
1044       //vgScale(command.w,command.h);
1045
1046       if (command.handle)   //special behaviout for bw images they act as a mask on the current paint
1047       {
1048         vgTranslate(command.x, command.y);
1049         vgSetPaint(static_cast<VGPaint>(command.handle), VG_FILL_PATH);
1050         vgSetPaint(static_cast<VGPaint>(command.handle), VG_STROKE_PATH);
1051         vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
1052         vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
1053         vgScale(aspect_correction, 1.f);
1054         vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
1055         vgGetMatrix(save_matrix2);
1056         vgScale(imagewidth, imageheight);
1057       }
1058       else
1059       {
1060         //vgScale(720.f/((float)BACKBUFFER_WIDTH), 576.f/((float)BACKBUFFER_HEIGHT));
1061         float scalex = command.w / imagewidth;
1062         float scaley = command.h / imageheight;
1063         float tx = command.x;
1064         float ty = command.y;
1065
1066         if (command.corner == TopLeftLimited)
1067         {
1068           if (scalex != 0.f && scaley != 0.f)
1069           {
1070             float imageaspect = imagewidth / imageheight;
1071             float boxaspect = command.w / command.h / aspect_correction;
1072
1073             if (imageaspect > boxaspect)
1074             {
1075               scaley = 0.f;
1076               ty += (command.h - imageheight * scalex / aspect_correction) * 0.5f;
1077             }
1078             else
1079             {
1080               scalex = 0.f;
1081               tx += (command.w - imagewidth * scaley * aspect_correction) * 0.5f;
1082             }
1083           }
1084         }
1085
1086         if (scalex == 0.f && scaley == 0.f)
1087         {
1088           scalex = aspect_correction;
1089           scaley = 1.f;
1090         }
1091         else if (scalex == 0.f)
1092         {
1093           scalex = scaley * aspect_correction;
1094         }
1095         else if (scaley == 0.f)
1096         {
1097           scaley = scalex / aspect_correction;
1098         }
1099
1100         if (command.corner ==  BottomRight || command.corner ==  BottomLeft || command.corner == BottomMiddle)
1101         {
1102           ty -= imageheight * scaley;
1103         }
1104
1105         if (command.corner ==  BottomRight || command.corner ==  TopRight)
1106         {
1107           tx -= imagewidth * scalex;
1108         }
1109
1110         if (command.corner ==  BottomMiddle || command.corner ==  TopMiddle)
1111         {
1112           tx -= imagewidth * scalex * 0.5f;
1113         }
1114
1115         vgTranslate(tx, ty);
1116         //vgScale(command.w/imagewidth,command.h/imageheight);
1117         vgScale(scalex, scaley);
1118         vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
1119         vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
1120         //Log::getInstance()->log("OSD", Log::DEBUG, "TVMedia Draw Image Scale  %g %g %g %g %g %g",command.w,imagewidth,command.h,imageheight,scalex,scaley);
1121       }
1122
1123       //vgLoadIdentity();
1124       //vgTranslate(200.f,500.f);
1125       //vgScale(100.f,100.f);
1126
1127       vgDrawImage(static_cast<VGImage>(command.target.image));
1128
1129       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Image %d %x %g %g %g %g %x",command.handle,command.target.image,command.x,command.y,command.w,command.h,
1130       //                vgGetError());
1131       if (command.handle)
1132       {
1133         vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
1134         vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
1135         vgLoadMatrix(save_matrix2);
1136       }
1137
1138       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
1139
1140       vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
1141       vgLoadMatrix(save_matrix);
1142       break;
1143     }
1144     case DrawGlyph:
1145     {
1146       vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
1147       vgGetMatrix(save_matrix);
1148       vgSetPaint(static_cast<VGPaint>(command.handle), VG_FILL_PATH);
1149       vgSetPaint(static_cast<VGPaint>(command.handle), VG_STROKE_PATH);
1150       vgTranslate(command.x, command.y);
1151       vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
1152       vgGetMatrix(save_matrix2);
1153       unsigned int glyph_index = FT_Get_Char_Index(ft_face, command.target.textchar);
1154       vgScale(font_exp_x[glyph_index], font_height);
1155
1156       VGfloat gori[] = {0., 0.};
1157       vgSetfv(VG_GLYPH_ORIGIN, 2, gori);
1158
1159       vgDrawGlyph(vgfont, glyph_index, VG_FILL_PATH, VG_FALSE);
1160       //vgDrawPath(std_paths[Rectangle],VG_FILL_PATH);
1161       /*        Log::getInstance()->log("OSD", Log::DEBUG, "Draw Glyph %d %c %d %g %g %x",command.handle,command.target.textchar,glyph_index,command.x,command.y,
1162                                         vgGetError());*/
1163       vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
1164       vgLoadMatrix(save_matrix);
1165       vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
1166       vgLoadMatrix(save_matrix2);
1167
1168       vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
1169       break;
1170     }
1171     case DrawTTchar:
1172     {
1173       cTeletextChar tchar;
1174       tchar.setInternal(command.target.ttchar);
1175       vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
1176       vgGetMatrix(save_matrix);
1177       enumTeletextColor ttforegcolour = tchar.GetFGColor();
1178       enumTeletextColor ttbackgcolour = tchar.GetBGColor();
1179
1180       if (tchar.GetBoxedOut())
1181       {
1182         ttforegcolour = ttcTransparent;
1183         ttbackgcolour = ttcTransparent;
1184       }
1185
1186       vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
1187       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
1188
1189       vgTranslate(command.x + command.w * 11.85f * 1.4f, command.y + command.h * 19.75f);
1190       VGfloat gori[] = {0., 0.};
1191       vgSetfv(VG_GLYPH_ORIGIN, 2, gori);
1192
1193       vgScale(-1.4f, 2.f);
1194       unsigned int color = Surface::enumTeletextColorToCoulour(ttbackgcolour).rgba();
1195       color = color << 8 | (color & 0xff000000) >> 24;
1196       vgSetColor(vgttpaint, color);
1197       vgSetPaint(static_cast<VGPaint>(vgttpaint), VG_FILL_PATH);
1198       vgSetPaint(static_cast<VGPaint>(vgttpaint), VG_STROKE_PATH);
1199       cTeletextChar filled;
1200       filled.setInternal(0x187f);
1201       unsigned int glyph_index = loadTTchar(filled);
1202       vgDrawGlyph(vgttfont, glyph_index, VG_FILL_PATH, VG_FALSE);
1203
1204       color = Surface::enumTeletextColorToCoulour(ttforegcolour).rgba();
1205       color = color << 8 | (color & 0xff000000) >> 24;
1206       vgSetColor(vgttpaint, color);
1207       vgSetPaint(static_cast<VGPaint>(vgttpaint), VG_FILL_PATH);
1208       vgSetPaint(static_cast<VGPaint>(vgttpaint), VG_STROKE_PATH);
1209       glyph_index = loadTTchar(tchar);
1210       vgDrawGlyph(vgttfont, glyph_index, VG_FILL_PATH, VG_FALSE);
1211
1212       /*        Log::getInstance()->log("OSD", Log::DEBUG, "Draw TTchar %x %x %x %x",glyph_index,ttforegcolour,Surface::enumTeletextColorToCoulour(ttforegcolour).rgba(),
1213                         vgGetColor(vgttpaint));*/
1214
1215       vgLoadMatrix(save_matrix);
1216       vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
1217       vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
1218       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
1219       break;
1220     }
1221     case DrawClipping:
1222     {
1223       VGint coords[4] = {0, 0, 0, 0};
1224       coords[0] = ((command.x + clip_shift_x) * ((float)BACKBUFFER_WIDTH) / 720.f);
1225       coords[1] = ((576.f - command.y - clip_shift_y - command.h) * ((float)BACKBUFFER_HEIGHT) / 576.f);
1226       coords[2] = ((command.w - 1.f) * ((float)BACKBUFFER_WIDTH) / 720.f);
1227       coords[3] = ((command.h - 1.f) * ((float)BACKBUFFER_HEIGHT) / 576.f);
1228       vgSetiv(VG_SCISSOR_RECTS, 4, coords);
1229
1230       if (command.w == 0.f && command.h == 0.f)
1231         vgSeti(VG_SCISSORING, VG_FALSE);
1232       else
1233         vgSeti(VG_SCISSORING, VG_TRUE);
1234
1235       break;
1236     }
1237     case DrawImageLoading:
1238     case DrawNoop:
1239     {}
1240   }
1241 }
1242
1243 //int imcount=0;// this is debug code and should not go into release
1244 unsigned int OsdOpenVG::handleTask(OpenVGCommand& command)
1245 {
1246   switch (command.task)
1247   {
1248     case OVGreplacefont:
1249     {
1250       vgDestroyFont(vgfont);
1251       loadFont(true);
1252       return 0;
1253     }
1254     case OVGdestroyImageRef:  //imcount--;
1255     {
1256       //Log::getInstance()->log("OSD", Log::DEBUG, "TVMedia Draw Image Destroy %x %d",command.param1,imcount);
1257       vgDestroyImage(static_cast<VGImage>(command.param1));
1258       return 0;
1259     }
1260     case OVGdestroyPaint:
1261     {
1262       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint Destroy %d ",command.param1);
1263       vgDestroyPaint(static_cast<VGPaint>(command.param1));
1264       return 0;
1265     }
1266     case OVGcreateImagePalette:  //imcount++;
1267     {
1268       VGImage input = vgCreateImage(VG_A_8, command.param1, command.param2,
1269                                     VG_IMAGE_QUALITY_NONANTIALIASED |
1270                                     VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_BETTER);
1271       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create palette  %d %d %x %d",command.param1,command.param2,vgGetError(),input);
1272       vgImageSubData(input, command.data, command.param1,
1273                      VG_A_8, 0, 0, command.param1, command.param2); // upload palettized image data
1274       VGImage handle = vgCreateImage(VG_sRGBA_8888, command.param1, command.param2,
1275                                      VG_IMAGE_QUALITY_NONANTIALIASED |
1276                                      VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_BETTER);
1277       VGuint* palette = static_cast<VGuint*>(malloc(256 * sizeof(VGuint)));
1278       const VGuint* in_palette = static_cast<const VGuint*>(command.data2);
1279
1280       for (int i = 0; i < 256; i++)
1281       {
1282         VGuint color = in_palette[i];
1283         palette[i] = color << 8 | (color & 0xff000000) >> 24;
1284       }
1285
1286       vgLookupSingle(handle, input, palette, VG_ALPHA, VG_FALSE, VG_FALSE);
1287       free(palette);
1288       vgDestroyImage(input);
1289
1290       return handle;
1291     }
1292     case OVGcreateMonoBitmap:  //imcount++;
1293     {
1294       VGImage handle = vgCreateImage(VG_A_1, command.param1, command.param2,
1295                                      VG_IMAGE_QUALITY_FASTER);
1296       //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
1297       unsigned int buffer_len = (command.param1 * command.param2) >> 3;
1298       unsigned char* buffer = static_cast<unsigned char*>(malloc(buffer_len));
1299       unsigned char* r_buffer1 = buffer;
1300       const unsigned char* r_buffer2 = static_cast<const unsigned char*>(command.data);
1301       unsigned char* buffer_end = buffer + buffer_len;
1302
1303       while (r_buffer1 != buffer_end)
1304       {
1305         unsigned char byte = *r_buffer2;
1306         *r_buffer1 = ((byte * 0x0802LU & 0x22110LU) | (byte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
1307         r_buffer1++; r_buffer2++;
1308       }
1309
1310       vgImageSubData(handle, buffer, command.param1 >> 3, VG_A_1, 0, 0, command.param1, command.param2);
1311       free(buffer);
1312       //        Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono2  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
1313       return handle;
1314     }
1315     /*case OVGcreateImageFile: {
1316         VGImage handle;
1317         try{
1318                 Image *imagefile=(Image*)command.data;
1319                 Blob imageblob;
1320                 imagefile->write(&imageblob,"RGBA");
1321
1322                 handle=vgCreateImage(VG_sXBGR_8888,imagefile->columns(),imagefile->rows(),
1323                                 VG_IMAGE_QUALITY_BETTER);
1324                 //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark1",imagefile->columns(),imagefile->rows(),(unsigned int*)imageblob.data());
1325                 vgImageSubData(handle,imageblob.data(),imagefile->columns()*4,
1326                                 VG_sXBGR_8888,0,0,imagefile->columns(),imagefile->rows());
1327                 //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark2",imagefile->columns(),imagefile->rows(),(unsigned int*)imageblob.data());
1328                 delete imagefile;
1329         }catch( Exception &error_ )
1330         {
1331                 Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick hT: %s",error_.what());
1332
1333                 return 0;
1334         }
1335
1336         //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create file  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
1337         return handle;
1338     } */
1339     case OVGcreateImageMemory:  //imcount++;
1340     {
1341       const PictureInfo* info = static_cast<const PictureInfo*>(command.data);
1342       VGImage handle;
1343       //Log::getInstance()->log("OSD", Log::DEBUG, "TVMedia OVGcreateImageMemory %d",imcount);
1344       handle = vgCreateImage(VG_sABGR_8888, info->width, info->height, VG_IMAGE_QUALITY_BETTER);
1345       vgImageSubData(handle, info->image, info->width * 4,
1346                      VG_sABGR_8888, 0, 0, info->width, info->height);
1347       info->decoder->freeReference(info->reference);
1348
1349       bool static_image = true;
1350
1351       if (info->lindex & 0xffffffff) static_image = false;
1352
1353       Message* m = new  Message();
1354       // We have a pictures! send a message to ourself, to switch to gui thread
1355       m->from = this;
1356       m->p_to = Message::CONTROL;
1357       m->data = reinterpret_cast<void*>(handle);
1358
1359       if (!static_image)
1360       {
1361         m->message = Message::NEW_PICTURE;
1362         m->tag = info->lindex;
1363       }
1364       else
1365       {
1366         m->message = Message::NEW_PICTURE_STATIC;
1367         m->tag = info->lindex >> 32LL;
1368       }
1369
1370       MessageQueue::getInstance()->postMessage(m); // inform control about new picture
1371
1372       delete info;
1373       break;
1374     }
1375     case OVGcreateEGLImage:  //imcount++;
1376     {
1377       PictureInfo* info = const_cast<PictureInfo*>(static_cast<const PictureInfo*>(command.data));
1378       VGImage handle;
1379
1380       handle = vgCreateImage(VG_sABGR_8888, info->width, info->height, VG_IMAGE_QUALITY_BETTER);
1381       //                Log::getInstance()->log("OSD", Log::DEBUG, "TVMedia OVGcreateEGLImage %d %d %x %d",info->width,info->height, handle,imcount);
1382
1383       info->handle = handle;
1384       info->reference =  eglCreateImageKHR(egl_display, egl_context, EGL_VG_PARENT_IMAGE_KHR, reinterpret_cast<EGLClientBuffer>(handle), NULL);
1385       if (info->reference) return true;
1386
1387       Log::getInstance()->log("OSD", Log::DEBUG, "TVMedia OVGcreateEGLImage %d %d %x Fail!", info->width, info->height, handle);
1388       if (handle) vgDestroyImage(handle);
1389       return false;
1390     }
1391     case OVGreadyEGLImage:
1392     {
1393       PictureInfo* info = const_cast<PictureInfo*>(static_cast<const PictureInfo*>(command.data));
1394       eglDestroyImageKHR(egl_display, info->reference);
1395       bool static_image = true;
1396
1397       if (info->lindex & 0xffffffff) static_image = false;
1398
1399       Message* m = new  Message();
1400       m->from = this;
1401       m->p_to = Message::CONTROL;
1402       m->data = reinterpret_cast<void*>(info->handle);
1403
1404       if (!static_image)
1405       {
1406         m->message = Message::NEW_PICTURE;
1407         m->tag = info->lindex;
1408       }
1409       else
1410       {
1411         m->message = Message::NEW_PICTURE_STATIC;
1412         m->tag = info->lindex >> 32LL;
1413       }
1414
1415       MessageQueue::getInstance()->postMessage(m); // inform command about new picture
1416
1417       delete info;
1418       break;
1419     }
1420     case OVGcreateColorRef:
1421     {
1422       VGPaint handle;
1423       handle = vgCreatePaint();
1424       const DrawStyle* style = static_cast<const DrawStyle*>(command.data);
1425
1426       switch (style->ft)
1427       {
1428         case DrawStyle::Color:
1429         {
1430           vgSetParameteri(handle, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
1431           vgSetColor(handle, command.param1);
1432           //VGuint rgba;
1433           //rgba = vgGetColor((VGPaint)handle);
1434           //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint %d %x %x",handle,command.param1,rgba);
1435           break;
1436         }
1437         case DrawStyle::GradientLinear:
1438         {
1439           vgSetParameteri(handle, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
1440           VGfloat params[] = {style->x1, style->y1, style->x2, style->y2, style->r};
1441           //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Gradient %d %g %g %g %g",handle,params[0],params[1],params[2],params[3]);
1442           vgSetParameterfv(handle, VG_PAINT_LINEAR_GRADIENT, 4, params);
1443           break;
1444         }
1445         case DrawStyle::GradientRadial:
1446         {
1447           vgSetParameteri(handle, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT);
1448           VGfloat params[] = {style->x1, style->y1, style->x2, style->y2, style->r};
1449           vgSetParameterfv(handle, VG_PAINT_RADIAL_GRADIENT, 5, params);
1450           break;
1451         }
1452       }
1453
1454       if (style->ft == DrawStyle::GradientLinear || style->ft == DrawStyle::GradientRadial)
1455       {
1456         VGfloat colorramp[5 * 5];
1457         colorramp[0 + 0 * 5] = 0.f;
1458         colorramp[1 + 0 * 5] = style->red / 255.f;
1459         colorramp[2 + 0 * 5] = style->green / 255.f;
1460         colorramp[3 + 0 * 5] = style->blue / 255.f;
1461         colorramp[4 + 0 * 5] = style->alpha / 255.f;
1462
1463         for (int i = 0; i < (style->num_colors - 1); i++)
1464         {
1465           colorramp[0 + (i + 1) * 5] = style->grad_pos[i];
1466           colorramp[1 + (i + 1) * 5] = style->grad_col[i].red / 255.f;
1467           colorramp[2 + (i + 1) * 5] = style->grad_col[i].green / 255.f;
1468           colorramp[3 + (i + 1) * 5] = style->grad_col[i].blue / 255.f;
1469           colorramp[4 + (i + 1) * 5] = style->grad_col[i].alpha / 255.f;
1470         }
1471
1472         colorramp[0 + (style->num_colors) * 5] = 1.f;
1473         colorramp[1 + (style->num_colors) * 5] = style->grad_col[style->num_colors - 1].red / 255.f;
1474         colorramp[2 + (style->num_colors) * 5] = style->grad_col[style->num_colors - 1].green / 255.f;
1475         colorramp[3 + (style->num_colors) * 5] = style->grad_col[style->num_colors - 1].blue / 255.f;
1476         colorramp[4 + (style->num_colors) * 5] = style->grad_col[style->num_colors - 1].alpha / 255.f;
1477         vgSetParameteri(handle, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_REFLECT);
1478         vgSetParameteri(handle, VG_PAINT_COLOR_RAMP_PREMULTIPLIED, VG_FALSE);
1479         vgSetParameterfv(handle, VG_PAINT_COLOR_RAMP_STOPS, 5 + (style->num_colors) * 5, colorramp);
1480       }
1481
1482       return handle;
1483       break;
1484     }
1485     case OVGimageUploadLine:
1486     {}
1487   }
1488
1489   return 0;
1490 }
1491
1492 bool OsdOpenVG::processTasks()
1493 {
1494   bool worked = false;
1495   taskmutex.lock();
1496   vgmutex.lock();
1497
1498   while (vgcommands.size() > 0)
1499   {
1500     OpenVGCommand comm = vgcommands.front();
1501     vgcommands.pop_front();
1502     taskmutex.unlock();
1503
1504     OpenVGResponse resp;
1505     resp.result = handleTask(comm);
1506     resp.id = comm.id;
1507     taskmutex.lock();
1508
1509     if (comm.id)
1510     {
1511       vgresponses.push_back(resp);
1512     }
1513
1514     taskmutex.unlock();
1515     vgmutex.unlock();
1516
1517     /* Getting rid of Signal class. As with VideoOMX, just replicate what Signal did here
1518      * and figure out if any of this can be simplified later. e.g. taskmutex sounds
1519      * like it should be the mutex being used. 3 mutexes here???
1520      */
1521
1522     vgTaskSignalMutex.lock();
1523     vgTaskSignal.notify_one();
1524     vgTaskSignalMutex.unlock();
1525
1526     taskmutex.lock();
1527     vgmutex.lock();
1528     worked = true;
1529   }
1530
1531   taskmutex.unlock();
1532   vgmutex.unlock();
1533
1534   return worked;
1535 }
1536
1537 unsigned int OsdOpenVG::putOpenVGCommand(OpenVGCommand& comm, bool wait)
1538 {
1539   taskmutex.lock();
1540
1541   if (wait)
1542     comm.id = wait_id++;
1543   else
1544     comm.id = 0; // we are not waiting
1545
1546   vgcommands.push_back(comm);
1547   taskmutex.unlock();
1548
1549   threadSignal();
1550
1551   if (!wait) return 0;
1552
1553   while(1)
1554   {
1555     // Is there a response now?
1556     taskmutex.lock();
1557     for (auto& vgresponse : vgresponses)
1558     {
1559       if (vgresponse.id == comm.id)
1560       {
1561         UINT resp = vgresponse.result;
1562         taskmutex.unlock();
1563         return resp;
1564       }
1565     }
1566     // No.
1567     taskmutex.unlock();
1568
1569     std::unique_lock<std::mutex> ul(vgTaskSignalMutex);
1570     vgTaskSignal.wait_for(ul, std::chrono::milliseconds(100));
1571     ul.unlock();
1572   }
1573 }
1574
1575 void OsdOpenVG::destroyImageRef(ImageIndex index)
1576 {
1577   struct OpenVGCommand comm;
1578   comm.task = OVGdestroyImageRef;
1579   comm.param1 = index;
1580   putOpenVGCommand(comm, false);
1581 }
1582
1583 bool OsdOpenVG::getStaticImageData(unsigned int static_id, UCHAR** userdata, ULONG* length)
1584 {
1585   if (sa_MAX > static_id)
1586   {
1587     *userdata = static_artwork_begin[static_id];
1588     *length = static_artwork_end[static_id] - static_artwork_begin[static_id];
1589     return true;
1590   }
1591
1592   *userdata = NULL;
1593   *length = 0;
1594   return false;
1595 }
1596
1597 void OsdOpenVG::createPicture(struct PictureInfo& pict_inf)
1598 {
1599   struct OpenVGCommand comm;
1600   Log::getInstance()->log("OsdOpenVG", Log::DEBUG, "TVMedia Create Picture %d", pict_inf.type);
1601
1602   if (pict_inf.type == PictureInfo::RGBAMemBlock)
1603   {
1604     comm.task = OVGcreateImageMemory;
1605     comm.data =  new PictureInfo(pict_inf);
1606     putOpenVGCommand(comm, false);
1607   }
1608   else if (pict_inf.type == PictureInfo::EGLImage)
1609   {
1610     comm.task = OVGreadyEGLImage;
1611     comm.data =  new PictureInfo(pict_inf);
1612     putOpenVGCommand(comm, false);
1613   }
1614   else
1615   {
1616     // unsupported
1617     pict_inf.decoder->freeReference(pict_inf.reference);
1618   }
1619 }
1620
1621 bool OsdOpenVG::getEGLPicture(struct OsdVector::PictureInfo& info, EGLDisplay* display)
1622 {
1623   struct OpenVGCommand comm;
1624   info.type = PictureInfo::EGLImage;
1625   comm.task = OVGcreateEGLImage;
1626   comm.data = &info;
1627   *display = egl_display;
1628   return  putOpenVGCommand(comm, true);
1629 }
1630
1631 ImageIndex OsdOpenVG::createMonoBitmap(void* base, int width, int height)
1632 {
1633   struct OpenVGCommand comm;
1634   comm.task = OVGcreateMonoBitmap;
1635   comm.param1 = width;
1636   comm.param2 = height;
1637   comm.data = base;
1638   return putOpenVGCommand(comm, true);
1639 }
1640
1641 ImageIndex OsdOpenVG::createImagePalette(int width, int height, const unsigned char* image_data, const unsigned int* palette_data)
1642 {
1643   struct OpenVGCommand comm;
1644   comm.task = OVGcreateImagePalette;
1645   comm.param1 = width;
1646   comm.param2 = height;
1647   comm.data = image_data;
1648   comm.data2 = palette_data;
1649   return putOpenVGCommand(comm, true);
1650 }
1651
1652 void OsdOpenVG::destroyDrawStyleHandle(VectorHandle index)
1653 {
1654   struct OpenVGCommand comm;
1655   comm.task = OVGdestroyPaint;
1656   comm.param1 = index;
1657   putOpenVGCommand(comm, false);
1658 }
1659
1660 VectorHandle OsdOpenVG::createDrawStyleHandle(const DrawStyle& c)
1661 {
1662   unsigned int col = c.rgba();
1663   struct OpenVGCommand comm;
1664   comm.task = OVGcreateColorRef;
1665   comm.param1 = col << 8 | (col & 0xff000000) >> 24;
1666   comm.data = &c;
1667   return putOpenVGCommand(comm, true);
1668 }