/* * (C) 2003-2006 Gabest * (C) 2006-2014 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC 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 3 of the License, or * (at your option) any later version. * * MPC-HC 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, see . * */ #include "stdafx.h" #include "DX7SubPic.h" #include // // CDX7SubPic // CDX7SubPic::CDX7SubPic(IDirect3DDevice7* pD3DDev, IDirectDrawSurface7* pSurface) : m_pD3DDev(pD3DDev) , m_pSurface(pSurface) { DDSURFACEDESC2 ddsd; INITDDSTRUCT(ddsd); if (SUCCEEDED(m_pSurface->GetSurfaceDesc(&ddsd))) { m_maxsize.SetSize(ddsd.dwWidth, ddsd.dwHeight); m_rcDirty.SetRect(0, 0, ddsd.dwWidth, ddsd.dwHeight); } } // ISubPic STDMETHODIMP_(void*) CDX7SubPic::GetObject() { return (IDirectDrawSurface7*)m_pSurface; } STDMETHODIMP CDX7SubPic::GetDesc(SubPicDesc& spd) { DDSURFACEDESC2 ddsd; INITDDSTRUCT(ddsd); if (FAILED(m_pSurface->GetSurfaceDesc(&ddsd))) { return E_FAIL; } spd.type = 0; spd.w = m_size.cx; spd.h = m_size.cy; spd.bpp = (WORD)ddsd.ddpfPixelFormat.dwRGBBitCount; spd.pitch = ddsd.lPitch; spd.bits = (BYTE*)ddsd.lpSurface; // should be NULL spd.vidrect = m_vidrect; return S_OK; } STDMETHODIMP CDX7SubPic::CopyTo(ISubPic* pSubPic) { HRESULT hr; if (FAILED(hr = __super::CopyTo(pSubPic))) { return hr; } CPoint p = m_rcDirty.TopLeft(); hr = m_pD3DDev->Load((IDirectDrawSurface7*)pSubPic->GetObject(), &p, m_pSurface, m_rcDirty, 0); return SUCCEEDED(hr) ? S_OK : E_FAIL; } STDMETHODIMP CDX7SubPic::ClearDirtyRect(DWORD color) { if (m_rcDirty.IsRectEmpty()) { return S_FALSE; } DDBLTFX fx; INITDDSTRUCT(fx); fx.dwFillColor = color; m_pSurface->Blt(&m_rcDirty, nullptr, nullptr, DDBLT_WAIT | DDBLT_COLORFILL, &fx); m_rcDirty.SetRectEmpty(); return S_OK; } STDMETHODIMP CDX7SubPic::Lock(SubPicDesc& spd) { DDSURFACEDESC2 ddsd; INITDDSTRUCT(ddsd); if (FAILED(m_pSurface->Lock(nullptr, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, nullptr))) { return E_FAIL; } spd.type = 0; spd.w = m_size.cx; spd.h = m_size.cy; spd.bpp = (WORD)ddsd.ddpfPixelFormat.dwRGBBitCount; spd.pitch = ddsd.lPitch; spd.bits = (BYTE*)ddsd.lpSurface; spd.vidrect = m_vidrect; return S_OK; } STDMETHODIMP CDX7SubPic::Unlock(RECT* pDirtyRect) { m_pSurface->Unlock(nullptr); if (pDirtyRect) { m_rcDirty = *pDirtyRect; m_rcDirty.InflateRect(1, 1); m_rcDirty &= CRect(CPoint(0, 0), m_size); } else { m_rcDirty = CRect(CPoint(0, 0), m_size); } return S_OK; } STDMETHODIMP CDX7SubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) { ASSERT(pTarget == nullptr); if (!m_pD3DDev || !m_pSurface || !pSrc || !pDst) { return E_POINTER; } CRect src(*pSrc), dst(*pDst); DDSURFACEDESC2 ddsd; INITDDSTRUCT(ddsd); if (FAILED(m_pSurface->GetSurfaceDesc(&ddsd))) { return E_FAIL; } float w = (float)ddsd.dwWidth; float h = (float)ddsd.dwHeight; // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly // initialized and thus the subtitles weren't shown. struct { float x, y, z, rhw; float tu, tv; } pVertices[] = { {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, }; for (size_t i = 0; i < _countof(pVertices); i++) { pVertices[i].x -= 0.5f; pVertices[i].y -= 0.5f; } m_pD3DDev->SetTexture(0, m_pSurface); m_pD3DDev->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); m_pD3DDev->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE); m_pD3DDev->SetRenderState(D3DRENDERSTATE_BLENDENABLE, TRUE); m_pD3DDev->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... m_pD3DDev->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_bInvAlpha ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); if (src == dst) { m_pD3DDev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT); m_pD3DDev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_POINT); } else { m_pD3DDev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); m_pD3DDev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_LINEAR); } m_pD3DDev->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_NONE); m_pD3DDev->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); /*// D3DDEVICEDESC7 d3ddevdesc; m_pD3DDev->GetCaps(&d3ddevdesc); if (d3ddevdesc.dpcTriCaps.dwAlphaCmpCaps & D3DPCMPCAPS_LESS) { m_pD3DDev->SetRenderState(D3DRENDERSTATE_ALPHAREF, (DWORD)0x000000FE); m_pD3DDev->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE); m_pD3DDev->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DPCMPCAPS_LESS); } */// if (FAILED(m_pD3DDev->BeginScene())) { return E_FAIL; } m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_TEX1, pVertices, 4, D3DDP_WAIT); m_pD3DDev->EndScene(); m_pD3DDev->SetTexture(0, nullptr); return S_OK; } // // CDX7SubPicAllocator // CDX7SubPicAllocator::CDX7SubPicAllocator(IDirect3DDevice7* pD3DDev, SIZE maxsize) : CSubPicAllocatorImpl(maxsize, true) , m_pD3DDev(pD3DDev) , m_maxsize(maxsize) { } // ISubPicAllocator STDMETHODIMP CDX7SubPicAllocator::ChangeDevice(IUnknown* pDev) { CComQIPtr pD3DDev = pDev; CheckPointer(pD3DDev, E_NOINTERFACE); CAutoLock cAutoLock(this); HRESULT hr = S_FALSE; if (m_pD3DDev != pD3DDev) { m_pD3DDev = pD3DDev; hr = __super::ChangeDevice(pDev); } return hr; } STDMETHODIMP CDX7SubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) { CAutoLock cAutoLock(this); if (m_maxsize != maxTextureSize) { m_maxsize = maxTextureSize; } return SetCurSize(m_maxsize); } // ISubPicAllocatorImpl bool CDX7SubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) { if (!ppSubPic) { return false; } if (m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { return false; } CAutoLock cAutoLock(this); DDSURFACEDESC2 ddsd; INITDDSTRUCT(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | (fStatic ? DDSCAPS_SYSTEMMEMORY : 0); ddsd.ddsCaps.dwCaps2 = fStatic ? 0 : (DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTSTATIC); ddsd.dwWidth = m_maxsize.cx; ddsd.dwHeight = m_maxsize.cy; ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; ddsd.ddpfPixelFormat.dwRGBBitCount = 32; ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xFF000000; ddsd.ddpfPixelFormat.dwRBitMask = 0x00FF0000; ddsd.ddpfPixelFormat.dwGBitMask = 0x0000FF00; ddsd.ddpfPixelFormat.dwBBitMask = 0x000000FF; CComPtr pD3D; CComQIPtr pDD; if (FAILED(m_pD3DDev->GetDirect3D(&pD3D)) || !pD3D || !(pDD = pD3D)) { return false; } CComPtr pSurface; if (FAILED(pDD->CreateSurface(&ddsd, &pSurface, nullptr))) { return false; } try { *ppSubPic = DEBUG_NEW CDX7SubPic(m_pD3DDev, pSurface); } catch (CMemoryException* e) { e->Delete(); return false; } (*ppSubPic)->AddRef(); return true; }