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, see <https://www.gnu.org/licenses/>.
22 // FIXME swap these two lines around
26 #include "surfacewin.h"
28 #include "messagequeue.h"
29 #include "teletxt/txtfont.h"
32 #define OSD_BUFFER_WIDTH 1280
33 #define OSD_BUFFER_HEIGHT 720
35 #include "staticartwork.h"
37 #include "osdwinvector.h"
39 #define EXTERNALPICTURE(name, fname, fileextension) #name,
41 char *ext_pict_name[] {
46 #undef EXTERNALPICTURE
49 class WICPictDecoder : public OsdVector::PictureDecoder {
51 WICPictDecoder(OsdVector::PictureReader* treader, OsdWinVector *posd);
52 virtual ~WICPictDecoder();
54 unsigned char *decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem);
56 bool getDecodedPicture(struct OsdVector::PictureInfo& pict_inf);
58 void freeReference(void * ref);
61 OsdVector::PictureInfo pictInf;
63 IWICImagingFactory *wicfactory;
67 WICPictDecoder::WICPictDecoder(OsdVector::PictureReader* treader, OsdWinVector *posd) : OsdVector::PictureDecoder(treader)
71 HRESULT hres = CoCreateInstance(CLSID_WICImagingFactory,
72 NULL,CLSCTX_INPROC_SERVER,
73 IID_IWICImagingFactory, (void**)&wicfactory);
78 WICPictDecoder::~WICPictDecoder()
80 wicfactory->Release();
83 unsigned char * WICPictDecoder::decodePicture(LoadIndex index, unsigned char * buffer, unsigned int length, bool freemem)
85 if (pictInfValid) return buffer; // does support only one image at a Time;
87 IWICStream * stream = NULL;
88 IWICBitmapDecoder *decoder = NULL;
89 IWICBitmapFrameDecode *source = NULL;
90 IWICFormatConverter *converter = NULL;
94 hres = wicfactory->CreateStream(&stream);
99 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not create stream %d", hres);
102 hres = stream->InitializeFromMemory(buffer, length);
106 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not initialize from memory %d", hres);
112 hres = wicfactory->CreateDecoderFromStream(stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder);
116 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not create decoder %d", hres);
121 hres = decoder->GetFrame(0, &source);
125 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not get source %d", hres);
131 hres = wicfactory->CreateFormatConverter(&converter);
135 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not get source %d", hres);
142 hres= converter->Initialize(source, GUID_WICPixelFormat32bppPBGRA,
143 WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
147 Log::getInstance()->log("WICDecoder", Log::DEBUG, "Could not initialise converter %d", hres);
148 converter->Release();
155 ID2D1RenderTarget * rt=osd->LockOsdDrawing();
159 hres = rt->CreateBitmapFromWicBitmap(converter, NULL, &bitmap);
161 D2D1_SIZE_F size = bitmap->GetSize();
162 pictInf.reference = (void*)bitmap;
163 pictInf.width = size.width;
164 pictInf.height = size.height;
165 pictInf.image = bitmap;
166 pictInf.decoder = this;
167 pictInf.type = OsdVector::PictureInfo::D2DBitmap;
168 pictInf.lindex = index;
175 osd->UnlockOsdDrawing();
177 converter->Release();
182 if (pictInfValid) return NULL;
186 void WICPictDecoder::freeReference(void * ref)
188 ID2D1Bitmap* bitmap = (ID2D1Bitmap*)ref;
189 if (ref) bitmap->Release();
192 bool WICPictDecoder::getDecodedPicture(struct OsdVector::PictureInfo& pict_inf)
194 if (!pictInfValid) return false;
196 pictInfValid = false;
201 //This is stuff for rendering the OSD
203 OsdWinVector::OsdWinVector()
207 currentosd_render.surf9 = NULL;
208 currentosd_render.surf10 = NULL;
209 currentosd_render.query9 = NULL;
210 currentosd_render.query10 = NULL;
211 currentosd_render.surfdxgi = NULL;
212 currentosd_render.sharedhandle = NULL;
213 currentosd_render.rendtarget2D = NULL;
214 currentosd_backbuffer = currentosd_backbuffer;
215 aspect_correction = 1.;
216 is_direct_write_initted = false;
220 fontaspect_corr = 1.f;
224 ttchar_end.atlas = 0;
225 ttchar_end.position = 0;
228 const wchar_t *fontname = L"Arial";
229 cur_fontname = (wchar_t*)malloc(2*wcslen(fontname) + 2);
230 wcscpy(cur_fontname, fontname);
232 WICPictDecoder * wicdecode = new WICPictDecoder(&reader, this);
233 reader.addDecoder(wicdecode);
237 OsdWinVector::~OsdWinVector()
239 if (cur_fontname) free(cur_fontname);
244 if (dwritefac) dwritefac->Release();
245 if (!fontnames.size()) {
246 std::vector<char*>::iterator itty = fontnames.begin();
247 while (itty != fontnames.end()) {
253 /*if (!fontnames_keys.size()) {
254 vector<char*>::iterator itty = fontnames_keys.begin();
255 while (itty != fontnames_keys.end()) {
261 if (font) font->Release();
262 if (fontface) fontface->Release();
268 int OsdWinVector::init()
270 if (initted) return 0;
273 if (!createDirect3D9Objects()) return 0;
275 // then create the Device
277 if (D3D10CreateDevice1(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, D3D10_CREATE_DEVICE_BGRA_SUPPORT, D3D10_FEATURE_LEVEL_9_1,
278 D3D10_1_SDK_VERSION, &d3ddevice10) != S_OK) {
279 Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D10 device!");
283 if (d3ddevice10->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgidevice) != S_OK) {
284 Log::getInstance()->log("OSD", Log::WARN, "Could not query Dxgi device!");
288 if (D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, __uuidof(ID2D1Factory),(void**) &d2dfactory) != S_OK) {
289 Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct2dfactory");
298 DXGI_SURFACE_DESC surf_desc;
299 surf_desc.Width = OSD_BUFFER_WIDTH;
300 surf_desc.Height = OSD_BUFFER_HEIGHT;
301 surf_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
302 surf_desc.SampleDesc.Count = 1;
303 surf_desc.SampleDesc.Quality = 0;
307 D2D1_RENDER_TARGET_PROPERTIES rt_prop;
308 rt_prop.dpiX = rt_prop.dpiY = 0;
309 rt_prop.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED);
310 rt_prop.minLevel = D2D1_FEATURE_LEVEL_9;
311 rt_prop.type = D2D1_RENDER_TARGET_TYPE_HARDWARE;
312 rt_prop.usage = D2D1_RENDER_TARGET_USAGE_NONE;
314 for (int i = 0; i < 3; i++) {
315 SurfaceInfo surfinfo;
316 surfinfo.surf9 = NULL;
317 surfinfo.surf10 = NULL;
318 surfinfo.query9 = NULL;
319 surfinfo.query10 = NULL;
320 surfinfo.surfdxgi = NULL;
321 surfinfo.sharedhandle = NULL;
322 surfinfo.rendtarget2D = NULL;
325 hres = d3ddevice->CreateTexture(OSD_BUFFER_WIDTH, OSD_BUFFER_HEIGHT, 1, D3DUSAGE_RENDERTARGET, /*D3DFMT_A8R8G8B8*/D3DFMT_A8R8G8B8,
326 D3DPOOL_DEFAULT, &surfinfo.surf9, &surfinfo.sharedhandle);
328 Log::getInstance()->log("OSD", Log::WARN, "Could not create Texture for Direct3D9 !");
333 hres = d3ddevice->CreateQuery(D3DQUERYTYPE_EVENT, &surfinfo.query9);
335 Log::getInstance()->log("OSD", Log::WARN, "Could not create Query for Direct3D9 !");
340 DXGI_SHARED_RESOURCE dxgi_res;
341 dxgi_res.Handle = surfinfo.sharedhandle;
343 ID3D10Resource * tempres = NULL;
344 hres = d3ddevice10->OpenSharedResource(surfinfo.sharedhandle, __uuidof(ID3D10Resource), (void**)&tempres);
346 Log::getInstance()->log("OSD", Log::WARN, "Could not open resourcee for Direct3D10 !");
351 hres = tempres->QueryInterface(__uuidof(ID3D10Texture2D), (void**)&surfinfo.surf10);
353 Log::getInstance()->log("OSD", Log::WARN, "Could not query surface for Direct3D10 !");
360 hres = surfinfo.surf10->QueryInterface(__uuidof(IDXGISurface), (void**)&surfinfo.surfdxgi);
362 Log::getInstance()->log("OSD", Log::WARN, "Could not query surface for DXGI !");
367 hres = d2dfactory->CreateDxgiSurfaceRenderTarget(surfinfo.surfdxgi, &rt_prop, &surfinfo.rendtarget2D);
369 Log::getInstance()->log("OSD", Log::WARN, "Could not create render target!");
374 surfinfo.rendtarget2D->GetDpi(&dpix, &dpiy);
377 surfinfo.rendtarget2D->CreateSolidColorBrush(D2D1::ColorF(0xFFFFFFFF, 1.f), &ttbrush);
380 D3D10_QUERY_DESC qdesc;
381 qdesc.Query = D3D10_QUERY_EVENT;
384 hres = d3ddevice10->CreateQuery(&qdesc, &surfinfo.query10);
386 Log::getInstance()->log("OSD", Log::WARN, "Could not create Query for Direct2D Direct3D10 !");
390 allsurfs.push_back(surfinfo);
391 d3dtod2d.push(surfinfo);
393 aspect_correction = ((float)OSD_BUFFER_HEIGHT) / 576.f / (((float)OSD_BUFFER_WIDTH) / 720.f);
402 initted = true; // must set this here or create surface won't work
410 int OsdWinVector::shutdown()
412 if (!initted) return 0;
420 if (currentosd_render.surf9) {
421 currentosd_render.surf9 = NULL;
424 if (currentosd_backbuffer.surf9) {
425 currentosd_backbuffer.surf9 = NULL;
430 for (int i = 0; i < tt_atlas.size(); i++)
432 tt_atlas[i]->Release();
435 tt_font_chars.clear();
439 while (allsurfs.size()) {
440 SurfaceInfo surfinfo = allsurfs.front();
441 allsurfs.pop_front();
442 if (surfinfo.rendtarget2D) {
443 ID2D1RenderTarget *temp = surfinfo.rendtarget2D;
444 surfinfo.rendtarget2D = NULL;
448 if (surfinfo.surf9) {
449 LPDIRECT3DTEXTURE9 temp = surfinfo.surf9;
450 surfinfo.surf9 = NULL;
454 if (surfinfo.query9) {
455 IDirect3DQuery9* temp = surfinfo.query9;
456 surfinfo.query9 = NULL;
460 if (surfinfo.surf10) {
461 ID3D10Texture2D * temp = surfinfo.surf10;
462 surfinfo.surf10 = NULL;
466 if (surfinfo.surfdxgi) {
467 IDXGISurface *temp = surfinfo.surfdxgi;
468 surfinfo.surfdxgi = NULL;
471 if (surfinfo.query10) {
472 ID3D10Query* temp = surfinfo.query10;
473 surfinfo.query10 = NULL;
478 while (d3dtod2d.size()) d3dtod2d.pop();
479 while (d2dtod3d.size()) d2dtod3d.pop();
486 ID2D1Factory *temp = d2dfactory;
492 ID3D10Device *temp = d3ddevice10;
497 shutdownDirect3D9Objects();
504 void OsdWinVector::initPaths()
506 ID2D1PathGeometry *current = NULL;
507 ID2D1GeometrySink *currentsink = NULL;
509 d2dfactory->CreatePathGeometry(¤t);
510 current->Open(¤tsink);
511 currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_HOLLOW);
513 currentsink->AddLine(D2D1::Point2F(1.f, 0));
515 currentsink->EndFigure(D2D1_FIGURE_END_OPEN);
517 std_paths[PIHorzLine] = current;
520 currentsink->Close();
521 currentsink->Release();
524 d2dfactory->CreatePathGeometry(¤t);
525 current->Open(¤tsink);
526 currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_HOLLOW);
528 currentsink->AddLine(D2D1::Point2F(0, 1.f));
529 currentsink->EndFigure(D2D1_FIGURE_END_OPEN);
532 std_paths[PIVertLine] = current;
535 currentsink->Close();
536 currentsink->Release();
539 d2dfactory->CreatePathGeometry(¤t);
540 current->Open(¤tsink);
541 currentsink->BeginFigure(D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_FILLED);
543 currentsink->AddLine(D2D1::Point2F(1, 0));
544 currentsink->AddLine(D2D1::Point2F(1, 1));
545 currentsink->AddLine(D2D1::Point2F(0, 1));
546 currentsink->EndFigure(D2D1_FIGURE_END_CLOSED);
548 std_paths[PIRectangle] = current;
551 currentsink->Close();
552 currentsink->Release();
555 d2dfactory->CreatePathGeometry(¤t);
556 current->Open(¤tsink);
557 currentsink->BeginFigure(D2D1::Point2F(0, 0.f), D2D1_FIGURE_BEGIN_FILLED);
559 currentsink->AddArc(D2D1::ArcSegment(
560 D2D1::Point2F(0, 0.f),
561 D2D1::SizeF(1.f, 1.f),
563 D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
564 D2D1_ARC_SIZE_LARGE));
566 currentsink->EndFigure(D2D1_FIGURE_END_CLOSED);
570 std_paths[PIPoint] = current;
573 currentsink->Close();
574 currentsink->Release();
579 void OsdWinVector::destroyPaths()
581 std_paths[PIHorzLine]->Release();
582 std_paths[PIVertLine]->Release();
583 std_paths[PIRectangle]->Release();
584 std_paths[PIPoint]->Release();
590 int OsdWinVector::loadFont(bool newfont)
593 if (!is_direct_write_initted)
596 hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
597 (IUnknown**)(&dwritefac));
599 Log::getInstance()->log("OSD", Log::WARN, "Could not create DirectWrite Factory!");
603 is_direct_write_initted = true;
606 if (fontnames.size())
611 IDWriteFontCollection * fontcol = NULL;
612 if (dwritefac->GetSystemFontCollection(&fontcol) != S_OK) {
613 Log::getInstance()->log("OSD", Log::WARN, "Could not get System Font Collection!");
616 UINT num_font = fontcol->GetFontFamilyCount();
617 for (UINT i = 0; i < num_font; i++) {
618 IDWriteFontFamily * family=NULL;
619 if (fontcol->GetFontFamily(i, &family)!=S_OK) continue;
620 IDWriteLocalizedStrings* fam_name=NULL;
621 if (family->GetFamilyNames(&fam_name) != S_OK) {
627 if (fam_name->FindLocaleName(L"en-us", &id, &exist) == S_OK) {
630 fam_name->GetStringLength(id, &strlen);
631 wchar_t * stringbuf = new wchar_t[strlen + 1];
633 fam_name->GetString(id, stringbuf, strlen+1);
635 int strlenutf8 = WideCharToMultiByte(CP_UTF8, 0, stringbuf, -1,
637 char *stringbufutf8 = new char[strlenutf8 + 1];
638 WideCharToMultiByte(CP_UTF8, 0, stringbuf, -1,
639 stringbufutf8, strlenutf8+1, 0, NULL);
642 if (wcscmp(cur_fontname, stringbuf) == 0) {
643 IDWriteFont* new_font;
644 if (family->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL,
645 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &new_font) == S_OK) {
646 IDWriteFontFace *newfontface = NULL;
647 new_font->CreateFontFace(&newfontface);
649 IDWriteFont* temp_font = font;
650 IDWriteFontFace* temp_fontface = fontface;
652 fontface = newfontface;
654 if (temp_font) temp_font->Release();
655 if (temp_fontface) temp_fontface->Release();
660 fontnames.push_back(stringbufutf8);
668 DWRITE_FONT_METRICS metrics;
669 font->GetMetrics(&metrics);
670 fontheight = ((float)( metrics.ascent + metrics.descent + metrics.lineGap))*13.f
671 / ((float)metrics.designUnitsPerEm) / 576.f * ((float)OSD_BUFFER_HEIGHT)/72.f*dpiy;
672 fontzero = ((float)(metrics.ascent))*13.f
673 / ((float)metrics.designUnitsPerEm) / 576.f * ((float)OSD_BUFFER_HEIGHT) / 72.f*dpiy;
675 fontaspect_corr = ((float)OSD_BUFFER_HEIGHT) / ((float)OSD_BUFFER_WIDTH) * 720.f / 576.f;
678 for (UINT32 i = 0; i<256; i++) {
679 DWRITE_GLYPH_METRICS glyph_metrics;
681 fontface->GetGlyphIndices(&i, 1, &glyph_index);
682 HRESULT hres=fontface->GetDesignGlyphMetrics(&glyph_index, 1, &glyph_metrics, FALSE);
685 byte_char_width[i] = ((float)glyph_metrics.advanceWidth)*13.f
686 / ((float)metrics.designUnitsPerEm) *fontaspect_corr / 72.f*dpix;
689 byte_char_width[i] = 0.f;
703 OsdWinVector::TTIndex OsdWinVector::loadTTchar(cTeletextChar c)
705 /* map<unsigned int, TTIndex> tt_font_chars;
706 vector<ID2D1Bitmap *> tt_atlas;
707 TTIndex ttchar_end;*/
710 unsigned int glyph_index = c.getGlyphIndex();
711 std::map<unsigned int, TTIndex>::iterator glypos = tt_font_chars.find(glyph_index);
712 if (glypos != tt_font_chars.end())
714 return (*glypos).second;
716 TTIndex our_index = ttchar_end;
718 unsigned int buffer[10];
719 unsigned int * charmap = GetFontChar(c, buffer);
720 if (!charmap) { //invalid char
721 our_index.atlas = our_index.position = 0;
727 // Now we have to determine, if the atlas is already created
728 if (our_index.atlas == tt_atlas.size()) {
729 //Now we have to create the atlas
730 ID2D1Bitmap * atlas = NULL;
734 D2D1_BITMAP_PROPERTIES bitmap_prop;
735 bitmap_prop.dpiX = dpix;
736 bitmap_prop.dpiY = dpiy;
737 bitmap_prop.pixelFormat.format = DXGI_FORMAT_A8_UNORM;
738 bitmap_prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_STRAIGHT;
740 HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, bitmap_prop, &atlas);
743 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap for atlas failed %d", hres);
745 our_index.atlas = our_index.position = 0;
748 tt_atlas.push_back(atlas);
752 unsigned char buffer_final[120];
753 for (int i = 0; i<10; i++) {
754 for (int j = 0; j < 12; j++) {
755 buffer_final[i*12+j] = ((charmap[i] >> (16-j)) & 1)? 0xFF: 0x00;
759 D2D1_RECT_U dst_rect = { (our_index.position % 10)*12,
760 (our_index.position /10) *10,
761 (our_index.position % 10+1)*12,
762 (our_index.position / 10+1)*10,
765 HRESULT hres=tt_atlas[our_index.atlas]->CopyFromMemory(&dst_rect, buffer_final, 12);
768 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CopyFromMemory for atlas failed %d", hres);
769 our_index.atlas = our_index.position = 0;
773 tt_font_chars[glyph_index] = our_index;
774 ttchar_end.position++;
775 if (ttchar_end.position == 120) {
776 ttchar_end.position = 0;
783 int OsdWinVector::getFontNames(const char *** names, const char *** names_keys)
785 *names = (const char**)&(fontnames[0]);
786 *names_keys = (const char**)&(fontnames/*_keys*/[0]);
787 return fontnames.size();
790 void OsdWinVector::setFont(const char * fontname) {
792 wchar_t * wfontname= new wchar_t[strlen(fontname)+1];
794 MultiByteToWideChar(CP_UTF8, 0, fontname, -1,
795 wfontname, strlen(fontname) + 1);
797 if (wcscmp(wfontname, cur_fontname)) {
799 if (cur_fontname) free(cur_fontname);
800 cur_fontname = (wchar_t*)malloc(2*wcslen(wfontname) + 2);
801 wcscpy(cur_fontname, wfontname);
813 void OsdWinVector::drawSetTrans(SurfaceInfo & sc)
815 D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Identity();
817 trans = trans*D2D1::Matrix3x2F::Scale(((float)OSD_BUFFER_WIDTH) / 720.f, ((float)OSD_BUFFER_HEIGHT) / 576.f);
818 trans=D2D1::Matrix3x2F::Translation(0.f + sc.x, sc.y)*trans;
820 currentosd_backbuffer.rendtarget2D->SetTransform(trans);
826 void OsdWinVector::executeDrawCommand(SVGCommand & command)
828 D2D1::Matrix3x2F save_matrix;
829 D2D1::Matrix3x2F save_matrix2;
832 switch (command.instr) {
834 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
836 D2D1::Matrix3x2F matrix;
838 D2D1::Matrix3x2F::Scale(command.w, command.h)*D2D1::Matrix3x2F::Translation(command.x, command.y)*save_matrix;
839 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
840 currentosd_backbuffer.rendtarget2D->FillGeometry(std_paths[command.target.path_index],
841 (ID2D1Brush*)command.handle);
843 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
847 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
848 ID2D1Bitmap * bitmap = (ID2D1Bitmap*)command.target.image;
850 D2D1_SIZE_F size=bitmap->GetSize();
852 D2D1::Matrix3x2F matrix;
855 if (command.handle) { //special behaviour for bw images they act as a mask on the current paint
857 D2D1::Matrix3x2F::Scale(1.f*aspect_correction, 1.f)
858 *D2D1::Matrix3x2F::Translation(command.x, command.y)*save_matrix;
862 float scalex = command.w / size.width;
863 float scaley = command.h / size.height;
864 float tx = command.x;
865 float ty = command.y;
866 if (command.corner == TopLeftLimited) {
867 if (scalex != 0.f && scaley != 0.f) {
868 float imageaspect = size.width / size.height;
869 float boxaspect = command.w / command.h / aspect_correction;
870 if (imageaspect > boxaspect) {
872 ty += (command.h - size.height * scalex / aspect_correction)*0.5f;
876 tx += (command.w - size.width * scaley*aspect_correction)*0.5f;
882 if (scalex == 0.f && scaley == 0.f) {
883 scalex = aspect_correction;
886 else if (scalex == 0.f) {
887 scalex = scaley*aspect_correction;
889 else if (scaley == 0.f) {
890 scaley = scalex / aspect_correction;
894 if (command.corner == BottomRight || command.corner == BottomLeft || command.corner == BottomMiddle)
896 ty -= size.height * scaley;
899 if (command.corner == BottomRight || command.corner == TopRight)
901 tx -= size.width * scalex;
904 if (command.corner == BottomMiddle || command.corner == TopMiddle)
906 tx -= size.width * scalex *0.5f;
910 D2D1::Matrix3x2F::Scale(scalex, scaley)*D2D1::Matrix3x2F::Translation(tx, ty)*save_matrix;
915 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
917 if (command.handle) {
918 currentosd_backbuffer.rendtarget2D->FillOpacityMask(bitmap, (ID2D1Brush*)command.handle, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
923 currentosd_backbuffer.rendtarget2D->DrawBitmap(bitmap);
929 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
934 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
936 D2D1::Matrix3x2F matrix;
937 matrix = D2D1::Matrix3x2F::Scale(fontaspect_corr, 1.f)*
938 D2D1::Matrix3x2F::Translation(command.x, command.y + fontzero)*save_matrix;
939 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
940 UINT32 tchar = command.target.textchar;
942 DWRITE_GLYPH_RUN glyph_run;
943 glyph_run.fontEmSize = 13.f / (74.f / 96.f);
944 glyph_run.fontFace=fontface;
945 glyph_run.glyphCount=1;
946 glyph_run.glyphIndices = &glyphindex;
948 fontface->GetGlyphIndices(&tchar, 1, &glyphindex);
951 DWRITE_GLYPH_OFFSET zero2 = { 0.f, 0.f };
952 glyph_run.glyphAdvances=&zero;
953 glyph_run.glyphOffsets=&zero2;
954 glyph_run.isSideways=false;
955 glyph_run.bidiLevel=0;
956 D2D1_POINT_2F pos = { 0.f, 0.f };
958 currentosd_backbuffer.rendtarget2D->DrawGlyphRun(pos, &glyph_run,
959 (ID2D1Brush*)command.handle);
960 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
965 tchar.setInternal(command.target.ttchar);
966 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
968 enumTeletextColor ttforegcolour = tchar.GetFGColor();
969 enumTeletextColor ttbackgcolour = tchar.GetBGColor();
970 if (tchar.GetBoxedOut()) {
971 ttforegcolour = ttcTransparent;
972 ttbackgcolour = ttcTransparent;
974 D2D1::Matrix3x2F matrix;
975 matrix = D2D1::Matrix3x2F::Scale(1.5f+0.05f, 2.f)
976 *D2D1::Matrix3x2F::Translation(command.x + command.w*11.85f*1.4f, command.y + command.h*19.75f)
979 currentosd_backbuffer.rendtarget2D->SetTransform(matrix);
982 Colour color = Surface::enumTeletextColorToCoulour(ttbackgcolour);
984 ttbrush->SetColor(D2D1::ColorF(color.rgba(), ((float)color.alpha) / 255.f));
986 cTeletextChar filled;
987 filled.setInternal(0x187f);
988 TTIndex glyph_index = loadTTchar(filled);
991 D2D1_RECT_F src_rect = { (glyph_index.position % 10)*12.f,
992 (glyph_index.position / 10) *10.f,
993 (glyph_index.position % 10 + 1)*12.f,
994 (glyph_index.position / 10 + 1)*10.f,
998 currentosd_backbuffer.rendtarget2D->FillOpacityMask(tt_atlas[glyph_index.atlas], ttbrush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
1002 color = Surface::enumTeletextColorToCoulour(ttforegcolour);
1003 ttbrush->SetColor(D2D1::ColorF(color.rgba(), ((float)color.alpha) / 255.f));
1006 glyph_index = loadTTchar(tchar);
1009 D2D1_RECT_F src_rect = { (glyph_index.position % 10)*12.f,
1010 (glyph_index.position / 10) *10.f,
1011 (glyph_index.position % 10 + 1)*12.f,
1012 (glyph_index.position / 10 + 1)*10.f,
1016 currentosd_backbuffer.rendtarget2D->FillOpacityMask(tt_atlas[glyph_index.atlas], ttbrush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
1021 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
1025 case DrawClipping: {
1026 currentosd_backbuffer.rendtarget2D->GetTransform(&save_matrix);
1027 currentosd_backbuffer.rendtarget2D->SetTransform(D2D1::IdentityMatrix());
1029 D2D1_RECT_F coords = { ((command.x + clip_shift_x)*((float)OSD_BUFFER_WIDTH) / 720.f),
1030 (( command.y + clip_shift_y )*((float)OSD_BUFFER_HEIGHT) / 576.f),
1031 ((command.x + clip_shift_x+command.w - 1.f)*((float)OSD_BUFFER_WIDTH) / 720.f),
1032 (command.y + clip_shift_y+(command.h - 1.f)*((float)OSD_BUFFER_HEIGHT) / 576.f) };
1033 if (command.w == 0.f && command.h == 0.f) {
1034 while (num_clips > 0) {
1036 currentosd_backbuffer.rendtarget2D->PopAxisAlignedClip();
1040 currentosd_backbuffer.rendtarget2D->PushAxisAlignedClip(coords, D2D1_ANTIALIAS_MODE_ALIASED);
1043 currentosd_backbuffer.rendtarget2D->SetTransform(save_matrix);
1048 float OsdWinVector::getFontHeight()
1052 float OsdWinVector::getCharWidth(wchar_t c)
1054 if (c<256) return byte_char_width[c];
1055 if (!font) return 13.f;
1056 DWRITE_FONT_METRICS metrics;
1057 font->GetMetrics(&metrics);
1060 DWRITE_GLYPH_METRICS glyph_metrics;
1063 fontface->GetGlyphIndices(&tchar, 1, &glyph_index);
1064 fontface->GetDesignGlyphMetrics(&glyph_index, 1, &glyph_metrics, FALSE);
1066 return ((float)glyph_metrics.advanceWidth)*13.f
1067 / ((float)metrics.designUnitsPerEm) *fontaspect_corr / 72.f*dpiy;
1072 void OsdWinVector::getScreenSize(int &width, int &height)
1074 width = OSD_BUFFER_WIDTH;
1075 height = OSD_BUFFER_HEIGHT;
1078 void OsdWinVector::getRealScreenSize(int &width, int &height)
1080 width = BACKBUFFER_WIDTH;
1081 height = BACKBUFFER_HEIGHT;
1084 bool OsdWinVector::screenShotInternal(void *buffer, int width, int height, bool includeOSD)
1086 //screen->screenShot(fileName);
1090 LPDIRECT3DTEXTURE9 OsdWinVector::getNextOsdTexture()
1093 if (d2dtod3d.size())
1095 SurfaceInfo surfinfo = d2dtod3d.front();
1096 //Now we have to check, if the resource is ready, or busy somewhere else
1097 // if (surfinfo.query10->GetData(NULL, 0, D3D10_ASYNC_GETDATA_DONOTFLUSH) == S_OK) {
1098 //the surface is ready
1099 if (currentosd_render.surf9) {
1100 currentosd_render.query9->Issue(D3DISSUE_END); //mark the end of the 9 api access
1101 d3dtod2d.push(currentosd_render);
1103 currentosd_render = surfinfo;
1107 queuemutex.unlock();
1109 return currentosd_render.surf9;
1112 void OsdWinVector::updateOsd()
1116 if (d3dtod2d.size())
1118 currentosd_backbuffer = d3dtod2d.front();
1119 //Now we have to check, if the resource is ready, or busy somewhere else
1120 if (currentosd_backbuffer.query9->GetData(NULL, 0, 0) == S_OK) {
1123 //queuemutex.unlock();
1124 currentosd_backbuffer.query10->Begin();
1126 currentosd_backbuffer.rendtarget2D->BeginDraw();
1127 currentosd_backbuffer.rendtarget2D->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.0f));
1128 currentosd_backbuffer.rendtarget2D->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
1133 while (num_clips>0) {
1134 currentosd_backbuffer.rendtarget2D->PopAxisAlignedClip();
1138 currentosd_backbuffer.rendtarget2D->EndDraw();
1139 currentosd_backbuffer.rendtarget2D->Flush();
1140 d3ddevice10->Flush();
1141 currentosd_backbuffer.query10->End();
1143 //queuemutex.lock();
1145 d2dtod3d.push(currentosd_backbuffer);
1151 queuemutex.unlock();
1155 ID2D1RenderTarget * OsdWinVector::LockOsdDrawing()
1158 if (d3dtod2d.size())
1160 currentosd_backbuffer=d3dtod2d.front();
1161 return currentosd_backbuffer.rendtarget2D;
1163 queuemutex.unlock();
1166 while (loop < 100) {
1168 if (d3dtod2d.size())
1170 currentosd_backbuffer = d3dtod2d.front();
1171 return currentosd_backbuffer.rendtarget2D;
1173 queuemutex.unlock();
1179 currentosd_backbuffer.surf10 = NULL;
1180 currentosd_backbuffer.surf9 = NULL;
1184 void OsdWinVector::UnlockOsdDrawing()
1186 queuemutex.unlock();
1189 void OsdWinVector::lostDestroyObjects()
1194 void OsdWinVector::lostRecreateObjects()
1200 void OsdWinVector::getTextureCoordinates(FLOAT* x, FLOAT* y)
1209 void OsdWinVector::destroyImageRef(ImageIndex index)
1211 ID2D1Bitmap* bitmap = (ID2D1Bitmap*)index;
1212 if (bitmap) bitmap->Release();
1216 bool OsdWinVector::getStaticImageData(unsigned int static_id, UCHAR **userdata, ULONG *length)
1218 if (sa_MAX>static_id) {
1219 HRSRC hrc = FindResource(GetModuleHandle(NULL), ext_pict_name[static_id], RT_RCDATA);
1220 *length = SizeofResource(GetModuleHandle(NULL), hrc);
1221 *userdata = (UCHAR*) LockResource(LoadResource(GetModuleHandle(NULL), hrc));
1232 void OsdWinVector::createPicture(struct PictureInfo& pict_inf)
1235 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "TVMedia Create Picture %d", pict_inf.type);
1236 if (pict_inf.type == PictureInfo::D2DBitmap) {
1237 bool static_image = true;
1238 if (pict_inf.lindex & 0xffffffff) static_image = false;
1240 Message* m = new Message();
1241 // We have a pictures! send a message to ourself, to switch to gui thread
1243 m->p_to = Message::CONTROL;
1244 m->data = pict_inf.reference;
1245 if (!static_image) {
1246 m->message = Message::NEW_PICTURE;
1247 m->tag = pict_inf.lindex;
1250 m->message = Message::NEW_PICTURE_STATIC;
1251 m->tag = pict_inf.lindex >> 32LL;
1253 MessageQueue::getInstance()->postMessage(m); // inform control about new picture
1256 pict_inf.decoder->freeReference(pict_inf.reference);
1262 ImageIndex OsdWinVector::createMonoBitmap(void *base, int width, int height)
1264 // 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
1269 unsigned char *basechar = (unsigned char*) base;
1270 unsigned int bytesIn, bitsIn;
1271 int widthBytes = width / 8;
1273 unsigned char *alphamem = (unsigned char*)malloc(width*height);
1274 unsigned char *alphamemrun = alphamem;
1276 for (y = 0; y < height; y++) {
1277 for (x = 0; x < width; x++) {
1278 bytesIn = (y * widthBytes) + (int)(x / 8);
1280 (*alphamemrun) = ((basechar[bytesIn] >> (7 - bitsIn)) & 0x01) ? 0xFF : 0x00;
1285 size.height = height;
1287 D2D1_BITMAP_PROPERTIES bitmap_prop;
1288 bitmap_prop.dpiX = dpix;
1289 bitmap_prop.dpiY = dpiy;
1290 bitmap_prop.pixelFormat.format = DXGI_FORMAT_A8_UNORM;
1291 bitmap_prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_STRAIGHT;
1293 ID2D1Bitmap *bitmap = NULL;
1295 HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, alphamem, width, bitmap_prop, &bitmap);
1298 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap failed %d", hres);
1306 return (void*)bitmap;
1310 ImageIndex OsdWinVector::createImagePalette(int width, int height, const unsigned char *image_data, const unsigned int*palette_data)
1312 // 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
1317 UINT32 *mem = (UINT32*)malloc(width*height*sizeof(UINT32));
1318 UINT32 *memrun = mem;
1319 const unsigned char* image_run = image_data;
1321 for (y = 0; y < height; y++) {
1322 for (x = 0; x < width; x++) {
1324 (*memrun) = palette_data[(*image_run)];
1330 size.height = height;
1332 D2D1_BITMAP_PROPERTIES bitmap_prop;
1333 bitmap_prop.dpiX = dpix;
1334 bitmap_prop.dpiY = dpiy;
1335 bitmap_prop.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
1336 bitmap_prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
1338 ID2D1Bitmap *bitmap = NULL;
1340 HRESULT hres = currentosd_backbuffer.rendtarget2D->CreateBitmap(size, mem, width*sizeof(UINT32), bitmap_prop, &bitmap);
1343 Log::getInstance()->log("OsdWinVector", Log::DEBUG, "CreateBitmap failed %d", hres);
1351 return (void*)bitmap;
1355 void OsdWinVector::destroyDrawStyleHandle(VectorHandle index)
1357 if (!initted) return;
1358 ID2D1Brush *brush = (ID2D1Brush*)(index);
1363 VectorHandle OsdWinVector::createDrawStyleHandle(const DrawStyle &c)
1368 case DrawStyle::Color: {
1369 ID2D1SolidColorBrush * newbrush=NULL;
1370 currentosd_backbuffer.rendtarget2D->CreateSolidColorBrush(
1371 D2D1::ColorF(c.rgba(),((float)c.alpha)/255.f),
1376 case DrawStyle::GradientLinear:
1377 case DrawStyle::GradientRadial: {
1378 D2D1_GRADIENT_STOP grad_stop[5];
1379 grad_stop[0].color = D2D1::ColorF(c.rgba());
1380 grad_stop[0].position = 0.0f;
1382 for (int i = 0; i < (c.num_colors - 1); i++) {
1383 grad_stop[i + 1].color = D2D1::ColorF(c.grad_col[i].rgba(), ((float)c.grad_col[i].alpha) / 255.f);
1384 grad_stop[i + 1].position = c.grad_pos[i];
1386 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);
1387 grad_stop[c.num_colors].position = 1.f;
1389 ID2D1GradientStopCollection *gradstopobj;
1391 currentosd_backbuffer.rendtarget2D->CreateGradientStopCollection(
1395 D2D1_EXTEND_MODE_CLAMP,
1399 if (c.ft == DrawStyle::GradientLinear) {
1400 ID2D1LinearGradientBrush * newbrush=NULL;
1401 currentosd_backbuffer.rendtarget2D->CreateLinearGradientBrush(
1402 D2D1::LinearGradientBrushProperties(
1403 D2D1::Point2F(c.x1, c.y1),
1404 D2D1::Point2F(c.x2, c.y2)),
1408 gradstopobj->Release();
1412 if (c.ft == DrawStyle::GradientRadial) {
1413 ID2D1RadialGradientBrush * newbrush = NULL;
1414 currentosd_backbuffer.rendtarget2D->CreateRadialGradientBrush(
1415 D2D1::RadialGradientBrushProperties(
1416 D2D1::Point2F(c.x1, c.y1),
1417 D2D1::Point2F(c.x2, c.y2),c.r,c.r),
1421 gradstopobj->Release();