]> git.vomp.tv Git - vompclient.git/blob - osdwinvector.cc
Compile fixes for stretch
[vompclient.git] / osdwinvector.cc
1 /*
2     Copyright 2014 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 "osdwinvector.h"
23 #include "mtd.h"
24 #include "videowin.h"
25 #include "surfacewin.h"
26
27
28 #include "message.h"
29 #include "command.h"
30
31 #include "teletxt/txtfont.h"
32
33 #include <wincodec.h>
34
35 #define  OSD_BUFFER_WIDTH 1280
36 #define  OSD_BUFFER_HEIGHT 720
37
38 #include "staticartwork.h"
39
40 #define EXTERNALPICTURE(name, fname, fileextension)  #name, 
41
42 char *ext_pict_name[] {
43         "None",
44         EXTERNAL_PICTS
45 };
46
47 #undef EXTERNALPICTURE
48
49
50 class WICPictDecoder : public OsdVector::PictureDecoder {
51 public:
52         WICPictDecoder(OsdVector::PictureReader* treader, OsdWinVector *posd);
53         virtual ~WICPictDecoder();
54
55         unsigned char *decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem);
56
57         bool getDecodedPicture(struct OsdVector::PictureInfo& pict_inf);
58
59         void freeReference(void * ref);
60
61 protected:
62         OsdVector::PictureInfo pictInf;
63         bool pictInfValid;
64         IWICImagingFactory *wicfactory;
65         OsdWinVector * osd;
66 };
67
68 WICPictDecoder::WICPictDecoder(OsdVector::PictureReader* treader, OsdWinVector *posd) : OsdVector::PictureDecoder(treader)
69 {
70         pictInfValid = false; 
71         osd = posd;
72         HRESULT hres = CoCreateInstance(CLSID_WICImagingFactory,
73                 NULL,CLSCTX_INPROC_SERVER,
74                 IID_IWICImagingFactory, (void**)&wicfactory);
75
76
77 }
78
79 WICPictDecoder::~WICPictDecoder()
80 {
81         wicfactory->Release();
82 }
83
84 unsigned char * WICPictDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem)
85 {
86         if (pictInfValid) return buffer; // does support only one image at a Time;
87         
88         IWICStream * stream = NULL;
89         IWICBitmapDecoder *decoder = NULL;
90         IWICBitmapFrameDecode *source = NULL;
91         IWICFormatConverter *converter = NULL;
92
93         HRESULT hres;
94
95         hres = wicfactory->CreateStream(&stream);
96
97         if (hres != S_OK)
98         {
99
100                 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not create stream %d", hres);
101                 return buffer;
102         }
103         hres = stream->InitializeFromMemory(buffer, length);
104
105         if (hres != S_OK)
106         {
107                 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not initialize from memory %d", hres);
108                 stream->Release();
109                 return buffer;
110         }
111
112
113         hres = wicfactory->CreateDecoderFromStream(stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder);
114         if (hres != S_OK)
115         {
116
117                 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not create decoder %d", hres);
118                 stream->Release();
119                 return buffer;
120         }
121
122         hres = decoder->GetFrame(0, &source);
123         if (hres != S_OK)
124         {
125
126                 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not get source %d", hres);
127                 decoder->Release();
128                 stream->Release();
129                 return buffer;
130         }
131
132         hres = wicfactory->CreateFormatConverter(&converter);
133         if (hres != S_OK)
134         {
135
136                 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not get source %d", hres);
137                 source->Release();
138                 decoder->Release();
139                 stream->Release();
140                 return buffer;
141         }
142
143         hres= converter->Initialize(source, GUID_WICPixelFormat32bppPBGRA,
144                 WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
145         if (hres != S_OK)
146         {
147
148                 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not initialise converter %d", hres);
149                 converter->Release();
150                 source->Release();
151                 decoder->Release();
152                 stream->Release();
153                 return buffer;
154         }
155
156         ID2D1RenderTarget * rt=osd->LockOsdDrawing();
157
158
159         ID2D1Bitmap* bitmap;
160         hres = rt->CreateBitmapFromWicBitmap(converter, NULL, &bitmap);
161         if (hres == S_OK) {
162                 D2D1_SIZE_F size = bitmap->GetSize();
163                 pictInf.reference = (void*)bitmap;
164                 pictInf.width = size.width;
165                 pictInf.height = size.height;
166                 pictInf.image = bitmap;
167                 pictInf.decoder = this;
168                 pictInf.type = OsdVector::PictureInfo::D2DBitmap;
169                 pictInf.lindex = index;
170                 pictInfValid = true;
171                 if (freemem) {
172                         free(buffer);
173                 }
174         }
175
176         osd->UnlockOsdDrawing();
177
178         converter->Release();
179         source->Release();
180         decoder->Release();
181         stream->Release();
182
183         if (pictInfValid) return NULL;
184         else return buffer;
185 }
186
187 void WICPictDecoder::freeReference(void * ref)
188 {
189         ID2D1Bitmap* bitmap = (ID2D1Bitmap*)ref;
190         if (ref) bitmap->Release();
191 }
192
193 bool WICPictDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
194 {
195         if (!pictInfValid) return false;
196         pict_inf = pictInf;
197         pictInfValid = false;
198         return true;
199 }
200
201
202 //This is stuff for rendering the OSD
203
204 OsdWinVector::OsdWinVector()
205 {
206         d3ddevice10 = NULL;
207         d2dfactory = NULL;
208         currentosd_render.surf9 = NULL;
209         currentosd_render.surf10 = NULL;
210         currentosd_render.query9 = NULL;
211         currentosd_render.query10 = NULL;
212         currentosd_render.surfdxgi = NULL;
213         currentosd_render.sharedhandle = NULL;
214         currentosd_render.rendtarget2D = NULL;
215         currentosd_backbuffer = currentosd_backbuffer;
216         aspect_correction = 1.;
217         is_direct_write_initted = false;
218         dwritefac = NULL;
219         font = NULL;
220         fontface = NULL;
221         fontaspect_corr = 1.f;
222         dpix = dpiy = 72.f;
223         
224
225         ttchar_end.atlas = 0;
226         ttchar_end.position = 0;
227         ttbrush = NULL;
228
229         const wchar_t *fontname = L"Arial";
230         cur_fontname = (wchar_t*)malloc(2*wcslen(fontname) + 2);
231         wcscpy(cur_fontname, fontname);
232
233         WICPictDecoder * wicdecode = new WICPictDecoder(&reader, this);
234         reader.addDecoder(wicdecode);
235   
236 }
237
238 OsdWinVector::~OsdWinVector()
239 {
240         if (cur_fontname) free(cur_fontname);
241
242   if (initted) 
243   {
244                 shutdown();
245                 if (dwritefac) dwritefac->Release();
246                 if (!fontnames.size()) {
247                         vector<char*>::iterator itty = fontnames.begin();
248                         while (itty != fontnames.end()) {
249                                 free((void*)*itty);
250
251                                 itty++;
252                         }
253                 }
254                 /*if (!fontnames_keys.size()) {
255                         vector<char*>::iterator itty = fontnames_keys.begin();
256                         while (itty != fontnames_keys.end()) {
257                                 free((void*)*itty);
258
259                                 itty++;
260                         }
261                 }*/
262                 if (font) font->Release();
263                 if (fontface) fontface->Release();
264   }
265 }
266
267
268
269 int OsdWinVector::init(void* device)
270 {
271   if (initted) return 0;
272   reader.init();
273
274   if (!createDirect3D9Objects()) return 0;
275
276   // then create the Device
277
278   if (D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, D3D10_CREATE_DEVICE_BGRA_SUPPORT, D3D10_FEATURE_LEVEL_9_1,
279           D3D10_1_SDK_VERSION, &d3ddevice10) != S_OK) {
280           Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D10 device!");
281           return 0;
282   }
283
284   if (d3ddevice10->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgidevice) != S_OK) {
285           Log::getInstance()->log("OSD", Log::WARN, "Could not query Dxgi device!");
286           return 0;
287   }
288
289   if (D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, __uuidof(ID2D1Factory),(void**) &d2dfactory) != S_OK) {
290           Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct2dfactory");
291           return 0;
292   }
293
294
295
296   queuemutex.Lock();
297
298   HRESULT hres;
299   DXGI_SURFACE_DESC  surf_desc;
300   surf_desc.Width = OSD_BUFFER_WIDTH;
301   surf_desc.Height = OSD_BUFFER_HEIGHT;
302   surf_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
303   surf_desc.SampleDesc.Count = 1;
304   surf_desc.SampleDesc.Quality = 0;
305
306
307
308   D2D1_RENDER_TARGET_PROPERTIES rt_prop;
309   rt_prop.dpiX = rt_prop.dpiY = 0; 
310   rt_prop.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED);
311   rt_prop.minLevel = D2D1_FEATURE_LEVEL_9;
312   rt_prop.type = D2D1_RENDER_TARGET_TYPE_HARDWARE;
313   rt_prop.usage = D2D1_RENDER_TARGET_USAGE_NONE;
314
315   for (int i = 0; i < 3; i++) {
316           SurfaceInfo surfinfo;
317           surfinfo.surf9 = NULL;
318           surfinfo.surf10 = NULL;
319           surfinfo.query9 = NULL;
320           surfinfo.query10 = NULL;
321           surfinfo.surfdxgi = NULL;
322           surfinfo.sharedhandle = NULL;
323           surfinfo.rendtarget2D = NULL;
324
325           
326           hres = d3ddevice->CreateTexture(OSD_BUFFER_WIDTH, OSD_BUFFER_HEIGHT, 1, D3DUSAGE_RENDERTARGET, /*D3DFMT_A8R8G8B8*/D3DFMT_A8R8G8B8,
327                   D3DPOOL_DEFAULT, &surfinfo.surf9, &surfinfo.sharedhandle);
328           if (hres != S_OK) {
329                   Log::getInstance()->log("OSD", Log::WARN, "Could not create Texture for Direct3D9 !");
330                   queuemutex.Unlock();
331                   return 0;
332           }
333
334           hres = d3ddevice->CreateQuery(D3DQUERYTYPE_EVENT, &surfinfo.query9);
335           if (hres != S_OK) {
336                   Log::getInstance()->log("OSD", Log::WARN, "Could not create Query for Direct3D9 !");
337                   queuemutex.Unlock();
338                   return 0;
339           }
340
341           DXGI_SHARED_RESOURCE dxgi_res;
342           dxgi_res.Handle = surfinfo.sharedhandle;
343
344           ID3D10Resource * tempres = NULL;
345           hres = d3ddevice10->OpenSharedResource(surfinfo.sharedhandle, __uuidof(ID3D10Resource), (void**)&tempres);
346           if (hres != S_OK) {
347                   Log::getInstance()->log("OSD", Log::WARN, "Could not open resourcee for Direct3D10 !");
348                   queuemutex.Unlock();
349                   return 0;
350           }
351
352           hres = tempres->QueryInterface(__uuidof(ID3D10Texture2D), (void**)&surfinfo.surf10);
353           if (hres != S_OK) {
354                   Log::getInstance()->log("OSD", Log::WARN, "Could not query surface for Direct3D10 !");
355                   queuemutex.Unlock();
356                   return 0;
357           }
358           tempres->Release();
359
360
361           hres = surfinfo.surf10->QueryInterface(__uuidof(IDXGISurface), (void**)&surfinfo.surfdxgi);
362           if (hres != S_OK) {
363                   Log::getInstance()->log("OSD", Log::WARN, "Could not query surface for DXGI !");
364                   queuemutex.Unlock();
365                   return 0;
366           }
367
368           hres = d2dfactory->CreateDxgiSurfaceRenderTarget(surfinfo.surfdxgi, &rt_prop, &surfinfo.rendtarget2D);
369           if (hres != S_OK) {
370                   Log::getInstance()->log("OSD", Log::WARN, "Could not create render target!");
371                   queuemutex.Unlock();
372                   return 0;
373           }
374
375           surfinfo.rendtarget2D->GetDpi(&dpix, &dpiy);
376
377           if (i == 0) {
378                   surfinfo.rendtarget2D->CreateSolidColorBrush(D2D1::ColorF(0xFFFFFFFF, 1.f), &ttbrush);
379           }
380
381           D3D10_QUERY_DESC qdesc;
382           qdesc.Query = D3D10_QUERY_EVENT;
383           qdesc.MiscFlags = 0;
384
385           hres = d3ddevice10->CreateQuery(&qdesc, &surfinfo.query10);
386           if (hres != S_OK) {
387                   Log::getInstance()->log("OSD", Log::WARN, "Could not create Query for Direct2D Direct3D10 !");
388                   queuemutex.Unlock();
389                   return 0;
390           }
391           allsurfs.push_back(surfinfo);
392           d3dtod2d.push(surfinfo);
393   }
394   aspect_correction = ((float)OSD_BUFFER_HEIGHT) / 576.f / (((float)OSD_BUFFER_WIDTH) / 720.f);
395
396   
397   queuemutex.Unlock();
398
399   initPaths();
400
401   loadFont(false);
402
403   initted = 1; // must set this here or create surface won't work
404
405   startRenderLoop();
406
407   return 1;
408 }
409
410
411 int OsdWinVector::shutdown()
412 {
413   if (!initted) return 0;
414   initted = 0;
415   stopRenderLoop();
416   reader.shutdown();
417   destroyPaths();
418
419
420   queuemutex.Lock();
421   if (currentosd_render.surf9) {
422           currentosd_render.surf9 = NULL;
423   }
424
425   if (currentosd_backbuffer.surf9) {
426           currentosd_backbuffer.surf9 = NULL;
427   }
428
429
430
431   for (int i = 0; i < tt_atlas.size(); i++)
432   {
433           tt_atlas[i]->Release();
434   }
435   tt_atlas.clear();
436   tt_font_chars.clear();
437   ttbrush->Release();
438   ttbrush = NULL;
439
440   while (allsurfs.size()) {
441           SurfaceInfo surfinfo = allsurfs.front();
442           allsurfs.pop_front();
443           if (surfinfo.rendtarget2D) {
444                   ID2D1RenderTarget *temp = surfinfo.rendtarget2D;
445                   surfinfo.rendtarget2D = NULL;
446                   temp->Release();
447           }
448
449           if (surfinfo.surf9) {
450                   LPDIRECT3DTEXTURE9 temp = surfinfo.surf9;
451                   surfinfo.surf9 = NULL;
452                   temp->Release();
453           }
454
455           if (surfinfo.query9) {
456                   IDirect3DQuery9* temp = surfinfo.query9;
457                   surfinfo.query9 = NULL;
458                   temp->Release();
459           }
460
461           if (surfinfo.surf10) {
462                   ID3D10Texture2D * temp = surfinfo.surf10;
463                   surfinfo.surf10 = NULL;
464                   temp->Release();
465           }
466
467           if (surfinfo.surfdxgi) {
468                   IDXGISurface *temp = surfinfo.surfdxgi;
469                   surfinfo.surfdxgi = NULL;
470                   temp->Release();
471           }
472           if (surfinfo.query10) {
473                   ID3D10Query* temp = surfinfo.query10;
474                   surfinfo.query10 = NULL;
475                   temp->Release();
476           }
477   }
478
479   while (d3dtod2d.size()) d3dtod2d.pop();
480   while (d2dtod3d.size()) d2dtod3d.pop();
481
482   queuemutex.Unlock();
483
484
485
486   if (d2dfactory) {
487           ID2D1Factory *temp = d2dfactory;
488           d2dfactory = NULL;
489           temp->Release();
490   }
491
492   if (d3ddevice10) {
493           ID3D10Device *temp = d3ddevice10;
494           d3ddevice10 = NULL;
495           temp->Release();
496   }
497
498   shutdownDirect3D9Objects();
499  
500
501   return 1;
502 }
503
504
505 void OsdWinVector::initPaths()
506 {
507         ID2D1PathGeometry *current = NULL;
508         ID2D1GeometrySink *currentsink = NULL;
509
510         d2dfactory->CreatePathGeometry(&current);
511         current->Open(&currentsink);
512         currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_HOLLOW);
513
514         currentsink->AddLine(D2D1::Point2F(1.f, 0));
515
516         currentsink->EndFigure(D2D1_FIGURE_END_OPEN);
517         // HorzLine
518         std_paths[PIHorzLine] = current;
519
520         current = NULL;
521         currentsink->Close();
522         currentsink->Release();
523         currentsink=NULL;
524
525         d2dfactory->CreatePathGeometry(&current);
526         current->Open(&currentsink);
527         currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_HOLLOW);
528
529         currentsink->AddLine(D2D1::Point2F(0, 1.f));
530         currentsink->EndFigure(D2D1_FIGURE_END_OPEN);
531
532         // VertLine
533         std_paths[PIVertLine] = current;
534
535         current = NULL;
536         currentsink->Close();
537         currentsink->Release();
538         currentsink = NULL;
539
540         d2dfactory->CreatePathGeometry(&current);
541         current->Open(&currentsink);
542         currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_FILLED);
543
544         currentsink->AddLine(D2D1::Point2F(1, 0));
545         currentsink->AddLine(D2D1::Point2F(1, 1));
546         currentsink->AddLine(D2D1::Point2F(0, 1));
547         currentsink->EndFigure(D2D1_FIGURE_END_CLOSED);
548         // Rectabgle
549         std_paths[PIRectangle] = current;
550
551         current = NULL;
552         currentsink->Close();
553         currentsink->Release();
554         currentsink = NULL;
555
556         d2dfactory->CreatePathGeometry(&current);
557         current->Open(&currentsink);
558         currentsink->BeginFigure(D2D1::Point2F(0, 0.f), D2D1_FIGURE_BEGIN_FILLED);
559
560         currentsink->AddArc(D2D1::ArcSegment(
561                 D2D1::Point2F(0, 0.f),
562                 D2D1::SizeF(1.f, 1.f),
563                 0.0f,
564                 D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
565                 D2D1_ARC_SIZE_LARGE));
566
567         currentsink->EndFigure(D2D1_FIGURE_END_CLOSED);
568
569
570         // Point
571         std_paths[PIPoint] = current;
572
573         current = NULL;
574         currentsink->Close();
575         currentsink->Release();
576         currentsink = NULL;
577
578 }
579
580 void OsdWinVector::destroyPaths()
581 {
582         std_paths[PIHorzLine]->Release();
583         std_paths[PIVertLine]->Release();
584         std_paths[PIRectangle]->Release();
585         std_paths[PIPoint]->Release();
586
587 }
588
589
590
591 int  OsdWinVector::loadFont(bool newfont)
592 {
593         HRESULT hres;
594         if (!is_direct_write_initted)
595         {
596                 
597                 hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
598                         (IUnknown**)(&dwritefac));
599                 if (hres != S_OK)  {
600                         Log::getInstance()->log("OSD", Log::WARN, "Could not create DirectWrite Factory!");
601                         return 0;
602                 }
603
604                 is_direct_write_initted = true;
605         }
606
607         if (fontnames.size())
608         {
609                 fontnames.clear();
610         }
611
612         IDWriteFontCollection * fontcol = NULL;
613         if (dwritefac->GetSystemFontCollection(&fontcol) != S_OK) {
614                 Log::getInstance()->log("OSD", Log::WARN, "Could not get System Font Collection!");
615                 return 0;
616         }
617         UINT num_font = fontcol->GetFontFamilyCount();
618         for (UINT i = 0; i < num_font; i++) {
619                 IDWriteFontFamily * family=NULL;
620                 if (fontcol->GetFontFamily(i, &family)!=S_OK) continue;
621                 IDWriteLocalizedStrings* fam_name=NULL;
622                 if (family->GetFamilyNames(&fam_name) != S_OK) {
623                         family->Release();
624                         continue;
625                 }
626                 UINT32 id = 0;
627                 BOOL exist = false;
628                 if (fam_name->FindLocaleName(L"en-us", &id, &exist) == S_OK) {
629                         if (!exist) id = 0;
630                         UINT32  strlen=0;
631                         fam_name->GetStringLength(id, &strlen);
632                         wchar_t * stringbuf = new wchar_t[strlen + 1];
633                         
634                         fam_name->GetString(id, stringbuf, strlen+1);
635
636                         int strlenutf8 = WideCharToMultiByte(CP_UTF8, 0, stringbuf, -1,
637                                 NULL, 0, 0, NULL);
638                         char *stringbufutf8 = new char[strlenutf8 + 1];
639                         WideCharToMultiByte(CP_UTF8, 0, stringbuf, -1,
640                                 stringbufutf8, strlenutf8+1, 0, NULL);
641                 
642
643                         if (wcscmp(cur_fontname, stringbuf) == 0) {
644                                 IDWriteFont* new_font;
645                                 if (family->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL,
646                                         DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &new_font) == S_OK) {
647                                         IDWriteFontFace *newfontface = NULL;
648                                         new_font->CreateFontFace(&newfontface);
649
650                                         IDWriteFont* temp_font = font;
651                                         IDWriteFontFace* temp_fontface = fontface;
652                                         font = new_font;
653                                         fontface = newfontface;
654
655                                         if (temp_font) temp_font->Release();    
656                                         if (temp_fontface) temp_fontface->Release();
657                                 }
658                         }
659
660                         delete[] stringbuf;
661                         fontnames.push_back(stringbufutf8);
662                 }
663                 fam_name->Release();
664                 family->Release();
665         }
666         fontcol->Release();
667         
668         if (font) {
669                 DWRITE_FONT_METRICS metrics;
670                 font->GetMetrics(&metrics);
671                 fontheight = ((float)( metrics.ascent + metrics.descent + metrics.lineGap))*13.f 
672                         / ((float)metrics.designUnitsPerEm) / 576.f * ((float)OSD_BUFFER_HEIGHT)/72.f*dpiy;
673                 fontzero = ((float)(metrics.ascent))*13.f
674                         / ((float)metrics.designUnitsPerEm) / 576.f * ((float)OSD_BUFFER_HEIGHT) / 72.f*dpiy;
675
676                 fontaspect_corr = ((float)OSD_BUFFER_HEIGHT) / ((float)OSD_BUFFER_WIDTH) * 720.f / 576.f;
677                 
678
679                 for (UINT32 i = 0; i<256; i++) {
680                         DWRITE_GLYPH_METRICS glyph_metrics;
681                         UINT16 glyph_index;
682                         fontface->GetGlyphIndices(&i, 1, &glyph_index);
683                         HRESULT hres=fontface->GetDesignGlyphMetrics(&glyph_index, 1, &glyph_metrics, FALSE);
684                 
685                         if (hres == S_OK) {
686                                 byte_char_width[i] = ((float)glyph_metrics.advanceWidth)*13.f
687                                         / ((float)metrics.designUnitsPerEm)  *fontaspect_corr / 72.f*dpix;
688                         }
689                         else {
690                                 byte_char_width[i] = 0.f;
691                         }
692                 }
693
694                 
695
696
697         }
698
699
700         return 1;
701 }
702
703
704 OsdWinVector::TTIndex OsdWinVector::loadTTchar(cTeletextChar c)
705 {
706         /*      map<unsigned int, TTIndex> tt_font_chars;
707         vector<ID2D1Bitmap *> tt_atlas;
708         TTIndex ttchar_end;*/
709
710
711         unsigned int glyph_index = c.getGlyphIndex();
712         map<unsigned int, TTIndex>::iterator glypos = tt_font_chars.find(glyph_index);
713         if (glypos != tt_font_chars.end())
714         {
715                 return (*glypos).second;
716         }
717         TTIndex our_index = ttchar_end;
718
719         unsigned int buffer[10];
720         unsigned int * charmap = GetFontChar(c, buffer);
721         if (!charmap) { //invalid char
722                 our_index.atlas = our_index.position = 0;
723                 return our_index;
724         }
725
726
727
728         // Now we have to determine, if the atlas is already created
729         if (our_index.atlas == tt_atlas.size()) {
730                 //Now we have to create the atlas
731                 ID2D1Bitmap * atlas = NULL;
732                 D2D1_SIZE_U size;
733                 size.height = 120;
734                 size.width = 120;
735                 D2D1_BITMAP_PROPERTIES bitmap_prop;
736                 bitmap_prop.dpiX = dpix;
737                 bitmap_prop.dpiY = dpiy;
738                 bitmap_prop.pixelFormat.format = DXGI_FORMAT_A8_UNORM;
739                 bitmap_prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_STRAIGHT;
740
741                 HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, bitmap_prop, &atlas);
742
743                 if (hres != S_OK) {
744                         Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap for atlas failed %d", hres);
745                         atlas = NULL;
746                         our_index.atlas = our_index.position = 0;
747                         return our_index;
748                 }
749                 tt_atlas.push_back(atlas);
750
751         }
752
753         unsigned char buffer_final[120];
754         for (int i = 0; i<10; i++) {
755                 for (int j = 0; j < 12; j++) {
756                         buffer_final[i*12+j] = ((charmap[i] >> (16-j)) & 1)? 0xFF: 0x00;
757                 }
758         }
759
760         D2D1_RECT_U dst_rect = { (our_index.position % 10)*12,
761                 (our_index.position /10) *10,
762                 (our_index.position % 10+1)*12,
763                 (our_index.position / 10+1)*10,
764         };
765
766         HRESULT hres=tt_atlas[our_index.atlas]->CopyFromMemory(&dst_rect, buffer_final, 12);
767
768         if (hres != S_OK) {
769                 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CopyFromMemory for atlas failed %d", hres);
770                 our_index.atlas = our_index.position = 0;
771                 return our_index;
772         }
773
774         tt_font_chars[glyph_index] = our_index;
775         ttchar_end.position++;
776         if (ttchar_end.position == 120) {
777                 ttchar_end.position = 0;
778                 ttchar_end.atlas++;
779         }
780         return our_index;
781
782 }
783
784 int OsdWinVector::getFontNames(const char *** names, const char *** names_keys)
785 {
786         *names = (const char**)&(fontnames[0]);
787         *names_keys = (const char**)&(fontnames/*_keys*/[0]);
788         return fontnames.size();
789 }
790
791 void OsdWinVector::setFont(const char * fontname) {
792
793         wchar_t * wfontname= new wchar_t[strlen(fontname)+1];
794
795         MultiByteToWideChar(CP_UTF8, 0, fontname, -1,
796                 wfontname, strlen(fontname) + 1);
797
798         if (wcscmp(wfontname, cur_fontname)) {
799                 // new font!
800                 if (cur_fontname) free(cur_fontname);
801                 cur_fontname = (wchar_t*)malloc(2*wcslen(wfontname) + 2);
802                 wcscpy(cur_fontname, wfontname);
803                 loadFont(true);
804
805         }
806
807
808         delete[] wfontname;
809
810 }
811
812
813
814 void OsdWinVector::drawSetTrans(SurfaceCommands & sc)
815 {
816         D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Identity();
817
818         trans = trans*D2D1::Matrix3x2F::Scale(((float)OSD_BUFFER_WIDTH) / 720.f, ((float)OSD_BUFFER_HEIGHT) / 576.f);
819         trans=D2D1::Matrix3x2F::Translation(0.f + sc.x,  sc.y)*trans;
820
821         currentosd_backbuffer.rendtarget2D->SetTransform(trans);
822
823         clip_shift_x = sc.x;
824         clip_shift_y = sc.y;
825 }
826
827 void OsdWinVector::executeDrawCommand(SVGCommand & command)
828 {
829         D2D1::Matrix3x2F save_matrix;
830         D2D1::Matrix3x2F save_matrix2;
831
832
833         switch (command.instr) {
834         case DrawPath: {
835                 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
836                 
837                 D2D1::Matrix3x2F matrix;
838                 matrix =  
839                         D2D1::Matrix3x2F::Scale(command.w, command.h)*D2D1::Matrix3x2F::Translation(command.x, command.y)*save_matrix;
840                 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
841                 currentosd_backbuffer.rendtarget2D->FillGeometry(std_paths[command.target.path_index], 
842                         (ID2D1Brush*)command.reference);
843
844                 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
845
846         } break;
847         case DrawImage: {
848                                                 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
849                                                 ID2D1Bitmap * bitmap = (ID2D1Bitmap*)command.target.image;
850                                                 if (!bitmap) return;
851                                                 D2D1_SIZE_F  size=bitmap->GetSize(); 
852                                                 
853                                                 D2D1::Matrix3x2F matrix;
854                                                 
855
856                                                 if (command.reference) { //special behaviour for bw images they act as a mask on the current paint
857                                                         matrix =
858                                                                 D2D1::Matrix3x2F::Scale(1.f*aspect_correction, 1.f)
859                                                                 *D2D1::Matrix3x2F::Translation(command.x, command.y)*save_matrix;
860                                                 }
861                                                 else {
862
863                                                         float scalex = command.w / size.width;
864                                                         float scaley = command.h / size.height;
865                                                         float tx = command.x;
866                                                         float ty = command.y;
867                                                         if (command.corner == TopLeftLimited) {
868                                                                 if (scalex != 0.f && scaley != 0.f) {
869                                                                         float imageaspect = size.width / size.height;
870                                                                         float boxaspect = command.w / command.h / aspect_correction;
871                                                                         if (imageaspect > boxaspect) {
872                                                                                 scaley = 0.f;
873                                                                                 ty += (command.h - size.height * scalex / aspect_correction)*0.5f;
874                                                                         }
875                                                                         else {
876                                                                                 scalex = 0.f;
877                                                                                 tx += (command.w - size.width * scaley*aspect_correction)*0.5f;
878                                                                         }
879
880                                                                 }
881
882                                                         }
883                                                         if (scalex == 0.f && scaley == 0.f) {
884                                                                 scalex = aspect_correction;
885                                                                 scaley = 1.f;
886                                                         }
887                                                         else if (scalex == 0.f) {
888                                                                 scalex = scaley*aspect_correction;
889                                                         }
890                                                         else if (scaley == 0.f) {
891                                                                 scaley = scalex / aspect_correction;
892                                                         }
893
894
895                                                         if (command.corner == BottomRight || command.corner == BottomLeft || command.corner == BottomMiddle)
896                                                         {
897                                                                 ty -= size.height * scaley;
898                                                         }
899
900                                                         if (command.corner == BottomRight || command.corner == TopRight)
901                                                         {
902                                                                 tx -= size.width * scalex;
903                                                         }
904
905                                                         if (command.corner == BottomMiddle || command.corner == TopMiddle)
906                                                         {
907                                                                 tx -= size.width * scalex *0.5f;
908                                                         }
909
910                                                         matrix =
911                                                                 D2D1::Matrix3x2F::Scale(scalex, scaley)*D2D1::Matrix3x2F::Translation(tx, ty)*save_matrix;
912
913                                         
914                                                 }
915
916                                                 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
917
918                                                 if (command.reference) {
919                                                         currentosd_backbuffer.rendtarget2D->FillOpacityMask(bitmap, (ID2D1Brush*)command.reference, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
920                                                         
921                                                 }
922                                                 else 
923                                                 {
924                                                         currentosd_backbuffer.rendtarget2D->DrawBitmap(bitmap);
925                                                 }
926                         
927                                         
928
929                                                 
930                                                 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
931
932
933         } break;
934         case DrawGlyph: {
935                                                 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
936
937                                                 D2D1::Matrix3x2F matrix;
938                                                 matrix = D2D1::Matrix3x2F::Scale(fontaspect_corr, 1.f)*
939                                                         D2D1::Matrix3x2F::Translation(command.x, command.y + fontzero)*save_matrix;
940                                                 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
941                                                 UINT32 tchar = command.target.textchar;
942                                                 UINT16 glyphindex;
943                                                 DWRITE_GLYPH_RUN glyph_run;
944                                                 glyph_run.fontEmSize = 13.f / (74.f / 96.f);
945                                                 glyph_run.fontFace=fontface;
946                                                 glyph_run.glyphCount=1;
947                                                 glyph_run.glyphIndices = &glyphindex;
948
949                                                 fontface->GetGlyphIndices(&tchar, 1, &glyphindex);
950                                         
951                                                 FLOAT zero = 0.f;
952                                                 DWRITE_GLYPH_OFFSET zero2 = { 0.f, 0.f };
953                                                 glyph_run.glyphAdvances=&zero;
954                                                 glyph_run.glyphOffsets=&zero2;
955                                                 glyph_run.isSideways=false;
956                                                 glyph_run.bidiLevel=0;
957                                                 D2D1_POINT_2F pos = { 0.f, 0.f };
958
959                                                 currentosd_backbuffer.rendtarget2D->DrawGlyphRun(pos, &glyph_run,
960                                                         (ID2D1Brush*)command.reference);                
961                                                 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
962
963         } break;
964         case DrawTTchar:{
965                                                 cTeletextChar tchar;
966                                                 tchar.setInternal(command.target.ttchar);
967                                                 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
968
969                                                 enumTeletextColor ttforegcolour = tchar.GetFGColor();
970                                                 enumTeletextColor ttbackgcolour = tchar.GetBGColor();
971                                                 if (tchar.GetBoxedOut()) {
972                                                         ttforegcolour = ttcTransparent;
973                                                         ttbackgcolour = ttcTransparent;
974                                                 }
975                                                 D2D1::Matrix3x2F matrix;
976                                                 matrix = D2D1::Matrix3x2F::Scale(1.5f+0.05f, 2.f)
977                                                         *D2D1::Matrix3x2F::Translation(command.x + command.w*11.85f*1.4f, command.y + command.h*19.75f)
978                                                         *save_matrix;
979
980                                                 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
981
982
983                                                 Colour color = Surface::enumTeletextColorToCoulour(ttbackgcolour);
984
985                                                 ttbrush->SetColor(D2D1::ColorF(color.rgba(), ((float)color.alpha) / 255.f));
986                                                 
987                                                 cTeletextChar filled;
988                                                 filled.setInternal(0x187f);
989                                                 TTIndex glyph_index = loadTTchar(filled);
990
991                                                 {
992                                                         D2D1_RECT_F src_rect = { (glyph_index.position % 10)*12.f,
993                                                                 (glyph_index.position / 10) *10.f,
994                                                                 (glyph_index.position % 10 + 1)*12.f,
995                                                                 (glyph_index.position / 10 + 1)*10.f,
996                                                         };
997
998
999                                                         currentosd_backbuffer.rendtarget2D->FillOpacityMask(tt_atlas[glyph_index.atlas], ttbrush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
1000                                                                 NULL, &src_rect);
1001                                                 }
1002
1003                                                 color = Surface::enumTeletextColorToCoulour(ttforegcolour);
1004                                                 ttbrush->SetColor(D2D1::ColorF(color.rgba(), ((float)color.alpha) / 255.f));
1005
1006                                         
1007                                                 glyph_index = loadTTchar(tchar);
1008
1009                                                 {
1010                                                         D2D1_RECT_F src_rect = { (glyph_index.position % 10)*12.f,
1011                                                                 (glyph_index.position / 10) *10.f,
1012                                                                 (glyph_index.position % 10 + 1)*12.f,
1013                                                                 (glyph_index.position / 10 + 1)*10.f,
1014                                                         };
1015
1016
1017                                                         currentosd_backbuffer.rendtarget2D->FillOpacityMask(tt_atlas[glyph_index.atlas], ttbrush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
1018                                                                 NULL, &src_rect);
1019                                                 }
1020
1021
1022                                                 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
1023                                         
1024
1025         }break;
1026         case DrawClipping: {
1027                                                    currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
1028                                                    currentosd_backbuffer.rendtarget2D->SetTransform(D2D1::IdentityMatrix());
1029
1030                                                    D2D1_RECT_F coords = { ((command.x + clip_shift_x)*((float)OSD_BUFFER_WIDTH) / 720.f),
1031                                                            (( command.y + clip_shift_y )*((float)OSD_BUFFER_HEIGHT) / 576.f),
1032                                                            ((command.x + clip_shift_x+command.w - 1.f)*((float)OSD_BUFFER_WIDTH) / 720.f),
1033                                                            (command.y + clip_shift_y+(command.h - 1.f)*((float)OSD_BUFFER_HEIGHT) / 576.f) };
1034                                                    if (command.w == 0.f && command.h == 0.f) {
1035                                                            while (num_clips > 0) {
1036                                                                    num_clips--;
1037                                                                    currentosd_backbuffer.rendtarget2D->PopAxisAlignedClip();
1038                                                            }
1039                                                    } else {
1040                                                            num_clips++;
1041                                                            currentosd_backbuffer.rendtarget2D->PushAxisAlignedClip(coords, D2D1_ANTIALIAS_MODE_ALIASED);
1042                                                         
1043                                                    }
1044                                                    currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
1045         } break;
1046         }
1047 }
1048
1049 float OsdWinVector::getFontHeight()
1050 {
1051         return fontheight; 
1052 }
1053 float OsdWinVector::getCharWidth(wchar_t c)
1054 {
1055         if (c<256) return byte_char_width[c];
1056         if (!font) return 13.f;
1057         DWRITE_FONT_METRICS metrics;
1058         font->GetMetrics(&metrics);
1059
1060         
1061         DWRITE_GLYPH_METRICS glyph_metrics;
1062         UINT16 glyph_index;
1063         UINT32 tchar = c;
1064         fontface->GetGlyphIndices(&tchar, 1, &glyph_index);
1065         fontface->GetDesignGlyphMetrics(&glyph_index, 1, &glyph_metrics, FALSE);
1066
1067         return ((float)glyph_metrics.advanceWidth)*13.f
1068                 / ((float)metrics.designUnitsPerEm) *fontaspect_corr / 72.f*dpiy;
1069         
1070
1071 }
1072
1073 void OsdWinVector::getScreenSize(int &width, int &height)
1074 {
1075         width = OSD_BUFFER_WIDTH;
1076         height = OSD_BUFFER_HEIGHT;
1077 }
1078
1079 void OsdWinVector::getRealScreenSize(int &width, int &height)
1080 {
1081         width = BACKBUFFER_WIDTH;
1082         height = BACKBUFFER_HEIGHT;
1083 }
1084
1085 bool OsdWinVector::screenShot(void *buffer, int width, int height, bool osd /*include osd*/) 
1086 {
1087   //screen->screenShot(fileName);
1088         return false;
1089 }
1090
1091 LPDIRECT3DTEXTURE9 OsdWinVector::getNextOsdTexture()
1092 {
1093         queuemutex.Lock();
1094         if (d2dtod3d.size())
1095         {
1096                 SurfaceInfo surfinfo = d2dtod3d.front();
1097                 //Now we have to check, if the resource is ready, or busy somewhere else
1098            // if (surfinfo.query10->GetData(NULL, 0, D3D10_ASYNC_GETDATA_DONOTFLUSH) == S_OK) {
1099                         //the surface is ready
1100                         if (currentosd_render.surf9) {
1101                                 currentosd_render.query9->Issue(D3DISSUE_END); //mark the end of the 9 api access
1102                                 d3dtod2d.push(currentosd_render);
1103                         }
1104                         currentosd_render = surfinfo;
1105                         d2dtod3d.pop();
1106                 //}
1107         }
1108         queuemutex.Unlock();
1109         
1110         return currentosd_render.surf9;
1111 }
1112
1113 void  OsdWinVector::updateOsd()
1114 {
1115
1116         queuemutex.Lock();      
1117         if (d3dtod2d.size())
1118         {
1119                 currentosd_backbuffer = d3dtod2d.front();
1120                 //Now we have to check, if the resource is ready, or busy somewhere else
1121                 if (currentosd_backbuffer.query9->GetData(NULL, 0, 0) == S_OK) {
1122                         
1123
1124                         //queuemutex.Unlock();
1125                         currentosd_backbuffer.query10->Begin();
1126                 
1127                         currentosd_backbuffer.rendtarget2D->BeginDraw();
1128                         currentosd_backbuffer.rendtarget2D->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.0f));
1129                         currentosd_backbuffer.rendtarget2D->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
1130                 
1131                         num_clips = 0;
1132                         // We can draw here
1133                         drawSurfaces();
1134                         while (num_clips>0) {
1135                                 currentosd_backbuffer.rendtarget2D->PopAxisAlignedClip();
1136                                 num_clips--;
1137                         }
1138
1139                         currentosd_backbuffer.rendtarget2D->EndDraw();
1140                         currentosd_backbuffer.rendtarget2D->Flush();
1141                         d3ddevice10->Flush();
1142                         currentosd_backbuffer.query10->End();
1143
1144                         //queuemutex.Lock();
1145                         d3dtod2d.pop();
1146                         d2dtod3d.push(currentosd_backbuffer);
1147                                 
1148                 }
1149
1150         }
1151         
1152         queuemutex.Unlock();
1153
1154 }
1155
1156 ID2D1RenderTarget * OsdWinVector::LockOsdDrawing()
1157 {
1158         queuemutex.Lock();
1159         if (d3dtod2d.size())
1160         {
1161                 currentosd_backbuffer=d3dtod2d.front();
1162                 return currentosd_backbuffer.rendtarget2D;
1163         }
1164         queuemutex.Unlock();
1165
1166         int loop = 0;
1167         while (loop < 100) {
1168                 queuemutex.Lock();
1169                 if (d3dtod2d.size())
1170                 {
1171                         currentosd_backbuffer = d3dtod2d.front();
1172                         return currentosd_backbuffer.rendtarget2D;
1173                 }
1174                 queuemutex.Unlock();
1175
1176                 MILLISLEEP(100);
1177                 loop++;
1178         }
1179
1180         currentosd_backbuffer.surf10 = NULL;
1181         currentosd_backbuffer.surf9 = NULL;
1182         return NULL;
1183
1184 }
1185 void OsdWinVector::UnlockOsdDrawing()
1186 {
1187         queuemutex.Unlock();
1188 }
1189
1190 void OsdWinVector::lostDestroyObjects()
1191 {
1192
1193 }
1194
1195 void OsdWinVector::lostRecreateObjects()
1196 {
1197
1198 }
1199
1200
1201 void OsdWinVector::getTextureCoordinates(FLOAT* x, FLOAT* y)
1202 {
1203         *x = 1.f;
1204         *y = 1.f;
1205 }
1206
1207
1208
1209
1210 void OsdWinVector::destroyImageRef(ImageIndex index)
1211 {
1212         ID2D1Bitmap* bitmap = (ID2D1Bitmap*)index;
1213         if (bitmap) bitmap->Release();
1214 }
1215
1216
1217 bool OsdWinVector::getStaticImageData(unsigned int static_id, UCHAR **userdata, ULONG *length)
1218 {
1219         if (sa_MAX>static_id) {
1220                 HRSRC hrc = FindResource(GetModuleHandle(NULL), ext_pict_name[static_id], RT_RCDATA);
1221                 *length = SizeofResource(GetModuleHandle(NULL), hrc);
1222                 *userdata = (UCHAR*) LockResource(LoadResource(GetModuleHandle(NULL), hrc));
1223
1224                 return true;
1225         }
1226
1227         *userdata = NULL;
1228         *length = 0;
1229         return false;
1230
1231 }
1232
1233 void  OsdWinVector::createPicture(struct PictureInfo& pict_inf)
1234 {
1235         
1236         Log::getInstance()->log("OsdWinVector", Log::DEBUG, "TVMedia Create Picture %d", pict_inf.type);
1237         if (pict_inf.type == PictureInfo::D2DBitmap) {
1238                 bool static_image = true;
1239                 if (pict_inf.lindex & 0xffffffff) static_image = false;
1240
1241                 Message* m = new  Message();
1242                 // We have a pictures! send a message to ourself, to switch to gui thread
1243                 m->from = this;
1244                 m->to = Command::getInstance();
1245                 m->parameter.handle = pict_inf.reference;
1246                 if (!static_image) {
1247                         m->message = Message::NEW_PICTURE;
1248                         m->tag = pict_inf.lindex;
1249                 }
1250                 else {
1251                         m->message = Message::NEW_PICTURE_STATIC;
1252                         m->tag = pict_inf.lindex >> 32LL;
1253                 }
1254                 Command::getInstance()->postMessageFromOuterSpace(m); // inform command about new picture
1255
1256         } else {
1257                 pict_inf.decoder->freeReference(pict_inf.reference);
1258         }
1259         
1260 }
1261
1262
1263 ImageIndex OsdWinVector::createMonoBitmap(void *base, int width, int height)
1264 {
1265         // First we have  to convert it to 8 bit alpha, we could use WIC but actually writing this code is not hard to port from base class
1266
1267         LockOsdDrawing();
1268
1269         int x, y;
1270         unsigned char *basechar = (unsigned char*) base;
1271         unsigned int bytesIn, bitsIn;
1272         int widthBytes = width / 8;
1273
1274         unsigned char *alphamem = (unsigned char*)malloc(width*height);
1275         unsigned char *alphamemrun = alphamem;
1276
1277         for (y = 0; y < height; y++) {
1278                 for (x = 0; x < width; x++) {
1279                         bytesIn = (y * widthBytes) + (int)(x / 8);
1280                         bitsIn = x % 8;
1281                         (*alphamemrun) = ((basechar[bytesIn] >> (7 - bitsIn)) & 0x01) ? 0xFF : 0x00; 
1282                         alphamemrun++;
1283                 }
1284         }
1285         D2D1_SIZE_U size;
1286         size.height = height;
1287         size.width = width;
1288         D2D1_BITMAP_PROPERTIES bitmap_prop;
1289         bitmap_prop.dpiX = dpix;
1290         bitmap_prop.dpiY = dpiy;
1291         bitmap_prop.pixelFormat.format = DXGI_FORMAT_A8_UNORM;
1292         bitmap_prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_STRAIGHT;
1293
1294         ID2D1Bitmap *bitmap = NULL;
1295
1296         HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, alphamem, width, bitmap_prop, &bitmap);
1297
1298         if (hres != S_OK) {
1299                 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap failed %d", hres);
1300                 bitmap = NULL;
1301         }
1302
1303         free(alphamem);
1304
1305         UnlockOsdDrawing();
1306
1307         return (void*)bitmap;
1308
1309 }
1310
1311 ImageIndex OsdWinVector::createImagePalette(int width, int height, const unsigned char *image_data, const unsigned int*palette_data)
1312 {
1313         // First we have  to convert it to 32 bit RGBA, we could use WIC but actually writing this code is not hard to port from base class
1314
1315         LockOsdDrawing();
1316
1317         int x, y;
1318         UINT32 *mem = (UINT32*)malloc(width*height*sizeof(UINT32));
1319         UINT32 *memrun = mem;
1320         const unsigned char* image_run = image_data;
1321
1322         for (y = 0; y < height; y++) {
1323                 for (x = 0; x < width; x++) {
1324
1325                         (*memrun) = palette_data[(*image_run)];
1326                         memrun++;
1327                         image_run++;
1328                 }
1329         }
1330         D2D1_SIZE_U size;
1331         size.height = height;
1332         size.width = width;
1333         D2D1_BITMAP_PROPERTIES bitmap_prop;
1334         bitmap_prop.dpiX = dpix;
1335         bitmap_prop.dpiY = dpiy;
1336         bitmap_prop.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
1337         bitmap_prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
1338
1339         ID2D1Bitmap *bitmap = NULL;
1340
1341         HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, mem, width*sizeof(UINT32), bitmap_prop, &bitmap);
1342
1343         if (hres != S_OK) {
1344                 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap failed %d", hres);
1345                 bitmap = NULL;
1346         }
1347
1348         free(mem);
1349
1350         UnlockOsdDrawing();
1351
1352         return (void*)bitmap;
1353
1354 }
1355
1356 void OsdWinVector::destroyStyleRef(VectorHandle index)
1357 {
1358         if (!initted) return;
1359         ID2D1Brush *brush = (ID2D1Brush*)(index);
1360         brush->Release();
1361         
1362 }
1363
1364 VectorHandle OsdWinVector::createStyleRef(const DrawStyle &c)
1365 {
1366         LockOsdDrawing();
1367
1368         switch (c.ft) {
1369         case DrawStyle::Color: {
1370                 ID2D1SolidColorBrush * newbrush=NULL;
1371                 currentosd_backbuffer.rendtarget2D->CreateSolidColorBrush(
1372                                 D2D1::ColorF(c.rgba(),((float)c.alpha)/255.f),
1373                                 &newbrush);
1374                 UnlockOsdDrawing();
1375                 return newbrush;
1376         } break;
1377         case DrawStyle::GradientLinear: 
1378         case DrawStyle::GradientRadial: {
1379                 D2D1_GRADIENT_STOP grad_stop[5];
1380                 grad_stop[0].color = D2D1::ColorF(c.rgba());
1381                 grad_stop[0].position = 0.0f;
1382
1383                 for (int i = 0; i < (c.num_colors - 1); i++) {
1384                         grad_stop[i + 1].color = D2D1::ColorF(c.grad_col[i].rgba(), ((float)c.grad_col[i].alpha) / 255.f);
1385                         grad_stop[i + 1].position = c.grad_pos[i];
1386                 }
1387                 grad_stop[c.num_colors].color = D2D1::ColorF(c.grad_col[c.num_colors - 1].rgba(), ((float)c.grad_col[c.num_colors - 1].alpha) / 255.f);
1388                 grad_stop[c.num_colors].position = 1.f;
1389
1390                 ID2D1GradientStopCollection *gradstopobj;
1391
1392                 currentosd_backbuffer.rendtarget2D->CreateGradientStopCollection(
1393                         grad_stop,
1394                         c.num_colors+1,
1395                         D2D1_GAMMA_2_2,
1396                         D2D1_EXTEND_MODE_CLAMP,
1397                         &gradstopobj
1398                         );
1399
1400                 if (c.ft == DrawStyle::GradientLinear) {
1401                         ID2D1LinearGradientBrush * newbrush=NULL;
1402                         currentosd_backbuffer.rendtarget2D->CreateLinearGradientBrush(
1403                                 D2D1::LinearGradientBrushProperties(
1404                                 D2D1::Point2F(c.x1, c.y1),
1405                                 D2D1::Point2F(c.x2, c.y2)),
1406                                 gradstopobj,
1407                                 &newbrush
1408                                 );
1409                         gradstopobj->Release();
1410                         UnlockOsdDrawing();
1411                         return newbrush;
1412                 }
1413                 if (c.ft == DrawStyle::GradientRadial) {
1414                         ID2D1RadialGradientBrush * newbrush = NULL;
1415                         currentosd_backbuffer.rendtarget2D->CreateRadialGradientBrush(
1416                                 D2D1::RadialGradientBrushProperties(
1417                                 D2D1::Point2F(c.x1, c.y1),
1418                                 D2D1::Point2F(c.x2, c.y2),c.r,c.r),
1419                                 gradstopobj,
1420                                 &newbrush
1421                                 );
1422                         gradstopobj->Release();
1423                         UnlockOsdDrawing();
1424                         return newbrush;
1425                 }                               
1426
1427         } break;
1428         };
1429
1430         UnlockOsdDrawing();
1431         return NULL;
1432
1433 }
1434
1435