]> git.vomp.tv Git - vompclient-marten.git/blob - osdopenvg.cc
Remove unnecessary dependencies
[vompclient-marten.git] / osdopenvg.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, 2006,2011-2012 Marten Richter
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21
22 #include "osdopenvg.h"
23 #include "mtd.h"
24 #include "videoomx.h"
25 #include "surface.h"
26 #include <Magick++.h>
27
28 #include "message.h"
29 #include "command.h"
30 #include "teletxt/txtfont.h"
31
32 #include <sys/syscall.h>
33 #include <vector>
34 #include <math.h>
35
36 using namespace Magick;
37
38 extern uint8_t font_data[]     asm("_binary_fonts_sourcesans_ttf_start");
39 extern uint8_t font_data_end[] asm("_binary_fonts_sourcesans_ttf_end");
40 extern uint8_t vdr_data[]     asm("_binary_other_vdrhires_jpg_start");
41 extern uint8_t vdr_data_end[] asm("_binary_other_vdrhires_jpg_end");
42 extern uint8_t wallpaper_data[]     asm("_binary_other_wallpaper720p_jpg_start");
43 extern uint8_t wallpaper_data_end[] asm("_binary_other_wallpaper720p_jpg_end");
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   freetype_inited=false;
61   wait_id=1;
62
63 }
64
65 OsdOpenVG::~OsdOpenVG()
66 {
67
68   if (initted)
69   {
70                 shutdown();
71   }
72
73   if (freetype_inited) FT_Done_Face(ft_face);
74
75   vgmutex.Unlock();
76   taskmutex.Unlock();
77 }
78
79
80
81 int OsdOpenVG::init(void* device)
82 {
83   if (initted) return 0;
84   Video* video = Video::getInstance();
85    //window=*((HWND*)device);
86
87    // May be this device specific part should go to a device specific child class
88
89    //init broadcom chipset (Move to video?)
90
91
92    //First get connection to egl
93    egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);
94
95    if (egl_display==EGL_NO_DISPLAY) {
96            Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x",eglGetError());
97            vgmutex.Unlock();
98            return 0;
99    }
100
101
102
103    if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {
104            Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x",eglGetError());
105            vgmutex.Unlock();
106            return 0;
107    }
108
109
110    const char *query_str=eglQueryString(egl_display,EGL_CLIENT_APIS);
111    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
112    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
113    query_str=eglQueryString(egl_display,EGL_EXTENSIONS);
114    if (query_str)    Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
115    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
116
117    if (eglBindAPI(EGL_OPENVG_API)==EGL_FALSE) {
118            Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api failed! %x",eglGetError());
119            vgmutex.Unlock();
120            return 0;
121    }
122
123    const EGLint attributs[]={
124                  EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,
125          EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
126          EGL_CONFORMANT, EGL_OPENVG_BIT,
127          EGL_NONE
128    }; // Here, we might have to select the resolution!
129
130
131    EGLint number;
132
133    if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number)==EGL_FALSE) {
134            Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x",eglGetError());
135            vgmutex.Unlock();
136            return 0;
137    }
138
139
140
141    egl_context=eglCreateContext(egl_display,egl_ourconfig,NULL,NULL);
142    if (egl_context==EGL_NO_CONTEXT) {
143            Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x",eglGetError());
144            vgmutex.Unlock();
145            return 0;
146    }
147
148    // warning broadcom specific, get display size!
149    display_width=display_height=0;
150    if (graphics_get_display_size(0, &display_width, &display_height)<0) {
151            Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");
152            vgmutex.Unlock();
153            return 0;
154    }
155    Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);
156    VC_RECT_T dst_rect ={0,0,display_width,display_height};
157    VC_RECT_T src_rect={0,0,BACKBUFFER_WIDTH <<16,BACKBUFFER_HEIGHT<<16};
158   // VC_RECT_T src_rect_bg={0,0,1<<16,1<<16};
159  //  VC_RECT_T src_rect_im={0,0,1,1};
160
161   /* uint32_t back_image_ptr;
162    bcm_backres=vc_dispmanx_resource_create(VC_IMAGE_RGB888,1,1,&back_image_ptr);
163    unsigned int color=0x00FF0000;
164    vc_dispmanx_resource_write_data(bcm_backres,VC_IMAGE_RGB888,4,&color,&src_rect_im);*/
165
166    DISPMANX_UPDATE_HANDLE_T  bcm_update;
167    bcm_display=vc_dispmanx_display_open(0);
168    bcm_update=vc_dispmanx_update_start(0);
169    bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,
170          2,&dst_rect, 0,
171          &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);
172
173
174  /*  bcm_background=vc_dispmanx_element_add(bcm_update,bcm_display,
175             0,&dst_rect,bcm_backres ,
176             &src_rect_bg,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);*/
177
178    vc_dispmanx_update_submit_sync(bcm_update);
179
180
181
182    static EGL_DISPMANX_WINDOW_T nativewindow;
183    nativewindow.element=bcm_element;
184    nativewindow.height=BACKBUFFER_HEIGHT;
185    nativewindow.width=BACKBUFFER_WIDTH;
186
187    egl_surface = eglCreateWindowSurface(egl_display,egl_ourconfig, &nativewindow,NULL );
188    if (egl_surface==EGL_NO_SURFACE) {
189            Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");
190            vgmutex.Unlock();
191            return 0;
192    }
193    Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current in1%d",syscall(SYS_gettid));
194    if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
195            Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");
196            vgmutex.Unlock();
197                    return 0;
198    }
199    // Test stuff
200
201    query_str=(const char*)vgGetString(VG_VERSION) ;
202    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
203    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
204
205    query_str=(const char*)vgGetString(VG_VENDOR) ;
206    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
207    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
208
209    query_str=(const char*)vgGetString(VG_RENDERER) ;
210    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
211    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
212
213    query_str=(const char*)vgGetString(VG_EXTENSIONS) ;
214    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
215    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
216
217   aspect_correction= ((float)BACKBUFFER_HEIGHT)/576.f/(((float)BACKBUFFER_WIDTH)/720.f);
218   initPaths();
219   if (!loadFont()) {
220           return 0;
221   }
222   vgttfont=vgCreateFont(0);
223   vgttpaint=vgCreatePaint();
224   vgSetParameteri( vgttpaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
225   vgSetColor(vgttpaint,0xffffffff);
226
227   eglSwapInterval(egl_display, 1 );
228
229   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out 1%d",syscall(SYS_gettid));
230   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
231   //Now we will create the Screen
232   initted = 1; // must set this here or create surface won't work
233
234
235   /*if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init  stuff
236           return 0;
237   }*/
238   InitializeMagick("");
239
240   pthread_cond_init(&vgtaskCond, NULL);
241   pthread_mutex_init(&vgtaskCondMutex, NULL);
242
243   threadStart();
244   taskmutex.Unlock();
245   vgmutex.Unlock();
246
247
248   return 1;
249 }
250
251
252 void OsdOpenVG::initPaths()
253 {
254
255
256         VGPath current;
257         current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
258                         VG_PATH_DATATYPE_F,1.f,0.f,
259                         0,0,VG_PATH_CAPABILITY_ALL);
260
261         vguLine(current,0.f,0.f,1.f,0.f);
262         // HorzLine
263         std_paths[HorzLine]=current;
264
265         current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
266                                 VG_PATH_DATATYPE_F,1.f,0.f,
267                                 0,0,VG_PATH_CAPABILITY_ALL);
268         vguLine(current,0.f,0.f,0.f,1.f);
269         // VertLine
270         std_paths[VertLine]=current;
271
272         current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
273                                 VG_PATH_DATATYPE_F,1.f,0.f,
274                                 0,0,VG_PATH_CAPABILITY_ALL);
275         //vguRect(current,0.f,0.f,1.f,1.f);
276         vguRect(current,0.f,0.f,1.f,1.f);
277         // Rectabgle
278         std_paths[Rectangle]=current;
279
280         current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
281                                 VG_PATH_DATATYPE_F,1.f,0.f,
282                                 0,0,0);
283         vguEllipse(current,0.f,0.f,1.f,1.f);
284         // Point
285         std_paths[Point]=current;
286
287 }
288
289 void OsdOpenVG::destroyPaths()
290 {
291         vgDestroyPath(std_paths[HorzLine]);
292         vgDestroyPath(std_paths[VertLine]);
293         vgDestroyPath(std_paths[Rectangle]);
294         vgDestroyPath(std_paths[Point]);
295
296 }
297
298 int OsdOpenVG::stopUpdate()
299 {
300         threadStop();
301         processTasks();
302         return 1;
303 }
304
305
306 int OsdOpenVG::shutdown()
307 {
308   if (!initted) return 0;
309
310   initted = 0;
311   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1");
312   threadStop();
313   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark2");
314   processTasks();
315   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark3");
316
317   taskmutex.Lock();
318   vgmutex.Lock();
319   //(((VideoOMX*)Video::getInstance())->shutdownUsingOSDObjects());
320
321
322
323   vgDestroyFont(vgfont);
324   vgDestroyFont(vgttfont);
325   vgDestroyPaint(vgttpaint);
326   destroyPaths();
327   vgClear(0,0,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT);
328   eglSwapBuffers(egl_display, egl_surface);
329   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out final");
330   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
331   eglDestroySurface(egl_display,egl_surface);
332   eglDestroyContext(egl_display,egl_context);
333   eglTerminate(egl_display );
334
335   DISPMANX_UPDATE_HANDLE_T  bcm_update;
336   bcm_update=vc_dispmanx_update_start(0);
337
338   vc_dispmanx_element_remove(bcm_update,bcm_element);
339 //  vc_dispmanx_element_remove(bcm_update,bcm_background);
340   vc_dispmanx_update_submit_sync(bcm_update);
341 //  vc_dispmanx_resource_delete(bcm_backres);
342   vc_dispmanx_display_close(bcm_display);
343
344
345
346   return 1;
347 }
348
349
350
351
352 void OsdOpenVG::threadMethod()
353 {
354         // We have to claim the egl context for this thread
355
356         if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
357                 Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %x",eglGetError());
358                 return;
359         }
360         int ts=0;
361         while (true)
362         {
363                 ts=1;
364                 unsigned int waittime=1;
365
366                 if (initted) {
367
368                         long long time1 = getTimeMS();
369                         if ((time1 - lastrendertime) > 200) {//5 fps for OSD updates are enough, avoids tearing
370                                 InternalRendering();
371                                 lastrendertime = getTimeMS();
372
373                         }
374                         if (processTasks()) ts=0;
375                 }
376                 threadCheckExit();
377                 if (ts!=0) {
378                         struct timespec target_time;
379                         clock_gettime(CLOCK_REALTIME,&target_time);
380                         target_time.tv_nsec+=1000000LL*ts;
381                         if (target_time.tv_nsec>999999999) {
382                                 target_time.tv_nsec-=1000000000L;
383                                 target_time.tv_sec+=1;
384                         }
385                         threadLock();
386                         threadWaitForSignalTimed(&target_time);
387                         threadUnlock();
388                 }
389                 //Sleep(1);
390         }
391         //eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
392 }
393
394
395 void OsdOpenVG::threadPostStopCleanup()
396 {
397         //Doing nothing
398         //goo;
399 }
400
401
402
403
404
405
406 void OsdOpenVG::InternalRendering(){
407         vgmutex.Lock();
408     float colclear[]={1.f,1.0f,1.f,1.f};
409     vgSetfv(VG_CLEAR_COLOR,4,colclear);
410         vgClear(0,0,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT);
411         vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
412
413
414         drawSurfaces(); //iterate through and draws all commands
415
416         //Show it to the user!
417         eglSwapBuffers(egl_display, egl_surface);
418         vgmutex.Unlock();
419
420 }
421
422 /*font stuff*/
423
424 float OsdOpenVG::getFontHeight()
425 {
426         return font_height; //dummy
427 }
428 float OsdOpenVG::getCharWidth(wchar_t c)
429 {
430         unsigned int glyph_index=FT_Get_Char_Index(ft_face,c);
431         return font_exp_x[glyph_index];
432 }
433
434 unsigned int OsdOpenVG::loadTTchar(cTeletextChar c)
435 {
436         unsigned int glyph_index=c.getGlyphIndex();
437         if (tt_font_chars.find(glyph_index)!=tt_font_chars.end())
438         {
439                 return glyph_index;
440         }
441
442         unsigned int buffer[10];
443         const VGfloat glyphOrigin[] = { 0.f, 0.f };
444         const VGfloat escapement[] = { 12.f, 0.f };
445         unsigned int * charmap = GetFontChar(c, buffer);
446         if (!charmap) { //invalid char
447                 return 0;
448         }
449         for (int i=0;i<10;i++) {
450                 buffer[i]=charmap[i]>>4;
451         }
452
453         VGImage handle = vgCreateImage(
454                         VG_A_8,
455                         12,
456                         10,
457                         VG_IMAGE_QUALITY_NONANTIALIASED | VG_IMAGE_QUALITY_FASTER
458                                         | VG_IMAGE_QUALITY_BETTER);
459         vgImageSubData(handle, buffer, 4, VG_A_1, 0, 0, 12, 10);
460         vgSetGlyphToImage(
461                         vgttfont,
462                         glyph_index,
463                         handle, glyphOrigin, escapement);
464         vgDestroyImage(handle);
465         tt_font_chars[glyph_index]=1;
466
467         return glyph_index;
468 }
469
470 int  OsdOpenVG::loadFont()
471 {
472         int error;
473         float font_size=16.f;
474         if (!freetype_inited) {
475                 error=FT_Init_FreeType(&ft_library);
476                 if (error)
477                 {
478                         Log::getInstance()->log("OSD", Log::WARN, "Could not load freetype %x",error);
479                         return 0;
480                 }
481
482                 error=FT_New_Memory_Face(ft_library,font_data,font_data_end-font_data,0,&ft_face );
483                 if (error) {
484                         Log::getInstance()->log("OSD", Log::WARN, "Could not load font face %x",error);
485                         return 0;
486                 }
487                 error=FT_Set_Char_Size(ft_face,0,font_size*64,0,0 /*dpi*/);
488                 if (error) {
489                         FT_Done_Face(ft_face);
490                         Log::getInstance()->log("OSD", Log::WARN, "Could not set  face size %x",error);
491                         return 0;
492                 }
493                 freetype_inited=true;
494         }
495         vgfont=vgCreateFont(0);
496         FT_ULong cur_char;
497         FT_UInt glyph;
498         font_height=ft_face->size->metrics.height/64.f;
499         cur_char = FT_Get_First_Char(ft_face,&glyph);
500         vector<VGubyte> segments;
501         vector<VGfloat> coord;
502         segments.reserve(256);
503         coord.reserve(1024);
504         //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph test %d %x %x %d",cur_char,font_data_end,font_data,glyph);
505         while (glyph !=0)
506         {
507                 error=FT_Load_Glyph(ft_face,glyph,FT_LOAD_DEFAULT);
508                 if (error){
509                         FT_Done_Face(ft_face);
510                         Log::getInstance()->log("OSD", Log::WARN, "Could not load glyph %x",error);
511                         return 0;
512                 }
513                 VGPath path;
514                 FT_Outline ot=ft_face->glyph->outline;
515                 segments.clear();
516                 coord.clear();
517
518                 if (ot.n_contours ==0) {
519                         path=VG_INVALID_HANDLE;
520                 } else {
521                         path=vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
522                                         1.0f,0.f,0,0,VG_PATH_CAPABILITY_ALL);
523
524                         /* convert glyph */
525                         FT_Vector *pt=ot.points;
526                         const char *tags=ot.tags;
527                         const short* cont=ot.contours;
528                         short n_cont=ot.n_contours;
529                         short n_point=ot.n_points;
530                         short last_cont=0;
531                         for (short point=0;n_cont!=0;cont++,n_cont--) {
532                                 short next_cont=*cont+1;
533                                 bool first=true;
534                                 char last_tag=0;
535                                 short first_point=point;
536                                 //Log::getInstance()->log("OSD", Log::DEBUG, "runs %d",*cont);
537                                 for (;point<next_cont;point++) {
538                                         char tag=tags[point];
539                                         FT_Vector fpoint=pt[point];
540                                 //      Log::getInstance()->log("OSD", Log::DEBUG, "tag %d point %d %d: %d %d",tag,fpoint.x,fpoint.y,point,n_point);
541                                         if (first) {
542                                                 segments.push_back(VG_MOVE_TO);
543                                                 first=false;
544                                         } else if (tag &0x1) { //on curve
545                                                 if (last_tag &0x1) {
546                                                         segments.push_back(VG_LINE_TO);
547                                                 } else if (last_tag &0x2){
548                                                         segments.push_back(VG_CUBIC_TO);
549                                                 } else {
550                                                         segments.push_back(VG_QUAD_TO);
551                                                 }
552
553                                         } else {
554                                                 if (!(tag &0x2)){
555                                                         if (!(last_tag &0x1)) {
556                                                                 segments.push_back(VG_QUAD_TO);
557                                                                 int coord_size=coord.size();
558                                                                 VGfloat x=(coord[coord_size-2]+ ((float)fpoint.x)/64.f)*0.5f*aspect_correction;
559                                                                 VGfloat y=(coord[coord_size-1]+(font_size- ((float)fpoint.y)/64.f))*0.5f;
560                                                                 coord.push_back(x);
561                                                                 coord.push_back(y);
562                                                         }
563                                                 }
564
565
566                                         }
567                                         last_tag=tag;
568                                         coord.push_back(((float)fpoint.x)*aspect_correction/64.);
569                                         coord.push_back(font_size-((float)fpoint.y)/64.);
570                                         //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]);
571                                 }
572                                 if (!(last_tag &0x1)) {
573                                         if (last_tag &0x2) {
574                                                 segments.push_back(VG_CUBIC_TO);
575                                         } else {
576                                                 segments.push_back(VG_QUAD_TO);
577                                         }
578                                         coord.push_back(((float)pt[first_point].x)*aspect_correction/64.);
579                                         coord.push_back(font_size-((float)pt[first_point].y)/64.);
580                                 }
581                                 //segments.push_back(VG_CLOSE_PATH);
582
583
584                         }
585                         vgAppendPathData(path,segments.size(),&segments[0],&coord[0]);
586                         int n=0;
587                 /*      for (int m=0;m<segments.size();m++) {
588                                 switch (segments[m])
589                                 {
590                                 case VG_MOVE_TO:
591                                         Log::getInstance()->log("OSD", Log::DEBUG, "Move To %g %g",coord[n],coord[n+1]);n+=2; break;
592                                 case VG_LINE_TO:
593                                         Log::getInstance()->log("OSD", Log::DEBUG, "Line To %g %g",coord[n],coord[n+1]);n+=2; break;
594                                 case VG_CUBIC_TO:
595                                         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;
596                                 case VG_QUAD_TO:
597                                         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;
598                                 case VG_CLOSE_PATH:
599                                         Log::getInstance()->log("OSD", Log::DEBUG, "Close Path"); break;
600                                 }
601
602                         }*/
603                         //vguRect(path,0.f,0.f,1.f,1.f);
604                         //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph %d %x",segments.size(),vgGetError());
605                 }
606                 VGfloat ori[]={0.f,0.f};
607                 VGfloat esp[]={ft_face->glyph->advance.x/64.f*aspect_correction,ft_face->glyph->advance.y/64.f};
608                 font_exp_x[glyph]=ft_face->glyph->advance.x/64.f*aspect_correction; //recalculate
609
610                 vgSetGlyphToPath(vgfont,glyph,path,VG_FALSE,ori,esp);
611                 //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph %d %d %x",path,glyph,vgGetError());
612                 if (path!=VG_INVALID_HANDLE) {
613                         vgDestroyPath(path);
614                 }
615                 cur_char = FT_Get_Next_Char(ft_face,cur_char,&glyph);
616         }
617         return 1;
618 }
619
620
621 void OsdOpenVG::drawSetTrans(SurfaceCommands & sc)
622 {
623         vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
624         vgLoadIdentity();
625         vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
626         vgTranslate(0.f+sc.x,-576.f+sc.y);
627
628         vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
629         vgLoadIdentity();
630     vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
631         vgTranslate(0.f+sc.x,-576.f+sc.y);
632
633         vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
634         vgLoadIdentity();
635         vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
636         vgTranslate(0.f+sc.x,-576.f+sc.y);
637
638
639
640         //vgTranslate(0.f+sc.x,576.f-sc.y);
641         //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Translate %g %g",sc.x,sc.y);
642
643 }
644 void OsdOpenVG::executeDrawCommand(SVGCommand & command)
645 {
646
647         VGfloat  save_matrix[9];
648         switch (command.instr) {
649         case DrawPath: {
650         vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
651         //      VGuint rgba;
652         //      rgba = vgGetColor((VGPaint) command.reference);
653                 //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);
654                 //vgSeti(VG_FILL_RULE,);
655
656                 vgGetMatrix(save_matrix);
657                 vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
658                 vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
659                 vgTranslate(command.x,command.y);
660                 vgScale(command.w,command.h);
661                 vgDrawPath(std_paths[command.target.path_index],VG_FILL_PATH);
662                 vgLoadMatrix(save_matrix);
663         } break;
664         case DrawImage: {
665             vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
666                 vgGetMatrix(save_matrix);
667                 vgTranslate(command.x,command.y);
668                 //vgScale(command.w,command.h);
669                 if (command.reference) { //special behaviout for bw images they act as a mask on the current paint
670                         vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
671                         vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
672                         vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL);
673                         vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
674                         vgScale(aspect_correction,1.f);
675                 } else {
676                         VGfloat imagewidth=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_WIDTH);
677                         VGfloat imageheight=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_HEIGHT);
678                         //vgScale(720.f/((float)BACKBUFFER_WIDTH), 576.f/((float)BACKBUFFER_HEIGHT));
679                         float scalex=command.w/imagewidth;
680                         float scaley=command.h/imageheight;
681                         //vgScale(command.w/imagewidth,command.h/imageheight);
682                         vgScale(scalex,scaley);
683                         vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
684                         //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Image Scale  %g %g %g %g %g %g",command.w,imagewidth,command.h,imageheight,scalex,scaley);
685                 }
686
687
688                 //vgLoadIdentity();
689                 //vgTranslate(200.f,500.f);
690                 //vgScale(100.f,100.f);
691
692                 vgDrawImage((VGImage) command.target.image);
693                 //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,
694                 //              vgGetError());
695                 if (command.reference) {
696                         vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
697                         vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
698                 }
699                 vgLoadMatrix(save_matrix);
700         } break;
701         case DrawGlyph: {
702                 vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
703                 vgGetMatrix(save_matrix);
704                 vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
705                 vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
706                 vgTranslate(command.x,command.y);
707                 VGfloat gori[]={0.,0.};
708                 vgSetfv(VG_GLYPH_ORIGIN,2,gori);
709
710                 unsigned int glyph_index=FT_Get_Char_Index(ft_face,command.target.textchar);
711                 vgDrawGlyph(vgfont,glyph_index,VG_FILL_PATH,VG_FALSE);
712                 //vgDrawPath(std_paths[Rectangle],VG_FILL_PATH);
713         /*      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,
714                                                 vgGetError());*/
715                 vgLoadMatrix(save_matrix);
716                 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
717         } break;
718         case DrawTTchar:{
719                 cTeletextChar tchar;
720                 tchar.setInternal(command.target.ttchar);
721                 vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
722                 vgGetMatrix(save_matrix);
723                 enumTeletextColor ttforegcolour=tchar.GetFGColor();
724                 enumTeletextColor ttbackgcolour=tchar.GetBGColor();
725             if (tchar.GetBoxedOut()) {
726                 ttforegcolour=ttcTransparent;
727                 ttbackgcolour=ttcTransparent;
728             }
729             vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL);
730             vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
731
732
733                 vgTranslate(command.x+command.w*11.85f*1.4f,command.y+command.h*19.75f);
734                 VGfloat gori[]={0.,0.};
735                 vgSetfv(VG_GLYPH_ORIGIN,2,gori);
736
737                 vgScale(-1.4f,2.f);
738                 unsigned int color=Surface::enumTeletextColorToCoulour(ttbackgcolour).rgba();
739                 color=color<<8 | (color &0xff000000)>>24;
740                 vgSetColor(vgttpaint,color);
741                 vgSetPaint((VGPaint) vgttpaint,VG_FILL_PATH);
742                 vgSetPaint((VGPaint) vgttpaint,VG_STROKE_PATH);
743                 cTeletextChar filled;
744                 filled.setInternal(0x187f);
745                 unsigned int glyph_index=loadTTchar(filled);
746                 vgDrawGlyph(vgttfont,glyph_index,VG_FILL_PATH,VG_FALSE);
747
748                 color=Surface::enumTeletextColorToCoulour(ttforegcolour).rgba();
749                 color=color<<8 | (color &0xff000000)>>24;
750                 vgSetColor(vgttpaint,color);
751                 vgSetPaint((VGPaint) vgttpaint,VG_FILL_PATH);
752                 vgSetPaint((VGPaint) vgttpaint,VG_STROKE_PATH);
753                 glyph_index=loadTTchar(tchar);
754                 vgDrawGlyph(vgttfont,glyph_index,VG_FILL_PATH,VG_FALSE);
755
756                 /*      Log::getInstance()->log("OSD", Log::DEBUG, "Draw TTchar %x %x %x %x",glyph_index,ttforegcolour,Surface::enumTeletextColorToCoulour(ttforegcolour).rgba(),
757                                         vgGetColor(vgttpaint));*/
758
759
760                 vgLoadMatrix(save_matrix);
761                 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
762                 vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
763                 vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
764
765         }break;
766         }
767 }
768
769 unsigned int OsdOpenVG::handleTask(OpenVGCommand& command)
770 {
771         switch (command.task){
772         case OVGdestroyImageRef: {
773                 vgDestroyImage((VGImage)command.param1);
774                 return 0;
775         } break;
776         case OVGdestroyPaint: {
777                 Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint Destroy %d ",command.param1);
778                 vgDestroyPaint((VGPaint)command.param1);
779                 return 0;
780         } break;
781         case OVGcreateImagePalette: {
782                 VGImage input=vgCreateImage(VG_A_8,command.param1, command.param2,
783                                 VG_IMAGE_QUALITY_NONANTIALIASED|
784                                 VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
785                 vgImageSubData(input,command.data,command.param1,
786                                                         VG_A_8,0,0,command.param1, command.param2); // upload palettized image data
787                 VGImage handle=vgCreateImage(VG_sRGBA_8888,command.param1, command.param2,
788                                                 VG_IMAGE_QUALITY_NONANTIALIASED|
789                                                 VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
790                 VGuint *palette=(VGuint*)malloc(256*sizeof(VGuint));
791                 VGuint *in_palette=(VGuint*)command.data2;
792                 for (int i=0;i<256;i++) {
793                         VGuint color=in_palette[i];
794                         palette[i]=color<<8 | (color &0xff000000)>>24;
795                 }
796
797                 vgLookupSingle(handle,input,palette,VG_ALPHA,VG_FALSE,VG_FALSE);
798                 free(palette);
799                 vgDestroyImage(input);
800
801                 return handle;
802         } break;
803         case OVGcreateMonoBitmap: {
804                 VGImage handle=vgCreateImage(VG_A_1,command.param1, command.param2,
805                                         VG_IMAGE_QUALITY_NONANTIALIASED|
806                                         VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
807                 //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
808                 unsigned int buffer_len=(command.param1*command.param2)>>3;
809                 unsigned char * buffer=(unsigned char*)malloc(buffer_len);
810                 unsigned char * r_buffer1=buffer;
811                 const unsigned char * r_buffer2=(const unsigned char *)command.data;
812                 unsigned char *buffer_end=buffer+buffer_len;
813                 while (r_buffer1!=buffer_end) {
814                         unsigned char byte=*r_buffer2;
815                         *r_buffer1=((byte * 0x0802LU & 0x22110LU) | (byte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
816                         r_buffer1++;r_buffer2++;
817                 }
818
819
820                 vgImageSubData(handle,buffer,command.param1>>3,
821                                         VG_A_1,0,0,command.param1, command.param2);
822                 free(buffer);
823         //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono2  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
824                 return handle;
825         } break;
826         case OVGcreateImageFile: {
827                 VGImage handle;
828                 try{
829                         Image *imagefile=(Image*)command.data;
830                         Blob imageblob;
831                         imagefile->write(&imageblob,"RGBA");
832
833
834                         handle=vgCreateImage(VG_sXBGR_8888,imagefile->columns(),imagefile->rows(),
835                                         VG_IMAGE_QUALITY_NONANTIALIASED|
836                                         VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
837                 //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark1",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data());
838                         vgImageSubData(handle,imageblob.data(),imagefile->columns()*4,
839                                         VG_sXBGR_8888,0,0,imagefile->columns(),imagefile->rows());
840                 //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark2",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data());
841                         delete imagefile;
842                 }catch( Exception &error_ )
843                 {
844                         Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick hT: %s",error_.what());
845
846                         return 0;
847                 }
848
849                 //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create file  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
850                 return handle;
851         } break;
852         case OVGcreateColorRef :{
853                 VGPaint handle;
854                 handle=vgCreatePaint();
855                 vgSetParameteri(handle, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
856                 vgSetColor(handle,command.param1);
857                 VGuint rgba;
858                 rgba = vgGetColor((VGPaint)handle);
859                 Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint %d %x %x",handle,command.param1,rgba);
860                 return handle;
861         } break;
862         case OVGimageUploadLine: {
863                 vgImageSubData((VGImage)command.param1,command.data,0,VG_sARGB_8888,0,command.param2,command.param3,1);
864                 return 0;
865         } break;
866
867         }
868 }
869
870 bool OsdOpenVG::processTasks()
871 {
872         bool worked=false;
873         taskmutex.Lock();
874         vgmutex.Lock();
875         while (vgcommands.size()>0)
876         {
877                 OpenVGCommand &comm=vgcommands.front();
878                 OpenVGResponse resp;
879                 resp.result=handleTask(comm);
880                 resp.id=comm.id;
881                 if (comm.id) {
882                         vgresponses.push_back(resp);
883                 }
884                 vgcommands.pop_front();
885                 taskmutex.Unlock();
886                 vgmutex.Unlock();
887                 //threadCheckExit();
888                 pthread_mutex_lock(&vgtaskCondMutex);
889                 pthread_cond_signal(&vgtaskCond);
890                 pthread_mutex_unlock(&vgtaskCondMutex);
891                 taskmutex.Lock();
892                 vgmutex.Lock();
893                 worked=true;
894         }
895         taskmutex.Unlock();
896         vgmutex.Unlock();
897
898         return worked;
899 }
900
901 bool OsdOpenVG::haveOpenVGResponse(unsigned int id,unsigned int * resp)
902 {
903         taskmutex.Lock();
904         if (vgresponses.size()>0)
905         {
906                 deque<OpenVGResponse>::iterator itty=vgresponses.begin();
907                 while (itty!=vgresponses.end())
908                 {
909                         if ((*itty).id==id) {
910                                 *resp=(*itty).result;
911                                 taskmutex.Unlock();
912                                 return true;
913                         }
914                         itty++;
915                 }
916         }
917         taskmutex.Unlock();
918         return false;
919 }
920
921
922 unsigned int  OsdOpenVG::putOpenVGCommand(OpenVGCommand& comm,bool wait)
923 {
924         taskmutex.Lock();
925         if (wait){
926                 comm.id=wait_id;
927                 wait_id++;
928         } else {
929                 comm.id=0; // we are not waiting
930         }
931         vgcommands.push_back(comm);
932         taskmutex.Unlock();
933         threadSignal();
934         while (wait) {
935                 unsigned int resp;
936                 if (!haveOpenVGResponse(comm.id,&resp)) {
937                         struct timespec target_time;
938                         clock_gettime(CLOCK_REALTIME,&target_time);
939                         target_time.tv_nsec+=1000000LL*100;
940                         if (target_time.tv_nsec>999999999) {
941                                         target_time.tv_nsec-=1000000000L;
942                                         target_time.tv_sec+=1;
943                         }
944                         pthread_mutex_lock(&vgtaskCondMutex);
945                         pthread_cond_timedwait(&vgtaskCond, &vgtaskCondMutex,&target_time);
946                         pthread_mutex_unlock(&vgtaskCondMutex);
947                 } else {
948                         return resp;
949                 }
950         }
951         return 0;
952 }
953
954 void OsdOpenVG::imageUploadLine(ImageIndex index,unsigned int j,unsigned int width,void *data)
955 {
956         vgImageSubData((VGImage)index,data,0,VG_sARGB_8888,0,j,width,1);
957
958         struct OpenVGCommand comm;
959         comm.task=OVGimageUploadLine;
960         comm.param1=index;
961         comm.param2=j;
962         comm.param3=width;
963         comm.data=data;
964         putOpenVGCommand(comm,true);
965 }
966
967 void OsdOpenVG::destroyImageRef(ImageIndex index)
968 {
969         struct OpenVGCommand comm;
970         comm.task=OVGdestroyImageRef;
971         comm.param1=index;
972         putOpenVGCommand(comm,false);
973 }
974
975 ImageIndex OsdOpenVG::createJpeg(const char* fileName, int *width,int *height)
976 {
977         Image* magicimage=NULL;
978         bool mem=false;
979         struct OpenVGCommand comm;
980         comm.task=OVGcreateImageFile;
981
982         try{
983                 // Now figure out, if it is a special case
984                 if (strcmp(fileName,"/vdr.jpg")==0) {
985                         magicimage=new Image(Blob(vdr_data,vdr_data_end-vdr_data));
986                         *height=100; // this is faked so that the system does use the old coordinate system
987                         *width=ceil(190.f*aspect_correction);
988                         Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm vdr.jpg");
989                 } else if (strcmp(fileName,"/wallpaperPAL.jpg")==0) {
990                         magicimage=new Image(Blob(wallpaper_data,wallpaper_data_end-wallpaper_data));
991                         *width=720; // this is faked so that the system does use the old coordinate system
992                         *height=576;
993                         Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm wallpaperPAL.jpg");
994                 } else {
995                         magicimage=new Image();
996                         magicimage->read(fileName);
997                         Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm file: %s",fileName);
998                         *width=ceil(magicimage->baseColumns()*aspect_correction); // this is faked so that the system does use the old coordinate system
999                         *height=magicimage->baseRows();
1000                 }
1001
1002         }catch( Exception &error_ )
1003         {
1004                 Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick: %s",error_.what());
1005
1006                 return 0;
1007         }
1008         comm.data=magicimage;
1009         return putOpenVGCommand(comm,true);
1010 }
1011
1012 ImageIndex OsdOpenVG::createMonoBitmap(void *base,int width,int height)
1013 {
1014         struct OpenVGCommand comm;
1015         comm.task=OVGcreateMonoBitmap;
1016         comm.param1=width;
1017         comm.param2=height;
1018         comm.data=base;
1019         return putOpenVGCommand(comm,true);
1020 }
1021
1022 ImageIndex OsdOpenVG::createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
1023 {
1024     struct OpenVGCommand comm;
1025     comm.task=OVGcreateImagePalette;
1026     comm.param1=width;
1027     comm.param2=height;
1028     comm.data=image_data;
1029     comm.data2=palette_data;
1030     return putOpenVGCommand(comm,true);
1031 }
1032
1033 void OsdOpenVG::destroyStyleRef(unsigned int index)
1034 {
1035         struct OpenVGCommand comm;
1036         comm.task=OVGdestroyPaint;
1037         comm.param1=index;
1038         putOpenVGCommand(comm,false);
1039 }
1040
1041 unsigned int OsdOpenVG::createStyleRef(const DrawStyle &c)
1042 {
1043         unsigned int col=c.rgba();
1044         struct OpenVGCommand comm;
1045         comm.task=OVGcreateColorRef;
1046         comm.param1=col<<8 | (col &0xff000000)>>24;
1047         comm.data=&c;
1048         return putOpenVGCommand(comm,true);
1049 }
1050
1051 unsigned int OsdOpenVG::createColorRef(const Colour &c)
1052 {
1053         unsigned int col=c.rgba();
1054         struct OpenVGCommand comm;
1055         comm.task=OVGcreateColorRef;
1056         comm.param1=col<<8 | (col &0xff000000)>>24;
1057         comm.data=&c;
1058         return putOpenVGCommand(comm,true);
1059 }
1060
1061