2 Copyright 2014 Marten Richter
4 This file is part of VOMP.
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.
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.
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.
22 #include "osdwinvector.h"
25 #include "surfacewin.h"
31 #include "teletxt/txtfont.h"
35 #define OSD_BUFFER_WIDTH 1280
36 #define OSD_BUFFER_HEIGHT 720
38 #include "staticartwork.h"
40 #define EXTERNALPICTURE(name, fname, fileextension) #name,
42 char *ext_pict_name[] {
47 #undef EXTERNALPICTURE
50 class WICPictDecoder : public OsdVector::PictureDecoder {
52 WICPictDecoder(OsdVector::PictureReader* treader, OsdWinVector *posd);
53 virtual ~WICPictDecoder();
55 unsigned char *decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem);
57 bool getDecodedPicture(struct OsdVector::PictureInfo& pict_inf);
59 void freeReference(void * ref);
62 OsdVector::PictureInfo pictInf;
64 IWICImagingFactory *wicfactory;
68 WICPictDecoder::WICPictDecoder(OsdVector::PictureReader* treader, OsdWinVector *posd) : OsdVector::PictureDecoder(treader)
72 HRESULT hres = CoCreateInstance(CLSID_WICImagingFactory,
73 NULL,CLSCTX_INPROC_SERVER,
74 IID_IWICImagingFactory, (void**)&wicfactory);
79 WICPictDecoder::~WICPictDecoder()
81 wicfactory->Release();
84 unsigned char * WICPictDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem)
86 if (pictInfValid) return buffer; // does support only one image at a Time;
88 IWICStream * stream = NULL;
89 IWICBitmapDecoder *decoder = NULL;
90 IWICBitmapFrameDecode *source = NULL;
91 IWICFormatConverter *converter = NULL;
95 hres = wicfactory->CreateStream(&stream);
100 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not create stream %d", hres);
103 hres = stream->InitializeFromMemory(buffer, length);
107 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not initialize from memory %d", hres);
113 hres = wicfactory->CreateDecoderFromStream(stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder);
117 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not create decoder %d", hres);
122 hres = decoder->GetFrame(0, &source);
126 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not get source %d", hres);
132 hres = wicfactory->CreateFormatConverter(&converter);
136 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not get source %d", hres);
143 hres= converter->Initialize(source, GUID_WICPixelFormat32bppPBGRA,
144 WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
148 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not initialise converter %d", hres);
149 converter->Release();
156 ID2D1RenderTarget * rt=osd->LockOsdDrawing();
160 hres = rt->CreateBitmapFromWicBitmap(converter, NULL, &bitmap);
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;
176 osd->UnlockOsdDrawing();
178 converter->Release();
183 if (pictInfValid) return NULL;
187 void WICPictDecoder::freeReference(void * ref)
189 ID2D1Bitmap* bitmap = (ID2D1Bitmap*)ref;
190 if (ref) bitmap->Release();
193 bool WICPictDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
195 if (!pictInfValid) return false;
197 pictInfValid = false;
202 //This is stuff for rendering the OSD
204 OsdWinVector::OsdWinVector()
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;
221 fontaspect_corr = 1.f;
225 ttchar_end.atlas = 0;
226 ttchar_end.position = 0;
229 const wchar_t *fontname = L"Arial";
230 cur_fontname = (wchar_t*)malloc(2*wcslen(fontname) + 2);
231 wcscpy(cur_fontname, fontname);
233 WICPictDecoder * wicdecode = new WICPictDecoder(&reader, this);
234 reader.addDecoder(wicdecode);
238 OsdWinVector::~OsdWinVector()
240 if (cur_fontname) free(cur_fontname);
245 if (dwritefac) dwritefac->Release();
246 if (!fontnames.size()) {
247 vector<char*>::iterator itty = fontnames.begin();
248 while (itty != fontnames.end()) {
254 /*if (!fontnames_keys.size()) {
255 vector<char*>::iterator itty = fontnames_keys.begin();
256 while (itty != fontnames_keys.end()) {
262 if (font) font->Release();
263 if (fontface) fontface->Release();
269 int OsdWinVector::init(void* device)
271 if (initted) return 0;
274 if (!createDirect3D9Objects()) return 0;
276 // then create the Device
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!");
284 if (d3ddevice10->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgidevice) != S_OK) {
285 Log::getInstance()->log("OSD", Log::WARN, "Could not query Dxgi device!");
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");
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;
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;
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;
326 hres = d3ddevice->CreateTexture(OSD_BUFFER_WIDTH, OSD_BUFFER_HEIGHT, 1, D3DUSAGE_RENDERTARGET, /*D3DFMT_A8R8G8B8*/D3DFMT_A8R8G8B8,
327 D3DPOOL_DEFAULT, &surfinfo.surf9, &surfinfo.sharedhandle);
329 Log::getInstance()->log("OSD", Log::WARN, "Could not create Texture for Direct3D9 !");
334 hres = d3ddevice->CreateQuery(D3DQUERYTYPE_EVENT, &surfinfo.query9);
336 Log::getInstance()->log("OSD", Log::WARN, "Could not create Query for Direct3D9 !");
341 DXGI_SHARED_RESOURCE dxgi_res;
342 dxgi_res.Handle = surfinfo.sharedhandle;
344 ID3D10Resource * tempres = NULL;
345 hres = d3ddevice10->OpenSharedResource(surfinfo.sharedhandle, __uuidof(ID3D10Resource), (void**)&tempres);
347 Log::getInstance()->log("OSD", Log::WARN, "Could not open resourcee for Direct3D10 !");
352 hres = tempres->QueryInterface(__uuidof(ID3D10Texture2D), (void**)&surfinfo.surf10);
354 Log::getInstance()->log("OSD", Log::WARN, "Could not query surface for Direct3D10 !");
361 hres = surfinfo.surf10->QueryInterface(__uuidof(IDXGISurface), (void**)&surfinfo.surfdxgi);
363 Log::getInstance()->log("OSD", Log::WARN, "Could not query surface for DXGI !");
368 hres = d2dfactory->CreateDxgiSurfaceRenderTarget(surfinfo.surfdxgi, &rt_prop, &surfinfo.rendtarget2D);
370 Log::getInstance()->log("OSD", Log::WARN, "Could not create render target!");
375 surfinfo.rendtarget2D->GetDpi(&dpix, &dpiy);
378 surfinfo.rendtarget2D->CreateSolidColorBrush(D2D1::ColorF(0xFFFFFFFF, 1.f), &ttbrush);
381 D3D10_QUERY_DESC qdesc;
382 qdesc.Query = D3D10_QUERY_EVENT;
385 hres = d3ddevice10->CreateQuery(&qdesc, &surfinfo.query10);
387 Log::getInstance()->log("OSD", Log::WARN, "Could not create Query for Direct2D Direct3D10 !");
391 allsurfs.push_back(surfinfo);
392 d3dtod2d.push(surfinfo);
394 aspect_correction = ((float)OSD_BUFFER_HEIGHT) / 576.f / (((float)OSD_BUFFER_WIDTH) / 720.f);
403 initted = 1; // must set this here or create surface won't work
411 int OsdWinVector::shutdown()
413 if (!initted) return 0;
421 if (currentosd_render.surf9) {
422 currentosd_render.surf9 = NULL;
425 if (currentosd_backbuffer.surf9) {
426 currentosd_backbuffer.surf9 = NULL;
431 for (int i = 0; i < tt_atlas.size(); i++)
433 tt_atlas[i]->Release();
436 tt_font_chars.clear();
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;
449 if (surfinfo.surf9) {
450 LPDIRECT3DTEXTURE9 temp = surfinfo.surf9;
451 surfinfo.surf9 = NULL;
455 if (surfinfo.query9) {
456 IDirect3DQuery9* temp = surfinfo.query9;
457 surfinfo.query9 = NULL;
461 if (surfinfo.surf10) {
462 ID3D10Texture2D * temp = surfinfo.surf10;
463 surfinfo.surf10 = NULL;
467 if (surfinfo.surfdxgi) {
468 IDXGISurface *temp = surfinfo.surfdxgi;
469 surfinfo.surfdxgi = NULL;
472 if (surfinfo.query10) {
473 ID3D10Query* temp = surfinfo.query10;
474 surfinfo.query10 = NULL;
479 while (d3dtod2d.size()) d3dtod2d.pop();
480 while (d2dtod3d.size()) d2dtod3d.pop();
487 ID2D1Factory *temp = d2dfactory;
493 ID3D10Device *temp = d3ddevice10;
498 shutdownDirect3D9Objects();
505 void OsdWinVector::initPaths()
507 ID2D1PathGeometry *current = NULL;
508 ID2D1GeometrySink *currentsink = NULL;
510 d2dfactory->CreatePathGeometry(¤t);
511 current->Open(¤tsink);
512 currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_HOLLOW);
514 currentsink->AddLine(D2D1::Point2F(1.f, 0));
516 currentsink->EndFigure(D2D1_FIGURE_END_OPEN);
518 std_paths[PIHorzLine] = current;
521 currentsink->Close();
522 currentsink->Release();
525 d2dfactory->CreatePathGeometry(¤t);
526 current->Open(¤tsink);
527 currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_HOLLOW);
529 currentsink->AddLine(D2D1::Point2F(0, 1.f));
530 currentsink->EndFigure(D2D1_FIGURE_END_OPEN);
533 std_paths[PIVertLine] = current;
536 currentsink->Close();
537 currentsink->Release();
540 d2dfactory->CreatePathGeometry(¤t);
541 current->Open(¤tsink);
542 currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_FILLED);
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);
549 std_paths[PIRectangle] = current;
552 currentsink->Close();
553 currentsink->Release();
556 d2dfactory->CreatePathGeometry(¤t);
557 current->Open(¤tsink);
558 currentsink->BeginFigure(D2D1::Point2F(0, 0.f), D2D1_FIGURE_BEGIN_FILLED);
560 currentsink->AddArc(D2D1::ArcSegment(
561 D2D1::Point2F(0, 0.f),
562 D2D1::SizeF(1.f, 1.f),
564 D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
565 D2D1_ARC_SIZE_LARGE));
567 currentsink->EndFigure(D2D1_FIGURE_END_CLOSED);
571 std_paths[PIPoint] = current;
574 currentsink->Close();
575 currentsink->Release();
580 void OsdWinVector::destroyPaths()
582 std_paths[PIHorzLine]->Release();
583 std_paths[PIVertLine]->Release();
584 std_paths[PIRectangle]->Release();
585 std_paths[PIPoint]->Release();
591 int OsdWinVector::loadFont(bool newfont)
594 if (!is_direct_write_initted)
597 hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
598 (IUnknown**)(&dwritefac));
600 Log::getInstance()->log("OSD", Log::WARN, "Could not create DirectWrite Factory!");
604 is_direct_write_initted = true;
607 if (fontnames.size())
612 IDWriteFontCollection * fontcol = NULL;
613 if (dwritefac->GetSystemFontCollection(&fontcol) != S_OK) {
614 Log::getInstance()->log("OSD", Log::WARN, "Could not get System Font Collection!");
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) {
628 if (fam_name->FindLocaleName(L"en-us", &id, &exist) == S_OK) {
631 fam_name->GetStringLength(id, &strlen);
632 wchar_t * stringbuf = new wchar_t[strlen + 1];
634 fam_name->GetString(id, stringbuf, strlen+1);
636 int strlenutf8 = WideCharToMultiByte(CP_UTF8, 0, stringbuf, -1,
638 char *stringbufutf8 = new char[strlenutf8 + 1];
639 WideCharToMultiByte(CP_UTF8, 0, stringbuf, -1,
640 stringbufutf8, strlenutf8+1, 0, NULL);
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);
650 IDWriteFont* temp_font = font;
651 IDWriteFontFace* temp_fontface = fontface;
653 fontface = newfontface;
655 if (temp_font) temp_font->Release();
656 if (temp_fontface) temp_fontface->Release();
661 fontnames.push_back(stringbufutf8);
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;
676 fontaspect_corr = ((float)OSD_BUFFER_HEIGHT) / ((float)OSD_BUFFER_WIDTH) * 720.f / 576.f;
679 for (UINT32 i = 0; i<256; i++) {
680 DWRITE_GLYPH_METRICS glyph_metrics;
682 fontface->GetGlyphIndices(&i, 1, &glyph_index);
683 HRESULT hres=fontface->GetDesignGlyphMetrics(&glyph_index, 1, &glyph_metrics, FALSE);
686 byte_char_width[i] = ((float)glyph_metrics.advanceWidth)*13.f
687 / ((float)metrics.designUnitsPerEm) *fontaspect_corr / 72.f*dpix;
690 byte_char_width[i] = 0.f;
704 OsdWinVector::TTIndex OsdWinVector::loadTTchar(cTeletextChar c)
706 /* map<unsigned int, TTIndex> tt_font_chars;
707 vector<ID2D1Bitmap *> tt_atlas;
708 TTIndex ttchar_end;*/
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())
715 return (*glypos).second;
717 TTIndex our_index = ttchar_end;
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;
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;
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;
741 HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, bitmap_prop, &atlas);
744 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap for atlas failed %d", hres);
746 our_index.atlas = our_index.position = 0;
749 tt_atlas.push_back(atlas);
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;
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,
766 HRESULT hres=tt_atlas[our_index.atlas]->CopyFromMemory(&dst_rect, buffer_final, 12);
769 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CopyFromMemory for atlas failed %d", hres);
770 our_index.atlas = our_index.position = 0;
774 tt_font_chars[glyph_index] = our_index;
775 ttchar_end.position++;
776 if (ttchar_end.position == 120) {
777 ttchar_end.position = 0;
784 int OsdWinVector::getFontNames(const char *** names, const char *** names_keys)
786 *names = (const char**)&(fontnames[0]);
787 *names_keys = (const char**)&(fontnames/*_keys*/[0]);
788 return fontnames.size();
791 void OsdWinVector::setFont(const char * fontname) {
793 wchar_t * wfontname= new wchar_t[strlen(fontname)+1];
795 MultiByteToWideChar(CP_UTF8, 0, fontname, -1,
796 wfontname, strlen(fontname) + 1);
798 if (wcscmp(wfontname, cur_fontname)) {
800 if (cur_fontname) free(cur_fontname);
801 cur_fontname = (wchar_t*)malloc(2*wcslen(wfontname) + 2);
802 wcscpy(cur_fontname, wfontname);
814 void OsdWinVector::drawSetTrans(SurfaceCommands & sc)
816 D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Identity();
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;
821 currentosd_backbuffer.rendtarget2D->SetTransform(trans);
827 void OsdWinVector::executeDrawCommand(SVGCommand & command)
829 D2D1::Matrix3x2F save_matrix;
830 D2D1::Matrix3x2F save_matrix2;
833 switch (command.instr) {
835 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
837 D2D1::Matrix3x2F 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);
844 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
848 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
849 ID2D1Bitmap * bitmap = (ID2D1Bitmap*)command.target.image;
851 D2D1_SIZE_F size=bitmap->GetSize();
853 D2D1::Matrix3x2F matrix;
856 if (command.reference) { //special behaviour for bw images they act as a mask on the current paint
858 D2D1::Matrix3x2F::Scale(1.f*aspect_correction, 1.f)
859 *D2D1::Matrix3x2F::Translation(command.x, command.y)*save_matrix;
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) {
873 ty += (command.h - size.height * scalex / aspect_correction)*0.5f;
877 tx += (command.w - size.width * scaley*aspect_correction)*0.5f;
883 if (scalex == 0.f && scaley == 0.f) {
884 scalex = aspect_correction;
887 else if (scalex == 0.f) {
888 scalex = scaley*aspect_correction;
890 else if (scaley == 0.f) {
891 scaley = scalex / aspect_correction;
895 if (command.corner == BottomRight || command.corner == BottomLeft || command.corner == BottomMiddle)
897 ty -= size.height * scaley;
900 if (command.corner == BottomRight || command.corner == TopRight)
902 tx -= size.width * scalex;
905 if (command.corner == BottomMiddle || command.corner == TopMiddle)
907 tx -= size.width * scalex *0.5f;
911 D2D1::Matrix3x2F::Scale(scalex, scaley)*D2D1::Matrix3x2F::Translation(tx, ty)*save_matrix;
916 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
918 if (command.reference) {
919 currentosd_backbuffer.rendtarget2D->FillOpacityMask(bitmap, (ID2D1Brush*)command.reference, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
924 currentosd_backbuffer.rendtarget2D->DrawBitmap(bitmap);
930 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
935 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
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;
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;
949 fontface->GetGlyphIndices(&tchar, 1, &glyphindex);
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 };
959 currentosd_backbuffer.rendtarget2D->DrawGlyphRun(pos, &glyph_run,
960 (ID2D1Brush*)command.reference);
961 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
966 tchar.setInternal(command.target.ttchar);
967 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
969 enumTeletextColor ttforegcolour = tchar.GetFGColor();
970 enumTeletextColor ttbackgcolour = tchar.GetBGColor();
971 if (tchar.GetBoxedOut()) {
972 ttforegcolour = ttcTransparent;
973 ttbackgcolour = ttcTransparent;
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)
980 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
983 Colour color = Surface::enumTeletextColorToCoulour(ttbackgcolour);
985 ttbrush->SetColor(D2D1::ColorF(color.rgba(), ((float)color.alpha) / 255.f));
987 cTeletextChar filled;
988 filled.setInternal(0x187f);
989 TTIndex glyph_index = loadTTchar(filled);
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,
999 currentosd_backbuffer.rendtarget2D->FillOpacityMask(tt_atlas[glyph_index.atlas], ttbrush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
1003 color = Surface::enumTeletextColorToCoulour(ttforegcolour);
1004 ttbrush->SetColor(D2D1::ColorF(color.rgba(), ((float)color.alpha) / 255.f));
1007 glyph_index = loadTTchar(tchar);
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,
1017 currentosd_backbuffer.rendtarget2D->FillOpacityMask(tt_atlas[glyph_index.atlas], ttbrush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
1022 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
1026 case DrawClipping: {
1027 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
1028 currentosd_backbuffer.rendtarget2D->SetTransform(D2D1::IdentityMatrix());
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) {
1037 currentosd_backbuffer.rendtarget2D->PopAxisAlignedClip();
1041 currentosd_backbuffer.rendtarget2D->PushAxisAlignedClip(coords, D2D1_ANTIALIAS_MODE_ALIASED);
1044 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
1049 float OsdWinVector::getFontHeight()
1053 float OsdWinVector::getCharWidth(wchar_t c)
1055 if (c<256) return byte_char_width[c];
1056 if (!font) return 13.f;
1057 DWRITE_FONT_METRICS metrics;
1058 font->GetMetrics(&metrics);
1061 DWRITE_GLYPH_METRICS glyph_metrics;
1064 fontface->GetGlyphIndices(&tchar, 1, &glyph_index);
1065 fontface->GetDesignGlyphMetrics(&glyph_index, 1, &glyph_metrics, FALSE);
1067 return ((float)glyph_metrics.advanceWidth)*13.f
1068 / ((float)metrics.designUnitsPerEm) *fontaspect_corr / 72.f*dpiy;
1073 void OsdWinVector::getScreenSize(int &width, int &height)
1075 width = OSD_BUFFER_WIDTH;
1076 height = OSD_BUFFER_HEIGHT;
1079 void OsdWinVector::getRealScreenSize(int &width, int &height)
1081 width = BACKBUFFER_WIDTH;
1082 height = BACKBUFFER_HEIGHT;
1085 bool OsdWinVector::screenShot(void *buffer, int width, int height, bool osd /*include osd*/)
1087 //screen->screenShot(fileName);
1091 LPDIRECT3DTEXTURE9 OsdWinVector::getNextOsdTexture()
1094 if (d2dtod3d.size())
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);
1104 currentosd_render = surfinfo;
1108 queuemutex.Unlock();
1110 return currentosd_render.surf9;
1113 void OsdWinVector::updateOsd()
1117 if (d3dtod2d.size())
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) {
1124 //queuemutex.Unlock();
1125 currentosd_backbuffer.query10->Begin();
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);
1134 while (num_clips>0) {
1135 currentosd_backbuffer.rendtarget2D->PopAxisAlignedClip();
1139 currentosd_backbuffer.rendtarget2D->EndDraw();
1140 currentosd_backbuffer.rendtarget2D->Flush();
1141 d3ddevice10->Flush();
1142 currentosd_backbuffer.query10->End();
1144 //queuemutex.Lock();
1146 d2dtod3d.push(currentosd_backbuffer);
1152 queuemutex.Unlock();
1156 ID2D1RenderTarget * OsdWinVector::LockOsdDrawing()
1159 if (d3dtod2d.size())
1161 currentosd_backbuffer=d3dtod2d.front();
1162 return currentosd_backbuffer.rendtarget2D;
1164 queuemutex.Unlock();
1167 while (loop < 100) {
1169 if (d3dtod2d.size())
1171 currentosd_backbuffer = d3dtod2d.front();
1172 return currentosd_backbuffer.rendtarget2D;
1174 queuemutex.Unlock();
1180 currentosd_backbuffer.surf10 = NULL;
1181 currentosd_backbuffer.surf9 = NULL;
1185 void OsdWinVector::UnlockOsdDrawing()
1187 queuemutex.Unlock();
1190 void OsdWinVector::lostDestroyObjects()
1195 void OsdWinVector::lostRecreateObjects()
1201 void OsdWinVector::getTextureCoordinates(FLOAT* x, FLOAT* y)
1210 void OsdWinVector::destroyImageRef(ImageIndex index)
1212 ID2D1Bitmap* bitmap = (ID2D1Bitmap*)index;
1213 if (bitmap) bitmap->Release();
1217 bool OsdWinVector::getStaticImageData(unsigned int static_id, UCHAR **userdata, ULONG *length)
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));
1233 void OsdWinVector::createPicture(struct PictureInfo& pict_inf)
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;
1241 Message* m = new Message();
1242 // We have a pictures! send a message to ourself, to switch to gui thread
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;
1251 m->message = Message::NEW_PICTURE_STATIC;
1252 m->tag = pict_inf.lindex >> 32LL;
1254 Command::getInstance()->postMessageFromOuterSpace(m); // inform command about new picture
1257 pict_inf.decoder->freeReference(pict_inf.reference);
1263 ImageIndex OsdWinVector::createMonoBitmap(void *base, int width, int height)
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
1270 unsigned char *basechar = (unsigned char*) base;
1271 unsigned int bytesIn, bitsIn;
1272 int widthBytes = width / 8;
1274 unsigned char *alphamem = (unsigned char*)malloc(width*height);
1275 unsigned char *alphamemrun = alphamem;
1277 for (y = 0; y < height; y++) {
1278 for (x = 0; x < width; x++) {
1279 bytesIn = (y * widthBytes) + (int)(x / 8);
1281 (*alphamemrun) = ((basechar[bytesIn] >> (7 - bitsIn)) & 0x01) ? 0xFF : 0x00;
1286 size.height = height;
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;
1294 ID2D1Bitmap *bitmap = NULL;
1296 HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, alphamem, width, bitmap_prop, &bitmap);
1299 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap failed %d", hres);
1307 return (void*)bitmap;
1311 ImageIndex OsdWinVector::createImagePalette(int width, int height, const unsigned char *image_data, const unsigned int*palette_data)
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
1318 UINT32 *mem = (UINT32*)malloc(width*height*sizeof(UINT32));
1319 UINT32 *memrun = mem;
1320 const unsigned char* image_run = image_data;
1322 for (y = 0; y < height; y++) {
1323 for (x = 0; x < width; x++) {
1325 (*memrun) = palette_data[(*image_run)];
1331 size.height = height;
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;
1339 ID2D1Bitmap *bitmap = NULL;
1341 HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, mem, width*sizeof(UINT32), bitmap_prop, &bitmap);
1344 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap failed %d", hres);
1352 return (void*)bitmap;
1356 void OsdWinVector::destroyStyleRef(VectorHandle index)
1358 if (!initted) return;
1359 ID2D1Brush *brush = (ID2D1Brush*)(index);
1364 VectorHandle OsdWinVector::createStyleRef(const DrawStyle &c)
1369 case DrawStyle::Color: {
1370 ID2D1SolidColorBrush * newbrush=NULL;
1371 currentosd_backbuffer.rendtarget2D->CreateSolidColorBrush(
1372 D2D1::ColorF(c.rgba(),((float)c.alpha)/255.f),
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;
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];
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;
1390 ID2D1GradientStopCollection *gradstopobj;
1392 currentosd_backbuffer.rendtarget2D->CreateGradientStopCollection(
1396 D2D1_EXTEND_MODE_CLAMP,
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)),
1409 gradstopobj->Release();
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),
1422 gradstopobj->Release();