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