blob: fa01fd97e9ad45c310ac449b0b367be28acf21dd [file] [log] [blame]
/////////////////////////////////////////////////////////////////////////////
//
// projectM-wmp.cpp : Implementation of CProjectMwmp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "projectM-wmp.h"
/////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::CProjectMwmp
// Constructor
HGLRC hrc = NULL;
bool starting = true;
int width, height;
projectM *globalPM;
CProjectMwmp::CProjectMwmp() :
m_hwndParent(NULL),
m_clrForeground(0x0000FF),
m_nPreset(0)
{
m_dwAdviseCookie = 0;
}
/////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::~CProjectMwmp
// Destructor
CProjectMwmp::~CProjectMwmp()
{
}
/////////////////////////////////////////////////////////////////////////////
// CProjectMwmp:::FinalConstruct
// Called when an effect is first loaded. Use this function to do one-time
// intializations that could fail (i.e. creating offscreen buffers) instead
// of doing this in the constructor, which cannot return an error.
HRESULT CProjectMwmp::FinalConstruct()
{
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CProjectMwmp:::FinalRelease
// Called when an effect is unloaded. Use this function to free any
// resources allocated in FinalConstruct.
void CProjectMwmp::FinalRelease()
{
ReleaseCore();
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::Render
// Called when an effect should render itself to the screen.
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::Render(TimedLevel *pLevels, HDC hdc, RECT *prc)
{
if (starting) {
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), 1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0
};
SetPixelFormat(hdc, ChoosePixelFormat(hdc,&pfd), &pfd);
hrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hrc);
starting = false;
width = (int)(prc->right - prc->left);
height = (int)(prc->bottom - prc->top);
globalPM = new projectM("C:\\Program Files\\projectM\\config.inp");//24,18,0,128,width,height,"C:\\Documents and Settings\\DEV2\\My Documents\\svn\\presets_projectM\\");
}
int newwidth = (int)(prc->right - prc->left);
int newheight = (int)(prc->bottom - prc->top);
if (width!= newwidth || height != newheight)
{
width=newwidth;
height=newheight;
globalPM->projectM_resetGL(width,height);
}
//PCM* pcm = globalPM->pcm;
//pcm->addPCM8(pLevels->waveform);
wglMakeCurrent(hdc, hrc);
globalPM->projectM_resetGL(width,height);
globalPM->renderFrame();
SwapBuffers(hdc);
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::MediaInfo
// Everytime new media is loaded, this method is called to pass the
// number of channels (mono/stereo), the sample rate of the media, and the
// title of the media
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::MediaInfo(LONG lChannelCount, LONG lSampleRate, BSTR bstrTitle )
{
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::GetCapabilities
// Returns the capabilities of this effect. Flags that can be returned are:
// EFFECT_CANGOFULLSCREEN -- effect supports full-screen rendering
// EFFECT_HASPROPERTYPAGE -- effect supports a property page
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::GetCapabilities(DWORD * pdwCapabilities)
{
if (NULL == pdwCapabilities)
{
return E_POINTER;
}
*pdwCapabilities = EFFECT_CANGOFULLSCREEN;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::GetTitle
// Invoked when a host wants to obtain the title of the effect
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::GetTitle(BSTR* bstrTitle)
{
USES_CONVERSION;
if (NULL == bstrTitle)
{
return E_POINTER;
}
CComBSTR bstrTemp;
bstrTemp.LoadString(IDS_EFFECTNAME);
if ((!bstrTemp) || (0 == bstrTemp.Length()))
{
return E_FAIL;
}
*bstrTitle = bstrTemp.Detach();
return S_OK;
}
STDMETHODIMP CProjectMwmp::RenderFullScreen(TimedLevel *pLevels)
{
// NULL parent window should not happen
if (NULL == m_hwndParent)
{
return E_UNEXPECTED;
}
// At this point the visualization should draw directly into the parent
// window. This sample just calls windowless render for simplicity.
HDC hdc = ::GetDC(m_hwndParent);
if (NULL == hdc)
{
return E_FAIL;
}
RECT rParent = { 0 };
::GetClientRect(m_hwndParent, &rParent);
Render(pLevels, hdc, &rParent);
::ReleaseDC(m_hwndParent, hdc);
return S_OK;
}
STDMETHODIMP CProjectMwmp::GoFullscreen(BOOL fFullScreen)
{
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::GetPresetTitle
// Invoked when a host wants to obtain the title of the given preset
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::GetPresetTitle(LONG nPreset, BSTR *bstrPresetTitle)
{
USES_CONVERSION;
if (NULL == bstrPresetTitle)
{
return E_POINTER;
}
CComBSTR bstrTemp;
bstrTemp = "projectM 1.0";
if ((!bstrTemp) || (0 == bstrTemp.Length()))
{
return E_FAIL;
}
*bstrPresetTitle = bstrTemp.Detach();
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::GetPresetCount
// Invoked when a host wants to obtain the number of supported presets
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::GetPresetCount(LONG *pnPresetCount)
{
if (NULL == pnPresetCount)
{
return E_POINTER;
}
*pnPresetCount = 1;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::SetCurrentPreset
// Invoked when a host wants to change the index of the current preset
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::SetCurrentPreset(LONG nPreset)
{
m_nPreset = 0;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::GetCurrentPreset
// Invoked when a host wants to obtain the index of the current preset
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::GetCurrentPreset(LONG *pnPreset)
{
if (NULL == pnPreset)
{
return E_POINTER;
}
*pnPreset = 0;
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::SetCore
// Set WMP core interface
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::SetCore(IWMPCore * pCore)
{
HRESULT hr = S_OK;
// release any existing WMP core interfaces
ReleaseCore();
// If we get passed a NULL core, this means
// that the plugin is being shutdown.
if (pCore == NULL)
{
return S_OK;
}
m_spCore = pCore;
// connect up the event interface
CComPtr<IConnectionPointContainer> spConnectionContainer;
hr = m_spCore->QueryInterface( &spConnectionContainer );
if (SUCCEEDED(hr))
{
hr = spConnectionContainer->FindConnectionPoint( __uuidof(IWMPEvents), &m_spConnectionPoint );
}
if (SUCCEEDED(hr))
{
hr = m_spConnectionPoint->Advise( GetUnknown(), &m_dwAdviseCookie );
if ((FAILED(hr)) || (0 == m_dwAdviseCookie))
{
m_spConnectionPoint = NULL;
}
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::Create
// Invoked when the visualization should be initialized.
//
// If hwndParent != NULL, RenderWindowed() will be called and the visualization
// should draw into the window specified by hwndParent. This will be the
// behavior when the visualization is hosted in a window.
//
// If hwndParent == NULL, Render() will be called and the visualization
// should draw into the DC passed to Render(). This will be the behavior when
// the visualization is hosted windowless (like in a skin for example).
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::Create(HWND hwndParent)
{
m_hwndParent = hwndParent;
if(!starting)
{
delete(globalPM);
starting = true;
}
//
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::Destroy
// Invoked when the visualization should be released.
//
// Any resources allocated for ing should be released.
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::Destroy()
{
if (!starting)
{
m_hwndParent = NULL;
starting = true;
delete(globalPM);
return S_OK;
}
}
char* ConvertBSTRToLPSTR (BSTR bstrIn)
{
LPSTR pszOut = NULL;
if (bstrIn != NULL)
{
int nInputStrLen = SysStringLen (bstrIn);
// Double NULL Termination
int nOutputStrLen = WideCharToMultiByte(CP_ACP, 0, bstrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
pszOut = new char [nOutputStrLen];
if (pszOut)
{
memset (pszOut, 0x00, sizeof (char)*nOutputStrLen);
WideCharToMultiByte (CP_ACP, 0, bstrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
}
}
return pszOut;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::NotifyNewMedia
// Invoked when a new media stream begins playing.
//
// The visualization can inspect this object for properties (like name or artist)
// that might be interesting for visualization.
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::NotifyNewMedia(IWMPMedia *pMedia)
{
if (starting == false && pMedia != NULL)
{
CComBSTR name;
pMedia->get_name(&name);
LPTSTR pszConvertedCharStr = ConvertBSTRToLPSTR (name);
std::string strConverted (pszConvertedCharStr);
delete [] pszConvertedCharStr;
globalPM->projectM_setTitle(strConverted);
return S_OK;
}
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::OnWindowMessage
// Window messages sent to the parent window.
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::OnWindowMessage(UINT msg, WPARAM WParam, LPARAM LParam, LRESULT *plResultParam )
{
// return S_OK only if the plugin has handled the window message
// return S_FALSE to let the defWindowProc handle the message
return S_FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::Windowed
// Called when an effect should render itself to the screen.
//
// The fRequiredRender flag specifies if an update is required, otherwise the
// update is optional. This allows visualizations that are fairly static (for example,
// album art visualizations) to only render when the parent window requires it,
// instead of n times a second for dynamic visualizations.
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::RenderWindowed(TimedLevel *pLevels, BOOL fRequiredRender )
{
// NULL parent window should not happen
if (NULL == m_hwndParent)
{
return E_UNEXPECTED;
}
// At this point the visualization should draw directly into the parent
// window. This sample just calls windowless render for simplicity.
HDC hdc = ::GetDC(m_hwndParent);
if (NULL == hdc)
{
return E_FAIL;
}
RECT rParent = { 0 };
::GetClientRect(m_hwndParent, &rParent);
Render(pLevels, hdc, &rParent);
::ReleaseDC(m_hwndParent, hdc);
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::ReleaseCore
// Release WMP core interfaces
//////////////////////////////////////////////////////////////////////////////
void CProjectMwmp::ReleaseCore()
{
if (m_spConnectionPoint)
{
if (0 != m_dwAdviseCookie)
{
m_spConnectionPoint->Unadvise(m_dwAdviseCookie);
m_dwAdviseCookie = 0;
}
m_spConnectionPoint = NULL;
}
if (m_spCore)
{
m_spCore = NULL;
}
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::get_foregroundColor
// Property get to retrieve the foregroundColor prop via the public interface.
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::get_foregroundColor(BSTR *pVal)
{
return ColorToWz( pVal, m_clrForeground);
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::put_foregroundColor
// Property put to set the foregroundColor prop via the public interface.
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CProjectMwmp::put_foregroundColor(BSTR newVal)
{
return WzToColor(newVal, &m_clrForeground);
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::WzToColor
// Helper function used to convert a string into a COLORREF.
//////////////////////////////////////////////////////////////////////////////
HRESULT CProjectMwmp::WzToColor(const WCHAR *pwszColor, COLORREF *pcrColor)
{
if (NULL == pwszColor)
{
//NULL color string passed in
return E_POINTER;
}
if (0 == lstrlenW(pwszColor))
{
//Empty color string passed in
return E_INVALIDARG;
}
if (NULL == pcrColor)
{
//NULL output color DWORD passed in
return E_POINTER;
}
if (lstrlenW(pwszColor) != 7)
{
//hex color string is not of the correct length
return E_INVALIDARG;
}
DWORD dwRet = 0;
for (int i = 1; i < 7; i++)
{
// shift dwRet by 4
dwRet <<= 4;
// and add in the value of this string
if ((pwszColor[i] >= L'0') && (pwszColor[i] <= L'9'))
{
dwRet += pwszColor[i] - '0';
}
else if ((pwszColor[i] >= L'A') && (pwszColor[i] <= L'F'))
{
dwRet += 10 + (pwszColor[i] - L'A');
}
else if ((pwszColor[i] >= L'a') && (pwszColor[i] <= L'f'))
{
dwRet += 10 + (pwszColor[i] - L'a');
}
else
{
//Invalid hex digit in color string
return E_INVALIDARG;
}
}
*pcrColor = SwapBytes(dwRet);
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::ColorToWz
// Helper function used to convert a COLORREF to a BSTR.
//////////////////////////////////////////////////////////////////////////////
HRESULT CProjectMwmp::ColorToWz( BSTR* pbstrColor, COLORREF crColor)
{
_ASSERT( NULL != pbstrColor );
_ASSERT( (crColor & 0x00FFFFFF) == crColor );
*pbstrColor = NULL;
WCHAR wsz[8];
HRESULT hr = S_OK;
swprintf_s( wsz, sizeof(wsz)/sizeof(wsz[0]), L"#%06X", SwapBytes(crColor) );
*pbstrColor = ::SysAllocString( wsz );
if (!pbstrColor)
{
hr = E_FAIL;
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// CProjectMwmp::SwapBytes
// Used to convert between a DWORD and COLORREF. Simply swaps the lowest
// and 3rd order bytes.
//////////////////////////////////////////////////////////////////////////////
inline DWORD CProjectMwmp::SwapBytes(DWORD dwRet)
{
return ((dwRet & 0x0000FF00) | ((dwRet & 0x00FF0000) >> 16) | ((dwRet & 0x000000FF) << 16));
}