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