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