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