/* * $Id$ * Copyright (C) 2011 gingko - http://gingko.homeip.net/ * * This file is part of Pouchin TV Mod, a free DVB-T viewer. * See http://www.pouchintv.fr/ for updates. * * Pouchin TV Mod is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Pouchin TV Mod is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * Most files of this project have been changed from the Pouchin TV * project (Copyright (C) 2006 Pouchin ), * to use with a modified version of this software. * See http://pouchinteve.free.fr/ for the original project. */ /** \file * \brief Gestion de la surface superposée à l'image pour les besoins de l'OSD. * * Implémentation des classes nécessaires à construire une surface * de rendu de texte et autres objets, selon des méthodes variables * (la méthode de base étant la bibliothèque GDI, les alternatives * possibles étant les diverses versions de DirectX). **/ #include "stdafx.h" #include "osd_layer.h" // ==================================================================================== /** * Calcul du rectangle client de la fenêtre (hors barre d'état) **/ RECT CalcCliRect() { RECT sRect; // Obtenir le rectangle client de la fenêtre : GetClientRect(hMainWnd, &sRect); // Si la barre d'état est présente, retirer la hauteur correspondante : if (hMainStatus != NULL && !IsRectEmpty(&sRect)) { RECT sStaRect; GetWindowRect(hMainStatus, &sStaRect); sRect.bottom = max(sRect.bottom - RHgt(sStaRect), sRect.top); } return sRect; } // ==================================================================================== // Allocateur de polices de caractères, méthode GDI // ==================================================================================== /// Gestion GDI du plan de dessin de l'OSD class COsdGdiFontAllocator : public COsdFontAllocator { HFONT hf; //!< Handle de la police utilisée public: /// Constructeur COsdGdiFontAllocator() : hf(NULL) { } /// Suppression de la police courante (par destructeur, ou bien après /// changement de taille, pour forcer la création d'une nouvelle) virtual void Reset() { if (hf) DeleteObject(hf); hf = NULL; } /// Obtenir la police courante (création si nécessaire) HFONT GetFont() { if (!hf && nFntHgt != 0) { LOGFONT sLf = { nFntHgt // lfHeight // le reste à zéro (implicite) }; myprintf(COLR(HYELLOW, TEXT("CreateFontIndirect, hgt=%i")) EOL, nFntHgt); hf = CreateFontIndirect(&sLf); } return hf; } /// Destructeur virtual ~COsdGdiFontAllocator() { Reset(); } }; // ==================================================================================== /// Affichage d'un objet OSD /// \param[in] cOsdObj Référence sur l'objet à afficher HRESULT COsdLayer::DrawOsdObject(COsdObjectPtr pObj) { // Chargement des références de position // (en retirant systématiquement 10 pixels à gauche et à droite) RECT sRct = pObj->cOSD.sOsdRect; sRct.left += 10; sRct.right -= 10; // Ajustement selon les paramètres spécifiques à l'objet courant pObj->AdjustOsdRect(sRct); switch (pObj->Type()) { case oot_Text: m_bNotEmpty = true; return DrawOsdText(*dynamic_cast(&*pObj), sRct); case oot_Bmp: m_bNotEmpty = true; return DrawOsdBmp(*dynamic_cast(&*pObj), sRct); } return E_FAIL; } // ==================================================================================== // Déclaration de classes de gestion du plan de dessin de l'OSD (méthodes GDI) // ==================================================================================== /// Utilisation du "display context" fourni par WM_PAINT class COsdHdcLayer : public COsdLayer { protected: HDC m_hDC; //!< "Device context" public: COsdHdcLayer(HDC hDC) : m_hDC(hDC) { } virtual bool layer_ok() const { return true; } virtual bool layer_set() const { return m_hDC != NULL; } virtual HRESULT Initialize() { return S_OK; } // sans objet virtual COsdFontAllocator * CreateFontAllocator() { return new COsdGdiFontAllocator; } virtual HRESULT Erase(); virtual SIZE GetSize() const { RECT sRect = CalcCliRect(); return MkSIZE(RWdt(sRect), RHgt(sRect)); } virtual HRESULT Create() { return Erase(); } virtual void Reset() { } // sans objet virtual HRESULT DrawOsdText(COsdObjectText & cOsdTxt, const RECT & sRct); virtual HRESULT DrawOsdBmp(COsdObjectBmp & cOsdBmp, const RECT & sRct); virtual HRESULT Present(IVMRMixerBitmap9 * pBMP) { return S_OK; } // sans objet virtual HRESULT Present(IMFVideoMixerBitmap * pBMP) { return S_OK; } // sans objet }; // ==================================================================================== HRESULT COsdHdcLayer::Erase() { if (!layer_set()) return E_FAIL; RECT sRct = MkRECT(GetSize()); #if OSD_DEBUGGING && defined(_DEBUG) // incrustation d'une trame de fond pour déboguer la position du bitmap AutoHandle cB2(CreateHatchBrush(HS_BDIAGONAL, RGB(255, 255, 255))); SetBkColor(m_hDC, colorKey); FillRect(m_hDC, &sRct, cB2); #else AutoHandle cBR(CreateSolidBrush(colorKey)); FillRect(m_hDC, &sRct, cBR); #endif m_bNotEmpty = false; return S_OK; } HRESULT COsdHdcLayer::DrawOsdText(COsdObjectText & cOsdTxt, const RECT & sRct) { // Récupérer le pointeur sur l'allocateur de polices shared_ptr pFontAlloc(dynamic_pointer_cast(cOsdTxt.GetFontAllocator())); if (!pFontAlloc) return E_FAIL; AutoSelect cFs(m_hDC, pFontAlloc->GetFont()); // Couleur de l'OSD (VERT ici) SetTextColor(m_hDC, osd_color); // Couleur de fond (remplacée par de la transparence) SetBkColor(m_hDC, colorKey); SetTextAlign(m_hDC, cOsdTxt.bRJustif ? TA_RIGHT : TA_LEFT); BOOL bRes = ExtTextOut(m_hDC, cOsdTxt.bRJustif ? sRct.right : sRct.left, sRct.top, ETO_CLIPPED|ETO_OPAQUE, &sRct, cOsdTxt.szText, cOsdTxt.nTextSize, NULL); myprintf(CMyP ERRX(TEXT("Erreur ExtTextOut code 0x%08x")), !bRes, GetLastError()); return bRes == TRUE ? S_OK : E_FAIL; } HRESULT COsdHdcLayer::DrawOsdBmp(COsdObjectBmp & cOsdBmp, const RECT & sRct) { AutoSelect cBmpS(cOsdBmp.m_hDC, cOsdBmp.m_hBmp); return BitBlt(m_hDC, sRct.left, sRct.top, RWdt(sRct), RHgt(sRct), cBmpS, 0, 0, SRCCOPY) ? S_OK : E_FAIL; } // ==================================================================================== /// Utilisation d'un "display context" dérivé de la fenêtre de l'application class COsdWinLayer : public COsdHdcLayer { public: COsdWinLayer() : COsdHdcLayer(NULL) { } virtual HRESULT Create() { Reset(); m_hDC = GetDC(hMainWnd); return Erase(); } virtual void Reset() { if (m_hDC) { ReleaseDC(hMainWnd, m_hDC); m_hDC = NULL; } } virtual ~COsdWinLayer() { Reset(); } }; // ==================================================================================== // Déclaration de la classe de gestion du plan de dessin de l'OSD (méthode GDI + bitmap) // ==================================================================================== /// Gestion du plan de dessin de l'OSD sous forme de bitmap class COsdBmpLayer : public COsdHdcLayer { HBITMAP m_hBmp; //!< Bitmap utilisé pour l'OSD public: COsdBmpLayer() : COsdHdcLayer(NULL), m_hBmp(NULL) { } virtual bool layer_set() const { return __super::layer_set() && m_hBmp != NULL; } virtual HRESULT Create(); virtual void Reset(); virtual HRESULT Erase(); virtual SIZE GetSize() const { return GetBmpSize(m_hBmp); } virtual HRESULT DrawOsdText(COsdObjectText & cOsdTxt, const RECT & sRct) { AutoSelect cDC(m_hDC, m_hBmp); return __super::DrawOsdText(cOsdTxt, sRct); } virtual HRESULT DrawOsdBmp(COsdObjectBmp & cOsdBmp, const RECT & sRct) { AutoSelect cDC(m_hDC, m_hBmp); return __super::DrawOsdBmp(cOsdBmp, sRct); } virtual HRESULT Present(IVMRMixerBitmap9 * pBMP); virtual HRESULT Present(IMFVideoMixerBitmap * pBMP); virtual ~COsdBmpLayer() { Reset(); } }; // ==================================================================================== HRESULT COsdBmpLayer::Create() { { AutoDC cDC_Main(hMainWnd); Reset(); // Creation d'un nouveau bitmap compatible avec la fenêtre d'affichage m_hBmp = CreateCompatibleBitmap(cDC_Main, m_sSize.cx, m_sSize.cy); myprintf(CMyP TEXT("Erreur CreateCompatibleBitmap, code=0x%08x") EOL, m_hBmp == NULL, GetLastError()); if (!m_hBmp) return E_FAIL; m_hDC = CreateCompatibleDC(cDC_Main); myprintf(CMyP TEXT("Erreur CreateCompatibleDC, code=0x%08x") EOL, m_hDC == NULL, GetLastError()); } if (!m_hDC) return E_FAIL; return Erase(); } void COsdBmpLayer::Reset() { if (m_hDC) { DeleteDC(m_hDC); m_hDC = NULL; } if (m_hBmp) { DeleteBitmap(m_hBmp); m_hBmp = NULL; } } HRESULT COsdBmpLayer::Erase() { if (!layer_set()) return E_FAIL; AutoSelect cBS(m_hDC, m_hBmp); return __super::Erase(); } HRESULT COsdBmpLayer::Present(IVMRMixerBitmap9 * pBMP) { // Configuration de la structure du bitmap du VMR VMR9AlphaBitmap sBmpParms = { VMR9AlphaBitmap_hDC | VMR9AlphaBitmap_SrcColorKey, // dwFlags m_hDC, // hdc (DC which has selected our bitmap) NULL, // pDDS MkRECT(GetSize()), // rSrc specifies the source rectangle in the GDI device context {0.0f, 0.0f, 1.0f, 1.0f}, // rDest float(osd_transparency)/100, // fAlpha (transparence : 1.0 est opaque, 0.0 est transparent) colorKey, // clrSrcKey 0 // dwFilterMode }; AutoSelect cBS(m_hDC, m_hBmp); // Incrustation de la couche OSD dans l'affichage return pBMP->SetAlphaBitmap(&sBmpParms); } HRESULT COsdBmpLayer::Present(IMFVideoMixerBitmap * pBMP) { // Configuration de la structure du bitmap du VMR MFVideoAlphaBitmap sBmpParms = { TRUE, // GetBitmapFromDC {m_hDC}, // bitmap.hdc { MFVideoAlphaBitmap_SrcColorKey | MFVideoAlphaBitmap_SrcRect | MFVideoAlphaBitmap_DestRect | MFVideoAlphaBitmap_Alpha | MFVideoAlphaBitmap_FilterMode, // params.dwFlags colorKey, // params.clrSrcKey MkRECT(GetSize()), // params.rcSrc {0.0f, 0.0f, 1.0f, 1.0f}, // params.nrcDest float(osd_transparency)/100, // params.fAlpha D3DTEXF_LINEAR // params.dwFilterMode } }; AutoSelect cBS(m_hDC, m_hBmp); // Incrustation de la couche OSD dans l'affichage return pBMP->SetAlphaBitmap(&sBmpParms); } // ==================================================================================== COsdFontAllocator * COsdFontAllocator::CreateInstance(LayerTypes eType) { switch (eType) { case lt_GDI: case lt_BMP: return new COsdGdiFontAllocator; } return NULL; } /** * Création d'une instance destinée à dessiner directement dans le rectangle client * de la fenêtre. * \param[in] hDC "Device context", à utiliser seulement si on dispose de la valeur * fournie par \p WM_PAINT; sinon, mettre NULL. * \return Pointeur sur l'objet créé. **/ COsdLayer * COsdLayer::CreateWinInstance(HDC hDC) { if (hDC) return new COsdHdcLayer(hDC); return new COsdWinLayer; } /** * Création d'une instance dont le type est défini par \p eType. * \param[in] eType Type de couche OSD à créer. * \return Pointeur sur l'objet créé. **/ COsdLayer * COsdLayer::CreateInstance(LayerTypes eType) { switch (eType) { case lt_GDI: return new COsdWinLayer; case lt_BMP: return new COsdBmpLayer; } return NULL; } // ====================================================================================