/* * $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" NAMESPACE_OSD_BEGIN // ==================================================================================== /** * 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; } // ==================================================================================== /// Affichage d'un objet OSD /// \param[in] cOsdObj Référence sur l'objet à afficher HRESULT COsdLayer::Draw(COsdObject & cObj) { // Chargement des références de position // (en retirant systématiquement 10 pixels à gauche et à droite) RECT sRct = cObj.cOSD.sOsdRect; sRct.left += 10; sRct.right -= 10; // Ajustement selon les paramètres spécifiques à l'objet courant cObj.AdjustOsdRect(sRct); m_bNotEmpty = true; return Draw(cObj, sRct); } // ==================================================================================== // 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); 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 Draw(COsdObject & cOsd, const RECT & sRct) { return cOsd.Draw(m_hDC, sRct); } virtual HRESULT Present(IVMRMixerBitmap9 * pBMP) { return S_OK; } // sans objet virtual HRESULT Present(IMFVideoMixerBitmap * pBMP) { return S_OK; } // sans objet }; // ==================================================================================== COsdHdcLayer::COsdHdcLayer(HDC hDC) : m_hDC(hDC) { } 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; } // ==================================================================================== /// 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 Draw(COsdObject & cOsd, const RECT & sRct) { AutoSelect cDC(m_hDC, m_hBmp); return __super::Draw(cOsd, 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; } // ==================================================================================== NAMESPACE_OSD_END