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