2024-09-24 12:54:57 +00:00
/*
LICENSE
- - - - - - -
Copyright 2005 - 2013 Nullsoft , Inc .
All rights reserved .
Redistribution and use in source and binary forms , with or without modification ,
are permitted provided that the following conditions are met :
* Redistributions of source code must retain the above copyright notice ,
this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
* Neither the name of Nullsoft nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND ANY EXPRESS OR
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER
IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
/*
TO DO
- - - - -
- done / v1 .06 :
- ( nothing yet )
-
-
- to do / v1 .06 :
- FFT : high freq . data kinda sucks because of the 8 - bit samples we get in ;
look for justin to put 16 - bit vis data into wa5 .
- make an ' advanced view ' button on config panel ; hide complicated stuff
til they click that .
- put an asterisk ( * ) next to the ' max framerate ' values that
2024-09-29 02:04:03 +00:00
are ideal ( given the current arch display mode or selected FS dispmode ) .
2024-09-24 12:54:57 +00:00
- or add checkbox : " smart sync "
- > matches FPS limit to nearest integer divisor of refresh rate .
- debug . txt / logging support !
- audio : make it a DSP plugin ? then we could get the complete , continuous waveform
2024-09-29 02:04:03 +00:00
and overlap our waveform arch , so we ' d never miss a brief high note .
2024-09-24 12:54:57 +00:00
- bugs :
- vms plugins sometimes freeze after a several - minute pause ; I ' ve seen it
with most of them . hard to repro , though .
- running FS on monitor 2 , hit ALT - TAB - > minimizes ! ! !
- but only if you let go of TAB first . Let go of ALT first and it ' s fine !
- > means it ' s related to the keyup . . .
- fix delayloadhelper leak ; one for each launch to config panel / plugin .
- also , delayload ( d3d9 . dll ) still leaks , if plugin has error initializing and
quits by returning false from PluginInitialize ( ) .
- add config panel option to ignore fake - fullscreen tips
- " tip " boxes in dxcontext . cpp
- " notice " box on WM_ACTIVATEAPP ?
- desktop mode :
- icon context menus : ' send to ' , ' cut ' , and ' copy ' links do nothing .
- http : //netez.com/2xExplorer/shellFAQ/bas_context.html
- create a 2 nd texture to render all icon text labels into
( they ' re the sole reason that desktop mode is slow )
- in UpdateIconBitmaps , don ' t read the whole bitmap and THEN
realize it ' s a dupe ; try to compare icon filename + index or somethign ?
- DRAG AND DROP . COMPLICATED ; MANY DETAILS .
- http : //netez.com/2xExplorer/shellFAQ/adv_drag.html
- http : //www.codeproject.com/shell/explorerdragdrop.asp
- hmm . . . you can ' t drag icons between the 2 desktops ( ugh )
- multiple delete / open / props / etc
- delete + enter + arrow keys .
- try to solve mysteries w / ShellExecuteEx ( ) and desktop * shortcuts * ( * . lnk ) .
- ( notice that when icons are selected , they get modulated by the
highlight color , when they should be blended 50 % with that color . )
- - - - - - - - - - - - - - - - - - - - - - - - - - -
final touches :
- Tests :
- make sure desktop still functions / responds properly when winamp paused
- desktop mode + multimon :
- try desktop mode on all monitors
- try moving taskbar around ; make sure icons are in the
right place , that context menus ( general & for
specific icons ) pop up in the right place , and that
text - off - left - edge is ok .
- try setting the 2 monitors to different / same resolutions
- check tab order of config panel controls !
- Clean All
- build in release mode to include in the ZIP
- leave only one file open in workspace : README . TXT .
- TEMPORARILY " ATTRIB -R " ALL FILES BEFORE ZIPPING THEM !
- - - - - - - - - - - - - - - - - - - - - - - - - - -
KEEP IN VIEW :
- EMBEDWND :
- kiv : on resize of embedwnd , it ' s out of our control ; winamp
resizes the child every time the mouse position changes ,
and we have to cleanup & reallocate everything , b / c we
can ' t tell when the resize begins & ends .
[ justin said he ' d fix in wa5 , though ]
2024-09-29 02:04:03 +00:00
- kiv : with embedded arch of any type ( plugin , playlist , etc . )
2024-09-24 12:54:57 +00:00
you can ' t place the winamp main wnd over them .
2024-09-29 02:04:03 +00:00
- kiv : embedded arch are child arch and don ' t get the
2024-09-24 12:54:57 +00:00
WM_SETFOCUS or WM_KILLFOCUS messages when they get or lose
the focus . ( For a workaround , see milkdrop & scroll lock key . )
- kiv : tiny bug ( IGNORE ) : when switching between embedwnd &
no - embedding , the window gets scooted a tiny tiny bit .
- kiv : fake fullscreen mode w / multiple monitors : there is no way
to keep the taskbar from popping up [ potentially overtop of
the plugin ] when you click on something besides the plugin .
To get around this , use true fullscreen mode .
- kiv : max_fps implementation assumptions :
- that most computers support high - precision timer
- that no computers [ regularly ] sleep for more than 1 - 2 ms
when you call Sleep ( 1 ) after timeBeginPeriod ( 1 ) .
- reminder : if vms_desktop . dll ' s interface needs changed ,
it will have to be renamed ! ( version # upgrades are ok
as long as it won ' t break on an old version ; if the
new functionality is essential , rename the DLL . )
- - - - - - - - - - - - - - - - - - - - - - - - - - -
REMEMBER :
- GF2MX + GF4 have icon scooting probs in desktop mode
( when taskbar is on upper or left edge of screen )
- Radeon is the one w / super slow text probs @ 1280 x1024 .
( it goes unstable after you show playlist AND helpscr ; - > ~ 1 fps )
- Mark ' s win98 machine has hidden cursor ( in all modes ) ,
but no one else seems to have this problem .
- links :
- win2k - only - style desktop mode : ( uses VirtualAllocEx , vs . DLL Injection )
http : //www.digiwar.com/scripts/renderpage.php?section=2&subsection=2
- http : //www.experts-exchange.com/Programming/Programming_Platforms/Win_Prog/Q_20096218.html
*/
# include "api__vis_milk2.h"
# include "pluginshell.h"
# include "utility.h"
# include "defines.h"
# include "shell_defines.h"
# include "resource.h"
# include "vis.h"
# include <multimon.h>
# include "../Winamp/wa_ipc.h"
# include "../nu/AutoCharFn.h"
# include <mmsystem.h>
# pragma comment(lib,"winmm.lib") // for timeGetTime
// STATE VALUES & VERTEX FORMATS FOR HELP SCREEN TEXTURE:
# define TEXT_SURFACE_NOT_READY 0
# define TEXT_SURFACE_REQUESTED 1
# define TEXT_SURFACE_READY 2
# define TEXT_SURFACE_ERROR 3
typedef struct _HELPVERTEX
{
float x , y ; // screen position
float z ; // Z-buffer depth
DWORD Diffuse ; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims)
float tu , tv ; // texture coordinates for texture #0
} HELPVERTEX , * LPHELPVERTEX ;
# define HELP_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
typedef struct _SIMPLEVERTEX
{
float x , y ; // screen position
float z ; // Z-buffer depth
DWORD Diffuse ; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims)
} SIMPLEVERTEX , * LPSIMPLEVERTEX ;
# define SIMPLE_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE)
extern wchar_t * g_szHelp ;
extern int g_szHelp_W ;
extern winampVisModule mod1 ;
// resides in vms_desktop.dll/lib:
void getItemData ( int x ) ;
CPluginShell : : CPluginShell ( )
{
// this should remain empty!
}
CPluginShell : : ~ CPluginShell ( )
{
// this should remain empty!
}
eScrMode CPluginShell : : GetScreenMode ( )
{
return m_screenmode ;
}
int CPluginShell : : GetFrame ( )
{
return m_frame ;
}
float CPluginShell : : GetTime ( )
{
return m_time ;
}
float CPluginShell : : GetFps ( )
{
return m_fps ;
}
HWND CPluginShell : : GetPluginWindow ( )
{
if ( m_lpDX ) return m_lpDX - > GetHwnd ( ) ; else return NULL ;
}
int CPluginShell : : GetWidth ( )
{
if ( m_lpDX ) return m_lpDX - > m_client_width ; else return 0 ;
}
int CPluginShell : : GetHeight ( )
{
if ( m_lpDX ) return m_lpDX - > m_client_height ; else return 0 ;
}
int CPluginShell : : GetCanvasMarginX ( )
{
if ( m_lpDX & & m_screenmode = = WINDOWED ) return ( m_lpDX - > m_client_width - m_lpDX - > m_REAL_client_width ) / 2 ; else return 0 ;
}
int CPluginShell : : GetCanvasMarginY ( )
{
if ( m_lpDX & & m_screenmode = = WINDOWED ) return ( m_lpDX - > m_client_height - m_lpDX - > m_REAL_client_height ) / 2 ; else return 0 ;
}
HWND CPluginShell : : GetWinampWindow ( )
{
return m_hWndWinamp ;
}
HINSTANCE CPluginShell : : GetInstance ( )
{
return m_hInstance ;
}
wchar_t * CPluginShell : : GetPluginsDirPath ( )
{
return m_szPluginsDirPath ;
}
wchar_t * CPluginShell : : GetConfigIniFile ( )
{
return m_szConfigIniFile ;
}
char * CPluginShell : : GetConfigIniFileA ( )
{
return m_szConfigIniFileA ;
}
int CPluginShell : : GetFontHeight ( eFontIndex idx )
{
if ( idx > = 0 & & idx < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ) return m_fontinfo [ idx ] . nSize ; else return 0 ;
}
int CPluginShell : : GetBitDepth ( )
{
return m_lpDX - > GetBitDepth ( ) ;
}
LPDIRECT3DDEVICE9 CPluginShell : : GetDevice ( )
{
if ( m_lpDX ) return m_lpDX - > m_lpDevice ; else return NULL ;
}
D3DCAPS9 * CPluginShell : : GetCaps ( )
{
if ( m_lpDX ) return & ( m_lpDX - > m_caps ) ; else return NULL ;
}
D3DFORMAT CPluginShell : : GetBackBufFormat ( )
{
if ( m_lpDX ) return m_lpDX - > m_current_mode . display_mode . Format ; else return D3DFMT_UNKNOWN ;
}
D3DFORMAT CPluginShell : : GetBackBufZFormat ( )
{
if ( m_lpDX ) return m_lpDX - > GetZFormat ( ) ; else return D3DFMT_UNKNOWN ;
}
LPD3DXFONT CPluginShell : : GetFont ( eFontIndex idx )
{
if ( idx > = 0 & & idx < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ) return m_d3dx_font [ idx ] ; else return NULL ;
}
char * CPluginShell : : GetDriverFilename ( )
{
if ( m_lpDX ) return m_lpDX - > GetDriver ( ) ; else return NULL ;
}
char * CPluginShell : : GetDriverDescription ( )
{
if ( m_lpDX ) return m_lpDX - > GetDesc ( ) ; else return NULL ;
}
int CPluginShell : : InitNondx9Stuff ( )
{
timeBeginPeriod ( 1 ) ;
m_fftobj . Init ( 576 , NUM_FREQUENCIES ) ;
if ( ! InitGDIStuff ( ) ) return false ;
return AllocateMyNonDx9Stuff ( ) ;
}
void CPluginShell : : CleanUpNondx9Stuff ( )
{
timeEndPeriod ( 1 ) ;
CleanUpMyNonDx9Stuff ( ) ;
CleanUpGDIStuff ( ) ;
m_fftobj . CleanUp ( ) ;
}
int CPluginShell : : InitGDIStuff ( )
{
wchar_t title [ 64 ] ;
// note: messagebox parent window should be NULL here, because lpDX is still NULL!
for ( int i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
{
if ( ! ( m_font [ i ] = CreateFontW ( m_fontinfo [ i ] . nSize , 0 , 0 , 0 , m_fontinfo [ i ] . bBold ? 900 : 400 , m_fontinfo [ i ] . bItalic , FALSE , FALSE , DEFAULT_CHARSET , OUT_DEFAULT_PRECIS , CLIP_DEFAULT_PRECIS , m_fontinfo [ i ] . bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY , DEFAULT_PITCH , m_fontinfo [ i ] . szFace ) ) )
{
MessageBoxW ( NULL , WASABI_API_LNGSTRINGW ( IDS_ERROR_CREATING_GDI_FONTS ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
}
if ( ! ( m_main_menu = WASABI_API_LOADMENU ( IDR_WINDOWED_CONTEXT_MENU ) ) )
{
MessageBoxW ( NULL , WASABI_API_LNGSTRINGW ( IDS_ERROR_LOADING_MAIN_MENU ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
if ( ! ( m_context_menu = GetSubMenu ( m_main_menu , 0 ) ) )
{
MessageBoxW ( NULL , WASABI_API_LNGSTRINGW ( IDS_ERROR_LOADING_CONTEXT_MENU ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
return true ;
}
void CPluginShell : : CleanUpGDIStuff ( )
{
for ( int i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
{
if ( m_font [ i ] )
{
DeleteObject ( m_font [ i ] ) ;
m_font [ i ] = NULL ;
}
}
/*if (m_context_menu)
{
DestroyMenu ( m_context_menu ) ;
m_context_menu = NULL ;
} */
if ( m_main_menu )
{
DestroyMenu ( m_main_menu ) ;
m_main_menu = NULL ;
}
//CleanUpMyGDIStuff();
}
int CPluginShell : : InitVJStuff ( RECT * pClientRect )
{
wchar_t title [ 64 ] ;
// Init VJ mode (second window for text):
if ( m_vj_mode )
{
DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU ;
POINT upper_left_corner ;
upper_left_corner . x = 0 ;
upper_left_corner . y = 0 ;
// Create direct 3d & get some infos
if ( ! ( m_vjd3d9 = Direct3DCreate9 ( D3D_SDK_VERSION ) ) )
{
MessageBoxW ( NULL , WASABI_API_LNGSTRINGW ( IDS_ERROR_CREATING_DIRECT3D_DEVICE_FOR_VJ_MODE ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) , MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
// Get ordinal adapter # for the currently-selected Windowed Mode display adapter
int ordinal_adapter = D3DADAPTER_DEFAULT ;
int nAdapters = m_vjd3d9 - > GetAdapterCount ( ) ;
for ( int i = 0 ; i < nAdapters ; i + + )
{
D3DADAPTER_IDENTIFIER9 temp ;
if ( ( m_vjd3d9 - > GetAdapterIdentifier ( i , /*D3DENUM_NO_WHQL_LEVEL*/ 0 , & temp ) = = D3D_OK ) & &
( memcmp ( & temp . DeviceIdentifier , & m_adapter_guid_windowed , sizeof ( GUID ) ) = = 0 ) )
{
ordinal_adapter = i ;
break ;
}
}
// Get current display mode for windowed-mode adapter:
D3DDISPLAYMODE dm ;
if ( D3D_OK ! = m_vjd3d9 - > GetAdapterDisplayMode ( ordinal_adapter , & dm ) )
{
MessageBoxW ( NULL , WASABI_API_LNGSTRINGW ( IDS_VJ_MODE_INIT_ERROR ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
// And get the upper-left corner of the monitor for it:
HMONITOR hMon = m_vjd3d9 - > GetAdapterMonitor ( ordinal_adapter ) ;
if ( hMon )
{
MONITORINFO mi ;
mi . cbSize = sizeof ( mi ) ;
if ( GetMonitorInfo ( hMon , & mi ) )
{
upper_left_corner . x = mi . rcWork . left ;
upper_left_corner . y = mi . rcWork . top ;
}
}
// CREATE THE WINDOW
RECT rect ;
if ( pClientRect )
{
rect = * pClientRect ;
AdjustWindowRect ( & rect , dwStyle , 0 ) ; // convert client->wnd
}
else
{
SetRect ( & rect , 0 , 0 , 384 , 384 ) ;
AdjustWindowRect ( & rect , dwStyle , 0 ) ; // convert client->wnd
rect . right - = rect . left ;
rect . left = 0 ;
rect . bottom - = rect . top ;
rect . top = 0 ;
rect . top + = upper_left_corner . y + 32 ;
rect . left + = upper_left_corner . x + 32 ;
rect . right + = upper_left_corner . x + 32 ;
rect . bottom + = upper_left_corner . y + 32 ;
}
WNDCLASS wc = { 0 } ;
wc . lpfnWndProc = VJModeWndProc ; // our window procedure
wc . hInstance = GetInstance ( ) ; // hInstance of DLL
wc . hIcon = LoadIcon ( GetInstance ( ) , MAKEINTRESOURCE ( IDI_PLUGIN_ICON ) ) ;
wc . lpszClassName = TEXT_WINDOW_CLASSNAME ; // our window class name
wc . style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ; // CS_DBLCLKS lets the window receive WM_LBUTTONDBLCLK, for toggling fullscreen mode...
wc . cbWndExtra = sizeof ( DWORD ) ;
wc . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
wc . hbrBackground = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;
if ( ! RegisterClass ( & wc ) )
{
MessageBoxW ( NULL , WASABI_API_LNGSTRINGW ( IDS_ERROR_REGISTERING_WINDOW_CLASS_FOR_TEXT_WINDOW ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
m_bTextWindowClassRegistered = true ;
//DWORD nThreadID;
//CreateThread(NULL, 0, TextWindowThread, &rect, 0, &nThreadID);
// Create the text window
m_hTextWnd = CreateWindowEx (
0 ,
TEXT_WINDOW_CLASSNAME , // our window class name
TEXT_WINDOW_CLASSNAME , // use description for a window title
dwStyle ,
rect . left , rect . top , // screen position (read from config)
rect . right - rect . left , rect . bottom - rect . top , // width & height of window (need to adjust client area later)
NULL , // parent window (winamp main window)
NULL , // no menu
GetInstance ( ) , // hInstance of DLL
NULL
) ; // no window creation data
if ( ! m_hTextWnd )
{
MessageBoxW ( NULL , WASABI_API_LNGSTRINGW ( IDS_ERROR_CREATING_VJ_WINDOW ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
SetWindowLongPtr ( m_hTextWnd , GWLP_USERDATA , ( LONG_PTR ) this ) ;
GetClientRect ( m_hTextWnd , & rect ) ;
m_nTextWndWidth = rect . right - rect . left ;
m_nTextWndHeight = rect . bottom - rect . top ;
// Create the device
D3DPRESENT_PARAMETERS pres_param ;
ZeroMemory ( & pres_param , sizeof ( pres_param ) ) ;
pres_param . BackBufferCount = 0 ;
pres_param . BackBufferFormat = dm . Format ;
pres_param . BackBufferWidth = rect . right - rect . left ;
pres_param . BackBufferHeight = rect . bottom - rect . top ;
pres_param . hDeviceWindow = m_hTextWnd ;
pres_param . AutoDepthStencilFormat = D3DFMT_D16 ;
pres_param . EnableAutoDepthStencil = FALSE ;
pres_param . SwapEffect = D3DSWAPEFFECT_DISCARD ;
pres_param . MultiSampleType = D3DMULTISAMPLE_NONE ;
pres_param . Flags = 0 ;
pres_param . FullScreen_RefreshRateInHz = 0 ;
pres_param . PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE ; //D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//m_current_mode.allow_page_tearing ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//D3DPRESENT_INTERVAL_ONE;
//pres_param.FullScreen_PresentationInterval = 0;
pres_param . Windowed = TRUE ;
HRESULT hr ;
if ( D3D_OK ! = ( hr = m_vjd3d9 - > CreateDevice ( ordinal_adapter , //D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL ,
m_hTextWnd ,
D3DCREATE_SOFTWARE_VERTEXPROCESSING ,
& pres_param ,
& m_vjd3d9_device ) ) )
{
m_vjd3d9_device = NULL ;
MessageBoxW ( m_lpDX - > GetHwnd ( ) , WASABI_API_LNGSTRINGW ( IDS_ERROR_CREATING_D3D_DEVICE_FOR_VJ_MODE ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
if ( ! AllocateFonts ( m_vjd3d9_device ) )
return false ;
if ( m_fix_slow_text ) // note that when not doing vj mode, m_lpDDSText is allocated in AllocateDX9Stuff
AllocateTextSurface ( ) ;
m_text . Finish ( ) ;
m_text . Init ( m_vjd3d9_device , m_lpDDSText , 0 ) ;
m_bClearVJWindow = true ;
}
return true ;
}
void CPluginShell : : CleanUpVJStuff ( )
{
// ALWAYS set the textures to NULL before releasing textures,
// otherwise they might still have a hanging reference!
if ( m_lpDX & & m_lpDX - > m_lpDevice )
{
for ( int i = 0 ; i < 16 ; i + + )
m_lpDX - > m_lpDevice - > SetTexture ( i , NULL ) ;
}
if ( m_vjd3d9_device )
{
for ( int i = 0 ; i < 16 ; i + + )
m_vjd3d9_device - > SetTexture ( i , NULL ) ;
}
if ( ! m_vj_mode )
return ;
// clean up VJ mode
{
CleanUpFonts ( ) ;
SafeRelease ( m_lpDDSText ) ;
SafeRelease ( m_vjd3d9_device ) ;
SafeRelease ( m_vjd3d9 ) ;
if ( m_hTextWnd )
{
//dumpmsg("Finish: destroying text window");
DestroyWindow ( m_hTextWnd ) ;
m_hTextWnd = NULL ;
//dumpmsg("Finish: text window destroyed");
}
if ( m_bTextWindowClassRegistered )
{
//dumpmsg("Finish: unregistering text window class");
UnregisterClass ( TEXT_WINDOW_CLASSNAME , GetInstance ( ) ) ; // unregister window class
m_bTextWindowClassRegistered = false ;
//dumpmsg("Finish: text window class unregistered");
}
}
}
int CPluginShell : : AllocateFonts ( IDirect3DDevice9 * pDevice )
{
// Create D3DX system font:
for ( int i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
if ( pCreateFontW ( pDevice , //m_font[i],
m_fontinfo [ i ] . nSize ,
m_fontinfo [ i ] . nSize * 4 / 10 ,
m_fontinfo [ i ] . bBold ? 900 : 400 ,
1 , // mip levels
m_fontinfo [ i ] . bItalic ,
DEFAULT_CHARSET ,
OUT_DEFAULT_PRECIS ,
m_fontinfo [ i ] . bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY ,
DEFAULT_PITCH ,
m_fontinfo [ i ] . szFace ,
& m_d3dx_font [ i ]
) ! = D3D_OK )
{
wchar_t title [ 64 ] ;
MessageBoxW ( m_lpDX ? m_lpDX - > GetHwnd ( ) : NULL , WASABI_API_LNGSTRINGW ( IDS_ERROR_CREATING_D3DX_FONTS ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
// get actual font heights
for ( int i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
{
RECT r ;
SetRect ( & r , 0 , 0 , 1024 , 1024 ) ;
int h = m_d3dx_font [ i ] - > DrawText ( NULL , " M " , - 1 , & r , DT_CALCRECT , 0xFFFFFFFF ) ;
if ( h > 0 ) m_fontinfo [ i ] . nSize = h ;
}
return true ;
}
void CPluginShell : : CleanUpFonts ( )
{
for ( int i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
SafeRelease ( m_d3dx_font [ i ] ) ;
}
void CPluginShell : : AllocateTextSurface ( )
{
IDirect3DDevice9 * pDevice = m_vjd3d9_device ? m_vjd3d9_device : GetDevice ( ) ;
int w = m_vjd3d9_device ? m_nTextWndWidth : GetWidth ( ) ;
int h = m_vjd3d9_device ? m_nTextWndHeight : GetHeight ( ) ;
if ( D3D_OK ! = pCreateTexture ( pDevice , w , h , 1 , D3DUSAGE_RENDERTARGET , GetBackBufFormat ( ) , D3DPOOL_DEFAULT , & m_lpDDSText ) )
m_lpDDSText = NULL ; // OK if there's not enough mem for it!
else
{
// if m_lpDDSText doesn't cover enough of screen, cancel it.
D3DSURFACE_DESC desc ;
if ( D3D_OK = = m_lpDDSText - > GetLevelDesc ( 0 , & desc ) )
{
if ( ( desc . Width < 256 & & w > = 256 ) | |
( desc . Height < 256 & & h > = 256 ) | |
( desc . Width / ( float ) w < 0.74f ) | |
( desc . Height / ( float ) h < 0.74f )
)
{
m_lpDDSText - > Release ( ) ;
m_lpDDSText = NULL ;
}
}
}
}
int CPluginShell : : AllocateDX9Stuff ( )
{
if ( ! m_vj_mode )
{
AllocateFonts ( m_lpDX - > m_lpDevice ) ;
if ( m_fix_slow_text ) // note that when not doing vj mode, m_lpDDSText is allocated in AllocateDX9Stuff
AllocateTextSurface ( ) ;
}
/*
// Create D3DX system font:
for ( int i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
if ( pCreateFontW ( m_lpDX - > m_lpDevice ,
m_fontinfo [ i ] . nSize ,
m_fontinfo [ i ] . nSize * 4 / 10 ,
m_fontinfo [ i ] . bBold ? 900 : 400 ,
0 , // mip levels
m_fontinfo [ i ] . bItalic ,
DEFAULT_CHARSET ,
OUT_DEFAULT_PRECIS ,
m_fontinfo [ i ] . bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY ,
DEFAULT_PITCH ,
m_fontinfo [ i ] . szFace ,
& m_d3dx_font [ i ]
) ! = D3D_OK )
{
MessageBox ( m_lpDX - > GetHwnd ( ) , " Error creating D3DX fonts " , " ERROR " , MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return false ;
}
// get actual font heights
for ( i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
{
RECT r ;
SetRect ( & r , 0 , 0 , 1024 , 1024 ) ;
int h = m_d3dx_font [ i ] - > DrawText ( NULL , " M " , - 1 , & r , DT_CALCRECT , 0xFFFFFFFF ) ;
if ( h > 0 ) m_fontinfo [ i ] . nSize = h ;
}
*/
if ( m_screenmode = = DESKTOP )
if ( ! InitDesktopMode ( ) )
return false ;
int ret = AllocateMyDX9Stuff ( ) ;
// invalidate various 'caches' here:
m_playlist_top_idx = - 1 ; // invalidating playlist cache forces recompute of playlist width
//m_icon_list.clear(); // clear desktop mode icon list, so it has to read the bitmaps back in
if ( ! m_vj_mode )
{
m_text . Finish ( ) ;
m_text . Init ( GetDevice ( ) , m_lpDDSText , 1 ) ;
}
return ret ;
}
void CPluginShell : : CleanUpDX9Stuff ( int final_cleanup )
{
// ALWAYS unbind the textures before releasing textures,
// otherwise they might still have a hanging reference!
if ( m_lpDX & & m_lpDX - > m_lpDevice )
{
for ( int i = 0 ; i < 16 ; i + + )
m_lpDX - > m_lpDevice - > SetTexture ( i , NULL ) ;
}
if ( m_screenmode = = DESKTOP )
CleanUpDesktopMode ( ) ;
if ( ! m_vj_mode )
{
for ( int i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
SafeRelease ( m_d3dx_font [ i ] ) ;
SafeRelease ( m_lpDDSText ) ;
}
CleanUpMyDX9Stuff ( final_cleanup ) ;
}
void CPluginShell : : OnUserResizeTextWindow ( )
{
// Update window properties
RECT w , c ;
GetWindowRect ( m_hTextWnd , & w ) ;
GetClientRect ( m_hTextWnd , & c ) ;
WINDOWPLACEMENT wp ;
ZeroMemory ( & wp , sizeof ( wp ) ) ;
wp . length = sizeof ( wp ) ;
GetWindowPlacement ( m_hTextWnd , & wp ) ;
// convert client rect from client coords to screen coords:
// (window rect is already in screen coords...)
POINT p ;
p . x = c . left ;
p . y = c . top ;
if ( ClientToScreen ( m_hTextWnd , & p ) )
{
c . left + = p . x ;
c . right + = p . x ;
c . top + = p . y ;
c . bottom + = p . y ;
}
if ( wp . showCmd ! = SW_SHOWMINIMIZED )
{
if ( m_nTextWndWidth ! = c . right - c . left | |
m_nTextWndHeight ! = c . bottom - c . top )
{
CleanUpVJStuff ( ) ;
if ( ! InitVJStuff ( & c ) )
{
SuggestHowToFreeSomeMem ( ) ;
m_lpDX - > m_ready = false ; // flag to exit
return ;
}
}
// save the new window position:
//if (wp.showCmd==SW_SHOWNORMAL)
// SaveTextWindowPos();
}
}
void CPluginShell : : OnUserResizeWindow ( )
{
// Update window properties
RECT w , c ;
GetWindowRect ( m_lpDX - > GetHwnd ( ) , & w ) ;
GetClientRect ( m_lpDX - > GetHwnd ( ) , & c ) ;
WINDOWPLACEMENT wp ;
ZeroMemory ( & wp , sizeof ( wp ) ) ;
wp . length = sizeof ( wp ) ;
GetWindowPlacement ( m_lpDX - > GetHwnd ( ) , & wp ) ;
// convert client rect from client coords to screen coords:
// (window rect is already in screen coords...)
POINT p ;
p . x = c . left ;
p . y = c . top ;
if ( ClientToScreen ( m_lpDX - > GetHwnd ( ) , & p ) )
{
c . left + = p . x ;
c . right + = p . x ;
c . top + = p . y ;
c . bottom + = p . y ;
}
if ( wp . showCmd ! = SW_SHOWMINIMIZED )
{
int new_REAL_client_w = c . right - c . left ;
int new_REAL_client_h = c . bottom - c . top ;
// kiv: could we just resize when the *snapped* w/h changes? slightly more ideal...
if ( m_lpDX - > m_REAL_client_width ! = new_REAL_client_w | |
m_lpDX - > m_REAL_client_height ! = new_REAL_client_h )
{
//CleanUpVJStuff();
CleanUpDX9Stuff ( 0 ) ;
if ( ! m_lpDX - > OnUserResizeWindow ( & w , & c ) )
{
// note: a basic warning messagebox will have already been given.
// now suggest specific advice on how to regain more video memory:
SuggestHowToFreeSomeMem ( ) ;
return ;
}
if ( ! AllocateDX9Stuff ( ) )
{
m_lpDX - > m_ready = false ; // flag to exit
return ;
}
/*if (!InitVJStuff())
{
m_lpDX - > m_ready = false ; // flag to exit
return ;
} */
}
// save the new window position:
if ( wp . showCmd = = SW_SHOWNORMAL )
m_lpDX - > SaveWindow ( ) ;
}
}
void CPluginShell : : StuffParams ( DXCONTEXT_PARAMS * pParams )
{
pParams - > screenmode = m_screenmode ;
pParams - > display_mode = m_disp_mode_fs ;
pParams - > nbackbuf = 1 ;
pParams - > m_dualhead_horz = m_dualhead_horz ;
pParams - > m_dualhead_vert = m_dualhead_vert ;
pParams - > m_skin = ( m_screenmode = = WINDOWED ) ? m_skin : 0 ;
switch ( m_screenmode )
{
case WINDOWED :
pParams - > allow_page_tearing = m_allow_page_tearing_w ;
pParams - > adapter_guid = m_adapter_guid_windowed ;
pParams - > multisamp = m_multisample_windowed ;
strcpy ( pParams - > adapter_devicename , m_adapter_devicename_windowed ) ;
break ;
case FULLSCREEN :
case FAKE_FULLSCREEN :
pParams - > allow_page_tearing = m_allow_page_tearing_fs ;
pParams - > adapter_guid = m_adapter_guid_fullscreen ;
pParams - > multisamp = m_multisample_fullscreen ;
strcpy ( pParams - > adapter_devicename , m_adapter_devicename_fullscreen ) ;
break ;
case DESKTOP :
pParams - > allow_page_tearing = m_allow_page_tearing_dm ;
pParams - > adapter_guid = m_adapter_guid_desktop ;
pParams - > multisamp = m_multisample_desktop ;
strcpy ( pParams - > adapter_devicename , m_adapter_devicename_desktop ) ;
break ;
}
pParams - > parent_window = ( m_screenmode = = DESKTOP ) ? m_hWndDesktopListView : NULL ;
}
void CPluginShell : : ToggleDesktop ( )
{
CleanUpDX9Stuff ( 0 ) ;
switch ( m_screenmode )
{
case WINDOWED :
case FULLSCREEN :
case FAKE_FULLSCREEN :
m_screenmode = DESKTOP ;
break ;
case DESKTOP :
m_screenmode = WINDOWED ;
break ;
}
DXCONTEXT_PARAMS params ;
StuffParams ( & params ) ;
if ( ! m_lpDX - > StartOrRestartDevice ( & params ) )
{
// note: a basic warning messagebox will have already been given.
if ( m_lpDX - > m_lastErr = = DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY )
SuggestHowToFreeSomeMem ( ) ;
return ;
}
if ( ! AllocateDX9Stuff ( ) )
{
m_lpDX - > m_ready = false ; // flag to exit
return ;
}
SetForegroundWindow ( m_lpDX - > GetHwnd ( ) ) ;
SetActiveWindow ( m_lpDX - > GetHwnd ( ) ) ;
SetFocus ( m_lpDX - > GetHwnd ( ) ) ;
}
# define IPC_IS_PLAYING_VIDEO 501 // from wa_ipc.h
# define IPC_SET_VIS_FS_FLAG 631 // a vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode
void CPluginShell : : ToggleFullScreen ( )
{
CleanUpDX9Stuff ( 0 ) ;
switch ( m_screenmode )
{
case DESKTOP :
case WINDOWED :
m_screenmode = m_fake_fullscreen_mode ? FAKE_FULLSCREEN : FULLSCREEN ;
if ( m_screenmode = = FULLSCREEN & & SendMessage ( GetWinampWindow ( ) , WM_WA_IPC , 0 , IPC_IS_PLAYING_VIDEO ) > 1 )
{
m_screenmode = FAKE_FULLSCREEN ;
}
SendMessage ( GetWinampWindow ( ) , WM_WA_IPC , 1 , IPC_SET_VIS_FS_FLAG ) ;
break ;
case FULLSCREEN :
case FAKE_FULLSCREEN :
m_screenmode = WINDOWED ;
SendMessage ( GetWinampWindow ( ) , WM_WA_IPC , 0 , IPC_SET_VIS_FS_FLAG ) ;
break ;
}
DXCONTEXT_PARAMS params ;
StuffParams ( & params ) ;
if ( ! m_lpDX - > StartOrRestartDevice ( & params ) )
{
// note: a basic warning messagebox will have already been given.
if ( m_lpDX - > m_lastErr = = DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY )
SuggestHowToFreeSomeMem ( ) ;
return ;
}
if ( ! AllocateDX9Stuff ( ) )
{
m_lpDX - > m_ready = false ; // flag to exit
return ;
}
SetForegroundWindow ( m_lpDX - > GetHwnd ( ) ) ;
SetActiveWindow ( m_lpDX - > GetHwnd ( ) ) ;
SetFocus ( m_lpDX - > GetHwnd ( ) ) ;
}
void CPluginShell : : ToggleHelp ( )
{
m_show_help = 1 - m_show_help ;
int ret = CheckMenuItem ( m_context_menu , ID_SHOWHELP , MF_BYCOMMAND | ( m_show_help ? MF_CHECKED : MF_UNCHECKED ) ) ;
}
void CPluginShell : : TogglePlaylist ( )
{
m_show_playlist = 1 - m_show_playlist ;
m_playlist_top_idx = - 1 ; // <- invalidates playlist cache
int ret = CheckMenuItem ( m_context_menu , ID_SHOWPLAYLIST , MF_BYCOMMAND | ( m_show_playlist ? MF_CHECKED : MF_UNCHECKED ) ) ;
}
int CPluginShell : : InitDirectX ( )
{
m_lpDX = new DXContext ( m_hWndWinamp , m_hInstance , CLASSNAME , WINDOWCAPTION , CPluginShell : : WindowProc , ( LONG_PTR ) this , m_minimize_winamp , m_szConfigIniFile ) ;
if ( ! m_lpDX )
{
wchar_t title [ 64 ] ;
MessageBoxW ( NULL , WASABI_API_LNGSTRINGW ( IDS_UNABLE_TO_INIT_DXCONTEXT ) ,
WASABI_API_LNGSTRINGW_BUF ( IDS_MILKDROP_ERROR , title , 64 ) ,
MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
return FALSE ;
}
if ( m_lpDX - > m_lastErr ! = S_OK )
{
// warning messagebox will have already been given
delete m_lpDX ;
return FALSE ;
}
// initialize graphics
DXCONTEXT_PARAMS params ;
StuffParams ( & params ) ;
if ( ! m_lpDX - > StartOrRestartDevice ( & params ) )
{
// note: a basic warning messagebox will have already been given.
if ( m_lpDX - > m_lastErr = = DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY )
{
// suggest specific advice on how to regain more video memory:
SuggestHowToFreeSomeMem ( ) ;
}
delete m_lpDX ;
m_lpDX = NULL ;
return FALSE ;
}
return TRUE ;
}
void CPluginShell : : CleanUpDirectX ( )
{
SafeDelete ( m_lpDX ) ;
}
int CPluginShell : : PluginPreInitialize ( HWND hWinampWnd , HINSTANCE hWinampInstance )
{
// PROTECTED CONFIG PANEL SETTINGS (also see 'private' settings, below)
m_start_fullscreen = 0 ;
m_start_desktop = 0 ;
m_fake_fullscreen_mode = 0 ;
m_max_fps_fs = 30 ;
m_max_fps_dm = 30 ;
m_max_fps_w = 30 ;
m_show_press_f1_msg = 1 ;
m_allow_page_tearing_w = 1 ;
m_allow_page_tearing_fs = 0 ;
m_allow_page_tearing_dm = 0 ;
m_minimize_winamp = 1 ;
m_desktop_show_icons = 1 ;
m_desktop_textlabel_boxes = 1 ;
m_desktop_manual_icon_scoot = 0 ;
m_desktop_555_fix = 2 ;
m_dualhead_horz = 2 ;
m_dualhead_vert = 1 ;
m_save_cpu = 1 ;
m_skin = 1 ;
m_fix_slow_text = 0 ;
// initialize font settings:
wcscpy ( m_fontinfo [ SIMPLE_FONT ] . szFace , SIMPLE_FONT_DEFAULT_FACE ) ;
m_fontinfo [ SIMPLE_FONT ] . nSize = SIMPLE_FONT_DEFAULT_SIZE ;
m_fontinfo [ SIMPLE_FONT ] . bBold = SIMPLE_FONT_DEFAULT_BOLD ;
m_fontinfo [ SIMPLE_FONT ] . bItalic = SIMPLE_FONT_DEFAULT_ITAL ;
m_fontinfo [ SIMPLE_FONT ] . bAntiAliased = SIMPLE_FONT_DEFAULT_AA ;
wcscpy ( m_fontinfo [ DECORATIVE_FONT ] . szFace , DECORATIVE_FONT_DEFAULT_FACE ) ;
m_fontinfo [ DECORATIVE_FONT ] . nSize = DECORATIVE_FONT_DEFAULT_SIZE ;
m_fontinfo [ DECORATIVE_FONT ] . bBold = DECORATIVE_FONT_DEFAULT_BOLD ;
m_fontinfo [ DECORATIVE_FONT ] . bItalic = DECORATIVE_FONT_DEFAULT_ITAL ;
m_fontinfo [ DECORATIVE_FONT ] . bAntiAliased = DECORATIVE_FONT_DEFAULT_AA ;
wcscpy ( m_fontinfo [ HELPSCREEN_FONT ] . szFace , HELPSCREEN_FONT_DEFAULT_FACE ) ;
m_fontinfo [ HELPSCREEN_FONT ] . nSize = HELPSCREEN_FONT_DEFAULT_SIZE ;
m_fontinfo [ HELPSCREEN_FONT ] . bBold = HELPSCREEN_FONT_DEFAULT_BOLD ;
m_fontinfo [ HELPSCREEN_FONT ] . bItalic = HELPSCREEN_FONT_DEFAULT_ITAL ;
m_fontinfo [ HELPSCREEN_FONT ] . bAntiAliased = HELPSCREEN_FONT_DEFAULT_AA ;
wcscpy ( m_fontinfo [ PLAYLIST_FONT ] . szFace , PLAYLIST_FONT_DEFAULT_FACE ) ;
m_fontinfo [ PLAYLIST_FONT ] . nSize = PLAYLIST_FONT_DEFAULT_SIZE ;
m_fontinfo [ PLAYLIST_FONT ] . bBold = PLAYLIST_FONT_DEFAULT_BOLD ;
m_fontinfo [ PLAYLIST_FONT ] . bItalic = PLAYLIST_FONT_DEFAULT_ITAL ;
m_fontinfo [ PLAYLIST_FONT ] . bAntiAliased = PLAYLIST_FONT_DEFAULT_AA ;
# if (NUM_EXTRA_FONTS >= 1)
wcscpy ( m_fontinfo [ NUM_BASIC_FONTS + 0 ] . szFace , EXTRA_FONT_1_DEFAULT_FACE ) ;
m_fontinfo [ NUM_BASIC_FONTS + 0 ] . nSize = EXTRA_FONT_1_DEFAULT_SIZE ;
m_fontinfo [ NUM_BASIC_FONTS + 0 ] . bBold = EXTRA_FONT_1_DEFAULT_BOLD ;
m_fontinfo [ NUM_BASIC_FONTS + 0 ] . bItalic = EXTRA_FONT_1_DEFAULT_ITAL ;
m_fontinfo [ NUM_BASIC_FONTS + 0 ] . bAntiAliased = EXTRA_FONT_1_DEFAULT_AA ;
# endif
# if (NUM_EXTRA_FONTS >= 2)
wcscpy ( m_fontinfo [ NUM_BASIC_FONTS + 1 ] . szFace , EXTRA_FONT_2_DEFAULT_FACE ) ;
m_fontinfo [ NUM_BASIC_FONTS + 1 ] . nSize = EXTRA_FONT_2_DEFAULT_SIZE ;
m_fontinfo [ NUM_BASIC_FONTS + 1 ] . bBold = EXTRA_FONT_2_DEFAULT_BOLD ;
m_fontinfo [ NUM_BASIC_FONTS + 1 ] . bItalic = EXTRA_FONT_2_DEFAULT_ITAL ;
m_fontinfo [ NUM_BASIC_FONTS + 1 ] . bAntiAliased = EXTRA_FONT_2_DEFAULT_AA ;
# endif
# if (NUM_EXTRA_FONTS >= 3)
strcpy ( m_fontinfo [ NUM_BASIC_FONTS + 2 ] . szFace , EXTRA_FONT_3_DEFAULT_FACE ) ;
m_fontinfo [ NUM_BASIC_FONTS + 2 ] . nSize = EXTRA_FONT_3_DEFAULT_SIZE ;
m_fontinfo [ NUM_BASIC_FONTS + 2 ] . bBold = EXTRA_FONT_3_DEFAULT_BOLD ;
m_fontinfo [ NUM_BASIC_FONTS + 2 ] . bItalic = EXTRA_FONT_3_DEFAULT_ITAL ;
m_fontinfo [ NUM_BASIC_FONTS + 2 ] . bAntiAliased = EXTRA_FONT_3_DEFAULT_AA ;
# endif
# if (NUM_EXTRA_FONTS >= 4)
strcpy ( m_fontinfo [ NUM_BASIC_FONTS + 3 ] . szFace , EXTRA_FONT_4_DEFAULT_FACE ) ;
m_fontinfo [ NUM_BASIC_FONTS + 3 ] . nSize = EXTRA_FONT_4_DEFAULT_SIZE ;
m_fontinfo [ NUM_BASIC_FONTS + 3 ] . bBold = EXTRA_FONT_4_DEFAULT_BOLD ;
m_fontinfo [ NUM_BASIC_FONTS + 3 ] . bItalic = EXTRA_FONT_4_DEFAULT_ITAL ;
m_fontinfo [ NUM_BASIC_FONTS + 3 ] . bAntiAliased = EXTRA_FONT_4_DEFAULT_AA ;
# endif
# if (NUM_EXTRA_FONTS >= 5)
strcpy ( m_fontinfo [ NUM_BASIC_FONTS + 4 ] . szFace , EXTRA_FONT_5_DEFAULT_FACE ) ;
m_fontinfo [ NUM_BASIC_FONTS + 4 ] . nSize = EXTRA_FONT_5_DEFAULT_SIZE ;
m_fontinfo [ NUM_BASIC_FONTS + 4 ] . bBold = EXTRA_FONT_5_DEFAULT_BOLD ;
m_fontinfo [ NUM_BASIC_FONTS + 4 ] . bItalic = EXTRA_FONT_5_DEFAULT_ITAL ;
m_fontinfo [ NUM_BASIC_FONTS + 4 ] . bAntiAliased = EXTRA_FONT_5_DEFAULT_AA ;
# endif
m_disp_mode_fs . Width = DEFAULT_FULLSCREEN_WIDTH ;
m_disp_mode_fs . Height = DEFAULT_FULLSCREEN_HEIGHT ;
m_disp_mode_fs . Format = D3DFMT_UNKNOWN ;
m_disp_mode_fs . RefreshRate = 60 ;
// better yet - in case there is no config INI file saved yet, use the current display mode (if detectable) as the default fullscreen res:
DEVMODE dm ;
dm . dmSize = sizeof ( dm ) ;
dm . dmDriverExtra = 0 ;
if ( EnumDisplaySettings ( NULL , ENUM_CURRENT_SETTINGS , & dm ) )
{
m_disp_mode_fs . Width = dm . dmPelsWidth ;
m_disp_mode_fs . Height = dm . dmPelsHeight ;
m_disp_mode_fs . RefreshRate = dm . dmDisplayFrequency ;
m_disp_mode_fs . Format = ( dm . dmBitsPerPel = = 16 ) ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8 ;
}
// PROTECTED STRUCTURES/POINTERS
int i = 0 ;
for ( int i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
m_d3dx_font [ i ] = NULL ;
m_d3dx_desktop_font = NULL ;
m_lpDDSText = NULL ;
ZeroMemory ( & m_sound , sizeof ( td_soundinfo ) ) ;
for ( int ch = 0 ; ch < 2 ; ch + + )
for ( i = 0 ; i < 3 ; i + + )
{
m_sound . infinite_avg [ ch ] [ i ] = m_sound . avg [ ch ] [ i ] = m_sound . med_avg [ ch ] [ i ] = m_sound . long_avg [ ch ] [ i ] = 1.0f ;
}
// GENERAL PRIVATE STUFF
//m_screenmode: set at end (derived setting)
m_frame = 0 ;
m_time = 0 ;
m_fps = 30 ;
m_hWndWinamp = hWinampWnd ;
m_hInstance = hWinampInstance ;
m_lpDX = NULL ;
m_szPluginsDirPath [ 0 ] = 0 ; // will be set further down
m_szConfigIniFile [ 0 ] = 0 ; // will be set further down
// m_szPluginsDirPath:
wchar_t * p ;
if ( hWinampWnd
& & ( p = ( wchar_t * ) SendMessage ( hWinampWnd , WM_WA_IPC , 0 , IPC_GETPLUGINDIRECTORYW ) )
& & p ! = ( wchar_t * ) 1 )
{
swprintf ( m_szPluginsDirPath , L " %s \\ " , p ) ;
}
else
{
// get path to INI file & read in prefs/settings right away, so DumpMsg works!
GetModuleFileNameW ( m_hInstance , m_szPluginsDirPath , MAX_PATH ) ;
wchar_t * p = m_szPluginsDirPath + wcslen ( m_szPluginsDirPath ) ;
while ( p > = m_szPluginsDirPath & & * p ! = L ' \\ ' ) p - - ;
if ( + + p > = m_szPluginsDirPath ) * p = 0 ;
}
if ( hWinampWnd
& & ( p = ( wchar_t * ) SendMessage ( hWinampWnd , WM_WA_IPC , 0 , IPC_GETINIDIRECTORYW ) )
& & p ! = ( wchar_t * ) 1 )
{
// load settings as well as coping with moving old settings to a contained folder
wchar_t m_szOldConfigIniFile [ MAX_PATH ] = { 0 } , temp [ MAX_PATH ] = { 0 } , temp2 [ MAX_PATH ] = { 0 } ;
swprintf ( m_szOldConfigIniFile , L " %s \\ Plugins \\ %s " , p , INIFILE ) ;
swprintf ( m_szConfigIniFile , L " %s \\ Plugins \\ %s%s " , p , SUBDIR , INIFILE ) ;
swprintf ( temp , L " %s \\ Plugins \\ %s " , p , SUBDIR ) ;
swprintf ( temp2 , L " %s \\ Plugins \\ " , p ) ;
CreateDirectoryW ( temp , NULL ) ;
if ( PathFileExistsW ( m_szOldConfigIniFile ) & & ! PathFileExistsW ( m_szConfigIniFile ) )
{
MoveFileW ( m_szOldConfigIniFile , m_szConfigIniFile ) ;
wchar_t m_szMsgIniFile [ MAX_PATH ] = { 0 } , m_szNewMsgIniFile [ MAX_PATH ] = { 0 } ,
m_szImgIniFile [ MAX_PATH ] = { 0 } , m_szNewImgIniFile [ MAX_PATH ] = { 0 } ,
m_szAdaptersFile [ MAX_PATH ] = { 0 } , m_szNewAdaptersFile [ MAX_PATH ] = { 0 } ;
swprintf ( m_szMsgIniFile , L " %s%s " , temp2 , MSG_INIFILE ) ;
swprintf ( m_szNewMsgIniFile , L " %s%s " , temp , MSG_INIFILE ) ;
swprintf ( m_szImgIniFile , L " %s%s " , temp2 , IMG_INIFILE ) ;
swprintf ( m_szNewImgIniFile , L " %s%s " , temp , IMG_INIFILE ) ;
swprintf ( m_szAdaptersFile , L " %s%s " , temp2 , ADAPTERSFILE ) ;
swprintf ( m_szNewAdaptersFile , L " %s%s " , temp , ADAPTERSFILE ) ;
MoveFileW ( m_szImgIniFile , m_szNewImgIniFile ) ;
MoveFileW ( m_szMsgIniFile , m_szNewMsgIniFile ) ;
MoveFileW ( m_szAdaptersFile , m_szNewAdaptersFile ) ;
}
}
else
{
swprintf ( m_szConfigIniFile , L " %s%s " , m_szPluginsDirPath , INIFILE ) ;
}
lstrcpyn ( m_szConfigIniFileA , AutoCharFn ( m_szConfigIniFile ) , MAX_PATH ) ;
// PRIVATE CONFIG PANEL SETTINGS
m_multisample_fullscreen = D3DMULTISAMPLE_NONE ;
m_multisample_desktop = D3DMULTISAMPLE_NONE ;
m_multisample_windowed = D3DMULTISAMPLE_NONE ;
ZeroMemory ( & m_adapter_guid_fullscreen , sizeof ( GUID ) ) ;
ZeroMemory ( & m_adapter_guid_desktop , sizeof ( GUID ) ) ;
ZeroMemory ( & m_adapter_guid_windowed , sizeof ( GUID ) ) ;
m_adapter_devicename_windowed [ 0 ] = 0 ;
m_adapter_devicename_fullscreen [ 0 ] = 0 ;
m_adapter_devicename_desktop [ 0 ] = 0 ;
// PRIVATE RUNTIME SETTINGS
m_lost_focus = 0 ;
m_hidden = 0 ;
m_resizing = 0 ;
m_show_help = 0 ;
m_show_playlist = 0 ;
m_playlist_pos = 0 ;
m_playlist_pageups = 0 ;
m_playlist_top_idx = - 1 ;
m_playlist_btm_idx = - 1 ;
// m_playlist_width_pixels will be considered invalid whenever 'm_playlist_top_idx' is -1.
// m_playlist[256][256] will be considered invalid whenever 'm_playlist_top_idx' is -1.
m_exiting = 0 ;
m_upper_left_corner_y = 0 ;
m_lower_left_corner_y = 0 ;
m_upper_right_corner_y = 0 ;
m_lower_right_corner_y = 0 ;
m_left_edge = 0 ;
m_right_edge = 0 ;
m_force_accept_WM_WINDOWPOSCHANGING = 0 ;
// PRIVATE - GDI STUFF
m_main_menu = NULL ;
m_context_menu = NULL ;
for ( i = 0 ; i < NUM_BASIC_FONTS + NUM_EXTRA_FONTS ; i + + )
m_font [ i ] = NULL ;
m_font_desktop = NULL ;
// PRIVATE - DESKTOP MODE STUFF
m_icon_list . clear ( ) ;
for ( i = 0 ; i < MAX_ICON_TEXTURES ; i + + )
m_desktop_icons_texture [ i ] = NULL ;
FindDesktopWindows ( & m_hWndProgMan , & m_hWndDesktop , & m_hWndDesktopListView ) ;
GetDesktopFolder ( m_szDesktopFolder ) ;
m_desktop_icon_size = 32 ;
m_desktop_dragging = 0 ; // '1' when user is dragging icons around
m_desktop_box = 0 ; // '1' when user is drawing a box
m_desktop_wc_registered = 0 ;
m_desktop_bk_color = 0xFF000000 | BGR2RGB ( : : GetSysColor ( COLOR_BACKGROUND ) ) ;
m_desktop_text_color = 0xFF000000 | BGR2RGB ( SendMessage ( m_hWndDesktopListView , LVM_GETTEXTCOLOR , 0 , 0 ) ) ;
m_desktop_sel_color = 0xFF000000 | BGR2RGB ( : : GetSysColor ( COLOR_HIGHLIGHT ) ) ;
m_desktop_sel_text_color = 0xFF000000 | BGR2RGB ( : : GetSysColor ( COLOR_HIGHLIGHTTEXT ) ) ;
m_desktop_icon_state = 0 ;
m_desktop_icon_count = 0 ;
m_desktop_icon_update_frame = 0 ;
m_desktop_icons_disabled = 0 ;
m_vms_desktop_loaded = 0 ;
m_desktop_hook_set = 0 ;
// PRIVATE - MORE TIMEKEEPING
m_last_raw_time = 0 ;
memset ( m_time_hist , 0 , sizeof ( m_time_hist ) ) ;
m_time_hist_pos = 0 ;
if ( ! QueryPerformanceFrequency ( & m_high_perf_timer_freq ) )
m_high_perf_timer_freq . QuadPart = 0 ;
m_prev_end_of_frame . QuadPart = 0 ;
// PRIVATE AUDIO PROCESSING DATA
//(m_fftobj needs no init)
memset ( m_oldwave [ 0 ] , 0 , sizeof ( float ) * 576 ) ;
memset ( m_oldwave [ 1 ] , 0 , sizeof ( float ) * 576 ) ;
m_prev_align_offset [ 0 ] = 0 ;
m_prev_align_offset [ 1 ] = 0 ;
m_align_weights_ready = 0 ;
// SEPARATE TEXT WINDOW (FOR VJ MODE)
m_vj_mode = 0 ;
m_hidden_textwnd = 0 ;
m_resizing_textwnd = 0 ;
m_hTextWnd = NULL ;
m_nTextWndWidth = 0 ;
m_nTextWndHeight = 0 ;
m_bTextWindowClassRegistered = false ;
m_vjd3d9 = NULL ;
m_vjd3d9_device = NULL ;
//-----
m_screenmode = NOT_YET_KNOWN ;
OverrideDefaults ( ) ;
ReadConfig ( ) ;
if ( m_start_fullscreen )
{
m_screenmode = m_fake_fullscreen_mode ? FAKE_FULLSCREEN : FULLSCREEN ;
if ( m_screenmode = = FULLSCREEN & & SendMessage ( GetWinampWindow ( ) , WM_WA_IPC , 0 , IPC_IS_PLAYING_VIDEO ) > 1 )
{
m_screenmode = FAKE_FULLSCREEN ;
}
}
else if ( m_start_desktop )
m_screenmode = DESKTOP ;
else
m_screenmode = WINDOWED ;
MyPreInitialize ( ) ;
MyReadConfig ( ) ;
//-----
return TRUE ;
}
int CPluginShell : : PluginInitialize ( )
{
// note: initialize GDI before DirectX. Also separate them because
// when we change windowed<->fullscreen, or lose the device and restore it,
// we don't want to mess with any (persistent) GDI stuff.
if ( ! InitDirectX ( ) ) return FALSE ; // gives its own error messages
if ( ! InitNondx9Stuff ( ) ) return FALSE ; // gives its own error messages
if ( ! AllocateDX9Stuff ( ) ) return FALSE ; // gives its own error messages
if ( ! InitVJStuff ( ) ) return FALSE ;
return TRUE ;
}
void CPluginShell : : PluginQuit ( )
{
CleanUpVJStuff ( ) ;
CleanUpDX9Stuff ( 1 ) ;
CleanUpNondx9Stuff ( ) ;
CleanUpDirectX ( ) ;
SetFocus ( m_hWndWinamp ) ;
SetActiveWindow ( m_hWndWinamp ) ;
SetForegroundWindow ( m_hWndWinamp ) ;
}
wchar_t * BuildSettingName ( wchar_t * name , int number ) {
static wchar_t temp [ 64 ] ;
swprintf ( temp , L " %s%d " , name , number ) ;
return temp ;
}
void CPluginShell : : READ_FONT ( int n ) {
GetPrivateProfileStringW ( L " settings " , BuildSettingName ( L " szFontFace " , n ) , m_fontinfo [ n ] . szFace , m_fontinfo [ n ] . szFace , sizeof ( m_fontinfo [ n ] . szFace ) , m_szConfigIniFile ) ;
m_fontinfo [ n ] . nSize = GetPrivateProfileIntW ( L " settings " , BuildSettingName ( L " nFontSize " , n ) , m_fontinfo [ n ] . nSize , m_szConfigIniFile ) ;
m_fontinfo [ n ] . bBold = GetPrivateProfileIntW ( L " settings " , BuildSettingName ( L " bFontBold " , n ) , m_fontinfo [ n ] . bBold , m_szConfigIniFile ) ;
m_fontinfo [ n ] . bItalic = GetPrivateProfileIntW ( L " settings " , BuildSettingName ( L " bFontItalic " , n ) , m_fontinfo [ n ] . bItalic , m_szConfigIniFile ) ;
m_fontinfo [ n ] . bAntiAliased = GetPrivateProfileIntW ( L " settings " , BuildSettingName ( L " bFontAA " , n ) , m_fontinfo [ n ] . bItalic , m_szConfigIniFile ) ;
}
void CPluginShell : : ReadConfig ( )
{
int old_ver = GetPrivateProfileIntW ( L " settings " , L " version " , - 1 , m_szConfigIniFile ) ;
int old_subver = GetPrivateProfileIntW ( L " settings " , L " subversion " , - 1 , m_szConfigIniFile ) ;
// nuke old settings from prev. version:
if ( old_ver < INT_VERSION )
return ;
else if ( old_subver < INT_SUBVERSION )
return ;
//D3DMULTISAMPLE_TYPE m_multisample_fullscreen;
//D3DMULTISAMPLE_TYPE m_multisample_desktop;
//D3DMULTISAMPLE_TYPE m_multisample_windowed;
m_multisample_fullscreen = ( D3DMULTISAMPLE_TYPE ) GetPrivateProfileIntW ( L " settings " , L " multisample_fullscreen " , m_multisample_fullscreen , m_szConfigIniFile ) ;
m_multisample_desktop = ( D3DMULTISAMPLE_TYPE ) GetPrivateProfileIntW ( L " settings " , L " multisample_desktop " , m_multisample_desktop , m_szConfigIniFile ) ;
m_multisample_windowed = ( D3DMULTISAMPLE_TYPE ) GetPrivateProfileIntW ( L " settings " , L " multisample_windowed " , m_multisample_windowed , m_szConfigIniFile ) ;
//GUID m_adapter_guid_fullscreen
//GUID m_adapter_guid_desktop
//GUID m_adapter_guid_windowed
char str [ 256 ] ;
GetPrivateProfileString ( " settings " , " adapter_guid_fullscreen " , " " , str , sizeof ( str ) - 1 , m_szConfigIniFileA ) ;
TextToGuid ( str , & m_adapter_guid_fullscreen ) ;
GetPrivateProfileString ( " settings " , " adapter_guid_desktop " , " " , str , sizeof ( str ) - 1 , m_szConfigIniFileA ) ;
TextToGuid ( str , & m_adapter_guid_desktop ) ;
GetPrivateProfileString ( " settings " , " adapter_guid_windowed " , " " , str , sizeof ( str ) - 1 , m_szConfigIniFileA ) ;
TextToGuid ( str , & m_adapter_guid_windowed ) ;
GetPrivateProfileString ( " settings " , " adapter_devicename_fullscreen " , " " , m_adapter_devicename_fullscreen , sizeof ( m_adapter_devicename_fullscreen ) - 1 , m_szConfigIniFileA ) ;
GetPrivateProfileString ( " settings " , " adapter_devicename_desktop " , " " , m_adapter_devicename_desktop , sizeof ( m_adapter_devicename_desktop ) - 1 , m_szConfigIniFileA ) ;
GetPrivateProfileString ( " settings " , " adapter_devicename_windowed " , " " , m_adapter_devicename_windowed , sizeof ( m_adapter_devicename_windowed ) - 1 , m_szConfigIniFileA ) ;
// FONTS
READ_FONT ( 0 ) ;
READ_FONT ( 1 ) ;
READ_FONT ( 2 ) ;
READ_FONT ( 3 ) ;
# if (NUM_EXTRA_FONTS >= 1)
READ_FONT ( 4 ) ;
# endif
# if (NUM_EXTRA_FONTS >= 2)
READ_FONT ( 5 ) ;
# endif
# if (NUM_EXTRA_FONTS >= 3)
READ_FONT ( 6 ) ;
# endif
# if (NUM_EXTRA_FONTS >= 4)
READ_FONT ( 7 ) ;
# endif
# if (NUM_EXTRA_FONTS >= 5)
READ_FONT ( 8 ) ;
# endif
m_start_fullscreen = GetPrivateProfileIntW ( L " settings " , L " start_fullscreen " , m_start_fullscreen , m_szConfigIniFile ) ;
m_start_desktop = GetPrivateProfileIntW ( L " settings " , L " start_desktop " , m_start_desktop , m_szConfigIniFile ) ;
m_fake_fullscreen_mode = GetPrivateProfileIntW ( L " settings " , L " fake_fullscreen_mode " , m_fake_fullscreen_mode , m_szConfigIniFile ) ;
m_max_fps_fs = GetPrivateProfileIntW ( L " settings " , L " max_fps_fs " , m_max_fps_fs , m_szConfigIniFile ) ;
m_max_fps_dm = GetPrivateProfileIntW ( L " settings " , L " max_fps_dm " , m_max_fps_dm , m_szConfigIniFile ) ;
m_max_fps_w = GetPrivateProfileIntW ( L " settings " , L " max_fps_w " , m_max_fps_w , m_szConfigIniFile ) ;
m_show_press_f1_msg = GetPrivateProfileIntW ( L " settings " , L " show_press_f1_msg " , m_show_press_f1_msg , m_szConfigIniFile ) ;
m_allow_page_tearing_w = GetPrivateProfileIntW ( L " settings " , L " allow_page_tearing_w " , m_allow_page_tearing_w , m_szConfigIniFile ) ;
m_allow_page_tearing_fs = GetPrivateProfileIntW ( L " settings " , L " allow_page_tearing_fs " , m_allow_page_tearing_fs , m_szConfigIniFile ) ;
m_allow_page_tearing_dm = GetPrivateProfileIntW ( L " settings " , L " allow_page_tearing_dm " , m_allow_page_tearing_dm , m_szConfigIniFile ) ;
m_minimize_winamp = GetPrivateProfileIntW ( L " settings " , L " minimize_winamp " , m_minimize_winamp , m_szConfigIniFile ) ;
m_desktop_show_icons = GetPrivateProfileIntW ( L " settings " , L " desktop_show_icons " , m_desktop_show_icons , m_szConfigIniFile ) ;
m_desktop_textlabel_boxes = GetPrivateProfileIntW ( L " settings " , L " desktop_textlabel_boxes " , m_desktop_textlabel_boxes , m_szConfigIniFile ) ;
m_desktop_manual_icon_scoot = GetPrivateProfileIntW ( L " settings " , L " desktop_manual_icon_scoot " , m_desktop_manual_icon_scoot , m_szConfigIniFile ) ;
m_desktop_555_fix = GetPrivateProfileIntW ( L " settings " , L " desktop_555_fix " , m_desktop_555_fix , m_szConfigIniFile ) ;
m_dualhead_horz = GetPrivateProfileIntW ( L " settings " , L " dualhead_horz " , m_dualhead_horz , m_szConfigIniFile ) ;
m_dualhead_vert = GetPrivateProfileIntW ( L " settings " , L " dualhead_vert " , m_dualhead_vert , m_szConfigIniFile ) ;
m_save_cpu = GetPrivateProfileIntW ( L " settings " , L " save_cpu " , m_save_cpu , m_szConfigIniFile ) ;
m_skin = GetPrivateProfileIntW ( L " settings " , L " skin " , m_skin , m_szConfigIniFile ) ;
m_fix_slow_text = GetPrivateProfileIntW ( L " settings " , L " fix_slow_text " , m_fix_slow_text , m_szConfigIniFile ) ;
m_vj_mode = GetPrivateProfileBoolW ( L " settings " , L " vj_mode " , m_vj_mode , m_szConfigIniFile ) ;
//D3DDISPLAYMODE m_fs_disp_mode
m_disp_mode_fs . Width = GetPrivateProfileIntW ( L " settings " , L " disp_mode_fs_w " , m_disp_mode_fs . Width , m_szConfigIniFile ) ;
m_disp_mode_fs . Height = GetPrivateProfileIntW ( L " settings " , L " disp_mode_fs_h " , m_disp_mode_fs . Height , m_szConfigIniFile ) ;
m_disp_mode_fs . RefreshRate = GetPrivateProfileIntW ( L " settings " , L " disp_mode_fs_r " , m_disp_mode_fs . RefreshRate , m_szConfigIniFile ) ;
m_disp_mode_fs . Format = ( D3DFORMAT ) GetPrivateProfileIntW ( L " settings " , L " disp_mode_fs_f " , m_disp_mode_fs . Format , m_szConfigIniFile ) ;
// note: we don't call MyReadConfig() yet, because we
// want to completely finish CPluginShell's preinit (and ReadConfig)
// before calling CPlugin's preinit and ReadConfig.
}
void CPluginShell : : WRITE_FONT ( int n ) {
WritePrivateProfileStringW ( L " settings " , BuildSettingName ( L " szFontFace " , n ) , m_fontinfo [ n ] . szFace , m_szConfigIniFile ) ;
WritePrivateProfileIntW ( m_fontinfo [ n ] . bBold , BuildSettingName ( L " bFontBold " , n ) , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_fontinfo [ n ] . bItalic , BuildSettingName ( L " bFontItalic " , n ) , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_fontinfo [ n ] . nSize , BuildSettingName ( L " nFontSize " , n ) , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_fontinfo [ n ] . bAntiAliased , BuildSettingName ( L " bFontAA " , n ) , m_szConfigIniFile , L " settings " ) ;
}
void CPluginShell : : WriteConfig ( )
{
//D3DMULTISAMPLE_TYPE m_multisample_fullscreen;
//D3DMULTISAMPLE_TYPE m_multisample_desktop;
//D3DMULTISAMPLE_TYPE m_multisample_windowed;
WritePrivateProfileIntW ( ( int ) m_multisample_fullscreen , L " multisample_fullscreen " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( ( int ) m_multisample_desktop , L " multisample_desktop " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( ( int ) m_multisample_windowed , L " multisample_windowed " , m_szConfigIniFile , L " settings " ) ;
//GUID m_adapter_guid_fullscreen
//GUID m_adapter_guid_desktop
//GUID m_adapter_guid_windowed
char str [ 256 ] ;
GuidToText ( & m_adapter_guid_fullscreen , str , sizeof ( str ) ) ;
WritePrivateProfileString ( " settings " , " adapter_guid_fullscreen " , str , m_szConfigIniFileA ) ;
GuidToText ( & m_adapter_guid_desktop , str , sizeof ( str ) ) ;
WritePrivateProfileString ( " settings " , " adapter_guid_desktop " , str , m_szConfigIniFileA ) ;
GuidToText ( & m_adapter_guid_windowed , str , sizeof ( str ) ) ;
WritePrivateProfileString ( " settings " , " adapter_guid_windowed " , str , m_szConfigIniFileA ) ;
WritePrivateProfileString ( " settings " , " adapter_devicename_fullscreen " , m_adapter_devicename_fullscreen , m_szConfigIniFileA ) ;
WritePrivateProfileString ( " settings " , " adapter_devicename_desktop " , m_adapter_devicename_desktop , m_szConfigIniFileA ) ;
WritePrivateProfileString ( " settings " , " adapter_devicename_windowed " , m_adapter_devicename_windowed , m_szConfigIniFileA ) ;
// FONTS
WRITE_FONT ( 0 ) ;
WRITE_FONT ( 1 ) ;
WRITE_FONT ( 2 ) ;
WRITE_FONT ( 3 ) ;
# if (NUM_EXTRA_FONTS >= 1)
WRITE_FONT ( 4 ) ;
# endif
# if (NUM_EXTRA_FONTS >= 2)
WRITE_FONT ( 5 ) ;
# endif
# if (NUM_EXTRA_FONTS >= 3)
WRITE_FONT ( 6 ) ;
# endif
# if (NUM_EXTRA_FONTS >= 4)
WRITE_FONT ( 7 ) ;
# endif
# if (NUM_EXTRA_FONTS >= 5)
WRITE_FONT ( 8 ) ;
# endif
WritePrivateProfileIntW ( m_start_fullscreen , L " start_fullscreen " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_start_desktop , L " start_desktop " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_fake_fullscreen_mode , L " fake_fullscreen_mode " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_max_fps_fs , L " max_fps_fs " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_max_fps_dm , L " max_fps_dm " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_max_fps_w , L " max_fps_w " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_show_press_f1_msg , L " show_press_f1_msg " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_allow_page_tearing_w , L " allow_page_tearing_w " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_allow_page_tearing_fs , L " allow_page_tearing_fs " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_allow_page_tearing_dm , L " allow_page_tearing_dm " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_minimize_winamp , L " minimize_winamp " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_desktop_show_icons , L " desktop_show_icons " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_desktop_textlabel_boxes , L " desktop_textlabel_boxes " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_desktop_manual_icon_scoot , L " desktop_manual_icon_scoot " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_desktop_555_fix , L " desktop_555_fix " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_dualhead_horz , L " dualhead_horz " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_dualhead_vert , L " dualhead_vert " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_save_cpu , L " save_cpu " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_skin , L " skin " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_fix_slow_text , L " fix_slow_text " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_vj_mode , L " vj_mode " , m_szConfigIniFile , L " settings " ) ;
//D3DDISPLAYMODE m_fs_disp_mode
WritePrivateProfileIntW ( m_disp_mode_fs . Width , L " disp_mode_fs_w " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_disp_mode_fs . Height , L " disp_mode_fs_h " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_disp_mode_fs . RefreshRate , L " disp_mode_fs_r " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( m_disp_mode_fs . Format , L " disp_mode_fs_f " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( INT_VERSION , L " version " , m_szConfigIniFile , L " settings " ) ;
WritePrivateProfileIntW ( INT_SUBVERSION , L " subversion " , m_szConfigIniFile , L " settings " ) ;
// finally, save the plugin's unique settings:
MyWriteConfig ( ) ;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
//----------------------------------------------------------------------
int CPluginShell : : PluginRender ( unsigned char * pWaveL , unsigned char * pWaveR ) //, unsigned char *pSpecL, unsigned char *pSpecR)
{
// return FALSE here to tell Winamp to terminate the plugin
if ( ! m_lpDX | | ! m_lpDX - > m_ready )
{
// note: 'm_ready' will go false when a device reset fatally fails
// (for example, when user resizes window, or toggles fullscreen.)
m_exiting = 1 ;
return false ; // EXIT THE PLUGIN
}
if ( m_hTextWnd )
m_lost_focus = ( ( GetFocus ( ) ! = GetPluginWindow ( ) ) & & ( GetFocus ( ) ! = m_hTextWnd ) ) ;
else
m_lost_focus = ( GetFocus ( ) ! = GetPluginWindow ( ) ) ;
if ( ( m_screenmode = = WINDOWED & & m_hidden ) | |
( m_screenmode = = FULLSCREEN & & m_lost_focus ) | |
( m_screenmode = = WINDOWED & & m_resizing )
)
{
Sleep ( 30 ) ;
return true ;
}
// test for lost device
// (this happens when device is fullscreen & user alt-tabs away,
// or when monitor power-saving kicks in)
HRESULT hr = m_lpDX - > m_lpDevice - > TestCooperativeLevel ( ) ;
if ( hr = = D3DERR_DEVICENOTRESET )
{
// device WAS lost, and is now ready to be reset (and come back online):
CleanUpDX9Stuff ( 0 ) ;
if ( m_lpDX - > m_lpDevice - > Reset ( & m_lpDX - > m_d3dpp ) ! = D3D_OK )
{
// note: a basic warning messagebox will have already been given.
// now suggest specific advice on how to regain more video memory:
if ( m_lpDX - > m_lastErr = = DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY )
SuggestHowToFreeSomeMem ( ) ;
return false ; // EXIT THE PLUGIN
}
if ( ! AllocateDX9Stuff ( ) )
return false ; // EXIT THE PLUGIN
}
else if ( hr ! = D3D_OK )
{
// device is lost, and not yet ready to come back; sleep.
Sleep ( 30 ) ;
return true ;
}
if ( m_vjd3d9_device )
{
HRESULT hr = m_vjd3d9_device - > TestCooperativeLevel ( ) ;
if ( hr = = D3DERR_DEVICENOTRESET )
{
RECT c ;
GetClientRect ( m_hTextWnd , & c ) ;
POINT p ;
p . x = c . left ;
p . y = c . top ;
if ( ClientToScreen ( m_hTextWnd , & p ) )
{
c . left + = p . x ;
c . right + = p . x ;
c . top + = p . y ;
c . bottom + = p . y ;
}
CleanUpVJStuff ( ) ;
if ( ! InitVJStuff ( & c ) )
return false ; // EXIT THE PLUGIN
}
}
if ( m_screenmode = = DESKTOP )
{
PushWindowToJustBeforeDesktop ( GetPluginWindow ( ) ) ;
}
DoTime ( ) ;
AnalyzeNewSound ( pWaveL , pWaveR ) ;
AlignWaves ( ) ;
DrawAndDisplay ( 0 ) ;
EnforceMaxFPS ( ) ;
m_frame + + ;
return true ;
}
void CPluginShell : : PushWindowToJustBeforeDesktop ( HWND h )
{
// if our window isn't already at the bottom of the Z order,
// freshly send it to HWND_BOTTOM.
// this usually gives us the Program Manager window:
HWND hWndBottom = GetWindow ( h , GW_HWNDLAST ) ;
// then, bottommost 'normal' window is usually the one just in front of it:
if ( hWndBottom = = m_hWndProgMan )
hWndBottom = GetWindow ( hWndBottom , GW_HWNDPREV ) ;
if ( hWndBottom ! = h )
{
m_force_accept_WM_WINDOWPOSCHANGING = 1 ;
SetWindowPos ( h , HWND_BOTTOM , 0 , 0 , 0 , 0 , SWP_NOMOVE | SWP_NOSIZE ) ;
m_force_accept_WM_WINDOWPOSCHANGING = 0 ;
}
/*
HWND hDesktopBkgWnd = FindWindow ( " SHELLDLL_DefView " , " " ) ;
if ( hDesktopBkgWnd )
{
HWND hWndInFrontOfIcons = GetWindow ( h , GW_HWNDPREV ) ;
if ( hWndInFrontOfIcons ! = h )
{
m_force_accept_WM_WINDOWPOSCHANGING = 1 ;
SetWindowPos ( hDesktopBkgWnd , h , 0 , 0 , 0 , 0 , SWP_NOMOVE | SWP_NOSIZE ) ;
m_force_accept_WM_WINDOWPOSCHANGING = 0 ;
}
}
*/
}
void CPluginShell : : DrawAndDisplay ( int redraw )
{
int cx = m_vjd3d9_device ? m_nTextWndWidth : m_lpDX - > m_client_width ;
int cy = m_vjd3d9_device ? m_nTextWndHeight : m_lpDX - > m_client_height ;
if ( m_lpDDSText )
{
D3DSURFACE_DESC desc ;
if ( D3D_OK = = m_lpDDSText - > GetLevelDesc ( 0 , & desc ) )
{
cx = min ( cx , ( int ) desc . Width ) ;
cy = min ( cy , ( int ) desc . Height ) ;
}
}
m_upper_left_corner_y = TEXT_MARGIN + GetCanvasMarginY ( ) ;
m_upper_right_corner_y = TEXT_MARGIN + GetCanvasMarginY ( ) ;
m_lower_left_corner_y = cy - TEXT_MARGIN - GetCanvasMarginY ( ) ;
m_lower_right_corner_y = cy - TEXT_MARGIN - GetCanvasMarginY ( ) ;
m_left_edge = TEXT_MARGIN + GetCanvasMarginX ( ) ;
m_right_edge = cx - TEXT_MARGIN - GetCanvasMarginX ( ) ;
/*if (m_screenmode == DESKTOP || m_screenmode == FAKE_FULLSCREEN)
{
// check if taskbar is above plugin window;
// if so, scoot text & icons out of the way.
// [...should always be true for Desktop Mode,
// but it's like this for code simplicity.]
int taskbar_is_above_plugin_window = 1 ;
HWND h = FindWindow ( " Shell_TrayWnd " , NULL ) ;
2024-09-29 02:04:03 +00:00
while ( h ) //(..shouldn't be very many arch to iterate through here)
2024-09-24 12:54:57 +00:00
{
h = GetWindow ( h , GW_HWNDPREV ) ;
if ( h = = GetPluginWindow ( ) )
{
taskbar_is_above_plugin_window = 0 ;
break ;
}
}
if ( taskbar_is_above_plugin_window )
{
// respect the taskbar area; make sure the text, desktop icons, etc.
// don't appear underneath it.
//m_upper_left_corner_y += m_lpDX->m_monitor_work_rect.top - m_lpDX->m_monitor_rect.top;
//m_upper_right_corner_y += m_lpDX->m_monitor_work_rect.top - m_lpDX->m_monitor_rect.top;
//m_lower_left_corner_y -= m_lpDX->m_monitor_rect.bottom - m_lpDX->m_monitor_work_rect.bottom;
//m_lower_right_corner_y -= m_lpDX->m_monitor_rect.bottom - m_lpDX->m_monitor_work_rect.bottom;
//m_left_edge += m_lpDX->m_monitor_work_rect.left - m_lpDX->m_monitor_rect.left;
//m_right_edge -= m_lpDX->m_monitor_rect.right - m_lpDX->m_monitor_work_rect.right;
m_lpDX - > UpdateMonitorWorkRect ( ) ;
m_upper_left_corner_y = max ( m_upper_left_corner_y , m_lpDX - > m_monitor_work_rect . top - m_lpDX - > m_monitor_rect . top + TEXT_MARGIN + GetCanvasMarginY ( ) ) ;
m_upper_right_corner_y = max ( m_upper_right_corner_y , m_lpDX - > m_monitor_work_rect . top - m_lpDX - > m_monitor_rect . top + TEXT_MARGIN + GetCanvasMarginY ( ) ) ;
m_lower_left_corner_y = min ( m_lower_left_corner_y , m_lpDX - > m_client_height - ( m_lpDX - > m_monitor_rect . bottom - m_lpDX - > m_monitor_work_rect . bottom ) - TEXT_MARGIN - GetCanvasMarginY ( ) ) ;
m_lower_right_corner_y = min ( m_lower_right_corner_y , m_lpDX - > m_client_height - ( m_lpDX - > m_monitor_rect . bottom - m_lpDX - > m_monitor_work_rect . bottom ) - TEXT_MARGIN - GetCanvasMarginY ( ) ) ;
m_left_edge = max ( m_left_edge , m_lpDX - > m_monitor_work_rect . left - m_lpDX - > m_monitor_rect . left + TEXT_MARGIN + GetCanvasMarginX ( ) ) ;
m_right_edge = min ( m_right_edge , m_lpDX - > m_client_width - ( m_lpDX - > m_monitor_rect . right - m_lpDX - > m_monitor_work_rect . right ) - TEXT_MARGIN + GetCanvasMarginX ( ) ) ;
}
} */
if ( D3D_OK = = m_lpDX - > m_lpDevice - > BeginScene ( ) )
{
MyRenderFn ( redraw ) ;
PrepareFor2DDrawing_B ( GetDevice ( ) , GetWidth ( ) , GetHeight ( ) ) ;
RenderDesktop ( ) ;
if ( ! m_vjd3d9_device ) // in VJ mode, this renders to different context, so do it after BeginScene() on 2nd device.
RenderBuiltInTextMsgs ( ) ; // to m_lpDDSText?
MyRenderUI ( & m_upper_left_corner_y , & m_upper_right_corner_y , & m_lower_left_corner_y , & m_lower_right_corner_y , m_left_edge , m_right_edge ) ;
RenderPlaylist ( ) ;
if ( ! m_vjd3d9_device )
m_text . DrawNow ( ) ;
m_lpDX - > m_lpDevice - > EndScene ( ) ;
}
// VJ Mode:
if ( m_vj_mode & & m_vjd3d9_device & & ! m_hidden_textwnd & & D3D_OK = = m_vjd3d9_device - > BeginScene ( ) )
{
if ( ! m_lpDDSText | | m_bClearVJWindow )
m_vjd3d9_device - > Clear ( 0 , 0 , D3DCLEAR_TARGET , 0xFF000000 , 1.0f , 0 ) ;
m_bClearVJWindow = false ;
// note: when using debug DX runtime, textwnd will flash red/green after frame 4, if no text is drawn on a frame!
RenderBuiltInTextMsgs ( ) ;
PrepareFor2DDrawing_B ( m_vjd3d9_device , m_nTextWndWidth , m_nTextWndHeight ) ;
m_text . DrawNow ( ) ;
m_vjd3d9_device - > EndScene ( ) ;
}
if ( m_screenmode = = DESKTOP )
{
// window is hidden after creation, until 1st frame is ready to go;
// now that it's ready, we show it.
// see dxcontext::Internal_Init()'s call to SetWindowPos() for the DESKTOP case.
if ( ! IsWindowVisible ( GetPluginWindow ( ) ) )
ShowWindow ( GetPluginWindow ( ) , SW_SHOWNORMAL ) ;
}
if ( m_screenmode = = WINDOWED & & ( m_lpDX - > m_client_width ! = m_lpDX - > m_REAL_client_width | | m_lpDX - > m_client_height ! = m_lpDX - > m_REAL_client_height ) )
{
int real_w = m_lpDX - > m_REAL_client_width ; // real client size, in pixels
int real_h = m_lpDX - > m_REAL_client_height ;
int fat_w = m_lpDX - > m_client_width ; // oversized VS canvas size, in pixels
int fat_h = m_lpDX - > m_client_height ;
int extra_w = fat_w - real_w ;
int extra_h = fat_h - real_h ;
RECT src , dst ;
SetRect ( & src , extra_w / 2 , extra_h / 2 , extra_w / 2 + real_w , extra_h / 2 + real_h ) ;
SetRect ( & dst , 0 , 0 , real_w , real_h ) ;
m_lpDX - > m_lpDevice - > Present ( & src , & dst , NULL , NULL ) ;
}
else
m_lpDX - > m_lpDevice - > Present ( NULL , NULL , NULL , NULL ) ;
if ( m_vjd3d9_device & & ! m_hidden_textwnd )
m_vjd3d9_device - > Present ( NULL , NULL , NULL , NULL ) ;
}
void CPluginShell : : EnforceMaxFPS ( )
{
int max_fps ;
switch ( m_screenmode )
{
case WINDOWED : max_fps = m_max_fps_w ; break ;
case FULLSCREEN : max_fps = m_max_fps_fs ; break ;
case FAKE_FULLSCREEN : max_fps = m_max_fps_fs ; break ;
case DESKTOP : max_fps = m_max_fps_dm ; break ;
}
if ( max_fps < = 0 )
return ;
float fps_lo = ( float ) max_fps ;
float fps_hi = ( float ) max_fps ;
if ( m_save_cpu )
{
// Find the optimal lo/hi bounds for the fps
// that will result in a maximum difference,
// in the time for a single frame, of 0.003 seconds -
// the assumed granularity for Sleep(1) -
// Using this range of acceptable fps
// will allow us to do (sloppy) fps limiting
// using only Sleep(1), and never the
// second half of it: Sleep(0) in a tight loop,
// which sucks up the CPU (whereas Sleep(1)
// leaves it idle).
// The original equation:
// 1/(max_fps*t1) = 1/(max*fps/t1) - 0.003
// where:
// t1 > 0
// max_fps*t1 is the upper range for fps
// max_fps/t1 is the lower range for fps
float a = 1 ;
float b = - 0.003f * max_fps ;
float c = - 1.0f ;
float det = b * b - 4 * a * c ;
if ( det > 0 )
{
float t1 = ( - b + sqrtf ( det ) ) / ( 2 * a ) ;
//float t2 = (-b - sqrtf(det)) / (2*a);
if ( t1 > 1.0f )
{
fps_lo = max_fps / t1 ;
fps_hi = max_fps * t1 ;
// verify: now [1.0f/fps_lo - 1.0f/fps_hi] should equal 0.003 seconds.
// note: allowing tolerance to go beyond these values for
// fps_lo and fps_hi would gain nothing.
}
}
}
if ( m_high_perf_timer_freq . QuadPart > 0 )
{
LARGE_INTEGER t ;
QueryPerformanceCounter ( & t ) ;
if ( m_prev_end_of_frame . QuadPart ! = 0 )
{
int ticks_to_wait_lo = ( int ) ( ( float ) m_high_perf_timer_freq . QuadPart / ( float ) fps_hi ) ;
int ticks_to_wait_hi = ( int ) ( ( float ) m_high_perf_timer_freq . QuadPart / ( float ) fps_lo ) ;
int done = 0 ;
int loops = 0 ;
do
{
QueryPerformanceCounter ( & t ) ;
__int64 t2 = t . QuadPart - m_prev_end_of_frame . QuadPart ;
if ( t2 > 2147483000 )
done = 1 ;
if ( t . QuadPart < m_prev_end_of_frame . QuadPart ) // time wrap
done = 1 ;
// this is sloppy - if your freq. is high, this can overflow (to a (-) int) in just a few minutes
// but it's ok, we have protection for that above.
int ticks_passed = ( int ) ( t . QuadPart - m_prev_end_of_frame . QuadPart ) ;
if ( ticks_passed > = ticks_to_wait_lo )
done = 1 ;
if ( ! done )
{
// if > 0.01s left, do Sleep(1), which will actually sleep some
// steady amount of up to 3 ms (depending on the OS),
// and do so in a nice way (cpu meter drops; laptop battery spared).
// otherwise, do a few Sleep(0)'s, which just give up the timeslice,
// but don't really save cpu or battery, but do pass a tiny
// amount of time.
//if (ticks_left > (int)m_high_perf_timer_freq.QuadPart/500)
if ( ticks_to_wait_hi - ticks_passed > ( int ) m_high_perf_timer_freq . QuadPart / 100 )
Sleep ( 5 ) ;
else if ( ticks_to_wait_hi - ticks_passed > ( int ) m_high_perf_timer_freq . QuadPart / 1000 )
Sleep ( 1 ) ;
else
for ( int i = 0 ; i < 10 ; i + + )
Sleep ( 0 ) ; // causes thread to give up its timeslice
}
}
while ( ! done ) ;
}
m_prev_end_of_frame = t ;
}
else
{
Sleep ( 1000 / max_fps ) ;
}
}
void CPluginShell : : DoTime ( )
{
if ( m_frame = = 0 )
{
m_fps = 30 ;
m_time = 0 ;
m_time_hist_pos = 0 ;
}
double new_raw_time ;
float elapsed ;
if ( m_high_perf_timer_freq . QuadPart ! = 0 )
{
// get high-precision time
// precision: usually from 1..6 us (MICROseconds), depending on the cpu speed.
// (higher cpu speeds tend to have better precision here)
LARGE_INTEGER t ;
if ( ! QueryPerformanceCounter ( & t ) )
{
m_high_perf_timer_freq . QuadPart = 0 ; // something went wrong (exception thrown) -> revert to crappy timer
}
else
{
new_raw_time = ( double ) t . QuadPart ;
elapsed = ( float ) ( ( new_raw_time - m_last_raw_time ) / ( double ) m_high_perf_timer_freq . QuadPart ) ;
}
}
if ( m_high_perf_timer_freq . QuadPart = = 0 )
{
// get low-precision time
// precision: usually 1 ms (MILLIsecond) for win98, and 10 ms for win2k.
new_raw_time = ( double ) ( timeGetTime ( ) * 0.001 ) ;
elapsed = ( float ) ( new_raw_time - m_last_raw_time ) ;
}
m_last_raw_time = new_raw_time ;
int slots_to_look_back = ( m_high_perf_timer_freq . QuadPart = = 0 ) ? TIME_HIST_SLOTS : TIME_HIST_SLOTS / 2 ;
m_time + = 1.0f / m_fps ;
// timekeeping goals:
// 1. keep 'm_time' increasing SMOOTHLY: (smooth animation depends on it)
// m_time += 1.0f/m_fps; // where m_fps is a bit damped
// 2. keep m_time_hist[] 100% accurate (except for filtering out pauses),
// so that when we look take the difference between two entries,
// we get the real amount of time that passed between those 2 frames.
// m_time_hist[i] = m_last_raw_time + elapsed_corrected;
if ( m_frame > TIME_HIST_SLOTS )
{
if ( m_fps < 60.0f )
slots_to_look_back = ( int ) ( slots_to_look_back * ( 0.1f + 0.9f * ( m_fps / 60.0f ) ) ) ;
if ( elapsed > 5.0f / m_fps | | elapsed > 1.0f | | elapsed < 0 )
elapsed = 1.0f / 30.0f ;
float old_hist_time = m_time_hist [ ( m_time_hist_pos - slots_to_look_back + TIME_HIST_SLOTS ) % TIME_HIST_SLOTS ] ;
float new_hist_time = m_time_hist [ ( m_time_hist_pos - 1 + TIME_HIST_SLOTS ) % TIME_HIST_SLOTS ]
+ elapsed ;
m_time_hist [ m_time_hist_pos ] = new_hist_time ;
m_time_hist_pos = ( m_time_hist_pos + 1 ) % TIME_HIST_SLOTS ;
float new_fps = slots_to_look_back / ( float ) ( new_hist_time - old_hist_time ) ;
float damping = ( m_high_perf_timer_freq . QuadPart = = 0 ) ? 0.93f : 0.87f ;
// damp heavily, so that crappy timer precision doesn't make animation jerky
if ( fabsf ( m_fps - new_fps ) > 3.0f )
m_fps = new_fps ;
else
m_fps = damping * m_fps + ( 1 - damping ) * new_fps ;
}
else
{
float damping = ( m_high_perf_timer_freq . QuadPart = = 0 ) ? 0.8f : 0.6f ;
if ( m_frame < 2 )
elapsed = 1.0f / 30.0f ;
else if ( elapsed > 1.0f | | elapsed < 0 )
elapsed = 1.0f / m_fps ;
float old_hist_time = m_time_hist [ 0 ] ;
float new_hist_time = m_time_hist [ ( m_time_hist_pos - 1 + TIME_HIST_SLOTS ) % TIME_HIST_SLOTS ]
+ elapsed ;
m_time_hist [ m_time_hist_pos ] = new_hist_time ;
m_time_hist_pos = ( m_time_hist_pos + 1 ) % TIME_HIST_SLOTS ;
if ( m_frame > 0 )
{
float new_fps = ( m_frame ) / ( new_hist_time - old_hist_time ) ;
m_fps = damping * m_fps + ( 1 - damping ) * new_fps ;
}
}
// Synchronize the audio and video by telling Winamp how many milliseconds we want the audio data,
// before it's actually audible. If we set this to the amount of time it takes to display 1 frame
// (1/fps), the video and audio should be perfectly synchronized.
if ( m_fps < 2.0f )
mod1 . latencyMs = 500 ;
else if ( m_fps > 125.0f )
mod1 . latencyMs = 8 ;
else
mod1 . latencyMs = ( int ) ( 1000.0f / m_fps * m_lpDX - > m_frame_delay + 0.5f ) ;
}
void CPluginShell : : AnalyzeNewSound ( unsigned char * pWaveL , unsigned char * pWaveR )
{
// we get 576 samples in from winamp.
// the output of the fft has 'num_frequencies' samples,
// and represents the frequency range 0 hz - 22,050 hz.
// usually, plugins only use half of this output (the range 0 hz - 11,025 hz),
// since >10 khz doesn't usually contribute much.
int i ;
float temp_wave [ 2 ] [ 576 ] ;
int old_i = 0 ;
for ( i = 0 ; i < 576 ; i + + )
{
m_sound . fWaveform [ 0 ] [ i ] = ( float ) ( ( pWaveL [ i ] ^ 128 ) - 128 ) ;
m_sound . fWaveform [ 1 ] [ i ] = ( float ) ( ( pWaveR [ i ] ^ 128 ) - 128 ) ;
// simulating single frequencies from 200 to 11,025 Hz:
//float freq = 1.0f + 11050*(GetFrame() % 100)*0.01f;
//m_sound.fWaveform[0][i] = 10*sinf(i*freq*6.28f/44100.0f);
// damp the input into the FFT a bit, to reduce high-frequency noise:
temp_wave [ 0 ] [ i ] = 0.5f * ( m_sound . fWaveform [ 0 ] [ i ] + m_sound . fWaveform [ 0 ] [ old_i ] ) ;
temp_wave [ 1 ] [ i ] = 0.5f * ( m_sound . fWaveform [ 1 ] [ i ] + m_sound . fWaveform [ 1 ] [ old_i ] ) ;
old_i = i ;
}
m_fftobj . time_to_frequency_domain ( temp_wave [ 0 ] , m_sound . fSpectrum [ 0 ] ) ;
m_fftobj . time_to_frequency_domain ( temp_wave [ 1 ] , m_sound . fSpectrum [ 1 ] ) ;
// sum (left channel) spectrum up into 3 bands
// [note: the new ranges do it so that the 3 bands are equally spaced, pitch-wise]
float min_freq = 200.0f ;
float max_freq = 11025.0f ;
float net_octaves = ( logf ( max_freq / min_freq ) / logf ( 2.0f ) ) ; // 5.7846348455575205777914165223593
float octaves_per_band = net_octaves / 3.0f ; // 1.9282116151858401925971388407864
float mult = powf ( 2.0f , octaves_per_band ) ; // each band's highest freq. divided by its lowest freq.; 3.805831305510122517035102576162
// [to verify: min_freq * mult * mult * mult should equal max_freq.]
for ( int ch = 0 ; ch < 2 ; ch + + )
{
for ( i = 0 ; i < 3 ; i + + )
{
// old guesswork code for this:
// float exp = 2.1f;
// int start = (int)(NUM_FREQUENCIES*0.5f*powf(i/3.0f, exp));
// int end = (int)(NUM_FREQUENCIES*0.5f*powf((i+1)/3.0f, exp));
// results:
// old range: new range (ideal):
// bass: 0-1097 200-761
// mids: 1097-4705 761-2897
// treb: 4705-11025 2897-11025
int start = ( int ) ( NUM_FREQUENCIES * min_freq * powf ( mult , ( float ) i ) / 11025.0f ) ;
int end = ( int ) ( NUM_FREQUENCIES * min_freq * powf ( mult , ( float ) ( i + 1 ) ) / 11025.0f ) ;
if ( start < 0 ) start = 0 ;
if ( end > NUM_FREQUENCIES ) end = NUM_FREQUENCIES ;
m_sound . imm [ ch ] [ i ] = 0 ;
for ( int j = start ; j < end ; j + + )
m_sound . imm [ ch ] [ i ] + = m_sound . fSpectrum [ ch ] [ j ] ;
m_sound . imm [ ch ] [ i ] / = ( float ) ( end - start ) ;
}
}
// some code to find empirical long-term averages for imm[0..2]:
/*{
static float sum [ 3 ] ;
static int count = 0 ;
# define FRAMES_PER_SONG 300 // should be at least 200!
if ( m_frame < FRAMES_PER_SONG )
{
sum [ 0 ] = sum [ 1 ] = sum [ 2 ] = 0 ;
count = 0 ;
}
else
{
if ( m_frame % FRAMES_PER_SONG = = 0 )
{
char buf [ 256 ] ;
sprintf ( buf , " %.4f, %.4f, %.4f (%d samples / ~%d songs) \n " ,
sum [ 0 ] / ( float ) ( count ) ,
sum [ 1 ] / ( float ) ( count ) ,
sum [ 2 ] / ( float ) ( count ) ,
count ,
count / ( FRAMES_PER_SONG - 10 )
) ;
OutputDebugString ( buf ) ;
// skip to next song
PostMessage ( m_hWndWinamp , WM_COMMAND , 40048 , 0 ) ;
}
else if ( m_frame % FRAMES_PER_SONG = = 5 )
{
// then advance to 0-2 minutes into the song:
PostMessage ( m_hWndWinamp , WM_USER , ( 20 + ( warand ( ) % 65 ) + ( rand ( ) % 65 ) ) * 1000 , 106 ) ;
}
else if ( m_frame % FRAMES_PER_SONG > = 10 )
{
sum [ 0 ] + = m_sound . imm [ 0 ] ;
sum [ 1 ] + = m_sound . imm [ 1 ] ;
sum [ 2 ] + = m_sound . imm [ 2 ] ;
count + + ;
}
}
} */
// multiply by long-term, empirically-determined inverse averages:
// (for a trial of 244 songs, 10 seconds each, somewhere in the 2nd or 3rd minute,
// the average levels were: 0.326781557 0.38087377 0.199888934
for ( int ch = 0 ; ch < 2 ; ch + + )
{
m_sound . imm [ ch ] [ 0 ] / = 0.326781557f ; //0.270f;
m_sound . imm [ ch ] [ 1 ] / = 0.380873770f ; //0.343f;
m_sound . imm [ ch ] [ 2 ] / = 0.199888934f ; //0.295f;
}
// do temporal blending to create attenuated and super-attenuated versions
for ( int ch = 0 ; ch < 2 ; ch + + )
{
for ( i = 0 ; i < 3 ; i + + )
{
// m_sound.avg[i]
{
float avg_mix ;
if ( m_sound . imm [ ch ] [ i ] > m_sound . avg [ ch ] [ i ] )
avg_mix = AdjustRateToFPS ( 0.2f , 14.0f , m_fps ) ;
else
avg_mix = AdjustRateToFPS ( 0.5f , 14.0f , m_fps ) ;
m_sound . avg [ ch ] [ i ] = m_sound . avg [ ch ] [ i ] * avg_mix + m_sound . imm [ ch ] [ i ] * ( 1 - avg_mix ) ;
}
// m_sound.med_avg[i]
// m_sound.long_avg[i]
{
float med_mix = 0.91f ; //0.800f + 0.11f*powf(t, 0.4f); // primarily used for velocity_damping
float long_mix = 0.96f ; //0.800f + 0.16f*powf(t, 0.2f); // primarily used for smoke plumes
med_mix = AdjustRateToFPS ( med_mix , 14.0f , m_fps ) ;
long_mix = AdjustRateToFPS ( long_mix , 14.0f , m_fps ) ;
m_sound . med_avg [ ch ] [ i ] = m_sound . med_avg [ ch ] [ i ] * ( med_mix ) + m_sound . imm [ ch ] [ i ] * ( 1 - med_mix ) ;
m_sound . long_avg [ ch ] [ i ] = m_sound . long_avg [ ch ] [ i ] * ( long_mix ) + m_sound . imm [ ch ] [ i ] * ( 1 - long_mix ) ;
}
}
}
}
void CPluginShell : : PrepareFor2DDrawing_B ( IDirect3DDevice9 * pDevice , int w , int h )
{
// New 2D drawing area will have x,y coords in the range <-1,-1> .. <1,1>
// +--------+ Y=-1
// | |
// | screen | Z=0: front of scene
// | | Z=1: back of scene
// +--------+ Y=1
// X=-1 X=1
// NOTE: After calling this, be sure to then call (at least):
// 1. SetVertexShader()
// 2. SetTexture(), if you need it
// before rendering primitives!
// Also, be sure your sprites have a z coordinate of 0.
pDevice - > SetRenderState ( D3DRS_ZENABLE , TRUE ) ;
pDevice - > SetRenderState ( D3DRS_ZWRITEENABLE , TRUE ) ;
pDevice - > SetRenderState ( D3DRS_ZFUNC , D3DCMP_LESSEQUAL ) ;
pDevice - > SetRenderState ( D3DRS_SHADEMODE , D3DSHADE_GOURAUD ) ;
pDevice - > SetRenderState ( D3DRS_FILLMODE , D3DFILL_SOLID ) ;
pDevice - > SetRenderState ( D3DRS_FOGENABLE , FALSE ) ;
pDevice - > SetRenderState ( D3DRS_CULLMODE , D3DCULL_NONE ) ;
pDevice - > SetRenderState ( D3DRS_CLIPPING , TRUE ) ;
pDevice - > SetRenderState ( D3DRS_LIGHTING , FALSE ) ;
pDevice - > SetRenderState ( D3DRS_ALPHABLENDENABLE , FALSE ) ;
pDevice - > SetRenderState ( D3DRS_LOCALVIEWER , FALSE ) ;
pDevice - > SetRenderState ( D3DRS_COLORVERTEX , TRUE ) ;
pDevice - > SetTexture ( 0 , NULL ) ;
pDevice - > SetTexture ( 1 , NULL ) ;
pDevice - > SetSamplerState ( 0 , D3DSAMP_MAGFILTER , D3DTEXF_POINT ) ; //D3DTEXF_LINEAR);
pDevice - > SetSamplerState ( 1 , D3DSAMP_MAGFILTER , D3DTEXF_POINT ) ; //D3DTEXF_LINEAR);
pDevice - > SetTextureStageState ( 0 , D3DTSS_TEXTURETRANSFORMFLAGS , D3DTTFF_DISABLE ) ;
pDevice - > SetTextureStageState ( 1 , D3DTSS_TEXTURETRANSFORMFLAGS , D3DTTFF_DISABLE ) ;
pDevice - > SetTextureStageState ( 0 , D3DTSS_COLOROP , D3DTOP_MODULATE ) ;
pDevice - > SetTextureStageState ( 0 , D3DTSS_COLORARG1 , D3DTA_TEXTURE ) ;
pDevice - > SetTextureStageState ( 0 , D3DTSS_COLORARG2 , D3DTA_CURRENT ) ;
pDevice - > SetTextureStageState ( 1 , D3DTSS_COLOROP , D3DTOP_DISABLE ) ;
pDevice - > SetTextureStageState ( 0 , D3DTSS_ALPHAOP , D3DTOP_SELECTARG1 ) ;
pDevice - > SetTextureStageState ( 0 , D3DTSS_ALPHAARG1 , D3DTA_DIFFUSE ) ;
pDevice - > SetTextureStageState ( 1 , D3DTSS_ALPHAOP , D3DTOP_DISABLE ) ;
pDevice - > SetRenderState ( D3DRS_ALPHABLENDENABLE , FALSE ) ;
// set up for 2D drawing:
{
D3DXMATRIX Ortho2D ;
D3DXMATRIX Identity ;
pMatrixOrthoLH ( & Ortho2D , ( float ) w , ( float ) h , 0.0f , 1.0f ) ;
D3DXMatrixIdentity ( & Identity ) ;
pDevice - > SetTransform ( D3DTS_PROJECTION , & Ortho2D ) ;
pDevice - > SetTransform ( D3DTS_WORLD , & Identity ) ;
pDevice - > SetTransform ( D3DTS_VIEW , & Identity ) ;
}
}
void CPluginShell : : DrawDarkTranslucentBox ( RECT * pr )
{
// 'pr' is the rectangle that some text will occupy;
// a black box will be drawn around it, plus a bit of extra margin space.
if ( m_vjd3d9_device )
return ;
m_lpDX - > m_lpDevice - > SetVertexShader ( NULL ) ;
m_lpDX - > m_lpDevice - > SetPixelShader ( NULL ) ;
m_lpDX - > m_lpDevice - > SetFVF ( SIMPLE_VERTEX_FORMAT ) ;
m_lpDX - > m_lpDevice - > SetTexture ( 0 , NULL ) ;
m_lpDX - > m_lpDevice - > SetRenderState ( D3DRS_ALPHABLENDENABLE , TRUE ) ;
m_lpDX - > m_lpDevice - > SetRenderState ( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA ) ;
m_lpDX - > m_lpDevice - > SetRenderState ( D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA ) ;
m_lpDX - > m_lpDevice - > SetTextureStageState ( 0 , D3DTSS_COLOROP , D3DTOP_SELECTARG1 ) ;
m_lpDX - > m_lpDevice - > SetTextureStageState ( 0 , D3DTSS_COLORARG1 , D3DTA_DIFFUSE ) ;
m_lpDX - > m_lpDevice - > SetTextureStageState ( 1 , D3DTSS_COLOROP , D3DTOP_DISABLE ) ;
m_lpDX - > m_lpDevice - > SetTextureStageState ( 0 , D3DTSS_ALPHAOP , D3DTOP_SELECTARG1 ) ;
m_lpDX - > m_lpDevice - > SetTextureStageState ( 0 , D3DTSS_ALPHAARG1 , D3DTA_DIFFUSE ) ;
// set up a quad
SIMPLEVERTEX verts [ 4 ] ;
for ( int i = 0 ; i < 4 ; i + + )
{
verts [ i ] . x = ( i % 2 = = 0 ) ? ( float ) ( - m_lpDX - > m_client_width / 2 + pr - > left ) :
( float ) ( - m_lpDX - > m_client_width / 2 + pr - > right ) ;
verts [ i ] . y = ( i / 2 = = 0 ) ? ( float ) - ( - m_lpDX - > m_client_height / 2 + pr - > bottom ) :
( float ) - ( - m_lpDX - > m_client_height / 2 + pr - > top ) ;
verts [ i ] . z = 0 ;
verts [ i ] . Diffuse = ( m_screenmode = = DESKTOP ) ? 0xE0000000 : 0xD0000000 ;
}
m_lpDX - > m_lpDevice - > DrawPrimitiveUP ( D3DPT_TRIANGLESTRIP , 2 , verts , sizeof ( SIMPLEVERTEX ) ) ;
// undo unusual state changes:
m_lpDX - > m_lpDevice - > SetRenderState ( D3DRS_ZENABLE , TRUE ) ;
m_lpDX - > m_lpDevice - > SetRenderState ( D3DRS_ALPHABLENDENABLE , FALSE ) ;
}
void CPluginShell : : RenderBuiltInTextMsgs ( )
{
int _show_press_f1_NOW = ( m_show_press_f1_msg & & m_time < PRESS_F1_DUR ) ;
{
RECT r ;
if ( m_show_help )
{
int y = m_upper_left_corner_y ;
SetRect ( & r , 0 , 0 , GetWidth ( ) , GetHeight ( ) ) ;
if ( ! g_szHelp_W )
m_d3dx_font [ HELPSCREEN_FONT ] - > DrawTextA ( NULL , ( char * ) g_szHelp , - 1 , & r , DT_CALCRECT , 0xFFFFFFFF ) ;
else
m_d3dx_font [ HELPSCREEN_FONT ] - > DrawTextW ( NULL , g_szHelp , - 1 , & r , DT_CALCRECT , 0xFFFFFFFF ) ;
r . top + = m_upper_left_corner_y ;
r . left + = m_left_edge ;
r . right + = m_left_edge + PLAYLIST_INNER_MARGIN * 2 ;
r . bottom + = m_upper_left_corner_y + PLAYLIST_INNER_MARGIN * 2 ;
DrawDarkTranslucentBox ( & r ) ;
r . top + = PLAYLIST_INNER_MARGIN ;
r . left + = PLAYLIST_INNER_MARGIN ;
r . right - = PLAYLIST_INNER_MARGIN ;
r . bottom - = PLAYLIST_INNER_MARGIN ;
if ( ! g_szHelp_W )
m_d3dx_font [ HELPSCREEN_FONT ] - > DrawTextA ( NULL , ( char * ) g_szHelp , - 1 , & r , 0 , 0xFFFFFFFF ) ;
else
m_d3dx_font [ HELPSCREEN_FONT ] - > DrawTextW ( NULL , g_szHelp , - 1 , & r , 0 , 0xFFFFFFFF ) ;
m_upper_left_corner_y + = r . bottom - r . top + PLAYLIST_INNER_MARGIN * 3 ;
}
// render 'Press F1 for Help' message in lower-right corner:
if ( _show_press_f1_NOW )
{
int dx = ( int ) ( 160.0f * powf ( m_time / ( float ) ( PRESS_F1_DUR ) , ( float ) ( PRESS_F1_EXP ) ) ) ;
SetRect ( & r , m_left_edge , m_lower_right_corner_y - GetFontHeight ( DECORATIVE_FONT ) , m_right_edge + dx , m_lower_right_corner_y ) ;
m_lower_right_corner_y - = m_d3dx_font [ DECORATIVE_FONT ] - > DrawTextW ( NULL , WASABI_API_LNGSTRINGW ( IDS_PRESS_F1_MSG ) , - 1 , & r , DT_RIGHT , 0xFFFFFFFF ) ;
}
}
}
void CPluginShell : : RenderPlaylist ( )
{
// draw playlist:
if ( m_show_playlist )
{
RECT r ;
int nSongs = SendMessage ( m_hWndWinamp , WM_USER , 0 , 124 ) ;
int now_playing = SendMessage ( m_hWndWinamp , WM_USER , 0 , 125 ) ;
if ( nSongs < = 0 )
{
m_show_playlist = 0 ;
}
else
{
int playlist_vert_pixels = m_lower_left_corner_y - m_upper_left_corner_y ;
int disp_lines = min ( MAX_SONGS_PER_PAGE , ( playlist_vert_pixels - PLAYLIST_INNER_MARGIN * 2 ) / GetFontHeight ( PLAYLIST_FONT ) ) ;
int total_pages = ( nSongs ) / disp_lines ;
if ( disp_lines < = 0 )
return ;
// apply PgUp/PgDn keypresses since last time
m_playlist_pos - = m_playlist_pageups * disp_lines ;
m_playlist_pageups = 0 ;
if ( m_playlist_pos < 0 )
m_playlist_pos = 0 ;
if ( m_playlist_pos > = nSongs )
m_playlist_pos = nSongs - 1 ;
// NOTE: 'dwFlags' is used for both DDRAW and DX9
DWORD dwFlags = DT_SINGLELINE ; // | DT_NOPREFIX | DT_WORD_ELLIPSIS;
DWORD color ;
int cur_page = ( m_playlist_pos ) / disp_lines ;
int cur_line = ( m_playlist_pos + disp_lines - 1 ) % disp_lines ;
int new_top_idx = cur_page * disp_lines ;
int new_btm_idx = new_top_idx + disp_lines ;
wchar_t buf [ 1024 ] = { 0 } ;
// ask winamp for the song names, but DO IT BEFORE getting the DC,
// otherwise vaio will crash (~DDRAW port).
if ( m_playlist_top_idx ! = new_top_idx | |
m_playlist_btm_idx ! = new_btm_idx )
{
for ( int i = 0 ; i < disp_lines ; i + + )
{
int j = new_top_idx + i ;
if ( j < nSongs )
{
// clip max len. of song name to 240 chars, to prevent overflows
lstrcpynW ( buf , ( wchar_t * ) SendMessage ( m_hWndWinamp , WM_USER , j , IPC_GETPLAYLISTTITLEW ) , 240 ) ;
wsprintfW ( m_playlist [ i ] , L " %d. %s " , j + 1 , buf ) ; // leave an extra space @ end, so italicized fonts don't get clipped
}
}
}
// update playlist cache, if necessary:
if ( m_playlist_top_idx ! = new_top_idx | |
m_playlist_btm_idx ! = new_btm_idx )
{
m_playlist_top_idx = new_top_idx ;
m_playlist_btm_idx = new_btm_idx ;
m_playlist_width_pixels = 0 ;
int max_w = min ( m_right_edge - m_left_edge , m_lpDX - > m_client_width - TEXT_MARGIN * 2 - PLAYLIST_INNER_MARGIN * 2 ) ;
for ( int i = 0 ; i < disp_lines ; i + + )
{
int j = new_top_idx + i ;
if ( j < nSongs )
{
// clip max len. of song name to 240 chars, to prevent overflows
//strcpy(buf, (char*)SendMessage(m_hWndWinamp, WM_USER, j, 212));
//buf[240] = 0;
//sprintf(m_playlist[i], "%d. %s ", j+1, buf); // leave an extra space @ end, so italicized fonts don't get clipped
SetRect ( & r , 0 , 0 , max_w , 1024 ) ;
m_d3dx_font [ PLAYLIST_FONT ] - > DrawTextW ( NULL , m_playlist [ i ] , - 1 , & r , dwFlags | DT_CALCRECT , 0xFFFFFFFF ) ;
int w = r . right - r . left ;
if ( w > 0 )
m_playlist_width_pixels = max ( m_playlist_width_pixels , w ) ;
}
else
{
m_playlist [ i ] [ 0 ] = 0 ;
}
}
if ( m_playlist_width_pixels = = 0 | |
m_playlist_width_pixels > max_w )
m_playlist_width_pixels = max_w ;
}
int start = max ( 0 , ( cur_page ) * disp_lines ) ;
int end = min ( nSongs , ( cur_page + 1 ) * disp_lines ) ;
// draw dark box around where the playlist will go:
RECT r ;
r . top = m_upper_left_corner_y ;
r . left = m_left_edge ;
r . right = m_left_edge + m_playlist_width_pixels + PLAYLIST_INNER_MARGIN * 2 ;
r . bottom = m_upper_left_corner_y + ( end - start ) * GetFontHeight ( PLAYLIST_FONT ) + PLAYLIST_INNER_MARGIN * 2 ;
DrawDarkTranslucentBox ( & r ) ;
//m_d3dx_font[PLAYLIST_FONT]->Begin();
// draw playlist text
int y = m_upper_left_corner_y + PLAYLIST_INNER_MARGIN ;
for ( int i = start ; i < end ; i + + )
{
SetRect ( & r , m_left_edge + PLAYLIST_INNER_MARGIN , y , m_left_edge + PLAYLIST_INNER_MARGIN + m_playlist_width_pixels , y + GetFontHeight ( PLAYLIST_FONT ) ) ;
if ( m_lpDX - > GetBitDepth ( ) = = 8 )
color = ( i = = m_playlist_pos ) ?
( i = = now_playing ? 0xFFFFFFFF : 0xFFFFFFFF ) :
( i = = now_playing ? 0xFFFFFFFF : 0xFF707070 ) ;
else
color = ( i = = m_playlist_pos ) ?
( i = = now_playing ? PLAYLIST_COLOR_BOTH : PLAYLIST_COLOR_HILITE_TRACK ) :
( i = = now_playing ? PLAYLIST_COLOR_PLAYING_TRACK : PLAYLIST_COLOR_NORMAL ) ;
y + = m_d3dx_font [ PLAYLIST_FONT ] - > DrawTextW ( NULL , m_playlist [ i - start ] , - 1 , & r , dwFlags , color ) ;
}
//m_d3dx_font[PLAYLIST_FONT]->End();
}
}
}
void CPluginShell : : SuggestHowToFreeSomeMem ( )
{
// This function is called when the plugin runs out of video memory;
// it lets you show a messagebox to the user so you can (intelligently)
// suggest how to free up some video memory, based on what settings
// they've chosen.
wchar_t str [ 1024 ] ;
if ( m_lpDX - > m_current_mode . multisamp ! = D3DMULTISAMPLE_NONE )
{
if ( m_lpDX - > m_current_mode . screenmode = = WINDOWED )
WASABI_API_LNGSTRINGW_BUF ( IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG , str , 2048 ) ;
else if ( m_lpDX - > m_current_mode . screenmode = = FAKE_FULLSCREEN )
WASABI_API_LNGSTRINGW_BUF ( IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_2 , str , 2048 ) ;
else
WASABI_API_LNGSTRINGW_BUF ( IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_3 , str , 2048 ) ;
}
else
if ( m_lpDX - > m_current_mode . screenmode = = FULLSCREEN ) // true fullscreen
WASABI_API_LNGSTRINGW_BUF ( IDS_TO_FREE_UP_VIDEO_MEMORY , str , 2048 ) ;
else // windowed, desktop mode, or fake fullscreen
WASABI_API_LNGSTRINGW_BUF ( IDS_TO_FREE_UP_VIDEO_MEMORY , str , 2048 ) ;
MessageBoxW ( m_lpDX - > GetHwnd ( ) , str , WASABI_API_LNGSTRINGW ( IDS_MILKDROP_SUGGESTION ) , MB_OK | MB_SETFOREGROUND | MB_TOPMOST ) ;
}
LRESULT CALLBACK CPluginShell : : WindowProc ( HWND hWnd , unsigned uMsg , WPARAM wParam , LPARAM lParam )
{
//if (uMsg==WM_GETDLGCODE)
// return DLGC_WANTALLKEYS|DLGC_WANTCHARS|DLGC_WANTMESSAGE; // this tells the embedwnd that we want keypresses to flow through to our client wnd.
if ( uMsg = = WM_CREATE )
{
CREATESTRUCT * create = ( CREATESTRUCT * ) lParam ;
SetWindowLongPtr ( hWnd , GWLP_USERDATA , ( LONG_PTR ) create - > lpCreateParams ) ;
}
CPluginShell * p = ( CPluginShell * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
if ( p )
return p - > PluginShellWindowProc ( hWnd , uMsg , wParam , lParam ) ;
else
return DefWindowProcW ( hWnd , uMsg , wParam , lParam ) ;
}
LRESULT CPluginShell : : PluginShellWindowProc ( HWND hWnd , unsigned uMsg , WPARAM wParam , LPARAM lParam )
{
USHORT mask = 1 < < ( sizeof ( SHORT ) * 8 - 1 ) ;
//bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0;
bool bCtrlHeldDown = ( GetKeyState ( VK_CONTROL ) & mask ) ! = 0 ;
//bool bAltHeldDown: most keys come in under WM_SYSKEYDOWN when ALT is depressed.
int i ;
# ifdef _DEBUG
char caption [ 256 ] = " WndProc: frame 0, " ;
if ( m_frame > 0 )
{
float time = m_time ;
int hours = ( int ) ( time / 3600 ) ;
time - = hours * 3600 ;
int minutes = ( int ) ( time / 60 ) ;
time - = minutes * 60 ;
int seconds = ( int ) time ;
time - = seconds ;
int dsec = ( int ) ( time * 100 ) ;
sprintf ( caption , " WndProc: frame %d, t=%dh:%02dm:%02d.%02ds, " , m_frame , hours , minutes , seconds , dsec ) ;
}
if ( uMsg ! = WM_MOUSEMOVE & &
uMsg ! = WM_NCHITTEST & &
uMsg ! = WM_SETCURSOR & &
uMsg ! = WM_COPYDATA & &
uMsg ! = WM_USER )
OutputDebugMessage ( caption , hWnd , uMsg , wParam , lParam ) ;
# endif
switch ( uMsg )
{
case WM_USER :
if ( m_screenmode = = DESKTOP )
{
// this function resides in vms_desktop.dll;
// its response will come later, via the WM_COPYDATA
// message (See below).
//KIV: **THIS CALL CRASHES EXPLORER IN VISTA**
getItemData ( wParam ) ;
return 0 ;
}
break ;
case WM_COPYDATA :
if ( m_screenmode = = DESKTOP )
{
// this message is vms_desktop.dll's response to
// our call to getItemData().
PCOPYDATASTRUCT c = ( PCOPYDATASTRUCT ) lParam ;
if ( c & & ( c - > cbData % sizeof ( icon_t ) = = 0 ) )
{
icon_t * pNewIcons = ( icon_t * ) c - > lpData ;
EnterCriticalSection ( & m_desktop_cs ) ;
if ( m_desktop_icon_state = = 1 & & ( c - > dwData & 0x80000000 ) ) // if doing a total refresh...
{
// ...we build the list from zero
int len = c - > dwData & 0xFFFF ;
for ( int i = 0 ; i < len ; i + + )
m_icon_list . push_back ( pNewIcons [ i ] ) ;
}
else if ( m_desktop_icon_state = = 3 & & ! ( c - > dwData & 0x80000000 ) )
{
// otherwise, we alter existing things in the list:
IconList : : iterator p ;
int start = c - > dwData & 0xFFFF ;
int len = c - > dwData > > 16 ;
int i = 0 ;
for ( p = m_icon_list . begin ( ) ; p ! = m_icon_list . end ( ) & & i < start ; p + + )
i + + ;
for ( ; p ! = m_icon_list . end ( ) & & i < start + len ; p + + )
{
p - > x = pNewIcons [ i - start ] . x ;
p - > y = pNewIcons [ i - start ] . y ;
memcpy ( p - > name , pNewIcons [ i - start ] . name , sizeof ( p - > name ) ) ;
memcpy ( p - > pidl , pNewIcons [ i - start ] . pidl , sizeof ( p - > pidl ) ) ;
i + + ;
}
m_desktop_icon_state = 2 ;
m_desktop_icon_update_frame = GetFrame ( ) ;
}
LeaveCriticalSection ( & m_desktop_cs ) ;
}
return 0 ;
}
break ;
case WM_ERASEBKGND :
// Repaint window when song is paused and image needs to be repainted:
if ( SendMessage ( m_hWndWinamp , WM_USER , 0 , 104 ) ! = 1 & & m_lpDX & & m_lpDX - > m_lpDevice & & GetFrame ( ) > 0 ) // WM_USER/104 return codes: 1=playing, 3=paused, other=stopped
{
m_lpDX - > m_lpDevice - > Present ( NULL , NULL , NULL , NULL ) ;
return 0 ;
}
break ;
case WM_WINDOWPOSCHANGING :
if (
m_screenmode = = DESKTOP
& & ( ! m_force_accept_WM_WINDOWPOSCHANGING )
& & m_lpDX & & m_lpDX - > m_ready
)
{
// unless we requested it ourselves or it's init time,
// prevent the fake desktop window from moving around
// in the Z order! (i.e., keep it on the bottom)
// without this code, when you click on the 'real' desktop
2024-09-29 02:04:03 +00:00
// in a multimon setup, any arch that are overtop of the
2024-09-24 12:54:57 +00:00
// 'fake' desktop will flash, since they'll be covered
// up by the fake desktop window (but then shown again on
// the next frame, when we detect that the fake desktop
// window isn't on bottom & send it back to the bottom).
LPWINDOWPOS pwp = ( LPWINDOWPOS ) lParam ;
if ( pwp )
pwp - > flags | = SWP_NOOWNERZORDER | SWP_NOZORDER ;
}
if ( m_screenmode = = WINDOWED & & m_lpDX & & m_lpDX - > m_ready & & m_lpDX - > m_current_mode . m_skin )
m_lpDX - > SaveWindow ( ) ;
break ;
case WM_NCACTIVATE :
// *Very Important Handler!*
// -Without this code, the app would not work properly when running in true
// fullscreen mode on multiple monitors; it would auto-minimize whenever the
// user clicked on a window in another display.
if ( wParam = = 0 & &
m_screenmode = = FULLSCREEN & &
m_frame > 0 & &
! m_exiting & &
m_lpDX & &
m_lpDX - > m_ready
& & m_lpDX - > m_lpD3D & &
m_lpDX - > m_lpD3D - > GetAdapterCount ( ) > 1
)
{
return 0 ;
}
break ;
case WM_DESTROY :
// note: don't post quit message here if the window is being destroyed
// and re-created on a switch between windowed & FAKE fullscreen modes.
if ( ! m_lpDX - > TempIgnoreDestroyMessages ( ) )
{
// this is a final exit, and not just destroy-then-recreate-the-window.
// so, flag DXContext so it knows that someone else
// will take care of destroying the window!
m_lpDX - > OnTrulyExiting ( ) ;
PostQuitMessage ( 0 ) ;
}
return FALSE ;
break ;
// benski> a little hack to get the window size correct. it seems to work
case WM_USER + 555 :
if ( m_lpDX & & m_lpDX - > m_ready & & m_screenmode = = WINDOWED & & ! m_resizing )
{
OnUserResizeWindow ( ) ;
m_lpDX - > SaveWindow ( ) ;
}
break ;
case WM_MOVE :
m_lpDX - > SaveWindow ( ) ;
break ;
case WM_SIZE :
// clear or set activity flag to reflect focus
if ( m_lpDX & & m_lpDX - > m_ready & & m_screenmode = = WINDOWED & & ! m_resizing )
{
m_hidden = ( SIZE_MAXHIDE = = wParam | | SIZE_MINIMIZED = = wParam ) ? TRUE : FALSE ;
if ( SIZE_MAXIMIZED = = wParam | | SIZE_RESTORED = = wParam ) // the window has been maximized or restored
OnUserResizeWindow ( ) ;
}
break ;
case WM_ENTERSIZEMOVE :
m_resizing = 1 ;
break ;
case WM_EXITSIZEMOVE :
if ( m_lpDX & & m_lpDX - > m_ready & & m_screenmode = = WINDOWED )
OnUserResizeWindow ( ) ;
m_lpDX - > SaveWindow ( ) ;
m_resizing = 0 ;
break ;
case WM_GETMINMAXINFO :
{
// don't let the window get too small
MINMAXINFO * p = ( MINMAXINFO * ) lParam ;
if ( p - > ptMinTrackSize . x < 64 )
p - > ptMinTrackSize . x = 64 ;
p - > ptMinTrackSize . y = p - > ptMinTrackSize . x * 3 / 4 ;
}
return 0 ;
case WM_MOUSEMOVE :
if ( m_screenmode = = DESKTOP & & ( m_desktop_dragging = = 1 | | m_desktop_box = = 1 ) )
{
m_desktop_drag_curpos . x = LOWORD ( lParam ) ;
m_desktop_drag_curpos . y = HIWORD ( lParam ) ;
if ( m_desktop_box = = 1 )
{
// update selection based on box coords
RECT box , temp ;
box . left = min ( m_desktop_drag_curpos . x , m_desktop_drag_startpos . x ) ;
box . right = max ( m_desktop_drag_curpos . x , m_desktop_drag_startpos . x ) ;
box . top = min ( m_desktop_drag_curpos . y , m_desktop_drag_startpos . y ) ;
box . bottom = max ( m_desktop_drag_curpos . y , m_desktop_drag_startpos . y ) ;
IconList : : iterator p ;
for ( p = m_icon_list . begin ( ) ; p ! = m_icon_list . end ( ) ; p + + )
{
p - > selected = 0 ;
if ( IntersectRect ( & temp , & box , & p - > label_rect ) )
p - > selected = 1 ;
else if ( IntersectRect ( & temp , & box , & p - > icon_rect ) )
p - > selected = 1 ;
}
}
// repaint window manually, if winamp is paused
if ( SendMessage ( m_hWndWinamp , WM_USER , 0 , 104 ) ! = 1 )
{
PushWindowToJustBeforeDesktop ( GetPluginWindow ( ) ) ;
DrawAndDisplay ( 1 ) ;
}
//return 0;
}
m_lpDX - > SaveWindow ( ) ;
break ;
case WM_LBUTTONUP :
if ( m_screenmode = = DESKTOP )
{
if ( m_desktop_dragging )
{
m_desktop_dragging = 0 ;
// move selected item(s) to new cursor position
int dx = LOWORD ( lParam ) - m_desktop_drag_startpos . x ;
int dy = HIWORD ( lParam ) - m_desktop_drag_startpos . y ;
if ( dx ! = 0 | | dy ! = 0 )
{
int idx = 0 ;
IconList : : iterator p ;
for ( p = m_icon_list . begin ( ) ; p ! = m_icon_list . end ( ) ; p + + )
{
if ( p - > selected )
{
SendMessage ( m_hWndDesktopListView , LVM_SETITEMPOSITION , idx , MAKELPARAM ( p - > x + dx , p - > y + dy ) ) ;
p - > x + = dx ;
p - > y + = dy ;
}
idx + + ;
}
}
// repaint window manually, if winamp is paused
if ( SendMessage ( m_hWndWinamp , WM_USER , 0 , 104 ) ! = 1 )
{
PushWindowToJustBeforeDesktop ( GetPluginWindow ( ) ) ;
DrawAndDisplay ( 1 ) ;
}
}
if ( m_desktop_box )
{
m_desktop_box = 0 ;
// repaint window manually, if winamp is paused
if ( SendMessage ( m_hWndWinamp , WM_USER , 0 , 104 ) ! = 1 )
{
PushWindowToJustBeforeDesktop ( GetPluginWindow ( ) ) ;
DrawAndDisplay ( 1 ) ;
}
}
//return 0;
}
break ;
case WM_USER + 1666 :
if ( wParam = = 1 & & lParam = = 15 )
{
if ( m_screenmode = = FULLSCREEN | | m_screenmode = = FAKE_FULLSCREEN )
ToggleFullScreen ( ) ;
}
return 0 ;
case WM_LBUTTONDOWN :
case WM_LBUTTONDBLCLK :
case WM_RBUTTONDOWN :
case WM_RBUTTONUP :
// Toggle between Fullscreen and Windowed modes on double-click
// note: this requires the 'CS_DBLCLKS' windowclass style!
if ( m_screenmode ! = DESKTOP )
{
SetFocus ( hWnd ) ;
if ( uMsg = = WM_LBUTTONDBLCLK & & m_frame > 0 )
{
ToggleFullScreen ( ) ;
return 0 ;
}
}
else
{
POINT pt ;
pt . x = LOWORD ( lParam ) ;
pt . y = HIWORD ( lParam ) ;
int done = 0 ;
for ( int pass = 0 ; pass < 2 & & ! done ; pass + + )
{
IconList : : iterator p ;
for ( p = m_icon_list . begin ( ) ; p ! = m_icon_list . end ( ) ; p + + )
{
RECT * pr = ( pass = = 0 ) ? & p - > icon_rect : & p - > label_rect ;
int bottom_extend = ( pass = = 0 ) ? 3 : 0 ; // accepts clicks in the 3-pixel gap between the icon and the text label.
if ( pt . x > = pr - > left & &
pt . x < = pr - > right & &
pt . y > = pr - > top & &
pt . y < = pr - > bottom + bottom_extend )
{
switch ( uMsg )
{
case WM_RBUTTONUP :
//pt.x += m_lpDX->m_monitor_rect.left;
//pt.y += m_lpDX->m_monitor_rect.top;
DoExplorerMenu ( GetPluginWindow ( ) , ( LPITEMIDLIST ) p - > pidl , pt ) ;
break ;
case WM_LBUTTONDBLCLK :
{
char buf [ MAX_PATH ] ;
sprintf ( buf , " %s \\ %s " , m_szDesktopFolder , p - > name ) ;
ExecutePidl ( ( LPITEMIDLIST ) p - > pidl , buf , m_szDesktopFolder , GetPluginWindow ( ) ) ;
}
break ;
case WM_LBUTTONDOWN :
m_desktop_dragging = 1 ;
memcpy ( m_desktop_drag_pidl , p - > pidl , sizeof ( m_desktop_drag_pidl ) ) ;
m_desktop_drag_startpos . x = LOWORD ( lParam ) ;
m_desktop_drag_startpos . y = HIWORD ( lParam ) ;
m_desktop_drag_curpos . x = LOWORD ( lParam ) ;
m_desktop_drag_curpos . y = HIWORD ( lParam ) ;
if ( ! ( wParam & MK_CONTROL ) ) // if CTRL not held down
{
if ( ! p - > selected )
{
DeselectDesktop ( ) ;
p - > selected = 1 ;
}
}
else
{
p - > selected = 1 - p - > selected ;
}
break ;
case WM_RBUTTONDOWN :
DeselectDesktop ( ) ;
p - > selected = 1 ;
break ;
}
done = 1 ;
break ;
}
}
}
if ( ! done )
{
// deselect all, unless they're CTRL+clicking and missed an icon.
if ( uMsg ! = WM_LBUTTONDOWN | | ! ( wParam & MK_CONTROL ) )
DeselectDesktop ( ) ;
if ( uMsg = = WM_RBUTTONUP ) // || uMsg==WM_RBUTTONDOWN)
{
// note: can't use GetMenu and TrackPopupMenu here because the hwnd param to TrackPopupMenu must belong to current application.
// (before sending coords to desktop window, xform them into its client coords:)
POINT pt ;
pt . x = LOWORD ( lParam ) ;
pt . y = HIWORD ( lParam ) ;
ScreenToClient ( m_hWndDesktopListView , & pt ) ;
lParam = MAKELPARAM ( pt . x + m_lpDX - > m_monitor_rect . left , pt . y + m_lpDX - > m_monitor_rect . top ) ;
PostMessage ( m_hWndDesktopListView , uMsg , wParam , lParam ) ;
//PostMessage(m_hWndDesktopListView, WM_CONTEXTMENU, (WPARAM)m_hWndDesktopListView, lParam);
}
else if ( uMsg = = WM_LBUTTONDOWN )
{
m_desktop_box = 1 ;
m_desktop_drag_startpos . x = LOWORD ( lParam ) ;
m_desktop_drag_startpos . y = HIWORD ( lParam ) ;
m_desktop_drag_curpos . x = LOWORD ( lParam ) ;
m_desktop_drag_curpos . y = HIWORD ( lParam ) ;
}
}
// repaint window manually, if winamp is paused
if ( SendMessage ( m_hWndWinamp , WM_USER , 0 , 104 ) ! = 1 )
{
PushWindowToJustBeforeDesktop ( GetPluginWindow ( ) ) ;
DrawAndDisplay ( 1 ) ;
}
//return 0;
}
break ;
case WM_SETFOCUS :
// note: this msg never comes in when embedwnd is used, but that's ok, because that's only
// in Windowed mode, and m_lost_focus only makes us sleep when fullscreen.
m_lost_focus = 0 ;
break ;
case WM_KILLFOCUS :
// note: this msg never comes in when embedwnd is used, but that's ok, because that's only
// in Windowed mode, and m_lost_focus only makes us sleep when fullscreen.
m_lost_focus = 1 ;
break ;
case WM_SETCURSOR :
if (
( m_screenmode = = FULLSCREEN ) | |
( m_screenmode = = FAKE_FULLSCREEN & & m_lpDX - > m_fake_fs_covers_all )
)
{
// hide the cursor
SetCursor ( NULL ) ;
return TRUE ; // prevent Windows from setting cursor to window class cursor
}
break ;
case WM_NCHITTEST :
// Prevent the user from selecting the menu in fullscreen mode
if ( m_screenmode ! = WINDOWED )
return HTCLIENT ;
break ;
case WM_SYSCOMMAND :
// Prevent *moving/sizing* and *entering standby mode* when in fullscreen mode
switch ( wParam )
{
case SC_MOVE :
case SC_SIZE :
case SC_MAXIMIZE :
case SC_KEYMENU :
if ( m_screenmode ! = WINDOWED )
return 1 ;
break ;
case SC_MONITORPOWER :
if ( m_screenmode = = FULLSCREEN | | m_screenmode = = FAKE_FULLSCREEN )
return 1 ;
break ;
}
break ;
case WM_CONTEXTMENU :
// launch popup context menu. see handler for WM_COMMAND also.
if ( m_screenmode = = DESKTOP )
{
// note: execution should never reach this point,
// because we don't pass WM_RBUTTONUP to DefWindowProc
// when in desktop mode!
return 0 ;
}
else if ( m_screenmode = = WINDOWED ) // context menus only allowed in ~windowed modes
{
TrackPopupMenuEx ( m_context_menu , TPM_VERTICAL , LOWORD ( lParam ) , HIWORD ( lParam ) , hWnd , NULL ) ;
return 0 ;
}
break ;
case WM_COMMAND :
// handle clicks on items on context menu.
if ( m_screenmode = = WINDOWED )
{
switch ( LOWORD ( wParam ) )
{
case ID_QUIT :
m_exiting = 1 ;
PostMessage ( hWnd , WM_CLOSE , 0 , 0 ) ;
return 0 ;
case ID_GO_FS :
if ( m_frame > 0 )
ToggleFullScreen ( ) ;
return 0 ;
case ID_DESKTOP_MODE :
if ( m_frame > 0 )
ToggleDesktop ( ) ;
return 0 ;
case ID_SHOWHELP :
ToggleHelp ( ) ;
return 0 ;
case ID_SHOWPLAYLIST :
TogglePlaylist ( ) ;
return 0 ;
}
// then allow the plugin to override any command:
if ( MyWindowProc ( hWnd , uMsg , wParam , lParam ) = = 0 )
return 0 ;
}
break ;
/*
KEY HANDLING : the basic idea :
- in all cases , handle or capture :
- ZXCVBRS , zxcvbrs
- also make sure it ' s case - insensitive ! ( lowercase come through only as WM_CHAR ; uppercase come in as both )
- ( ALT + ENTER )
- ( F1 , ESC , UP , DN , Left , Right , SHIFT + l / r )
- ( P for playlist )
- when playlist showing : steal J , HOME , END , PGUP , PGDN , UP , DOWN , ESC
- ( BLOCK J , L )
- when integrated with winamp ( using embedwnd ) , also handle these keys :
- j , l , L , CTRL + L [ windowed mode only ! ]
- CTRL + P , CTRL + D
- CTRL + TAB
- ALT - E
- ALT + F ( main menu )
- ALT + 3 ( id3 )
*/
case WM_SYSKEYDOWN :
if ( wParam = = VK_RETURN & & m_frame > 0 )
{
ToggleFullScreen ( ) ;
return 0 ;
}
// if in embedded mode (using winamp skin), pass ALT+ keys on to winamp
// ex: ALT+E, ALT+F, ALT+3...
if ( m_screenmode = = WINDOWED & & m_lpDX - > m_current_mode . m_skin )
return PostMessage ( m_hWndWinamp , uMsg , wParam , lParam ) ; // force-pass to winamp; required for embedwnd
break ;
case WM_SYSKEYUP :
if ( m_screenmode = = WINDOWED & & m_lpDX - > m_current_mode . m_skin )
return PostMessage ( m_hWndWinamp , uMsg , wParam , lParam ) ; // force-pass to winamp; required for embedwnd
break ;
case WM_SYSCHAR :
if ( ( wParam = = ' k ' | | wParam = = ' K ' ) )
{
OnAltK ( ) ;
return 0 ;
}
if ( ( wParam = = ' d ' | | wParam = = ' D ' ) & & m_frame > 0 )
{
ToggleDesktop ( ) ;
return 0 ;
}
break ;
case WM_CHAR :
// if playlist is showing, steal p/j keys from the plugin:
if ( m_show_playlist )
{
switch ( wParam )
{
case ' j ' :
case ' J ' :
m_playlist_pos = SendMessage ( m_hWndWinamp , WM_USER , 0 , 125 ) ;
return 0 ;
default :
{
int nSongs = SendMessage ( m_hWndWinamp , WM_USER , 0 , 124 ) ;
int found = 0 ;
int orig_pos = m_playlist_pos ;
int inc = ( wParam > = ' A ' & & wParam < = ' Z ' ) ? - 1 : 1 ;
while ( 1 )
{
if ( inc = = 1 & & m_playlist_pos > = nSongs - 1 )
break ;
if ( inc = = - 1 & & m_playlist_pos < = 0 )
break ;
m_playlist_pos + = inc ;
char buf [ 32 ] ;
strncpy ( buf , ( char * ) SendMessage ( m_hWndWinamp , WM_USER , m_playlist_pos , 212 ) , 31 ) ;
buf [ 31 ] = 0 ;
// remove song # and period from beginning
char * p = buf ;
while ( * p > = ' 0 ' & & * p < = ' 9 ' ) p + + ;
if ( * p = = ' . ' & & * ( p + 1 ) = = ' ' )
{
p + = 2 ;
int pos = 0 ;
while ( * p ! = 0 )
{
buf [ pos + + ] = * p ;
p + + ;
}
buf [ pos + + ] = 0 ;
}
int wParam2 = ( wParam > = ' A ' & & wParam < = ' Z ' ) ? ( wParam + ' a ' - ' A ' ) : ( wParam + ' A ' - ' a ' ) ;
if ( buf [ 0 ] = = wParam | | buf [ 0 ] = = wParam2 )
{
found = 1 ;
break ;
}
}
if ( ! found )
m_playlist_pos = orig_pos ;
}
return 0 ;
}
}
// then allow the plugin to override any keys:
if ( MyWindowProc ( hWnd , uMsg , wParam , lParam ) = = 0 )
return 0 ;
// finally, default key actions:
if ( wParam = = keyMappings [ 5 ] | | wParam = = keyMappings [ 6 ] ) // 'z' or 'Z'
{
PostMessage ( m_hWndWinamp , WM_COMMAND , 40044 , 0 ) ;
return 0 ;
}
else
{
switch ( wParam )
{
// WINAMP PLAYBACK CONTROL KEYS:
case ' x ' :
case ' X ' :
PostMessage ( m_hWndWinamp , WM_COMMAND , 40045 , 0 ) ;
return 0 ;
case ' c ' :
case ' C ' :
PostMessage ( m_hWndWinamp , WM_COMMAND , 40046 , 0 ) ;
return 0 ;
case ' v ' :
case ' V ' :
PostMessage ( m_hWndWinamp , WM_COMMAND , 40047 , 0 ) ;
return 0 ;
case ' b ' :
case ' B ' :
PostMessage ( m_hWndWinamp , WM_COMMAND , 40048 , 0 ) ;
return 0 ;
case ' s ' :
case ' S ' :
//if (SendMessage(m_hWndWinamp,WM_USER,0,250))
// sprintf(m_szUserMessage, "shuffle is now OFF"); // shuffle was on
//else
// sprintf(m_szUserMessage, "shuffle is now ON"); // shuffle was off
// toggle shuffle
PostMessage ( m_hWndWinamp , WM_COMMAND , 40023 , 0 ) ;
return 0 ;
case ' r ' :
case ' R ' :
// toggle repeat
PostMessage ( m_hWndWinamp , WM_COMMAND , 40022 , 0 ) ;
return 0 ;
case ' p ' :
case ' P ' :
TogglePlaylist ( ) ;
return 0 ;
case ' l ' :
// note that this is actually correct; when you hit 'l' from the
// MAIN winamp window, you get an "open files" dialog; when you hit
// 'l' from the playlist editor, you get an "add files to playlist" dialog.
// (that sends IDC_PLAYLIST_ADDMP3==1032 to the playlist, which we can't
// do from here.)
PostMessage ( m_hWndWinamp , WM_COMMAND , 40029 , 0 ) ;
return 0 ;
case ' L ' :
PostMessage ( m_hWndWinamp , WM_COMMAND , 40187 , 0 ) ;
return 0 ;
case ' j ' :
PostMessage ( m_hWndWinamp , WM_COMMAND , 40194 , 0 ) ;
return 0 ;
}
return 0 ; //DefWindowProc(hWnd,uMsg,wParam,lParam);
}
break ; // end case WM_CHAR
case WM_KEYUP :
// allow the plugin to override any keys:
if ( MyWindowProc ( hWnd , uMsg , wParam , lParam ) = = 0 )
return 0 ;
/*
switch ( wParam )
{
case VK_SOMETHING :
. . .
break ;
}
*/
return 0 ;
break ;
case WM_KEYDOWN :
if ( m_show_playlist )
{
switch ( wParam )
{
case VK_ESCAPE :
if ( m_show_playlist )
TogglePlaylist ( ) ;
//m_show_playlist = 0;
return 0 ;
case VK_UP :
{
int nRepeat = lParam & 0xFFFF ;
if ( GetKeyState ( VK_SHIFT ) & mask )
m_playlist_pos - = 10 * nRepeat ;
else
m_playlist_pos - = nRepeat ;
}
return 0 ;
case VK_DOWN :
{
int nRepeat = lParam & 0xFFFF ;
if ( GetKeyState ( VK_SHIFT ) & mask )
m_playlist_pos + = 10 * nRepeat ;
else
m_playlist_pos + = nRepeat ;
}
return 0 ;
case VK_HOME :
m_playlist_pos = 0 ;
return 0 ;
case VK_END :
m_playlist_pos = SendMessage ( m_hWndWinamp , WM_USER , 0 , 124 ) - 1 ;
return 0 ;
case VK_PRIOR :
if ( GetKeyState ( VK_SHIFT ) & mask )
m_playlist_pageups + = 10 ;
else
m_playlist_pageups + + ;
return 0 ;
case VK_NEXT :
if ( GetKeyState ( VK_SHIFT ) & mask )
m_playlist_pageups - = 10 ;
else
m_playlist_pageups - - ;
return 0 ;
case VK_RETURN :
SendMessage ( m_hWndWinamp , WM_USER , m_playlist_pos , 121 ) ; // set sel
SendMessage ( m_hWndWinamp , WM_COMMAND , 40045 , 0 ) ; // play it
return 0 ;
}
}
// allow the plugin to override any keys:
if ( MyWindowProc ( hWnd , uMsg , wParam , lParam ) = = 0 )
return 0 ;
switch ( wParam )
{
case VK_F1 :
m_show_press_f1_msg = 0 ;
ToggleHelp ( ) ;
return 0 ;
case VK_ESCAPE :
if ( m_show_help )
ToggleHelp ( ) ;
else
{
if ( m_screenmode = = FAKE_FULLSCREEN | | m_screenmode = = FULLSCREEN )
{
ToggleFullScreen ( ) ;
}
else if ( m_screenmode = = DESKTOP )
{
ToggleDesktop ( ) ;
}
// exit the program on escape
//m_exiting = 1;
//PostMessage(hWnd, WM_CLOSE, 0, 0);
}
return 0 ;
case VK_UP :
// increase volume
{
int nRepeat = lParam & 0xFFFF ;
for ( i = 0 ; i < nRepeat * 2 ; i + + ) PostMessage ( m_hWndWinamp , WM_COMMAND , 40058 , 0 ) ;
}
return 0 ;
case VK_DOWN :
// decrease volume
{
int nRepeat = lParam & 0xFFFF ;
for ( i = 0 ; i < nRepeat * 2 ; i + + ) PostMessage ( m_hWndWinamp , WM_COMMAND , 40059 , 0 ) ;
}
return 0 ;
case VK_LEFT :
case VK_RIGHT :
{
bool bShiftHeldDown = ( GetKeyState ( VK_SHIFT ) & mask ) ! = 0 ;
int cmd = ( wParam = = VK_LEFT ) ? 40144 : 40148 ;
int nRepeat = lParam & 0xFFFF ;
int reps = ( bShiftHeldDown ) ? 6 * nRepeat : 1 * nRepeat ;
for ( int i = 0 ; i < reps ; i + + )
PostMessage ( m_hWndWinamp , WM_COMMAND , cmd , 0 ) ;
}
return 0 ;
default :
// pass CTRL+A thru CTRL+Z, and also CTRL+TAB, to winamp, *if we're in windowed mode* and using an embedded window.
// be careful though; uppercase chars come both here AND to WM_CHAR handler,
// so we have to eat some of them here, to avoid them from acting twice.
if ( m_screenmode = = WINDOWED & & m_lpDX & & m_lpDX - > m_current_mode . m_skin )
{
if ( bCtrlHeldDown & & ( ( wParam > = ' A ' & & wParam < = ' Z ' ) | | wParam = = VK_TAB ) )
{
PostMessage ( m_hWndWinamp , uMsg , wParam , lParam ) ;
return 0 ;
}
}
return 0 ;
}
return 0 ;
break ;
}
return MyWindowProc ( hWnd , uMsg , wParam , lParam ) ; //DefWindowProc(hWnd, uMsg, wParam, lParam);
//return 0L;
}
LRESULT CALLBACK CPluginShell : : DesktopWndProc ( HWND hWnd , unsigned uMsg , WPARAM wParam , LPARAM lParam )
{
CPluginShell * p = ( CPluginShell * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
if ( p )
return p - > PluginShellDesktopWndProc ( hWnd , uMsg , wParam , lParam ) ;
else
return DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
}
LRESULT CPluginShell : : PluginShellDesktopWndProc ( HWND hWnd , unsigned uMsg , WPARAM wParam , LPARAM lParam )
{
//#ifdef _DEBUG
// OutputDebugMessage("kbfocus", hWnd, uMsg, wParam, lParam);
//#endif
switch ( uMsg )
{
case WM_KEYDOWN :
case WM_KEYUP :
case WM_CHAR :
case WM_SYSCHAR :
case WM_SYSKEYDOWN :
case WM_SYSKEYUP :
//PostMessage(GetPluginWindow(), uMsg, wParam, lParam);
PluginShellWindowProc ( GetPluginWindow ( ) , uMsg , wParam , lParam ) ;
return 0 ;
break ;
}
return DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
}
void CPluginShell : : AlignWaves ( )
{
// align waves, using recursive (mipmap-style) least-error matching
// note: NUM_WAVEFORM_SAMPLES must be between 32 and 576.
int align_offset [ 2 ] = { 0 , 0 } ;
# if (NUM_WAVEFORM_SAMPLES < 576) // [don't let this code bloat our DLL size if it's not going to be used]
int nSamples = NUM_WAVEFORM_SAMPLES ;
# define MAX_OCTAVES 10
int octaves = ( int ) floorf ( logf ( ( float ) ( 576 - nSamples ) ) / logf ( 2.0f ) ) ;
if ( octaves < 4 )
return ;
if ( octaves > MAX_OCTAVES )
octaves = MAX_OCTAVES ;
for ( int ch = 0 ; ch < 2 ; ch + + )
{
// only worry about matching the lower 'nSamples' samples
float temp_new [ MAX_OCTAVES ] [ 576 ] ;
float temp_old [ MAX_OCTAVES ] [ 576 ] ;
static float temp_weight [ MAX_OCTAVES ] [ 576 ] ;
static int first_nonzero_weight [ MAX_OCTAVES ] ;
static int last_nonzero_weight [ MAX_OCTAVES ] ;
int spls [ MAX_OCTAVES ] ;
int space [ MAX_OCTAVES ] ;
memcpy ( temp_new [ 0 ] , m_sound . fWaveform [ ch ] , sizeof ( float ) * 576 ) ;
memcpy ( temp_old [ 0 ] , & m_oldwave [ ch ] [ m_prev_align_offset [ ch ] ] , sizeof ( float ) * nSamples ) ;
spls [ 0 ] = 576 ;
space [ 0 ] = 576 - nSamples ;
// potential optimization: could reuse (instead of recompute) mip levels for m_oldwave[2][]?
int octave = 0 ;
for ( octave = 1 ; octave < octaves ; octave + + )
{
spls [ octave ] = spls [ octave - 1 ] / 2 ;
space [ octave ] = space [ octave - 1 ] / 2 ;
for ( int n = 0 ; n < spls [ octave ] ; n + + )
{
temp_new [ octave ] [ n ] = 0.5f * ( temp_new [ octave - 1 ] [ n * 2 ] + temp_new [ octave - 1 ] [ n * 2 + 1 ] ) ;
temp_old [ octave ] [ n ] = 0.5f * ( temp_old [ octave - 1 ] [ n * 2 ] + temp_old [ octave - 1 ] [ n * 2 + 1 ] ) ;
}
}
if ( ! m_align_weights_ready )
{
m_align_weights_ready = 1 ;
for ( octave = 0 ; octave < octaves ; octave + + )
{
int compare_samples = spls [ octave ] - space [ octave ] ;
int n = 0 ;
for ( n = 0 ; n < compare_samples ; n + + )
{
// start with pyramid-shaped pdf, from 0..1..0
if ( n < compare_samples / 2 )
temp_weight [ octave ] [ n ] = n * 2 / ( float ) compare_samples ;
else
temp_weight [ octave ] [ n ] = ( compare_samples - 1 - n ) * 2 / ( float ) compare_samples ;
// TWEAK how much the center matters, vs. the edges:
temp_weight [ octave ] [ n ] = ( temp_weight [ octave ] [ n ] - 0.8f ) * 5.0f + 0.8f ;
// clip:
if ( temp_weight [ octave ] [ n ] > 1 ) temp_weight [ octave ] [ n ] = 1 ;
if ( temp_weight [ octave ] [ n ] < 0 ) temp_weight [ octave ] [ n ] = 0 ;
}
n = 0 ;
while ( temp_weight [ octave ] [ n ] = = 0 & & n < compare_samples )
n + + ;
first_nonzero_weight [ octave ] = n ;
n = compare_samples - 1 ;
while ( temp_weight [ octave ] [ n ] = = 0 & & n > = 0 )
n - - ;
last_nonzero_weight [ octave ] = n ;
}
}
int n1 = 0 ;
int n2 = space [ octaves - 1 ] ;
for ( octave = octaves - 1 ; octave > = 0 ; octave - - )
{
// for example:
// space[octave] == 4
// spls[octave] == 36
// (so we test 32 samples, w/4 offsets)
int compare_samples = spls [ octave ] - space [ octave ] ;
int lowest_err_offset = - 1 ;
float lowest_err_amount = 0 ;
for ( int n = n1 ; n < n2 ; n + + )
{
float err_sum = 0 ;
//for (int i=0; i<compare_samples; i++)
for ( int i = first_nonzero_weight [ octave ] ; i < = last_nonzero_weight [ octave ] ; i + + )
{
float x = ( temp_new [ octave ] [ i + n ] - temp_old [ octave ] [ i ] ) * temp_weight [ octave ] [ i ] ;
if ( x > 0 )
err_sum + = x ;
else
err_sum - = x ;
}
if ( lowest_err_offset = = - 1 | | err_sum < lowest_err_amount )
{
lowest_err_offset = n ;
lowest_err_amount = err_sum ;
}
}
// now use 'lowest_err_offset' to guide bounds of search in next octave:
// space[octave] == 8
// spls[octave] == 72
// -say 'lowest_err_offset' was 2
// -that corresponds to samples 4 & 5 of the next octave
// -also, expand about this by 2 samples? YES.
// (so we'd test 64 samples, w/8->4 offsets)
if ( octave > 0 )
{
n1 = lowest_err_offset * 2 - 1 ;
n2 = lowest_err_offset * 2 + 2 + 1 ;
if ( n1 < 0 ) n1 = 0 ;
if ( n2 > space [ octave - 1 ] ) n2 = space [ octave - 1 ] ;
}
else
align_offset [ ch ] = lowest_err_offset ;
}
}
# endif
memcpy ( m_oldwave [ 0 ] , m_sound . fWaveform [ 0 ] , sizeof ( float ) * 576 ) ;
memcpy ( m_oldwave [ 1 ] , m_sound . fWaveform [ 1 ] , sizeof ( float ) * 576 ) ;
m_prev_align_offset [ 0 ] = align_offset [ 0 ] ;
m_prev_align_offset [ 1 ] = align_offset [ 1 ] ;
// finally, apply the results: modify m_sound.fWaveform[2][0..576]
// by scooting the aligned samples so that they start at m_sound.fWaveform[2][0].
for ( int ch = 0 ; ch < 2 ; ch + + )
if ( align_offset [ ch ] > 0 )
{
for ( int i = 0 ; i < nSamples ; i + + )
m_sound . fWaveform [ ch ] [ i ] = m_sound . fWaveform [ ch ] [ i + align_offset [ ch ] ] ;
// zero the rest out, so it's visually evident that these samples are now bogus:
memset ( & m_sound . fWaveform [ ch ] [ nSamples ] , 0 , ( 576 - nSamples ) * sizeof ( float ) ) ;
}
}
LRESULT CALLBACK CPluginShell : : VJModeWndProc ( HWND hWnd , unsigned uMsg , WPARAM wParam , LPARAM lParam )
{
CPluginShell * p = ( CPluginShell * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
if ( p )
return p - > PluginShellVJModeWndProc ( hWnd , uMsg , wParam , lParam ) ;
else
return DefWindowProc ( hWnd , uMsg , wParam , lParam ) ;
}
LRESULT CPluginShell : : PluginShellVJModeWndProc ( HWND hwnd , UINT message , WPARAM wParam , LPARAM lParam )
{
# ifdef _DEBUG
if ( message ! = WM_MOUSEMOVE & &
message ! = WM_NCHITTEST & &
message ! = WM_SETCURSOR & &
message ! = WM_COPYDATA & &
message ! = WM_USER )
{
char caption [ 256 ] = " VJWndProc: frame 0, " ;
if ( m_frame > 0 )
{
float time = m_time ;
int hours = ( int ) ( time / 3600 ) ;
time - = hours * 3600 ;
int minutes = ( int ) ( time / 60 ) ;
time - = minutes * 60 ;
int seconds = ( int ) time ;
time - = seconds ;
int dsec = ( int ) ( time * 100 ) ;
sprintf ( caption , " VJWndProc: frame %d, t=%dh:%02dm:%02d.%02ds, " , m_frame , hours , minutes , seconds , dsec ) ;
}
OutputDebugMessage ( caption , hwnd , message , wParam , lParam ) ;
}
# endif
switch ( message )
{
case WM_KEYDOWN :
case WM_KEYUP :
case WM_CHAR :
case WM_SYSKEYDOWN :
case WM_SYSKEYUP :
case WM_SYSCHAR :
// pass keystrokes on to plugin!
return PluginShellWindowProc ( GetPluginWindow ( ) , message , wParam , lParam ) ;
case WM_ERASEBKGND :
// Repaint window when song is paused and image needs to be repainted:
if ( SendMessage ( m_hWndWinamp , WM_USER , 0 , 104 ) ! = 1 & & m_vjd3d9_device & & GetFrame ( ) > 0 ) // WM_USER/104 return codes: 1=playing, 3=paused, other=stopped
{
m_vjd3d9_device - > Present ( NULL , NULL , NULL , NULL ) ;
return 0 ;
}
break ;
/*
case WM_WINDOWPOSCHANGING :
if ( m_screenmode = = DESKTOP )
{
LPWINDOWPOS pwp = ( LPWINDOWPOS ) lParam ;
if ( pwp )
pwp - > flags | = SWP_NOOWNERZORDER | SWP_NOZORDER ;
}
break ;
case WM_ACTIVATEAPP :
// *Very Important Handler!*
// -Without this code, the app would not work properly when running in true
// fullscreen mode on multiple monitors; it would auto-minimize whenever the
// user clicked on a window in another display.
if ( wParam = = 1 & &
m_screenmode = = DESKTOP & &
m_frame > 0 & &
! m_exiting
)
{
return 0 ;
}
break ;
/*
case WM_NCACTIVATE :
// *Very Important Handler!*
// -Without this code, the app would not work properly when running in true
// fullscreen mode on multiple monitors; it would auto-minimize whenever the
// user clicked on a window in another display.
// (NOTE: main window also handles this message this way)
if ( wParam = = 0 & &
m_screenmode = = FULLSCREEN & &
m_frame > 0 & &
! m_exiting & &
m_lpDX & &
m_lpDX - > m_ready
& & m_lpDX - > m_lpD3D & &
m_lpDX - > m_lpD3D - > GetAdapterCount ( ) > 1
)
{
return 0 ;
}
break ;
*/
/*
case WM_ACTIVATEAPP :
if ( wParam = = 1 & &
m_screenmode = = DESKTOP & &
m_frame > 0 & &
! m_exiting & &
m_vjd3d9_device
)
{
return 0 ;
}
break ;
*/
/*
case WM_WINDOWPOSCHANGING :
if (
m_screenmode = = DESKTOP
& & ( ! m_force_accept_WM_WINDOWPOSCHANGING )
& & m_lpDX & & m_lpDX - > m_ready
)
{
// unless we requested it ourselves or it's init time,
// prevent the fake desktop window from moving around
// in the Z order! (i.e., keep it on the bottom)
// without this code, when you click on the 'real' desktop
2024-09-29 02:04:03 +00:00
// in a multimon setup, any arch that are overtop of the
2024-09-24 12:54:57 +00:00
// 'fake' desktop will flash, since they'll be covered
// up by the fake desktop window (but then shown again on
// the next frame, when we detect that the fake desktop
// window isn't on bottom & send it back to the bottom).
LPWINDOWPOS pwp = ( LPWINDOWPOS ) lParam ;
if ( pwp )
pwp - > flags | = SWP_NOOWNERZORDER | SWP_NOZORDER ;
}
break ;
*/
case WM_CLOSE :
// if they close the VJ window (by some means other than ESC key),
// this will make the graphics window close, too.
m_exiting = 1 ;
if ( GetPluginWindow ( ) )
PostMessage ( GetPluginWindow ( ) , WM_CLOSE , 0 , 0 ) ;
break ;
case WM_GETMINMAXINFO :
{
// don't let the window get too small
MINMAXINFO * p = ( MINMAXINFO * ) lParam ;
if ( p - > ptMinTrackSize . x < 64 )
p - > ptMinTrackSize . x = 64 ;
p - > ptMinTrackSize . y = p - > ptMinTrackSize . x * 3 / 4 ;
}
return 0 ;
case WM_SIZE :
// clear or set activity flag to reflect focus
if ( m_vjd3d9_device & & ! m_resizing_textwnd )
{
m_hidden_textwnd = ( SIZE_MAXHIDE = = wParam | | SIZE_MINIMIZED = = wParam ) ? TRUE : FALSE ;
if ( SIZE_MAXIMIZED = = wParam | | SIZE_RESTORED = = wParam ) // the window has been maximized or restored
OnUserResizeTextWindow ( ) ;
}
break ;
case WM_ENTERSIZEMOVE :
m_resizing_textwnd = 1 ;
break ;
case WM_EXITSIZEMOVE :
if ( m_vjd3d9_device )
OnUserResizeTextWindow ( ) ;
m_resizing_textwnd = 0 ;
break ;
}
return DefWindowProc ( hwnd , message , wParam , lParam ) ;
}