diff --git a/Agave/Language/api_language.h b/Agave/Language/api_language.h new file mode 100644 index 0000000..4cb78b2 --- /dev/null +++ b/Agave/Language/api_language.h @@ -0,0 +1,326 @@ +#ifndef NULLSOFT_API_LANGUAGE_H +#define NULLSOFT_API_LANGUAGE_H + +#include +#include "lang.h" +#include + +#if (_MSC_VER <= 1200) + struct threadlocaleinfostruct; + struct threadmbcinfostruct; + typedef struct threadlocaleinfostruct * pthreadlocinfo; + typedef struct threadmbcinfostruct * pthreadmbcinfo; + + typedef struct localeinfo_struct + { + pthreadlocinfo locinfo; + pthreadmbcinfo mbcinfo; + } _locale_tstruct, *_locale_t; +#endif + +class api_language : public Dispatchable +{ +protected: + api_language() {} + ~api_language() {} +public: + char *GetString(HINSTANCE hinst, HINSTANCE owner, UINT uID, char *str=NULL, size_t maxlen=0); + wchar_t *GetStringW(HINSTANCE hinst, HINSTANCE owner, UINT uID, wchar_t *str=NULL, size_t maxlen=0); + + char *GetStringFromGUID(const GUID guid, HINSTANCE owner, UINT uID, char *str=NULL, size_t maxlen=0); + wchar_t *GetStringFromGUIDW(const GUID guid, HINSTANCE owner, UINT uID, wchar_t *str=NULL, size_t maxlen=0); + + HINSTANCE FindDllHandleByGUID(GUID guid); + HINSTANCE FindDllHandleByString(const char* str); + HINSTANCE FindDllHandleByStringW(const wchar_t* str); + HINSTANCE StartLanguageSupport(HINSTANCE hinstance, const GUID guid); + + const wchar_t *GetLanguageFolder(); + + #define LANG_IDENT_STR 0 + #define LANG_LANG_CODE 1 + #define LANG_COUNTRY_CODE 2 + const wchar_t *GetLanguageIdentifier(int mode); + + HWND CreateLDialogParam(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param); + INT_PTR LDialogBoxParam(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param); + HMENU LoadLMenu(HINSTANCE localised, HINSTANCE original, UINT id); + + HWND CreateLDialogParamW(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param); + INT_PTR LDialogBoxParamW(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param); + HMENU LoadLMenuW(HINSTANCE localised, HINSTANCE original, UINT id); + + void* LoadResourceFromFile(HINSTANCE hinst, HINSTANCE owner, LPCTSTR lpType, LPCTSTR lpName, DWORD* size); + void* LoadResourceFromFileW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpType, LPCWSTR lpName, DWORD* size); + + HACCEL LoadAcceleratorsA(HINSTANCE hinst, HINSTANCE owner, LPCSTR lpTableName); + HACCEL LoadAcceleratorsW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpTableName); + + // Implemented in 5.58+ + // When called this will attempt to set the locale used for numeric representation + // to that of the user running the current Winamp instance as long as the language + // and country identifiers match those reported within the language pack (if used) + // + // If you're running under a different thread then this will need to be called as + // the locale is set on a per thread basis which generally means anything under the + // Winamp process will be handled correctly unless a UI aspect is running under a + // different thread. Internally this is called within winamp.exe and vis_milk2.dll + BOOL UseUserNumericLocale(); + + // Get_C_NumericLocale() is a wrapper for _create_locale(LC_NUMERIC, "C") which can + // then be used in _atof_l(..), _sscanf_l(..) or other locale based functions when + // you need to process numbers without localisation handling ie the "C" locale. + // This function is provided for convenience unless you want to do it all manually. + _locale_t Get_C_NumericLocale(); + + // Implemented in 5.7+ + wchar_t* FormattedSizeString(wchar_t *out, int cchLen, __int64 size); + +public: + DISPATCH_CODES + { + API_LANGUAGE_GETSTRING = 10, + API_LANGUAGE_GETSTRINGW = 11, + + API_LANGUAGE_GETSTRINGFROMGUID = 12, + API_LANGUAGE_GETSTRINGFROMGUIDW = 13, + + API_LANGUAGE_GETHINSTANCEBYGUID = 20, + API_LANGUAGE_GETHINSTANCEBYNAME = 21, + API_LANGUAGE_GETHINSTANCEBYNAMEW = 22, + + API_LANGUAGE_STARTUP = 30, + API_LANGUAGE_SHUTDOWN = 31, + + API_LANGUAGE_GETLANGUAGEFOLDER = 40, + + API_LANGUAGE_CREATELDIALOGPARAM = 50, + API_LANGUAGE_LDIALOGBOXPARAM = 51, + API_LANGUAGE_LOADLMENU = 52, + API_LANGUAGE_CREATELDIALOGPARAMW = 53, + API_LANGUAGE_LDIALOGBOXPARAMW = 54, + API_LANGUAGE_LOADLMENUW = 55, + + API_LANGUAGE_GETLANGUAGEIDENTIFIER = 60, + + API_LANGUAGE_LOADRESOURCEFROMFILE = 70, + API_LANGUAGE_LOADRESOURCEFROMFILEW = 71, + + API_LANGUAGE_LOADACCELERATORSA = 80, + API_LANGUAGE_LOADACCELERATORSW = 81, + + // Implemented in 5.58+ + // See UseUserNumericLocale notes + API_LANGUAGE_USEUSERNUMERICLOCALE = 90, + API_LANGUAGE_GET_C_NUMERICLOCALE = 91, + + // Implemented in 5.7+ + API_LANGUAGE_FORMATTEDSIZESTRING = 100, + }; +}; + +inline char *api_language::GetString(HINSTANCE hinst, HINSTANCE owner, UINT uID, char *str, size_t maxlen) +{ + return _call(API_LANGUAGE_GETSTRING, (char * )0, hinst, owner, uID, str, maxlen); +} + +inline wchar_t *api_language::GetStringW(HINSTANCE hinst, HINSTANCE owner, UINT uID, wchar_t *str, size_t maxlen) +{ + return _call(API_LANGUAGE_GETSTRINGW, (wchar_t * )0, hinst, owner, uID, str, maxlen); +} + +inline char *api_language::GetStringFromGUID(const GUID guid, HINSTANCE owner, UINT uID, char *str, size_t maxlen) +{ + return _call(API_LANGUAGE_GETSTRINGFROMGUID, (char * )0, guid, owner, uID, str, maxlen); +} + +inline wchar_t *api_language::GetStringFromGUIDW(const GUID guid, HINSTANCE owner, UINT uID, wchar_t *str, size_t maxlen) +{ + return _call(API_LANGUAGE_GETSTRINGFROMGUIDW, (wchar_t * )0, guid, owner, uID, str, maxlen); +} + +inline HINSTANCE api_language::FindDllHandleByGUID(const GUID guid) +{ + return _call(API_LANGUAGE_GETHINSTANCEBYGUID, (HINSTANCE )0, guid); +} + +inline HINSTANCE api_language::FindDllHandleByString(const char* str) +{ + return _call(API_LANGUAGE_GETHINSTANCEBYNAME, (HINSTANCE )0, str); +} + +inline HINSTANCE api_language::FindDllHandleByStringW(const wchar_t* str) +{ + return _call(API_LANGUAGE_GETHINSTANCEBYNAMEW, (HINSTANCE )0, str); +} + +inline HINSTANCE api_language::StartLanguageSupport(HINSTANCE hinstance, const GUID guid) +{ + return _call(API_LANGUAGE_STARTUP, (HINSTANCE )0, hinstance, guid); +} + +inline const wchar_t *api_language::GetLanguageFolder() +{ + return _call(API_LANGUAGE_GETLANGUAGEFOLDER, (const wchar_t *)0); +} + +inline HWND api_language::CreateLDialogParam(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param) +{ + return _call(API_LANGUAGE_CREATELDIALOGPARAM, (HWND)0, localised, original, id, parent, proc, param); +} + +inline INT_PTR api_language::LDialogBoxParam(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param) +{ + return _call(API_LANGUAGE_LDIALOGBOXPARAM, (INT_PTR)0, localised, original, id, parent, proc, param); +} + +inline HMENU api_language::LoadLMenu(HINSTANCE localised, HINSTANCE original, UINT id) +{ + return _call(API_LANGUAGE_LOADLMENU, (HMENU)0, localised, original, id); +} + +inline HWND api_language::CreateLDialogParamW(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param) +{ + return _call(API_LANGUAGE_CREATELDIALOGPARAMW, (HWND)0, localised, original, id, parent, proc, param); +} + +inline INT_PTR api_language::LDialogBoxParamW(HINSTANCE localised, HINSTANCE original, UINT id, HWND parent, DLGPROC proc, LPARAM param) +{ + return _call(API_LANGUAGE_LDIALOGBOXPARAMW, (INT_PTR)0, localised, original, id, parent, proc, param); +} + +inline HMENU api_language::LoadLMenuW(HINSTANCE localised, HINSTANCE original, UINT id) +{ + return _call(API_LANGUAGE_LOADLMENUW, (HMENU)0, localised, original, id); +} + +inline const wchar_t *api_language::GetLanguageIdentifier(int mode) +{ + return _call(API_LANGUAGE_GETLANGUAGEIDENTIFIER, (const wchar_t *)0, mode); +} + +inline void *api_language::LoadResourceFromFile(HINSTANCE hinst, HINSTANCE owner, LPCTSTR lpType, LPCTSTR lpName, DWORD* size) +{ + return _call(API_LANGUAGE_LOADRESOURCEFROMFILE, (void*)0, hinst, owner, lpType, lpName, size); +} + +inline void *api_language::LoadResourceFromFileW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpType, LPCWSTR lpName, DWORD* size) +{ + return _call(API_LANGUAGE_LOADRESOURCEFROMFILEW, (void*)0, hinst, owner, lpType, lpName, size); +} + +inline HACCEL api_language::LoadAcceleratorsA(HINSTANCE hinst, HINSTANCE owner, LPCSTR lpTableName) +{ + return _call(API_LANGUAGE_LOADACCELERATORSA, (HACCEL)NULL, hinst, owner, lpTableName); +} + +inline HACCEL api_language::LoadAcceleratorsW(HINSTANCE hinst, HINSTANCE owner, LPCWSTR lpTableName) +{ + return _call(API_LANGUAGE_LOADACCELERATORSA, (HACCEL)NULL, hinst, owner, lpTableName); +} + +inline BOOL api_language::UseUserNumericLocale() +{ + return _call(API_LANGUAGE_USEUSERNUMERICLOCALE, (BOOL)0); +} + +inline _locale_t api_language::Get_C_NumericLocale() +{ + return _call(API_LANGUAGE_GET_C_NUMERICLOCALE, (_locale_t)0); +} + +inline wchar_t *api_language::FormattedSizeString(wchar_t *out, int cchLen, __int64 size) +{ + return _call(API_LANGUAGE_FORMATTEDSIZESTRING, (wchar_t*)0, out, cchLen, size); +} + + +// utility macros and relevant predefined variables for use with the service + macros +extern api_language *languageManager; +#define WASABI_API_LNG languageManager + +extern HINSTANCE api_localised_hinstance; +#define WASABI_API_LNG_HINST api_localised_hinstance + +extern HINSTANCE api_orig_hinstance; +#define WASABI_API_ORIG_HINST api_orig_hinstance + +#define WASABI_API_LNGSTR WASABI_API_LNG->GetString +// use this is you want a temp copy of the string +#define WASABI_API_LNGSTRING(uID) \ + WASABI_API_LNGSTR(WASABI_API_LNG_HINST,WASABI_API_ORIG_HINST,uID) +// use this is you want a temp copy of the string but need it to fallback to a different module +#define WASABI_API_LNGSTRING_HINST(hinst,uID) \ + WASABI_API_LNGSTR(WASABI_API_LNG_HINST,hinst,uID) +// use this is you want a copy of the string +#define WASABI_API_LNGSTRING_BUF(uID,buf,len) \ + WASABI_API_LNGSTR(WASABI_API_LNG_HINST,WASABI_API_ORIG_HINST,uID,buf,len) +// use this is you want a copy of the string but need it to fallback to a different module +#define WASABI_API_LNGSTRING_HINST_BUF(hinst,uID,buf,len) \ + WASABI_API_LNGSTR(WASABI_API_LNG_HINST,hinst,uID,buf,len) + +// unicode versions of the above macros +#define WASABI_API_LNGSTRW WASABI_API_LNG->GetStringW +#define WASABI_API_LNGSTRINGW(uID) \ + WASABI_API_LNGSTRW(WASABI_API_LNG_HINST,WASABI_API_ORIG_HINST,uID) +#define WASABI_API_LNGSTRINGW_HINST(hinst,uID) \ + WASABI_API_LNGSTRW(WASABI_API_LNG_HINST,hinst,uID) +#define WASABI_API_LNGSTRINGW_BUF(uID,buf,len) \ + WASABI_API_LNGSTRW(WASABI_API_LNG_HINST,WASABI_API_ORIG_HINST,uID,buf,len) +#define WASABI_API_LNGSTRINGW_BUF_HINST(hinst,uID,buf,len) \ + WASABI_API_LNGSTRW(WASABI_API_LNG_HINST,hinst,uID,buf,len) + +// Dialog handling functions (will revert back to the non-localised version if not valid/present) +#define WASABI_API_CREATEDIALOGPARAM(id, parent, proc, param) \ + WASABI_API_LNG->CreateLDialogParam(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id, parent, (DLGPROC)proc, param) +#define WASABI_API_CREATEDIALOG(id, parent, proc) \ + WASABI_API_LNG->CreateLDialogParam(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id, parent, (DLGPROC)proc, 0) + +#define WASABI_API_CREATEDIALOGPARAMW(id, parent, proc, param) \ + WASABI_API_LNG->CreateLDialogParamW(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id, parent, (DLGPROC)proc, param) +#define WASABI_API_CREATEDIALOGW(id, parent, proc) \ + WASABI_API_LNG->CreateLDialogParamW(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id, parent, (DLGPROC)proc, 0) + +#define WASABI_API_DIALOGBOXPARAM(id, parent, proc, param) \ + WASABI_API_LNG->LDialogBoxParam(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id, parent, (DLGPROC)proc, param) +#define WASABI_API_DIALOGBOX(id, parent, proc) \ + WASABI_API_LNG->LDialogBoxParam(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id, parent, (DLGPROC)proc, 0) + +#define WASABI_API_DIALOGBOXPARAMW(id, parent, proc, param) \ + WASABI_API_LNG->LDialogBoxParamW(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id, parent, (DLGPROC)proc, param) +#define WASABI_API_DIALOGBOXW(id, parent, proc) \ + WASABI_API_LNG->LDialogBoxParamW(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id, parent, (DLGPROC)proc, 0) + +#define WASABI_API_LOADMENU(id) \ + WASABI_API_LNG->LoadLMenu(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id) +#define WASABI_API_LOADMENUW(id) \ + WASABI_API_LNG->LoadLMenuW(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, id) + + +#define WASABI_API_LOADACCELERATORSA(__id) \ + WASABI_API_LNG->LoadAcceleratorsA(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, MAKEINTRESOURCEA(__id)) +#define WASABI_API_LOADACCELERATORSW(__id) \ + WASABI_API_LNG->LoadAcceleratorsW(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, MAKEINTRESOURCEW(__id)) + +#ifdef UNICODE +#define WASABI_API_LOADACCELERATORS WASABI_API_LOADACCELERATORSW +#else +#define WASABI_API_LOADACCELERATORS WASABI_API_LOADACCELERATORSA +#endif + +#define WASABI_API_START_LANG(orig_hinst, guid) \ +{ \ + WASABI_API_ORIG_HINST = orig_hinst; \ + WASABI_API_LNG_HINST = WASABI_API_LNG->StartLanguageSupport(WASABI_API_ORIG_HINST,guid); \ +} + +#define WASABI_API_LOADRESFROMFILE(lpType, lpName, size) \ + WASABI_API_LNG->LoadResourceFromFile(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, lpType, lpName, size) +#define WASABI_API_LOADRESFROMFILEW(lpType, lpName, size) \ + WASABI_API_LNG->LoadResourceFromFileW(WASABI_API_LNG_HINST, WASABI_API_ORIG_HINST, lpType, lpName, size) + +// {30AED4E5-EF10-4277-8D49-27AB5570E891} +static const GUID languageApiGUID = +{ 0x30aed4e5, 0xef10, 0x4277, { 0x8d, 0x49, 0x27, 0xab, 0x55, 0x70, 0xe8, 0x91 } }; + +#endif \ No newline at end of file diff --git a/Agave/Language/lang.h b/Agave/Language/lang.h new file mode 100644 index 0000000..df34a63 --- /dev/null +++ b/Agave/Language/lang.h @@ -0,0 +1,619 @@ +#ifndef _LANG_GUIDS_H_ +#define _LANG_GUIDS_H_ +#ifdef __cplusplus +extern "C" +{ +#endif + +// this is just the stringtable id and the +// stringtable block where the guid is stored +#define LANG_DLL_GUID_STRING_ID 65535 +#define LANG_DLL_GUID_BLOCK_ID 4096 + +// this is the stringtable id in winamp.exe's lng file where +// the language of the lang pack is declared. +// the actual string is defined as language_code-country_code +// e.g. +// en-US - US English +// en-GB - UK English +#define LANG_PACK_LANG_ID 65534 + +// this is the indentifiers required as of 5.57+ for the localisation +// 'about page' shown in supporting language packs in the 'about' box +#define LANG_DLL_AUTHOR_HOMEPAGE 65533 +#define LANG_DLL_AUTHOR_HOMEPAGE2 65532 +#define LANG_DLL_LOCALIZED_HOMEPAGE 65531 +#define LANG_DLL_ABOUT_TRANSLATION_DLG_ID 1378 + +// this holds all of the guids that will be used in modules lng files +// using these will allow you to make use of the language resources +// between plugins / for 3rd party plugins for compatability support + +// {A0099AA7-F980-45cf-818D-64EAA9F4EF4B} +static const GUID WinampLangGUID = +{ 0xa0099aa7, 0xf980, 0x45cf, { 0x81, 0x8d, 0x64, 0xea, 0xa9, 0xf4, 0xef, 0x4b } }; + +// {0E844B2A-70E8-4007-A73A-E9C05DB3F06D} +static const GUID WinampALangGUID = +{ 0xe844b2a, 0x70e8, 0x4007, { 0xa7, 0x3a, 0xe9, 0xc0, 0x5d, 0xb3, 0xf0, 0x6d } }; + +// {250FAA3C-20CD-49db-A932-67B1C0191B0E} +static const GUID GenHotkeysLangGUID = +{ 0x250faa3c, 0x20cd, 0x49db, { 0xa9, 0x32, 0x67, 0xb1, 0xc0, 0x19, 0x1b, 0xe } }; + +// {25B50046-5B31-418b-B77E-1B0D140D64ED} +static const GUID GenTrayLangGUID = +{ 0x25b50046, 0x5b31, 0x418b, { 0xb7, 0x7e, 0x1b, 0xd, 0x14, 0xd, 0x64, 0xed } }; + +// {3D968813-F245-40ad-8589-5599C754B924} +static const GUID GenMlLangGUID = +{ 0x3d968813, 0xf245, 0x40ad, { 0x85, 0x89, 0x55, 0x99, 0xc7, 0x54, 0xb9, 0x24 } }; + +// {A3A1E7C0-761B-4391-A08A-F0D7AF38931C} +static const GUID MlBookmarkLangGUID = +{ 0xa3a1e7c0, 0x761b, 0x4391, { 0xa0, 0x8a, 0xf0, 0xd7, 0xaf, 0x38, 0x93, 0x1c } }; + +// {40450D34-E85A-428c-A01C-B2546BF23CE0} +static const GUID MlDashboardLangGUID = +{ 0x40450d34, 0xe85a, 0x428c, { 0xa0, 0x1c, 0xb2, 0x54, 0x6b, 0xf2, 0x3c, 0xe0 } }; + +// {168BA411-7E26-4749-98F0-FF02810D9B51} +static const GUID MlADDONSLangGUID = +{ 0x168ba411, 0x7e26, 0x4749, { 0x98, 0xf0, 0xff, 0x2, 0x81, 0xd, 0x9b, 0x51 } }; + +// {7F31F590-6602-45c9-B3F8-F61AE05BD1D3} +static const GUID MlNowPlayingLangGUID = +{ 0x7f31f590, 0x6602, 0x45c9, { 0xb3, 0xf8, 0xf6, 0x1a, 0xe0, 0x5b, 0xd1, 0xd3 } }; + +// {F8756C00-11D2-4857-8C50-163AE4A57783} +static const GUID MlHistoryLangGUID = +{ 0xf8756c00, 0x11d2, 0x4857, { 0x8c, 0x50, 0x16, 0x3a, 0xe4, 0xa5, 0x77, 0x83 } }; + +// {5E766B4F-818E-4f14-9C42-0902B2C571DC} +static const GUID MlPlaylistsLangGUID = +{ 0x5e766b4f, 0x818e, 0x4f14, { 0x9c, 0x42, 0x9, 0x2, 0xb2, 0xc5, 0x71, 0xdc } }; + +// {D006C700-557E-43c7-A580-B4C50C56957A} +static const GUID MlOnlineLangGUID = +{ 0xd006c700, 0x557e, 0x43c7, { 0xa5, 0x80, 0xb4, 0xc5, 0xc, 0x56, 0x95, 0x7a } }; + +// {5F633543-148D-48cc-B683-DA82F592CF28} +static const GUID MlReplayGainLangGUID = +{ 0x5f633543, 0x148d, 0x48cc, { 0xb6, 0x83, 0xda, 0x82, 0xf5, 0x92, 0xcf, 0x28 } }; + +// {699B8BA5-B292-4aba-8047-D46B0DF4E1D6} +static const GUID MlTranscodeLangGUID = +{ 0x699b8ba5, 0xb292, 0x4aba, { 0x80, 0x47, 0xd4, 0x6b, 0xd, 0xf4, 0xe1, 0xd6 } }; + +// {34DF1A2D-7EAD-41ab-B1A7-9AFA6DE2AFF1} +static const GUID EncWavLangGUID = +{ 0x34df1a2d, 0x7ead, 0x41ab, { 0xb1, 0xa7, 0x9a, 0xfa, 0x6d, 0xe2, 0xaf, 0xf1 } }; + +// {33BC12FD-E7F7-42ec-8FE3-2D8BD3A977C2} +static const GUID EncWMALangGUID = +{ 0x33bc12fd, 0xe7f7, 0x42ec, { 0x8f, 0xe3, 0x2d, 0x8b, 0xd3, 0xa9, 0x77, 0xc2 } }; + +// {8FBADBBB-B4D5-47d9-A723-5C8C8E88EE73} +static const GUID EncAACLangGUID = +{ 0x8fbadbbb, 0xb4d5, 0x47d9, { 0xa7, 0x23, 0x5c, 0x8c, 0x8e, 0x88, 0xee, 0x73 } }; + +// {F1534ECA-6E64-42c2-9781-812E61154515} +static const GUID EncLameLangGUID = +{ 0xf1534eca, 0x6e64, 0x42c2, { 0x97, 0x81, 0x81, 0x2e, 0x61, 0x15, 0x45, 0x15 } }; + +// deprecated enc_flac.dll based on FLAKE +// {5C0BA1EE-5A59-47cc-BC28-5B9F0C5EA1B7} +static const GUID EncFlakeLangGUID = +{ 0x5c0ba1ee, 0x5a59, 0x47cc, { 0xbc, 0x28, 0x5b, 0x9f, 0xc, 0x5e, 0xa1, 0xb7 } }; + +// {A23C2B70-C66B-475e-8A67-E0F33FD5BD12} +static const GUID EncVorbisLangGUID = +{ 0xa23c2b70, 0xc66b, 0x475e, { 0x8a, 0x67, 0xe0, 0xf3, 0x3f, 0xd5, 0xbd, 0x12 } }; + +// {D40620FB-E44B-47b3-98EE-8E5A089C0C94} +static const GUID tagzLangGUID = +{ 0xd40620fb, 0xe44b, 0x47b3, { 0x98, 0xee, 0x8e, 0x5a, 0x8, 0x9c, 0xc, 0x94 } }; + +// {06A3F81D-043D-4b5c-B341-590ED7053492} +static const GUID MlLocalLangGUID = +{ 0x6a3f81d, 0x43d, 0x4b5c, { 0xb3, 0x41, 0x59, 0xe, 0xd7, 0x5, 0x34, 0x92 } }; + +// {706549D3-D813-45dd-9A0B-E3793A1B63A8} +static const GUID MlDownloadsLangGUID = +{ 0x706549d3, 0xd813, 0x45dd, { 0x9a, 0xb, 0xe3, 0x79, 0x3a, 0x1b, 0x63, 0xa8 } }; + +// {1FF327B2-A41D-4c67-A58A-EB09BA1470D3} +static const GUID MlWireLangGUID = +{ 0x1ff327b2, 0xa41d, 0x4c67, { 0xa5, 0x8a, 0xeb, 0x9, 0xba, 0x14, 0x70, 0xd3 } }; + +// {04C986EE-9CE3-4369-820D-A64394C63D60} +static const GUID MlPMPLangGUID = +{ 0x4c986ee, 0x9ce3, 0x4369, { 0x82, 0xd, 0xa6, 0x43, 0x94, 0xc6, 0x3d, 0x60 } }; + +// {E553C1A4-5DE2-4838-8000-FDF8DC377DD4} +static const GUID PmpUSBLangGUID = +{ 0xe553c1a4, 0x5de2, 0x4838, { 0x80, 0x0, 0xfd, 0xf8, 0xdc, 0x37, 0x7d, 0xd4 } }; + +// {01C3E74C-261E-45e2-AA30-ED4039DCD3A2} +static const GUID PmpP4SLangGUID = +{ 0x1c3e74c, 0x261e, 0x45e2, { 0xaa, 0x30, 0xed, 0x40, 0x39, 0xdc, 0xd3, 0xa2 } }; + +// {4F5B2300-19D1-4390-BE04-89019441100B} +static const GUID PmpNJBLangGUID = +{ 0x4f5b2300, 0x19d1, 0x4390, { 0xbe, 0x4, 0x89, 0x1, 0x94, 0x41, 0x10, 0xb } }; + +// {B81F32B8-4AA4-4eba-8798-95F13812F638} +static const GUID PmpACTIVESYNCLangGUID = +{ 0xb81f32b8, 0x4aa4, 0x4eba, { 0x87, 0x98, 0x95, 0xf1, 0x38, 0x12, 0xf6, 0x38 } }; + +// {C2EE3DA5-B29B-42a0-AB5E-B202393435D6} +static const GUID PmpIPODLangGUID = +{ 0xc2ee3da5, 0xb29b, 0x42a0, { 0xab, 0x5e, 0xb2, 0x2, 0x39, 0x34, 0x35, 0xd6 } }; + +// {2C913A2F-CD49-40a1-8F1A-8EF7C2A22229} +static const GUID MlDiscLangGUID = +{ 0x2c913a2f, 0xcd49, 0x40a1, { 0x8f, 0x1a, 0x8e, 0xf7, 0xc2, 0xa2, 0x22, 0x29 } }; + +// {1A710E67-5180-49ac-8102-105856ED0A2F} +static const GUID OutDiskLangGUID = +{ 0x1a710e67, 0x5180, 0x49ac, { 0x81, 0x2, 0x10, 0x58, 0x56, 0xed, 0xa, 0x2f } }; + +// {858FBF71-9878-4d86-BFDD-8FEA8361238C} +static const GUID VisNFSFLangGUID = +{ 0x858fbf71, 0x9878, 0x4d86, { 0xbf, 0xdd, 0x8f, 0xea, 0x83, 0x61, 0x23, 0x8c } }; + +// {BE608673-B723-4a59-9EBA-52DC77109E10} +static const GUID VisAVSLangGUID = +{ 0xbe608673, 0xb723, 0x4a59, { 0x9e, 0xba, 0x52, 0xdc, 0x77, 0x10, 0x9e, 0x10 } }; + +// {226275F6-3318-4d4b-A6B3-5B1B5B077BE8} +static const GUID VisMilkdropLangGUID = +{ 0x226275f6, 0x3318, 0x4d4b, { 0xa6, 0xb3, 0x5b, 0x1b, 0x5b, 0x7, 0x7b, 0xe8 } }; + +// {C5D175F1-E4E4-47ee-B85C-4EDC6B026A35} +static const GUID VisMilk2LangGUID = +{ 0xc5d175f1, 0xe4e4, 0x47ee, { 0xb8, 0x5c, 0x4e, 0xdc, 0x6b, 0x2, 0x6a, 0x35 } }; + +// {87DCEEC2-1EC3-4c59-BED4-E8F42232C7D8} +static const GUID InCDDALangGUID = +{ 0x87dceec2, 0x1ec3, 0x4c59, { 0xbe, 0xd4, 0xe8, 0xf4, 0x22, 0x32, 0xc7, 0xd8 } }; + +// {20395FD0-AC67-446d-B8D0-D88BFD3174FC} +static const GUID IndshowLangGUID = +{ 0x20395fd0, 0xac67, 0x446d, { 0xb8, 0xd0, 0xd8, 0x8b, 0xfd, 0x31, 0x74, 0xfc } }; + +// {9475116B-F8C4-4dff-BC19-9601B238557D} +static const GUID InFlacLangGUID = +{ 0x9475116b, 0xf8c4, 0x4dff, { 0xbc, 0x19, 0x96, 0x1, 0xb2, 0x38, 0x55, 0x7d } }; + +// {EA1C197A-D227-474c-A9FD-1C79DE722BDD} +static const GUID InLineInLangGUID = +{ 0xea1c197a, 0xd227, 0x474c, { 0xa9, 0xfd, 0x1c, 0x79, 0xde, 0x72, 0x2b, 0xdd } }; + +// {96374982-0142-41a5-AEDE-244505C45D30} +static const GUID InWavLangGUID = +{ 0x96374982, 0x142, 0x41a5, { 0xae, 0xde, 0x24, 0x45, 0x5, 0xc4, 0x5d, 0x30 } }; + +// {5C5BCA4E-279E-4867-8E24-58C8B186959A} +static const GUID InVorbisLangGUID = +{ 0x5c5bca4e, 0x279e, 0x4867, { 0x8e, 0x24, 0x58, 0xc8, 0xb1, 0x86, 0x95, 0x9a } }; + +// {A786C0B0-69DE-49e2-9461-4F592808B0B3} +static const GUID ndeLangGUID = +{ 0xa786c0b0, 0x69de, 0x49e2, { 0x94, 0x61, 0x4f, 0x59, 0x28, 0x8, 0xb0, 0xb3 } }; + +// {11B847DB-29A7-47ac-B386-43B40385B817} +static const GUID InNSVLangGUID = +{ 0x11b847db, 0x29a7, 0x47ac, { 0xb3, 0x86, 0x43, 0xb4, 0x3, 0x85, 0xb8, 0x17 } }; + +// {5F24DF00-C163-4eaa-AB9D-22F106588C25} +static const GUID MLOrbLangGUID = +{ 0x5f24df00, 0xc163, 0x4eaa, { 0xab, 0x9d, 0x22, 0xf1, 0x6, 0x58, 0x8c, 0x25 } }; + +// {0FED0FEE-C995-4499-AB47-E2482336C046} +static const GUID InMidiLangGUID = +{ 0xfed0fee, 0xc995, 0x4499, { 0xab, 0x47, 0xe2, 0x48, 0x23, 0x36, 0xc0, 0x46 } }; + +// {F30C75C1-D284-4cd5-9CED-2BD9E7869438} +static const GUID InMp4LangGUID = +{ 0xf30c75c1, 0xd284, 0x4cd5, { 0x9c, 0xed, 0x2b, 0xd9, 0xe7, 0x86, 0x94, 0x38 } }; + +// {CD3EEF98-011C-4213-BC16-3F91C937B9B8} +static const GUID InMp3LangGUID = +{ 0xcd3eef98, 0x11c, 0x4213, { 0xbc, 0x16, 0x3f, 0x91, 0xc9, 0x37, 0xb9, 0xb8 } }; + +// {A1A39D49-671A-4c2f-AE42-BEA134EAF6A9} +static const GUID InModLangGUID = +{ 0xa1a39d49, 0x671a, 0x4c2f, { 0xae, 0x42, 0xbe, 0xa1, 0x34, 0xea, 0xf6, 0xa9 } }; + +// {4B567AEB-89CE-4881-9D7D-B31D7B65979A} +static const GUID DspSpsLangGUID = +{ 0x4b567aeb, 0x89ce, 0x4881, { 0x9d, 0x7d, 0xb3, 0x1d, 0x7b, 0x65, 0x97, 0x9a } }; + +// {004A91D9-CCD6-44e5-973A-4B7045C4662B} +static const GUID OutWaveLangGUID = +{ 0x4a91d9, 0xccd6, 0x44e5, { 0x97, 0x3a, 0x4b, 0x70, 0x45, 0xc4, 0x66, 0x2b } }; + +// {A812F3D3-633B-4af6-8749-3BA75290BAC0} +static const GUID OutDSLangGUID = +{ 0xa812f3d3, 0x633b, 0x4af6, { 0x87, 0x49, 0x3b, 0xa7, 0x52, 0x90, 0xba, 0xc0 } }; + +// {C5B78F09-3222-4a64-AA98-F1ABC5A9E355} +static const GUID InWmLangGUID = +{ 0xc5b78f09, 0x3222, 0x4a64, { 0xaa, 0x98, 0xf1, 0xab, 0xc5, 0xa9, 0xe3, 0x55 } }; + +// {C14FAE1D-B410-459f-B008-1A8BE3633000} +static const GUID burnlibLangGUID = +{ 0xc14fae1d, 0xb410, 0x459f, { 0xb0, 0x8, 0x1a, 0x8b, 0xe3, 0x63, 0x30, 0x0 } }; + +// {ACD05A75-030B-4943-A100-540DAD98FB00} +static const GUID GenFFLangGUID = +{ 0xacd05a75, 0x30b, 0x4943, { 0xa1, 0x0, 0x54, 0xd, 0xad, 0x98, 0xfb, 0x0 } }; + +// {0CE0174D-8334-479e-B322-9D80D48FC74D} +static const GUID MlPlgLangGUID = +{ 0xce0174d, 0x8334, 0x479e, { 0xb3, 0x22, 0x9d, 0x80, 0xd4, 0x8f, 0xc7, 0x4d } }; + +// {9E398E5F-EDEC-4dd8-A40D-E29B385A88C0} +static const GUID playlistLangGUID = +{ 0x9e398e5f, 0xedec, 0x4dd8, { 0xa4, 0xd, 0xe2, 0x9b, 0x38, 0x5a, 0x88, 0xc0 } }; + +// {092A97EF-7DC0-41a7-80D1-90DEEB18F12D} +static const GUID GenCrasherLangGUID = +{ 0x92a97ef, 0x7dc0, 0x41a7, { 0x80, 0xd1, 0x90, 0xde, 0xeb, 0x18, 0xf1, 0x2d } }; + +// {D8DBA660-90BD-431d-8F4E-189D6ACB407E} +static const GUID MlAutoTagLangGUID = +{ 0xd8dba660, 0x90bd, 0x431d, { 0x8f, 0x4e, 0x18, 0x9d, 0x6a, 0xcb, 0x40, 0x7e } }; + +// {EC959D43-9122-4807-B928-7B46207AFA49} +static const GUID InFlvLangGUID = +{ 0xec959d43, 0x9122, 0x4807, { 0xb9, 0x28, 0x7b, 0x46, 0x20, 0x7a, 0xfa, 0x49 } }; + +// {2430A7AC-317D-4d64-B33C-E1452A6384A2} +static const GUID InSwfLangGUID = +{ 0x2430a7ac, 0x317d, 0x4d64, { 0xb3, 0x3c, 0xe1, 0x45, 0x2a, 0x63, 0x84, 0xa2 } }; + +// {22661553-8D22-4012-8D3B-0FF8FE57A9ED} +static const GUID MlImpexLangGUID = +{ 0x22661553, 0x8d22, 0x4012, { 0x8d, 0x3b, 0xf, 0xf8, 0xfe, 0x57, 0xa9, 0xed } }; + +// {73760073-560C-433b-BC59-3FCC94CDEA4A} +static const GUID EncFlacLangGUID = +{ 0x73760073, 0x560c, 0x433b, { 0xbc, 0x59, 0x3f, 0xcc, 0x94, 0xcd, 0xea, 0x4a } }; + +// {95C65BA3-3C34-40ec-AE74-8D2C60AAE3C8} +static const GUID authLangGUID = +{ 0x95c65ba3, 0x3c34, 0x40ec, { 0xae, 0x74, 0x8d, 0x2c, 0x60, 0xaa, 0xe3, 0xc8 } }; + +// {CA36E14A-3742-4edc-A40F-2BC87F26B347} +static const GUID InAviLangGUID = +{ 0xca36e14a, 0x3742, 0x4edc, { 0xa4, 0xf, 0x2b, 0xc8, 0x7f, 0x26, 0xb3, 0x47 } }; + +// {5BDA8055-292D-4fcd-8404-884C2A34A8F9} +static const GUID InMkvLangGUID = +{ 0x5bda8055, 0x292d, 0x4fcd, { 0x84, 0x4, 0x88, 0x4c, 0x2a, 0x34, 0xa8, 0xf9 } }; + +// {0233DC7B-7060-43e5-8354-D2F2C7C7611D} +static const GUID GenMudLangGUID = +{ 0x233dc7b, 0x7060, 0x43e5, { 0x83, 0x54, 0xd2, 0xf2, 0xc7, 0xc7, 0x61, 0x1d } }; + +// {DCCF5A41-D16B-452b-8B7A-CFCA3360D8E8} +static const GUID omBrowserLangGUID = +{ 0xdccf5a41, 0xd16b, 0x452b, { 0x8b, 0x7a, 0xcf, 0xca, 0x33, 0x60, 0xd8, 0xe8 } }; + +// Winamp Android plugin (pmp_android.dll) +// {EBFF6E00-39D8-45e6-B3EC-E3B07A45E6B0} +static const GUID PmpAndroidLangGUID = +{ 0xebff6e00, 0x39d8, 0x45e6, { 0xb3, 0xec, 0xe3, 0xb0, 0x7a, 0x45, 0xe6, 0xb0 } }; + +// Winamp Wifi plugin (pmp_wifi.dll) +// {3066887B-CA40-4683-897F-4416FE349D7E} +static const GUID PmpWifiLangGUID = +{ 0x3066887b, 0xca40, 0x4683, { 0x89, 0x7f, 0x44, 0x16, 0xfe, 0x34, 0x9d, 0x7e } }; + +// Fraunhofer AAC Encoder plugin (enc_fhgaac.dll) +// {E1763EF4-08AD-44a3-914A-8302748AB975} +static const GUID EncFhgAacLangGUID = +{ 0xe1763ef4, 0x8ad, 0x44a3, { 0x91, 0x4a, 0x83, 0x2, 0x74, 0x8a, 0xb9, 0x75 } }; + +// Nullsoft Ogg Demuxer (in_ogg.dll) +// {90B01366-39C1-47b2-99DC-BBAE2D4DC5BF} +static const GUID InOggLangGUID = +{ 0x90b01366, 0x39c1, 0x47b2, { 0x99, 0xdc, 0xbb, 0xae, 0x2d, 0x4d, 0xc5, 0xbf } }; + +// Winamp Cloud plugin (ml_cloud.dll) +// {0253CD84-4BB1-415b-B95B-B13EBD7EA6FD} +static const GUID MlCloudLangGUID = +{ 0x253cd84, 0x4bb1, 0x415b, { 0xb9, 0x5b, 0xb1, 0x3e, 0xbd, 0x7e, 0xa6, 0xfd } }; + +// Winamp Cloud Device plugin (pmp_cloud.dll) +// {5F99429F-43B0-4544-ABA0-DE5D9DA65283} +static const GUID PmpCloudLangGUID = +{ 0x5f99429f, 0x43b0, 0x4544, { 0xab, 0xa0, 0xde, 0x5d, 0x9d, 0xa6, 0x52, 0x83 } }; + + +/* +** These are guids for known 3rd party lng files +*/ + +// WavPack Input plugin (in_wv.dll) +// {6DE2E465-690E-4df1-B6E2-2A9B33ED3DBB} +static const GUID InWvLangGuid = +{ 0x6de2e465, 0x690e, 0x4df1, { 0xb6, 0xe2, 0x2a, 0x9b, 0x33, 0xed, 0x3d, 0xbb } }; + +// Nullsoft Waveform Wrapper plugin (in_wav.dll) +// {1CED00E8-4B1B-4e10-A188-9A7C6BBEB421} +static const GUID InWavLangGuid = +{ 0x1ced00e8, 0x4b1b, 0x4e10, { 0xa1, 0x88, 0x9a, 0x7c, 0x6b, 0xbe, 0xb4, 0x21 } }; + +// Jump To File Extra (JTFE) plugin (gen_jumpex.dll) +// Note: this used to be {243355FE-8B16-48d2-89C3-FD80B3902875} but was changed with +// v1.1 (the build in 5.58) due to mass of changes to the file to ensure that +// this will work correctly if an old / partial file is present in the langpack +// {4693FA7D-2055-4b36-A239-0AD998B5A884} +static const GUID GenJTFELangGUID = +{ 0x4693fa7d, 0x2055, 0x4b36, { 0xa2, 0x39, 0xa, 0xd9, 0x98, 0xb5, 0xa8, 0x84 } }; + +// Time Restore & Autoplay (TRAP) plugin (gen_timerestore.dll) +// {75854C46-1F1A-4fae-B3FA-EEA6B253490E} +static const GUID GenTRAPLangGUID = +{ 0x75854c46, 0x1f1a, 0x4fae, { 0xb3, 0xfa, 0xee, 0xa6, 0xb2, 0x53, 0x49, 0xe } }; + +// Playlist File Remover (PLFR) plugin (gen_play_remove.dll) +// {58D8276F-12DD-44a7-A930-AA336BC8BA9A} +static const GUID GenPLFRLangGUID = +{ 0x58d8276f, 0x12dd, 0x44a7, { 0xa9, 0x30, 0xaa, 0x33, 0x6b, 0xc8, 0xba, 0x9a } }; + +// Skin Manager plugin (gen_skinmanager.dll) +// {D877C116-0201-44b2-A003-335C0600BF7A} +static const GUID GenSkinManagerGUID = +{ 0xd877c116, 0x201, 0x44b2, { 0xa0, 0x3, 0x33, 0x5c, 0x6, 0x0, 0xbf, 0x7a } }; + +// Playlist Undo plugin (gen_undo.dll) +// {3050F3A7-DADB-459f-900A-A8A224B7F32D} +static const GUID GenUndoLangGUID = +{ 0x3050f3a7, 0xdadb, 0x459f, { 0x90, 0xa, 0xa8, 0xa2, 0x24, 0xb7, 0xf3, 0x2d } }; + +// Playlist Separator plugin (in_text.dll) +// {505CAF53-D00E-4580-AA67-B31DEA6FE946} +static const GUID InTextLangGUID = +{ 0x505caf53, 0xd00e, 0x4580, { 0xaa, 0x67, 0xb3, 0x1d, 0xea, 0x6f, 0xe9, 0x46 } }; + +// One for Nunz plugin (gen_nunzio.dll) +// {CB659857-7468-40ef-BC51-844449253780} +static const GUID GenOne4NunzLangGUID = +{ 0xcb659857, 0x7468, 0x40ef, { 0xbc, 0x51, 0x84, 0x44, 0x49, 0x25, 0x37, 0x80 } }; + +// Save File As plugin (gen_saveas.dll) +// {71174948-4965-4f61-90F5-E53FF30E6578} +static const GUID GenSaveAsLangGUID = +{ 0x71174948, 0x4965, 0x4f61, { 0x90, 0xf5, 0xe5, 0x3f, 0xf3, 0xe, 0x65, 0x78 } }; + +// Yar-matey! Playlist Copier plugin (gen_yar.dll) +// {9725C8BF-B577-4d72-93EF-5FB41D88FFC2} +static const GUID GenYarLangGUID = +{ 0x9725c8bf, 0xb577, 0x4d72, { 0x93, 0xef, 0x5f, 0xb4, 0x1d, 0x88, 0xff, 0xc2 } }; + +// Album Art plugin (gen_classicart.dll) +// {EAD1E933-6D75-4c2c-B9C4-B4D7F06B7D8D} +static const GUID GenClasicArtGUID = +{ 0xead1e933, 0x6d75, 0x4c2c, { 0xb9, 0xc4, 0xb4, 0xd7, 0xf0, 0x6b, 0x7d, 0x8d } }; + +// Windows 7 Taskbar Integration plugin (gen_win7shell.dll) +// {7204A532-5D37-415d-B431-272C953B7459} +static const GUID GenWin7ShellLangGUID = +{ 0x7204a532, 0x5d37, 0x415d, { 0xb4, 0x31, 0x27, 0x2c, 0x95, 0x3b, 0x74, 0x59 } }; + +// Find File on Disk plugin (gen_find_on_disk.dll) +// {8CCF206C-1EA0-484e-88A3-943B4C4AF272} +static const GUID GenFFODLangGUID = +{ 0x8ccf206c, 0x1ea0, 0x484e, { 0x88, 0xa3, 0x94, 0x3b, 0x4c, 0x4a, 0xf2, 0x72 } }; + +// ML Bookmark Categoriser plugin (ml_bkmk.dll) +// {C3BC5F81-B400-4c64-BCC5-3B758D6BE2E1} +static const GUID MlBkCatLangGUID = +{ 0xc3bc5f81, 0xb400, 0x4c64, { 0xbc, 0xc5, 0x3b, 0x75, 0x8d, 0x6b, 0xe2, 0xe1 } }; + +// Lite'n Winamp Preferences plugin (gen_nopro.dll) +// {E6C98DDD-FC99-4ccc-B845-79A81B8C1959} +static const GUID GenNoProLangGUID = +{ 0xe6c98ddd, 0xfc99, 0x4ccc, { 0xb8, 0x45, 0x79, 0xa8, 0x1b, 0x8c, 0x19, 0x59 } }; + +// ML Enqueue & Play plugin (ml_enqplay.dll) +// {0DF6B872-74C3-4236-BE78-E1EAE665C62D} +static const GUID MlEnqPlayLangGUID = +{ 0xdf6b872, 0x74c3, 0x4236, { 0xbe, 0x78, 0xe1, 0xea, 0xe6, 0x65, 0xc6, 0x2d } }; + +// YMAMP (in_ym.dll) +// {C5F9EFFA-4727-4075-9017-A6BAE72B848C} +static const GUID InYMAMPLangGUID = +{ 0xc5f9effa, 0x4727, 0x4075, { 0x90, 0x17, 0xa6, 0xba, 0xe7, 0x2b, 0x84, 0x8c } }; + +// SNESAmp wrapper (in_snes.dll + in_snes.trb + in_snes_trb.lng) +// {7B2084F6-B7A7-449b-A133-12F1916F188E} +static const GUID InSNESWrapperLangGUID = +{ 0x7b2084f6, 0xb7a7, 0x449b, { 0xa1, 0x33, 0x12, 0xf1, 0x91, 0x6f, 0x18, 0x8e } }; + +// View Current File Information Hotkey (gen_wolfgang) plugin +// {E16E2C50-71AB-4188-9193-B9D5FB127F97} +static const GUID GenWolfgangLangGUID = +{ 0xe16e2c50, 0x71ab, 0x4188, { 0x91, 0x93, 0xb9, 0xd5, 0xfb, 0x12, 0x7f, 0x97 } }; + +// Mute Hotkey (gen_mute) plugin +// {E87B8C7F-51DA-442c-BB2A-D5F941318853} +static const GUID GenMuteLangGUID = +{ 0xe87b8c7f, 0x51da, 0x442c, { 0xbb, 0x2a, 0xd5, 0xf9, 0x41, 0x31, 0x88, 0x53 } }; + +// Play Random Song Hotkey (gen_prs) plugin +// {1112230B-6928-4f20-BD0E-F559FE6AD66E} +static const GUID GenPRSLangGUID = +{ 0x1112230b, 0x6928, 0x4f20, { 0xbd, 0xe, 0xf5, 0x59, 0xfe, 0x6a, 0xd6, 0x6e } }; + +// Randomise Playlist Hotkey (gen_grp) plugin +// {554151CC-ADEC-4bdc-8A96-7812BF69058D} +static const GUID GenRandPLLangGUID = +{ 0x554151cc, 0xadec, 0x4bdc, { 0x8a, 0x96, 0x78, 0x12, 0xbf, 0x69, 0x5, 0x8d } }; + +// Clear Current Playlist Hotkey (gen_gcp) plugin +// {1C71FF32-D2E1-403b-B39C-897AF7F4B4AE} +static const GUID GenCleardPLLangGUID = +{ 0x1c71ff32, 0xd2e1, 0x403b, { 0xb3, 0x9c, 0x89, 0x7a, 0xf7, 0xf4, 0xb4, 0xae } }; + +// EQ Hotkeys (gen_eq_hotkeys) plugin +// {4EA319B6-955A-4519-807E-A36EEDDC6224} +static const GUID GenEQGHKLangGUID = +{ 0x4ea319b6, 0x955a, 0x4519, { 0x80, 0x7e, 0xa3, 0x6e, 0xed, 0xdc, 0x62, 0x24 } }; + +// Auto EQ (gen_autoeq) plugin +// {5A2E5855-239A-44a6-A49B-1F495BBFD0D6} +static const GUID GenAutoEQLangGUID = +{ 0x5a2e5855, 0x239a, 0x44a6, { 0xa4, 0x9b, 0x1f, 0x49, 0x5b, 0xbf, 0xd0, 0xd6 } }; + +// CD Menu Tweaker (gen_cd_menu.dll) +// {A609C17B-44F3-47d8-9B76-C660FF5D3739} +static const GUID GenCDMenuTweakLangGUID = +{ 0xa609c17b, 0x44f3, 0x47d8, { 0x9b, 0x76, 0xc6, 0x60, 0xff, 0x5d, 0x37, 0x39 } }; + +// Three Mode Repeat (gen_3mode.dll) +// {81EE2A10-80E9-4d22-B363-AEA820AE988F} +static const GUID Gen3ModeLangGUID = +{ 0x81ee2a10, 0x80e9, 0x4d22, { 0xb3, 0x63, 0xae, 0xa8, 0x20, 0xae, 0x98, 0x8f } }; + +// Taskbar Text Mod (gen_ttm.dll) +// {BBFD3662-DBDF-417a-AAAC-23914D55F24B} +static const GUID GenTTMLangGUID = +{ 0xbbfd3662, 0xdbdf, 0x417a, { 0xaa, 0xac, 0x23, 0x91, 0x4d, 0x55, 0xf2, 0x4b } }; + +// OS Pos Restorer (gen_os_diag.dll) +// {B5A3AD19-2180-45d7-AFFE-80D2B7575CD1} +static const GUID GenOSDiagLangGUID = +{ 0xb5a3ad19, 0x2180, 0x45d7, { 0xaf, 0xfe, 0x80, 0xd2, 0xb7, 0x57, 0x5c, 0xd1 } }; + +// Shuffle Restorer (gen_shuffle_restorer.dll) +// {B13ED906-B8E9-4753-B03F-351B05A6E250} +static const GUID GenShuffleRestorerLangGUID = +{ 0xb13ed906, 0xb8e9, 0x4753, { 0xb0, 0x3f, 0x35, 0x1b, 0x5, 0xa6, 0xe2, 0x50 } }; + +// Shuffle Change Blocker (gen_shufblock.dll) +// {FCCFABF2-6EF3-4651-A43C-F7CA38176889} +static const GUID GenShuffleBlockerLangGUID = +{ 0xfccfabf2, 0x6ef3, 0x4651, { 0xa4, 0x3c, 0xf7, 0xca, 0x38, 0x17, 0x68, 0x89 } }; + +// Single Click 'n' Play (gen_singleclick.dll) +// {AF67A1E2-8827-4fa3-9F9F-3A3DE2886022} +static const GUID GenSingleClickLangGUID = +{ 0xaf67a1e2, 0x8827, 0x4fa3, { 0x9f, 0x9f, 0x3a, 0x3d, 0xe2, 0x88, 0x60, 0x22 } }; + +// No Minimise (gen_no_min.dll) +// {8BCF7C51-6F88-455f-88FD-0B6911650997} +static const GUID GenNoMinimiseLangGUID = +{ 0x8bcf7c51, 0x6f88, 0x455f, { 0x88, 0xfd, 0xb, 0x69, 0x11, 0x65, 0x9, 0x97 } }; + +// Repeater (gen_repeater.dll) +// {1C4C8774-8BBC-4f11-851E-936BF5C85E96} +static const GUID GenRepeaterLangGUID = +{ 0x1c4c8774, 0x8bbc, 0x4f11, { 0x85, 0x1e, 0x93, 0x6b, 0xf5, 0xc8, 0x5e, 0x96 } }; + +// Alt Close (gen_alt_close.dll) +// {0FD70024-FA0E-4f4f-A0D4-CD560913C146} +static const GUID GenAltCloseLangGUID = +{ 0xfd70024, 0xfa0e, 0x4f4f, { 0xa0, 0xd4, 0xcd, 0x56, 0x9, 0x13, 0xc1, 0x46 } }; + +// ML Exporter (ml_exporter.dll) +// {3B441F40-E8E9-46bf-B399-556FB6CD4295} +static const GUID MLExporterLangGUID = +{ 0x3b441f40, 0xe8e9, 0x46bf, { 0xb3, 0x99, 0x55, 0x6f, 0xb6, 0xcd, 0x42, 0x95 } }; + +// Silence Detector DSP (dsp_silence_detect.dll) +// {15CCEBE6-C1F5-4246-A7B0-A6E66025C01C} +static const GUID DspSilenceDetectLangGUID = +{ 0x15ccebe6, 0xc1f5, 0x4246, { 0xa7, 0xb0, 0xa6, 0xe6, 0x60, 0x25, 0xc0, 0x1c } }; + +// Skinned Preferences (gen_prefs_skin.dll) +// {AE99B23F-0E51-4a99-9AB0-21AEA7B4B3CA} +static const GUID GenSkinPrefsLangGUID = +{ 0xae99b23f, 0xe51, 0x4a99, { 0x9a, 0xb0, 0x21, 0xae, 0xa7, 0xb4, 0xb3, 0xca } }; + +// Jump to Track (gen_jtt.dll) +// {D7D804A3-0794-4761-B43B-4873E5B41873} +static const GUID GenJTTLangGUID = +{ 0xd7d804a3, 0x794, 0x4761, { 0xb4, 0x3b, 0x48, 0x73, 0xe5, 0xb4, 0x18, 0x73 } }; + +// Jump to Time Extra (gen_jumptotime.dll) +// {9B5DC220-F06A-44cc-909E-D2157513F280} +static const GUID GenJumpToTimeLangGUID = +{ 0x9b5dc220, 0xf06a, 0x44cc, { 0x90, 0x9e, 0xd2, 0x15, 0x75, 0x13, 0xf2, 0x80 } }; + +// Jumper (gen_jumper.dll) +// {5D793BF9-0903-4bc9-A78D-D10AB92C7EE5} +static const GUID GenJumperLangGUID = +{ 0x5d793bf9, 0x903, 0x4bc9, { 0xa7, 0x8d, 0xd1, 0xa, 0xb9, 0x2c, 0x7e, 0xe5 } }; + +// One Click Show and Hide (gen_one_click.dll) +// {8F3FCFB3-1F5A-43c6-A71E-891026479301} +static const GUID GenOneClickLangGUID = +{ 0x8f3fcfb3, 0x1f5a, 0x43c6, { 0xa7, 0x1e, 0x89, 0x10, 0x26, 0x47, 0x93, 0x1 } }; + +// Playback Excluder (gen_exclude.dll) +// {15C44197-EBC5-4cc7-B935-EDE40C9C1AF6} +static const GUID GenPlaybackExluderLangGUID = +{ 0x15c44197, 0xebc5, 0x4cc7, { 0xb9, 0x35, 0xed, 0xe4, 0xc, 0x9c, 0x1a, 0xf6 } }; + +// Close to Notification Area (gen_d3x7r0.dll) +// {2A3BC93A-99FF-469a-A94B-576218CF6265} +static const GUID GenCloseToNotAreaLangGUID = +{ 0x2a3bc93a, 0x99ff, 0x469a, { 0xa9, 0x4b, 0x57, 0x62, 0x18, 0xcf, 0x62, 0x65 } }; + +// Crop Die (gen_crop_die.dll) +// {9E79066C-58C5-41b9-9361-C1951DA989CD} +static const GUID GenCropDieLangGUID = +{ 0x9e79066c, 0x58c5, 0x41b9, { 0x93, 0x61, 0xc1, 0x95, 0x1d, 0xa9, 0x89, 0xcd } }; + +// Play Selected Song Hotkey (gen_gpss.dll) +// {94E8B2B6-685F-484b-9938-EC929F6874EC} +static const GUID GenPlaySelGHKLangGUID = +{ 0x94e8b2b6, 0x685f, 0x484b, { 0x99, 0x38, 0xec, 0x92, 0x9f, 0x68, 0x74, 0xec } }; + +// Close After Current (gen_cac.dll) +// {8B6A33FB-A6C5-49a0-A52A-0A0F14913BB2} +static const GUID GenCACLangGUID = +{ 0x8b6a33fb, 0xa6c5, 0x49a0, { 0xa5, 0x2a, 0xa, 0xf, 0x14, 0x91, 0x3b, 0xb2 } }; + +// Enhancer Wrapper DSP (dsp_enhancer.dll) +// {78842EF6-CCA2-410c-9E23-C498ABB24373} +static const GUID DspEnhancerLangGUID = +{ 0x78842ef6, 0xcca2, 0x410c, { 0x9e, 0x23, 0xc4, 0x98, 0xab, 0xb2, 0x43, 0x73 } }; + +// Shutdown on Close (gen_soc.dll) +// {CAE88304-4A0B-46e5-8B50-BEDFAE00FA6A} +static const GUID GenSOCLangGUID = +{ 0xcae88304, 0x4a0b, 0x46e5, { 0x8b, 0x50, 0xbe, 0xdf, 0xae, 0x0, 0xfa, 0x6a } }; + +// Mouse Wheel Blocker (gen_mwblock.dll) +// {C9D6697C-4C7B-4aec-A4C7-45395F0771EA} +static const GUID GenMouseWheelBlockLangGUID = +{ 0xc9d6697c, 0x4c7b, 0x4aec, { 0xa4, 0xc7, 0x45, 0x39, 0x5f, 0x7, 0x71, 0xea } }; + +// ML Icon Control plugin (ml_icon_control.dll) +// {4A55AE4D-B3CB-42df-A94E-53588FD761BA} +static const GUID MlIconControlLangGUID= +{ 0x4a55ae4d, 0xb3cb, 0x42df, { 0xa9, 0x4e, 0x53, 0x58, 0x8f, 0xd7, 0x61, 0xba } }; + +// File Copier plug-in (gen_copy.dll) +// {A2121FC9-6FC3-4a56-88F2-A36FF64D10EA} +static const GUID GenFileCopierLangGUID = +{ 0xa2121fc9, 0x6fc3, 0x4a56, { 0x88, 0xf2, 0xa3, 0x6f, 0xf6, 0x4d, 0x10, 0xea } }; + +// Shoutcast Source DSP plug-in +// Note: this used to be {FD4D4A01-C337-4144-85D7-00678B3B2D2D} but was changed with +// v2.3.0 due to mass of changes to the file to ensure that this will work +// correctly if an old / partial file is present in the langpack +// {88380E65-4068-49BA-8EA4-3F2AF12D0A4F} +static const GUID DspShoutcastLangGUID = +{ 0x88380e65, 0x4068, 0x49ba, { 0x8e, 0xa4, 0x3f, 0x2a, 0xf1, 0x2d, 0xa, 0x4f } }; + +#ifdef __cplusplus +} // extern "C" +#endif +#endif \ No newline at end of file diff --git a/Wasabi/api/application/api_application.h b/Wasabi/api/application/api_application.h new file mode 100644 index 0000000..86d497f --- /dev/null +++ b/Wasabi/api/application/api_application.h @@ -0,0 +1,395 @@ +// ---------------------------------------------------------------------------- +// Generated by InterfaceFactory [Wed May 07 00:55:56 2003] +// +// File : api_application.h +// Class : api_application +// class layer : Dispatchable Interface +// ---------------------------------------------------------------------------- + +#ifndef __API_APPLICATION_H +#define __API_APPLICATION_H + +#include +#include +#include +#ifdef _WIN32 +#include "ifc_messageprocessor.h" +#endif + +// ---------------------------------------------------------------------------- + +enum +{ + API_APPLICATION_SUCCESS = 0, + API_APPLICATION_FAILURE = 1, +}; + +enum +{ + TRANSLATE_MODE_NORMAL = 0, + TRANSLATE_MODE_GLOBAL = 1, + TRANSLATE_MODE_CHILD = 2, +}; + +class NOVTABLE api_application: public Dispatchable +{ +protected: + api_application() + {} + ~api_application() + {} +public: + const wchar_t *main_getAppName(); // returns (e.g.) "Winamp" + const wchar_t *main_getVersionString(); // returns (e.g.) "Winamp 5.12" + const wchar_t *main_getVersionNumString(); // returns (e.g.) "5.12" + unsigned int main_getBuildNumber(); // returns (e.g.) 666 + GUID main_getGUID(); +#ifdef _WIN32 + HANDLE main_getMainThreadHandle(); // This actually gives you a DuplicateHandle, so call CloseHandle() when you are done. + HINSTANCE main_gethInstance(); +#endif + const wchar_t *main_getCommandLine(); + void main_shutdown(int deferred = TRUE); + void main_cancelShutdown(); + int main_isShuttingDown(); + const wchar_t *path_getAppPath(); + const wchar_t *path_getUserSettingsPath(); + // added for 5.58+ so gen_ff can fill @SKINSPATH@ in scripts correctly + const wchar_t *path_getSkinSettingsPath(); + int app_getInitCount(); + intptr_t app_messageLoopStep(); +#ifdef _WIN32 + void app_addMessageProcessor(ifc_messageprocessor *processor); + void app_removeMessageProcessor(ifc_messageprocessor *processor); + + void app_addModelessDialog(HWND hwnd); /* deprectated since 5.61 use ActiveDialog_XXX instead*/ + void app_removeModelessDialog(HWND hwnd); /* deprectated since 5.61 use ActiveDialog_XXX instead*/ + /* accelerators are 5.53+ */ + void app_addAccelerators(HWND hwnd, HACCEL *phAccel, INT cAccel, UINT translateMode); + void app_removeAccelerators(HWND hwnd); + bool app_translateAccelerators(MSG *msg); + int app_getAccelerators(HWND hwnd, HACCEL *phAccel, INT cchAccelMax, BOOL bGlobal); // phAccel == NULL && cchAccelMax == 0 -> returns accels count + /* register window as part of winamp global group (5.54+) */ + void app_registerGlobalWindow(HWND hwnd); + void app_unregisterGlobalWindow(HWND hwnd); + + /* 5.58 + */ + bool DirectMouseWheel_RegisterSkipClass(ATOM klass); + bool DirectMouseWheel_UnregisterSkipClass(ATOM klass); + bool DirectMouseWheel_EnableConvertToMouseWheel(HWND hwnd, BOOL enable); // !!! must be disabled before window destroyed !!! + /* 5.7 + */ + BOOL DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam, const int controls[], int controlslen); + + /* 5.61 + */ + void ActiveDialog_Register(HWND hwnd); + void ActiveDialog_Unregister(HWND hwnd); + HWND ActiveDialog_Get(); +#endif + /* + note: on windows, these two functions DON'T call Set/GetCurrentDirectory, Winamp maintains it's own path + because calling SetCurrentDirectory locks the folder + Added for 5.34 + */ + const wchar_t *path_getWorkingPath(); // useful to call for populating lpstrInitialDir in GetOpenFileName + void path_setWorkingPath(const wchar_t *newPath); // useful to call for populating lpstrInitialDir in GetOpenFileName + + /* + The following three function return you unique IDs you can use if you need + They are created anonymously, so information cannot be tracked back to a specific person + The main reason for their existence is that a few third party libraries require them + and some online media providers require this info for billing. + You can call this functions with a pointer to any 16 byte data structure cast to a GUID * + Added for 5.35 + */ + // returns an ID unique to this computer, but not unique to the logged in user (two windows accts would share this ID) + int GetMachineID(GUID *id); + // returns an ID unique to this user. Another user logged in to the computer will have a different ID + // note that if Winamp was installed with "shared settings", the IDs of multiple users will probably be identical + // as we're just storing it in winamp.ini for now + int GetUserID(GUID *id); + // returns a unique ID for this session. Generated on the fly the first time someone calls this function + int GetSessionID(GUID *id); + + /* 5.54 + */ + size_t AllocateThreadStorage(); // returns an index, -1 for error + void *GetThreadStorage(size_t index); + void SetThreadStorage(size_t index, void *value); + +protected: + enum + { + API_APPLICATION_MAIN_GETAPPNAME = 10, + API_APPLICATION_MAIN_GETVERSIONSTRING = 20, + API_APPLICATION_MAIN_GETVERSIONSTRING2 = 21, + API_APPLICATION_MAIN_GETBUILDNUMBER = 30, + API_APPLICATION_MAIN_GETGUID = 40, + API_APPLICATION_MAIN_GETMAINTHREADHANDLE = 50, + API_APPLICATION_MAIN_GETHINSTANCE = 60, + API_APPLICATION_MAIN_GETCOMMANDLINE = 70, + API_APPLICATION_MAIN_SHUTDOWN = 80, + API_APPLICATION_MAIN_CANCELSHUTDOWN = 90, + API_APPLICATION_MAIN_ISSHUTTINGDOWN = 100, + API_APPLICATION_PATH_GETAPPPATH = 110, + API_APPLICATION_PATH_GETUSERSETTINGSPATH = 120, + API_APPLICATION_APP_GETINITCOUNT = 130, + API_APPLICATION_APP_MESSAGELOOPSTEP = 140, + API_APPLICATION_APP_ADDMESSAGEPROCESSOR = 150, + API_APPLICATION_APP_REMOVEMESSAGEPROCESSOR = 160, + API_APPLICATION_APP_ADDMODELESSDIALOG = 170, + API_APPLICATION_APP_REMOVEMODELESSDIALOG = 180, + API_APPLICATION_PATH_GETWORKINGPATH = 190, + API_APPLICATION_PATH_SETWORKINGPATH = 200, + API_APPLICATION_GETMACHINEID = 210, + API_APPLICATION_GETUSERID = 220, + API_APPLICATION_GETSESSIONID = 230, + API_APPLICATION_APP_ADDACCELERATORS = 240, + API_APPLICATION_APP_REMOVEACCELERATORS = 250, + API_APPLICATION_APP_TRANSLATEACCELERATORS = 260, + API_APPLICATION_APP_GETACCELERATORS = 270, + API_APPLICATION_APP_REGISTERGLOBALWINDOW = 280, + API_APPLICATION_APP_UNREGISTERGLOBALWINDOW = 290, + API_APPLICATION_ALLOCATETHREADSTORAGE = 300, + API_APPLICATION_GETTHREADSTORAGE = 310, + API_APPLICATION_SETTHREADSTORAGE = 320, + API_APPLICATION_PATH_GETSKINSETTINGSPATH = 330, + API_APPLICATION_DIRECTMOUSEWHEEL_REGISTERSKIPCLASS = 340, + API_APPLICATION_DIRECTMOUSEWHEEL_UNREGISTERSKIPCLASS = 350, + API_APPLICATION_DIRECTMOUSEWHEEL_ENABLECONVERTTOMOUSEWHEEL = 360, + API_APPLICATION_DIRECTMOUSEWHEEL_PROCESSDIALOGMESSAGE = 365, + API_APPLICATION_ACTIVEDIALOG_REGISTER = 370, + API_APPLICATION_ACTIVEDIALOG_UNREGISTER = 380, + API_APPLICATION_ACTIVEDIALOG_GET = 390, + }; +}; + +// ---------------------------------------------------------------------------- + +inline const wchar_t *api_application::main_getAppName() +{ + const wchar_t *__retval = _call(API_APPLICATION_MAIN_GETAPPNAME, (const wchar_t *)0); + return __retval; +} + +inline const wchar_t *api_application::main_getVersionString() +{ + const wchar_t *__retval = _call(API_APPLICATION_MAIN_GETVERSIONSTRING, (const wchar_t *)0); + return __retval; +} + +inline const wchar_t *api_application::main_getVersionNumString() +{ + return _call(API_APPLICATION_MAIN_GETVERSIONSTRING2, (const wchar_t *)0); +} + +inline unsigned int api_application::main_getBuildNumber() +{ + return _call(API_APPLICATION_MAIN_GETBUILDNUMBER, 0); +} + +inline GUID api_application::main_getGUID() +{ + GUID __retval = _call(API_APPLICATION_MAIN_GETGUID, INVALID_GUID); + return __retval; +} + +#ifdef _WIN32 +inline HANDLE api_application::main_getMainThreadHandle() +{ + HANDLE __retval = _call(API_APPLICATION_MAIN_GETMAINTHREADHANDLE, (HANDLE)NULL); + return __retval; +} + +inline HINSTANCE api_application::main_gethInstance() +{ + HINSTANCE __retval = _call(API_APPLICATION_MAIN_GETHINSTANCE, (HINSTANCE)NULL); + return __retval; +} +#endif + +inline const wchar_t *api_application::main_getCommandLine() +{ + const wchar_t *__retval = _call(API_APPLICATION_MAIN_GETCOMMANDLINE, (const wchar_t *)0); + return __retval; +} + +inline void api_application::main_shutdown(int deferred) +{ + _voidcall(API_APPLICATION_MAIN_SHUTDOWN, deferred); +} + +inline void api_application::main_cancelShutdown() +{ + _voidcall(API_APPLICATION_MAIN_CANCELSHUTDOWN); +} + +inline int api_application::main_isShuttingDown() +{ + int __retval = _call(API_APPLICATION_MAIN_ISSHUTTINGDOWN, (int)0); + return __retval; +} + +inline const wchar_t *api_application::path_getAppPath() +{ + const wchar_t *__retval = _call(API_APPLICATION_PATH_GETAPPPATH, (const wchar_t *)0); + return __retval; +} + +inline const wchar_t *api_application::path_getUserSettingsPath() +{ + return _call(API_APPLICATION_PATH_GETUSERSETTINGSPATH, (const wchar_t *)0); +} + +inline const wchar_t *api_application::path_getSkinSettingsPath() +{ + return _call(API_APPLICATION_PATH_GETSKINSETTINGSPATH, (const wchar_t *)0); +} + +inline int api_application::app_getInitCount() +{ + int __retval = _call(API_APPLICATION_APP_GETINITCOUNT, 0); + return __retval; +} + +inline intptr_t api_application::app_messageLoopStep() +{ + return _call(API_APPLICATION_APP_MESSAGELOOPSTEP, (intptr_t)1); +} + +#ifdef _WIN32 +inline void api_application::app_addMessageProcessor(ifc_messageprocessor *processor) +{ + _voidcall(API_APPLICATION_APP_ADDMESSAGEPROCESSOR, processor); +} + +inline void api_application::app_removeMessageProcessor(ifc_messageprocessor *processor) +{ + _voidcall(API_APPLICATION_APP_REMOVEMESSAGEPROCESSOR, processor); +} + +inline void api_application::app_addModelessDialog(HWND hwnd) +{ + _voidcall(API_APPLICATION_APP_ADDMODELESSDIALOG, hwnd); +} + +inline void api_application::app_removeModelessDialog(HWND hwnd) +{ + _voidcall(API_APPLICATION_APP_REMOVEMODELESSDIALOG, hwnd); +} + +inline void api_application::app_addAccelerators(HWND hwnd, HACCEL *phAccel, INT cAccel, UINT translateMode) +{ + _voidcall(API_APPLICATION_APP_ADDACCELERATORS, hwnd, phAccel, cAccel, translateMode); +} + +inline void api_application::app_removeAccelerators(HWND hwnd) +{ + _voidcall(API_APPLICATION_APP_REMOVEACCELERATORS, hwnd); +} + +inline bool api_application::app_translateAccelerators(MSG *msg) +{ + return _call(API_APPLICATION_APP_TRANSLATEACCELERATORS, (bool)false, msg); +} + +inline int api_application::app_getAccelerators(HWND hwnd, HACCEL *phAccel, INT cchAccelMax, BOOL bGlobal) +{ + return _call(API_APPLICATION_APP_GETACCELERATORS, (int)0, hwnd, phAccel, cchAccelMax, bGlobal); +} + +inline void api_application::app_registerGlobalWindow(HWND hwnd) +{ + _voidcall(API_APPLICATION_APP_REGISTERGLOBALWINDOW, hwnd); +} + +inline void api_application::app_unregisterGlobalWindow(HWND hwnd) +{ + _voidcall(API_APPLICATION_APP_UNREGISTERGLOBALWINDOW, hwnd); +} + +inline bool api_application::DirectMouseWheel_RegisterSkipClass(ATOM klass) +{ + return _call(API_APPLICATION_DIRECTMOUSEWHEEL_REGISTERSKIPCLASS, (bool)false, klass); +} + +inline bool api_application::DirectMouseWheel_UnregisterSkipClass(ATOM klass) +{ + return _call(API_APPLICATION_DIRECTMOUSEWHEEL_UNREGISTERSKIPCLASS, (bool)false, klass); +} + +inline bool api_application::DirectMouseWheel_EnableConvertToMouseWheel(HWND hwnd, BOOL enable) +{ + return _call(API_APPLICATION_DIRECTMOUSEWHEEL_ENABLECONVERTTOMOUSEWHEEL, (bool)false, hwnd, enable); +} + +inline BOOL api_application::DirectMouseWheel_ProcessDialogMessage(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam, const int controls[], int controlslen) +{ + return _call(API_APPLICATION_DIRECTMOUSEWHEEL_PROCESSDIALOGMESSAGE, (BOOL)FALSE, hwnd, uMsg, wParam, lParam, controls, controlslen); +} + +inline void api_application::ActiveDialog_Register(HWND hwnd) +{ + _voidcall(API_APPLICATION_ACTIVEDIALOG_REGISTER, hwnd); +} + +inline void api_application::ActiveDialog_Unregister(HWND hwnd) +{ + _voidcall(API_APPLICATION_ACTIVEDIALOG_UNREGISTER, hwnd); +} + +inline HWND api_application::ActiveDialog_Get() +{ + return _call(API_APPLICATION_ACTIVEDIALOG_GET, (HWND)NULL); +} +#endif + +inline const wchar_t *api_application::path_getWorkingPath() +{ + return _call(API_APPLICATION_PATH_GETWORKINGPATH, (wchar_t *)0); +} + +inline void api_application::path_setWorkingPath(const wchar_t *newPath) +{ + _voidcall(API_APPLICATION_PATH_SETWORKINGPATH, newPath); +} + +inline int api_application::GetMachineID(GUID *id) +{ + return _call(API_APPLICATION_GETMACHINEID, (int)API_APPLICATION_FAILURE, id); +} + +inline int api_application::GetUserID(GUID *id) +{ + return _call(API_APPLICATION_GETUSERID, (int)API_APPLICATION_FAILURE, id); +} + +inline int api_application::GetSessionID(GUID *id) +{ + return _call(API_APPLICATION_GETSESSIONID, (int)API_APPLICATION_FAILURE, id); +} + +inline size_t api_application::AllocateThreadStorage() +{ + return _call(API_APPLICATION_ALLOCATETHREADSTORAGE, (size_t)-1); +} + +inline void *api_application::GetThreadStorage(size_t index) +{ + return _call(API_APPLICATION_GETTHREADSTORAGE, (void *)0, index); +} + +inline void api_application::SetThreadStorage(size_t index, void *value) +{ + _voidcall(API_APPLICATION_SETTHREADSTORAGE, index, value); +} + +// ---------------------------------------------------------------------------- + +// {23B96771-09D7-46d3-9AE2-20DCEA6C86EA} +static const GUID applicationApiServiceGuid = + { + 0x23b96771, 0x9d7, 0x46d3, { 0x9a, 0xe2, 0x20, 0xdc, 0xea, 0x6c, 0x86, 0xea } + }; + +extern api_application *applicationApi; + +#endif // __API_APPLICATION_H \ No newline at end of file diff --git a/Wasabi/api/application/ifc_messageprocessor.h b/Wasabi/api/application/ifc_messageprocessor.h new file mode 100644 index 0000000..b54d3f3 --- /dev/null +++ b/Wasabi/api/application/ifc_messageprocessor.h @@ -0,0 +1,25 @@ +#ifndef __WASABI_IFC_MESSAGEPROCESSOR_H +#define __WASABI_IFC_MESSAGEPROCESSOR_H + +#include +#include +class ifc_messageprocessor : public Dispatchable +{ +protected: + ifc_messageprocessor() {} + ~ifc_messageprocessor() {} +public: + bool ProcessMessage(MSG *msg); // return true to 'eat' the message +public: + DISPATCH_CODES + { + IFC_MESSAGEPROCESSOR_PROCESS_MESSAGE = 10, + }; +}; +inline bool ifc_messageprocessor::ProcessMessage(MSG *msg) +{ + return _call(IFC_MESSAGEPROCESSOR_PROCESS_MESSAGE, false, msg); +} + +typedef ifc_messageprocessor api_messageprocessor; // TODO: CUT! +#endif \ No newline at end of file diff --git a/Wasabi/api/service/api_service.h b/Wasabi/api/service/api_service.h new file mode 100644 index 0000000..9c5549e --- /dev/null +++ b/Wasabi/api/service/api_service.h @@ -0,0 +1,155 @@ +// ---------------------------------------------------------------------------- +// Generated by InterfaceFactory [Wed May 07 00:56:11 2003] +// +// File : api_service.h +// Class : api_service +// class layer : Dispatchable Interface +// ---------------------------------------------------------------------------- + +#ifndef __API_SERVICE_H +#define __API_SERVICE_H + +#include +#include + +namespace SvcNotify { + enum { + ONREGISTERED=100, // init yourself here -- not all other services are registered yet + ONSTARTUP=200, // everyone is initialized, safe to talk to other services + ONAPPRUNNING=210, // app is showing and processing events + ONSHUTDOWN=300, // studio is shutting down, release resources from other services + ONDEREGISTERED=400, // bye bye + ONDBREADCOMPLETE=500,// after db is read in (happens asynchronously after ONSTARTUP) + ONBEFORESHUTDOWN=600, // system is about to shutdown, call WASABI_API_APP->main_cancelShutdown() to cancel + }; +} + + class waServiceFactory; + +// ---------------------------------------------------------------------------- + +class NOVTABLE api_service: public Dispatchable { + protected: + api_service() {} + ~api_service() {} + public: + int service_register(waServiceFactory *svc); + int service_deregister(waServiceFactory *svc); + size_t service_getNumServices(FOURCC svc_type); + waServiceFactory *service_enumService(FOURCC svc_type, size_t n); + waServiceFactory *service_getServiceByGuid(GUID guid); + int service_lock(waServiceFactory *owner, void *svcptr); + int service_clientLock(void *svcptr); + int service_release(void *svcptr); + const char *service_getTypeName(FOURCC svc_type); + #ifdef WASABI_COMPILE_COMPONENTS + GUID service_getOwningComponent(void *svcptr); + GUID service_getLockingComponent(void *svcptr); + #endif // WASABI_COMPILE_COMPONENTS + int service_unlock(void *svcptr); + int service_isvalid(FOURCC svctype, waServiceFactory *service); + // removes "me" from the services list and finds a second service with the same GUID and puts it in the same position + // this is used by the lazy loader service factory - you shouldn't need it for any other purposes. + // returns 0 if compaction actually happened + int service_compactDuplicates(waServiceFactory *me); + + protected: + enum { + API_SERVICE_SERVICE_REGISTER = 10, + API_SERVICE_SERVICE_DEREGISTER = 20, + API_SERVICE_SERVICE_GETNUMSERVICES = 30, + API_SERVICE_SERVICE_ENUMSERVICE = 40, + API_SERVICE_SERVICE_GETSERVICEBYGUID = 50, + API_SERVICE_SERVICE_LOCK = 60, + API_SERVICE_SERVICE_CLIENTLOCK = 70, + API_SERVICE_SERVICE_RELEASE = 80, + API_SERVICE_SERVICE_GETTYPENAME = 90, + #ifdef WASABI_COMPILE_COMPONENTS + API_SERVICE_SERVICE_GETOWNINGCOMPONENT = 100, + API_SERVICE_SERVICE_GETLOCKINGCOMPONENT = 110, + #endif // WASABI_COMPILE_COMPONENTS + API_SERVICE_SERVICE_UNLOCK = 120, + API_SERVICE_ISVALID = 130, + API_SERVICE_COMPACT_DUPLICATES = 140, + }; +}; + +// ---------------------------------------------------------------------------- + +inline int api_service::service_register(waServiceFactory *svc) { + int __retval = _call(API_SERVICE_SERVICE_REGISTER, (int)0, svc); + return __retval; +} + +inline int api_service::service_deregister(waServiceFactory *svc) { + int __retval = _call(API_SERVICE_SERVICE_DEREGISTER, (int)0, svc); + return __retval; +} + +inline size_t api_service::service_getNumServices(FOURCC svc_type) { + int __retval = _call(API_SERVICE_SERVICE_GETNUMSERVICES, (int)0, svc_type); + return __retval; +} + +inline waServiceFactory *api_service::service_enumService(FOURCC svc_type, size_t n) { + waServiceFactory *__retval = _call(API_SERVICE_SERVICE_ENUMSERVICE, (waServiceFactory *)0, svc_type, n); + return __retval; +} + +inline waServiceFactory *api_service::service_getServiceByGuid(GUID guid) { + waServiceFactory *__retval = _call(API_SERVICE_SERVICE_GETSERVICEBYGUID, (waServiceFactory *)0, guid); + return __retval; +} + +inline int api_service::service_lock(waServiceFactory *owner, void *svcptr) { + int __retval = _call(API_SERVICE_SERVICE_LOCK, (int)0, owner, svcptr); + return __retval; +} + +inline int api_service::service_clientLock(void *svcptr) { + int __retval = _call(API_SERVICE_SERVICE_CLIENTLOCK, (int)0, svcptr); + return __retval; +} + +inline int api_service::service_release(void *svcptr) { + int __retval = _call(API_SERVICE_SERVICE_RELEASE, (int)0, svcptr); + return __retval; +} + +inline const char *api_service::service_getTypeName(FOURCC svc_type) { + const char *__retval = _call(API_SERVICE_SERVICE_GETTYPENAME, (const char *)0, svc_type); + return __retval; +} + +#ifdef WASABI_COMPILE_COMPONENTS +inline GUID api_service::service_getOwningComponent(void *svcptr) { + GUID __retval = _call(API_SERVICE_SERVICE_GETOWNINGCOMPONENT, INVALID_GUID, svcptr); + return __retval; +} + +inline GUID api_service::service_getLockingComponent(void *svcptr) { + GUID __retval = _call(API_SERVICE_SERVICE_GETLOCKINGCOMPONENT, INVALID_GUID, svcptr); + return __retval; +} + +#endif // WASABI_COMPILE_COMPONENTS +inline int api_service::service_unlock(void *svcptr) { + int __retval = _call(API_SERVICE_SERVICE_UNLOCK, (int)0, svcptr); + return __retval; +} + +inline int api_service::service_isvalid(FOURCC svctype, waServiceFactory *service) { + int __retval = _call(API_SERVICE_ISVALID, (int)0, svctype, service); + return __retval; +} + +inline int api_service::service_compactDuplicates(waServiceFactory *me) +{ + return _call(API_SERVICE_COMPACT_DUPLICATES, (int)1, me); +} +// ---------------------------------------------------------------------------- + + +extern api_service *serviceApi; + +#endif // __API_SERVICE_H diff --git a/Wasabi/api/service/waservicefactory.h b/Wasabi/api/service/waservicefactory.h new file mode 100644 index 0000000..c5af91e --- /dev/null +++ b/Wasabi/api/service/waservicefactory.h @@ -0,0 +1,97 @@ +// ---------------------------------------------------------------------------- +// Generated by InterfaceFactory [Wed May 07 00:57:16 2003] +// +// File : waservicefactory.h +// Class : waServiceFactory +// class layer : Dispatchable Interface +// ---------------------------------------------------------------------------- + +#ifndef __WASERVICEFACTORY_H +#define __WASERVICEFACTORY_H + +#include +#include +#include "api_service.h" +// ---------------------------------------------------------------------------- + +class NOVTABLE waServiceFactory: public Dispatchable { + protected: + waServiceFactory() throw() {} + ~waServiceFactory() throw() {} + protected: + + public: + FOURCC getServiceType(); + const char *getServiceName(); + GUID getGuid(); + void *getInterface(int global_lock = TRUE); + int supportNonLockingGetInterface(); + int releaseInterface(void *ifc); + const wchar_t *getTestString(); + int serviceNotify(int msg, intptr_t param1 = 0, intptr_t param2 = 0); + + protected: + enum { + WASERVICEFACTORY_GETSERVICETYPE = 100, + WASERVICEFACTORY_GETSERVICENAME = 200, + WASERVICEFACTORY_GETGUID = 210, + WASERVICEFACTORY_GETINTERFACE = 300, + WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE = 301, + WASERVICEFACTORY_RELEASEINTERFACE = 310, + WASERVICEFACTORY_GETTESTSTRING = 500, + WASERVICEFACTORY_SERVICENOTIFY = 600, + }; +}; + +// ---------------------------------------------------------------------------- + +inline FOURCC waServiceFactory::getServiceType() { + FOURCC __retval = _call(WASERVICEFACTORY_GETSERVICETYPE, (FOURCC)NULL); + return __retval; +} + +inline const char *waServiceFactory::getServiceName() { + const char *__retval = _call(WASERVICEFACTORY_GETSERVICENAME, (const char *)0); + return __retval; +} + +inline GUID waServiceFactory::getGuid() { + GUID __retval = _call(WASERVICEFACTORY_GETGUID, INVALID_GUID); + return __retval; +} + +inline void *waServiceFactory::getInterface(int global_lock) { + void *__retval = _call(WASERVICEFACTORY_GETINTERFACE, (void *)NULL, global_lock); + +#if 0 // unused in Winamp 5 + // -- generated code - edit in waservicefactoryi.h + // support old code that always locks even when global_lock==FALSE + if (!global_lock && __retval != NULL && !supportNonLockingGetInterface()) + WASABI_API_SVC->service_unlock(__retval); +#endif + return __retval; +} + +inline int waServiceFactory::supportNonLockingGetInterface() { + int __retval = _call(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, (int)0); + return __retval; +} + +inline int waServiceFactory::releaseInterface(void *ifc) { + int __retval = _call(WASERVICEFACTORY_RELEASEINTERFACE, (int)0, ifc); + return __retval; +} + +inline const wchar_t *waServiceFactory::getTestString() { + return _call(WASERVICEFACTORY_GETTESTSTRING, (const wchar_t *)0); + +} + +inline int waServiceFactory::serviceNotify(int msg, intptr_t param1, intptr_t param2) { + int __retval = _call(WASERVICEFACTORY_SERVICENOTIFY, (int)0, msg, param1, param2); + return __retval; +} + +// ---------------------------------------------------------------------------- + +#endif // __WASERVICEFACTORY_H diff --git a/Wasabi/api/syscb/api_syscb.h b/Wasabi/api/syscb/api_syscb.h new file mode 100644 index 0000000..2e8a132 --- /dev/null +++ b/Wasabi/api/syscb/api_syscb.h @@ -0,0 +1,77 @@ +// ---------------------------------------------------------------------------- +// Generated by InterfaceFactory [Wed May 07 00:58:14 2003] +// +// File : api_syscb.h +// Class : api_syscb +// class layer : Dispatchable Interface +// ---------------------------------------------------------------------------- + +#ifndef __API_SYSCB_H +#define __API_SYSCB_H + +#include +#include + +class SysCallback; + + +// ---------------------------------------------------------------------------- + +class NOVTABLE api_syscb: public Dispatchable +{ + protected: + api_syscb() {} + ~api_syscb() {} + public: + int syscb_registerCallback(SysCallback *cb, void *param = 0); + int syscb_deregisterCallback(SysCallback *cb); + int syscb_issueCallback(int eventtype, int msg, intptr_t param1 = 0, intptr_t param2 = 0); + + /** pass eventtype == 0 to enumerate all syscallbacks + ** call Release() on the returned SysCallback when you are done + ** although very few wasabi objects support this at this time (2 June 2008) + **/ + SysCallback *syscb_enum(int eventtype, size_t n); + + protected: + enum { + API_SYSCB_SYSCB_REGISTERCALLBACK = 20, + API_SYSCB_SYSCB_DEREGISTERCALLBACK = 10, + API_SYSCB_SYSCB_ISSUECALLBACK = 30, + API_SYSCB_SYSCB_ENUM = 40, + }; +}; + +// ---------------------------------------------------------------------------- + +inline int api_syscb::syscb_registerCallback(SysCallback *cb, void *param) { + int __retval = _call(API_SYSCB_SYSCB_REGISTERCALLBACK, (int)0, cb, param); + return __retval; +} + +inline int api_syscb::syscb_deregisterCallback(SysCallback *cb) { + int __retval = _call(API_SYSCB_SYSCB_DEREGISTERCALLBACK, (int)0, cb); + return __retval; +} + +inline int api_syscb::syscb_issueCallback(int eventtype, int msg, intptr_t param1 , intptr_t param2) { + int __retval = _call(API_SYSCB_SYSCB_ISSUECALLBACK, (int)0, eventtype, msg, param1, param2); + return __retval; +} + +inline SysCallback *api_syscb::syscb_enum(int eventtype, size_t n) +{ + return _call(API_SYSCB_SYSCB_ENUM, (SysCallback *)0, eventtype, n); +} +// ---------------------------------------------------------------------------- + + +// -- generated code - edit in api_syscbi.h + +// {57B7A1B6-700E-44ff-9CB0-70B92BAF3959} +static const GUID syscbApiServiceGuid = +{ 0x57b7a1b6, 0x700e, 0x44ff, { 0x9c, 0xb0, 0x70, 0xb9, 0x2b, 0xaf, 0x39, 0x59 } }; + +extern api_syscb *sysCallbackApi; + +#endif // __API_SYSCB_H diff --git a/Wasabi/api/syscb/callbacks/browsercb.h b/Wasabi/api/syscb/callbacks/browsercb.h new file mode 100644 index 0000000..55c876a --- /dev/null +++ b/Wasabi/api/syscb/callbacks/browsercb.h @@ -0,0 +1,11 @@ +#ifndef __WASABI_BROWSERCB_H +#define __WASABI_BROWSERCB_H + +#include + +namespace BrowserCallback { + enum { + ONOPENURL=10, + }; +}; +#endif diff --git a/Wasabi/api/syscb/callbacks/syscb.h b/Wasabi/api/syscb/callbacks/syscb.h new file mode 100644 index 0000000..0959c80 --- /dev/null +++ b/Wasabi/api/syscb/callbacks/syscb.h @@ -0,0 +1,73 @@ +// ---------------------------------------------------------------------------- +// Generated by InterfaceFactory [Wed May 07 00:58:36 2003] +// +// File : syscb.h +// Class : SysCallback +// class layer : Dispatchable Interface +// ---------------------------------------------------------------------------- + +#ifndef __SYSCALLBACK_H +#define __SYSCALLBACK_H + +#include +#include +//#include +#include +#include + +// ---------------------------------------------------------------------------- + +class SysCallback: public Dispatchable { + protected: + SysCallback() {} + ~SysCallback() {} + public: + +public: +// -- begin generated - edit in syscbi.h +enum { // event types + NONE = 0, + RUNLEVEL = MK4CC('r','u','n','l'), // system runlevel + CONSOLE = MK3CC('c','o','n'), // debug messages + SKINCB = MK4CC('s','k','i','n'), // skin unloading/loading + DB = MK2CC('d','b'), // database change messages + WINDOW = MK3CC('w','n','d'), // window events + GC = MK2CC('g','c'), // garbage collection event + POPUPEXIT = MK4CC('p','o','p','x'), // popup exit + CMDLINE = MK4CC('c','m','d','l'), // command line sent (possibly from outside) + SYSMEM = MK4CC('s','y','s','m'), // api->sysMalloc/sysFree + SERVICE = MK3CC('s','v','c'), + BROWSER = MK3CC('u','r','l'), // browser open requests + META = MK4CC('m','e','t','a'), // metadata changes + AUTH = MK4CC('a','u','t','h'), // credentials change +}; +// -- end generated + + public: + FOURCC getEventType(); + int notify(int msg, intptr_t param1 = 0, intptr_t param2 = 0); + + protected: + enum { + SYSCALLBACK_GETEVENTTYPE = 101, + SYSCALLBACK_NOTIFY = 200, + }; +}; + +// ---------------------------------------------------------------------------- + +inline FOURCC SysCallback::getEventType() { + FOURCC __retval = _call(SYSCALLBACK_GETEVENTTYPE, (FOURCC)NULL); + return __retval; +} +#pragma warning(push) +#pragma warning(disable:4244) +inline int SysCallback::notify(int msg, intptr_t param1, intptr_t param2) { + int __retval = _call(SYSCALLBACK_NOTIFY, (int)0, msg, param1, param2); + return __retval; +} +#pragma warning(pop) + +// ---------------------------------------------------------------------------- + +#endif // __SYSCALLBACK_H diff --git a/Wasabi/bfc/dispatch.h b/Wasabi/bfc/dispatch.h new file mode 100644 index 0000000..f14bb60 --- /dev/null +++ b/Wasabi/bfc/dispatch.h @@ -0,0 +1,567 @@ +#pragma once +//#include +#include +#include + +#ifdef WIN32 +#ifndef NOVTABLE +#define NOVTABLE __declspec(novtable) +#endif +#else +#define NOVTABLE +#endif +class DispatchableCallback; + +#pragma warning(disable: 4786) +#pragma warning(disable: 4275) +#pragma warning(disable: 4100) + +enum +{ + DISPATCH_SUCCESS=0, + DISPATCH_FAILURE=1, +}; + + +class NOVTABLE Dispatchable { +public: +// // fake virtual destructor +// void destruct() { _voidcall(DESTRUCT); } + + // this is virtual so it is visible across modules + virtual int _dispatch(int msg, void *retval, void **params=0, int nparam=0)=0; + + + /* added 22 May 2007. these aren't used yet. To be used in the future + in the meantime, don't use negative numbers for your msg values */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + enum + { + ADDREF=-1, + RELEASE=-2, + QUERYINTERFACE=-3, + }; +protected: +// // protected real destructor +// ~Dispatchable() {} + // helper templates to implement client-side methods + int _voidcall(int msg) { + return _dispatch(msg, 0); + } + + template + int _voidcall(int msg, PARAM1 param1) { + void *params[1] = { ¶m1 }; + return _dispatch(msg, 0, params, 1); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2) { + void *params[2] = { ¶m1, ¶m2 }; + return _dispatch(msg, 0, params, 2); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3) { + void *params[3] = { ¶m1, ¶m2, ¶m3 }; + return _dispatch(msg, 0, params, 3); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4) { + void *params[4] = { ¶m1, ¶m2, ¶m3, ¶m4 }; + return _dispatch(msg, 0, params, 4); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5) { +// void *params[4] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5 }; // mig found another bug + void *params[5] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5 }; + return _dispatch(msg, 0, params, 5); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6) { +// void *params[4] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 }; // mig found another bug + void *params[6] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 }; + return _dispatch(msg, 0, params, 6); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7) { + void *params[7] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 , ¶m7 }; + return _dispatch(msg, 0, params, 7); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8) { + void *params[8] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 , ¶m7 , ¶m8 }; + return _dispatch(msg, 0, params, 8); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9) { + void *params[9] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 , ¶m7 , ¶m8 , ¶m9 }; + return _dispatch(msg, 0, params, 9); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10) { + void *params[10] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 , ¶m7 , ¶m8 , ¶m9 , ¶m10 }; + return _dispatch(msg, 0, params, 10); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10, PARAM11 param11, PARAM12 param12, PARAM13 param13, PARAM14 param14) { + void *params[14] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 , ¶m7 , ¶m8 , ¶m9 , ¶m10 , ¶m11 , ¶m12 , ¶m13 , ¶m14 }; + return _dispatch(msg, 0, params, 14); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10, PARAM11 param11, PARAM12 param12, PARAM13 param13, PARAM14 param14, PARAM15 param15, PARAM16 param16) { + void *params[16] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 , ¶m7 , ¶m8 , ¶m9 , ¶m10 , ¶m11 , ¶m12 , ¶m13 , ¶m14 , ¶m15 , ¶m16 }; + return _dispatch(msg, 0, params, 16); + } + + template + int _voidcall(int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10, PARAM11 param11, PARAM12 param12, PARAM13 param13, PARAM14 param14, PARAM15 param15, PARAM16 param16, PARAM17 param17) { + void *params[17] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 , ¶m7 , ¶m8 , ¶m9 , ¶m10 , ¶m11 , ¶m12 , ¶m13 , ¶m14 , ¶m15 , ¶m16 , ¶m17 }; + return _dispatch(msg, 0, params, 17); + } + + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval) { + RETURN_TYPE retval; + if (_dispatch(msg, &retval)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1) { + void *params[1] = { ¶m1 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 1)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2) { + void *params[2] = { ¶m1, ¶m2 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 2)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3) { + void *params[3] = { ¶m1, ¶m2, ¶m3 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 3)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4) { + void *params[4] = { ¶m1, ¶m2, ¶m3, ¶m4 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 4)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5) { + void *params[5] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 5)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6) { + void *params[6] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 6)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7) { + void *params[7] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6, ¶m7 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 7)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8) { + void *params[8] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6, ¶m7, ¶m8 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 8)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9) { + void *params[9] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6, ¶m7, ¶m8, ¶m9 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 9)) return retval; + return defval; + } + + template + RETURN_TYPE _call(int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10) { + void *params[10] = { ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6, ¶m7, ¶m8, ¶m9, ¶m10 }; + RETURN_TYPE retval; + if (_dispatch(msg, &retval, params, 10)) return retval; + return defval; + } + + template + void cb(RETVAL (CLASSNAME::*fn)(), void *retval, void **params) { + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(); + } + + template + void vcb(void (CLASSNAME::*fn)(), void *retval, void **params) { + (static_cast(static_cast(this))->*fn)(); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1); + } + + template + void vcb(void (CLASSNAME::*fn)(PARAM1), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + (static_cast(static_cast(this))->*fn)(*p1); + } + + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + (static_cast(static_cast(this))->*fn)(*p1, *p2); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2); + } + + // 3 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3); + } + + // 4 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4); + } + + // 5 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5); + } + + // 6 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6); + } + + // 7 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7); + } + + // 8 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8); + } + + // 9 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9); + } + + // 10 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10); + } + + template + void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + *static_cast(retval) = (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10); + } + + // 14 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + PARAM11 *p11 = static_cast(params[10]); + PARAM12 *p12 = static_cast(params[11]); + PARAM13 *p13 = static_cast(params[12]); + PARAM14 *p14 = static_cast(params[13]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14); + } + + // 16 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14, PARAM15, PARAM16), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + PARAM11 *p11 = static_cast(params[10]); + PARAM12 *p12 = static_cast(params[11]); + PARAM13 *p13 = static_cast(params[12]); + PARAM14 *p14 = static_cast(params[13]); + PARAM15 *p15 = static_cast(params[14]); + PARAM16 *p16 = static_cast(params[15]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16); + } + + // 17 params + template + void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14, PARAM15, PARAM16, PARAM17), void *retval, void **params) { + PARAM1 *p1 = static_cast(params[0]); + PARAM2 *p2 = static_cast(params[1]); + PARAM3 *p3 = static_cast(params[2]); + PARAM4 *p4 = static_cast(params[3]); + PARAM5 *p5 = static_cast(params[4]); + PARAM6 *p6 = static_cast(params[5]); + PARAM7 *p7 = static_cast(params[6]); + PARAM8 *p8 = static_cast(params[7]); + PARAM9 *p9 = static_cast(params[8]); + PARAM10 *p10 = static_cast(params[9]); + PARAM11 *p11 = static_cast(params[10]); + PARAM12 *p12 = static_cast(params[11]); + PARAM13 *p13 = static_cast(params[12]); + PARAM14 *p14 = static_cast(params[13]); + PARAM15 *p15 = static_cast(params[14]); + PARAM16 *p16 = static_cast(params[15]); + PARAM17 *p17 = static_cast(params[16]); + (static_cast(static_cast(this))->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16, *p17); + } + + + enum { DESTRUCT=0xffff }; +}; +#define CB(x, y) case (x): cb(&CBCLASS::y, retval, params); break; +#define CBT(x, y) case (x): cb(&CBCLASS::y, retval, params); break; +#define VCB(x, y) case (x): vcb(&CBCLASS::y, retval, params); break; +#define VCBT(x, y) case (x): vcb(&CBCLASS::y, retval, params); break; + +#define RECVS_DISPATCH virtual int _dispatch(int msg, void *retval, void **params=0, int nparam=0) + +#define START_DISPATCH \ + int CBCLASS::_dispatch(int msg, void *retval, void **params, int nparam) { \ + switch (msg) { +#define START_DISPATCH_INLINE \ + int _dispatch(int msg, void *retval, void **params, int nparam) { \ + switch (msg) { + +//FINISH case DESTRUCT: delete this; return 1; +#define END_DISPATCH \ + default: return 0; \ + } \ + return 1; \ + } +#define FORWARD_DISPATCH(x) \ + default: return x::_dispatch(msg, retval, params, nparam); \ + } \ + return 1; \ + } + +#define DISPATCH_CODES enum + +inline size_t Dispatchable::AddRef() +{ + return _call(Dispatchable::ADDREF, 0); +} + +inline size_t Dispatchable::Release() +{ + return _call(Dispatchable::RELEASE, 0); +} + +inline int Dispatchable::QueryInterface(GUID interface_guid, void **object) +{ + return _call(Dispatchable::QUERYINTERFACE, 0, interface_guid, object); +} + +#ifndef DECLARE_EXTERNAL_SERVICE +#define DECLARE_EXTERNAL_SERVICE(_type, _name) extern _type *_name +#endif + +#ifndef DEFINE_EXTERNAL_SERVICE +#define DEFINE_EXTERNAL_SERVICE(_type, _name) _type *_name=0 +#endif diff --git a/Wasabi/bfc/nsguid.h b/Wasabi/bfc/nsguid.h new file mode 100644 index 0000000..6c05e8a --- /dev/null +++ b/Wasabi/bfc/nsguid.h @@ -0,0 +1,33 @@ +#ifndef _NSGUID_H +#define _NSGUID_H +#include "platform/guid.h" +#include +//#include + +// Some conversion functions to allow +// us to have GUIDs translatable to and from other data types. +class nsGUID { +public: + // To the "Human Readable" character format. + // {1B3CA60C-DA98-4826-B4A9-D79748A5FD73} + static char *toChar(const GUID &guid, char *target); + static wchar_t *toCharW(const GUID &guid, wchar_t *target); + static GUID fromCharW(const wchar_t *source); + // To the "C Structure" character format. + // { 0x1b3ca60c, 0xda98, 0x4826, { 0xb4, 0xa9, 0xd7, 0x97, 0x48, 0xa5, 0xfd, 0x73 } }; + static char *toCode(const GUID &guid, char *target); + static GUID fromCode(const char *source); + + // Compare function, returns -1, 0, 1 + static int compare(const GUID &a, const GUID &b); + + // strlen("{xx xxx xxx-xxxx-xxxx-xxxx-xxx xxx xxx xxx}" + enum { GUID_STRLEN = 38 }; + +#ifdef WASABI_COMPILE_CREATEGUID + static void createGuid(GUID *g); +#endif +}; + + +#endif //_NSGUID_H diff --git a/Wasabi/bfc/platform/guid.h b/Wasabi/bfc/platform/guid.h new file mode 100644 index 0000000..7e638c7 --- /dev/null +++ b/Wasabi/bfc/platform/guid.h @@ -0,0 +1,35 @@ +#ifndef WASABI2_FOUNDATION_GUID_H +#define WASABI2_FOUNDATION_GUID_H +#pragma once + +#include "types.h" + +#if !defined(_WIN32) +#ifdef __cplusplus +#if !defined(GUID_EQUALS_DEFINED) || !defined(_SYS_GUID_OPERATOR_EQ_) +#define GUID_EQUALS_DEFINED +#include +#include +static __inline int operator ==(const GUID &a, const GUID &b) { + return !memcmp(&a, &b, sizeof(GUID)); +} +static __inline int operator !=(const GUID &a, const GUID &b) { + return !!memcmp(&a, &b, sizeof(GUID)); +} +#endif //GUID_EQUALS_DEFINED +#endif //__cplusplus +#else +#include +#endif + +#ifdef __cplusplus +static __inline int operator <(const GUID &a, const GUID &b) { + return memcmp(&a, &b, sizeof(GUID)) < 0; +} +#endif + + +static const GUID INVALID_GUID = { 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }; +static const GUID GENERIC_GUID = { 0xFFFFFFFF, 0xFFFF, 0xFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }; + +#endif diff --git a/Wasabi/bfc/platform/platform.h b/Wasabi/bfc/platform/platform.h new file mode 100644 index 0000000..6a14967 --- /dev/null +++ b/Wasabi/bfc/platform/platform.h @@ -0,0 +1,498 @@ +#pragma once + +#include +#include // for MKnCC + +#ifdef WIN32 +# include + +#define OSMODULEHANDLE HINSTANCE +#define INVALIDOSMODULEHANDLE ((OSMODULEHANDLE)0) +#define OSWINDOWHANDLE HWND +#define INVALIDOSWINDOWHANDLE ((OSWINDOWHANDLE)0) +#define OSICONHANDLE HICON +#define INVALIDOSICONHANDLE ((OSICONHANDLE)0) +#define OSCURSORHANDLE HICON +#define INVALIDOSCURSORHANDLE ((OSCURSORHANDLE)0) +#define OSTHREADHANDLE HANDLE +#define INVALIDOSTHREADHANDLE ((OSTHREADHANDLE)0) +#define OSREGIONHANDLE HRGN +#define INVALIDOSREGIONHANDLE ((OSREGIONHANDLE)0) +typedef HMENU OSMENUHANDLE; + +#define RGBA(r,g,b,a) ((ARGB32)((uint8_t)(r) | ((uint8_t)(g) << 8) | ((uint8_t)(b) << 16) | ((uint8_t)(a) << 24))) + +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif + +#elif defined(LINUX) +# include +#elif defined(__APPLE__) +#include + +typedef HIShapeRef OSREGIONHANDLE; +typedef int OSCURSOR; // TODO: find a good one for this +typedef int OSCURSORHANDLE; // TODO: find a good one for this +typedef HIWindowRef OSWINDOWHANDLE; +typedef void *OSMODULEHANDLE; // TODO: +typedef CGContextRef HDC; // TODO: find a better name +typedef MenuRef OSMENUHANDLE; +typedef CGImageRef OSICONHANDLE; + +#ifdef __LITTLE_ENDIAN__ +#define RGBA(r,g,b,a) ((ARGB32)((uint8_t)(r) | ((uint8_t)(g) << 8) | ((uint8_t)(b) << 16) | ((uint8_t)(a) << 24))) +#elif defined(__BIG_ENDIAN__) +#define RGBA(r,g,b,a) ((ARGB32)((uint8_t)(a) | ((uint8_t)(r) << 8) | ((uint8_t)(g) << 16) | ((uint8_t)(b) << 24))) +#else +#error endian preprocessor symbol not defined +#endif + +#define RGB(r,g,b) RGBA(r,g,b,0xFF) + +static const HIWindowRef INVALIDOSWINDOWHANDLE = 0; // TODO: maybe there's an apple-defined name for this +#define INVALIDOSMODULEHANDLE 0 +#define INVALIDOSCURSORHANDLE 0 + +typedef char OSFNCHAR; +typedef char *OSFNSTR; + +typedef const char OSFNCCHAR; +typedef const char *OSFNCSTR; + +#define FNT(x) x + +typedef struct tagRECT +{ + int left; + int top; + int right; + int bottom; +} +RECT; +typedef RECT * LPRECT; + +inline RECT RECTFromHIRect(const HIRect *r) +{ + RECT rect; + rect.left = r->origin.x; + rect.right = r->origin.x + r->size.width; + rect.top = r->origin.y; + rect.bottom = r->origin.y + r->size.height; + return rect; +} + +inline HIRect HIRectFromRECT(const RECT *r) +{ + HIRect rect; + rect.origin.x = r->left; + rect.origin.y = r->top; + rect.size.width = r->right - r->left; + rect.size.height = r->bottom - r->top; + return rect; +} + +typedef struct tagPOINT +{ + int x; + int y; +} +POINT; +typedef struct tagPOINT * LPPOINT; + +inline HIPoint HIPointFromPOINT(const POINT *pt) +{ + HIPoint p; + p.x = pt->x; + p.y = pt->y; + return p; +} + +inline int MulDiv(int a, int b, int c) +{ + int s; + int v; + + s = 0; + if (a < 0) + { + s = !s; + a = -a; + } + if (b < 0) + { + s = !s; + b = -b; + } + if (c < 0) + { + s = !s; + c = -c; + } + double d; + d = ((double)a * (double)b) / (double)c; + if (d >= 4294967296.) + return -1; + v = d; + if (s) + v = -v; + return v; +} + +#else +#error port me +// Windows API dependant definitions for non-windows platforms + +#define __cdecl +#define __stdcall +#define WINAPI +#define WINBASEAPI +#define WINUSERAPI +#define WINGDIAPI +#define WINOLEAPI +#define CALLBACK +#define FARPROC void * + +#define FALSE 0 +#define TRUE 1 + +#define ERROR 0 + +#define CONST const +#define VOID void + +typedef unsigned long DWORD; +typedef unsigned short WORD; +typedef unsigned char BYTE; +typedef long LONG; +typedef int INT; +typedef int BOOL; +typedef short SHORT; +typedef void * PVOID; +typedef void * LPVOID; + +typedef char CHAR; +typedef unsigned short WCHAR; +typedef char * LPSTR; +typedef WCHAR * LPWSTR; +typedef const char * LPCSTR; +typedef const WCHAR * LPCWSTR; +typedef LPWSTR PTSTR, LPTSTR; +typedef LPCWSTR LPCTSTR; +typedef char TCHAR; +typedef WCHAR OLECHAR; + +typedef void * HANDLE; +typedef void * HWND; +typedef void * HDC; +typedef void * HFONT; +typedef void * HBITMAP; +typedef void * HINSTANCE; +typedef void * HICON; +typedef void * HRGN; +typedef void * HPEN; +typedef void * HBRUSH; +typedef void * HRSRC; +typedef void * HGLOBAL; +typedef void * HACCEL; +typedef void * HMODULE; +typedef void * HMENU; +typedef void * HGDIOBJ; + +typedef void * ATOM; +typedef void * CRITICAL_SECTION; +typedef void * LPCRITICAL_SECTION; + +typedef UINT WPARAM; +typedef UINT LPARAM; +typedef LONG LRESULT; +typedef UINT COLORREF; + +typedef LRESULT(*WNDPROC)(HWND, UINT, WPARAM, LPARAM); +typedef BOOL CALLBACK WNDENUMPROC(HWND, LPARAM); +typedef VOID CALLBACK *TIMERPROC(HWND, UINT, UINT, DWORD); + +typedef struct tagPOINT +{ + LONG x; + LONG y; +} +POINT; +typedef struct tagPOINT * LPPOINT; + +typedef struct tagSIZE +{ + LONG cx; + LONG cy; +} +SIZE; + + +typedef struct tagRECT +{ + LONG left; + LONG top; + LONG right; + LONG bottom; +} +RECT; +typedef RECT * LPRECT; + +typedef struct _COORD +{ + SHORT X; + SHORT Y; +} +COORD, *PCOORD; + +typedef struct tagPAINTSTRUCT +{ + HDC hdc; + BOOL fErase; + RECT rcPaint; + BOOL fRestore; + BOOL fIncUpdate; + BYTE rgbReserved[32]; +} +PAINTSTRUCT; + +typedef struct tagBITMAP +{ /* bm */ + int bmType; + int bmWidth; + int bmHeight; + int bmWidthBytes; + BYTE bmPlanes; + BYTE bmBitsPixel; + LPVOID bmBits; +} +BITMAP; + +typedef struct tagRGBQUAD +{ + BYTE rgbRed; + BYTE rgbGreen; + BYTE rgbBlue; + BYTE rgbReserved; +} +RGBQUAD; + +typedef struct tagBITMAPINFOHEADER +{ + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} +BITMAPINFOHEADER; + +typedef struct tagBITMAPINFO +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; +} +BITMAPINFO, *LPBITMAPINFO; + +typedef struct tagMSG +{ + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + DWORD time; + POINT pt; +} +MSG; + +typedef MSG * LPMSG; + +typedef struct _RGNDATAHEADER +{ + DWORD dwSize; + DWORD iType; + DWORD nCount; + DWORD nRgnSize; + RECT rcBound; +} +RGNDATAHEADER, *PRGNDATAHEADER; + +typedef struct _RGNDATA +{ + RGNDATAHEADER rdh; + char Buffer[1]; +} +RGNDATA, *PRGNDATA; + +// Windows messages + +#define WM_SYSCOMMAND 0x112 +#define WM_LBUTTONDOWN 0x201 +#define WM_LBUTTONUP 0x202 +#define WM_RBUTTONDOWN 0x204 +#define WM_RBUTTONUP 0x205 + +#define WM_USER 0x400 + +#define WS_EX_TOOLWINDOW 0x00000080L + +#define WS_OVERLAPPED 0x00000000L +#define WS_MAXIMIZEBOX 0x00010000L +#define WS_MINIMIZEBOX 0x00020000L +#define WS_SYSMENU 0x00080000L +#define WS_CAPTION 0x00C00000L +#define WS_CLIPCHILDREN 0x02000000L +#define WS_CLIPSIBLINGS 0x04000000L +#define WS_VISIBLE 0x10000000L +#define WS_CHILD 0x40000000L +#define WS_POPUP 0x80000000L + +#define HWND_TOP ((HWND)0) +#define HWND_TOPMOST ((HWND)-1) +#define HWND_NOTOPMOST ((HWND)-2) + +#define GWL_STYLE (-16) + +#define GW_HWNDFIRST 0 +#define GW_HWNDNEXT 2 + +#define SWP_NOMOVE 0x0002 +#define SWP_NOSIZE 0x0001 +#define SWP_SHOWWINDOW 0x0040 +#define SWP_DEFERERASE 0x2000 +#define SWP_NOZORDER 0x0004 +#define SWP_NOACTIVATE 0x0010 + +#define SW_SHOW 5 + +#define SC_MINIMIZE 0xF020 +#define SC_MAXIMIZE 0xF030 +#define SC_RESTORE 0xF120 + +#define GCL_HICONSM (-34) +#define GCL_HICON (-14) + +#define MB_OK 0 +#define MB_OKCANCEL 1 +#define MB_TASKMODAL 0x2000L + +#define IDOK 1 +#define IDCANCEL 2 + +#define VK_SHIFT 0x10 +#define VK_CONTROL 0x11 +#define VK_MENU 0x12 + +#define RT_RCDATA 10 + +#define IMAGE_BITMAP 0 + +#define LR_LOADFROMFILE 0x0010 + +#define DIB_RGB_COLORS 0 + +#define MAX_PATH 1024 +#define _MAX_PATH MAX_PATH +#define _MAX_DRIVE 3 +#define _MAX_DIR 256 +#define _MAX_FNAME 256 +#define _MAX_EXT 256 + +#define GMEM_FIXED 0x0 +#define GMEM_ZEROINIT 0x40 +#define GPTR (GMEM_FIXED | GMEM_ZEROINIT) + +#define SPI_GETWORKAREA 48 + +#define SM_CXDOUBLECLK 36 +#define SM_CYDOUBLECLK 37 + +#define COLORONCOLOR 3 + +#define SRCCOPY (DWORD)0x00CC0020 + +#define BI_RGB 0L + +#define NULLREGION 1 + +#define DT_LEFT 0x00000000 +#define DT_CENTER 0x00000001 +#define DT_RIGHT 0x00000002 +#define DT_VCENTER 0x00000004 +#define DT_WORDBREAK 0x00000010 +#define DT_SINGLELINE 0x00000020 +#define DT_CALCRECT 0x00000400 +#define DT_NOPREFIX 0x00000800 +#define DT_PATH_ELLIPSIS 0x00004000 +#define DT_END_ELLIPSIS 0x00008000 +#define DT_MODIFYSTRING 0x00010000 + +#define FW_NORMAL 400 +#define FW_BOLD 700 + +#define FF_DONTCARE (0<<4) + +#define BLACK_BRUSH 4 +#define NULL_BRUSH 5 + +#define PS_SOLID 0 +#define PS_DOT 2 + +#define TRANSPARENT 1 +#define OPAQUE 2 + +#define ANSI_CHARSET 0 +#define ANSI_VAR_FONT 12 + +#define OUT_DEFAULT_PRECIS 0 +#define CLIP_DEFAULT_PRECIS 0 + +#define PROOF_QUALITY 2 + +#define VARIABLE_PITCH 2 + +#define RGN_AND 1 +#define RGN_OR 2 +#define RGN_DIFF 4 +#define RGN_COPY 5 + +#define RDH_RECTANGLES 1 + +#define MAXLONG 0x7fffffff + +// define GUID +#include + +#endif /* not WIN32 */ + +#include +#include +//#ifdef __cplusplus +//#include +//#else +//#include +//#endif +#include + + +#ifdef WIN32 +#define OSPIPE HANDLE +#define OSPROCESSID int +#endif + +// Ode macro keyworkds +#define DISPATCH_ // makes a method dispatchable, automatically assigns a free ID (requires Interface) +#define DISPATCH(x) // makes a method dispatchable and specifies its ID (not duplicate check, requires Interface) +#define NODISPATCH // prevents a method from being dispatched if the class is marked for dispatching by default +#define EVENT // marks a method as being an event to which other classes can connect to receive notification (used by Script and DependentItem helpers) +#define SCRIPT // exposes a method to script interfaces (requires Script helper) +#define IN // Input parameter +#define OUT // Output parameter +#define INOUT // Input/Output parameter + diff --git a/Wasabi/bfc/platform/types.h b/Wasabi/bfc/platform/types.h new file mode 100644 index 0000000..494af8a --- /dev/null +++ b/Wasabi/bfc/platform/types.h @@ -0,0 +1,94 @@ +#pragma once +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +// first, some standard int types +typedef unsigned int UINT; +typedef signed int SINT; + +typedef unsigned char UCHAR; +typedef signed char SCHAR; + +typedef unsigned long ARGB32; +typedef unsigned long RGB32; + +typedef unsigned long ARGB24; +typedef unsigned long RGB24; + +typedef unsigned short ARGB16; +typedef unsigned short RGB16; + +typedef unsigned long FOURCC; + +typedef wchar_t nsxml_char_t; +typedef wchar_t ns_char_t; +typedef wchar_t nsfilename_char_t; + +typedef int socklen_t; + +#if defined(_WIN32) && !defined(__GNUC__) +#include +#if _MSC_VER >= 1600 +#include +#else + // since windows doesn't have stdint.h + typedef unsigned __int64 uint64_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int8 uint8_t; + typedef __int64 int64_t; + typedef __int32 int32_t; + typedef __int16 int16_t; + typedef __int8 int8_t; +#ifdef _M_IX86 + typedef int64_t intptr2_t; +#else if defined(_M_IX64) + typedef unsigned __int128 uint128_t; + typedef __int128 int128_t; + typedef int128_t intptr2_t +#endif +#endif +#else +#include +#include +#include +#endif + + #ifndef GUID_DEFINED + #define GUID_DEFINED + + typedef struct _GUID + { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; + } GUID; +/* +#ifndef _REFCLSID_DEFINED +#define REFGUID const GUID & +#define _REFCLSID_DEFINED +#endif +*/ +#endif + +// this is for GUID == and != +#include +#ifndef GUID_EQUALS_DEFINED + #define GUID_EQUALS_DEFINED +#endif + + typedef SSIZE_T ssize_t; +#ifdef NULL + #undef NULL +#endif +#ifndef NULL + #define NULL 0 +#endif + +#ifdef _WIN32_WCE +typedef int intptr_t; +#endif diff --git a/Wasabi/bfc/platform/win32.h b/Wasabi/bfc/platform/win32.h new file mode 100644 index 0000000..fe4939f --- /dev/null +++ b/Wasabi/bfc/platform/win32.h @@ -0,0 +1,32 @@ +#pragma once + +#ifndef WIN32 +#error this file is only for win32 +#endif + + +// this should be the *only* place windows.h gets included! +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#ifndef _WIN32_WCE +#include +#endif + +#if defined(_MSC_VER) // msvc +# define WASABIDLLEXPORT __declspec(dllexport) +# if _MSC_VER >= 1100 +# define NOVTABLE __declspec(novtable) +# endif +#endif + + + +#define OSPIPE HANDLE + + +typedef WCHAR OSFNCHAR; +typedef LPWSTR OSFNSTR; +typedef LPCWSTR OSFNCSTR; + diff --git a/Wasabi/bfc/std_mkncc.h b/Wasabi/bfc/std_mkncc.h new file mode 100644 index 0000000..113e464 --- /dev/null +++ b/Wasabi/bfc/std_mkncc.h @@ -0,0 +1,11 @@ +#ifndef _STD_MKNCC +#define _STD_MKNCC + +// note: this is endian-incompatible with win32's MAKEFOURCC +// otoh, it shows up nicely in a debug register ;) + +#define MK4CC(a, b, c, d) ( (((unsigned long)a)<<24)|(((unsigned long)b)<<16)|(((unsigned long)c)<<8)|((unsigned long)d) ) +#define MK3CC(b, c, d) ( (((unsigned long)b)<<16)|(((unsigned long)c)<<8)|((unsigned long)d) ) +#define MK2CC(c, d) ( (((unsigned long)c)<<8)|((unsigned long)d) ) + +#endif diff --git a/Winamp/VIS.H b/Winamp/VIS.H new file mode 100644 index 0000000..d841405 --- /dev/null +++ b/Winamp/VIS.H @@ -0,0 +1,94 @@ +#ifndef NULLSOFT_VISH +#define NULLSOFT_VISH +// Visualization plugin interface + +typedef struct winampVisModule { + char *description; // description of module + HWND hwndParent; // parent window (filled in by calling app) + HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app) + int sRate; // sample rate (filled in by calling app) + int nCh; // number of channels (filled in...) + int latencyMs; // latency from call of RenderFrame to actual drawing + // (calling app looks at this value when getting data) + int delayMs; // delay between calls in ms + + // the data is filled in according to the respective Nch entry + int spectrumNch; + int waveformNch; + unsigned char spectrumData[2][576]; + unsigned char waveformData[2][576]; + + void (__cdecl *Config)(struct winampVisModule *this_mod); // configuration dialog + int (__cdecl *Init)(struct winampVisModule *this_mod); // 0 on success, creates window, etc + int (__cdecl *Render)(struct winampVisModule *this_mod); // returns 0 if successful, 1 if vis should end + void (__cdecl *Quit)(struct winampVisModule *this_mod); // call when done + + void *userData; // user data, optional +} winampVisModule; + +typedef struct { + int version; // VID_HDRVER + char *description; // description of library + winampVisModule* (__cdecl *getModule)(int); +} winampVisHeader; + +// exported symbols +#ifdef USE_VIS_HDR_HWND +typedef winampVisHeader* (__cdecl *winampVisGetHeaderType)(HWND); + +// version of current module (0x102 == 1.02) +#define VIS_HDRVER 0x102 + +#else +typedef winampVisHeader* (__cdecl *winampVisGetHeaderType)(); + +// version of current module (0x101 == 1.01) +#define VIS_HDRVER 0x101 + +#endif + +// Version note: +// +// Updated to 1.02 for 5.36+ +// Added passing of Winamp's main hwnd in the call to the exported winampVisGetHeader() +// which allows for primarily the use of localisation features with the bundled plugins. +// If you want to use the new version then either you can edit you version of vis.h or +// you can add USE_VIS_HRD_HWND to your project's defined list or before use of vis.h +// + +// Miscellaneous notes: +// * Any window that remains in foreground should optimally pass keystrokes to the parent +// (Winamp's) window, so that the user can still control it unless escape is pressed or +// some option key specific to the visualization is pressed. +// * Storing configuration can be done any where though it's recommended to use the api +// IPC_GETINIDIRECTORY as the basis of the path to save things to e.g. INIDIR\plugins\plugin.ini +// * ints are 32 bits and structure members are aligned on the default 8 byte boundaries. + +// These are the return values to be used with the uninstall plugin export function: +// __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) +// which determines if Winamp can uninstall the plugin immediately or on winamp restart. +// If this is not exported then Winamp will assume an uninstall with reboot is the only way. +// Note: visualization plugins are always uninstalled without a reboot (unlike other plugin types). +// +#define VIS_PLUGIN_UNINSTALL_NOW 0x0 +// +// Uninstall support was added from 5.0+ and uninstall now support from 5.5+ though note +// that it is down to you to ensure that if uninstall now is returned that it will not +// cause a crash i.e. don't use if you've been subclassing the main window. +// +// The HWND passed in the calling of winampUninstallPlugin(..) is the preference page HWND. +// + +// For a vis plugin to be correctly detected by Winamp you need to ensure that +// the exported winampVisGetHeader(..) is exported as an undecorated function +// e.g. +// #ifdef __cplusplus +// extern "C" { +// #endif +// __declspec(dllexport) winampVisHeader * __cdecl winampVisGetHeader(){ return &plugin; } +// #ifdef __cplusplus +// } +// #endif +// + +#endif \ No newline at end of file diff --git a/Winamp/wa_ipc.h b/Winamp/wa_ipc.h new file mode 100644 index 0000000..f938f7c --- /dev/null +++ b/Winamp/wa_ipc.h @@ -0,0 +1,2967 @@ +/* +** Copyright (C) 1997-2013 Nullsoft, Inc. +** +** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held +** liable for any damages arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to +** alter it and redistribute it freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. +** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +** +** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +** +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#ifndef _WA_IPC_H_ +#define _WA_IPC_H_ + +#include +#include +#if (_MSC_VER <= 1200) +typedef int intptr_t; +#endif +/* +** This is the modern replacement for the classic 'frontend.h'. Most of these +** updates are designed for in-process use, i.e. from a plugin. +** +*/ + +/* Most of the IPC_* messages involve sending the message in the form of: +** result = SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*); +** Where different then this is specified (typically with WM_COPYDATA variants) +** +** When you use SendMessage(hwnd_winamp,WM_WA_IPC,(parameter),IPC_*) and specify a IPC_* +** which is not currently implemented/supported by the Winamp version being used then it +** will return 1 for 'result'. This is a good way of helping to check if an api being +** used which returns a function pointer, etc is even going to be valid. +*/ + + +#define WM_WA_IPC WM_USER +/* but some of them use WM_COPYDATA. be afraid. +*/ + +#define WINAMP_VERSION_MAJOR(winampVersion) ((winampVersion & 0x0000FF00) >> 12) +#define WINAMP_VERSION_MINOR(winampVersion) (winampVersion & 0x000000FF) // returns, i.e. 0x12 for 5.12 and 0x10 for 5.1... + + +#define IPC_GETVERSION 0 +/* int version = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION); +** +** The version returned will be 0x20yx for Winamp 2.yx. +** Versions previous to Winamp 2.0 typically (but not always) use 0x1zyx for 1.zx. +** Just a bit weird but that's the way it goes. +** +** For Winamp 5.x it uses the format 0x50yx for Winamp 5.yx +** e.g. 5.01 -> 0x5001 +** 5.09 -> 0x5009 +** 5.1 -> 0x5010 +** +** Notes: For 5.02 this api will return the same value as for a 5.01 build. +** For 5.07 this api will return the same value as for a 5.06 build. +*/ + + +#define IPC_GETVERSIONSTRING 1 + + +#define IPC_GETREGISTEREDVERSION 770 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETREGISTEREDVERSION); +** +** This will open the Winamp Preferences and show the Winamp Pro page. +*/ + + +#define IPC_IS_SAFEMODE 999 +/* (requires Winamp 5.7+) +** int res = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_SAFEMODE); +** +** This will indicate if running in safe mode or not (only applies to native plugins). +** This returns: +** 0 if in safe mode +** 1 if in normal mode +** 2 if in safe mode and media library plug-ins are to be disabled +** +** Safe mode is used to disable 3rd party plugins to determine if they are the cause +** of stability issues and crashes for users experiencing issues without having to +** first remove plug-in dlls which is often found 'too hard' to do properly most times. +*/ + + +typedef struct { + const char *filename; + const char *title; + int length; +} enqueueFileWithMetaStruct; // send this to a IPC_PLAYFILE in a non WM_COPYDATA, +// and you get the nice desired result. if title is NULL, it is treated as a "thing", +// otherwise it's assumed to be a file (for speed) + +typedef struct { + const wchar_t *filename; + const wchar_t *title; + int length; +} enqueueFileWithMetaStructW; + +#define IPC_PLAYFILE 100 // dont be fooled, this is really the same as enqueufile +#define IPC_ENQUEUEFILE 100 +#define IPC_PLAYFILEW 1100 +#define IPC_ENQUEUEFILEW 1100 +/* This is sent as a WM_COPYDATA with IPC_PLAYFILE as the dwData member and the string +** of the file / playlist to be enqueued into the playlist editor as the lpData member. +** This will just enqueue the file or files since you can use this to enqueue a playlist. +** It will not clear the current playlist or change the playback state. +** +** COPYDATASTRUCT cds = {0}; +** cds.dwData = IPC_ENQUEUEFILE; +** cds.lpData = (void*)"c:\\test\\folder\\test.mp3"; +** cds.cbData = lstrlen((char*)cds.lpData)+1; // include space for null char +** SendMessage(hwnd_winamp,WM_COPYDATA,0,(LPARAM)&cds); +** +** +** With 2.9+ and all of the 5.x versions you can send this as a normal WM_WA_IPC +** (non WM_COPYDATA) with an enqueueFileWithMetaStruct as the param. +** If the title member is null then it is treated as a "thing" otherwise it will be +** assumed to be a file (for speed). +** +** enqueueFileWithMetaStruct eFWMS = {0}; +** eFWMS.filename = "c:\\test\\folder\\test.mp3"; +** eFWMS.title = "Whipping Good"; +** eFWMS.length = 300; // this is the number of seconds for the track +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&eFWMS,IPC_ENQUEUEFILE); +*/ + + +#define IPC_DELETE 101 +#define IPC_DELETE_INT 1101 +/* SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_DELETE); +** Use this api to clear Winamp's internal playlist. +** You should not need to use IPC_DELETE_INT since it is used internally by Winamp when +** it is dealing with some lame Windows Explorer issues (hard to believe that!). +*/ + + +#define IPC_STARTPLAY 102 +#define IPC_STARTPLAY_INT 1102 +/* SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_STARTPLAY); +** Sending this will start playback and is almost the same as hitting the play button. +** The IPC_STARTPLAY_INT version is used internally and you should not need to use it +** since it won't be any fun. +*/ + + +#define IPC_CHDIR 103 +/* This is sent as a WM_COPYDATA type message with IPC_CHDIR as the dwData value and the +** directory you want to change to as the lpData member. +** +** COPYDATASTRUCT cds = {0}; +** cds.dwData = IPC_CHDIR; +** cds.lpData = (void*)"c:\\download"; +** cds.cbData = lstrlen((char*)cds.lpData)+1; // include space for null char +** SendMessage(hwnd_winamp,WM_COPYDATA,0,(LPARAM)&cds); +** +** The above example will make Winamp change to the directory 'C:\download'. +*/ + + +#define IPC_ISPLAYING 104 +/* int res = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING); +** This is sent to retrieve the current playback state of Winamp. +** If it returns 1, Winamp is playing. +** If it returns 3, Winamp is paused. +** If it returns 0, Winamp is not playing. +*/ + + +#define IPC_GETOUTPUTTIME 105 +/* int res = SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETOUTPUTTIME); +** This api can return two different sets of information about current playback status. +** +** If mode = 0 then it will return the position (in ms) of the currently playing track. +** Will return -1 if Winamp is not playing. +** +** If mode = 1 then it will return the current track length (in seconds). +** Will return -1 if there are no tracks (or possibly if Winamp cannot get the length). +** +** If mode = 2 then it will return the current track length (in milliseconds). +** Will return -1 if there are no tracks (or possibly if Winamp cannot get the length). +*/ + + +#define IPC_JUMPTOTIME 106 +/* (requires Winamp 1.60+) +** SendMessage(hwnd_winamp,WM_WA_IPC,ms,IPC_JUMPTOTIME); +** This api sets the current position (in milliseconds) for the currently playing song. +** The resulting playback position may only be an approximate time since some playback +** formats do not provide exact seeking e.g. mp3 +** This returns -1 if Winamp is not playing, 1 on end of file, or 0 if it was successful. +*/ + + +#define IPC_GETMODULENAME 109 +#define IPC_EX_ISRIGHTEXE 666 +/* usually shouldnt bother using these, but here goes: +** send a WM_COPYDATA with IPC_GETMODULENAME, and an internal +** flag gets set, which if you send a normal WM_WA_IPC message with +** IPC_EX_ISRIGHTEXE, it returns whether or not that filename +** matches. lame, I know. +*/ + + +#define IPC_WRITEPLAYLIST 120 +/* (requires Winamp 1.666+) +** int cur = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_WRITEPLAYLIST); +** +** IPC_WRITEPLAYLIST will write the current playlist to winamp.m3u and on unicode clients +** it will also write the current playlist to winamp.m3u8. This will also return the +** current playlist position (see IPC_GETLISTPOS). +** +** Where the playlist(s) are saved to depends on the Winamp client version used though it +** is simple to find the path using the correct location (when working in-process): +** +** Pre 2.90 -> '\\Winamp.m3u' +** From 2.90 to 5.1 -> Use IPC_GETINIDIRECTORY +** From 5.11 -> Use IPC_GETM3UDIRECTORY +** +** If working from an external program then it is possible to work out the location of the +** playlist by reading relevant values out of paths.ini (if found) otherwise the pre 2.90 +** behaviour is what will be attempted to be used (as Winamp does if there is any failure). +** +** This is kinda obsoleted by some of the newer 2.x api items but it still is good for +** use with a front-end program (instead of a plug-in) and you want to see what is in the +** current playlist. +** +** This api will only save out extended file information in the #EXTINF entry if Winamp +** has already read the data such as if the file was played of scrolled into view. If +** Winamp has not read the data then you will only find the file with its filepath entry +** (as is the base requirements for a m3u playlist). +*/ + + +#define IPC_SETPLAYLISTPOS 121 +/* (requires Winamp 2.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,position,IPC_SETPLAYLISTPOS) +** IPC_SETPLAYLISTPOS sets the playlist position to the specified 'position'. +** It will not change playback status or anything else. It will just set the current +** position in the playlist and will update the playlist view if necessary. +** +** If you use SendMessage(hwnd_winamp,WM_COMMAND,MAKEWPARAM(WINAMP_BUTTON2,0),0); +** after using IPC_SETPLAYLISTPOS then Winamp will start playing the file at 'position'. +*/ + + +#define IPC_SETVOLUME 122 +/* (requires Winamp 2.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,volume,IPC_SETVOLUME); +** IPC_SETVOLUME sets the volume of Winamp (between the range of 0 to 255). +** +** If you pass 'volume' as -666 then the message will return the current volume. +** int curvol = SendMessage(hwnd_winamp,WM_WA_IPC,-666,IPC_SETVOLUME); +*/ + + +#define IPC_GETVOLUME(hwnd_winamp) SendMessage(hwnd_winamp,WM_WA_IPC,-666,IPC_SETVOLUME) +/* (requires Winamp 2.0+) +** int curvol = IPC_GETVOLUME(hwnd_winamp); +** This will return the current volume of Winamp (between the range of 0 to 255). +*/ + + +#define IPC_SETPANNING 123 +#define IPC_SETBALANCE 123 +/* (requires Winamp 2.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,panning,IPC_SETPANNING); +** IPC_SETPANNING sets the panning of Winamp from 0 (left) to 255 (right). +** +** At least in 5.x+ this works from -127 (left) to 127 (right). +** +** If you pass 'panning' as -666 to this api then it will return the current panning. +** int curpan = SendMessage(hwnd_winamp,WM_WA_IPC,-666,IPC_SETPANNING); +*/ + + +#define IPC_GETPANNING(hwnd_winamp) SendMessage(hwnd_winamp,WM_WA_IPC,-666,IPC_SETPANNING) +#define IPC_GETBALANCE(hwnd_winamp) SendMessage(hwnd_winamp,WM_WA_IPC,-666,IPC_SETBALANCE) +/* (requires Winamp 2.0+) +** int curpan = IPC_GETPANNING(hwnd_winamp); +** This will return the current panning level of Winamp (5.x) from -127 (left) to 127 (right) +** or from 0 (left) to 255 (right) on older client versions. +*/ + + +#define IPC_GETLISTLENGTH 124 +/* (requires Winamp 2.0+) +** int length = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTLENGTH); +** IPC_GETLISTLENGTH returns the length of the current playlist as the number of tracks. +*/ + + +#define IPC_GETLISTPOS 125 +/* (requires Winamp 2.05+) +** int pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS); +** IPC_GETLISTPOS returns the current playlist position (which is shown in the playlist +** editor as a differently coloured text entry e.g is yellow for the classic skin). +** +** This api is a lot like IPC_WRITEPLAYLIST but a lot faster since it does not have to +** write out the whole of the current playlist first. +*/ + + +#define IPC_GETNEXTLISTPOS 136 +/* (requires Winamp 5.61+) +** int pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETNEXTLISTPOS); +** IPC_GETNEXTLISTPOS returns the next playlist position expected to be played from the +** current playlist and allows for determining the next playlist item to be played even +** if shuffle mode (see IPC_GET_SHUFFLE) is enabled at the time of using this api. +** +** If there is no known next playlist item then this will return -1 i.e. if there's only +** one playlist item or at the end of the current playlist and repeat is disabled. +** +** Notes: If a plug-in (like the JTFE plug-in) uses IPC_GET_NEXT_PLITEM to override the +** playlist order then you will need to query the plug-in directly (via api_queue +** for the JTFE plug-in) to get the correct next playlist item to be played. +** +** If a change is made to the internal shuffle table, the value returned by prior +** use of this api is likely to be different and so will need to be re-queried. +** +** The returned playlist item position is zero-based. +*/ + + +#define IPC_GETINFO 126 +/* (requires Winamp 2.05+) +** int inf=SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO); +** IPC_GETINFO returns info about the current playing song. The value +** it returns depends on the value of 'mode'. +** Mode Meaning +** ------------------ +** 0 Samplerate, in kilohertz (i.e. 44) +** 1 Bitrate (i.e. 128) +** 2 Channels (i.e. 2) +** 3 (5+) Video LOWORD=w HIWORD=h +** 4 (5+) > 65536, string (video description) +** 5 (5.25+) Samplerate, in hertz (i.e. 44100) +*/ + + +#define IPC_GETEQDATA 127 +/* (requires Winamp 2.05+) +** int data=SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA); +** IPC_GETEQDATA queries the status of the EQ. +** The value returned depends on what 'pos' is set to: +** Value Meaning +** ------------------ +** 0-9 The 10 bands of EQ data. 0-63 (+20db - -20db) +** 10 The preamp value. 0-63 (+20db - -20db) +** 11 Enabled. zero if disabled, nonzero if enabled. +** 12 Autoload. zero if disabled, nonzero if enabled. +*/ + + +#define IPC_SETEQDATA 128 +/* (requires Winamp 2.05+) +** SendMessage(hwnd_winamp,WM_WA_IPC,pos,IPC_GETEQDATA); +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SETEQDATA); +** IPC_SETEQDATA sets the value of the last position retrieved +** by IPC_GETEQDATA. This is pretty lame, and we should provide +** an extended version that lets you do a MAKELPARAM(pos,value). +** someday... + + new (2.92+): + if the high byte is set to 0xDB, then the third byte specifies + which band, and the bottom word specifies the value. +*/ + + +#define IPC_ADDBOOKMARK 129 +#define IPC_ADDBOOKMARKW 131 +/* (requires Winamp 2.4+) +** This is sent as a WM_COPYDATA using IPC_ADDBOOKMARK as the dwData value and the +** directory you want to change to as the lpData member. This will add the specified +** file / url to the Winamp bookmark list. +** +** COPYDATASTRUCT cds = {0}; +** cds.dwData = IPC_ADDBOOKMARK; +** cds.lpData = (void*)"http://www.blah.com/listen.pls"; +** cds.cbData = lstrlen((char*)cds.lpData)+1; // include space for null char +** SendMessage(hwnd_winamp,WM_COPYDATA,0,(LPARAM)&cds); +** +** +** In Winamp 5.0+ we use this as a normal WM_WA_IPC and the string is null separated as +** the filename and then the title of the entry. +** +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(char*)"filename\0title\0",IPC_ADDBOOKMARK); +** +** This will notify the library / bookmark editor that a bookmark was added. +** Note that using this message in this context does not actually add the bookmark. +** Do not use, it is essentially just a notification type message :) +** +** Additional Notes: +** +** If IPC_ADDBOOKMARK is called with wParam as zero then it returns the bookmark filepath +** as an ansi string. +** +** As of 5.58+, calling IPC_ADDBOOKMARKW with wParam as zero will return the bookmark +** filepath as a unicode string and IPC_ADDBOOKMARK will behave as prior to 5.58. +** Passing wParam as 666 will return the winamp.bm8 filepath and is valid for both apis. +*/ + + +#define IPC_INSTALLPLUGIN 130 +/* This is not implemented (and is very unlikely to be done due to safety concerns). +** If it was then you could do a WM_COPYDATA with a path to a .wpz and it would then +** install the plugin for you. +** +** COPYDATASTRUCT cds = {0}; +** cds.dwData = IPC_INSTALLPLUGIN; +** cds.lpData = (void*)"c:\\path\\to\\file.wpz"; +** cds.cbData = lstrlen((char*)cds.lpData)+1; // include space for null char +** SendMessage(hwnd_winamp,WM_COPYDATA,0,(LPARAM)&cds); +*/ + + +#define IPC_RESTARTWINAMP 135 +/* (requires Winamp 2.2+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTWINAMP); +** IPC_RESTARTWINAMP will restart Winamp (isn't that obvious ? :) ) +** If this fails to make Winamp start after closing then there is a good chance one (or +** more) of the currently installed plugins caused Winamp to crash on exit (either as a +** silent crash or a full crash log report before it could call itself start again. +*/ + + +#define IPC_RESTARTSAFEWINAMP 1135 +/* (requires Winamp 5.7+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_RESTARTSAFEWINAMP); +** IPC_RESTARTSAFEWINAMP will restart Winamp (isn't that obvious ? :) ) in safe mode. +** If this fails to make Winamp start after closing then there is a good chance one (or +** more) of the currently installed plugins caused Winamp to crash on exit (either as a +** silent crash or a full crash log report before it could call itself start again. +*/ + + +#define IPC_ISFULLSTOP 400 +/* (requires winamp 2.7+ I think) +** int ret=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISFULLSTOP); +** This is useful for when you're an output plugin and you want to see if the stop/close +** happening is a full stop or if you are just between tracks. This returns zero if it is +** a full stop (such as the user pressing stop) or non-zero if it is just the end of a +** file or other internal events. +*/ + + +#define IPC_INETAVAILABLE 242 +/* (requires Winamp 2.05+) +** int val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INETAVAILABLE); +** IPC_INETAVAILABLE will return 1 if an Internet connection is available for Winamp and +** relates to the internet connection type setting on the main general preferences page +** in the Winamp preferences. +*/ + + +#define IPC_UPDTITLE 243 +/* (requires Winamp 2.2+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_UPDTITLE); +** IPC_UPDTITLE will ask Winamp to update the information about the current title and +** causes GetFileInfo(..) in the input plugin associated with the current playlist entry +** to be called. This can be called such as when an input plugin is buffering a file so +** that it can cause the buffer percentage to appear in the playlist. +*/ + + +#define IPC_REFRESHPLCACHE 247 +/* (requires Winamp 2.2+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_REFRESHPLCACHE); +** IPC_REFRESHPLCACHE will flush the playlist cache buffer and you send this if you want +** Winamp to go refetch the titles for all of the entries in the current playlist. +** +** 5.3+: +** If you pass a wchar_t * string in wParam then it will be be found using strnicmp() and +** the cache for that entry only will be cleared unlike passing nothing which clears all. +*/ + + +#define IPC_GET_SHUFFLE 250 +/* (requires Winamp 2.4+) +** int val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_SHUFFLE); +** IPC_GET_SHUFFLE returns the status of the shuffle option. +** If set then it will return 1 and if not set then it will return 0. +*/ + + +#define IPC_GET_REPEAT 251 +/* (requires Winamp 2.4+) +** int val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_REPEAT); +** IPC_GET_REPEAT returns the status of the repeat option. +** If set then it will return 1 and if not set then it will return 0. +*/ + + +#define IPC_SET_SHUFFLE 252 +/* (requires Winamp 2.4+) +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_SHUFFLE); +** IPC_SET_SHUFFLE sets the status of the shuffle option. +** If 'value' is 1 then shuffle is turned on. +** If 'value' is 0 then shuffle is turned off. +*/ + + +#define IPC_SET_REPEAT 253 +/* (requires Winamp 2.4+) +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_REPEAT); +** IPC_SET_REPEAT sets the status of the repeat option. +** If 'value' is 1 then shuffle is turned on. +** If 'value' is 0 then shuffle is turned off. +*/ + + +#define IPC_ENABLEDISABLE_ALL_WINDOWS 259 // 0xdeadbeef to disable +/* (requires Winamp 2.9+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(enable?0:0xdeadbeef),IPC_ENABLEDISABLE_ALL_WINDOWS); +** Sending this message with 0xdeadbeef as the param will disable all winamp windows and +** any other values will enable all of the Winamp windows again. When disabled you won't +** get any response on clicking or trying to do anything to the Winamp windows. If the +** taskbar icon is shown then you may still have control ;) +*/ + + +#define IPC_GETWND 260 +/* (requires Winamp 2.9+) +** HWND h=SendMessage(hwnd_winamp,WM_WA_IPC,IPC_GETWND_xxx,IPC_GETWND); +** returns the HWND of the window specified. +*/ + #define IPC_GETWND_EQ 0 // use one of these for the param + #define IPC_GETWND_PE 1 + #define IPC_GETWND_MB 2 + #define IPC_GETWND_VIDEO 3 +#define IPC_ISWNDVISIBLE 261 // same param as IPC_GETWND + + +/************************************************************************ +***************** in-process only (WE LOVE PLUGINS) +************************************************************************/ + +#define IPC_SETSKINW 199 +#define IPC_SETSKIN 200 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"skinname",IPC_SETSKIN); +** IPC_SETSKIN sets the current skin to "skinname". Note that skinname +** can be the name of a skin, a skin .zip file, with or without path. +** If path isn't specified, the default search path is the winamp skins +** directory. +*/ + + +#define IPC_GETSKIN 201 +#define IPC_GETSKINW 1201 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)skinname_buffer,IPC_GETSKIN); +** IPC_GETSKIN puts the directory where skin bitmaps can be found +** into skinname_buffer. +** skinname_buffer must be MAX_PATH characters in length. +** When using a .zip'd skin file, it'll return a temporary directory +** where the ZIP was decompressed. +*/ + + +#define IPC_EXECPLUG 202 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)"vis_file.dll",IPC_EXECPLUG); +** IPC_EXECPLUG executes a visualization plug-in pointed to by WPARAM. +** the format of this string can be: +** "vis_whatever.dll" +** "vis_whatever.dll,0" // (first mod, file in winamp plug-in dir) +** "C:\\dir\\vis_whatever.dll,1" +*/ + + +#define IPC_GETPLAYLISTFILE 211 +#define IPC_GETPLAYLISTFILEW 214 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTFILE); +** IPC_GETPLAYLISTFILE gets the filename of the playlist entry [index]. +** returns a pointer to it. returns NULL on error. +*/ + + +#define IPC_GETPLAYLISTTITLE 212 +#define IPC_GETPLAYLISTTITLEW 213 +/* (requires Winamp 2.04+, only usable from plug-ins (not external apps)) +** char *name=SendMessage(hwnd_winamp,WM_WA_IPC,index,IPC_GETPLAYLISTTITLE); +** +** IPC_GETPLAYLISTTITLE gets the title of the playlist entry [index]. +** returns a pointer to it. returns NULL on error. +*/ + + +#define IPC_GETHTTPGETTER 240 +/* retrieves a function pointer to a HTTP retrieval function. +** if this is unsupported, returns 1 or 0. +** the function should be: +** int (*httpRetrieveFile)(HWND hwnd, char *url, char *file, char *dlgtitle); +** if you call this function, with a parent window, a URL, an output file, and a dialog title, +** it will return 0 on successful download, 1 on error. +*/ + + +#define IPC_GETHTTPGETTERW 1240 +/* int (*httpRetrieveFileW)(HWND hwnd, char *url, wchar_t *file, wchar_t *dlgtitle); */ + + +#define IPC_MBOPEN 241 +/* (requires Winamp 2.05+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_MBOPEN); +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPEN); +** IPC_MBOPEN will open a new URL in the minibrowser. if url is NULL, it will open the Minibrowser window. +*/ + + +#define IPC_CHANGECURRENTFILE 245 +/* (requires Winamp 2.05+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILE); +** IPC_CHANGECURRENTFILE will set the current playlist item. +*/ + + +#define IPC_CHANGECURRENTFILEW 1245 +/* (requires Winamp 5.3+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)file,IPC_CHANGECURRENTFILEW); +** IPC_CHANGECURRENTFILEW will set the current playlist item. +*/ + + +#define IPC_GETMBURL 246 +/* (requires Winamp 2.2+) +** char buffer[4096]; // Urls can be VERY long +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)buffer,IPC_GETMBURL); +** IPC_GETMBURL will retrieve the current Minibrowser URL into buffer. +** buffer must be at least 4096 bytes long. +*/ + + +#define IPC_MBBLOCK 248 +/* (requires Winamp 2.4+) +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_MBBLOCK); +** +** IPC_MBBLOCK will block the Minibrowser from updates if value is set to 1 +*/ + + +#define IPC_MBOPENREAL 249 +/* (requires Winamp 2.4+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)url,IPC_MBOPENREAL); +** +** IPC_MBOPENREAL works the same as IPC_MBOPEN except that it will works even if +** IPC_MBBLOCK has been set to 1 +*/ + + +#define IPC_ADJUST_OPTIONSMENUPOS 280 +/* (requires Winamp 2.9+) +** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_OPTIONSMENUPOS); +** This moves where Winamp expects the Options menu to be in the main menu. +** This is useful if you wish to insert a menu item above the options/skins/vis menus for a window. +** If you pass adjust_offset as zero then it will return the current offset without adjusting it. +*/ + + +#define IPC_GET_HMENU 281 +/* (requires Winamp 2.9+) +** HMENU hMenu=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GET_HMENU); +** +** For 2.9x installs the following values are valid: +** 0 : main popup menu (mapped to -1 in 5.x installs) +** 1 : main menubar file menu +** 2 : main menubar options menu +** 3 : main menubar windows menu +** 4 : main menubar help menu +** +** For 5.x client versions the following values are valid (changed due to Modern skin support): +** -1 : the main winamp menu resource (same as doing LoadMenu(winamp_module_or_lng_file,101) +** 0 : main popup menu +** 1 : main menubar file menu +** 2 : main menubar play menu +** 3 : main menubar options menu +** 4 : main menubar windows menu +** 5 : main menubar windows help +** 6 : playlist editor menubar file menu +** 7 : playlist editor menubar playlist menu +** 8 : playlist editor menubar sort menu +** 9 : media library menubar file menu +** 10 : media library menubar view menu +** +** In all client versions, unsupported values will return NULL. +** +** e.g. (psuedo code to add an item to the end of the main window 'view' menu) +** HMENU windows_menu = (HMENU)SendMessage(hwnd_winamp,WM_WA_IPC,4,IPC_GET_HMENU); +** if(windows_menu) +** { +** // WA_MENUITEM_ID is obtained from IPC_REGISTER_WINAMP_IPCMESSAGE or a predefined +** // value if that api is not supported on the client version you are working with. +** +** int window_visible = 1; // this would be updated as needed for the window view state +** MENUITEMINFO i = {sizeof(i), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING, +** window_visible ? MFS_CHECKED : 0, WA_MENUITEM_ID}; +** i.dwTypeData = "My Menu Item"; +** InsertMenuItem(windows_menu, GetMenuItemCount(windows_menu), TRUE, &i); +** } +*/ + + +#define IPC_GET_EXTENDED_FILE_INFO 290 //pass a pointer to the following struct in wParam +#define IPC_GET_EXTENDED_FILE_INFO_HOOKABLE 296 +/* (requires Winamp 2.9+) +** to use, create an extendedFileInfoStruct, point the values filename and metadata to the +** filename and metadata field you wish to query, and ret to a buffer, with retlen to the +** length of that buffer, and then SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_GET_EXTENDED_FILE_INFO); +** the results should be in the buffer pointed to by ret. +** returns 1 if the decoder supports a getExtendedFileInfo method +*/ +typedef struct { + const char *filename; + const char *metadata; + char *ret; + size_t retlen; +} extendedFileInfoStruct; + + +#define IPC_GET_BASIC_FILE_INFO 291 //pass a pointer to the following struct in wParam +typedef struct { + const char *filename; + + int quickCheck; // set to 0 to always get, 1 for quick, 2 for default (if 2, quickCheck will be set to 0 if quick wasnot used) + + // filled in by winamp + int length; + char *title; + int titlelen; +} basicFileInfoStruct; + + +#define IPC_GET_BASIC_FILE_INFOW 1291 //pass a pointer to the following struct in wParam +typedef struct { + const wchar_t *filename; + + int quickCheck; // set to 0 to always get, 1 for quick, 2 for default (if 2, quickCheck will be set to 0 if quick wasnot used) + + // filled in by winamp + int length; + wchar_t *title; + int titlelen; +} basicFileInfoStructW; + + +#define IPC_GET_EXTLIST 292 //returns doublenull delimited. GlobalFree() it when done. if data is 0, returns raw extlist, if 1, returns something suitable for getopenfilename +#define IPC_GET_EXTLISTW 1292 // wide char version of above + + +typedef struct { + HWND parent; + char *filename; +} infoBoxParam; + +#define IPC_INFOBOX 293 +/* (requires Winamp 5.0+) +** infoBoxParam infoBox = {parent_hwnd,"c:\\test\\folder\\test.mp3"}; +** int ret_val = SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&infoBox,IPC_INFOBOX); +** +** ret_val is 0 if OK was pressed and is 1 if CANCEL was pressed +** The standard behaviour is to abort any loops used with this api if a cancel occurs. +*/ + + +typedef struct { + HWND parent; + const wchar_t *filename; +} infoBoxParamW; + +#define IPC_INFOBOXW 1293 +/* (requires Winamp 5.3+) +** infoBoxParamW infoBoxW = {parent_hwnd,L"c:\\test\\folder\\test.mp3"}; +** int ret_val = SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&infoBoxW,IPC_INFOBOXW); +** +** ret_val is 0 if OK was pressed and is 1 if CANCEL was pressed +** The standard behaviour is to abort any loops used with this api if a cancel occurs. +*/ + + +#define IPC_SET_EXTENDED_FILE_INFO 294 //pass a pointer to the a extendedFileInfoStruct in wParam +/* (requires Winamp 2.9+) +** to use, create an extendedFileInfoStruct, point the values filename and metadata to the +** filename and metadata field you wish to write in ret. (retlen is not used). and then +** SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_SET_EXTENDED_FILE_INFO); +** returns 1 if the metadata is supported +** Call IPC_WRITE_EXTENDED_FILE_INFO once you're done setting all the metadata you want to update +*/ + + +#define IPC_WRITE_EXTENDED_FILE_INFO 295 +/* (requires Winamp 2.9+) +** writes all the metadata set thru IPC_SET_EXTENDED_FILE_INFO to the file +** returns 1 if the file has been successfully updated, 0 if error +*/ + + +#define IPC_FORMAT_TITLE 297 +typedef struct +{ + char *spec; // NULL=default winamp spec + void *p; + + char *out; + int out_len; + + char * (*TAGFUNC)(const char * tag, void * p); //return 0 if not found + void (*TAGFREEFUNC)(char * tag,void * p); +} waFormatTitle; + + +#define IPC_FORMAT_TITLE_EXTENDED 298 // similiar to IPC_FORMAT_TITLE, but falls back to Winamp's %tags% if your passed tag function doesn't handle it +typedef struct +{ + const wchar_t *filename; + int useExtendedInfo; // set to 1 if you want the Title Formatter to query the input plugins for any tags that your tag function fails on + const wchar_t *spec; // NULL=default winamp spec + void *p; + + wchar_t *out; + int out_len; + + wchar_t * (*TAGFUNC)(const wchar_t * tag, void * p); //return 0 if not found, -1 for empty tag + void (*TAGFREEFUNC)(wchar_t *tag, void *p); +} waFormatTitleExtended; + + +#define IPC_COPY_EXTENDED_FILE_INFO 299 +typedef struct +{ + const char *source; + const char *dest; +} copyFileInfoStruct; + + +#define IPC_COPY_EXTENDED_FILE_INFOW 1299 +typedef struct +{ + const wchar_t *source; + const wchar_t *dest; +} copyFileInfoStructW; + + +typedef struct { + int (*inflateReset)(void *strm); + int (*inflateInit_)(void *strm,const char *version, int stream_size); + int (*inflate)(void *strm, int flush); + int (*inflateEnd)(void *strm); + unsigned long (*crc32)(unsigned long crc, const unsigned char *buf, unsigned int len); +} wa_inflate_struct; + +#define IPC_GETUNCOMPRESSINTERFACE 331 +/* returns a function pointer to uncompress(). +** int (*uncompress)(unsigned char *dest, unsigned long *destLen, const unsigned char *source, unsigned long sourceLen); +** right out of zlib, useful for decompressing zlibbed data. +** if you pass the parm of 0x10100000, it will return a wa_inflate_struct * to an inflate API. +*/ + + +typedef struct _prefsDlgRec { + HINSTANCE hInst; // dll instance containing the dialog resource + int dlgID; // resource identifier of the dialog + void *proc; // window proceedure for handling the dialog defined as + // LRESULT CALLBACK PrefsPage(HWND,UINT,WPARAM,LPARAM) + + char *name; // name shown for the prefs page in the treelist + intptr_t where; // section in the treelist the prefs page is to be added to + // 0 for General Preferences + // 1 for Plugins + // 2 for Skins + // 3 for Bookmarks (no longer in the 5.0+ prefs) + // 4 for Prefs (the old 'Setup' section - no longer in 5.0+) + + intptr_t _id; + struct _prefsDlgRec *next; // no longer implemented as a linked list, now used by Winamp for other means +} prefsDlgRec; + +typedef struct _prefsDlgRecW { + HINSTANCE hInst; // dll instance containing the dialog resource + int dlgID; // resource identifier of the dialog + void *proc; // window proceedure for handling the dialog defined as + // LRESULT CALLBACK PrefsPage(HWND,UINT,WPARAM,LPARAM) + + wchar_t *name; // name shown for the prefs page in the treelist + intptr_t where; // section in the treelist the prefs page is to be added to + // 0 for General Preferences + // 1 for Plugins + // 2 for Skins + // 3 for Bookmarks (no longer in the 5.0+ prefs) + // 4 for Prefs (the old 'Setup' section - no longer in 5.0+) + + intptr_t _id; + struct _prefsDlgRec *next; // no longer implemented as a linked list, now used by Winamp for other means +} prefsDlgRecW; + +#define IPC_ADD_PREFS_DLG 332 +#define IPC_ADD_PREFS_DLGW 1332 +#define IPC_REMOVE_PREFS_DLG 333 +#define IPC_UPDATE_PREFS_DLG 342 +#define IPC_UPDATE_PREFS_DLGW 1342 +/* (requires Winamp 2.9+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG); +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_REMOVE_PREFS_DLG); +** +** IPC_ADD_PREFS_DLG: +** To use this you need to allocate a prefsDlgRec structure (either on the heap or with +** some global data but NOT on the stack) and then initialise the members of the structure +** (see the definition of the prefsDlgRec structure above). +** +** hInst - dll instance of where the dialog resource is located. +** dlgID - id of the dialog resource. +** proc - dialog window procedure for the prefs dialog. +** name - name of the prefs page as shown in the preferences list. +** where - see above for the valid locations the page can be added. +** +** Then you do SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG); +** +** example: +** +** prefsDlgRec* prefsRec = 0; +** prefsRec = GlobalAlloc(GPTR,sizeof(prefsDlgRec)); +** prefsRec->hInst = hInst; +** prefsRec->dlgID = IDD_PREFDIALOG; +** prefsRec->name = "Pref Page"; +** prefsRec->where = 0; +** prefsRec->proc = PrefsPage; +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_ADD_PREFS_DLG); +** +** +** IPC_REMOVE_PREFS_DLG: +** To use you pass the address of the same prefsRec you used when adding the prefs page +** though you shouldn't really ever have to do this but it's good to clean up after you +** when you're plugin is being unloaded. +** +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_REMOVE_PREFS_DLG); +** +** IPC_ADD_PREFS_DLGW +** requires Winamp 5.53+ +** +** IPC_UPDATE_PREFS_DLG +** IPC_UPDATE_PREFS_DLGW +** requires Winamp 5.7+ +*/ + + +#define IPC_OPENPREFSTOPAGE 380 +/* SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&prefsRec,IPC_OPENPREFSTOPAGE); +** +** There are two ways of opening a preferences page. +** +** The first is to pass an id of a builtin preferences page (see below for ids) or a +** &prefsDlgRec of the preferences page to open and this is normally done if you are +** opening a prefs page you added yourself. +** +** If the page id does not or the &prefsRec is not valid then the prefs dialog will be +** opened to the first page available (usually the Winamp Pro page). +** +** (requires Winamp 5.04+) +** Passing -1 for param will open the preferences dialog to the last page viewed. +** +** Note: v5.0 to 5.03 had a bug in this api +** +** On the first call then the correct prefs page would be opened to but on the next call +** the prefs dialog would be brought to the front but the page would not be changed to the +** specified. +** In 5.04+ it will change to the prefs page specified if the prefs dialog is already open. +*/ + +/* Builtin Preference page ids (valid for 5.0+) +** (stored in the lParam member of the TVITEM structure from the tree item) +** +** These can be useful if you want to detect a specific prefs page and add things to it +** yourself or something like that ;) +** +** Winamp Pro 20 +** General Preferences 0 +** File Types 1 +** Playlist 23 +** Titles 21 +** Playback 42 (added in 5.25) +** Station Info 41 (added in 5.11 & removed in 5.5) +** Video 24 +** Localization 25 (added in 5.5) +** Skins 40 +** Classic Skins 22 +** Plugins 30 +** Input 31 +** Output 32 +** Visualisation 33 +** DSP/Effect 34 +** General Purpose 35 +** +** Note: +** Custom page ids begin from 60 +** The value of the normal custom pages (Global Hotkeys, Jump To File, etc) is not +** guaranteed since it depends on the order in which the plugins are loaded which can +** change on different systems. +** +** Global Hotkeys, Jump To File, Media Library (under General Preferences and child pages), +** Media Library (under Plugins), Portables, CD Ripping and Modern Skins are custom pages +** created by the plugins shipped with Winamp. +*/ + + +#define IPC_GETINIFILE 334 +/* (requires Winamp 2.9+) +** char *ini=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILE); +** This returns a pointer to the full file path of winamp.ini. +** +** char ini_path[MAX_PATH] = {0}; +** +** void GetIniFilePath(HWND hwnd){ +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION) >= 0x2900){ +** // this gets the string of the full ini file path +** lstrcpynA(ini_path,(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILE),sizeof(ini_path)); +** } +** else{ +** char* p = ini_path; +** p += GetModuleFileNameA(0,ini_path,sizeof(ini_path)) - 1; +** while(p && *p != '.' && p != ini_path){p = CharPrevA(ini_path,p);} +** lstrcpynA(p+1,"ini",sizeof(ini_path)); +** } +** } +*/ + + +#define IPC_GETINIFILEW 1334 +/* (requires Winamp 5.58+) +** wchar_t *ini=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILEW); +** This returns a pointer to the full file path of winamp.ini. +** +** wchar_t ini_path[MAX_PATH] = {0}; +** +** void GetIniFilePath(HWND hwnd){ +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION) >= 0x5058){ +** // this gets the string of the full ini file path +** lstrcpynW(ini_path,(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIFILEW),sizeof(ini_path)); +** } +** else{ +** wchar_t* p = ini_path; +** p += GetModuleFileNameW(0,ini_path,sizeof(ini_path)) - 1; +** while(p && *p != '.' && p != ini_path){p = CharPrevW(ini_path,p);} +** lstrcpynW(p+1,L"ini",sizeof(ini_path)); +** } +** } +** +** IPC_GETINIFILEW requires 5.58+ +*/ + + +#define IPC_GETINIDIRECTORY 335 +/* (requires Winamp 2.9+) +** char *dir=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIDIRECTORY); +** This returns a pointer to the directory where winamp.ini can be found and is +** useful if you want store config files but you don't want to use winamp.ini. +*/ + + +#define IPC_GETINIDIRECTORYW 1335 +/* (requires Winamp 5.58+) +** wchar_t *dir=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETINIDIRECTORYW); +** This returns a pointer to the directory where winamp.ini can be found and is +** useful if you want store config files but you don't want to use winamp.ini. +*/ + + +#define IPC_GETPLUGINDIRECTORY 336 +/* (requires Winamp 5.11+) +** char *plugdir=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETPLUGINDIRECTORY); +** This returns a pointer to the directory where Winamp has its plugins stored and is +** useful if you want store config files in plugins.ini in the plugins folder or for +** accessing any local files in the plugins folder. +*/ + + +#define IPC_GETPLUGINDIRECTORYW 1336 +/* (requires Winamp 5.58+) +** wchar_t *plugdir=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETPLUGINDIRECTORYW); +** This returns a pointer to the directory where Winamp has its plugins stored and is +** useful if you want store config files in plugins.ini in the plugins folder or for +** accessing any local files in the plugins folder. +*/ + + +#define IPC_GETM3UDIRECTORY 337 +/* (requires Winamp 5.11+) +** char *m3udir=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETM3UDIRECTORY); +** This returns a pointer to the directory where winamp.m3u (and winamp.m3u8 if supported) is stored in. +*/ + + +#define IPC_GETM3UDIRECTORYW 338 +/* (requires Winamp 5.3+) +** wchar_t *m3udirW=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETM3UDIRECTORYW); +** This returns a pointer to the directory where winamp.m3u (and winamp.m3u8 if supported) is stored in. +*/ + + +#define IPC_GETVISDIRECTORYW 339 +/* (requires Winamp 5.58+) +** wchar_t *visdir=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVISDIRECTORYW); +** This returns a pointer to the directory set to load/store visualization plugins from. +** +** This can otherwise be obtained by reading the "VISDir" entry in the winamp section of +** winamp.ini which if null then you need to assume \plugins +*/ + + +#define IPC_GETSKINDIRECTORYW 340 +/* (requires Winamp 5.58+) +** wchar_t *skindir=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETSKINDIRECTORYW); +** This returns a pointer to the directory set to load/store installed skins from. +** +** This can otherwise be obtained by reading the "SkinDir" entry in the winamp section of +** winamp.ini which if null then you need to assume \skins +*/ + + +#define IPC_GETDSPDIRECTORYW 341 +/* (requires Winamp 5.58+) +** wchar_t *dspdir=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETDSPDIRECTORYW); +** This returns a pointer to the directory set to load/store installed DSP/effect plugins from. +** +** This can otherwise be obtained by reading the "DSPDir" entry in the winamp section of +** winamp.ini which if null then you need to assume \plugins +*/ + + +#define IPC_SPAWNBUTTONPOPUP 361 // param = +// 0 = eject +// 1 = previous +// 2 = next +// 3 = pause +// 4 = play +// 5 = stop + + +#define IPC_OPENURLBOX 360 +/* (requires Winamp 5.0+) +** HGLOBAL hglobal = (HGLOBAL)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENURLBOX); +** You pass a hwnd for the dialog to be parented to (which modern skin support uses). +** This will return a HGLOBAL that needs to be freed with GlobalFree() if this worked. +*/ + + +#define IPC_OPENFILEBOX 362 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENFILEBOX); +** You pass a hwnd for the dialog to be parented to (which modern skin support uses). +*/ + + +#define IPC_OPENDIRBOX 363 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_OPENDIRBOX); +** You pass a hwnd for the dialog to be parented to (which modern skin support uses). +*/ + + +#define IPC_SETDIALOGBOXPARENT 364 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)parent,IPC_SETDIALOGBOXPARENT); +** Pass 'parent' as the window which will be used as the parent for a number of the built +** in Winamp dialogs and is useful when you are taking over the whole of the UI so that +** the dialogs will not appear at the bottom right of the screen since the main winamp +** window is located at 3000x3000 by gen_ff when this is used. Call this again with +** parent = null to reset the parent back to the orginal Winamp window. +*/ + + +#define IPC_GETDIALOGBOXPARENT 365 +/* (requires Winamp 5.51+) +** HWND hwndParent = SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GETDIALOGBOXPARENT); +** hwndParent can / must be passed to all modal dialogs/MessageBoxes when using Winamp as a parent. +*/ + + +#define IPC_UPDATEDIALOGBOXPARENT 366 +/* (requires Winamp 5.53+) +** If you previously called IPC_SETDIALOGBOXPARENT then call this every time your window resizes. +*/ + + +#define IPC_DRO_MIN 401 // reserved for DrO + +#define IPC_SET_JTF_COMPARATOR 409 +/* (requires Winamp 5.2+) +/* pass me an int (__cdecl *)(const char *, const char *) in wParam +** If this is not set or if it is cleared then Winamp reverts to it's own comparator. +** It is not until Winamp 5.33+ that passing wParam=0 or another function will allow +** for it to be changed from what was set on the first calling of this api. +*/ + +#define IPC_SET_JTF_COMPARATOR_W 410 +/* (requires Winamp 5.55+) +** pass me an int (__cdecl *)(const wchar_t *, const wchar_t *) in wParam +** If this is not set or if it is cleared then Winamp will revert to the +** IPC_SET_JTF_COMPARATOR handler or the native search function if not set. +*/ + +#define IPC_SET_JTF_DRAWTEXT 416 + +#define IPC_DRO_MAX 499 + + +// pass 0 for a copy of the skin HBITMAP +// pass 1 for name of font to use for playlist editor likeness +// pass 2 for font charset +// pass 3 for font size +#define IPC_GET_GENSKINBITMAP 503 + + +#ifdef __cplusplus +class ifc_window; +#endif + +typedef struct embedWindowState embedWindowState; + +#define FFC_CREATEEMBED 0 // param = (LPARAM)(ifc_window*)windowParent; return 1 to terminate creation. +#define FFC_DESTROYEMBED 1 + +typedef int (CALLBACK *FFCALLBACK)(embedWindowState* /*windowState*/, INT /*eventId*/, LPARAM /*param*/); + +typedef struct embedWindowState +{ + HWND me; //hwnd of the window + + #define EMBED_FLAGS_NORESIZE 0x1 + // set this bit to keep window from being resizable + + #define EMBED_FLAGS_NOTRANSPARENCY 0x2 + // set this bit to make gen_ff turn transparency off for this window + + #define EMBED_FLAGS_NOWINDOWMENU 0x4 + // set this bit to prevent gen_ff from automatically adding your window to the right-click menu + + #define EMBED_FLAGS_GUID 0x8 + // (5.31+) call SET_EMBED_GUID(yourEmbedWindowStateStruct, GUID) to define a GUID for this window + + #define EMBED_FLAGS_FFCALLBACK 0x10 + // 5.55+ + + #define SET_EMBED_GUID(windowState, windowGUID) { windowState->flags |= EMBED_FLAGS_GUID; *((GUID *)&windowState->extra_data[4])=windowGUID; } + #define GET_EMBED_GUID(windowState) (*((GUID *)&windowState->extra_data[4])) + + int flags; // see above + + RECT r; + void *user_ptr; // for application use + + union + { + #pragma warning(push) + #pragma warning(disable:4201) + #pragma pack(push, 1) + struct + { + struct embedWindowState *link; + intptr_t attached; + intptr_t padding1[2]; //2-3 + GUID guid; // 4-7 + #ifdef _WIN64 + intptr_t guidpadding; + #endif + FFCALLBACK callback; // MAKSIM UPDATE HERE + intptr_t padding2[52]; // 9-60 + intptr_t hostcount; // 61 + intptr_t reparenting; // 62 + #ifdef __cplusplus + ifc_window *wasabi_window; + #else + void *wasabi_window; // ifc_window * + #endif + }; + #pragma warning(pop) + #pragma pack(pop) + intptr_t extra_data[64]; // for internal winamp use + }; +} embedWindowState; + + +#define IPC_GET_EMBEDIF 505 +/* (requires Winamp 2.9+) +** HWND myframe = (HWND)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&wa_wnd,IPC_GET_EMBEDIF); +** +** or +** +** HWND myframe = 0; +** HWND (*embed)(embedWindowState *params)=0; +** *(void**)&embed = (void*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_EMBEDIF); +** myframe = embed(&wa_wnd); +** +** You pass an embedWindowState* and it will return a hwnd for the frame window or if you +** pass wParam as null then it will return a HWND embedWindow(embedWindowState *); +** +** Embed window can send notification to the first child. +** Notifications will come in form of WM_NOTIFY. +** Notifications: +*/ + +#define EWN_FIRST (0) + +typedef struct __EMBEDSHOW +{ + NMHDR hdr; + BOOL fShow; + UINT nStatus; +} EMBEDSHOW; + +#define EWN_SHOWWINDOW (EWN_FIRST + 0) // lParam = (LPARAM)(EMBEDSHOW*)pnmh. This is preffered way to show hide your chold window + +#define IPC_SKINWINDOW 534 + +#define SWF_NORESIZE EMBED_FLAGS_NORESIZE +#define SWF_NOTRANSPARENCY EMBED_FLAGS_NOTRANSPARENCY +#define SWF_NOWINDOWMENU EMBED_FLAGS_NOWINDOWMENU + +typedef struct __SKINWINDOWPARAM +{ + INT cbSize; // sizeof(SKINWINDOWPARAM) + HWND hwndToSkin; + GUID windowGuid; + UINT flagsEx; + FFCALLBACK callbackFF; +} SKINWINDOWPARAM; + + +typedef struct embedEnumStruct +{ + int (*enumProc)(embedWindowState *ws, struct embedEnumStruct *param); // return 1 to abort + int user_data; // or more :) +} embedEnumStruct; // pass +#define IPC_EMBED_ENUM 532 +/* (requires Winamp 2.9+) +*/ + + +#define IPC_EMBED_ISVALID 533 +/* (requires Winamp 2.9+) +** int valid = SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)embedhwnd,IPC_EMBED_ISVALID); +** Pass a hwnd in the wParam to this to check if the hwnd is a valid embed window or not. +*/ + + +#define IPC_CONVERTFILE 506 +/* (requires Winamp 2.92+) +** Converts a given file to a different format (PCM, MP3, etc...) +** To use, pass a pointer to a waFileConvertStruct struct +** This struct can be either on the heap or some global +** data, but NOT on the stack. At least, until the conversion is done. +** +** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE); +** +** Return value: +** 0: Can't start the conversion. Look at myConvertStruct->error for details. +** 1: Conversion started. Status messages will be sent to the specified callbackhwnd. +** Be sure to call IPC_CONVERTFILE_END when your callback window receives the +** IPC_CB_CONVERT_DONE message. +*/ +#ifdef __cplusplus +class ifc_audiostream; +class AudioCoder; +#else +typedef void *ifc_audiostream; +typedef void *AudioCoder; +#endif +typedef struct +{ + char *sourcefile; // "c:\\source.mp3" + char *destfile; // "c:\\dest.pcm" + intptr_t destformat[8]; // like 'PCM ',srate,nch,bps. + //hack alert! you can set destformat[6]=mmioFOURCC('I','N','I',' '); and destformat[7]=(int)my_ini_file; (where my_ini_file is a char*) + HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages + + //filled in by winamp.exe + char *error; //if IPC_CONVERTFILE returns 0, the reason will be here + + int bytes_done; //you can look at both of these values for speed statistics + int bytes_total; + int bytes_out; + + int killswitch; // don't set it manually, use IPC_CONVERTFILE_END + /* everything below is for internal use */ + ifc_audiostream *decoder; // for internal winamp use + HANDLE convert_thread; + HANDLE file_handle; + AudioCoder *audio_coder; + HMODULE encoder_mod; + int bps; + int channels; + int sample_rate; + intptr_t extra_data[56]; // for future use +} convertFileStruct; + + +#define IPC_CONVERTFILEW 515 +// (requires Winamp 5.36+) + +typedef struct +{ + wchar_t *sourcefile; // "c:\\source.mp3" + wchar_t *destfile; // "c:\\dest.pcm" + intptr_t destformat[8]; // like 'PCM ',srate,nch,bps. + //hack alert! you can set destformat[6]=mmioFOURCC('I','N','I',' '); and destformat[7]=(int)my_ini_file; (where my_ini_file is a char*) + HWND callbackhwnd; // window that will receive the IPC_CB_CONVERT notification messages + + //filled in by winamp.exe + wchar_t *error; //if IPC_CONVERTFILE returns 0, the reason will be here + + int bytes_done; //you can look at both of these values for speed statistics + int bytes_total; + int bytes_out; + + int killswitch; // don't set it manually, use IPC_CONVERTFILE_END + /* everything below is for internal use */ + ifc_audiostream *decoder; // for internal winamp use + HANDLE convert_thread; + HANDLE file_handle; + AudioCoder *audio_coder; + HMODULE encoder_mod; + int bps; + int channels; + int sample_rate; + intptr_t extra_data[56]; // for future use +} convertFileStructW; + + +#define IPC_CONVERTFILE_END 507 +/* (requires Winamp 2.92+) +** Stop/ends a convert process started from IPC_CONVERTFILE +** You need to call this when you receive the IPC_CB_CONVERTDONE message or when you +** want to abort a conversion process +** +** eg: SendMessage(hwnd_winamp,WM_WA_IPC,&myConvertStruct,IPC_CONVERTFILE_END); +** +** No return value +*/ + + +#define IPC_CONVERTFILEW_END 516 +// (requires Winamp 5.36+) + + +typedef struct { + HWND hwndParent; + int format; + + //filled in by winamp.exe + HWND hwndConfig; + int extra_data[8]; + //hack alert! you can set extra_data[6]=mmioFOURCC('I','N','I',' '); and extra_data[7]=(int)my_ini_file; (where my_ini_file is a char*) +} convertConfigStruct; + +#define IPC_CONVERT_CONFIG 508 +#define IPC_CONVERT_CONFIG_END 509 + + +typedef struct +{ + void (*enumProc)(intptr_t user_data, const char *desc, int fourcc); + intptr_t user_data; +} converterEnumFmtStruct; + +#define IPC_CONVERT_CONFIG_ENUMFMTS 510 +/* (requires Winamp 2.92+) +*/ + + +typedef struct +{ + char cdletter; + char *playlist_file; + HWND callback_hwnd; + + //filled in by winamp.exe + char *error; +} burnCDStruct; +#define IPC_BURN_CD 511 +/* (requires Winamp 5.0+) +*/ + + +typedef struct +{ + convertFileStruct *cfs; + int priority; +} convertSetPriority; + +#define IPC_CONVERT_SET_PRIORITY 512 + + +typedef struct +{ + convertFileStructW *cfs; + int priority; +} convertSetPriorityW; + +#define IPC_CONVERT_SET_PRIORITYW 517 +// (requires Winamp 5.36+) + + +#define IPC_CONVERT_TEST 518 +/* requires Winamp 5.55+ +* pass a convertFileStructW and it will verify that you are able to transcode +* checks: +* - valid input file +* - valid destination format / encoder type (including winamp pro authorization for mp3) +* - valid destination file (not that as a side-effect, this function will create a 0 byte destination file!) +*/ + + +typedef struct +{ + unsigned int format; //fourcc value + char *item; // config item, eg "bitrate" + char *data; // buffer to recieve, or buffer that contains the data + int len; // length of the data buffer (only used when getting a config item) + char *configfile; // config file to read from +} convertConfigItem; + +#define IPC_CONVERT_CONFIG_SET_ITEM 513 // returns TRUE if successful +#define IPC_CONVERT_CONFIG_GET_ITEM 514 // returns TRUE if successful + + +typedef struct +{ + const char *filename; + char *title; // 2048 bytes + int length; + int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit +} waHookTitleStruct; + +#define IPC_HOOK_TITLES 850 +/* (requires Winamp 5.0+) +** If you hook this message and modify the information then make sure to return TRUE. +** If you don't hook the message then make sure you pass it on through the subclass chain. +** +** LRESULT CALLBACK WinampWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) +** { +** LRESULT ret = CallWindowProc((WNDPROC)WinampProc,hwnd,umsg,wParam,lParam); +** +** if(message==WM_WA_IPC && lParam==IPC_HOOK_TITLES) +** { +** waHookTitleStruct *ht = (waHookTitleStruct *) wParam; +** // Doing ATF stuff with ht->title, whatever... +** return TRUE; +** } +** return ret; +** } +*/ + + +typedef struct +{ + const wchar_t *filename; + wchar_t *title; // 2048 characters + int length; + int force_useformatting; // can set this to 1 if you want to force a url to use title formatting shit +} waHookTitleStructW; + +#define IPC_HOOK_TITLESW 851 +/* (requires Winamp 5.3+) +** See information on IPC_HOOK_TITLES for how to process this. +*/ + + +#define IPC_GETSADATAFUNC 800 +/* (requires Winamp 5.0+) +** = SendMessage(hwnd_winamp,WM_WA_IPC,param,IPC_GETSADATAFUNC); +** where param can be 0 , 1 or 2. A param == 2 is meant to replace param == 0 as of 5.5+ +** +** void (*export_sa_setreq)(int want); +** *(void **)&export_sa_setreq=(void *)SendMessage(hwnd_winamp,WM_WA_IPC,1,IPC_GETSADATAFUNC); +** This can called as either want = 0 -> use user setting (ie classic skin mode) +** or want = 1 -> just obtain data (ie modern skin mode) +** +** (replaces passing wParam == 0 and if not present then this call will return a null function pointer) +** char * (*export_sa_get)(char data[75*2 + 8]); +** *(void **)&export_sa_get=(void*)SendMessage(hwnd_winamp,WM_WA_IPC,2,IPC_GETSADATAFUNC); +** +** When called this will fill the passed buffer with 150 bytes of data and return a pointer to it. +** char data[75*2 + 8]; +** char *p = export_sa_get(data); +** +** +** (deprecated as of at least 5.5+ but should still work) +** char * (*export_sa_get_deprecated)(); +** *(void **)&export_sa_get_deprecated=(void*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETSADATAFUNC); +** +** When called this will return 150 bytes of data as a static buffer inside Winamp. +** char *data = export_sa_get_deprecated(); +*/ + + +#define IPC_GETVUDATAFUNC 801 +/* (requires Winamp 5.0+) +** +** int (*export_vu_get)(int channel); +** *(void **)&export_vu_get=(void*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVUDATAFUNC); +** +** +** This returns a function pointer of int export_vu_get(int channel) and when called it +** will return values between 0 - 255 or or it will return -1 for a bad channel / value. +** +** Calling export_vu_get(0) will return the left channel. +** Calling export_vu_get(1) will return the right channel. +*/ + + +#define IPC_ISMAINWNDVISIBLE 900 +/* (requires Winamp 5.0+) +** int visible=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISMAINWNDVISIBLE); +** You send this to Winamp to query if the main window is visible or not such as by +** unchecking the option in the main right-click menu. If the main window is visible then +** this will return 1 otherwise it returns 0. +*/ + + +typedef struct +{ + int numElems; + int *elems; + HBITMAP bm; // set if you want to override +} waSetPlColorsStruct; + +#define IPC_SETPLEDITCOLORS 920 +/* (requires Winamp 5.0+) +** This is sent by gen_ff when a modern skin is being loaded to set the colour scheme for +** the playlist editor. When sent numElems is usually 6 and matches with the 6 possible +** colours which are provided be pledit.txt from the classic skins. The elems array is +** defined as follows: +** +** elems = 0 => normal text +** elems = 1 => current text +** elems = 2 => normal background +** elems = 3 => selected background +** elems = 4 => minibroswer foreground +** elems = 5 => minibroswer background +** +** if(uMsg == WM_WA_IPC && lParam == IPC_SETPLEDITCOLORS) +** { +** waSetPlColorsStruct* colStr = (waSetPlColorsStruct*)wp; +** if(colStr) +** { +** // set or inspect the colours being used (basically for gen_ff's benefit) +** } +** } +*/ + + +typedef struct +{ + HWND wnd; + int xpos; // in screen coordinates + int ypos; +} waSpawnMenuParms; + +// waSpawnMenuParms2 is used by the menubar submenus +typedef struct +{ + HWND wnd; + int xpos; // in screen coordinates + int ypos; + int width; + int height; +} waSpawnMenuParms2; + +// the following IPC use waSpawnMenuParms as parameter +#define IPC_SPAWNEQPRESETMENU 933 +#define IPC_SPAWNFILEMENU 934 //menubar +#define IPC_SPAWNOPTIONSMENU 935 //menubar +#define IPC_SPAWNWINDOWSMENU 936 //menubar +#define IPC_SPAWNHELPMENU 937 //menubar +#define IPC_SPAWNPLAYMENU 938 //menubar +#define IPC_SPAWNPEFILEMENU 939 //menubar +#define IPC_SPAWNPEPLAYLISTMENU 940 //menubar +#define IPC_SPAWNPESORTMENU 941 //menubar +#define IPC_SPAWNPEHELPMENU 942 //menubar +#define IPC_SPAWNMLFILEMENU 943 //menubar +#define IPC_SPAWNMLVIEWMENU 944 //menubar +#define IPC_SPAWNMLHELPMENU 945 //menubar +#define IPC_SPAWNPELISTOFPLAYLISTS 946 + + +#define WM_WA_SYSTRAY WM_USER+1 +/* This is sent by the system tray when an event happens (you might want to simulate it). +** +** if(uMsg == WM_WA_SYSTRAY) +** { +** switch(lParam) +** { +** // process the messages sent from the tray +** } +** } +*/ + + +#define WM_WA_MPEG_EOF WM_USER+2 +/* Input plugins send this when they are done playing back the current file to inform +** Winamp or anyother installed plugins that the current +** +** if(uMsg == WM_WA_MPEG_EOF) +** { +** // do what is needed here +** } +*/ + + +//// video stuff + +#define IPC_IS_PLAYING_VIDEO 501 // returns >1 if playing, 0 if not, 1 if old version (so who knows):) +#define IPC_GET_IVIDEOOUTPUT 500 // see below for IVideoOutput interface +#define VIDEO_MAKETYPE(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24)) +#define VIDUSER_SET_INFOSTRING 0x1000 +#define VIDUSER_GET_VIDEOHWND 0x1001 +#define VIDUSER_SET_VFLIP 0x1002 +#define VIDUSER_SET_TRACKSELINTERFACE 0x1003 // give your ITrackSelector interface as param2 +#define VIDUSER_OPENVIDEORENDERER 0x1004 +#define VIDUSER_CLOSEVIDEORENDERER 0x1005 +#define VIDUSER_GETPOPUPMENU 0x1006 +#define VIDUSER_SET_INFOSTRINGW 0x1007 +#define VIDUSER_SET_THREAD_SAFE 0x1008 // set param2 = 1 if open(), draw() and close() will be called on the same thread +#define VIDUSER_SET_PALETTE 0x1010 + +typedef struct +{ + int w; + int h; + int vflip; + double aspectratio; + unsigned int fmt; +} VideoOpenStruct; + +#ifndef NO_IVIDEO_DECLARE +#ifdef __cplusplus + +class VideoOutput; +class SubsItem; + +#ifndef _NSV_DEC_IF_H_ +struct YV12_PLANE { + unsigned char* baseAddr; + long rowBytes; +} ; + +struct YV12_PLANES { + YV12_PLANE y; + YV12_PLANE u; + YV12_PLANE v; +}; +#endif + +class IVideoOutput +{ + public: + virtual ~IVideoOutput() { } + virtual int open(int w, int h, int vflip, double aspectratio, unsigned int fmt)=0; + virtual void setcallback(LRESULT (*msgcallback)(void *token, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam), void *token) { (void)token; (void)msgcallback; /* to eliminate warning C4100 */ } + virtual void close()=0; + virtual void draw(void *frame)=0; + virtual void drawSubtitle(SubsItem *item) {UNREFERENCED_PARAMETER(item); } + virtual void showStatusMsg(const char *text) {UNREFERENCED_PARAMETER(text); } + virtual int get_latency() { return 0; } + virtual void notifyBufferState(int bufferstate) { UNREFERENCED_PARAMETER(bufferstate); } /* 0-255*/ + virtual INT_PTR extended(INT_PTR param1, INT_PTR param2, INT_PTR param3) { UNREFERENCED_PARAMETER(param1); UNREFERENCED_PARAMETER(param2); UNREFERENCED_PARAMETER(param3); return 0; } // Dispatchable, eat this! +}; + +class ITrackSelector +{ + public: + virtual int getNumAudioTracks()=0; + virtual void enumAudioTrackName(int n, char *buf, int size)=0; + virtual int getCurAudioTrack()=0; + virtual int getNumVideoTracks()=0; + virtual void enumVideoTrackName(int n, char *buf, int size)=0; + virtual int getCurVideoTrack()=0; + + virtual void setAudioTrack(int n)=0; + virtual void setVideoTrack(int n)=0; +}; + +#endif //cplusplus +#endif//NO_IVIDEO_DECLARE + +// these messages are callbacks that you can grab by subclassing the winamp window + +// wParam = +#define IPC_CB_WND_EQ 0 // use one of these for the param +#define IPC_CB_WND_PE 1 +#define IPC_CB_WND_MB 2 +#define IPC_CB_WND_VIDEO 3 +#define IPC_CB_WND_MAIN 4 + +#define IPC_CB_ONSHOWWND 600 +#define IPC_CB_ONHIDEWND 601 + +#define IPC_CB_GETTOOLTIP 602 +#define IPC_CB_GETTOOLTIPW 1602 + +#define IPC_CB_MISC 603 + #define IPC_CB_MISC_TITLE 0 // start of playing/stop/pause + #define IPC_CB_MISC_VOLUME 1 // volume/pan + #define IPC_CB_MISC_STATUS 2 // start playing/stop/pause/ffwd/rwd + #define IPC_CB_MISC_EQ 3 + #define IPC_CB_MISC_INFO 4 + #define IPC_CB_MISC_VIDEOINFO 5 + #define IPC_CB_MISC_TITLE_RATING 6 // (5.5+ for when the rating is changed via the songticker menu on current file) + +/* Example of using IPC_CB_MISC_STATUS to detect the start of track playback with 5.x +** +** if(lParam == IPC_CB_MISC && wParam == IPC_CB_MISC_STATUS) +** { +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISPLAYING) == 1 && +** !SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETOUTPUTTIME)) +** { +** char* file = (char*)SendMessage(hwnd_winamp,WM_WA_IPC, +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS),IPC_GETPLAYLISTFILE); +** // only output if a valid file was found +** if(file) +** { +** MessageBox(hwnd_winamp,file,"starting",0); +** // or do something else that you need to do +** } +** } +** } +*/ + + +#define IPC_CB_CONVERT_STATUS 604 // param value goes from 0 to 100 (percent) +#define IPC_CB_CONVERT_DONE 605 + + +#define IPC_ADJUST_FFWINDOWSMENUPOS 606 +/* (requires Winamp 2.9+) +** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFWINDOWSMENUPOS); +** This will move where Winamp expects the freeform windows in the menubar windows main +** menu. This is useful if you wish to insert a menu item above extra freeform windows. +*/ + + +#define IPC_ISDOUBLESIZE 608 +/* (requires Winamp 5.0+) +** int dsize=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISDOUBLESIZE); +** You send this to Winamp to query if the double size mode is enabled or not. +** If it is on then this will return 1 otherwise it will return 0. +*/ + + +#define IPC_ADJUST_FFOPTIONSMENUPOS 609 +/* (requires Winamp 2.9+) +** int newpos=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)adjust_offset,IPC_ADJUST_FFOPTIONSMENUPOS); +** moves where winamp expects the freeform preferences item in the menubar windows main +** menu. This is useful if you wish to insert a menu item above the preferences item. +** If you pass adjust_offset as zero then it will return the current offset without adjusting it. +** +** Note: This setting was ignored by gen_ff until it was fixed in 5.1 +** gen_ff would assume that the menu position was 11 in all cases and so when you +** had two plugins attempting to add entries into the main right click menu it +** would cause the 'colour themes' submenu to either be incorrectly duplicated or +** to just disappear instead. +*/ + + +#define IPC_GETTIMEDISPLAYMODE 610 +/* (requires Winamp 5.0+) +** int mode=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETTIMEDISPLAYMODE); +** This will return the status of the time display i.e. shows time elapsed or remaining. +** This returns 0 if Winamp is displaying time elapsed or 1 for the time remaining. +*/ + + +#define IPC_SETVISWND 611 +/* (requires Winamp 5.0+) +** int viswnd=(HWND)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)viswnd,IPC_SETVISWND); +** This allows you to set a window to receive the following message commands (which are +** used as part of the modern skin integration). +** When you have finished or your visualisation is closed then send wParam as zero to +** ensure that things are correctly tidied up. +*/ + +/* The following messages are received as the LOWORD(wParam) of the WM_COMMAND message. +** See %SDK%\winamp\wa5vis.txt for more info about visualisation integration in Winamp. +*/ +#define ID_VIS_NEXT 40382 +#define ID_VIS_PREV 40383 +#define ID_VIS_RANDOM 40384 +#define ID_VIS_FS 40389 +#define ID_VIS_CFG 40390 +#define ID_VIS_MENU 40391 + + +#define IPC_GETVISWND 612 +/* (requires Winamp 5.0+) +** int viswnd=(HWND)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVISWND); +** This returns a HWND to the visualisation command handler window if set by IPC_SETVISWND. +*/ + + +#define IPC_ISVISRUNNING 613 +/* (requires Winamp 5.0+) +** int visrunning=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_ISVISRUNNING); +** This will return 1 if a visualisation is currently running and 0 if one is not running. +*/ + + +#define IPC_CB_VISRANDOM 628 // param is status of random + + +#define IPC_SETIDEALVIDEOSIZE 614 +/* (requires Winamp 5.0+) +** This is sent by Winamp back to itself so it can be trapped and adjusted as needed with +** the desired width in HIWORD(wParam) and the desired height in LOWORD(wParam). +** +** if(uMsg == WM_WA_IPC){ +** if(lParam == IPC_SETIDEALVIDEOSIZE){ +** wParam = MAKEWPARAM(height,width); +** } +** } +*/ + + +#define IPC_GETSTOPONVIDEOCLOSE 615 +/* (requires Winamp 5.0+) +** int sovc=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETSTOPONVIDEOCLOSE); +** This will return 1 if 'stop on video close' is enabled and 0 if it is disabled. +*/ + + +#define IPC_SETSTOPONVIDEOCLOSE 616 +/* (requires Winamp 5.0+) +** int sovc=SendMessage(hwnd_winamp,WM_WA_IPC,enabled,IPC_SETSTOPONVIDEOCLOSE); +** Set enabled to 1 to enable and 0 to disable the 'stop on video close' option. +*/ + + +typedef struct { + HWND hwnd; + int uMsg; + WPARAM wParam; + LPARAM lParam; +} transAccelStruct; + +#define IPC_TRANSLATEACCELERATOR 617 +/* (requires Winamp 5.0+) +** (deprecated as of 5.53x+) +*/ + + +typedef struct { + int cmd; + int x; + int y; + int align; +} windowCommand; // send this as param to an IPC_PLCMD, IPC_MBCMD, IPC_VIDCMD + + +#define IPC_CB_ONTOGGLEAOT 618 + + +#define IPC_GETPREFSWND 619 +/* (requires Winamp 5.0+) +** HWND prefs = (HWND)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETPREFSWND); +** This will return a handle to the preferences dialog if it is open otherwise it will +** return zero. A simple check with the OS api IsWindow(..) is a good test if it's valid. +** +** e.g. this will open (or close if already open) the preferences dialog and show if we +** managed to get a valid +** SendMessage(hwnd_winamp,WM_COMMAND,MAKEWPARAM(WINAMP_OPTIONS_PREFS,0),0); +** MessageBox(hwnd_winamp,(IsWindow((HWND)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETPREFSWND))?"Valid":"Not Open"),0,MB_OK); +*/ + + +#define IPC_SET_PE_WIDTHHEIGHT 620 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&point,IPC_SET_PE_WIDTHHEIGHT); +** You pass a pointer to a POINT structure which holds the width and height and Winamp +** will set the playlist editor to that size (this is used by gen_ff on skin changes). +** There does not appear to be any bounds limiting with this so it is possible to create +** a zero size playlist editor window (which is a pretty silly thing to do). +*/ + + +#define IPC_GETLANGUAGEPACKINSTANCE 621 +/* (requires Winamp 5.0+) +** HINSTANCE hInst = (HINSTANCE)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE); +** This will return the HINSTANCE to the currently used language pack file for winamp.exe +** +** (5.5+) +** If you pass 1 in wParam then you will have zero returned if a language pack is in use. +** if(!SendMessage(hwnd_winamp,WM_WA_IPC,1,IPC_GETLANGUAGEPACKINSTANCE)){ +** // winamp is currently using a language pack +** } +** +** If you pass 2 in wParam then you will get the path to the language pack folder. +** wchar_t* lngpackfolder = (wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,2,IPC_GETLANGUAGEPACKINSTANCE); +** +** If you pass 3 in wParam then you will get the path to the currently extracted language pack. +** wchar_t* lngpack = (wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,3,IPC_GETLANGUAGEPACKINSTANCE); +** +** If you pass 4 in wParam then you will get the name of the currently used language pack. +** wchar_t* lngname = (char*)SendMessage(hwnd_winamp,WM_WA_IPC,4,IPC_GETLANGUAGEPACKINSTANCE); +*/ +#define LANG_IDENT_STR 0 +#define LANG_LANG_CODE 1 +#define LANG_COUNTRY_CODE 2 +/* +** (5.51+) +** If you pass 5 in LOWORD(wParam) then you will get the ident string/code string +** (based on the param passed in the HIWORD(wParam) of the currently used language pack. +** The string returned with LANG_IDENT_STR is used to represent the language that the +** language pack is intended for following ISO naming conventions for consistancy. +** +** wchar_t* ident_str = (wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,MAKEWPARAM(5,LANG_XXX),IPC_GETLANGUAGEPACKINSTANCE); +** +** e.g. +** For the default language it will return the following for the different LANG_XXX codes +** LANG_IDENT_STR -> "en-US" (max buffer size of this is 9 wchar_t) +** LANG_LANG_CODE -> "en" (language code) +** LANG_COUNTRY_CODE -> "US" (country code) +** +** On pre 5.51 installs you can get LANG_IDENT_STR using the following method +** (you'll have to custom process the string returned if you want the langugage or country but that's easy ;) ) +** +** #define LANG_PACK_LANG_ID 65534 (if you don't have lang.h) +** HINSTANCE hInst = (HINSTANCE)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE); +** TCHAR buffer[9] = {0}; +** LoadString(hInst,LANG_PACK_LANG_ID,buffer,sizeof(buffer)); +** +** +** +** The following example shows how using the basic api will allow you to load the playlist +** context menu resource from the currently loaded language pack or it will fallback to +** the default winamp.exe instance. +** +** HINSTANCE lang = (HINSTANCE)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLANGUAGEPACKINSTANCE); +** HMENU popup = GetSubMenu(GetSubMenu((LoadMenu(lang?lang:GetModuleHandle(0),MAKEINTRESOURCE(101))),2),5); +** // do processing as needed on the menu before displaying it +** TrackPopupMenuEx(orig,TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,rc.left,rc.bottom,hwnd_owner,0); +** DestroyMenu(popup); +** +** If you need a specific menu handle then look at IPC_GET_HMENU for more information. +*/ + + +#define IPC_CB_PEINFOTEXT 622 // data is a string, ie: "04:21/45:02" + + +#define IPC_CB_OUTPUTCHANGED 623 // output plugin was changed in config + + +#define IPC_GETOUTPUTPLUGIN 625 +/* (requires Winamp 5.0+) +** char* outdll = (char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETOUTPUTPLUGIN); +** This returns a string of the current output plugin's dll name. +** e.g. if the directsound plugin was selected then this would return 'out_ds.dll'. +*/ + + +#define IPC_SETDRAWBORDERS 626 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,enabled,IPC_SETDRAWBORDERS); +** Set enabled to 1 to enable and 0 to disable drawing of the playlist editor and winamp +** gen class windows (used by gen_ff to allow it to draw its own window borders). +*/ + + +#define IPC_DISABLESKINCURSORS 627 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,enabled,IPC_DISABLESKINCURSORS); +** Set enabled to 1 to enable and 0 to disable the use of skinned cursors. +*/ + + +#define IPC_GETSKINCURSORS 628 +/* (requires Winamp 5.36+) +** data = (WACURSOR)cursorId. (check wa_dlg.h for values) +*/ + + +#define IPC_CB_RESETFONT 629 + + +#define IPC_IS_FULLSCREEN 630 +/* (requires Winamp 5.0+) +** int val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_FULLSCREEN); +** This will return 1 if the video or visualisation is in fullscreen mode or 0 otherwise. +*/ + + +#define IPC_SET_VIS_FS_FLAG 631 +/* (requires Winamp 5.0+) +** 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 +*/ + + +#define IPC_SHOW_NOTIFICATION 632 +/* (requires Winamp 5.0+ & Modern skin support - gen_ff.dll present) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_SHOW_NOTIFICATION); +** If a Modern skin is loaded and this message is sent/received then it will +** trigger the Modern skin notifier to appear (subject to user settings). +*/ + + +#define IPC_GETSKININFO 633 +#define IPC_GETSKININFOW 1633 +/* (requires Winamp 5.0+) +** This is a notification message sent to the main Winamp window by itself whenever it +** needs to get information to be shown about the current skin in the 'Current skin +** information' box on the main Skins page in the Winamp preferences. +** +** When this notification is received and the current skin is one you are providing the +** support for then you return a valid buffer for Winamp to be able to read from with +** information about it such as the name of the skin file. +** +** if(uMsg == WM_WA_IPC && lParam == IPC_GETSKININFO){ +** if(is_our_skin()){ +** return is_our_skin_name(); +** } +** } +*/ + + +#define IPC_GET_MANUALPLADVANCE 634 +/* (requires Winamp 5.03+) +** int val=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_MANUALPLADVANCE); +** IPC_GET_MANUALPLADVANCE returns the status of the Manual Playlist Advance. +** If enabled this will return 1 otherwise it will return 0. +*/ + + +#define IPC_SET_MANUALPLADVANCE 635 +/* (requires Winamp 5.03+) +** SendMessage(hwnd_winamp,WM_WA_IPC,value,IPC_SET_MANUALPLADVANCE); +** IPC_SET_MANUALPLADVANCE sets the status of the Manual Playlist Advance option. +** Set value = 1 to turn it on and value = 0 to turn it off. +*/ + + +#define IPC_GET_NEXT_PLITEM 636 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_NEXT_PLITEM); +** +** Sent to Winamp's main window when an item has just finished playback or the next +** button has been pressed and requesting the new playlist item number to go to. +** +** Subclass this message in your application to return the new item number. +** Return -1 for normal Winamp operation (default) or the new item number in +** the playlist to be played instead of the originally selected next track. +** +** This is primarily provided for the JTFE plugin (gen_jumpex.dll). +*/ + + +#define IPC_GET_PREVIOUS_PLITEM 637 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PREVIOUS_PLITEM); +** +** Sent to Winamp's main window when the previous button has been pressed and Winamp is +** requesting the new playlist item number to go to. +** +** Return -1 for normal Winamp operation (default) or the new item number in +** the playlist to be played instead of the originally selected previous track. +** +** This is primarily provided for the JTFE plugin (gen_jumpex.dll). +*/ + + +#define IPC_IS_WNDSHADE 638 +/* (requires Winamp 5.04+) +** int is_shaded=SendMessage(hwnd_winamp,WM_WA_IPC,wnd,IPC_IS_WNDSHADE); +** Pass 'wnd' as an id as defined for IPC_GETWND or pass -1 to query the status of the +** main window. This returns 1 if the window is in winshade mode and 0 if it is not. +** Make sure you only test for this on a 5.04+ install otherwise you get a false result. +** (See the notes about unhandled WM_WA_IPC messages). +*/ + + +#define IPC_SETRATING 639 +/* (requires Winamp 5.04+ with ML) +** int rating=SendMessage(hwnd_winamp,WM_WA_IPC,rating,IPC_SETRATING); +** This will allow you to set the 'rating' on the current playlist entry where 'rating' +** is an integer value from 0 (no rating) to 5 (5 stars). +** +** The following example should correctly allow you to set the rating for any specified +** playlist entry assuming of course that you're trying to get a valid playlist entry. +** +** void SetPlaylistItemRating(int item_to_set, int rating_to_set){ +** int cur_pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS); +** SendMessage(hwnd_winamp,WM_WA_IPC,item_to_set,IPC_SETPLAYLISTPOS); +** SendMessage(hwnd_winamp,WM_WA_IPC,rating_to_set,IPC_SETRATING); +** SendMessage(hwnd_winamp,WM_WA_IPC,cur_pos,IPC_SETPLAYLISTPOS); +** } +** +** Note: Winamp 5.6+ allows you to save the rating directly into the file as long as the +** file being rated supports the rating metadata field via a supporting input plug-in +** to process the tag save as appropriate. If not then the rating will not be saved. +*/ + + +#define IPC_GETRATING 640 +/* (requires Winamp 5.04+ with ML) +** int rating=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETRATING); +** This returns the current playlist entry's rating between 0 (no rating) to 5 (5 stars). +** +** The following example should correctly allow you to get the rating for any specified +** playlist entry assuming of course that you're trying to get a valid playlist entry. +** +** int GetPlaylistItemRating(int item_to_get, int rating_to_set){ +** int cur_pos=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETLISTPOS), rating = 0; +** SendMessage(hwnd_winamp,WM_WA_IPC,item_to_get,IPC_SETPLAYLISTPOS); +** rating = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETRATING); +** SendMessage(hwnd_winamp,WM_WA_IPC,cur_pos,IPC_SETPLAYLISTPOS); +** return rating; +** } +*/ + + +#define IPC_GETNUMAUDIOTRACKS 641 +/* (requires Winamp 5.04+) +** int n = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETNUMAUDIOTRACKS); +** This will return the number of audio tracks available from the currently playing item. +*/ + + +#define IPC_GETNUMVIDEOTRACKS 642 +/* (requires Winamp 5.04+) +** int n = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETNUMVIDEOTRACKS); +** This will return the number of video tracks available from the currently playing item. +*/ + + +#define IPC_GETAUDIOTRACK 643 +/* (requires Winamp 5.04+) +** int cur = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETAUDIOTRACK); +** This will return the id of the current audio track for the currently playing item. +*/ + + +#define IPC_GETVIDEOTRACK 644 +/* (requires Winamp 5.04+) +** int cur = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVIDEOTRACK); +** This will return the id of the current video track for the currently playing item. +*/ + + +#define IPC_SETAUDIOTRACK 645 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,track,IPC_SETAUDIOTRACK); +** This allows you to switch to a new audio track (if supported) in the current playing file. +*/ + + +#define IPC_SETVIDEOTRACK 646 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,track,IPC_SETVIDEOTRACK); +** This allows you to switch to a new video track (if supported) in the current playing file. +*/ + + +#define IPC_PUSH_DISABLE_EXIT 647 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_PUSH_DISABLE_EXIT); +** This will let you disable or re-enable the UI exit functions (close button, context +** menu, alt-f4). Remember to call IPC_POP_DISABLE_EXIT when you are done doing whatever +** was required that needed to prevent exit otherwise you have to kill the Winamp process. +*/ + + +#define IPC_POP_DISABLE_EXIT 648 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_POP_DISABLE_EXIT); +** See IPC_PUSH_DISABLE_EXIT +*/ + + +#define IPC_IS_EXIT_ENABLED 649 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_EXIT_ENABLED); +** This will return 0 if the 'exit' option of Winamp's menu is disabled and 1 otherwise. +*/ + + +#define IPC_IS_AOT 650 +/* (requires Winamp 5.04+) +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_IS_AOT); +** This will return the status of the always on top flag. +** Note: This may not match the actual TOPMOST window flag while another fullscreen +** application is focused if the user has the 'Disable always on top while fullscreen +** applications are focused' option under the General Preferences page is checked. +*/ + + +#define IPC_USES_RECYCLEBIN 651 +/* (requires Winamp 5.09+) +** int use_bin=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_USES_RECYCLEBIN); +** This will return 1 if the deleted file should be sent to the recycle bin or +** 0 if deleted files should be deleted permanently (default action for < 5.09). +** +** Note: if you use this on pre 5.09 installs of Winamp then it will return 1 which is +** not correct but is due to the way that SendMessage(..) handles un-processed messages. +** Below is a quick case for checking if the returned value is correct. +** +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_USES_RECYCLEBIN) && +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETVERSION)>=0x5009) +** { +** // can safely follow the option to recycle the file +** } +** else +* { +** // need to do a permanent delete of the file +** } +*/ + + +#define IPC_FLUSHAUDITS 652 +/* +** SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_FLUSHAUDITS); +** +** Will flush any pending audits in the global audits queue +** +*/ + +#define IPC_GETPLAYITEM_START 653 +#define IPC_GETPLAYITEM_END 654 + + +#define IPC_GETVIDEORESIZE 655 +#define IPC_SETVIDEORESIZE 656 + + +#define IPC_INITIAL_SHOW_STATE 657 +/* (requires Winamp 5.36+) +** int show_state = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INITIAL_SHOW_STATE); +** returns the processed value of nCmdShow when Winamp was started +** (see MSDN documentation the values passed to WinMain(..) for what this should be) +** +** e.g. +** if(SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_INITIAL_SHOW_STATE) == SW_SHOWMINIMIZED){ +** // we are starting minimised so process as needed (keep our window hidden) +** } +** +** Useful for seeing if winamp was run minimised on startup so you can act accordingly. +** On pre-5.36 versions this will effectively return SW_NORMAL/SW_SHOWNORMAL due to the +** handling of unknown apis returning 1 from Winamp. +*/ + + +#define IPC_GET_STOP_AFTER_CURRENT 658 +/* (requires Winamp 5.58+) +** int stopping=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_STOP_AFTER_CURRENT); +** IPC_GET_STOP_AFTER_CURRENT returns the status of the Stop After Current state. +** If enabled this will return 0 otherwise it will return 1 (see the notes about +** SendMessage(WM_WA_IPC) handling with unsupported apis for why this is inverted). +*/ + +// >>>>>>>>>>> Next is 659 + +#define IPC_PLCMD 1000 + +#define PLCMD_ADD 0 +#define PLCMD_REM 1 +#define PLCMD_SEL 2 +#define PLCMD_MISC 3 +#define PLCMD_LIST 4 + +//#define IPC_MBCMD 1001 + +#define MBCMD_BACK 0 +#define MBCMD_FORWARD 1 +#define MBCMD_STOP 2 +#define MBCMD_RELOAD 3 +#define MBCMD_MISC 4 + +#define IPC_VIDCMD 1002 + +#define VIDCMD_FULLSCREEN 0 +#define VIDCMD_1X 1 +#define VIDCMD_2X 2 +#define VIDCMD_LIB 3 +#define VIDPOPUP_MISC 4 + +//#define IPC_MBURL 1003 //sets the URL +//#define IPC_MBGETCURURL 1004 //copies the current URL into wParam (have a 4096 buffer ready) +//#define IPC_MBGETDESC 1005 //copies the current URL description into wParam (have a 4096 buffer ready) +//#define IPC_MBCHECKLOCFILE 1006 //checks that the link file is up to date (otherwise updates it). wParam=parent HWND +//#define IPC_MBREFRESH 1007 //refreshes the "now playing" view in the library +//#define IPC_MBGETDEFURL 1008 //copies the default URL into wParam (have a 4096 buffer ready) + +#define IPC_STATS_LIBRARY_ITEMCNT 1300 // updates library count status + +/* +** IPC's in the message range 2000 - 3000 are reserved internally for freeform messages. +** These messages are taken from ff_ipc.h which is part of the Modern skin integration. +*/ + +#define IPC_FF_FIRST 2000 + +#define IPC_FF_COLOURTHEME_CHANGE IPC_FF_ONCOLORTHEMECHANGED +#define IPC_FF_ONCOLORTHEMECHANGED IPC_FF_FIRST + 3 +/* +** This is a notification message sent when the user changes the colour theme in a Modern +** skin and can also be detected when the Modern skin is first loaded as the gen_ff plugin +** applies relevant settings and styles (like the colour theme). +** +** The value of wParam is the name of the new color theme being switched to. +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(const char*)colour_theme_name,IPC_FF_ONCOLORTHEMECHANGED); +** +** (IPC_FF_COLOURTHEME_CHANGE is the name i (DrO) was using before getting a copy of +** ff_ipc.h with the proper name in it). +*/ + + +#define IPC_FF_ISMAINWND IPC_FF_FIRST + 4 +/* +** int ismainwnd = (HWND)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)test_wnd,IPC_FF_ISMAINWND); +** +** This allows you to determine if the window handle passed to it is a modern skin main +** window or not. If it is a main window or any of its windowshade variants then it will +** return 1. +** +** Because of the way modern skins are implemented, it is possible for this message to +** return a positive test result for a number of window handles within the current Winamp +** process. This appears to be because you can have a visible main window, a compact main +** window and also a winshaded version. +** +** The following code example below is one way of seeing how this api works since it will +** enumerate all windows related to Winamp at the time and allows you to process as +** required when a detection happens. +** +** +** EnumThreadWindows(GetCurrentThreadId(),enumWndProc,0); +** +** BOOL CALLBACK enumWndProc(HWND hwnd, LPARAM lParam){ +** +** if(SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)hwnd,IPC_FF_ISMAINWND)){ +** // do processing in here +** // or continue the enum for other main windows (if they exist) +** // and just comment out the line below +** return 0; +** } +** return 1; +** } +*/ + + +#define IPC_FF_GETCONTENTWND IPC_FF_FIRST + 5 +/* +** HWND wa2embed = (HWND)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(HWND)test_wnd,IPC_FF_GETCONTENTWND); +** +** This will return the Winamp 2 window that is embedded in the window's container +** i.e. if hwnd is the playlist editor windowshade hwnd then it will return the Winamp 2 +** playlist editor hwnd. +** +** If no content is found such as the window has nothing embedded then this will return +** the hwnd passed to it. +*/ + + +#define IPC_FF_NOTIFYHOTKEY IPC_FF_FIRST + 6 +/* +** This is a notification message sent when the user uses a global hotkey combination +** which had been registered with the gen_hotkeys plugin. +** +** The value of wParam is the description of the hotkey as passed to gen_hotkeys. +** SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(const char*)hotkey_desc,IPC_FF_NOTIFYHOTKEY); +*/ + +#define IPC_FF_LAST 3000 + + +/* +** General IPC messages in Winamp +** +** All notification messages appear in the lParam of the main window message proceedure. +*/ + + +#define IPC_GETDROPTARGET 3001 +/* (requires Winamp 5.0+) +** IDropTarget* IDrop = (IDropTarget*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GETDROPTARGET); +** +** You call this to retrieve a copy of the IDropTarget interface which Winamp created for +** handling external drag and drop operations on to it's Windows. This is only really +** useful if you're providing an alternate interface and want your Windows to provide the +** same drag and drop support as Winamp normally provides the user. Check out MSDN or +** your prefered search facility for more information about the IDropTarget interface and +** what's needed to handle it in your own instance. +*/ + + +#define IPC_PLAYLIST_MODIFIED 3002 +/* (requires Winamp 5.0+) +** This is a notification message sent to the main Winamp window whenever the playlist is +** modified in any way e.g. the addition/removal of a playlist entry. +** +** It is not a good idea to do large amounts of processing in this notification since it +** will slow down Winamp as playlist entries are modified (especially when you're adding +** in a large playlist). +** +** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYLIST_MODIFIED) +** { +** // do what you need to do here +** } +*/ + + +#define IPC_PLAYING_FILE 3003 +/* (requires Winamp 5.0+) +** This is a notification message sent to the main Winamp window when playback begins for +** a file. This passes the full filepath in the wParam of the message received. +** +** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYING_FILE) +** { +** // do what you need to do here, e.g. +** process_file((char*)wParam); +** } +*/ + + +#define IPC_PLAYING_FILEW 13003 +/* (requires Winamp 5.3+) +** This is a notification message sent to the main Winamp window when playback begins for +** a file. This passes the full filepath in the wParam of the message received. +** +** if(uMsg == WM_WA_IPC && lParam == IPC_PLAYING_FILEW) +** { +** // do what you need to do here, e.g. +** process_file((wchar_t*)wParam); +** } +*/ + + +#define IPC_FILE_TAG_MAY_HAVE_UPDATED 3004 +#define IPC_FILE_TAG_MAY_HAVE_UPDATEDW 3005 +/* (requires Winamp 5.0+) +** This is a notification message sent to the main Winamp window when a file's tag +** (e.g. id3) may have been updated. This appears to be sent when the InfoBox(..) function +** of the associated input plugin returns a 1 (which is the file information dialog/editor +** call normally). +** +** if(uMsg == WM_WA_IPC && lParam == IPC_FILE_TAG_MAY_HAVE_UPDATED) +** { +** // do what you need to do here, e.g. +** update_info_on_file_update((char*)wParam); +** } +*/ + + +#define IPC_ALLOW_PLAYTRACKING 3007 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,allow,IPC_ALLOW_PLAYTRACKING); +** Send allow as nonzero to allow play tracking and zero to disable the mode. +** This is useful if you're an input plugin and need to edit a tag in a file +** whilst playing that track so this can be sent to Winamp so it appears like +** there wasn't a stop in the playback of the file (as far as the UI display). +*/ + + +#define IPC_HOOK_OKTOQUIT 3010 +/* (requires Winamp 5.0+) +** This is a notification message sent to the main Winamp window asking if it's okay to +** close or not. Return zero to prevent Winamp from closing or return anything non-zero +** to allow Winamp to close. +** +** The best implementation of this option is to let the message pass through to the +** original window proceedure since another plugin may want to have a say in the matter +** with regards to Winamp closing. +** +** if(uMsg == WM_WA_IPC && lParam == IPC_HOOK_OKTOQUIT) +** { +** // do what you need to do here, e.g. +** if(no_shut_down()) +** { +** return 1; +** } +** } +*/ + + +#define IPC_WRITECONFIG 3011 +/* (requires Winamp 5.0+) +** SendMessage(hwnd_winamp,WM_WA_IPC,write_type,IPC_WRITECONFIG); +** +** Send write_type as 2 to write all config settings and the current playlist. +** +** Send write_type as 1 to write the playlist and common settings. +** This won't save the following ini settings:: +** +** defext, titlefmt, proxy, visplugin_name, dspplugin_name, check_ft_startup, +** visplugin_num, pe_fontsize, visplugin_priority, visplugin_autoexec, dspplugin_num, +** sticon, splash, taskbar, dropaotfs, ascb_new, ttips, riol, minst, whichicon, +** whichicon2, addtolist, snap, snaplen, parent, hilite, disvis, rofiob, shownumsinpl, +** keeponscreen, eqdsize, usecursors, fixtitles, priority, shuffle_morph_rate, +** useexttitles, bifont, inet_mode, ospb, embedwnd_freesize, no_visseh +** (the above was valid for 5.1) +** +** Send write_type as 0 to write the common and less common settings and no playlist. +*/ + + +#define IPC_UPDATE_URL 3012 +// pass the URL (char *) in lparam, will be free()'d on done. + + +#define IPC_GET_RANDFUNC 3015 // returns a function to get a random number +/* (requires Winamp 5.1+) +** int (*randfunc)(void) = (int(*)(void))SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GET_RANDFUNC); +** if(randfunc && randfunc != 1){ +** randfunc(); +** } +** +** This will return a positive 32-bit number (essentially 31-bit). +** The check for a returned value of 1 is because that's the default return value from +** SendMessage(..) when it is not handled so is good to check for it in this situation. +*/ + + +#define IPC_METADATA_CHANGED 3017 +/* (requires Winamp 5.1+) +** int changed=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)(char*)field,IPC_METADATA_CHANGED); +** a plugin can SendMessage this to winamp if internal metadata has changes. +** wParam should be a char * of what field changed +** +** Currently used for internal actions (and very few at that) the intent of this api is +** to allow a plugin to call it when metadata has changed in the current playlist entry +** e.g.a new id3v2 tag was found in a stream +** +** The wparam value can either be NULL or a pointer to an ansi string for the metadata +** which has changed. This can be thought of as an advanced version of IPC_UPDTITLE and +** could be used to allow for update of the current title when a specific tag changed. +** +** Not recommended to be used since there is not the complete handling implemented in +** Winamp for it at the moment. +*/ + + +#define IPC_SKIN_CHANGED 3018 +/* (requires Winamp 5.1+) +** This is a notification message sent to the main Winamp window by itself whenever +** the skin in use is changed. There is no information sent by the wParam for this. +** +** if(message == WM_WA_IPC && lparam == IPC_SKIN_CHANGED) +** { +** // do what you need to do to handle skin changes, e.g. call WADlg_init(hwnd_winamp); +** } +*/ + + +#define IPC_REGISTER_LOWORD_COMMAND 3019 +/* (requires Winamp 5.1+) +** WORD id = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_REGISTER_LOWORD_COMMAND); +** This will assign you a unique id for making your own commands such as for extra menu +** entries. The starting value returned by this message will potentially change as and +** when the main resource file of Winamp is updated with extra data so assumptions cannot +** be made on what will be returned and plugin loading order will affect things as well. + +** 5.33+ +** If you want to reserve more than one id, you can pass the number of ids required in wParam +*/ + + +typedef struct +{ + wchar_t *name; // filled in by plugin, make sure it's a unicode string!! (i.e. L"myObject" instead of "myObject). + struct IDispatch *dispatch; // filled in by plugin + DWORD id; // filled in by winamp on return +} DispatchInfo; + +#define IPC_GET_DISPATCH_OBJECT 3020 // gets winamp main IDispatch * (for embedded webpages) +#define IPC_GET_UNIQUE_DISPATCH_ID 3021 // gives you a unique dispatch ID that won't conflict with anything in winamp's IDispatch * +#define IPC_ADD_DISPATCH_OBJECT 3022 // add your own dispatch object into winamp's. This lets embedded webpages access your functions +// pass a pointer to DispatchInfo (see below). Winamp makes a copy of all this data so you can safely delete it later + +#define IPC_REMOVE_DISPATCH_OBJECT 3038 +/* (requires Winamp 5.56+) +** remove registered IDispatch. pass (DWORD)dispatchId ad parameter +*/ + +// see IPC_JSAPI2_GET_DISPATCH_OBJECT for version 2 of the Dispatchable scripting interface + + +#define IPC_GET_PROXY_STRING 3023 +/* (requires Winamp 5.11+) +** char* proxy_string=(char*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PROXY_STRING); +** This will return the same string as is shown on the General Preferences page. +*/ + + +#define IPC_USE_REGISTRY 3024 +/* (requires Winamp 5.11+) +** int reg_enabled=SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_USE_REGISTRY); +** This will return 0 if you should leave your grubby hands off the registry (i.e. for +** lockdown mode). This is useful if Winamp is run from a USB drive and you can't alter +** system settings, etc. +*/ + + +#define IPC_GET_API_SERVICE 3025 +/* (requires Winamp 5.12+) +** api_service* api_service = (api_service*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_API_SERVICE); +** This api will return Winamp's api_service pointer (which is what Winamp3 used, heh). +** If this api is not supported in the Winamp version that is being used at the time then +** the returned value from this api will be 1 which is a good version check. +** +** As of 5.12 there is support for .w5s plugins which reside in %WinampDir%\System and +** are intended for common code that can be shared amongst other plugins e.g. jnetlib.w5s +** which contains jnetlib in one instance instead of being duplicated multiple times in +** all of the plugins which need internet access. +** +** Details on the .w5s specifications will come at some stage (possibly). +*/ + + +typedef struct { + const wchar_t *filename; + const wchar_t *metadata; + wchar_t *ret; + size_t retlen; +} extendedFileInfoStructW; + +#define IPC_GET_EXTENDED_FILE_INFOW 3026 +/* (requires Winamp 5.13+) +** Pass a pointer to the above struct in wParam +*/ + + +#define IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE 3027 +#define IPC_SET_EXTENDED_FILE_INFOW 3028 +/* (requires Winamp 5.13+) +** Pass a pointer to the above struct in wParam +*/ + + +#define IPC_PLAYLIST_GET_NEXT_SELECTED 3029 +/* (requires 5.2+) +** int pl_item = SendMessage(hwnd_winamp,WM_WA_IPC,start,IPC_PLAYLIST_GET_NEXT_SELECTED); +** +** This works just like the ListView_GetNextItem(..) macro for ListView controls. +** 'start' is the index of the playlist item that you want to begin the search after or +** set this as -1 for the search to begin with the first item of the current playlist. +** +** This will return the index of the selected playlist according to the 'start' value or +** it returns -1 if there is no selection or no more selected items according to 'start'. +** +** Quick example: +** +** int sel = -1; +** // keep incrementing the start of the search so we get all of the selected entries +** while((sel = SendMessage(hwnd_winamp,WM_WA_IPC,sel,IPC_PLAYLIST_GET_NEXT_SELECTED))!=-1){ +** // show the playlist file entry of the selected item(s) if there were any +** MessageBox(hwnd_winamp,(char*)SendMessage(hwnd_winamp,WM_WA_IPC,sel,IPC_GETPLAYLISTFILE),0,0); +** } +*/ + + +#define IPC_PLAYLIST_GET_SELECTED_COUNT 3030 +/* (requires 5.2+) +** int selcnt = SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_PLAYLIST_GET_SELECTED_COUNT); +** This will return the number of selected playlist entries. +*/ + + +#define IPC_GET_PLAYING_FILENAME 3031 +/* (requires Winamp 5.?+) +** wchar_t* fn=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PLAYING_FILENAME); +** This will return the currently playing filename string as held by Winamp. +*/ + + +#define IPC_OPEN_URL 3032 +// send either ANSI or Unicode string (it'll figure it out, but it MUST start with "h"!, so don't send ftp:// or anything funny) +// you can also send this one from another process via WM_COPYDATA (unicode only) + + +#define IPC_USE_UXTHEME_FUNC 3033 +/* (requires Winamp 5.35+) +** int ret = SendMessage(hwnd_winamp,WM_WA_IPC,param,IPC_USE_UXTHEME_FUNC); +** param can be IPC_ISWINTHEMEPRESENT or IPC_ISAEROCOMPOSITIONACTIVE or a valid hwnd. +** +** If you pass a hwnd then it will apply EnableThemeDialogTexture(ETDT_ENABLETAB) +** so your tabbed dialogs can use the correct theme (on supporting OSes ie XP+). +** +** Otherwise this will return a value based on the param passed (as defined below). +** For compatability, the return value will be zero on success (as 1 is returned +** for unsupported ipc calls on older Winamp versions) +*/ + #define IPC_ISWINTHEMEPRESENT 0 +/* This will return 0 if uxtheme.dll is present +** int isthemethere = !SendMessage(hwnd_winamp,WM_WA_IPC,IPC_ISWINTHEMEPRESENT,IPC_USE_UXTHEME_FUNC); +*/ + #define IPC_ISAEROCOMPOSITIONACTIVE 1 +/* This will return 0 if aero composition is active +** int isaero = !SendMessage(hwnd_winamp,WM_WA_IPC,IPC_ISAEROCOMPOSITIONACTIVE,IPC_USE_UXTHEME_FUNC); +*/ + + +#define IPC_GET_PLAYING_TITLE 3034 +/* (requires Winamp 5.5+) +** wchar_t* title=(wchar_t*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_PLAYING_TITLE); +** This will return the currently playing file title string as displayed in Winamp's window. +*/ + + +#define IPC_CANPLAY 3035 +/* (requires Winamp 5.5+) +** In_Module *in_mod=(In_Module*)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)fn,IPC_CANPLAY); +** This api will return either a In_Module* for plugin associated with the file passed or +** it will return 0 to indicate there is not a supporting input plugin. +** Pass a unicode (wchar_t) filepath. +** +** In_Module *in_mod=(In_Module*)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)fn,IPC_CANPLAY); +** if(in_mod && (in_mod != (In_Module*)1){ +** // we got a valid In_Module * +** } +*/ + + +typedef struct { + // fill these in... + size_t size; // init to sizeof(artFetchData) + HWND parent; // parent window of the dialogue + + // fill as much of these in as you can, otherwise leave them 0 + const wchar_t *artist; + const wchar_t *album; + int year, amgArtistId, amgAlbumId; + + int showCancelAll; // if set to 1, this shows a "Cancel All" button on the dialogue + + // winamp will fill these in if the call returns successfully: + void* imgData; // a buffer filled with compressed image data. free with WASABI_API_MEMMGR->sysFree() + int imgDataLen; // the size of the buffer + wchar_t type[10]; // eg: "jpg" + const wchar_t *gracenoteFileId; // if you know it +} artFetchData; + +#define IPC_FETCH_ALBUMART 3036 +/* pass an artFetchData*. This will show a dialog guiding the use through choosing art, and return when it's finished +** return values: +** 1: error showing dialog +** 0: success +** -1: cancel was pressed +** -2: cancel all was pressed +*/ + + +#define IPC_JSAPI2_GET_DISPATCH_OBJECT 3037 +/* pass your service's unique ID, as a wchar_t * string, in wParam +** Winamp will copy the string, so don't worry about keeping it around +** An IDispatch * object will be returned (cast the return value from SendMessage) +** This IDispatch can be used for scripting/automation/VB interaction +** Pass to IE via IDocHostUIHandler::GetExternal and it will become window.external in javscript +*/ + +// #define IPC_REMOVE_DISPATCH_OBJECT 3038 /* this id already in use */ + + +#define IPC_HANDLE_URI 3039 /* only for use in WM_COPYDATA, passes Winamp a filename that will get handled by svc_urihandler */ + + +#define IPC_PLAYFILEW_NDE 3040 /* just like IPC_PLAYFILEW, but the filename is an NDE reference-counted string (but not the title!!) */ +#define IPC_PLAYFILEW_NDE_TITLE 3041 /* use this if the title is reference counted also */ + + +#define IPC_OUTPUT_STARTED 3042 +/* (requires Winamp 5.57+) +** This is a notification message sent to the main Winamp window by an output plugin +** when the pre-buffer has been filled and output has started which is useful if you +** want to wait until playback has buffered before doing something on song transition. +** +** It is not guaranteed that this message is implemented in all output plugins (with +** only out_ds supporting it as of 5.57) so is recommended to wait for 5 seconds or +** until you receive this notification message before handling the song transition. +** +** if(message == WM_WA_IPC && lparam == IPC_OUTPUT_STARTED) +** { +** // do what you need to do +** } +*/ + + +typedef struct { + int last_time; + int g_fullstop; +} stopPlayingInfoStruct; + +#define IPC_STOPPLAYING 3043 +/* (requires Winamp 5.57+) +** This is a notification message sent to the main Winamp window by itself whenever +** playback is stopped either when file playback ends or the user stops playing. +** +** if(message == WM_WA_IPC && lparam == IPC_STOPPLAYING) +** { +** // do what you need to do such as logging where playback was +** } +*/ + + +#define IPC_GET_D3DX9 3044 +/* (requires Winamp 5.57+) +** HMODULE d3dx9 = (HMODULE)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_D3DX9); +** +** This will return the module handle of a d3dx9_*.dll based against the version +** internally required by Winamp and it's supporting plug-ins (version can change). +** +** HMODULE d3dx9 = (HMODULE)SendMessage(hwnd_winamp,WM_WA_IPC, 0, IPC_GET_D3DX9); +** if (!d3dx9 || d3dx9 == (HMODULE)1) { +** // if here then loading failed and you'll need to manually load the library +** } +*/ + + +#define IPC_GET_FILEREGISTRAR_OBJECT 3045 +/* (requires Winamp 5.58+) +** IFileTypeRegistrar* registrar = (IFileTypeRegistrar*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_FILEREGISTRAR_OBJECT); +** +** You call this to retrieve a copy of a IFileTypeRegistrar object which Winamp will +** create which provides some commonly used functions for registry and file access +** which will be automatically elevated on Vista / Window 7 depending on the user's +** permissions as required. +** +** // it is best to call this everytime that the object is required as there is no +** // guarantee it will already have been created or if it's already been released +** IFileTypeRegistrar *registrar = (IFileTypeRegistrar*)SendMessage(hwnd_winamp,WM_WA_IPC,0,IPC_GET_FILEREGISTRAR_OBJECT); +** // make sure that we've got a valid object (as 1 is an unsupported api return) +** if(registrar && (registrar != (IFileTypeRegistrar*)1)){ +** // we got a valid copy of the object (automatically elevated as required) +** // so now we can start using the IFileTypeRegistrar object as required +** +** // once we're done using the IFileTypeRegistrar object for the immediate moment +** // then we should release the object so everything is kept as clean as possible +** registrar->Release(); +** } +*/ + + +#define IPC_REGISTER_WINAMP_IPCMESSAGE 65536 +/* (requires Winamp 5.0+) +** DWORD id = SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)name,IPC_REGISTER_WINAMP_IPCMESSAGE); +** e.g. DWORD id = SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&"enter_a_different_string",IPC_REGISTER_WINAMP_IPCMESSAGE); +** +** The value 'id' returned is > 65536 and is incremented on subsequent calls for unique +** 'name' values passed to it. By using the same 'name' in different plugins will allow a +** common runtime api to be provided for the currently running instance of Winamp +** e.g. +** PostMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)my_param,registered_ipc); +** Have a look at wa_hotkeys.h for an example on how this api is used in practice for a +** custom WM_WA_IPC message. +** +** +** if(uMsg == WM_WA_IPC && lParam == id_from_register_winamp_ipcmessage){ +** // do things +** } +*/ + +#endif//_WA_IPC_H_ \ No newline at end of file diff --git a/ns-eel2/asm-nseel-ppc-gcc.c b/ns-eel2/asm-nseel-ppc-gcc.c new file mode 100644 index 0000000..19a09ba --- /dev/null +++ b/ns-eel2/asm-nseel-ppc-gcc.c @@ -0,0 +1,1041 @@ +#if EEL_F_SIZE == 8 + +void nseel_asm_1pdd(void) +{ + + __asm__( + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r3)\n" + "mtctr r5\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: ); +} +void nseel_asm_1pdd_end(void){} + +void nseel_asm_2pdd(void) +{ + + __asm__( + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "lfd f2, 0(r3)\n" + "lfd f1, 0(r14)\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: ); +}; +void nseel_asm_2pdd_end(void){} + +void nseel_asm_2pdds(void) +{ + __asm__( + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f2, 0(r3)\n" + "lfd f1, 0(r14)\n" + "mtctr r5\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + :: ); +} +void nseel_asm_2pdds_end(void){} + +#else // 32 bit floating point calls + +#error mac only can do 64 bit floats for now + +#endif + + +void nseel_asm_2pp(void) +{ +// r3=firstparm, r4=second parm, returns in f1 + __asm__( + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "mtctr r5\n" + "mr r4, r3\n" + "mr r3, r14\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: ); +}; +void nseel_asm_2pp_end(void){} + +void nseel_asm_1pp(void) +{ + __asm__( + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "mtctr r5\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: ); +}; +void nseel_asm_1pp_end(void){} + + +//--------------------------------------------------------------------------------------------------------------- + + + +// do nothing, eh +void nseel_asm_exec2(void) +{ +} +void nseel_asm_exec2_end(void) { } + + + +void nseel_asm_invsqrt(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "frsqrte f1, f1\n" // less accurate than our x86 equivilent, but invsqrt() is inherently inaccurate anyway + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_invsqrt_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sqr(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "fmul f1, f1, f1\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_sqr_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_abs(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "fabs f1, f1\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_abs_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "stfd f1, 0(r14)\n" + ); +} +void nseel_asm_assign_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_add(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fadd f1, f1, f2\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_add_end(void) {} + +void nseel_asm_add_op(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fadd f1, f1, f2\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + ); +} +void nseel_asm_add_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sub(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fsub f1, f2, f1\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_sub_end(void) {} + +void nseel_asm_sub_op(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fsub f1, f2, f1\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + ); +} +void nseel_asm_sub_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_mul(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fmul f1, f2, f1\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_mul_end(void) {} + +void nseel_asm_mul_op(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fmul f1, f2, f1\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + ); +} +void nseel_asm_mul_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_div(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fdiv f1, f2, f1\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_div_end(void) {} + +void nseel_asm_div_op(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fdiv f1, f2, f1\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + ); +} +void nseel_asm_div_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_mod(void) +{ + __asm__( + + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fabs f1, f1\n" + "fabs f2, f2\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, 8(r16)\n" + "stfd f2, 16(r16)\n" + "lwz r10, 12(r16)\n" + "lwz r11, 20(r16)\n" //r11 and r12 have the integers + + "divw r12, r11, r10\n" + "mullw r12, r12, r10\n" + "subf r10, r12, r11\n" + + "addis r11, 0, 0x4330\n" + "addis r12, 0, 0x8000\n" + "xoris r10, r10, 0x8000\n" + "stw r11, 8(r16)\n" // 0x43300000 + "stw r10, 12(r16)\n" // our integer sign flipped + "stw r11, 16(r16)\n" // 0x43300000 + "stw r12, 20(r16)\n" // 0x80000000 + "lfd f1, 8(r16)\n" + "lfd f2, 16(r16)\n" + "fsub f1, f1, f2\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + + + ); +} +void nseel_asm_mod_end(void) {} + +void nseel_asm_mod_op(void) +{ + + __asm__( + + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fabs f1, f1\n" + "fabs f2, f2\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, 8(r16)\n" + "stfd f2, 16(r16)\n" + "lwz r10, 12(r16)\n" + "lwz r11, 20(r16)\n" //r11 and r12 have the integers + + "divw r12, r11, r10\n" + "mullw r12, r12, r10\n" + "subf r10, r12, r11\n" + + "addis r11, 0, 0x4330\n" + "addis r12, 0, 0x8000\n" + "xoris r10, r10, 0x8000\n" + "stw r11, 8(r16)\n" // 0x43300000 + "stw r10, 12(r16)\n" // our integer sign flipped + "stw r11, 16(r16)\n" // 0x43300000 + "stw r12, 20(r16)\n" // 0x80000000 + "lfd f1, 8(r16)\n" + "lfd f2, 16(r16)\n" + "fsub f1, f1, f2\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + ); + +} +void nseel_asm_mod_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_or(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, 8(r16)\n" + "stfd f2, 16(r16)\n" + "lwz r10, 12(r16)\n" + "lwz r11, 20(r16)\n" //r11 and r12 have the integers + "or r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "addis r12, 0, 0x8000\n" + "xoris r10, r10, 0x8000\n" + "stw r11, 8(r16)\n" // 0x43300000 + "stw r10, 12(r16)\n" // our integer sign flipped + "stw r11, 16(r16)\n" // 0x43300000 + "stw r12, 20(r16)\n" // 0x80000000 + "lfd f1, 8(r16)\n" + "lfd f2, 16(r16)\n" + "fsub f1, f1, f2\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_or_end(void) {} + +void nseel_asm_or_op(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, 8(r16)\n" + "stfd f2, 16(r16)\n" + "lwz r10, 12(r16)\n" + "lwz r11, 20(r16)\n" //r11 and r12 have the integers + "or r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "addis r12, 0, 0x8000\n" + "xoris r10, r10, 0x8000\n" + "stw r11, 8(r16)\n" // 0x43300000 + "stw r10, 12(r16)\n" // our integer sign flipped + "stw r11, 16(r16)\n" // 0x43300000 + "stw r12, 20(r16)\n" // 0x80000000 + "lfd f1, 8(r16)\n" + "lfd f2, 16(r16)\n" + "fsub f1, f1, f2\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + ); +} +void nseel_asm_or_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_and(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, 8(r16)\n" + "stfd f2, 16(r16)\n" + "lwz r10, 12(r16)\n" + "lwz r11, 20(r16)\n" //r11 and r12 have the integers + "and r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "addis r12, 0, 0x8000\n" + "xoris r10, r10, 0x8000\n" + "stw r11, 8(r16)\n" // 0x43300000 + "stw r10, 12(r16)\n" // our integer sign flipped + "stw r11, 16(r16)\n" // 0x43300000 + "stw r12, 20(r16)\n" // 0x80000000 + "lfd f1, 8(r16)\n" + "lfd f2, 16(r16)\n" + "fsub f1, f1, f2\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + );} +void nseel_asm_and_end(void) {} + +void nseel_asm_and_op(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, 8(r16)\n" + "stfd f2, 16(r16)\n" + "lwz r10, 12(r16)\n" + "lwz r11, 20(r16)\n" //r11 and r12 have the integers + "and r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "addis r12, 0, 0x8000\n" + "xoris r10, r10, 0x8000\n" + "stw r11, 8(r16)\n" // 0x43300000 + "stw r10, 12(r16)\n" // our integer sign flipped + "stw r11, 16(r16)\n" // 0x43300000 + "stw r12, 20(r16)\n" // 0x80000000 + "lfd f1, 8(r16)\n" + "lfd f2, 16(r16)\n" + "fsub f1, f1, f2\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + ); +} +void nseel_asm_and_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_uplus(void) // this is the same as doing nothing, it seems +{ +} +void nseel_asm_uplus_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_uminus(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "fneg f1, f1\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + ); +} +void nseel_asm_uminus_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sign(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f2, 0(r5)\n" + "lis r9, 0xbff0\n" + "fcmpu cr7, f1, f2\n" + "blt- cr7, 0f\n" + "ble- cr7, 1f\n" + " lis r9, 0x3ff0\n" + "0:\n" + " li r10, 0\n" + " stwu r9, 8(r16)\n" + " stw r10, 4(r16)\n" + " b 2f\n" + "1:\n" + " stfdu f1, 8(r16)\n" + "2:\n" + " mr r3, r16\n" + :: + ); +} +void nseel_asm_sign_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_bnot(void) +{ + __asm__( + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f2, 0(r5)\n" + "lfd f1, 0(r3)\n" + "fabs f1, f1\n" + "fcmpu cr7, f1, f2\n" + "blt cr7, 0f\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "b 1f\n" + "0:\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "1:\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + :: + ); +} +void nseel_asm_bnot_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_if(void) +{ + __asm__( + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f2, 0(r5)\n" + "lfd f1, 0(r3)\n" + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "fabs f1, f1\n" + "fcmpu cr7, f1, f2\n" + "blt cr7, 0f\n" + " mtctr r6\n" + "b 1f\n" + "0:\n" + " mtctr r7\n" + "1:\n" + "bctrl\n" + :: ); +} +void nseel_asm_if_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_repeat(void) +{ + __asm__( + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + "addis r7, 0, ha16(%0)\n" + "addi r7, r7, lo16(%0)\n" + "lfd f1, 0(r3)\n" + "fctiwz f1, f1\n" + "stfd f1, 8(r16)\n" + "lwz r5, 12(r16)\n" // r5 has count now + "cmpwi cr0, r5, 0\n" + "ble cr0, 1f\n" + "cmpw cr0, r7, r5\n" + "bge cr0, 0f\n" + "mr r5, r7\n" // set r5 to max if we have to +"0:\n" + "stw r5, -4(r1)\n" + "stw r6, -8(r1)\n" + "stwu r16, -12(r1)\n" + + "mtctr r6\n" + "bctrl\n" + + "lwz r16, 0(r1)\n" + "lwz r6, 4(r1)\n" + "lwz r5, 8(r1)\n" + "addi r1, r1, 12\n" + "addi r5, r5, -1\n" + + "cmpwi cr0, r5, 0\n" + "bgt cr0, 0b\n" + "1:\n" + ::"g" (NSEEL_LOOPFUNC_SUPPORT_MAXLEN) + ); +} +void nseel_asm_repeat_end(void) {} + +void nseel_asm_repeatwhile(void) +{ + __asm__( + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + "addis r5, 0, ha16(%0)\n" + "addi r5, r5, lo16(%0)\n" +"0:\n" + "stw r5, -4(r1)\n" + "stw r6, -8(r1)\n" + "stwu r16, -12(r1)\n" + + "mtctr r6\n" + "bctrl\n" + + "lwz r16, 0(r1)\n" + "lwz r6, 4(r1)\n" + "lwz r5, 8(r1)\n" + "addi r1, r1, 12\n" + "addi r5, r5, -1\n" + + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "lfd f2, 0(r7)\n" + + "lfd f1, 0(r3)\n" + "fabs f1, f1\n" + "fcmpu cr7, f1, f2\n" + "blt cr7, 1f\n" + + "cmpwi cr0, r5, 0\n" + "bgt cr0, 0b\n" + "1:\n" + ::"g" (NSEEL_LOOPFUNC_SUPPORT_MAXLEN) + ); +} +void nseel_asm_repeatwhile_end(void) {} + + +void nseel_asm_band(void) +{ + __asm__( + + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f2, 0(r5)\n" + "lfd f1, 0(r3)\n" + "fabs f1, f1\n" + "fcmpu cr7, f1, f2\n" + "blt cr7, 0f\n" + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + " mtctr r6\n" + " bctrl\n" + " addis r5, 0, 0xdead\n" + " ori r5, r5, 0xbeef\n" + " lfd f2, 0(r5)\n" + " lfd f1, 0(r3)\n" + " fabs f1, f1\n" + " fcmpu cr7, f1, f2\n" + " bge cr7, 1f\n" + "0:\n" + " fsub f1, f1, f1\n" // set f1 to 0! + " b 2f\n" + "1:\n" + " addis r5, 0, 0xdead\n" // set f1 to 1 + " ori r5, r5, 0xbeef\n" + " lfd f1, 0(r5)\n" + "2:\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: ); +} +void nseel_asm_band_end(void) {} + +void nseel_asm_bor(void) +{ + __asm__( + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f2, 0(r5)\n" + "lfd f1, 0(r3)\n" + "fabs f1, f1\n" + "fcmpu cr7, f1, f2\n" + "bge cr7, 0f\n" + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + " mtctr r6\n" + " bctrl\n" + " addis r5, 0, 0xdead\n" + " ori r5, r5, 0xbeef\n" + " lfd f2, 0(r5)\n" + " lfd f1, 0(r3)\n" + " fabs f1, f1\n" + " fcmpu cr7, f1, f2\n" + " blt cr7, 1f\n" + "0:\n" + " addis r5, 0, 0xdead\n" // set f1 to 1 + " ori r5, r5, 0xbeef\n" + " lfd f1, 0(r5)\n" + " b 2f\n" + "1:\n" + " fsub f1, f1, f1\n" // set f1 to 0! + "2:\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: ); +} +void nseel_asm_bor_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_equal(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "fsub f1, f1, f2\n" + "fabs f1, f1\n" + "lfd f2, 0(r5)\n" + "fcmpu cr7, f1, f2\n" + "blt cr7, 0f\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "b 1f\n" + "0:\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "1:\n" + "lfd f1, 0(r5)\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + :: + ); +} +void nseel_asm_equal_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_notequal(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "fsub f1, f1, f2\n" + "fabs f1, f1\n" + "lfd f2, 0(r5)\n" + "fcmpu cr7, f1, f2\n" + "blt cr7, 0f\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "b 1f\n" + "0:\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "1:\n" + "lfd f1, 0(r5)\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + :: + ); +} +void nseel_asm_notequal_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_below(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "blt cr7, 0f\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "b 1f\n" + "0:\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "1:\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + :: + ); +} +void nseel_asm_below_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_beloweq(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "ble cr7, 0f\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "b 1f\n" + "0:\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "1:\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + :: + ); +} +void nseel_asm_beloweq_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_above(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "bgt cr7, 0f\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "b 1f\n" + "0:\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "1:\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + :: + ); +} +void nseel_asm_above_end(void) {} + +void nseel_asm_aboveeq(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "bge cr7, 0f\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "b 1f\n" + "0:\n" + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "lfd f1, 0(r5)\n" + "1:\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + :: + ); +} +void nseel_asm_aboveeq_end(void) {} + + + +void nseel_asm_min(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "bgt cr7, 0f\n" + "fmr f1, f2\n" + "0:\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + ); +} +void nseel_asm_min_end(void) {} + +void nseel_asm_max(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "blt cr7, 0f\n" + "fmr f1, f2\n" + "0:\n" + " stfdu f1, 8(r16)\n" + " mr r3, r16\n" + ); +} + +void nseel_asm_max_end(void) {} + + + + + + + + + +void _asm_generic3parm(void) +{ + __asm__( + "mr r6, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mr r4, r15\n" + "mr r5, r14\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + :: + ); +} +void _asm_generic3parm_end(void) {} + +void _asm_generic3parm_retd(void) +{ + __asm__( + "mr r6, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mr r4, r15\n" + "mr r5, r14\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: + ); +} +void _asm_generic3parm_retd_end(void) {} + + +void _asm_generic2parm(void) // this prob neds to be fixed for ppc +{ + __asm__( + "mr r5, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mr r4, r14\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + :: + ); +} +void _asm_generic2parm_end(void) {} + + +void _asm_generic2parm_retd(void) +{ + __asm__( + "mr r5, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mr r4, r14\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: + ); +} +void _asm_generic2parm_retd_end(void) {} + +void _asm_generic1parm(void) // this prob neds to be fixed for ppc +{ + __asm__( + "mr r4, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + :: + ); +} +void _asm_generic1parm_end(void) {} + + + +void _asm_generic1parm_retd(void) +{ + __asm__( + "mr r4, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfdu f1, 8(r16)\n" + "mr r3, r16\n" + :: + ); +} +void _asm_generic1parm_retd_end(void) {} + + + + +void _asm_megabuf(void) +{ + __asm__( + "lfd f1, 0(r3)\n" + "addis r3, 0, 0xdead\n" // set up context pointer + "ori r3, r3, 0xbeef\n" + "addis r4, 0, 0xdead\n" + "ori r4, r4, 0xbeef\n" + "lfd f2, 0(r4)\n" + "fadd f1, f2, f1\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mtctr r7\n" + "fctiwz f1, f1\n" + "stfd f1, 8(r16)\n" + "lwz r4, 12(r16)\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "cmpi cr0, r3, 0\n" + "bne cr0, 0f\n" + "sub r5, r5, r5\n" + "stwu r5, 8(r16)\n" + "stw r5, 4(r16)\n" + "mr r3, r16\n" + "0:\n" + :: + ); +} + +void _asm_megabuf_end(void) {} diff --git a/ns-eel2/asm-nseel-x64-macho.o b/ns-eel2/asm-nseel-x64-macho.o new file mode 100644 index 0000000..76e918e Binary files /dev/null and b/ns-eel2/asm-nseel-x64-macho.o differ diff --git a/ns-eel2/asm-nseel-x86-gcc.c b/ns-eel2/asm-nseel-x86-gcc.c new file mode 100644 index 0000000..e7cd7e9 --- /dev/null +++ b/ns-eel2/asm-nseel-x86-gcc.c @@ -0,0 +1,1566 @@ +#if defined(__APPLE__) +#define SAVE_STACK "pushl %ebp\nmovl %esp, %ebp\nandl $-16, %esp\n" +#define RESTORE_STACK "leave\n" +#else +#define SAVE_STACK +#define RESTORE_STACK +#endif + +/* note: only EEL_F_SIZE=8 is now supported (no float EEL_F's) */ + +void nseel_asm_1pdd(void) +{ + __asm__( + SAVE_STACK +#ifdef TARGET_X64 + "movq (%eax), %xmm0\n" + "subl $128, %rsp\n" + "movl $0xffffffff, %edi\n" +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "call *%edi\n" + "movl %r15, %rsi\n" + "movq xmm0, (%r15)\n" +#else + "call *%edi\n" + "movq xmm0, (%esi)\n" +#endif + "addl $128, %rsp\n" +#else + "subl $8, %esp\n" /* keep stack aligned */ + "pushl 4(%eax)\n" /* push parameter */ + "pushl (%eax)\n" /* push the rest of the parameter */ + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "fstpl (%esi)\n" /* store result */ + "addl $16, %esp\n" +#endif + "movl %esi, %eax\n" /* set return value */ + "addl $8, %esi\n" /* advance worktab ptr */ + RESTORE_STACK + ); +} +void nseel_asm_1pdd_end(void){} + +void nseel_asm_2pdd(void) +{ + __asm__( + SAVE_STACK +#ifdef TARGET_X64 + "movq (%eax), xmm1\n" + "movq (%edi), xmm0\n" + "subl $128, %rsp\n" + "movl $0xffffffff, %edi\n" +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "call *%edi\n" + "movl %r15, %rsi\n" + "movq xmm0, (%r15)\n" +#else + "call *%edi\n" + "movq xmm0, (%esi)\n" +#endif + "addl $128, %rsp\n" +#else + "pushl 4(%eax)\n" /* push parameter */ + "pushl (%eax)\n" /* push the rest of the parameter */ + "pushl 4(%edi)\n" /* push parameter */ + "pushl (%edi)\n" /* push the rest of the parameter */ + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "fstpl (%esi)\n" /* store result */ + "addl $16, %esp\n" +#endif + "movl %esi, %eax\n" /* set return value */ + "addl $8, %esi\n" /* advance worktab ptr */ + RESTORE_STACK + ); +} +void nseel_asm_2pdd_end(void){} + +void nseel_asm_2pdds(void) +{ + __asm__( + SAVE_STACK +#ifdef TARGET_X64 + "movq (%eax), xmm1\n" + "movq (%edi), xmm0\n" + "subl $128, %rsp\n" + "movl $0xffffffff, %eax\n" +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %rdi, %r14\n" + "call *%eax\n" + "movl %r15, %rsi\n" + "movq xmm0, (%r14)\n" + "movl %r14, %rax\n" /* set return value */ +#else + "call *%eax\n" + "movq xmm0, (%edi)\n" + "movl %edi, %eax\n" /* set return value */ +#endif + "subl $128, %rsp\n" +#else + "pushl 4(%eax)\n" /* push parameter */ + "pushl (%eax)\n" /* push the rest of the parameter */ + "pushl 4(%edi)\n" /* push parameter */ + "pushl (%edi)\n" /* push the rest of the parameter */ + "movl $0xffffffff, %eax\n" + "call *%eax\n" + "fstpl (%edi)\n" /* store result */ + "addl $16, %esp\n" + "movl %edi, %eax\n" /* set return value */ +#endif +RESTORE_STACK + ); +} +void nseel_asm_2pdds_end(void){} + +void nseel_asm_2pp(void) +{ + __asm__( +SAVE_STACK +#ifdef TARGET_X64 + +#ifdef AMD64ABI + "movl %rsi, %r15\n" + /* rdi is first parameter */ + "movl %rax, %rsi\n" + "subl $128, %rsp\n" + "movl $0xffffffff, %eax\n" + "call *%eax\n" + "movl %r15, %rsi\n" + "movq xmm0, (%r15)\n" +#else + "movl %edi, %ecx\n" + "movl %eax, %edx\n" + "subl $128, %rsp\n" + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "movq xmm0, (%esi)\n" +#endif + "addl $128, %rsp\n" +#else + "subl $8, %esp\n" /* keep stack aligned */ + "pushl %eax\n" /* push parameter */ + "pushl %edi\n" /* push second parameter */ + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" /* store result */ + "addl $16, %esp\n" +#endif + "movl %esi, %eax\n" /* set return value */ + "addl $" EEL_F_SSTR ", %esi\n" /* advance worktab ptr */ +RESTORE_STACK + ); +} +void nseel_asm_2pp_end(void) {} + + +void nseel_asm_1pp(void) +{ +__asm__( +SAVE_STACK +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %eax, %edi\n" + "subl $128, %rsp\n" + "movl $0xffffffff, %rax\n" + "call *%rax\n" + "movl %r15, %rsi\n" + "movq xmm0, (%r15)\n" +#else + "movl %eax, %ecx\n" + "subl $128, %rsp\n" + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "movq xmm0, (%esi)\n" +#endif + "addl $128, %rsp\n" +#else + "subl $12, %esp\n" /* keep stack aligned */ + "pushl %eax\n" /* push parameter */ + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" /* store result */ + "addl $16, %esp\n" +#endif + "movl %esi, %eax\n" /* set return value */ + "addl $" EEL_F_SSTR ", %esi\n" /* advance worktab ptr */ +RESTORE_STACK + ); +} +void nseel_asm_1pp_end(void){} + + + +//--------------------------------------------------------------------------------------------------------------- + + +// do nothing, eh +void nseel_asm_exec2(void) +{ + __asm__( + "" + ); +} +void nseel_asm_exec2_end(void) { } + + + +void nseel_asm_invsqrt(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "movl $0x5f3759df, %edx\n" + "fsts (%esi)\n" +#ifdef TARGET_X64 + "movl 0xffffffff, %rax\n" + "subl %ecx, %ecx\n" + "fmul" EEL_F_SUFFIX " (%rax)\n" +#else + "fmul" EEL_F_SUFFIX " (0xffffffff)\n" +#endif + "movl (%esi), %ecx\n" + "sarl $1, %ecx\n" + "subl %ecx, %edx\n" + "movl %edx, (%esi)\n" + "fmuls (%esi)\n" + "fmuls (%esi)\n" +#ifdef TARGET_X64 + "movl 0xffffffff, %rax\n" + "fadd" EEL_F_SUFFIX " (%rax)\n" +#else + "fadd" EEL_F_SUFFIX " (0xffffffff)\n" +#endif + "fmuls (%esi)\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_invsqrt_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sin(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fsin\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_sin_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_cos(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fcos\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_cos_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_tan(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fptan\n" + "movl %esi, %eax\n" + "fstp %st(0)\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_tan_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sqr(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fmul %st(0), %st(0)\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_sqr_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sqrt(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" + "fsqrt\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_sqrt_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_log(void) +{ + __asm__( + "fldln2\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "movl %esi, %eax\n" + "fyl2x\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_log_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_log10(void) +{ + __asm__( + "fldlg2\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "movl %esi, %eax\n" + "fyl2x\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + + ); +} +void nseel_asm_log10_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_abs(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_abs_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign(void) +{ +#ifdef TARGET_X64 + + __asm__( + "movll (%rax), %rdx\n" + "movll %rdx, %rcx\n" + "shrl $32, %rdx\n" + "andl $0x7FF00000, %edx\n" + "jz 1f\n" + "cmpl $0x7FF00000, %edx\n" + "je 1f\n" + "jmp 0f\n" + "1:\n" + "subl %rcx, %rcx\n" + "0:\n" + "movll %rcx, (%edi)\n" + ); + +#else + + +#if EEL_F_SIZE == 8 + __asm__( + "movl 4(%eax), %edx\n" + "movl (%eax), %ecx\n" + "andl $0x7ff00000, %edx\n" + "jz 1f\n" // if exponent=zero, zero + "cmpl $0x7ff00000, %edx\n" + "je 1f\n" // if exponent=all 1s, zero + "movl 4(%eax), %edx\n" // reread + "jmp 0f\n" + "1:\n" + "subl %ecx, %ecx\n" + "subl %edx, %edx\n" + "0:\n" + "movl %ecx, (%edi)\n" + "movl %edx, 4(%edi)\n" + ); +#else + __asm__( + "movl (%eax), %ecx\n" + "movl %ecx, (%edi)\n" + ); +#endif + +#endif + +} +void nseel_asm_assign_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_add(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fadd" EEL_F_SUFFIX " (%edi)\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_add_end(void) {} + +void nseel_asm_add_op(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fadd" EEL_F_SUFFIX " (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + ); +} +void nseel_asm_add_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sub(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fsub" EEL_F_SUFFIX " (%eax)\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_sub_end(void) {} + +void nseel_asm_sub_op(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fsub" EEL_F_SUFFIX " (%eax)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + ); +} +void nseel_asm_sub_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_mul(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fmul" EEL_F_SUFFIX " (%eax)\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_mul_end(void) {} + +void nseel_asm_mul_op(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fmul" EEL_F_SUFFIX " (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + ); +} +void nseel_asm_mul_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_div(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fdiv" EEL_F_SUFFIX " (%eax)\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_div_end(void) {} + +void nseel_asm_div_op(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fdiv" EEL_F_SUFFIX " (%eax)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + ); +} +void nseel_asm_div_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_mod(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" + "fistpl (%esi)\n" + "fabs\n" + "fistpl 4(%esi)\n" + "xorl %edx, %edx\n" +#ifdef TARGET_X64 + "subl %eax, %eax\n" +#endif + "cmpl $0, (%esi)\n" + "je 0f\n" // skip devide, set return to 0 + "movl 4(%esi), %eax\n" + "divl (%esi)\n" + "0:\n" + "movl %edx, (%esi)\n" + "fildl (%esi)\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_mod_end(void) {} + +void nseel_asm_mod_op(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" + "fistpl (%edi)\n" + "fabs\n" + "fistpl (%esi)\n" +#ifdef TARGET_X64 + "subl %eax, %eax\n" +#endif + "xorl %edx, %edx\n" + "cmpl $0, (%edi)\n" + "je 0f\n" // skip devide, set return to 0 + "movl (%esi), %eax\n" + "divl (%edi)\n" + "0:\n" + "movl %edx, (%edi)\n" + "fildl (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + ); +} +void nseel_asm_mod_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_or(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "movl %esi, %eax\n" + "fistpll (%esi)\n" + "fistpll 8(%esi)\n" +#ifdef TARGET_X64 + "movll 8(%rsi), %rdi\n" + "orll %rdi, (%rsi)\n" +#else + "movl 8(%esi), %edi\n" + "movl 12(%esi), %ecx\n" + "orl %edi, (%esi)\n" + "orl %ecx, 4(%esi)\n" +#endif + "fildll (%esi)\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_or_end(void) {} + +void nseel_asm_or_op(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "fistpll (%edi)\n" + "fistpll (%esi)\n" +#ifdef TARGET_X64 + "movll (%rsi), %rax\n" + "orll %rax, (%rdi)\n" +#else + "movl (%esi), %eax\n" + "movl 4(%esi), %ecx\n" + "orl %eax, (%edi)\n" + "orl %ecx, 4(%edi)\n" +#endif + "fildll (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + ); +} +void nseel_asm_or_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_and(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "movl %esi, %eax\n" + "fistpll (%esi)\n" + "fistpll 8(%esi)\n" +#ifdef TARGET_X64 + "movll 8(%rsi), %rdi\n" + "andll %rdi, (%rsi)\n" +#else + "movl 8(%esi), %edi\n" + "movl 12(%esi), %ecx\n" + "andl %edi, (%esi)\n" + "andl %ecx, 4(%esi)\n" +#endif + "fildll (%esi)\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_and_end(void) {} + +void nseel_asm_and_op(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "fistpll (%edi)\n" + "fistpll (%esi)\n" +#ifdef TARGET_X64 + "movll (%rsi), %rax\n" + "andll %rax, (%rdi)\n" +#else + "movl (%esi), %eax\n" + "movl 4(%esi), %ecx\n" + "andl %eax, (%edi)\n" + "andl %ecx, 4(%edi)\n" +#endif + "fildll (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + ); +} +void nseel_asm_and_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_uplus(void) // this is the same as doing nothing, it seems +{ + __asm__( + "" + ); +} +void nseel_asm_uplus_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_uminus(void) +{ + __asm__( +#if EEL_F_SIZE == 8 + "movl (%eax), %ecx\n" + "movl 4(%eax), %edi\n" + "movl %ecx, (%esi)\n" + "xorl $0x80000000, %edi\n" + "movl %esi, %eax\n" + "movl %edi, 4(%esi)\n" + "addl $8, %esi\n" +#else + "movl (%eax), %ecx\n" + "xorl $0x80000000, %ecx\n" + "movl %esi, %eax\n" + "movl %ecx, (%esi)\n" + "addl $4, %esi\n" +#endif + ); +} +void nseel_asm_uminus_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sign(void) +{ + __asm__( + +#ifdef TARGET_X64 + + + "movl $0xFFFFFFFF, %rdi\n" + "movll (%rax), %rcx\n" + "movll $0x7FFFFFFFFFFFFFFF, %rdx\n" + "testl %rdx, %rcx\n" + "jz 1f\n" + "shr $60, %rcx\n" + "andl $8, %rcx\n" + "addll %rdi, %rcx\n" + "movl %rsi, %rax\n" + "addl $8, %rsi\n" + "movll (%rcx), %rdi\n" + "movll %rdi, (%rax)\n" + "1:\n" + + +#else + + "movl $0xFFFFFFFF, %edi\n" +#if EEL_F_SIZE == 8 + "movl 4(%eax), %ecx\n" + "movl (%eax), %edx\n" + "testl $0xFFFFFFFF, %edx\n" + "jnz 0f\n" +#else + "movl (%eax), %ecx\n" +#endif + // high dword (minus sign bit) is zero + "test $0x7FFFFFFF, %ecx\n" + "jz 1f\n" // zero zero, return the value passed directly + "0:\n" +#if EEL_F_SIZE == 8 + "shrl $28, %ecx\n" +#else + "shrl $29, %ecx\n" +#endif + + "andl $" EEL_F_SSTR ", %ecx\n" + "addl %edi, %ecx\n" + + "movl %esi, %eax\n" + "addl $" EEL_F_SSTR ", %esi\n" + + "movl (%ecx), %edi\n" +#if EEL_F_SIZE == 8 + "movl 4(%ecx), %edx\n" +#endif + "movl %edi, (%eax)\n" +#if EEL_F_SIZE == 8 + "movl %edx, 4(%eax)\n" +#endif + "1:\n" + +#endif +); +} +void nseel_asm_sign_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_bnot(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "test $256, %eax\n" + "movl %esi, %eax\n" + "jz 0f\n" + "fld1\n" + "jmp 1f\n" + "0:\n" + "fldz\n" + "1:\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_bnot_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_if(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] + "movll $0xFFFFFFFF, %rax\n" + "movll %rax, (%esi)\n" // conversion script will extend these out to full len + "movll $0xFFFFFFFF, %rax\n" + "movll %rax, 8(%esi)\n" + "fstsw %ax\n" + "shrl $5, %rax\n" + "andl $8, %rax\n" + "movll (%rax, %rsi), %rax\n" + "subl $8, %rsp\n" +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] + "movl $0xFFFFFFFF, (%esi)\n" + "movl $0xFFFFFFFF, 4(%esi)\n" + "fstsw %ax\n" + "shrl $6, %eax\n" + "andl $4, %eax\n" + "movl (%eax, %esi), %eax\n" +#endif + "call *%eax\n" +#ifdef TARGET_X64 + "addl $8, %rsp\n" +#endif + + ); +} +void nseel_asm_if_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_repeat(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fistpl (%esi)\n" +#ifdef TARGET_X64 // safe not sure if movl ecx will zero the high word + "xorl %ecx, %ecx\n" +#endif + "movl (%esi), %ecx\n" + "cmpl $1, %ecx\n" + "jl 1f\n" + "cmpl $" NSEEL_LOOPFUNC_SUPPORT_MAXLEN_STR ", %ecx\n" + "jl 0f\n" + "movl $" NSEEL_LOOPFUNC_SUPPORT_MAXLEN_STR ", %ecx\n" +"0:\n" + "movl $0xFFFFFFFF, %edx\n" + "subl $8, %esp\n" /* keep stack aligned -- note this is required on x64 too!*/ + "pushl %esi\n" // revert back to last temp workspace + "pushl %ecx\n" + "call *%edx\n" + "popl %ecx\n" + "popl %esi\n" + "addl $8, %esp\n" /* keep stack aligned -- also required on x64*/ + "decl %ecx\n" + "jnz 0b\n" +"1:\n" + ); +} +void nseel_asm_repeat_end(void) {} + +void nseel_asm_repeatwhile(void) +{ + __asm__( + "movl $" NSEEL_LOOPFUNC_SUPPORT_MAXLEN_STR ", %ecx\n" +"0:\n" + "movl $0xFFFFFFFF, %edx\n" + "subl $8, %esp\n" /* keep stack aligned -- required on x86 and x64*/ + "pushl %esi\n" // revert back to last temp workspace + "pushl %ecx\n" + "call *%edx\n" + "popl %ecx\n" + "popl %esi\n" + "addl $8, %esp\n" /* keep stack aligned -- required on x86 and x64 */ + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "testl $256, %eax\n" + "jnz 0f\n" + "decl %ecx\n" + "jnz 0b\n" + "0:\n" + "movl %esi, %eax\n" + ); +} +void nseel_asm_repeatwhile_end(void) {} + + +void nseel_asm_band(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "testl $256, %eax\n" + "jnz 0f\n" // if Z, then we are nonzero + + "movl $0xFFFFFFFF, %ecx\n" +#ifdef TARGET_X64 + "subl $8, %rsp\n" +#endif + "call *%ecx\n" +#ifdef TARGET_X64 + "addl $8, %rsp\n" +#endif + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "testl $256, %eax\n" + "jnz 0f\n" + "fld1\n" + "jmp 1f\n" + +"0:\n" + "fldz\n" +"1:\n" + + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_band_end(void) {} + +void nseel_asm_bor(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "testl $256, %eax\n" + "jz 0f\n" // if Z, then we are nonzero + + "movl $0xFFFFFFFF, %ecx\n" +#ifdef TARGET_X64 + "subl $8, %rsp\n" +#endif + "call *%ecx\n" +#ifdef TARGET_X64 + "addl $8, %rsp\n" +#endif + "fld" EEL_F_SUFFIX " (%eax)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "testl $256, %eax\n" + "jz 0f\n" + "fldz\n" + "jmp 1f\n" + +"0:\n" + "fld1\n" +"1:\n" + + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_bor_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_equal(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fsub" EEL_F_SUFFIX " (%edi)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "testl $256, %eax\n" + "movl %esi, %eax\n" + "jz 0f\n" + "fld1\n" + "jmp 1f\n" + "0:\n" + "fldz\n" + "1:\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_equal_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_notequal(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fsub" EEL_F_SUFFIX " (%edi)\n" + "fabs\n" +#ifdef TARGET_X64 + "movl $0xFFFFFFFF, %rax\n" + "fcomp" EEL_F_SUFFIX " (%rax)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " (0xFFFFFFFF)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "testl $256, %eax\n" + "movl %esi, %eax\n" + "jnz 0f\n" + "fld1\n" + "jmp 1f\n" + "0:\n" + "fldz\n" + "1:\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_notequal_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_below(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fcomp" EEL_F_SUFFIX " (%eax)\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "movl %esi, %eax\n" + "jz 0f\n" + "fld1\n" + "jmp 1f\n" + "0:\n" + "fldz\n" + "1:\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_below_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_beloweq(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fcomp" EEL_F_SUFFIX " (%edi)\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "movl %esi, %eax\n" + "jnz 0f\n" + "fld1\n" + "jmp 1f\n" + "0:\n" + "fldz\n" + "1:\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_beloweq_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_above(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%eax)\n" + "fcomp" EEL_F_SUFFIX " (%edi)\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "movl %esi, %eax\n" + "jz 0f\n" + "fld1\n" + "jmp 1f\n" + "0:\n" + "fldz\n" + "1:\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_above_end(void) {} + +void nseel_asm_aboveeq(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fcomp" EEL_F_SUFFIX " (%eax)\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "movl %esi, %eax\n" + "jnz 0f\n" + "fld1\n" + "jmp 1f\n" + "0:\n" + "fldz\n" + "1:\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + ); +} +void nseel_asm_aboveeq_end(void) {} + + + +void nseel_asm_min(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fcomp" EEL_F_SUFFIX " (%eax)\n" + "pushl %eax\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "popl %eax\n" + "jz 0f\n" + "movl %edi, %eax\n" + "0:\n" + ); + +} +void nseel_asm_min_end(void) {} + +void nseel_asm_max(void) +{ + __asm__( + "fld" EEL_F_SUFFIX " (%edi)\n" + "fcomp" EEL_F_SUFFIX " (%eax)\n" + "pushl %eax\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "popl %eax\n" + "jnz 0f\n" + "movl %edi, %eax\n" + "0:\n" + ); +} +void nseel_asm_max_end(void) {} + + + + + +// just generic functions left, yay + + + + +void _asm_generic3parm(void) +{ + __asm__( +#ifdef TARGET_X64 + +#ifdef AMD64ABI + + "movl %rsi, %r15\n" + "movl %rdi, %rdx\n" // third parameter = parm + "movl $0xFFFFFFFF, %rdi\n" // first parameter= context + + "movl %ecx, %rsi\n" // second parameter = parm + "movl %rax, %rcx\n" // fourth parameter = parm + "movl $0xffffffff, %rax\n" // call function + "subl $128, %rsp\n" + "call *%rax\n" + + "movl %r15, %rsi\n" + "addl $128, %rsp\n" + +#else + "movl %ecx, %edx\n" // second parameter = parm + "movl $0xFFFFFFFF, %ecx\n" // first parameter= context + "movl %rdi, %r8\n" // third parameter = parm + "movl %rax, %r9\n" // fourth parameter = parm + "movl $0xffffffff, %edi\n" // call function + "subl $128, %rsp\n" + "call *%edi\n" + "addl $128, %rsp\n" +#endif + +#else +SAVE_STACK + "movl $0xFFFFFFFF, %edx\n" + "pushl %eax\n" // push parameter + "pushl %edi\n" // push parameter + "pushl %ecx\n" // push parameter + "pushl %edx\n" // push context pointer + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "addl $16, %esp\n" +RESTORE_STACK +#endif + ); +} +void _asm_generic3parm_end(void) {} + + +void _asm_generic3parm_retd(void) +{ + __asm__( +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %rdi, %rdx\n" // third parameter = parm + "movl $0xFFFFFFFF, %rdi\n" // first parameter= context + "movl %ecx, %rsi\n" // second parameter = parm + "movl %rax, %rcx\n" // fourth parameter = parm + "movl $0xffffffff, %rax\n" // call function + "subl $128, %rsp\n" + "call *%rax\n" + "addl $128, %rsp\n" + "movl %r15, %rsi\n" + "movl %r15, %rax\n" + "movq xmm0, (%r15)\n" + "addl $8, %rsi\n" +#else + "movl %ecx, %edx\n" // second parameter = parm + "movl $0xFFFFFFFF, %ecx\n" // first parameter= context + "movl %rdi, %r8\n" // third parameter = parm + "movl %rax, %r9\n" // fourth parameter = parm + "movl $0xffffffff, %edi\n" // call function + "subl $128, %rsp\n" + "call *%edi\n" + "addl $128, %rsp\n" + "movq xmm0, (%rsi)\n" + "movl %rsi, %rax\n" + "addl $8, %rsi\n" +#endif +#else +SAVE_STACK + "movl $0xFFFFFFFF, %edx\n" + "pushl %eax\n" // push parameter + "pushl %edi\n" // push parameter + "pushl %ecx\n" // push parameter + "pushl %edx\n" // push context pointer + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + "addl $16, %esp\n" +RESTORE_STACK +#endif + ); +} +void _asm_generic3parm_retd_end(void) {} + + +void _asm_generic2parm(void) // this prob neds to be fixed for ppc +{ + __asm__( +#ifdef TARGET_X64 + +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %edi, %esi\n" // second parameter = parm + "movl $0xFFFFFFFF, %edi\n" // first parameter= context + "movl %rax, %rdx\n" // third parameter = parm + "movl $0xffffffff, %rcx\n" // call function + "subl $128, %rsp\n" + "call *%rcx\n" + "movl %r15, %rsi\n" + "addl $128, %rsp\n" +#else + "movl $0xFFFFFFFF, %ecx\n" // first parameter= context + "movl %edi, %edx\n" // second parameter = parm + "movl %rax, %r8\n" // third parameter = parm + "movl $0xffffffff, %edi\n" // call function + "subl $128, %rsp\n" + "call *%edi\n" + "addl $128, %rsp\n" +#endif +#else +SAVE_STACK + "movl $0xFFFFFFFF, %edx\n" + "subl $4, %esp\n" // keep stack aligned + "pushl %eax\n" // push parameter + "pushl %edi\n" // push parameter + "pushl %edx\n" // push context pointer + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "addl $16, %esp\n" +RESTORE_STACK +#endif + ); +} +void _asm_generic2parm_end(void) {} + + +void _asm_generic2parm_retd(void) +{ + __asm__( +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %rdi, %rsi\n" // second parameter = parm + "movl $0xFFFFFFFF, %rdi\n" // first parameter= context + "movl %rax, %rdx\n" // third parameter = parm + "movl $0xffffffff, %rcx\n" // call function + "subl $128, %rsp\n" + "call *%rcx\n" + "movl %r15, %rsi\n" + "addl $128, %rsp\n" + "movq xmm0, (%r15)\n" + "movl %r15, %rax\n" + "addl $8, %rsi\n" +#else + "movl $0xFFFFFFFF, %ecx\n" // first parameter= context + "movl %edi, %edx\n" // second parameter = parm + "movl %rax, %r8\n" // third parameter = parm + "movl $0xffffffff, %edi\n" // call function + "subl $128, %rsp\n" + "call *%edi\n" + "addl $128, %rsp\n" + "movq xmm0, (%rsi)\n" + "movl %rsi, %rax\n" + "addl $8, %rsi\n" +#endif +#else +SAVE_STACK + "movl $0xFFFFFFFF, %edx\n" + "pushl %eax\n" // push parameter + "pushl %edi\n" // push parameter + "pushl %ecx\n" // push parameter + "pushl %edx\n" // push context pointer + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + "addl $16, %esp\n" +RESTORE_STACK +#endif + ); +} +void _asm_generic2parm_retd_end(void) {} + + + + + +void _asm_generic1parm(void) // this prob neds to be fixed for ppc +{ + __asm__( +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl $0xFFFFFFFF, %rdi\n" // first parameter= context + "movl %rsi, %r15\n" + "movl %eax, %rsi\n" // second parameter = parm + "subl $128, %rsp\n" + "movl $0xffffffff, %rcx\n" // call function + "call *%rcx\n" + "movl %r15, %rsi\n" + "addl $128, %rsp\n" +#else + "movl $0xFFFFFFFF, %ecx\n" // first parameter= context + "movl %eax, %edx\n" // second parameter = parm + "movl $0xffffffff, %edi\n" // call function + "subl $128, %rsp\n" + "call *%edi\n" + "addl $128, %rsp\n" +#endif +#else +SAVE_STACK + "movl $0xFFFFFFFF, %edx\n" + "subl $8, %esp\n" // keep stack aligned + "pushl %eax\n" // push parameter + "pushl %edx\n" // push context pointer + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "addl $16, %esp\n" +RESTORE_STACK +#endif + + ); +} +void _asm_generic1parm_end(void) {} + + +void _asm_generic1parm_retd(void) // 1 parameter returning double +{ + __asm__( +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl $0xFFFFFFFF, %rdi\n" // first parameter= context + "movl %rax, %rsi\n" // second parameter = parm + "movl $0xffffffff, %rcx\n" // call function + "subl $128, %rsp\n" + "call *%rcx\n" + "movl %r15, %rsi\n" + "addl $128, %rsp\n" + "movq xmm0, (%r15)\n" + "movl %r15, %rax\n" + "addl $8, %rsi\n" +#else + "movl $0xFFFFFFFF, %ecx\n" // first parameter= context + "movl %eax, %edx\n" // second parameter = parm + "movl $0xffffffff, %edi\n" // call function + "subl $128, %rsp\n" + "call *%edi\n" + "addl $128, %rsp\n" + "movq xmm0, (%rsi)\n" + "movl %rsi, %rax\n" + "addl $8, %rsi\n" +#endif +#else +SAVE_STACK + "movl $0xFFFFFFFF, %edx\n" + "subl $8, %esp\n" // keep stack aligned + "pushl %eax\n" // push parameter + "pushl %edx\n" // push context pointer + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "movl %esi, %eax\n" + "fstp" EEL_F_SUFFIX " (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + "addl $16, %esp\n" +RESTORE_STACK +#endif + ); +} +void _asm_generic1parm_retd_end(void) {} + + + + + +// this gets its own stub because it's pretty crucial for performance :/ + +void _asm_megabuf(void) +{ + __asm__( +SAVE_STACK + +#ifdef TARGET_X64 + + +#ifdef AMD64ABI + + "movl %rsi, %r15\n" + "movl $0xFFFFFFFF, %rdi\n" // first parameter = context pointer + "fld" EEL_F_SUFFIX " (%eax)\n" + "movl $0xFFFFFFFF, %rdx\n" + "fadd" EEL_F_SUFFIX " (%rdx)\n" + "fistpl (%r15)\n" + "xorl %rsi, %rsi\n" + "movl (%r15), %esi\n" // r15 = esi (from above) + "movl $0xffffffff, %edx\n" + "subl $128, %rsp\n" + "call *%edx\n" + "movl %r15, %rsi\n" + "addl $128, %rsp\n" + "and %rax, %rax\n" + "jnz 0f\n" + "movl %r15, %rax\n" + "movll $0, (%esi)\n" + "addl $" EEL_F_SSTR ", %rsi\n" + "0:" + +#else + "movl $0xFFFFFFFF, %ecx\n" // first parameter = context pointer + "fld" EEL_F_SUFFIX " (%eax)\n" + "movl $0xFFFFFFFF, %edx\n" + "fadd" EEL_F_SUFFIX " (%rdx)\n" + "fistpl (%esi)\n" + "xorl %rdx, %rdx\n" + "movl (%esi), %edx\n" + "movl $0xffffffff, %edi\n" + "subl $128, %rsp\n" + "call *%edi\n" + "addl $128, %rsp\n" + "and %rax, %rax\n" + "jnz 0f\n" + "movl %rsi, %rax\n" + "movll $0, (%esi)\n" + "addl $" EEL_F_SSTR ", %esi\n" + "0:" +#endif + + +#else + "movl $0xFFFFFFFF, %edx\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "fadd" EEL_F_SUFFIX " (0xFFFFFFFF)\n" + "fistpl (%esi)\n" + "subl $8, %esp\n" // keep stack aligned + "pushl (%esi)\n" // parameter + "pushl %edx\n" // push context pointer + "movl $0xffffffff, %edi\n" + "call *%edi\n" + "addl $16, %esp\n" + "and %eax, %eax\n" + "jnz 0f\n" + "movl %esi, %eax\n" + "movl $0, (%esi)\n" +#if EEL_F_SIZE == 8 + "movl $0, 4(%esi)\n" +#endif + "addl $" EEL_F_SSTR ", %esi\n" + "0:" + + +#endif + +RESTORE_STACK + + ); +} + +void _asm_megabuf_end(void) {} + + +#ifdef TARGET_X64 +void win64_callcode() +{ + __asm__( +#ifdef AMD64ABI + "movll %edi, %eax\n" +#else + "movll %ecx, %eax\n" +#endif + + "push %rbx\n" + "push %rbp\n" +#ifndef AMD64ABI + "push %rdi\n" + "push %rsi\n" + "push %r12\n" + "push %r13\n" +#endif + "push %r14\n" // on AMD64ABI, we'll use r14/r15 to save edi/esi + "push %r15\n" + "call %eax\n" + "pop %r15\n" + "pop %r14\n" +#ifndef AMD64ABI + "pop %r13\n" + "pop %r12\n" + "pop %rsi\n" + "pop %rdi\n" + "fclex\n" +#endif + "pop %rbp\n" + "pop %rbx\n" + "ret\n" + ); +} + +#endif \ No newline at end of file diff --git a/ns-eel2/asm-nseel-x86-msvc.c b/ns-eel2/asm-nseel-x86-msvc.c new file mode 100644 index 0000000..30c88c5 --- /dev/null +++ b/ns-eel2/asm-nseel-x86-msvc.c @@ -0,0 +1,2463 @@ +// THIS FILE AUTOGENERATED FROM asm-nseel-x86-gcc.c by a2i.php + +#if EEL_F_SIZE == 8 + #define EEL_ASM_TYPE qword ptr +#else + #define EEL_ASM_TYPE dword ptr +#endif + +#if defined(__APPLE__) +#define SAVE_STACK "pushl %ebp\nmovl %esp, %ebp\nandl $-16, %esp\n" +#define RESTORE_STACK "leave\n" +#else +#define SAVE_STACK +#define RESTORE_STACK +#endif + +/* note: only EEL_F_SIZE=8 is now supported (no float EEL_F's) */ + +__declspec(naked) void nseel_asm_1pdd(void) +{ + __asm { + SAVE_STACK +#ifdef TARGET_X64 + movq xmm0, [eax]; + sub rsp, 128; + mov edi, 0xffffffff; +#ifdef AMD64ABI + mov r15, rsi; + call edi; + mov rsi, r15; + movq [r15], xmm0; +#else + call edi; + movq [esi], xmm0; +#endif + add rsp, 128; +#else + sub esp, 8; /* keep stack aligned */ + push dword ptr [eax+4]; /* push parameter */ + push dword ptr [eax]; /* push the rest of the parameter */ + mov edi, 0xffffffff; + call edi; + fstp qword ptr [esi]; /* store result */ + add esp, 16; +#endif + mov eax, esi; /* set return value */ + add esi, 8; /* advance worktab ptr */ + RESTORE_STACK +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_1pdd_end(void){} + +__declspec(naked) void nseel_asm_2pdd(void) +{ + __asm { + SAVE_STACK +#ifdef TARGET_X64 + movq xmm1, [eax]; + movq xmm0, [edi]; + sub rsp, 128; + mov edi, 0xffffffff; +#ifdef AMD64ABI + mov r15, rsi; + call edi; + mov rsi, r15; + movq [r15], xmm0; +#else + call edi; + movq [esi], xmm0; +#endif + add rsp, 128; +#else + push dword ptr [eax+4]; /* push parameter */ + push dword ptr [eax]; /* push the rest of the parameter */ + push dword ptr [edi+4]; /* push parameter */ + push dword ptr [edi]; /* push the rest of the parameter */ + mov edi, 0xffffffff; + call edi; + fstp qword ptr [esi]; /* store result */ + add esp, 16; +#endif + mov eax, esi; /* set return value */ + add esi, 8; /* advance worktab ptr */ + RESTORE_STACK +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_2pdd_end(void){} + +__declspec(naked) void nseel_asm_2pdds(void) +{ + __asm { + SAVE_STACK +#ifdef TARGET_X64 + movq xmm1, [eax]; + movq xmm0, [edi]; + sub rsp, 128; + mov eax, 0xffffffff; +#ifdef AMD64ABI + mov r15, rsi; + mov r14, rdi; + call eax; + mov rsi, r15; + movq [r14], xmm0; + mov rax, r14; /* set return value */ +#else + call eax; + movq [edi], xmm0; + mov eax, edi; /* set return value */ +#endif + sub rsp, 128; +#else + push dword ptr [eax+4]; /* push parameter */ + push dword ptr [eax]; /* push the rest of the parameter */ + push dword ptr [edi+4]; /* push parameter */ + push dword ptr [edi]; /* push the rest of the parameter */ + mov eax, 0xffffffff; + call eax; + fstp qword ptr [edi]; /* store result */ + add esp, 16; + mov eax, edi; /* set return value */ +#endif +RESTORE_STACK +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_2pdds_end(void){} + +__declspec(naked) void nseel_asm_2pp(void) +{ + __asm { +SAVE_STACK +#ifdef TARGET_X64 + +#ifdef AMD64ABI + mov r15, rsi; + /* rdi is first parameter */ + mov rsi, rax; + sub rsp, 128; + mov eax, 0xffffffff; + call eax; + mov rsi, r15; + movq [r15], xmm0; +#else + mov ecx, edi; + mov edx, eax; + sub rsp, 128; + mov edi, 0xffffffff; + call edi; + movq [esi], xmm0; +#endif + add rsp, 128; +#else + sub esp, 8; /* keep stack aligned */ + push eax; /* push parameter */ + push edi; /* push second parameter */ + mov edi, 0xffffffff; + call edi; + fstp EEL_ASM_TYPE [esi]; /* store result */ + add esp, 16; +#endif + mov eax, esi; /* set return value */ + add esi, EEL_F_SIZE; /* advance worktab ptr */ +RESTORE_STACK +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_2pp_end(void) {} + + +__declspec(naked) void nseel_asm_1pp(void) +{ +__asm { +SAVE_STACK +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov r15, rsi; + mov edi, eax; + sub rsp, 128; + mov rax, 0xffffffff; + call rax; + mov rsi, r15; + movq [r15], xmm0; +#else + mov ecx, eax; + sub rsp, 128; + mov edi, 0xffffffff; + call edi; + movq [esi], xmm0; +#endif + add rsp, 128; +#else + sub esp, 12; /* keep stack aligned */ + push eax; /* push parameter */ + mov edi, 0xffffffff; + call edi; + fstp EEL_ASM_TYPE [esi]; /* store result */ + add esp, 16; +#endif + mov eax, esi; /* set return value */ + add esi, EEL_F_SIZE; /* advance worktab ptr */ +RESTORE_STACK +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_1pp_end(void){} + + + +//--------------------------------------------------------------------------------------------------------------- + + +// do nothing, eh +__declspec(naked) void nseel_asm_exec2(void) +{ + __asm { + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_exec2_end(void) { } + + + +__declspec(naked) void nseel_asm_invsqrt(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + mov edx, 0x5f3759df; + fst dword ptr [esi]; +#ifdef TARGET_X64 + mov rax, 0xffffffff; + sub ecx, ecx; + fmul EEL_ASM_TYPE [rax]; +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fmul qword ptr [0xffffffff] +_emit 0x0D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fmul dword ptr [0xffffffff] +_emit 0x0D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + mov ecx, dword ptr [esi]; + sar ecx, 1; + sub edx, ecx; + mov dword ptr [esi], edx; + fmul dword ptr [esi]; + fmul dword ptr [esi]; +#ifdef TARGET_X64 + mov rax, 0xffffffff; + fadd EEL_ASM_TYPE [rax]; +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fadd qword ptr [0xffffffff] +_emit 0x05; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fadd dword ptr [0xffffffff] +_emit 0x05; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fmul dword ptr [esi]; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_invsqrt_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sin(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fsin; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sin_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_cos(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fcos; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_cos_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_tan(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fptan; + mov eax, esi; + fstp st(0); + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_tan_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sqr(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fmul st(0), st(0); + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sqr_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sqrt(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fabs; + fsqrt; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sqrt_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_log(void) +{ + __asm { + fldln2; + fld EEL_ASM_TYPE [eax]; + mov eax, esi; + fyl2x; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_log_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_log10(void) +{ + __asm { + fldlg2; + fld EEL_ASM_TYPE [eax]; + mov eax, esi; + fyl2x; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_log10_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_abs(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fabs; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_abs_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_assign(void) +{ +#ifdef TARGET_X64 + + __asm { + mov rdx, qword ptr [rax]; + mov rcx, rdx; + shr rdx, 32; + and edx, 0x7FF00000; + jz label_0; + cmp edx, 0x7FF00000; + je label_0; + jmp label_1; +label_0: + + sub rcx, rcx; +label_1: + + mov qword ptr [edi], rcx; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + +#if EEL_F_SIZE == 8 + __asm { + mov edx, dword ptr [eax+4]; + mov ecx, dword ptr [eax]; + and edx, 0x7ff00000; + jz label_2; // if exponent=zero, zero + cmp edx, 0x7ff00000; + je label_2; // if exponent=all 1s, zero + mov edx, dword ptr [eax+4]; // reread + jmp label_3; +label_2: + + sub ecx, ecx; + sub edx, edx; +label_3: + + mov dword ptr [edi], ecx; + mov dword ptr [edi+4], edx; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +#else + __asm { + mov ecx, dword ptr [eax]; + mov dword ptr [edi], ecx; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +#endif + +#endif + +} +__declspec(naked) void nseel_asm_assign_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_add(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fadd EEL_ASM_TYPE [edi]; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_add_end(void) {} + +__declspec(naked) void nseel_asm_add_op(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fadd EEL_ASM_TYPE [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_add_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sub(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fsub EEL_ASM_TYPE [eax]; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sub_end(void) {} + +__declspec(naked) void nseel_asm_sub_op(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fsub EEL_ASM_TYPE [eax]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sub_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_mul(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fmul EEL_ASM_TYPE [eax]; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mul_end(void) {} + +__declspec(naked) void nseel_asm_mul_op(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fmul EEL_ASM_TYPE [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mul_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_div(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fdiv EEL_ASM_TYPE [eax]; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_div_end(void) {} + +__declspec(naked) void nseel_asm_div_op(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fdiv EEL_ASM_TYPE [eax]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_div_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_mod(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fld EEL_ASM_TYPE [eax]; + fabs; + fistp dword ptr [esi]; + fabs; + fistp dword ptr [esi+4]; + xor edx, edx; +#ifdef TARGET_X64 + sub eax, eax; +#endif + cmp dword ptr [esi], 0; + je label_4; // skip devide, set return to 0 + mov eax, dword ptr [esi+4]; + div dword ptr [esi]; +label_4: + + mov dword ptr [esi], edx; + fild dword ptr [esi]; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mod_end(void) {} + +__declspec(naked) void nseel_asm_mod_op(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fld EEL_ASM_TYPE [eax]; + fabs; + fistp dword ptr [edi]; + fabs; + fistp dword ptr [esi]; +#ifdef TARGET_X64 + sub eax, eax; +#endif + xor edx, edx; + cmp dword ptr [edi], 0; + je label_5; // skip devide, set return to 0 + mov eax, dword ptr [esi]; + div dword ptr [edi]; +label_5: + + mov dword ptr [edi], edx; + fild dword ptr [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mod_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_or(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fld EEL_ASM_TYPE [eax]; + mov eax, esi; + fistp qword ptr [esi]; + fistp qword ptr [esi+8]; +#ifdef TARGET_X64 + mov rdi, qword ptr [rsi+8]; + or qword ptr [rsi], rdi; +#else + mov edi, dword ptr [esi+8]; + mov ecx, dword ptr [esi+12]; + or dword ptr [esi], edi; + or dword ptr [esi+4], ecx; +#endif + fild qword ptr [esi]; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_or_end(void) {} + +__declspec(naked) void nseel_asm_or_op(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fld EEL_ASM_TYPE [eax]; + fistp qword ptr [edi]; + fistp qword ptr [esi]; +#ifdef TARGET_X64 + mov rax, qword ptr [rsi]; + or qword ptr [rdi], rax; +#else + mov eax, dword ptr [esi]; + mov ecx, dword ptr [esi+4]; + or dword ptr [edi], eax; + or dword ptr [edi+4], ecx; +#endif + fild qword ptr [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_or_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_and(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fld EEL_ASM_TYPE [eax]; + mov eax, esi; + fistp qword ptr [esi]; + fistp qword ptr [esi+8]; +#ifdef TARGET_X64 + mov rdi, qword ptr [rsi+8]; + and qword ptr [rsi], rdi; +#else + mov edi, dword ptr [esi+8]; + mov ecx, dword ptr [esi+12]; + and dword ptr [esi], edi; + and dword ptr [esi+4], ecx; +#endif + fild qword ptr [esi]; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_and_end(void) {} + +__declspec(naked) void nseel_asm_and_op(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fld EEL_ASM_TYPE [eax]; + fistp qword ptr [edi]; + fistp qword ptr [esi]; +#ifdef TARGET_X64 + mov rax, qword ptr [rsi]; + and qword ptr [rdi], rax; +#else + mov eax, dword ptr [esi]; + mov ecx, dword ptr [esi+4]; + and dword ptr [edi], eax; + and dword ptr [edi+4], ecx; +#endif + fild qword ptr [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_and_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_uplus(void) // this is the same as doing nothing, it seems +{ + __asm { + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_uplus_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_uminus(void) +{ + __asm { +#if EEL_F_SIZE == 8 + mov ecx, dword ptr [eax]; + mov edi, dword ptr [eax+4]; + mov dword ptr [esi], ecx; + xor edi, 0x80000000; + mov eax, esi; + mov dword ptr [esi+4], edi; + add esi, 8; +#else + mov ecx, dword ptr [eax]; + xor ecx, 0x80000000; + mov eax, esi; + mov dword ptr [esi], ecx; + add esi, 4; +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_uminus_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sign(void) +{ + __asm { + +#ifdef TARGET_X64 + + + mov rdi, 0xFFFFFFFF; + mov rcx, qword ptr [rax]; + mov rdx, 0x7FFFFFFFFFFFFFFF; + test rcx, rdx; + jz label_6; + shr rcx, 60; + and rcx, 8; + add rcx, rdi; + mov rax, rsi; + add rsi, 8; + mov rdi, qword ptr [rcx]; + mov qword ptr [rax], rdi; +label_6: + + + +#else + + mov edi, 0xFFFFFFFF; +#if EEL_F_SIZE == 8 + mov ecx, dword ptr [eax+4]; + mov edx, dword ptr [eax]; + test edx, 0xFFFFFFFF; + jnz label_7; +#else + mov ecx, dword ptr [eax]; +#endif + // high dword (minus sign bit) is zero + test ecx, 0x7FFFFFFF; + jz label_8; // zero zero, return the value passed directly +label_7: + +#if EEL_F_SIZE == 8 + shr ecx, 28; +#else + shr ecx, 29; +#endif + + and ecx, EEL_F_SIZE; + add ecx, edi; + + mov eax, esi; + add esi, EEL_F_SIZE; + + mov edi, dword ptr [ecx]; +#if EEL_F_SIZE == 8 + mov edx, dword ptr [ecx+4]; +#endif + mov dword ptr [eax], edi; +#if EEL_F_SIZE == 8 + mov dword ptr [eax+4], edx; +#endif +label_8: + + +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +} +} +__declspec(naked) void nseel_asm_sign_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_bnot(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fstsw ax; + test eax, 256; + mov eax, esi; + jz label_9; + fld1; + jmp label_10; +label_9: + + fldz; +label_10: + + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_bnot_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_if(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] + mov rax, 0xFFFFFFFF; + mov qword ptr [esi], rax; // conversion script will extend these out to full len + mov rax, 0xFFFFFFFF; + mov qword ptr [esi+8], rax; + fstsw ax; + shr rax, 5; + and rax, 8; + mov rax, qword ptr [rax+rsi]; + sub rsp, 8; +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif + mov dword ptr [esi], 0xFFFFFFFF; + mov dword ptr [esi+4], 0xFFFFFFFF; + fstsw ax; + shr eax, 6; + and eax, 4; + mov eax, dword ptr [eax+esi]; +#endif + call eax; +#ifdef TARGET_X64 + add rsp, 8; +#endif + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_if_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_repeat(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fistp dword ptr [esi]; +#ifdef TARGET_X64 // safe not sure if movl ecx will zero the high word + xor ecx, ecx; +#endif + mov ecx, dword ptr [esi]; + cmp ecx, 1; + jl label_11; + cmp ecx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN; + jl label_12; + mov ecx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN; +label_12: + + mov edx, 0xFFFFFFFF; + sub esp, 8; /* keep stack aligned -- note this is required on x64 too!*/ + push esi; // revert back to last temp workspace + push ecx; + call edx; + pop ecx; + pop esi; + add esp, 8; /* keep stack aligned -- also required on x64*/ + dec ecx; + jnz label_12; +label_11: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_repeat_end(void) {} + +__declspec(naked) void nseel_asm_repeatwhile(void) +{ + __asm { + mov ecx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN; +label_13: + + mov edx, 0xFFFFFFFF; + sub esp, 8; /* keep stack aligned -- required on x86 and x64*/ + push esi; // revert back to last temp workspace + push ecx; + call edx; + pop ecx; + pop esi; + add esp, 8; /* keep stack aligned -- required on x86 and x64 */ + fld EEL_ASM_TYPE [eax]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fstsw ax; + test eax, 256; + jnz label_14; + dec ecx; + jnz label_13; +label_14: + + mov eax, esi; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_repeatwhile_end(void) {} + + +__declspec(naked) void nseel_asm_band(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fstsw ax; + test eax, 256; + jnz label_15; // if Z, then we are nonzero + + mov ecx, 0xFFFFFFFF; +#ifdef TARGET_X64 + sub rsp, 8; +#endif + call ecx; +#ifdef TARGET_X64 + add rsp, 8; +#endif + fld EEL_ASM_TYPE [eax]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fstsw ax; + test eax, 256; + jnz label_15; + fld1; + jmp label_16; + +label_15: + + fldz; +label_16: + + + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_band_end(void) {} + +__declspec(naked) void nseel_asm_bor(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fstsw ax; + test eax, 256; + jz label_17; // if Z, then we are nonzero + + mov ecx, 0xFFFFFFFF; +#ifdef TARGET_X64 + sub rsp, 8; +#endif + call ecx; +#ifdef TARGET_X64 + add rsp, 8; +#endif + fld EEL_ASM_TYPE [eax]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fstsw ax; + test eax, 256; + jz label_17; + fldz; + jmp label_18; + +label_17: + + fld1; +label_18: + + + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_bor_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_equal(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fsub EEL_ASM_TYPE [edi]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fstsw ax; + test eax, 256; + mov eax, esi; + jz label_19; + fld1; + jmp label_20; +label_19: + + fldz; +label_20: + + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_equal_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_notequal(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fsub EEL_ASM_TYPE [edi]; + fabs; +#ifdef TARGET_X64 + mov rax, 0xFFFFFFFF; + fcomp EEL_ASM_TYPE [rax]; //[g_closefact] +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fcomp qword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fcomp dword ptr [0xffffffff] +_emit 0x1D; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif +#endif + fstsw ax; + test eax, 256; + mov eax, esi; + jnz label_21; + fld1; + jmp label_22; +label_21: + + fldz; +label_22: + + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_notequal_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_below(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fcomp EEL_ASM_TYPE [eax]; + fstsw ax; + test eax, 256; + mov eax, esi; + jz label_23; + fld1; + jmp label_24; +label_23: + + fldz; +label_24: + + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_below_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_beloweq(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fcomp EEL_ASM_TYPE [edi]; + fstsw ax; + test eax, 256; + mov eax, esi; + jnz label_25; + fld1; + jmp label_26; +label_25: + + fldz; +label_26: + + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_beloweq_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_above(void) +{ + __asm { + fld EEL_ASM_TYPE [eax]; + fcomp EEL_ASM_TYPE [edi]; + fstsw ax; + test eax, 256; + mov eax, esi; + jz label_27; + fld1; + jmp label_28; +label_27: + + fldz; +label_28: + + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_above_end(void) {} + +__declspec(naked) void nseel_asm_aboveeq(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fcomp EEL_ASM_TYPE [eax]; + fstsw ax; + test eax, 256; + mov eax, esi; + jnz label_29; + fld1; + jmp label_30; +label_29: + + fldz; +label_30: + + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_aboveeq_end(void) {} + + + +__declspec(naked) void nseel_asm_min(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fcomp EEL_ASM_TYPE [eax]; + push eax; + fstsw ax; + test eax, 256; + pop eax; + jz label_31; + mov eax, edi; +label_31: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +} +__declspec(naked) void nseel_asm_min_end(void) {} + +__declspec(naked) void nseel_asm_max(void) +{ + __asm { + fld EEL_ASM_TYPE [edi]; + fcomp EEL_ASM_TYPE [eax]; + push eax; + fstsw ax; + test eax, 256; + pop eax; + jnz label_32; + mov eax, edi; +label_32: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_max_end(void) {} + + + + + +// just generic functions left, yay + + + + +__declspec(naked) void _asm_generic3parm(void) +{ + __asm { +#ifdef TARGET_X64 + +#ifdef AMD64ABI + + mov r15, rsi; + mov rdx, rdi; // third parameter = parm + mov rdi, 0xFFFFFFFF; // first parameter= context + + mov rsi, ecx; // second parameter = parm + mov rcx, rax; // fourth parameter = parm + mov rax, 0xffffffff; // call function + sub rsp, 128; + call rax; + + mov rsi, r15; + add rsp, 128; + +#else + mov edx, ecx; // second parameter = parm + mov ecx, 0xFFFFFFFF; // first parameter= context + mov r8, rdi; // third parameter = parm + mov r9, rax; // fourth parameter = parm + mov edi, 0xffffffff; // call function + sub rsp, 128; + call edi; + add rsp, 128; +#endif + +#else +SAVE_STACK + mov edx, 0xFFFFFFFF; + push eax; // push parameter + push edi; // push parameter + push ecx; // push parameter + push edx; // push context pointer + mov edi, 0xffffffff; + call edi; + add esp, 16; +RESTORE_STACK +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic3parm_end(void) {} + + +__declspec(naked) void _asm_generic3parm_retd(void) +{ + __asm { +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov r15, rsi; + mov rdx, rdi; // third parameter = parm + mov rdi, 0xFFFFFFFF; // first parameter= context + mov rsi, ecx; // second parameter = parm + mov rcx, rax; // fourth parameter = parm + mov rax, 0xffffffff; // call function + sub rsp, 128; + call rax; + add rsp, 128; + mov rsi, r15; + mov rax, r15; + movq [r15], xmm0; + add rsi, 8; +#else + mov edx, ecx; // second parameter = parm + mov ecx, 0xFFFFFFFF; // first parameter= context + mov r8, rdi; // third parameter = parm + mov r9, rax; // fourth parameter = parm + mov edi, 0xffffffff; // call function + sub rsp, 128; + call edi; + add rsp, 128; + movq [rsi], xmm0; + mov rax, rsi; + add rsi, 8; +#endif +#else +SAVE_STACK + mov edx, 0xFFFFFFFF; + push eax; // push parameter + push edi; // push parameter + push ecx; // push parameter + push edx; // push context pointer + mov edi, 0xffffffff; + call edi; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; + add esp, 16; +RESTORE_STACK +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic3parm_retd_end(void) {} + + +__declspec(naked) void _asm_generic2parm(void) // this prob neds to be fixed for ppc +{ + __asm { +#ifdef TARGET_X64 + +#ifdef AMD64ABI + mov r15, rsi; + mov esi, edi; // second parameter = parm + mov edi, 0xFFFFFFFF; // first parameter= context + mov rdx, rax; // third parameter = parm + mov rcx, 0xffffffff; // call function + sub rsp, 128; + call rcx; + mov rsi, r15; + add rsp, 128; +#else + mov ecx, 0xFFFFFFFF; // first parameter= context + mov edx, edi; // second parameter = parm + mov r8, rax; // third parameter = parm + mov edi, 0xffffffff; // call function + sub rsp, 128; + call edi; + add rsp, 128; +#endif +#else +SAVE_STACK + mov edx, 0xFFFFFFFF; + sub esp, 4; // keep stack aligned + push eax; // push parameter + push edi; // push parameter + push edx; // push context pointer + mov edi, 0xffffffff; + call edi; + add esp, 16; +RESTORE_STACK +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic2parm_end(void) {} + + +__declspec(naked) void _asm_generic2parm_retd(void) +{ + __asm { +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov r15, rsi; + mov rsi, rdi; // second parameter = parm + mov rdi, 0xFFFFFFFF; // first parameter= context + mov rdx, rax; // third parameter = parm + mov rcx, 0xffffffff; // call function + sub rsp, 128; + call rcx; + mov rsi, r15; + add rsp, 128; + movq [r15], xmm0; + mov rax, r15; + add rsi, 8; +#else + mov ecx, 0xFFFFFFFF; // first parameter= context + mov edx, edi; // second parameter = parm + mov r8, rax; // third parameter = parm + mov edi, 0xffffffff; // call function + sub rsp, 128; + call edi; + add rsp, 128; + movq [rsi], xmm0; + mov rax, rsi; + add rsi, 8; +#endif +#else +SAVE_STACK + mov edx, 0xFFFFFFFF; + push eax; // push parameter + push edi; // push parameter + push ecx; // push parameter + push edx; // push context pointer + mov edi, 0xffffffff; + call edi; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; + add esp, 16; +RESTORE_STACK +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic2parm_retd_end(void) {} + + + + + +__declspec(naked) void _asm_generic1parm(void) // this prob neds to be fixed for ppc +{ + __asm { +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov rdi, 0xFFFFFFFF; // first parameter= context + mov r15, rsi; + mov rsi, eax; // second parameter = parm + sub rsp, 128; + mov rcx, 0xffffffff; // call function + call rcx; + mov rsi, r15; + add rsp, 128; +#else + mov ecx, 0xFFFFFFFF; // first parameter= context + mov edx, eax; // second parameter = parm + mov edi, 0xffffffff; // call function + sub rsp, 128; + call edi; + add rsp, 128; +#endif +#else +SAVE_STACK + mov edx, 0xFFFFFFFF; + sub esp, 8; // keep stack aligned + push eax; // push parameter + push edx; // push context pointer + mov edi, 0xffffffff; + call edi; + add esp, 16; +RESTORE_STACK +#endif + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic1parm_end(void) {} + + +__declspec(naked) void _asm_generic1parm_retd(void) // 1 parameter returning double +{ + __asm { +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov r15, rsi; + mov rdi, 0xFFFFFFFF; // first parameter= context + mov rsi, rax; // second parameter = parm + mov rcx, 0xffffffff; // call function + sub rsp, 128; + call rcx; + mov rsi, r15; + add rsp, 128; + movq [r15], xmm0; + mov rax, r15; + add rsi, 8; +#else + mov ecx, 0xFFFFFFFF; // first parameter= context + mov edx, eax; // second parameter = parm + mov edi, 0xffffffff; // call function + sub rsp, 128; + call edi; + add rsp, 128; + movq [rsi], xmm0; + mov rax, rsi; + add rsi, 8; +#endif +#else +SAVE_STACK + mov edx, 0xFFFFFFFF; + sub esp, 8; // keep stack aligned + push eax; // push parameter + push edx; // push context pointer + mov edi, 0xffffffff; + call edi; + mov eax, esi; + fstp EEL_ASM_TYPE [esi]; + add esi, EEL_F_SIZE; + add esp, 16; +RESTORE_STACK +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic1parm_retd_end(void) {} + + + + + +// this gets its own stub because it's pretty crucial for performance :/ + +__declspec(naked) void _asm_megabuf(void) +{ + __asm { +SAVE_STACK + +#ifdef TARGET_X64 + + +#ifdef AMD64ABI + + mov r15, rsi; + mov rdi, 0xFFFFFFFF; // first parameter = context pointer + fld EEL_ASM_TYPE [eax]; + mov rdx, 0xFFFFFFFF; + fadd EEL_ASM_TYPE [rdx]; + fistp dword ptr [r15]; + xor rsi, rsi; + mov esi, dword ptr [r15]; // r15 = esi (from above) + mov edx, 0xffffffff; + sub rsp, 128; + call edx; + mov rsi, r15; + add rsp, 128; + and rax, rax; + jnz label_33; + mov rax, r15; + mov qword ptr [esi], 0; + add rsi, EEL_F_SIZE; +label_33: + + +#else + mov ecx, 0xFFFFFFFF; // first parameter = context pointer + fld EEL_ASM_TYPE [eax]; + mov edx, 0xFFFFFFFF; + fadd EEL_ASM_TYPE [rdx]; + fistp dword ptr [esi]; + xor rdx, rdx; + mov edx, dword ptr [esi]; + mov edi, 0xffffffff; + sub rsp, 128; + call edi; + add rsp, 128; + and rax, rax; + jnz label_34; + mov rax, rsi; + mov qword ptr [esi], 0; + add esi, EEL_F_SIZE; +label_34: + +#endif + + +#else + mov edx, 0xFFFFFFFF; + fld EEL_ASM_TYPE [eax]; +#if EEL_F_SIZE == 8 +_emit 0xDC; // fadd qword ptr [0xffffffff] +_emit 0x05; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#else +_emit 0xD8; // fadd dword ptr [0xffffffff] +_emit 0x05; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +_emit 0xFF; +#endif + fistp dword ptr [esi]; + sub esp, 8; // keep stack aligned + push dword ptr [esi]; // parameter + push edx; // push context pointer + mov edi, 0xffffffff; + call edi; + add esp, 16; + and eax, eax; + jnz label_35; + mov eax, esi; + mov dword ptr [esi], 0; +#if EEL_F_SIZE == 8 + mov dword ptr [esi+4], 0; +#endif + add esi, EEL_F_SIZE; +label_35: + + + +#endif + +RESTORE_STACK + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} + +__declspec(naked) void _asm_megabuf_end(void) {} + + +#ifdef TARGET_X64 +__declspec(naked) void win64_callcode() +{ + __asm { +#ifdef AMD64ABI + mov eax, edi; +#else + mov eax, ecx; +#endif + + push rbx; + push rbp; +#ifndef AMD64ABI + push rdi; + push rsi; + push r12; + push r13; +#endif + push r14; // on AMD64ABI, we'll use r14/r15 to save edi/esi + push r15; + call eax; + pop r15; + pop r14; +#ifndef AMD64ABI + pop r13; + pop r12; + pop rsi; + pop rdi; + fclex; +#endif + pop rbp; + pop rbx; + ret; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} + +#endif diff --git a/ns-eel2/ns-eel-addfuncs.h b/ns-eel2/ns-eel-addfuncs.h new file mode 100644 index 0000000..e653e0a --- /dev/null +++ b/ns-eel2/ns-eel-addfuncs.h @@ -0,0 +1,74 @@ +/* + Nullsoft Expression Evaluator Library (NS-EEL) + Copyright (C) 1999-2003 Nullsoft, Inc. + + ns-eel-addfuncs.h: defines macros useful for adding functions to the compiler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef __NS_EEL_ADDFUNCS_H__ +#define __NS_EEL_ADDFUNCS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct _compileContext; +typedef void (*NSEEL_PPPROC)(void *data, int data_size, struct _compileContext *userfunc_data); + +void NSEEL_PProc_RAM(void *data, int data_size, struct _compileContext *ctx); +void NSEEL_PProc_THIS(void *data, int data_size, struct _compileContext *ctx); + + +void _asm_generic3parm(void); // 3 double * parms, returning double * +void _asm_generic3parm_end(void); +void _asm_generic3parm_retd(void); // 3 double * parms, returning double +void _asm_generic3parm_retd_end(void); +void _asm_generic2parm(void); // 2 double * parms, returning double * +void _asm_generic2parm_end(void); +void _asm_generic2parm_retd(void); // 2 double * parms, returning double +void _asm_generic2parm_retd_end(void); +void _asm_generic1parm(void); // 1 double * parms, returning double * +void _asm_generic1parm_end(void); +void _asm_generic1parm_retd(void); // 1 double * parms, returning double +void _asm_generic1parm_retd_end(void); + +void _asm_megabuf(void); +void _asm_megabuf_end(void); + + + +#if EEL_F_SIZE == 4 +#define EEL_F_SSTR "4" +#define EEL_F_SUFFIX "s" +#else +#define EEL_F_SSTR "8" +#define EEL_F_SUFFIX "l" +#endif + +#ifdef _MSC_VER +#define NSEEL_CGEN_CALL __cdecl +#else +#define NSEEL_CGEN_CALL +#endif + +#ifdef __cplusplus +}; + +#endif +#endif//__NS_EEL_ADDFUNCS_H__ diff --git a/ns-eel2/ns-eel-int.h b/ns-eel2/ns-eel-int.h new file mode 100644 index 0000000..3718604 --- /dev/null +++ b/ns-eel2/ns-eel-int.h @@ -0,0 +1,227 @@ +/* + Nullsoft Expression Evaluator Library (NS-EEL) + Copyright (C) 1999-2003 Nullsoft, Inc. + + ns-eel-int.h: internal code definition header. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef __NS_EELINT_H__ +#define __NS_EELINT_H__ + +#ifdef _WIN32 +#include +#else +#include "../wdltypes.h" +#endif + +#include "ns-eel.h" +#include "ns-eel-addfuncs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FN_ASSIGN 0 +#define FN_MULTIPLY 1 +#define FN_DIVIDE 2 +#define FN_MODULO 3 +#define FN_ADD 4 +#define FN_SUB 5 +#define FN_AND 6 +#define FN_OR 7 +#define FN_UMINUS 8 +#define FN_UPLUS 9 + +#define MATH_SIMPLE 0 +#define MATH_FN 1 + +#define YYSTYPE INT_PTR + +#define NSEEL_CLOSEFACTOR 0.00001 + +typedef struct +{ + int srcByteCount; + int destByteCount; +} lineRecItem; + +typedef struct _compileContext +{ + EEL_F **varTable_Values; + char **varTable_Names; + int varTable_numBlocks; + + int errVar; + int colCount; + INT_PTR result; + char last_error_string[256]; + YYSTYPE yylval; + int yychar; /* the lookahead symbol */ + int yynerrs; /* number of parse errors so far */ + char yytext[256]; + char lastVar[256]; + + char *llsave[16]; /* Look ahead buffer */ + char llbuf[100]; /* work buffer */ + char *llp1;// = &llbuf[0]; /* pointer to next avail. in token */ + char *llp2;// = &llbuf[0]; /* pointer to end of lookahead */ + char *llend;// = &llbuf[0]; /* pointer to end of token */ + char *llebuf;// = &llbuf[sizeof llbuf]; + int lleof; + int yyline;// = 0; + + void *tmpblocks_head,*blocks_head; + int computTableTop; // make it abort on potential overflow =) + int l_stats[4]; // source bytes, static code bytes, call code bytes, data bytes + + lineRecItem *compileLineRecs; + int compileLineRecs_size; + int compileLineRecs_alloc; + + void *ram_blocks; // this needs to be immediately followed by + int ram_needfree; + + void *gram_blocks; + + void *caller_this; +} +compileContext; + +#define NSEEL_VARS_PER_BLOCK 64 + +typedef struct { + const char *name; + void *afunc; + void *func_e; + int nParams; + void *replptrs[4]; + NSEEL_PPPROC pProc; +} functionType; + + +extern functionType *nseel_getFunctionFromTable(int idx); + +INT_PTR nseel_createCompiledValue(compileContext *ctx, EEL_F value, EEL_F *addrValue); +INT_PTR nseel_createCompiledFunction1(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code); +INT_PTR nseel_createCompiledFunction2(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code1, INT_PTR code2); +INT_PTR nseel_createCompiledFunction3(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code1, INT_PTR code2, INT_PTR code3); + +extern EEL_F nseel_globalregs[100]; + +void nseel_resetVars(compileContext *ctx); +EEL_F *nseel_getVarPtr(compileContext *ctx, char *varName); +EEL_F *nseel_registerVar(compileContext *ctx, char *varName); + +INT_PTR *EEL_GLUE_set_immediate(void *_p, void *newv); + +// other shat + + + +INT_PTR nseel_setVar(compileContext *ctx, INT_PTR varNum); +INT_PTR nseel_getVar(compileContext *ctx, INT_PTR varNum); +void *nseel_compileExpression(compileContext *ctx, char *txt); + +#define VALUE 258 +#define IDENTIFIER 259 +#define FUNCTION1 260 +#define FUNCTION2 261 +#define FUNCTION3 262 +#define UMINUS 263 +#define UPLUS 264 + +INT_PTR nseel_translate(compileContext *ctx, int type); +void nseel_count(compileContext *ctx); +void nseel_setLastVar(compileContext *ctx); +INT_PTR nseel_lookup(compileContext *ctx, int *typeOfObject); +int nseel_yyerror(compileContext *ctx); +int nseel_yylex(compileContext *ctx, char **exp); +int nseel_yyparse(compileContext *ctx, char *exp); +void nseel_llinit(compileContext *ctx); +int nseel_gettoken(compileContext *ctx, char *lltb, int lltbsiz); + +struct lextab { + int llendst; /* Last state number */ + char *lldefault; /* Default state table */ + char *llnext; /* Next state table */ + char *llcheck; /* Check table */ + int *llbase; /* Base table */ + int llnxtmax; /* Last in next table */ + int (*llmove)(); /* Move between states */ + char *llfinal; /* Final state descriptions */ + int (*llactr)(); /* Action routine */ + int *lllook; /* Look ahead vector if != NULL */ + char *llign; /* Ignore char vec if != NULL */ + char *llbrk; /* Break char vec if != NULL */ + char *llill; /* Illegal char vec if != NULL */ +}; +extern struct lextab nseel_lextab; + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAMAlloc(EEL_F ***blocks, int w); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAMAllocGMEM(EEL_F ***blocks, int w); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemSet(EEL_F ***blocks,EEL_F *dest, EEL_F *v, EEL_F *lenptr); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemFree(EEL_F ***blocks, EEL_F *which); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemCpy(EEL_F ***blocks,EEL_F *dest, EEL_F *src, EEL_F *lenptr); + + + +#ifndef max +#define max(x,y) ((x)<(y)?(y):(x)) +#define min(x,y) ((x)<(y)?(x):(y)) +#endif + + + +#ifdef __ppc__ + + #define EEL_F2int(x) ((int)(x)) + +#elif defined (_WIN64) + + // todo: AMD64 version? + #define EEL_F2int(x) ((int)(x)) + +#elif defined(_MSC_VER) + +static __inline int EEL_F2int(EEL_F d) +{ + int tmp; + __asm { + fld d + fistp tmp + } + return tmp; +} + +#else + +static inline int EEL_F2int(EEL_F d) +{ + int tmp; + __asm__ __volatile__ ("fistpl %0" : "=m" (tmp) : "t" (d) : "st") ; + return tmp; +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif//__NS_EELINT_H__ diff --git a/ns-eel2/ns-eel.h b/ns-eel2/ns-eel.h new file mode 100644 index 0000000..cb56137 --- /dev/null +++ b/ns-eel2/ns-eel.h @@ -0,0 +1,155 @@ +/* + Nullsoft Expression Evaluator Library (NS-EEL) + Copyright (C) 1999-2003 Nullsoft, Inc. + + ns-eel.h: main application interface header + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef __NS_EEL_H__ +#define __NS_EEL_H__ + +// put standard includes here +#include +#include + +#ifdef _MSC_VER +#define strcasecmp stricmp +#define strncasecmp _strnicmp +#endif + +#ifndef EEL_F_SIZE +#define EEL_F_SIZE 8 +#endif + +#if EEL_F_SIZE == 4 +typedef float EEL_F; +#else +typedef double EEL_F; +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +// host should implement these (can be empty stub functions if no VM will execute code in multiple threads at once) + + // implement if you will be running the code in same VM from multiple threads, + // or VMs that have the same GRAM pointer from different threads, or multiple + // VMs that have a NULL GRAM pointer from multiple threads. + // if you give each VM it's own unique GRAM and only run each VM in one thread, then you can leave it blank. + + // or if you're daring.... + +void NSEEL_HOSTSTUB_EnterMutex(); +void NSEEL_HOSTSTUB_LeaveMutex(); + + +int NSEEL_init(); // returns 0 on success. clears any added functions as well + +#define NSEEL_addfunction(name,nparms,code,len) NSEEL_addfunctionex((name),(nparms),(code),(len),0,0) +#define NSEEL_addfunctionex(name,nparms,code,len,pproc,fptr) NSEEL_addfunctionex2((name),(nparms),(code),(len),(pproc),(fptr),0) +void NSEEL_addfunctionex2(const char *name, int nparms, char *code_startaddr, int code_len, void *pproc, void *fptr, void *fptr2); + +void NSEEL_quit(); + +int *NSEEL_getstats(); // returns a pointer to 5 ints... source bytes, static code bytes, call code bytes, data bytes, number of code handles +EEL_F *NSEEL_getglobalregs(); + +typedef void *NSEEL_VMCTX; +typedef void *NSEEL_CODEHANDLE; + +NSEEL_VMCTX NSEEL_VM_alloc(); // return a handle +void NSEEL_VM_free(NSEEL_VMCTX ctx); // free when done with a VM and ALL of its code have been freed, as well + +void NSEEL_VM_enumallvars(NSEEL_VMCTX ctx, int (*func)(const char *name, EEL_F *val, void *ctx), void *userctx); // return false from func to stop +void NSEEL_VM_resetvars(NSEEL_VMCTX ctx); // clears all vars to 0.0. + +EEL_F *NSEEL_VM_regvar(NSEEL_VMCTX ctx, const char *name); // register a variable (before compilation) + +void NSEEL_VM_freeRAM(NSEEL_VMCTX ctx); // clears and frees all (VM) RAM used +void NSEEL_VM_freeRAMIfCodeRequested(NSEEL_VMCTX); // call after code to free the script-requested memory +int NSEEL_VM_wantfreeRAM(NSEEL_VMCTX ctx); // want NSEEL_VM_freeRAMIfCodeRequested? + +// if you set this, it uses a local GMEM context. +// Must be set before compilation. +// void *p=NULL; +// NSEEL_VM_SetGRAM(ctx,&p); +// .. do stuff +// NSEEL_VM_FreeGRAM(&p); +void NSEEL_VM_SetGRAM(NSEEL_VMCTX ctx, void **gram); +void NSEEL_VM_FreeGRAM(void **ufd); // frees a gmem context. +void NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx, void *thisptr); + + + // note that you shouldnt pass a C string directly, since it may need to + // fudge with the string during the compilation (it will always restore it to the + // original value though). +#ifdef __cplusplus +NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX ctx, char *code, int lineoffs=0); +#else +NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX ctx, char *code, int lineoffs); +#endif + +char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx); +void NSEEL_code_execute(NSEEL_CODEHANDLE code); +void NSEEL_code_free(NSEEL_CODEHANDLE code); +int *NSEEL_code_getstats(NSEEL_CODEHANDLE code); // 4 ints...source bytes, static code bytes, call code bytes, data bytes + + +// global memory control/view +extern unsigned int NSEEL_RAM_limitmem; // if nonzero, memory limit for user data, in bytes +extern unsigned int NSEEL_RAM_memused; +extern int NSEEL_RAM_memused_errors; + + + +// configuration: + +#define NSEEL_MAX_VARIABLE_NAMELEN 16 +// define this to override the max variable length (default is 16 bytes) + +//#define NSEEL_MAX_TEMPSPACE_ENTRIES 2048 +// define this to override the maximum working space in 8 byte units. +// 2048 is the default, and is way more than enough for most applications +// but in theory you might be able to come up with an expression big enough? maybe? + + +// maximum loop length +#define NSEEL_LOOPFUNC_SUPPORT_MAXLEN 1048576 // scary, we can do a million entries. probably will never want to, though. +#define NSEEL_LOOPFUNC_SUPPORT_MAXLEN_STR "1048576" + + + +// when a VM ctx doesn't have a GRAM context set, make the global one this big +#define NSEEL_SHARED_GRAM_SIZE (1<<20) + +// 128*65536 = ~8million entries. (64MB RAM used) +#define NSEEL_RAM_BLOCKS 128 +#define NSEEL_RAM_ITEMSPERBLOCK 65536 + + + + +#ifdef __cplusplus +} +#endif + +#endif//__NS_EEL_H__ diff --git a/ns-eel2/nseel-caltab.c b/ns-eel2/nseel-caltab.c new file mode 100644 index 0000000..1d8a6d3 --- /dev/null +++ b/ns-eel2/nseel-caltab.c @@ -0,0 +1,553 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2008 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-caltab.c + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "ns-eel-int.h" + +#define VALUE 258 +#define IDENTIFIER 259 +#define FUNCTION1 260 +#define FUNCTION2 261 +#define FUNCTION3 262 +#define UMINUS 263 +#define UPLUS 264 + +#define YYERROR(x) nseel_yyerror(ctx) + +#define YYFINAL 51 +#define YYFLAG -32768 +#define YYNTBASE 21 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 264 ? yytranslate[x] : 26) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 14, 9, 2, 18, + 19, 12, 10, 20, 11, 2, 13, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 17, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 8, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, + 6, 7, 15, 16 +}; + + +static const short yyr1[] = { 0, + 21, 21, 22, 23, 23, 23, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 25, 25, 25 +}; + +static const short yyr2[] = { 0, + 1, 3, 1, 1, 1, 3, 1, 3, 3, 3, + 3, 3, 3, 3, 2, 2, 1, 4, 6, 8 +}; + +static const short yydefact[] = { 0, + 3, 4, 0, 0, 0, 0, 0, 0, 5, 7, + 1, 17, 0, 0, 0, 0, 4, 16, 15, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 6, 14, 13, 11, 12, 8, 9, 10, 18, + 0, 0, 0, 0, 19, 0, 0, 20, 0, 0, + 0 +}; + +static const short yydefgoto[] = { 49, + 9, 10, 11, 12 +}; + +static const short yypact[] = { 19, +-32768, -11, -7, -5, -4, 38, 38, 38,-32768,-32768, + 136,-32768, 38, 38, 38, 38,-32768,-32768,-32768, 88, + 38, 38, 38, 38, 38, 38, 38, 136, 100, 49, + 62,-32768, 41, 54, -9, -9,-32768,-32768,-32768,-32768, + 38, 38, 112, 75,-32768, 38, 124,-32768, 12, 27, +-32768 +}; + +static const short yypgoto[] = {-32768, +-32768,-32768, -6,-32768 +}; + + +#define YYLAST 150 + + +static const short yytable[] = { 18, + 19, 20, 25, 26, 27, 13, 28, 29, 30, 31, + 14, 50, 15, 16, 33, 34, 35, 36, 37, 38, + 39, 1, 2, 3, 4, 5, 51, 0, 6, 7, + 0, 0, 0, 0, 43, 44, 8, 0, 0, 47, + 1, 17, 3, 4, 5, 0, 0, 6, 7, 22, + 23, 24, 25, 26, 27, 8, 21, 22, 23, 24, + 25, 26, 27, 23, 24, 25, 26, 27, 41, 21, + 22, 23, 24, 25, 26, 27, 0, 0, 0, 0, + 0, 42, 21, 22, 23, 24, 25, 26, 27, 0, + 0, 0, 0, 0, 46, 21, 22, 23, 24, 25, + 26, 27, 0, 0, 0, 0, 32, 21, 22, 23, + 24, 25, 26, 27, 0, 0, 0, 0, 40, 21, + 22, 23, 24, 25, 26, 27, 0, 0, 0, 0, + 45, 21, 22, 23, 24, 25, 26, 27, 0, 0, + 0, 0, 48, 21, 22, 23, 24, 25, 26, 27 +}; + +static const short yycheck[] = { 6, + 7, 8, 12, 13, 14, 17, 13, 14, 15, 16, + 18, 0, 18, 18, 21, 22, 23, 24, 25, 26, + 27, 3, 4, 5, 6, 7, 0, -1, 10, 11, + -1, -1, -1, -1, 41, 42, 18, -1, -1, 46, + 3, 4, 5, 6, 7, -1, -1, 10, 11, 9, + 10, 11, 12, 13, 14, 18, 8, 9, 10, 11, + 12, 13, 14, 10, 11, 12, 13, 14, 20, 8, + 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, + -1, 20, 8, 9, 10, 11, 12, 13, 14, -1, + -1, -1, -1, -1, 20, 8, 9, 10, 11, 12, + 13, 14, -1, -1, -1, -1, 19, 8, 9, 10, + 11, 12, 13, 14, -1, -1, -1, -1, 19, 8, + 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, + 19, 8, 9, 10, 11, 12, 13, 14, -1, -1, + -1, -1, 19, 8, 9, 10, 11, 12, 13, 14 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (ctx->yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#define YYLEX nseel_yylex(ctx,&exp) + +/* If nonreentrant, generate the variables here */ + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#define YYINITDEPTH 5000 +#define YYMAXDEPTH 5000 + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +#define __yy_bcopy(from,to,count) memcpy(to,from,(count)>0?(count):0) + +//#ln 131 "bison.simple" +int nseel_yyparse(compileContext *ctx, char *exp) +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + + int yystacksize = YYINITDEPTH; + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + + ctx->yylval = 0; + yystate = 0; + yyerrstatus = 0; + ctx->yynerrs = 0; + ctx->yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. */ + + yyssp = yyss - 1; + yyvsp = yyvs; + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ +// YYSTYPE *yyvs1 = yyvs; + // short *yyss1 = yyss; + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + + if (yystacksize >= YYMAXDEPTH) + { + YYERROR("internal error: parser stack overflow"); + return 2; + } + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; + + + if (yyssp >= yyss + yystacksize - 1) YYABORT; + } + + +// yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (ctx->yychar == YYEMPTY) + { +// yyStackSize = yyssp - (yyss - 1); + ctx->yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (ctx->yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + ctx->yychar = YYEOF; /* Don't call YYLEX any more */ + + } + else + { + yychar1 = YYTRANSLATE(ctx->yychar); + + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + + + /* Discard the token being shifted unless it is eof. */ + if (ctx->yychar != YYEOF) + ctx->yychar = YYEMPTY; + + *++yyvsp = ctx->yylval; + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + + + switch (yyn) { + +case 1: +//#ln 32 "cal.y" +{ yyval = yyvsp[0]; ctx->result = yyvsp[0]; ; + break;} +case 2: +//#ln 34 "cal.y" +{ { + YYSTYPE i = nseel_setVar(ctx,yyvsp[-2]); + YYSTYPE v=nseel_getVar(ctx,i); + + yyval = nseel_createCompiledFunction2(ctx,MATH_SIMPLE, FN_ASSIGN, v, yyvsp[0]); + ctx->result = yyval; + } + ; + break;} +case 3: +//#ln 50 "cal.y" +{ yyval = yyvsp[0] ; + break;} +case 4: +//#ln 55 "cal.y" +{ yyval = nseel_getVar(ctx,yyvsp[0]);; + break;} +case 5: +//#ln 57 "cal.y" +{ yyval = yyvsp[0];; + break;} +case 6: +//#ln 59 "cal.y" +{ yyval = yyvsp[-1];; + break;} +case 7: +//#ln 64 "cal.y" +{ yyval = yyvsp[0]; ; + break;} +case 8: +//#ln 66 "cal.y" +{ yyval = nseel_createCompiledFunction2(ctx,MATH_SIMPLE, FN_MULTIPLY, yyvsp[-2], yyvsp[0]); + break;} +case 9: +//#ln 72 "cal.y" +{ yyval = nseel_createCompiledFunction2(ctx,MATH_SIMPLE, FN_DIVIDE, yyvsp[-2], yyvsp[0]); + break;} +case 10: +//#ln 78 "cal.y" +{ yyval = nseel_createCompiledFunction2(ctx,MATH_SIMPLE, FN_MODULO, yyvsp[-2], yyvsp[0]); + break;} +case 11: +//#ln 84 "cal.y" +{ yyval = nseel_createCompiledFunction2(ctx,MATH_SIMPLE, FN_ADD, yyvsp[-2], yyvsp[0]); + break;} +case 12: +//#ln 90 "cal.y" +{ yyval = nseel_createCompiledFunction2(ctx,MATH_SIMPLE, FN_SUB, yyvsp[-2], yyvsp[0]); + break;} +case 13: +//#ln 96 "cal.y" +{ yyval = nseel_createCompiledFunction2(ctx,MATH_SIMPLE, FN_AND, yyvsp[-2], yyvsp[0]); + break;} +case 14: +//#ln 102 "cal.y" +{ yyval = nseel_createCompiledFunction2(ctx,MATH_SIMPLE, FN_OR, yyvsp[-2], yyvsp[0]); + break;} +case 15: +//#ln 108 "cal.y" +{ yyval = nseel_createCompiledFunction1(ctx,MATH_SIMPLE, FN_UMINUS, yyvsp[0]); + break;} +case 16: +//#ln 114 "cal.y" +{ yyval = nseel_createCompiledFunction1(ctx,MATH_SIMPLE, FN_UPLUS, yyvsp[0]); + break;} +case 17: +//#ln 120 "cal.y" +{ yyval = yyvsp[0]; + break;} +case 18: +//#ln 125 "cal.y" +{ yyval = nseel_createCompiledFunction1(ctx,MATH_FN, yyvsp[-3], yyvsp[-1]); + break;} +case 19: +//#ln 131 "cal.y" +{ yyval = nseel_createCompiledFunction2(ctx,MATH_FN, yyvsp[-5], yyvsp[-3], yyvsp[-1]); + break;} +case 20: +//#ln 137 "cal.y" +{ yyval = nseel_createCompiledFunction3(ctx,MATH_FN, yyvsp[-7], yyvsp[-5], yyvsp[-3], yyvsp[-1]); + break;} +} + /* the action file gets copied in in place of this dollarsign */ +//#ln 362 "bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; + + *++yyvsp = yyval; + + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++ctx->yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; +#error this should not compile + msg = (char *) xmalloc(size + 15); + strcpy(msg, "syntax error"); + + if (count < 5) + { + count = 0; + for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + YYERROR(msg); + free(msg); + } + else +#endif /* YYERROR_VERBOSE */ + YYERROR("syntax error"); + } + +//yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (ctx->yychar == YYEOF) YYABORT; + + ctx->yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; + + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = ctx->yylval; + + yystate = yyn; + goto yynewstate; +} diff --git a/ns-eel2/nseel-cfunc.c b/ns-eel2/nseel-cfunc.c new file mode 100644 index 0000000..57cb7c0 --- /dev/null +++ b/ns-eel2/nseel-cfunc.c @@ -0,0 +1,131 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2008 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-cfunc.c: assembly/C implementation of operator/function templates + This file should be ideally compiled with optimizations towards "minimize size" + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "ns-eel-int.h" +#include +#include + + + +// these are used by our assembly code + + +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +static unsigned int genrand_int32(void) +{ + + unsigned int y; + static unsigned int mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + static unsigned int mt[N]; /* the array for the state vector */ + static int mti; /* mti==N+1 means mt[N] is not initialized */ + + + if (!mti) + { + unsigned int s=0x4141f00d; + mt[0]= s & 0xffffffffUL; + for (mti=1; mti> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } + } + + if (mti >= N) { /* generate N words at one time */ + int kk; + + for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; + } + for (;kk> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + + + +//--------------------------------------------------------------------------------------------------------------- +EEL_F NSEEL_CGEN_CALL nseel_int_rand(EEL_F *f) +{ + EEL_F x=floor(*f); + if (x < 1.0) x=1.0; + +#ifdef NSEEL_EEL1_COMPAT_MODE + return (EEL_F)(genrand_int32()%(int)x); +#else + return (EEL_F) (genrand_int32()*(1.0/(double)0xFFFFFFFF)*x); +#endif +// return (EEL_F)(rand()%EEL_F2int(x)); +} + +//--------------------------------------------------------------------------------------------------------------- + + + +#ifdef __ppc__ +#include "asm-nseel-ppc-gcc.c" +#else + #ifdef _MSC_VER + #ifdef _WIN64 + //nasm + #else + #include "asm-nseel-x86-msvc.c" + #endif + #elif !defined(__LP64__) + #include "asm-nseel-x86-gcc.c" + #endif +#endif + diff --git a/ns-eel2/nseel-compiler.c b/ns-eel2/nseel-compiler.c new file mode 100644 index 0000000..bb34673 --- /dev/null +++ b/ns-eel2/nseel-compiler.c @@ -0,0 +1,1791 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2008 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-compiler.c + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +// for VirtualProtect + +#include "ns-eel-int.h" + + +#include +#include +#include +#include + +#ifndef _WIN64 + #ifndef __ppc__ + #include + #endif +#endif + +#ifdef __APPLE__ + #ifdef __LP64__ + #define EEL_USE_MPROTECT + #endif +#endif + +#ifdef EEL_USE_MPROTECT +#include +#include +#include +#endif + +#ifdef NSEEL_EEL1_COMPAT_MODE + +#ifndef EEL_NO_CHANGE_FPFLAGS +#define EEL_NO_CHANGE_FPFLAGS +#endif + +#endif + +#ifndef _WIN64 +#if !defined(_RC_CHOP) && !defined(EEL_NO_CHANGE_FPFLAGS) + +#include +#define _RC_CHOP _FPU_RC_ZERO +#define _MCW_RC _FPU_RC_ZERO +static unsigned int _controlfp(unsigned int val, unsigned int mask) +{ + unsigned int ret; + _FPU_GETCW(ret); + if (mask) + { + ret&=~mask; + ret|=val; + _FPU_SETCW(ret); + } + return ret; +} + +#endif +#endif + + +#ifdef __ppc__ + +#define GLUE_MOV_EAX_DIRECTVALUE_SIZE 8 +static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, INT_PTR v) +{ + unsigned int uv=(unsigned int)v; + unsigned short *p=(unsigned short *)b; + + *p++ = 0x3C60; // addis r3, r0, hw + *p++ = (uv>>16)&0xffff; + *p++ = 0x6063; // ori r3, r3, lw + *p++ = uv&0xffff; +} + + +// mflr r5 +// stwu r5, -4(r1) +const static unsigned int GLUE_FUNC_ENTER[2] = { 0x7CA802A6, 0x94A1FFFC }; + +// lwz r5, 0(r1) +// addi r1, r1, 4 +// mtlr r5 +const static unsigned int GLUE_FUNC_LEAVE[3] = { 0x80A10000, 0x38210004, 0x7CA803A6 }; +#define GLUE_FUNC_ENTER_SIZE sizeof(GLUE_FUNC_ENTER) +#define GLUE_FUNC_LEAVE_SIZE sizeof(GLUE_FUNC_LEAVE) + +const static unsigned int GLUE_RET[]={0x4E800020}; // blr + +const static unsigned int GLUE_MOV_ESI_EDI=0x7E308B78; // mr r16, r17 + +static int GLUE_RESET_ESI(char *out, void *ptr) +{ + if (out) memcpy(out,&GLUE_MOV_ESI_EDI,sizeof(GLUE_MOV_ESI_EDI)); + return sizeof(GLUE_MOV_ESI_EDI); + +} + + + +// stwu r3, -4(r1) +const static unsigned int GLUE_PUSH_EAX[1]={ 0x9461FFFC}; + +// lwz r14, 0(r1) +// addi r1, r1, 4 +const static unsigned int GLUE_POP_EBX[2]={ 0x81C10000, 0x38210004, }; + +// lwz r15, 0(r1) +// addi r1, r1, 4 +const static unsigned int GLUE_POP_ECX[2]={ 0x81E10000, 0x38210004 }; + + +static void GLUE_CALL_CODE(INT_PTR bp, INT_PTR cp) +{ + __asm__( + "stmw r14, -80(r1)\n" + "mtctr %0\n" + "mr r17, %1\n" + "subi r17, r17, 8\n" + "mflr r5\n" + "stw r5, -84(r1)\n" + "subi r1, r1, 88\n" + "bctrl\n" + "addi r1, r1, 88\n" + "lwz r5, -84(r1)\n" + "lmw r14, -80(r1)\n" + "mtlr r5\n" + ::"r" (cp), "r" (bp)); +}; + +INT_PTR *EEL_GLUE_set_immediate(void *_p, void *newv) +{ +// todo 64 bit ppc will take some work + unsigned int *p=(unsigned int *)_p; + while ((p[0]&0x0000FFFF) != 0x0000dead && + (p[1]&0x0000FFFF) != 0x0000beef) p++; + p[0] = (p[0]&0xFFFF0000) | (((unsigned int)newv)>>16); + p[1] = (p[1]&0xFFFF0000) | (((unsigned int)newv)&0xFFFF); + + return (INT_PTR*)++p; +} + + +#else + +//x86 specific code + +#define GLUE_FUNC_ENTER_SIZE 0 +#define GLUE_FUNC_LEAVE_SIZE 0 +const static unsigned int GLUE_FUNC_ENTER[1]; +const static unsigned int GLUE_FUNC_LEAVE[1]; + +#if defined(_WIN64) || defined(__LP64__) +#define GLUE_MOV_EAX_DIRECTVALUE_SIZE 10 +static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, INT_PTR v) { + unsigned short *bb = (unsigned short *)b; + *bb++ =0xB848; + *(INT_PTR *)bb = v; +} +const static unsigned char GLUE_PUSH_EAX[2]={ 0x50,0x50}; // push rax ; push rax (push twice to preserve alignment) +const static unsigned char GLUE_POP_EBX[2]={0x5F, 0x5f}; //pop rdi ; twice +const static unsigned char GLUE_POP_ECX[2]={0x59, 0x59 }; // pop rcx ; twice +#else +#define GLUE_MOV_EAX_DIRECTVALUE_SIZE 5 +static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, int v) +{ + *((unsigned char *)b) =0xB8; + b= ((unsigned char *)b)+1; + *(int *)b = v; +} +const static unsigned char GLUE_PUSH_EAX[4]={0x83, 0xEC, 12, 0x50}; // sub esp, 12, push eax +const static unsigned char GLUE_POP_EBX[4]={0x5F, 0x83, 0xC4, 12}; //pop ebx, add esp, 12 // DI=5F, BX=0x5B; +const static unsigned char GLUE_POP_ECX[4]={0x59, 0x83, 0xC4, 12}; // pop ecx, add esp, 12 + +#endif + +//const static unsigned short GLUE_MOV_ESI_EDI=0xF78B; +const static unsigned char GLUE_RET=0xC3; + +static int GLUE_RESET_ESI(unsigned char *out, void *ptr) +{ +#if defined(_WIN64) || defined(__LP64__) + if (out) + { + *out++ = 0x48; + *out++ = 0xBE; // mov rsi, constant64 + *(void **)out = ptr; + out+=sizeof(void *); + } + return 2+sizeof(void *); +#else + if (out) + { + *out++ = 0xBE; // mov esi, constant + memcpy(out,&ptr,sizeof(void *)); + out+=sizeof(void *); + } + return 1+sizeof(void *); +#endif +} + +static void GLUE_CALL_CODE(INT_PTR bp, INT_PTR cp) +{ + #if defined(_WIN64) || defined(__LP64__) + extern void win64_callcode(INT_PTR code); + win64_callcode(cp); + #else // non-64 bit + #ifdef _MSC_VER + #ifndef EEL_NO_CHANGE_FPFLAGS + unsigned int old_v=_controlfp(0,0); + _controlfp(_RC_CHOP,_MCW_RC); + #endif + + __asm + { + mov eax, cp + pushad + call eax + popad + }; + + #ifndef EEL_NO_CHANGE_FPFLAGS + _controlfp(old_v,_MCW_RC); + #endif + +#else // gcc x86 + #ifndef EEL_NO_CHANGE_FPFLAGS + unsigned int old_v=_controlfp(0,0); + _controlfp(_RC_CHOP,_MCW_RC); + #endif + __asm__("call *%%eax"::"a" (cp): "%ecx","%edx","%esi","%edi"); + #ifndef EEL_NO_CHANGE_FPFLAGS + _controlfp(old_v,_MCW_RC); + #endif + #endif //gcc x86 + #endif // 32bit +} + +INT_PTR *EEL_GLUE_set_immediate(void *_p, void *newv) +{ + char *p=(char*)_p; + while (*(INT_PTR *)p != ~(INT_PTR)0) p++; + *(INT_PTR *)p = (INT_PTR)newv; + return ((INT_PTR*)p)+1; +} + +#endif + + +static void *GLUE_realAddress(void *fn, void *fn_e, int *size) +{ +#if defined(_MSC_VER) || defined(__LP64__) + + unsigned char *p; + +#if defined(_DEBUG) && !defined(__LP64__) + if (*(unsigned char *)fn == 0xE9) // this means jump to the following address + { + fn = ((unsigned char *)fn) + *(int *)((char *)fn+1) + 5; + } +#endif + + // this may not work in debug mode + p=(unsigned char *)fn; + for (;;) + { + int a; + for (a=0;a<12;a++) + { + if (p[a] != (a?0x90:0x89)) break; + } + if (a>=12) + { + *size = (char *)p - (char *)fn; + // if (*size<0) MessageBox(NULL,"expect poof","a",0); + return fn; + } + p++; + } +#else + char *p=(char *)fn_e - sizeof(GLUE_RET); + if (p <= (char *)fn) *size=0; + else + { + while (p > (char *)fn && memcmp(p,&GLUE_RET,sizeof(GLUE_RET))) p-=sizeof(GLUE_RET); + *size = p - (char *)fn; + } + return fn; +#endif +} + + + +static int nseel_evallib_stats[5]; // source bytes, static code bytes, call code bytes, data bytes, segments +int *NSEEL_getstats() +{ + return nseel_evallib_stats; +} +EEL_F *NSEEL_getglobalregs() +{ + return nseel_globalregs; +} + +// this stuff almost works +static int findByteOffsetInSource(compileContext *ctx, int byteoffs,int *destoffs) +{ + int x; + if (!ctx->compileLineRecs || !ctx->compileLineRecs_size) return *destoffs=0; + if (byteoffs < ctx->compileLineRecs[0].destByteCount) + { + *destoffs=0; + return 1; + } + for (x = 0; x < ctx->compileLineRecs_size-1; x ++) + { + if (byteoffs >= ctx->compileLineRecs[x].destByteCount && + byteoffs < ctx->compileLineRecs[x+1].destByteCount) break; + } + *destoffs=ctx->compileLineRecs[(x&&x==ctx->compileLineRecs_size-1)?x-1:x].srcByteCount; + + return x+2; +} + + +static void onCompileNewLine(compileContext *ctx, int srcBytes, int destBytes) +{ + if (!ctx->compileLineRecs || ctx->compileLineRecs_size >= ctx->compileLineRecs_alloc) + { + ctx->compileLineRecs_alloc = ctx->compileLineRecs_size+1024; + ctx->compileLineRecs = (lineRecItem *)realloc(ctx->compileLineRecs,sizeof(lineRecItem)*ctx->compileLineRecs_alloc); + } + if (ctx->compileLineRecs) + { + ctx->compileLineRecs[ctx->compileLineRecs_size].srcByteCount=srcBytes; + ctx->compileLineRecs[ctx->compileLineRecs_size++].destByteCount=destBytes; + } +} + + + +#define LLB_DSIZE (65536-64) +typedef struct _llBlock { + struct _llBlock *next; + int sizeused; + char block[LLB_DSIZE]; +} llBlock; + +typedef struct _startPtr { + struct _startPtr *next; + void *startptr; +} startPtr; + +typedef struct { + void *workTable; + + llBlock *blocks; + void *code; + int code_stats[4]; +} codeHandleType; + +#ifndef NSEEL_MAX_TEMPSPACE_ENTRIES +#define NSEEL_MAX_TEMPSPACE_ENTRIES 2048 +#endif + +static void *__newBlock(llBlock **start,int size); + +#define newTmpBlock(x) __newTmpBlock((llBlock **)&ctx->tmpblocks_head,x) +#define newBlock(x,a) __newBlock_align(ctx,x,a) + +static void *__newTmpBlock(llBlock **start, int size) +{ + void *p=__newBlock(start,size+4); + if (p && size>=0) *((int *)p) = size; + return p; +} + +static void *__newBlock_align(compileContext *ctx, int size, int align) // makes sure block is aligned to 32 byte boundary, for code +{ + int a1=align-1; + char *p=(char*)__newBlock((llBlock **)&ctx->blocks_head,size+a1); + return p+((align-(((INT_PTR)p)&a1))&a1); +} + +static void freeBlocks(llBlock **start); + +#define DECL_ASMFUNC(x) \ + void nseel_asm_##x(void); \ + void nseel_asm_##x##_end(void); \ + + DECL_ASMFUNC(sin) + DECL_ASMFUNC(cos) + DECL_ASMFUNC(tan) + DECL_ASMFUNC(1pdd) + DECL_ASMFUNC(2pdd) + DECL_ASMFUNC(2pdds) + DECL_ASMFUNC(1pp) + DECL_ASMFUNC(2pp) + DECL_ASMFUNC(sqr) + DECL_ASMFUNC(sqrt) + DECL_ASMFUNC(log) + DECL_ASMFUNC(log10) + DECL_ASMFUNC(abs) + DECL_ASMFUNC(min) + DECL_ASMFUNC(max) + DECL_ASMFUNC(sig) + DECL_ASMFUNC(sign) + DECL_ASMFUNC(band) + DECL_ASMFUNC(bor) + DECL_ASMFUNC(bnot) + DECL_ASMFUNC(if) + DECL_ASMFUNC(repeat) + DECL_ASMFUNC(repeatwhile) + DECL_ASMFUNC(equal) + DECL_ASMFUNC(notequal) + DECL_ASMFUNC(below) + DECL_ASMFUNC(above) + DECL_ASMFUNC(beloweq) + DECL_ASMFUNC(aboveeq) + DECL_ASMFUNC(assign) + DECL_ASMFUNC(add) + DECL_ASMFUNC(sub) + DECL_ASMFUNC(add_op) + DECL_ASMFUNC(sub_op) + DECL_ASMFUNC(mul) + DECL_ASMFUNC(div) + DECL_ASMFUNC(mul_op) + DECL_ASMFUNC(div_op) + DECL_ASMFUNC(mod) + DECL_ASMFUNC(mod_op) + DECL_ASMFUNC(or) + DECL_ASMFUNC(and) + DECL_ASMFUNC(or_op) + DECL_ASMFUNC(and_op) + DECL_ASMFUNC(uplus) + DECL_ASMFUNC(uminus) + DECL_ASMFUNC(invsqrt) + DECL_ASMFUNC(exec2) + +static void NSEEL_PProc_GRAM(void *data, int data_size, compileContext *ctx) +{ + if (data_size>0) EEL_GLUE_set_immediate(data, ctx->gram_blocks); +} + + +static EEL_F g_signs[2]={1.0,-1.0}; +static EEL_F negativezeropointfive=-0.5f; +static EEL_F onepointfive=1.5f; +static EEL_F g_closefact = NSEEL_CLOSEFACTOR; +static const EEL_F eel_zero=0.0, eel_one=1.0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +static double __floor(double a) { return floor(a); } +#endif + +static double eel1band(double a, double b) +{ + return (fabs(a)>g_closefact && fabs(b) > g_closefact) ? 1.0 : 0.0; +} +static double eel1bor(double a, double b) +{ + return (fabs(a)>g_closefact || fabs(b) > g_closefact) ? 1.0 : 0.0; +} + +static double eel1sigmoid(double x, double constraint) +{ + double t = (1+exp(-x * (constraint))); + return fabs(t)>g_closefact ? 1.0/t : 0; +} + + +EEL_F NSEEL_CGEN_CALL nseel_int_rand(EEL_F *f); + +static functionType fnTable1[] = { + { "_if", nseel_asm_if,nseel_asm_if_end, 3, {&g_closefact} }, + { "_and", nseel_asm_band,nseel_asm_band_end, 2 } , + { "_or", nseel_asm_bor,nseel_asm_bor_end, 2 } , + { "loop", nseel_asm_repeat,nseel_asm_repeat_end, 2 }, + { "while", nseel_asm_repeatwhile,nseel_asm_repeatwhile_end, 1 }, + +#ifdef __ppc__ + { "_not", nseel_asm_bnot,nseel_asm_bnot_end, 1, {&g_closefact,&eel_zero,&eel_one} } , + { "_equal", nseel_asm_equal,nseel_asm_equal_end, 2, {&g_closefact,&eel_zero, &eel_one} }, + { "_noteq", nseel_asm_notequal,nseel_asm_notequal_end, 2, {&g_closefact,&eel_one,&eel_zero} }, + { "_below", nseel_asm_below,nseel_asm_below_end, 2, {&eel_zero, &eel_one} }, + { "_above", nseel_asm_above,nseel_asm_above_end, 2, {&eel_zero, &eel_one} }, + { "_beleq", nseel_asm_beloweq,nseel_asm_beloweq_end, 2, {&eel_zero, &eel_one} }, + { "_aboeq", nseel_asm_aboveeq,nseel_asm_aboveeq_end, 2, {&eel_zero, &eel_one} }, +#else + { "_not", nseel_asm_bnot,nseel_asm_bnot_end, 1, {&g_closefact} } , + { "_equal", nseel_asm_equal,nseel_asm_equal_end, 2, {&g_closefact} }, + { "_noteq", nseel_asm_notequal,nseel_asm_notequal_end, 2, {&g_closefact} }, + { "_below", nseel_asm_below,nseel_asm_below_end, 2 }, + { "_above", nseel_asm_above,nseel_asm_above_end, 2 }, + { "_beleq", nseel_asm_beloweq,nseel_asm_beloweq_end, 2 }, + { "_aboeq", nseel_asm_aboveeq,nseel_asm_aboveeq_end, 2 }, +#endif + + { "_set",nseel_asm_assign,nseel_asm_assign_end,2}, + { "_mod",nseel_asm_mod,nseel_asm_mod_end,2}, + { "_mulop",nseel_asm_mul_op,nseel_asm_mul_op_end,2}, + { "_divop",nseel_asm_div_op,nseel_asm_div_op_end,2}, + { "_orop",nseel_asm_or_op,nseel_asm_or_op_end,2}, + { "_andop",nseel_asm_and_op,nseel_asm_and_op_end,2}, + { "_addop",nseel_asm_add_op,nseel_asm_add_op_end,2}, + { "_subop",nseel_asm_sub_op,nseel_asm_sub_op_end,2}, + { "_modop",nseel_asm_mod_op,nseel_asm_mod_op_end,2}, + + +#ifdef __ppc__ + { "sin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&sin} }, + { "cos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&cos} }, + { "tan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&tan} }, +#else + { "sin", nseel_asm_sin,nseel_asm_sin_end, 1 }, + { "cos", nseel_asm_cos,nseel_asm_cos_end, 1 }, + { "tan", nseel_asm_tan,nseel_asm_tan_end, 1 }, +#endif + { "asin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&asin}, }, + { "acos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&acos}, }, + { "atan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&atan}, }, + { "atan2", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&atan2}, }, + { "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1 }, +#ifdef __ppc__ + { "sqrt", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&sqrt}, }, +#else + { "sqrt", nseel_asm_sqrt,nseel_asm_sqrt_end, 1 }, +#endif + { "pow", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&pow}, }, + { "_powop", nseel_asm_2pdds,nseel_asm_2pdds_end, 2, {&pow}, }, + { "exp", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&exp}, }, +#ifdef __ppc__ + { "log", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&log} }, + { "log10", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&log10} }, +#else + { "log", nseel_asm_log,nseel_asm_log_end, 1, }, + { "log10", nseel_asm_log10,nseel_asm_log10_end, 1, }, +#endif + { "abs", nseel_asm_abs,nseel_asm_abs_end, 1 }, + { "min", nseel_asm_min,nseel_asm_min_end, 2 }, + { "max", nseel_asm_max,nseel_asm_max_end, 2 }, +#ifdef __ppc__ + { "sign", nseel_asm_sign,nseel_asm_sign_end, 1, {&eel_zero}} , +#else + { "sign", nseel_asm_sign,nseel_asm_sign_end, 1, {&g_signs}} , +#endif + { "rand", nseel_asm_1pp,nseel_asm_1pp_end, 1, {&nseel_int_rand}, } , + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + { "floor", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&__floor} }, +#else + { "floor", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&floor} }, +#endif + { "ceil", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&ceil} }, +#ifdef __ppc__ + { "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1, }, +#else + { "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1, {&negativezeropointfive, &onepointfive} }, +#endif + + { "sigmoid", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1sigmoid}, }, + + // these differ from _and/_or, they always evaluate both... + { "band", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1band}, }, + { "bor", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1bor}, }, + + {"exec2",nseel_asm_exec2,nseel_asm_exec2_end,2}, + {"exec3",nseel_asm_exec2,nseel_asm_exec2_end,3}, + {"_mem",_asm_megabuf,_asm_megabuf_end,1,{&g_closefact,&__NSEEL_RAMAlloc},NSEEL_PProc_RAM}, + {"_gmem",_asm_megabuf,_asm_megabuf_end,1,{&g_closefact,&__NSEEL_RAMAllocGMEM},NSEEL_PProc_GRAM}, + {"freembuf",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemFree},NSEEL_PProc_RAM}, + {"memcpy",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemCpy},NSEEL_PProc_RAM}, + {"memset",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemSet},NSEEL_PProc_RAM}, +}; + +static functionType *fnTableUser; +static int fnTableUser_size; + +functionType *nseel_getFunctionFromTable(int idx) +{ + if (idx<0) return 0; + if (idx>=sizeof(fnTable1)/sizeof(fnTable1[0])) + { + idx -= sizeof(fnTable1)/sizeof(fnTable1[0]); + if (!fnTableUser || idx >= fnTableUser_size) return 0; + return fnTableUser+idx; + } + return fnTable1+idx; +} + +int NSEEL_init() // returns 0 on success +{ + NSEEL_quit(); + return 0; +} + +void NSEEL_addfunctionex2(const char *name, int nparms, char *code_startaddr, int code_len, void *pproc, void *fptr, void *fptr2) +{ + if (!fnTableUser || !(fnTableUser_size&7)) + { + fnTableUser=(functionType *)realloc(fnTableUser,(fnTableUser_size+8)*sizeof(functionType)); + } + if (fnTableUser) + { + memset(&fnTableUser[fnTableUser_size],0,sizeof(functionType)); + fnTableUser[fnTableUser_size].nParams = nparms; + fnTableUser[fnTableUser_size].name = name; + fnTableUser[fnTableUser_size].afunc = code_startaddr; + fnTableUser[fnTableUser_size].func_e = code_startaddr + code_len; + fnTableUser[fnTableUser_size].pProc = (NSEEL_PPPROC) pproc; + fnTableUser[fnTableUser_size].replptrs[0]=fptr; + fnTableUser[fnTableUser_size].replptrs[1]=fptr2; + fnTableUser_size++; + } +} + +void NSEEL_quit() +{ + free(fnTableUser); + fnTableUser_size=0; + fnTableUser=0; +} + +//--------------------------------------------------------------------------------------------------------------- +static void freeBlocks(llBlock **start) +{ + llBlock *s=*start; + *start=0; + while (s) + { + llBlock *llB = s->next; +#ifdef _WIN32 + VirtualFree(s, 0 /*LLB_DSIZE*/, MEM_RELEASE); +#else + free(s); +#endif + s=llB; + } +} + +//--------------------------------------------------------------------------------------------------------------- +static void *__newBlock(llBlock **start, int size) +{ + llBlock *llb; + int alloc_size; + if (*start && (LLB_DSIZE - (*start)->sizeused) >= size) + { + void *t=(*start)->block+(*start)->sizeused; + (*start)->sizeused+=(size+7)&~7; + return t; + } + + alloc_size=sizeof(llBlock); + if ((int)size > LLB_DSIZE) alloc_size += size - LLB_DSIZE; + +#ifdef _WIN32 + llb = (llBlock *)VirtualAlloc(NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + llb = (llBlock *)malloc(alloc_size); // grab bigger block if absolutely necessary (heh) +#endif +#if defined(EEL_USE_MPROTECT) + { + static int pagesize = 0; + if (!pagesize) + { + pagesize=sysconf(_SC_PAGESIZE); + if (!pagesize) pagesize=4096; + } + uintptr_t offs,eoffs; + offs=((uintptr_t)llb)&~(pagesize-1); + eoffs=((uintptr_t)llb + alloc_size + pagesize-1)&~(pagesize-1); + mprotect((void*)offs,eoffs-offs,PROT_WRITE|PROT_READ|PROT_EXEC); + } +#endif + llb->sizeused=(size+7)&~7; + llb->next = *start; + *start = llb; + return llb->block; +} + + +//--------------------------------------------------------------------------------------------------------------- +INT_PTR nseel_createCompiledValue(compileContext *ctx, EEL_F value, EEL_F *addrValue) +{ + unsigned char *block; + + block=(unsigned char *)newTmpBlock(GLUE_MOV_EAX_DIRECTVALUE_SIZE); + + if (addrValue == NULL) + { + *(addrValue = (EEL_F *)newBlock(sizeof(EEL_F),sizeof(EEL_F))) = value; + ctx->l_stats[3]+=sizeof(EEL_F); + } + + GLUE_MOV_EAX_DIRECTVALUE_GEN(block+4,(INT_PTR)addrValue); + + return ((INT_PTR)(block)); + +} + +//--------------------------------------------------------------------------------------------------------------- +static void *nseel_getFunctionAddress(int fntype, int fn, int *size, NSEEL_PPPROC *pProc, void ***replList) +{ + *replList=0; + switch (fntype) + { + case MATH_SIMPLE: + switch (fn) + { + case FN_ASSIGN: + return GLUE_realAddress(nseel_asm_assign,nseel_asm_assign_end,size); + case FN_ADD: + return GLUE_realAddress(nseel_asm_add,nseel_asm_add_end,size); + case FN_SUB: + return GLUE_realAddress(nseel_asm_sub,nseel_asm_sub_end,size); + case FN_MULTIPLY: + return GLUE_realAddress(nseel_asm_mul,nseel_asm_mul_end,size); + case FN_DIVIDE: + return GLUE_realAddress(nseel_asm_div,nseel_asm_div_end,size); + case FN_MODULO: + return GLUE_realAddress(nseel_asm_exec2,nseel_asm_exec2_end,size); + case FN_AND: + return GLUE_realAddress(nseel_asm_and,nseel_asm_and_end,size); + case FN_OR: + return GLUE_realAddress(nseel_asm_or,nseel_asm_or_end,size); + case FN_UPLUS: + return GLUE_realAddress(nseel_asm_uplus,nseel_asm_uplus_end,size); + case FN_UMINUS: + return GLUE_realAddress(nseel_asm_uminus,nseel_asm_uminus_end,size); + } + case MATH_FN: + { + functionType *p=nseel_getFunctionFromTable(fn); + if (p) + { + *replList=p->replptrs; + *pProc=p->pProc; + return GLUE_realAddress(p->afunc,p->func_e,size); + } + } + } + + *size=0; + return 0; +} + + +//--------------------------------------------------------------------------------------------------------------- +INT_PTR nseel_createCompiledFunction3(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code1, INT_PTR code2, INT_PTR code3) +{ + int sizes1=((int *)code1)[0]; + int sizes2=((int *)code2)[0]; + int sizes3=((int *)code3)[0]; + + if (fntype == MATH_FN && fn == 0) // special case: IF + { + void *func3; + int size; + INT_PTR *ptr; + char *block; + + unsigned char *newblock2,*newblock3; + unsigned char *p; + + p=newblock2=newBlock(sizes2+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32); + memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE; + memcpy(p,(char*)code2+4,sizes2); p+=sizes2; + memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE; + memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET); + + p=newblock3=newBlock(sizes3+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32); + memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE; + memcpy(p,(char*)code3+4,sizes3); p+=sizes3; + memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE; + memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET); + + ctx->l_stats[2]+=sizes2+sizes3+sizeof(GLUE_RET)*2; + + func3 = GLUE_realAddress(nseel_asm_if,nseel_asm_if_end,&size); + + block=(char *)newTmpBlock(sizes1+size); + + memcpy(block+4,(char*)code1+4,sizes1); + ptr=(INT_PTR *)(block+4+sizes1); + memcpy(ptr,func3,size); + + ptr=EEL_GLUE_set_immediate(ptr,&g_closefact); + ptr=EEL_GLUE_set_immediate(ptr,newblock2); + EEL_GLUE_set_immediate(ptr,newblock3); + + ctx->computTableTop++; + + return (INT_PTR)block; + + } + else + { + int size2; + unsigned char *block; + unsigned char *outp; + + void *myfunc; + NSEEL_PPPROC preProc=0; + void **repl; + + myfunc = nseel_getFunctionAddress(fntype, fn, &size2, &preProc,&repl); + + block=(unsigned char *)newTmpBlock(size2+sizes1+sizes2+sizes3+ + sizeof(GLUE_PUSH_EAX) + + sizeof(GLUE_PUSH_EAX) + + sizeof(GLUE_POP_EBX) + + sizeof(GLUE_POP_ECX)); + + outp=block+4; + memcpy(outp,(char*)code1+4,sizes1); + outp+=sizes1; + memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX); + memcpy(outp,(char*)code2+4,sizes2); + outp+=sizes2; + memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX); + memcpy(outp,(char*)code3+4,sizes3); + outp+=sizes3; + memcpy(outp,&GLUE_POP_EBX,sizeof(GLUE_POP_EBX)); outp+=sizeof(GLUE_POP_EBX); + memcpy(outp,&GLUE_POP_ECX,sizeof(GLUE_POP_ECX)); outp+=sizeof(GLUE_POP_ECX); + + memcpy(outp,myfunc,size2); + if (preProc) preProc(outp,size2,ctx); + if (repl) + { + if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]); + if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]); + if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]); + if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]); + } + + ctx->computTableTop++; + + return ((INT_PTR)(block)); + } +} + +//--------------------------------------------------------------------------------------------------------------- +INT_PTR nseel_createCompiledFunction2(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code1, INT_PTR code2) +{ + int size2; + unsigned char *outp; + void *myfunc; + int sizes1=((int *)code1)[0]; + int sizes2=((int *)code2)[0]; + if (fntype == MATH_FN && (fn == 1 || fn == 2 || fn == 3)) // special case: LOOP/BOR/BAND + { + void *func3; + int size; + INT_PTR *ptr; + char *block; + + unsigned char *newblock2, *p; + + p=newblock2=newBlock(sizes2+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32); + memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE; + memcpy(p,(char*)code2+4,sizes2); p+=sizes2; + memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE; + memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET); + + ctx->l_stats[2]+=sizes2+2; + + if (fn == 1) func3 = GLUE_realAddress(nseel_asm_band,nseel_asm_band_end,&size); + else if (fn == 3) func3 = GLUE_realAddress(nseel_asm_repeat,nseel_asm_repeat_end,&size); + else func3 = GLUE_realAddress(nseel_asm_bor,nseel_asm_bor_end,&size); + + block=(char *)newTmpBlock(sizes1+size); + memcpy(block+4,(char*)code1+4,sizes1); + ptr=(INT_PTR *)(block+4+sizes1); + memcpy(ptr,func3,size); + + if (fn!=3) ptr=EEL_GLUE_set_immediate(ptr,&g_closefact); // for or/and + ptr=EEL_GLUE_set_immediate(ptr,newblock2); + if (fn!=3) ptr=EEL_GLUE_set_immediate(ptr,&g_closefact); // for or/and +#ifdef __ppc__ + if (fn!=3) // for or/and on ppc we need a one + { + ptr=EEL_GLUE_set_immediate(ptr,&eel_one); + } +#endif + + ctx->computTableTop++; + return (INT_PTR)block; + } + + { + NSEEL_PPPROC preProc=0; + unsigned char *block; + void **repl; + myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc,&repl); + + block=(unsigned char *)newTmpBlock(size2+sizes1+sizes2+sizeof(GLUE_PUSH_EAX)+sizeof(GLUE_POP_EBX)); + + outp=block+4; + memcpy(outp,(char*)code1+4,sizes1); + outp+=sizes1; + memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX); + memcpy(outp,(char*)code2+4,sizes2); + outp+=sizes2; + memcpy(outp,&GLUE_POP_EBX,sizeof(GLUE_POP_EBX)); outp+=sizeof(GLUE_POP_EBX); + + memcpy(outp,myfunc,size2); + if (preProc) preProc(outp,size2,ctx); + if (repl) + { + if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]); + if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]); + if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]); + if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]); + } + + ctx->computTableTop++; + + return ((INT_PTR)(block)); + } +} + + +//--------------------------------------------------------------------------------------------------------------- +INT_PTR nseel_createCompiledFunction1(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code) +{ + NSEEL_PPPROC preProc=0; + int size,size2; + char *block; + void *myfunc; + void *func1; + + size =((int *)code)[0]; + func1 = (void *)(code+4); + + + if (fntype == MATH_FN && fn == 4) // special case: while + { + void *func3; + INT_PTR *ptr; + + unsigned char *newblock2, *p; + + p=newblock2=newBlock(size+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32); + memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE; + memcpy(p,func1,size); p+=size; + memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE; + memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET); + + ctx->l_stats[2]+=size+2; + + func3 = GLUE_realAddress(nseel_asm_repeatwhile,nseel_asm_repeatwhile_end,&size); + + block=(char *)newTmpBlock(size); + ptr = (INT_PTR *)(block+4); + memcpy(ptr,func3,size); + ptr=EEL_GLUE_set_immediate(ptr,newblock2); + EEL_GLUE_set_immediate(ptr,&g_closefact); + + ctx->computTableTop++; + return (INT_PTR)block; + } + + { + void **repl; + myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc,&repl); + + block=(char *)newTmpBlock(size+size2); + + memcpy(block+4, func1, size); + memcpy(block+size+4,myfunc,size2); + if (preProc) preProc(block+size+4,size2,ctx); + if (repl) + { + unsigned char *outp=(unsigned char *)block+size+4; + if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]); + if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]); + if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]); + if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]); + } + + ctx->computTableTop++; + + return ((INT_PTR)(block)); + } +} + + +static char *preprocessCode(compileContext *ctx, char *expression) +{ + char *expression_start=expression; + int len=0; + int alloc_len=strlen(expression)+1+64; + char *buf=(char *)malloc(alloc_len); + int semicnt=0; + // we need to call onCompileNewLine for each new line we get + + //onCompileNewLine(ctx, + + while (*expression) + { + if (len > alloc_len-64) + { + alloc_len = len+128; + buf=(char*)realloc(buf,alloc_len); + } + + if (expression[0] == '/') + { + if (expression[1] == '/') + { + expression+=2; + while (expression[0] && expression[0] != '\n') expression++; + continue; + } + else if (expression[1] == '*') + { + expression+=2; + while (expression[0] && (expression[0] != '*' || expression[1] != '/')) + { + if (expression[0] == '\n') onCompileNewLine(ctx,expression+1-expression_start,len); + expression++; + } + if (expression[0]) expression+=2; // at this point we KNOW expression[0]=* and expression[1]=/ + continue; + } + } + + if (expression[0] == '$') + { + if (toupper(expression[1]) == 'X') + { + char *p=expression+2; + unsigned int v=strtoul(expression+2,&p,16); + char tmp[64]; + expression=p; + + sprintf(tmp,"%u",v); + memcpy(buf+len,tmp,strlen(tmp)); + len+=strlen(tmp); + ctx->l_stats[0]+=strlen(tmp); + continue; + + } + if (expression[1]=='\'' && expression[2] && expression[3]=='\'') + { + char tmp[64]; + sprintf(tmp,"%u",((unsigned char *)expression)[2]); + expression+=4; + + memcpy(buf+len,tmp,strlen(tmp)); + len+=strlen(tmp); + ctx->l_stats[0]+=strlen(tmp); + continue; + } + if (toupper(expression[1]) == 'P' && toupper(expression[2]) == 'I') + { + static char *str="3.141592653589793"; + expression+=3; + memcpy(buf+len,str,17); + len+=17; //strlen(str); + ctx->l_stats[0]+=17; + continue; + } + if (toupper(expression[1]) == 'E') + { + static char *str="2.71828183"; + expression+=2; + memcpy(buf+len,str,10); + len+=10; //strlen(str); + ctx->l_stats[0]+=10; + continue; + } + if (toupper(expression[1]) == 'P' && toupper(expression[2]) == 'H' && toupper(expression[3]) == 'I') + { + static char *str="1.61803399"; + expression+=4; + memcpy(buf+len,str,10); + len+=10; //strlen(str); + ctx->l_stats[0]+=10; + continue; + } + + } + + { + char c=*expression++; + + if (c == '\n') onCompileNewLine(ctx,expression-expression_start,len); + if (isspace(c)) c=' '; + + if (c == '(') semicnt++; + else if (c == ')') { semicnt--; if (semicnt < 0) semicnt=0; } + else if (c == ';' && semicnt > 0) + { + // convert ; to % if next nonwhitespace char is alnum, otherwise convert to space + int p=0; + int nc; + int commentstate=0; + while ((nc=expression[p])) + { + if (!commentstate && nc == '/') + { + if (expression[p+1] == '/') commentstate=1; + else if (expression[p+1] == '*') commentstate=2; + } + + if (commentstate == 1 && nc == '\n') commentstate=0; + else if (commentstate == 2 && nc == '*' && expression[p+1]=='/') + { + p++; // skip * + commentstate=0; + } + else if (!commentstate && !isspace(nc)) break; + + p++; + } + // fucko, we should look for even more chars, me thinks + if (nc && (isalnum(nc) +#if 1 + || nc == '(' || nc == '_' || nc == '!' || nc == '$' +#endif + )) c='%'; + else c = ' '; // stray ; + } +#if 0 + else if (semicnt > 0 && c == ',') + { + int p=0; + int nc; + while ((nc=expression[p]) && isspace(nc)) p++; + if (nc == ',' || nc == ')') + { + expression += p+1; + buf[len++]=','; + buf[len++]='0'; + c=nc; // append this char + } + } +#endif + // list of operators + + else if (!isspace(c) && !isalnum(c)) // check to see if this operator is ours + { + + static char *symbollists[]= + { + "", // or any control char that is not parenthed + ":(,;?%", + ",):?;", // or || or && + ",);", // jf> removed :? from this, for = + ",);", + "", // only scans for a negative ] level + + }; + + + static struct + { + char op[2]; + char lscan,rscan; + char *func; + } preprocSymbols[] = + { + {{'+','='}, 0, 3, "_addop" }, + {{'-','='}, 0, 3, "_subop" }, + {{'%','='}, 0, 3, "_modop" }, + {{'|','='}, 0, 3, "_orop" }, + {{'&','='}, 0, 3, "_andop"}, + + {{'/','='}, 0, 3, "_divop"}, + {{'*','='}, 0, 3, "_mulop"}, + {{'^','='}, 0, 3, "_powop"}, + + {{'=','='}, 1, 2, "_equal" }, + {{'<','='}, 1, 2, "_beleq" }, + {{'>','='}, 1, 2, "_aboeq" }, + {{'<',0 }, 1, 2, "_below" }, + {{'>',0 }, 1, 2, "_above" }, + {{'!','='}, 1, 2, "_noteq" }, + {{'|','|'}, 1, 2, "_or" }, + {{'&','&'}, 1, 2, "_and" }, + {{'=',0 }, 0, 3, "_set" }, + {{'%',0}, 0, 0, "_mod" }, + {{'^',0}, 0, 0, "pow" }, + + + {{'[',0 }, 0, 5, }, + {{'!',0 },-1, 0, }, // this should also ignore any leading +- + {{'?',0 }, 1, 4, }, + + }; + + + int n; + int ns=sizeof(preprocSymbols)/sizeof(preprocSymbols[0]); + for (n = 0; n < ns; n++) + { + if (c == preprocSymbols[n].op[0] && (!preprocSymbols[n].op[1] || expression[0] == preprocSymbols[n].op[1])) + { + break; + } + } + if (n < ns) + { + + int lscan=preprocSymbols[n].lscan; + int rscan=preprocSymbols[n].rscan; + + // parse left side of =, scanning back for an unparenthed nonwhitespace nonalphanumeric nonparenth? + // so megabuf(x+y)= would be fine, x=, but +x= would do +set(x,) + char *l_ptr=0; + char *r_ptr=0; + if (lscan >= 0) + { + char *scan=symbollists[lscan]; + int l_semicnt=0; + l_ptr=buf + len - 1; + while (l_ptr >= buf) + { + if (*l_ptr == ')') l_semicnt++; + else if (*l_ptr == '(') + { + l_semicnt--; + if (l_semicnt < 0) break; + } + else if (!l_semicnt) + { + if (!*scan) + { + if (!isspace(*l_ptr) && !isalnum(*l_ptr) && *l_ptr != '_' && *l_ptr != '.') break; + } + else + { + char *sc=scan; + if (lscan == 2 && ( // not currently used, even + (l_ptr[0]=='|' && l_ptr[1] == '|')|| + (l_ptr[0]=='&' && l_ptr[1] == '&') + ) + ) break; + while (*sc && *l_ptr != *sc) sc++; + if (*sc) break; + } + } + l_ptr--; + } + buf[len]=0; + + l_ptr++; + + len = l_ptr - buf; + + l_ptr = strdup(l_ptr); // doesn't need to be preprocessed since it just was + } + if (preprocSymbols[n].op[1]) expression++; + + r_ptr=expression; + { + // scan forward to an uncommented, unparenthed semicolon, comma, or ) + int r_semicnt=0; + int r_qcnt=0; + char *scan=symbollists[rscan]; + int commentstate=0; + int hashadch=0; + int bracketcnt=0; + while (*r_ptr) + { + if (!commentstate && *r_ptr == '/') + { + if (r_ptr[1] == '/') commentstate=1; + else if (r_ptr[1] == '*') commentstate=2; + } + if (commentstate == 1 && *r_ptr == '\n') commentstate=0; + else if (commentstate == 2 && *r_ptr == '*' && r_ptr[1]=='/') + { + r_ptr++; // skip * + commentstate=0; + } + else if (!commentstate) + { + if (*r_ptr == '(') {hashadch=1; r_semicnt++; } + else if (*r_ptr == ')') + { + r_semicnt--; + if (r_semicnt < 0) break; + } + else if (!r_semicnt) + { + char *sc=scan; + if (*r_ptr == ';' || *r_ptr == ',') break; + + if (!rscan) + { + if (*r_ptr == ':') break; + if (!isspace(*r_ptr) && !isalnum(*r_ptr) && *r_ptr != '_' && *r_ptr != '.' && hashadch) break; + if (isalnum(*r_ptr) || *r_ptr == '_')hashadch=1; + } + else if (rscan == 2 && + ((r_ptr[0]=='|' && r_ptr[1] == '|')|| + (r_ptr[0]=='&' && r_ptr[1] == '&') + ) + ) break; + + else if (rscan == 3 || rscan == 4) + { + if (*r_ptr == ':') r_qcnt--; + else if (*r_ptr == '?') r_qcnt++; + + if (r_qcnt < 3-rscan) break; + } + else if (rscan == 5) + { + if (*r_ptr == '[') bracketcnt++; + else if (*r_ptr == ']') bracketcnt--; + if (bracketcnt < 0) break; + } + + while (*sc && *r_ptr != *sc) sc++; + if (*sc) break; + } + } + r_ptr++; + } + // expression -> r_ptr is our string (not including r_ptr) + + { + char *orp=r_ptr; + + char rps=*orp; + *orp=0; // temporarily terminate + + r_ptr=preprocessCode(ctx,expression); + expression=orp; + + *orp = rps; // fix termination(restore string) + } + + } + + if (r_ptr) + { + int thisl = strlen(l_ptr?l_ptr:"") + strlen(r_ptr) + 32; + + if (len+thisl > alloc_len-64) + { + alloc_len = len+thisl+128; + buf=(char*)realloc(buf,alloc_len); + } + + + if (n == ns-3) + { + char *lp = l_ptr; + char *rp = r_ptr; + while (lp && *lp && isspace(*lp)) lp++; + while (rp && *rp && isspace(*rp)) rp++; + if (lp && !strncasecmp(lp,"gmem",4) && (!lp[4] || isspace(lp[4]))) + { + len+=sprintf(buf+len,"_gmem(%s",r_ptr && *r_ptr ? r_ptr : "0"); + ctx->l_stats[0]+=strlen(l_ptr)+4; + } + else if (rp && *rp && strcmp(rp,"0")) + { + len+=sprintf(buf+len,"_mem((%s)+(%s)",lp,rp); + ctx->l_stats[0]+=strlen(lp)+strlen(rp)+8; + } + else + { + len+=sprintf(buf+len,"_mem(%s",lp); + ctx->l_stats[0]+=strlen(lp)+4; + } + + // skip the ] + if (*expression == ']') expression++; + + } + else if (n == ns-2) + { + len+=sprintf(buf+len,"_not(%s", + r_ptr); + + ctx->l_stats[0]+=4; + } + else if (n == ns-1)// if (l_ptr,r_ptr1,r_ptr2) + { + char *rptr2=r_ptr; + char *tmp=r_ptr; + int parcnt=0; + int qcnt=1; + while (*rptr2) + { + if (*rptr2 == '?') qcnt++; + else if (*rptr2 == ':') qcnt--; + else if (*rptr2 == '(') parcnt++; + else if (*rptr2 == ')') parcnt--; + if (parcnt < 0) break; + if (!parcnt && !qcnt && *rptr2 == ':') break; + rptr2++; + } + if (*rptr2) *rptr2++=0; + while (isspace(*rptr2)) rptr2++; + + while (isspace(*tmp)) tmp++; + + len+=sprintf(buf+len,"_if(%s,%s,%s",l_ptr,*tmp?tmp:"0",*rptr2?rptr2:"0"); + ctx->l_stats[0]+=6; + } + else + { + len+=sprintf(buf+len,"%s(%s,%s",preprocSymbols[n].func,l_ptr?l_ptr:"",r_ptr); + ctx->l_stats[0]+=strlen(preprocSymbols[n].func)+2; + } + + } + + free(r_ptr); + free(l_ptr); + + + c = ')'; // close parenth below + } + } + +// if (c != ' ' || (len && buf[len-1] != ' ')) // don't bother adding multiple spaces + { + buf[len++]=c; + if (c != ' ') ctx->l_stats[0]++; + } + } + } + buf[len]=0; + + return buf; +} + +#ifdef PPROC_TEST + +int main(int argc, char* argv[]) +{ + compileContext ctx={0}; + char *p=preprocessCode(&ctx,argv[1]); + if (p)printf("%s\n",p); + free(p); + return 0; +} + +#endif + +#if 0 +static void movestringover(char *str, int amount) +{ + char tmp[1024+8]; + + int l=(int)strlen(str); + l=min(1024-amount-1,l); + + memcpy(tmp,str,l+1); + + while (l >= 0 && tmp[l]!='\n') l--; + l++; + + tmp[l]=0;//ensure we null terminate + + memcpy(str+amount,tmp,l+1); +} +#endif + +//------------------------------------------------------------------------------ +NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX _ctx, char *_expression, int lineoffs) +{ + compileContext *ctx = (compileContext *)_ctx; + char *expression,*expression_start; + int computable_size=0; + codeHandleType *handle; + startPtr *scode=NULL; + startPtr *startpts=NULL; + + if (!ctx) return 0; + + ctx->last_error_string[0]=0; + + if (!_expression || !*_expression) return 0; + + freeBlocks((llBlock **)&ctx->tmpblocks_head); // free blocks + freeBlocks((llBlock **)&ctx->blocks_head); // free blocks + memset(ctx->l_stats,0,sizeof(ctx->l_stats)); + free(ctx->compileLineRecs); ctx->compileLineRecs=0; ctx->compileLineRecs_size=0; ctx->compileLineRecs_alloc=0; + + handle = (codeHandleType*)newBlock(sizeof(codeHandleType),8); + + if (!handle) + { + return 0; + } + + memset(handle,0,sizeof(codeHandleType)); + + expression_start=expression=preprocessCode(ctx,_expression); + + + while (*expression) + { + void *startptr; + char *expr; + ctx->colCount=0; + ctx->computTableTop=0; + + // single out segment + while (*expression == ';' || isspace(*expression)) expression++; + if (!*expression) break; + expr=expression; + + while (*expression && *expression != ';') expression++; + if (*expression) *expression++ = 0; + + // parse + + startptr=nseel_compileExpression(ctx,expr); + + if (ctx->computTableTop > NSEEL_MAX_TEMPSPACE_ENTRIES- /* safety */ 16 - /* alignment */4 || + !startptr) + { + int byteoffs = expr - expression_start; + int destoffs,linenumber; + char buf[21], *p; + int x,le; + +#ifdef NSEEL_EEL1_COMPAT_MODE + if (!startptr) continue; +#endif + if (ctx->errVar > 0) byteoffs += ctx->errVar; + linenumber=findByteOffsetInSource(ctx,byteoffs,&destoffs); + if (destoffs < 0) destoffs=0; + + le=strlen(_expression); + if (destoffs >= le) destoffs=le; + p= _expression + destoffs; + for (x = 0;x < 20; x ++) + { + if (!*p || *p == '\r' || *p == '\n') break; + buf[x]=*p++; + } + buf[x]=0; + + sprintf(ctx->last_error_string,"Around line %d '%s'",linenumber+lineoffs,buf); + + ctx->last_error_string[sizeof(ctx->last_error_string)-1]=0; + scode=NULL; + break; + } + if (computable_size < ctx->computTableTop) + { + computable_size=ctx->computTableTop; + } + + { + startPtr *tmp=(startPtr*) __newBlock((llBlock **)&ctx->tmpblocks_head,sizeof(startPtr)); + if (!tmp) break; + + tmp->startptr = startptr; + tmp->next=NULL; + if (!scode) scode=startpts=tmp; + else + { + scode->next=tmp; + scode=tmp; + } + } +} + free(ctx->compileLineRecs); ctx->compileLineRecs=0; ctx->compileLineRecs_size=0; ctx->compileLineRecs_alloc=0; + + // check to see if failed on the first startingCode + if (!scode) + { + handle=NULL; // return NULL (after resetting blocks_head) + } + else + { + char *tabptr = (char *)(handle->workTable=calloc(computable_size+64, sizeof(EEL_F))); + unsigned char *writeptr; + startPtr *p=startpts; + int size=sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE; // for ret at end :) + + if (((INT_PTR)tabptr)&31) + tabptr += 32-(((INT_PTR)tabptr)&31); + + // now we build one big code segment out of our list of them, inserting a mov esi, computable before each item + while (p) + { + size += GLUE_RESET_ESI(NULL,0); + size+=*(int *)p->startptr; + p=p->next; + } + handle->code = newBlock(size,32); + if (handle->code) + { + writeptr=(unsigned char *)handle->code; + memcpy(writeptr,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); writeptr += GLUE_FUNC_ENTER_SIZE; + p=startpts; + while (p) + { + int thissize=*(int *)p->startptr; + writeptr+=GLUE_RESET_ESI(writeptr,tabptr); + //memcpy(writeptr,&GLUE_MOV_ESI_EDI,sizeof(GLUE_MOV_ESI_EDI)); + //writeptr+=sizeof(GLUE_MOV_ESI_EDI); + memcpy(writeptr,(char*)p->startptr + 4,thissize); + writeptr += thissize; + + p=p->next; + } + memcpy(writeptr,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); writeptr += GLUE_FUNC_LEAVE_SIZE; + memcpy(writeptr,&GLUE_RET,sizeof(GLUE_RET)); writeptr += sizeof(GLUE_RET); + ctx->l_stats[1]=size; + } + handle->blocks = ctx->blocks_head; + ctx->blocks_head=0; + + } + freeBlocks((llBlock **)&ctx->tmpblocks_head); // free blocks + freeBlocks((llBlock **)&ctx->blocks_head); // free blocks + + if (handle) + { + memcpy(handle->code_stats,ctx->l_stats,sizeof(ctx->l_stats)); + nseel_evallib_stats[0]+=ctx->l_stats[0]; + nseel_evallib_stats[1]+=ctx->l_stats[1]; + nseel_evallib_stats[2]+=ctx->l_stats[2]; + nseel_evallib_stats[3]+=ctx->l_stats[3]; + nseel_evallib_stats[4]++; + } + memset(ctx->l_stats,0,sizeof(ctx->l_stats)); + + free(expression_start); + + return (NSEEL_CODEHANDLE)handle; +} + +//------------------------------------------------------------------------------ +void NSEEL_code_execute(NSEEL_CODEHANDLE code) +{ + INT_PTR tabptr; + INT_PTR codeptr; + codeHandleType *h = (codeHandleType *)code; + if (!h || !h->code) return; + + codeptr = (INT_PTR) h->code; +#if 0 + { + unsigned int *p=(unsigned int *)codeptr; + while (*p != GLUE_RET[0]) + { + printf("instr:%04X:%04X\n",*p>>16,*p&0xffff); + p++; + } + } +#endif + + tabptr=(INT_PTR)h->workTable; + if (tabptr&31) + tabptr += 32-((tabptr)&31); + //printf("calling code!\n"); + GLUE_CALL_CODE(tabptr,codeptr); + +} + + +char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx) +{ + compileContext *c=(compileContext *)ctx; + if (ctx && c->last_error_string[0]) return c->last_error_string; + return 0; +} + +//------------------------------------------------------------------------------ +void NSEEL_code_free(NSEEL_CODEHANDLE code) +{ + codeHandleType *h = (codeHandleType *)code; + if (h != NULL) + { + free(h->workTable); + nseel_evallib_stats[0]-=h->code_stats[0]; + nseel_evallib_stats[1]-=h->code_stats[1]; + nseel_evallib_stats[2]-=h->code_stats[2]; + nseel_evallib_stats[3]-=h->code_stats[3]; + nseel_evallib_stats[4]--; + freeBlocks(&h->blocks); + + + } + +} + + +//------------------------------------------------------------------------------ +void NSEEL_VM_resetvars(NSEEL_VMCTX _ctx) +{ + if (_ctx) + { + compileContext *ctx=(compileContext *)_ctx; + int x; + if (ctx->varTable_Names || ctx->varTable_Values) for (x = 0; x < ctx->varTable_numBlocks; x ++) + { + if (ctx->varTable_Names) free(ctx->varTable_Names[x]); + if (ctx->varTable_Values) free(ctx->varTable_Values[x]); + } + + free(ctx->varTable_Values); + free(ctx->varTable_Names); + ctx->varTable_Values=0; + ctx->varTable_Names=0; + + ctx->varTable_numBlocks=0; + } +} + + +NSEEL_VMCTX NSEEL_VM_alloc() // return a handle +{ + compileContext *ctx=calloc(1,sizeof(compileContext)); + return ctx; +} + +void NSEEL_VM_free(NSEEL_VMCTX _ctx) // free when done with a VM and ALL of its code have been freed, as well +{ + + if (_ctx) + { + compileContext *ctx=(compileContext *)_ctx; + NSEEL_VM_resetvars(_ctx); + NSEEL_VM_freeRAM(_ctx); + + freeBlocks((llBlock **)&ctx->tmpblocks_head); // free blocks + freeBlocks((llBlock **)&ctx->blocks_head); // free blocks + free(ctx->compileLineRecs); + free(ctx); + } + +} + +int *NSEEL_code_getstats(NSEEL_CODEHANDLE code) +{ + codeHandleType *h = (codeHandleType *)code; + if (h) + { + return h->code_stats; + } + return 0; +} + +void NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx, void *thisptr) +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + c->caller_this=thisptr; + } +} + + + + + +void NSEEL_PProc_RAM(void *data, int data_size, compileContext *ctx) +{ + if (data_size>0) EEL_GLUE_set_immediate(data, &ctx->ram_blocks); +} +void NSEEL_PProc_THIS(void *data, int data_size, compileContext *ctx) +{ + if (data_size>0) EEL_GLUE_set_immediate(data, ctx->caller_this); +} diff --git a/ns-eel2/nseel-eval.c b/ns-eel2/nseel-eval.c new file mode 100644 index 0000000..2dc1d06 --- /dev/null +++ b/ns-eel2/nseel-eval.c @@ -0,0 +1,321 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2008 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-eval.c + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include +#include +#include "ns-eel-int.h" + +#define NSEEL_VARS_MALLOC_CHUNKSIZE 8 +#define NSEEL_GLOBALVAR_BASE (1<<24) + +#ifndef NSEEL_MAX_VARIABLE_NAMELEN +#define NSEEL_MAX_VARIABLE_NAMELEN 8 +#endif + +#define strnicmp(x,y,z) strncasecmp(x,y,z) + + +#define INTCONST 1 +#define DBLCONST 2 +#define HEXCONST 3 +#define VARIABLE 4 +#define OTHER 5 + +EEL_F nseel_globalregs[100]; + + +//------------------------------------------------------------------------------ +void *nseel_compileExpression(compileContext *ctx, char *exp) +{ + ctx->errVar=0; + nseel_llinit(ctx); + if (!nseel_yyparse(ctx,exp) && !ctx->errVar) + { + return (void*)ctx->result; + } + return 0; +} + +//------------------------------------------------------------------------------ +void nseel_setLastVar(compileContext *ctx) +{ + nseel_gettoken(ctx,ctx->lastVar, sizeof(ctx->lastVar)); +} + +void NSEEL_VM_enumallvars(NSEEL_VMCTX ctx, int (*func)(const char *name, EEL_F *val, void *ctx), void *userctx) +{ + compileContext *tctx = (compileContext *) ctx; + int wb; + if (!tctx) return; + + for (wb = 0; wb < tctx->varTable_numBlocks; wb ++) + { + int ti; + int namepos=0; + for (ti = 0; ti < NSEEL_VARS_PER_BLOCK; ti ++) + { + char *p=tctx->varTable_Names[wb]+namepos; + if (!*p) break; + + + if (!func(p,&tctx->varTable_Values[wb][ti],userctx)) + break; + + namepos += NSEEL_MAX_VARIABLE_NAMELEN; + } + if (ti < NSEEL_VARS_PER_BLOCK) + break; + } +} + + + +static INT_PTR register_var(compileContext *ctx, const char *name, EEL_F **ptr) +{ + int wb; + int ti=0; + int i=0; + char *nameptr; + for (wb = 0; wb < ctx->varTable_numBlocks; wb ++) + { + int namepos=0; + for (ti = 0; ti < NSEEL_VARS_PER_BLOCK; ti ++) + { + if (!ctx->varTable_Names[wb][namepos] || !strnicmp(ctx->varTable_Names[wb]+namepos,name,NSEEL_MAX_VARIABLE_NAMELEN)) + { + break; + } + namepos += NSEEL_MAX_VARIABLE_NAMELEN; + i++; + } + if (ti < NSEEL_VARS_PER_BLOCK) + break; + } + if (wb == ctx->varTable_numBlocks) + { + ti=0; + // add new block + if (!(ctx->varTable_numBlocks&(NSEEL_VARS_MALLOC_CHUNKSIZE-1)) || !ctx->varTable_Values || !ctx->varTable_Names ) + { + ctx->varTable_Values = (EEL_F **)realloc(ctx->varTable_Values,(ctx->varTable_numBlocks+NSEEL_VARS_MALLOC_CHUNKSIZE) * sizeof(EEL_F *)); + ctx->varTable_Names = (char **)realloc(ctx->varTable_Names,(ctx->varTable_numBlocks+NSEEL_VARS_MALLOC_CHUNKSIZE) * sizeof(char *)); + } + ctx->varTable_numBlocks++; + + ctx->varTable_Values[wb] = (EEL_F *)calloc(sizeof(EEL_F),NSEEL_VARS_PER_BLOCK); + ctx->varTable_Names[wb] = (char *)calloc(NSEEL_MAX_VARIABLE_NAMELEN,NSEEL_VARS_PER_BLOCK); + } + + nameptr=ctx->varTable_Names[wb]+ti*NSEEL_MAX_VARIABLE_NAMELEN; + if (!nameptr[0]) + { + strncpy(nameptr,name,NSEEL_MAX_VARIABLE_NAMELEN); + } + if (ptr) *ptr = ctx->varTable_Values[wb] + ti; + return i; +} + +//------------------------------------------------------------------------------ +INT_PTR nseel_setVar(compileContext *ctx, INT_PTR varNum) +{ + if (varNum < 0) // adding new var + { + char *var=ctx->lastVar; + if (!strnicmp(var,"reg",3) && strlen(var) == 5 && isdigit(var[3]) && isdigit(var[4])) + { + int i,x=atoi(var+3); + if (x < 0 || x > 99) x=0; + i=NSEEL_GLOBALVAR_BASE+x; + return i; + } + + return register_var(ctx,ctx->lastVar,NULL); + + } + + // setting/getting oldvar + + if (varNum >= NSEEL_GLOBALVAR_BASE && varNum < NSEEL_GLOBALVAR_BASE+100) + { + return varNum; + } + + { + int wb,ti; + char *nameptr; + if (varNum < 0 || varNum >= ctx->varTable_numBlocks*NSEEL_VARS_PER_BLOCK) return -1; + + wb=varNum/NSEEL_VARS_PER_BLOCK; + ti=(varNum%NSEEL_VARS_PER_BLOCK); + nameptr=ctx->varTable_Names[wb]+ti*NSEEL_MAX_VARIABLE_NAMELEN; + if (!nameptr[0]) + { + strncpy(nameptr,ctx->lastVar,NSEEL_MAX_VARIABLE_NAMELEN); + } + return varNum; + } + +} + +//------------------------------------------------------------------------------ +INT_PTR nseel_getVar(compileContext *ctx, INT_PTR i) +{ + if (i >= 0 && i < (NSEEL_VARS_PER_BLOCK*ctx->varTable_numBlocks)) + return nseel_createCompiledValue(ctx,0, ctx->varTable_Values[i/NSEEL_VARS_PER_BLOCK] + i%NSEEL_VARS_PER_BLOCK); + if (i >= NSEEL_GLOBALVAR_BASE && i < NSEEL_GLOBALVAR_BASE+100) + return nseel_createCompiledValue(ctx,0, nseel_globalregs+i-NSEEL_GLOBALVAR_BASE); + + return nseel_createCompiledValue(ctx,0, NULL); +} + + + +//------------------------------------------------------------------------------ +EEL_F *NSEEL_VM_regvar(NSEEL_VMCTX _ctx, const char *var) +{ + compileContext *ctx = (compileContext *)_ctx; + EEL_F *r; + if (!ctx) return 0; + + if (!strnicmp(var,"reg",3) && strlen(var) == 5 && isdigit(var[3]) && isdigit(var[4])) + { + int x=atoi(var+3); + if (x < 0 || x > 99) x=0; + return nseel_globalregs + x; + } + + register_var(ctx,var,&r); + + return r; +} + +//------------------------------------------------------------------------------ +INT_PTR nseel_translate(compileContext *ctx, int type) +{ + int v; + int n; + *ctx->yytext = 0; + nseel_gettoken(ctx,ctx->yytext, sizeof(ctx->yytext)); + + switch (type) + { + case INTCONST: return nseel_createCompiledValue(ctx,(EEL_F)atoi(ctx->yytext), NULL); + case DBLCONST: return nseel_createCompiledValue(ctx,(EEL_F)atof(ctx->yytext), NULL); + case HEXCONST: + v=0; + n=0; + while (1) + { + int a=ctx->yytext[n++]; + if (a >= '0' && a <= '9') v=(v<<4)+a-'0'; + else if (a >= 'A' && a <= 'F') v=(v<<4)+10+a-'A'; + else if (a >= 'a' && a <= 'f') v=(v<<4)+10+a-'a'; + else break; + } + return nseel_createCompiledValue(ctx,(EEL_F)v, NULL); + } + return 0; +} + +//------------------------------------------------------------------------------ +INT_PTR nseel_lookup(compileContext *ctx, int *typeOfObject) +{ + int i, ti, wb; + const char *nptr; + nseel_gettoken(ctx,ctx->yytext, sizeof(ctx->yytext)); + + if (!strnicmp(ctx->yytext,"reg",3) && strlen(ctx->yytext) == 5 && isdigit(ctx->yytext[3]) && isdigit(ctx->yytext[4]) && (i=atoi(ctx->yytext+3))>=0 && i<100) + { + *typeOfObject=IDENTIFIER; + return i+NSEEL_GLOBALVAR_BASE; + } + + i=0; + for (wb = 0; wb < ctx->varTable_numBlocks; wb ++) + { + int namepos=0; + for (ti = 0; ti < NSEEL_VARS_PER_BLOCK; ti ++) + { + if (!ctx->varTable_Names[wb][namepos]) break; + + if (!strnicmp(ctx->varTable_Names[wb]+namepos,ctx->yytext,NSEEL_MAX_VARIABLE_NAMELEN)) + { + *typeOfObject = IDENTIFIER; + return i; + } + + namepos += NSEEL_MAX_VARIABLE_NAMELEN; + i++; + } + if (ti < NSEEL_VARS_PER_BLOCK) break; + } + + + nptr = ctx->yytext; + if (!strcasecmp(nptr,"if")) nptr="_if"; + else if (!strcasecmp(nptr,"bnot")) nptr="_not"; + else if (!strcasecmp(nptr,"assign")) nptr="_set"; + else if (!strcasecmp(nptr,"equal")) nptr="_equal"; + else if (!strcasecmp(nptr,"below")) nptr="_below"; + else if (!strcasecmp(nptr,"above")) nptr="_above"; + else if (!strcasecmp(nptr,"megabuf")) nptr="_mem"; + else if (!strcasecmp(nptr,"gmegabuf")) nptr="_gmem"; + else if (!strcasecmp(nptr,"int")) nptr="floor"; + + for (i=0;nseel_getFunctionFromTable(i);i++) + { + functionType *f=nseel_getFunctionFromTable(i); + if (!strcasecmp(f->name, nptr)) + { + switch (f->nParams) + { + case 1: *typeOfObject = FUNCTION1; break; + case 2: *typeOfObject = FUNCTION2; break; + case 3: *typeOfObject = FUNCTION3; break; + default: *typeOfObject = IDENTIFIER; break; + } + return i; + } + } + + *typeOfObject = IDENTIFIER; + nseel_setLastVar(ctx); + return nseel_setVar(ctx,-1); +} + + + +//--------------------------------------------------------------------------- +void nseel_count(compileContext *ctx) +{ + nseel_gettoken(ctx,ctx->yytext, sizeof(ctx->yytext)); + ctx->colCount+=strlen(ctx->yytext); +} + +//--------------------------------------------------------------------------- +int nseel_yyerror(compileContext *ctx) +{ + ctx->errVar = ctx->colCount; + return 0; +} diff --git a/ns-eel2/nseel-lextab.c b/ns-eel2/nseel-lextab.c new file mode 100644 index 0000000..9d90b76 --- /dev/null +++ b/ns-eel2/nseel-lextab.c @@ -0,0 +1,277 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2008 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-lextab.c + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "ns-eel-int.h" + + +#define LEXSKIP (-1) + +static int _lmovb(struct lextab *lp, int c, int st) +{ + int base; + + while ((base = lp->llbase[st]+c) > lp->llnxtmax || + (lp->llcheck[base] & 0377) != st) { + + if (st != lp->llendst) { + base = lp->lldefault[st] & 0377; + st = base; + } + else + return(-1); + } + return(lp->llnext[base]&0377); +} + +#define INTCONST 1 +#define DBLCONST 2 +#define HEXCONST 3 +#define VARIABLE 4 +#define OTHER 5 + +static int _Alextab(compileContext *ctx, int __na__) +{ + // fucko: JF> 17 -> 19? + + if (__na__ >= 0 && __na__ <= 17) + nseel_count(ctx); + switch (__na__) + { + case 0: + *ctx->yytext = 0; + nseel_gettoken(ctx,ctx->yytext, sizeof(ctx->yytext)); + if (ctx->yytext[0] < '0' || ctx->yytext[0] > '9') // not really a hex value, lame + { + nseel_setLastVar(ctx); ctx->yylval = nseel_lookup(ctx,&__na__); return __na__; + } + ctx->yylval = nseel_translate(ctx,HEXCONST); + return VALUE; + case 1: ctx->yylval = nseel_translate(ctx,INTCONST); return VALUE; + case 2: ctx->yylval = nseel_translate(ctx,INTCONST); return VALUE; + case 3: ctx->yylval = nseel_translate(ctx,DBLCONST); return VALUE; + case 4: + case 5: nseel_setLastVar(ctx); ctx->yylval = nseel_lookup(ctx,&__na__); return __na__; + case 6: return '+'; + case 7: return '-'; + case 8: return '*'; + case 9: return '/'; + case 10: return '%'; + case 11: return '&'; + case 12: return '|'; + case 13: return '('; + case 14: return ')'; + case 15: return '='; + case 16: return ','; + case 17: return ';'; + } + return (LEXSKIP); +} + + +static char _Flextab[] = + { + 1, 18, 17, 16, 15, 14, 13, 12, + 11, 10, 9, 8, 7, 6, 4, 5, + 5, 4, 4, 3, 3, 3, 3, 4, + 0, 4, 5, 0, 5, 4, 1, 3, + 0, 2, -1, 1, -1, + }; + + +static char _Nlextab[] = + { + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 1, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 1, 36, 36, 36, 36, 9, 8, 36, + 6, 5, 11, 13, 3, 12, 19, 10, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 36, 2, 36, 4, 36, 36, + 36, 29, 29, 29, 29, 29, 29, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 36, 36, 36, 36, 18, + 36, 29, 29, 29, 29, 29, 23, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 14, 18, + 18, 18, 18, 36, 7, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 36, + 36, 36, 36, 36, 36, 36, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 36, 36, 36, 36, 17, 36, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 36, 36, 36, 36, 36, 36, + 36, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 36, 36, 36, 36, 16, + 36, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 36, + 20, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 36, 36, 36, 36, 36, + 36, 36, 25, 25, 25, 25, 25, 25, + 36, 24, 36, 36, 36, 36, 36, 36, + 20, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 25, 25, 25, 25, 25, 25, + 36, 24, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 36, 36, 36, 36, + 36, 36, 36, 28, 28, 28, 28, 28, + 28, 36, 27, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 28, 28, 28, 28, 28, + 28, 31, 27, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 36, 36, 36, + 36, 36, 36, 36, 34, 34, 34, 33, + 34, 34, 36, 32, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 34, 34, 34, 33, + 34, 34, 36, 32, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 36, 36, + 36, 36, 36, 36, 36, 34, 34, 34, + 34, 34, 34, 36, 32, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 34, 34, 34, + 34, 34, 34, 36, 32, + }; + +static char _Clextab[] = + { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, -1, -1, -1, -1, 0, 0, -1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, -1, 0, -1, -1, + -1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -1, -1, -1, -1, 0, + -1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -1, 0, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, -1, + -1, -1, -1, -1, -1, -1, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + -1, -1, -1, -1, 14, -1, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, -1, -1, -1, -1, -1, -1, + -1, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, -1, -1, -1, -1, 15, + -1, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, -1, + 19, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, -1, -1, -1, -1, -1, + -1, -1, 23, 23, 23, 23, 23, 23, + -1, 23, -1, -1, -1, -1, -1, -1, + 19, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 23, 23, 23, 23, 23, 23, + -1, 23, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, -1, -1, -1, -1, + -1, -1, -1, 26, 26, 26, 26, 26, + 26, -1, 26, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 26, 26, 26, 26, 26, + 26, 30, 26, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, -1, -1, -1, + -1, -1, -1, -1, 30, 30, 30, 30, + 30, 30, -1, 30, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 30, 30, 30, 30, + 30, 30, -1, 30, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, -1, -1, + -1, -1, -1, -1, -1, 33, 33, 33, + 33, 33, 33, -1, 33, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 33, 33, 33, + 33, 33, 33, -1, 33, + }; + +static char _Dlextab[] = + { + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 15, 14, 14, 36, 36, 20, 19, 14, + 14, 23, 15, 15, 26, 23, 36, 19, + 36, 36, 33, 30, + }; + +static int _Blextab[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 77, 152, + 0, 0, 0, 227, 237, 0, 0, 249, + 0, 0, 306, 0, 0, 0, 363, 0, + 0, 420, 0, 0, 0, + }; + +struct lextab nseel_lextab = { + 36, + _Dlextab, + _Nlextab, + _Clextab, + _Blextab, + 524, + _lmovb, + _Flextab, + _Alextab, + + 0, + 0, + 0, + 0, + }; + + diff --git a/ns-eel2/nseel-ram.c b/ns-eel2/nseel-ram.c new file mode 100644 index 0000000..d20dd44 --- /dev/null +++ b/ns-eel2/nseel-ram.c @@ -0,0 +1,320 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2008 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "ns-eel.h" +#include "ns-eel-int.h" +#include +#include +#include +#include + + +#ifdef _WIN32 +#include +#endif + +unsigned int NSEEL_RAM_limitmem=0; +unsigned int NSEEL_RAM_memused=0; +int NSEEL_RAM_memused_errors=0; + + + +int NSEEL_VM_wantfreeRAM(NSEEL_VMCTX ctx) +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + if (c->ram_needfree) + return 1; + } + return 0; +} + +void NSEEL_VM_freeRAMIfCodeRequested(NSEEL_VMCTX ctx) // check to see if our free flag was set +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + if (c->ram_needfree) + { + NSEEL_HOSTSTUB_EnterMutex(); + if (c->ram_blocks) + { + INT_PTR startpos=((INT_PTR)c->ram_needfree)-1; + EEL_F **blocks = (EEL_F **)c->ram_blocks; + INT_PTR pos=0; + int x; + for (x = 0; x < NSEEL_RAM_BLOCKS; x ++) + { + if (pos >= startpos) + { + if (blocks[x]) + { + if (NSEEL_RAM_memused >= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK) + NSEEL_RAM_memused -= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK; + else NSEEL_RAM_memused_errors++; + } + free(blocks[x]); + blocks[x]=0; + } + pos+=NSEEL_RAM_ITEMSPERBLOCK; + } + if (!startpos) + { + free(blocks); + c->ram_blocks=0; + } + } + c->ram_needfree=0; + NSEEL_HOSTSTUB_LeaveMutex(); + } + + } +} + + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAMAllocGMEM(EEL_F ***blocks, int w) +{ + static EEL_F * volatile gmembuf; + if (blocks) return __NSEEL_RAMAlloc(blocks,w); + + if (!gmembuf) + { + NSEEL_HOSTSTUB_EnterMutex(); + if (!gmembuf) gmembuf=(EEL_F*)calloc(sizeof(EEL_F),NSEEL_SHARED_GRAM_SIZE); + NSEEL_HOSTSTUB_LeaveMutex(); + + if (!gmembuf) return 0; + } + + return gmembuf+(((unsigned int)w)&((NSEEL_SHARED_GRAM_SIZE)-1)); +} + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAMAlloc(EEL_F ***blocks, int w) +{ + int whichblock; + EEL_F **pblocks=*blocks; + + int is_locked=0; + + if (!pblocks) + { + if (!is_locked) { is_locked=1; NSEEL_HOSTSTUB_EnterMutex(); } + + if (!(pblocks=*blocks)) + { + pblocks = *blocks = (EEL_F **)calloc(sizeof(EEL_F *),NSEEL_RAM_BLOCKS); + if (!pblocks) { + if (is_locked) NSEEL_HOSTSTUB_LeaveMutex(); + return 0; + } + } + } + +// fprintf(stderr,"got request at %d, %d\n",w/NSEEL_RAM_ITEMSPERBLOCK, w&(NSEEL_RAM_ITEMSPERBLOCK-1)); + if (w >= 0 && (whichblock = w/NSEEL_RAM_ITEMSPERBLOCK) < NSEEL_RAM_BLOCKS) + { + EEL_F *p=pblocks[whichblock]; + if (!p) + { + if (!is_locked) { is_locked=1; NSEEL_HOSTSTUB_EnterMutex(); } + + if (!(p=pblocks[whichblock])) + { + + const int msize=sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK; + if (!NSEEL_RAM_limitmem || NSEEL_RAM_memused+msize < NSEEL_RAM_limitmem) + { + p=pblocks[whichblock]=(EEL_F *)calloc(sizeof(EEL_F),NSEEL_RAM_ITEMSPERBLOCK); + if (p) NSEEL_RAM_memused+=msize; + } + if (!p) w=0; + } + } + if (is_locked) NSEEL_HOSTSTUB_LeaveMutex(); + return p + (w&(NSEEL_RAM_ITEMSPERBLOCK-1)); + } + if (is_locked) NSEEL_HOSTSTUB_LeaveMutex(); +// fprintf(stderr,"ret 0\n"); + return 0; +} + + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemFree(EEL_F ***blocks, EEL_F *which) +{ + int d=EEL_F2int(*which); + if (d < 0) d=0; + if (d < NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) ((INT_PTR *)blocks)[1]=1+d; + return which; +} + + + + + + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemCpy(EEL_F ***blocks,EEL_F *dest, EEL_F *src, EEL_F *lenptr) +{ + int dest_offs = EEL_F2int(*dest + 0.0001); + int src_offs = EEL_F2int(*src + 0.0001); + int len = EEL_F2int(*lenptr + 0.0001); + + // trim to front + if (src_offs<0) + { + len += src_offs; + dest_offs -= src_offs; + src_offs=0; + } + if (dest_offs<0) + { + len += dest_offs; + src_offs -= dest_offs; + dest_offs=0; + } + + while (len > 0) + { + EEL_F *srcptr,*destptr; + int copy_len = len; + int maxdlen=NSEEL_RAM_ITEMSPERBLOCK - (dest_offs&(NSEEL_RAM_ITEMSPERBLOCK-1)); + int maxslen=NSEEL_RAM_ITEMSPERBLOCK - (src_offs&(NSEEL_RAM_ITEMSPERBLOCK-1)); + + if (dest_offs >= NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK || + src_offs >= NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) break; + + if (copy_len > maxdlen) copy_len=maxdlen; + if (copy_len > maxslen) copy_len=maxslen; + + if (copy_len<1) break; + + srcptr = __NSEEL_RAMAlloc(blocks,src_offs); + destptr = __NSEEL_RAMAlloc(blocks,dest_offs); + if (!srcptr || !destptr) break; + + memmove(destptr,srcptr,sizeof(EEL_F)*copy_len); + src_offs+=copy_len; + dest_offs+=copy_len; + len-=copy_len; + } + return dest; +} + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemSet(EEL_F ***blocks,EEL_F *dest, EEL_F *v, EEL_F *lenptr) +{ + int offs = EEL_F2int(*dest + 0.0001); + int len = EEL_F2int(*lenptr + 0.0001); + EEL_F t; + if (offs<0) + { + len += offs; + offs=0; + } + if (offs >= NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) return dest; + + if (offs+len > NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) len = NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK - offs; + + if (len < 1) return dest; + + + t=*v; // set value + +// int lastBlock=-1; + while (len > 0) + { + int lcnt; + EEL_F *ptr=__NSEEL_RAMAlloc(blocks,offs); + if (!ptr) break; + + lcnt=NSEEL_RAM_ITEMSPERBLOCK-(offs&(NSEEL_RAM_ITEMSPERBLOCK-1)); + if (lcnt > len) lcnt=len; + + len -= lcnt; + offs += lcnt; + + while (lcnt--) + { + *ptr++=t; + } + } + return dest; +} + + +void NSEEL_VM_SetGRAM(NSEEL_VMCTX ctx, void **gram) +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + c->gram_blocks = gram; + } +} + + +void NSEEL_VM_freeRAM(NSEEL_VMCTX ctx) +{ + if (ctx) + { + int x; + compileContext *c=(compileContext*)ctx; + if (c->ram_blocks) + { + EEL_F **blocks = (EEL_F **)c->ram_blocks; + for (x = 0; x < NSEEL_RAM_BLOCKS; x ++) + { + if (blocks[x]) + { + if (NSEEL_RAM_memused >= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK) + NSEEL_RAM_memused -= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK; + else NSEEL_RAM_memused_errors++; + } + free(blocks[x]); + blocks[x]=0; + } + free(blocks); + c->ram_blocks=0; + } + c->ram_needfree=0; // no need to free anymore + } +} + +void NSEEL_VM_FreeGRAM(void **ufd) +{ + if (ufd[0]) + { + EEL_F **blocks = (EEL_F **)ufd[0]; + int x; + for (x = 0; x < NSEEL_RAM_BLOCKS; x ++) + { + if (blocks[x]) + { + if (NSEEL_RAM_memused >= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK) + NSEEL_RAM_memused -= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK; + else NSEEL_RAM_memused_errors++; + } + free(blocks[x]); + blocks[x]=0; + } + free(blocks); + ufd[0]=0; + } +} \ No newline at end of file diff --git a/ns-eel2/nseel-yylex.c b/ns-eel2/nseel-yylex.c new file mode 100644 index 0000000..605b477 --- /dev/null +++ b/ns-eel2/nseel-yylex.c @@ -0,0 +1,163 @@ +/* + Expression Evaluator Library (NS-EEL) + Copyright (C) 2004-2008 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-yylex.c + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "ns-eel-int.h" + + +#define NBPW 16 +#define EOF (-1) + + +#define YYERRORVAL 256 /* yacc's value */ + +static int llset(compileContext *ctx); +static int llinp(compileContext *ctx, char **exp); +static int lexgetc(char **exp) +{ + char c= **exp; + if (c) (*exp)++; + return( c != 0 ? c : -1); +} +static int tst__b(register int c, char tab[]) +{ + return (tab[(c >> 3) & 037] & (1 << (c & 07)) ); +} + +int nseel_gettoken(compileContext *ctx, char *lltb, int lltbsiz) +{ + register char *lp, *tp, *ep; + + tp = lltb; + ep = tp+lltbsiz-1; + for (lp = ctx->llbuf; lp < ctx->llend && tp < ep;) + *tp++ = *lp++; + *tp = 0; + return(tp-lltb); +} + + +int nseel_yylex(compileContext *ctx, char **exp) +{ + register int c, st; + int final, l, llk, i; + register struct lextab *lp; + char *cp; + + while (1) + { + llk = 0; + if (llset(ctx)) return(0); + st = 0; + final = -1; + lp = &nseel_lextab; + + do { + if (lp->lllook && (l = lp->lllook[st])) { + for (c=0; cllsave[c] = ctx->llp1; + llk++; + } + if ((i = lp->llfinal[st]) != -1) { + final = i; + ctx->llend = ctx->llp1; + } + if ((c = llinp(ctx,exp)) < 0) + break; + if ((cp = lp->llbrk) && llk==0 && tst__b(c, cp)) { + ctx->llp1--; + break; + } + } while ((st = (*lp->llmove)(lp, c, st)) != -1); + + + if (ctx->llp2 < ctx->llp1) + ctx->llp2 = ctx->llp1; + if (final == -1) { + ctx->llend = ctx->llp1; + if (st == 0 && c < 0) + return(0); + if ((cp = lp->llill) && tst__b(c, cp)) { + continue; + } + return(YYERRORVAL); + } + if ((c = (final >> 11) & 037)) + ctx->llend = ctx->llsave[c-1]; + if ((c = (*lp->llactr)(ctx,final&03777)) >= 0) + return(c); + } +} + +void nseel_llinit(compileContext *ctx) +{ + ctx->llp1 = ctx->llp2 = ctx->llend = ctx->llbuf; + ctx->llebuf = ctx->llbuf + sizeof(ctx->llbuf); + ctx->lleof = ctx->yyline = 0; +} + + +static int llinp(compileContext *ctx, char **exp) +{ + register int c; + register struct lextab *lp; + register char *cp; + + lp = &nseel_lextab; + cp = lp->llign; /* Ignore class */ + for (;;) { + /* + * Get the next character from the save buffer (if possible) + * If the save buffer's empty, then return EOF or the next + * input character. Ignore the character if it's in the + * ignore class. + */ + c = (ctx->llp1 < ctx->llp2) ? *ctx->llp1 & 0377 : (ctx->lleof) ? EOF : lexgetc(exp); + if (c >= 0) { /* Got a character? */ + if (cp && tst__b(c, cp)) + continue; /* Ignore it */ + if (ctx->llp1 >= ctx->llebuf) { /* No, is there room? */ + return -1; + } + *ctx->llp1++ = c; /* Store in token buff */ + } else + ctx->lleof = 1; /* Set EOF signal */ + return(c); + } +} + +static int llset(compileContext *ctx) +/* + * Return TRUE if EOF and nothing was moved in the look-ahead buffer + */ +{ + register char *lp1, *lp2; + + for (lp1 = ctx->llbuf, lp2 = ctx->llend; lp2 < ctx->llp2;) + *lp1++ = *lp2++; + ctx->llend = ctx->llp1 = ctx->llbuf; + ctx->llp2 = lp1; + return(ctx->lleof && lp1 == ctx->llbuf); +} diff --git a/nu/AutoCharFn.h b/nu/AutoCharFn.h new file mode 100644 index 0000000..3b5b775 --- /dev/null +++ b/nu/AutoCharFn.h @@ -0,0 +1,50 @@ +#ifndef NULLSOFT_UTILITY_AUTOCHARFN_H +#define NULLSOFT_UTILITY_AUTOCHARFN_H + +/* Winamp defines this, but this little block lets us use this thing outside of Winamp */ +#ifndef FILENAME_SIZE +#define FILENAME_SIZE (MAX_PATH*4) +#define REMOVE_FILENAME_SIZE +#endif + + +#include +#include + +class AutoCharFn +{ +public: + AutoCharFn(const wchar_t *filename) + { + out[0]=0; + if (!filename) + return; + if (PathIsURLW(filename)) + { + WideCharToMultiByte(CP_ACP, 0, filename, -1, out, FILENAME_SIZE, NULL, NULL); + return ; + } + + BOOL unconvertable = FALSE; + WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, filename, -1, out, FILENAME_SIZE, NULL, &unconvertable); + + if (unconvertable) + { + wchar_t temp[MAX_PATH]; + if (GetShortPathNameW(filename, temp, MAX_PATH)) + WideCharToMultiByte(CP_ACP, 0, temp, -1, out, FILENAME_SIZE, NULL, NULL); + + } + } + + operator char *() { return out; } +private: + char out[FILENAME_SIZE]; +}; + + +#ifdef REMOVE_FILENAME_SIZE +#undef FILENAME_SIZE +#endif + +#endif diff --git a/nu/AutoWide.h b/nu/AutoWide.h new file mode 100644 index 0000000..26f3edb --- /dev/null +++ b/nu/AutoWide.h @@ -0,0 +1,86 @@ +#ifndef AUTOWIDEH +#define AUTOWIDEH +#ifdef WIN32 +#include + +inline wchar_t *AutoWideDup(const char *convert, UINT codePage=CP_ACP) +{ + wchar_t *wide = 0; + if (!convert) + return 0; + + int size = MultiByteToWideChar(codePage, 0, convert, -1, 0,0); + if (!size) + return 0; + + wide = (wchar_t *)malloc(size*sizeof(wchar_t)); + if (!MultiByteToWideChar(codePage, 0, convert, -1, wide,size)) + { + free(wide); + wide=0; + } + return wide; +} + +class AutoWide +{ +public: + AutoWide(const char *convert, UINT codePage=CP_ACP) : wide(0) + { + wide = AutoWideDup(convert, codePage); + } + ~AutoWide() + { + free(wide); + wide=0; + } + operator wchar_t *() + { + return wide; + } +private: + wchar_t *wide; +}; +#elif defined(__APPLE__) +#include +inline wchar_t *AutoWideDup(const char *convert) +{ + wchar_t *wide=0; + if (!convert) + return 0; + int size = strlen(convert)+1; + if (!size) + return 0; + + wide = (wchar_t *)malloc(size*sizeof(wchar_t)); + if (mbstowcs(wide, convert, size) == (size_t)-1) + { + free(wide); + wide=0; + } + return wide; +} + +class AutoWide +{ +public: + AutoWide(const char *convert) : wide(0) + { + wide = AutoWideDup(convert); + } + ~AutoWide() + { + free(wide); + wide=0; + } + operator wchar_t *() + { + return wide; + } +private: + wchar_t *wide; +}; + +#endif + +#endif \ No newline at end of file diff --git a/nu/Vector.h b/nu/Vector.h new file mode 100644 index 0000000..4c0b4ae --- /dev/null +++ b/nu/Vector.h @@ -0,0 +1,223 @@ +#ifndef NULLSOFT_VECTOR_H +#define NULLSOFT_VECTOR_H +#include +#include + +template +class Vector +{ +public: + typedef Type *iterator; + typedef const Type *const_iterator; +public: + Vector() : values(0), numPtrs(0), allocSize(0) + {} + virtual ~Vector() + { + delete [] values; + } + + Vector(const Vector ©): values(0), numPtrs(0), allocSize(0) + { + if (copy.numPtrs) + { + values = new Type[copy.numPtrs]; + allocSize = copy.numPtrs; + numPtrs = copy.numPtrs; + for (size_t i = 0;i != numPtrs;i++) + { + values[i] = copy.values[i]; + } + } + } + + void operator=(const Vector ©) + { + Reset(); + if (copy.numPtrs) + { + values = new Type[copy.numPtrs]; + allocSize = copy.numPtrs; + numPtrs = copy.numPtrs; + for (size_t i = 0;i != numPtrs;i++) + { + values[i] = copy.values[i]; + } + } + } + + Type &operator[](size_t index) + { + return values[index]; + } + Type *data() + { + return values; + } + Type *begin() const + { + return values; + } + Type *end() const + { + if (values) return values + numPtrs; else return 0; + } + void Reset() + { + delete [] values; values = 0; numPtrs = 0; allocSize=0; + } + void clear() + { + numPtrs = 0; + } + size_t size() const + { + return numPtrs; + } + size_t capacity() + { + return allocSize; + } + Type &back() + { + return values[numPtrs-1]; + } + + Type &at(size_t index) const + { + return values[index]; + } + + void reserve(size_t size) + { + if (size <= numPtrs) + return; + + Type *newTable = new Type[size]; + for (size_t i = 0;i != numPtrs;i++) + { + newTable[i] = values[i]; + } + allocSize = size; + delete[] values; + values = newTable; + } + + void push_back(Type t) + { + if (numPtrs == allocSize) + reserve(allocSize*MULTIPLIER + INCREMENT); + values[numPtrs++] = t; + } + + void insert(size_t index, const Type &value) + { + if (numPtrs == allocSize) + reserve(allocSize*MULTIPLIER + INCREMENT); + + for (size_t i = numPtrs;i != index;i--) + { + values[i] = values[i-1]; + } + values[index] = value; + numPtrs++; + } + + void append(size_t size, Type *t) + { + reserve(numPtrs + size + INCREMENT); + for (size_t i = 0;i != size;i++) + { + push_back(t[i]); + } + } + + void pop_back() + { + if (numPtrs) + { + numPtrs--; + // next line removed to allow structs and classes + // values[numPtrs] = 0; // TODO: an inplace delete might be better? + } + } + + void erase(iterator itr) + { + size_t index = itr - values; + eraseAt(index); + } + + void eraseAt(size_t index) + { + if (numPtrs > index) + { + for (size_t k = index + 1; k < numPtrs; k++) + { + values[k-1] = values[k]; + } + numPtrs--; + } + } + + /* Removes an item by swapping it with the last item in the list. faster but can ruin order */ + void eraseAtFast(size_t index) + { + if (index < numPtrs) + { + values[index] = values[--numPtrs]; +// if (numPtrs != index) +// values[numPtrs]=0; + } + } + + bool empty() const + { + return numPtrs == 0; + } + + void resize(size_t newSize, Type val) + { + if (newSize < numPtrs) + { + numPtrs = newSize; + } + else if (newSize > numPtrs) + { + reserve(allocSize + (newSize - numPtrs) + INCREMENT); + + while(numPtrs < newSize) + { + values[numPtrs] = val; + numPtrs++; + } + } + } + + void resize(size_t newSize) + { + if (newSize < numPtrs) + { + numPtrs = newSize; + } + else if (newSize > numPtrs) + { + reserve(allocSize + (newSize - numPtrs) + INCREMENT); + numPtrs = newSize; + } + } + + void set(Type *ptr, size_t num) + { + delete [] values; + values=ptr; + numPtrs=num; + } + +private: + size_t numPtrs; + size_t allocSize; + Type *values; +}; + +#endif diff --git a/vis_milk2/DOCUMENTATION.TXT b/vis_milk2/DOCUMENTATION.TXT new file mode 100644 index 0000000..df3ef7f --- /dev/null +++ b/vis_milk2/DOCUMENTATION.TXT @@ -0,0 +1,1022 @@ + +----------------------------------------------------------------------- + WINAMP 2.X VISUALIZATION PLUG-IN "MEGA SDK" + ('Vis Mega SDK' for short) + ('VMS' for shorter) +----------------------------------------------------------------------- + Description: A codebase for rapidly creating robust and feature-rich + DX8-based visualization plug-ins of your own. + Version: custom version based on 1.05 beta 1; upgraded to use DX9. + Released: n/a + Author: Ryan Geiss + Copyright: (c) 2002-2007 Nullsoft, Inc. + VMS HOMEPAGE: http://www.nullsoft.com/free/vms/ + VMS AT WINAMP: http://www.winamp.com/nsdn/winamp2x/dev/plugins/vis.jhtml + SUPPORT FORUM: http://forums.winamp.com/forumdisplay.php?forumid=147 +----------------------------------------------------------------------- + + +TABLE OF CONTENTS +----------------- + 1. Purpose of this package + 2. Features + 3. Required software + 4. Setting up the build environment + 5. Starting Your Own Plugin Based on the Framework + 6. Writing your own Plugin: A Brief Tour + 7. Order of Function Calls + 8. Using Data From the Base Class (CPluginShell) + 9. Adding Controls to the Config Panel + 10. Enabling Additional Tabs (pages) on the Config Panel + 11. Using Visual C++ to Debug your Plugin + 12. Releasing a Plugin + 13. Tips to pass on the the user, in your documentation + 14. Performance Tips for DirectX 8 + 15. Other Resources + 16. Known Bugs + 17. Version History + 18. License + + +Purpose of this package +----------------------- + This package is for DEVELOPERS who want to write their own + visualization plugins. + + It aims to provide a codebase that enables all developers + (beginning to advanced) to easily build robust Winamp 2.x + visualization plugins whose graphics are to be generated + though the DirectX 8 API. This codebase will 1) drastically + reduce the time it takes to write your plugin, 2) ensure + that it is robust (if you follow directions), and 3) give + you built-in support for many cool features, such as + multiple monitors. (See below for more details.) + + Feel free to base any plugins on this "framework". + + +Features +-------- + -DESKTOP MODE. Lets your plugin run as animated wallpaper, + with very little CPU overhead. (Your plugin can also + run in windowed or fullscreen modes, and the user can + switch between all 3 on the fly.) + -SUPERIOR MULTIMON SUPPORT. Your plugin will work on systems + with multiple display adapters, as well as systems with + a multi-head card. For multi-head cards that treat all + screens as one giant display (ie. resolutions like 2048x768 + or 1024x1536), your users can even use 'fake' fullscreen mode + to run your plugin fullscreen on just one monitor! + -SOUND ANALYSIS: the framework provides your plugin with a + super-high-quality FFT (fast fourier transform) for doing your + own frequency analysis, or for drawing spectra. Framework also + provides super-simple loudness levels for 3 bands (bass, + mids, and treble) and at varying attenuation (damping) rates. + -A very nice CONFIGURATION PANEL is provided for the plugin. + On the first page (tab) of the config panel are all the + settings that all plugins share in common [handled by VMS]; + on subsequent tabs, you add your own controls, for settings + that are specific to your plugin. The example plugin also + shows you how to easily handle the reading/writing of settings + that you add to/from the .INI file that will store your + plugin's settings. + -OTHER PERKS like a runtime help screen and playlist; high-precision + timing (accurate to 10 microseconds, or 0.00001 seconds); + pause-filtering (so your timing code won't got haywire + when Winamp is unpaused); and many others. + -CPU-FRIENDLY: when the window is minimized, or when you're + in fullscreen mode and ALT-TAB out, the plugin sleeps to + preserve CPU. FPS limiting also does its best to preserve + CPU, while at the same time, accurately limiting the FPS. + -ERROR FEEDBACK: provides detailed error messages to the user + on failure, as well as suggestions on how to fix problems. + + +Required software +----------------- + 1. Nullsoft Winamp 2.X (~1 MB) + http://www.winamp.com/ + 2. Microsoft DirectX 8.0+ - (~11 MB) + http://www.microsoft.com/windows/directx/ + 3. Microsoft Developer Studio (Visual C++) 6.0 + (a retail product) + 4. Microsoft DirectX 8.0 SDK (Software Development Kit) - (~173 MB) + http://www.microsoft.com/windows/directx/ + (then click the 'msdn' icon in the lower right, under + "info for developers") + *** NOTE that you can use a later SDK, such as 8.1b; but if you + do, then your plugin will only run on systems with that version + (or later) of the DirectX runtime installed! *** + *** You can also install several versions of the SDK into + different directories, and as long as the 8.0 sdk paths are + selected in Dev Studio (see below), your plugin will only + require the 8.0 runtime. *** + 5. MSDN (Microsoft Developer Network) help library (OPTIONAL) (~1GB) + (also a retail product; optional, but highly recommended + to have around. If you can't get the CD's, though, you + can always access the help database online at + http://msdn.microsoft.com/library/ ) + + +Setting up the build environment +-------------------------------- + [Note: for Visual C++ .Net users, see below] + + 1. Make sure DirectX 8.0 or later is installed. + 2. Make sure the DirectX 8.0 SDK (source development kit) is installed. + ** (see notes above & below) ** + 3. Configure Visual C++ to use the [appropriate] DX8 SDK: + + In Visual C++, go to Tools, then Options. Click on the + 'Directories' tab. Under 'Show directories for:', select + 'Include Files.' Then, below, add the INCLUDE folder + underneath the folder into which you installed the DX8 SDK. + Now highlight your addition and use the fancy-looking 'up' + arrow icon to move it to the top of the list of directories. + + Now do the same thing for the LIB folder. Under 'Show + directories for:', select 'Library Files.' Now add the LIB + folder underneath the folder into which you installed the + DX8 SDK. Again, use the fancy-looking 'up' arrow icon + to move it to the top of the list of directories. + + *** NOTE that if you have multiple DirectX 8 SDK's (such as 8.0 + and 8.1b) installed to different directories, you'll want the + earliest one (hopefully 8.0) to be first in the list; that's + the one that will get used when you compile & link. Otherwise, + your plugin will only run on systems with the other version + (or later) of the DirectX runtime installed! *** + + 4. (optional) you might want to set Visual C++ up to use + 4 spaces instead of symbolic tabs, to keep the formatting + of new code that you write consistent with this code. + If you want to do this, go to menu:Tools->Options, click + the 'Tabs' tab, set the 'Tab Size' to 4 and click on + 'Insert Spaces'. + + [FOR VISUAL C++ .NET USERS:] + You'll want to start a fresh DLL-based project and manually + add all the source/header files to it. Then go into project + settings and make it **Use MFC in a SHARED DLL**. + + +Starting Your Own Plugin Based on the Framework +----------------------------------------------- + 1. Copy the files in the 'ExPlugin' folder to a new folder, + such as 'MyPlugin' - it can be anything. + 2. In the new folder, rename the workspace file ExPlugin.dsw + to MyPlugin.dsw (or equivalent). + 3. Open the new workspace file (that you just renamed) in Visual C++. + 4. Go to menu:Build->Configurations and select 'plugin - Win32 Debug'. + 5. Go to menu:Project->Settings + a. In the upper-left corner, where it says 'Settings For:', + select 'All Configurations' from the dropdown box. + b. Click the 'debug' tab, and under 'Executable for debug + session', point it to winamp.exe (most likely + c:\program files\winamp\winamp.exe). (This will enable + you to debug your plugin using Visual C++.) + c. Click the 'link' tab, and under 'Output file name', + enter the name of the .DLL to write (such as + c:\program files\winamp\plugins\vis_myplugin.dll). + This should start with 'vis_' and end in the + '.dll' extension. This DLL will be your plugin. + d. click OK. + 6. On the left you should see the workspace view (if not, hit ALT+ZERO) + to bring it up) with 3 tabs at the bottom (ClassView, ResourceView, + FileView). Click 'FileView'. Expand everything in this view so you + can see all the files. + 7. Open 'defines.h' by double-clicking it. Now edit this file according + to the comments, to give your plugin a name, a version number, enter + the author's name, copyright string, the name of the .INI file you + want to save the user's settings in, the name of the documentation + file, and so on. (You can always come back and change these values + later, of course). + + Now you're ready to build & run the plugin: + + 8. Press F7 to build the plugin. + a. If you get any of these error messages: + fatal error C1083: Cannot open include file: 'd3d8.h'... + fatal error C1083: Cannot open include file: 'd3dx8.h'... + Then you haven't added the DX8 SDK *include* path to your + build environment. See 'To set up the build environment' + above. + b. If you any linker error messages, such as this one: + LINK : fatal error LNK1104: cannot open file "d3d8.lib" + Then you haven't added the DX8 SDK *library* file path to your + build environment. See 'To set up the build environment' + above. + + 9. Copy the files 'ex_tex.jpg' and 'vms_desktop.dll' from the MyPlugin + directory to your Winamp PLUGINS folder (usually c:\program files\ + winamp\plugins). + + 10. Run Winamp, press CTRL+P to select your plugin, and make sure that + it appears in the list. Notice that the name matches what you + entered into the 'defines.h' file as APPNAME; if you didn't change + it, it will appear as 'Example Plugin v1.04 / VisMegaSDK' (or + something similar). Next, configure the plugin, hit OK, & run it + by clicking 'Start'. + + +Writing your own Plugin: A Brief Tour +------------------------------------- + This starts out by pointing you at the important source code, + then by showing you around the resource editor and, finally, + the DirectX 8 and MSDN help libraries. + + 1. Take a look at each of the 6 files in the 'My Plugin Source Files' + and 'My Plugin Header Files' groups. These will give you an idea + of the code that makes up the example plugin. All of the + behind-the-scenes code is wrapped up in the 'Framework Files' + group, which you shouldn't have to bother with (unless you + want to). + + 2. Take a close look at plugin.h. This is the C++ class that makes + up your plugin. Note that the class is derived from the + CPluginShell class (which is in pluginshell.h/cpp), so it inherits + all its functions & variables. What you see here (in plugin.h) + are the data members and functions ADDED for this specific + (example) plugin, as well as the 12 pure virtual functions we've + implemented from the base class. + + 3. Take a close look at plugin.cpp. READ THE BRIEF COMMENTS AT THE + TOP OF THOSE 12 VIRTUAL FUNCTIONS TO GET AN IDEA OF WHEN THEY'RE + CALLED AND WHAT THEY DO. + + 4. Next we'll go into the Resource Editor. + Click the 'ResourceView' tab at the bottom of the Workspace view. + Then expand 'plugin resources' by double-clicking it, expand + 'Dialog' in the same way, and double-click 'IDD_CONFIG' to open + the template for the config panel. You can now double-click + individual controls to edit their properties; move/resize them; + press CTRL+T to test the dialog; press CTRL+D to define the tab + order; and even add new controls (using the floating toolbar) + (note that added controls require a lot of support code in + plugin.cpp; see 'Adding Controls to the Config Panel' below). + + Also expand the 'Icon' folder on the left (just after 'Dialog') + and double-click IDI_PLUGIN_ICON. This is the icon used in the + taskbar, window title, and ALT+TAB screen when your plugin is + running. Note that there are 5 different icons within this one, + all at different resolutions and color depths, accessible by + changing the 'device' (just above the enlarged icon in the + resource editor). So, when you go to update the icon, don't forget + to update it for all devices! + + 5. In Windows, go to Start Menu -> Program Files -> Microsoft + DirectX 8 SDK -> DirectX Documentation (Visual C++). This + is the help library for DirectX 8; you will need to refer to + it religiously in order to get anything done in DirectX 8. + The good news is, it's *extremely* well-written. + + 6. In Windows, go to Start Menu -> Program Files -> Microsoft + Developer Network -> MSDN Library. This is the help library + for the general Win32 platform, but might not have info on + DirectX 8 (depending on when your version was published). + If you couldn't get the MSDN CD's, you can access the MSDN + library online at: + http://msdn.microsoft.com/library/ + You'll have to do this from time to time to write a plugin, + but not nearly as often as you'll be accessing the DirectX 8 + help library. + + You might also want to take a look at the useful goodies inside + utility.cpp; they could come in handy. + + That's it; you've now seen all the 'screens' you'll spend 99% of + your time on, in order to write your own plugin. + + +Order of Function Calls +----------------------- + The only code that will be called by the plugin framework are the + 12 virtual functions in plugin.h. But in what order are they called? + A breakdown follows. A function name in { } means that it is only + called under certain conditions. + + Order of function calls... + + When the PLUGIN launches + ------------------------ + INITIALIZATION + OverrideDefaults + MyPreInitialize + MyReadConfig + << DirectX gets initialized at this point >> + AllocateMyNonDx8Stuff + AllocateMyDX8Stuff + RUNNING + +--> { CleanUpMyDX8Stuff + AllocateMyDX8Stuff } // called together when user resizes window or toggles fullscreen<->windowed. + | MyRenderFn + | MyRenderUI + | { MyWindowProc } // called, between frames, on mouse/keyboard/system events. 100% threadsafe. + +----<< repeat >> + CLEANUP + CleanUpMyDX8Stuff + CleanUpMyNonDx8Stuff + << DirectX gets uninitialized at this point >> + + When the CONFIG PANEL launches + ------------------------------ + INITIALIZATION + OverrideDefaults + MyPreInitialize + MyReadConfig + << DirectX gets initialized at this point >> + RUNNING + { MyConfigTabProc } // called on startup & on keyboard events + CLEANUP + [ MyWriteConfig ] // only called if user clicked 'OK' to exit + << DirectX gets uninitialized at this point >> + + +Using Data From the Base Class (CPluginShell) +--------------------------------------------- + The base class from which your CPlugin class (in plugin.cpp) is + derived is called CPluginShell and is defined in pluginshell.cpp. + Many of its data members are 'protected', which means that only that + class itself, *plus derived classes*, can access them. ('Public' + members can be accessed by anyone; 'private' are unaccessible even + to derived classes.) + + The protected data members and methods (functions) are as follows. + Generally, you should treat the data members as READ-ONLY; the only + exception is in OverrideDefaults(), where you can modify some of + their values to alter the "default defaults". See the comments at + the top of OverrideDefaults() in plugin.cpp for more information. + + Here are all of the members & methods maintained by the plugin shell, + and available to CPlugin: + + + // GET METHODS + // ------------------------------------------------------------ + int GetFrame(); // returns current frame # (starts at zero) + float GetTime(); // returns current animation time (in seconds) (starts at zero) (updated once per frame) + float GetFps(); // returns current estimate of framerate (frames per second) + eScrMode GetScreenMode(); // returns WINDOWED, FULLSCREEN, FAKE_FULLSCREEN, DESKTOP, or NOT_YET_KNOWN (if called before or during OverrideDefaults()). + HWND GetWinampWindow(); // returns handle to Winamp main window + HINSTANCE GetInstance(); // returns handle to the plugin DLL module; used for things like loading resources (dialogs, bitmaps, icons...) that are built into the plugin. + char* GetPluginsDirPath(); // usually returns 'c:\\program files\\winamp\\plugins\\' + char* GetConfigIniFile(); // usually returns 'c:\\program files\\winamp\\plugins\\something.ini' - filename is determined from identifiers in 'defines.h' + + // GET METHODS THAT ONLY WORK ONCE DIRECTX IS READY + // ------------------------------------------------------------ + // The following 'Get' methods are only available after DirectX has been initialized. + // If you call these from OverrideDefaults, MyPreInitialize, or MyReadConfig, + // they will return NULL (zero). + // ------------------------------------------------------------ + HWND GetPluginWindow(); // returns handle to the plugin window. NOT persistent; can change! + int GetWidth(); // returns width of plugin window interior, in pixels. + int GetHeight(); // returns height of plugin window interior, in pixels. + int GetBitDepth(); // returns 8, 16, 24 (rare), or 32 + LPDIRECT3DDEVICE8 GetDevice(); // returns a pointer to the DirectX 8 Device. NOT persistent; can change! + D3DCAPS8* GetCaps(); // returns a pointer to the D3DCAPS8 structer for the device. NOT persistent; can change. + D3DFORMAT GetBackBufFormat(); // returns the pixelformat of the back buffer (probably D3DFMT_R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5, D3DFMT_A4R4G4B4, D3DFMT_R3G3B2, D3DFMT_A8R3G3B2, D3DFMT_X4R4G4B4, or D3DFMT_UNKNOWN) + D3DFORMAT GetBackBufZFormat(); // returns the pixelformat of the back buffer's Z buffer (probably D3DFMT_D16_LOCKABLE, D3DFMT_D32, D3DFMT_D15S1, D3DFMT_D24S8, D3DFMT_D16, D3DFMT_D24X8, D3DFMT_D24X4S4, or D3DFMT_UNKNOWN) + char* GetDriverFilename(); // returns a text string with the filename of the current display adapter driver, such as "nv4_disp.dll" + char* GetDriverDescription(); // returns a text string describing the current display adapter, such as "NVIDIA GeForce4 Ti 4200" + + // FONTS & TEXT + // ------------------------------------------------------------ + LPD3DXFONT GetFont(eFontIndex idx); // returns a D3DX font handle for drawing text; see shell_defines.h for the definition of the 'eFontIndex' enum. + int GetFontHeight(eFontIndex idx); // returns the height of the font, in pixels; see shell_defines.h for the definition of the 'eFontIndex' enum. + + // MISC + // ------------------------------------------------------------ + td_soundinfo m_sound; // a structure always containing the most recent sound analysis information; defined in pluginshell.h. + void SuggestHowToFreeSomeMem(); // gives the user a 'smart' messagebox that suggests how they can free up some video memory. + + // CONFIG PANEL SETTINGS + // ------------------------------------------------------------ + // *** only read/write these values during CPlugin::OverrideDefaults! *** + int m_start_fullscreen; // 0 or 1 + int m_start_desktop; // 0 or 1 + int m_fake_fullscreen_mode; // 0 or 1 + int m_max_fps_fs; // 1-120, or 0 for 'unlimited' + int m_max_fps_dm; // 1-120, or 0 for 'unlimited' + int m_max_fps_w; // 1-120, or 0 for 'unlimited' + int m_show_press_f1_msg; // 0 or 1 + int m_allow_page_tearing_w; // 0 or 1 + int m_allow_page_tearing_fs; // 0 or 1 + int m_allow_page_tearing_dm; // 0 or 1 + int m_minimize_winamp; // 0 or 1 + int m_desktop_show_icons; // 0 or 1 + int m_desktop_textlabel_boxes; // 0 or 1 + int m_desktop_manual_icon_scoot; // 0 or 1 + int m_desktop_555_fix; // 0 = 555, 1 = 565, 2 = 888 + int m_dualhead_horz; // 0 = both, 1 = left, 2 = right + int m_dualhead_vert; // 0 = both, 1 = top, 2 = bottom + int m_save_cpu; // 0 or 1 + int m_skin; // 0 or 1 + td_fontinfo m_fontinfo[NUM_BASIC_FONTS + NUM_EXTRA_FONTS]; + D3DDISPLAYMODE m_disp_mode_fs; // a D3DDISPLAYMODE struct that specifies the width, height, refresh rate, and color format to use when the plugin goes fullscreen. + + +Adding Controls to the Config Panel +----------------------------------- + There are four basic aspects of adding a new control to the config panel, + outlined below. + + 1. Add the control to one of the property pages in the config panel (2..8), + via the Resource Editor. Note that you should not modify the config + panel itself (IDD_CONFIG) or the first property page (IDD_PROPSHEET_1). + Also, do not resize the page dialogs or the config panel; they are designed + to fit on a 640x480 screen, and should not be expanded. + + 2. Add a variable (data member) to represent the control to your CPlugin class, + in plugin.h. + + 3. In plugin.cpp: + a. initialize the variable to its default value in MyPreInitialize(), + b. read its value from the INI file in MyReadConfig(), and + c. write its value to the INI file in MyWriteConfig(). + + 4. In plugin.cpp, in the MyConfigTabProc function, **when 'nPage' is + the index (2..8) of the tab on which the control was placed:** + a. add code under WM_INITDIALOG to set the state of the control + (from the variable) when the config panel is started + b. add code under WM_COMMAND, case IDOK, to read the state + of the control and save the result in the variable + c. add a handler for your new control underneath WM_HELP, so that + when the user clicks the '?' in the config panel titlebar, + then clicks on your control, they get a helpful messagebox + explaining what the control does. + + +Enabling Additional Tabs (pages) on the Config Panel +---------------------------------------------------- + By default, only two 'tabs' (pages) are enabled on the config panel. + The first is handled by the framework, and should not be modified; + the second, and any you add, are handled in plugin.cpp, in MyConfigTabProc(). + The maximum number of tabs/pages is 8 (unless you want to modify the + framework files). + + To add a third page (for example), simply open defines.h, and give a name + to the tab by setting the value of CONFIG_PANEL_BUTTON_3. This is all you + have to do to make the tab appear! To add controls to the new page, see + the above section entitled 'Adding Controls to the Config Panel.' + + If you want to extend the framework to add a 9th page (?!), you need to: + 1. create a dialog called IDD_PROPPAGE_9 (style=child, border=none, visible, ctrl parent, control). + 2. in config.cpp, increment MAX_PROPERTY_PAGES + 3. in config.cpp, add IDD_PROPPAGE_9 to g_proppage_id[] + 4. in config.cpp, call AddButton for it + + +Using Visual C++ to Debug your Plugin +------------------------------------- + 1. Build the plugin in the 'Debug' configuration + (menu:Build->Configurations, then select 'debug'). + 2. Go to menu:Project->Settings (ALT+F7) and click the + 'Debug' tab. Under 'Executable for debug session', + point it to winamp.exe. + 3. Press F5 to start debug session; it will launch winamp. + 4. You can now configure your plugin or run it; just set a + breakpoint anywhere in your code (F9) and when the code + gets to that point, it will break, and you can look at + variable values and browse structures (SHIFT+F9), jump + around on the call stack (ALT+7), and so on. + + +Releasing a Plugin +------------------ + 1. Build in Release Mode + + Once you're done debugging and ready to share your plugin + with others, go to menu:Build->Configurations and select + 'plugin - Win32 Release', then go to menu:Build->Clean and + menu:Build->Rebuild All. Building in release mode makes + your code smaller and faster (but doesn't allow debugging). + + 2. Package it up an a self-installing .EXE + + Here you'll want to download the Nullsoft Superpimp Install + System (NSIS) from http://www.nullsoft.com/free/nsis/ to + make your users' lives easier. + + Then read the instructions at the top of the install script + file 'installer.nsi' (next to DOCUMENTATION.TXT) and edit the + install script to reflect the name and version of your plugin, + the paths & filenames & destination paths of everything you + want packaged up, and the output installer filename. + + After installing NSIS, editing installer.nsi, and doing + a final release build, run a command something like this + from the command prompt (you'll have to adjust the paths): + + "c:\program files\Nsis\makensis" C:\MyProjects\MyPlugin\installer.nsi + + If all goes well, you'll have a file named something like + 'myplugin_100.exe' in your MyPlugin directory. Test it + out on a fresh machine to make sure the install screens + say the right thing and install the right files, and + you're set to go! + + 3. Checklist: (prior to actually running makensis.exe) + + * Did you update the version number and APPNAME in defines.h? + * Did you do a final pass on the tab ordering (CTRL+D from the + Resource Editor) of the config panel? + * Did you add WM_HELP handlers to new controls on the config panel? + * If you added any MessageBox() commands, did you supply the right + HWND parameter? (The messagebox will pop up on the same monitor + that that HWND is on.) + * Did you test your plugin in Desktop Mode, while Winamp is + *paused*, and then try moving icons around, to make sure that + you're properly handling the 'redraw' flag in MyRenderFn()? + * Did you update the version numbers throughout installer.nsi? + * Did you update the help screen text? (see top of plugin.cpp) + * Did you do your final build in Release mode? + * Did you write/update documentation? + Does the config panel link to it work? + * Did you make/update a webpage? + Does the config panel link to it work? + + +Tips to pass on the the user, in your documentation +--------------------------------------------------- + 1. In general, it's a very good idea to use only Microsoft-certified + WHQL (Windows Hardware Quality Labs) drivers for your video card. + Often people want to get the newest, fastest beta drivers, but + these drivers are almost ALWAYS riddled with new bugs. + + 2. If you want Winamp to listen to your sound card's Line-In or Mic-In + (or other audio input channel on your system) for driving the + visuals, just do the following: + + 1. CONNECT WIRES + Connect your audio source (a stereo, a live feed, whatever) into + the line-in (or microphone) 1/8" jack on your sound card. + + 2. SELECT SOUND INPUT CHANNEL & ADJUST VOLUME + In Windows, double-click the speaker icon in your systray (where + the clock is). Then, on the menu, go to Options -> Properties + and select the "Recording" option. Then make sure the Line In + (or Microphone) input channel (whichever is appropriate for + your case) is SELECTED (with a check mark) and that the volume + is close to, or at, the maximum. Hit OK. + + 3. TELL WINAMP TO USE LINE-IN + Open Winamp, and hit CTRL+L (the "Open Location" hotkey). Now + type in "linein://" as the location you want to open. (Leave out + the quotes and make sure you use FORWARD slashes.) Hit PLAY + in Winamp, and the little built-in oscilloscope (or spectrum + analyzer) in Winamp should start showing your signal. + + 4. RUN YOUR VISUALIZATION PLUGIN OF CHOICE + If the plugin seems to be responding too much or too little, + try adjusting the volume from Windows' Volume Control, or adjust + the sound level at the source. + + 3. For the best graphics performance, try to close as many other + applications as you can, before running the plugin, especially + those that tend to work in the background, such as anti-virus + or file-swapping software. Also, if you must leave other + applications open, try to minimize them (i.e. shrink the window + down to the taskbar) so that they stay out of the painting loop. + + 4. LCD screens: Note that most LCD screens (flatpanels) run at 60 Hz only, + meaning that they update the screen 60 times per second. However, + sometimes the video driver reports that it supports other refresh + rates, such as 72, 75, 85, etc. It is strongly recommended that + [for fullscreen mode, and for Windows in general] you choose a + display mode with a 60 Hz refresh rate, for the smoothest possible + animation. For this plugin, you will also want to choose + Maximum Framerates that divide evenly into 60 - such as 60, 30, 20, + 15, 12, 10, 6, 5, and so on - so that the # of times the LCD shows + each frame of animation remains constant, resulting in the smoothest + possible animation. + + 5. Multiple Monitors: It is recommended that whenever you modify your Windows + multimon setup (i.e. turn an adapter on/off, change its color depth, etc.) + that you reboot Windows before running this plugin. + + 6. Video Capture: If you'd like to save sequences of video from this plugin, + there are several programs out there that will let you do this. Warning: + you will need a ton of free hard drive space, and a fast CPU helps. A + few of these programs are: + "FRAPS" http://www.fraps.com/ + "Hypercam" http://www.hyperionics.com + + (That's it, for now. PLEASE include the tip about live audio input!) + + +Performance Tips for DirectX 8 +------------------------------ + 1. Minimize state changes (SetTexture, SetTextureStageState, + and SetRenderState) at all cost; group polygons together + that share the same rendering settings and send them all + together. You will be amazed at the performance gain. + + 2. Use Vertex Buffers and Index Buffers for all your static + geometry (i.e. vertices/indices that don't change every + frame - like a static model that doesn't change, even + though it might move around, rotate, resize, etc. due + to the world/view/projection matrices). These buffers + will keep the geometry in video memory (if possible) so + that the data doesn't have to cross the bus every frame; + if not, they'll try to at least place the geometry/indices + in AGP memory. If you don't use these driver-managed + buffers (and instead use DrawPrimitiveUP and + DrawIndexedPrimitiveUP), you're keeping all of your data + in non-AGP system memory, and unless the data is very + small, you can expect a major bottleneck. Note that for + dynamically-generated vertex data (i.e. vertices are + generated each frame - like when you draw a waveform), + you don't have a choice. + + If you follow these two tips and use common sense (and know + the basic theory behind how 3D accelerators work), you should + be getting 30 fps on a Voodoo 3 (assuming your overdraw is low, + i.e. you don't draw each pixel on the screen more than once or + twice per frame). + + For more tips, look in the DX8 SDK Documentation, or look on + the web. + + +Other Resources +--------------- + 1. DX8 SDK: The DX8 documentation that came with your DX8 SDK is, + by far, the most critical resource you have. It fully documents + the entire API, and much more. The SDK also comes with tons of + samples and their source code. + 2. NSDN: the Nullsoft Developer Network, where the Winamp API + is published: http://www.winamp.com/nsdn/winamp2x/ + If you want to do anything in MyWindowProc() that involves + communicating with the Winamp window directly (such as + querying for the song title/time/length, querying the playlist, + adjusting the panning, toggling shuffle, etc.), you'll need + to delve into NSDN. It's all extremely straightforward and + simple. For a few examples of how to talk to the main Winamp + window, check out PluginShellWindowProc() in pluginshell.cpp. + 3. Here are links to a few sites with good DirectX tutorials/faqs/code: + The X-Zone: http://www.mvps.org/directx/ + Gamedev.net: http://www.gamedev.net/reference/ + + +Known Bugs +---------- + 1. When running [true] fullscreen in a multimon setup, + sometimes when the user presses ALT-TAB to switch away from the plugin + and to another window, the plugin will minimize. The 'sometimes' is + determined as follows: + -if the user releases TAB before depressing ALT, the window + minimizes (undesired behavior). + -if the user depresses ALT before releasing TAB, the window does + not minimize (desired behavior). + 2. Desktop Mode: some features are not implemented yet. They are: + -right-click -> cut/copy/paste/rename + -right-click -> "send to" doesn't work on all machines + -no keyboard commands (delete, enter, arrows, CTRL+X/C/V/Z) + -no drag-and-drop for files + -desktop shortcuts mostly work when you double-click them, + but on some machines bring up an "open/save" dialog + instead of actually launching the file. + + That's it for now. + + If anyone finds a solution for any of these bugs, please post the solution + in the VMS forum, and it will be included in the next VMS release. + + +Version History +----------------------------------------------------------------------- +[v1.05 beta 1 - June 26, 2003] + + -revamped the way keyboard commands are routed between your plugin + and the plugin shell. Before, the shell captured certain keys + ('p' for playlist, 'zxcvb' for playback, 's' for shuffle, 'F1' + for help, ESC to exit, arrows for volume/seeking, etc.) + and the plugin was unable to override these. Now, the shell + will pass the WM_KEYDOWN/WM_CHAR message to the plugin + (MyWindowProc) first, to see if it wants to process it. If the + plugin steals the key, it returns 0, and the shell ignores it. + If the plugin does not process the key, it returns 1, and then + the shell is free to process it. + +*** NOTE that if you are upgrading to VMS 1.05, this means you'll have to +*** update the way your WM_CHAR and WM_KEYDOWN handlers work in plugin.cpp! +*** [primarily, you'll have to return 0 when you handle a key, and 1 +*** otherwise.] + + -added key: 'r' for repeat + -added SKINNING; if you have Winamp 2.90+, you can now check the + 'integrate with winamp' checkbox and the plugin [when running in + windowed mode] will be skinned just like Winamp. The integrated + window works just like any other Winamp window; it docks with + other windows, CTRL+TAB cycles between them all, and lots of new + keys work (J, L, CTRL+P, ALT+E, etc.). + -fixed bug (or error in judgment?) where fake fullscreen mode window + would actually run at the *bottom* of the Z order when running + on a multiple monitor setup. The problem was that if you clicked + on any other window, the taskbar would pop up, potentially overtop + of the plugin. Since there's really no way around this, I decided + (before) to just stick the plugin at the bottom of the Z order in + this case. Well, this is now fixed; the plugin tries its best + to stay on top, but watch out - if you try and click on any other + windows, the taskbar WILL pop up. If you want to avoid that, + you'll have to run in true fullscreen mode. + -improved audio and video synchronization + -the current framerate is now used to tell Winamp, each frame, + exactly how far in advance it should give us the audio data. + For example, if we're getting 20 fps, we should get the + audio 50 ms in advance for the proper video frame to appear + when the user will actually hear those audio samples. + -timing: added calls to beginTimePeriod and endTimePeriod, so the assumed + granularity for Sleep() is now 2 ms (down from 10 ms). + This means that CPU usage will dramatically drop, and + fortunately, there should be no effect on framerate accuracy. + -desktop mode: added 'show icons' option to the desktop mode options + dialog, so users can uncheck it (and hide/disable the icons) if they + like. + -user can no longer shrink the window to less than 64x48 in size. + (often the minimum size will be higher than this though; see + WM_GETMINMAXINFO in pluginshell.cpp). + -user can now switch modes (windowed <-> fullscreen <-> desktop mode) + immediately. (before, it was blocked until frame 5.) + -(fixed a small bug in the example plugin, where handler for WM_KEYUP + returned DefWindowProc instead of 1). + -any time the DirectX setup fails when starting up (or switching to) + windowed mode, the window coords are now saved to disk as a 256x256 + window placed at (64,64). That way, if the problem was due to running + out of video memory, it will be less likely to recur. + -config panel: + -added two more fonts: one for the playlist, and another for the + help screen. + -it's now easy to add your own fonts to the font dialog in the + config panel; just add the appropriate #defines in the file + defines.h. Then you can access them easily from plugin.cpp by + calling GetFont(EXTRA_1), GetFont(EXTRA_2), and so on, up to + GetFont(EXTRA_5). You can also get their height by calling + GetFontHeight(EXTRA_1) through GetFontHeight(EXTRA_5). + -greatly improved the installer script. + -now selects winamp2 dir by default, if both winamp 2 & 3 are installed. + -fixed a bug where the plugin wasn't being correctly set as the default plugin + in winamp. Also, this is no longer an option - it just automatically does it. + -now, when you go to install to winamp 3, it checks to see if ClassicVis + is installed. If it is, you're set; if not, it prompts you to go download + it. If you choose not to, it alerts you that the installation failed. + -the FFT class (fft.cpp, fft.h) now has 2 extra optional init parameters. + -'bEqualize' is 1 by default; set it to 0 to have a non-equlized FFT; + bass frequencies will be much higher in magnitude than treble frequencies. + -'envelope_power' is 1.0 by default; adjust it to change the characteristics + of the resulting frequency spectrum (see comments in fft.cpp, in + InitEnvelopeTable). Set this to a negative value to not use an envelope. + -the help screen is no longer pre-rendered to a texture; it is now just drawn every + frame that it's needed. (Decided that that precious memory on some 8MB graphics + cards was more important than having a good framerate, on some cards, while viewing + the help screen.) + -added some nice macros to MyRenderUI() in plugin.cpp; makes the code for drawing + text much simpler. + -added 2 functions, GetDriver and GetDesc, which will return text strings with the + name & description of the currently active display adapter. (search these + strings for vendor substrings like "nvidia", using strstr or something similar, + to do vendor-specific bug workarounds. blech.) + -fixed a bug in SSE detection + -added handy memset_MMX() function to utility.cpp (alongside memcpy_MMX) + -fixed tabbing order for controls config panel tab #1 (doh) + -in 'defines.h', you now specify a long name + a short name for your plugin. + The long name is used for the description string in winamp's list of plugins; + the short name is used for the window caption. + -in the example plugin, in plugin.cpp, the F3 key (show song length) + is now a three-state toggle: off, current time, and current time / total + length. + +[v1.04 - October 29, 2002] + + -DESKTOP MODE: the icing on the cake. + -Allows users to run your plugin as animated wallpaper, with very + little cpu overhead. Uses no overlays or other unusual hardware + features. + -Just make sure you include the file 'vms_desktop.dll' with your + plugin; it is required for Desktop Mode to work properly. + It's small, though - only 48 kb. This file is now included + in the sample install script (installer.nsi). + -You can toggle Desktop Mode on/off at runtime by hitting ALT+D. + And as before, you can toggle Fullscreen via ALT+ENTER. + -Not all features of the desktop are fully implemented, but most + of the most-frequently-used features should be working. + For a list of the features not yet implemented, see the + 'Known Bugs' section above. + -CHANGES MADE TO PLUGIN.H,CPP: (isolated for ease-of-merging purposes) + 1. added a few config settings; see OverrideDefaults() + in PLUGIN.CPP. + 2. added 'redraw' flag to MyRenderFn - see the comments + at the top of MyRenderFn. Make sure you respect this + flag, or else, when the user moves icons around in + Desktop Mode while Winamp is paused, your plugin + will mysteriously start animating. + 3. added the 'MyRenderUI' function - please break your + text-rendering code in MyRenderFn off into this function. + 4. removed the ClipPlaylist() functions and, instead, provided + pointers to some values as params to MyRenderUI() that tell + you where to place text in each of the corners. As you + draw text, be sure to update these values, so that any + text drawn by the plugin shell (parent class) won't try to + draw text overtop of your text. + -Plugins based on VMS now remember the window position when they last + (successfully) exited windowed mode, and use that as the + default when they re-enter windowed mode (during the same + session or in a later session). If there is an error creating + that window (too big/not enough video memory, off-screen + because display mode resolution decreased, etc.) it will + revert to the default window size & position. + -Config Panel: + -For users with DualHead cards that run two monitors as one + virtual display (e.g. 2048x768 or 1024x1536), you can now + specify which half of the screen you want Fake Fullscreen Mode + and Desktop Mode to occupy, or both. See the 'DualHead' + button on the config panel. + -Added an option to save cpu usage by using a more-tolerant + framerate limitation algorithm - saves 0-20%. Default: ON. + -Fixed appearance of the help screen by adding +0.5-texel offset; + on some cards, help screen text was kind of jaggy and munged. + -Release builds no longer log window messages to the debug + output stream. + -The D3DX font for the help screen text is now created at + initialization time, instead of on demand. + -Framework Files: + -renamed 'fontdialog.cpp' to 'config2.cpp', since it now contains + more than just the font dialog code. + -added 'desktop_mode.cpp' and 'icon_t.h' to support Desktop Mode. + -Changes made to the sample installer script: [installer.nsi] + -added UnInstall options for winamp 2 and 3 + -simplified things by using some !define's at the top + -updated it to look for Winamp 3's new executable + name: winamp3.exe (in addition to the old, which was + studio.exe) + +----------------------------------------------------------------------- +[v1.03 - August 27, 2002] + + [MAJOR CHANGES] + -audio: + -vastly improved frequency analysis by multiplying the waveform by a + bell-shaped envelope before sending it to the FFT, lessening the + frequency response of the old square filter and producing a more + precise frequency analysis. Also improved it by doing a 1024-sample + FFT (instead of a 512). Special thanks goes out to Alan Seefeldt + and Alan Peevers for sharing their extensive knowledge in this area! + -config panel: + -split it into separate property sheets, so that + future updates to VMS (this sdk) will be easier to integrate + with code based on previous versions. Also, this gives developers + a lot more space to add things to the config panel. + -split the settings for 'fake fullscreen' mode and regular + fullscreen mode into two separate sets of controls, instead + of sharing controls; it was too confusing that way. + -added option to minimize winamp when going fullscreen. + Only actually minimizes winampwhen going fullscreen + (or fake fullscreen) AND winamp and the plugin window + are situated on the same monitor. + -added user-configurable fonts to the config panel. + -text: + -added a built-in playlist! + -added some sample code (in plugin.cpp / RenderText()) for showing + the current song title, position, and length. + -timing: + -oops... hi-precision timer was disabled in last version! + -also discovered an even more high-precision timer, which provides + a time sampling precision of from 1 to 5 *MICRO*seconds! + -ditched the 'frame delay' system and replaced it with a 'max fps' + system that should work more intuitively, and be extremely + accurate (thanks to the new timer). + -classes: + -got rid of InitMyGDIStuff() and CleanUpMyGDIStuff() - not really needed + -got rid of MyPreRenderFn() - also not really needed + -in windowed mode, if there is not enough video memory to create + the window at the default size, the window will now try to shrink + further and further, until it is small enough to work. + -fixed problem where the plugin wouldn't show up in the plug-ins list + in Winamp, if the user didn't have DX8 or later installed. Now + it does show up in the list, and if they try to run/configure it + and DX8 is missing, it will indicate this, and even offer to + take them to the MS DirectX website to download it. + -also started calling LoadLibrary("d3d8.dll") before calling + Direct3DCreate8(), so the latter wouldn't crash on systems + without DX8. + -yanked the fractal stuff out of the example plugin; too complicated. + + [MINOR CHANGES] + -now more resilient when user turns off some display (in a multimon + setup), then goes to run the plugin on that display (because they + didn't return to the config panel and update the display adapter + selection). + -improved suggested actions for when the plugin fails to start + because there is not enough video memory; suggestions now + include turning off other programs that might be using up + video memory (Windows Media Player, NetMeeting, and so on). + -config panel: disabled caps checking; sometimes requesting + the caps fails when you dynamically enable/disable monitors in + a multimon setup, so adapters that really exist (and are on) + would be missing in the list. + -config panel: added a sample combobox & slider to the 2nd property page, + which now features a checkbox, slider, and combobox, all + as simple examples for the plugin developer to build off of. + -noticed that multipsampling only works with D3DSWAPEFFECT_DISCARD, + so the code is now protected against using D3DSWAPEFFECT_COPY_VSYNC + with multisampling. The config panel has also been updated to + indicate to the user that if page tearing is disallowed, + multisampling will not function. This is a limitation of + the DirectX 8 API. + -added OverrideDefaults() function; see comments in plugin.cpp + -revamped the sample beat detection code + -tightened up the interface to CPluginShell + -made DirectX get initialized earlier (and cleaned up later) + so that GetWidth() and GetHeight() would be valid longer + -moved srand(time(NULL)) up to top of MyPreInitialize, in case + the developer wants to randomly initialize any of their + variables there. + -modified PrepareFor2DDrawing() so that it always makes the range + of X,Y coords -1..1 (before it was -width/2..width/2, and similarly + for height). Also inverted Y, so that y==-1 is actually at the + top of the screen, and Y==1 is at the bottom. + -added PrepareFor3DDrawing() + -improved auto-selection of best-match video mode; now, if it can't + find the exact pixel format that was in the INI file, + if will try other video modes that have the same bit depth, + but a different arrangement of the bits. [This applies to both + the config panel, AND when you go to run the plugin fullscreen.] + -respected key repeat count for playlist navigation (up/down), volume + adjust (up/down), and seeking (left/right). + -fixed a bug where the plugin would close on WM_KEYUP/VK_ESCAPE. Now, + instead, it closes on WM_KEYDOWN/VK_ESCAPE. This was a problem when + you hit ESCAPE to close some other app (on WM_KEYDOWN), then the focus + went to the plugin, and WM_KEYUP/VK_ESCAPE got sent to the plugin. + Not sure why it was even like this in the first place... + -fixed a timing but where, when the frame delay was zero (or fps + was unlimited), and the plugin was using the low-precision timer, + the fps reading would blow up and m_time would stop. + -fixed a bug w/a parameter to CreateFont: max font weight was + 900; 'twas calling it with 1000 + -fixed bug with context menu cleanup + -fixed a bug where winamp playback nav. keys (zxcvbs) were + handled under WM_KEYDOWN; should have been under WM_CHAR. + -fixed a bug where DXContext was calling DestroyWindow (on the final + exit of the plugin), when in fact, the window had already been + destroyed (by Windows, it seems). + -fixed a bug in config panel, where list of video modes wasn't updating + when you changed the fullscreen adapter. + -fixed a bug where DXContext was remembering the native windows display + mode for the first monitor that the window was created on, only. + This was a problem because if two monitors had different bit depths, + and you ran it and switched to another monitor by toggling fullscreen, + it would try to create a device with a back buffer whose bit depth + was that of the original monitor. To fix this, it now does the + following: the first time it creates a window, before changing the + display mode, it remembers the native display mode for all the + adapters present, then uses the appropriate one whenever it needs + it. + -deleted the 'DX8 Includes' project folder from the workspace; + use 'External Dependencies' folder instead, it automatically + points you to the right directories. + + +----------------------------------------------------------------------- +[1.02, August 5, 2002] + -Fixed bug where the plugin would minimize if you were running + [true] fullscreen with multiple monitors, and went to click + in another window. Previously the workaround was to use fake + fullscreen mode, but now this is not necessary. Fake fullscreen + mode still remains, though; for the rationale, see the help text + for the 'fake fullscreen mode' checkbox in the config panel. + -Decided that InitMyNonDx8Stuff() should be called first, instead + of last, and that CleanUpMyNonDx8Stuff() should be called last, + not first. + -Might have fixed a bug with high-precision timer. + -Added a custom icon (...which the developer can modify, of course). + + +----------------------------------------------------------------------- +[1.01, July 19, 2002] + -Initial release + + +----------------------------------------------------------------------- + +License +------- +Copyright (C) 1999-2002 Nullsoft, Inc. + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. + + + + diff --git a/vis_milk2/api.h b/vis_milk2/api.h new file mode 100644 index 0000000..8b25cfd --- /dev/null +++ b/vis_milk2/api.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_APIH +#define NULLSOFT_APIH + +#include +#include "../Agave/Language/api_language.h" +#include +#include +#include +#include +extern api_syscb *WASABI_API_SYSCB; +#define WASABI_API_SYSCB sysCallbackApi +#include +extern api_application *applicationApi; +#define WASABI_API_APP applicationApi + +#endif \ No newline at end of file diff --git a/vis_milk2/config.cpp b/vis_milk2/config.cpp new file mode 100644 index 0000000..dab0601 --- /dev/null +++ b/vis_milk2/config.cpp @@ -0,0 +1,1588 @@ +/* + 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. +*/ + +#include "api.h" +#include "pluginshell.h" +#include "resource.h" +#include "utility.h" +#include "defines.h" +#include "shell_defines.h" +#include "vis.h" +#include +#include +#include +#include +#include +#include +#include + +#define PREFERRED_FORMAT D3DFMT_X8R8G8B8 +#define MAX_PROPERTY_PAGES 8 +#define MAX_DISPLAY_ADAPTERS 16 +#define MAX_MAX_FPS 120 +#define MAX_DISPLAY_MODES 1024 + +extern winampVisModule mod1; + +IDirect3D9* g_lpDX; +HMODULE g_hmod_d3d9; +HMODULE g_hmod_d3dx9; +D3DADAPTER_IDENTIFIER9 g_disp_adapter_w[MAX_DISPLAY_ADAPTERS]; // NOTE: indices into this list might not equal the ordinal adapter indices! +D3DADAPTER_IDENTIFIER9 g_disp_adapter_fs[MAX_DISPLAY_ADAPTERS]; // NOTE: indices into this list might not equal the ordinal adapter indices! +D3DADAPTER_IDENTIFIER9 g_disp_adapter_dm[MAX_DISPLAY_ADAPTERS]; // NOTE: indices into this list might not equal the ordinal adapter indices! +D3DDISPLAYMODE g_disp_mode[MAX_DISPLAY_MODES]; +HWND g_config_hwnd; +HWND g_subwnd; +int g_num_disp_modes; +int g_nTab; +int g_ignore_clicks; +int g_zero_display_modes_warning_given; +int g_proppage_id[MAX_PROPERTY_PAGES]; + +void GetCurrentDisplayMode(D3DDISPLAYMODE *pMode) +{ + if (!pMode) + return; + + DEVMODE dm; + dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; + if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) + return; + + pMode->Width = dm.dmPelsWidth; + pMode->Height = dm.dmPelsHeight; + pMode->Format = (dm.dmBitsPerPel==16) ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8; + pMode->RefreshRate = dm.dmDisplayFrequency; +} + +bool CPluginShell::InitConfig(HWND hDialogWnd) +{ + // ******* do initialization of global variables HERE ******* + // ******* do initialization of global variables HERE ******* + // ******* do initialization of global variables HERE ******* + + g_lpDX = NULL; + g_hmod_d3d9 = NULL; + g_hmod_d3dx9 = NULL; + g_num_disp_modes = 0; + g_config_hwnd = hDialogWnd; + g_ignore_clicks = 1; + g_subwnd = NULL; + g_nTab = 0; + g_zero_display_modes_warning_given = 0; + + g_proppage_id[0] = IDD_PROPPAGE_1; + g_proppage_id[1] = IDD_PROPPAGE_2; + g_proppage_id[2] = IDD_PROPPAGE_3; + g_proppage_id[3] = IDD_PROPPAGE_4; + g_proppage_id[4] = IDD_PROPPAGE_5; + g_proppage_id[5] = IDD_PROPPAGE_6; + g_proppage_id[6] = IDD_PROPPAGE_7; + g_proppage_id[7] = IDD_PROPPAGE_8; + + // ******* do initialization of global variables HERE ******* + // ******* do initialization of global variables HERE ******* + // ******* do initialization of global variables HERE ******* + + return true; +} + +void CPluginShell::EndConfig() +{ + SafeRelease(g_lpDX); + + if (g_subwnd) + { + DestroyWindow(g_subwnd); + g_subwnd = NULL; + } + + if (g_hmod_d3d9) + { + FreeLibrary(g_hmod_d3d9); + g_hmod_d3d9 = NULL; + } + if (g_hmod_d3dx9) + { + g_hmod_d3dx9 = NULL; + } +} + +static bool AddButton(int pos, HWND tabctrl, LPWSTR szButtonText) +{ + if (szButtonText && szButtonText[0] && szButtonText[0] != L' ') + { + TCITEMW tie = {0}; + tie.mask = TCIF_TEXT | TCIF_IMAGE; + tie.iImage = -1; + tie.pszText = szButtonText; + + if (SendMessageW(tabctrl, TCM_INSERTITEMW, pos, (LPARAM)&tie) == -1) + return false; + } + return true; +} + +void CPluginShell::UpdateAdapters(int screenmode) +{ + int i; + + if (!g_lpDX) return; + + int nDispAdapters = 0; + + HWND ctrl; + GUID* pGUID = NULL; + char deviceName[256]; + switch(screenmode) + { + case FULLSCREEN: + ctrl = GetDlgItem(g_subwnd, IDC_ADAPTER_FS); + pGUID = &m_adapter_guid_fullscreen; + StringCbCopy(deviceName, sizeof(deviceName), m_adapter_devicename_fullscreen); + break; + case WINDOWED: + ctrl = GetDlgItem(g_subwnd, IDC_ADAPTER_W); + pGUID = &m_adapter_guid_windowed; + StringCbCopy(deviceName, sizeof(deviceName), m_adapter_devicename_windowed); + break; + /*case FAKE_FULLSCREEN: + ctrl = GetDlgItem(g_subwnd, IDC_ADAPTER_FFS); + pGUID = &m_adapter_guid_fake_fullscreen; + strcpy(deviceName, m_adapter_devicename_fake_fullscreen); + break;*/ + case DESKTOP: + ctrl = GetDlgItem(g_subwnd, IDC_ADAPTER_DMS); + pGUID = &m_adapter_guid_desktop; + StringCbCopy(deviceName, sizeof(deviceName), m_adapter_devicename_desktop); + break; + } + + // clear the combo box + SendMessage( ctrl, CB_RESETCONTENT, 0, 0); + + // repopulate the combo box with a list of adapters + { + char szDesc[1024]; + + D3DADAPTER_IDENTIFIER9* global_adapter_list; + switch(screenmode) + { + case FULLSCREEN: + global_adapter_list = g_disp_adapter_fs; + break; + case WINDOWED: + global_adapter_list = g_disp_adapter_w; + break; + /*case FAKE_FULLSCREEN: + global_adapter_list = g_disp_adapter_w; // [sic] + break;*/ + case DESKTOP: + global_adapter_list = g_disp_adapter_dm; + break; + } + + int nAdapters = g_lpDX->GetAdapterCount(); + + // re-populate it: + + wchar_t szDebugFile[MAX_PATH]; + StringCbCopyW(szDebugFile, sizeof(szDebugFile), m_szConfigIniFile); + wchar_t* p = wcsrchr(szDebugFile, L'\\'); + if (p) + { + lstrcpyW(p+1, ADAPTERSFILE); + FILE* f = _wfopen(szDebugFile, L"w"); + if (f) + { + DWORD winamp_version = SendMessage(GetWinampWindow(),WM_WA_IPC,0,0); + fprintf(f, "Winamp version = 0x%04X\n", winamp_version); + fprintf(f, "Plugin long name = \"%s\", version=%d, subversion=%d\n", LONGNAME, INT_VERSION, INT_SUBVERSION); + fprintf(f, "Enumeration of Display Adapters:\n"); + //fprintf(f, "...this is a temporary debug file created by MilkDrop 2.\n"); + //fprintf(f, "...don't worry - the final release of the plug-in will NOT generate this file.\n"); + for (i=0; iGetAdapterIdentifier(i, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &global_adapter_list[nDispAdapters]) == D3D_OK) + { + // Now get the caps, and filter out any graphics cards that can't + // do, say, gouraud shading: + + int adapter_ok = 1; + + /* + D3DCAPS9 caps; + if (g_lpDX->GetDeviceCaps(i, D3DDEVTYPE_HAL, &caps)==D3D_OK) + { + // check the caps here, make sure the device is up to par. example: + if (caps.ShadeCaps & D3DPSHADECAPS_COLORGOURAUDRGB) + adapter_ok = 0; + } + */ + + if (f) { + fprintf(f, "%d. Driver=%s\n", nDispAdapters+1, global_adapter_list[nDispAdapters].Driver); + fprintf(f, " Description=%s\n", global_adapter_list[nDispAdapters].Description); + fprintf(f, " DeviceName=%s\n", global_adapter_list[nDispAdapters].DeviceName); + fprintf(f, " DriverVersion=0x%08X (%d)\n",global_adapter_list[nDispAdapters].DriverVersion); + fprintf(f, " VendorId=%d\n", global_adapter_list[nDispAdapters].VendorId); + fprintf(f, " DeviceId=%d\n", global_adapter_list[nDispAdapters].DeviceId); + fprintf(f, " SubSysId=0x%08X\n", global_adapter_list[nDispAdapters].SubSysId); + fprintf(f, " Revision=%d\n", global_adapter_list[nDispAdapters].Revision); + //fprintf(f, " DeviceIdentifier=0x%08X\n", global_adapter_list[nDispAdapters].DeviceIdentifier); + char szGuidText[512]; + GuidToText(&global_adapter_list[nDispAdapters].DeviceIdentifier, szGuidText, sizeof(szGuidText)); + fprintf(f, " WHQLLevel=%d\n", global_adapter_list[nDispAdapters].WHQLLevel); + fprintf(f, " GUID=%s\n", szGuidText); + } + + if (adapter_ok) + { + sprintf(szDesc, "%d. %s [%s]", nDispAdapters+1, global_adapter_list[nDispAdapters].Description, global_adapter_list[nDispAdapters].Driver); + SendMessage( ctrl, CB_ADDSTRING, nDispAdapters, (LPARAM)szDesc); + nDispAdapters++; + } + } + } + fclose(f); + } + } + + // set selection(s): + // find i where global_adapter_list[i].DeviceIdentifier is the same as last time, + // and select it. + int found = 0; + for (i=0; iGetAdapterModeCount(nAdapterOrdinal, PREFERRED_FORMAT); + + if (nVideoModesTotal <= 0 && !g_zero_display_modes_warning_given) + { + g_zero_display_modes_warning_given = 1; + wchar_t title[64]; + MessageBoxW(g_config_hwnd, WASABI_API_LNGSTRINGW(IDS_GRAPHICS_SUBSYSTEM_IS_TEMPORARILY_UNSTABLE), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + + // clear the combo box + SendMessage( hwnd_listbox, CB_RESETCONTENT, 0, 0); + + int nAdded = 0; + + // re-populate it: + for (i=0; i= MAX_DISPLAY_MODES) + break; + + // get info for display mode into g_disp_mode[nAdded] + if (g_lpDX->EnumAdapterModes(nAdapterOrdinal, PREFERRED_FORMAT, i, &g_disp_mode[nAdded]) != D3D_OK) + continue; + + // add to combo box + int bpp = 0; + switch(g_disp_mode[nAdded].Format) + { + default: + case D3DFMT_UNKNOWN : WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN, szfmt, 256); bpp=0; break; + case D3DFMT_R8G8B8 : lstrcpynW(szfmt, L"RGB-888", 256); bpp=32; break; + case D3DFMT_A8R8G8B8 : lstrcpynW(szfmt, L"ARGB-8888", 256); bpp=32; break; + case D3DFMT_X8R8G8B8 : lstrcpynW(szfmt, L"XRGB-8888", 256); bpp=32; break; + case D3DFMT_R5G6B5 : lstrcpynW(szfmt, L"RGB-565", 256); bpp=16; break; + case D3DFMT_X1R5G5B5 : lstrcpynW(szfmt, L"XRGB-1555", 256); bpp=16; break; + case D3DFMT_A1R5G5B5 : lstrcpynW(szfmt, L"ARGB-1555", 256); bpp=16; break; + case D3DFMT_A4R4G4B4 : lstrcpynW(szfmt, L"ARGB-4444", 256); bpp=16; break; + case D3DFMT_X4R4G4B4 : lstrcpynW(szfmt, L"XRGB-4444", 256); bpp=16; break; + } + swprintf(str, L" %s, %4d x %4d, %3d %s ", + szfmt, g_disp_mode[nAdded].Width, + g_disp_mode[nAdded].Height, + g_disp_mode[nAdded].RefreshRate, + WASABI_API_LNGSTRINGW(IDS_HZ)); + + /* + #ifdef DONT_ALLOW_8BIT_FULLSCREEN + if (bpp==8) continue; + #endif + #ifdef DONT_ALLOW_16_24_32_BIT_FULLSCREEN + if (bpp==16 || bpp==24 || bpp==32) continue; + #endif + */ + + int nPos = SendMessageW( hwnd_listbox, CB_ADDSTRING, 0, (LPARAM)str); + + // keep a record of the original index, because the combo box SORTS the data: + SendMessage( hwnd_listbox, CB_SETITEMDATA, nPos, i); + + nAdded++; + } + + g_num_disp_modes = nAdded; + + // now set selection, based on best match to prev. video mode. + int found = 0; + + // Fallback order: + // 0. exact match (4 params) w,h,r,f + // 1. ignore refresh rate, but still heed color format + // 2. heed only w,h, and if desired_mode.Format is UNKNOWN, + // try for a 16-bpp color format and 60 Hz + // 3. heed only w,h, and if desired_mode.Format is UNKNOWN, + // try for a 16-bpp color format at any Hz + // 4. heed only w,h. + + D3DDISPLAYMODE desired_mode = m_disp_mode_fs; + + assert(desired_mode.Format != D3DFMT_UNKNOWN); + // this should never happen anymore, now that we set smarter default FS display mode + // (to match the current display mode) in PluginShell.cpp's PluginPreInitialize(). + /*if (desired_mode.Format==D3DFMT_UNKNOWN) + { + GetCurrentDisplayMode(&desired_mode); + + // first-time config: try to find a video mode that matches our ideal. + // do many passes until we find one, each time relaxing more constraints. + // outline of the passes: + + // PASS MATCH: + // 0. w,h,r,16bpp + // 1. w,h,-,16bpp + // 2. w,h,r,- + // 3. w,h,-,- + // 4. -,-,-,- + for (int rep=0; rep<5; rep++) + { + for (i=0; i disable multisampling! + SendMessage( hwnd_listbox, CB_RESETCONTENT, 0, 0); + SendMessageW( hwnd_listbox, CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_DISABLED_PAGE_TEARING)); + SendMessage( hwnd_listbox, CB_SETITEMDATA, 0, 0 ); + SendMessage( hwnd_listbox, CB_SETCURSEL, 0, 0); + EnableWindow( hwnd_listbox, 0 ); + } + else + { + EnableWindow( hwnd_listbox, 1 ); + + // figure out which [fullscreen/windowed] adapter is currently selected: + int nAdapterOrdinal = GetCurrentlySelectedAdapter(screenmode); + + // figure out current format: + D3DFORMAT format = D3DFMT_UNKNOWN; + if ((screenmode == WINDOWED) || + (screenmode == FULLSCREEN && m_fake_fullscreen_mode) || + (screenmode == DESKTOP)) + { + // ** get it from the current display mode + // of the currently-selected [windowed/fake fullscreen] mode adapter ** + D3DDISPLAYMODE dispmode; + if (g_lpDX->GetAdapterDisplayMode(nAdapterOrdinal, &dispmode) == D3D_OK) + format = dispmode.Format; + } + else + { + // **get it from the currently-selected fullscreen display mode** + int n = SendMessage( GetDlgItem( g_subwnd, IDC_DISP_MODE ), CB_GETCURSEL, 0, 0); + if (n != CB_ERR) + { + // since the combobox contents were sorted, we need to look up the original + // index into g_disp_mode[]: + n = SendMessage( GetDlgItem( g_subwnd, IDC_DISP_MODE ), CB_GETITEMDATA, n, 0); + if (n != CB_ERR) + format = g_disp_mode[n].Format; + } + } + + D3DMULTISAMPLE_TYPE check[16] = { + D3DMULTISAMPLE_NONE, + D3DMULTISAMPLE_2_SAMPLES , + D3DMULTISAMPLE_3_SAMPLES , + D3DMULTISAMPLE_4_SAMPLES , + D3DMULTISAMPLE_5_SAMPLES , + D3DMULTISAMPLE_6_SAMPLES , + D3DMULTISAMPLE_7_SAMPLES , + D3DMULTISAMPLE_8_SAMPLES , + D3DMULTISAMPLE_9_SAMPLES , + D3DMULTISAMPLE_10_SAMPLES, + D3DMULTISAMPLE_11_SAMPLES, + D3DMULTISAMPLE_12_SAMPLES, + D3DMULTISAMPLE_13_SAMPLES, + D3DMULTISAMPLE_14_SAMPLES, + D3DMULTISAMPLE_15_SAMPLES, + D3DMULTISAMPLE_16_SAMPLES, + }; + + // clear the combo box + SendMessage( hwnd_listbox, CB_RESETCONTENT, 0, 0); + + // re-populate it: + for (i=0; i<16; i++) + { + if (i==0 || SUCCEEDED(g_lpDX->CheckDeviceMultiSampleType(nAdapterOrdinal, D3DDEVTYPE_HAL, + format, + (screenmode==FULLSCREEN) ? 0 : 1,//bWindowed, + check[i], NULL))) + { + // add to listbox + if (i==0) + WASABI_API_LNGSTRINGW_BUF(IDS_NONE, str, 256); + else + StringCbPrintfW(str, sizeof(str), L"%2dX", i+1); + + SendMessage( hwnd_listbox, CB_ADDSTRING, nSampleTypes, (LPARAM)str); + + // set the item data to the D3DMULTISAMPLE_TYPE value: + SendMessage( hwnd_listbox, CB_SETITEMDATA, nSampleTypes, check[i] ); + + nSampleTypes++; + } + } + + // set prev. selection + D3DMULTISAMPLE_TYPE prev_seln; + switch(screenmode) + { + case FULLSCREEN: prev_seln = m_multisample_fullscreen; break; + case WINDOWED: prev_seln = m_multisample_windowed; break; + //case FAKE_FULLSCREEN: prev_seln = m_multisample_fake_fullscreen; break; + case DESKTOP: prev_seln = m_multisample_desktop; break; + } + + for (i=0; i 0) + n = MAX_MAX_FPS+1 - n; + + switch(screenmode) + { + case FULLSCREEN: m_max_fps_fs = n; break; + case WINDOWED: m_max_fps_w = n; break; + //case FAKE_FULLSCREEN: m_max_fps_fake_fs = n; break; + case DESKTOP: m_max_fps_dm = n; break; + } + } +} + +void CPluginShell::SaveAdapter(int screenmode) +{ + HWND ctrl; + switch(screenmode) + { + case FULLSCREEN: ctrl = GetDlgItem(g_subwnd, IDC_ADAPTER_FS); break; + case WINDOWED: ctrl = GetDlgItem(g_subwnd, IDC_ADAPTER_W); break; + //case FAKE_FULLSCREEN: ctrl = GetDlgItem(g_subwnd, IDC_ADAPTER_FFS); break; + case DESKTOP: ctrl = GetDlgItem(g_subwnd, IDC_ADAPTER_DMS); break; + } + + // save windowed/fullscreen adapter + int n = SendMessage( ctrl, CB_GETCURSEL, 0, 0); + if (n != CB_ERR) + { + switch(screenmode) + { + case FULLSCREEN: + m_adapter_guid_fullscreen = g_disp_adapter_fs[n].DeviceIdentifier; + StringCbCopy(m_adapter_devicename_fullscreen, sizeof(m_adapter_devicename_fullscreen), g_disp_adapter_fs[n].DeviceName); + //strcpy(m_adapter_desc_fullscreen, g_disp_adapter_fs[n].Description); + break; + case WINDOWED: + m_adapter_guid_windowed = g_disp_adapter_w[n].DeviceIdentifier; + StringCbCopy(m_adapter_devicename_windowed, sizeof(m_adapter_devicename_windowed), g_disp_adapter_fs[n].DeviceName); + //strcpy(m_adapter_desc_windowed, g_disp_adapter_fs[n].Description); + break; + //case FAKE_FULLSCREEN: + //m_adapter_guid_fake_fullscreen = g_disp_adapter_w[n].DeviceIdentifier; + //strcpy(m_adapter_desc_fake_fullscreen, g_disp_adapter_fs[n].Description); + //break; // [sic] + case DESKTOP: + m_adapter_guid_desktop = g_disp_adapter_dm[n].DeviceIdentifier; + StringCbCopy(m_adapter_devicename_desktop, sizeof(m_adapter_devicename_desktop), g_disp_adapter_fs[n].DeviceName); + //strcpy(m_adapter_desc_desktop, g_disp_adapter_fs[n].Description); + break; + } + } +} + +/* +BOOL CALLBACK GenericTabCtrlProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + return 0; +} +*/ + +// OnTabChanged - processes the TCN_SELCHANGE notification. +void CPluginShell::OnTabChanged(int nNewTab) +{ + if (g_subwnd) + { + DestroyWindow(g_subwnd); + g_subwnd = NULL; + } + + g_nTab = nNewTab; + + if (g_nTab >= 0 && g_nTab < MAX_PROPERTY_PAGES) + { + HWND h = WASABI_API_CREATEDIALOGPARAMW(g_proppage_id[g_nTab], g_config_hwnd, this->TabCtrlProc, (LPARAM)this); + // NOTE: CreateDialogParam will call TabCtrlProc with WM_INITDIALOG, + // which is where 'g_subwnd' will get set. + + // do this here to ensure that the current prefs page is correctly themed + if(!SendMessage(this->m_hWndWinamp,WM_WA_IPC,IPC_ISWINTHEMEPRESENT,IPC_USE_UXTHEME_FUNC)) + { + SendMessage(this->m_hWndWinamp,WM_WA_IPC,(WPARAM)h,IPC_USE_UXTHEME_FUNC); + } + } +} + +INT_PTR CALLBACK CPluginShell::TabCtrlProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + if (msg==WM_INITDIALOG && lParam > 0 && GetWindowLongPtr(hwnd,GWLP_USERDATA)==0) + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + + CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + if (p && g_nTab >= 0 && g_nTab < MAX_PROPERTY_PAGES) + { + if (msg==WM_INITDIALOG) + g_subwnd = hwnd; + + if (g_nTab==0) + p->PluginShellConfigTab1Proc(hwnd, msg, wParam, lParam); + p->MyConfigTabProc(g_nTab+1, hwnd, msg, wParam, lParam); + + if (msg==WM_INITDIALOG) + { + // once it has been initialized, reposition the subdialog: + RECT r; + GetWindowRect(GetDlgItem(g_config_hwnd,IDC_RECT),&r); + ScreenToClient(g_config_hwnd,(LPPOINT)&r); + SetWindowPos(g_subwnd,0,r.left,r.top,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER); + ShowWindow(g_subwnd,SW_SHOWNA); + } + } + + const int controls[] = + { + IDC_BRIGHT_SLIDER, + IDC_HARDCUT_LOUDNESS, + }; + if (FALSE != WASABI_API_APP->DirectMouseWheel_ProcessDialogMessage(hwnd, msg, wParam, lParam, controls, ARRAYSIZE(controls))) + { + return TRUE; + } + + return FALSE; +} + +BOOL CPluginShell::PluginShellConfigTab1Proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + #ifdef _DEBUG + OutputDebugMessage(" Tab1Proc: ", hwnd, msg, wParam, lParam); + #endif + + switch (msg) + { + case WM_INITDIALOG: + { + // pre-checks + if (m_start_fullscreen && m_start_desktop) + m_start_desktop = 0; + if (!mod1.hwndParent || SendMessage(mod1.hwndParent,WM_WA_IPC,0,0) < 0x2900) + { + m_skin = 0; + EnableWindow(GetDlgItem(hwnd,IDC_CB_SKIN), 0); + char buf[256]; + buf[0] = 0; + GetWindowText(GetDlgItem(hwnd,IDC_CB_SKIN), buf, 255); + StringCbCat(buf, sizeof(buf), " 2.90+"); + SetWindowText(GetDlgItem(hwnd,IDC_CB_SKIN), buf); + } + + // set checkboxes + CheckDlgButton(hwnd, IDC_CB_FS, m_start_fullscreen); + CheckDlgButton(hwnd, IDC_CB_DMS, m_start_desktop); + CheckDlgButton(hwnd, IDC_CB_FAKE, m_fake_fullscreen_mode); + CheckDlgButton(hwnd, IDC_CB_PRESS_F1_MSG, m_show_press_f1_msg); + CheckDlgButton(hwnd, IDC_CB_WPT, m_allow_page_tearing_w); + CheckDlgButton(hwnd, IDC_CB_FSPT, m_allow_page_tearing_fs); + CheckDlgButton(hwnd, IDC_CB_DMSPT, m_allow_page_tearing_dm); + CheckDlgButton(hwnd, IDC_CB_MIN, m_minimize_winamp); + CheckDlgButton(hwnd, IDC_CB_SAVE_CPU, m_save_cpu); + CheckDlgButton(hwnd, IDC_CB_SKIN, m_skin); + CheckDlgButton(hwnd, IDC_CB_FIXSLOWTEXT, m_fix_slow_text); + CheckDlgButton(hwnd, IDC_CB_VJMODE, m_vj_mode); + + // Enumerate available adapters. + UpdateAdapters(0); // fullscreen + //-calls UpdateFSAdapterDispModes() + //-which then calls UpdateDispModeMultiSampling(0). + UpdateAdapters(1); // windowed + //-skips UpdateFSAdapterDispModes() (not necessary for windowed mode) + //-then calls UpdateDispModeMultiSampling(1). + UpdateAdapters(3); // desktop + //-skips UpdateFSAdapterDispModes() (not necessary for fake fullscreen mode) + //-then calls UpdateDispModeMultiSampling(2). + UpdateMaxFps(0); + UpdateMaxFps(1); + UpdateMaxFps(3); // desktop + + // disable a few things if fake fullscreen mode enabled: + EnableWindow(GetDlgItem(hwnd, IDC_DISP_MODE), !m_fake_fullscreen_mode); + //EnableWindow(GetDlgItem(hwnd, IDC_FSMS), !m_fake_fullscreen_mode); + } + break; + + case WM_DESTROY: + { + // read checkboxes + m_start_fullscreen = DlgItemIsChecked(hwnd, IDC_CB_FS ); + m_start_desktop = DlgItemIsChecked(hwnd, IDC_CB_DMS ); + m_fake_fullscreen_mode = DlgItemIsChecked(hwnd, IDC_CB_FAKE ); + m_show_press_f1_msg = DlgItemIsChecked(hwnd, IDC_CB_PRESS_F1_MSG); + m_allow_page_tearing_w = DlgItemIsChecked(hwnd, IDC_CB_WPT ); + m_allow_page_tearing_fs= DlgItemIsChecked(hwnd, IDC_CB_FSPT ); + m_allow_page_tearing_dm= DlgItemIsChecked(hwnd, IDC_CB_DMSPT); + m_minimize_winamp = DlgItemIsChecked(hwnd, IDC_CB_MIN ); + m_save_cpu = DlgItemIsChecked(hwnd, IDC_CB_SAVE_CPU ); + m_fix_slow_text = DlgItemIsChecked(hwnd, IDC_CB_FIXSLOWTEXT); + m_vj_mode = DlgItemIsChecked(hwnd, IDC_CB_VJMODE); + + if (mod1.hwndParent && SendMessage(mod1.hwndParent,WM_WA_IPC,0,0) >= 0x2900) + m_skin = DlgItemIsChecked(hwnd, IDC_CB_SKIN ); + + // read all 3 adapters + SaveAdapter(0); + SaveAdapter(1); + SaveAdapter(3); + + // read fullscreen display mode + SaveDisplayMode(); + + // read all 3 multisampling settings: + SaveMultiSamp(0); + SaveMultiSamp(1); + SaveMultiSamp(3); + + // read all 3 max fps settings + SaveMaxFps(0); + SaveMaxFps(1); + SaveMaxFps(3); + } + break; + + case WM_COMMAND: + if (!g_ignore_clicks) + { + int id = LOWORD(wParam); + g_ignore_clicks = 1; + switch(id) + { + case ID_FONTS: + WASABI_API_DIALOGBOXPARAMW(IDD_FONTDIALOG, hwnd, FontDialogProc, (LPARAM)this); + break; + + case ID_DM_MORE: + WASABI_API_DIALOGBOXPARAMW(IDD_DESKTOPMODE, hwnd, DesktopOptionsDialogProc, (LPARAM)this); + break; + + case ID_DUALHEAD: + WASABI_API_DIALOGBOXPARAMW(IDD_DUALHEAD, hwnd, DualheadDialogProc, (LPARAM)this); + break; + + case IDC_ADAPTER_FS: + SaveDisplayMode(); + SaveMultiSamp(FULLSCREEN); + SaveAdapter(0); + UpdateFSAdapterDispModes(); + break; + + case IDC_ADAPTER_W: + SaveMultiSamp(WINDOWED); + UpdateDispModeMultiSampling(WINDOWED); + break; + + /* + case IDC_ADAPTER_FFS: + SaveMultiSamp(FAKE_FULLSCREEN); + UpdateDispModeMultiSampling(FAKE_FULLSCREEN); + break; + */ + + case IDC_ADAPTER_DMS: + SaveMultiSamp(DESKTOP); + UpdateDispModeMultiSampling(DESKTOP); + break; + + case IDC_DISP_MODE: + SaveMultiSamp(FULLSCREEN); + UpdateDispModeMultiSampling(FULLSCREEN); + break; + + case IDC_CB_WPT: + SaveMultiSamp(WINDOWED); + m_allow_page_tearing_w = DlgItemIsChecked(hwnd, IDC_CB_WPT); + UpdateDispModeMultiSampling(WINDOWED); + break; + + case IDC_CB_FSPT: + SaveMultiSamp(FULLSCREEN); + m_allow_page_tearing_fs = DlgItemIsChecked(hwnd, IDC_CB_FSPT); + UpdateDispModeMultiSampling(FULLSCREEN); + break; + + case IDC_CB_DMSPT: + SaveMultiSamp(DESKTOP); + m_allow_page_tearing_dm = DlgItemIsChecked(hwnd, IDC_CB_DMSPT); + UpdateDispModeMultiSampling(DESKTOP); + break; + + case IDC_CB_FS: + m_start_fullscreen = DlgItemIsChecked(hwnd, IDC_CB_FS ); + if (m_start_fullscreen && m_start_desktop) + { + m_start_desktop = 0; + CheckDlgButton(hwnd, IDC_CB_DMS, m_start_desktop); + } + break; + + case IDC_CB_DMS: + m_start_desktop = DlgItemIsChecked(hwnd, IDC_CB_DMS ); + if (m_start_fullscreen && m_start_desktop) + { + m_start_fullscreen = 0; + CheckDlgButton(hwnd, IDC_CB_FS, m_start_fullscreen); + } + break; + + case IDC_CB_FAKE: + SaveMultiSamp(FULLSCREEN); + m_fake_fullscreen_mode = DlgItemIsChecked(hwnd, IDC_CB_FAKE ); + EnableWindow(GetDlgItem(hwnd, IDC_DISP_MODE), !m_fake_fullscreen_mode); + CheckDlgButton(hwnd, IDC_CB_FSPT, m_fake_fullscreen_mode ? m_allow_page_tearing_fs : 0); + EnableWindow(GetDlgItem(hwnd, IDC_CB_FSPT), m_fake_fullscreen_mode ? 1 : 0); + UpdateDispModeMultiSampling(FULLSCREEN); + break; + + /* + case IDC_CB_FFSPT: + SaveMultiSamp(FAKE_FULLSCREEN); + m_allow_page_tearing_fake_fs = DlgItemIsChecked(hwnd, IDC_CB_FFSPT); + UpdateDispModeMultiSampling(FAKE_FULLSCREEN); + break; + */ + } + g_ignore_clicks = 0; + } + break; // case WM_COMMAND + + case WM_HELP: + if (lParam) + { + HELPINFO *ph = (HELPINFO*)lParam; + wchar_t title[1024]; + wchar_t buf[2048]; + wchar_t ctrl_name[1024]; + GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name)); + RemoveSingleAmpersands(ctrl_name); + buf[0] = 0; + + switch(ph->iCtrlId) + { + case ID_FONTS: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_BUTTON), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_FONTS_HELP, buf, 2048); + break; + + case ID_DUALHEAD: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_BUTTON), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_DUAL_HEAD_HELP, buf, 2048); + break; + + case IDC_W_MULTISAMPLING_CAPTION: + case IDC_FS_MULTISAMPLING_CAPTION: + case IDC_DMS_MULTISAMPLING_CAPTION: + //case IDC_FFS_MULTISAMPLING_CAPTION: + case IDC_WMS: + case IDC_FSMS: + case IDC_DMSMS: + //case IDC_FFSMS: + WASABI_API_LNGSTRINGW_BUF(IDS_MULTI_SAMPLING, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_MULTI_SAMPLING_HELP, buf, 2048); + break; + + case IDC_W_MAXFPS: + case IDC_FS_MAXFPS: + case IDC_DMS_MAXFPS: + //case IDC_FFS_MAXFPS: + case IDC_W_MAXFPS_CAPTION: + case IDC_FS_MAXFPS_CAPTION: + case IDC_DMS_MAXFPS_CAPTION: + //case IDC_FFS_MAXFPS_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_MAX_FRAMERATE, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_MAX_FRAMERATE_HELP, buf, 2048); + break; + + case IDC_CB_FAKE: + WASABI_API_LNGSTRINGW_BUF(IDS_FAKE_FULLSCREEN, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_FAKE_FULLSCREEN_HELP, buf, 2048); + break; + + case IDC_ADAPTER_FS: + case IDC_FS_ADAPTER_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_FULLSCREEN_ADAPTER, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_FULLSCREEN_ADAPTER_HELP, buf, 2048); + break; + + case IDC_ADAPTER_W: + case IDC_W_ADAPTER_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_WINDOWED_ADPATER, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_WINDOWED_ADPATER_HELP, buf, 2048); + break; + + case IDC_ADAPTER_DMS: + case IDC_DMS_ADAPTER_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_DESKTOP_ADAPTER, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_DESKTOP_ADAPTER_HELP, buf, 2048); + break; + + case IDC_DISP_MODE: + case IDC_DISP_MODE_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_FS_DISPLAY_MODE, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_FS_DISPLAY_MODE_HELP, buf, 2048); + break; + + case IDC_CB_WPT: + case IDC_CB_FSPT: + case IDC_CB_DMSPT: + //case IDC_CB_FFSPT: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_CHECKBOX), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_HELP_ON_X_CHECKBOX_HELP, buf, 2048); + break; + + case IDC_CB_FS: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_CHECKBOX), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_FORCE_INTO_FS_MODE_HELP, buf, 2048); + break; + + case IDC_CB_DMS: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_CHECKBOX), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_FORCE_INTO_DESKTOP_MODE_HELP, buf, 2048); + break; + + case IDC_CB_PRESS_F1_MSG: + WASABI_API_LNGSTRINGW_BUF(IDS_HELP_ON_F1, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_HELP_ON_F1_HELP, buf, 2048); + break; + + case IDC_CB_SKIN: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_CHECKBOX), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_CB_SKIN_HELP, buf, 2048); + break; + + case IDC_CB_SAVE_CPU: + WASABI_API_LNGSTRINGW_BUF(IDS_SAVE_CPU_CHECKBOX, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_SAVE_CPU_CHECKBOX_HELP, buf, 2048); + break; + + case IDC_CB_MIN: + WASABI_API_LNGSTRINGW_BUF(IDS_HELP_MINIMIZE_WINAMP, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_HELP_MINIMIZE_WINAMP_HELP, buf, 2048); + break; + + case IDC_CB_FIXSLOWTEXT: + WASABI_API_LNGSTRINGW_BUF(IDS_TRY_TO_FIX_SLOW_TEXT, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_TRY_TO_FIX_SLOW_TEXT_HELP, buf, 2048); + break; + + case IDC_CB_VJMODE: + WASABI_API_LNGSTRINGW_BUF(IDS_VJ_MODE, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_VJ_MODE_HELP, buf, 2048); + break; + + case IDC_DMS_LABEL: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_DMS_LABEL_HELP, buf, 2048); + break; + + case IDC_FS_LABEL: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_FS_LABEL_HELP, buf, 2048); + break; + + case IDC_W_LABEL: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_W_LABEL_HELP, buf, 2048); + break; + + case ID_DM_MORE: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_DM_MORE_HELP, buf, 2048); + break; + } + + if (buf[0]) + MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + + } + break; // case WM_HELP + } + + return 0; +} + +BOOL CALLBACK CPluginShell::ConfigDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + if (msg==WM_INITDIALOG && lParam > 0 && GetWindowLongPtr(hwnd,GWLP_USERDATA)==0) + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + + CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + if (p) + return p->PluginShellConfigDialogProc(hwnd, msg, wParam, lParam); + else + return FALSE; +} + +BOOL CPluginShell::PluginShellConfigDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + #ifdef _DEBUG + OutputDebugMessage("CfgDlgProc: ", hwnd, msg, wParam, lParam); + #endif + + switch (msg) + { + case WM_DESTROY: + EndConfig(); + return 0; + + case WM_INITDIALOG: + { + // Initialize all config panel global variables: + if (!InitConfig(hwnd)) + { + wchar_t title[64]; + MessageBoxW(hwnd, WASABI_API_LNGSTRINGW(IDS_INITCONFIG_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + EndConfig(); + int id=LOWORD(wParam); + EndDialog(hwnd,id); + return false; + } + + // set window caption + SetWindowText( hwnd, WINDOWCAPTION ); + + // Test for DirectX 9 + start it + // note: if you don't call LoadLibrary here, and you're on a system + // where DX9 is missing, Direct3DCreate9() might crash; so call it. + int d3d9_already_loaded = (GetModuleHandle("d3d9.dll") != NULL) ? 1 : 0; + if (!d3d9_already_loaded) + g_hmod_d3d9 = LoadLibrary("d3d9.dll"); + + if ( (!d3d9_already_loaded && !g_hmod_d3d9) || + !(g_lpDX = Direct3DCreate9(D3D_SDK_VERSION)) + ) + { + MissingDirectX(hwnd); + + EndConfig(); + int id=LOWORD(wParam); + EndDialog(hwnd,id); + return false; + } + + if (!g_hmod_d3dx9) + g_hmod_d3dx9 = FindD3DX9(GetWinampWindow()); + + if ((!g_hmod_d3dx9)) + { + MissingDirectX(hwnd); + EndConfig(); + int id=LOWORD(wParam); + EndDialog(hwnd,id); + return false; + } + + // enable the 'view website' button only if plugin author has #defined a URL (in defines.h): + #ifndef PLUGIN_WEB_URL + ShowWindow(GetDlgItem(hwnd, ID_WEB), SW_HIDE); + #else + if (wcslen(PLUGIN_WEB_URL)==0) + ShowWindow(GetDlgItem(hwnd, ID_WEB), SW_HIDE); + #endif + + // enable the 'view docs' button only if plugin author has #defined a filename (in defines.h): + #ifndef DOCFILE + ShowWindow(GetDlgItem(hwnd, ID_DOCS), SW_HIDE); + #else + if (wcslen(DOCFILE)==0) + ShowWindow(GetDlgItem(hwnd, ID_DOCS), SW_HIDE); + #endif + + // set contents of IDC_SZ_ABOUT + wchar_t about[256]; + StringCchPrintfW(about, 256, WASABI_API_LNGSTRINGW(IDS_ABOUT_STRING), LONGNAMEW, AUTHOR_NAME, COPYRIGHT); + SetDlgItemTextW(hwnd, IDC_SZ_ABOUT, about); + + // initialize tab control: + { + HWND tabWnd = GetDlgItem(hwnd,IDC_TABS); + // Add Tabs: + if (!AddButton(0, tabWnd, WASABI_API_LNGSTRINGW(IDS_CONFIG_PANEL_BUTTON_1)) || + !AddButton(1, tabWnd, WASABI_API_LNGSTRINGW(IDS_CONFIG_PANEL_BUTTON_2)) || + !AddButton(2, tabWnd, WASABI_API_LNGSTRINGW(IDS_CONFIG_PANEL_BUTTON_3)) || + !AddButton(3, tabWnd, WASABI_API_LNGSTRINGW(IDS_CONFIG_PANEL_BUTTON_4)) || + !AddButton(4, tabWnd, WASABI_API_LNGSTRINGW(IDS_CONFIG_PANEL_BUTTON_5)) || + !AddButton(5, tabWnd, WASABI_API_LNGSTRINGW(IDS_CONFIG_PANEL_BUTTON_6)) || + !AddButton(6, tabWnd, WASABI_API_LNGSTRINGW(IDS_CONFIG_PANEL_BUTTON_7)) || + !AddButton(7, tabWnd, WASABI_API_LNGSTRINGW(IDS_CONFIG_PANEL_BUTTON_8))) + { + wchar_t title[64]; + MessageBoxW(hwnd, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_LOAD_TABS), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + EndConfig(); + int id=LOWORD(wParam); + EndDialog(hwnd,id); + return false; + } + + // Simulate selection of the first tab. + int last_tab = GetPrivateProfileIntW(L"settings",L"last_tab",0,m_szConfigIniFile); + TabCtrl_SetCurSel(tabWnd, last_tab); + OnTabChanged(last_tab); + } + + g_ignore_clicks = 0; + + SetFocus(hwnd); + } + return 0; + + case WM_NOTIFY: + if (!g_ignore_clicks) + { + LPNMHDR pnmh = (LPNMHDR)lParam; + switch(pnmh->code) + { + case TCN_SELCHANGE: + OnTabChanged(TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_TABS))); + break; + } + } + break; + + case WM_COMMAND: + if (!g_ignore_clicks) + { + int id = LOWORD(wParam); + switch(id) + { + case IDOK: + // kill current tab window, so that its settings get read + WritePrivateProfileIntW(TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_TABS)),L"last_tab",m_szConfigIniFile,L"settings"); + OnTabChanged(-1); + + // then save new config + WriteConfig(); + + EndDialog(hwnd,id); + return 0; + + case IDCANCEL: + WritePrivateProfileIntW(TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_TABS)),L"last_tab",m_szConfigIniFile,L"settings"); + EndDialog(hwnd,id); + return 0; + + case ID_DOCS: + { + wchar_t szPath[512], szFile[512]; + lstrcpyW(szPath, m_szPluginsDirPath); + lstrcpyW(szFile, szPath); + lstrcatW(szFile, DOCFILE); + + intptr_t ret = myOpenURL(0,szFile); + if (ret <= 32) + { + wchar_t buf[1024]; + switch(ret) + { + case SE_ERR_FNF: + case SE_ERR_PNF: + StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_DOCUMENTATION_FILE_NOT_FOUND), szFile); + break; + case SE_ERR_ACCESSDENIED: + case SE_ERR_SHARE: + StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_DOCUMENTATION_FILE_DENIED), szFile); + break; + case SE_ERR_NOASSOC: + StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_DOCUMENTATION_FILE_FAILED_DUE_TO_NO_ASSOC), szFile); + break; + default: + StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_DOCUMENTATION_FILE_FAILED_CODE_X), szFile, ret); + break; + } + MessageBoxW(hwnd, buf, WASABI_API_LNGSTRINGW(IDS_ERROR_OPENING_DOCUMENTATION), MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + } + break; + + case ID_WEB: + { + intptr_t ret = myOpenURL(NULL, PLUGIN_WEB_URL); + if (ret <= 32) + { + wchar_t buf[1024]; + switch(ret) + { + case SE_ERR_FNF: + case SE_ERR_PNF: + StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_URL_COULD_NOT_OPEN), PLUGIN_WEB_URL); + break; + case SE_ERR_ACCESSDENIED: + case SE_ERR_SHARE: + StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_WAS_DENIED), PLUGIN_WEB_URL); + break; + case SE_ERR_NOASSOC: + StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_FAILED_DUE_TO_NO_ASSOC), PLUGIN_WEB_URL); + break; + default: + StringCbPrintfW(buf, sizeof(buf), WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_FAILED_CODE_X), PLUGIN_WEB_URL, ret); + break; + } + MessageBoxW(hwnd, buf, WASABI_API_LNGSTRINGW(IDS_ERROR_OPENING_URL), MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + } + break; + + case ID_DEFAULTS: + wchar_t title[64]; + if (IDYES == MessageBoxW(hwnd, WASABI_API_LNGSTRINGW(IDS_RESTORE_ALL_DEFAULTS), + WASABI_API_LNGSTRINGW_BUF(IDS_RESTORE_ALL_DEFAULTS_TITLE, title, 64), + MB_YESNO|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL)) + { + DeleteFileW(m_szConfigIniFile); + Sleep(100); + EndDialog(hwnd,id); + } + break; + + default: + return 0; + } + } + break; // case WM_COMMAND + + case WM_HELP: + if (lParam) + { + HELPINFO *ph = (HELPINFO*)lParam; + wchar_t title[1024]; + wchar_t buf[2048]; + wchar_t ctrl_name[1024]; + GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name)); + RemoveSingleAmpersands(ctrl_name); + buf[0] = 0; + switch(ph->iCtrlId) + { + case IDOK: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_BUTTON), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_OK_HELP, buf, 2048); + break; + + case IDCANCEL: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_BUTTON), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_CANCEL_HELP, buf, 2048); + break; + + case ID_DEFAULTS: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_BUTTON), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_RESTORE_DEFAULTS_HELP, buf, 2048); + break; + + case ID_DOCS: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_BUTTON), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_DOCUMENTATION_BUTTON_HELP, buf, 2048); + break; + + case ID_WEB: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_BUTTON), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_VIEW_ONLINE_DOCS_HELP, buf, 2048); + break; + + default: + return 0; + } + + if (buf[0]) + MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + break; // case WM_HELP + } + + return 0; +} \ No newline at end of file diff --git a/vis_milk2/config2.cpp b/vis_milk2/config2.cpp new file mode 100644 index 0000000..c210f38 --- /dev/null +++ b/vis_milk2/config2.cpp @@ -0,0 +1,425 @@ +/* + 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. +*/ + +#include "api.h" +#include "pluginshell.h" +#include "resource.h" +#include "utility.h" +#include + +int g_nFontSize[] = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30, 32, + 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 88, 96, 104, 112, 120, 128 }; + +int CALLBACK EnumFontsProc( + CONST LOGFONT *lplf, // logical-font data + CONST TEXTMETRIC *lptm, // physical-font data + DWORD dwType, // font type + LPARAM lpData // application-defined data +) +{ + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT1), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT2), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT3), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT4), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT5), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT6), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT7), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT8), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT9), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + return 1; +} + +void SaveFont2(td_fontinfo *fi, DWORD ctrl1, DWORD ctrl2, DWORD bold_id, DWORD ital_id, DWORD aa_id, HWND hwnd) +{ + HWND fontbox = GetDlgItem( hwnd, ctrl1 ); + HWND sizebox = GetDlgItem( hwnd, ctrl2 ); + + // font face + int t = SendMessage( fontbox, CB_GETCURSEL, 0, 0); + SendMessageW( fontbox, CB_GETLBTEXT, t, (LPARAM)fi->szFace); + + // font size + t = SendMessage( sizebox, CB_GETCURSEL, 0, 0); + if (t != CB_ERR) + { + int nMax = sizeof(g_nFontSize)/sizeof(int); + fi->nSize =g_nFontSize[nMax-1 - t]; + } + + // font options + fi->bBold = DlgItemIsChecked(hwnd, bold_id); + fi->bItalic = DlgItemIsChecked(hwnd, ital_id); + fi->bAntiAliased = DlgItemIsChecked(hwnd, aa_id); +} + +void InitFont2(td_fontinfo *fi, DWORD ctrl1, DWORD ctrl2, DWORD bold_id, DWORD ital_id, DWORD aa_id, HWND hwnd, DWORD ctrl4, wchar_t* szFontName) +{ + HWND namebox = ctrl4 ? GetDlgItem( hwnd, ctrl4 ) : 0; + HWND fontbox = GetDlgItem( hwnd, ctrl1 ); + HWND sizebox = GetDlgItem( hwnd, ctrl2 ); + ShowWindow(fontbox, SW_NORMAL); + ShowWindow(sizebox, SW_NORMAL); + ShowWindow(GetDlgItem(hwnd,bold_id), SW_NORMAL); + ShowWindow(GetDlgItem(hwnd,ital_id), SW_NORMAL); + ShowWindow(GetDlgItem(hwnd,aa_id), SW_NORMAL); + if (namebox && szFontName && szFontName[0]) + { + ShowWindow(namebox, SW_NORMAL); + wchar_t buf[256]; + StringCbPrintfW(buf, sizeof(buf), L"%s:", szFontName); + SetWindowTextW(GetDlgItem(hwnd,ctrl4), buf); + } + + // set selection + int nPos = SendMessageW( fontbox, CB_FINDSTRINGEXACT, -1, (LPARAM)fi->szFace); + if (nPos == CB_ERR) + nPos = 0; + SendMessage( fontbox, CB_SETCURSEL, nPos, 0); + + //---------font size box------------------- + int nSel = 0; + int nMax = sizeof(g_nFontSize)/sizeof(int); + for (int i=0; inSize) + nSel = i; + } + SendMessage(sizebox, CB_SETCURSEL, nSel, 0); + + //---------font options box------------------- + CheckDlgButton(hwnd, bold_id, fi->bBold); + CheckDlgButton(hwnd, ital_id, fi->bItalic); + CheckDlgButton(hwnd, aa_id, fi->bAntiAliased); +} + +void SCOOT_CONTROL(HWND hwnd, int ctrl_id, int dx, int dy) +{ + RECT r; + GetWindowRect(GetDlgItem(hwnd,ctrl_id), &r); + ScreenToClient(hwnd, (LPPOINT)&r); + SetWindowPos (GetDlgItem(hwnd,ctrl_id), NULL, r.left + dx, r.top + dy, 0, 0, SWP_NOSIZE|SWP_NOZORDER); +} + +BOOL CALLBACK CPluginShell::FontDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + if (msg==WM_INITDIALOG && lParam > 0 && GetWindowLongPtr(hwnd,GWLP_USERDATA)==0) + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + + CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + if (p) + return p->PluginShellFontDialogProc(hwnd, msg, wParam, lParam); + else + return FALSE; +} + +BOOL CPluginShell::PluginShellFontDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + #ifdef _DEBUG + OutputDebugMessage("FontDlgProc: ", hwnd, msg, wParam, lParam); + #endif + + switch (msg) + { + case WM_DESTROY: + return 0; + + case WM_INITDIALOG: + { + // Initialize all font dialog global variables here: + // ... + + HDC hdc = GetDC(hwnd); + if (hdc) + { + EnumFonts(hdc, NULL, &EnumFontsProc, (LPARAM)hwnd); + ReleaseDC(hwnd, hdc); + } + + #define InitFont(n, m) InitFont2(&m_fontinfo[n-1], IDC_FONT##n, IDC_FONTSIZE##n, IDC_FONTBOLD##n, IDC_FONTITAL##n, IDC_FONTAA##n, hwnd, IDC_FONT_NAME_##n, m) + InitFont(1, 0); + InitFont(2, 0); + InitFont(3, 0); + InitFont(4, 0); + #if (NUM_EXTRA_FONTS >= 1) + InitFont(5, WASABI_API_LNGSTRINGW(IDS_EXTRA_FONT_1_NAME)); + #endif + #if (NUM_EXTRA_FONTS >= 2) + InitFont(6, WASABI_API_LNGSTRINGW(IDS_EXTRA_FONT_2_NAME)); + #endif + #if (NUM_EXTRA_FONTS >= 3) + InitFont(7, EXTRA_FONT_3_NAME); + #endif + #if (NUM_EXTRA_FONTS >= 4) + InitFont(5, EXTRA_FONT_4_NAME); + #endif + #if (NUM_EXTRA_FONTS >= 5) + InitFont(9, EXTRA_FONT_5_NAME); + #endif + + // Finally, if not all extra fonts are in use, shrink the window size, and + // move up any controls that were at the bottom: + RECT r; + GetWindowRect(hwnd, &r); + int scoot_factor = 128*(MAX_EXTRA_FONTS-NUM_EXTRA_FONTS)/MAX_EXTRA_FONTS; + if (scoot_factor>0) + { + SetWindowPos(hwnd, NULL, 0, 0, r.right-r.left, r.bottom-r.top - scoot_factor, SWP_NOMOVE|SWP_NOZORDER); + SCOOT_CONTROL(hwnd, IDC_FONT_TEXT, 0, -scoot_factor); + SCOOT_CONTROL(hwnd, IDOK, 0, -scoot_factor); + SCOOT_CONTROL(hwnd, IDCANCEL, 0, -scoot_factor); + } + } + break; + + case WM_COMMAND: + { + int id = LOWORD(wParam); + switch(id) + { + case IDOK: + + #define SaveFont(n) SaveFont2(&m_fontinfo[n-1], IDC_FONT##n, IDC_FONTSIZE##n, IDC_FONTBOLD##n, IDC_FONTITAL##n, IDC_FONTAA##n, hwnd) + SaveFont(1); + SaveFont(2); + SaveFont(3); + SaveFont(4); + #if (NUM_EXTRA_FONTS >= 1) + SaveFont(5); + #endif + #if (NUM_EXTRA_FONTS >= 2) + SaveFont(6); + #endif + #if (NUM_EXTRA_FONTS >= 3) + SaveFont(7); + #endif + #if (NUM_EXTRA_FONTS >= 4) + SaveFont(5); + #endif + #if (NUM_EXTRA_FONTS >= 5) + SaveFont(9); + #endif + + EndDialog(hwnd,id); + break; + + case IDCANCEL: + EndDialog(hwnd,id); + break; + } + } + break; + + } + + return 0; +} + +void EnableStuff(HWND hwnd, int bEnable) +{ + EnableWindow(GetDlgItem(hwnd, IDC_CB_BOX), bEnable); + EnableWindow(GetDlgItem(hwnd, IDC_CB_MANUAL_SCOOT), bEnable); + EnableWindow(GetDlgItem(hwnd, IDC_DM_ALPHA_FIX_CAPTION), bEnable); + EnableWindow(GetDlgItem(hwnd, IDC_DM_ALPHA_FIX), bEnable); +} + +BOOL CALLBACK CPluginShell::DesktopOptionsDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + if (msg==WM_INITDIALOG && lParam > 0 && GetWindowLongPtr(hwnd,GWLP_USERDATA)==0) + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + + CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + if (p) + return p->PluginShellDesktopOptionsDialogProc(hwnd, msg, wParam, lParam); + else + return FALSE; +} + +BOOL CPluginShell::PluginShellDesktopOptionsDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + #ifdef _DEBUG + OutputDebugMessage("DmDlgProc: ", hwnd, msg, wParam, lParam); + #endif + + switch (msg) + { + case WM_DESTROY: + return 0; + + case WM_INITDIALOG: + { + CheckDlgButton(hwnd, IDC_CB_SHOW_ICONS, m_desktop_show_icons ); + CheckDlgButton(hwnd, IDC_CB_BOX, m_desktop_textlabel_boxes ); + CheckDlgButton(hwnd, IDC_CB_MANUAL_SCOOT, m_desktop_manual_icon_scoot); + + HWND ctrl = GetDlgItem(hwnd, IDC_DM_ALPHA_FIX); + SendMessageW( ctrl, CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_5_6_5_TEXTURE)); + SendMessageW( ctrl, CB_ADDSTRING, 1, (LPARAM)WASABI_API_LNGSTRINGW(IDS_5_5_5_TEXTURE)); + SendMessageW( ctrl, CB_ADDSTRING, 2, (LPARAM)WASABI_API_LNGSTRINGW(IDS_8_8_8_TEXTURE)); + SendMessageW( ctrl, CB_SETCURSEL, m_desktop_555_fix, 0 ); + + EnableStuff(hwnd, m_desktop_show_icons); + } + break; + + case WM_COMMAND: + { + int id = LOWORD(wParam); + switch(id) + { + case IDC_CB_SHOW_ICONS: + m_desktop_show_icons = DlgItemIsChecked(hwnd, IDC_CB_SHOW_ICONS); + EnableStuff(hwnd, m_desktop_show_icons); + break; + + case IDOK: + m_desktop_show_icons = DlgItemIsChecked(hwnd, IDC_CB_SHOW_ICONS); + m_desktop_textlabel_boxes = DlgItemIsChecked(hwnd, IDC_CB_BOX); + m_desktop_manual_icon_scoot = DlgItemIsChecked(hwnd, IDC_CB_MANUAL_SCOOT); + m_desktop_555_fix = SendMessage( GetDlgItem(hwnd, IDC_DM_ALPHA_FIX), CB_GETCURSEL, 0, 0 ); + + EndDialog(hwnd,id); + break; + + case IDCANCEL: + EndDialog(hwnd,id); + break; + } + } + break; + + case WM_HELP: + if (lParam) + { + HELPINFO *ph = (HELPINFO*)lParam; + wchar_t title[1024]; + wchar_t buf[2048]; + wchar_t ctrl_name[1024]; + GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name)); + RemoveSingleAmpersands(ctrl_name); + buf[0] = 0; + + switch(ph->iCtrlId) + { + case IDC_DM_ALPHA_FIX: + case IDC_DM_ALPHA_FIX_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_NO_ALPHA_FALLBACK, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_NO_ALPHA_FALLBACK_HELP, buf, 2048); + break; + + case IDC_CB_SHOW_ICONS: + StringCbPrintfW(title, sizeof(title), WASABI_API_LNGSTRINGW(IDS_HELP_ON_X_CHECKBOX), ctrl_name); + WASABI_API_LNGSTRINGW_BUF(IDS_CB_SHOW_ICONS_HELP, buf, 2048); + break; + + case IDC_CB_BOX: + WASABI_API_LNGSTRINGW_BUF(IDS_CB_BOX, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_CB_BOX_HELP, buf, 2048); + break; + + case IDC_CB_MANUAL_SCOOT: + WASABI_API_LNGSTRINGW_BUF(IDS_CB_MANUAL_SCOOT, title, 1024); + WASABI_API_LNGSTRINGW_BUF(IDS_CB_MANUAL_SCOOT_HELP, buf, 2048); + break; + } + + if (buf[0]) + MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + break; + } + return 0; +} + +BOOL CALLBACK CPluginShell::DualheadDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + if (msg==WM_INITDIALOG && lParam > 0 && GetWindowLongPtr(hwnd,GWLP_USERDATA)==0) + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + + CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hwnd,GWLP_USERDATA); + + if (p) + return p->PluginShellDualheadDialogProc(hwnd, msg, wParam, lParam); + else + return FALSE; +} + +BOOL CPluginShell::PluginShellDualheadDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + #ifdef _DEBUG + OutputDebugMessage("DHDlgProc: ", hwnd, msg, wParam, lParam); + #endif + + switch (msg) + { + case WM_DESTROY: + return 0; + + case WM_INITDIALOG: + { + HWND ctrl = GetDlgItem(hwnd, IDC_H_PICK); + SendMessageW( ctrl, CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_SPAN_BOTH_SCREENS)); + SendMessageW( ctrl, CB_ADDSTRING, 1, (LPARAM)WASABI_API_LNGSTRINGW(IDS_USE_LEFT_SCREEN_ONLY)); + SendMessageW( ctrl, CB_ADDSTRING, 2, (LPARAM)WASABI_API_LNGSTRINGW(IDS_USE_RIGHT_SCREEN_ONLY)); + SendMessage( ctrl, CB_SETCURSEL, m_dualhead_horz, 0 ); + + ctrl = GetDlgItem(hwnd, IDC_V_PICK); + SendMessageW( ctrl, CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_SPAN_BOTH_SCREENS)); + SendMessageW( ctrl, CB_ADDSTRING, 1, (LPARAM)WASABI_API_LNGSTRINGW(IDS_USE_TOP_SCREEN_ONLY)); + SendMessageW( ctrl, CB_ADDSTRING, 2, (LPARAM)WASABI_API_LNGSTRINGW(IDS_USE_BOTTOM_SCREEN_ONLY)); + SendMessage( ctrl, CB_SETCURSEL, m_dualhead_vert, 0 ); + } + break; + + case WM_COMMAND: + { + int id = LOWORD(wParam); + switch(id) + { + case IDOK: + m_dualhead_horz = SendMessage( GetDlgItem(hwnd, IDC_H_PICK), CB_GETCURSEL, 0, 0 ); + m_dualhead_vert = SendMessage( GetDlgItem(hwnd, IDC_V_PICK), CB_GETCURSEL, 0, 0 ); + + EndDialog(hwnd,id); + break; + + case IDCANCEL: + EndDialog(hwnd,id); + break; + } + } + break; + } + return 0; +} \ No newline at end of file diff --git a/vis_milk2/d3d9.lib b/vis_milk2/d3d9.lib new file mode 100644 index 0000000..9e08d86 Binary files /dev/null and b/vis_milk2/d3d9.lib differ diff --git a/vis_milk2/d3dx9.lib b/vis_milk2/d3dx9.lib new file mode 100644 index 0000000..ffc9f0d Binary files /dev/null and b/vis_milk2/d3dx9.lib differ diff --git a/vis_milk2/defines.h b/vis_milk2/defines.h new file mode 100644 index 0000000..80a7c2d --- /dev/null +++ b/vis_milk2/defines.h @@ -0,0 +1,223 @@ +/* + LICENSE + ------- +Copyright 2005-2012 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. +*/ + +#ifndef __NULLSOFT_DX8_PLUGIN_SHELL_DEFINES_H__ +#define __NULLSOFT_DX8_PLUGIN_SHELL_DEFINES_H__ 1 + +// APPNAME should be something like "MyPlugin 1.0". +// This is the name that will appear in Winamp's list of installed plugins. +// Try to include the version number with the name. +// Note: to change the name of the *file* (DLL) that the plugin is +// compiled to, go to Project Settings -> Link tab -> and change the +// 'output file name'. Don't forget to do it for both Debug AND +// Release builds! +#define SHORTNAME "MilkDrop 2" // used as window caption for both MilkDrop and the config panel. avoid numbers or punctuation; when 'integrate with winamp' option is enabled, these characters don't always work with all skins. +#define LONGNAME "MilkDrop v2.25c" // appears at bottom of config panel +#define LONGNAMEW L"MilkDrop v2.25c" // appears at bottom of config panel + +// INT_VERSION is the major version #, multipled by 100 (ie. version 1.02 +// would be 102). If the app goes to read in the INI file and sees that +// the INI file is from an older version of your plugin, it will ignore +// their old settings and reset them to the defaults for the new version; +// but that only works if you keep this value up-to-date. ***To disable this +// behavior, just always leave this at 100. *** +#define INT_VERSION 200 +// INT_SUBVERSION is the minor version #, counting up from 0 as you do +// mini-releases. If the plugin goes to read the old INI file and sees that +// the major version # is the same but the minor version # is not, it will, +// again, ignore their old settings and reset them to the defaults for the +// new version. ***To disable this behavior, just always leave this at 0. *** +#define INT_SUBVERSION 5 //straight=0, a=1, b=2, ... + +// SUBDIR puts milkdrop's documentation, INI file, presets folder, etc. +// in a subdir underneath Winamp\Plugins. +#define SUBDIR L"Milkdrop2\\" //"" + +// INIFILE is the name of the .INI file that will save the user's +// config panel settings. Do not include a path; just give the filename. +// The actual file will be stored in the WINAMP\PLUGINS directory, +// OR POSSIBLY c:\application data\...(user)...\winamp\plugins!!! - if +// they have sep. settings for each user! +#define INIFILE L"milk2.ini" //*** DO NOT PUT IN A SUBDIR because on save, if dir doesn't already exist, + // it won't be able to save the INI file. +#define MSG_INIFILE L"milk2_msg.ini" //*** could be in c:\program files\winamp\plugins, or in +#define IMG_INIFILE L"milk2_img.ini" // c:\application data\...user...\winamp\plugins !! +#define ADAPTERSFILE L"milk2_adapters.txt" + +// DOCFILE is the name of the documentation file that you'll write +// for your users. Do not include a path; just give the filename. +// When a user clicks the 'View Docs' button on the config panel, +// the plugin will try to display this file, located in the +// WINAMP\PLUGINS directory. +// +// ***Note that the button will be invisible (on the config panel) +// at runtime if this string is empty.*** +#define DOCFILE SUBDIR L"docs\\milkdrop.html" // set this to something like "myplugin.html" + +// PLUGIN_WEB_URL is the web address of the homepage for your plugin. +// It should be a well-formed URL (http://...). When a user clicks +// the 'View Webpage' button on the config panel, the plugin will +// launch their default browser to display this page. +// +// ***Note that the button will be invisible (on the config panel) +// at runtime if this string is empty.*** +#define PLUGIN_WEB_URL L"http://www.nullsoft.com/free/milkdrop/" // set this to something like "http://www.myplugin.com/" + +// The following two strings - AUTHOR_NAME and COPYRIGHT - will be used +// in a little box in the config panel, to identify the author & copyright +// holder of the plugin. Keep them short so they fit in the box. +#define AUTHOR_NAME L"Ryan Geiss" +#define COPYRIGHT L"(c) 2001-2013 Nullsoft, Inc." + +// CLASSNAME is the name of the window class that the plugin will +// use. You don't want this to overlap with any other plugins +// or applications that are running, so change this to something +// that will probably be unique. For example, if your plugin was +// called Libido, then "LibidoClass" would probably be a safe bet. +#define CLASSNAME L"MilkDrop2" + +// Here you can give names to the buttons (~tabs) along the top +// of the config panel. Each button, when clicked, will bring +// up the corresponding 'property page' (embedded dialog), +// IDD_PROPPAGE_1 through IDD_PROPPAGE_8. If you want less than +// 8 buttons to show up, just leave their names as blank. For +// full instructions on how to add a new tab/page, see +// DOCUMENTATION.TXT. +//#define CONFIG_PANEL_BUTTON_1 " Common Settings " // nPage==1 +//#define CONFIG_PANEL_BUTTON_2 " MORE SETTINGS " // nPage==2 +//#define CONFIG_PANEL_BUTTON_3 " Artist Tools " // nPage==3 +//#define CONFIG_PANEL_BUTTON_4 " Transitions " // nPage==4 +//#define CONFIG_PANEL_BUTTON_5 "" // nPage==5 +//#define CONFIG_PANEL_BUTTON_6 "" // nPage==6 +//#define CONFIG_PANEL_BUTTON_7 "" // nPage==7 +//#define CONFIG_PANEL_BUTTON_8 "" // nPage==8 +// As if 2.0e, these strings are defined in the stringtable of the dll +// and otherwise work the same as these header defines. +// (The equivelent of "" in these is a single space now) + +// adjust the defaults for the 4 built-in fonts here. +// (note: if you want the font to be available on 98 + ME + 2k + XP, use one of the following...) +// arial +// courier 10-12-15 +// courier new +// comic san[s] ms +// lucida console +// ms sans serif +// ms serif +// small fonts +// symbol 8-10-12-14-18-24 +// tahoma +// times new roman +// verdana +// webdings +#define SIMPLE_FONT_DEFAULT_FACE L"Courier" //"MS Sans Serif" - changed to Courier because menus + code FAR more legible! +#define SIMPLE_FONT_DEFAULT_SIZE 12 //16 +#define SIMPLE_FONT_DEFAULT_BOLD 0 +#define SIMPLE_FONT_DEFAULT_ITAL 0 +#define SIMPLE_FONT_DEFAULT_AA 0 +#define DECORATIVE_FONT_DEFAULT_FACE L"Times New Roman" +#define DECORATIVE_FONT_DEFAULT_SIZE 24 +#define DECORATIVE_FONT_DEFAULT_BOLD 0 +#define DECORATIVE_FONT_DEFAULT_ITAL 1 +#define DECORATIVE_FONT_DEFAULT_AA 1 +#define HELPSCREEN_FONT_DEFAULT_FACE L"MS Sans Serif" +#define HELPSCREEN_FONT_DEFAULT_SIZE 14 // NOTE: should fit on 640x480 screen! +#define HELPSCREEN_FONT_DEFAULT_BOLD 1 +#define HELPSCREEN_FONT_DEFAULT_ITAL 0 +#define HELPSCREEN_FONT_DEFAULT_AA 0 +#define PLAYLIST_FONT_DEFAULT_FACE L"Arial" +#define PLAYLIST_FONT_DEFAULT_SIZE 16 +#define PLAYLIST_FONT_DEFAULT_BOLD 0 +#define PLAYLIST_FONT_DEFAULT_ITAL 0 +#define PLAYLIST_FONT_DEFAULT_AA 0 + +// automatically add extra fonts to the config panel +// by simply #defining them here, UP TO A MAX OF 5 EXTRA FONTS. +// access the font by calling GetFont(EXTRA_1) for extra font #1, +// GetExtraFont(EXTRA_2) for extra font #2, and so on. +#define NUM_EXTRA_FONTS 2 // <- don't exceed 5 here! +#define TOOLTIP_FONT EXTRA_1 +//#define EXTRA_FONT_1_NAME "Tooltips" +// defined in the stringtable resources now since 2.0e +#define EXTRA_FONT_1_DEFAULT_FACE L"Arial" +#define EXTRA_FONT_1_DEFAULT_SIZE 14 +#define EXTRA_FONT_1_DEFAULT_BOLD 0 +#define EXTRA_FONT_1_DEFAULT_ITAL 0 +#define EXTRA_FONT_1_DEFAULT_AA 0 +#define SONGTITLE_FONT EXTRA_2 +//#define EXTRA_FONT_2_NAME "Animated Songtitles" +// defined in the stringtable resources now since 2.0e +#define EXTRA_FONT_2_DEFAULT_FACE L"Times New Roman" +#define EXTRA_FONT_2_DEFAULT_SIZE 18 +#define EXTRA_FONT_2_DEFAULT_BOLD 0 +#define EXTRA_FONT_2_DEFAULT_ITAL 1 +#define EXTRA_FONT_2_DEFAULT_AA 1 + +#define WINDOWCAPTION SHORTNAME // the caption that will appear on the plugin window +#define DLLDESC LONGNAME // the desc. of this DLL, as it appears in Winamp's list of viz plugins +#define MODULEDESC LONGNAME // the desc. of this viz module within the DLL (..this framework is set up for just 1 module per DLL) + +// Finally, a few parameters that will control how things are done +// inside the plugin shell: +#define NUM_WAVEFORM_SAMPLES 480 // RANGE: 32-576. This is the # of samples of waveform data that you want. + // Note that if it is less than 576, then VMS will do its best + // to line up the waveforms from frame to frame for you, using + // the extra samples as 'squish' space. + // Note: the more 'slush' samples you leave, the better the alignment + // will be. 512 samples gives you decent alignment; 400 samples + // leaves room for fantastic alignment. + // Observe that if you specify a value here (say 400) and then only + // render a sub-portion of that in some cases (say, 200 samples), + // make sure you render the *middle* 200 samples (#100-300), because + // the alignment happens *mostly at the center*. +#define NUM_FREQUENCIES 512 // # of freq. samples you want *out* of the FFT, for 0-11kHz range. + // ** this must be a power of 2! + // ** the actual FFT will use twice this many frequencies ** + +#define TEXT_MARGIN 10 // the # of pixels of margin to leave between text and the edge of the screen +#define PLAYLIST_INNER_MARGIN 4 // the extra margin between the playlist box and the text inside + +#define PLAYLIST_COLOR_PLAYING_TRACK 0xFFCCFF00 // alpha|red|green|blue +#define PLAYLIST_COLOR_HILITE_TRACK 0xFFFF5050 +#define PLAYLIST_COLOR_BOTH 0xFFFFCC22 +#define PLAYLIST_COLOR_NORMAL 0xFFCCCCCC + +#define MENU_COLOR 0xFFCCCCCC +#define MENU_HILITE_COLOR 0xFFFF4400 +#define DIR_COLOR 0xFF88CCFF +#define TOOLTIP_COLOR 0xFFBBBBCC + +#define MAX_PRESETS_PER_PAGE 32 + +//#define PRESS_F1_MSG "Press F1 for Help " // leave extra space @ end, so italicized fonts don't get clipped +// defined in the stringtable resources now since 2.0e +#define PRESS_F1_DUR 3.0f // in seconds +#define PRESS_F1_EXP 10.0f // exponent for how quickly it accelerates to leave the screen. 1 = linear; >1 = stays & then dashes off @ end + +#endif \ No newline at end of file diff --git a/vis_milk2/desktop_mode.cpp b/vis_milk2/desktop_mode.cpp new file mode 100644 index 0000000..98f7473 --- /dev/null +++ b/vis_milk2/desktop_mode.cpp @@ -0,0 +1,1097 @@ +/* + 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. +*/ + +#include "api.h" +#include "pluginshell.h" +#include "resource.h" +#include "utility.h" +#include "defines.h" +#include + +//---------------------------------------------------------------------- + +#define VMS_DESKTOP_DLLNAME (SUBDIR L"data\\vms_desktop.dll") + +//---------------------------------------------------------------------- + +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; + +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 SIMPLE_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE) +#define HELP_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) + +//---------------------------------------------------------------------- + +// resides in vms_desktop.dll/lib: +int setHook(HWND hlv,HWND w,int version); +void removeHook(); + +//---------------------------------------------------------------------- + +typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); +bool IsVistaOrLater() +{ + // adapted from "Getting the System Version" on MSDN - http://msdn2.microsoft.com/en-us/library/ms724429.aspx + OSVERSIONINFOEX osvi; + SYSTEM_INFO si; + PGNSI pGNSI; + BOOL bOsVersionInfoEx; + + ZeroMemory(&si, sizeof(SYSTEM_INFO)); + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) + { + // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. + pGNSI = (PGNSI) GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo" ); + if(NULL != pGNSI) + pGNSI(&si); + else + GetSystemInfo(&si); + + if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId && osvi.dwMajorVersion > 4 ) + { + if ( osvi.dwMajorVersion >= 6 ) + return true; + } + } + return false; +} + +int CPluginShell::InitDesktopMode() +{ + if (m_screenmode != DESKTOP) + return false; + + // check for Vista - if Vista, don't try to draw desktop icons. + // [ vms_desktop.dll's message posts to the desktop listview window cause explorer to crash... + // whether it sends WM_NULL or WM_USER+516/517. ] + if (m_desktop_show_icons && IsVistaOrLater()) + m_desktop_show_icons = false; + + if (!m_desktop_show_icons) + return true; + + // note: we have to explicitly make sure the DLL is present, + // since we're delay-loading it; otherwise, calling setHook, etc. will crash it. + wchar_t szVmsDesktopDll[MAX_PATH]; + swprintf(szVmsDesktopDll, L"%s%s", GetPluginsDirPath(), VMS_DESKTOP_DLLNAME); + if (!GetModuleHandleW(szVmsDesktopDll)) + { + if (!LoadLibraryW(szVmsDesktopDll)) + { + wchar_t buf[2048]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_COULD_NOT_FIND_FILE_FOR_DESKTOP_MODE_X), szVmsDesktopDll); + MessageBoxW(GetPluginWindow(),buf,WASABI_API_LNGSTRINGW(IDS_MILKDROP_ERROR_FILE_MISSING), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + //return false; + m_desktop_icons_disabled = 1; + } + else + { + m_vms_desktop_loaded = 1; + } + } + + InitializeCriticalSection(&m_desktop_cs); + + m_desktop_icon_state = 0; + m_desktop_icon_count = 0; + m_desktop_icon_update_frame = 0; + m_desktop_icon_size = GetDesktopIconSize(); + + // GDI font for desktop mode: + LOGFONT lf = {0}; + wchar_t title[64]; + if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0)) + { + if (!(m_font_desktop = CreateFontIndirect(&lf))) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_GDI_DESKTOP_FONT), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + } + else + { + if (!(m_font_desktop = CreateFont(14, 0, 0, 0, 0, 0, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, "Monotype Sans Serif"))) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_GDI_DESKTOP_FONT), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + } + + // Create D3DX font for drawing icon labels on desktop: + if (pCreateFontW(m_lpDX->m_lpDevice, 14, 0, 0, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, L"Monotype Sans Serif", &m_d3dx_desktop_font) != D3D_OK) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_DESKTOP_FONT), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + // create first texture for holding icon bitmaps: + // (do it now, to ensure that at least 1 gets created, before + // the plugin does all of its DX9 allocations.) + if (!CreateDesktopIconTexture(&m_desktop_icons_texture[0])) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_TEXTURE_FOR_ICON_BITMAPS), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + } + + if (!m_desktop_icons_disabled) + { + int ret = setHook(m_hWndDesktopListView, GetPluginWindow(), 1); + if (ret == 1) + m_desktop_hook_set = 1; + else if (ret == -1) + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_OUTDATED_VMS_DESKTOP_DLL_NEED_TO_REINSTALL), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + else + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_HOOK_PROC_DESKTOP_ICONS_NOT_AVAILABLE), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + } + + return true; +} + +//---------------------------------------------------------------------- + +void CPluginShell::CleanUpDesktopMode() +{ + if (m_screenmode != DESKTOP) + return; + if (!m_desktop_show_icons) + return; + + if (m_desktop_hook_set) + { + m_desktop_hook_set = 0; + removeHook(); + } + + for (int i=0; iRelease(); + *ppTex = NULL; + } + + // create new + int ntries = (m_lpDX->m_d3dpp.BackBufferFormat == D3DFMT_R5G6B5) ? 3 : 1; + for (int ntry=0; ntrym_d3dpp.BackBufferFormat; + switch(m_lpDX->m_d3dpp.BackBufferFormat) + { + case D3DFMT_R8G8B8: + case D3DFMT_X8R8G8B8: + fmt = D3DFMT_A8R8G8B8; + break; + case D3DFMT_R5G6B5: // <- PROBLEM: NO ALPHA CHANNEL FOR ICONS + if (ntry==0) + switch(m_desktop_555_fix) + { + case 0: fmt = D3DFMT_R5G6B5; break; + case 1: fmt = D3DFMT_A1R5G5B5; break; + case 2: fmt = D3DFMT_A8R8G8B8; break; + } + else if (ntry==1) + switch(m_desktop_555_fix) + { + case 0: fmt = D3DFMT_A1R5G5B5; break; + case 1: fmt = D3DFMT_A8R8G8B8; break; + case 2: fmt = D3DFMT_A1R5G5B5; break; + } + else + switch(m_desktop_555_fix) + { + case 0: fmt = D3DFMT_A8R8G8B8; break; + case 1: fmt = D3DFMT_R5G6B5; break; + case 2: fmt = D3DFMT_R5G6B5; break; + } + break; + case D3DFMT_X1R5G5B5: + fmt = D3DFMT_A1R5G5B5; + break; + } + + if (m_lpDX->m_lpDevice->CreateTexture(ICON_TEXTURE_SIZE, ICON_TEXTURE_SIZE, 1, 0, fmt, D3DPOOL_MANAGED, ppTex, NULL) != D3D_OK) + *ppTex = NULL; + else + break; + } + + return (*ppTex) ? 1 : 0; +} + +//---------------------------------------------------------------------- + +void CPluginShell::DeselectDesktop() +{ + IconList::iterator p; + for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) + p->selected = 0; +} + +//---------------------------------------------------------------------- + +void CPluginShell::UpdateDesktopBitmaps() +{ + // update the D3DX textures that hold all the icons: + + int idx = 0; + int texnum = 0; + int show_msgs = 1; + + // if no icon texture could be created at startup, + // don't bother trying anything here, and don't give them + // any extra error messages. + if (!m_desktop_icons_texture[0]) + return; + + IconList::iterator p; + for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) + p->icon_bitmap_idx = -1; + + do + { + idx = StuffIconBitmaps(idx, texnum++, &show_msgs); + } + while (idx > 0 && texnum < MAX_ICON_TEXTURES); + + if (idx > 0) + { + wchar_t title[64]; + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + } +} + +//---------------------------------------------------------------------- + +int CPluginShell::StuffIconBitmaps(int iStartIconIdx, int iTexNum, int *show_msgs) +{ + // returns: + // 0 if done (or error), or + // N if the texture is full & we need to start another one, + // where N is the new iStartIconIdx to use. + + if (m_screenmode != DESKTOP) + return 0; + + wchar_t title[64]; + if (!m_desktop_icons_texture[iTexNum]) + { + int ret = CreateDesktopIconTexture(&m_desktop_icons_texture[iTexNum]); + if (!ret) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_TOO_MANY_UNIQUE_ICON_BITMAPS), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return 0; + } + } + + D3DSURFACE_DESC sd; + if (m_desktop_icons_texture[iTexNum]->GetLevelDesc(0, &sd) != D3D_OK) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_COULD_NOT_GET_LEVEL_DESCRIPTION), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return 0; + } + + D3DLOCKED_RECT lr; + if (m_desktop_icons_texture[iTexNum]->LockRect(0, &lr, NULL, 0) != D3D_OK) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_LOCKRECT_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return 0; + } + if (lr.pBits == NULL) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_LR_PBITS_IS_NULL), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + m_desktop_icons_texture[iTexNum]->UnlockRect(0); + return 0; + } + + unsigned __int16* p16 = (unsigned __int16*)lr.pBits; + unsigned __int32* p32 = (unsigned __int32*)lr.pBits; + int WIDTH = sd.Width; + + int i; + + int start; + int bpp; + int rshift[3]; // 1. bits to first shift right r,g,b + int mask[3]; // 2. mask for r, g, b + int lshift[3]; // 3. bits to then shift left r,g,b + + switch(sd.Format) + { + case D3DFMT_R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + start = 0xFF000000; + bpp = 32; + rshift[0] = 0; + rshift[1] = 0; + rshift[2] = 0; + mask[0] = 0xFF; + mask[1] = 0xFF; + mask[2] = 0xFF; + lshift[0] = 16; + lshift[1] = 8; + lshift[2] = 0; + break; + + case D3DFMT_R5G6B5: + start = 0x0000; + bpp = 16; + rshift[0] = 3; + rshift[1] = 2; + rshift[2] = 3; + mask[0] = 0x1F; + mask[1] = 0x3F; + mask[2] = 0x1F; + lshift[0] = 11; + lshift[1] = 5; + lshift[2] = 0; + break; + + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + start = 0x8000; + bpp = 16; + rshift[0] = 3; + rshift[1] = 3; + rshift[2] = 3; + mask[0] = 0x1F; + mask[1] = 0x1F; + mask[2] = 0x1F; + lshift[0] = 10; + lshift[1] = 5; + lshift[2] = 0; + break; + + case D3DFMT_A4R4G4B4: + start = 0xF000; + bpp = 16; + rshift[0] = 4; + rshift[1] = 4; + rshift[2] = 4; + mask[0] = 0x0F; + mask[1] = 0x0F; + mask[2] = 0x0F; + lshift[0] = 8; + lshift[1] = 4; + lshift[2] = 0; + break; + + default: + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_UNKNOWN_PIXEL_FORMAT), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + m_desktop_icons_texture[iTexNum]->UnlockRect(0); + return 0; + } + + HDC hdc = GetDC(NULL); + if (!hdc) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_COULDNT_GET_HDC), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + m_desktop_icons_texture[iTexNum]->UnlockRect(0); + return 0; + } + + #define MAX_ICON_SIZE 128 + unsigned char data[MAX_ICON_SIZE*MAX_ICON_SIZE*4]; + + int nAcross = ICON_TEXTURE_SIZE/m_desktop_icon_size; + int nDown = ICON_TEXTURE_SIZE/m_desktop_icon_size; + + // for each icon, add its bitmap to the texture (if not already there), + // and set 'icon_bitmap_idx'. + IconList::iterator p = m_icon_list.begin(); + for (i=0; i < iStartIconIdx; i++) + p++; + + int bitmap_idx = 0; + int list_idx = iStartIconIdx; + + for ( ; p != m_icon_list.end() && bitmap_idx < nAcross*nDown; p++) + { + // note: 'p' points to the correct icon to start with, + // but 'idx' starts at zero! + + // get the icon: + SHFILEINFO sfi; + int flags = SHGFI_ICON|SHGFI_PIDL|SHGFI_SHELLICONSIZE | ((m_desktop_icon_size > 32) ? SHGFI_LARGEICON : 0); + if (SHGetFileInfo((LPCTSTR)p->pidl, 0, &sfi, sizeof(sfi), flags)) + { + ICONINFO ii; + if (GetIconInfo(sfi.hIcon, &ii)) + { + int x0 = (bitmap_idx%nAcross)*m_desktop_icon_size; + int y0 = (bitmap_idx/nAcross)*m_desktop_icon_size; + int checksum[3] = { 0, 0, 0 }; + + BITMAPINFO bmi; + + // pass 1: get the colors + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = m_desktop_icon_size; + bmi.bmiHeader.biHeight = m_desktop_icon_size; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + if (GetDIBits( + hdc, // handle to DC + ii.hbmColor, // handle to bitmap + 0, // first scan line to set + m_desktop_icon_size,// number of scan lines to copy + data, // array for bitmap bits + &bmi, // bitmap data buffer + DIB_RGB_COLORS // RGB or palette index + )) + { + int w = min(bmi.bmiHeader.biWidth , m_desktop_icon_size); + int h = min(bmi.bmiHeader.biHeight, m_desktop_icon_size); + + for (int y=0; y> rshift[0]) & mask[0]) << lshift[0]) | + (((g >> rshift[1]) & mask[1]) << lshift[1]) | + (((b >> rshift[2]) & mask[2]) << lshift[2]); + else + p32[out_offset] = start | + (((r >> rshift[0]) & mask[0]) << lshift[0]) | + (((g >> rshift[1]) & mask[1]) << lshift[1]) | + (((b >> rshift[2]) & mask[2]) << lshift[2]); + } + } + else + { + if (*show_msgs) + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_CALL_TO_GETDIBITS_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + *show_msgs = 0; + } + + // pass 2: get the alpha mask + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = m_desktop_icon_size; + bmi.bmiHeader.biHeight = m_desktop_icon_size; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + if (GetDIBits( + hdc, // handle to DC + ii.hbmMask, // handle to bitmap + 0, // first scan line to set + m_desktop_icon_size,// number of scan lines to copy + data, // array for bitmap bits + &bmi, // bitmap data buffer + DIB_RGB_COLORS // RGB or palette index + )) + { + int w = min(bmi.bmiHeader.biWidth , m_desktop_icon_size); + int h = min(bmi.bmiHeader.biHeight, m_desktop_icon_size); + + for (int y=0; ychecksum[0] && + checksum[1] == q->checksum[1] && + checksum[2] == q->checksum[2]) + { + p->icon_bitmap_idx = q->icon_bitmap_idx; + done = 1; + break; + } + } + + // otherwise, keep new icon + if (!done) + { + p->icon_bitmap_idx = nAcross*nDown*iTexNum + bitmap_idx; + p->checksum[0] = checksum[0]; + p->checksum[1] = checksum[1]; + p->checksum[2] = checksum[2]; + + bitmap_idx++; + } + + DeleteObject(ii.hbmMask); + DeleteObject(ii.hbmColor); + } + else + { + if (*show_msgs) + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_GETICONINFO_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + *show_msgs = 0; + } + + DestroyIcon(sfi.hIcon); + } + else + { + if (*show_msgs) + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_SHGETFILEINFO_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + *show_msgs = 0; + } + + list_idx++; + } + + ReleaseDC(NULL, hdc); + m_desktop_icons_texture[iTexNum]->UnlockRect(0); + + if (bitmap_idx >= nAcross*nDown) + return list_idx; + else + return 0; // all done +} + +//---------------------------------------------------------------------- + +void CPluginShell::RenderDesktop() +{ + if (m_screenmode != DESKTOP) + return; + if (!m_desktop_show_icons) + return; + if (m_desktop_icons_disabled) + return; + + IconList::iterator p; + + EnterCriticalSection(&m_desktop_cs); + + int iconcount = static_cast(SendMessage(m_hWndDesktopListView, LVM_GETITEMCOUNT, 0, 0)); + if (iconcount == 0) + { + LeaveCriticalSection(&m_desktop_cs); + return; + } + + // if the icons list is empty, + // or if we check it for consistency and an update is recommended (GetDesktopIcons(1)==2), + // update the icons list & the bitmaps: + /*if (m_icon_list.size()==0 || GetDesktopIcons(1)==2) + { + m_icon_list.clear(); + GetDesktopIcons(0); + + UpdateDesktopBitmaps(); + }*/ + + // check for invalid entries. (if there is an error in getItemData(), + // it will return the icon_t structure anyway, but with empty strings.) + int invalid_entries = 0; + if (m_desktop_icon_state >= 2) + { + for (p = m_icon_list.begin(); p != m_icon_list.end() && !invalid_entries; p++) + { + if (p->name[0]==0) + invalid_entries = 1; + //if (p->pidl[0].mkid.cb==0 && p->pidl[0].mkid.abID[0]==0) + if (p->pidl[0]==0 && p->pidl[1]==0) + invalid_entries = 1; + } + } + + if ( + (m_desktop_icon_state == 0) || + (m_desktop_icon_state >= 2 && m_desktop_icon_count != iconcount) || + (m_desktop_icon_state >= 2 && invalid_entries) + ) + { + // begin total refresh + m_desktop_icon_state = 1; + m_desktop_icon_count = iconcount; + m_desktop_icon_update_frame = GetFrame(); + m_icon_list.clear(); + + SendMessage(GetPluginWindow(), WM_USER, 0x80000000 | iconcount, 0);//getItemData(i); + + // try to get the desktop window's listview to respond to + // the queries as quickly as possible: + { + LeaveCriticalSection(&m_desktop_cs); + + DWORD procid = NULL; + DWORD threadid = GetWindowThreadProcessId(m_hWndDesktopListView, &procid); + + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION, FALSE, procid); + DWORD x = GetPriorityClass(hProcess); + if (x) SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); + + for (int i=0; i<5; i++) + { + Sleep(10); + + MSG msg; + while(PeekMessage(&msg,GetPluginWindow(),0,0,PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + if (x) SetPriorityClass(hProcess, x); + CloseHandle(hProcess); + + EnterCriticalSection(&m_desktop_cs); + } + } + else if (m_desktop_icon_state == 1 && + m_icon_list.size() < (size_t)m_desktop_icon_count) + { + // waiting for the 'total refresh' to complete + // ... + if (GetFrame() > m_desktop_icon_update_frame+64) + { + m_desktop_icon_state = 0; + } + } + else + if (m_desktop_icon_state == 1 && + m_icon_list.size() == m_desktop_icon_count) + { + // done with total refresh + m_desktop_icon_state = 2; + m_desktop_icon_update_frame = GetFrame(); + UpdateDesktopBitmaps(); + } + else if (m_desktop_icon_state == 2) + { + if (GetFrame() > m_desktop_icon_update_frame+4) + { + m_desktop_icon_state = 3; // will mean we're waiting on data to return. + m_desktop_icon_update_frame = GetFrame(); + int start = 0; + int len = iconcount; + SendMessage(GetPluginWindow(), WM_USER, start | (len << 16), 0);//getItemData(i); + } + } + else if (m_desktop_icon_state == 3) + { + if (GetFrame() > m_desktop_icon_update_frame+64) + { + // timeout; give up waiting for update message to come back, + // and just request another. + m_desktop_icon_state = 2; + m_desktop_icon_update_frame = GetFrame(); + } + } + + // get horz. spacing between icons (...determines width of labels) + ICONMETRICS icm; + icm.cbSize = sizeof(icm); + if (!SystemParametersInfo(SPI_GETICONMETRICS, sizeof(icm), &icm, 0)) + icm.iHorzSpacing = 68; + + /*int font_height = 0; + { + RECT r; + m_d3dx_desktop_font->DrawText(NULL, "M", -1, &r, DT_CALCRECT, 0xFFFFFFFF); + font_height = r.bottom - r.top; + }*/ + + // display the desktop. + + m_lpDX->m_lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); + + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + m_lpDX->m_lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);//D3DTOP_SELECTARG1 ); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + m_lpDX->m_lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + int nAcross = ICON_TEXTURE_SIZE/m_desktop_icon_size; + int nDown = ICON_TEXTURE_SIZE/m_desktop_icon_size; + + // The icon's x and y coordinates (as returned by the + // getIconData/WM_COPYDATA system) are (0,0) at the + // upper-left corner of the rectangle that encompasses + // all the monitors together (m_lpDX->m_all_monitors_rect). + + // Note that in 'm_all_monitors_rect', (0,0) represents + // the upper-left corner of the PRIMARY DISPLAY - not necessarily + // the one we're showing the fake desktop on. + + // What we have to do here is determine icon_dx and icon_dy, + // which are the transformation from the coordinate space used + // by the desktop itself (as returned in WM_COPYDATA) + // and the coordinates used by Windows itself (where 0,0 is + // the upper-left corner of the PRIMARY DISPLAY, and coordinates + // in other displays can be negative if they are above/left of it). + + int upperleft_x = min(m_lpDX->m_all_monitors_rect.left, m_lpDX->m_monitor_rect.left); + int upperleft_y = min(m_lpDX->m_all_monitors_rect.top , m_lpDX->m_monitor_rect.top ); + int icon_dx = m_lpDX->m_monitor_rect.left - upperleft_x; // subtract this amount + int icon_dy = m_lpDX->m_monitor_rect.top - upperleft_y; // subtract this amount + + if (!m_desktop_manual_icon_scoot) + { + icon_dx -= m_lpDX->m_monitor_rect.left - m_lpDX->m_monitor_work_rect.left; + icon_dy -= m_lpDX->m_monitor_rect.top - m_lpDX->m_monitor_work_rect.top ; + } + + // pass 0: draw normal text & icons + // pass 1: redraw icon currently being dragged, transparently + int nPasses = m_desktop_dragging ? 2 : 1; + for (int pass=0; passm_lpDevice->SetVertexShader( NULL ); + m_lpDX->m_lpDevice->SetFVF( SIMPLE_VERTEX_FORMAT ); + m_lpDX->m_lpDevice->SetTexture(0, NULL); + SIMPLEVERTEX verts[4]; + + // pass2==0: draw text labels + // pass2==1: draw text overtop + // (separated for speed, so ID3DXFont can get the HDC just once for all the DrawText calls) + for (int pass2=0; pass2<2; pass2++) + { + //if (pass2==1) + //m_d3dx_desktop_font->Begin(); + + for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) + { + if (pass==0 || (p->selected && m_desktop_dragging)) + { + int max_width = icm.iHorzSpacing-5+m_desktop_icon_size-32;//icm.iHorzSpacing-5; + + int dx = 0; + int dy = 4; + + if (pass>0) + { + dx += m_desktop_drag_curpos.x - m_desktop_drag_startpos.x; + dy += m_desktop_drag_curpos.y - m_desktop_drag_startpos.y; + } + + SetRect(&p->label_rect, + p->x + m_desktop_icon_size/2 - icon_dx - max_width/2 + dx, + p->y + m_desktop_icon_size - icon_dy + dy, + p->x + m_desktop_icon_size/2 - icon_dx + max_width/2 + dx, + p->y + m_desktop_icon_size - icon_dy + 0 + dy // will be extended by DT_CALCRECT step! + ); + + // calculate rect for the text label + DWORD style = DT_CENTER|DT_WORDBREAK|DT_END_ELLIPSIS|DT_WORD_ELLIPSIS; + // these aren't supported by D3DX9: + style &= ~(DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX); + m_d3dx_desktop_font->DrawText(NULL, p->name, -1, &p->label_rect, style|DT_CALCRECT, 0xFFFFFFFF); + + // D3DX doesn't handle text so well if it goes off + // the left edge of the screen, so don't show text labels + // that are mostly off (on the left side): + if ((p->label_rect.left + p->label_rect.right)/2 > 0) + { + // also, if label would go off left edge of screen, + // push it to the right: + if (p->label_rect.left < 0 && p->label_rect.right > 0) + { + p->label_rect.right -= p->label_rect.left; + p->label_rect.left = 0; + } + + //if (p->selected) // ...draw blue background around text label + if (pass2==0) + { + if (m_desktop_textlabel_boxes || p->selected) + { + #define EXTEND_LEFT 3 + #define EXTEND_RIGHT 2 + #define EXTEND_TOP 0 + #define EXTEND_BOTTOM 2 + for (int i=0; i<4; i++) + { + verts[i].x = (i%2==0) ? (float)(-m_lpDX->m_client_width/2 + p->label_rect.left - EXTEND_LEFT) : (float)(-m_lpDX->m_client_width/2 + p->label_rect.right + EXTEND_RIGHT); // was -2/+3 + verts[i].y = (i/2==0) ? (float)(m_lpDX->m_client_height/2 - p->label_rect.top + EXTEND_TOP ) : (float)(m_lpDX->m_client_height/2 - p->label_rect.bottom - EXTEND_BOTTOM); // was +1/-1 + verts[i].z = 0; + verts[i].Diffuse = (p->selected) ? m_desktop_sel_color : m_desktop_bk_color;//0xFF000000; + if (pass>0) + verts[i].Diffuse &= 0x7FFFFFFF; + } + m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(SIMPLEVERTEX)); + } + } + else + { + DWORD text_color = (p->selected) ? m_desktop_sel_text_color : m_desktop_text_color; + if (pass==1) + text_color &= 0x7FFFFFFF; + // these aren't supported by D3DX9: + style &= ~(DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX); + m_d3dx_desktop_font->DrawText(NULL, p->name, -1, &p->label_rect, style, text_color); + } + } + } + } + + //if (pass2==1) + // m_d3dx_desktop_font->End(); + } + } + + 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 ); + + // second, draw icon bitmaps (overtop) + if (m_desktop_icon_state >= 2) + { + int dx = 0; + int dy = 0; + int iTexNum = 0; + + while (m_desktop_icons_texture[iTexNum] && iTexNum < MAX_ICON_TEXTURES) + { + HELPVERTEX verts[4]; + m_lpDX->m_lpDevice->SetVertexShader( NULL ); + m_lpDX->m_lpDevice->SetFVF( HELP_VERTEX_FORMAT ); + m_lpDX->m_lpDevice->SetTexture(0, m_desktop_icons_texture[iTexNum]); + + for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) + { + int icon_tex_idx = (p->icon_bitmap_idx==-1) ? 0 : (p->icon_bitmap_idx / (nAcross*nDown)); + int icon_bitmap_idx = (p->icon_bitmap_idx==-1) ? 0 : (p->icon_bitmap_idx % (nAcross*nDown)); + if ( + (icon_tex_idx == iTexNum) && + (pass==0 || (p->selected && m_desktop_dragging)) + ) + { + SetRect(&p->icon_rect, + p->x - icon_dx + dx, + p->y - icon_dy + dy, + p->x - icon_dx + dx + m_desktop_icon_size, + p->y - icon_dy + dy + m_desktop_icon_size); + + int lookup_x = 0; + int lookup_y = 0; + + if (icon_bitmap_idx >= 0) // if -1, means icon didn't fit in the texture + { + lookup_x = icon_bitmap_idx % nAcross; + lookup_y = icon_bitmap_idx / nAcross; + } + + for (int i=0; i<4; i++) + { + verts[i].x = (i%2==0) ? (float)(-m_lpDX->m_client_width/2 + p->icon_rect.left) : (float)(-m_lpDX->m_client_width/2 + p->icon_rect.right ); + verts[i].y = (i/2==0) ? (float)(m_lpDX->m_client_height/2 - p->icon_rect.top ) : (float)(m_lpDX->m_client_height/2 - p->icon_rect.bottom); + verts[i].z = 0; + verts[i].tu = ((lookup_x + i%2)*m_desktop_icon_size + 0.5f)/(float)ICON_TEXTURE_SIZE; + verts[i].tv = ((lookup_y + i/2)*m_desktop_icon_size + 0.5f)/(float)ICON_TEXTURE_SIZE; + verts[i].Diffuse = (p->selected) ? m_desktop_sel_color : 0xFFFFFFFF; + if (pass>0) + { + verts[i].x += m_desktop_drag_curpos.x - m_desktop_drag_startpos.x; + verts[i].y -= m_desktop_drag_curpos.y - m_desktop_drag_startpos.y; + verts[i].Diffuse &= 0x7FFFFFFF; + } + } + + m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(HELPVERTEX)); + } + } + + iTexNum++; + } + } + } + + // finally, draw selection box (if user is dragging one) + if (m_desktop_box) + { + m_lpDX->m_lpDevice->SetVertexShader( NULL ); + m_lpDX->m_lpDevice->SetFVF( SIMPLE_VERTEX_FORMAT ); + m_lpDX->m_lpDevice->SetTexture(0, NULL); + SIMPLEVERTEX verts[5]; + for (int i=0; i<4; i++) + { + verts[i].x = (i==1||i==2) ? (float)(-m_lpDX->m_client_width/2 + m_desktop_drag_startpos.x) : (float)(-m_lpDX->m_client_width/2 + m_desktop_drag_curpos.x); + verts[i].y = (i==0||i==1) ? (float)(m_lpDX->m_client_height/2 - m_desktop_drag_startpos.y) : (float)(m_lpDX->m_client_height/2 - m_desktop_drag_curpos.y); + verts[i].z = 0; + verts[i].Diffuse = 0x80FFFFFF; + } + verts[4] = verts[0]; + m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, 4, verts, sizeof(SIMPLEVERTEX)); + } + + m_lpDX->m_lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + m_lpDX->m_lpDevice->SetTexture(0, NULL); + + LeaveCriticalSection(&m_desktop_cs); +} + +//---------------------------------------------------------------------- + +/* +NOTES LOG + +-problem: you can't click on the 1st monitor's desktop & do stuff + -> fixed if you get rid of m_desktop_focuswnd and + don't block WM_MOUSEACTIVATE. + -> but doing this causes a flash when you click on + the real desktop (in multimon setup) of any windows + that are overtop of the fake desktop, since the + fake desktop rises up in the Z order (activates) + and then, next frame, gets pushed back again. + -> so how do we avoid the flash? + by [conditionally] stopping any z-order changes; + intercept & change WM_WINDOWPOSCHANGING messages + so there's no z-change, unless *we* specifically + requested it (in PushWindowToBack()). + -> new problem: right-click context menu won't go away + until you click something. + -> was fixed by making the plugin window a child + of m_hWndDesktopListView. +*/ \ No newline at end of file diff --git a/vis_milk2/dxcontext.cpp b/vis_milk2/dxcontext.cpp new file mode 100644 index 0000000..2de8e79 --- /dev/null +++ b/vis_milk2/dxcontext.cpp @@ -0,0 +1,1415 @@ +/* + 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. +*/ + +#include "api.h" +#include "DXContext.h" +#include "utility.h" +#include "shell_defines.h" +#include "resource.h" +#define COMPILE_MULTIMON_STUBS 1 +#include +#include + +// note: added WS_EX_CONTROLPARENT and WS_TABSTOP for embedwnd so window frame will pass on KB commands to us, if it has focus & receives them. +// however, it is still not working. Maksim says he needs to use GetNextDlgTabItem() and then it will work. +// aha- had to remove WS_EX_CONTROLPARENT and WS_OVERLAPPED. Should now work with winamp 5.5 build 1620. +#define MY_EXT_WINDOW_STYLE (m_current_mode.m_skin ? 0/*WS_EX_CONTROLPARENT*/ : ((m_current_mode.screenmode==DESKTOP) ? (WS_EX_TOOLWINDOW) : 0)) // note: changed from TOOLWINDOW to APPWINDOW b/c we wanted the plugin to appear in the taskbar. +#define SKINNED_WS (WS_VISIBLE|WS_CHILDWINDOW/*|WS_OVERLAPPED*/|WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_TABSTOP) +#define MY_WINDOW_STYLE (m_current_mode.m_skin ? SKINNED_WS : ((m_current_mode.screenmode==FAKE_FULLSCREEN || m_current_mode.screenmode==DESKTOP) ? WS_POPUP : WS_OVERLAPPEDWINDOW)) // note: WS_POPUP (by itself) removes all borders, captions, etc. + +#include "vis.h" +extern winampVisModule mod1; + +DXContext::DXContext(HWND hWndWinamp,HINSTANCE hInstance,LPCWSTR szClassName,LPCSTR szWindowCaption,WNDPROC pProc,LONG_PTR uWindowLong, int minimize_winamp, wchar_t* szIniFile) +{ + m_classAtom = 0; + m_szWindowCaption[0] = 0; + m_hwnd = NULL; + m_lpD3D = NULL; + m_lpDevice = NULL; + m_hmod_d3d9 = NULL; + m_hmod_d3dx9 = NULL; + m_zFormat = D3DFMT_UNKNOWN; + for (int i=0; i= 1) + if (m_current_mode.screenmode == WINDOWED) + { + // oversize it - then we'll just crop - so onscreen text has no stretching :) + m_client_width = max(1, (m_REAL_client_width + 31)/32)*32; + m_client_height = max(1, (m_REAL_client_height + 31)/32)*32; + } +#endif +} + +BOOL DXContext::TestFormat(int ordinal_adapter, D3DFORMAT fmt) +{ + if (D3D_OK==m_lpD3D->CheckDeviceType(ordinal_adapter,D3DDEVTYPE_HAL,fmt,fmt,FALSE)) + return TRUE; + return FALSE; +} + +BOOL DXContext::TestDepth(int ordinal_adapter, D3DFORMAT fmt) +{ + if (D3D_OK!=m_lpD3D->CheckDeviceFormat(ordinal_adapter,D3DDEVTYPE_HAL,m_current_mode.display_mode.Format, + D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,fmt)) + return FALSE; + if (D3D_OK!=m_lpD3D->CheckDepthStencilMatch(ordinal_adapter,D3DDEVTYPE_HAL, + m_current_mode.display_mode.Format,m_current_mode.display_mode.Format,fmt)) + return FALSE; + return TRUE; +} + +int DXContext::CheckAndCorrectFullscreenDispMode(int ordinal_adapter, D3DDISPLAYMODE *pdm) +{ + // given the user's choice of fullscreen display mode, + // go through all the display modes available to the currently-selected adapter + // and find the best match. + + // returns 1 if it altered pdm to the best match, + // or 0 if it was able to find a perfect match. + + // if it returns 1, you might want to notify the user. + + +#define MAX_DISPLAY_MODES 4096 + D3DDISPLAYMODE list[MAX_DISPLAY_MODES]; + int nCount = min(m_lpD3D->GetAdapterModeCount(ordinal_adapter, D3DFMT_A8R8G8B8), MAX_DISPLAY_MODES); + int nValid = 0; + for (int i=0; iEnumAdapterModes(ordinal_adapter, D3DFMT_A8R8G8B8, i, &list[nValid]) == D3D_OK) + nValid++; + + // do many passes through the set until we find a match, + // each time relaxing more constraints. + // outline of the passes: + + int bpp_desired = 0; + switch (pdm->Format) + { + case D3DFMT_R8G8B8 : bpp_desired = 32; break; + case D3DFMT_A8R8G8B8: bpp_desired = 32; break; + case D3DFMT_X8R8G8B8: bpp_desired = 32; break; + case D3DFMT_R5G6B5 : bpp_desired = 16; break; + case D3DFMT_X1R5G5B5: bpp_desired = 16; break; + case D3DFMT_A1R5G5B5: bpp_desired = 16; break; + case D3DFMT_A4R4G4B4: bpp_desired = 16; break; + case D3DFMT_R3G3B2 : bpp_desired = 8; break; + case D3DFMT_A8R3G3B2: bpp_desired = 16; break; + case D3DFMT_X4R4G4B4: bpp_desired = 16; break; + } + + // rep MATCH: + // 0. w,h,r,f + // 1. w,h,-,f + // 2. w,h,r,- pass: + // 3. w,h,-,- -on pass 0, for 'f', match exact format + // 4. 8,6,r,f -on pass 1, for 'f', just match # of bits per pixel + // 5. 8,6,-,f (more relaxed match) + // 6. 8,6,r,- + // 7. 8,6,-,- + // 8. -,-,r,f + // 9. -,-,-,f + // 10. -,-,r,- + // 11. -,-,-,- + int found = 0; + for (int rep=0; rep<12 && !found; rep++) + { + for (int pass=0; pass<2 && !found; pass++) + { + for (i=0; iWidth != list[i].Width) + bMatch = false; + if (pdm->Height != list[i].Height) + bMatch = false; + } + else if (rep < 8) + { + if (DEFAULT_FULLSCREEN_WIDTH != list[i].Width) + bMatch = false; + if (DEFAULT_FULLSCREEN_HEIGHT != list[i].Height) + bMatch = false; + } + + if (((rep/2)%2)==0) + { + if (pass==0 && pdm->Format != list[i].Format) + bMatch = false; + else if (pass==1 && bpp_desired != bpp_this_mode) + bMatch = false; + } + + if (((rep%2)==0) && pdm->RefreshRate != list[i].RefreshRate) + { + bMatch = false; + } + + if (bMatch) + { + memcpy(pdm, &list[i], sizeof(D3DDISPLAYMODE)); + found = 1; + if (rep != 0 || pass != 0) + { + return 1; + } + } + } + } + } + return 0; +} + +BOOL CALLBACK MyMonitorEnumProc( + HMONITOR hMonitor, // handle to display monitor + HDC hdcMonitor, // handle to monitor DC + LPRECT lprcMonitor, // monitor intersection rectangle + LPARAM dwData // data +) +{ + RECT* p = (RECT*)dwData; + if (hMonitor) + { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(hMonitor, &mi)) + { + p->top = min(p->top , mi.rcMonitor.top); + p->left = min(p->left , mi.rcMonitor.left); + p->right = max(p->right , mi.rcMonitor.right); + p->bottom = max(p->bottom, mi.rcMonitor.bottom); + } + } + + return TRUE; +} + +int DXContext::GetWindowedModeAutoSize(int iteration) +{ + // note: requires 'm_monitor_rect' has been set! + + // generically determine size of window, for windowed mode: + int x = m_monitor_rect.right-m_monitor_rect.left; + int y = m_monitor_rect.bottom-m_monitor_rect.top; + + // if running in horz/vert-span multi-display mode, base the window size on + // an actual display size, not the giant double-sized monitor. Also, position + // the window on the same monitor that Winamp is on. + if (x >= y*2) + { + x /= 2; + + // move window to same display that Winamp is on: + WINDOWPLACEMENT wp; + wp.length = sizeof(wp); + if (GetWindowPlacement(m_hwnd_winamp, &wp)) + { + int winamp_center_x = (wp.rcNormalPosition.right + wp.rcNormalPosition.left)/2; + if (winamp_center_x > x) + { + m_monitor_rect.left += x; + m_monitor_rect.right += x; + } + } + } + else if (y > x*4/3) + { + y /= 2; + + // move window to same display that Winamp is on: + WINDOWPLACEMENT wp; + wp.length = sizeof(wp); + if (GetWindowPlacement(m_hwnd_winamp, &wp)) + { + int winamp_center_y = (wp.rcNormalPosition.top + wp.rcNormalPosition.bottom)/2; + if (winamp_center_y > y) + { + m_monitor_rect.top += y; + m_monitor_rect.bottom += y; + } + } + } + + int size = min(x, y); + size = (int)(size*DEFAULT_WINDOW_SIZE); + size = (size/64 - iteration)*64; + if (size < 64) + size = 64; + + return size; +} + +void DXContext::WriteSafeWindowPos() +{ + if (m_current_mode.screenmode == WINDOWED) + { + WritePrivateProfileIntW(64, L"nMainWndTop", m_szIniFile, L"settings"); + WritePrivateProfileIntW(64, L"nMainWndLeft", m_szIniFile, L"settings"); + WritePrivateProfileIntW(64+256, L"nMainWndRight", m_szIniFile, L"settings"); + WritePrivateProfileIntW(64+256, L"nMainWndBottom", m_szIniFile, L"settings"); + WritePrivateProfileIntW(64, L"avs_wx",m_szIniFile,L"settings"); + WritePrivateProfileIntW(64, L"avs_wy",m_szIniFile,L"settings"); + WritePrivateProfileIntW(256, L"avs_ww",m_szIniFile,L"settings"); + WritePrivateProfileIntW(256, L"avs_wh",m_szIniFile,L"settings"); + } +} + +// {0000000A-000C-0010-FF7B-01014263450C} +const GUID avs_guid = + { 10, 12, 16, { 255, 123, 1, 1, 66, 99, 69, 12 } }; + +BOOL DXContext::Internal_Init(DXCONTEXT_PARAMS *pParams, BOOL bFirstInit) +{ + memcpy(&m_current_mode, pParams, sizeof(DXCONTEXT_PARAMS)); + memset(&myWindowState,0,sizeof(myWindowState)); + + // various checks + if (m_current_mode.screenmode != WINDOWED) + m_current_mode.m_skin = 0; + + // 1. destroy old window + if (m_hwnd) + { + m_ignore_wm_destroy = 1; + DestroyWindow(m_hwnd); + m_ignore_wm_destroy = 0; + m_hwnd = NULL; + } + + // 2. CHECK TO MAKE SURE DIRECTX/DDRAW IS INSTALLED + if (bFirstInit) + { + // Test for DirectX 9 + start it + // note: if you don't call LoadLibrary here, and you're on a system + // where DX9 is missing, Direct3DCreate8() might crash; so call it. + int d3d9_already_loaded = (GetModuleHandle("d3d9.dll") != NULL) ? 1 : 0; + if (!d3d9_already_loaded) + m_hmod_d3d9 = LoadLibrary("d3d9.dll"); + + if ((!d3d9_already_loaded && !m_hmod_d3d9) || + !(m_lpD3D = Direct3DCreate9(D3D_SDK_VERSION)) + ) + { + MissingDirectX(NULL); + m_lastErr = DXC_ERR_CREATE3D; + return FALSE; + } + + if (!m_hmod_d3dx9) + m_hmod_d3dx9 = FindD3DX9(m_hwnd_winamp); + + if ((!m_hmod_d3dx9)) + { + MissingDirectX(NULL); + m_lastErr = DXC_ERR_CREATE3D; + return FALSE; + } + } + + // 3. get the smallest single rectangle that encloses ALL the monitors on the desktop: + SetRect(&m_all_monitors_rect, 0, 0, 0, 0); + EnumDisplayMonitors(NULL, NULL, MyMonitorEnumProc, (LPARAM)&m_all_monitors_rect); + + // 4. some DirectX- / DDraw-specific stuff. Also determine hPluginMonitor. + HMONITOR hPluginMonitor = NULL; + { + D3DADAPTER_IDENTIFIER9 temp; + + // find the ordinal # of the adapter whose GUID matches what the user picked from the config panel, + // and whose DeviceName matches as well. + // if no match found, use D3DADAPTER_DEFAULT. + m_ordinal_adapter = D3DADAPTER_DEFAULT; + int nAdapters = m_lpD3D->GetAdapterCount(); + { + for (int i=0; iGetAdapterIdentifier(i, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &temp) == D3D_OK) && + (memcmp(&temp.DeviceIdentifier, &m_current_mode.adapter_guid, sizeof(GUID))==0) && + !strcmp(temp.DeviceName, m_current_mode.adapter_devicename) + ) + { + m_ordinal_adapter = i; + break; + } + } + } + + if (m_lpD3D->GetAdapterIdentifier(m_ordinal_adapter, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &temp) == D3D_OK) + { + StringCbCopy(m_szDriver, sizeof(m_szDriver), temp.Driver); + StringCbCopy(m_szDesc, sizeof(m_szDesc), temp.Description); + } + + int caps_ok = 0; + int caps_tries = 0; + int changed_fs_disp_mode; + + // try to get the device caps for the adapter selected from the config panel. + // if GetDeviceCaps() fails, it's probably because the adapter has been + // removed from the system (or disabled), so we try again with other adapter(s). + do + { + changed_fs_disp_mode = 0; + + SetRect(&m_monitor_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); + + // get bounding rect of the monitor attached to the adapter (to assist w/window positioning) + // note: in vert/horz span setups (psuedo-multimon), + // this will be 2048x768 or 1024x1536 or something like that. + hPluginMonitor = m_lpD3D->GetAdapterMonitor(m_ordinal_adapter); + /*if (hPluginMonitor) + { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(hPluginMonitor, &mi)) + { + memcpy(&m_monitor_rect, &mi.rcMonitor, sizeof(RECT)); + memcpy(&m_monitor_work_rect, &mi.rcWork, sizeof(RECT)); + } + }*/ + + if (bFirstInit) + { + for (int i=0; iGetAdapterDisplayMode(i, &d3ddm))) + { + d3ddm.Format = D3DFMT_UNKNOWN; + } + m_orig_windowed_mode_format[i] = d3ddm.Format; + } + } + + // figure out pixel (color) format for back buffer: (m_current_mode.display_mode.Format) + if (m_current_mode.screenmode!=FULLSCREEN && m_ordinal_adapter < MAX_DXC_ADAPTERS) + m_current_mode.display_mode.Format = m_orig_windowed_mode_format[m_ordinal_adapter]; + // else + // for fullscreen, use what they gave us + + if (m_current_mode.display_mode.Format == D3DFMT_UNKNOWN || + !TestFormat(m_ordinal_adapter, m_current_mode.display_mode.Format)) + { + // if they try to run the plugin without ever running the config panel + // first (& pressing OK), then the fullscreen pixelformat hasn't been + // chosen... so we try all the possilibities until one works: + if (TestFormat(m_ordinal_adapter,D3DFMT_A8R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_A8R8G8B8; + else if (TestFormat(m_ordinal_adapter,D3DFMT_X8R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_X8R8G8B8; + else if (TestFormat(m_ordinal_adapter,D3DFMT_R8G8B8)) m_current_mode.display_mode.Format = D3DFMT_R8G8B8 ; + else if (TestFormat(m_ordinal_adapter,D3DFMT_R5G6B5)) m_current_mode.display_mode.Format = D3DFMT_R5G6B5 ; + else if (TestFormat(m_ordinal_adapter,D3DFMT_X1R5G5B5)) m_current_mode.display_mode.Format = D3DFMT_X1R5G5B5; + else if (TestFormat(m_ordinal_adapter,D3DFMT_A1R5G5B5)) m_current_mode.display_mode.Format = D3DFMT_A1R5G5B5; + else if (TestFormat(m_ordinal_adapter,D3DFMT_A4R4G4B4)) m_current_mode.display_mode.Format = D3DFMT_A4R4G4B4; + else if (TestFormat(m_ordinal_adapter,D3DFMT_X4R4G4B4)) m_current_mode.display_mode.Format = D3DFMT_X4R4G4B4; + } + + if (m_current_mode.display_mode.Format==D3DFMT_UNKNOWN) + { + wchar_t title[64]; + m_lastErr = DXC_ERR_FORMAT; + MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_DIRECTX_INIT_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return FALSE; + } + + if (m_current_mode.screenmode == FULLSCREEN) + changed_fs_disp_mode = CheckAndCorrectFullscreenDispMode(m_ordinal_adapter, &m_current_mode.display_mode); + + // figure out pixel format of the z-buffer: (m_zFormat) + m_zFormat = D3DFMT_UNKNOWN; + /* + if (TestDepth(m_ordinal_adapter,D3DFMT_D32 )) m_zFormat=D3DFMT_D32; + else if (TestDepth(m_ordinal_adapter,D3DFMT_D24S8 )) m_zFormat=D3DFMT_D24S8; + else if (TestDepth(m_ordinal_adapter,D3DFMT_D24X4S4 )) m_zFormat=D3DFMT_D24X4S4; + else if (TestDepth(m_ordinal_adapter,D3DFMT_D24X8 )) m_zFormat=D3DFMT_D24X8; + else if (TestDepth(m_ordinal_adapter,D3DFMT_D16 )) m_zFormat=D3DFMT_D16; + else if (TestDepth(m_ordinal_adapter,D3DFMT_D15S1 )) m_zFormat=D3DFMT_D15S1; + else if (TestDepth(m_ordinal_adapter,D3DFMT_D16_LOCKABLE)) m_zFormat=D3DFMT_D16_LOCKABLE; + */ + + // get device caps: + memset(&m_caps, 0, sizeof(m_caps)); + if (FAILED(m_lpD3D->GetDeviceCaps(m_ordinal_adapter, D3DDEVTYPE_HAL, &m_caps))) + { + // that adapter was found in the system, but it might be disabled + // (i.e. 'extend my Windows desktop onto this monitor') is unchecked) + // so, try other adapters (try all sequentially). + + if (caps_tries < nAdapters) + { + // try again, this time using the default adapter: + m_ordinal_adapter = caps_tries; + caps_tries++; + } + else + { + wchar_t title[64]; + m_lastErr = DXC_ERR_CAPSFAIL; + MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_DXC_ERR_CAPSFAIL), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return FALSE; + } + } + else + { + caps_ok = 1; + } + } + while (!caps_ok); + + if (changed_fs_disp_mode) + { + wchar_t title[64]; + MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_FS_DISPLAY_MODE_SELECTED_IS_INVALID), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + } + + switch (m_current_mode.display_mode.Format) + { + case D3DFMT_R8G8B8 : m_bpp = 32; break; + case D3DFMT_A8R8G8B8: m_bpp = 32; break; + case D3DFMT_X8R8G8B8: m_bpp = 32; break; + case D3DFMT_R5G6B5 : m_bpp = 16; break; + case D3DFMT_X1R5G5B5: m_bpp = 16; break; + case D3DFMT_A1R5G5B5: m_bpp = 16; break; + case D3DFMT_A8R3G3B2: m_bpp = 16; break; + case D3DFMT_A4R4G4B4: m_bpp = 16; break; + case D3DFMT_X4R4G4B4: m_bpp = 16; break; + case D3DFMT_R3G3B2 : m_bpp = 8; break; // misleading? implies a palette... + } + } + + // 5. set m_monitor_rect and m_monitor_work_rect. + if (hPluginMonitor) + { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(hPluginMonitor, &mi)) + { + m_monitor_rect = mi.rcMonitor; + m_monitor_rect_orig = mi.rcMonitor; + m_monitor_work_rect = mi.rcWork; + m_monitor_work_rect_orig = mi.rcWork; + } + } + + // 6. embedded window stuff [where the plugin window is integrated w/winamp] + if (m_current_mode.m_skin) + { + // set up the window's position on screen + // note that we'd prefer to set the CLIENT size we want, but we can't, so we'll just do + // this here, and later, adjust the client rect size to what's left... + int size = GetWindowedModeAutoSize(0); // note: requires 'm_monitor_rect' has been set! + myWindowState.r.left = GetPrivateProfileIntW(L"settings",L"avs_wx",64,m_szIniFile); + myWindowState.r.top = GetPrivateProfileIntW(L"settings",L"avs_wy",64,m_szIniFile); + myWindowState.r.right = myWindowState.r.left + GetPrivateProfileIntW(L"settings",L"avs_ww",size+24,m_szIniFile); + myWindowState.r.bottom = myWindowState.r.top + GetPrivateProfileIntW(L"settings",L"avs_wh",size+40,m_szIniFile); + + // only works on winamp 2.90+! + int success = 0; + if (GetWinampVersion(mod1.hwndParent) >= 0x2900) + { + SET_EMBED_GUID((&myWindowState), avs_guid); + myWindowState.flags |= EMBED_FLAGS_NOTRANSPARENCY; + HWND (*e)(embedWindowState *v); + *(void**)&e = (void *)SendMessage(mod1.hwndParent,WM_WA_IPC,(LPARAM)0,IPC_GET_EMBEDIF); + if (e) + { + m_current_mode.parent_window = e(&myWindowState); + if (m_current_mode.parent_window) + { + SetWindowText(m_current_mode.parent_window, m_szWindowCaption); + success = 1; + } + } + } + + if (!success) + m_current_mode.m_skin = 0; + } + + // remember the client rect that was originally desired... + RECT windowed_mode_desired_client_rect; + windowed_mode_desired_client_rect.top = GetPrivateProfileIntW(L"settings",L"nMainWndTop",-1,m_szIniFile); + windowed_mode_desired_client_rect.left = GetPrivateProfileIntW(L"settings",L"nMainWndLeft",-1,m_szIniFile); + windowed_mode_desired_client_rect.right = GetPrivateProfileIntW(L"settings",L"nMainWndRight",-1,m_szIniFile); + windowed_mode_desired_client_rect.bottom = GetPrivateProfileIntW(L"settings",L"nMainWndBottom",-1,m_szIniFile); + + // ...and in case windowed mode init fails severely, + // set it up to try next time for a simple 256x256 window. + WriteSafeWindowPos(); + + // 7. create the window, if not already created + if (!m_hwnd) + { + m_hwnd = CreateWindowEx( + MY_EXT_WINDOW_STYLE, // extended style + MAKEINTATOM(m_classAtom), // class + m_szWindowCaption, // caption + MY_WINDOW_STYLE, // style + 0, // left + 0, // top + 256, // temporary width + 256, // temporary height + m_current_mode.parent_window, // parent window + NULL, // menu + m_hInstance, // instance + (LPVOID)m_uWindowLong + ); // parms + + if (!m_hwnd) + { + wchar_t title[64]; + m_lastErr = DXC_ERR_CREATEWIN; + MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_CREATEWINDOW_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return FALSE; + } + + SendMessage(m_hwnd_winamp, WM_WA_IPC, (WPARAM)m_hwnd, IPC_SETVISWND); + + if (m_current_mode.m_skin) + { + if (GetWinampVersion(mod1.hwndParent) < 0x5051) + ShowWindow(m_current_mode.parent_window,SW_SHOWNA); // showing the parent wnd will make it size the child, too + else + SendMessage(m_current_mode.parent_window, WM_USER+102, 0, 0); // benski> major hack alert. winamp's embedwnd will call ShowWindow in response. SendMessage moves us over to the main thread (we're currently sitting on the viz thread) + } + } + + // 8. minimize winamp before creating devices & such, so there aren't + // any confusing window-focus issues + MinimizeWinamp(hPluginMonitor); + + // 9. loop to try and create the window. + // if in windowed mode and not enough vidmem, it will try again w/smaller window + // (repeatedly, until window client size would be < 64) + int iteration = 0; + int device_ok = 0; + do + { + // set the window position + if (m_current_mode.screenmode==DESKTOP || + m_current_mode.screenmode==FAKE_FULLSCREEN) + { + int x = m_monitor_rect.right - m_monitor_rect.left; + int y = m_monitor_rect.bottom - m_monitor_rect.top; + + if (x >= y*2) + { + // (pseudo-multimon modes like 2048x768) + int mid = (m_monitor_rect.left + m_monitor_rect.right)/2; + if (m_current_mode.m_dualhead_horz==1) // show on left side + m_monitor_rect.right = mid; + else if (m_current_mode.m_dualhead_horz==2) // show on right side + m_monitor_rect.left = mid; + } + else if (y > x*4/3) + { + // (pseudo-multimon modes like 1024x1536) + int mid = (m_monitor_rect.top + m_monitor_rect.bottom)/2; + if (m_current_mode.m_dualhead_vert==1) // show on top half + m_monitor_rect.bottom = mid; + else if (m_current_mode.m_dualhead_vert==2) // show on bottom half + m_monitor_rect.top = mid; + } + + // recompute width & height (into x,y): + x = m_monitor_rect.right - m_monitor_rect.left; + y = m_monitor_rect.bottom - m_monitor_rect.top; + + m_client_width = x; + m_client_height = y; + m_window_width = x; + m_window_height = y; + + if (m_current_mode.screenmode == DESKTOP) + { + // note: we initially hide the window, and then + // only display it once the desktop is all nice & ready. + // see CPluginShell::DrawAndDisplay(). + + RECT r = m_monitor_rect; + + // if possible, shrink the desktop window so it doesn't cover the taskbar. + HWND hTaskbar = FindWindow("Shell_TrayWnd", ""); + if (hTaskbar) + { + RECT taskbar; + GetWindowRect(hTaskbar, &taskbar); + int tbw = taskbar.right - taskbar.left; + int tbh = taskbar.bottom-taskbar.top; + + if (taskbar.bottom == m_monitor_rect.bottom && + taskbar.left == m_monitor_rect.left && + taskbar.right == m_monitor_rect.right) + { + r.bottom -= tbh; + } + else if (taskbar.top == m_monitor_rect.top && + taskbar.left == m_monitor_rect.left && + taskbar.right == m_monitor_rect.right) + { + r.top += tbh; + } + else if (taskbar.left == m_monitor_rect.left && + taskbar.top == m_monitor_rect.top && + taskbar.bottom == m_monitor_rect.bottom) + { + r.left += tbw; + } + else if (taskbar.right == m_monitor_rect.right && + taskbar.top == m_monitor_rect.top && + taskbar.bottom == m_monitor_rect.bottom) + { + r.right -= tbw; + } + + m_client_width = r.right - r.left; + m_client_height = r.bottom - r.top; + m_REAL_client_width = m_client_width; + m_REAL_client_height = m_client_height; + m_window_width = m_client_width; + m_window_height = m_client_height; + + //...ok, but text is squished - some w/h is not right... + + } + + SetWindowPos(m_hwnd,HWND_BOTTOM,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_HIDEWINDOW); + } + else // FAKE_FULLSCREEN + { + if (memcmp(&m_all_monitors_rect, &m_monitor_rect, sizeof(RECT))==0) + { + // there's only one display, and it's entirely covered + // by the plugin -> PUT THE PLUGIN ABOVE THE TASKBAR + // -> normally, if the user clicked another window, + // it would pop the taskbar to the top; but we don't + // have to worry about that here, since we're taking + // up the whole screen. + // -> don't worry about making the text, etc. avoid + // the taskbar in this case (see DrawAndDisplay()) + // -> DO worry about hiding the mouse cursor in this case + // (see WM_SETCURSOR handler) + + m_fake_fs_covers_all = 1; + //SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW); + } + else + { + // there is space to work outside of the plugin window. + // -> here we pretty much have to let the taskbar stay on + // top, because it really likes to be there; i.e., + // if you click any other window, it automatically + // pops up again. + // -> therefore, TRY TO KEEP THE WINDOW ON BOTTOM + // (below the taskbar). (see PushWindowToBack) + // -> don't worry about hiding the mouse cursor in this case + // (see WM_SETCURSOR handler) + // -> DO worry about making the text, etc. avoid + // the taskbar in this case (see DrawAndDisplay()) + + // (note that if taskbar is in the way, they can move it, + // since there are other monitors available) + + m_fake_fs_covers_all = 0; + //SetWindowPos(m_hwnd,HWND_TOP,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW); + } + + SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW); + } + } + else if (m_current_mode.screenmode == FULLSCREEN) + { + int x = m_current_mode.display_mode.Width ; + int y = m_current_mode.display_mode.Height; + int cx = m_monitor_rect.right - m_monitor_rect.left; + int cy = m_monitor_rect.bottom - m_monitor_rect.top; + + // test #1 + if (x >= y*2 || y > x*4/3) // tackle problem of vert/horz spans + { + wchar_t title[64]; + int ret = MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS), + WASABI_API_LNGSTRINGW_BUF(IDS_TIP, title, 64), + MB_OKCANCEL|MB_SETFOREGROUND|MB_TOPMOST); + if (ret==IDCANCEL) + { + m_lastErr = DXC_ERR_USER_CANCELED; + return FALSE; + } + } + + // test #2 + if ((cx >= cy*2 && x < y*2) || (cy > cx*4/3 && y <= x*4/3)) + { + wchar_t title[64]; + int ret = MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS_2), + WASABI_API_LNGSTRINGW_BUF(IDS_TIP, title, 64), + MB_OKCANCEL|MB_SETFOREGROUND|MB_TOPMOST); + if (ret==IDCANCEL) + { + m_lastErr = DXC_ERR_USER_CANCELED; + return FALSE; + } + } + + m_client_width = x; + m_client_height = y; + m_window_width = x; + m_window_height = y; + SetWindowPos(m_hwnd,HWND_TOPMOST,m_monitor_rect.left,m_monitor_rect.top,m_window_width,m_window_height,SWP_SHOWWINDOW); + } + else // WINDOWED + { + RECT margin; + if (m_current_mode.m_skin) + { + RECT r1, r2; + GetWindowRect(m_current_mode.parent_window, &r1); + GetWindowRect(m_hwnd , &r2); + margin.left = r2.left - r1.left; + margin.right = r1.right - r2.right; + margin.top = r2.top - r1.top; + margin.bottom= r1.bottom - r2.bottom; + } + else + { + RECT r1; + SetRect(&r1, 0, 0, 256, 256); + AdjustWindowRect(&r1, MY_WINDOW_STYLE, 0); + margin.left = 0 - r1.left; + margin.right = r1.right - 256; + margin.top = 0 - r1.top; + margin.bottom= r1.bottom - 256; + } + + int autosize = 1; + + RECT r = windowed_mode_desired_client_rect; + if (iteration==0 && r.top != -1 && r.left != -1 && r.bottom != -1 && r.right != -1) + { + // use prev. window coordinates: + m_REAL_client_width = r.right - r.left; + m_REAL_client_height = r.bottom - r.top; + GetSnappedClientSize(); + if (m_current_mode.m_skin) // check this here in case they got a non-aligned size by resizing when "integrated with winamp" was unchecked, then checked it & ran the plugin... + { + // STRANGE ALIGNMENTS FOR THE WINDOW FRAME: (required by winamp 2): + // the window frame's width must be divisible by 25, and height by 29. + if (GetWinampVersion(mod1.hwndParent) < 0x4000) // ... winamp 5 doesn't have this prob. (test vs. 0x4000 because winamp5 betas have version tags like 0x4987) + { + m_REAL_client_width = ((m_client_width + margin.left + margin.right)/25)*25 - margin.left - margin.right; + m_REAL_client_height = ((m_client_height + margin.top + margin.bottom)/29)*29 - margin.top - margin.bottom; + GetSnappedClientSize(); + } + } + + // transform screen-space CLIENT rect into screen-space WINDOW rect + r.top = windowed_mode_desired_client_rect.top - margin.top; + r.left = windowed_mode_desired_client_rect.left - margin.left; + r.right = r.left + margin.left + m_REAL_client_width + margin.right; + r.bottom = r.top + margin.top + m_REAL_client_height + margin.bottom; + + // make sure the window is entirely visible on the selected monitor; + // otherwise, autosize/place it. + // (note that this test is only appled 1) at startup, and 2) after a resize/max/restore. + // this test is not applied when merely moving the window.) + if (r.top >= m_monitor_work_rect.top && + r.left >= m_monitor_work_rect.left && + r.right <= m_monitor_work_rect.right && + r.bottom <= m_monitor_work_rect.bottom) + { + if (m_current_mode.m_skin) + { + m_window_width = m_REAL_client_width ; // m_window_width/height are for OUR borderless window, not the embedwnd parent frame. + m_window_height = m_REAL_client_height; + SetWindowPos(m_current_mode.parent_window,HWND_NOTOPMOST, r.left, r.top, r.right-r.left, r.bottom-r.top, /*SWP_SHOWWINDOW|*//*SWP_ASYNCWINDOWPOS*/0); + SetWindowPos(m_hwnd ,HWND_NOTOPMOST, windowed_mode_desired_client_rect.left, + windowed_mode_desired_client_rect.top, + m_REAL_client_width, + m_REAL_client_height, + SWP_SHOWWINDOW); + } + else + { + m_window_width = r.right - r.left; + m_window_height = r.bottom - r.top; + SetWindowPos(m_hwnd,HWND_NOTOPMOST,r.left,r.top,m_window_width,m_window_height,SWP_SHOWWINDOW); + } + + autosize = 0; + } + } + + if (autosize) + { + int size = GetWindowedModeAutoSize(iteration); // note: requires 'm_monitor_rect' has been set! + + m_REAL_client_width = size; + m_REAL_client_height = size; + GetSnappedClientSize(); + + if (m_current_mode.m_skin) + { + // STRANGE ALIGNMENTS FOR THE WINDOW FRAME: (required by winamp 2): + // the window frame's width must be divisible by 25, and height by 29. + if (GetWinampVersion(mod1.hwndParent) < 0x4000) // ... winamp 5 doesn't have this prob. (test vs. 0x4000 because winamp5 betas have version tags like 0x4987) + { + m_REAL_client_width = ((m_client_width + margin.left + margin.right)/25)*25 - margin.left - margin.right; + m_REAL_client_height = ((m_client_height + margin.top + margin.bottom)/29)*29 - margin.top - margin.bottom; + GetSnappedClientSize(); + } + + m_window_width = m_client_width ; // m_window_width/height are for OUR [borderless] window, not the parent window (which is the embedwnd frame). + m_window_height = m_client_height; + SetWindowPos(m_current_mode.parent_window,HWND_NOTOPMOST, m_monitor_work_rect.left+32, m_monitor_work_rect.top+32, m_client_width + margin.left + margin.right, m_client_height + margin.top + margin.bottom, /*SWP_SHOWWINDOW|*//*SWP_ASYNCWINDOWPOS*/0); + SetWindowPos(m_hwnd ,HWND_NOTOPMOST, m_monitor_work_rect.left+32 + margin.left, m_monitor_work_rect.top+32 + margin.top, m_client_width, m_client_height, SWP_SHOWWINDOW); + } + else + { + SetRect(&r, 0, 0, size, size); + AdjustWindowRect(&r, MY_WINDOW_STYLE, 0); + + m_window_width = r.right - r.left; + m_window_height = r.bottom - r.top; + + SetWindowPos(m_hwnd,HWND_NOTOPMOST, m_monitor_work_rect.left+32, m_monitor_work_rect.top+32, m_window_width, m_window_height, SWP_SHOWWINDOW); + } + } + } + + m_frame_delay = 1; // set this to 2 if you use triple buffering! + + { + m_current_mode.display_mode.Width = m_client_width; + m_current_mode.display_mode.Height = m_client_height; + + // set up m_d3dpp (presentation parameters): + ZeroMemory(&m_d3dpp,sizeof(m_d3dpp)); + m_d3dpp.Windowed = (m_current_mode.screenmode==FULLSCREEN) ? 0 : 1; + m_d3dpp.BackBufferFormat = m_current_mode.display_mode.Format; + m_d3dpp.BackBufferWidth = m_client_width; + m_d3dpp.BackBufferHeight = m_client_height; + m_d3dpp.BackBufferCount = m_current_mode.nbackbuf; + if (m_current_mode.screenmode==FULLSCREEN) + m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//D3DSWAPEFFECT_FLIP; + else // windowed or fake FS + m_d3dpp.SwapEffect = (m_current_mode.allow_page_tearing) ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_COPY;//D3DSWAPEFFECT_DISCARD;//D3DSWAPEFFECT_FLIP; + // note: multisampling is only allowed if swapeffect is DISCARD! + m_d3dpp.MultiSampleType = (m_d3dpp.SwapEffect==D3DSWAPEFFECT_DISCARD) ? m_current_mode.multisamp : D3DMULTISAMPLE_NONE; + //m_d3dpp.hDeviceWindow = m_hwnd; + if (m_current_mode.screenmode==FULLSCREEN) + { + m_d3dpp.FullScreen_RefreshRateInHz = m_current_mode.display_mode.RefreshRate;//D3DPRESENT_RATE_DEFAULT; + m_d3dpp.PresentationInterval = m_current_mode.allow_page_tearing ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//D3DPRESENT_INTERVAL_ONE; + } + if (m_zFormat != D3DFMT_UNKNOWN) + { + m_d3dpp.EnableAutoDepthStencil=TRUE; + m_d3dpp.AutoDepthStencilFormat=m_zFormat; + } + + // finally, create the device: + HRESULT hRes; + if (FAILED(hRes = m_lpD3D->CreateDevice( + m_ordinal_adapter, + D3DDEVTYPE_HAL, + m_hwnd, + (m_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &m_d3dpp, + &m_lpDevice))) + { + int code = LOWORD(hRes); + + wchar_t str[1024]; + if (code==2156) //D3DERR_NOTAVAILABLE + { + m_lastErr = DXC_ERR_CREATEDEV_NOT_AVAIL; + + wchar_t str[2048]; + WASABI_API_LNGSTRINGW_BUF(IDS_UNABLE_TO_CREATE_DIRECTX_DEVICE, str, 2048); + + if (m_current_mode.screenmode == FULLSCREEN) + StringCbCatW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_OLDER_DISPLAY_ADAPTER_CATENATION)); + else + StringCbCatW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_OLDER_DISPLAY_ADAPTER_CATENATION_2)); + + MessageBoxW(m_hwnd,str, + WASABI_API_LNGSTRINGW(IDS_MILKDROP_ERROR), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return FALSE; + } + else if (m_current_mode.screenmode==WINDOWED && m_client_width>64) + { + // DO NOTHING; try again w/smaller window + } + else if (m_current_mode.screenmode != WINDOWED || m_client_width <= 64) + { + // usually, code==2154 here, which is D3DERR_OUTOFVIDEOMEMORY + m_lastErr = DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY; + StringCbPrintfW(str, sizeof(str), WASABI_API_LNGSTRINGW(IDS_DIRECTX_INIT_FAILED_X), LOWORD(hRes)); + + // NOTE: *A 'SUGGESTION' SCREEN SHOULD APPEAR NEXT, PROVIDED BY THE CALLER* + MessageBoxW(m_hwnd, str, + WASABI_API_LNGSTRINGW(IDS_MILKDROP_ERROR), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return FALSE; + } + } + else + { + device_ok = 1; + } + } + + iteration++; + } + while (!device_ok); + + // set initial viewport + SetViewport(); + + // for desktop mode, push window to back again: + if (m_current_mode.screenmode==DESKTOP) + SetWindowPos(m_hwnd,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); + + if (m_current_mode.m_skin) + { + if (GetWinampVersion(mod1.hwndParent) < 0x5051) + SetFocus(m_current_mode.parent_window); + else + PostMessage(m_current_mode.parent_window, WM_USER+103, 0, 0); + + //SetActiveWindow(m_current_mode.parent_window); + //SetForegroundWindow(m_current_mode.parent_window); + } + + /*if (m_current_mode.screenmode == WINDOWED) + SaveWindow();*/ + + // return success + m_ready = TRUE; + // benski> a little hack to get the window size correct. it seems to work + if (m_current_mode.screenmode==WINDOWED) + PostMessage(m_hwnd, WM_USER+555, 0, 0); + return TRUE; +} + +BOOL DXContext::StartOrRestartDevice(DXCONTEXT_PARAMS *pParams) +{ + // call this to [re]initialize the DirectX environment with new parameters. + // examples: startup; toggle windowed/fullscreen mode; change fullscreen resolution; + // and so on. + // be sure to clean up all your DirectX stuff first (textures, vertex buffers, + // D3DX allocations, etc.) and reallocate it afterwards! + + // note: for windowed mode, 'pParams->disp_mode' (w/h/r/f) is ignored. + + // destroy old window + if (myWindowState.me) + { + m_ignore_wm_destroy = 1; + if (m_current_mode.screenmode == WINDOWED) + SaveWindow(); + DestroyWindow(myWindowState.me); + myWindowState.me = NULL; + m_ignore_wm_destroy = 0; + m_hwnd=0; + } + else if (m_hwnd) + { + SendMessage(m_hwnd_winamp, WM_WA_IPC, NULL, IPC_SETVISWND); + m_ignore_wm_destroy = 1; + DestroyWindow(m_hwnd); + m_ignore_wm_destroy = 0; + m_hwnd = NULL; + } + + if (!m_ready) + { + // first-time init: create a fresh new device + return Internal_Init(pParams, TRUE); + } + else + { + // re-init: preserve the DX9 object (m_lpD3D), + // but destroy and re-create the DX9 device (m_lpDevice). + m_ready = FALSE; + + SafeRelease(m_lpDevice); + // but leave the D3D object! + + RestoreWinamp(); + return Internal_Init(pParams, FALSE); + } +} + +BOOL DXContext::OnUserResizeWindow(RECT *new_window_rect, RECT *new_client_rect) +{ + // call this function on WM_EXITSIZEMOVE when running windowed. + // don't bother calling this when fullscreen. + // be sure to clean up all your DirectX stuff first (textures, vertex buffers, + // D3DX allocations, etc.) and reallocate it afterwards! + + if (!m_ready || (m_current_mode.screenmode != WINDOWED)) + return FALSE; + + if ((m_client_width == new_client_rect->right - new_client_rect->left) && + (m_client_height == new_client_rect->bottom - new_client_rect->top) && + (m_window_width == new_window_rect->right - new_window_rect->left) && + (m_window_height == new_window_rect->bottom - new_window_rect->top)) + { + return TRUE; + } + + m_ready = FALSE; + + m_window_width = new_window_rect->right - new_window_rect->left; + m_window_height = new_window_rect->bottom - new_window_rect->top; + m_REAL_client_width = new_client_rect->right - new_client_rect->left; + m_REAL_client_height = new_client_rect->bottom - new_client_rect->top; + GetSnappedClientSize(); //sets m_client_width/height, but with snapping, if in windowed mode. + + m_d3dpp.BackBufferWidth = m_client_width; + m_d3dpp.BackBufferHeight = m_client_height; + if (m_lpDevice->Reset(&m_d3dpp) != D3D_OK) + { + WriteSafeWindowPos(); + + wchar_t title[64]; + MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_WINDOW_RESIZE_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_OUT_OF_VIDEO_MEMORY, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + + m_lastErr = DXC_ERR_RESIZEFAILED; + return FALSE; + } + + SetViewport(); + m_ready = TRUE; + return TRUE; +} + +void DXContext::SetViewport() +{ + D3DVIEWPORT9 v; + v.X = 0; + v.Y = 0; + v.Width = m_client_width; + v.Height = m_client_height; + v.MinZ = 0.0f; + v.MaxZ = 1.0f; + m_lpDevice->SetViewport(&v); +} + +void DXContext::MinimizeWinamp(HMONITOR hPluginMonitor) +{ + // minimize Winamp window + + HMONITOR hWinampMon = MonitorFromWindow(m_hwnd_winamp, MONITOR_DEFAULTTONEAREST); + HMONITOR hPluginMon = hPluginMonitor;//MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);//m_lpD3D->GetAdapterMonitor(ordinal_adapter); + + if ((m_current_mode.screenmode == FULLSCREEN || m_current_mode.screenmode == FAKE_FULLSCREEN) && + (m_minimize_winamp) && + (hWinampMon && hPluginMon && hPluginMon==hWinampMon) && + (!m_winamp_minimized) + ) + { + // nitpicky check: if we're in fake fullscreen mode + // and are only going to display on half the screen, + // don't minimize Winamp. + if (m_current_mode.screenmode == FAKE_FULLSCREEN) + { + int x = m_monitor_rect.right - m_monitor_rect.left; + int y = m_monitor_rect.bottom - m_monitor_rect.top; + if ((x >= y*2 && m_current_mode.m_dualhead_horz != 0) || + (y > x*4/3 && m_current_mode.m_dualhead_vert != 0)) + { + return; + } + } + + ShowWindow(m_hwnd_winamp, SW_MINIMIZE); + // also restore the focus to the plugin window, since this will steal it: + SetFocus(m_hwnd); + SetActiveWindow(m_hwnd); + SetForegroundWindow(m_hwnd); + m_winamp_minimized = 1; + } +} + +void DXContext::RestoreWinamp() +{ + if (m_winamp_minimized) + { + ShowWindow(m_hwnd_winamp, SW_RESTORE); + m_winamp_minimized = 0; + } +} + +void DXContext::UpdateMonitorWorkRect() +{ + // get active monitor's bounding rectangle (to assist w/window positioning) + // note: in vert/horz span setups (psuedo-multimon), + // this will be 2048x768 or 1024x1536 or something like that. + + // calling this each frame allows you to detect when the taskbar + // moves around on the screen (from edge to edge), and rearrange + // the visual elements accordingly, so nothing is obscured. + + HMONITOR hMon = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);//m_lpD3D->GetAdapterMonitor(m_ordinal_adapter); + if (hMon) + { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(hMon, &mi)) + { + m_monitor_work_rect = mi.rcWork; + m_monitor_work_rect_orig = mi.rcWork; + + // if the monitor rect we're using is the same as the + // whole area of the monitor, there's no need to update it... + //if (memcmp(&mi.rcMonitor, &m_monitor_rect, sizeof(RECT))==0) + // return; + + // otherwise, we're doing a half-screen special case + // and are running in some pseudo-multimon res like + // 2048x768 or 1024x1536, but only using half of it + // (i.e. fake fullscreen or desktop mode) + + // therefore... we need to update the work-area rectangle + // to reflect which half of the screen it's on. + + if (m_monitor_rect.left == mi.rcMonitor.left) + m_monitor_work_rect.left = mi.rcWork.left; + else + m_monitor_work_rect.left = m_monitor_rect.left + (mi.rcWork.left - mi.rcMonitor.left); + + if (m_monitor_rect.top == mi.rcMonitor.top) + m_monitor_work_rect.top = mi.rcWork.top; + else + m_monitor_work_rect.top = m_monitor_rect.top + (mi.rcWork.top - mi.rcMonitor.top); + + if (m_monitor_rect.right == mi.rcMonitor.right) + m_monitor_work_rect.right = mi.rcWork.right; + else + m_monitor_work_rect.right = m_monitor_rect.right; + + if (m_monitor_rect.bottom == mi.rcMonitor.bottom) + m_monitor_work_rect.bottom = mi.rcWork.bottom; + else + m_monitor_work_rect.bottom = m_monitor_rect.bottom; + } + } +} + +void DXContext::SaveWindow() +{ + if (m_current_mode.screenmode == WINDOWED) + { + RECT c; + GetClientRect(m_hwnd, &c); + + // 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_hwnd, &p)) + { + c.left += p.x; + c.right += p.x; + c.top += p.y; + c.bottom += p.y; + } + + // save bounds for window CLIENT area, but in screen coords + WritePrivateProfileIntW(c.top, L"nMainWndTop", m_szIniFile, L"settings"); + WritePrivateProfileIntW(c.left, L"nMainWndLeft", m_szIniFile, L"settings"); + WritePrivateProfileIntW(c.right, L"nMainWndRight", m_szIniFile, L"settings"); + WritePrivateProfileIntW(c.bottom,L"nMainWndBottom", m_szIniFile, L"settings"); + + // also save bounds for embedwnd + if (m_current_mode.m_skin && myWindowState.me) + { + WritePrivateProfileIntW(myWindowState.r.left,L"avs_wx",m_szIniFile,L"settings"); + WritePrivateProfileIntW(myWindowState.r.top ,L"avs_wy",m_szIniFile,L"settings"); + WritePrivateProfileIntW(myWindowState.r.right-myWindowState.r.left,L"avs_ww",m_szIniFile,L"settings"); + WritePrivateProfileIntW(myWindowState.r.bottom-myWindowState.r.top,L"avs_wh",m_szIniFile,L"settings"); + } + else if (!m_current_mode.m_skin && m_hwnd) + { + RECT r; + GetWindowRect(m_hwnd, &r); + WritePrivateProfileIntW(r.left,L"avs_wx",m_szIniFile,L"settings"); + WritePrivateProfileIntW(r.top ,L"avs_wy",m_szIniFile,L"settings"); + WritePrivateProfileIntW(r.right-r.left,L"avs_ww",m_szIniFile,L"settings"); + WritePrivateProfileIntW(r.bottom-r.top,L"avs_wh",m_szIniFile,L"settings"); + } + } +} \ No newline at end of file diff --git a/vis_milk2/dxcontext.h b/vis_milk2/dxcontext.h new file mode 100644 index 0000000..15076f9 --- /dev/null +++ b/vis_milk2/dxcontext.h @@ -0,0 +1,151 @@ +/* + 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. +*/ + +#ifndef __NULLSOFT_DX9_PLUGIN_SHELL_DXCONTEXT_H__ +#define __NULLSOFT_DX9_PLUGIN_SHELL_DXCONTEXT_H__ 1 + +#include +#include "shell_defines.h" + +#ifdef _DEBUG + #define D3D_DEBUG_INFO // declare this before including d3d9.h +#endif +#include +#include + +#define SNAP_WINDOWED_MODE_BLOCKSIZE 32 // or use 0 if you don't want snapping + +typedef struct +{ + eScrMode screenmode; // WINDOWED, FULLSCREEN, or FAKE FULLSCREEN + int nbackbuf; + int allow_page_tearing; + GUID adapter_guid; + char adapter_devicename[256]; + D3DDISPLAYMODE display_mode; // ONLY VALID FOR FULLSCREEN MODE. + D3DMULTISAMPLE_TYPE multisamp; + HWND parent_window; + int m_dualhead_horz; // 0 = span both, 1 = left only, 2 = right only + int m_dualhead_vert; // 0 = span both, 1 = top only, 2 = bottom only + int m_skin; +} +DXCONTEXT_PARAMS; + +#define MAX_DXC_ADAPTERS 32 + +class DXContext +{ + public: + // PUBLIC FUNCTIONS + DXContext(HWND hWndWinamp,HINSTANCE hInstance,LPCWSTR szClassName,LPCSTR szWindowCaption,WNDPROC pProc,LONG_PTR uWindowLong, int minimize_winamp, wchar_t* szIniFile); + ~DXContext(); + BOOL StartOrRestartDevice(DXCONTEXT_PARAMS *pParams); // also serves as Init() function + BOOL OnUserResizeWindow(RECT *new_window_rect, RECT *new_client_rect); + inline HWND GetHwnd() { return m_hwnd; }; + inline int TempIgnoreDestroyMessages() { return m_ignore_wm_destroy; }; + void OnTrulyExiting() { m_truly_exiting = 1; } + void UpdateMonitorWorkRect(); + int GetBitDepth() { return m_bpp; }; + inline D3DFORMAT GetZFormat() { return m_zFormat; }; + char* GetDriver() { return m_szDriver; }; + char* GetDesc() { return m_szDesc; }; + void SaveWindow(); + + // PUBLIC DATA - DO NOT WRITE TO THESE FROM OUTSIDE THE CLASS + int m_ready; + HRESULT m_lastErr; + int m_window_width; + int m_window_height; + int m_client_width; //in windowed mode, these are the SNAPPED (locked to nearest 32x32) + int m_client_height; // width and height + int m_REAL_client_width; //these are the ACTUAL (raw) width and height - + int m_REAL_client_height; // only valid in windowed mode! + int m_fake_fs_covers_all; + int m_frame_delay; + RECT m_all_monitors_rect; // rect that encompasses all monitors that make up the desktop. The primary monitor's upper-left corner is (0,0). + RECT m_monitor_rect; // rect for monitor the plugin is running on; for pseudo-multimon modes like 2048x768, if user decides to only run on half the monitor, this rect reflects that as well. + RECT m_monitor_rect_orig; // same, but it's the original rect; does not account for pseudo-multimon modes like 2048x768 + RECT m_monitor_work_rect; // same, but excludes the taskbar area. + RECT m_monitor_work_rect_orig; // original work rect; does not account for pseudo-multimon modes like 2048x768 + DXCONTEXT_PARAMS m_current_mode; + LPDIRECT3DDEVICE9 m_lpDevice; + D3DPRESENT_PARAMETERS m_d3dpp; + LPDIRECT3D9 m_lpD3D; + D3DCAPS9 m_caps; + + protected: + D3DMULTISAMPLE_TYPE m_multisamp; + D3DFORMAT m_zFormat; + D3DFORMAT m_orig_windowed_mode_format[MAX_DXC_ADAPTERS]; + HMODULE m_hmod_d3d9, m_hmod_d3dx9; + int m_ordinal_adapter; + HWND m_hwnd; + HWND m_hwnd_winamp; + LONG_PTR m_uWindowLong; + ATOM m_classAtom; + char m_szWindowCaption[512]; + wchar_t m_szIniFile[MAX_PATH]; + char m_szDriver[MAX_DEVICE_IDENTIFIER_STRING]; + char m_szDesc[MAX_DEVICE_IDENTIFIER_STRING]; + HINSTANCE m_hInstance; + int m_ignore_wm_destroy; + int m_minimize_winamp; + int m_winamp_minimized; + int m_truly_exiting; + int m_bpp; + + embedWindowState myWindowState; + + void WriteSafeWindowPos(); + int GetWindowedModeAutoSize(int iteration); + BOOL TestDepth(int ordinal_adapter, D3DFORMAT fmt); + BOOL TestFormat(int ordinal_adapter, D3DFORMAT fmt); + int CheckAndCorrectFullscreenDispMode(int ordinal_adapter, D3DDISPLAYMODE *pdm); + void SetViewport(); + void MinimizeWinamp(HMONITOR hPluginMonitor); + BOOL Internal_Init(DXCONTEXT_PARAMS *pParams, BOOL bFirstInit); + void Internal_CleanUp(); + void RestoreWinamp(); + void GetSnappedClientSize(); //windowed mode only +}; + +#define DXC_ERR_REGWIN -2 +#define DXC_ERR_CREATEWIN -3 +#define DXC_ERR_CREATE3D -4 +#define DXC_ERR_GETFORMAT -5 +#define DXC_ERR_FORMAT -6 +#define DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY -7 +#define DXC_ERR_RESIZEFAILED -8 +#define DXC_ERR_CAPSFAIL -9 +#define DXC_ERR_BAD_FS_DISPLAYMODE -10 +#define DXC_ERR_USER_CANCELED -11 +#define DXC_ERR_CREATEDEV_NOT_AVAIL -12 +#define DXC_ERR_CREATEDDRAW -13 + +#endif \ No newline at end of file diff --git a/vis_milk2/fft.cpp b/vis_milk2/fft.cpp new file mode 100644 index 0000000..7c0a512 --- /dev/null +++ b/vis_milk2/fft.cpp @@ -0,0 +1,320 @@ +/* + 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. +*/ + +#include +#include +#include "fft.h" + +#define PI 3.141592653589793238462643383279502884197169399f + +#define SafeDeleteArray(x) { if (x) { delete [] x; x = 0; } } + +/*****************************************************************************/ + +FFT::FFT() +{ + NFREQ = 0; + + envelope = 0; + equalize = 0; + bitrevtable = 0; + cossintable = 0; + temp1 = 0; + temp2 = 0; +} + +/*****************************************************************************/ + +FFT::~FFT() +{ + CleanUp(); +} + +/*****************************************************************************/ + +void FFT::Init(int samples_in, int samples_out, int bEqualize, float envelope_power) +{ + // samples_in: # of waveform samples you'll feed into the FFT + // samples_out: # of frequency samples you want out; MUST BE A POWER OF 2. + // bEqualize: set to 1 if you want the magnitude of the basses and trebles + // to be roughly equalized; 0 to leave them untouched. + // envelope_power: set to -1 to disable the envelope; otherwise, specify + // the envelope power you want here. See InitEnvelopeTable for more info. + + CleanUp(); + + m_samples_in = samples_in; + NFREQ = samples_out*2; + + InitBitRevTable(); + InitCosSinTable(); + if (envelope_power > 0) + InitEnvelopeTable(envelope_power); + if (bEqualize) + InitEqualizeTable(); + temp1 = new float[NFREQ]; + temp2 = new float[NFREQ]; +} + +/*****************************************************************************/ + +void FFT::CleanUp() +{ + SafeDeleteArray(envelope); + SafeDeleteArray(equalize); + SafeDeleteArray(bitrevtable); + SafeDeleteArray(cossintable); + SafeDeleteArray(temp1); + SafeDeleteArray(temp2); +} + +/*****************************************************************************/ + +void FFT::InitEqualizeTable() +{ + int i; + float scaling = -0.02f; + float inv_half_nfreq = 1.0f/(float)(NFREQ/2); + + equalize = new float[NFREQ/2]; + + for (i=0; i i) + { + temp = bitrevtable[i]; + bitrevtable[i] = bitrevtable[j]; + bitrevtable[j] = temp; + } + + m = NFREQ >> 1; + + while (m >= 1 && j >= m) + { + j -= m; + m >>= 1; + } + + j += m; + } +} + +/*****************************************************************************/ + +void FFT::InitCosSinTable() +{ + + int i,dftsize,tabsize; + float theta; + + dftsize = 2; + tabsize = 0; + while (dftsize <= NFREQ) + { + tabsize++; + dftsize <<= 1; + } + + cossintable = new float[tabsize][2]; + + dftsize = 2; + i = 0; + while (dftsize <= NFREQ) + { + theta = (float)(-2.0f*PI/(float)dftsize); + cossintable[i][0] = (float)cosf(theta); + cossintable[i][1] = (float)sinf(theta); + i++; + dftsize <<= 1; + } +} + +/*****************************************************************************/ + +void FFT::time_to_frequency_domain(float *in_wavedata, float *out_spectraldata) +{ + // Converts time-domain samples from in_wavedata[] + // into frequency-domain samples in out_spectraldata[]. + // The array lengths are the two parameters to Init(). + + // The last sample of the output data will represent the frequency + // that is 1/4th of the input sampling rate. For example, + // if the input wave data is sampled at 44,100 Hz, then the last + // sample of the spectral data output will represent the frequency + // 11,025 Hz. The first sample will be 0 Hz; the frequencies of + // the rest of the samples vary linearly in between. + // Note that since human hearing is limited to the range 200 - 20,000 + // Hz. 200 is a low bass hum; 20,000 is an ear-piercing high shriek. + // Each time the frequency doubles, that sounds like going up an octave. + // That means that the difference between 200 and 300 Hz is FAR more + // than the difference between 5000 and 5100, for example! + // So, when trying to analyze bass, you'll want to look at (probably) + // the 200-800 Hz range; whereas for treble, you'll want the 1,400 - + // 11,025 Hz range. + // If you want to get 3 bands, try it this way: + // a) 11,025 / 200 = 55.125 + // b) to get the number of octaves between 200 and 11,025 Hz, solve for n: + // 2^n = 55.125 + // n = log 55.125 / log 2 + // n = 5.785 + // c) so each band should represent 5.785/3 = 1.928 octaves; the ranges are: + // 1) 200 - 200*2^1.928 or 200 - 761 Hz + // 2) 200*2^1.928 - 200*2^(1.928*2) or 761 - 2897 Hz + // 3) 200*2^(1.928*2) - 200*2^(1.928*3) or 2897 - 11025 Hz + + // A simple sine-wave-based envelope is convolved with the waveform + // data before doing the FFT, to emeliorate the bad frequency response + // of a square (i.e. nonexistent) filter. + + // You might want to slightly damp (blur) the input if your signal isn't + // of a very high quality, to reduce high-frequency noise that would + // otherwise show up in the output. + + int j, m, i, dftsize, hdftsize, t; + float wr, wi, wpi, wpr, wtemp, tempr, tempi; + + if (!bitrevtable) return; + //if (!envelope) return; + //if (!equalize) return; + if (!temp1) return; + if (!temp2) return; + if (!cossintable) return; + + // 1. set up input to the fft + if (envelope) + { + for (i=0; i> 1; + + for (m = 0; m < hdftsize; m+=1) + { + for (i = m; i < NFREQ; i+=dftsize) + { + j = i + hdftsize; + tempr = wr*real[j] - wi*imag[j]; + tempi = wr*imag[j] + wi*real[j]; + real[j] = real[i] - tempr; + imag[j] = imag[i] - tempi; + real[i] += tempr; + imag[i] += tempi; + } + + wr = (wtemp=wr)*wpr - wi*wpi; + wi = wi*wpr + wtemp*wpi; + } + + dftsize <<= 1; + t++; + } + + // 3. take the magnitude & equalize it (on a log10 scale) for output + if (equalize) + for (i=0; i + +class GString +{ +public: + GString() + { + m_data = new wchar_t[1]; + m_data[0] = 0; + m_size = 1; + } + + GString(const wchar_t* src) + { + m_data = NULL; + m_size = 0; + operator=(src); + } + + GString(const GString &src_string) + { + m_data = NULL; + m_size = 0; + operator=(src_string); + } + + ~GString() + { + delete m_data; // note: delete is safe on NULL ptrs + m_data = NULL; + m_size = 0; + } + + inline GString& operator=(const wchar_t* src) + { + if (src != m_data) // don't do anything on "x = x.c_str();" + { + delete m_data; // note: delete is safe on NULL ptrs + if (src) + { + m_size = wcslen(src)+1; + m_data = new wchar_t[m_size]; + memcpy(m_data, src, m_size*2); + } + else + { + m_size = 1; + m_data = new wchar_t[1]; + m_data[0] = 0; + } + } + return *this; + } + + inline GString& operator=(const GString &src_string) + { + if (&src_string != this) // don't do anything on "x = x;" + { + if (src_string.GetSize() != m_size) //optimization + { + delete m_data; + m_size = src_string.GetSize(); + m_data = new wchar_t[m_size]; + } + memcpy(m_data, src_string.c_str(), m_size*2); + } + return *this; + } + + inline wchar_t operator[](int index) const + { + return m_data[index]; + } + + inline bool operator==(const wchar_t* comp) + { + return (wcscmp(m_data,comp) == 0); + } + + inline bool operator==(const GString &comp) + { + if (m_size != comp.m_size) // shortcut + return false; + return (wcscmp(m_data,comp.c_str()) == 0); //return operator==(comp.m_data); + } + + inline const wchar_t* c_str() const + { + return m_data; + } + + // This is actually unsafe, but we need it for convenience, unless we really + // feel like copying all data twice. BE WARNED! When this class reallocates + // memory, all old references to _data are invalid! + //operator const char*() const { return _data; } + inline int GetSize() const //in bytes - including terminating NULL char. + { + return m_size; + } + + inline int GetLength() const + { + return (m_size >= 1) ? m_size-1 : 0; + } + +private: + wchar_t* m_data; + int m_size; +}; + +class GStringA +{ +public: + GStringA() + { + m_data = new char[1]; + m_data[0] = 0; + m_size = 1; + } + + GStringA(const char* src) + { + m_data = NULL; + m_size = 0; + operator=(src); + } + + GStringA(const GStringA &src_string) + { + m_data = NULL; + m_size = 0; + operator=(src_string); + } + + ~GStringA() + { + delete m_data; // note: delete is safe on NULL ptrs + m_data = NULL; + m_size = 0; + } + + inline GStringA& operator=(const char* src) + { + if (src != m_data) // don't do anything on "x = x.c_str();" + { + delete m_data; // note: delete is safe on NULL ptrs + if (src) + { + m_size = strlen(src)+1; + m_data = new char[m_size]; + memcpy(m_data, src, m_size); + } + else + { + m_size = 1; + m_data = new char[1]; + m_data[0] = 0; + } + } + return *this; + } + + inline GStringA& operator=(const GStringA &src_string) + { + if (&src_string != this) // don't do anything on "x = x;" + { + if (src_string.GetSize() != m_size) //optimization + { + delete m_data; + m_size = src_string.GetSize(); + m_data = new char[m_size]; + } + memcpy(m_data, src_string.c_str(), m_size); + } + return *this; + } + + inline char operator[](int index) const + { + return m_data[index]; + } + + inline bool operator==(const char* comp) + { + return (strcmp(m_data,comp) == 0); + } + + inline bool operator==(const GStringA &comp) + { + if (m_size != comp.m_size) // shortcut + return false; + return (strcmp(m_data,comp.c_str()) == 0); //return operator==(comp.m_data); + } + + inline const char* c_str() const + { + return m_data; + } + + // This is actually unsafe, but we need it for convenience, unless we really + // feel like copying all data twice. BE WARNED! When this class reallocates + // memory, all old references to _data are invalid! + //operator const char*() const { return _data; } + inline int GetSize() const //in bytes - including terminating NULL char. + { + return m_size; + } + + inline int GetLength() const + { + return (m_size >= 1) ? m_size-1 : 0; + } + +private: + char* m_data; + int m_size; +}; + +#endif \ No newline at end of file diff --git a/vis_milk2/icon_t.h b/vis_milk2/icon_t.h new file mode 100644 index 0000000..c1f6e90 --- /dev/null +++ b/vis_milk2/icon_t.h @@ -0,0 +1,49 @@ +/* + 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. +*/ + +#ifndef __ICON_T_H__ +#define __ICON_T_H__ 1 + +#include +#include // for ITEMIDLIST + +typedef struct +{ + int x, y, selected, icon_bitmap_idx, checksum[3], bUpdate; + DWORD dwReserved1; + DWORD dwReserved2; + DWORD dwReserved3; + DWORD dwReserved4; + RECT icon_rect; + RECT label_rect; + BYTE pidl[1024]; // when using this, cast it to an ITEMIDLIST + TCHAR name[MAX_PATH]; +} icon_t; + +#endif \ No newline at end of file diff --git a/vis_milk2/manifest.xml b/vis_milk2/manifest.xml new file mode 100644 index 0000000..5f91bfc --- /dev/null +++ b/vis_milk2/manifest.xml @@ -0,0 +1 @@ +Nullsoft Winamp Milkdrop 2 (So You Don't Have To Keep Hacking The Plug-in Dll \ No newline at end of file diff --git a/vis_milk2/md_defines.h b/vis_milk2/md_defines.h new file mode 100644 index 0000000..3600323 --- /dev/null +++ b/vis_milk2/md_defines.h @@ -0,0 +1,83 @@ +/* + 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. +*/ + +#ifndef __MILKDROP_DEFINES_H__ +#define __MILKDROP_DEFINES_H__ 1 + +// IDENTIFIERS +/* +#define CURRENT_VERSION 220 +#define CURRENT_SUBVERSION 0 // 0=first release, 1=a, 2=b, 3=c... +#define MODULEDESC "MilkDrop 2.2" // used for module desc (from Winamp/Prefs) + window title for fullscreen mode +#define DLLDESC "MilkDrop 2.2" +#define NAME "MilkDrop" +#define TITLE "MilkDrop" +#define CLASSNAME "MilkDrop" // window class name +*/ +#define TEXT_WINDOW_CLASSNAME "MilkDrop Console [VJ Mode]" +#define DEBUGFILE "c:\\m_debug.txt" +//#define CONFIG_INIFILE "milkdrop_config.ini" +//#define PRESET_INIFILE "milkdrop_presets.ini" +#define DEBUGFILEHEADER "[milkdrop debug file]\n" + +// define this to disable expression evaluation: +// (...for some reason, evallib kills the debugger) +#ifdef _DEBUG + #define _NO_EXPR_ //FIXME +#endif + +#define MAX_GRID_X 192//128 +#define MAX_GRID_Y 144//96 +#define NUM_WAVES 8 +#define NUM_MODES 7 +#define LINEFEED_CONTROL_CHAR 1 // note: this char should be outside the ascii range from SPACE (32) to lowercase 'z' (122) +#define MAX_CUSTOM_MESSAGE_FONTS 16 // 0-15 +#define MAX_CUSTOM_MESSAGES 100 // 00-99 +#define MAX_CUSTOM_WAVES 4 +#define MAX_CUSTOM_SHAPES 4 + +// aspect ratio makes the motion in the UV field [0..1] cover the screen appropriately, +//#define ASPECT_X 1.00 +//#define ASPECT_Y 0.75 // ~h/w +//#define ASPECT_X ( (m_nTexSizeY > m_nTexSizeX) ? m_nTexSizeX/(float)m_nTexSizeY : 1.0f ) //0.75f +//#define ASPECT_Y ( (m_nTexSizeX > m_nTexSizeY) ? m_nTexSizeY/(float)m_nTexSizeX : 1.0f ) //0.75f +// --> now stored in m_fAspectX, m_fInvAspectY, etc. <-- + +#define WM_MILKDROP_SYSTRAY_MSG WM_USER + 407 +#define IDC_MILKDROP_SYSTRAY_ICON 555 +#define ID_MILKDROP_SYSTRAY_CLOSE 556 +//#define ID_MILKDROP_SYSTRAY_RESUME 559 +//#define ID_MILKDROP_SYSTRAY_SUSPEND 560 +//#define ID_MILKDROP_SYSTRAY_HOTKEYS 561 + +#define NUMERIC_INPUT_MODE_CUST_MSG 0 +#define NUMERIC_INPUT_MODE_SPRITE 1 +#define NUMERIC_INPUT_MODE_SPRITE_KILL 2 + +#endif \ No newline at end of file diff --git a/vis_milk2/menu.cpp b/vis_milk2/menu.cpp new file mode 100644 index 0000000..65830c5 --- /dev/null +++ b/vis_milk2/menu.cpp @@ -0,0 +1,750 @@ +/* + 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. +*/ + +#include "api.h" +#include "state.h" // for CBlendableFloat - fix this +#include "menu.h" +#include "plugin.h" +#include +#include +#include +#include "resource.h" + +extern CPlugin g_plugin; // declared in main.cpp + +//---------------------------------------- + +CMilkMenuItem::CMilkMenuItem() +{ + WASABI_API_LNGSTRINGW_BUF(IDS_UNTITLED_MENU_ITEM,m_szName,64); + m_szToolTip[0] = 0; + m_type = MENUITEMTYPE_BUNK; + m_fMin = 0.0f; + m_fMax = 0.0f; + m_var_offset = NULL; + m_pCallbackFn = NULL; + m_pNext = NULL; + m_original_value = NULL; + m_nLastCursorPos = 0; + m_bEnabled = true; +} + +CMilkMenuItem::~CMilkMenuItem() +{ + if (m_pNext) + { + delete m_pNext; + m_pNext = NULL; + } +} + +//---------------------------------------- + +CMilkMenu::CMilkMenu() +{ + //Reset(); +} + +CMilkMenu::~CMilkMenu() +{ + /* + if (m_pFirstChildItem) + { + delete m_pFirstChildItem; + m_pFirstChildItem = NULL; + } + */ +} + +//---------------------------------------- + +bool CMilkMenu::ItemIsEnabled(int j) +{ + if (j < m_nChildMenus) + return m_ppChildMenu[j]->IsEnabled(); + + int i = m_nChildMenus; + CMilkMenuItem *pChild = m_pFirstChildItem; + while (pChild && im_pNext; + i++; + } + if (pChild) + return pChild->m_bEnabled; + + return false; +} + +//---------------------------------------- + +void CMilkMenu::EnableItem(wchar_t* szName, bool bEnable) +{ + //search submenus + for (int i=0; iGetName(), szName)) + { + m_ppChildMenu[i]->Enable(bEnable); + if (!bEnable) + { + while (m_nCurSel > 0 && !ItemIsEnabled(m_nCurSel)) + m_nCurSel--; + if (m_nCurSel==0 && !ItemIsEnabled(m_nCurSel)) + while (m_nCurSel < m_nChildMenus+m_nChildItems-1 && !ItemIsEnabled(m_nCurSel)) + m_nCurSel++; + } + return; + } + } + + //search child items + CMilkMenuItem *pChild = m_pFirstChildItem; + while (pChild) + { + if (!wcscmp(pChild->m_szName, szName)) + { + pChild->m_bEnabled = bEnable; + if (!bEnable) + { + while (m_nCurSel > 0 && !ItemIsEnabled(m_nCurSel)) + m_nCurSel--; + if (m_nCurSel==0 && !ItemIsEnabled(m_nCurSel)) + while (m_nCurSel < m_nChildMenus+m_nChildItems-1 && !ItemIsEnabled(m_nCurSel)) + m_nCurSel++; + } + return; + } + pChild = pChild->m_pNext; + i++; + } +} + +//---------------------------------------- + +void CMilkMenu::Reset() +{ + m_pParentMenu = NULL; + for (int i=0; iSetParentPointer(this); + } +} + +//---------------------------------------- + +void CMilkMenu::AddItem(wchar_t *szName, void *var, MENUITEMTYPE type, wchar_t *szToolTip, + float min, float max, MilkMenuCallbackFnPtr pCallback, + unsigned int wParam, unsigned int lParam) +{ + CMilkMenuItem *pLastItem = NULL; + + // find last item in linked list + if (!m_pFirstChildItem) + { + // first item + m_pFirstChildItem = new CMilkMenuItem; + pLastItem = m_pFirstChildItem; + } + else + { + pLastItem = m_pFirstChildItem; + while (pLastItem->m_pNext) + pLastItem = pLastItem->m_pNext; + + // allocate a new CMilkMenuItem + pLastItem->m_pNext = new CMilkMenuItem; + pLastItem = pLastItem->m_pNext; + } + + // set its attributes + wcsncpy(pLastItem->m_szName, szName, 64); + wcsncpy(pLastItem->m_szToolTip, szToolTip, 1024); + pLastItem->m_var_offset = (size_t)var - (size_t)(g_plugin.m_pState); + pLastItem->m_type = type; + pLastItem->m_fMin = min; + pLastItem->m_fMax = max; + pLastItem->m_wParam = wParam; + pLastItem->m_lParam = lParam; + if ((type==MENUITEMTYPE_LOGBLENDABLE || type==MENUITEMTYPE_LOGFLOAT) && min==max) + { + // special defaults + pLastItem->m_fMin = 0.01f; + pLastItem->m_fMax = 100.0f; + } + pLastItem->m_pCallbackFn = pCallback; + + m_nChildItems++; +} + +//---------------------------------------- + +void MyMenuTextOut(eFontIndex font_index, wchar_t* str, DWORD color, RECT* pRect, int bCalcRect, RECT* pCalcRect) +{ + if (bCalcRect) + { + RECT t = *pRect; + pRect->top += g_plugin.m_text.DrawTextW(g_plugin.GetFont(font_index), str, -1, &t, DT_SINGLELINE | DT_END_ELLIPSIS | DT_CALCRECT, 0xFFFFFFFF, false); + pCalcRect->bottom += t.bottom - t.top; + //if (pCalcRect->bottom > pRect->bottom) + // pCalcRect->bottom = pRect->bottom; + pCalcRect->right = max(pCalcRect->right, pCalcRect->left + t.right - t.left); + } + else + { + pRect->top += g_plugin.m_text.DrawTextW(g_plugin.GetFont(font_index), str, -1, pRect, DT_SINGLELINE | DT_END_ELLIPSIS, color, false); + } +} + +void CMilkMenu::DrawMenu(RECT rect, int xR, int yB, int bCalcRect, RECT* pCalcRect) +{ + // 'rect' is the bounding rectangle in which we're allowed to draw the menu; + // it's .top member is incremented as we draw downward. + // if bCalcRect==1, then we return pCalcRect as the area that the menu actually + // occupies, excluding any tooltips. + + if (bCalcRect!=0 && pCalcRect==NULL) + return; + + if (bCalcRect) + { + pCalcRect->left = rect.left; + pCalcRect->right = rect.left; + pCalcRect->top = rect.top; + pCalcRect->bottom = rect.top; + } + + if (!m_bEditingCurSel) + { + int nLines = (rect.bottom - rect.top - PLAYLIST_INNER_MARGIN*2) / g_plugin.GetFontHeight(SIMPLE_FONT) - 1; // save 1 line for the tooltip + if (nLines<1) return; + int nStart = (m_nCurSel/nLines)*nLines; + + int nLinesDrawn = 0; + + for (int i=0; i < m_nChildMenus; i++) + { + if (i >= nStart && i < nStart+nLines) + { + //rect.top += g_plugin.GetFont(SIMPLE_FONT)->DrawText(m_ppChildMenu[i]->m_szMenuName, -1, pRect, DT_SINGLELINE | DT_END_ELLIPSIS, (i == m_nCurSel) ? MENU_HILITE_COLOR : MENU_COLOR); + if (m_ppChildMenu[i]->IsEnabled()) { + MyMenuTextOut(SIMPLE_FONT, m_ppChildMenu[i]->m_szMenuName, (i == m_nCurSel) ? MENU_HILITE_COLOR : MENU_COLOR, &rect, bCalcRect, pCalcRect); + nLinesDrawn++; + } + + if (g_plugin.m_bShowMenuToolTips && i == m_nCurSel && !bCalcRect) + { + // tooltip: + g_plugin.DrawTooltip(WASABI_API_LNGSTRINGW(IDS_SZ_MENU_NAV_TOOLTIP), xR, yB); + } + } + } + + CMilkMenuItem *pItem = m_pFirstChildItem; + + while (pItem && nLinesDrawn < nStart+nLines) + { + if (!pItem->m_bEnabled) + { + pItem = pItem->m_pNext; + i++; + continue; + } + + size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState; + if (i >= nStart) + { + wchar_t szItemText[256]; + switch(pItem->m_type) + { + case MENUITEMTYPE_STRING: + lstrcpyW(szItemText, pItem->m_szName); + break; + case MENUITEMTYPE_BOOL: + swprintf(szItemText, L"%s [%s]", pItem->m_szName, + WASABI_API_LNGSTRINGW(*((bool *)(addr)) ? IDS_ON : IDS_OFF)); + break; + default: + lstrcpyW(szItemText, pItem->m_szName); + break; + } + + if (i == m_nCurSel) + { + MyMenuTextOut(SIMPLE_FONT, szItemText, MENU_HILITE_COLOR, &rect, bCalcRect, pCalcRect); + + if (g_plugin.m_bShowMenuToolTips && !bCalcRect) + { + // tooltip: + g_plugin.DrawTooltip(pItem->m_szToolTip, xR, yB); + } + } + else + { + MyMenuTextOut(SIMPLE_FONT, szItemText, MENU_COLOR, &rect, bCalcRect, pCalcRect); + } + nLinesDrawn++; + } + + pItem = pItem->m_pNext; + i++; + } + } + else + { + // editing current selection + + // find the item + CMilkMenuItem *pItem = m_pFirstChildItem; + for (int i=m_nChildMenus; i < m_nCurSel; i++) + pItem = pItem->m_pNext; + size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState; + + wchar_t buf[256]; + + MyMenuTextOut(SIMPLE_FONT, WASABI_API_LNGSTRINGW(IDS_USE_UP_DOWN_ARROW_KEYS), MENU_COLOR, &rect, bCalcRect, pCalcRect); + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_CURRENT_VALUE_OF_X), pItem->m_szName); + MyMenuTextOut(SIMPLE_FONT, buf, MENU_COLOR, &rect, bCalcRect, pCalcRect); + + switch(pItem->m_type) + { + case MENUITEMTYPE_INT: + swprintf(buf, L" %d ", *((int*)(addr)) ); + break; + case MENUITEMTYPE_FLOAT: + case MENUITEMTYPE_LOGFLOAT: + swprintf(buf, L" %5.3f ", *((float*)(addr)) ); + break; + case MENUITEMTYPE_BLENDABLE: + case MENUITEMTYPE_LOGBLENDABLE: + swprintf(buf, L" %5.3f ", ((CBlendableFloat*)addr)->eval(-1) ); + break; + default: + lstrcpyW(buf, L" ? "); + break; + } + + MyMenuTextOut(SIMPLE_FONT, buf, MENU_HILITE_COLOR, &rect, bCalcRect, pCalcRect); + + // tooltip: + if (g_plugin.m_bShowMenuToolTips && !bCalcRect) + { + g_plugin.DrawTooltip(pItem->m_szToolTip, xR, yB); + } + } +} + +void CMilkMenu::OnWaitStringAccept(wchar_t *szNewString) +{ + m_bEditingCurSel = false; + + // find the item + CMilkMenuItem *pItem = m_pFirstChildItem; + for (int i=m_nChildMenus; i < m_nCurSel; i++) + pItem = pItem->m_pNext; + size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState; + + assert(pItem->m_type == MENUITEMTYPE_STRING); + + // apply the edited string + lstrcpyW((wchar_t *)(addr), szNewString); + + // if user gave us a callback function pointer, call it now + if (pItem->m_pCallbackFn) + { + pItem->m_pCallbackFn(0, 0); + } + + // remember the last cursor position + pItem->m_nLastCursorPos = g_plugin.m_waitstring.nCursorPos; +} + +//---------------------------------------- + +LRESULT CMilkMenu::HandleKeydown(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + // all WM_KEYDOWNS that your app gets when a menu is up should be handled here, + // by the menu that is currently active. + + // return value: FALSE if it handled the key; TRUE if it didn't + + int nRepeat = LOWORD(lParam); + int rep; + + if (!m_bEditingCurSel) + { + switch(wParam) + { + case VK_UP: + for (rep=0; rep 0 && !ItemIsEnabled(m_nCurSel)); + } + if (m_nCurSel < 0) m_nCurSel = 0;//m_nChildMenus + m_nChildItems - 1; + while (m_nCurSel < m_nChildMenus + m_nChildItems - 1 && !ItemIsEnabled(m_nCurSel)) + m_nCurSel++; + return 0; // we processed (or absorbed) the key + + case VK_DOWN: + for (rep=0; rep= m_nChildMenus + m_nChildItems) m_nCurSel = m_nChildMenus + m_nChildItems - 1;//0; + while (m_nCurSel > 0 && !ItemIsEnabled(m_nCurSel)) + m_nCurSel--; + return 0; // we processed (or absorbed) the key + + case VK_HOME: + m_nCurSel = 0; + return 0; // we processed (or absorbed) the key + + case VK_END: + m_nCurSel = m_nChildMenus + m_nChildItems - 1; + return 0; // we processed (or absorbed) the key + + case VK_ESCAPE: + g_plugin.m_UI_mode = UI_REGULAR; + return 0; // we processed (or absorbed) the key + + case VK_BACK: + case VK_LEFT: + if (m_pParentMenu) + g_plugin.m_pCurMenu = m_pParentMenu; + else + g_plugin.m_UI_mode = UI_REGULAR; // exit the menu + return 0; // we processed (or absorbed) the key + + case VK_RETURN: + case VK_RIGHT: + case VK_SPACE: + if (m_nCurSel < m_nChildMenus) + { + // go to sub-menu + g_plugin.m_pCurMenu = m_ppChildMenu[m_nCurSel]; + } + else + { + // find the item + CMilkMenuItem *pItem = GetCurItem(); + size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState; + + float fTemp; + + // begin editing the item + + switch(pItem->m_type) + { + case MENUITEMTYPE_UIMODE: + g_plugin.m_UI_mode = (ui_mode)pItem->m_wParam; + + if (g_plugin.m_UI_mode==UI_IMPORT_WAVE || + g_plugin.m_UI_mode==UI_EXPORT_WAVE || + g_plugin.m_UI_mode==UI_IMPORT_SHAPE || + g_plugin.m_UI_mode==UI_EXPORT_SHAPE) + { + g_plugin.m_bPresetLockedByCode = true; + + // enter WaitString mode + g_plugin.m_waitstring.bActive = true; + g_plugin.m_waitstring.bFilterBadChars = false; + g_plugin.m_waitstring.bDisplayAsCode = false; + g_plugin.m_waitstring.nSelAnchorPos = -1; + g_plugin.m_waitstring.nMaxLen = min(sizeof(g_plugin.m_waitstring.szText)-1, MAX_PATH - wcslen(g_plugin.GetPresetDir()) - 6); // 6 for the extension + null char. We set this because win32 LoadFile, MoveFile, etc. barf if the path+filename+ext are > MAX_PATH chars. + swprintf(g_plugin.m_waitstring.szText, L"%sfile.dat", g_plugin.m_szPresetDir); + if (g_plugin.m_UI_mode==UI_IMPORT_WAVE || g_plugin.m_UI_mode==UI_IMPORT_SHAPE) + WASABI_API_LNGSTRINGW_BUF(IDS_LOAD_FROM_FILE,g_plugin.m_waitstring.szPrompt,512); + else + WASABI_API_LNGSTRINGW_BUF(IDS_SAVE_TO_FILE,g_plugin.m_waitstring.szPrompt,512); + g_plugin.m_waitstring.szToolTip[0] = 0; + g_plugin.m_waitstring.nCursorPos = wcslen(g_plugin.m_waitstring.szText); // set the starting edit position + } + break; + case MENUITEMTYPE_BOOL: + *((bool *)addr) = !(*((bool *)addr)); + break; + case MENUITEMTYPE_INT: + m_bEditingCurSel = true; + pItem->m_original_value = (LPARAM)(*((int*)(addr))); + break; + case MENUITEMTYPE_FLOAT: + case MENUITEMTYPE_LOGFLOAT: + m_bEditingCurSel = true; + pItem->m_original_value = (LPARAM)(*((float*)(addr))*10000L); + break; + case MENUITEMTYPE_BLENDABLE: + case MENUITEMTYPE_LOGBLENDABLE: + m_bEditingCurSel = true; + { + //CBlendableFloat *p = (CBlendableFloat*)(pItem->m_pVariable); + //*p = 0.99f; + fTemp = ((CBlendableFloat*)addr)->eval(-1);//p->eval(-1); + } + pItem->m_original_value = (LPARAM)(fTemp*10000L); + break; + case MENUITEMTYPE_STRING: + // enter waitstring mode. ***This function will cease to receive keyboard input + // while the string is being edited*** + g_plugin.m_UI_mode = UI_EDIT_MENU_STRING; + g_plugin.m_waitstring.bActive = true; + g_plugin.m_waitstring.bFilterBadChars = false; + g_plugin.m_waitstring.bDisplayAsCode = true; + g_plugin.m_waitstring.nSelAnchorPos = -1; + g_plugin.m_waitstring.nMaxLen = pItem->m_wParam ? pItem->m_wParam : 8190; + g_plugin.m_waitstring.nMaxLen = min(g_plugin.m_waitstring.nMaxLen, sizeof(g_plugin.m_waitstring.szText)-16); + //lstrcpyW(g_plugin.m_waitstring.szText, (wchar_t *)addr); + lstrcpyA((char*)g_plugin.m_waitstring.szText, (char*)addr); + swprintf(g_plugin.m_waitstring.szPrompt, WASABI_API_LNGSTRINGW(IDS_ENTER_THE_NEW_STRING), pItem->m_szName); + lstrcpyW(g_plugin.m_waitstring.szToolTip, pItem->m_szToolTip); + g_plugin.m_waitstring.nCursorPos = strlen/*wcslen*/((char*)g_plugin.m_waitstring.szText); + if (pItem->m_nLastCursorPos < g_plugin.m_waitstring.nCursorPos) + g_plugin.m_waitstring.nCursorPos = pItem->m_nLastCursorPos; + break; + /* + case MENUITEMTYPE_OSC: + m_bEditingCurSel = true; + pItem->m_bEditingSubSel = false; + break; + */ + } + } + return 0; // we processed (or absorbed) the key + + default: + // key wasn't handled + return TRUE; + break; + } + } + else // m_bEditingCurSel + { + float fMult = 1.0f; + bool bDec; + + // find the item + CMilkMenuItem *pItem = m_pFirstChildItem; + for (int i=m_nChildMenus; i < m_nCurSel; i++) + pItem = pItem->m_pNext; + size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState; + + switch(wParam) + { + case VK_ESCAPE: // exit Edit mode & restore original value + + switch(pItem->m_type) + { + case MENUITEMTYPE_INT: + m_bEditingCurSel = false; + *((int *)addr) = (int)pItem->m_original_value; + break; + case MENUITEMTYPE_FLOAT: + m_bEditingCurSel = false; + *((float *)addr) = ((float)pItem->m_original_value)*0.0001f; + break; + case MENUITEMTYPE_LOGFLOAT: + m_bEditingCurSel = false; + *((float *)addr) = ((float)pItem->m_original_value)*0.0001f; + break; + case MENUITEMTYPE_BLENDABLE: + m_bEditingCurSel = false; + *((CBlendableFloat *)(addr)) = ((float)(pItem->m_original_value))*0.0001f; + break; + case MENUITEMTYPE_LOGBLENDABLE: + m_bEditingCurSel = false; + *((CBlendableFloat *)(addr)) = ((float)(pItem->m_original_value))*0.0001f; + break; + //case MENUITEMTYPE_STRING: + // won't ever happen - see OnWaitStringCancel() + } + return 0; + + case VK_RETURN: + + //if (pItem->m_type == MENUITEMTYPE_STRING) + // ... won't ever happen - see OnWaitStringAccept() + + m_bEditingCurSel = false; + return 0; + + + case VK_NEXT: + case VK_PRIOR: + fMult *= 10.0f; + // break intentionally left out here... + case VK_UP: + case VK_DOWN: + + { + USHORT mask = 1 << (sizeof(USHORT)*8 - 1); // we want the highest-order bit + bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0; + //bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0; + if (bShiftHeldDown && (wParam==VK_UP || wParam==VK_DOWN)) + fMult *= 0.1f; + } + + bDec = (wParam == VK_DOWN || wParam == VK_NEXT); + + switch(pItem->m_type) + { + case MENUITEMTYPE_INT: + { + int *pInt = ((int *)addr); + if (fMult<1) fMult=1; + (*pInt) += (int)((bDec) ? -fMult : fMult); + if (*pInt < pItem->m_fMin) *pInt = (int)pItem->m_fMin; + if (*pInt > pItem->m_fMax) *pInt = (int)pItem->m_fMax; + } + break; + case MENUITEMTYPE_FLOAT: + { + float *pFloat = ((float *)addr); + float fInc = (pItem->m_fMax - pItem->m_fMin)*0.01f*fMult; + (*pFloat) += (bDec) ? -fInc : fInc; + if (*pFloat < pItem->m_fMin) *pFloat = pItem->m_fMin; + if (*pFloat > pItem->m_fMax) *pFloat = pItem->m_fMax; + } + break; + case MENUITEMTYPE_LOGFLOAT: + { + float *pFloat = ((float *)addr); + (*pFloat) *= (bDec) ? powf(1.0f/1.01f, fMult) : powf(1.01f, fMult); + if (*pFloat < pItem->m_fMin) *pFloat = pItem->m_fMin; + if (*pFloat > pItem->m_fMax) *pFloat = pItem->m_fMax; + } + break; + case MENUITEMTYPE_BLENDABLE: + { + CBlendableFloat *pBlend = ((CBlendableFloat *)addr); + float fInc = (pItem->m_fMax - pItem->m_fMin)*0.01f*fMult; + (*pBlend) += (bDec) ? -fInc : fInc; + if (pBlend->eval(-1) < pItem->m_fMin) *pBlend = pItem->m_fMin; + if (pBlend->eval(-1) > pItem->m_fMax) *pBlend = pItem->m_fMax; + } + break; + case MENUITEMTYPE_LOGBLENDABLE: + { + CBlendableFloat *pBlend = ((CBlendableFloat *)addr); + (*pBlend) *= (bDec) ? powf(1.0f/1.01f, fMult) : powf(1.01f, fMult); + if (pBlend->eval(-1) < pItem->m_fMin) *pBlend = pItem->m_fMin; + if (pBlend->eval(-1) > pItem->m_fMax) *pBlend = pItem->m_fMax; + } + break; + /* + case MENUITEMTYPE_OSC: + if (pItem->m_bEditingSubSel) + { + if (wParam == VK_UP) + { + pItem->m_nSubSel--; + if (pItem->m_nSubSel < 0) pItem->m_nSubSel = 4; + } + else if (wParam == VK_DOWN) + { + pItem->m_nSubSel++; + if (pItem->m_nSubSel > 4) pItem->m_nSubSel = 0; + } + } + else + { + switch(pItem->m_nSubSel) + { + also to do: make 'drawtext' draw it properly + + case 0: + fixme - what are the bounds for each type? and are incs constant or log? + break; + case 1: + fixme + break; + case 2: + fixme + break; + case 3: + fixme + break; + case 4: + fixme + break; + } + } + break; + */ + } + return 0; + + default: + // key wasn't handled + return TRUE; + break; + } + } + + return TRUE; +} \ No newline at end of file diff --git a/vis_milk2/menu.h b/vis_milk2/menu.h new file mode 100644 index 0000000..2668032 --- /dev/null +++ b/vis_milk2/menu.h @@ -0,0 +1,126 @@ +/* + 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. +*/ + +#ifndef _MILKDROP_MENU_H_ +#define _MILKDROP_MENU_H_ 1 + +//---------------------------------------- + +#include + +//---------------------------------------- + +typedef enum { + MENUITEMTYPE_BUNK, + MENUITEMTYPE_BOOL, + MENUITEMTYPE_INT, + MENUITEMTYPE_FLOAT, + MENUITEMTYPE_LOGFLOAT, + MENUITEMTYPE_BLENDABLE, + MENUITEMTYPE_LOGBLENDABLE, + MENUITEMTYPE_STRING, + MENUITEMTYPE_UIMODE, + //MENUITEMTYPE_OSC, +} MENUITEMTYPE; +#define MAX_CHILD_MENUS 16 +typedef void (*MilkMenuCallbackFnPtr)(LPARAM param1, LPARAM param2); // MilkMenuCallbackFnPtr is synonym for "pointer to function returning void, and taking 2 lparams" + +//---------------------------------------- +class CMilkMenuItem +{ +public: + CMilkMenuItem(); + ~CMilkMenuItem(); + + wchar_t m_szName[64]; + wchar_t m_szToolTip[1024]; + MENUITEMTYPE m_type; + float m_fMin; // note: has different meanings based on the MENUITEMTYPE + float m_fMax; // note: has different meanings based on the MENUITEMTYPE + unsigned int m_wParam; + unsigned int m_lParam; + MilkMenuCallbackFnPtr m_pCallbackFn; // Callback Function pointer; if non-NULL, this functino will be called whenever the menu item is modified by the user. + ptrdiff_t m_var_offset; // dist of variable's mem loc., in bytes, from pg->m_pState. + LPARAM m_original_value; // can hold a float or int + int m_nLastCursorPos; // for strings; remembers most recent pos. of the cursor + bool m_bEnabled; + + // special data used for MENUITEMTYPE_OSCILLATOR: + //int m_nSubSel; + //bool m_bEditingSubSel; + + CMilkMenuItem *m_pNext; +}; +//---------------------------------------- + +//---------------------------------------- +class CMilkMenu +{ +public: + CMilkMenu(); + ~CMilkMenu(); + + void Init(wchar_t *szName); + void Finish(); + void AddChildMenu(CMilkMenu *pChildMenu); + void AddItem(wchar_t *szName, void *var, MENUITEMTYPE type, wchar_t *szToolTip, + float min=0, float max=0, MilkMenuCallbackFnPtr pCallback=NULL, + unsigned int wParam=0, unsigned int lParam=0); + void SetParentPointer(CMilkMenu *pParentMenu) { m_pParentMenu = pParentMenu; } + LRESULT HandleKeydown(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + void DrawMenu(RECT rect, int xR, int yB, int bCalcRect=0, RECT* pCalcRect=NULL); + void OnWaitStringAccept(wchar_t *szNewString); + void EnableItem(wchar_t* szName, bool bEnable); + CMilkMenuItem* GetCurItem() // NOTE: ONLY WORKS IF AN *ITEM* IS HIGHLIGHTED; NOT A CHILD MENU + { + CMilkMenuItem *pItem = m_pFirstChildItem; + for (int i=m_nChildMenus; i < m_nCurSel; i++) + pItem = pItem->m_pNext; + return pItem; + } + const wchar_t* GetName() { return m_szMenuName; } + void Enable(bool bEnabled) { m_bEnabled = bEnabled; } + bool IsEnabled() { return m_bEnabled; } + bool ItemIsEnabled(int i); + +protected: + void Reset(); + CMilkMenu *m_pParentMenu; + CMilkMenu *m_ppChildMenu[MAX_CHILD_MENUS]; // pointers are kept here, but these should be cleaned up by the app. + CMilkMenuItem *m_pFirstChildItem; // linked list; these are dynamically allocated, and automatically cleaned up in destructor + wchar_t m_szMenuName[64]; + int m_nChildMenus; + int m_nChildItems; + int m_nCurSel; + bool m_bEditingCurSel; + bool m_bEnabled; +}; +//---------------------------------------- + +#endif //_MILKDROP_MENU_H_ \ No newline at end of file diff --git a/vis_milk2/milkdrop.nsi b/vis_milk2/milkdrop.nsi new file mode 100644 index 0000000..c10333e --- /dev/null +++ b/vis_milk2/milkdrop.nsi @@ -0,0 +1,439 @@ +; 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. + +; ---------------------------------------------------------------- +; NOTE: this .nsi script was last built with 'makensis.exe' +; version 1.98. If you go to install it (unchanged) and get errors, +; try tracking down that older version, or try to figure out what +; has changed since then. You can get NSIS at: +; +; http://www.nullsoft.com/free/nsis/ +; +; This installer will produce a single EXE file that, when run, +; will decompress and install your plugin and all of its data files +; to Winamp 2 or Winamp 3. +; ---------------------------------------------------------------- +; MODIFYING THIS SCRIPT TO CREATE AN INSTALLER FOR YOUR OWN PLUGIN: +; ---------------------------------------------------------------- +; 1) there are three sections below, each marked 'EDIT THIS SECTION +; [x/3]' where 'x' is the section number. These are the 3 +; places where you need to make changes to customize this +; installer script for your particular plugin. Go to each +; and make the changes, reading the comments there for +; more information. +; 2) download NSIS from http://www.nullsoft.com/free/nsis/, if you +; haven't already. +; 3) run the command 'makensis.exe installer.nsi' to build +; the executable. (note: ignore the warning message about +; 'InstallRegKey' being used multiple times; this is necessary +; to determine whether Winamp 2 or 3 is a better candidate +; for the install.) +; ---------------------------------------------------------------- +; WHAT THIS INSTALLER SCRIPT DOES: +; ---------------------------------------------------------------- +; If Winamp 2 is installed, it will install your plugin to Winamp 2, +; in the directory Winamp\Plugins (or whatever is specified as the +; vis plugins path, in Winamp\winamp.ini). It will also select +; the plugin as the current plugin. (Note that Winamp must be +; closed to do this, so if it's open, the installer will ask the +; user to close it before proceeding.) At the end of a successful +; install, it asks if they'd like to run Winamp. +; +; If Winamp 2 is not present but Winamp 3 is, or if the user manually +; selects the Winamp 3 directory to install to, the plugin will be +; installed to Winamp 3 as a classic visualization plugin, to the +; directory Winamp3\Plugins. At install time, if ClassicVis is not +; installed, it will prompt the user to go download it. If they +; don't download it, it will tell them the installation failed. +; If they already had it, or after they presumably download it, +; the installer will briefly tell them how to select their new +; plugin and run it in Winamp 3, using ClassicVis. Finally, at +; the end of a successful install, it asks if they'd like to run +; Winamp 3. +; ---------------------------------------------------------------- + + + +; -------------------- EDIT THIS SECTION [1/3] -------------------- +; -------------------- EDIT THIS SECTION [1/3] -------------------- +; -------------------- EDIT THIS SECTION [1/3] -------------------- + + !define PLUGIN_NAME "MilkDrop 2" ; Brief name of the component. Can have spaces in it. + !define INSTALL_CAPTION "MilkDrop 2.2 Setup" ; Caption for the installer dialog + !define PLUGIN_DLL "vis_milk2.dll" ; The filename of the actual plugin + !define PLUGIN_OUTFILE "milkdrop_2.exe" ; Name of the installer to create + +; ----------------------- END SECTION [1/3] ----------------------- +; ----------------------- END SECTION [1/3] ----------------------- +; ----------------------- END SECTION [1/3] ----------------------- + +; ---------------------------------------------------------------- +Name ${PLUGIN_NAME} +Caption "${INSTALL_CAPTION}" +OutFile ${PLUGIN_OUTFILE} +; ---------------------------------------------------------------- + +; to determine the install directory, we start with Program Files\Winamp. +; then, if winamp 3 is found, override this and use that directory. +; finally, if winamp 2 is found, override again and use that directory. +InstallDir $PROGRAMFILES\Winamp +InstallDirRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\Winamp3" "UninstallString" +InstallDirRegKey HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\Winamp" "UninstallString" +DirText \ + "The installer has determined that this is the path to Winamp.$\rIf it is not correct, please change it. You will not be able to proceed$\runtil a valid path is found." \ + "Select the directory in which Winamp 2 or 3 is installed:" + +Function .onInit + IfFileExists $INSTDIR\winamp.exe End ; else if winamp.exe found (winamp2), we're good + IfFileExists $INSTDIR\winamp3.exe End ; if winamp3.exe found (winamp3), we're good + IfFileExists $INSTDIR\studio.exe End ; or if studio.exe found (older version of winamp3), we're good + ; the above will work fine if winamp 2 or 3 is installed, + ; but will break if winamp 2 or 3 was uninstalled *but the directory remains.* + IfFileExists $PROGRAMFILES\Winamp\winamp.exe SelectNaturalWinamp2 ; last but not least, try the default winamp 2 directory + IfFileExists $PROGRAMFILES\Winamp3\winamp3.exe SelectNaturalWinamp3 ; otherwise, try the default winamp 3 directory + IfFileExists $PROGRAMFILES\Winamp3\studio.exe SelectNaturalWinamp3 ; otherwise, try the default winamp 3 directory + ; if all of these failed, no good path to Winamp (2 or 3) could be found, + ; and the 'Next' button will be disabled until the user can specify + ; the correct folder. + Goto End + + SelectNaturalWinamp3: + strcpy $INSTDIR $PROGRAMFILES\Winamp3 + goto End + + SelectNaturalWinamp2: + strcpy $INSTDIR $PROGRAMFILES\Winamp + goto End + + End: +FunctionEnd + + +Function .onVerifyInstDir + IfFileExists $INSTDIR\Winamp.exe DirOk + IfFileExists $INSTDIR\Winamp3.exe DirOk + IfFileExists $INSTDIR\Studio.exe DirOk + Abort ; leaves the directory as the selected one, but disables the 'Next' button... + + DirOk: +FunctionEnd + + + + + +Function QueryWinampVisPath + ; input: $INSTDIR, the currently-selected install dir (path to winamp) + ; output: $1, the path to the winamp vis plugins subdirectory + ; -for winamp 3x, this is just $INSTDIR\plugins + ; -for winamp 2x, it comes from the winamp.ini file + ; (or just $INSTDIR\plugins if there is an error reading it.) + IfFileExists $INSTDIR\Winamp.exe CaseWinamp2 + IfFileExists $INSTDIR\Winamp3.exe CaseWinamp3 + IfFileExists $INSTDIR\Studio.exe CaseWinamp3 ; legacy check + goto CaseImpossible + + CaseWinamp2: + StrCpy $1 $INSTDIR\Plugins\MilkDrop2 + ReadINIStr $8 $INSTDIR\winamp.ini Winamp VisDir + StrCmp $8 "" End + IfFileExists $8 0 End + StrCpy $1 $8 ; update dir + goto end + + CaseWinamp3: + CaseImpossible: + StrCpy $1 $INSTDIR\Plugins\MilkDrop2 + goto end + + End: +FunctionEnd + + +; The stuff to install +Section "" + + CloseWinamp2: + ; make sure winamp is closed before we 1) try to install files + ; and 2) (later) edit winamp.ini. for 1), if they're running + ; (or were running) some other vms-based plugin using + ; vms_desktop.dll, then if winamp is still open, the installer + ; could have trouble overwriting vms_desktop.dll, or other files; + ; the user would get an abort/retry/ignore box, but it's easier + ; to just play it safe. + FindWindow $R0 "winamp v1.x" + StrCmp $R0 0 "" RequestCloseWinamp2 + goto Winamp2Closed + RequestCloseWinamp2: + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "Winamp is currently running; please close it,$\rand then hit OK to continue..." \ + IDCANCEL WarnWinampStillOpen + goto CloseWinamp2 + WarnWinampStillOpen: + FindWindow $R0 "winamp v1.x" + StrCmp $R0 0 "" WarnWinampStillOpen2 + goto Winamp2Closed + WarnWinampStillOpen2: + MessageBox MB_OK|MB_ICONEXCLAMATION "Warning: Winamp is still open; as a result, the installer$\rwill not be able to set ${PLUGIN_NAME} as the default plugin; you will$\rhave to do this yourself.$\r$\rTo do so, wait until the installation is finished. Then bring up $\rWinamp and hit CTRL+K. From there, you will be able to select$\r${PLUGIN_NAME} from the list of visualization plug-ins, and it will$\rbecome the new default." + goto Winamp2Closed + Winamp2Closed: + + ; this function sets $1 to point to the 'winamp\plugins\milkdrop2' folder: + ; (see function definition above) + Call QueryWinampVisPath + + ; -------------------- EDIT THIS SECTION [2/3] -------------------- + ; -------------------- EDIT THIS SECTION [2/3] -------------------- + ; -------------------- EDIT THIS SECTION [2/3] -------------------- + + ; LIST FILES TO INCLUDE WITH THE INSTALLER + + ; For each file we want to install onto the destination system, + ; we first set the output directory (relative to $1, which is + ; the PLUGINS directory) and then list files. The paths for + ; the files will be local paths on your hard disk, but fear not - + ; the files will be placed in the current output directory + ; (as last set by SetOutPath) on the destination system. + + ; So, first, we set the current output path (the folder to which + ; files will be decompressed on the user's system) to '$1', + ; which is the path to their winamp plugins folder. + + SetOutPath $1 + File "C:\program files\winamp\plugins\${PLUGIN_DLL}" + + SetOutPath $1\Milkdrop2\config + File "C:\program files\winamp\plugins\milkdrop2\config\milk_msg.ini" + File "C:\program files\winamp\plugins\milkdrop2\config\milk_img.ini" + ;File "C:\program files\winamp\plugins\milkdrop2\config\milkdrop.ini" ;this one will be generated - do not install + + SetOutPath $1\Milkdrop2\data + File "C:\program files\winamp\plugins\milkdrop2\data\vms_desktop.dll" + File "C:\program files\winamp\plugins\milkdrop2\data\comp_ps.fx" + File "C:\program files\winamp\plugins\milkdrop2\data\comp_vs.fx" + File "C:\program files\winamp\plugins\milkdrop2\data\warp_ps.fx" + File "C:\program files\winamp\plugins\milkdrop2\data\warp_vs.fx" + File "C:\program files\winamp\plugins\milkdrop2\data\include.fx" + + SetOutPath $1\Milkdrop2\docs + File "C:\program files\winamp\plugins\milkdrop2\docs\milkdrop.html" + File "C:\program files\winamp\plugins\milkdrop2\docs\milkdrop_preset_authoring.html" + File "C:\program files\winamp\plugins\milkdrop2\docs\q_and_t_vars.gif" + + SetOutPath $1\Milkdrop2\textures + File "C:\program files\winamp\plugins\milkdrop2\textures\*.*" + + SetOutPath $1\Milkdrop2\presets + File "C:\program files\winamp\plugins\milkdrop2\presets\*.milk" + + hmmm + SetOutPath $1\MilkDrop2\presets\3d + File "C:\program files\winamp\plugins\milkdrop2\presets\3d\*.milk" + + hmmm + SetOutPath $1\MilkDrop2\presets\inverted + File "C:\program files\winamp\plugins\milkdrop2\presets\inverted\*.milk" + + ; ----------------------- END SECTION [2/3] ----------------------- + ; ----------------------- END SECTION [2/3] ----------------------- + ; ----------------------- END SECTION [2/3] ----------------------- + + + ; now time to create the Uninstaller: + + IfFileExists $INSTDIR\Winamp.exe UninstWinamp2 + IfFileExists $INSTDIR\Winamp3.exe UninstWinamp3 + IfFileExists $INSTDIR\Studio.exe UninstWinamp3 ; legacy check + goto UninstDone + + UninstWinamp3: + WriteRegStr HKLM SOFTWARE\${PLUGIN_DLL}Winamp3 "Install_Dir" "$INSTDIR" + WriteRegStr HKLM SOFTWARE\${PLUGIN_DLL}Winamp3 "Install_Plugins_Dir" $1 + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PLUGIN_DLL}Winamp3" "DisplayName" "${PLUGIN_NAME} for Winamp 3 (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PLUGIN_DLL}Winamp3" "UninstallString" '"$INSTDIR\uninst-${PLUGIN_DLL}.exe"' + WriteUninstaller "$INSTDIR\uninst-${PLUGIN_DLL}.exe" + CreateDirectory "$SMPROGRAMS\Winamp3\Vis Plugin Uninstallers" + CreateShortCut "$SMPROGRAMS\Winamp3\Vis Plugin Uninstallers\Uninstall ${PLUGIN_NAME}.lnk" "$INSTDIR\uninst-${PLUGIN_DLL}.exe" "" "$INSTDIR\uninst-${PLUGIN_DLL}.exe" 0 + goto UninstDone + + UninstWinamp2: + WriteRegStr HKLM SOFTWARE\${PLUGIN_DLL}Winamp "Install_Dir" "$INSTDIR" + WriteRegStr HKLM SOFTWARE\${PLUGIN_DLL}Winamp "Install_Plugins_Dir" $1 + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PLUGIN_DLL}Winamp" "DisplayName" "${PLUGIN_NAME} for Winamp 2x (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PLUGIN_DLL}Winamp" "UninstallString" '"$INSTDIR\uninst-${PLUGIN_DLL}.exe"' + WriteUninstaller "$INSTDIR\uninst-${PLUGIN_DLL}.exe" + CreateDirectory "$SMPROGRAMS\Winamp\Vis Plugin Uninstallers" + CreateShortCut "$SMPROGRAMS\Winamp\Vis Plugin Uninstallers\Uninstall ${PLUGIN_NAME}.lnk" "$INSTDIR\uninst-${PLUGIN_DLL}.exe" "" "$INSTDIR\uninst-${PLUGIN_DLL}.exe" 0 + goto UninstDone + + UninstDone: + +SectionEnd + +;---------------------------------------------------------------------- + +UninstallText "This will uninstall the ${PLUGIN_NAME} plugin. Hit next to continue." +ShowUninstDetails Show + +Section "Uninstall" + + ; This section is the code that will be run when the user goes + ; to Uninstall the plugin. + + IfFileExists $INSTDIR\Winamp.exe UninstStep1Winamp2 + IfFileExists $INSTDIR\Winamp3.exe UninstStep1Winamp3 + IfFileExists $INSTDIR\Studio.exe UninstStep1Winamp3 ; legacy check + goto UninstScriptDone + + UninstStep1Winamp3: + ReadRegStr $1 HKLM SOFTWARE\${PLUGIN_DLL}Winamp3 "Install_Plugins_Dir" + goto UninstStep2 + UninstStep1Winamp2: + ReadRegStr $1 HKLM SOFTWARE\${PLUGIN_DLL}Winamp "Install_Plugins_Dir" + goto UninstStep2 + + UninstStep2: + + ; -------------------- EDIT THIS SECTION [3/3] -------------------- + ; -------------------- EDIT THIS SECTION [3/3] -------------------- + ; -------------------- EDIT THIS SECTION [3/3] -------------------- + + ; LIST OF FILES TO DELETE WHEN USER RUNS THE UNINSTALL + + Delete "$1\${PLUGIN_DLL}" + ;Delete "$1\vms_desktop.dll" ** DO NOT DELETE! ** + Delete "$1\milkdrop.html" + Delete "$1\milkdrop_preset_authoring.html" + Delete "$1\q_and_t_vars.gif" + + MessageBox MB_YESNO|MB_ICONQUESTION \ + "Clear your saved settings?:$\r $1\milkdrop_config.ini$\r $1\milk_msg.ini$\r $1\milk_img.ini" \ + IDNO SaveSettings + + Delete "$1\milkdrop_config.ini" + Delete "$1\milk_msg.ini" + Delete "$1\milk_img.ini" + + SaveSettings: + + MessageBox MB_YESNO|MB_ICONQUESTION \ + "Delete all presets in these 3 directories?:$\r $1\milkdrop$\r $1\milkdrop\3d$\r $1\milkdrop\inverted" \ + IDNO SavePresets + + Delete "$1\milkdrop2\inverted\*.milk" + Delete "$1\milkdrop2\3d\*.milk" + Delete "$1\milkdrop2\*.milk" + RMDir "$1\milkdrop2\inverted" + RMDir "$1\milkdrop2\3d" + RMDir "$1\milkdrop2" + + SavePresets: + + ; ----------------------- END SECTION [3/3] ----------------------- + ; ----------------------- END SECTION [3/3] ----------------------- + ; ----------------------- END SECTION [3/3] ----------------------- + + IfFileExists $INSTDIR\Winamp.exe UninstStep3Winamp2 + IfFileExists $INSTDIR\Winamp3.exe UninstStep3Winamp3 + IfFileExists $INSTDIR\Studio.exe UninstStep3Winamp3 ; legacy check + goto UninstScriptDone + + UninstStep3Winamp3: + DeleteRegKey HKLM SOFTWARE\${PLUGIN_DLL}Winamp3 + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PLUGIN_DLL}Winamp3" + Delete $INSTDIR\uninst-${PLUGIN_DLL}.exe + Delete "$SMPROGRAMS\Winamp3\Vis Plugin Uninstallers\Uninstall ${PLUGIN_NAME}.lnk" + RMDir "$SMPROGRAMS\Winamp3\Vis Plugin Uninstallers" + goto UninstScriptDone + UninstStep3Winamp2: + DeleteRegKey HKLM SOFTWARE\${PLUGIN_DLL}Winamp + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PLUGIN_DLL}Winamp" + Delete $INSTDIR\uninst-${PLUGIN_DLL}.exe + Delete "$SMPROGRAMS\Winamp\Vis Plugin Uninstallers\Uninstall ${PLUGIN_NAME}.lnk" + RMDir "$SMPROGRAMS\Winamp\Vis Plugin Uninstallers" + goto UninstScriptDone + + UninstScriptDone: +SectionEnd + +;---------------------------------------------------------------------- + +Function .onInstSuccess + IfFileExists $INSTDIR\Winamp.exe CaseWinamp2 + IfFileExists $INSTDIR\Winamp3.exe CaseWinamp3 + IfFileExists $INSTDIR\Studio.exe CaseWinamp3 ; legacy check + goto CaseImpossible + + CaseWinamp3: + IfFileExists $INSTDIR\wacs\classicvis.wac ClassicVisOk + ; no classicvis -> give them instructions + MessageBox MB_YESNO|MB_ICONEXCLAMATION \ + "IMPORTANT: You must download and install the Classic Visualization$\rComponent before ${PLUGIN_NAME} will work with Winamp 3.$\r$\rWould you like to download it now?" \ + IDNO FailNoClassicVis + ExecShell "open" "http://www.winamp.com/components3/detail.jhtml?componentId=122130" + MessageBox MB_OK|MB_ICONINFORMATION \ + "Your web browser will now open and allow you to download$\rthe Classic Visualization Component. Please download$\rand install it.$\r$\rOnce it is installed, open Winamp 3 and hit CTRL+P$\rto open the Preferences screen. Then, on the left,$\rscroll to 'Classic Visualizations' and select it. From there,$\ryou can easily select, configure and run any plugins$\rinstalled to Winamp 2 or 3." + goto end + FailNoClassicVis: + MessageBox MB_OK|MB_ICONSTOP "Installation failed." + goto end + ClassicVisOk: + FindWindow $R0 "STUDIO" + StrCmp $R0 0 "" DoneWinamp3 + MessageBox MB_YESNO|MB_ICONQUESTION \ + "${PLUGIN_NAME} was installed successfully.$\rWould you like to run Winamp 3 now?" \ + IDNO DoneWinamp3 + ; to do here: update 'oldvisname' string in the *xml* file winamp3\studio.xnf, + ; and set 'oldvisidx' to "0" + IfFileExists $INSTDIR\Winamp3.exe CaseWinamp3b + Exec '"$INSTDIR\studio.exe"' + goto DoneWinamp3 + CaseWinamp3b: + Exec '"$INSTDIR\winamp3.exe"' + goto DoneWinamp3 + DoneWinamp3: + MessageBox MB_OK "While in Winamp 3, press CTRL+P to bring up the$\rPreferences screen, then scroll down and select$\rthe 'Classic Visualizations' option. From there,$\ryou can select, configure, and run the ${PLUGIN_NAME} plugin." + goto end + + CaseWinamp2: + ; note: winamp 2 should already be closed at this point. + WriteINIStr "$INSTDIR\Winamp.ini" "Winamp" "visplugin_name" ${PLUGIN_DLL} + WriteINIStr "$INSTDIR\Winamp.ini" "Winamp" "visplugin_num" "0" + MessageBox MB_YESNO|MB_ICONQUESTION \ + "${PLUGIN_NAME} was installed successfully.$\r$\rWhile in Winamp, press ALT+K to configure it (optional);$\rpress CTRL+SHIFT+K to execute it.$\r$\rWould you like to run Winamp now?" \ + IDNO end + Exec '"$INSTDIR\Winamp.exe"' + Goto end + + CaseImpossible: + MessageBox MB_OK|MB_ICONEXCLAMATION "ERROR: unable to find winamp.exe (winamp2) or studio.exe/winamp3.exe (winamp3) in the install directory..." + Goto end + + End: +FunctionEnd + +; eof + diff --git a/vis_milk2/milkdrop_DX9.sln b/vis_milk2/milkdrop_DX9.sln new file mode 100644 index 0000000..24028fd --- /dev/null +++ b/vis_milk2/milkdrop_DX9.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vis_milk2", "plugin.vcproj", "{881FB534-7396-485A-ADC2-6FBEBED7A0F4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {881FB534-7396-485A-ADC2-6FBEBED7A0F4}.Debug|Win32.ActiveCfg = Debug|Win32 + {881FB534-7396-485A-ADC2-6FBEBED7A0F4}.Debug|Win32.Build.0 = Debug|Win32 + {881FB534-7396-485A-ADC2-6FBEBED7A0F4}.Release|Win32.ActiveCfg = Release|Win32 + {881FB534-7396-485A-ADC2-6FBEBED7A0F4}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/vis_milk2/milkdropfs.cpp b/vis_milk2/milkdropfs.cpp new file mode 100644 index 0000000..820188e --- /dev/null +++ b/vis_milk2/milkdropfs.cpp @@ -0,0 +1,4796 @@ +/* + 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. +*/ + +#include "api.h" +#include "plugin.h" +#include "resource.h" +#include "support.h" +//#include "evallib\eval.h" // for math. expr. eval - thanks Francis! (in SourceOffSite, it's the 'vis_avs\evallib' project.) +//#include "evallib\compiler.h" +#include "../ns-eel2/ns-eel.h" +#include "utility.h" +#include +#include + +#define D3DCOLOR_RGBA_01(r,g,b,a) D3DCOLOR_RGBA(((int)(r*255)),((int)(g*255)),((int)(b*255)),((int)(a*255))) +#define FRAND ((warand() % 7381)/7380.0f) + +#define VERT_CLIP 0.75f // warning: top/bottom can get clipped if you go < 0.65! + +int g_title_font_sizes[] = +{ + // NOTE: DO NOT EXCEED 64 FONTS HERE. + 6, 8, 10, 12, 14, 16, + 20, 26, 32, 38, 44, 50, 56, + 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, + 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, + 480, 512 /**/ +}; + +//#define COMPILE_MULTIMON_STUBS 1 +//#include + +// This function evaluates whether the floating-point +// control Word is set to single precision/round to nearest/ +// exceptions disabled. If not, the +// function changes the control Word to set them and returns +// TRUE, putting the old control Word value in the passback +// location pointed to by pwOldCW. +static void MungeFPCW( WORD *pwOldCW ) +{ +#if 0 + BOOL ret = FALSE; + WORD wTemp, wSave; + + __asm fstcw wSave + if (wSave & 0x300 || // Not single mode + 0x3f != (wSave & 0x3f) || // Exceptions enabled + wSave & 0xC00) // Not round to nearest mode + { + __asm + { + mov ax, wSave + and ax, not 300h ;; single mode + or ax, 3fh ;; disable all exceptions + and ax, not 0xC00 ;; round to nearest mode + mov wTemp, ax + fldcw wTemp + } + ret = TRUE; + } + if (pwOldCW) *pwOldCW = wSave; + // return ret; +#else + _controlfp(_PC_24, _MCW_PC); // single precision + _controlfp(_RC_NEAR, _MCW_RC); // round to nearest mode + _controlfp(_EM_ZERODIVIDE, _EM_ZERODIVIDE); // disable divide-by-zero +#endif +} + +void RestoreFPCW(WORD wSave) +{ + __asm fldcw wSave +} + +int GetNumToSpawn(float fTime, float fDeltaT, float fRate, float fRegularity, int iNumSpawnedSoFar) +{ + // PARAMETERS + // ------------ + // fTime: sum of all fDeltaT's so far (excluding this one) + // fDeltaT: time window for this frame + // fRate: avg. rate (spawns per second) of generation + // fRegularity: regularity of generation + // 0.0: totally chaotic + // 0.2: getting chaotic / very jittered + // 0.4: nicely jittered + // 0.6: slightly jittered + // 0.8: almost perfectly regular + // 1.0: perfectly regular + // iNumSpawnedSoFar: the total number of spawnings so far + // + // RETURN VALUE + // ------------ + // The number to spawn for this frame (add this to your net count!). + // + // COMMENTS + // ------------ + // The spawn values returned will, over time, match + // (within 1%) the theoretical totals expected based on the + // amount of time passed and the average generation rate. + // + // UNRESOLVED ISSUES + // ----------------- + // actual results of mixed gen. (0 < reg < 1) are about 1% too low + // in the long run (vs. analytical expectations). Decided not + // to bother fixing it since it's only 1% (and VERY consistent). + + float fNumToSpawnReg; + float fNumToSpawnIrreg; + float fNumToSpawn; + + // compute # spawned based on regular generation + fNumToSpawnReg = ((fTime + fDeltaT) * fRate) - iNumSpawnedSoFar; + + // compute # spawned based on irregular (random) generation + if (fDeltaT <= 1.0f / fRate) + { + // case 1: avg. less than 1 spawn per frame + if ((warand() % 16384)/16384.0f < fDeltaT * fRate) + fNumToSpawnIrreg = 1.0f; + else + fNumToSpawnIrreg = 0.0f; + } + else + { + // case 2: avg. more than 1 spawn per frame + fNumToSpawnIrreg = fDeltaT * fRate; + fNumToSpawnIrreg *= 2.0f*(warand() % 16384)/16384.0f; + } + + // get linear combo. of regular & irregular + fNumToSpawn = fNumToSpawnReg*fRegularity + fNumToSpawnIrreg*(1.0f - fRegularity); + + // round to nearest integer for result + return (int)(fNumToSpawn + 0.49f); +} + +bool CPlugin::OnResizeTextWindow() +{ + /* + if (!m_hTextWnd) + return false; + + RECT rect; + GetClientRect(m_hTextWnd, &rect); + + if (rect.right - rect.left != m_nTextWndWidth || + rect.bottom - rect.top != m_nTextWndHeight) + { + m_nTextWndWidth = rect.right - rect.left; + m_nTextWndHeight = rect.bottom - rect.top; + + // first, resize fonts if necessary + //if (!InitFont()) + //return false; + + // then resize the memory bitmap used for double buffering + if (m_memDC) + { + SelectObject(m_memDC, m_oldBM); // delete our doublebuffer + DeleteObject(m_memDC); + DeleteObject(m_memBM); + m_memDC = NULL; + m_memBM = NULL; + m_oldBM = NULL; + } + + HDC hdc = GetDC(m_hTextWnd); + if (!hdc) return false; + + m_memDC = CreateCompatibleDC(hdc); + m_memBM = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top); + m_oldBM = (HBITMAP)SelectObject(m_memDC,m_memBM); + + ReleaseDC(m_hTextWnd, hdc); + + // save new window pos + WriteRealtimeConfig(); + }*/ + + return true; +} + + +void CPlugin::ClearGraphicsWindow() +{ + // clear the window contents, to avoid a 1-pixel-thick border of noise that sometimes sticks around + /* + RECT rect; + GetClientRect(GetPluginWindow(), &rect); + + HDC hdc = GetDC(GetPluginWindow()); + FillRect(hdc, &rect, m_hBlackBrush); + ReleaseDC(GetPluginWindow(), hdc); + */ +} + +/* +bool CPlugin::OnResizeGraphicsWindow() +{ + // NO LONGER NEEDED, SINCE PLUGIN SHELL CREATES A NEW DIRECTX + // OBJECT WHENEVER WINDOW IS RESIZED. +} +*/ + +bool CPlugin::RenderStringToTitleTexture() // m_szSongMessage +{ + if (!m_lpDDSTitle) // this *can* be NULL, if not much video mem! + return false; + + if (m_supertext.szTextW[0]==0) + return false; + + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return false; + + wchar_t szTextToDraw[512]; + swprintf(szTextToDraw, L" %s ", m_supertext.szTextW); //add a space @ end for italicized fonts; and at start, too, because it's centered! + + // Remember the original backbuffer and zbuffer + LPDIRECT3DSURFACE9 pBackBuffer=NULL;//, pZBuffer=NULL; + lpDevice->GetRenderTarget( 0, &pBackBuffer ); + //lpDevice->GetDepthStencilSurface( &pZBuffer ); + + // set render target to m_lpDDSTitle + { + lpDevice->SetTexture(0, NULL); + + IDirect3DSurface9* pNewTarget = NULL; + if (m_lpDDSTitle->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) + { + SafeRelease(pBackBuffer); + //SafeRelease(pZBuffer); + return false; + } + lpDevice->SetRenderTarget(0, pNewTarget); + //lpDevice->SetDepthStencilSurface( NULL ); + pNewTarget->Release(); + + lpDevice->SetTexture(0, NULL); + } + + // clear the texture to black + { + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( WFVERTEX_FORMAT ); + lpDevice->SetTexture(0, NULL); + + lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); + + // set up a quad + WFVERTEX verts[4]; + for (int i=0; i<4; i++) + { + verts[i].x = (i%2==0) ? -1.f : 1.f; + verts[i].y = (i/2==0) ? -1.f : 1.f; + verts[i].z = 0; + verts[i].Diffuse = 0xFF000000; + } + + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(WFVERTEX)); + } + + /*// 1. clip title if too many chars + if (m_supertext.bIsSongTitle) + { + // truncate song title if too long; don't clip custom messages, though! + int clip_chars = 32; + int user_title_size = GetFontHeight(SONGTITLE_FONT); + + #define MIN_CHARS 8 // max clip_chars *for BIG FONTS* + #define MAX_CHARS 64 // max clip chars *for tiny fonts* + float t = (user_title_size-10)/(float)(128-10); + t = min(1,max(0,t)); + clip_chars = (int)(MAX_CHARS - (MAX_CHARS-MIN_CHARS)*t); + + if ((int)strlen(szTextToDraw) > clip_chars+3) + lstrcpy(&szTextToDraw[clip_chars], "..."); + }*/ + + bool ret = true; + + // use 2 lines; must leave room for bottom of 'g' characters and such! + RECT rect; + rect.left = 0; + rect.right = m_nTitleTexSizeX; + rect.top = m_nTitleTexSizeY* 1/21; // otherwise, top of '%' could be cut off (1/21 seems safe) + rect.bottom = m_nTitleTexSizeY*17/21; // otherwise, bottom of 'g' could be cut off (18/21 seems safe, but we want some leeway) + + if (!m_supertext.bIsSongTitle) + { + // custom msg -> pick font to use that will best fill the texture + + HFONT gdi_font = NULL; + LPD3DXFONT d3dx_font = NULL; + + int lo = 0; + int hi = sizeof(g_title_font_sizes)/sizeof(int) - 1; + + // limit the size of the font used: + + //int user_title_size = GetFontHeight(SONGTITLE_FONT); + //while (g_title_font_sizes[hi] > user_title_size*2 && hi>4) + // hi--; + + RECT temp; + while (1)//(lo < hi-1) + { + int mid = (lo+hi)/2; + + // create new gdi font at 'mid' size: + gdi_font = CreateFontW( g_title_font_sizes[mid], 0, 0, 0, m_supertext.bBold ? 900 : 400, m_supertext.bItal, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + m_fontinfo[SONGTITLE_FONT].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY, + DEFAULT_PITCH, m_supertext.nFontFace ); + if (gdi_font) + { + // create new d3dx font at 'mid' size: + if (pCreateFontW( + lpDevice, + g_title_font_sizes[mid], + 0, + m_supertext.bBold ? 900 : 400, + 1, + m_supertext.bItal, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + ANTIALIASED_QUALITY,//m_fontinfo[SONGTITLE_FONT].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY, + DEFAULT_PITCH, + m_supertext.nFontFace, + &d3dx_font + ) == D3D_OK) + { + if (lo == hi-1) + break; // DONE; but the 'lo'-size font is ready for use! + + // compute size of text if drawn w/font of THIS size: + temp = rect; + int h = d3dx_font->DrawTextW(NULL, szTextToDraw, -1, &temp, DT_SINGLELINE | DT_CALCRECT /*| DT_NOPREFIX*/, 0xFFFFFFFF); + + // adjust & prepare to reiterate: + if (temp.right >= rect.right || h > rect.bottom-rect.top) + hi = mid; + else + lo = mid; + + SafeRelease(d3dx_font); + } + + DeleteObject(gdi_font); gdi_font=NULL; + } + } + + if (gdi_font && d3dx_font) + { + // do actual drawing + set m_supertext.nFontSizeUsed; use 'lo' size + int h = d3dx_font->DrawTextW(NULL, szTextToDraw, -1, &temp, DT_SINGLELINE | DT_CALCRECT /*| DT_NOPREFIX*/ | DT_CENTER, 0xFFFFFFFF); + temp.left = 0; + temp.right = m_nTitleTexSizeX; // now allow text to go all the way over, since we're actually drawing! + temp.top = m_nTitleTexSizeY/2 - h/2; + temp.bottom = m_nTitleTexSizeY/2 + h/2; + m_supertext.nFontSizeUsed = d3dx_font->DrawTextW(NULL, szTextToDraw, -1, &temp, DT_SINGLELINE /*| DT_NOPREFIX*/ | DT_CENTER, 0xFFFFFFFF); + + ret = true; + } + else + { + ret = false; + } + + // clean up font: + SafeRelease(d3dx_font); + if (gdi_font) DeleteObject(gdi_font); gdi_font=NULL; + } + else // song title + { + wchar_t* str = m_supertext.szTextW; + + // clip the text manually... + // NOTE: DT_END_ELLIPSIS CAUSES NOTHING TO DRAW, IF YOU USE W/D3DX9! + int h; + int max_its = 6; + int it = 0; + while (it < max_its) + { + it++; + + if (!str[0]) + break; + + RECT temp = rect; + h = m_d3dx_title_font_doublesize->DrawTextW(NULL, str, -1, &temp, DT_SINGLELINE | DT_CALCRECT /*| DT_NOPREFIX | DT_END_ELLIPSIS*/, 0xFFFFFFFF); + if (temp.right-temp.left <= m_nTitleTexSizeX) + break; + + // 11/01/2009 DO - disabled as it was causing to users 'random' titles against + // what is expected so we now just work on the ellipse at the end approach which + + // manually clip the text... chop segments off the front + /*wchar_t* p = wcsstr(str, L" - "); + if (p) + { + str = p+3; + continue; + }*/ + + // no more stuff to chop off the front; chop off the end w/ ... + int len = wcslen(str); + float fPercentToKeep = 0.91f * m_nTitleTexSizeX / (float)(temp.right-temp.left); + if (len > 8) + lstrcpyW( &str[ (int)(len*fPercentToKeep) ], L"..."); + break; + } + + // now actually draw it + RECT temp; + temp.left = 0; + temp.right = m_nTitleTexSizeX; // now allow text to go all the way over, since we're actually drawing! + temp.top = m_nTitleTexSizeY/2 - h/2; + temp.bottom = m_nTitleTexSizeY/2 + h/2; + + // NOTE: DT_END_ELLIPSIS CAUSES NOTHING TO DRAW, IF YOU USE W/D3DX9! + m_supertext.nFontSizeUsed = m_d3dx_title_font_doublesize->DrawTextW(NULL, str, -1, &temp, DT_SINGLELINE /*| DT_NOPREFIX | DT_END_ELLIPSIS*/ | DT_CENTER , 0xFFFFFFFF); + } + + // Change the rendertarget back to the original setup + lpDevice->SetTexture(0, NULL); + lpDevice->SetRenderTarget( 0, pBackBuffer ); + //lpDevice->SetDepthStencilSurface( pZBuffer ); + SafeRelease(pBackBuffer); + //SafeRelease(pZBuffer); + + return ret; +} + +void CPlugin::LoadPerFrameEvallibVars(CState* pState) +{ + // load the 'var_pf_*' variables in this CState object with the correct values. + // for vars that affect pixel motion, that means evaluating them at time==-1, + // (i.e. no blending w/blendto value); the blending of the file dx/dy + // will be done *after* execution of the per-vertex code. + // for vars that do NOT affect pixel motion, evaluate them at the current time, + // so that if they're blending, both states see the blended value. + + // 1. vars that affect pixel motion: (eval at time==-1) + *pState->var_pf_zoom = (double)pState->m_fZoom.eval(-1);//GetTime()); + *pState->var_pf_zoomexp = (double)pState->m_fZoomExponent.eval(-1);//GetTime()); + *pState->var_pf_rot = (double)pState->m_fRot.eval(-1);//GetTime()); + *pState->var_pf_warp = (double)pState->m_fWarpAmount.eval(-1);//GetTime()); + *pState->var_pf_cx = (double)pState->m_fRotCX.eval(-1);//GetTime()); + *pState->var_pf_cy = (double)pState->m_fRotCY.eval(-1);//GetTime()); + *pState->var_pf_dx = (double)pState->m_fXPush.eval(-1);//GetTime()); + *pState->var_pf_dy = (double)pState->m_fYPush.eval(-1);//GetTime()); + *pState->var_pf_sx = (double)pState->m_fStretchX.eval(-1);//GetTime()); + *pState->var_pf_sy = (double)pState->m_fStretchY.eval(-1);//GetTime()); + // read-only: + *pState->var_pf_time = (double)(GetTime() - m_fStartTime); + *pState->var_pf_fps = (double)GetFps(); + *pState->var_pf_bass = (double)mysound.imm_rel[0]; + *pState->var_pf_mid = (double)mysound.imm_rel[1]; + *pState->var_pf_treb = (double)mysound.imm_rel[2]; + *pState->var_pf_bass_att = (double)mysound.avg_rel[0]; + *pState->var_pf_mid_att = (double)mysound.avg_rel[1]; + *pState->var_pf_treb_att = (double)mysound.avg_rel[2]; + *pState->var_pf_frame = (double)GetFrame(); + //*pState->var_pf_monitor = 0; -leave this as it was set in the per-frame INIT code! + for (int vi=0; vivar_pf_q[vi] = pState->q_values_after_init_code[vi];//0.0f; + *pState->var_pf_monitor = pState->monitor_after_init_code; + *pState->var_pf_progress = (GetTime() - m_fPresetStartTime) / (m_fNextPresetTime - m_fPresetStartTime); + + // 2. vars that do NOT affect pixel motion: (eval at time==now) + *pState->var_pf_decay = (double)pState->m_fDecay.eval(GetTime()); + *pState->var_pf_wave_a = (double)pState->m_fWaveAlpha.eval(GetTime()); + *pState->var_pf_wave_r = (double)pState->m_fWaveR.eval(GetTime()); + *pState->var_pf_wave_g = (double)pState->m_fWaveG.eval(GetTime()); + *pState->var_pf_wave_b = (double)pState->m_fWaveB.eval(GetTime()); + *pState->var_pf_wave_x = (double)pState->m_fWaveX.eval(GetTime()); + *pState->var_pf_wave_y = (double)pState->m_fWaveY.eval(GetTime()); + *pState->var_pf_wave_mystery= (double)pState->m_fWaveParam.eval(GetTime()); + *pState->var_pf_wave_mode = (double)pState->m_nWaveMode; //?!?! -why won't it work if set to pState->m_nWaveMode??? + *pState->var_pf_ob_size = (double)pState->m_fOuterBorderSize.eval(GetTime()); + *pState->var_pf_ob_r = (double)pState->m_fOuterBorderR.eval(GetTime()); + *pState->var_pf_ob_g = (double)pState->m_fOuterBorderG.eval(GetTime()); + *pState->var_pf_ob_b = (double)pState->m_fOuterBorderB.eval(GetTime()); + *pState->var_pf_ob_a = (double)pState->m_fOuterBorderA.eval(GetTime()); + *pState->var_pf_ib_size = (double)pState->m_fInnerBorderSize.eval(GetTime()); + *pState->var_pf_ib_r = (double)pState->m_fInnerBorderR.eval(GetTime()); + *pState->var_pf_ib_g = (double)pState->m_fInnerBorderG.eval(GetTime()); + *pState->var_pf_ib_b = (double)pState->m_fInnerBorderB.eval(GetTime()); + *pState->var_pf_ib_a = (double)pState->m_fInnerBorderA.eval(GetTime()); + *pState->var_pf_mv_x = (double)pState->m_fMvX.eval(GetTime()); + *pState->var_pf_mv_y = (double)pState->m_fMvY.eval(GetTime()); + *pState->var_pf_mv_dx = (double)pState->m_fMvDX.eval(GetTime()); + *pState->var_pf_mv_dy = (double)pState->m_fMvDY.eval(GetTime()); + *pState->var_pf_mv_l = (double)pState->m_fMvL.eval(GetTime()); + *pState->var_pf_mv_r = (double)pState->m_fMvR.eval(GetTime()); + *pState->var_pf_mv_g = (double)pState->m_fMvG.eval(GetTime()); + *pState->var_pf_mv_b = (double)pState->m_fMvB.eval(GetTime()); + *pState->var_pf_mv_a = (double)pState->m_fMvA.eval(GetTime()); + *pState->var_pf_echo_zoom = (double)pState->m_fVideoEchoZoom.eval(GetTime()); + *pState->var_pf_echo_alpha = (double)pState->m_fVideoEchoAlpha.eval(GetTime()); + *pState->var_pf_echo_orient = (double)pState->m_nVideoEchoOrientation; + // new in v1.04: + *pState->var_pf_wave_usedots = (double)pState->m_bWaveDots; + *pState->var_pf_wave_thick = (double)pState->m_bWaveThick; + *pState->var_pf_wave_additive = (double)pState->m_bAdditiveWaves; + *pState->var_pf_wave_brighten = (double)pState->m_bMaximizeWaveColor; + *pState->var_pf_darken_center = (double)pState->m_bDarkenCenter; + *pState->var_pf_gamma = (double)pState->m_fGammaAdj.eval(GetTime()); + *pState->var_pf_wrap = (double)pState->m_bTexWrap; + *pState->var_pf_invert = (double)pState->m_bInvert; + *pState->var_pf_brighten = (double)pState->m_bBrighten; + *pState->var_pf_darken = (double)pState->m_bDarken; + *pState->var_pf_solarize = (double)pState->m_bSolarize; + *pState->var_pf_meshx = (double)m_nGridX; + *pState->var_pf_meshy = (double)m_nGridY; + *pState->var_pf_pixelsx = (double)GetWidth(); + *pState->var_pf_pixelsy = (double)GetHeight(); + *pState->var_pf_aspectx = (double)m_fInvAspectX; + *pState->var_pf_aspecty = (double)m_fInvAspectY; + // new in v2.0: + *pState->var_pf_blur1min = (double)pState->m_fBlur1Min.eval(GetTime()); + *pState->var_pf_blur2min = (double)pState->m_fBlur2Min.eval(GetTime()); + *pState->var_pf_blur3min = (double)pState->m_fBlur3Min.eval(GetTime()); + *pState->var_pf_blur1max = (double)pState->m_fBlur1Max.eval(GetTime()); + *pState->var_pf_blur2max = (double)pState->m_fBlur2Max.eval(GetTime()); + *pState->var_pf_blur3max = (double)pState->m_fBlur3Max.eval(GetTime()); + *pState->var_pf_blur1_edge_darken = (double)pState->m_fBlur1EdgeDarken.eval(GetTime()); +} + +void CPlugin::RunPerFrameEquations(int code) +{ + // run per-frame calculations + + /* + code is only valid when blending. + OLDcomp ~ blend-from preset has a composite shader; + NEWwarp ~ blend-to preset has a warp shader; etc. + + code OLDcomp NEWcomp OLDwarp NEWwarp + 0 + 1 1 + 2 1 + 3 1 1 + 4 1 + 5 1 1 + 6 1 1 + 7 1 1 1 + 8 1 + 9 1 1 + 10 1 1 + 11 1 1 1 + 12 1 1 + 13 1 1 1 + 14 1 1 1 + 15 1 1 1 1 + */ + + // when blending booleans (like darken, invert, etc) for pre-shader presets, + // if blending to/from a pixel-shader preset, we can tune the snap point + // (when it changes during the blend) for a less jumpy transition: + m_fSnapPoint = 0.5f; + if (m_pState->m_bBlending) + { + switch(code) + { + case 4: + case 6: + case 12: + case 14: + // old preset (only) had a comp shader + m_fSnapPoint = -0.01f; + break; + case 1: + case 3: + case 9: + case 11: + // new preset (only) has a comp shader + m_fSnapPoint = 1.01f; + break; + case 0: + case 2: + case 8: + case 10: + // neither old or new preset had a comp shader + m_fSnapPoint = 0.5f; + break; + case 5: + case 7: + case 13: + case 15: + // both old and new presets use a comp shader - so it won't matter + m_fSnapPoint = 0.5f; + break; + } + } + + int num_reps = (m_pState->m_bBlending) ? 2 : 1; + for (int rep=0; repvar_pv_time = *pState->var_pf_time; + *pState->var_pv_fps = *pState->var_pf_fps; + *pState->var_pv_frame = *pState->var_pf_frame; + *pState->var_pv_progress = *pState->var_pf_progress; + *pState->var_pv_bass = *pState->var_pf_bass; + *pState->var_pv_mid = *pState->var_pf_mid; + *pState->var_pv_treb = *pState->var_pf_treb; + *pState->var_pv_bass_att = *pState->var_pf_bass_att; + *pState->var_pv_mid_att = *pState->var_pf_mid_att; + *pState->var_pv_treb_att = *pState->var_pf_treb_att; + *pState->var_pv_meshx = (double)m_nGridX; + *pState->var_pv_meshy = (double)m_nGridY; + *pState->var_pv_pixelsx = (double)GetWidth(); + *pState->var_pv_pixelsy = (double)GetHeight(); + *pState->var_pv_aspectx = (double)m_fInvAspectX; + *pState->var_pv_aspecty = (double)m_fInvAspectY; + //*pState->var_pv_monitor = *pState->var_pf_monitor; + + // execute once-per-frame expressions: +#ifndef _NO_EXPR_ + if (pState->m_pf_codehandle) + { + if (pState->m_pf_codehandle) + { + NSEEL_code_execute(pState->m_pf_codehandle); + } + } +#endif + + // save some things for next frame: + pState->monitor_after_init_code = *pState->var_pf_monitor; + + // save some things for per-vertex code: + for (int vi=0; vivar_pv_q[vi] = *pState->var_pf_q[vi]; + + // (a few range checks:) + *pState->var_pf_gamma = max(0 , min( 8, *pState->var_pf_gamma )); + *pState->var_pf_echo_zoom = max(0.001, min( 1000, *pState->var_pf_echo_zoom)); + + /* + if (m_pState->m_bRedBlueStereo || m_bAlways3D) + { + // override wave colors + *pState->var_pf_wave_r = 0.35f*(*pState->var_pf_wave_r) + 0.65f; + *pState->var_pf_wave_g = 0.35f*(*pState->var_pf_wave_g) + 0.65f; + *pState->var_pf_wave_b = 0.35f*(*pState->var_pf_wave_b) + 0.65f; + } + */ + } + + if (m_pState->m_bBlending) + { + // For all variables that do NOT affect pixel motion, blend them NOW, + // so later the user can just access m_pState->m_pf_whatever. + double mix = (double)CosineInterp(m_pState->m_fBlendProgress); + double mix2 = 1.0 - mix; + *m_pState->var_pf_decay = mix*(*m_pState->var_pf_decay ) + mix2*(*m_pOldState->var_pf_decay ); + *m_pState->var_pf_wave_a = mix*(*m_pState->var_pf_wave_a ) + mix2*(*m_pOldState->var_pf_wave_a ); + *m_pState->var_pf_wave_r = mix*(*m_pState->var_pf_wave_r ) + mix2*(*m_pOldState->var_pf_wave_r ); + *m_pState->var_pf_wave_g = mix*(*m_pState->var_pf_wave_g ) + mix2*(*m_pOldState->var_pf_wave_g ); + *m_pState->var_pf_wave_b = mix*(*m_pState->var_pf_wave_b ) + mix2*(*m_pOldState->var_pf_wave_b ); + *m_pState->var_pf_wave_x = mix*(*m_pState->var_pf_wave_x ) + mix2*(*m_pOldState->var_pf_wave_x ); + *m_pState->var_pf_wave_y = mix*(*m_pState->var_pf_wave_y ) + mix2*(*m_pOldState->var_pf_wave_y ); + *m_pState->var_pf_wave_mystery = mix*(*m_pState->var_pf_wave_mystery) + mix2*(*m_pOldState->var_pf_wave_mystery); + // wave_mode: exempt (integer) + *m_pState->var_pf_ob_size = mix*(*m_pState->var_pf_ob_size ) + mix2*(*m_pOldState->var_pf_ob_size ); + *m_pState->var_pf_ob_r = mix*(*m_pState->var_pf_ob_r ) + mix2*(*m_pOldState->var_pf_ob_r ); + *m_pState->var_pf_ob_g = mix*(*m_pState->var_pf_ob_g ) + mix2*(*m_pOldState->var_pf_ob_g ); + *m_pState->var_pf_ob_b = mix*(*m_pState->var_pf_ob_b ) + mix2*(*m_pOldState->var_pf_ob_b ); + *m_pState->var_pf_ob_a = mix*(*m_pState->var_pf_ob_a ) + mix2*(*m_pOldState->var_pf_ob_a ); + *m_pState->var_pf_ib_size = mix*(*m_pState->var_pf_ib_size ) + mix2*(*m_pOldState->var_pf_ib_size ); + *m_pState->var_pf_ib_r = mix*(*m_pState->var_pf_ib_r ) + mix2*(*m_pOldState->var_pf_ib_r ); + *m_pState->var_pf_ib_g = mix*(*m_pState->var_pf_ib_g ) + mix2*(*m_pOldState->var_pf_ib_g ); + *m_pState->var_pf_ib_b = mix*(*m_pState->var_pf_ib_b ) + mix2*(*m_pOldState->var_pf_ib_b ); + *m_pState->var_pf_ib_a = mix*(*m_pState->var_pf_ib_a ) + mix2*(*m_pOldState->var_pf_ib_a ); + *m_pState->var_pf_mv_x = mix*(*m_pState->var_pf_mv_x ) + mix2*(*m_pOldState->var_pf_mv_x ); + *m_pState->var_pf_mv_y = mix*(*m_pState->var_pf_mv_y ) + mix2*(*m_pOldState->var_pf_mv_y ); + *m_pState->var_pf_mv_dx = mix*(*m_pState->var_pf_mv_dx ) + mix2*(*m_pOldState->var_pf_mv_dx ); + *m_pState->var_pf_mv_dy = mix*(*m_pState->var_pf_mv_dy ) + mix2*(*m_pOldState->var_pf_mv_dy ); + *m_pState->var_pf_mv_l = mix*(*m_pState->var_pf_mv_l ) + mix2*(*m_pOldState->var_pf_mv_l ); + *m_pState->var_pf_mv_r = mix*(*m_pState->var_pf_mv_r ) + mix2*(*m_pOldState->var_pf_mv_r ); + *m_pState->var_pf_mv_g = mix*(*m_pState->var_pf_mv_g ) + mix2*(*m_pOldState->var_pf_mv_g ); + *m_pState->var_pf_mv_b = mix*(*m_pState->var_pf_mv_b ) + mix2*(*m_pOldState->var_pf_mv_b ); + *m_pState->var_pf_mv_a = mix*(*m_pState->var_pf_mv_a ) + mix2*(*m_pOldState->var_pf_mv_a ); + *m_pState->var_pf_echo_zoom = mix*(*m_pState->var_pf_echo_zoom ) + mix2*(*m_pOldState->var_pf_echo_zoom ); + *m_pState->var_pf_echo_alpha = mix*(*m_pState->var_pf_echo_alpha ) + mix2*(*m_pOldState->var_pf_echo_alpha ); + *m_pState->var_pf_echo_orient = (mix < m_fSnapPoint) ? *m_pOldState->var_pf_echo_orient : *m_pState->var_pf_echo_orient; + // added in v1.04: + *m_pState->var_pf_wave_usedots = (mix < m_fSnapPoint) ? *m_pOldState->var_pf_wave_usedots : *m_pState->var_pf_wave_usedots ; + *m_pState->var_pf_wave_thick = (mix < m_fSnapPoint) ? *m_pOldState->var_pf_wave_thick : *m_pState->var_pf_wave_thick ; + *m_pState->var_pf_wave_additive= (mix < m_fSnapPoint) ? *m_pOldState->var_pf_wave_additive : *m_pState->var_pf_wave_additive; + *m_pState->var_pf_wave_brighten= (mix < m_fSnapPoint) ? *m_pOldState->var_pf_wave_brighten : *m_pState->var_pf_wave_brighten; + *m_pState->var_pf_darken_center= (mix < m_fSnapPoint) ? *m_pOldState->var_pf_darken_center : *m_pState->var_pf_darken_center; + *m_pState->var_pf_gamma = mix*(*m_pState->var_pf_gamma ) + mix2*(*m_pOldState->var_pf_gamma ); + *m_pState->var_pf_wrap = (mix < m_fSnapPoint) ? *m_pOldState->var_pf_wrap : *m_pState->var_pf_wrap ; + *m_pState->var_pf_invert = (mix < m_fSnapPoint) ? *m_pOldState->var_pf_invert : *m_pState->var_pf_invert ; + *m_pState->var_pf_brighten = (mix < m_fSnapPoint) ? *m_pOldState->var_pf_brighten : *m_pState->var_pf_brighten ; + *m_pState->var_pf_darken = (mix < m_fSnapPoint) ? *m_pOldState->var_pf_darken : *m_pState->var_pf_darken ; + *m_pState->var_pf_solarize = (mix < m_fSnapPoint) ? *m_pOldState->var_pf_solarize : *m_pState->var_pf_solarize ; + // added in v2.0: + *m_pState->var_pf_blur1min = mix*(*m_pState->var_pf_blur1min ) + mix2*(*m_pOldState->var_pf_blur1min ); + *m_pState->var_pf_blur2min = mix*(*m_pState->var_pf_blur2min ) + mix2*(*m_pOldState->var_pf_blur2min ); + *m_pState->var_pf_blur3min = mix*(*m_pState->var_pf_blur3min ) + mix2*(*m_pOldState->var_pf_blur3min ); + *m_pState->var_pf_blur1max = mix*(*m_pState->var_pf_blur1max ) + mix2*(*m_pOldState->var_pf_blur1max ); + *m_pState->var_pf_blur2max = mix*(*m_pState->var_pf_blur2max ) + mix2*(*m_pOldState->var_pf_blur2max ); + *m_pState->var_pf_blur3max = mix*(*m_pState->var_pf_blur3max ) + mix2*(*m_pOldState->var_pf_blur3max ); + *m_pState->var_pf_blur1_edge_darken = mix*(*m_pState->var_pf_blur1_edge_darken) + mix2*(*m_pOldState->var_pf_blur1_edge_darken); + } +} + +void CPlugin::RenderFrame(int bRedraw) +{ + int i; + + float fDeltaT = 1.0f/GetFps(); + + if (bRedraw) + { + // pre-un-flip buffers, so we are redoing the same work as we did last frame... + IDirect3DTexture9* pTemp = m_lpVS[0]; + m_lpVS[0] = m_lpVS[1]; + m_lpVS[1] = pTemp; + } + + // update time + /* + float fDeltaT = (GetFrame()==0) ? 1.0f/30.0f : GetTime() - m_prev_time; + DWORD dwTime = GetTickCount(); + float fDeltaT = (dwTime - m_dwPrevTickCount)*0.001f; + if (GetFrame() > 64) + { + fDeltaT = (fDeltaT)*0.2f + 0.8f*(1.0f/m_fps); + if (fDeltaT > 2.0f/m_fps) + { + char buf[64]; + sprintf(buf, "fixing time gap of %5.3f seconds", fDeltaT); + dumpmsg(buf); + + fDeltaT = 1.0f/m_fps; + } + } + m_dwPrevTickCount = dwTime; + GetTime() += fDeltaT; + */ + + if (GetFrame()==0) + { + m_fStartTime = GetTime(); + m_fPresetStartTime = GetTime(); + } + + if (m_fNextPresetTime < 0) + { + float dt = m_fTimeBetweenPresetsRand * (warand()%1000)*0.001f; + m_fNextPresetTime = GetTime() + m_fBlendTimeAuto + m_fTimeBetweenPresets + dt; + } + + /* + if (m_bPresetLockedByUser || m_bPresetLockedByCode) + { + // if the user has the preset LOCKED, or if they're in the middle of + // saving it, then keep extending the time at which the auto-switch will occur + // (by the length of this frame). + + m_fPresetStartTime += fDeltaT; + m_fNextPresetTime += fDeltaT; + }*/ + + // update fps + /* + if (GetFrame() < 4) + { + m_fps = 0.0f; + } + else if (GetFrame() <= 64) + { + m_fps = GetFrame() / (float)(GetTime() - m_fTimeHistory[0]); + } + else + { + m_fps = 64.0f / (float)(GetTime() - m_fTimeHistory[m_nTimeHistoryPos]); + } + m_fTimeHistory[m_nTimeHistoryPos] = GetTime(); + m_nTimeHistoryPos = (m_nTimeHistoryPos + 1) % 64; + */ + + // limit fps, if necessary + /* + if (m_nFpsLimit > 0 && (GetFrame() % 64) == 0 && GetFrame() > 64) + { + float spf_now = 1.0f / m_fps; + float spf_desired = 1.0f / (float)m_nFpsLimit; + + float new_sleep = m_fFPSLimitSleep + (spf_desired - spf_now)*1000.0f; + + if (GetFrame() <= 128) + m_fFPSLimitSleep = new_sleep; + else + m_fFPSLimitSleep = m_fFPSLimitSleep*0.8f + 0.2f*new_sleep; + + if (m_fFPSLimitSleep < 0) m_fFPSLimitSleep = 0; + if (m_fFPSLimitSleep > 100) m_fFPSLimitSleep = 100; + + //sprintf(m_szUserMessage, "sleep=%f", m_fFPSLimitSleep); + //m_fShowUserMessageUntilThisTime = GetTime() + 3.0f; + } + + static float deficit; + if (GetFrame()==0) deficit = 0; + float ideal_sleep = (m_fFPSLimitSleep + deficit); + int actual_sleep = (int)ideal_sleep; + if (actual_sleep > 0) + Sleep(actual_sleep); + deficit = ideal_sleep - actual_sleep; + if (deficit < 0) deficit = 0; // just in case + if (deficit > 1) deficit = 1; // just in case + */ + + if (!bRedraw) + { + m_rand_frame = D3DXVECTOR4(FRAND, FRAND, FRAND, FRAND); + + // randomly change the preset, if it's time + if (m_fNextPresetTime < GetTime()) + { + if (m_nLoadingPreset==0) // don't start a load if one is already underway! + LoadRandomPreset(m_fBlendTimeAuto); + } + + // randomly spawn Song Title, if time + if (m_fTimeBetweenRandomSongTitles > 0 && + !m_supertext.bRedrawSuperText && + GetTime() >= m_supertext.fStartTime + m_supertext.fDuration + 1.0f/GetFps()) + { + int n = GetNumToSpawn(GetTime(), fDeltaT, 1.0f/m_fTimeBetweenRandomSongTitles, 0.5f, m_nSongTitlesSpawned); + if (n > 0) + { + LaunchSongTitleAnim(); + m_nSongTitlesSpawned += n; + } + } + + // randomly spawn Custom Message, if time + if (m_fTimeBetweenRandomCustomMsgs > 0 && + !m_supertext.bRedrawSuperText && + GetTime() >= m_supertext.fStartTime + m_supertext.fDuration + 1.0f/GetFps()) + { + int n = GetNumToSpawn(GetTime(), fDeltaT, 1.0f/m_fTimeBetweenRandomCustomMsgs, 0.5f, m_nCustMsgsSpawned); + if (n > 0) + { + LaunchCustomMessage(-1); + m_nCustMsgsSpawned += n; + } + } + + // update m_fBlendProgress; + if (m_pState->m_bBlending) + { + m_pState->m_fBlendProgress = (GetTime() - m_pState->m_fBlendStartTime) / m_pState->m_fBlendDuration; + if (m_pState->m_fBlendProgress > 1.0f) + { + m_pState->m_bBlending = false; + } + } + + // handle hard cuts here (just after new sound analysis) + static float m_fHardCutThresh; + if (GetFrame() == 0) + m_fHardCutThresh = m_fHardCutLoudnessThresh*2.0f; + if (GetFps() > 1.0f && !m_bHardCutsDisabled && !m_bPresetLockedByUser && !m_bPresetLockedByCode) + { + if (mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2] > m_fHardCutThresh*3.0f) + { + if (m_nLoadingPreset==0) // don't start a load if one is already underway! + LoadRandomPreset(0.0f); + m_fHardCutThresh *= 2.0f; + } + else + { + /* + float halflife_modified = m_fHardCutHalflife*0.5f; + //thresh = (thresh - 1.5f)*0.99f + 1.5f; + float k = -0.69315f / halflife_modified;*/ + float k = -1.3863f / (m_fHardCutHalflife*GetFps()); + //float single_frame_multiplier = powf(2.7183f, k / GetFps()); + float single_frame_multiplier = expf(k); + m_fHardCutThresh = (m_fHardCutThresh - m_fHardCutLoudnessThresh)*single_frame_multiplier + m_fHardCutLoudnessThresh; + } + } + + // smooth & scale the audio data, according to m_state, for display purposes + float scale = m_pState->m_fWaveScale.eval(GetTime()) / 128.0f; + mysound.fWave[0][0] *= scale; + mysound.fWave[1][0] *= scale; + float mix2 = m_pState->m_fWaveSmoothing.eval(GetTime()); + float mix1 = scale*(1.0f - mix2); + for (i=1; i<576; i++) + { + mysound.fWave[0][i] = mysound.fWave[0][i]*mix1 + mysound.fWave[0][i-1]*mix2; + mysound.fWave[1][i] = mysound.fWave[1][i]*mix1 + mysound.fWave[1][i-1]*mix2; + } + } + + bool bOldPresetUsesWarpShader = (m_pOldState->m_nWarpPSVersion > 0); + bool bNewPresetUsesWarpShader = (m_pState->m_nWarpPSVersion > 0); + bool bOldPresetUsesCompShader = (m_pOldState->m_nCompPSVersion > 0); + bool bNewPresetUsesCompShader = (m_pState->m_nCompPSVersion > 0); + + // note: 'code' is only meaningful if we are BLENDING. + int code = (bOldPresetUsesWarpShader ? 8 : 0) | + (bOldPresetUsesCompShader ? 4 : 0) | + (bNewPresetUsesWarpShader ? 2 : 0) | + (bNewPresetUsesCompShader ? 1 : 0); + + RunPerFrameEquations(code); + + // restore any lost surfaces + //m_lpDD->RestoreAllSurfaces(); + + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + // Remember the original backbuffer and zbuffer + LPDIRECT3DSURFACE9 pBackBuffer=NULL;//, pZBuffer=NULL; + lpDevice->GetRenderTarget( 0, &pBackBuffer ); + //lpDevice->GetDepthStencilSurface( &pZBuffer ); + + // set up render state + { + DWORD texaddr = (*m_pState->var_pf_wrap > m_fSnapPoint) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; + lpDevice->SetRenderState(D3DRS_WRAP0, 0);//D3DWRAPCOORD_0|D3DWRAPCOORD_1|D3DWRAPCOORD_2|D3DWRAPCOORD_3); + //lpDevice->SetRenderState(D3DRS_WRAP0, (*m_pState->var_pf_wrap) ? D3DWRAP_U|D3DWRAP_V|D3DWRAP_W : 0); + //lpDevice->SetRenderState(D3DRS_WRAP1, (*m_pState->var_pf_wrap) ? D3DWRAP_U|D3DWRAP_V|D3DWRAP_W : 0); + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);//texaddr); + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);//texaddr); + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP);//texaddr); + lpDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + lpDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + lpDevice->SetSamplerState(1, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP); + + lpDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD ); + lpDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE ); + lpDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); + lpDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); + lpDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE ); + lpDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); + lpDevice->SetRenderState( D3DRS_COLORVERTEX, TRUE ); + lpDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); + lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); + lpDevice->SetRenderState( D3DRS_AMBIENT, 0xFFFFFFFF ); //? + lpDevice->SetRenderState( D3DRS_CLIPPING, TRUE ); + + // stages 0 and 1 always just use bilinear filtering. + lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + + // note: this texture stage state setup works for 0 or 1 texture. + // if you set a texture, it will be modulated with the current diffuse color. + // if you don't set a texture, it will just use the current diffuse color. + lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); + lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + // NOTE: don't forget to call SetTexture and SetVertexShader before drawing! + // Examples: + // SPRITEVERTEX verts[4]; // has texcoords + // lpDevice->SetTexture(0, m_sprite_tex); + // lpDevice->SetVertexShader( SPRITEVERTEX_FORMAT ); + // + // WFVERTEX verts[4]; // no texcoords + // lpDevice->SetTexture(0, NULL); + // lpDevice->SetVertexShader( WFVERTEX_FORMAT ); + } + + // render string to m_lpDDSTitle, if necessary + if (m_supertext.bRedrawSuperText) + { + if (!RenderStringToTitleTexture()) + m_supertext.fStartTime = -1.0f; + m_supertext.bRedrawSuperText = false; + } + + // set up to render [from NULL] to VS0 (for motion vectors). + { + lpDevice->SetTexture(0, NULL); + + IDirect3DSurface9* pNewTarget = NULL; + if (m_lpVS[0]->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) + return; + lpDevice->SetRenderTarget(0, pNewTarget ); + //lpDevice->SetDepthStencilSurface( NULL ); + pNewTarget->Release(); + + lpDevice->SetTexture(0, NULL); + } + + // draw motion vectors to VS0 + DrawMotionVectors(); + + lpDevice->SetTexture(0, NULL); + lpDevice->SetTexture(1, NULL); + + // on first frame, clear OLD VS. + if (m_nFramesSinceResize == 0) + { + IDirect3DSurface9* pNewTarget = NULL; + if (m_lpVS[0]->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) + return; + lpDevice->SetRenderTarget(0, pNewTarget ); + //lpDevice->SetDepthStencilSurface( NULL ); + pNewTarget->Release(); + + lpDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0); + } + + // set up to render [from VS0] to VS1. + { + IDirect3DSurface9* pNewTarget = NULL; + if (m_lpVS[1]->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) + return; + lpDevice->SetRenderTarget(0, pNewTarget ); + //lpDevice->SetDepthStencilSurface( NULL ); + pNewTarget->Release(); + } + + if (m_bAutoGamma && GetFrame()==0) + { + if (strstr(GetDriverDescription(), "nvidia") || + strstr(GetDriverDescription(), "nVidia") || + strstr(GetDriverDescription(), "NVidia") || + strstr(GetDriverDescription(), "NVIDIA")) + m_n16BitGamma = 2; + else if (strstr(GetDriverDescription(), "ATI RAGE MOBILITY M")) + m_n16BitGamma = 2; + else + m_n16BitGamma = 0; + } + + ComputeGridAlphaValues(); + + // do the warping for this frame [warp shader] + if (!m_pState->m_bBlending) + { + // no blend + if (bNewPresetUsesWarpShader) + WarpedBlit_Shaders(1, false, false, false, false); + else + WarpedBlit_NoShaders(1, false, false, false, false); + } + else + { + // blending + // WarpedBlit( nPass, bAlphaBlend, bFlipAlpha, bCullTiles, bFlipCulling ) + // note: alpha values go from 0..1 during a blend. + // note: bFlipCulling==false means tiles with alpha>0 will draw. + // bFlipCulling==true means tiles with alpha<255 will draw. + + if (bOldPresetUsesWarpShader && bNewPresetUsesWarpShader) + { + WarpedBlit_Shaders (0, false, false, true, true); + WarpedBlit_Shaders (1, true, false, true, false); + } + else if (!bOldPresetUsesWarpShader && bNewPresetUsesWarpShader) + { + WarpedBlit_NoShaders(0, false, false, true, true); + WarpedBlit_Shaders (1, true, false, true, false); + } + else if (bOldPresetUsesWarpShader && !bNewPresetUsesWarpShader) + { + WarpedBlit_Shaders (0, false, false, true, true); + WarpedBlit_NoShaders(1, true, false, true, false); + } + else if (!bOldPresetUsesWarpShader && !bNewPresetUsesWarpShader) + { + //WarpedBlit_NoShaders(0, false, false, true, true); + //WarpedBlit_NoShaders(1, true, false, true, false); + + // special case - all the blending just happens in the vertex UV's, so just pretend there's no blend. + WarpedBlit_NoShaders(1, false, false, false, false); + } + } + + if (m_nMaxPSVersion > 0) + BlurPasses(); + + // draw audio data + DrawCustomShapes(); // draw these first; better for feedback if the waves draw *over* them. + DrawCustomWaves(); + DrawWave(mysound.fWave[0], mysound.fWave[1]); + DrawSprites(); + + float fProgress = (GetTime() - m_supertext.fStartTime) / m_supertext.fDuration; + + // if song title animation just ended, burn it into the VS: + if (m_supertext.fStartTime >= 0 && + fProgress >= 1.0f && + !m_supertext.bRedrawSuperText) + { + ShowSongTitleAnim(m_nTexSizeX, m_nTexSizeY, 1.0f); + } + + // Change the rendertarget back to the original setup + lpDevice->SetTexture(0, NULL); + lpDevice->SetRenderTarget(0, pBackBuffer ); + //lpDevice->SetDepthStencilSurface( pZBuffer ); + SafeRelease(pBackBuffer); + //SafeRelease(pZBuffer); + + // show it to the user [composite shader] + if (!m_pState->m_bBlending) + { + // no blend + if (bNewPresetUsesCompShader) + ShowToUser_Shaders(1, false, false, false, false); + else + ShowToUser_NoShaders();//1, false, false, false, false); + } + else + { + // blending + // ShowToUser( nPass, bAlphaBlend, bFlipAlpha, bCullTiles, bFlipCulling ) + // note: alpha values go from 0..1 during a blend. + // note: bFlipCulling==false means tiles with alpha>0 will draw. + // bFlipCulling==true means tiles with alpha<255 will draw. + + // NOTE: ShowToUser_NoShaders() must always come before ShowToUser_Shaders(), + // because it always draws the full quad (it can't do tile culling or alpha blending). + // [third case here] + + if (bOldPresetUsesCompShader && bNewPresetUsesCompShader) + { + ShowToUser_Shaders (0, false, false, true, true); + ShowToUser_Shaders (1, true, false, true, false); + } + else if (!bOldPresetUsesCompShader && bNewPresetUsesCompShader) + { + ShowToUser_NoShaders(); + ShowToUser_Shaders (1, true, false, true, false); + } + else if (bOldPresetUsesCompShader && !bNewPresetUsesCompShader) + { + // THA FUNKY REVERSAL + //ShowToUser_Shaders (0); + //ShowToUser_NoShaders(1); + ShowToUser_NoShaders(); + ShowToUser_Shaders (0, true, true, true, true); + } + else if (!bOldPresetUsesCompShader && !bNewPresetUsesCompShader) + { + // special case - all the blending just happens in the blended state vars, so just pretend there's no blend. + ShowToUser_NoShaders();//1, false, false, false, false); + } + } + + // finally, render song title animation to back buffer + if (m_supertext.fStartTime >= 0 && + !m_supertext.bRedrawSuperText) + { + ShowSongTitleAnim(GetWidth(), GetHeight(), min(fProgress, 0.9999f)); + if (fProgress >= 1.0f) + m_supertext.fStartTime = -1.0f; // 'off' state + } + + DrawUserSprites(); + + // flip buffers + IDirect3DTexture9* pTemp = m_lpVS[0]; + m_lpVS[0] = m_lpVS[1]; + m_lpVS[1] = pTemp; + + /* + // FIXME - remove EnforceMaxFPS() if never used + //EnforceMaxFPS(!(m_nLoadingPreset==1 || m_nLoadingPreset==2 || m_nLoadingPreset==4 || m_nLoadingPreset==5)); // this call just turns it on or off; doesn't do it now... + //EnforceMaxFPS(!(m_nLoadingPreset==2 || m_nLoadingPreset==5)); // this call just turns it on or off; doesn't do it now... + + // FIXME - remove this stuff, and change 'm_last_raw_time' in pluginshell (and others) back to private. + static float fOldTime = 0; + float fNewTime = (float)((double)m_last_raw_time/(double)m_high_perf_timer_freq.QuadPart); + float dt = fNewTime-fOldTime; + if (m_nLoadingPreset != 0) { + char buf[256]; + sprintf(buf, "m_nLoadingPreset==%d: dt=%d ms\n", m_nLoadingPreset, (int)(dt*1000) ); + OutputDebugString(buf); + } + fOldTime = fNewTime; + */ +} + +void CPlugin::DrawMotionVectors() +{ + // FLEXIBLE MOTION VECTOR FIELD + if ((float)*m_pState->var_pf_mv_a >= 0.001f) + { + //------------------------------------------------------- + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + lpDevice->SetTexture(0, NULL); + lpDevice->SetVertexShader(NULL); + lpDevice->SetFVF(WFVERTEX_FORMAT); + //------------------------------------------------------- + + int x,y; + + int nX = (int)(*m_pState->var_pf_mv_x);// + 0.999f); + int nY = (int)(*m_pState->var_pf_mv_y);// + 0.999f); + float dx = (float)*m_pState->var_pf_mv_x - nX; + float dy = (float)*m_pState->var_pf_mv_y - nY; + if (nX > 64) { nX = 64; dx = 0; } + if (nY > 48) { nY = 48; dy = 0; } + + if (nX > 0 && nY > 0) + { + /* + float dx2 = m_fMotionVectorsTempDx;//(*m_pState->var_pf_mv_dx) * 0.05f*GetTime(); // 0..1 range + float dy2 = m_fMotionVectorsTempDy;//(*m_pState->var_pf_mv_dy) * 0.05f*GetTime(); // 0..1 range + if (GetFps() > 2.0f && GetFps() < 300.0f) + { + dx2 += (float)(*m_pState->var_pf_mv_dx) * 0.05f / GetFps(); + dy2 += (float)(*m_pState->var_pf_mv_dy) * 0.05f / GetFps(); + } + if (dx2 > 1.0f) dx2 -= (int)dx2; + if (dy2 > 1.0f) dy2 -= (int)dy2; + if (dx2 < 0.0f) dx2 = 1.0f - (-dx2 - (int)(-dx2)); + if (dy2 < 0.0f) dy2 = 1.0f - (-dy2 - (int)(-dy2)); + // hack: when there is only 1 motion vector on the screem, to keep it in + // the center, we gradually migrate it toward 0.5. + dx2 = dx2*0.995f + 0.5f*0.005f; + dy2 = dy2*0.995f + 0.5f*0.005f; + // safety catch + if (dx2 < 0 || dx2 > 1 || dy2 < 0 || dy2 > 1) + { + dx2 = 0.5f; + dy2 = 0.5f; + } + m_fMotionVectorsTempDx = dx2; + m_fMotionVectorsTempDy = dy2;*/ + float dx2 = (float)(*m_pState->var_pf_mv_dx); + float dy2 = (float)(*m_pState->var_pf_mv_dy); + + float len_mult = (float)*m_pState->var_pf_mv_l; + if (dx < 0) dx = 0; + if (dy < 0) dy = 0; + if (dx > 1) dx = 1; + if (dy > 1) dy = 1; + //dx = dx * 1.0f/(float)nX; + //dy = dy * 1.0f/(float)nY; + float inv_texsize = 1.0f/(float)m_nTexSizeX; + float min_len = 1.0f*inv_texsize; + + WFVERTEX v[(64+1)*2]; + ZeroMemory(v, sizeof(WFVERTEX)*(64+1)*2); + v[0].Diffuse = D3DCOLOR_RGBA_01((float)*m_pState->var_pf_mv_r,(float)*m_pState->var_pf_mv_g,(float)*m_pState->var_pf_mv_b,(float)*m_pState->var_pf_mv_a); + for (x=1; x<(nX+1)*2; x++) + v[x].Diffuse = v[0].Diffuse; + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + + for (y=0; y 0.0001f && fy < 0.9999f) + { + int n = 0; + for (x=0; x 0.0001f && fx < 0.9999f) + { + float fx2, fy2; + ReversePropagatePoint(fx, fy, &fx2, &fy2); // NOTE: THIS IS REALLY A REVERSE-PROPAGATION + //fx2 = fx*2 - fx2; + //fy2 = fy*2 - fy2; + //fx2 = fx + 1.0f/(float)m_nTexSize; + //fy2 = 1-(fy + 1.0f/(float)m_nTexSize); + + // enforce minimum trail lengths: + { + float dx = (fx2 - fx); + float dy = (fy2 - fy); + dx *= len_mult; + dy *= len_mult; + float len = sqrtf(dx*dx + dy*dy); + + if (len > min_len) + { + + } + else if (len > 0.00000001f) + { + len = min_len/len; + dx *= len; + dy *= len; + } + else + { + dx = min_len; + dy = min_len; + } + + fx2 = fx + dx; + fy2 = fy + dy; + } + /**/ + + v[n].x = fx * 2.0f - 1.0f; + v[n].y = fy * 2.0f - 1.0f; + v[n+1].x = fx2 * 2.0f - 1.0f; + v[n+1].y = fy2 * 2.0f - 1.0f; + + // actually, project it in the reverse direction + //v[n+1].x = v[n].x*2.0f - v[n+1].x;// + dx*2; + //v[n+1].y = v[n].y*2.0f - v[n+1].y;// + dy*2; + //v[n].x += dx*2; + //v[n].y += dy*2; + + n += 2; + } + } + + // draw it + lpDevice->DrawPrimitiveUP(D3DPT_LINELIST, n/2, v, sizeof(WFVERTEX)); + } + } + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + } +} + +/* +void CPlugin::UpdateSongInfo() +{ + if (m_bShowSongTitle || m_bSongTitleAnims) + { + char szOldSongMessage[512]; + lstrcpy(szOldSongMessage, m_szSongMessage); + + if (::GetWindowText(m_hWndParent, m_szSongMessage, sizeof(m_szSongMessage))) + { + // remove ' - Winamp' at end + if (strlen(m_szSongMessage) > 9) + { + int check_pos = strlen(m_szSongMessage) - 9; + if (lstrcmp(" - Winamp", (char *)(m_szSongMessage + check_pos)) == 0) + m_szSongMessage[check_pos] = 0; + } + + // remove ' - Winamp [Paused]' at end + if (strlen(m_szSongMessage) > 18) + { + int check_pos = strlen(m_szSongMessage) - 18; + if (lstrcmp(" - Winamp [Paused]", (char *)(m_szSongMessage + check_pos)) == 0) + m_szSongMessage[check_pos] = 0; + } + + // remove song # and period from beginning + char *p = m_szSongMessage; + while (*p >= '0' && *p <= '9') p++; + if (*p == '.' && *(p+1) == ' ') + { + p += 2; + int pos = 0; + while (*p != 0) + { + m_szSongMessage[pos++] = *p; + p++; + } + m_szSongMessage[pos++] = 0; + } + + // fix &'s for display + /* + { + int pos = 0; + int len = strlen(m_szSongMessage); + while (m_szSongMessage[pos]) + { + if (m_szSongMessage[pos] == '&') + { + for (int x=len; x>=pos; x--) + m_szSongMessage[x+1] = m_szSongMessage[x]; + len++; + pos++; + } + pos++; + } + }*/ + /* + if (m_bSongTitleAnims && + ((lstrcmp(szOldSongMessage, m_szSongMessage) != 0) || (GetFrame()==0))) + { + // launch song title animation + LaunchSongTitleAnim(); + + /* + m_supertext.bRedrawSuperText = true; + m_supertext.bIsSongTitle = true; + lstrcpy(m_supertext.szText, m_szSongMessage); + lstrcpy(m_supertext.nFontFace, m_szTitleFontFace); + m_supertext.fFontSize = (float)m_nTitleFontSize; + m_supertext.bBold = m_bTitleFontBold; + m_supertext.bItal = m_bTitleFontItalic; + m_supertext.fX = 0.5f; + m_supertext.fY = 0.5f; + m_supertext.fGrowth = 1.0f; + m_supertext.fDuration = m_fSongTitleAnimDuration; + m_supertext.nColorR = 255; + m_supertext.nColorG = 255; + m_supertext.nColorB = 255; + + m_supertext.fStartTime = GetTime(); + */ +/* } + } + else + { + sprintf(m_szSongMessage, ""); + } + } + + m_nTrackPlaying = SendMessage(m_hWndParent,WM_USER, 0, 125); + + // append song time + if (m_bShowSongTime && m_nSongPosMS >= 0) + { + float time_s = m_nSongPosMS*0.001f; + + int minutes = (int)(time_s/60); + time_s -= minutes*60; + int seconds = (int)time_s; + time_s -= seconds; + int dsec = (int)(time_s*100); + + sprintf(m_szSongTime, "%d:%02d.%02d", minutes, seconds, dsec); + } + + // append song length + if (m_bShowSongLen && m_nSongLenMS > 0) + { + int len_s = m_nSongLenMS/1000; + int minutes = len_s/60; + int seconds = len_s - minutes*60; + + char buf[512]; + sprintf(buf, " / %d:%02d", minutes, seconds); + lstrcat(m_szSongTime, buf); + } +} +*/ + +bool CPlugin::ReversePropagatePoint(float fx, float fy, float *fx2, float *fy2) +{ + //float fy = y/(float)nMotionVectorsY; + int y0 = (int)(fy*m_nGridY); + float dy = fy*m_nGridY - y0; + + //float fx = x/(float)nMotionVectorsX; + int x0 = (int)(fx*m_nGridX); + float dx = fx*m_nGridX - x0; + + int x1 = x0 + 1; + int y1 = y0 + 1; + + if (x0 < 0) return false; + if (y0 < 0) return false; + //if (x1 < 0) return false; + //if (y1 < 0) return false; + //if (x0 > m_nGridX) return false; + //if (y0 > m_nGridY) return false; + if (x1 > m_nGridX) return false; + if (y1 > m_nGridY) return false; + + float tu, tv; + tu = m_verts[y0*(m_nGridX+1)+x0].tu * (1-dx)*(1-dy); + tv = m_verts[y0*(m_nGridX+1)+x0].tv * (1-dx)*(1-dy); + tu += m_verts[y0*(m_nGridX+1)+x1].tu * (dx)*(1-dy); + tv += m_verts[y0*(m_nGridX+1)+x1].tv * (dx)*(1-dy); + tu += m_verts[y1*(m_nGridX+1)+x0].tu * (1-dx)*(dy); + tv += m_verts[y1*(m_nGridX+1)+x0].tv * (1-dx)*(dy); + tu += m_verts[y1*(m_nGridX+1)+x1].tu * (dx)*(dy); + tv += m_verts[y1*(m_nGridX+1)+x1].tv * (dx)*(dy); + + *fx2 = tu; + *fy2 = 1.0f - tv; + return true; +} + +void CPlugin::GetSafeBlurMinMax(CState* pState, float* blur_min, float* blur_max) +{ + blur_min[0] = (float)*pState->var_pf_blur1min; + blur_min[1] = (float)*pState->var_pf_blur2min; + blur_min[2] = (float)*pState->var_pf_blur3min; + blur_max[0] = (float)*pState->var_pf_blur1max; + blur_max[1] = (float)*pState->var_pf_blur2max; + blur_max[2] = (float)*pState->var_pf_blur3max; + + // check that precision isn't wasted in later blur passes [...min-max gap can't grow!] + // also, if min-max are close to each other, push them apart: + const float fMinDist = 0.1f; + if (blur_max[0] - blur_min[0] < fMinDist) { + float avg = (blur_min[0] + blur_max[0])*0.5f; + blur_min[0] = avg - fMinDist*0.5f; + blur_max[0] = avg - fMinDist*0.5f; + } + blur_max[1] = min(blur_max[0], blur_max[1]); + blur_min[1] = max(blur_min[0], blur_min[1]); + if (blur_max[1] - blur_min[1] < fMinDist) { + float avg = (blur_min[1] + blur_max[1])*0.5f; + blur_min[1] = avg - fMinDist*0.5f; + blur_max[1] = avg - fMinDist*0.5f; + } + blur_max[2] = min(blur_max[1], blur_max[2]); + blur_min[2] = max(blur_min[1], blur_min[2]); + if (blur_max[2] - blur_min[2] < fMinDist) { + float avg = (blur_min[2] + blur_max[2])*0.5f; + blur_min[2] = avg - fMinDist*0.5f; + blur_max[2] = avg - fMinDist*0.5f; + } +} + +void CPlugin::BlurPasses() +{ + #if (NUM_BLUR_TEX>0) + + // Note: Blur is currently a little funky. It blurs the *current* frame after warp; + // this way, it lines up well with the composite pass. However, if you switch + // presets instantly, to one whose *warp* shader uses the blur texture, + // it will be outdated (just for one frame). Oh well. + // This also means that when sampling the blurred textures in the warp shader, + // they are one frame old. This isn't too big a deal. Getting them to match + // up for the composite pass is probably more important. + + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + int passes = min(NUM_BLUR_TEX, m_nHighestBlurTexUsedThisFrame*2); + if (passes==0) + return; + + LPDIRECT3DSURFACE9 pBackBuffer=NULL;//, pZBuffer=NULL; + lpDevice->GetRenderTarget( 0, &pBackBuffer ); + + //lpDevice->SetFVF( MYVERTEX_FORMAT ); + lpDevice->SetVertexShader( m_BlurShaders[0].vs.ptr ); + lpDevice->SetVertexDeclaration(m_pMyVertDecl); + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + DWORD wrap = D3DTADDRESS_CLAMP;//D3DTADDRESS_WRAP;// : D3DTADDRESS_CLAMP; + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, wrap); + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, wrap); + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSW, wrap); + lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 1); + + IDirect3DSurface9* pNewTarget = NULL; + + // clear texture bindings + for (int i=0; i<16; i++) + lpDevice->SetTexture(i, NULL); + + // set up fullscreen quad + MYVERTEX v[4]; + + v[0].x = -1; + v[0].y = -1; + v[1].x = 1; + v[1].y = -1; + v[2].x = -1; + v[2].y = 1; + v[3].x = 1; + v[3].y = 1; + + v[0].tu = 0; //kiv: upside-down? + v[0].tv = 0; + v[1].tu = 1; + v[1].tv = 0; + v[2].tu = 0; + v[2].tv = 1; + v[3].tu = 1; + v[3].tv = 1; + + const float w[8] = { 4.0f, 3.8f, 3.5f, 2.9f, 1.9f, 1.2f, 0.7f, 0.3f }; //<- user can specify these + float edge_darken = (float)*m_pState->var_pf_blur1_edge_darken; + float blur_min[3], blur_max[3]; + GetSafeBlurMinMax(m_pState, blur_min, blur_max); + + float fscale[3]; + float fbias[3]; + + // figure out the progressive scale & bias needed, at each step, + // to go from one [min..max] range to the next. + float temp_min, temp_max; + fscale[0] = 1.0f / (blur_max[0] - blur_min[0]); + fbias [0] = -blur_min[0] * fscale[0]; + temp_min = (blur_min[1] - blur_min[0]) / (blur_max[0] - blur_min[0]); + temp_max = (blur_max[1] - blur_min[0]) / (blur_max[0] - blur_min[0]); + fscale[1] = 1.0f / (temp_max - temp_min); + fbias [1] = -temp_min * fscale[1]; + temp_min = (blur_min[2] - blur_min[1]) / (blur_max[1] - blur_min[1]); + temp_max = (blur_max[2] - blur_min[1]) / (blur_max[1] - blur_min[1]); + fscale[2] = 1.0f / (temp_max - temp_min); + fbias [2] = -temp_min * fscale[2]; + + // note: warped blit just rendered from VS0 to VS1. + for (i=0; iGetSurfaceLevel(0, &pNewTarget) != D3D_OK) + return; + lpDevice->SetRenderTarget(0, pNewTarget); + pNewTarget->Release(); + + // hook up correct source texture - assume there is only one, at stage 0 + lpDevice->SetTexture(0, (i==0) ? m_lpVS[0] : m_lpBlur[i-1]); + + // set pixel shader + lpDevice->SetPixelShader (m_BlurShaders[i%2].ps.ptr); + + // set constants + LPD3DXCONSTANTTABLE pCT = m_BlurShaders[i%2].ps.CT; + D3DXHANDLE* h = m_BlurShaders[i%2].ps.params.const_handles; + + int srcw = (i==0) ? GetWidth() : m_nBlurTexW[i-1]; + int srch = (i==0) ? GetHeight() : m_nBlurTexH[i-1]; + D3DXVECTOR4 srctexsize = D3DXVECTOR4( (float)srcw, (float)srch, 1.0f/(float)srcw, 1.0f/(float)srch ); + + float fscale_now = fscale[i/2]; + float fbias_now = fbias[i/2]; + + if (i%2==0) + { + // pass 1 (long horizontal pass) + //------------------------------------- + const float w1 = w[0] + w[1]; + const float w2 = w[2] + w[3]; + const float w3 = w[4] + w[5]; + const float w4 = w[6] + w[7]; + const float d1 = 0 + 2*w[1]/w1; + const float d2 = 2 + 2*w[3]/w2; + const float d3 = 4 + 2*w[5]/w3; + const float d4 = 6 + 2*w[7]/w4; + const float w_div = 0.5f/(w1+w2+w3+w4); + //------------------------------------- + //float4 _c0; // source texsize (.xy), and inverse (.zw) + //float4 _c1; // w1..w4 + //float4 _c2; // d1..d4 + //float4 _c3; // scale, bias, w_div, 0 + //------------------------------------- + if (h[0]) pCT->SetVector( lpDevice, h[0], &srctexsize ); + if (h[1]) pCT->SetVector( lpDevice, h[1], &D3DXVECTOR4( w1,w2,w3,w4 )); + if (h[2]) pCT->SetVector( lpDevice, h[2], &D3DXVECTOR4( d1,d2,d3,d4 )); + if (h[3]) pCT->SetVector( lpDevice, h[3], &D3DXVECTOR4( fscale_now,fbias_now,w_div,0)); + } + else + { + // pass 2 (short vertical pass) + //------------------------------------- + const float w1 = w[0]+w[1] + w[2]+w[3]; + const float w2 = w[4]+w[5] + w[6]+w[7]; + const float d1 = 0 + 2*((w[2]+w[3])/w1); + const float d2 = 2 + 2*((w[6]+w[7])/w2); + const float w_div = 1.0f/((w1+w2)*2); + //------------------------------------- + //float4 _c0; // source texsize (.xy), and inverse (.zw) + //float4 _c5; // w1,w2,d1,d2 + //float4 _c6; // w_div, edge_darken_c1, edge_darken_c2, edge_darken_c3 + //------------------------------------- + if (h[0]) pCT->SetVector( lpDevice, h[0], &srctexsize ); + if (h[5]) pCT->SetVector( lpDevice, h[5], &D3DXVECTOR4( w1,w2,d1,d2 )); + if (h[6]) + { + // note: only do this first time; if you do it many times, + // then the super-blurred levels will have big black lines along the top & left sides. + if (i==1) + pCT->SetVector( lpDevice, h[6], &D3DXVECTOR4( w_div,(1-edge_darken),edge_darken,5.0f )); //darken edges + else + pCT->SetVector( lpDevice, h[6], &D3DXVECTOR4( w_div,1.0f,0.0f,5.0f )); // don't darken + } + } + + // draw fullscreen quad + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(MYVERTEX)); + + // clear texture bindings + lpDevice->SetTexture(0, NULL); + } + + lpDevice->SetRenderTarget(0, pBackBuffer); + pBackBuffer->Release(); + lpDevice->SetPixelShader( NULL ); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetTexture(0, NULL); + lpDevice->SetFVF( MYVERTEX_FORMAT ); + #endif + + m_nHighestBlurTexUsedThisFrame = 0; +} + +void CPlugin::ComputeGridAlphaValues() +{ + float fBlend = m_pState->m_fBlendProgress;//max(0,min(1,(m_pState->m_fBlendProgress*1.6f - 0.3f))); + /*switch(code) //if (nPassOverride==0) + { + //case 8: + //case 9: + //case 12: + //case 13: + // note - these are the 4 cases where the old preset uses a warp shader, but new preset doesn't. + fBlend = 1-fBlend; // <-- THIS IS THE KEY - FLIPS THE ALPHAS AND EVERYTHING ELSE JUST WORKS. + break; + }*/ + //fBlend = 1-fBlend; // <-- THIS IS THE KEY - FLIPS THE ALPHAS AND EVERYTHING ELSE JUST WORKS. + bool bBlending = m_pState->m_bBlending;//(fBlend >= 0.0001f && fBlend <= 0.9999f); + + + // warp stuff + float fWarpTime = GetTime() * m_pState->m_fWarpAnimSpeed; + float fWarpScaleInv = 1.0f / m_pState->m_fWarpScale.eval(GetTime()); + float f[4]; + f[0] = 11.68f + 4.0f*cosf(fWarpTime*1.413f + 10); + f[1] = 8.77f + 3.0f*cosf(fWarpTime*1.113f + 7); + f[2] = 10.54f + 3.0f*cosf(fWarpTime*1.233f + 3); + f[3] = 11.49f + 4.0f*cosf(fWarpTime*0.933f + 5); + + // texel alignment + float texel_offset_x = 0.5f / (float)m_nTexSizeX; + float texel_offset_y = 0.5f / (float)m_nTexSizeY; + + int num_reps = (m_pState->m_bBlending) ? 2 : 1; + int start_rep = 0; + + // FIRST WE HAVE 1-2 PASSES FOR CRUNCHING THE PER-VERTEX EQUATIONS + for (int rep=start_rep; repvar_pf_zoom); + float fZoomExp = (float)(*pState->var_pf_zoomexp); + float fRot = (float)(*pState->var_pf_rot); + float fWarp = (float)(*pState->var_pf_warp); + float fCX = (float)(*pState->var_pf_cx); + float fCY = (float)(*pState->var_pf_cy); + float fDX = (float)(*pState->var_pf_dx); + float fDY = (float)(*pState->var_pf_dy); + float fSX = (float)(*pState->var_pf_sx); + float fSY = (float)(*pState->var_pf_sy); + + int n = 0; + + for (int y=0; y<=m_nGridY; y++) + { + for (int x=0; x<=m_nGridX; x++) + { + // Note: x, y, z are now set at init. time - no need to mess with them! + //m_verts[n].x = i/(float)m_nGridX*2.0f - 1.0f; + //m_verts[n].y = j/(float)m_nGridY*2.0f - 1.0f; + //m_verts[n].z = 0.0f; + + if (pState->m_pp_codehandle) + { + // restore all the variables to their original states, + // run the user-defined equations, + // then move the results into local vars for computation as floats + + *pState->var_pv_x = (double)(m_verts[n].x* 0.5f*m_fAspectX + 0.5f); + *pState->var_pv_y = (double)(m_verts[n].y*-0.5f*m_fAspectY + 0.5f); + *pState->var_pv_rad = (double)m_vertinfo[n].rad; + *pState->var_pv_ang = (double)m_vertinfo[n].ang; + *pState->var_pv_zoom = *pState->var_pf_zoom; + *pState->var_pv_zoomexp = *pState->var_pf_zoomexp; + *pState->var_pv_rot = *pState->var_pf_rot; + *pState->var_pv_warp = *pState->var_pf_warp; + *pState->var_pv_cx = *pState->var_pf_cx; + *pState->var_pv_cy = *pState->var_pf_cy; + *pState->var_pv_dx = *pState->var_pf_dx; + *pState->var_pv_dy = *pState->var_pf_dy; + *pState->var_pv_sx = *pState->var_pf_sx; + *pState->var_pv_sy = *pState->var_pf_sy; + //*pState->var_pv_time = *pState->var_pv_time; // (these are all now initialized + //*pState->var_pv_bass = *pState->var_pv_bass; // just once per frame) + //*pState->var_pv_mid = *pState->var_pv_mid; + //*pState->var_pv_treb = *pState->var_pv_treb; + //*pState->var_pv_bass_att = *pState->var_pv_bass_att; + //*pState->var_pv_mid_att = *pState->var_pv_mid_att; + //*pState->var_pv_treb_att = *pState->var_pv_treb_att; + +#ifndef _NO_EXPR_ + NSEEL_code_execute(pState->m_pp_codehandle); +#endif + + fZoom = (float)(*pState->var_pv_zoom); + fZoomExp = (float)(*pState->var_pv_zoomexp); + fRot = (float)(*pState->var_pv_rot); + fWarp = (float)(*pState->var_pv_warp); + fCX = (float)(*pState->var_pv_cx); + fCY = (float)(*pState->var_pv_cy); + fDX = (float)(*pState->var_pv_dx); + fDY = (float)(*pState->var_pv_dy); + fSX = (float)(*pState->var_pv_sx); + fSY = (float)(*pState->var_pv_sy); + } + + float fZoom2 = powf(fZoom, powf(fZoomExp, m_vertinfo[n].rad*2.0f - 1.0f)); + + // initial texcoords, w/built-in zoom factor + float fZoom2Inv = 1.0f/fZoom2; + float u = m_verts[n].x*m_fAspectX*0.5f*fZoom2Inv + 0.5f; + float v = -m_verts[n].y*m_fAspectY*0.5f*fZoom2Inv + 0.5f; + //float u_orig = u; + //float v_orig = v; + //m_verts[n].tr = u_orig + texel_offset_x; + //m_verts[n].ts = v_orig + texel_offset_y; + + // stretch on X, Y: + u = (u - fCX)/fSX + fCX; + v = (v - fCY)/fSY + fCY; + + // warping: + //if (fWarp > 0.001f || fWarp < -0.001f) + //{ + u += fWarp*0.0035f*sinf(fWarpTime*0.333f + fWarpScaleInv*(m_verts[n].x*f[0] - m_verts[n].y*f[3])); + v += fWarp*0.0035f*cosf(fWarpTime*0.375f - fWarpScaleInv*(m_verts[n].x*f[2] + m_verts[n].y*f[1])); + u += fWarp*0.0035f*cosf(fWarpTime*0.753f - fWarpScaleInv*(m_verts[n].x*f[1] - m_verts[n].y*f[2])); + v += fWarp*0.0035f*sinf(fWarpTime*0.825f + fWarpScaleInv*(m_verts[n].x*f[0] + m_verts[n].y*f[3])); + //} + + // rotation: + float u2 = u - fCX; + float v2 = v - fCY; + + float cos_rot = cosf(fRot); + float sin_rot = sinf(fRot); + u = u2*cos_rot - v2*sin_rot + fCX; + v = u2*sin_rot + v2*cos_rot + fCY; + + // translation: + u -= fDX; + v -= fDY; + + // undo aspect ratio fix: + u = (u-0.5f)*m_fInvAspectX + 0.5f; + v = (v-0.5f)*m_fInvAspectY + 0.5f; + + // final half-texel-offset translation: + u += texel_offset_x; + v += texel_offset_y; + + if (rep==0) + { + // UV's for m_pState + m_verts[n].tu = u; + m_verts[n].tv = v; + m_verts[n].Diffuse = 0xFFFFFFFF; + } + else + { + // blend to UV's for m_pOldState + float mix2 = m_vertinfo[n].a*fBlend + m_vertinfo[n].c;//fCosineBlend2; + mix2 = max(0,min(1,mix2)); + // if fBlend un-flipped, then mix2 is 0 at the beginning of a blend, 1 at the end... + // and alphas are 0 at the beginning, 1 at the end. + m_verts[n].tu = m_verts[n].tu*(mix2) + u*(1-mix2); + m_verts[n].tv = m_verts[n].tv*(mix2) + v*(1-mix2); + // this sets the alpha values for blending between two presets: + m_verts[n].Diffuse = 0x00FFFFFF | (((DWORD)(mix2*255))<<24); + } + + n++; + } + } + + } +} + +void CPlugin::WarpedBlit_NoShaders(int nPass, bool bAlphaBlend, bool bFlipAlpha, bool bCullTiles, bool bFlipCulling) +{ + MungeFPCW(NULL); // puts us in single-precision mode & disables exceptions + + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + if (!wcscmp(m_pState->m_szDesc, INVALID_PRESET_DESC)) + { + // if no valid preset loaded, clear the target to black, and return + lpDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0); + return; + } + + lpDevice->SetTexture(0, m_lpVS[0]); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetPixelShader( NULL ); + lpDevice->SetFVF( MYVERTEX_FORMAT ); + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + // stages 0 and 1 always just use bilinear filtering. + lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + + // note: this texture stage state setup works for 0 or 1 texture. + // if you set a texture, it will be modulated with the current diffuse color. + // if you don't set a texture, it will just use the current diffuse color. + lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); + lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + DWORD texaddr = (*m_pState->var_pf_wrap > m_fSnapPoint) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, texaddr); + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, texaddr); + lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSW, texaddr); + + // decay + float fDecay = (float)(*m_pState->var_pf_decay); + + //if (m_pState->m_bBlending) + // fDecay = fDecay*(fCosineBlend) + (1.0f-fCosineBlend)*((float)(*m_pOldState->var_pf_decay)); + + if (m_n16BitGamma > 0 && + (GetBackBufFormat()==D3DFMT_R5G6B5 || GetBackBufFormat()==D3DFMT_X1R5G5B5 || GetBackBufFormat()==D3DFMT_A1R5G5B5 || GetBackBufFormat()==D3DFMT_A4R4G4B4) && + fDecay < 0.9999f) + { + fDecay = min(fDecay, (32.0f - m_n16BitGamma)/32.0f); + } + + D3DCOLOR cDecay = D3DCOLOR_RGBA_01(fDecay,fDecay,fDecay,1); + + // hurl the triangle strips at the video card + int poly; + for (poly=0; poly<(m_nGridX+1)*2; poly++) + m_verts_temp[poly].Diffuse = cDecay; + + if (bAlphaBlend) + { + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + if (bFlipAlpha) + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + } + else + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } + } + else + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + int nAlphaTestValue = 0; + if (bFlipCulling) + nAlphaTestValue = 1-nAlphaTestValue; + + // Hurl the triangles at the video card. + // We're going to un-index it, so that we don't stress any crappy (AHEM intel g33) + // drivers out there. + // If we're blending, we'll skip any polygon that is all alpha-blended out. + // This also respects the MaxPrimCount limit of the video card. + MYVERTEX tempv[1024 * 3]; + int max_prims_per_batch = min( GetCaps()->MaxPrimitiveCount, (sizeof(tempv)/sizeof(tempv[0]))/3) - 4; + int primCount = m_nGridX*m_nGridY*2; + int src_idx = 0; + int prims_sent = 0; + while (src_idx < primCount*3) + { + int prims_queued = 0; + int i=0; + while (prims_queued < max_prims_per_batch && src_idx < primCount*3) + { + // copy 3 verts + for (int j=0; j<3; j++) + { + tempv[i++] = m_verts[ m_indices_list[src_idx++] ]; + // don't forget to flip sign on Y and factor in the decay color!: + tempv[i-1].y *= -1; + tempv[i-1].Diffuse = (cDecay & 0x00FFFFFF) | (tempv[i-1].Diffuse & 0xFF000000); + } + if (bCullTiles) + { + DWORD d1 = (tempv[i-3].Diffuse >> 24); + DWORD d2 = (tempv[i-2].Diffuse >> 24); + DWORD d3 = (tempv[i-1].Diffuse >> 24); + bool bIsNeeded; + if (nAlphaTestValue) + bIsNeeded = ((d1 & d2 & d3) < 255);//(d1 < 255) || (d2 < 255) || (d3 < 255); + else + bIsNeeded = ((d1|d2|d3) > 0);//(d1 > 0) || (d2 > 0) || (d3 > 0); + if (!bIsNeeded) + i -= 3; + else + prims_queued++; + } + else + prims_queued++; + } + if (prims_queued > 0) + lpDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, prims_queued, tempv, sizeof(MYVERTEX) ); + } + + /* + if (!bCullTiles) + { + assert(!bAlphaBlend); //not handled yet + + // draw normally - just a full triangle strip for each half-row of cells + // (even if we are blending, it is between two pre-pixel-shader presets, + // so the blend all happens exclusively in the per-vertex equations.) + for (int strip=0; stripDrawPrimitiveUP(D3DPT_TRIANGLESTRIP, m_nGridX, (void*)m_verts_temp, sizeof(MYVERTEX)); + } + } + else + { + // we're blending to/from a new pixel-shader enabled preset; + // only draw the cells needed! (an optimization) + int nAlphaTestValue = 0; + if (bFlipCulling) + nAlphaTestValue = 1-nAlphaTestValue; + + int idx[2048]; + for (int y=0; y> 24); + DWORD d2 = (m_verts[ref_vert+m_nGridX+1].Diffuse >> 24); + if (nAlphaTestValue) + bWasNeeded = (d1 < 255) || (d2 < 255); + else + bWasNeeded = (d1 > 0) || (d2 > 0); + for (i=0; i> 24); + DWORD d2 = (m_verts[ref_vert+1+m_nGridX+1].Diffuse >> 24); + if (nAlphaTestValue) + bIsNeeded = (d1 < 255) || (d2 < 255); + else + bIsNeeded = (d1 > 0) || (d2 > 0); + + if (bIsNeeded || bWasNeeded) + { + idx[count++] = nVert; + idx[count++] = nVert+1; + idx[count++] = nVert+m_nGridX+1; + idx[count++] = nVert+m_nGridX+1; + idx[count++] = nVert+1; + idx[count++] = nVert+m_nGridX+2; + } + bWasNeeded = bIsNeeded; + + nVert++; + ref_vert++; + } + lpDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, (m_nGridX+1)*2, count/3, (void*)idx, D3DFMT_INDEX32, (void*)m_verts_temp, sizeof(MYVERTEX)); + } + }/**/ + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); +} + +void CPlugin::WarpedBlit_Shaders(int nPass, bool bAlphaBlend, bool bFlipAlpha, bool bCullTiles, bool bFlipCulling) +{ + // if nPass==0, it draws old preset (blending 1 of 2). + // if nPass==1, it draws new preset (blending 2 of 2, OR done blending) + + MungeFPCW(NULL); // puts us in single-precision mode & disables exceptions + + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + if (!wcscmp(m_pState->m_szDesc, INVALID_PRESET_DESC)) + { + // if no valid preset loaded, clear the target to black, and return + lpDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 1.0f, 0); + return; + } + + //float fBlend = m_pState->m_fBlendProgress;//max(0,min(1,(m_pState->m_fBlendProgress*1.6f - 0.3f))); + //if (nPassOverride==0) + // fBlend = 1-fBlend; // <-- THIS IS THE KEY - FLIPS THE ALPHAS AND EVERYTHING ELSE JUST WORKS. + //bool bBlending = m_pState->m_bBlending;//(fBlend >= 0.0001f && fBlend <= 0.9999f); + + //lpDevice->SetTexture(0, m_lpVS[0]); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( MYVERTEX_FORMAT ); + + // texel alignment + float texel_offset_x = 0.5f / (float)m_nTexSizeX; + float texel_offset_y = 0.5f / (float)m_nTexSizeY; + + int nAlphaTestValue = 0; + if (bFlipCulling) + nAlphaTestValue = 1-nAlphaTestValue; + + if (bAlphaBlend) + { + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + if (bFlipAlpha) + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + } + else + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } + } + else + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + int pass = nPass; + { + // PASS 0: draw using *blended per-vertex motion vectors*, but with the OLD warp shader. + // PASS 1: draw using *blended per-vertex motion vectors*, but with the NEW warp shader. + PShaderInfo* si = (pass==0) ? &m_OldShaders.warp : &m_shaders.warp; + CState* state = (pass==0) ? m_pOldState : m_pState; + + lpDevice->SetVertexDeclaration(m_pMyVertDecl); + lpDevice->SetVertexShader(m_fallbackShaders_vs.warp.ptr); + lpDevice->SetPixelShader (si->ptr); + + ApplyShaderParams( &(si->params), si->CT, state ); + + // Hurl the triangles at the video card. + // We're going to un-index it, so that we don't stress any crappy (AHEM intel g33) + // drivers out there. + // We divide it into the two halves of the screen (top/bottom) so we can hack + // the 'ang' values along the angle-wrap seam, halfway through the draw. + // If we're blending, we'll skip any polygon that is all alpha-blended out. + // This also respects the MaxPrimCount limit of the video card. + MYVERTEX tempv[1024 * 3]; + int max_prims_per_batch = min( GetCaps()->MaxPrimitiveCount, (sizeof(tempv)/sizeof(tempv[0]))/3) - 4; + for (int half=0; half<2; half++) + { + // hack / restore the ang values along the angle-wrap [0 <-> 2pi] seam... + float new_ang = half ? 3.1415926535897932384626433832795f : -3.1415926535897932384626433832795f; + int y_offset = (m_nGridY/2) * (m_nGridX+1); + for (int x=0; x> 24); + DWORD d2 = (tempv[i-2].Diffuse >> 24); + DWORD d3 = (tempv[i-1].Diffuse >> 24); + bool bIsNeeded; + if (nAlphaTestValue) + bIsNeeded = ((d1 & d2 & d3) < 255);//(d1 < 255) || (d2 < 255) || (d3 < 255); + else + bIsNeeded = ((d1|d2|d3) > 0);//(d1 > 0) || (d2 > 0) || (d3 > 0); + if (!bIsNeeded) + i -= 3; + else + prims_queued++; + } + else + prims_queued++; + } + if (prims_queued > 0) + lpDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, prims_queued, tempv, sizeof(MYVERTEX) ); + } + } + } + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + RestoreShaderParams(); +} + +void CPlugin::DrawCustomShapes() +{ + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + //lpDevice->SetTexture(0, m_lpVS[0]);//NULL); + //lpDevice->SetVertexShader( SPRITEVERTEX_FORMAT ); + + int num_reps = (m_pState->m_bBlending) ? 2 : 1; + for (int rep=0; repm_fBlendProgress : (1-m_pState->m_fBlendProgress); + + for (int i=0; im_shape[i].enabled) + { + /* + int bAdditive = 0; + int nSides = 3;//3 + ((int)GetTime() % 8); + int bThickOutline = 0; + float x = 0.5f + 0.1f*cosf(GetTime()*0.8f+1); + float y = 0.5f + 0.1f*sinf(GetTime()*0.8f+1); + float rad = 0.15f + 0.07f*sinf(GetTime()*1.1f+3); + float ang = GetTime()*1.5f; + + // inside colors + float r = 1; + float g = 0; + float b = 0; + float a = 0.4f;//0.1f + 0.1f*sinf(GetTime()*0.31f); + + // outside colors + float r2 = 0; + float g2 = 1; + float b2 = 0; + float a2 = 0; + + // border colors + float border_r = 1; + float border_g = 1; + float border_b = 1; + float border_a = 0.5f; + */ + + for (int instance=0; instancem_shape[i].instances; instance++) + { + // 1. execute per-frame code + LoadCustomShapePerFrameEvallibVars(pState, i, instance); + + #ifndef _NO_EXPR_ + if (pState->m_shape[i].m_pf_codehandle) + { + NSEEL_code_execute(pState->m_shape[i].m_pf_codehandle); + } + #endif + + // save changes to t1-t8 this frame + /* + pState->m_shape[i].t_values_after_init_code[0] = *pState->m_shape[i].var_pf_t1; + pState->m_shape[i].t_values_after_init_code[1] = *pState->m_shape[i].var_pf_t2; + pState->m_shape[i].t_values_after_init_code[2] = *pState->m_shape[i].var_pf_t3; + pState->m_shape[i].t_values_after_init_code[3] = *pState->m_shape[i].var_pf_t4; + pState->m_shape[i].t_values_after_init_code[4] = *pState->m_shape[i].var_pf_t5; + pState->m_shape[i].t_values_after_init_code[5] = *pState->m_shape[i].var_pf_t6; + pState->m_shape[i].t_values_after_init_code[6] = *pState->m_shape[i].var_pf_t7; + pState->m_shape[i].t_values_after_init_code[7] = *pState->m_shape[i].var_pf_t8; + */ + + int sides = (int)(*pState->m_shape[i].var_pf_sides); + if (sides<3) sides=3; + if (sides>100) sides=100; + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, ((int)(*pState->m_shape[i].var_pf_additive) != 0) ? D3DBLEND_ONE : D3DBLEND_INVSRCALPHA); + + SPRITEVERTEX v[512]; // for textured shapes (has texcoords) + WFVERTEX v2[512]; // for untextured shapes + borders + + v[0].x = (float)(*pState->m_shape[i].var_pf_x* 2-1);// * ASPECT; + v[0].y = (float)(*pState->m_shape[i].var_pf_y*-2+1); + v[0].z = 0; + v[0].tu = 0.5f; + v[0].tv = 0.5f; + v[0].Diffuse = + ((((int)(*pState->m_shape[i].var_pf_a * 255 * alpha_mult)) & 0xFF) << 24) | + ((((int)(*pState->m_shape[i].var_pf_r * 255)) & 0xFF) << 16) | + ((((int)(*pState->m_shape[i].var_pf_g * 255)) & 0xFF) << 8) | + ((((int)(*pState->m_shape[i].var_pf_b * 255)) & 0xFF) ); + v[1].Diffuse = + ((((int)(*pState->m_shape[i].var_pf_a2 * 255 * alpha_mult)) & 0xFF) << 24) | + ((((int)(*pState->m_shape[i].var_pf_r2 * 255)) & 0xFF) << 16) | + ((((int)(*pState->m_shape[i].var_pf_g2 * 255)) & 0xFF) << 8) | + ((((int)(*pState->m_shape[i].var_pf_b2 * 255)) & 0xFF) ); + + for (int j=1; jm_shape[i].var_pf_rad*cosf(t*3.1415927f*2 + (float)*pState->m_shape[i].var_pf_ang + 3.1415927f*0.25f)*m_fAspectY; // DON'T TOUCH! + v[j].y = v[0].y + (float)*pState->m_shape[i].var_pf_rad*sinf(t*3.1415927f*2 + (float)*pState->m_shape[i].var_pf_ang + 3.1415927f*0.25f); // DON'T TOUCH! + v[j].z = 0; + v[j].tu = 0.5f + 0.5f*cosf(t*3.1415927f*2 + (float)*pState->m_shape[i].var_pf_tex_ang + 3.1415927f*0.25f)/((float)*pState->m_shape[i].var_pf_tex_zoom) * m_fAspectY; // DON'T TOUCH! + v[j].tv = 0.5f + 0.5f*sinf(t*3.1415927f*2 + (float)*pState->m_shape[i].var_pf_tex_ang + 3.1415927f*0.25f)/((float)*pState->m_shape[i].var_pf_tex_zoom); // DON'T TOUCH! + v[j].Diffuse = v[1].Diffuse; + } + v[sides+1] = v[1]; + + if ((int)(*pState->m_shape[i].var_pf_textured) != 0) + { + // draw textured version + lpDevice->SetTexture(0, m_lpVS[0]); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, sides, (void*)v, sizeof(SPRITEVERTEX)); + } + else + { + // no texture + for (j=0; j < sides+2; j++) + { + v2[j].x = v[j].x; + v2[j].y = v[j].y; + v2[j].z = v[j].z; + v2[j].Diffuse = v[j].Diffuse; + } + lpDevice->SetTexture(0, NULL); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( WFVERTEX_FORMAT ); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, sides, (void*)v2, sizeof(WFVERTEX)); + } + + // DRAW BORDER + if (*pState->m_shape[i].var_pf_border_a > 0) + { + lpDevice->SetTexture(0, NULL); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( WFVERTEX_FORMAT ); + + v2[0].Diffuse = + ((((int)(*pState->m_shape[i].var_pf_border_a * 255 * alpha_mult)) & 0xFF) << 24) | + ((((int)(*pState->m_shape[i].var_pf_border_r * 255)) & 0xFF) << 16) | + ((((int)(*pState->m_shape[i].var_pf_border_g * 255)) & 0xFF) << 8) | + ((((int)(*pState->m_shape[i].var_pf_border_b * 255)) & 0xFF) ); + for (j=0; jm_shape[i].var_pf_thick) != 0) ? 4 : 1; + float x_inc = 2.0f / (float)m_nTexSizeX; + float y_inc = 2.0f / (float)m_nTexSizeY; + for (int it=0; itDrawPrimitiveUP(D3DPT_LINESTRIP, sides, (void*)&v2[1], sizeof(WFVERTEX)); + } + } + + lpDevice->SetTexture(0, m_lpVS[0]); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + } + } + } + } + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); +} + +void CPlugin::LoadCustomShapePerFrameEvallibVars(CState* pState, int i, int instance) +{ + *pState->m_shape[i].var_pf_time = (double)(GetTime() - m_fStartTime); + *pState->m_shape[i].var_pf_frame = (double)GetFrame(); + *pState->m_shape[i].var_pf_fps = (double)GetFps(); + *pState->m_shape[i].var_pf_progress = (GetTime() - m_fPresetStartTime) / (m_fNextPresetTime - m_fPresetStartTime); + *pState->m_shape[i].var_pf_bass = (double)mysound.imm_rel[0]; + *pState->m_shape[i].var_pf_mid = (double)mysound.imm_rel[1]; + *pState->m_shape[i].var_pf_treb = (double)mysound.imm_rel[2]; + *pState->m_shape[i].var_pf_bass_att = (double)mysound.avg_rel[0]; + *pState->m_shape[i].var_pf_mid_att = (double)mysound.avg_rel[1]; + *pState->m_shape[i].var_pf_treb_att = (double)mysound.avg_rel[2]; + for (int vi=0; vim_shape[i].var_pf_q[vi] = *pState->var_pf_q[vi]; + for (vi=0; vim_shape[i].var_pf_t[vi] = pState->m_shape[i].t_values_after_init_code[vi]; + *pState->m_shape[i].var_pf_x = pState->m_shape[i].x; + *pState->m_shape[i].var_pf_y = pState->m_shape[i].y; + *pState->m_shape[i].var_pf_rad = pState->m_shape[i].rad; + *pState->m_shape[i].var_pf_ang = pState->m_shape[i].ang; + *pState->m_shape[i].var_pf_tex_zoom = pState->m_shape[i].tex_zoom; + *pState->m_shape[i].var_pf_tex_ang = pState->m_shape[i].tex_ang; + *pState->m_shape[i].var_pf_sides = pState->m_shape[i].sides; + *pState->m_shape[i].var_pf_additive = pState->m_shape[i].additive; + *pState->m_shape[i].var_pf_textured = pState->m_shape[i].textured; + *pState->m_shape[i].var_pf_instances = pState->m_shape[i].instances; + *pState->m_shape[i].var_pf_instance = instance; + *pState->m_shape[i].var_pf_thick = pState->m_shape[i].thickOutline; + *pState->m_shape[i].var_pf_r = pState->m_shape[i].r; + *pState->m_shape[i].var_pf_g = pState->m_shape[i].g; + *pState->m_shape[i].var_pf_b = pState->m_shape[i].b; + *pState->m_shape[i].var_pf_a = pState->m_shape[i].a; + *pState->m_shape[i].var_pf_r2 = pState->m_shape[i].r2; + *pState->m_shape[i].var_pf_g2 = pState->m_shape[i].g2; + *pState->m_shape[i].var_pf_b2 = pState->m_shape[i].b2; + *pState->m_shape[i].var_pf_a2 = pState->m_shape[i].a2; + *pState->m_shape[i].var_pf_border_r = pState->m_shape[i].border_r; + *pState->m_shape[i].var_pf_border_g = pState->m_shape[i].border_g; + *pState->m_shape[i].var_pf_border_b = pState->m_shape[i].border_b; + *pState->m_shape[i].var_pf_border_a = pState->m_shape[i].border_a; +} + +void CPlugin::LoadCustomWavePerFrameEvallibVars(CState* pState, int i) +{ + *pState->m_wave[i].var_pf_time = (double)(GetTime() - m_fStartTime); + *pState->m_wave[i].var_pf_frame = (double)GetFrame(); + *pState->m_wave[i].var_pf_fps = (double)GetFps(); + *pState->m_wave[i].var_pf_progress = (GetTime() - m_fPresetStartTime) / (m_fNextPresetTime - m_fPresetStartTime); + *pState->m_wave[i].var_pf_bass = (double)mysound.imm_rel[0]; + *pState->m_wave[i].var_pf_mid = (double)mysound.imm_rel[1]; + *pState->m_wave[i].var_pf_treb = (double)mysound.imm_rel[2]; + *pState->m_wave[i].var_pf_bass_att = (double)mysound.avg_rel[0]; + *pState->m_wave[i].var_pf_mid_att = (double)mysound.avg_rel[1]; + *pState->m_wave[i].var_pf_treb_att = (double)mysound.avg_rel[2]; + for (int vi=0; vim_wave[i].var_pf_q[vi] = *pState->var_pf_q[vi]; + for (vi=0; vim_wave[i].var_pf_t[vi] = pState->m_wave[i].t_values_after_init_code[vi]; + *pState->m_wave[i].var_pf_r = pState->m_wave[i].r; + *pState->m_wave[i].var_pf_g = pState->m_wave[i].g; + *pState->m_wave[i].var_pf_b = pState->m_wave[i].b; + *pState->m_wave[i].var_pf_a = pState->m_wave[i].a; + *pState->m_wave[i].var_pf_samples = pState->m_wave[i].samples; +} + +// does a better-than-linear smooth on a wave. Roughly doubles the # of points. +int SmoothWave(WFVERTEX* vi, int nVertsIn, WFVERTEX* vo) +{ + const float c1 = -0.15f; + const float c2 = 1.15f; + const float c3 = 1.15f; + const float c4 = -0.15f; + const float inv_sum = 1.0f/(c1+c2+c3+c4); + + int j = 0; + + int i_below = 0; + int i_above; + int i_above2 = 1; + for (int i=0; iSetTexture(0, NULL); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( WFVERTEX_FORMAT ); + + // note: read in all sound data from CPluginShell's m_sound + int num_reps = (m_pState->m_bBlending) ? 2 : 1; + for (int rep=0; repm_fBlendProgress : (1-m_pState->m_fBlendProgress); + + for (int i=0; im_wave[i].enabled) + { + int nSamples = pState->m_wave[i].samples; + int max_samples = pState->m_wave[i].bSpectrum ? 512 : NUM_WAVEFORM_SAMPLES; + if (nSamples > max_samples) + nSamples = max_samples; + nSamples -= pState->m_wave[i].sep; + + // 1. execute per-frame code + LoadCustomWavePerFrameEvallibVars(pState, i); + + // 2.a. do just a once-per-frame init for the *per-point* *READ-ONLY* variables + // (the non-read-only ones will be reset/restored at the start of each vertex) + *pState->m_wave[i].var_pp_time = *pState->m_wave[i].var_pf_time; + *pState->m_wave[i].var_pp_fps = *pState->m_wave[i].var_pf_fps; + *pState->m_wave[i].var_pp_frame = *pState->m_wave[i].var_pf_frame; + *pState->m_wave[i].var_pp_progress = *pState->m_wave[i].var_pf_progress; + *pState->m_wave[i].var_pp_bass = *pState->m_wave[i].var_pf_bass; + *pState->m_wave[i].var_pp_mid = *pState->m_wave[i].var_pf_mid; + *pState->m_wave[i].var_pp_treb = *pState->m_wave[i].var_pf_treb; + *pState->m_wave[i].var_pp_bass_att = *pState->m_wave[i].var_pf_bass_att; + *pState->m_wave[i].var_pp_mid_att = *pState->m_wave[i].var_pf_mid_att; + *pState->m_wave[i].var_pp_treb_att = *pState->m_wave[i].var_pf_treb_att; + + NSEEL_code_execute(pState->m_wave[i].m_pf_codehandle); + + for (int vi=0; vim_wave[i].var_pp_q[vi] = *pState->m_wave[i].var_pf_q[vi]; + for (vi=0; vim_wave[i].var_pp_t[vi] = *pState->m_wave[i].var_pf_t[vi]; + + nSamples = (int)*pState->m_wave[i].var_pf_samples; + nSamples = min(512, nSamples); + + if ((nSamples >= 2) || (pState->m_wave[i].bUseDots && nSamples >= 1)) + { + int j; + float tempdata[2][512]; + float mult = ((pState->m_wave[i].bSpectrum) ? 0.15f : 0.004f) * pState->m_wave[i].scaling * pState->m_fWaveScale.eval(-1); + float *pdata1 = (pState->m_wave[i].bSpectrum) ? m_sound.fSpectrum[0] : m_sound.fWaveform[0]; + float *pdata2 = (pState->m_wave[i].bSpectrum) ? m_sound.fSpectrum[1] : m_sound.fWaveform[1]; + + // initialize tempdata[2][512] + int j0 = (pState->m_wave[i].bSpectrum) ? 0 : (max_samples - nSamples)/2/**(1-pState->m_wave[i].bSpectrum)*/ - pState->m_wave[i].sep/2; + int j1 = (pState->m_wave[i].bSpectrum) ? 0 : (max_samples - nSamples)/2/**(1-pState->m_wave[i].bSpectrum)*/ + pState->m_wave[i].sep/2; + float t = (pState->m_wave[i].bSpectrum) ? (max_samples - pState->m_wave[i].sep)/(float)nSamples : 1; + float mix1 = powf(pState->m_wave[i].smoothing*0.98f, 0.5f); // lower exponent -> more default smoothing + float mix2 = 1-mix1; + // SMOOTHING: + tempdata[0][0] = pdata1[j0]; + tempdata[1][0] = pdata2[j1]; + for (j=1; j=0; j--) + { + tempdata[0][j] = tempdata[0][j]*mix2 + tempdata[0][j+1]*mix1; + tempdata[1][j] = tempdata[1][j]*mix2 + tempdata[1][j+1]*mix1; + } + // finally, scale to final size: + for (j=0; jm_wave[i].var_pp_sample = t; + *pState->m_wave[i].var_pp_value1 = value1; + *pState->m_wave[i].var_pp_value2 = value2; + *pState->m_wave[i].var_pp_x = 0.5f + value1; + *pState->m_wave[i].var_pp_y = 0.5f + value2; + *pState->m_wave[i].var_pp_r = *pState->m_wave[i].var_pf_r; + *pState->m_wave[i].var_pp_g = *pState->m_wave[i].var_pf_g; + *pState->m_wave[i].var_pp_b = *pState->m_wave[i].var_pf_b; + *pState->m_wave[i].var_pp_a = *pState->m_wave[i].var_pf_a; + + #ifndef _NO_EXPR_ + NSEEL_code_execute(pState->m_wave[i].m_pp_codehandle); + #endif + + v[j].x = (float)(*pState->m_wave[i].var_pp_x* 2-1)*m_fInvAspectX; + v[j].y = (float)(*pState->m_wave[i].var_pp_y*-2+1)*m_fInvAspectY; + v[j].z = 0; + v[j].Diffuse = + ((((int)(*pState->m_wave[i].var_pp_a * 255 * alpha_mult)) & 0xFF) << 24) | + ((((int)(*pState->m_wave[i].var_pp_r * 255)) & 0xFF) << 16) | + ((((int)(*pState->m_wave[i].var_pp_g * 255)) & 0xFF) << 8) | + ((((int)(*pState->m_wave[i].var_pp_b * 255)) & 0xFF) ); + } + + + + // save changes to t1-t8 this frame + /* + pState->m_wave[i].t_values_after_init_code[0] = *pState->m_wave[i].var_pp_t1; + pState->m_wave[i].t_values_after_init_code[1] = *pState->m_wave[i].var_pp_t2; + pState->m_wave[i].t_values_after_init_code[2] = *pState->m_wave[i].var_pp_t3; + pState->m_wave[i].t_values_after_init_code[3] = *pState->m_wave[i].var_pp_t4; + pState->m_wave[i].t_values_after_init_code[4] = *pState->m_wave[i].var_pp_t5; + pState->m_wave[i].t_values_after_init_code[5] = *pState->m_wave[i].var_pp_t6; + pState->m_wave[i].t_values_after_init_code[6] = *pState->m_wave[i].var_pp_t7; + pState->m_wave[i].t_values_after_init_code[7] = *pState->m_wave[i].var_pp_t8; + */ + + // 3. smooth it + WFVERTEX v2[2048]; + WFVERTEX *pVerts = v; + if (!pState->m_wave[i].bUseDots) + { + nSamples = SmoothWave(v, nSamples, v2); + pVerts = v2; + } + + // 4. draw it + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, pState->m_wave[i].bAdditive ? D3DBLEND_ONE : D3DBLEND_INVSRCALPHA); + + float ptsize = (float)((m_nTexSizeX >= 1024) ? 2 : 1) + (pState->m_wave[i].bDrawThick ? 1 : 0); + if (pState->m_wave[i].bUseDots) + lpDevice->SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&ptsize) ); + + int its = (pState->m_wave[i].bDrawThick && !pState->m_wave[i].bUseDots) ? 4 : 1; + float x_inc = 2.0f / (float)m_nTexSizeX; + float y_inc = 2.0f / (float)m_nTexSizeY; + for (int it=0; itDrawPrimitiveUP(pState->m_wave[i].bUseDots ? D3DPT_POINTLIST : D3DPT_LINESTRIP, nSamples - (pState->m_wave[i].bUseDots ? 0 : 1), (void*)pVerts, sizeof(WFVERTEX)); + } + + ptsize = 1.0f; + if (pState->m_wave[i].bUseDots) + lpDevice->SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&ptsize) ); + } + } + } + } + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); +} + +void CPlugin::DrawWave(float *fL, float *fR) +{ + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + lpDevice->SetTexture(0, NULL); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( WFVERTEX_FORMAT ); + + int i; + WFVERTEX v1[576+1], v2[576+1]; + + /* + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); //D3DSHADE_FLAT + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE); + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + if (m_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_DITHER) + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE); + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE); + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE); + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_COLORVERTEX, TRUE); + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_WIREFRAME); // vs. SOLID + m_lpD3DDev->SetRenderState(D3DRENDERSTATE_AMBIENT, D3DCOLOR_RGBA_01(1,1,1,1)); + + hr = m_lpD3DDev->SetTexture(0, NULL); + if (hr != D3D_OK) + { + //dumpmsg("Draw(): ERROR: SetTexture"); + //IdentifyD3DError(hr); + } + */ + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, (*m_pState->var_pf_wave_additive) ? D3DBLEND_ONE : D3DBLEND_INVSRCALPHA); + + //float cr = m_pState->m_waveR.eval(GetTime()); + //float cg = m_pState->m_waveG.eval(GetTime()); + //float cb = m_pState->m_waveB.eval(GetTime()); + float cr = (float)(*m_pState->var_pf_wave_r); + float cg = (float)(*m_pState->var_pf_wave_g); + float cb = (float)(*m_pState->var_pf_wave_b); + float cx = (float)(*m_pState->var_pf_wave_x); + float cy = (float)(*m_pState->var_pf_wave_y); // note: it was backwards (top==1) in the original milkdrop, so we keep it that way! + float fWaveParam = (float)(*m_pState->var_pf_wave_mystery); + + /*if (m_pState->m_bBlending) + { + cr = cr*(m_pState->m_fBlendProgress) + (1.0f-m_pState->m_fBlendProgress)*((float)(*m_pOldState->var_pf_wave_r)); + cg = cg*(m_pState->m_fBlendProgress) + (1.0f-m_pState->m_fBlendProgress)*((float)(*m_pOldState->var_pf_wave_g)); + cb = cb*(m_pState->m_fBlendProgress) + (1.0f-m_pState->m_fBlendProgress)*((float)(*m_pOldState->var_pf_wave_b)); + cx = cx*(m_pState->m_fBlendProgress) + (1.0f-m_pState->m_fBlendProgress)*((float)(*m_pOldState->var_pf_wave_x)); + cy = cy*(m_pState->m_fBlendProgress) + (1.0f-m_pState->m_fBlendProgress)*((float)(*m_pOldState->var_pf_wave_y)); + fWaveParam = fWaveParam*(m_pState->m_fBlendProgress) + (1.0f-m_pState->m_fBlendProgress)*((float)(*m_pOldState->var_pf_wave_mystery)); + }*/ + + if (cr < 0) cr = 0; + if (cg < 0) cg = 0; + if (cb < 0) cb = 0; + if (cr > 1) cr = 1; + if (cg > 1) cg = 1; + if (cb > 1) cb = 1; + + // maximize color: + if (*m_pState->var_pf_wave_brighten) + { + float fMaximizeWaveColorAmount = 1.0f; + float max = cr; + if (max < cg) max = cg; + if (max < cb) max = cb; + if (max > 0.01f) + { + cr = cr/max*fMaximizeWaveColorAmount + cr*(1.0f - fMaximizeWaveColorAmount); + cg = cg/max*fMaximizeWaveColorAmount + cg*(1.0f - fMaximizeWaveColorAmount); + cb = cb/max*fMaximizeWaveColorAmount + cb*(1.0f - fMaximizeWaveColorAmount); + } + } + + float fWavePosX = cx*2.0f - 1.0f; // go from 0..1 user-range to -1..1 D3D range + float fWavePosY = cy*2.0f - 1.0f; + + float bass_rel = mysound.imm[0]; + float mid_rel = mysound.imm[1]; + float treble_rel = mysound.imm[2]; + + int sample_offset = 0; + int new_wavemode = (int)(*m_pState->var_pf_wave_mode) % NUM_WAVES; // since it can be changed from per-frame code! + + int its = (m_pState->m_bBlending && (new_wavemode != m_pState->m_nOldWaveMode)) ? 2 : 1; + int nVerts1 = 0; + int nVerts2 = 0; + int nBreak1 = -1; + int nBreak2 = -1; + float alpha1, alpha2; + + for (int it=0; itm_nOldWaveMode; + int nVerts = NUM_WAVEFORM_SAMPLES; // allowed to peek ahead 64 (i.e. left is [i], right is [i+64]) + int nBreak = -1; + + float fWaveParam2 = fWaveParam; + //std::string fWaveParam; // kill its scope + if ((wave==0 || wave==1 || wave==4) && (fWaveParam2 < -1 || fWaveParam2 > 1)) + { + //fWaveParam2 = max(fWaveParam2, -1.0f); + //fWaveParam2 = min(fWaveParam2, 1.0f); + fWaveParam2 = fWaveParam2*0.5f + 0.5f; + fWaveParam2 -= floorf(fWaveParam2); + fWaveParam2 = fabsf(fWaveParam2); + fWaveParam2 = fWaveParam2*2-1; + } + + WFVERTEX *v = (it==0) ? v1 : v2; + ZeroMemory(v, sizeof(WFVERTEX)*nVerts); + + float alpha = (float)(*m_pState->var_pf_wave_a);//m_pState->m_fWaveAlpha.eval(GetTime()); + + switch(wave) + { + case 0: + // circular wave + + nVerts /= 2; + sample_offset = (NUM_WAVEFORM_SAMPLES-nVerts)/2;//mysound.GoGoAlignatron(nVerts * 12/10); // only call this once nVerts is final! + + if (m_pState->m_bModWaveAlphaByVolume) + alpha *= ((mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2])*0.333f - m_pState->m_fModWaveAlphaStart.eval(GetTime()))/(m_pState->m_fModWaveAlphaEnd.eval(GetTime()) - m_pState->m_fModWaveAlphaStart.eval(GetTime())); + if (alpha < 0) alpha = 0; + if (alpha > 1) alpha = 1; + //color = D3DCOLOR_RGBA_01(cr, cg, cb, alpha); + + { + float inv_nverts_minus_one = 1.0f/(float)(nVerts-1); + + for (i=0; im_bBlending) + { + nVerts++; + memcpy(&v[nVerts-1], &v[0], sizeof(WFVERTEX)); + } + + break; + + case 1: + // x-y osc. that goes around in a spiral, in time + + alpha *= 1.25f; + if (m_pState->m_bModWaveAlphaByVolume) + alpha *= ((mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2])*0.333f - m_pState->m_fModWaveAlphaStart.eval(GetTime()))/(m_pState->m_fModWaveAlphaEnd.eval(GetTime()) - m_pState->m_fModWaveAlphaStart.eval(GetTime())); + if (alpha < 0) alpha = 0; + if (alpha > 1) alpha = 1; + //color = D3DCOLOR_RGBA_01(cr, cg, cb, alpha); + + nVerts /= 2; + + for (i=0; im_bModWaveAlphaByVolume) + alpha *= ((mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2])*0.333f - m_pState->m_fModWaveAlphaStart.eval(GetTime()))/(m_pState->m_fModWaveAlphaEnd.eval(GetTime()) - m_pState->m_fModWaveAlphaStart.eval(GetTime())); + if (alpha < 0) alpha = 0; + if (alpha > 1) alpha = 1; + //color = D3DCOLOR_RGBA_01(cr, cg, cb, alpha); + + for (i=0; im_bModWaveAlphaByVolume) + alpha *= ((mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2])*0.333f - m_pState->m_fModWaveAlphaStart.eval(GetTime()))/(m_pState->m_fModWaveAlphaEnd.eval(GetTime()) - m_pState->m_fModWaveAlphaStart.eval(GetTime())); + if (alpha < 0) alpha = 0; + if (alpha > 1) alpha = 1; + //color = D3DCOLOR_RGBA_01(cr, cg, cb, alpha); + + for (i=0; i m_nTexSizeX/3) + nVerts = m_nTexSizeX/3; + + sample_offset = (NUM_WAVEFORM_SAMPLES-nVerts)/2;//mysound.GoGoAlignatron(nVerts + 25); // only call this once nVerts is final! + + /* + if (treble_rel > treb_thresh_for_wave6) + { + //alpha = 1.0f; + treb_thresh_for_wave6 = treble_rel * 1.025f; + } + else + { + alpha *= 0.2f; + treb_thresh_for_wave6 *= 0.996f; // fixme: make this fps-independent + } + */ + + if (m_pState->m_bModWaveAlphaByVolume) + alpha *= ((mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2])*0.333f - m_pState->m_fModWaveAlphaStart.eval(GetTime()))/(m_pState->m_fModWaveAlphaEnd.eval(GetTime()) - m_pState->m_fModWaveAlphaStart.eval(GetTime())); + if (alpha < 0) alpha = 0; + if (alpha > 1) alpha = 1; + //color = D3DCOLOR_RGBA_01(cr, cg, cb, alpha); + + { + float w1 = 0.45f + 0.5f*(fWaveParam2*0.5f + 0.5f); // 0.1 - 0.9 + float w2 = 1.0f - w1; + + float inv_nverts = 1.0f/(float)(nVerts); + + for (i=0; i1) + { + v[i].x = v[i].x*w2 + w1*(v[i-1].x*2.0f - v[i-2].x); + v[i].y = v[i].y*w2 + w1*(v[i-1].y*2.0f - v[i-2].y); + } + } + + /* + // center on Y + float avg_y = 0; + for (i=0; im_bModWaveAlphaByVolume) + alpha *= ((mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2])*0.333f - m_pState->m_fModWaveAlphaStart.eval(GetTime()))/(m_pState->m_fModWaveAlphaEnd.eval(GetTime()) - m_pState->m_fModWaveAlphaStart.eval(GetTime())); + if (alpha < 0) alpha = 0; + if (alpha > 1) alpha = 1; + //color = D3DCOLOR_RGBA_01(cr, cg, cb, alpha); + + { + float cos_rot = cosf(GetTime()*0.3f); + float sin_rot = sinf(GetTime()*0.3f); + + for (i=0; i m_nTexSizeX/3) + nVerts = m_nTexSizeX/3; + + if (wave==8) + nVerts = 256; + else + sample_offset = (NUM_WAVEFORM_SAMPLES-nVerts)/2;//mysound.GoGoAlignatron(nVerts); // only call this once nVerts is final! + + if (m_pState->m_bModWaveAlphaByVolume) + alpha *= ((mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2])*0.333f - m_pState->m_fModWaveAlphaStart.eval(GetTime()))/(m_pState->m_fModWaveAlphaEnd.eval(GetTime()) - m_pState->m_fModWaveAlphaStart.eval(GetTime())); + if (alpha < 0) alpha = 0; + if (alpha > 1) alpha = 1; + //color = D3DCOLOR_RGBA_01(cr, cg, cb, alpha); + + { + float ang = 1.57f*fWaveParam2; // from -PI/2 to PI/2 + float dx = cosf(ang); + float dy = sinf(ang); + + float edge_x[2], edge_y[2]; + + //edge_x[0] = fWavePosX - dx*3.0f; + //edge_y[0] = fWavePosY - dy*3.0f; + //edge_x[1] = fWavePosX + dx*3.0f; + //edge_y[1] = fWavePosY + dy*3.0f; + edge_x[0] = fWavePosX*cosf(ang + 1.57f) - dx*3.0f; + edge_y[0] = fWavePosX*sinf(ang + 1.57f) - dy*3.0f; + edge_x[1] = fWavePosX*cosf(ang + 1.57f) + dx*3.0f; + edge_y[1] = fWavePosX*sinf(ang + 1.57f) + dy*3.0f; + + for (i=0; i<2; i++) // for each point defining the line + { + // clip the point against 4 edges of screen + // be a bit lenient (use +/-1.1 instead of +/-1.0) + // so the dual-wave doesn't end too soon, after the channels are moved apart + for (int j=0; j<4; j++) + { + float t; + bool bClip = false; + + switch(j) + { + case 0: + if (edge_x[i] > 1.1f) + { + t = (1.1f - edge_x[1-i]) / (edge_x[i] - edge_x[1-i]); + bClip = true; + } + break; + case 1: + if (edge_x[i] < -1.1f) + { + t = (-1.1f - edge_x[1-i]) / (edge_x[i] - edge_x[1-i]); + bClip = true; + } + break; + case 2: + if (edge_y[i] > 1.1f) + { + t = (1.1f - edge_y[1-i]) / (edge_y[i] - edge_y[1-i]); + bClip = true; + } + break; + case 3: + if (edge_y[i] < -1.1f) + { + t = (-1.1f - edge_y[1-i]) / (edge_y[i] - edge_y[1-i]); + bClip = true; + } + break; + } + + if (bClip) + { + float dx = edge_x[i] - edge_x[1-i]; + float dy = edge_y[i] - edge_y[1-i]; + edge_x[i] = edge_x[1-i] + dx*t; + edge_y[i] = edge_y[1-i] + dy*t; + } + } + } + + dx = (edge_x[1] - edge_x[0]) / (float)nVerts; + dy = (edge_y[1] - edge_y[0]) / (float)nVerts; + float ang2 = atan2f(dy,dx); + float perp_dx = cosf(ang2 + 1.57f); + float perp_dy = sinf(ang2 + 1.57f); + + if (wave == 6) + for (i=0; ivar_pf_wave_usedots) ? D3DPT_POINTLIST : D3DPT_LINESTRIP; + //m_lpD3DDev->DrawPrimitive(primtype, D3DFVF_LVERTEX, (LPVOID)v, nVerts, NULL); + + for (i=0; im_fBlendProgress); + float mix2 = 1.0f - mix; + + // blend 2 waveforms + if (nVerts2 > 0) + { + // note: this won't yet handle the case where (nBreak1 > 0 && nBreak2 > 0) + // in this case, code must break wave into THREE segments + float m = (nVerts2-1)/(float)nVerts1; + float x,y; + for (int i=0; i 0) + { + alpha1 = alpha1*(mix) + alpha2*(1.0f-mix); + } + + // apply color & alpha + // ALSO reverse all y values, to stay consistent with the pre-VMS milkdrop, + // which DIDN'T: + v1[0].Diffuse = D3DCOLOR_RGBA_01(cr, cg, cb, alpha1); + for (i=0; ivar_pf_wave_usedots) ? D3DPT_POINTLIST : D3DPT_LINESTRIP; + float x_inc = 2.0f / (float)m_nTexSizeX; + float y_inc = 2.0f / (float)m_nTexSizeY; + int drawing_its = ((*m_pState->var_pf_wave_thick || *m_pState->var_pf_wave_usedots) && (m_nTexSizeX >= 512)) ? 4 : 1; + + for (int it=0; itvar_pf_wave_usedots) + lpDevice->DrawPrimitiveUP(D3DPT_POINTLIST, nVerts1, (void*)pVerts, sizeof(WFVERTEX)); + else + lpDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, nVerts1-1, (void*)pVerts, sizeof(WFVERTEX)); + } + else + { + if (*m_pState->var_pf_wave_usedots) + { + lpDevice->DrawPrimitiveUP(D3DPT_POINTLIST, nBreak1, (void*)pVerts, sizeof(WFVERTEX)); + lpDevice->DrawPrimitiveUP(D3DPT_POINTLIST, nVerts1-nBreak1, (void*)&pVerts[nBreak1], sizeof(WFVERTEX)); + } + else + { + lpDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, nBreak1-1, (void*)pVerts, sizeof(WFVERTEX)); + lpDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, nVerts1-nBreak1-1, (void*)&pVerts[nBreak1], sizeof(WFVERTEX)); + } + } + } + } + +SKIP_DRAW_WAVE: + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); +} + +void CPlugin::DrawSprites() +{ + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + lpDevice->SetTexture(0, NULL); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( WFVERTEX_FORMAT ); + + if (*m_pState->var_pf_darken_center) + { + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);//SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + + WFVERTEX v3[6]; + ZeroMemory(v3, sizeof(WFVERTEX)*6); + + // colors: + v3[0].Diffuse = D3DCOLOR_RGBA_01(0, 0, 0, 3.0f/32.0f); + v3[1].Diffuse = D3DCOLOR_RGBA_01(0, 0, 0, 0.0f/32.0f); + v3[2].Diffuse = v3[1].Diffuse; + v3[3].Diffuse = v3[1].Diffuse; + v3[4].Diffuse = v3[1].Diffuse; + v3[5].Diffuse = v3[1].Diffuse; + + // positioning: + float fHalfSize = 0.05f; + v3[0].x = 0.0f; + v3[1].x = 0.0f - fHalfSize*m_fAspectY; + v3[2].x = 0.0f; + v3[3].x = 0.0f + fHalfSize*m_fAspectY; + v3[4].x = 0.0f; + v3[5].x = v3[1].x; + v3[0].y = 0.0f; + v3[1].y = 0.0f; + v3[2].y = 0.0f - fHalfSize; + v3[3].y = 0.0f; + v3[4].y = 0.0f + fHalfSize; + v3[5].y = v3[1].y; + //v3[0].tu = 0; v3[1].tu = 1; v3[2].tu = 0; v3[3].tu = 1; + //v3[0].tv = 1; v3[1].tv = 1; v3[2].tv = 0; v3[3].tv = 0; + + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 4, (LPVOID)v3, sizeof(WFVERTEX)); + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + // do borders + { + float fOuterBorderSize = (float)*m_pState->var_pf_ob_size; + float fInnerBorderSize = (float)*m_pState->var_pf_ib_size; + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + + for (int it=0; it<2; it++) + { + WFVERTEX v3[4]; + ZeroMemory(v3, sizeof(WFVERTEX)*4); + + // colors: + float r = (it==0) ? (float)*m_pState->var_pf_ob_r : (float)*m_pState->var_pf_ib_r; + float g = (it==0) ? (float)*m_pState->var_pf_ob_g : (float)*m_pState->var_pf_ib_g; + float b = (it==0) ? (float)*m_pState->var_pf_ob_b : (float)*m_pState->var_pf_ib_b; + float a = (it==0) ? (float)*m_pState->var_pf_ob_a : (float)*m_pState->var_pf_ib_a; + if (a > 0.001f) + { + v3[0].Diffuse = D3DCOLOR_RGBA_01(r,g,b,a); + v3[1].Diffuse = v3[0].Diffuse; + v3[2].Diffuse = v3[0].Diffuse; + v3[3].Diffuse = v3[0].Diffuse; + + // positioning: + float fInnerRad = (it==0) ? 1.0f - fOuterBorderSize : 1.0f - fOuterBorderSize - fInnerBorderSize; + float fOuterRad = (it==0) ? 1.0f : 1.0f - fOuterBorderSize; + v3[0].x = fInnerRad; + v3[1].x = fOuterRad; + v3[2].x = fOuterRad; + v3[3].x = fInnerRad; + v3[0].y = fInnerRad; + v3[1].y = fOuterRad; + v3[2].y = -fOuterRad; + v3[3].y = -fInnerRad; + + for (int rot=0; rot<4; rot++) + { + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, (LPVOID)v3, sizeof(WFVERTEX)); + + // rotate by 90 degrees + for (int v=0; v<4; v++) + { + float t = 1.570796327f; + float x = v3[v].x; + float y = v3[v].y; + v3[v].x = x*cosf(t) - y*sinf(t); + v3[v].y = x*sinf(t) + y*cosf(t); + } + } + } + } + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } +} + +/* +bool CPlugin::SetMilkdropRenderTarget(LPDIRECTDRAWSURFACE7 lpSurf, int w, int h, char *szErrorMsg) +{ + HRESULT hr = m_lpD3DDev->SetRenderTarget(0, lpSurf, 0); + if (hr != D3D_OK) + { + //if (szErrorMsg && szErrorMsg[0]) dumpmsg(szErrorMsg); + //IdentifyD3DError(hr); + return false; + } + + //DDSURFACEDESC2 ddsd; + //ddsd.dwSize = sizeof(ddsd); + //lpSurf->GetSurfaceDesc(&ddsd); + + D3DVIEWPORT7 viewData; + ZeroMemory(&viewData, sizeof(D3DVIEWPORT7)); + viewData.dwWidth = w; // not: in windowed mode, when lpSurf is the back buffer, chances are good that w,h are smaller than the full surface size (since real size is fullscreen, but we're only using a portion of it as big as the window). + viewData.dwHeight = h; + hr = m_lpD3DDev->SetViewport(&viewData); + + return true; +} +*/ + +void CPlugin::DrawUserSprites() // from system memory, to back buffer. +{ + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + lpDevice->SetTexture(0, NULL); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + + //lpDevice->SetRenderState(D3DRS_WRAP0, 0); + //lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + //lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + //lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP); + + // reset these to the standard safe mode: + lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); + lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + /* + lpDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); //D3DSHADE_GOURAUD + lpDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE); + lpDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + if (m_D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_DITHER) + lpDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + lpDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + lpDevice->SetRenderState(D3DRS_COLORVERTEX, TRUE); + lpDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); // vs. wireframe + lpDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_RGBA_01(1,1,1,1)); + lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTFG_LINEAR ); + lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTFN_LINEAR ); + lpDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTFP_LINEAR ); + */ + + for (int iSlot=0; iSlot < NUM_TEX; iSlot++) + { + if (m_texmgr.m_tex[iSlot].pSurface) + { + int k; + + // set values of input variables: + *(m_texmgr.m_tex[iSlot].var_time) = (double)(GetTime() - m_texmgr.m_tex[iSlot].fStartTime); + *(m_texmgr.m_tex[iSlot].var_frame) = (double)(GetFrame() - m_texmgr.m_tex[iSlot].nStartFrame); + *(m_texmgr.m_tex[iSlot].var_fps) = (double)GetFps(); + *(m_texmgr.m_tex[iSlot].var_progress) = (double)m_pState->m_fBlendProgress; + *(m_texmgr.m_tex[iSlot].var_bass) = (double)mysound.imm_rel[0]; + *(m_texmgr.m_tex[iSlot].var_mid) = (double)mysound.imm_rel[1]; + *(m_texmgr.m_tex[iSlot].var_treb) = (double)mysound.imm_rel[2]; + *(m_texmgr.m_tex[iSlot].var_bass_att) = (double)mysound.avg_rel[0]; + *(m_texmgr.m_tex[iSlot].var_mid_att) = (double)mysound.avg_rel[1]; + *(m_texmgr.m_tex[iSlot].var_treb_att) = (double)mysound.avg_rel[2]; + + // evaluate expressions + #ifndef _NO_EXPR_ + if (m_texmgr.m_tex[iSlot].m_codehandle) + { + NSEEL_code_execute(m_texmgr.m_tex[iSlot].m_codehandle); + } + #endif + + bool bKillSprite = (*m_texmgr.m_tex[iSlot].var_done != 0.0); + bool bBurnIn = (*m_texmgr.m_tex[iSlot].var_burn != 0.0); + + // Remember the original backbuffer and zbuffer + LPDIRECT3DSURFACE9 pBackBuffer=NULL;//, pZBuffer=NULL; + lpDevice->GetRenderTarget( 0, &pBackBuffer ); + //lpDevice->GetDepthStencilSurface( &pZBuffer ); + + if (/*bKillSprite &&*/ bBurnIn) + { + // set up to render [from NULL] to VS1 (for burn-in). + + lpDevice->SetTexture(0, NULL); + + IDirect3DSurface9* pNewTarget = NULL; + if (m_lpVS[1]->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) + return; + lpDevice->SetRenderTarget(0, pNewTarget ); + //lpDevice->SetDepthStencilSurface( NULL ); + pNewTarget->Release(); + + lpDevice->SetTexture(0, NULL); + } + + // finally, use the results to draw the sprite. + if (lpDevice->SetTexture(0, m_texmgr.m_tex[iSlot].pSurface) != D3D_OK) + return; + + SPRITEVERTEX v3[4]; + ZeroMemory(v3, sizeof(SPRITEVERTEX)*4); + + /* + int dest_w, dest_h; + { + LPDIRECT3DSURFACE9 pRT; + lpDevice->GetRenderTarget( 0, &pRT ); + + D3DSURFACE_DESC desc; + pRT->GetDesc(&desc); + dest_w = desc.Width; + dest_h = desc.Height; + pRT->Release(); + }*/ + + float x = min(1000.0f, max(-1000.0f, (float)(*m_texmgr.m_tex[iSlot].var_x) * 2.0f - 1.0f )); + float y = min(1000.0f, max(-1000.0f, (float)(*m_texmgr.m_tex[iSlot].var_y) * 2.0f - 1.0f )); + float sx = min(1000.0f, max(-1000.0f, (float)(*m_texmgr.m_tex[iSlot].var_sx) )); + float sy = min(1000.0f, max(-1000.0f, (float)(*m_texmgr.m_tex[iSlot].var_sy) )); + float rot = (float)(*m_texmgr.m_tex[iSlot].var_rot); + int flipx = (*m_texmgr.m_tex[iSlot].var_flipx == 0.0) ? 0 : 1; + int flipy = (*m_texmgr.m_tex[iSlot].var_flipy == 0.0) ? 0 : 1; + float repeatx = min(100.0f, max(0.01f, (float)(*m_texmgr.m_tex[iSlot].var_repeatx) )); + float repeaty = min(100.0f, max(0.01f, (float)(*m_texmgr.m_tex[iSlot].var_repeaty) )); + + int blendmode = min(4, max(0, ((int)(*m_texmgr.m_tex[iSlot].var_blendmode)))); + float r = min(1.0f, max(0.0f, ((float)(*m_texmgr.m_tex[iSlot].var_r)))); + float g = min(1.0f, max(0.0f, ((float)(*m_texmgr.m_tex[iSlot].var_g)))); + float b = min(1.0f, max(0.0f, ((float)(*m_texmgr.m_tex[iSlot].var_b)))); + float a = min(1.0f, max(0.0f, ((float)(*m_texmgr.m_tex[iSlot].var_a)))); + + // set x,y coords + v3[0+flipx].x = -sx; + v3[1-flipx].x = sx; + v3[2+flipx].x = -sx; + v3[3-flipx].x = sx; + v3[0+flipy*2].y = -sy; + v3[1+flipy*2].y = -sy; + v3[2-flipy*2].y = sy; + v3[3-flipy*2].y = sy; + + // first aspect ratio: adjust for non-1:1 images + { + float aspect = m_texmgr.m_tex[iSlot].img_h / (float)m_texmgr.m_tex[iSlot].img_w; + + if (aspect < 1) + for (k=0; k<4; k++) v3[k].y *= aspect; // wide image + else + for (k=0; k<4; k++) v3[k].x /= aspect; // tall image + } + + // 2D rotation + { + float cos_rot = cosf(rot); + float sin_rot = sinf(rot); + for (k=0; k<4; k++) + { + float x2 = v3[k].x*cos_rot - v3[k].y*sin_rot; + float y2 = v3[k].x*sin_rot + v3[k].y*cos_rot; + v3[k].x = x2; + v3[k].y = y2; + } + } + + // translation + for (k=0; k<4; k++) + { + v3[k].x += x; + v3[k].y += y; + } + + // second aspect ratio: normalize to width of screen + { + float aspect = GetWidth() / (float)(GetHeight()); + + if (aspect > 1) + for (k=0; k<4; k++) v3[k].y *= aspect; + else + for (k=0; k<4; k++) v3[k].x /= aspect; + } + + // third aspect ratio: adjust for burn-in + if (bKillSprite && bBurnIn) // final render-to-VS1 + { + float aspect = GetWidth()/(float)(GetHeight()*4.0f/3.0f); + if (aspect < 1.0f) + for (k=0; k<4; k++) v3[k].x *= aspect; + else + for (k=0; k<4; k++) v3[k].y /= aspect; + } + + // finally, flip 'y' for annoying DirectX + //for (k=0; k<4; k++) v3[k].y *= -1.0f; + + // set u,v coords + { + float dtu = 0.5f;// / (float)m_texmgr.m_tex[iSlot].tex_w; + float dtv = 0.5f;// / (float)m_texmgr.m_tex[iSlot].tex_h; + v3[0].tu = -dtu; + v3[1].tu = dtu;///*m_texmgr.m_tex[iSlot].img_w / (float)m_texmgr.m_tex[iSlot].tex_w*/ - dtu; + v3[2].tu = -dtu; + v3[3].tu = dtu;///*m_texmgr.m_tex[iSlot].img_w / (float)m_texmgr.m_tex[iSlot].tex_w*/ - dtu; + v3[0].tv = -dtv; + v3[1].tv = -dtv; + v3[2].tv = dtv;///*m_texmgr.m_tex[iSlot].img_h / (float)m_texmgr.m_tex[iSlot].tex_h*/ - dtv; + v3[3].tv = dtv;///*m_texmgr.m_tex[iSlot].img_h / (float)m_texmgr.m_tex[iSlot].tex_h*/ - dtv; + + // repeat on x,y + for (k=0; k<4; k++) + { + v3[k].tu = (v3[k].tu - 0.0f)*repeatx + 0.5f; + v3[k].tv = (v3[k].tv - 0.0f)*repeaty + 0.5f; + } + } + + // blendmodes src alpha: dest alpha: + // 0 blend r,g,b=modulate a=opacity SRCALPHA INVSRCALPHA + // 1 decal r,g,b=modulate a=modulate D3DBLEND_ONE D3DBLEND_ZERO + // 2 additive r,g,b=modulate a=modulate D3DBLEND_ONE D3DBLEND_ONE + // 3 srccolor r,g,b=no effect a=no effect SRCCOLOR INVSRCCOLOR + // 4 colorkey r,g,b=modulate a=no effect + switch(blendmode) + { + case 0: + default: + // alpha blend + + /* + Q. I am rendering with alpha blending and setting the alpha + of the diffuse vertex component to determine the opacity. + It works when there is no texture set, but as soon as I set + a texture the alpha that I set is no longer applied. Why? + + The problem originates in the texture blending stages, rather + than in the subsequent alpha blending. Alpha can come from + several possible sources. If this has not been specified, + then the alpha will be taken from the texture, if one is selected. + If no texture is selected, then the default will use the alpha + channel of the diffuse vertex component. + + Explicitly specifying the diffuse vertex component as the source + for alpha will insure that the alpha is drawn from the alpha value + you set, whether a texture is selected or not: + + pDevice->SetSamplerState(D3DSAMP_ALPHAOP,D3DTOP_SELECTARG1); + pDevice->SetSamplerState(D3DSAMP_ALPHAARG1,D3DTA_DIFFUSE); + + If you later need to use the texture alpha as the source, set + D3DSAMP_ALPHAARG1 to D3DTA_TEXTURE. + */ + + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + for (k=0; k<4; k++) v3[k].Diffuse = D3DCOLOR_RGBA_01(r,g,b,a); + break; + case 1: + // decal + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + //lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + //lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + for (k=0; k<4; k++) v3[k].Diffuse = D3DCOLOR_RGBA_01(r*a,g*a,b*a,1); + break; + case 2: + // additive + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + for (k=0; k<4; k++) v3[k].Diffuse = D3DCOLOR_RGBA_01(r*a,g*a,b*a,1); + break; + case 3: + // srccolor + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR); + for (k=0; k<4; k++) v3[k].Diffuse = D3DCOLOR_RGBA_01(1,1,1,1); + break; + case 4: + // color keyed texture: use the alpha value in the texture to + // determine which texels get drawn. + /*lpDevice->SetRenderState(D3DRS_ALPHAREF, 0); + lpDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_NOTEQUAL); + lpDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + */ + + lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); + lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE); + lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + // also, smoothly blend this in-between texels: + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + for (k=0; k<4; k++) v3[k].Diffuse = D3DCOLOR_RGBA_01(r,g,b,a); + break; + } + + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (LPVOID)v3, sizeof(SPRITEVERTEX)); + + if (/*bKillSprite &&*/ bBurnIn) // final render-to-VS1 + { + // Change the rendertarget back to the original setup + lpDevice->SetTexture(0, NULL); + lpDevice->SetRenderTarget( 0, pBackBuffer ); + //lpDevice->SetDepthStencilSurface( pZBuffer ); + lpDevice->SetTexture(0, m_texmgr.m_tex[iSlot].pSurface); + + // undo aspect ratio changes (that were used to fit it to VS1): + { + float aspect = GetWidth()/(float)(GetHeight()*4.0f/3.0f); + if (aspect < 1.0f) + for (k=0; k<4; k++) v3[k].x /= aspect; + else + for (k=0; k<4; k++) v3[k].y *= aspect; + } + + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (LPVOID)v3, sizeof(SPRITEVERTEX)); + } + + SafeRelease(pBackBuffer); + //SafeRelease(pZBuffer); + + if (bKillSprite) + { + KillSprite(iSlot); + } + + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + } + } + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + // reset these to the standard safe mode: + lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); + lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); +} + +void CPlugin::UvToMathSpace(float u, float v, float* rad, float* ang) +{ + // (screen space = -1..1 on both axes; corresponds to UV space) + // uv space = [0..1] on both axes + // "math" space = what the preset authors are used to: + // upper left = [0,0] + // bottom right = [1,1] + // rad == 1 at corners of screen + // ang == 0 at three o'clock, and increases counter-clockwise (to 6.28). + float px = (u*2-1) * m_fAspectX; // probably 1.0 + float py = (v*2-1) * m_fAspectY; // probably <1 + + *rad = sqrtf(px*px + py*py) / sqrtf(m_fAspectX*m_fAspectX + m_fAspectY*m_fAspectY); + *ang = atan2f(py, px); + if (*ang < 0) + *ang += 6.2831853071796f; +} + +void CPlugin::RestoreShaderParams() +{ + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + for (int i=0; i<2; i++) + { + lpDevice->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);//texaddr); + lpDevice->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);//texaddr); + lpDevice->SetSamplerState(i, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP);//texaddr); + lpDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + } + + for (i=0; i<4; i++) + lpDevice->SetTexture( i, NULL ); + + lpDevice->SetVertexShader(NULL); + //lpDevice->SetVertexDeclaration(NULL); -directx debug runtime complains heavily about this + lpDevice->SetPixelShader(NULL); + +} + +void CPlugin::ApplyShaderParams(CShaderParams* p, LPD3DXCONSTANTTABLE pCT, CState* pState) +{ + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + + //if (p->texbind_vs >= 0) lpDevice->SetTexture( p->texbind_vs , m_lpVS[0] ); + //if (p->texbind_noise >= 0) lpDevice->SetTexture( p->texbind_noise, m_pTexNoise ); + + // bind textures + for (int i=0; im_texture_bindings)/sizeof(p->m_texture_bindings[0]); i++) + { + if (p->m_texcode[i] == TEX_VS) + lpDevice->SetTexture(i, m_lpVS[0]); + else + lpDevice->SetTexture(i, p->m_texture_bindings[i].texptr); + + // also set up sampler stage, if anything is bound here... + if (p->m_texcode[i]==TEX_VS || p->m_texture_bindings[i].texptr) + { + bool bAniso = false; + DWORD HQFilter = bAniso ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR; + DWORD wrap = p->m_texture_bindings[i].bWrap ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP; + DWORD filter = p->m_texture_bindings[i].bBilinear ? HQFilter : D3DTEXF_POINT; + lpDevice->SetSamplerState(i, D3DSAMP_ADDRESSU, wrap); + lpDevice->SetSamplerState(i, D3DSAMP_ADDRESSV, wrap); + lpDevice->SetSamplerState(i, D3DSAMP_ADDRESSW, wrap); + lpDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); + lpDevice->SetSamplerState(i, D3DSAMP_MINFILTER, filter); + lpDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, filter); + //lpDevice->SetSamplerState(i, D3DSAMP_MAXANISOTROPY, bAniso ? 4 : 1); //FIXME:ANISO + } + + // finally, if it was a blur texture, note that + if (p->m_texcode[i] >= TEX_BLUR1 && p->m_texcode[i] <= TEX_BLUR_LAST) + m_nHighestBlurTexUsedThisFrame = max(m_nHighestBlurTexUsedThisFrame, ((int)p->m_texcode[i] - (int)TEX_BLUR1) + 1); + } + + // bind "texsize_XYZ" params + int N = p->texsize_params.size(); + for (i=0; itexsize_params[i]); + pCT->SetVector( lpDevice, q->texsize_param, &D3DXVECTOR4((float)q->w,(float)q->h,1.0f/q->w,1.0f/q->h)); + } + + float time_since_preset_start = GetTime() - pState->GetPresetStartTime(); + float time_since_preset_start_wrapped = time_since_preset_start - (int)(time_since_preset_start/10000)*10000; + float time = GetTime() - m_fStartTime; + float progress = (GetTime() - m_fPresetStartTime) / (m_fNextPresetTime - m_fPresetStartTime); + float mip_x = logf((float)GetWidth())/logf(2.0f); + float mip_y = logf((float)GetWidth())/logf(2.0f); + float mip_avg = 0.5f*(mip_x + mip_y); + float aspect_x = 1; + float aspect_y = 1; + if (GetWidth() > GetHeight()) + aspect_y = GetHeight()/(float)GetWidth(); + else + aspect_x = GetWidth()/(float)GetHeight(); + + float blur_min[3], blur_max[3]; + GetSafeBlurMinMax(pState, blur_min, blur_max); + + // bind float4's + if (p->rand_frame ) pCT->SetVector( lpDevice, p->rand_frame , &m_rand_frame ); + if (p->rand_preset) pCT->SetVector( lpDevice, p->rand_preset, &pState->m_rand_preset ); + D3DXHANDLE* h = p->const_handles; + if (h[0]) pCT->SetVector( lpDevice, h[0], &D3DXVECTOR4( aspect_x, aspect_y, 1.0f/aspect_x, 1.0f/aspect_y )); + if (h[1]) pCT->SetVector( lpDevice, h[1], &D3DXVECTOR4(0, 0, 0, 0 )); + if (h[2]) pCT->SetVector( lpDevice, h[2], &D3DXVECTOR4(time_since_preset_start_wrapped, GetFps(), (float)GetFrame(), progress)); + if (h[3]) pCT->SetVector( lpDevice, h[3], &D3DXVECTOR4(mysound.imm_rel[0], mysound.imm_rel[1], mysound.imm_rel[2], 0.3333f*(mysound.imm_rel[0], mysound.imm_rel[1], mysound.imm_rel[2]) )); + if (h[4]) pCT->SetVector( lpDevice, h[4], &D3DXVECTOR4(mysound.avg_rel[0], mysound.avg_rel[1], mysound.avg_rel[2], 0.3333f*(mysound.avg_rel[0], mysound.avg_rel[1], mysound.avg_rel[2]) )); + if (h[5]) pCT->SetVector( lpDevice, h[5], &D3DXVECTOR4( blur_max[0]-blur_min[0], blur_min[0], blur_max[1]-blur_min[1], blur_min[1] )); + if (h[6]) pCT->SetVector( lpDevice, h[6], &D3DXVECTOR4( blur_max[2]-blur_min[2], blur_min[2], blur_min[0], blur_max[0] )); + if (h[7]) pCT->SetVector( lpDevice, h[7], &D3DXVECTOR4((float)m_nTexSizeX, (float)m_nTexSizeY, 1.0f/(float)m_nTexSizeX, 1.0f/(float)m_nTexSizeY )); + if (h[8]) pCT->SetVector( lpDevice, h[8], &D3DXVECTOR4( 0.5f+0.5f*cosf(time* 0.329f+1.2f), + 0.5f+0.5f*cosf(time* 1.293f+3.9f), + 0.5f+0.5f*cosf(time* 5.070f+2.5f), + 0.5f+0.5f*cosf(time*20.051f+5.4f) + )); + if (h[9]) pCT->SetVector( lpDevice, h[9], &D3DXVECTOR4( 0.5f+0.5f*sinf(time* 0.329f+1.2f), + 0.5f+0.5f*sinf(time* 1.293f+3.9f), + 0.5f+0.5f*sinf(time* 5.070f+2.5f), + 0.5f+0.5f*sinf(time*20.051f+5.4f) + )); + if (h[10]) pCT->SetVector( lpDevice, h[10], &D3DXVECTOR4( 0.5f+0.5f*cosf(time*0.0050f+2.7f), + 0.5f+0.5f*cosf(time*0.0085f+5.3f), + 0.5f+0.5f*cosf(time*0.0133f+4.5f), + 0.5f+0.5f*cosf(time*0.0217f+3.8f) + )); + if (h[11]) pCT->SetVector( lpDevice, h[11], &D3DXVECTOR4( 0.5f+0.5f*sinf(time*0.0050f+2.7f), + 0.5f+0.5f*sinf(time*0.0085f+5.3f), + 0.5f+0.5f*sinf(time*0.0133f+4.5f), + 0.5f+0.5f*sinf(time*0.0217f+3.8f) + )); + if (h[12]) pCT->SetVector( lpDevice, h[12], &D3DXVECTOR4( mip_x, mip_y, mip_avg, 0 )); + if (h[13]) pCT->SetVector( lpDevice, h[13], &D3DXVECTOR4( blur_min[1], blur_max[1], blur_min[2], blur_max[2] )); + + // write q vars + int num_q_float4s = sizeof(p->q_const_handles)/sizeof(p->q_const_handles[0]); + for (i=0; iq_const_handles[i]) + pCT->SetVector( lpDevice, p->q_const_handles[i], &D3DXVECTOR4( + (float)*pState->var_pf_q[i*4+0], + (float)*pState->var_pf_q[i*4+1], + (float)*pState->var_pf_q[i*4+2], + (float)*pState->var_pf_q[i*4+3] )); + } + + // write matrices + for (i=0; i<20; i++) + { + if (p->rot_mat[i]) + { + D3DXMATRIX mx,my,mz,mxlate,temp; + + pMatrixRotationX(&mx, pState->m_rot_base[i].x + pState->m_rot_speed[i].x*time); + pMatrixRotationY(&my, pState->m_rot_base[i].y + pState->m_rot_speed[i].y*time); + pMatrixRotationZ(&mz, pState->m_rot_base[i].z + pState->m_rot_speed[i].z*time); + pMatrixTranslation(&mxlate, pState->m_xlate[i].x, pState->m_xlate[i].y, pState->m_xlate[i].z); + + pMatrixMultiply(&temp, &mx, &mxlate); + pMatrixMultiply(&temp, &temp, &mz); + pMatrixMultiply(&temp, &temp, &my); + + pCT->SetMatrix(lpDevice, p->rot_mat[i], &temp); + } + } + // the last 4 are totally random, each frame + for (i=20; i<24; i++) + { + if (p->rot_mat[i]) + { + D3DXMATRIX mx,my,mz,mxlate,temp; + + pMatrixRotationX(&mx, FRAND * 6.28f); + pMatrixRotationY(&my, FRAND * 6.28f); + pMatrixRotationZ(&mz, FRAND * 6.28f); + pMatrixTranslation(&mxlate, FRAND, FRAND, FRAND); + + pMatrixMultiply(&temp, &mx, &mxlate); + pMatrixMultiply(&temp, &temp, &mz); + pMatrixMultiply(&temp, &temp, &my); + + pCT->SetMatrix(lpDevice, p->rot_mat[i], &temp); + } + } +} + +void CPlugin::ShowToUser_NoShaders()//int bRedraw, int nPassOverride) +{ + // note: this one has to draw the whole screen! (one big quad) + + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + lpDevice->SetTexture(0, m_lpVS[1]); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetPixelShader( NULL ); + lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + + // stages 0 and 1 always just use bilinear filtering. + lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + lpDevice->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + + // note: this texture stage state setup works for 0 or 1 texture. + // if you set a texture, it will be modulated with the current diffuse color. + // if you don't set a texture, it will just use the current diffuse color. + lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); + lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + float fZoom = 1.0f; + SPRITEVERTEX v3[4]; + ZeroMemory(v3, sizeof(SPRITEVERTEX)*4); + + // extend the poly we draw by 1 pixel around the viewable image area, + // in case the video card wraps u/v coords with a +0.5-texel offset + // (otherwise, a 1-pixel-wide line of the image would wrap at the top and left edges). + float fOnePlusInvWidth = 1.0f + 1.0f/(float)GetWidth(); + float fOnePlusInvHeight = 1.0f + 1.0f/(float)GetHeight(); + v3[0].x = -fOnePlusInvWidth; + v3[1].x = fOnePlusInvWidth; + v3[2].x = -fOnePlusInvWidth; + v3[3].x = fOnePlusInvWidth; + v3[0].y = fOnePlusInvHeight; + v3[1].y = fOnePlusInvHeight; + v3[2].y = -fOnePlusInvHeight; + v3[3].y = -fOnePlusInvHeight; + + //float aspect = GetWidth() / (float)(GetHeight()/(ASPECT)/**4.0f/3.0f*/); + float aspect = GetWidth() / (float)(GetHeight()*m_fInvAspectY/**4.0f/3.0f*/); + float x_aspect_mult = 1.0f; + float y_aspect_mult = 1.0f; + + if (aspect>1) + y_aspect_mult = aspect; + else + x_aspect_mult = 1.0f/aspect; + + for (int n=0; n<4; n++) + { + v3[n].x *= x_aspect_mult; + v3[n].y *= y_aspect_mult; + } + + { + float shade[4][3] = { + { 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f } }; // for each vertex, then each comp. + + float fShaderAmount = m_pState->m_fShader.eval(GetTime()); + + if (fShaderAmount > 0.001f) + { + for (int i=0; i<4; i++) + { + shade[i][0] = 0.6f + 0.3f*sinf(GetTime()*30.0f*0.0143f + 3 + i*21 + m_fRandStart[3]); + shade[i][1] = 0.6f + 0.3f*sinf(GetTime()*30.0f*0.0107f + 1 + i*13 + m_fRandStart[1]); + shade[i][2] = 0.6f + 0.3f*sinf(GetTime()*30.0f*0.0129f + 6 + i*9 + m_fRandStart[2]); + float max = ((shade[i][0] > shade[i][1]) ? shade[i][0] : shade[i][1]); + if (shade[i][2] > max) max = shade[i][2]; + for (int k=0; k<3; k++) + { + shade[i][k] /= max; + shade[i][k] = 0.5f + 0.5f*shade[i][k]; + } + for (k=0; k<3; k++) + { + shade[i][k] = shade[i][k]*(fShaderAmount) + 1.0f*(1.0f - fShaderAmount); + } + v3[i].Diffuse = D3DCOLOR_RGBA_01(shade[i][0],shade[i][1],shade[i][2],1); + } + } + + float fVideoEchoZoom = (float)(*m_pState->var_pf_echo_zoom);//m_pState->m_fVideoEchoZoom.eval(GetTime()); + float fVideoEchoAlpha = (float)(*m_pState->var_pf_echo_alpha);//m_pState->m_fVideoEchoAlpha.eval(GetTime()); + int nVideoEchoOrientation = (int) (*m_pState->var_pf_echo_orient) % 4;//m_pState->m_nVideoEchoOrientation; + float fGammaAdj = (float)(*m_pState->var_pf_gamma);//m_pState->m_fGammaAdj.eval(GetTime()); + + if (m_pState->m_bBlending && + m_pState->m_fVideoEchoAlpha.eval(GetTime()) > 0.01f && + m_pState->m_fVideoEchoAlphaOld > 0.01f && + m_pState->m_nVideoEchoOrientation != m_pState->m_nVideoEchoOrientationOld) + { + if (m_pState->m_fBlendProgress < m_fSnapPoint) + { + nVideoEchoOrientation = m_pState->m_nVideoEchoOrientationOld; + fVideoEchoAlpha *= 1.0f - 2.0f*CosineInterp(m_pState->m_fBlendProgress); + } + else + { + fVideoEchoAlpha *= 2.0f*CosineInterp(m_pState->m_fBlendProgress) - 1.0f; + } + } + + if (fVideoEchoAlpha > 0.001f) + { + // video echo + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + + for (int i=0; i<2; i++) + { + fZoom = (i==0) ? 1.0f : fVideoEchoZoom; + + float temp_lo = 0.5f - 0.5f/fZoom; + float temp_hi = 0.5f + 0.5f/fZoom; + v3[0].tu = temp_lo; + v3[0].tv = temp_hi; + v3[1].tu = temp_hi; + v3[1].tv = temp_hi; + v3[2].tu = temp_lo; + v3[2].tv = temp_lo; + v3[3].tu = temp_hi; + v3[3].tv = temp_lo; + + // flipping + if (i==1) + { + for (int j=0; j<4; j++) + { + if (nVideoEchoOrientation % 2) + v3[j].tu = 1.0f - v3[j].tu; + if (nVideoEchoOrientation >= 2) + v3[j].tv = 1.0f - v3[j].tv; + } + } + + float mix = (i==1) ? fVideoEchoAlpha : 1.0f - fVideoEchoAlpha; + for (int k=0; k<4; k++) + v3[k].Diffuse = D3DCOLOR_RGBA_01(mix*shade[k][0],mix*shade[k][1],mix*shade[k][2],1); + + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + + if (i==0) + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + } + + if (fGammaAdj > 0.001f) + { + // draw layer 'i' a 2nd (or 3rd, or 4th...) time, additively + int nRedraws = (int)(fGammaAdj - 0.0001f); + float gamma; + + for (int nRedraw=0; nRedraw < nRedraws; nRedraw++) + { + if (nRedraw == nRedraws-1) + gamma = fGammaAdj - (int)(fGammaAdj - 0.0001f); + else + gamma = 1.0f; + + for (int k=0; k<4; k++) + v3[k].Diffuse = D3DCOLOR_RGBA_01(gamma*mix*shade[k][0],gamma*mix*shade[k][1],gamma*mix*shade[k][2],1); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + } + } + } + } + else + { + // no video echo + v3[0].tu = 0; v3[1].tu = 1; v3[2].tu = 0; v3[3].tu = 1; + v3[0].tv = 1; v3[1].tv = 1; v3[2].tv = 0; v3[3].tv = 0; + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + + // draw it iteratively, solid the first time, and additively after that + int nPasses = (int)(fGammaAdj - 0.001f) + 1; + float gamma; + + for (int nPass=0; nPass < nPasses; nPass++) + { + if (nPass == nPasses - 1) + gamma = fGammaAdj - (float)nPass; + else + gamma = 1.0f; + + for (int k=0; k<4; k++) + v3[k].Diffuse = D3DCOLOR_RGBA_01(gamma*shade[k][0],gamma*shade[k][1],gamma*shade[k][2],1); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + + if (nPass==0) + { + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + } + } + } + + SPRITEVERTEX v3[4]; + ZeroMemory(v3, sizeof(SPRITEVERTEX)*4); + float fOnePlusInvWidth = 1.0f + 1.0f/(float)GetWidth(); + float fOnePlusInvHeight = 1.0f + 1.0f/(float)GetHeight(); + v3[0].x = -fOnePlusInvWidth; + v3[1].x = fOnePlusInvWidth; + v3[2].x = -fOnePlusInvWidth; + v3[3].x = fOnePlusInvWidth; + v3[0].y = fOnePlusInvHeight; + v3[1].y = fOnePlusInvHeight; + v3[2].y = -fOnePlusInvHeight; + v3[3].y = -fOnePlusInvHeight; + for (int i=0; i<4; i++) v3[i].Diffuse = D3DCOLOR_RGBA_01(1,1,1,1); + + if (*m_pState->var_pf_brighten && + (GetCaps()->SrcBlendCaps & D3DPBLENDCAPS_INVDESTCOLOR ) && + (GetCaps()->DestBlendCaps & D3DPBLENDCAPS_DESTCOLOR) + ) + { + // square root filter + + //lpDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE); //? + //lpDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); //? + + lpDevice->SetTexture(0, NULL); + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + // first, a perfect invert + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVDESTCOLOR); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + + // then modulate by self (square it) + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + + // then another perfect invert + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVDESTCOLOR); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + } + + if (*m_pState->var_pf_darken && + (GetCaps()->DestBlendCaps & D3DPBLENDCAPS_DESTCOLOR) + ) + { + // squaring filter + + //lpDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE); //? + //lpDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); //? + + lpDevice->SetTexture(0, NULL); + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + + //lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR); + //lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + //lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + + } + + if (*m_pState->var_pf_solarize && + (GetCaps()->SrcBlendCaps & D3DPBLENDCAPS_DESTCOLOR ) && + (GetCaps()->DestBlendCaps & D3DPBLENDCAPS_INVDESTCOLOR) + ) + { + //lpDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE); //? + //lpDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); //? + + lpDevice->SetTexture(0, NULL); + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVDESTCOLOR); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + } + + if (*m_pState->var_pf_invert && + (GetCaps()->SrcBlendCaps & D3DPBLENDCAPS_INVDESTCOLOR ) + ) + { + //lpDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE); //? + //lpDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); //? + + lpDevice->SetTexture(0, NULL); + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVDESTCOLOR); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + + lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, (void*)v3, sizeof(SPRITEVERTEX)); + } + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } +} + +void CPlugin::ShowToUser_Shaders(int nPass, bool bAlphaBlend, bool bFlipAlpha, bool bCullTiles, bool bFlipCulling)//int bRedraw, int nPassOverride, bool bFlipAlpha) +{ + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + //lpDevice->SetTexture(0, m_lpVS[1]); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( MYVERTEX_FORMAT ); + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + float fZoom = 1.0f; + + float aspect = GetWidth() / (float)(GetHeight()*m_fInvAspectY/**4.0f/3.0f*/); + float x_aspect_mult = 1.0f; + float y_aspect_mult = 1.0f; + + if (aspect>1) + y_aspect_mult = aspect; + else + x_aspect_mult = 1.0f/aspect; + + // hue shader + float shade[4][3] = { + { 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f } }; // for each vertex, then each comp. + + float fShaderAmount = 1;//since we don't know if shader uses it or not! m_pState->m_fShader.eval(GetTime()); + + if (fShaderAmount > 0.001f || m_pState->m_bBlending) + { + // pick 4 colors for the 4 corners + for (int i=0; i<4; i++) + { + shade[i][0] = 0.6f + 0.3f*sinf(GetTime()*30.0f*0.0143f + 3 + i*21 + m_fRandStart[3]); + shade[i][1] = 0.6f + 0.3f*sinf(GetTime()*30.0f*0.0107f + 1 + i*13 + m_fRandStart[1]); + shade[i][2] = 0.6f + 0.3f*sinf(GetTime()*30.0f*0.0129f + 6 + i*9 + m_fRandStart[2]); + float max = ((shade[i][0] > shade[i][1]) ? shade[i][0] : shade[i][1]); + if (shade[i][2] > max) max = shade[i][2]; + for (int k=0; k<3; k++) + { + shade[i][k] /= max; + shade[i][k] = 0.5f + 0.5f*shade[i][k]; + } + // note: we now pass the raw hue shader colors down; the shader can only use a certain % if it wants. + //for (k=0; k<3; k++) + // shade[i][k] = shade[i][k]*(fShaderAmount) + 1.0f*(1.0f - fShaderAmount); + //m_comp_verts[i].Diffuse = D3DCOLOR_RGBA_01(shade[i][0],shade[i][1],shade[i][2],1); + } + + // interpolate the 4 colors & apply to all the verts + for (int j=0; jx*0.5f + 0.5f; + float y = p->y*0.5f + 0.5f; + + float col[3] = { 1, 1, 1 }; + if (fShaderAmount > 0.001f) + { + for (int c=0; c<3; c++) + col[c] = shade[0][c]*( x)*( y) + + shade[1][c]*(1-x)*( y) + + shade[2][c]*( x)*(1-y) + + shade[3][c]*(1-x)*(1-y); + } + + // TO DO: improve interp here? + // TO DO: during blend, only send the triangles needed + + // if blending, also set up the alpha values - pull them from the alphas used for the Warped Blit + double alpha = 1; + if (m_pState->m_bBlending) + { + x *= (m_nGridX + 1); + y *= (m_nGridY + 1); + x = max(min(x,m_nGridX-1),0); + y = max(min(y,m_nGridY-1),0); + int nx = (int)x; + int ny = (int)y; + double dx = x - nx; + double dy = y - ny; + double alpha00 = (m_verts[(ny )*(m_nGridX+1) + (nx )].Diffuse >> 24); + double alpha01 = (m_verts[(ny )*(m_nGridX+1) + (nx+1)].Diffuse >> 24); + double alpha10 = (m_verts[(ny+1)*(m_nGridX+1) + (nx )].Diffuse >> 24); + double alpha11 = (m_verts[(ny+1)*(m_nGridX+1) + (nx+1)].Diffuse >> 24); + alpha = alpha00*(1-dx)*(1-dy) + + alpha01*( dx)*(1-dy) + + alpha10*(1-dx)*( dy) + + alpha11*( dx)*( dy); + alpha /= 255.0f; + //if (bFlipAlpha) + // alpha = 1-alpha; + + //alpha = (m_verts[y*(m_nGridX+1) + x].Diffuse >> 24) / 255.0f; + } + p->Diffuse = D3DCOLOR_RGBA_01(col[0],col[1],col[2],alpha); + } + } + } + + int nAlphaTestValue = 0; + if (bFlipCulling) + nAlphaTestValue = 1-nAlphaTestValue; + + if (bAlphaBlend) + { + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + if (bFlipAlpha) + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + } + else + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } + } + else + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + // Now do the final composite blit, fullscreen; + // or do it twice, alpha-blending, if we're blending between two sets of shaders. + + int pass = nPass; + { + // PASS 0: draw using *blended per-vertex motion vectors*, but with the OLD comp shader. + // PASS 1: draw using *blended per-vertex motion vectors*, but with the NEW comp shader. + PShaderInfo* si = (pass==0) ? &m_OldShaders.comp : &m_shaders.comp; + CState* state = (pass==0) ? m_pOldState : m_pState; + + lpDevice->SetVertexDeclaration(m_pMyVertDecl); + lpDevice->SetVertexShader(m_fallbackShaders_vs.comp.ptr); + lpDevice->SetPixelShader (si->ptr); + + ApplyShaderParams( &(si->params), si->CT, state ); + + // Hurl the triangles at the video card. + // We're going to un-index it, so that we don't stress any crappy (AHEM intel g33) + // drivers out there. Not a big deal - only ~800 polys / 24kb of data. + // If we're blending, we'll skip any polygon that is all alpha-blended out. + // This also respects the MaxPrimCount limit of the video card. + MYVERTEX tempv[1024 * 3]; + int primCount = (FCGSX-2)*(FCGSY-2)*2; // although, some might not be drawn! + int max_prims_per_batch = min( GetCaps()->MaxPrimitiveCount, (sizeof(tempv)/sizeof(tempv[0]))/3) - 4; + int src_idx = 0; + while (src_idx < primCount*3) + { + int prims_queued = 0; + int i=0; + while (prims_queued < max_prims_per_batch && src_idx < primCount*3) + { + // copy 3 verts + for (int j=0; j<3; j++) + tempv[i++] = m_comp_verts[ m_comp_indices[src_idx++] ]; + if (bCullTiles) + { + DWORD d1 = (tempv[i-3].Diffuse >> 24); + DWORD d2 = (tempv[i-2].Diffuse >> 24); + DWORD d3 = (tempv[i-1].Diffuse >> 24); + bool bIsNeeded; + if (nAlphaTestValue) + bIsNeeded = ((d1 & d2 & d3) < 255);//(d1 < 255) || (d2 < 255) || (d3 < 255); + else + bIsNeeded = ((d1|d2|d3) > 0);//(d1 > 0) || (d2 > 0) || (d3 > 0); + if (!bIsNeeded) + i -= 3; + else + prims_queued++; + } + else + prims_queued++; + } + if (prims_queued > 0) + lpDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, prims_queued, tempv, sizeof(MYVERTEX) ); + } + } + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + RestoreShaderParams(); +} + +void CPlugin::ShowSongTitleAnim(int w, int h, float fProgress) +{ + int i,x,y; + + if (!m_lpDDSTitle) // this *can* be NULL, if not much video mem! + return; + + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + lpDevice->SetTexture(0, m_lpDDSTitle); + lpDevice->SetVertexShader( NULL ); + lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + + SPRITEVERTEX v3[128]; + ZeroMemory(v3, sizeof(SPRITEVERTEX)*128); + + if (m_supertext.bIsSongTitle) + { + // positioning: + float fSizeX = 50.0f / (float)m_supertext.nFontSizeUsed * powf(1.5f, m_supertext.fFontSize - 2.0f); + float fSizeY = fSizeX * m_nTitleTexSizeY/(float)m_nTitleTexSizeX;// * m_nWidth/(float)m_nHeight; + + if (fSizeX > 0.88f) + { + fSizeY *= 0.88f/fSizeX; + fSizeX = 0.88f; + } + + //fixme + if (fProgress < 1.0f)//(w!=h) // regular render-to-backbuffer + { + //float aspect = w/(float)(h*4.0f/3.0f); + //fSizeY *= aspect; + } + else // final render-to-VS0 + { + //float aspect = GetWidth()/(float)(GetHeight()*4.0f/3.0f); + //if (aspect < 1.0f) + //{ + // fSizeX *= aspect; + // fSizeY *= aspect; + //} + + //fSizeY *= -1; + } + + //if (fSizeX > 0.92f) fSizeX = 0.92f; + //if (fSizeY > 0.92f) fSizeY = 0.92f; + i = 0; + float vert_clip = VERT_CLIP;//1.0f;//0.45f; // warning: visible clipping has been observed at 0.4! + for (y=0; y<8; y++) + { + for (x=0; x<16; x++) + { + v3[i].tu = x/15.0f; + v3[i].tv = (y/7.0f - 0.5f)*vert_clip + 0.5f; + v3[i].x = (v3[i].tu*2.0f - 1.0f)*fSizeX; + v3[i].y = (v3[i].tv*2.0f - 1.0f)*fSizeY; + if (fProgress >= 1.0f) + v3[i].y += 1.0f/(float)m_nTexSizeY; //this is a pretty hacky guess @ getting it to align... + i++; + } + } + + // warping + float ramped_progress = max(0.0f, 1-fProgress*1.5f); + float t2 = powf(ramped_progress, 1.8f)*1.3f; + for (y=0; y<8; y++) + { + for (x=0; x<16; x++) + { + i = y*16+x; + v3[i].x += t2*0.070f*sinf(GetTime()*0.31f + v3[i].x*0.39f - v3[i].y*1.94f); + v3[i].x += t2*0.044f*sinf(GetTime()*0.81f - v3[i].x*1.91f + v3[i].y*0.27f); + v3[i].x += t2*0.061f*sinf(GetTime()*1.31f + v3[i].x*0.61f + v3[i].y*0.74f); + v3[i].y += t2*0.061f*sinf(GetTime()*0.37f + v3[i].x*1.83f + v3[i].y*0.69f); + v3[i].y += t2*0.070f*sinf(GetTime()*0.67f + v3[i].x*0.42f - v3[i].y*1.39f); + v3[i].y += t2*0.087f*sinf(GetTime()*1.07f + v3[i].x*3.55f + v3[i].y*0.89f); + } + } + + // scale down over time + float scale = 1.01f/(powf(fProgress, 0.21f) + 0.01f); + for (i=0; i<128; i++) + { + v3[i].x *= scale; + v3[i].y *= scale; + } + } + else + { + // positioning: + float fSizeX = (float)m_nTexSizeX/1024.0f * 100.0f / (float)m_supertext.nFontSizeUsed * powf(1.033f, m_supertext.fFontSize - 50.0f); + float fSizeY = fSizeX * m_nTitleTexSizeY/(float)m_nTitleTexSizeX; + + //fixme + if (fProgress < 1.0f)//w!=h) // regular render-to-backbuffer + { + //float aspect = w/(float)(h*4.0f/3.0f); + //fSizeY *= aspect; + } + else // final render-to-VS0 + { + //float aspect = GetWidth()/(float)(GetHeight()*4.0f/3.0f); + //if (aspect < 1.0f) + //{ + // fSizeX *= aspect; + // fSizeY *= aspect; + //} + //fSizeY *= -1; + } + + //if (fSize > 0.92f) fSize = 0.92f; + i = 0; + float vert_clip = VERT_CLIP;//0.67f; // warning: visible clipping has been observed at 0.5 (for very short strings) and even 0.6 (for wingdings)! + for (y=0; y<8; y++) + { + for (x=0; x<16; x++) + { + v3[i].tu = x/15.0f; + v3[i].tv = (y/7.0f - 0.5f)*vert_clip + 0.5f; + v3[i].x = (v3[i].tu*2.0f - 1.0f)*fSizeX; + v3[i].y = (v3[i].tv*2.0f - 1.0f)*fSizeY; + if (fProgress >= 1.0f) + v3[i].y += 1.0f/(float)m_nTexSizeY; //this is a pretty hacky guess @ getting it to align... + i++; + } + } + + // apply 'growth' factor and move to user-specified (x,y) + //if (fabsf(m_supertext.fGrowth-1.0f) > 0.001f) + { + float t = (1.0f)*(1-fProgress) + (fProgress)*(m_supertext.fGrowth); + float dx = (m_supertext.fX*2-1); + float dy = (m_supertext.fY*2-1); + if (w!=h) // regular render-to-backbuffer + { + float aspect = w/(float)(h*4.0f/3.0f); + if (aspect < 1) + dx /= aspect; + else + dy *= aspect; + } + + for (i=0; i<128; i++) + { + // note: (x,y) are in (-1,1) range, but m_supertext.f{X|Y} are in (0..1) range + v3[i].x = (v3[i].x)*t + dx; + v3[i].y = (v3[i].y)*t + dy; + } + } + } + + WORD indices[7*15*6]; + i = 0; + for (y=0; y<7; y++) + { + for (x=0; x<15; x++) + { + indices[i++] = y*16 + x; + indices[i++] = y*16 + x + 1; + indices[i++] = y*16 + x + 16; + indices[i++] = y*16 + x + 1; + indices[i++] = y*16 + x + 16; + indices[i++] = y*16 + x + 17; + } + } + + // final flip on y + //for (i=0; i<128; i++) + // v3[i].y *= -1.0f; + for (i=0; i<128; i++) + //v3[i].y /= ASPECT_Y; + v3[i].y *= m_fInvAspectY; + + for (int it=0; it<2; it++) + { + // colors + { + float t; + + if (m_supertext.bIsSongTitle) + t = powf(fProgress, 0.3f)*1.0f; + else + t = CosineInterp(min(1.0f, (fProgress/m_supertext.fFadeTime))); + + if (it==0) + v3[0].Diffuse = D3DCOLOR_RGBA_01(t,t,t,t); + else + v3[0].Diffuse = D3DCOLOR_RGBA_01(t*m_supertext.nColorR/255.0f,t*m_supertext.nColorG/255.0f,t*m_supertext.nColorB/255.0f,t); + + for (i=1; i<128; i++) + v3[i].Diffuse = v3[0].Diffuse; + } + + // nudge down & right for shadow, up & left for solid text + float offset_x = 0, offset_y = 0; + switch(it) + { + case 0: + offset_x = 2.0f/(float)m_nTitleTexSizeX; + offset_y = 2.0f/(float)m_nTitleTexSizeY; + break; + case 1: + offset_x = -4.0f/(float)m_nTitleTexSizeX; + offset_y = -4.0f/(float)m_nTitleTexSizeY; + break; + } + + for (i=0; i<128; i++) + { + v3[i].x += offset_x; + v3[i].y += offset_y; + } + + if (it == 0) + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);//SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR); + } + else + { + lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);//SRCALPHA); + lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + } + + lpDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 128, 15*7*6/3, indices, D3DFMT_INDEX16, v3, sizeof(SPRITEVERTEX)); + } + + lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); +} \ No newline at end of file diff --git a/vis_milk2/plugin.cpp b/vis_milk2/plugin.cpp new file mode 100644 index 0000000..57d8dc9 --- /dev/null +++ b/vis_milk2/plugin.cpp @@ -0,0 +1,9637 @@ +/* + 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. +*/ +/* + ########################################################################################## + + NOTE: + + The DX9 SDK include & lib files for building MilkDrop 2 are right here, in the subdirectory: + .\dx9sdk_summer04\ + + The summer 2004 SDK statically links you to d3dx9.lib (5,820 kb). It bloats vis_milk2.dll + a bit, but we (Ben Allison / Ryan Geiss) decided it's worth the stability. We tinkered + with using the February 2005 sdk, which lets you dynamically link to d3dx9_31.dll (?), + but decided to skip it because it would cause too much hassle/confusion among users. + + Summer 2004 sdk: http://www.microsoft.com/downloads/details.aspx?FamilyID=fd044a42-9912-42a3-9a9e-d857199f888e&DisplayLang=en + Feb 2005 sdk: http://www.microsoft.com/downloads/details.aspx?FamilyId=77960733-06E9-47BA-914A-844575031B81&displaylang=en + + ########################################################################################## +*/ + +/* +Order of Function Calls +----------------------- + The only code that will be called by the plugin framework are the + 12 virtual functions in plugin.h. But in what order are they called? + A breakdown follows. A function name in { } means that it is only + called under certain conditions. + + Order of function calls... + + When the PLUGIN launches + ------------------------ + INITIALIZATION + OverrideDefaults + MyPreInitialize + MyReadConfig + << DirectX gets initialized at this point >> + AllocateMyNonDx9Stuff + AllocateMyDX9Stuff + RUNNING + +--> { CleanUpMyDX9Stuff + AllocateMyDX9Stuff } // called together when user resizes window or toggles fullscreen<->windowed. + | MyRenderFn + | MyRenderUI + | { MyWindowProc } // called, between frames, on mouse/keyboard/system events. 100% threadsafe. + +----<< repeat >> + CLEANUP + CleanUpMyDX9Stuff + CleanUpMyNonDx9Stuff + << DirectX gets uninitialized at this point >> + + When the CONFIG PANEL launches + ------------------------------ + INITIALIZATION + OverrideDefaults + MyPreInitialize + MyReadConfig + << DirectX gets initialized at this point >> + RUNNING + { MyConfigTabProc } // called on startup & on keyboard events + CLEANUP + [ MyWriteConfig ] // only called if user clicked 'OK' to exit + << DirectX gets uninitialized at this point >> +*/ + +/* + NOTES + ----- + + + + To do + ----- + -VMS VERSION: + -based on vms 1.05, but the 'fix slow text' option has been added. + that includes m_lpDDSText, CTextManager (m_text), changes to + DrawDarkTranslucentBox, the replacement of all DrawText calls + (now routed through m_text), and adding the 'fix slow text' cb + to the config panel. + + -KILLED FEATURES: + -vj mode + + -NEW FEATURES FOR 1.04: + -added the following variables for per-frame scripting: (all booleans, except 'gamma') + wave_usedots, wave_thick, wave_additive, wave_brighten + gamma, darken_center, wrap, invert, brighten, darken, solarize + (also, note that echo_zoom, echo_alpha, and echo_orient were already in there, + but weren't covered in the documentation!) + d -fixed: spectrum w/512 samples + 256 separation -> infinite spike + d -reverted dumb changes to aspect ratio stuff + d -reverted wave_y fix; now it's backwards, just like it's always been + (i.e. for wave's y position, 0=bottom and 1=top, which is opposite + to the convention in the rest of milkdrop. decided to keep the + 'bug' so presets don't need modified.) + d -fixed: Krash: Inconsistency bug - pressing Escape while in the code windows + for custom waves completely takes you out of the editing menus, + rather than back to the custom wave menu + d -when editing code: fix display of '&' character + d -internal texture size now has a little more bias toward a finer texture, + based on the window size, when set to 'Auto'. (Before, for example, + to reach 1024x1024, the window had to be 768x768 or greater; now, it + only has to be 640x640 (25% of the way there). I adjusted it because + before, at in-between resolutions like 767x767, it looked very grainy; + now it will always look nice and crisp, at any window size, but still + won't cause too much aliasing (due to downsampling for display). + d -fixed: rova: + When creating presets have commented code // in the per_pixel section when cause error in preset. + Example nothing in per_frame and just comments in the per_pixel. EXamples on repuest I have a few. + d -added kill keys: + -CTRL+K kills all running sprites + -CTRL+T kills current song title anim + -CTRL+Y kills current custom message + d -notice to sprite users: + -in milk_img.ini, color key can't be a range anymore; it's + now limited to just a single color. 'colorkey_lo' and + 'colorkey_hi' have been replaced with just one setting, + 'colorkey'. + d -song titles + custom messages are working again + ? -fixed?: crashes on window resize [out of mem] + -Rova: BTW the same bug as krash with the window resizing. + -NOT due to the 'integrate w/winamp' option. + -> might be fixed now (had forgotten to release m_lpDDSText) + + d -added checkbox to config screen to automatically turn SCROLL LOCK on @ startup + d -added alphanumeric seeking to the playlist; while playlist is up, + you can now press A-Z and 0-9 to seek to the next song in the playlist + that starts with that character. + d - + d - + d - + d - + d - + ? - + ? - + ? - + d - + d - + d - + d - + d - + + -now when playlist is up, SHIFT+A-Z seeks upward (while lowercase/regular a-z seeks downward). + -custom shapes: + -OH MY GOD + -increased max. # of custom shapes (and waves) from 3 to 4 + -added 'texture' option, which allows you to use the last frame as a texture on the shape + -added "tex_ang" and "tex_zoom" params to control the texture coords + -each frame, custom shapes now draw BEFORE regular waveform + custom waves + -added init + per-frame vars: "texture", "additive", "thick", "tex_ang", "tex_zoom" + -fixed valid characters for filenames when importing/exporting custom shapes/waves; + also, it now gives error messages on error in import/export. + -cranked max. meshsize up to 96x72 + -Krash, Rova: now the 'q' variables, as modified by the preset per-frame equations, are again + readable by the custom waves + custom shapes. Sorry about that. Should be the end of the + 'q' confusion. + -added 'meshx' and 'meshy' [read-only] variables to the preset init, per-frame, and per-pixel + equations (...and inc'd the size of the global variable pool by 2). + -removed t1-t8 vars for Custom Shapes; they were unnecessary (since there's no per-point code there). + -protected custom waves from trying to draw when # of sample minus the separation is < 2 + (or 1 if drawing with dots) + -fixed some [minor] preset-blending bugs in the custom wave code + -created a visual map for the flow of values for the q1-q8 and t1-t8 variables: + q_and_t_vars.gif (or something). + -fixed clipping of onscreen text in low-video-memory situations. Now, if there isn't enough + video memory to create an offscreen texture that is at least 75% of the size of the + screen (or to create at least a 256x256 one), it won't bother using one, and will instead draw text directly to the screen. + Otherwise, if the texture is from 75%-99% of the screen size, text will now at least + appear in the correct position on the screen so that it will be visible; this will mean + that the right- and bottom-aligned text will no longer be fully right/bottom-aligned + to the edge of the screen. + -fixed blurry text + -VJ mode is partially restored; the rest will come with beta 7 or the final release. At the time of beta 6, VJ mode still has some glitches in it, but I'm working on them. Most notably, it doesn't resize the text image when you resize the window; that's next on my list. + + -now sprites can burn-in on any frame, not just on the last frame. + set 'burn' to one (in the sprite code) on any frame to make it burn in. + this will break some older sprites, but it's super easy to fix, and + I think it's worth it. =) thanks to papaw00dy for the suggestion! + -fixed the asymptotic-value bug with custom waves using spectral data & having < 512 samples (thanks to telek's example!) + -fixed motion vectors' reversed Y positioning. + -fixed truncation ("...") of long custom messages + -fixed that pesky bug w/the last line of code on a page + -fixed the x-positioning of custom waves & shapes. Before, if you were + saving some coordinates from the preset's per-frame equations (say in q1 and q2) + and then you set "x = q1; y = q2;" in a custom shape's per-frame code + (or in a custom wave's per-point code), the x position wouldn't really be + in the right place, because of aspect ratio multiplications. Before, you had + to actually write "x = (q1-0.5)*0.75 + 0.5; y = q2;" to get it to line up; + now it's fixed, though, and you can just write "x = q1; y = q2;". + -fixed some bugs where the plugin start up, in windowed mode, on the wrong window + (and hence run super slow). + -fixed some bugs w/a munged window frame when the "integrate with winamp" option + was checked. + + -preset ratings are no longer read in all at once; instead, they are scanned in + 1 per frame until they're all in. This fixes the long pauses when you switch + to a directory that has many hundreds of presets. If you want to switch + back to the old way (read them all in at once), there is an option for it + in the config panel. + -cranked max. mesh size up to 128x96 + -fixed bug in custom shape per-frame code, where t1-t8 vars were not + resetting, at the beginning of each frame, to the values that they had + @ the end of the custom shape init code's execution. + - + - + - + + + beta 2 thread: http://forums.winamp.com/showthread.php?threadid=142635 + beta 3 thread: http://forums.winamp.com/showthread.php?threadid=142760 + beta 4 thread: http://forums.winamp.com/showthread.php?threadid=143500 + beta 6 thread: http://forums.winamp.com/showthread.php?threadid=143974 + (+read about beat det: http://forums.winamp.com/showthread.php?threadid=102205) + +@ -code editing: when cursor is on 1st posn. in line, wrong line is highlighted!? + -requests: + -random sprites (...they can just write a prog for this, tho) + -Text-entry mode. + -Like your favorite online game, hit T or something to enter 'text entry' mode. Type a message, then either hit ESC to clear and cancel text-entry mode, or ENTER to display the text on top of the vis. Easier for custom messages than editing the INI file (and probably stopping or minimizing milkdrop to do it) and reloading. + -OR SKIP IT; EASY TO JUST EDIT, RELOAD, AND HIT 00. + -add 'AA' parameter to custom message text file? + -when mem is low, fonts get kicked out -> white boxes + -probably happening b/c ID3DXFont can't create a + temp surface to use to draw text, since all the + video memory is gobbled up. +* -add to installer: q_and_t_vars.gif +* -presets: + 1. pick final set + a. OK-do a pass weeding out slow presets (crank mesh size up) + b. OK-do 2nd pass; rate them & delete crappies + c. OK-merge w/set from 1.03; check for dupes; delete more suckies + 2. OK-check for cpu-guzzlers + 3. OK-check for big ones (>= 8kb) + 4. check for ultra-spastic-when-audio-quiet ones + 5. update all ratings + 6. zip 'em up for safekeeping +* -docs: + -link to milkdrop.co.uk + -preset authoring: + -there are 11 variable pools: + preset: + a) preset init & per-frame code + b) preset per-pixel code + custom wave 1: + c) init & per-frame code + d) per-point code + custom wave 2: + e) init & per-frame code + f) per-point code + custom wave 3: + g) init & per-frame code + h) per-point code + i) custom shape 1: init & per-frame code + j) custom shape 2: init & per-frame code + k) custom shape 3: init & per-frame code + + -all of these have predefined variables, the values of many of which + trickle down from init code, to per-frame code, to per-pixel code, + when the same variable is defined for each of these. + -however, variables that you define ("my_var = 5;") do NOT trickle down. + To allow you to pass custom values from, say, your per-frame code + to your per-pixel code, the variables q1 through q8 were created. + For custom waves and custom shapes, t1 through t8 work similarly. + -q1-q8: + -purpose: to allow [custom] values to carry from {the preset init + and/or per-frame equations}, TO: {the per-pixel equations}, + {custom waves}, and {custom shapes}. + -are first set in preset init code. + -are reset, at the beginning of each frame, to the values that + they had at the end of the preset init code. + -can be modified in per-frame code... + -changes WILL be passed on to the per-pixel code + -changes WILL pass on to the q1-q8 vars in the custom waves + & custom shapes code + -changes will NOT pass on to the next frame, though; + use your own (custom) variables for that. + -can be modified in per-pixel code... + -changes will pass on to the next *pixel*, but no further + -changes will NOT pass on to the q1-q8 vars in the custom + waves or custom shapes code. + -changes will NOT pass on to the next frame, after the + last pixel, though. + -CUSTOM SHAPES: q1-q8... + -are readable in both the custom shape init & per-frame code + -start with the same values as q1-q8 had at the end of the *preset* + per-frame code, this frame + -can be modified in the init code, but only for a one-time + pass-on to the per-frame code. For all subsequent frames + (after the first), the per-frame code will get the q1-q8 + values as described above. + -can be modified in the custom shape per-frame code, but only + as temporary variables; the changes will not pass on anywhere. + -CUSTOM WAVES: q1-q8... + -are readable in the custom wave init, per-frame, and per-point code + -start with the same values as q1-q8 had at the end of the *preset* + per-frame code, this frame + -can be modified in the init code, but only for a one-time + pass-on to the per-frame code. For all subsequent frames + (after the first), the per-frame code will get the q1-q8 + values as described above. + -can be modified in the custom wave per-frame code; changes will + pass on to the per-point code, but that's it. + -can be modified in the per-point code, and the modified values + will pass on from point to point, but won't carry beyond that. + -CUSTOM WAVES: t1-t8... + -allow you to generate & save values in the custom wave init code, + that can pass on to the per-frame and, more sigificantly, + per-point code (since it's in a different variable pool). + -... + + + + !-whatever the values of q1-q8 were at the end of the per-frame and per-pixel + code, these are copied to the q1-q8 variables in the custom wave & custom + shape code, for that frame. However, those values are separate. + For example, if you modify q1-q8 in the custom wave #1 code, those changes + will not be visible anywhere else; if you modify q1-q8 in the custom shape + #2 code, same thing. However, if you modify q1-q8 in the per-frame custom + wave code, those modified values WILL be visible to the per-point custom + wave code, and can be modified within it; but after the last point, + the values q1-q8 will be discarded; on the next frame, in custom wave #1 + per-frame code, the values will be freshly copied from the values of the + main q1-q8 after the preset's per-frame and per-point code have both been + executed. + -monitor: + -can be read/written in preset init code & preset per-frame code. + -not accessible from per-pixel code. + -if you write it on one frame, then that value persists to the next frame. + -t1-t8: + - + - + - + -regular docs: + -put in the stuff recommended by VMS (vidcap, etc.) + -add to troubleshooting: + 1) desktop mode icons not appearing? or + onscreen text looking like colored boxes? + -> try freeing up some video memory. lower your res; drop to 16 bit; + etc. TURN OFF AUTO SONGTITLES. + 1) slow desktop/fullscr mode? -> try disabling auto songtitles + desktop icons. + also try reducing texsize to 256x256, since that eats memory that the text surface could claim. + 2) + 3) + * -presets: + -add new + -fix 3d presets (bring gammas back down to ~1.0) + -check old ones, make sure they're ok + -"Rovastar - Bytes" + -check wave_y + * -document custom waves & shapes + * -slow text is mostly fixed... =( + -desktop icons + playlist both have begin/end around them now, but in desktop mode, + if you bring up playlist or Load menu, fps drops in half; press Esc, and fps doesn't go back up. + - + - + - + -DONE / v1.04: + -updated to VMS 1.05 + -[list benefits...] + - + - + -3d mode: + a) SWAPPED DEFAULT L/R LENS COLORS! All images on the web are left=red, right=blue! + b) fixed image display when viewing a 3D preset in a non-4:3 aspect ratio window + c) gamma now works for 3d presets! (note: you might have to update your old presets. + if they were 3D presets, the gamma was ignored and 1.0 was used; now, + if gamma was >1.0 in the old preset, it will probably appear extremely bright.) + d) added SHIFT+F9 and CTRL+C9 to inc/dec stereo separation + e) added default stereo separation to config panel + -cranked up the max. mesh size (was 48x36, now 64x48) and the default mesh size + (was 24x18, now 32x24) + -fixed aspect ratio for final display + -auto-texsize is now computed slightly differently; for vertically or horizontally-stretched + windows, the texsize is now biased more toward the larger dimension (vs. just the + average). + -added anisotropic filtering (for machines that support it) + -fixed bug where the values of many variables in the preset init code were not set prior + to execution of the init code (e.g. time, bass, etc. were all broken!) + -added various preset blend effects. In addition to the old uniform fade, there is + now a directional wipe, radial wipe, and plasma fade. + -FIXED SLOW TEXT for DX8 (at least, on the geforce 4). + Not using DT_RIGHT or DT_BOTTOM was the key. + + + -why does text kill it in desktop mode? + -text is SLOOW + -to do: add (and use) song title font + tooltip font + -re-test: menus, text, boxes, etc. + -re-test: TIME + -testing: + -make sure sound works perfectly. (had to repro old pre-vms sound analysis!) + -autogamma: currently assumes/requires that GetFrame() resets to 0 on a mode change + (i.e. windowed -> fullscreen)... is that the case? + -restore motion vectors + - + - + -restore lost surfaces + -test bRedraw flag (desktop mode/paused) + -search for //? in milkdropfs.cpp and fix things + + problem: no good soln for VJ mode + problem: D3DX won't give you solid background for your text. + soln: (for later-) create wrapper fn that draws w/solid bkg. + + SOLN?: use D3DX to draw all text (plugin.cpp stuff AND playlist); + then, for VJ mode, create a 2nd DxContext + w/its own window + windowproc + fonts. (YUCK) + 1) config panel: test, and add WM_HELP's (copy from tooltips) + 2) keyboard input: test; and... + -need to reset UI_MODE when playlist is turned on, and + -need to reset m_show_playlist when UI_MODE is changed. (?) + -(otherwise they can both show @ same time and will fight + for keys and draw over each other) + 3) comment out most of D3D stuff in milkdropfs.cpp, and then + get it running w/o any milkdrop, but with text, etc. + 4) sound + + Issues / To Do Later + -------------------- + 1) sprites: color keying stuff probably won't work any more... + 2) scroll lock: pull code from Monkey + 3) m_nGridY should not always be m_nGridX*3/4! + 4) get solid backgrounds for menus, waitstring code, etc. + (make a wrapper function!) + + 99) at end: update help screen + + Things that will be different + ----------------------------- + 1) font sizes are no longer relative to size of window; they are absolute. + 2) 'don't clear screen at startup' option is gone + 3) 'always on top' option is gone + 4) text will not be black-on-white when an inverted-color preset is showing + + -VJ mode: + -notes + 1. (remember window size/pos, and save it from session to session? nah.) + 2. (kiv: scroll lock) + 3. (VJ window + desktop mode:) + -ok w/o VJ mode + -w/VJ mode, regardless of 'fix slow text' option, probs w/focus; + click on vj window, and plugin window flashes to top of Z order! + -goes away if you comment out 1st call to PushWindowToJustBeforeDesktop()... + -when you disable PushWindowToJustBeforeDesktop: + -..and click on EITHER window, milkdrop jumps in front of the taskbar. + -..and click on a non-MD window, nothing happens. + d-FIXED somehow, magically, while fixing bugs w/true fullscreen mode! + 4. (VJ window + true fullscreen mode:) + d-make sure VJ window gets placed on the right monitor, at startup, + and respects taskbar posn. + d-bug - start in windowed mode, then dbl-clk to go [true] fullscreen + on 2nd monitor, all with VJ mode on, and it excepts somewhere + in m_text.DrawNow() in a call to DrawPrimitive()! + FIXED - had to check m_vjd3d8_device->TestCooperativeLevel + each frame, and destroy/reinit if device needed reset. + d-can't resize VJ window when grfx window is running true fullscreen! + -FIXED, by dropping the Sleep(30)/return when m_lost_focus + was true, and by not consuming WM_NCACTIVATE in true fullscreen + mode when m_hTextWnd was present, since DX8 doesn't do its + auto-minimize thing in that case. + + + +*/ + +#include "api.h" +#include "plugin.h" +#include "utility.h" +#include "support.h" +#include "resource.h" +#include "defines.h" +#include "shell_defines.h" +#include +#include +#include // for beginthread, etc. +#include +#include +#include "../nu/AutoCharFn.h" + +#define FRAND ((warand() % 7381)/7380.0f) + +void NSEEL_HOSTSTUB_EnterMutex(){} +void NSEEL_HOSTSTUB_LeaveMutex(){} + +// note: these must match layouts in support.h!! +D3DVERTEXELEMENT9 g_MyVertDecl[] = +{ + { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + { 0, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 32, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, + D3DDECL_END() +}; +D3DVERTEXELEMENT9 g_WfVertDecl[] = +{ + { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + D3DDECL_END() +}; +D3DVERTEXELEMENT9 g_SpriteVertDecl[] = +{ + // matches D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 + { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + { 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + D3DDECL_END() +}; + +//extern CSoundData* pg_sound; // declared in main.cpp +extern CPlugin g_plugin; // declared in main.cpp (note: was 'pg') + +// from support.cpp: +extern bool g_bDebugOutput; +extern bool g_bDumpFileCleared; + +// for __UpdatePresetList: +volatile HANDLE g_hThread; // only r/w from our MAIN thread +volatile bool g_bThreadAlive; // set true by MAIN thread, and set false upon exit from 2nd thread. +volatile int g_bThreadShouldQuit; // set by MAIN thread to flag 2nd thread that it wants it to exit. +static CRITICAL_SECTION g_cs; + +#define IsAlphabetChar(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z')) +#define IsAlphanumericChar(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || (x >= '0' && x <= '9') || x == '.') +#define IsNumericChar(x) (x >= '0' && x <= '9') + +const unsigned char LC2UC[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, + 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,255, + 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, + 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, + 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112, + 113,114,115,116,117,118,119,120,121,122,91,92,93,94,95,96, + 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112, + 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128, + 129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144, + 145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160, + 161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, + 177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192, + 193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208, + 209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224, + 225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240, + 241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, +}; + +/* + * Copies the given string TO the clipboard. + */ +void copyStringToClipboardA(const char * source) +{ + int ok = OpenClipboard(NULL); + if (!ok) + return; + + HGLOBAL clipbuffer; + EmptyClipboard(); + clipbuffer = GlobalAlloc(GMEM_DDESHARE, (lstrlenA(source)+1)*sizeof(char)); + char* buffer = (char*)GlobalLock(clipbuffer); + lstrcpyA(buffer, source); + GlobalUnlock(clipbuffer); + SetClipboardData(CF_TEXT, clipbuffer); + CloseClipboard(); +} + +void copyStringToClipboardW(const wchar_t * source) +{ + int ok = OpenClipboard(NULL); + if (!ok) + return; + + HGLOBAL clipbuffer; + EmptyClipboard(); + clipbuffer = GlobalAlloc(GMEM_DDESHARE, (lstrlenW(source)+1)*sizeof(wchar_t)); + wchar_t* buffer = (wchar_t*)GlobalLock(clipbuffer); + lstrcpyW(buffer, source); + GlobalUnlock(clipbuffer); + SetClipboardData(CF_UNICODETEXT, clipbuffer); + CloseClipboard(); +} + +/* + * Suppose there is a string on the clipboard. + * This function copies it FROM there. + */ +char * getStringFromClipboardA() +{ + int ok = OpenClipboard(NULL); + if (!ok) + return NULL; + + HANDLE hData = GetClipboardData(CF_TEXT); + char* buffer = (char*)GlobalLock(hData); + GlobalUnlock(hData); + CloseClipboard(); + return buffer; +} + +wchar_t * getStringFromClipboardW() +{ + int ok = OpenClipboard(NULL); + if (!ok) + return NULL; + + HANDLE hData = GetClipboardData(CF_UNICODETEXT); + wchar_t* buffer = (wchar_t*)GlobalLock(hData); + GlobalUnlock(hData); + CloseClipboard(); + return buffer; +} + +void ConvertCRsToLFCA(const char* src, char* dst) +{ + while (*src) + { + char ch = *src; + if (*src==13 && *(src+1)==10) + { + *dst++ = LINEFEED_CONTROL_CHAR; + src += 2; + } + else + { + *dst++ = *src++; + } + } + *dst = 0; +} + +void ConvertCRsToLFCW(const wchar_t* src, wchar_t* dst) +{ + while (*src) + { + wchar_t ch = *src; + if (*src==13 && *(src+1)==10) + { + *dst++ = LINEFEED_CONTROL_CHAR; + src += 2; + } + else + { + *dst++ = *src++; + } + } + *dst = 0; +} + +void ConvertLFCToCRsA(const char* src, char* dst) +{ + while (*src) + { + char ch = *src; + if (*src==LINEFEED_CONTROL_CHAR) + { + *dst++ = 13; + *dst++ = 10; + src++; + } + else + { + *dst++ = *src++; + } + } + *dst = 0; +} + +void ConvertLFCToCRsW(const wchar_t* src, wchar_t* dst) +{ + while (*src) + { + wchar_t ch = *src; + if (*src==LINEFEED_CONTROL_CHAR) + { + *dst++ = 13; + *dst++ = 10; + src++; + } + else + { + *dst++ = *src++; + } + } + *dst = 0; +} + +int mystrcmpiW(const wchar_t *s1, const wchar_t *s2) +{ + // returns 1 if s1 comes before s2 + // returns 0 if equal + // returns -1 if s1 comes after s2 + // treats all characters/symbols by their ASCII values, + // except that it DOES ignore case. + + int i=0; + + while (LC2UC[s1[i]] == LC2UC[s2[i]] && s1[i] != 0) + i++; + + //FIX THIS! + + if (s1[i]==0 && s2[i]==0) + return 0; + else if (s1[i]==0) + return -1; + else if (s2[i]==0) + return 1; + else + return (LC2UC[s1[i]] < LC2UC[s2[i]]) ? -1 : 1; +} + +bool ReadFileToString(const wchar_t* szBaseFilename, char* szDestText, int nMaxBytes, bool bConvertLFsToSpecialChar) +{ + wchar_t szFile[MAX_PATH]; + swprintf(szFile, L"%s%s", g_plugin.m_szMilkdrop2Path, szBaseFilename); + + // read in all chars. Replace char combos: { 13; 13+10; 10 } with LINEFEED_CONTROL_CHAR, if bConvertLFsToSpecialChar is true. + FILE* f = _wfopen(szFile, L"rb"); + if (!f) + { + wchar_t buf[1024], title[64]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_READ_DATA_FILE_X), szFile); + g_plugin.dumpmsg(buf); + MessageBoxW(NULL, buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + int len = 0; + int x; + char prev_ch = 0; + while ( (x = fgetc(f)) >= 0 && len < nMaxBytes-4 ) + { + char orig_ch = (char)x; + char ch = orig_ch; + bool bSkipChar = false; + if (bConvertLFsToSpecialChar) + { + if (ch==10) + { + if (prev_ch==13) + bSkipChar = true; + else + ch = LINEFEED_CONTROL_CHAR; + } + else if (ch==13) + ch = LINEFEED_CONTROL_CHAR; + } + + if (!bSkipChar) + szDestText[len++] = ch; + prev_ch = orig_ch; + } + szDestText[len] = 0; + szDestText[len++] = ' '; // make sure there is some whitespace after + fclose(f); + return true; +} + +// these callback functions are called by menu.cpp whenever the user finishes editing an eval_ expression. +void OnUserEditedPerFrame(LPARAM param1, LPARAM param2) +{ + g_plugin.m_pState->RecompileExpressions(RECOMPILE_PRESET_CODE, 0); +} + +void OnUserEditedPerPixel(LPARAM param1, LPARAM param2) +{ + g_plugin.m_pState->RecompileExpressions(RECOMPILE_PRESET_CODE, 0); +} + +void OnUserEditedPresetInit(LPARAM param1, LPARAM param2) +{ + g_plugin.m_pState->RecompileExpressions(RECOMPILE_PRESET_CODE, 1); +} + +void OnUserEditedWavecode(LPARAM param1, LPARAM param2) +{ + g_plugin.m_pState->RecompileExpressions(RECOMPILE_WAVE_CODE, 0); +} + +void OnUserEditedWavecodeInit(LPARAM param1, LPARAM param2) +{ + g_plugin.m_pState->RecompileExpressions(RECOMPILE_WAVE_CODE, 1); +} + +void OnUserEditedShapecode(LPARAM param1, LPARAM param2) +{ + g_plugin.m_pState->RecompileExpressions(RECOMPILE_SHAPE_CODE, 0); +} + +void OnUserEditedShapecodeInit(LPARAM param1, LPARAM param2) +{ + g_plugin.m_pState->RecompileExpressions(RECOMPILE_SHAPE_CODE, 1); +} + +void OnUserEditedWarpShaders(LPARAM param1, LPARAM param2) +{ + g_plugin.m_bNeedRescanTexturesDir = true; + g_plugin.ClearErrors(ERR_PRESET); + if (g_plugin.m_nMaxPSVersion == 0) + return; + if (!g_plugin.RecompilePShader(g_plugin.m_pState->m_szWarpShadersText, &g_plugin.m_shaders.warp, SHADER_WARP, false, g_plugin.m_pState->m_nWarpPSVersion)) + { + // switch to fallback + g_plugin.m_fallbackShaders_ps.warp.ptr->AddRef(); + g_plugin.m_fallbackShaders_ps.warp.CT->AddRef(); + g_plugin.m_shaders.warp = g_plugin.m_fallbackShaders_ps.warp; + } +} + +void OnUserEditedCompShaders(LPARAM param1, LPARAM param2) +{ + g_plugin.m_bNeedRescanTexturesDir = true; + g_plugin.ClearErrors(ERR_PRESET); + if (g_plugin.m_nMaxPSVersion == 0) + return; + if (!g_plugin.RecompilePShader(g_plugin.m_pState->m_szCompShadersText, &g_plugin.m_shaders.comp, SHADER_COMP, false, g_plugin.m_pState->m_nCompPSVersion)) + { + // switch to fallback + g_plugin.m_fallbackShaders_ps.comp.ptr->AddRef(); + g_plugin.m_fallbackShaders_ps.comp.CT->AddRef(); + g_plugin.m_shaders.comp = g_plugin.m_fallbackShaders_ps.comp; + } +} + +// Modify the help screen text here. +// Watch the # of lines, though; if there are too many, they will get cut off; +// and watch the length of the lines, since there is no wordwrap. +// A good guideline: your entire help screen should be visible when fullscreen +// @ 640x480 and using the default help screen font. +wchar_t* g_szHelp = 0; +int g_szHelp_W = 0; + +// this is for integrating modern skins (with their Random button) +// and having it match our Scroll Lock (preset lock) state... +#define IPC_CB_VISRANDOM 628 + +//---------------------------------------------------------------------- + +void CPlugin::OverrideDefaults() +{ + // Here, you have the option of overriding the "default defaults" + // for the stuff on tab 1 of the config panel, replacing them + // with custom defaults for your plugin. + // To override any of the defaults, just uncomment the line + // and change the value. + // DO NOT modify these values from any function but this one! + + // This example plugin only changes the default width/height + // for fullscreen mode; the "default defaults" are just + // 640 x 480. + // If your plugin is very dependent on smooth animation and you + // wanted it plugin to have the 'save cpu' option OFF by default, + // for example, you could set 'm_save_cpu' to 0 here. + + // m_start_fullscreen = 0; // 0 or 1 + // m_start_desktop = 0; // 0 or 1 + // m_fake_fullscreen_mode = 0; // 0 or 1 + // m_max_fps_fs = 30; // 1-120, or 0 for 'unlimited' + // m_max_fps_dm = 30; // 1-120, or 0 for 'unlimited' + // m_max_fps_w = 30; // 1-120, or 0 for 'unlimited' + // m_show_press_f1_msg = 1; // 0 or 1 + m_allow_page_tearing_w = 0; // 0 or 1 + // m_allow_page_tearing_fs = 0; // 0 or 1 + // m_allow_page_tearing_dm = 1; // 0 or 1 + // m_minimize_winamp = 1; // 0 or 1 + // m_desktop_textlabel_boxes = 1; // 0 or 1 + // m_save_cpu = 0; // 0 or 1 + + // lstrcpy(m_fontinfo[0].szFace, "Trebuchet MS"); // system font + // m_fontinfo[0].nSize = 18; + // m_fontinfo[0].bBold = 0; + // m_fontinfo[0].bItalic = 0; + // lstrcpy(m_fontinfo[1].szFace, "Times New Roman"); // decorative font + // m_fontinfo[1].nSize = 24; + // m_fontinfo[1].bBold = 0; + // m_fontinfo[1].bItalic = 1; + + // Don't override default FS mode here; shell is now smart and sets it to match + // the current desktop display mode, by default. + + //m_disp_mode_fs.Width = 1024; // normally 640 + //m_disp_mode_fs.Height = 768; // normally 480 + // use either D3DFMT_X8R8G8B8 or D3DFMT_R5G6B5. + // The former will match to any 32-bit color format available, + // and the latter will match to any 16-bit color available, + // if that exact format can't be found. + //m_disp_mode_fs.Format = D3DFMT_UNKNOWN; //<- this tells config panel & visualizer to use current display mode as a default!! //D3DFMT_X8R8G8B8; + // m_disp_mode_fs.RefreshRate = 60; +} + +//---------------------------------------------------------------------- + +void CPlugin::MyPreInitialize() +{ + // Initialize EVERY data member you've added to CPlugin here; + // these will be the default values. + // If you want to initialize any of your variables with random values + // (using rand()), be sure to seed the random number generator first! + // (If you want to change the default values for settings that are part of + // the plugin shell (framework), do so from OverrideDefaults() above.) + + // seed the system's random number generator w/the current system time: + //srand((unsigned)time(NULL)); -don't - let winamp do it + + // attempt to load a unicode F1 help message otherwise revert to the ansi version + g_szHelp = (wchar_t*)GetTextResource(IDR_TEXT2,1); + if(!g_szHelp) g_szHelp = (wchar_t*)GetTextResource(IDR_TEXT1,0); + else g_szHelp_W = 1; + + // CONFIG PANEL SETTINGS THAT WE'VE ADDED (TAB #2) + m_bFirstRun = true; + m_bInitialPresetSelected = false; + m_fBlendTimeUser = 1.7f; + m_fBlendTimeAuto = 2.7f; + m_fTimeBetweenPresets = 16.0f; + m_fTimeBetweenPresetsRand = 10.0f; + m_bSequentialPresetOrder = false; + m_bHardCutsDisabled = true; + m_fHardCutLoudnessThresh = 2.5f; + m_fHardCutHalflife = 60.0f; + //m_nWidth = 1024; + //m_nHeight = 768; + //m_nDispBits = 16; + m_nCanvasStretch = 0; + m_nTexSizeX = -1; // -1 means "auto" + m_nTexSizeY = -1; // -1 means "auto" + m_nTexBitsPerCh = 8; + m_nGridX = 48;//32; + m_nGridY = 36;//24; + + m_bShowPressF1ForHelp = true; + //lstrcpy(m_szMonitorName, "[don't use multimon]"); + m_bShowMenuToolTips = true; // NOTE: THIS IS CURRENTLY HARDWIRED TO TRUE - NO OPTION TO CHANGE + m_n16BitGamma = 2; + m_bAutoGamma = true; + //m_nFpsLimit = -1; + m_bEnableRating = true; + //m_bInstaScan = false; + m_bSongTitleAnims = true; + m_fSongTitleAnimDuration = 1.7f; + m_fTimeBetweenRandomSongTitles = -1.0f; + m_fTimeBetweenRandomCustomMsgs = -1.0f; + m_nSongTitlesSpawned = 0; + m_nCustMsgsSpawned = 0; + m_nFramesSinceResize = 0; + + //m_bAlways3D = false; + //m_fStereoSep = 1.0f; + //m_bAlwaysOnTop = false; + //m_bFixSlowText = true; + //m_bWarningsDisabled = false; + m_bWarningsDisabled2 = false; + //m_bAnisotropicFiltering = true; + m_bPresetLockOnAtStartup = false; + m_bPreventScollLockHandling = false; + m_nMaxPSVersion_ConfigPanel = -1; // -1 = auto, 0 = disable shaders, 2 = ps_2_0, 3 = ps_3_0 + m_nMaxPSVersion_DX9 = -1; // 0 = no shader support, 2 = ps_2_0, 3 = ps_3_0 + m_nMaxPSVersion = -1; // this one will be the ~min of the other two. 0/2/3. + m_nMaxImages = 32; + m_nMaxBytes = 16000000; + + #ifdef _DEBUG + m_dwShaderFlags = D3DXSHADER_DEBUG|(1<<16); + #else + m_dwShaderFlags = (1<<16);//D3DXSHADER_SKIPOPTIMIZATION|D3DXSHADER_NO_PRESHADER; + #endif + //m_pFragmentLinker = NULL; + //m_pCompiledFragments = NULL; + m_pShaderCompileErrors = NULL; + //m_vs_warp = NULL; + //m_ps_warp = NULL; + //m_vs_comp = NULL; + //m_ps_comp = NULL; + ZeroMemory(&m_shaders, sizeof(PShaderSet)); + ZeroMemory(&m_OldShaders, sizeof(PShaderSet)); + ZeroMemory(&m_NewShaders, sizeof(PShaderSet)); + ZeroMemory(&m_fallbackShaders_vs, sizeof(VShaderSet)); + ZeroMemory(&m_fallbackShaders_ps, sizeof(PShaderSet)); + ZeroMemory(m_BlurShaders, sizeof(m_BlurShaders)); + m_bWarpShaderLock = false; + m_bCompShaderLock = false; + m_bNeedRescanTexturesDir = true; + + // vertex declarations: + m_pSpriteVertDecl = NULL; + m_pWfVertDecl = NULL; + m_pMyVertDecl = NULL; + + m_gdi_title_font_doublesize = NULL; + m_d3dx_title_font_doublesize = NULL; + + // RUNTIME SETTINGS THAT WE'VE ADDED + m_prev_time = GetTime() - 0.0333f; // note: this will be updated each frame, at bottom of MyRenderFn. + m_bTexSizeWasAutoPow2 = false; + m_bTexSizeWasAutoExact = false; + //m_bPresetLockedByUser = false; NOW SET IN DERIVED SETTINGS + m_bPresetLockedByCode = false; + m_fStartTime = 0.0f; + m_fPresetStartTime = 0.0f; + m_fNextPresetTime = -1.0f; // negative value means no time set (...it will be auto-set on first call to UpdateTime) + m_nLoadingPreset = 0; + m_nPresetsLoadedTotal = 0; + m_fSnapPoint = 0.5f; + m_pState = &m_state_DO_NOT_USE[0]; + m_pOldState = &m_state_DO_NOT_USE[1]; + m_pNewState = &m_state_DO_NOT_USE[2]; + m_UI_mode = UI_REGULAR; + m_bShowShaderHelp = false; + + m_nMashSlot = 0; //0..MASH_SLOTS-1 + for (int mash=0; mash0) + for (i=0; i MAX_GRID_X) + m_nGridX = MAX_GRID_X; + if (m_nGridY > MAX_GRID_Y) + m_nGridY = MAX_GRID_Y; + if (m_fTimeBetweenPresetsRand < 0) + m_fTimeBetweenPresetsRand = 0; + if (m_fTimeBetweenPresets < 0.1f) + m_fTimeBetweenPresets = 0.1f; + + // DERIVED SETTINGS + m_bPresetLockedByUser = m_bPresetLockOnAtStartup; + //m_bMilkdropScrollLockState = m_bPresetLockOnAtStartup; +} + +//---------------------------------------------------------------------- + +void CPlugin::MyWriteConfig() +{ + // Write the user's settings to the .INI file. + // This gets called only when the user runs the config panel and hits OK. + // If you've added any controls to the config panel, write their value out + // to the .INI file here. + + // use this function declared in to write a value of this type: + // ----------------- ----------- ---------------------------- + // WritePrivateProfileInt Win32 API int + // WritePrivateProfileInt utility.h bool + // WritePrivateProfileInt utility.h BOOL + // WritePrivateProfileFloat utility.h float + // WritePrivateProfileString Win32 API string + + // ex: WritePrivateProfileInt(m_fog_enabled ,"fog_enabled" ,GetConfigIniFile(),"settings"); + + wchar_t *pIni = GetConfigIniFile(); + + // constants: + WritePrivateProfileStringW(L"settings",L"bConfigured",L"1",pIni); + + //note: m_szPresetDir is not written here; it is written manually, whenever it changes. + + wchar_t szSectionName[] = L"settings"; + + WritePrivateProfileIntW(m_bSongTitleAnims, L"bSongTitleAnims", pIni, L"settings"); + WritePrivateProfileIntW(m_bHardCutsDisabled, L"bHardCutsDisabled", pIni, L"settings"); + WritePrivateProfileIntW(m_bEnableRating, L"bEnableRating", pIni, L"settings"); + //WritePrivateProfileIntW(m_bInstaScan, "bInstaScan", pIni, "settings"); + WritePrivateProfileIntW(g_bDebugOutput, L"bDebugOutput", pIni, L"settings"); + + //itePrivateProfileInt(m_bShowPresetInfo, "bShowPresetInfo", pIni, "settings"); + //itePrivateProfileInt(m_bShowSongInfo, "bShowSongInfo", pIni, "settings"); + //itePrivateProfileInt(m_bFixPinkBug, "bFixPinkBug", pIni, "settings"); + + WritePrivateProfileIntW(m_bShowPressF1ForHelp, L"bShowPressF1ForHelp", pIni, L"settings"); + //itePrivateProfileInt(m_bShowMenuToolTips, "bShowMenuToolTips", pIni, "settings"); + WritePrivateProfileIntW(m_n16BitGamma, L"n16BitGamma", pIni, L"settings"); + WritePrivateProfileIntW(m_bAutoGamma, L"bAutoGamma", pIni, L"settings"); + + //WritePrivateProfileIntW(m_bAlways3D, "bAlways3D", pIni, "settings"); + //WritePrivateProfileFloat(m_fStereoSep, "fStereoSep", pIni, "settings"); + //WritePrivateProfileIntW(m_bFixSlowText, "bFixSlowText", pIni, "settings"); + //itePrivateProfileInt(m_bAlwaysOnTop, "bAlwaysOnTop", pIni, "settings"); + //WritePrivateProfileIntW(m_bWarningsDisabled, "bWarningsDisabled", pIni, "settings"); + WritePrivateProfileIntW(m_bWarningsDisabled2, L"bWarningsDisabled2", pIni, L"settings"); + //WritePrivateProfileIntW(m_bAnisotropicFiltering, "bAnisotropicFiltering",pIni, "settings"); + WritePrivateProfileIntW(m_bPresetLockOnAtStartup,L"bPresetLockOnAtStartup",pIni,L"settings"); + WritePrivateProfileIntW(m_bPreventScollLockHandling,L"m_bPreventScollLockHandling",pIni,L"settings"); + // note: this is also written @ exit of the visualizer + + WritePrivateProfileIntW(m_nCanvasStretch, L"nCanvasStretch", pIni, L"settings"); + WritePrivateProfileIntW(m_nTexSizeX, L"nTexSize", pIni, L"settings"); + WritePrivateProfileIntW(m_nTexBitsPerCh, L"nTexBitsPerCh", pIni, L"settings"); + WritePrivateProfileIntW(m_nGridX, L"nMeshSize", pIni, L"settings"); + WritePrivateProfileIntW(m_nMaxPSVersion_ConfigPanel, L"MaxPSVersion", pIni, L"settings"); + WritePrivateProfileIntW(m_nMaxImages, L"MaxImages", pIni, L"settings"); + WritePrivateProfileIntW(m_nMaxBytes , L"MaxBytes", pIni, L"settings"); + + WritePrivateProfileFloatW(m_fBlendTimeAuto, L"fBlendTimeAuto", pIni, L"settings"); + WritePrivateProfileFloatW(m_fBlendTimeUser, L"fBlendTimeUser", pIni, L"settings"); + WritePrivateProfileFloatW(m_fTimeBetweenPresets, L"fTimeBetweenPresets", pIni, L"settings"); + WritePrivateProfileFloatW(m_fTimeBetweenPresetsRand, L"fTimeBetweenPresetsRand", pIni, L"settings"); + WritePrivateProfileFloatW(m_fHardCutLoudnessThresh, L"fHardCutLoudnessThresh", pIni, L"settings"); + WritePrivateProfileFloatW(m_fHardCutHalflife, L"fHardCutHalflife", pIni, L"settings"); + WritePrivateProfileFloatW(m_fSongTitleAnimDuration, L"fSongTitleAnimDuration", pIni, L"settings"); + WritePrivateProfileFloatW(m_fTimeBetweenRandomSongTitles,L"fTimeBetweenRandomSongTitles",pIni, L"settings"); + WritePrivateProfileFloatW(m_fTimeBetweenRandomCustomMsgs,L"fTimeBetweenRandomCustomMsgs",pIni, L"settings"); +} + +//---------------------------------------------------------------------- + +void ConvertLLCto1310(char* d, const char *s) +{ + // src and dest can NOT be the same pointer. + assert(s != d); + + while (*s) + { + if (*s == LINEFEED_CONTROL_CHAR) + { + *d++ = 13; + *d++ = 10; + } + else + { + *d++ = *s; + } + s++; + }; + *d = 0; +} + +void StripComments(char* str) +{ + if (!str || !str[0] || !str[1]) + return; + + char c0 = str[0]; + char c1 = str[1]; + char* dest = str; + char* p = &str[1]; + bool bIgnoreTilEndOfLine = false; + bool bIgnoreTilCloseComment = false; //this one takes precedence + int nCharsToSkip = 0; + while (1) + { + // handle '//' comments + if (!bIgnoreTilCloseComment && c0=='/' && c1=='/') + bIgnoreTilEndOfLine = true; + if (bIgnoreTilEndOfLine && (c0==10 || c0==13)) + { + bIgnoreTilEndOfLine = false; + nCharsToSkip = 0; + } + + // handle /* */ comments + if (!bIgnoreTilEndOfLine && c0=='/' && c1=='*') + bIgnoreTilCloseComment = true; + if (bIgnoreTilCloseComment && c0=='*' && c1=='/') + { + bIgnoreTilCloseComment = false; + nCharsToSkip = 2; + } + + if (!bIgnoreTilEndOfLine && !bIgnoreTilCloseComment) + { + if (nCharsToSkip > 0) + nCharsToSkip--; + else + *dest++ = c0; + } + + if (c1==0) + break; + + p++; + c0 = c1; + c1 = *p; + } + + *dest++ = 0; +} + +int CPlugin::AllocateMyNonDx9Stuff() +{ + // This gets called only once, when your plugin is actually launched. + // If only the config panel is launched, this does NOT get called. + // (whereas MyPreInitialize() still does). + // If anything fails here, return FALSE to safely exit the plugin, + // but only after displaying a messagebox giving the user some information + // about what went wrong. + + /* + if (!m_hBlackBrush) + m_hBlackBrush = CreateSolidBrush(RGB(0,0,0)); + */ + + g_hThread = INVALID_HANDLE_VALUE; + g_bThreadAlive = false; + g_bThreadShouldQuit = false; + InitializeCriticalSection(&g_cs); + + // read in 'm_szShaderIncludeText' + bool bSuccess = true; + bSuccess = ReadFileToString(L"data\\include.fx", m_szShaderIncludeText, sizeof(m_szShaderIncludeText)-4, false); + if (!bSuccess) return false; + StripComments(m_szShaderIncludeText); + m_nShaderIncludeTextLen = lstrlen(m_szShaderIncludeText); + bSuccess |= ReadFileToString(L"data\\warp_vs.fx", m_szDefaultWarpVShaderText, sizeof(m_szDefaultWarpVShaderText), true); + if (!bSuccess) return false; + bSuccess |= ReadFileToString(L"data\\warp_ps.fx", m_szDefaultWarpPShaderText, sizeof(m_szDefaultWarpPShaderText), true); + if (!bSuccess) return false; + bSuccess |= ReadFileToString(L"data\\comp_vs.fx", m_szDefaultCompVShaderText, sizeof(m_szDefaultCompVShaderText), true); + if (!bSuccess) return false; + bSuccess |= ReadFileToString(L"data\\comp_ps.fx", m_szDefaultCompPShaderText, sizeof(m_szDefaultCompPShaderText), true); + if (!bSuccess) return false; + bSuccess |= ReadFileToString(L"data\\blur_vs.fx", m_szBlurVS, sizeof(m_szBlurVS), true); + if (!bSuccess) return false; + bSuccess |= ReadFileToString(L"data\\blur1_ps.fx", m_szBlurPSX, sizeof(m_szBlurPSX), true); + if (!bSuccess) return false; + bSuccess |= ReadFileToString(L"data\\blur2_ps.fx", m_szBlurPSY, sizeof(m_szBlurPSY), true); + if (!bSuccess) return false; + + BuildMenus(); + + m_bMMX = CheckForMMX(); + //m_bSSE = CheckForSSE(); + + m_pState->Default(); + m_pOldState->Default(); + m_pNewState->Default(); + + //LoadRandomPreset(0.0f); -avoid this here; causes some DX9 stuff to happen. + + return true; +} + +//---------------------------------------------------------------------- + +void CancelThread(int max_wait_time_ms) +{ + g_bThreadShouldQuit = true; + int waited = 0; + while (g_bThreadAlive && waited < max_wait_time_ms) + { + Sleep(30); + waited += 30; + } + + if (g_bThreadAlive) + { + TerminateThread(g_hThread,0); + g_bThreadAlive = false; + } + + if (g_hThread != INVALID_HANDLE_VALUE) + CloseHandle(g_hThread); + g_hThread = INVALID_HANDLE_VALUE; +} + +void CPlugin::CleanUpMyNonDx9Stuff() +{ + // This gets called only once, when your plugin exits. + // Be sure to clean up any objects here that were + // created/initialized in AllocateMyNonDx9Stuff. + + //sound.Finish(); + + // NOTE: DO NOT DELETE m_gdi_titlefont_doublesize HERE!!! + + DeleteCriticalSection(&g_cs); + + CancelThread(0); + + m_menuPreset .Finish(); + m_menuWave .Finish(); + m_menuAugment .Finish(); + m_menuCustomWave.Finish(); + m_menuCustomShape.Finish(); + m_menuMotion .Finish(); + m_menuPost .Finish(); + for (int i=0; i 0.5f) + return powf(x*2-1, fExp)*0.5f + 0.5f; + + return (1-powf(1-x*2, fExp))*0.5f; +} + +int GetNearestPow2Size(int w, int h) +{ + float fExp = logf( max(w,h)*0.75f + 0.25f*min(w,h) ) / logf(2.0f); + float bias = 0.55f; + if (fExp + bias >= 11.0f) // ..don't jump to 2048x2048 quite as readily + bias = 0.5f; + int nExp = (int)(fExp + bias); + int log2size = (int)powf(2.0f, (float)nExp); + return log2size; +} + +int CPlugin::AllocateMyDX9Stuff() +{ + // (...aka OnUserResizeWindow) + // (...aka OnToggleFullscreen) + + // Allocate and initialize all your DX9 and D3DX stuff here: textures, + // surfaces, vertex/index buffers, D3DX fonts, and so on. + // If anything fails here, return FALSE to safely exit the plugin, + // but only after displaying a messagebox giving the user some information + // about what went wrong. If the error is NON-CRITICAL, you don't *have* + // to return; just make sure that the rest of the code will be still safely + // run (albeit with degraded features). + // If you run out of video memory, you might want to show a short messagebox + // saying what failed to allocate and that the reason is a lack of video + // memory, and then call SuggestHowToFreeSomeMem(), which will show them + // a *second* messagebox that (intelligently) suggests how they can free up + // some video memory. + // Don't forget to account for each object you create/allocate here by cleaning + // it up in CleanUpMyDX9Stuff! + // IMPORTANT: + // Note that the code here isn't just run at program startup! + // When the user toggles between fullscreen and windowed modes + // or resizes the window, the base class calls this function before + // destroying & recreating the plugin window and DirectX object, and then + // calls AllocateMyDX9Stuff afterwards, to get your plugin running again. + + wchar_t buf[32768], title[64]; + + m_nFramesSinceResize = 0; + + int nNewCanvasStretch = (m_nCanvasStretch == 0) ? 100 : m_nCanvasStretch; + + DWORD PSVersion = GetCaps()->PixelShaderVersion & 0xFFFF; // 0x0300, etc. + if (PSVersion >= 0x0300) + m_nMaxPSVersion_DX9 = MD2_PS_3_0; + else if (PSVersion > 0x0200) + m_nMaxPSVersion_DX9 = MD2_PS_2_X; + else if (PSVersion >= 0x0200) + m_nMaxPSVersion_DX9 = MD2_PS_2_0; + else + m_nMaxPSVersion_DX9 = MD2_PS_NONE; + + if (m_nMaxPSVersion_ConfigPanel == -1) + m_nMaxPSVersion = m_nMaxPSVersion_DX9; + else + { + // to still limit their choice by what HW reports: + //m_nMaxPSVersion = min(m_nMaxPSVersion_DX9, m_nMaxPSVersion_ConfigPanel); + + // to allow them to override: + m_nMaxPSVersion = m_nMaxPSVersion_ConfigPanel; + } + + /* + Auto mode: do a check against a few known, *SLOW* DX9/ps_2_0 cards to see + if we should run them without pixel shaders instead. + Here is valve's list of the cards they run DX8 on (mostly because they're too slow under DX9 + ps_2_0): + NVIDIA GeForce FX 5200  31.12% + ATI Radeon 9200         21.29% + NVIDIA GeForce FX 5500  11.27% + NVIDIA GeForce4          7.74% + NVIDIA GeForce FX 5700   7.12% + NVIDIA GeForce FX 5600   5.16% + SiS 661FX_760_741        3.34% + NVIDIA GeForce FX 5900   3.24% + NVIDIA GeForce3          2.09% + ATI Radeon 9000          1.98% + other                    5.66% + [ from http://www.steampowered.com/status/survey.html ] + see also: + http://en.wikipedia.org/wiki/Radeon + http://en.wikipedia.org/wiki/Geforce_fx + */ + + const char* szGPU = GetDriverDescription(); + /* known examples of this string: + "ATI MOBILITY RADEON X600" + "RADEON X800 Series " <- note the spaces at the end + "Sapphire RADEON X700" + "NVIDIA GeForce Go 6200 " <- note the spaces at the end + "NVIDIA GeForce 6800 GT" + "Intel(R) 82865G Graphics Controller" + "Mobile Intel(R) 915GM/GMS,910GML Express Chipset Family" + + might want to consider adding these to the list: [from http://www.intel.com/support/graphics/sb/cs-014257.htm ] + (...they should support PS2.0, but not sure if they're fast...) + "Mobile Intel(R) 945GM Express Chipset Family" + "Mobile Intel(R) 915GM/GMS,910GML Express Chipset" + "Intel(R) 945G Express Chipset" + "Intel(R) 82915G/82910GL Express Chipset Family" + + or these, if they seem to be reporting that they do support ps_2_0, which would be very bogus info: + "Intel(R) 82865G Graphics Controller" + "Intel(R) 82852/82855 Graphics Controller Family" + "Intel(R) 82845G Graphics Controller" + "Intel(R) 82830M Graphics Controller" + "Intel(R) 82815 Graphics Controller" + "Intel(R) 82810 Graphics Controller" + */ + + // GREY LIST - slow ps_2_0 cards + // In Canvas Stretch==Auto mode, for these cards, if they (claim to) run ps_2_0, + // we run at half-res (cuz they're slow). + // THE GENERAL GUIDELINE HERE: + // It should be at least as fast as a GeForce FX 5700 or my GeForce 6200 (TC) + // if it's to run without stretch. + if (m_nCanvasStretch==0)// && m_nMaxPSVersion_DX9 > 0) + { + // put cards on this list if you see them successfully run ps_2_0 (using override) + // and they run well at a low resolution (512x512 or less). + if ( + strstr(szGPU, "GeForce 4" ) || // probably not even ps_2_0 + strstr(szGPU, "GeForce FX 52" ) || // chip's computer (FX 5200) - does do ps_2_0, but slow + strstr(szGPU, "GeForce FX 53" ) || + strstr(szGPU, "GeForce FX 54" ) || + strstr(szGPU, "GeForce FX 55" ) || //GeForce FX 5600 is 13 GB/s - 2.5x as fast as my 6200! + strstr(szGPU, "GeForce FX 56" ) || + //...GeForce FX 5700 and up, we let those run at full-res on ps_2_0... + strstr(szGPU, "GeForce FX 56" ) || + strstr(szGPU, "GeForce FX 56" ) || + strstr(szGPU, "SiS 300/305/630/540/730") || // mom's computer - just slow. + strstr(szGPU, "Radeon 8" ) || // no shader model 2. + strstr(szGPU, "Radeon 90" ) || // from Valve. no shader model 2. + strstr(szGPU, "Radeon 91" ) || // no shader model 2. + strstr(szGPU, "Radeon 92" ) || // from Valve. no shader model 2. + strstr(szGPU, "Radeon 93" ) || // no shader model 2. + strstr(szGPU, "Radeon 94" ) || // no shader model 2. + // guessing that 9500+ are ok - they're all ps_2_0 and the 9600 is like an FX 5900. + strstr(szGPU, "Radeon 9550") || // *maybe* - kiv - super budget R200 chip. def. ps_2_0 but possibly very slow. + strstr(szGPU, "Radeon X300") || // *maybe* - kiv - super budget R200 chip def. ps_2_0 but possibly very slow. + 0) + { + nNewCanvasStretch = 200; + } + } + + /* pix pipes + core Fill(G) membw(GB/s) + Radeon 9600 Pro 400 4 1.6 9.6 + Radeon 9600 XT 500 4 2.0 9.6 + GeForce FX 5600 Ultra 400 4 1.6 12.8 + GeForce FX 5700 Ultra 475 4 1.9 14.4 + GeForce FX 5900 XT 400 4 1.6 22.4 + GeForce FX 5900 450 4 1.8 27.2 + GeForce FX 5950 Ultra 475 4 2.9 30 + GeForce 6200 TC-32 350 4 1.1 5.6 (TurboDonkey) + GeForce 6600 GT 500 8 2.0 16 + GeForce 6800 Ultra 400 16 6.4 35 + ATI Radeon X800 XT PE 520 16 8.3 36 + ATI Radeon X850 XT PE 540 16 8.6 38 + + Entry-level GPU 5200, 5300, 5500 + Mid-Range GPU 5600, 5700 + High-end GPU 5800, 5900, 5950 + + Entry-level GPU 6200, 6500 + Mid-Range GPU 6600 + High-end GPU 6800 + + Entry-level GPU + Mid-Range GPU + High-end GPU + + R200: only ps_1_4. Radeon 8500-9250. + R300: ps_2_0. Radeon 9500-9800, X300-X600, X1050. 9600 fast enough (~FX5900). 9500/9700 ~ GeForce 4 Ti. + R420: ps_2_0 Radeon X700-8750 - ALL FAST ENOUGH. X700 is same speed as a GeForce 6600. + + 6600 ~ X700 + GeForce 4 < X300 / X600 / 9600 + GeForce 4 Ti > Radeon 8500 + FX 5900 = Radeon 9600 + FX 5900 Ultra << [half] Radeon 9800 Pro + GeForce FX < Radeon 9700/9800 + */ + + // BLACK LIST + // In Pixel Shaders==Auto mode, for these cards, we avoid ps_2_0 completely. + // There shouldn't be much on this list... feel free to put anything you KNOW doesn't do ps_2_0 (why not), + // and to put anything that is slow to begin with, and HAS BUGGY DRIVERS (INTEL). + if (m_nMaxPSVersion_ConfigPanel==-1) + { + if (strstr(szGPU, "GeForce2" ) || // from Valve + strstr(szGPU, "GeForce3" ) || // from Valve + strstr(szGPU, "GeForce4" ) || // from Valve + strstr(szGPU, "Radeon 7" ) || // from Valve + strstr(szGPU, "Radeon 8" ) || + strstr(szGPU, "SiS 661FX_760_741") || // from Valve + //FOR NOW, FOR THESE, ASSUME INTEL EITHER DOESN'T DO PS_2_0, + //OR DRIVERS SUCK AND IT WOULDN'T WORK ANYWAY! + (strstr(szGPU,"Intel") && strstr(szGPU,"945G")) || + (strstr(szGPU,"Intel") && strstr(szGPU,"915G")) || // ben allison's laptop - snow, freezing when you try ps_2_0 + (strstr(szGPU,"Intel") && strstr(szGPU,"910G")) || + (strstr(szGPU,"Intel") && strstr(szGPU,"8291")) || // gonna guess that this supports ps_2_0 but is SLOW + (strstr(szGPU,"Intel") && strstr(szGPU,"8281")) || // definitely DOESN'T support pixel shaders + (strstr(szGPU,"Intel") && strstr(szGPU,"8283")) || // definitely DOESN'T support pixel shaders + (strstr(szGPU,"Intel") && strstr(szGPU,"8284")) || // definitely DOESN'T support pixel shaders + (strstr(szGPU,"Intel") && strstr(szGPU,"8285")) || // definitely DOESN'T support pixel shaders + (strstr(szGPU,"Intel") && strstr(szGPU,"8286")) || // definitely DOESN'T support pixel shaders. Ben Allison's desktop (865) - no image w/ps_2_0. Plus Nes's desktop - no ps_2_0. + 0) + { + m_nMaxPSVersion = MD2_PS_NONE; + //if (m_nCanvasStretch==0) + // nNewCanvasStretch = 100; + } + } + + /*char fname[512]; + sprintf(fname, "%s%s", GetPluginsDirPath(), TEXTURE_NAME); + if (D3DXCreateTextureFromFile(GetDevice(), fname, &m_object_tex) != S_OK) + { + // just give a warning, and move on + m_object_tex = NULL; // (make sure pointer wasn't mangled by some bad driver) + + char msg[1024]; + sprintf(msg, "Unable to load texture:\r%s", fname); + MessageBox(GetPluginWindow(), msg, "WARNING", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + //return false; + }*/ + + // Note: this code used to be in OnResizeGraphicsWindow(). + + // SHADERS + //------------------------------------- + if (m_nMaxPSVersion > MD2_PS_NONE) + { + // Create vertex declarations (since we're not using FVF anymore) + if (D3D_OK != GetDevice()->CreateVertexDeclaration( g_MyVertDecl, &m_pMyVertDecl )) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_MY_VERTEX_DECLARATION,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (D3D_OK != GetDevice()->CreateVertexDeclaration( g_WfVertDecl, &m_pWfVertDecl )) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_WF_VERTEX_DECLARATION,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (D3D_OK != GetDevice()->CreateVertexDeclaration( g_SpriteVertDecl, &m_pSpriteVertDecl )) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_SPRITE_VERTEX_DECLARATION,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + + // Load the FALLBACK shaders... + if (!RecompilePShader(m_szDefaultWarpPShaderText, &m_fallbackShaders_ps.warp, SHADER_WARP, true, 2)) + { + wchar_t szSM[64]; + switch(m_nMaxPSVersion_DX9) + { + case MD2_PS_2_0: + case MD2_PS_2_X: + WASABI_API_LNGSTRINGW_BUF(IDS_SHADER_MODEL_2,szSM,64); break; + case MD2_PS_3_0: WASABI_API_LNGSTRINGW_BUF(IDS_SHADER_MODEL_3,szSM,64); break; + case MD2_PS_4_0: WASABI_API_LNGSTRINGW_BUF(IDS_SHADER_MODEL_4,szSM,64); break; + default: + swprintf(szSM, WASABI_API_LNGSTRINGW(IDS_UKNOWN_CASE_X), m_nMaxPSVersion_DX9); + break; + } + if (m_nMaxPSVersion_ConfigPanel >= MD2_PS_NONE && m_nMaxPSVersion_DX9 < m_nMaxPSVersion_ConfigPanel) + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_FAILED_TO_COMPILE_PIXEL_SHADERS_USING_X),szSM,PSVersion); + else + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_FAILED_TO_COMPILE_PIXEL_SHADERS_HARDWARE_MIS_REPORT),szSM,PSVersion); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (!RecompileVShader(m_szDefaultWarpVShaderText, &m_fallbackShaders_vs.warp, SHADER_WARP, true)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_FALLBACK_WV_SHADER,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (!RecompileVShader(m_szDefaultCompVShaderText, &m_fallbackShaders_vs.comp, SHADER_COMP, true)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_FALLBACK_CV_SHADER,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (!RecompilePShader(m_szDefaultCompPShaderText, &m_fallbackShaders_ps.comp, SHADER_COMP, true, 2)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_FALLBACK_CP_SHADER,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + + // Load the BLUR shaders... + if (!RecompileVShader(m_szBlurVS, &m_BlurShaders[0].vs, SHADER_BLUR, true)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_BLUR1_VERTEX_SHADER,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (!RecompilePShader(m_szBlurPSX, &m_BlurShaders[0].ps, SHADER_BLUR, true, 2)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_BLUR1_PIXEL_SHADER,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (!RecompileVShader(m_szBlurVS, &m_BlurShaders[1].vs, SHADER_BLUR, true)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_BLUR2_VERTEX_SHADER,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (!RecompilePShader(m_szBlurPSY, &m_BlurShaders[1].ps, SHADER_BLUR, true, 2)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_BLUR2_PIXEL_SHADER,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + } + + // create m_lpVS[2] + { + int log2texsize = GetNearestPow2Size(GetWidth(), GetHeight()); + + // auto-guess texsize + if (m_bTexSizeWasAutoExact) + { + // note: in windowed mode, the winamp window could be weird sizes, + // so the plugin shell now gives us a slightly enlarged size, + // which pads it out to the nearest 32x32 block size, + // and then on display, it intelligently crops the image. + // This is pretty likely to work on non-shitty GPUs. + // but some shitty ones will still only do powers of 2! + // So if we are running out of video memory here or experience + // other problems, though, we can make our VS's smaller; + // which will work, although it will lead to stretching. + m_nTexSizeX = GetWidth(); + m_nTexSizeY = GetHeight(); + } + else if (m_bTexSizeWasAutoPow2) + { + m_nTexSizeX = log2texsize; + m_nTexSizeY = log2texsize; + } + + // clip texsize by max. from caps + if ((DWORD)m_nTexSizeX > GetCaps()->MaxTextureWidth && GetCaps()->MaxTextureWidth>0) + m_nTexSizeX = GetCaps()->MaxTextureWidth; + if ((DWORD)m_nTexSizeY > GetCaps()->MaxTextureHeight && GetCaps()->MaxTextureHeight>0) + m_nTexSizeY = GetCaps()->MaxTextureHeight; + + // apply canvas stretch + m_nTexSizeX = (m_nTexSizeX * 100)/nNewCanvasStretch; + m_nTexSizeY = (m_nTexSizeY * 100)/nNewCanvasStretch; + + // re-compute closest power-of-2 size, now that we've factored in the stretching... + log2texsize = GetNearestPow2Size(m_nTexSizeX, m_nTexSizeY); + if (m_bTexSizeWasAutoPow2) + { + m_nTexSizeX = log2texsize; + m_nTexSizeY = log2texsize; + } + + // snap to 16x16 blocks + m_nTexSizeX = ((m_nTexSizeX+15)/16)*16; + m_nTexSizeY = ((m_nTexSizeY+15)/16)*16; + + // determine format for VS1/VS2 + D3DFORMAT fmt; + switch(m_nTexBitsPerCh) { + case 5: fmt = D3DFMT_R5G6B5 ; break; + case 8: fmt = D3DFMT_X8R8G8B8 ; break; + case 10: fmt = D3DFMT_A2R10G10B10; break; // D3DFMT_A2W10V10U10 or D3DFMT_A2R10G10B10 or D3DFMT_A2B10G10R10 + case 16: fmt = D3DFMT_A16B16G16R16F; break; + case 32: fmt = D3DFMT_A32B32G32R32F; break; //FIXME + default: fmt = D3DFMT_X8R8G8B8 ; break; + } + + // reallocate + bool bSuccess = false; + DWORD vs_flags = D3DUSAGE_RENDERTARGET;// | D3DUSAGE_AUTOGENMIPMAP;//FIXME! (make automipgen optional) + bool bRevertedBitDepth = false; + do + { + SafeRelease(m_lpVS[0]); + SafeRelease(m_lpVS[1]); + + // create VS1 + bSuccess = (GetDevice()->CreateTexture(m_nTexSizeX, m_nTexSizeY, 1, vs_flags, fmt, D3DPOOL_DEFAULT, &m_lpVS[0], NULL) == D3D_OK); + if (!bSuccess) + { + bSuccess = (GetDevice()->CreateTexture(m_nTexSizeX, m_nTexSizeY, 1, vs_flags, GetBackBufFormat(), D3DPOOL_DEFAULT, &m_lpVS[0], NULL) == D3D_OK); + if (bSuccess) + fmt = GetBackBufFormat(); + } + + // create VS2 + if (bSuccess) + bSuccess = (GetDevice()->CreateTexture(m_nTexSizeX, m_nTexSizeY, 1, vs_flags, fmt, D3DPOOL_DEFAULT, &m_lpVS[1], NULL) == D3D_OK); + + if (!bSuccess) + { + if (m_bTexSizeWasAutoExact) + { + if (m_nTexSizeX > 256 || m_nTexSizeY > 256) + { + m_nTexSizeX /= 2; + m_nTexSizeY /= 2; + m_nTexSizeX = ((m_nTexSizeX+15)/16)*16; + m_nTexSizeY = ((m_nTexSizeY+15)/16)*16; + } + else + { + m_nTexSizeX = log2texsize; + m_nTexSizeY = log2texsize; + m_bTexSizeWasAutoExact = false; + m_bTexSizeWasAutoPow2 = true; + } + } + else if (m_bTexSizeWasAutoPow2) + { + if (m_nTexSizeX > 256) + { + m_nTexSizeX /= 2; + m_nTexSizeY /= 2; + } + else + break; + } + } + } + while (!bSuccess);// && m_nTexSizeX >= 256 && (m_bTexSizeWasAutoExact || m_bTexSizeWasAutoPow2)); + + if (!bSuccess) + { + wchar_t buf[2048]; + UINT err_id = IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_NOT_ENOUGH_VID_MEM; + if (GetScreenMode() == FULLSCREEN) + err_id = IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_SMALLER_DISPLAY; + else if (!(m_bTexSizeWasAutoExact || m_bTexSizeWasAutoPow2)) + err_id = IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_NOT_ENOUGH_VID_MEM_RECOMMENDATION; + + WASABI_API_LNGSTRINGW_BUF(err_id,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + else + { + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SUCCESSFULLY_CREATED_VS0_VS1), m_nTexSizeX, m_nTexSizeY, GetWidth(), GetHeight()); + dumpmsg(buf); + } + + /* + if (m_nTexSizeX != GetWidth() || m_nTexSizeY != GetHeight()) + { + char buf[2048]; + sprintf(buf, "warning - canvas size adjusted from %dx%d to %dx%d.", GetWidth(), GetHeight(), m_nTexSizeX, m_nTexSizeY); + dumpmsg(buf); + AddError(buf, 3.2f, ERR_INIT, true); + }/**/ + + // create blur textures w/same format. A complete mip chain costs 33% more video mem then 1 full-sized VS. + #if (NUM_BLUR_TEX>0) + int w = m_nTexSizeX; + int h = m_nTexSizeY; + DWORD blurtex_flags = D3DUSAGE_RENDERTARGET;// | D3DUSAGE_AUTOGENMIPMAP;//FIXME! (make automipgen optional) + for (int i=0; iCreateTexture(w2, h2, 1, blurtex_flags, fmt, D3DPOOL_DEFAULT, &m_lpBlur[i], NULL) == D3D_OK); + m_nBlurTexW[i] = w2; + m_nBlurTexH[i] = h2; + if (!bSuccess) + { + m_nBlurTexW[i] = 1; + m_nBlurTexH[i] = 1; + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_CREATING_BLUR_TEXTURES,buf,sizeof(buf)), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + break; + } + + // add it to m_textures[]. + TexInfo x; + swprintf(x.texname, L"blur%d%s", i/2+1, (i%2) ? L"" : L"doNOTuseME"); + x.texptr = m_lpBlur[i]; + //x.texsize_param = NULL; + x.w = w2; + x.h = h2; + x.d = 1; + x.bEvictable = false; + x.nAge = m_nPresetsLoadedTotal; + x.nSizeInBytes = 0; + m_textures.push_back(x); + } + #endif + } + + + m_fAspectX = (m_nTexSizeY > m_nTexSizeX) ? m_nTexSizeX/(float)m_nTexSizeY : 1.0f; + m_fAspectY = (m_nTexSizeX > m_nTexSizeY) ? m_nTexSizeY/(float)m_nTexSizeX : 1.0f; + m_fInvAspectX = 1.0f/m_fAspectX; + m_fInvAspectY = 1.0f/m_fAspectY; + + + // BUILD VERTEX LIST for final composite blit + // note the +0.5-texel offset! + // (otherwise, a 1-pixel-wide line of the image would wrap at the top and left edges). + ZeroMemory(m_comp_verts, sizeof(MYVERTEX)*FCGSX*FCGSY); + //float fOnePlusInvWidth = 1.0f + 1.0f/(float)GetWidth(); + //float fOnePlusInvHeight = 1.0f + 1.0f/(float)GetHeight(); + float fHalfTexelW = 0.5f / (float)GetWidth(); // 2.5: 2 pixels bad @ bottom right + float fHalfTexelH = 0.5f / (float)GetHeight(); + float fDivX = 1.0f / (float)(FCGSX-2); + float fDivY = 1.0f / (float)(FCGSY-2); + for (int j=0; jx = sx; + p->y = sy; + p->z = 0; + float rad, ang; + UvToMathSpace( u, v, &rad, &ang ); + // fix-ups: + if (i==FCGSX/2-1) { + if (j < FCGSY/2-1) + ang = 3.1415926535898f*1.5f; + else if (j == FCGSY/2-1) + ang = 3.1415926535898f*1.25f; + else if (j == FCGSY/2) + ang = 3.1415926535898f*0.75f; + else + ang = 3.1415926535898f*0.5f; + } + else if (i==FCGSX/2) { + if (j < FCGSY/2-1) + ang = 3.1415926535898f*1.5f; + else if (j == FCGSY/2-1) + ang = 3.1415926535898f*1.75f; + else if (j == FCGSY/2) + ang = 3.1415926535898f*0.25f; + else + ang = 3.1415926535898f*0.5f; + } + else if (j==FCGSY/2-1) { + if (i < FCGSX/2-1) + ang = 3.1415926535898f*1.0f; + else if (i == FCGSX/2-1) + ang = 3.1415926535898f*1.25f; + else if (i == FCGSX/2) + ang = 3.1415926535898f*1.75f; + else + ang = 3.1415926535898f*2.0f; + } + else if (j==FCGSY/2) { + if (i < FCGSX/2-1) + ang = 3.1415926535898f*1.0f; + else if (i == FCGSX/2-1) + ang = 3.1415926535898f*0.75f; + else if (i == FCGSX/2) + ang = 3.1415926535898f*0.25f; + else + ang = 3.1415926535898f*0.0f; + } + p->tu = u; + p->tv = v; + //p->tu_orig = u; + //p->tv_orig = v; + p->rad = rad; + p->ang = ang; + p->Diffuse = 0xFFFFFFFF; + } + } + + // build index list for final composite blit - + // order should be friendly for interpolation of 'ang' value! + int* cur_index = &m_comp_indices[0]; + for (int y=0; y 16); + + if (hr != D3D_OK) + { + //dumpmsg("Init: -WARNING-: Title texture could not be created!"); + m_lpDDSTitle = NULL; + //SafeRelease(m_lpDDSTitle); + //return true; + } + else + { + //sprintf(buf, "Init: title texture size is %dx%d (ideal size was %dx%d)", m_nTitleTexSizeX, m_nTitleTexSizeY, m_nTexSize, m_nTexSize/4); + //dumpmsg(buf); + m_supertext.bRedrawSuperText = true; + } + } + + // ----------------- + + // create 'm_gdi_title_font_doublesize' + int songtitle_font_size = m_fontinfo[SONGTITLE_FONT].nSize * m_nTitleTexSizeX/256; + if (songtitle_font_size<6) songtitle_font_size=6; + if (!(m_gdi_title_font_doublesize = CreateFontW(songtitle_font_size, 0, 0, 0, m_fontinfo[SONGTITLE_FONT].bBold ? 900 : 400, + m_fontinfo[SONGTITLE_FONT].bItalic, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, m_fontinfo[SONGTITLE_FONT].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY, DEFAULT_PITCH, m_fontinfo[SONGTITLE_FONT].szFace))) + { + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_DOUBLE_SIZED_GDI_TITLE_FONT), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + if (pCreateFontW( GetDevice(), + songtitle_font_size, + 0, + m_fontinfo[SONGTITLE_FONT].bBold ? 900 : 400, + 1, + m_fontinfo[SONGTITLE_FONT].bItalic, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + ANTIALIASED_QUALITY,//DEFAULT_QUALITY, + DEFAULT_PITCH, + m_fontinfo[SONGTITLE_FONT].szFace, + &m_d3dx_title_font_doublesize + ) != D3D_OK) + { + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_DOUBLE_SIZED_D3DX_TITLE_FONT), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + // ----------------- + + m_texmgr.Init(GetDevice()); + + //dumpmsg("Init: mesh allocation"); + m_verts = new MYVERTEX[(m_nGridX+1)*(m_nGridY+1)]; + m_verts_temp = new MYVERTEX[(m_nGridX+2) * 4]; + m_vertinfo = new td_vertinfo[(m_nGridX+1)*(m_nGridY+1)]; + m_indices_strip = new int[(m_nGridX+2)*(m_nGridY*2)]; + m_indices_list = new int[m_nGridX*m_nGridY*6]; + if (!m_verts || !m_vertinfo) + { + swprintf(buf, L"couldn't allocate mesh - out of memory"); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + + int nVert = 0; + float texel_offset_x = 0.5f / (float)m_nTexSizeX; + float texel_offset_y = 0.5f / (float)m_nTexSizeY; + for (y=0; y<=m_nGridY; y++) + { + for (int x=0; x<=m_nGridX; x++) + { + // precompute x,y,z + m_verts[nVert].x = x/(float)m_nGridX*2.0f - 1.0f; + m_verts[nVert].y = y/(float)m_nGridY*2.0f - 1.0f; + m_verts[nVert].z = 0.0f; + + // precompute rad, ang, being conscious of aspect ratio + m_vertinfo[nVert].rad = sqrtf(m_verts[nVert].x*m_verts[nVert].x*m_fAspectX*m_fAspectX + m_verts[nVert].y*m_verts[nVert].y*m_fAspectY*m_fAspectY); + if (y==m_nGridY/2 && x==m_nGridX/2) + m_vertinfo[nVert].ang = 0.0f; + else + m_vertinfo[nVert].ang = atan2f(m_verts[nVert].y*m_fAspectY, m_verts[nVert].x*m_fAspectX); + m_vertinfo[nVert].a = 1; + m_vertinfo[nVert].c = 0; + + m_verts[nVert].rad = m_vertinfo[nVert].rad; + m_verts[nVert].ang = m_vertinfo[nVert].ang; + m_verts[nVert].tu_orig = m_verts[nVert].x*0.5f + 0.5f + texel_offset_x; + m_verts[nVert].tv_orig = -m_verts[nVert].y*0.5f + 0.5f + texel_offset_y; + + nVert++; + } + } + + // generate triangle strips for the 4 quadrants. + // each quadrant has m_nGridY/2 strips. + // each strip has m_nGridX+2 *points* in it, or m_nGridX/2 polygons. + int xref, yref; + int nVert_strip = 0; + for (int quadrant=0; quadrant<4; quadrant++) + { + for (int slice=0; slice < m_nGridY/2; slice++) + { + for (int i=0; i < m_nGridX + 2; i++) + { + // quadrants: 2 3 + // 0 1 + xref = i/2; + yref = (i%2) + slice; + + if (quadrant & 1) + xref = m_nGridX - xref; + if (quadrant & 2) + yref = m_nGridY - yref; + + int v = xref + (yref)*(m_nGridX+1); + + m_indices_strip[nVert_strip++] = v; + } + } + } + + // also generate triangle lists for drawing the main warp mesh. + int nVert_list = 0; + for (int quadrant=0; quadrant<4; quadrant++) + { + for (int slice=0; slice < m_nGridY/2; slice++) + { + for (int i=0; i < m_nGridX/2; i++) + { + // quadrants: 2 3 + // 0 1 + xref = i; + yref = slice; + + if (quadrant & 1) + xref = m_nGridX-1 - xref; + if (quadrant & 2) + yref = m_nGridY-1 - yref; + + int v = xref + (yref)*(m_nGridX+1); + + m_indices_list[nVert_list++] = v; + m_indices_list[nVert_list++] = v +1; + m_indices_list[nVert_list++] = v+m_nGridX+1 ; + m_indices_list[nVert_list++] = v +1; + m_indices_list[nVert_list++] = v+m_nGridX+1 ; + m_indices_list[nVert_list++] = v+m_nGridX+1+1; + } + } + } + + // GENERATED TEXTURES FOR SHADERS + //------------------------------------- + if (m_nMaxPSVersion > 0) + { + // Generate noise textures + if (!AddNoiseTex(L"noise_lq", 256, 1)) return false; + if (!AddNoiseTex(L"noise_lq_lite", 32, 1)) return false; + if (!AddNoiseTex(L"noise_mq", 256, 4)) return false; + if (!AddNoiseTex(L"noise_hq", 256, 8)) return false; + + if (!AddNoiseVol(L"noisevol_lq", 32, 1)) return false; + if (!AddNoiseVol(L"noisevol_hq", 32, 4)) return false; + } + + if (!m_bInitialPresetSelected) + { + UpdatePresetList(true); //...just does its initial burst! + LoadRandomPreset(0.0f); + m_bInitialPresetSelected = true; + } + else + LoadShaders(&m_shaders, m_pState, false); // Also force-load the shaders - otherwise they'd only get compiled on a preset switch. + + return true; +} + +float fCubicInterpolate(float y0, float y1, float y2, float y3, float t) +{ + float a0,a1,a2,a3,t2; + + t2 = t*t; + a0 = y3 - y2 - y0 + y1; + a1 = y0 - y1 - a0; + a2 = y2 - y0; + a3 = y1; + + return(a0*t*t2+a1*t2+a2*t+a3); +} + +DWORD dwCubicInterpolate(DWORD y0, DWORD y1, DWORD y2, DWORD y3, float t) +{ + // performs cubic interpolation on a D3DCOLOR value. + DWORD ret = 0; + DWORD shift = 0; + for (int i=0; i<4; i++) + { + float f = fCubicInterpolate( + ((y0 >> shift) & 0xFF)/255.0f, + ((y1 >> shift) & 0xFF)/255.0f, + ((y2 >> shift) & 0xFF)/255.0f, + ((y3 >> shift) & 0xFF)/255.0f, + t + ); + if (f<0) + f = 0; + if (f>1) + f = 1; + ret |= ((DWORD)(f*255)) << shift; + shift += 8; + } + return ret; +} + +bool CPlugin::AddNoiseTex(const wchar_t* szTexName, int size, int zoom_factor) +{ + // size = width & height of the texture; + // zoom_factor = how zoomed-in the texture features should be. + // 1 = random noise + // 2 = smoothed (interp) + // 4/8/16... = cubic interp. + + wchar_t buf[2048], title[64]; + + // Synthesize noise texture(s) + LPDIRECT3DTEXTURE9 pNoiseTex = NULL; + // try twice - once with mips, once without. + for (int i=0; i<2; i++) + { + if (D3D_OK != GetDevice()->CreateTexture(size, size, i, D3DUSAGE_DYNAMIC | (i ? 0 : D3DUSAGE_AUTOGENMIPMAP), D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pNoiseTex, NULL)) + { + if (i==1) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_NOISE_TEXTURE,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + } + else + break; + } + + D3DLOCKED_RECT r; + if (D3D_OK != pNoiseTex->LockRect(0, &r, NULL, D3DLOCK_DISCARD)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_LOCK_NOISE_TEXTURE,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + + if (r.Pitch < size*4) + { + WASABI_API_LNGSTRINGW_BUF(IDS_NOISE_TEXTURE_BYTE_LAYOUT_NOT_RECOGNISED,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + + // write to the bits... + DWORD* dst = (DWORD*)r.pBits; + int dwords_per_line = r.Pitch / sizeof(DWORD); + int RANGE = (zoom_factor > 1) ? 216 : 256; + for (int y=0; y 1) + { + // first go ACROSS, blending cubically on X, but only on the main lines. + DWORD* dst = (DWORD*)r.pBits; + for (int y=0; yUnlockRect(0); + + // add it to m_textures[]. + TexInfo x; + lstrcpyW(x.texname, szTexName); + x.texptr = pNoiseTex; + //x.texsize_param = NULL; + x.w = size; + x.h = size; + x.d = 1; + x.bEvictable = false; + x.nAge = m_nPresetsLoadedTotal; + x.nSizeInBytes = 0; + m_textures.push_back(x); + + return true; +} + +bool CPlugin::AddNoiseVol(const wchar_t* szTexName, int size, int zoom_factor) +{ + // size = width & height & depth of the texture; + // zoom_factor = how zoomed-in the texture features should be. + // 1 = random noise + // 2 = smoothed (interp) + // 4/8/16... = cubic interp. + + wchar_t buf[2048], title[64]; + + // Synthesize noise texture(s) + LPDIRECT3DVOLUMETEXTURE9 pNoiseTex = NULL; + // try twice - once with mips, once without. + // NO, TRY JUST ONCE - DX9 doesn't do auto mipgen w/volume textures. (Debug runtime complains.) + for (int i=1; i<2; i++) + { + if (D3D_OK != GetDevice()->CreateVolumeTexture(size, size, size, i, D3DUSAGE_DYNAMIC | (i ? 0 : D3DUSAGE_AUTOGENMIPMAP), D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pNoiseTex, NULL)) + { + if (i==1) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_3D_NOISE_TEXTURE,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + } + else + break; + } + D3DLOCKED_BOX r; + if (D3D_OK != pNoiseTex->LockBox(0, &r, NULL, D3DLOCK_DISCARD)) + { + WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_LOCK_3D_NOISE_TEXTURE,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + if (r.RowPitch < size*4 || r.SlicePitch < size*size*4) + { + WASABI_API_LNGSTRINGW_BUF(IDS_3D_NOISE_TEXTURE_BYTE_LAYOUT_NOT_RECOGNISED,buf,sizeof(buf)); + dumpmsg(buf); + MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + // write to the bits... + int dwords_per_slice = r.SlicePitch / sizeof(DWORD); + int dwords_per_line = r.RowPitch / sizeof(DWORD); + int RANGE = (zoom_factor > 1) ? 216 : 256; + for (int z=0; z 1) + { + // first go ACROSS, blending cubically on X, but only on the main lines. + DWORD* dst = (DWORD*)r.pBits; + for (int z=0; zUnlockBox(0); + + // add it to m_textures[]. + TexInfo x; + lstrcpyW(x.texname, szTexName); + x.texptr = pNoiseTex; + //x.texsize_param = NULL; + x.w = size; + x.h = size; + x.d = size; + x.bEvictable = false; + x.nAge = m_nPresetsLoadedTotal; + x.nSizeInBytes = 0; + m_textures.push_back(x); + + return true; +} + +void VShaderInfo::Clear() +{ + SafeRelease(ptr); + SafeRelease(CT); + params.Clear(); +} +void PShaderInfo::Clear() +{ + SafeRelease(ptr); + SafeRelease(CT); + params.Clear(); +} + +// global_CShaderParams_master_list: a master list of all CShaderParams classes in existence. +// ** when we evict a texture, we need to NULL out any texptrs these guys have! ** +CShaderParamsList global_CShaderParams_master_list; +CShaderParams::CShaderParams() { + global_CShaderParams_master_list.push_back(this); +} + +CShaderParams::~CShaderParams() { + int N = global_CShaderParams_master_list.size(); + for (int i=0; i0 && m_textures[i].nAge < m_nPresetsLoadedTotal-1) // note: -1 here keeps images around for the blend-from preset, too... + { + newest = min(newest, m_textures[i].nAge); + oldest = max(oldest, m_textures[i].nAge); + bAtLeastOneFound = true; + } + if (!bAtLeastOneFound) + return false; + + // find the "biggest" texture, but dilate things so that the newest textures + // are HALF as big as the oldest textures, and thus, less likely to get booted. + int biggest_bytes = 0; + int biggest_index = -1; + for (i=0; i0 && m_textures[i].nAge < m_nPresetsLoadedTotal-1) // note: -1 here keeps images around for the blend-from preset, too... + { + float size_mult = 1.0f + (m_textures[i].nAge - newest)/(float)(oldest-newest); + int bytes = (int)(m_textures[i].nSizeInBytes * size_mult); + if (bytes > biggest_bytes) + { + biggest_bytes = bytes; + biggest_index = i; + } + } + if (biggest_index == -1) + return false; + + + // evict that sucker + assert(m_textures[biggest_index].texptr); + + // notify all CShaderParams classes that we're releasing a bindable texture!! + N = global_CShaderParams_master_list.size(); + for (i=0; iOnTextureEvict( m_textures[biggest_index].texptr ); + + // 2. erase the texture itself + SafeRelease(m_textures[biggest_index].texptr); + m_textures.eraseAt(biggest_index); + + return true; +} + +GString texture_exts[] = { L"jpg", L"dds", L"png", L"tga", L"bmp", L"dib", }; +const wchar_t szExtsWithSlashes[] = L"jpg|png|dds|etc."; +typedef Vector StringVec; +bool PickRandomTexture(const wchar_t* prefix, wchar_t* szRetTextureFilename) //should be MAX_PATH chars +{ + static StringVec texfiles; + static DWORD texfiles_timestamp = 0; // update this a max of every ~2 seconds or so + + // if it's been more than a few seconds since the last textures dir scan, redo it. + // (..just enough to make sure we don't do it more than once per preset load) + //DWORD t = timeGetTime(); // in milliseconds + //if (abs(t - texfiles_timestamp) > 2000) + if (g_plugin.m_bNeedRescanTexturesDir) + { + g_plugin.m_bNeedRescanTexturesDir = false;//texfiles_timestamp = t; + texfiles.clear(); + + wchar_t szMask[MAX_PATH]; + swprintf(szMask, L"%stextures\\*.*", g_plugin.m_szMilkdrop2Path); + + WIN32_FIND_DATAW ffd = {0}; + + HANDLE hFindFile = INVALID_HANDLE_VALUE; + if( (hFindFile = FindFirstFileW(szMask, &ffd )) == INVALID_HANDLE_VALUE ) // note: returns filename -without- path + return false; + + // first, count valid texture files + do + { + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + wchar_t* ext = wcsrchr(ffd.cFileName, L'.'); + if (!ext) + continue; + + for (int i=0; iGetDesc(&d); + + D3DXCONSTANT_DESC cd; + + #define MAX_RAND_TEX 16 + GString RandTexName[MAX_RAND_TEX]; + + // pass 1: find all the samplers (and texture bindings). + for (UINT i=0; iGetConstant(NULL, i); + unsigned int count = 1; + pCT->GetConstantDesc(h, &cd, &count); + + // cd.Name = VS_Sampler + // cd.RegisterSet = D3DXRS_SAMPLER + // cd.RegisterIndex = 3 + if (cd.RegisterSet == D3DXRS_SAMPLER && cd.RegisterIndex >= 0 && cd.RegisterIndex < sizeof(m_texture_bindings)/sizeof(m_texture_bindings[0])) + { + assert(m_texture_bindings[cd.RegisterIndex].texptr == NULL); + + // remove "sampler_" prefix to create root file name. could still have "FW_" prefix or something like that. + wchar_t szRootName[MAX_PATH]; + if (!strncmp(cd.Name, "sampler_", 8)) + lstrcpyW(szRootName, AutoWide(&cd.Name[8])); + else + lstrcpyW(szRootName, AutoWide(cd.Name)); + + // also peel off "XY_" prefix, if it's there, to specify filtering & wrap mode. + bool bBilinear = true; + bool bWrap = true; + bool bWrapFilterSpecified = false; + if (lstrlenW(szRootName) > 3 && szRootName[2]==L'_') + { + wchar_t temp[3]; + temp[0] = szRootName[0]; + temp[1] = szRootName[1]; + temp[2] = 0; + // convert to uppercase + if (temp[0] >= L'a' && temp[0] <= L'z') + temp[0] -= L'a' - L'A'; + if (temp[1] >= L'a' && temp[1] <= L'z') + temp[1] -= L'a' - L'A'; + + if (!wcscmp(temp, L"FW")) { bWrapFilterSpecified = true; bBilinear = true; bWrap = true; } + else if (!wcscmp(temp, L"FC")) { bWrapFilterSpecified = true; bBilinear = true; bWrap = false; } + else if (!wcscmp(temp, L"PW")) { bWrapFilterSpecified = true; bBilinear = false; bWrap = true; } + else if (!wcscmp(temp, L"PC")) { bWrapFilterSpecified = true; bBilinear = false; bWrap = false; } + // also allow reverses: + else if (!wcscmp(temp, L"WF")) { bWrapFilterSpecified = true; bBilinear = true; bWrap = true; } + else if (!wcscmp(temp, L"CF")) { bWrapFilterSpecified = true; bBilinear = true; bWrap = false; } + else if (!wcscmp(temp, L"WP")) { bWrapFilterSpecified = true; bBilinear = false; bWrap = true; } + else if (!wcscmp(temp, L"CP")) { bWrapFilterSpecified = true; bBilinear = false; bWrap = false; } + + // peel off the prefix + int i = 0; + while (szRootName[i+3]) + { + szRootName[i] = szRootName[i+3]; + i++; + } + szRootName[i] = 0; + } + m_texture_bindings[ cd.RegisterIndex ].bWrap = bWrap; + m_texture_bindings[ cd.RegisterIndex ].bBilinear = bBilinear; + + // if is "main", map it to the VS... + if (!wcscmp(L"main", szRootName)) + { + m_texture_bindings[ cd.RegisterIndex ].texptr = NULL; + m_texcode[ cd.RegisterIndex ] = TEX_VS; + } + #if (NUM_BLUR_TEX >= 2) + else if (!wcscmp(L"blur1", szRootName)) + { + m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[1]; + m_texcode [ cd.RegisterIndex ] = TEX_BLUR1; + if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP + m_texture_bindings[ cd.RegisterIndex ].bWrap = false; + m_texture_bindings[ cd.RegisterIndex ].bBilinear = true; + } + } + #endif + #if (NUM_BLUR_TEX >= 4) + else if (!wcscmp(L"blur2", szRootName)) + { + m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[3]; + m_texcode [ cd.RegisterIndex ] = TEX_BLUR2; + if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP + m_texture_bindings[ cd.RegisterIndex ].bWrap = false; + m_texture_bindings[ cd.RegisterIndex ].bBilinear = true; + } + } + #endif + #if (NUM_BLUR_TEX >= 6) + else if (!wcscmp(L"blur3", szRootName)) + { + m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[5]; + m_texcode [ cd.RegisterIndex ] = TEX_BLUR3; + if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP + m_texture_bindings[ cd.RegisterIndex ].bWrap = false; + m_texture_bindings[ cd.RegisterIndex ].bBilinear = true; + } + } + #endif + #if (NUM_BLUR_TEX >= 8) + else if (!wcscmp("blur4", szRootName)) + { + m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[7]; + m_texcode [ cd.RegisterIndex ] = TEX_BLUR4; + if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP + m_texture_bindings[ cd.RegisterIndex ].bWrap = false; + m_texture_bindings[ cd.RegisterIndex ].bBilinear = true; + } + } + #endif + #if (NUM_BLUR_TEX >= 10) + else if (!wcscmp("blur5", szRootName)) + { + m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[9]; + m_texcode [ cd.RegisterIndex ] = TEX_BLUR5; + if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP + m_texture_bindings[ cd.RegisterIndex ].bWrap = false; + m_texture_bindings[ cd.RegisterIndex ].bBilinear = true; + } + } + #endif + #if (NUM_BLUR_TEX >= 12) + else if (!wcscmp("blur6", szRootName)) + { + m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[11]; + m_texcode [ cd.RegisterIndex ] = TEX_BLUR6; + if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP + m_texture_bindings[ cd.RegisterIndex ].bWrap = false; + m_texture_bindings[ cd.RegisterIndex ].bBilinear = true; + } + } + #endif + else + { + m_texcode[ cd.RegisterIndex ] = TEX_DISK; + + // check for request for random texture. + if (!wcsncmp(L"rand", szRootName, 4) && + IsNumericChar(szRootName[4]) && + IsNumericChar(szRootName[5]) && + (szRootName[6]==0 || szRootName[6]=='_') ) + { + int rand_slot = -1; + + // peel off filename prefix ("rand13_smalltiled", for example) + wchar_t prefix[MAX_PATH]; + if (szRootName[6]==L'_') + lstrcpyW(prefix, &szRootName[7]); + else + prefix[0] = 0; + szRootName[6] = 0; + + swscanf(&szRootName[4], L"%d", &rand_slot); + if (rand_slot >= 0 && rand_slot <= 15) // otherwise, not a special filename - ignore it + { + if (!PickRandomTexture(prefix, szRootName)) + { + if (prefix[0]) + swprintf(szRootName, L"[rand%02d] %s*", rand_slot, prefix); + else + swprintf(szRootName, L"[rand%02d] *", rand_slot); + } + else + { + //chop off extension + wchar_t *p = wcsrchr(szRootName, L'.'); + if (p) + *p = 0; + } + + assert(RandTexName[rand_slot].GetLength() == 0); + RandTexName[rand_slot] = szRootName; // we'll need to remember this for texsize_ params! + } + } + + // see if .tga or .jpg has already been loaded. + // (if so, grab a pointer to it) + // (if NOT, create & load it). + int N = g_plugin.m_textures.size(); + for (int n=0; nGetConstant(NULL, i); + unsigned int count = 1; + pCT->GetConstantDesc(h, &cd, &count); + + if (cd.RegisterSet == D3DXRS_FLOAT4) + { + if (cd.Class == D3DXPC_MATRIX_COLUMNS) + { + if (!strcmp(cd.Name, "rot_s1" )) rot_mat[0] = h; + else if (!strcmp(cd.Name, "rot_s2" )) rot_mat[1] = h; + else if (!strcmp(cd.Name, "rot_s3" )) rot_mat[2] = h; + else if (!strcmp(cd.Name, "rot_s4" )) rot_mat[3] = h; + else if (!strcmp(cd.Name, "rot_d1" )) rot_mat[4] = h; + else if (!strcmp(cd.Name, "rot_d2" )) rot_mat[5] = h; + else if (!strcmp(cd.Name, "rot_d3" )) rot_mat[6] = h; + else if (!strcmp(cd.Name, "rot_d4" )) rot_mat[7] = h; + else if (!strcmp(cd.Name, "rot_f1" )) rot_mat[8] = h; + else if (!strcmp(cd.Name, "rot_f2" )) rot_mat[9] = h; + else if (!strcmp(cd.Name, "rot_f3" )) rot_mat[10] = h; + else if (!strcmp(cd.Name, "rot_f4" )) rot_mat[11] = h; + else if (!strcmp(cd.Name, "rot_vf1")) rot_mat[12] = h; + else if (!strcmp(cd.Name, "rot_vf2")) rot_mat[13] = h; + else if (!strcmp(cd.Name, "rot_vf3")) rot_mat[14] = h; + else if (!strcmp(cd.Name, "rot_vf4")) rot_mat[15] = h; + else if (!strcmp(cd.Name, "rot_uf1")) rot_mat[16] = h; + else if (!strcmp(cd.Name, "rot_uf2")) rot_mat[17] = h; + else if (!strcmp(cd.Name, "rot_uf3")) rot_mat[18] = h; + else if (!strcmp(cd.Name, "rot_uf4")) rot_mat[19] = h; + else if (!strcmp(cd.Name, "rot_rand1")) rot_mat[20] = h; + else if (!strcmp(cd.Name, "rot_rand2")) rot_mat[21] = h; + else if (!strcmp(cd.Name, "rot_rand3")) rot_mat[22] = h; + else if (!strcmp(cd.Name, "rot_rand4")) rot_mat[23] = h; + } + else if (cd.Class == D3DXPC_VECTOR) + { + if (!strcmp(cd.Name, "rand_frame")) rand_frame = h; + else if (!strcmp(cd.Name, "rand_preset")) rand_preset = h; + else if (!strncmp(cd.Name, "texsize_", 8)) + { + // remove "texsize_" prefix to find root file name. + wchar_t szRootName[MAX_PATH]; + if (!strncmp(cd.Name, "texsize_", 8)) + lstrcpyW(szRootName, AutoWide(&cd.Name[8])); + else + lstrcpyW(szRootName, AutoWide(cd.Name)); + + // check for request for random texture. + // it should be a previously-seen random index - just fetch/reuse the name. + if (!wcsncmp(L"rand", szRootName, 4) && + IsNumericChar(szRootName[4]) && + IsNumericChar(szRootName[5]) && + (szRootName[6]==0 || szRootName[6]==L'_') ) + { + int rand_slot = -1; + + // ditch filename prefix ("rand13_smalltiled", for example) + // and just go by the slot + if (szRootName[6]==L'_') + szRootName[6] = 0; + + swscanf(&szRootName[4], L"%d", &rand_slot); + if (rand_slot >= 0 && rand_slot <= 15) // otherwise, not a special filename - ignore it + if (RandTexName[rand_slot].GetLength() > 0) + lstrcpyW(szRootName, RandTexName[rand_slot].c_str()); + } + + // see if .tga or .jpg has already been loaded. + bool bTexFound = false; + int N = g_plugin.m_textures.size(); + for (int n=0; n= 0 && z < sizeof(const_handles)/sizeof(const_handles[0])) + const_handles[z] = h; + } + else if (cd.Name[0] == '_' && cd.Name[1] == 'q') + { + int z = cd.Name[2] - 'a'; + if (z >= 0 && z < sizeof(q_const_handles)/sizeof(q_const_handles[0])) + q_const_handles[z] = h; + } + } + } + } +} + +//---------------------------------------------------------------------- + +bool CPlugin::RecompileVShader(const char* szShadersText, VShaderInfo *si, int shaderType, bool bHardErrors) +{ + SafeRelease(si->ptr); + ZeroMemory(si, sizeof(VShaderInfo)); + + // LOAD SHADER + if (!LoadShaderFromMemory( szShadersText, "VS", "vs_1_1", &si->CT, (void**)&si->ptr, shaderType, bHardErrors && (GetScreenMode()==WINDOWED))) + return false; + + // Track down texture & float4 param bindings for this shader. + // Also loads any textures that need loaded. + si->params.CacheParams(si->CT, bHardErrors); + + return true; +} + +bool CPlugin::RecompilePShader(const char* szShadersText, PShaderInfo *si, int shaderType, bool bHardErrors, int PSVersion) +{ + assert(m_nMaxPSVersion > 0); + + SafeRelease(si->ptr); + ZeroMemory(si, sizeof(PShaderInfo)); + + // LOAD SHADER + // note: ps_1_4 required for dependent texture lookups. + // ps_2_0 required for tex2Dbias. + char ver[16]; + lstrcpy(ver, "ps_0_0"); + switch(PSVersion) { + case MD2_PS_NONE: + // Even though the PRESET doesn't use shaders, if MilkDrop is running where it CAN do shaders, + // we run all the old presets through (shader) emulation. + // This way, during a MilkDrop session, we are always calling either WarpedBlit() or WarpedBlit_NoPixelShaders(), + // and blending always works. + lstrcpy(ver, "ps_2_0"); + break; + case MD2_PS_2_0: lstrcpy(ver, "ps_2_0"); break; + case MD2_PS_2_X: lstrcpy(ver, "ps_2_a"); break; // we'll try ps_2_a first, LoadShaderFromMemory will try ps_2_b if compilation fails + case MD2_PS_3_0: lstrcpy(ver, "ps_3_0"); break; + case MD2_PS_4_0: lstrcpy(ver, "ps_4_0"); break; + default: assert(0); break; + } + + if (!LoadShaderFromMemory( szShadersText, "PS", ver, &si->CT, (void**)&si->ptr, shaderType, bHardErrors && (GetScreenMode()==WINDOWED))) + return false; + + // Track down texture & float4 param bindings for this shader. + // Also loads any textures that need loaded. + si->params.CacheParams(si->CT, bHardErrors); + + return true; +} + +bool CPlugin::LoadShaders(PShaderSet* sh, CState* pState, bool bTick) +{ + if (m_nMaxPSVersion <= 0) + return true; + + // load one of the pixel shaders + if (!sh->warp.ptr && pState->m_nWarpPSVersion > 0) + { + bool bOK = RecompilePShader(pState->m_szWarpShadersText, &sh->warp, SHADER_WARP, false, pState->m_nWarpPSVersion); + if (!bOK) + { + // switch to fallback shader + m_fallbackShaders_ps.warp.ptr->AddRef(); + m_fallbackShaders_ps.warp.CT->AddRef(); + memcpy(&sh->warp, &m_fallbackShaders_ps.warp, sizeof(PShaderInfo)); + // cancel any slow-preset-load + //m_nLoadingPreset = 1000; + } + + if (bTick) + return true; + } + + if (!sh->comp.ptr && pState->m_nCompPSVersion > 0) + { + bool bOK = RecompilePShader(pState->m_szCompShadersText, &sh->comp, SHADER_COMP, false, pState->m_nCompPSVersion); + if (!bOK) + { + // switch to fallback shader + m_fallbackShaders_ps.comp.ptr->AddRef(); + m_fallbackShaders_ps.comp.CT->AddRef(); + memcpy(&sh->comp, &m_fallbackShaders_ps.comp, sizeof(PShaderInfo)); + // cancel any slow-preset-load + //m_nLoadingPreset = 1000; + } + } + + return true; +} + +//---------------------------------------------------------------------- + +/* +bool CPlugin::LoadShaderFromFile( char* szFile, char* szFn, char* szProfile, + LPD3DXCONSTANTTABLE* ppConstTable, void** ppShader ) +{ + LPD3DXBUFFER pShaderByteCode; + char buf[32768]; + + if (D3D_OK != D3DXCompileShaderFromFile( + szFile, + NULL,//CONST D3DXMACRO* pDefines, + NULL,//LPD3DXINCLUDE pInclude, + szFn, + szProfile, + m_dwShaderFlags, + &pShaderByteCode, + &m_pShaderCompileErrors, + ppConstTable + )) + { + sprintf(buf, "error compiling shader:\n"); + lstrcat(buf, szFile); + if (m_pShaderCompileErrors->GetBufferSize() < sizeof(buf) - 256) + { + lstrcat(buf, "\n\n"); + lstrcat(buf, (const char *)(m_pShaderCompileErrors->GetBufferPointer())); + } + dumpmsg(buf); + MessageBox(GetPluginWindow(), buf, "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + + HRESULT hr = 1; + if (szProfile[0] == 'v') + hr = GetDevice()->CreateVertexShader((const unsigned long *)(pShaderByteCode->GetBufferPointer()), (IDirect3DVertexShader9**)ppShader); + else if (szProfile[0] == 'p') + hr = GetDevice()->CreatePixelShader((const unsigned long *)(pShaderByteCode->GetBufferPointer()), (IDirect3DPixelShader9**)ppShader); + if (hr != D3D_OK) + { + sprintf(buf, "error creating shader:\n"); + lstrcat(buf, szFile); + dumpmsg(buf); + MessageBox(GetPluginWindow(), buf, "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + return false; + } + + pShaderByteCode->Release(); + + return true; +} +*/ + +bool CPlugin::LoadShaderFromMemory( const char* szOrigShaderText, char* szFn, char* szProfile, + LPD3DXCONSTANTTABLE* ppConstTable, void** ppShader, int shaderType, bool bHardErrors ) +{ + const char szWarpDefines[] = "#define rad _rad_ang.x\n" + "#define ang _rad_ang.y\n" + "#define uv _uv.xy\n" + "#define uv_orig _uv.zw\n"; + const char szCompDefines[] = "#define rad _rad_ang.x\n" + "#define ang _rad_ang.y\n" + "#define uv _uv.xy\n" + "#define uv_orig _uv.xy\n" //[sic] + "#define hue_shader _vDiffuse.xyz\n"; + const char szWarpParams[] = "float4 _vDiffuse : COLOR, float4 _uv : TEXCOORD0, float2 _rad_ang : TEXCOORD1, out float4 _return_value : COLOR0"; + const char szCompParams[] = "float4 _vDiffuse : COLOR, float2 _uv : TEXCOORD0, float2 _rad_ang : TEXCOORD1, out float4 _return_value : COLOR0"; + const char szFirstLine[] = " float3 ret = 0;"; + const char szLastLine[] = " _return_value = float4(ret.xyz, _vDiffuse.w);"; + + char szWhichShader[64]; + switch(shaderType) + { + case SHADER_WARP: lstrcpy(szWhichShader, "warp"); break; + case SHADER_COMP: lstrcpy(szWhichShader, "composite"); break; + case SHADER_BLUR: lstrcpy(szWhichShader, "blur"); break; + case SHADER_OTHER: lstrcpy(szWhichShader, "(other)"); break; + default: lstrcpy(szWhichShader, "(unknown)"); break; + } + + LPD3DXBUFFER pShaderByteCode; + wchar_t title[64]; + + *ppShader = NULL; + *ppConstTable = NULL; + + char szShaderText[128000]; + char temp[128000]; + int writePos = 0; + + // paste the universal #include + lstrcpy(&szShaderText[writePos], m_szShaderIncludeText); // first, paste in the contents of 'inputs.fx' before the actual shader text. Has 13's and 10's. + writePos += m_nShaderIncludeTextLen; + + // paste in any custom #defines for this shader type + if (shaderType == SHADER_WARP && szProfile[0]=='p') + { + lstrcpy(&szShaderText[writePos], szWarpDefines); + writePos += lstrlen(szWarpDefines); + } + else if (shaderType == SHADER_COMP && szProfile[0]=='p') + { + lstrcpy(&szShaderText[writePos], szCompDefines); + writePos += lstrlen(szCompDefines); + } + + // paste in the shader itself - converting LCC's to 13+10's. + // avoid lstrcpy b/c it might not handle the linefeed stuff...? + int shaderStartPos = writePos; + { + const char *s = szOrigShaderText; + char *d = &szShaderText[writePos]; + while (*s) + { + if (*s == LINEFEED_CONTROL_CHAR) + { + *d++ = 13; writePos++; + *d++ = 10; writePos++; + } + else + { + *d++ = *s; writePos++; + } + s++; + } + *d = 0; writePos++; + } + + // strip out all comments - but cheat a little - start at the shader test. + // (the include file was already stripped of comments) + StripComments(&szShaderText[shaderStartPos]); + + /*{ + char* p = szShaderText; + while (*p) + { + char buf[32]; + buf[0] = *p; + buf[1] = 0; + OutputDebugString(buf); + if ((rand() % 9) == 0) + Sleep(1); + p++; + } + OutputDebugString("\n"); + }/**/ + + //note: only do this stuff if type is WARP or COMP shader... not for blur, etc! + //FIXME - hints on the inputs / output / samplers etc. + // can go in the menu header, NOT the preset! =) + //then update presets + // -> be sure to update the presets on disk AND THE DEFAULT SHADERS (for loading MD1 presets) + //FIXME - then update auth. guide w/new examples, + // and a list of the invisible inputs (and one output) to each shader! + // warp: float2 uv, float2 uv_orig, rad, ang + // comp: float2 uv, rad, ang, float3 hue_shader + // test all this string code in Debug mode - make sure nothing bad is happening + + /* + 1. paste warp or comp #defines + 2. search for "void" + whitespace + szFn + [whitespace] + '(' + 3. insert params + 4. search for [whitespace] + ')'. + 5. search for final '}' (strrchr) + 6. back up one char, insert the Last Line, and add '}' and that's it. + */ + if ((shaderType == SHADER_WARP || shaderType == SHADER_COMP) && szProfile[0]=='p') + { + char* p = &szShaderText[shaderStartPos]; + + // seek to 'shader_body' and replace it with spaces + while (*p && strncmp(p, "shader_body", 11)) + p++; + if (p) + { + for (int i=0; i<11; i++) + *p++ = ' '; + } + + if (p) + { + // insert "void PS(...params...)\n" + lstrcpy(temp, p); + const char *params = (shaderType==SHADER_WARP) ? szWarpParams : szCompParams; + sprintf(p, "void %s( %s )\n", szFn, params); + p += lstrlen(p); + lstrcpy(p, temp); + + // find the starting curly brace + p = strchr(p, '{'); + if (p) + { + // skip over it + p++; + // then insert "float3 ret = 0;" + lstrcpy(temp, p); + sprintf(p, "%s\n", szFirstLine); + p += lstrlen(p); + lstrcpy(p, temp); + + // find the ending curly brace + p = strrchr(p, '}'); + // add the last line - " _return_value = float4(ret.xyz, _vDiffuse.w);" + if (p) + sprintf(p, " %s\n}\n", szLastLine); + } + } + + if (!p) + { + wchar_t temp[512]; + swprintf(temp, WASABI_API_LNGSTRINGW(IDS_ERROR_PARSING_X_X_SHADER), szProfile, szWhichShader); + dumpmsg(temp); + AddError(temp, 8.0f, ERR_PRESET, true); + return false; + } + } + + // now really try to compile it. + + bool failed=false; + int len = lstrlen(szShaderText); + if (D3D_OK != pCompileShader( + szShaderText, + len, + NULL,//CONST D3DXMACRO* pDefines, + NULL,//LPD3DXINCLUDE pInclude, + szFn, + szProfile, + m_dwShaderFlags, + &pShaderByteCode, + &m_pShaderCompileErrors, + ppConstTable + )) + { + failed=true; + } + // before we totally fail, let's try using ps_2_b instead of ps_2_a + if (failed && !strcmp(szProfile, "ps_2_a")) + { + SafeRelease(m_pShaderCompileErrors); + if (D3D_OK == pCompileShader(szShaderText, len, NULL, NULL, szFn, + "ps_2_b", m_dwShaderFlags, &pShaderByteCode, &m_pShaderCompileErrors, ppConstTable)) + { + failed=false; + } + } + + if (failed) + { + wchar_t temp[1024]; + swprintf(temp, WASABI_API_LNGSTRINGW(IDS_ERROR_COMPILING_X_X_SHADER), szProfile, szWhichShader); + if (m_pShaderCompileErrors && m_pShaderCompileErrors->GetBufferSize() < sizeof(temp) - 256) + { + lstrcatW(temp, L"\n\n"); + lstrcatW(temp, AutoWide((char*)m_pShaderCompileErrors->GetBufferPointer())); + } + SafeRelease(m_pShaderCompileErrors); + dumpmsg(temp); + if (bHardErrors) + MessageBoxW(GetPluginWindow(), temp, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + else { + AddError(temp, 8.0f, ERR_PRESET, true); + } + return false; + } + + HRESULT hr = 1; + if (szProfile[0] == 'v') + { + hr = GetDevice()->CreateVertexShader((const unsigned long *)(pShaderByteCode->GetBufferPointer()), (IDirect3DVertexShader9**)ppShader); + } + else if (szProfile[0] == 'p') + { + hr = GetDevice()->CreatePixelShader((const unsigned long *)(pShaderByteCode->GetBufferPointer()), (IDirect3DPixelShader9**)ppShader); + } + + if (hr != D3D_OK) + { + wchar_t temp[512]; + WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_CREATING_SHADER,temp,sizeof(temp)); + dumpmsg(temp); + if (bHardErrors) + MessageBoxW(GetPluginWindow(), temp, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + else { + AddError(temp, 6.0f, ERR_PRESET, true); + } + return false; + } + + pShaderByteCode->Release(); + + return true; +} + +//---------------------------------------------------------------------- + +void CPlugin::CleanUpMyDX9Stuff(int final_cleanup) +{ + // Clean up all your DX9 and D3DX textures, fonts, buffers, etc. here. + // EVERYTHING CREATED IN ALLOCATEMYDX9STUFF() SHOULD BE CLEANED UP HERE. + // The input parameter, 'final_cleanup', will be 0 if this is + // a routine cleanup (part of a window resize or switch between + // fullscr/windowed modes), or 1 if this is the final cleanup + // and the plugin is exiting. Note that even if it is a routine + // cleanup, *you still have to release ALL your DirectX stuff, + // because the DirectX device is being destroyed and recreated!* + // Also set all the pointers back to NULL; + // this is important because if we go to reallocate the DX9 + // stuff later, and something fails, then CleanUp will get called, + // but it will then be trying to clean up invalid pointers.) + // The SafeRelease() and SafeDelete() macros make your code prettier; + // they are defined here in utility.h as follows: + // #define SafeRelease(x) if (x) {x->Release(); x=NULL;} + // #define SafeDelete(x) if (x) {delete x; x=NULL;} + // IMPORTANT: + // This function ISN'T only called when the plugin exits! + // It is also called whenever the user toggles between fullscreen and + // windowed modes, or resizes the window. Basically, on these events, + // the base class calls CleanUpMyDX9Stuff before Reset()ing the DirectX + // device, and then calls AllocateMyDX9Stuff afterwards. + + + + // One funky thing here: if we're switching between fullscreen and windowed, + // or doing any other thing that causes all this stuff to get reloaded in a second, + // then if we were blending 2 presets, jump fully to the new preset. + // Otherwise the old preset wouldn't get all reloaded, and it app would crash + // when trying to use its stuff. + if (m_nLoadingPreset != 0) { + // finish up the pre-load & start the official blend + m_nLoadingPreset = 8; + LoadPresetTick(); + } + // just force this: + m_pState->m_bBlending = false; + + + + for (size_t i=0; iOnTextureEvict( m_textures[i].texptr ); + + SafeRelease(m_textures[i].texptr); + } + m_textures.clear(); + + // DON'T RELEASE blur textures - they were already released because they're in m_textures[]. + #if (NUM_BLUR_TEX>0) + for (i=0; iSetTexture(0, NULL); + GetDevice()->SetTexture(1, NULL); + }*/ + + SafeRelease(m_pSpriteVertDecl); + SafeRelease(m_pWfVertDecl); + SafeRelease(m_pMyVertDecl); + + m_shaders.comp.Clear(); + m_shaders.warp.Clear(); + m_OldShaders.comp.Clear(); + m_OldShaders.warp.Clear(); + m_NewShaders.comp.Clear(); + m_NewShaders.warp.Clear(); + m_fallbackShaders_vs.comp.Clear(); + m_fallbackShaders_ps.comp.Clear(); + m_fallbackShaders_vs.warp.Clear(); + m_fallbackShaders_ps.warp.Clear(); + m_BlurShaders[0].vs.Clear(); + m_BlurShaders[0].ps.Clear(); + m_BlurShaders[1].vs.Clear(); + m_BlurShaders[1].ps.Clear(); + /* + SafeRelease( m_shaders.comp.ptr ); + SafeRelease( m_shaders.warp.ptr ); + SafeRelease( m_OldShaders.comp.ptr ); + SafeRelease( m_OldShaders.warp.ptr ); + SafeRelease( m_NewShaders.comp.ptr ); + SafeRelease( m_NewShaders.warp.ptr ); + SafeRelease( m_fallbackShaders_vs.comp.ptr ); + SafeRelease( m_fallbackShaders_ps.comp.ptr ); + SafeRelease( m_fallbackShaders_vs.warp.ptr ); + SafeRelease( m_fallbackShaders_ps.warp.ptr ); + */ + SafeRelease( m_pShaderCompileErrors ); + //SafeRelease( m_pCompiledFragments ); + //SafeRelease( m_pFragmentLinker ); + + // 2. release stuff + SafeRelease(m_lpVS[0]); + SafeRelease(m_lpVS[1]); + SafeRelease(m_lpDDSTitle); + SafeRelease(m_d3dx_title_font_doublesize); + + // NOTE: THIS CODE IS IN THE RIGHT PLACE. + if (m_gdi_title_font_doublesize) + { + DeleteObject(m_gdi_title_font_doublesize); + m_gdi_title_font_doublesize = NULL; + } + + m_texmgr.Finish(); + + if (m_verts != NULL) + { + delete m_verts; + m_verts = NULL; + } + + if (m_verts_temp != NULL) + { + delete m_verts_temp; + m_verts_temp = NULL; + } + + if (m_vertinfo != NULL) + { + delete m_vertinfo; + m_vertinfo = NULL; + } + + if (m_indices_list != NULL) + { + delete m_indices_list; + m_indices_list = NULL; + } + + if (m_indices_strip != NULL) + { + delete m_indices_strip; + m_indices_strip = NULL; + } + + ClearErrors(); + + // This setting is closely tied to the modern skin "random" button. + // The "random" state should be preserved from session to session. + // It's pretty safe to do, because the Scroll Lock key is hard to + // accidentally click... :) + WritePrivateProfileIntW(m_bPresetLockedByUser,L"bPresetLockOnAtStartup", GetConfigIniFile(),L"settings"); +} + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + +void CPlugin::MyRenderFn(int redraw) +{ + EnterCriticalSection(&g_cs); + + // Render a frame of animation here. + // This function is called each frame just AFTER BeginScene(). + // For timing information, call 'GetTime()' and 'GetFps()'. + // The usual formula is like this (but doesn't have to be): + // 1. take care of timing/other paperwork/etc. for new frame + // 2. clear the background + // 3. get ready for 3D drawing + // 4. draw your 3D stuff + // 5. call PrepareFor2DDrawing() + // 6. draw your 2D stuff (overtop of your 3D scene) + // If the 'redraw' flag is 1, you should try to redraw + // the last frame; GetTime, GetFps, and GetFrame should + // all return the same values as they did on the last + // call to MyRenderFn(). Otherwise, the redraw flag will + // be zero, and you can draw a new frame. The flag is + // used to force the desktop to repaint itself when + // running in desktop mode and Winamp is paused or stopped. + + // 1. take care of timing/other paperwork/etc. for new frame + if (!redraw) + { + float dt = GetTime() - m_prev_time; + m_prev_time = GetTime(); // note: m_prev_time is not for general use! + m_bPresetLockedByCode = (m_UI_mode != UI_REGULAR); + if (m_bPresetLockedByUser || m_bPresetLockedByCode) + { + // to freeze time (at current preset time value) when menus are up or Scroll Lock is on: + //m_fPresetStartTime += dt; + //m_fNextPresetTime += dt; + // OR, to freeze time @ [preset] zero, so that when you exit menus, + // you don't run the risk of it changing the preset on you right away: + m_fPresetStartTime = GetTime(); + m_fNextPresetTime = -1.0f; // flags UpdateTime() to recompute this. + } + + //if (!m_bPresetListReady) + // UpdatePresetList(true);//UpdatePresetRatings(); // read in a few each frame, til they're all in + } + + // 2. check for lost or gained kb focus: + // (note: can't use wm_setfocus or wm_killfocus because they don't work w/embedwnd) + if (GetFrame()==0) + { + // NOTE: we skip this if we've already gotten a WM_COMMAND/ID_VIS_RANDOM message + // from the skin - if that happened, we're running windowed with a fancy + // skin with a 'rand' button. + + SetScrollLock(m_bPresetLockOnAtStartup, m_bPreventScollLockHandling); + + // make sure the 'random' button on the skin shows the right thing: + // NEVERMIND - if it's a fancy skin, it'll send us WM_COMMAND/ID_VIS_RANDOM + // and we'll match the skin's Random button state. + //SendMessage(GetWinampWindow(),WM_WA_IPC,m_bMilkdropScrollLockState, IPC_CB_VISRANDOM); + } + else + { + m_bHadFocus = m_bHasFocus; + + HWND winamp = GetWinampWindow(); + HWND plugin = GetPluginWindow(); + HWND focus = GetFocus(); + HWND cur = plugin; + + m_bHasFocus = false; + do + { + m_bHasFocus = (focus == cur); + if (m_bHasFocus) + break; + cur = GetParent(cur); + } + while (cur != NULL && cur != winamp); + + if (m_hTextWnd && focus==m_hTextWnd) + m_bHasFocus = 1; + + if (GetFocus()==NULL) + m_bHasFocus = 0; + ; + //HWND t1 = GetFocus(); + //HWND t2 = GetPluginWindow(); + //HWND t3 = GetParent(t2); + + if (m_bHadFocus==1 && m_bHasFocus==0) + { + //m_bMilkdropScrollLockState = GetKeyState(VK_SCROLL) & 1; + SetScrollLock(m_bOrigScrollLockState, m_bPreventScollLockHandling); + } + else if (m_bHadFocus==0 && m_bHasFocus==1) + { + m_bOrigScrollLockState = GetKeyState(VK_SCROLL) & 1; + SetScrollLock(m_bPresetLockedByUser, m_bPreventScollLockHandling); + } + } + + if (!redraw) + { + GetWinampSongTitle(GetWinampWindow(), m_szSongTitle, sizeof(m_szSongTitle)-1); + if (wcscmp(m_szSongTitle, m_szSongTitlePrev)) + { + lstrcpynW(m_szSongTitlePrev, m_szSongTitle, 512); + if (m_bSongTitleAnims) + LaunchSongTitleAnim(); + } + } + + // 2. Clear the background: + //DWORD clear_color = (m_fog_enabled) ? FOG_COLOR : 0xFF000000; + //GetDevice()->Clear(0, 0, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, clear_color, 1.0f, 0); + + // 5. switch to 2D drawing mode. 2D coord system: + // +--------+ Y=-1 + // | | + // | screen | Z=0: front of scene + // | | Z=1: back of scene + // +--------+ Y=1 + // X=-1 X=1 + PrepareFor2DDrawing(GetDevice()); + + if (!redraw) + DoCustomSoundAnalysis(); // emulates old pre-vms milkdrop sound analysis + + RenderFrame(redraw); // see milkdropfs.cpp + + /* + for (int i=0; i<10; i++) + { + RECT r; + r.top = GetHeight()*i/10; + r.left = 0; + r.right = GetWidth(); + r.bottom = r.top + GetFontHeight(DECORATIVE_FONT); + char buf[256]; + switch(i) + { + case 0: lstrcpy(buf, "this is a test"); break; + case 1: lstrcpy(buf, "argh"); break; + case 2: lstrcpy(buf, "!!"); break; + case 3: lstrcpy(buf, "TESTING FONTS"); break; + case 4: lstrcpy(buf, "rancid bear grease"); break; + case 5: lstrcpy(buf, "whoppers and ding dongs"); break; + case 6: lstrcpy(buf, "billy & joey"); break; + case 7: lstrcpy(buf, "."); break; + case 8: lstrcpy(buf, "---"); break; + case 9: lstrcpy(buf, "test"); break; + } + int t = (int)( 54 + 18*sin(i/10.0f*53.7f + 1) - 28*sin(i/10.0f*39.4f + 3) ); + if (((GetFrame() + i*107) % t) < t*8/9) + m_text.QueueText(GetFont(DECORATIVE_FONT), buf, r, 0, 0xFFFF00FF); + } + /**/ + + if (!redraw) + { + m_nFramesSinceResize++; + if (m_nLoadingPreset > 0) + { + LoadPresetTick(); + } + } + + LeaveCriticalSection(&g_cs); +} + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + +void CPlugin::DrawTooltip(wchar_t* str, int xR, int yB) +{ + // draws a string in the lower-right corner of the screen. + // note: ID3DXFont handles DT_RIGHT and DT_BOTTOM *very poorly*. + // it is best to calculate the size of the text first, + // then place it in the right spot. + // note: use DT_WORDBREAK instead of DT_WORD_ELLIPSES, otherwise certain fonts' + // calcrect (for the dark box) will be wrong. + + RECT r, r2; + SetRect(&r, 0, 0, xR-TEXT_MARGIN*2, 2048); + m_text.DrawTextW(GetFont(TOOLTIP_FONT), str, -1, &r, DT_CALCRECT, 0xFFFFFFFF, false); + r2.bottom = yB - TEXT_MARGIN; + r2.right = xR - TEXT_MARGIN; + r2.left = r2.right - (r.right-r.left); + r2.top = r2.bottom - (r.bottom-r.top); + RECT r3 = r2; r3.left -= 4; r3.top -= 2; r3.right += 2; r3.bottom += 2; + DrawDarkTranslucentBox(&r3); + m_text.DrawTextW(GetFont(TOOLTIP_FONT), str, -1, &r2, 0, 0xFFFFFFFF, false); +} + +#define MTO_UPPER_RIGHT 0 +#define MTO_UPPER_LEFT 1 +#define MTO_LOWER_RIGHT 2 +#define MTO_LOWER_LEFT 3 + +#define SelectFont(n) { \ + pFont = GetFont(n); \ + h = GetFontHeight(n); \ +} + +#define MyTextOut_BGCOLOR(str, corner, bDarkBox, boxColor) { \ + SetRect(&r, 0, 0, xR-xL, 2048); \ + m_text.DrawTextW(pFont, str, -1, &r, DT_NOPREFIX | ((corner == MTO_UPPER_RIGHT)?0:DT_SINGLELINE) | DT_WORD_ELLIPSIS | DT_CALCRECT | ((corner == MTO_UPPER_RIGHT) ? DT_RIGHT : 0), 0xFFFFFFFF, false, boxColor); \ + int w = r.right - r.left; \ + if (corner == MTO_UPPER_LEFT ) SetRect(&r, xL, *upper_left_corner_y, xL+w, *upper_left_corner_y + h); \ + else if (corner == MTO_UPPER_RIGHT) SetRect(&r, xR-w, *upper_right_corner_y, xR, *upper_right_corner_y + h); \ + else if (corner == MTO_LOWER_LEFT ) SetRect(&r, xL, *lower_left_corner_y - h, xL+w, *lower_left_corner_y); \ + else if (corner == MTO_LOWER_RIGHT) SetRect(&r, xR-w, *lower_right_corner_y - h, xR, *lower_right_corner_y); \ + m_text.DrawTextW(pFont, str, -1, &r, DT_NOPREFIX | ((corner == MTO_UPPER_RIGHT)?0:DT_SINGLELINE) | DT_WORD_ELLIPSIS | ((corner == MTO_UPPER_RIGHT) ? DT_RIGHT: 0), 0xFFFFFFFF, bDarkBox, boxColor); \ + if (corner == MTO_UPPER_LEFT ) *upper_left_corner_y += h; \ + else if (corner == MTO_UPPER_RIGHT) *upper_right_corner_y += h; \ + else if (corner == MTO_LOWER_LEFT ) *lower_left_corner_y -= h; \ + else if (corner == MTO_LOWER_RIGHT) *lower_right_corner_y -= h; \ +} + +#define MyTextOut(str, corner, bDarkBox) MyTextOut_BGCOLOR(str, corner, bDarkBox, 0xFF000000) + +#define MyTextOut_Shadow(str, corner) { \ + /* calc rect size */ \ + SetRect(&r, 0, 0, xR-xL, 2048); \ + m_text.DrawTextW(pFont, (wchar_t*)str, -1, &r, DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_CALCRECT, 0xFFFFFFFF, false, 0xFF000000); \ + int w = r.right - r.left; \ + /* first the shadow */ \ + if (corner == MTO_UPPER_LEFT ) SetRect(&r, xL, *upper_left_corner_y, xL+w, *upper_left_corner_y + h); \ + else if (corner == MTO_UPPER_RIGHT) SetRect(&r, xR-w, *upper_right_corner_y, xR, *upper_right_corner_y + h); \ + else if (corner == MTO_LOWER_LEFT ) SetRect(&r, xL, *lower_left_corner_y - h, xL+w, *lower_left_corner_y); \ + else if (corner == MTO_LOWER_RIGHT) SetRect(&r, xR-w, *lower_right_corner_y - h, xR, *lower_right_corner_y); \ + r.top += 1; r.left += 1; \ + m_text.DrawTextW(pFont, (wchar_t*)str, -1, &r, DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, 0xFF000000, false, 0xFF000000); \ + /* now draw real text */ \ + r.top -= 1; r.left -= 1; \ + m_text.DrawTextW(pFont, (wchar_t*)str, -1, &r, DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, 0xFFFFFFFF, false, 0xFF000000); \ + if (corner == MTO_UPPER_LEFT ) *upper_left_corner_y += h; \ + else if (corner == MTO_UPPER_RIGHT) *upper_right_corner_y += h; \ + else if (corner == MTO_LOWER_LEFT ) *lower_left_corner_y -= h; \ + else if (corner == MTO_LOWER_RIGHT) *lower_right_corner_y -= h; \ +} + +void CPlugin::OnAltK() +{ + AddError(WASABI_API_LNGSTRINGW(IDS_PLEASE_EXIT_VIS_BEFORE_RUNNING_CONFIG_PANEL), 3.0f, ERR_NOTIFY, true); +} + +void CPlugin::AddError(wchar_t* szMsg, float fDuration, int category, bool bBold) +{ + if (category == ERR_NOTIFY) + ClearErrors(category); + + assert(category != ERR_ALL); + ErrorMsg x; + x.msg = szMsg; + x.birthTime = GetTime(); + x.expireTime = GetTime() + fDuration; + x.category = category; + x.bBold = bBold; + m_errors.push_back(x); +} + +void CPlugin::ClearErrors(int category) // 0=all categories +{ + int N = m_errors.size(); + for (int i=0; im_szDesc : m_pState->m_szDesc); + MyTextOut_Shadow(buf, MTO_UPPER_RIGHT); + } + + // b) preset rating + if (m_bShowRating || GetTime() < m_fShowRatingUntilThisTime) + { + // see also: SetCurrentPresetRating() in milkdrop.cpp + SelectFont(DECORATIVE_FONT); + swprintf(buf, L" %s: %d ", WASABI_API_LNGSTRINGW(IDS_RATING), (int)m_pState->m_fRating); + if (!m_bEnableRating) lstrcatW(buf, WASABI_API_LNGSTRINGW(IDS_DISABLED)); + MyTextOut_Shadow(buf, MTO_UPPER_RIGHT); + } + + // c) fps display + if (m_bShowFPS) + { + SelectFont(DECORATIVE_FONT); + swprintf(buf, L"%s: %4.2f ", WASABI_API_LNGSTRINGW(IDS_FPS), GetFps()); // leave extra space @ end, so italicized fonts don't get clipped + MyTextOut_Shadow(buf, MTO_UPPER_RIGHT); + } + + // d) debug information + if (m_bShowDebugInfo) + { + SelectFont(SIMPLE_FONT); + swprintf(buf, L" %s: %6.4f ", WASABI_API_LNGSTRINGW(IDS_PF_MONITOR), (float)(*m_pState->var_pf_monitor)); + MyTextOut_Shadow(buf, MTO_UPPER_RIGHT); + } + + // NOTE: custom timed msg comes at the end!! + } + + // 2. render text in lower-right corner + { + // waitstring tooltip: + if (m_waitstring.bActive && m_bShowMenuToolTips && m_waitstring.szToolTip[0]) + { + DrawTooltip(m_waitstring.szToolTip, xR, *lower_right_corner_y); + } + } + + // 3. render text in lower-left corner + { + wchar_t buf2[512] = {0}; + wchar_t buf3[512+1] = {0}; // add two extra spaces to end, so italicized fonts don't get clipped + + // render song title in lower-left corner: + if (m_bShowSongTitle) + { + wchar_t buf4[512] = {0}; + SelectFont(DECORATIVE_FONT); + GetWinampSongTitle(GetWinampWindow(), buf4, sizeof(buf4)); // defined in utility.h/cpp + MyTextOut_Shadow(buf4, MTO_LOWER_LEFT); + } + + // render song time & len above that: + if (m_bShowSongTime || m_bShowSongLen) + { + GetWinampSongPosAsText(GetWinampWindow(), buf); // defined in utility.h/cpp + GetWinampSongLenAsText(GetWinampWindow(), buf2); // defined in utility.h/cpp + if (m_bShowSongTime && m_bShowSongLen) + { + // only show playing position and track length if it is playing (buffer is valid) + if(buf[0]) + swprintf(buf3, L"%s / %s ", buf, buf2); + else + lstrcpynW(buf3, buf2, 512); + } + else if (m_bShowSongTime) + lstrcpynW(buf3, buf, 512); + else + lstrcpynW(buf3, buf2, 512); + + SelectFont(DECORATIVE_FONT); + MyTextOut_Shadow(buf3, MTO_LOWER_LEFT); + } + } + + // 4. render text in upper-left corner + { + wchar_t buf[64000] = {0}; // must fit the longest strings (code strings are 32768 chars) + // AND leave extra space for &->&&, and [,[,& insertion + char bufA[64000] = {0}; + + SelectFont(SIMPLE_FONT); + + // stuff for loading presets, menus, etc: + + if (m_waitstring.bActive) + { + // 1. draw the prompt string + MyTextOut(m_waitstring.szPrompt, MTO_UPPER_LEFT, true); + + // extra instructions: + bool bIsWarp = m_waitstring.bDisplayAsCode && (m_pCurMenu == &m_menuPreset) && !wcscmp(m_menuPreset.GetCurItem()->m_szName, L"[ edit warp shader ]"); + bool bIsComp = m_waitstring.bDisplayAsCode && (m_pCurMenu == &m_menuPreset) && !wcscmp(m_menuPreset.GetCurItem()->m_szName, L"[ edit composite shader ]"); + if (bIsWarp || bIsComp) + { + if (m_bShowShaderHelp) { + MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESS_F9_TO_HIDE_SHADER_QREF), MTO_UPPER_LEFT, true); + } + else { + MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESS_F9_TO_SHOW_SHADER_QREF), MTO_UPPER_LEFT, true); + } + *upper_left_corner_y += h*2/3; + + if (m_bShowShaderHelp) + { + // draw dark box - based on longest line & # lines... + SetRect(&r, 0, 0, 2048, 2048); + m_text.DrawTextW(pFont, WASABI_API_LNGSTRINGW(IDS_STRING615), -1, &r, DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_CALCRECT, 0xFFFFFFFF, false, 0xFF000000); + RECT darkbox; + SetRect(&darkbox, xL, *upper_left_corner_y-2, xL+r.right-r.left, *upper_left_corner_y + (r.bottom-r.top)*13 + 2); + DrawDarkTranslucentBox(&darkbox); + + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING616), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING617), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING618), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING619), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING620), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING621), MTO_UPPER_LEFT, false); + if (bIsWarp) + { + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING622), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING623), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING624), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING625), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING626), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING627), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING628), MTO_UPPER_LEFT, false); + } + else if (bIsComp) + { + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING629), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING630), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING631), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING632), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING633), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING634), MTO_UPPER_LEFT, false); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING635), MTO_UPPER_LEFT, false); + } + *upper_left_corner_y += h*2/3; + } + } + else if (m_UI_mode == UI_SAVEAS && (m_bWarpShaderLock || m_bCompShaderLock)) + { + wchar_t buf[256] = {0}; + int shader_msg_id = IDS_COMPOSITE_SHADER_LOCKED; + if (m_bWarpShaderLock && m_bCompShaderLock) + shader_msg_id = IDS_WARP_AND_COMPOSITE_SHADERS_LOCKED; + else if (m_bWarpShaderLock && !m_bCompShaderLock) + shader_msg_id = IDS_WARP_SHADER_LOCKED; + else + shader_msg_id = IDS_COMPOSITE_SHADER_LOCKED; + + WASABI_API_LNGSTRINGW_BUF(shader_msg_id, buf, 256); + MyTextOut_BGCOLOR(buf, MTO_UPPER_LEFT, true, 0xFF000000); + *upper_left_corner_y += h*2/3; + } + else + *upper_left_corner_y += h*2/3; + + + // 2. reformat the waitstring text for display + int bBrackets = m_waitstring.nSelAnchorPos != -1 && m_waitstring.nSelAnchorPos != m_waitstring.nCursorPos; + int bCursorBlink = ( !bBrackets && + ((int)(GetTime()*270.0f) % 100 > 50) + //((GetFrame() % 3) >= 2) + ); + + lstrcpyW(buf, m_waitstring.szText); + lstrcpyA(bufA, (char*)m_waitstring.szText); + + int temp_cursor_pos = m_waitstring.nCursorPos; + int temp_anchor_pos = m_waitstring.nSelAnchorPos; + + if (bBrackets) + { + if (m_waitstring.bDisplayAsCode) + { + // insert [] around the selection + int start = (temp_cursor_pos < temp_anchor_pos) ? temp_cursor_pos : temp_anchor_pos; + int end = (temp_cursor_pos > temp_anchor_pos) ? temp_cursor_pos - 1 : temp_anchor_pos - 1; + int len = lstrlenA(bufA); + int i; + + for (i=len; i>end; i--) + bufA[i+1] = bufA[i]; + bufA[end+1] = ']'; + len++; + + for (i=len; i>=start; i--) + bufA[i+1] = bufA[i]; + bufA[start] = '['; + len++; + } + else + { + // insert [] around the selection + int start = (temp_cursor_pos < temp_anchor_pos) ? temp_cursor_pos : temp_anchor_pos; + int end = (temp_cursor_pos > temp_anchor_pos) ? temp_cursor_pos - 1 : temp_anchor_pos - 1; + int len = lstrlenW(buf); + int i; + + for (i=len; i>end; i--) + buf[i+1] = buf[i]; + buf[end+1] = L']'; + len++; + + for (i=len; i>=start; i--) + buf[i+1] = buf[i]; + buf[start] = L'['; + len++; + } + } + else + { + // underline the current cursor position by rapidly toggling the character with an underscore + if (m_waitstring.bDisplayAsCode) + { + if (bCursorBlink) + { + if (bufA[temp_cursor_pos] == 0) + { + bufA[temp_cursor_pos] = '_'; + bufA[temp_cursor_pos+1] = 0; + } + else if (bufA[temp_cursor_pos] == LINEFEED_CONTROL_CHAR) + { + for (int i=strlen(bufA); i>=temp_cursor_pos; i--) + bufA[i+1] = bufA[i]; + bufA[temp_cursor_pos] = '_'; + } + else if (bufA[temp_cursor_pos] == '_') + bufA[temp_cursor_pos] = ' '; + else // it's a space or symbol or alphanumeric. + bufA[temp_cursor_pos] = '_'; + } + else + { + if (bufA[temp_cursor_pos] == 0) + { + bufA[temp_cursor_pos] = ' '; + bufA[temp_cursor_pos+1] = 0; + } + else if (bufA[temp_cursor_pos] == LINEFEED_CONTROL_CHAR) + { + for (int i=strlen(bufA); i>=temp_cursor_pos; i--) + bufA[i+1] = bufA[i]; + bufA[temp_cursor_pos] = ' '; + } + //else if (buf[temp_cursor_pos] == '_') + // do nothing + //else // it's a space or symbol or alphanumeric. + // do nothing + } + } + else + { + if (bCursorBlink) + { + if (buf[temp_cursor_pos] == 0) + { + buf[temp_cursor_pos] = L'_'; + buf[temp_cursor_pos+1] = 0; + } + else if (buf[temp_cursor_pos] == LINEFEED_CONTROL_CHAR) + { + for (int i=wcslen(buf); i>=temp_cursor_pos; i--) + buf[i+1] = buf[i]; + buf[temp_cursor_pos] = L'_'; + } + else if (buf[temp_cursor_pos] == L'_') + buf[temp_cursor_pos] = L' '; + else // it's a space or symbol or alphanumeric. + buf[temp_cursor_pos] = L'_'; + } + else + { + if (buf[temp_cursor_pos] == 0) + { + buf[temp_cursor_pos] = L' '; + buf[temp_cursor_pos+1] = 0; + } + else if (buf[temp_cursor_pos] == LINEFEED_CONTROL_CHAR) + { + for (int i=wcslen(buf); i>=temp_cursor_pos; i--) + buf[i+1] = buf[i]; + buf[temp_cursor_pos] = L' '; + } + //else if (buf[temp_cursor_pos] == '_') + // do nothing + //else // it's a space or symbol or alphanumeric. + // do nothing + } + } + } + + RECT rect = {0}; + SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y); + rect.top += PLAYLIST_INNER_MARGIN; + rect.left += PLAYLIST_INNER_MARGIN; + rect.right -= PLAYLIST_INNER_MARGIN; + rect.bottom -= PLAYLIST_INNER_MARGIN; + + // then draw the edit string + if (m_waitstring.bDisplayAsCode) + { + char buf2[8192] = {0}; + int top_of_page_pos = 0; + + // compute top_of_page_pos so that the line the cursor is on will show. + // also compute dims of the black rectangle while we're at it. + { + int start = 0; + int pos = 0; + int ypixels = 0; + int page = 1; + int exit_on_next_page = 0; + + RECT box = rect; + box.right = box.left; + box.bottom = box.top; + + while (bufA[pos] != 0) // for each line of text... (note that it might wrap) + { + start = pos; + while (bufA[pos] != LINEFEED_CONTROL_CHAR && bufA[pos] != 0) + pos++; + + char ch = bufA[pos]; + bufA[pos] = 0; + sprintf(buf2, " %sX", &bufA[start]); // put a final 'X' instead of ' ' b/c CALCRECT returns w==0 if string is entirely whitespace! + RECT r2 = rect; + r2.bottom = 4096; + m_text.DrawTextA(GetFont(SIMPLE_FONT), buf2, -1, &r2, DT_CALCRECT /*| DT_WORDBREAK*/, 0xFFFFFFFF, false); + int h = r2.bottom-r2.top; + ypixels += h; + bufA[pos] = ch; + + if (start > m_waitstring.nCursorPos) // make sure 'box' gets updated for each line on this page + exit_on_next_page = 1; + + if (ypixels > rect.bottom-rect.top) // this line belongs on the next page + { + if (exit_on_next_page) + { + bufA[start] = 0; // so text stops where the box stops, when we draw the text + break; + } + + ypixels = h; + top_of_page_pos = start; + page++; + + box = rect; + box.right = box.left; + box.bottom = box.top; + } + box.bottom += h; + box.right = max(box.right, box.left + r2.right-r2.left); + + if (bufA[pos]==0) + break; + pos++; + } + + // use r2 to draw a dark box: + box.top -= PLAYLIST_INNER_MARGIN; + box.left -= PLAYLIST_INNER_MARGIN; + box.right += PLAYLIST_INNER_MARGIN; + box.bottom += PLAYLIST_INNER_MARGIN; + DrawDarkTranslucentBox(&box); + *upper_left_corner_y += box.bottom - box.top + PLAYLIST_INNER_MARGIN*3; + swprintf(m_waitstring.szToolTip, WASABI_API_LNGSTRINGW(IDS_PAGE_X), page); + } + + // display multiline (replace all character 13's with a CR) + { + int start = top_of_page_pos; + int pos = top_of_page_pos; + + while (bufA[pos] != 0) + { + while (bufA[pos] != LINEFEED_CONTROL_CHAR && bufA[pos] != 0) + pos++; + + char ch = bufA[pos]; + bufA[pos] = 0; + sprintf(buf2, " %s ", &bufA[start]); + DWORD color = MENU_COLOR; + if (m_waitstring.nCursorPos >= start && m_waitstring.nCursorPos <= pos) + color = MENU_HILITE_COLOR; + rect.top += m_text.DrawTextA(GetFont(SIMPLE_FONT), buf2, -1, &rect, 0/*DT_WORDBREAK*/, color, false); + bufA[pos] = ch; + + if (rect.top > rect.bottom) + break; + + if (bufA[pos] != 0) pos++; + start = pos; + } + } + // note: *upper_left_corner_y is updated above, when the dark box is drawn. + } + else + { + wchar_t buf2[8192] = {0}; + + // display on one line + RECT box = rect; + box.bottom = 4096; + swprintf(buf2, L" %sX", buf); // put a final 'X' instead of ' ' b/c CALCRECT returns w==0 if string is entirely whitespace! + m_text.DrawTextW(GetFont(SIMPLE_FONT), buf2, -1, &box, DT_CALCRECT, MENU_COLOR, false ); + + // use r2 to draw a dark box: + box.top -= PLAYLIST_INNER_MARGIN; + box.left -= PLAYLIST_INNER_MARGIN; + box.right += PLAYLIST_INNER_MARGIN; + box.bottom += PLAYLIST_INNER_MARGIN; + DrawDarkTranslucentBox(&box); + *upper_left_corner_y += box.bottom - box.top + PLAYLIST_INNER_MARGIN*3; + + swprintf(buf2, L" %s ", buf); + m_text.DrawTextW(GetFont(SIMPLE_FONT), buf2, -1, &rect, 0, MENU_COLOR, false ); + } + } + else if (m_UI_mode == UI_MENU) + { + assert(m_pCurMenu); + SetRect(&r, xL, *upper_left_corner_y, xR, *lower_left_corner_y); + + RECT darkbox = {0}; + m_pCurMenu->DrawMenu(r, xR, *lower_right_corner_y, 1, &darkbox); + *upper_left_corner_y += darkbox.bottom - darkbox.top + PLAYLIST_INNER_MARGIN*3; + + darkbox.right += PLAYLIST_INNER_MARGIN*2; + darkbox.bottom += PLAYLIST_INNER_MARGIN*2; + DrawDarkTranslucentBox(&darkbox); + + r.top += PLAYLIST_INNER_MARGIN; + r.left += PLAYLIST_INNER_MARGIN; + r.right += PLAYLIST_INNER_MARGIN; + r.bottom += PLAYLIST_INNER_MARGIN; + m_pCurMenu->DrawMenu(r, xR, *lower_right_corner_y); + } + else if (m_UI_mode == UI_UPGRADE_PIXEL_SHADER) + { + RECT rect = {0}; + SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y); + + if (m_pState->m_nWarpPSVersion >= m_nMaxPSVersion && + m_pState->m_nCompPSVersion >= m_nMaxPSVersion) + { + assert(m_pState->m_nMaxPSVersion == m_nMaxPSVersion); + wchar_t buf[1024] = {0}; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PRESET_USES_HIGHEST_PIXEL_SHADER_VERSION), m_nMaxPSVersion); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), buf, -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESS_ESC_TO_RETURN), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + } + else + { + if (m_pState->m_nMinPSVersion != m_pState->m_nMaxPSVersion) + { + switch(m_pState->m_nMinPSVersion) + { + case MD2_PS_NONE: + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_HAS_MIXED_VERSIONS_OF_SHADERS), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_SHADERS_TO_USE_PS2), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + break; + case MD2_PS_2_0: + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_HAS_MIXED_VERSIONS_OF_SHADERS), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_SHADERS_TO_USE_PS2X), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + break; + case MD2_PS_2_X: + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_HAS_MIXED_VERSIONS_OF_SHADERS), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_SHADERS_TO_USE_PS3), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + break; + case MD2_PS_3_0: + assert(false); + break; + default: + assert(0); + break; + } + } + else + { + switch(m_pState->m_nMinPSVersion) + { + case MD2_PS_NONE: + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_DOES_NOT_USE_PIXEL_SHADERS), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_TO_USE_PS2), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + break; + case MD2_PS_2_0: + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_CURRENTLY_USES_PS2), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_TO_USE_PS2X), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + break; + case MD2_PS_2_X: + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_CURRENTLY_USES_PS2X), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_TO_USE_PS3), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + break; + case MD2_PS_3_0: + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_CURRENTLY_USES_PS3), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_TO_USE_PS4), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + break; + default: + assert(0); + break; + } + } + } + *upper_left_corner_y = rect.top; + } + else if (m_UI_mode == UI_LOAD_DEL) + { + RECT rect; + SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_ARE_YOU_SURE_YOU_WANT_TO_DELETE_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PRESET_TO_DELETE), m_presets[m_nPresetListCurPos].szFilename.c_str()); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), buf, -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + *upper_left_corner_y = rect.top; + } + else if (m_UI_mode == UI_SAVE_OVERWRITE) + { + RECT rect; + SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_FILE_ALREADY_EXISTS_OVERWRITE_IT), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_FILE_IN_QUESTION_X_MILK), m_waitstring.szText); + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), buf, -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true); + if (m_bWarpShaderLock) + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_DO_NOT_FORGET_WARP_SHADER_WAS_LOCKED), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, 0xFFFFFFFF, true, 0xFFCC0000); + if (m_bCompShaderLock) + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_DO_NOT_FORGET_COMPOSITE_SHADER_WAS_LOCKED), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, 0xFFFFFFFF, true, 0xFFCC0000); + *upper_left_corner_y = rect.top; + } + else if (m_UI_mode == UI_MASHUP) + { + if (m_nPresets-m_nDirs == 0) + { + // note: this error message is repeated in milkdrop.cpp in LoadRandomPreset() + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILE_FOUND_IN_X_MILK), m_szPresetDir); + AddError(buf, 6.0f, ERR_MISC, true); + m_UI_mode = UI_REGULAR; + } + else + { + UpdatePresetList(); // make sure list is completely ready + + // quick checks + for (int mash=0; mash= m_nPresets) + m_nMashPreset[mash] = m_nPresets-1; + + // apply changes, if it's time + if (m_nLastMashChangeFrame[mash]+MASH_APPLY_DELAY_FRAMES+1 == GetFrame()) + { + // import just a fragment of a preset!! + DWORD ApplyFlags = 0; + switch(mash) + { + case 0: ApplyFlags = STATE_GENERAL; break; + case 1: ApplyFlags = STATE_MOTION; break; + case 2: ApplyFlags = STATE_WAVE; break; + case 3: ApplyFlags = STATE_WARP; break; + case 4: ApplyFlags = STATE_COMP; break; + } + + wchar_t szFile[MAX_PATH]; + swprintf(szFile, L"%s%s", m_szPresetDir, m_presets[m_nMashPreset[mash]].szFilename.c_str()); + + m_pState->Import(szFile, GetTime(), m_pState, ApplyFlags); + + if (ApplyFlags & STATE_WARP) + SafeRelease( m_shaders.warp.ptr ); + if (ApplyFlags & STATE_COMP) + SafeRelease( m_shaders.comp.ptr ); + LoadShaders(&m_shaders, m_pState, false); + + SetMenusForPresetVersion( m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion ); + } + } + + MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESET_MASH_UP_TEXT1), MTO_UPPER_LEFT, true); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESET_MASH_UP_TEXT2), MTO_UPPER_LEFT, true); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESET_MASH_UP_TEXT3), MTO_UPPER_LEFT, true); + MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESET_MASH_UP_TEXT4), MTO_UPPER_LEFT, true); + *upper_left_corner_y += PLAYLIST_INNER_MARGIN; + + RECT rect; + SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y); + rect.top += PLAYLIST_INNER_MARGIN; + rect.left += PLAYLIST_INNER_MARGIN; + rect.right -= PLAYLIST_INNER_MARGIN; + rect.bottom -= PLAYLIST_INNER_MARGIN; + + int lines_available = (rect.bottom - rect.top - PLAYLIST_INNER_MARGIN*2) / GetFontHeight(SIMPLE_FONT); + lines_available -= MASH_SLOTS; + + if (lines_available < 10) + { + // force it + rect.bottom = rect.top + GetFontHeight(SIMPLE_FONT)*10 + 1; + lines_available = 10; + } + if (lines_available > 16) + lines_available = 16; + + if (m_bUserPagedDown) + { + m_nMashPreset[m_nMashSlot] += lines_available; + if (m_nMashPreset[m_nMashSlot] >= m_nPresets) + m_nMashPreset[m_nMashSlot] = m_nPresets - 1; + m_bUserPagedDown = false; + } + if (m_bUserPagedUp) + { + m_nMashPreset[m_nMashSlot] -= lines_available; + if (m_nMashPreset[m_nMashSlot] < m_nDirs) + m_nMashPreset[m_nMashSlot] = m_nDirs; + m_bUserPagedUp = false; + } + + int i; + int first_line = m_nMashPreset[m_nMashSlot] - (m_nMashPreset[m_nMashSlot] % lines_available); + int last_line = first_line + lines_available; + wchar_t str[512], str2[512]; + + if (last_line > m_nPresets) + last_line = m_nPresets; + + // tooltip: + if (m_bShowMenuToolTips) + { + wchar_t buf[256]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PAGE_X_OF_X), m_nMashPreset[m_nMashSlot]/lines_available+1, (m_nPresets+lines_available-1)/lines_available); + DrawTooltip(buf, xR, *lower_right_corner_y); + } + + RECT orig_rect = rect; + + RECT box; + box.top = rect.top; + box.left = rect.left; + box.right = rect.left; + box.bottom = rect.top; + + int mashNames[MASH_SLOTS] = { IDS_MASHUP_GENERAL_POSTPROC, + IDS_MASHUP_MOTION_EQUATIONS, + IDS_MASHUP_WAVEFORMS_SHAPES, + IDS_MASHUP_WARP_SHADER, + IDS_MASHUP_COMP_SHADER, + }; + + + for (int pass=0; pass<2; pass++) + { + box = orig_rect; + int w = 0; + int h = 0; + + int start_y = orig_rect.top; + for (mash=0; mashBegin(); + + rect = orig_rect; + for (i=first_line; iEnd(); + + if (pass==0) // calculating dark box + { + box.top -= PLAYLIST_INNER_MARGIN; + box.left -= PLAYLIST_INNER_MARGIN; + box.right += PLAYLIST_INNER_MARGIN; + box.bottom += PLAYLIST_INNER_MARGIN; + DrawDarkTranslucentBox(&box); + *upper_left_corner_y = box.bottom + PLAYLIST_INNER_MARGIN; + } + else + orig_rect.top += box.bottom-box.top; + } + + orig_rect.top += PLAYLIST_INNER_MARGIN; + + } + } + else if (m_UI_mode == UI_LOAD) + { + if (m_nPresets == 0) + { + // note: this error message is repeated in milkdrop.cpp in LoadRandomPreset() + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILE_FOUND_IN_X_MILK), m_szPresetDir); + AddError(buf, 6.0f, ERR_MISC, true); + m_UI_mode = UI_REGULAR; + } + else + { + MyTextOut(WASABI_API_LNGSTRINGW(IDS_LOAD_WHICH_PRESET_PLUS_COMMANDS), MTO_UPPER_LEFT, true); + + wchar_t buf[MAX_PATH+64]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_DIRECTORY_OF_X), m_szPresetDir); + MyTextOut(buf, MTO_UPPER_LEFT, true); + + *upper_left_corner_y += h/2; + + RECT rect; + SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y); + rect.top += PLAYLIST_INNER_MARGIN; + rect.left += PLAYLIST_INNER_MARGIN; + rect.right -= PLAYLIST_INNER_MARGIN; + rect.bottom -= PLAYLIST_INNER_MARGIN; + + int lines_available = (rect.bottom - rect.top - PLAYLIST_INNER_MARGIN*2) / GetFontHeight(SIMPLE_FONT); + + if (lines_available < 1) + { + // force it + rect.bottom = rect.top + GetFontHeight(SIMPLE_FONT) + 1; + lines_available = 1; + } + if (lines_available > MAX_PRESETS_PER_PAGE) + lines_available = MAX_PRESETS_PER_PAGE; + + if (m_bUserPagedDown) + { + m_nPresetListCurPos += lines_available; + if (m_nPresetListCurPos >= m_nPresets) + m_nPresetListCurPos = m_nPresets - 1; + + // remember this preset's name so the next time they hit 'L' it jumps straight to it + //lstrcpy(m_szLastPresetSelected, m_presets[m_nPresetListCurPos].szFilename.c_str()); + + m_bUserPagedDown = false; + } + + if (m_bUserPagedUp) + { + m_nPresetListCurPos -= lines_available; + if (m_nPresetListCurPos < 0) + m_nPresetListCurPos = 0; + + // remember this preset's name so the next time they hit 'L' it jumps straight to it + //lstrcpy(m_szLastPresetSelected, m_presets[m_nPresetListCurPos].szFilename.c_str()); + + m_bUserPagedUp = false; + } + + int i; + int first_line = m_nPresetListCurPos - (m_nPresetListCurPos % lines_available); + int last_line = first_line + lines_available; + wchar_t str[512], str2[512]; + + if (last_line > m_nPresets) + last_line = m_nPresets; + + // tooltip: + if (m_bShowMenuToolTips) + { + wchar_t buf[256]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PAGE_X_OF_X), m_nPresetListCurPos/lines_available+1, (m_nPresets+lines_available-1)/lines_available); + DrawTooltip(buf, xR, *lower_right_corner_y); + } + + RECT orig_rect = rect; + + RECT box; + box.top = rect.top; + box.left = rect.left; + box.right = rect.left; + box.bottom = rect.top; + + for (int pass=0; pass<2; pass++) + { + //if (pass==1) + // GetFont(SIMPLE_FONT)->Begin(); + + rect = orig_rect; + for (i=first_line; im_szDesc, str)==0) + // bIsRunning = true; + } + + if (bIsRunning && m_bPresetLockedByUser) + lstrcatW(str2, WASABI_API_LNGSTRINGW(IDS_LOCKED)); + + DWORD color = bIsDir ? DIR_COLOR : PLAYLIST_COLOR_NORMAL; + if (bIsRunning) + color = bIsSelected ? PLAYLIST_COLOR_BOTH : PLAYLIST_COLOR_PLAYING_TRACK; + else if (bIsSelected) + color = PLAYLIST_COLOR_HILITE_TRACK; + + RECT r2 = rect; + rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), str2, -1, &r2, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | (pass==0 ? DT_CALCRECT : 0), color, false); + + if (pass==0) // calculating dark box + { + box.right = max(box.right, box.left + r2.right-r2.left); + box.bottom += r2.bottom-r2.top; + } + } + + //if (pass==1) + // GetFont(SIMPLE_FONT)->End(); + + if (pass==0) // calculating dark box + { + box.top -= PLAYLIST_INNER_MARGIN; + box.left -= PLAYLIST_INNER_MARGIN; + box.right += PLAYLIST_INNER_MARGIN; + box.bottom += PLAYLIST_INNER_MARGIN; + DrawDarkTranslucentBox(&box); + *upper_left_corner_y = box.bottom + PLAYLIST_INNER_MARGIN; + } + } + } + } + } + + // 5. render *remaining* text to upper-right corner + { + // e) custom timed message: + if (!m_bWarningsDisabled2) + { + wchar_t buf[512] = {0}; + SelectFont(SIMPLE_FONT); + float t = GetTime(); + int N = m_errors.size(); + for (int i=0; i= m_errors[i].birthTime && t < m_errors[i].expireTime) + { + swprintf(buf, L"%s ", m_errors[i].msg.c_str()); + float age_rel = (t - m_errors[i].birthTime) / (m_errors[i].expireTime - m_errors[i].birthTime); + DWORD cr = (DWORD)(200 - 199*powf(age_rel,4)); + DWORD cg = 0;//(DWORD)(136 - 135*powf(age_rel,1)); + DWORD cb = 0; + DWORD z = 0xFF000000 | (cr<<16) | (cg<<8) | cb; + MyTextOut_BGCOLOR(buf, MTO_UPPER_RIGHT, true, m_errors[i].bBold ? z : 0xFF000000); + } + else + { + m_errors.eraseAt(i); + i--; + N--; + } + } + } + } +} + +//---------------------------------------------------------------------- + +LRESULT CPlugin::MyWindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) +{ + // You can handle Windows messages here while the plugin is running, + // such as mouse events (WM_MOUSEMOVE/WM_LBUTTONDOWN), keypresses + // (WK_KEYDOWN/WM_CHAR), and so on. + // This function is threadsafe (thanks to Winamp's architecture), + // so you don't have to worry about using semaphores or critical + // sections to read/write your class member variables. + // If you don't handle a message, let it continue on the usual path + // (to Winamp) by returning DefWindowProc(hWnd,uMsg,wParam,lParam). + // If you do handle a message, prevent it from being handled again + // (by Winamp) by returning 0. + + // IMPORTANT: For the WM_KEYDOWN, WM_KEYUP, and WM_CHAR messages, + // you must return 0 if you process the message (key), + // and 1 if you do not. DO NOT call DefWindowProc() + // for these particular messages! + + USHORT mask = 1 << (sizeof(SHORT)*8 - 1); + bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0; + bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0; + + int nRepeat = 1; //updated as appropriate + int rep; + + switch (uMsg) + { + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case ID_VIS_NEXT: + NextPreset(m_fBlendTimeUser); + return 0; + case ID_VIS_PREV: + PrevPreset(m_fBlendTimeUser); + return 0; + case ID_VIS_RANDOM: + { + // note: when the vis is launched, if we're using a fancy modern skin + // (with a Random button), it will send us one of these... + // if it's NOT a fancy skin, we'll never get this message (confirmed). + + USHORT v = HIWORD(wParam); // here, v is 0 (locked) or 1 (random) or 0xFFFF (don't know / startup!) + if (v==0xFFFF) + { + // plugin just launched or changed modes - + // Winamp wants to know what our saved Random state is... + SendMessage(GetWinampWindow(), WM_WA_IPC, (m_bPresetLockOnAtStartup ? 0 : 1) << 16, IPC_CB_VISRANDOM); + + return 0; + } + + // otherwise it's 0 or 1 - user clicked the button, we should respond. + + v = v ? 1 : 0; // same here + + //see also - IPC_CB_VISRANDOM + m_bPresetLockedByUser = (v == 0); + SetScrollLock(m_bPresetLockedByUser, m_bPreventScollLockHandling); + + return 0; + } + case ID_VIS_FS: + PostMessage(hWnd, WM_USER + 1667, 0, 0); + return 0; + case ID_VIS_CFG: + ToggleHelp(); + return 0; + case ID_VIS_MENU: + POINT pt; + GetCursorPos(&pt); + SendMessage(hWnd, WM_CONTEXTMENU, (WPARAM)hWnd, (pt.y << 16) | pt.x); + return 0; + } + break; + + /* + case WM_SETFOCUS: + m_bOrigScrollLockState = GetKeyState(VK_SCROLL) & 1; + SetScrollLock(m_bMilkdropScrollLockState); + return DefWindowProc(hWnd, uMsg, wParam, lParam); + + case WM_KILLFOCUS: + m_bMilkdropScrollLockState = GetKeyState(VK_SCROLL) & 1; + SetScrollLock(m_bOrigScrollLockState); + return DefWindowProc(hWnd, uMsg, wParam, lParam); + */ + // this is used to work around a focusing issue when toggling fullscreen + // via the 'fullscreen' button in the bento (and most other) modern skin + case WM_USER+1667: + if (GetFrame() > 0) ToggleFullScreen(); + return 0; + + case WM_CHAR: // plain & simple alphanumeric keys + nRepeat = LOWORD(lParam); + if (m_waitstring.bActive) // if user is in the middle of editing a string + { + if ((wParam >= ' ' && wParam <= 'z') || wParam=='{' || wParam=='}') + { + int len; + if(m_waitstring.bDisplayAsCode) + len = lstrlenA((char*)m_waitstring.szText); + else + len = lstrlenW(m_waitstring.szText); + + if (m_waitstring.bFilterBadChars && + (wParam == '\"' || + wParam == '\\' || + wParam == '/' || + wParam == ':' || + wParam == '*' || + wParam == '?' || + wParam == '|' || + wParam == '<' || + wParam == '>' || + wParam == '&')) // NOTE: '&' is legal in filenames, but we try to avoid it since during GDI display it acts as a control code (it will not show up, but instead, underline the character following it). + { + // illegal char + AddError(WASABI_API_LNGSTRINGW(IDS_ILLEGAL_CHARACTER), 2.5f, ERR_MISC, true); + } + else if (len+nRepeat >= m_waitstring.nMaxLen) + { + // m_waitstring.szText has reached its limit + AddError(WASABI_API_LNGSTRINGW(IDS_STRING_TOO_LONG), 2.5f, ERR_MISC, true); + } + else + { + //m_fShowUserMessageUntilThisTime = GetTime(); // if there was an error message already, clear it + + if(m_waitstring.bDisplayAsCode) + { + char buf[16]; + sprintf(buf, "%c", wParam); + + if (m_waitstring.nSelAnchorPos != -1) + WaitString_NukeSelection(); + + if (m_waitstring.bOvertypeMode) + { + // overtype mode + for (rep=0; rep=m_waitstring.nCursorPos; i--) + *(ptr + i+1) = *(ptr + i); + *(ptr + m_waitstring.nCursorPos) = buf[0]; + m_waitstring.nCursorPos++; + len++; + } + } + } + else + { + wchar_t buf[16]; + swprintf(buf, L"%c", wParam); + + if (m_waitstring.nSelAnchorPos != -1) + WaitString_NukeSelection(); + + if (m_waitstring.bOvertypeMode) + { + // overtype mode + for (rep=0; rep=m_waitstring.nCursorPos; i--) + m_waitstring.szText[i+1] = m_waitstring.szText[i]; + m_waitstring.szText[m_waitstring.nCursorPos] = buf[0]; + m_waitstring.nCursorPos++; + len++; + } + } + } + } + } + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_LOAD_DEL) // waiting to confirm file delete + { + if (wParam == keyMappings[0] || wParam == keyMappings[1]) // 'y' or 'Y' + { + // first add pathname to filename + wchar_t szDelFile[512]; + swprintf(szDelFile, L"%s%s", GetPresetDir(), m_presets[m_nPresetListCurPos].szFilename.c_str()); + + DeletePresetFile(szDelFile); + //m_nCurrentPreset = -1; + } + + m_UI_mode = UI_LOAD; + + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_UPGRADE_PIXEL_SHADER) + { + if (wParam == keyMappings[0] || wParam == keyMappings[1]) // 'y' or 'Y' + { + if (m_pState->m_nMinPSVersion == m_pState->m_nMaxPSVersion) + { + switch(m_pState->m_nMinPSVersion) + { + case MD2_PS_NONE: + m_pState->m_nWarpPSVersion = MD2_PS_2_0; + m_pState->m_nCompPSVersion = MD2_PS_2_0; + m_pState->GenDefaultWarpShader(); + m_pState->GenDefaultCompShader(); + break; + case MD2_PS_2_0: + m_pState->m_nWarpPSVersion = MD2_PS_2_X; + m_pState->m_nCompPSVersion = MD2_PS_2_X; + break; + case MD2_PS_2_X: + m_pState->m_nWarpPSVersion = MD2_PS_3_0; + m_pState->m_nCompPSVersion = MD2_PS_3_0; + break; + default: + assert(0); + break; + } + } + else + { + switch(m_pState->m_nMinPSVersion) + { + case MD2_PS_NONE: + if (m_pState->m_nWarpPSVersion < MD2_PS_2_0) + { + m_pState->m_nWarpPSVersion = MD2_PS_2_0; + m_pState->GenDefaultWarpShader(); + } + if (m_pState->m_nCompPSVersion < MD2_PS_2_0) + { + m_pState->m_nCompPSVersion = MD2_PS_2_0; + m_pState->GenDefaultCompShader(); + } + break; + case MD2_PS_2_0: + m_pState->m_nWarpPSVersion = max(m_pState->m_nWarpPSVersion, MD2_PS_2_X); + m_pState->m_nCompPSVersion = max(m_pState->m_nCompPSVersion, MD2_PS_2_X); + break; + case MD2_PS_2_X: + m_pState->m_nWarpPSVersion = max(m_pState->m_nWarpPSVersion, MD2_PS_3_0); + m_pState->m_nCompPSVersion = max(m_pState->m_nCompPSVersion, MD2_PS_3_0); + break; + default: + assert(0); + break; + } + } + m_pState->m_nMinPSVersion = min(m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion); + m_pState->m_nMaxPSVersion = max(m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion); + + LoadShaders(&m_shaders, m_pState, false); + SetMenusForPresetVersion( m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion ); + } + if (wParam != 13) + m_UI_mode = UI_MENU; + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_SAVE_OVERWRITE) // waiting to confirm overwrite file on save + { + if (wParam == keyMappings[0] || wParam == keyMappings[1]) // 'y' or 'Y' + { + // first add pathname + extension to filename + wchar_t szNewFile[512]; + swprintf(szNewFile, L"%s%s.milk", GetPresetDir(), m_waitstring.szText); + + SavePresetAs(szNewFile); + + // exit waitstring mode + m_UI_mode = UI_REGULAR; + m_waitstring.bActive = false; + //m_bPresetLockedByCode = false; + } + else if ((wParam >= ' ' && wParam <= 'z') || wParam == 27) // 27 is the ESCAPE key + { + // go back to SAVE AS mode + m_UI_mode = UI_SAVEAS; + m_waitstring.bActive = true; + } + + return 0; // we processed (or absorbed) the key + } + else // normal handling of a simple key (all non-virtual-key hotkeys end up here) + { + if (HandleRegularKey(wParam)==0) + return 0; + } + return 1; // end case WM_CHAR + + case WM_KEYDOWN: // virtual-key codes + // Note that some keys will never reach this point, since they are + // intercepted by the plugin shell (see PluginShellWindowProc(), + // at the end of pluginshell.cpp for which ones). + // For a complete list of virtual-key codes, look up the keyphrase + // "virtual-key codes [win32]" in the msdn help. + nRepeat = LOWORD(lParam); + + switch(wParam) + { + case VK_F2: m_bShowSongTitle = !m_bShowSongTitle; return 0; // we processed (or absorbed) the key + case VK_F3: + if (m_bShowSongTime && m_bShowSongLen) + { + m_bShowSongTime = false; + m_bShowSongLen = false; + } + else if (m_bShowSongTime && !m_bShowSongLen) + { + m_bShowSongLen = true; + } + else + { + m_bShowSongTime = true; + m_bShowSongLen = false; + } + return 0; // we processed (or absorbed) the key + case VK_F4: m_bShowPresetInfo = !m_bShowPresetInfo; return 0; // we processed (or absorbed) the key + case VK_F5: m_bShowFPS = !m_bShowFPS; return 0; // we processed (or absorbed) the key + case VK_F6: m_bShowRating = !m_bShowRating; return 0; // we processed (or absorbed) the key + case VK_F7: + if (m_nNumericInputMode == NUMERIC_INPUT_MODE_CUST_MSG) + ReadCustomMessages(); // re-read custom messages + return 0; // we processed (or absorbed) the key + case VK_F8: + { + m_UI_mode = UI_CHANGEDIR; + + // enter WaitString mode + m_waitstring.bActive = true; + m_waitstring.bFilterBadChars = false; + m_waitstring.bDisplayAsCode = false; + m_waitstring.nSelAnchorPos = -1; + m_waitstring.nMaxLen = min(sizeof(m_waitstring.szText)-1, MAX_PATH - 1); + lstrcpyW(m_waitstring.szText, GetPresetDir()); + { + // for subtle beauty - remove the trailing '\' from the directory name (if it's not just "x:\") + int len = lstrlenW(m_waitstring.szText); + if (len > 3 && m_waitstring.szText[len-1] == '\\') + m_waitstring.szText[len-1] = 0; + } + WASABI_API_LNGSTRINGW_BUF(IDS_DIRECTORY_TO_JUMP_TO, m_waitstring.szPrompt, 512); + m_waitstring.szToolTip[0] = 0; + m_waitstring.nCursorPos = lstrlenW(m_waitstring.szText); // set the starting edit position + } + return 0; // we processed (or absorbed) the key + + case VK_F9: + m_bShowShaderHelp = !m_bShowShaderHelp; + return FALSE; + + case VK_SCROLL: + m_bPresetLockedByUser = GetKeyState(VK_SCROLL) & 1; + //SetScrollLock(m_bPresetLockedByUser); + SendMessage(GetWinampWindow(), WM_WA_IPC, (m_bPresetLockedByUser ? 0 : 1) << 16, IPC_CB_VISRANDOM); + //int set = m_bPresetLockedByUser ? + //PostMessage(GetWinampWindow(), WM_COMMAND, ID_VIS_RANDOM | (set << 16), 0); + + return 0; // we processed (or absorbed) the key + //case VK_F6: break; + //case VK_F7: conflict + //case VK_F8: break; + //case VK_F9: conflict + } + + // next handle the waitstring case (for string-editing), + // then the menu navigation case, + // then handle normal case (handle the message normally or pass on to winamp) + + // case 1: waitstring mode + if (m_waitstring.bActive) + { + // handle arrow keys, home, end, etc. + + USHORT mask = 1 << (sizeof(SHORT)*8 - 1); // we want the highest-order bit + bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0; + bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0; + + if (wParam == VK_LEFT || wParam == VK_RIGHT || + wParam == VK_HOME || wParam == VK_END || + wParam == VK_UP || wParam == VK_DOWN) + { + if (bShiftHeldDown) + { + if (m_waitstring.nSelAnchorPos == -1) + m_waitstring.nSelAnchorPos = m_waitstring.nCursorPos; + } + else + { + m_waitstring.nSelAnchorPos = -1; + } + } + + if (bCtrlHeldDown) // copy/cut/paste + { + switch(wParam) + { + case 'c': + case 'C': + case VK_INSERT: + WaitString_Copy(); + return 0; // we processed (or absorbed) the key + case 'x': + case 'X': + WaitString_Cut(); + return 0; // we processed (or absorbed) the key + case 'v': + case 'V': + WaitString_Paste(); + return 0; // we processed (or absorbed) the key + case VK_LEFT: WaitString_SeekLeftWord(); return 0; // we processed (or absorbed) the key + case VK_RIGHT: WaitString_SeekRightWord(); return 0; // we processed (or absorbed) the key + case VK_HOME: m_waitstring.nCursorPos = 0; return 0; // we processed (or absorbed) the key + case VK_END: + if (m_waitstring.bDisplayAsCode) + { + m_waitstring.nCursorPos = lstrlenA((char*)m_waitstring.szText); + } + else + { + m_waitstring.nCursorPos = lstrlenW(m_waitstring.szText); + } + return 0; // we processed (or absorbed) the key + case VK_RETURN: + if (m_waitstring.bDisplayAsCode) + { + // CTRL+ENTER accepts the string -> finished editing + //assert(m_pCurMenu); + m_pCurMenu->OnWaitStringAccept(m_waitstring.szText); + // OnWaitStringAccept calls the callback function. See the + // calls to CMenu::AddItem from milkdrop.cpp to find the + // callback functions for different "waitstrings". + m_waitstring.bActive = false; + m_UI_mode = UI_MENU; + } + return 0; // we processed (or absorbed) the key + } + } + else // waitstring mode key pressed, and ctrl NOT held down + { + switch(wParam) + { + case VK_INSERT: + m_waitstring.bOvertypeMode = !m_waitstring.bOvertypeMode; + return 0; // we processed (or absorbed) the key + + case VK_LEFT: + for (rep=0; rep 0) + m_waitstring.nCursorPos--; + return 0; // we processed (or absorbed) the key + + case VK_RIGHT: + for (rep=0; rep 0) + { + int len; + if (m_waitstring.bDisplayAsCode) + { + len = lstrlenA((char*)m_waitstring.szText); + } + else + { + len = lstrlenW(m_waitstring.szText); + } + int src_pos = m_waitstring.nCursorPos; + int dst_pos = m_waitstring.nCursorPos - nRepeat; + int gap = nRepeat; + int copy_chars = len - m_waitstring.nCursorPos + 1; // includes NULL @ end + if (dst_pos < 0) + { + gap += dst_pos; + //copy_chars += dst_pos; + dst_pos = 0; + } + + if (m_waitstring.bDisplayAsCode) + { + char* ptr = (char*)m_waitstring.szText; + for (int i=0; iGetCurItem()->m_lParam; + int ret; + switch(m_UI_mode) + { + case UI_IMPORT_WAVE : ret = m_pState->m_wave[i].Import(NULL, m_waitstring.szText, 0); break; + case UI_EXPORT_WAVE : ret = m_pState->m_wave[i].Export(NULL, m_waitstring.szText, 0); break; + case UI_IMPORT_SHAPE: ret = m_pState->m_shape[i].Import(NULL, m_waitstring.szText, 0); break; + case UI_EXPORT_SHAPE: ret = m_pState->m_shape[i].Export(NULL, m_waitstring.szText, 0); break; + } + + if (bImport) + m_pState->RecompileExpressions(1); + + //m_fShowUserMessageUntilThisTime = GetTime() - 1.0f; // if there was an error message already, clear it + if (!ret) + { + wchar_t buf[1024]; + if (m_UI_mode==UI_IMPORT_WAVE || m_UI_mode==UI_IMPORT_SHAPE) + WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_IMPORTING_BAD_FILENAME, buf, 1024); + else + WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_IMPORTING_BAD_FILENAME_OR_NOT_OVERWRITEABLE, buf, 1024); + AddError(WASABI_API_LNGSTRINGW(IDS_STRING_TOO_LONG), 2.5f, ERR_MISC, true); + } + + m_waitstring.bActive = false; + m_UI_mode = UI_MENU; + //m_bPresetLockedByCode = false; + } + else if (m_UI_mode == UI_SAVEAS) + { + // first add pathname + extension to filename + wchar_t szNewFile[512]; + swprintf(szNewFile, L"%s%s.milk", GetPresetDir(), m_waitstring.szText); + + if (GetFileAttributesW(szNewFile) != -1) // check if file already exists + { + // file already exists -> overwrite it? + m_waitstring.bActive = false; + m_UI_mode = UI_SAVE_OVERWRITE; + } + else + { + SavePresetAs(szNewFile); + + // exit waitstring mode + m_UI_mode = UI_REGULAR; + m_waitstring.bActive = false; + //m_bPresetLockedByCode = false; + } + } + else if (m_UI_mode == UI_EDIT_MENU_STRING) + { + if (m_waitstring.bDisplayAsCode) + { + if (m_waitstring.nSelAnchorPos != -1) + WaitString_NukeSelection(); + + int len = lstrlenA((char*)m_waitstring.szText); + char* ptr = (char*)m_waitstring.szText; + if (len + 1 < m_waitstring.nMaxLen) + { + // insert a linefeed. Use CTRL+return to accept changes in this case. + for (int pos=len+1; pos > m_waitstring.nCursorPos; pos--) + *(ptr + pos) = *(ptr + pos - 1); + *(ptr + m_waitstring.nCursorPos++) = LINEFEED_CONTROL_CHAR; + + //m_fShowUserMessageUntilThisTime = GetTime() - 1.0f; // if there was an error message already, clear it + } + else + { + // m_waitstring.szText has reached its limit + AddError(WASABI_API_LNGSTRINGW(IDS_STRING_TOO_LONG), 2.5f, ERR_MISC, true); + } + } + else + { + // finished editing + //assert(m_pCurMenu); + m_pCurMenu->OnWaitStringAccept(m_waitstring.szText); + // OnWaitStringAccept calls the callback function. See the + // calls to CMenu::AddItem from milkdrop.cpp to find the + // callback functions for different "waitstrings". + m_waitstring.bActive = false; + m_UI_mode = UI_MENU; + } + } + else if (m_UI_mode == UI_CHANGEDIR) + { + //m_fShowUserMessageUntilThisTime = GetTime(); // if there was an error message already, clear it + + // change dir + wchar_t szOldDir[512]; + wchar_t szNewDir[512]; + lstrcpyW(szOldDir, g_plugin.m_szPresetDir); + lstrcpyW(szNewDir, m_waitstring.szText); + + int len = lstrlenW(szNewDir); + if (len > 0 && szNewDir[len-1] != L'\\') + lstrcatW(szNewDir, L"\\"); + + lstrcpyW(g_plugin.m_szPresetDir, szNewDir); + + bool bSuccess = true; + if (GetFileAttributesW(g_plugin.m_szPresetDir) == -1) + bSuccess = false; + if (bSuccess) { + UpdatePresetList(false,true,false); + bSuccess = (m_nPresets > 0); + } + + if (!bSuccess) + { + // new dir. was invalid -> allow them to try again + lstrcpyW(g_plugin.m_szPresetDir, szOldDir); + + // give them a warning + AddError(WASABI_API_LNGSTRINGW(IDS_INVALID_PATH), 3.5f, ERR_MISC, true); + } + else + { + // success + lstrcpyW(g_plugin.m_szPresetDir, szNewDir); + + // save new path to registry + WritePrivateProfileStringW(L"settings",L"szPresetDir",g_plugin.m_szPresetDir,GetConfigIniFile()); + + // set current preset index to -1 because current preset is no longer in the list + m_nCurrentPreset = -1; + + // go to file load menu + m_waitstring.bActive = false; + m_UI_mode = UI_LOAD; + + ClearErrors(ERR_MISC); + } + } + return 0; // we processed (or absorbed) the key + + case VK_ESCAPE: + if (m_UI_mode == UI_LOAD_RENAME) + { + m_waitstring.bActive = false; + m_UI_mode = UI_LOAD; + } + else if ( + m_UI_mode == UI_SAVEAS || + m_UI_mode == UI_SAVE_OVERWRITE || + m_UI_mode == UI_EXPORT_SHAPE || + m_UI_mode == UI_IMPORT_SHAPE || + m_UI_mode == UI_EXPORT_WAVE || + m_UI_mode == UI_IMPORT_WAVE) + { + //m_bPresetLockedByCode = false; + m_waitstring.bActive = false; + m_UI_mode = UI_REGULAR; + } + else if (m_UI_mode == UI_EDIT_MENU_STRING) + { + m_waitstring.bActive = false; + if (m_waitstring.bDisplayAsCode) // if were editing code... + m_UI_mode = UI_MENU; // return to menu + else + m_UI_mode = UI_REGULAR; // otherwise don't (we might have been editing a filename, for example) + } + else /*if (m_UI_mode == UI_EDIT_MENU_STRING || m_UI_mode == UI_CHANGEDIR || 1)*/ + { + m_waitstring.bActive = false; + m_UI_mode = UI_REGULAR; + } + return 0; // we processed (or absorbed) the key + } + } + + // don't let keys go anywhere else + return 0; // we processed (or absorbed) the key + } + + // case 2: menu is up & gets the keyboard input + if (m_UI_mode == UI_MENU) + { + //assert(m_pCurMenu); + if (m_pCurMenu->HandleKeydown(hWnd, uMsg, wParam, lParam) == 0) + return 0; // we processed (or absorbed) the key + } + + // case 3: handle non-character keys (virtual keys) and return 0. + // if we don't handle them, return 1, and the shell will + // (passing some to the shell's key bindings, some to Winamp, + // and some to DefWindowProc) + // note: regular hotkeys should be handled in HandleRegularKey. + switch(wParam) + { + case VK_LEFT: + case VK_RIGHT: + if (m_UI_mode == UI_LOAD) + { + // it's annoying when the music skips if you hit the left arrow from the Load menu, so instead, we exit the menu + if (wParam == VK_LEFT) m_UI_mode = UI_REGULAR; + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_UPGRADE_PIXEL_SHADER) + { + m_UI_mode = UI_MENU; + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_MASHUP) + { + if (wParam==VK_LEFT) + m_nMashSlot = max(0, m_nMashSlot-1); + else + m_nMashSlot = min(MASH_SLOTS-1, m_nMashSlot+1); + return 0; // we processed (or absorbed) the key + } + break; + + case VK_ESCAPE: + if (m_UI_mode == UI_LOAD || m_UI_mode == UI_MENU || m_UI_mode == UI_MASHUP) + { + m_UI_mode = UI_REGULAR; + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_LOAD_DEL) + { + m_UI_mode = UI_LOAD; + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_UPGRADE_PIXEL_SHADER) + { + m_UI_mode = UI_MENU; + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_SAVE_OVERWRITE) + { + m_UI_mode = UI_SAVEAS; + // return to waitstring mode, leaving all the parameters as they were before: + m_waitstring.bActive = true; + return 0; // we processed (or absorbed) the key + } + /*else if (hwnd == GetPluginWindow()) // (don't close on ESC for text window) + { + dumpmsg("User pressed ESCAPE"); + //m_bExiting = true; + PostMessage(hwnd, WM_CLOSE, 0, 0); + return 0; // we processed (or absorbed) the key + }*/ + break; + + case VK_UP: + if (m_UI_mode == UI_MASHUP) + { + for (rep=0; rep 0) + m_nPresetListCurPos--; + return 0; // we processed (or absorbed) the key + + // remember this preset's name so the next time they hit 'L' it jumps straight to it + //lstrcpy(m_szLastPresetSelected, m_presets[m_nPresetListCurPos].szFilename.c_str()); + } + break; + + case VK_DOWN: + if (m_UI_mode == UI_MASHUP) + { + for (rep=0; rep frame) || + (bShiftHeldDown && m_texmgr.m_tex[x].nStartFrame < frame)) + { + newest = x; + frame = m_texmgr.m_tex[x].nStartFrame; + } + } + } + + if (newest != -1) + m_texmgr.KillTex(newest); + } + return 0; // we processed (or absorbed) the key + } + } + break; + + case VK_INSERT: // RENAME + if (m_UI_mode == UI_LOAD) + { + if (m_presets[m_nPresetListCurPos].szFilename.c_str()[0] != '*') // can't rename directories + { + // go into RENAME mode + m_UI_mode = UI_LOAD_RENAME; + m_waitstring.bActive = true; + m_waitstring.bFilterBadChars = true; + m_waitstring.bDisplayAsCode = false; + m_waitstring.nSelAnchorPos = -1; + m_waitstring.nMaxLen = min(sizeof(m_waitstring.szText)-1, MAX_PATH - lstrlenW(GetPresetDir()) - 6); // 6 for the extension + null char. We set this because win32 LoadFile, MoveFile, etc. barf if the path+filename+ext are > MAX_PATH chars. + + // initial string is the filename, minus the extension + lstrcpyW(m_waitstring.szText, m_presets[m_nPresetListCurPos].szFilename.c_str()); + RemoveExtension(m_waitstring.szText); + + // set the prompt & 'tooltip' + swprintf(m_waitstring.szPrompt, WASABI_API_LNGSTRINGW(IDS_ENTER_THE_NEW_NAME_FOR_X), m_waitstring.szText); + m_waitstring.szToolTip[0] = 0; + + // set the starting edit position + m_waitstring.nCursorPos = lstrlenW(m_waitstring.szText); + } + return 0; // we processed (or absorbed) the key + } + break; + + case VK_RETURN: + + if (m_UI_mode == UI_MASHUP) + { + m_nLastMashChangeFrame[m_nMashSlot] = GetFrame() + MASH_APPLY_DELAY_FRAMES; // causes instant apply + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_LOAD) + { + HitEnterFromLoadMenu: + + if (m_presets[m_nPresetListCurPos].szFilename.c_str()[0] == '*') + { + // CHANGE DIRECTORY + wchar_t *p = GetPresetDir(); + + if (wcscmp(m_presets[m_nPresetListCurPos].szFilename.c_str(), L"*..") == 0) + { + // back up one dir + wchar_t *p2 = wcsrchr(p, L'\\'); + if (p2) + { + *p2 = 0; + p2 = wcsrchr(p, L'\\'); + if (p2) *(p2+1) = 0; + } + } + else + { + // open subdir + lstrcatW(p, &m_presets[m_nPresetListCurPos].szFilename.c_str()[1]); + lstrcatW(p, L"\\"); + } + + WritePrivateProfileStringW(L"settings",L"szPresetDir",GetPresetDir(),GetConfigIniFile()); + + UpdatePresetList(false, true, false); + + // set current preset index to -1 because current preset is no longer in the list + m_nCurrentPreset = -1; + } + else + { + // LOAD NEW PRESET + m_nCurrentPreset = m_nPresetListCurPos; + + // first take the filename and prepend the path. (already has extension) + wchar_t s[MAX_PATH]; + lstrcpyW(s, GetPresetDir()); // note: m_szPresetDir always ends with '\' + lstrcatW(s, m_presets[m_nCurrentPreset].szFilename.c_str()); + + // now load (and blend to) the new preset + m_presetHistoryPos = (m_presetHistoryPos+1) % PRESET_HIST_LEN; + LoadPreset(s, (wParam==VK_SPACE) ? m_fBlendTimeUser : 0); + } + return 0; // we processed (or absorbed) the key + } + break; + + case VK_BACK: + // pass on to parent + //PostMessage(m_hWndParent,message,wParam,lParam); + PrevPreset(0); + m_fHardCutThresh *= 2.0f; // make it a little less likely that a random hard cut follows soon. + //m_nNumericInputDigits = 0; + //m_nNumericInputNum = 0; + return 0; + + case 'T': + if (bCtrlHeldDown) + { + // stop display of custom message or song title. + m_supertext.fStartTime = -1.0f; + return 0; + } + break; + case 'K': + if (bCtrlHeldDown) // kill all sprites + { + for (int x=0; x= 'A' && wParam <= 'Z') || (wParam >= 'a' && wParam <= 'z'))) + { + SeekToPreset((char)wParam); + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_MASHUP && wParam >= '1' && wParam <= ('0' + MASH_SLOTS)) + { + m_nMashSlot = wParam - '1'; + } + else switch(wParam) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int digit = wParam - '0'; + m_nNumericInputNum = (m_nNumericInputNum*10) + digit; + m_nNumericInputDigits++; + + if (m_nNumericInputDigits >= 2) + { + if (m_nNumericInputMode == NUMERIC_INPUT_MODE_CUST_MSG) + LaunchCustomMessage(m_nNumericInputNum); + else if (m_nNumericInputMode == NUMERIC_INPUT_MODE_SPRITE) + LaunchSprite(m_nNumericInputNum, -1); + else if (m_nNumericInputMode == NUMERIC_INPUT_MODE_SPRITE_KILL) + { + for (int x=0; xm_fVideoEchoZoom /= 1.05f; + return 0; // we processed (or absorbed) the key + case 'Q': + m_pState->m_fVideoEchoZoom *= 1.05f; + return 0; // we processed (or absorbed) the key + case 'w': + m_pState->m_nWaveMode++; + if (m_pState->m_nWaveMode >= NUM_WAVES) m_pState->m_nWaveMode = 0; + return 0; // we processed (or absorbed) the key + case 'W': + m_pState->m_nWaveMode--; + if (m_pState->m_nWaveMode < 0) m_pState->m_nWaveMode = NUM_WAVES - 1; + return 0; // we processed (or absorbed) the key + case 'e': + m_pState->m_fWaveAlpha -= 0.1f; + if (m_pState->m_fWaveAlpha.eval(-1) < 0.0f) m_pState->m_fWaveAlpha = 0.0f; + return 0; // we processed (or absorbed) the key + case 'E': + m_pState->m_fWaveAlpha += 0.1f; + //if (m_pState->m_fWaveAlpha.eval(-1) > 1.0f) m_pState->m_fWaveAlpha = 1.0f; + return 0; // we processed (or absorbed) the key + + case 'I': m_pState->m_fZoom -= 0.01f; return 0; // we processed (or absorbed) the key + case 'i': m_pState->m_fZoom += 0.01f; return 0; // we processed (or absorbed) the key + + case 'n': + case 'N': + m_bShowDebugInfo = !m_bShowDebugInfo; + return 0; // we processed (or absorbed) the key + + case 'r': + m_bSequentialPresetOrder = !m_bSequentialPresetOrder; + { + wchar_t buf[1024], tmp[64]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PRESET_ORDER_IS_NOW_X), + WASABI_API_LNGSTRINGW_BUF((m_bSequentialPresetOrder) ? IDS_SEQUENTIAL : IDS_RANDOM, tmp, 64)); + AddError(buf, 3.0f, ERR_NOTIFY, false); + } + + // erase all history, too: + m_presetHistory[0] = m_szCurrentPresetFile; + m_presetHistoryPos = 0; + m_presetHistoryFwdFence = 1; + m_presetHistoryBackFence = 0; + + return 0; // we processed (or absorbed) the key + + + case 'u': + case 'U': + if (SendMessage(GetWinampWindow(),WM_USER,0,250)) + AddError(WASABI_API_LNGSTRINGW(IDS_SHUFFLE_IS_NOW_OFF), 3.0f, ERR_NOTIFY, false); + else + AddError(WASABI_API_LNGSTRINGW(IDS_SHUFFLE_IS_NOW_ON), 3.0f, ERR_NOTIFY, false); + + //m_fShowUserMessageUntilThisTime = GetTime() + 4.0f; + + // toggle shuffle + PostMessage(GetWinampWindow(),WM_COMMAND,40023,0); + + return 0; // we processed (or absorbed) the key + + + /* + case 'u': m_pState->m_fWarpScale /= 1.1f; break; + case 'U': m_pState->m_fWarpScale *= 1.1f; break; + case 'i': m_pState->m_fWarpAnimSpeed /= 1.1f; break; + case 'I': m_pState->m_fWarpAnimSpeed *= 1.1f; break; + */ + case 't': + case 'T': + LaunchSongTitleAnim(); + return 0; // we processed (or absorbed) the key + case 'o': m_pState->m_fWarpAmount /= 1.1f; return 0; // we processed (or absorbed) the key + case 'O': m_pState->m_fWarpAmount *= 1.1f; return 0; // we processed (or absorbed) the key + + case '!': + // randomize warp shader + { + bool bWarpLock = m_bWarpShaderLock; + wchar_t szOldPreset[MAX_PATH]; + lstrcpyW(szOldPreset, m_szCurrentPresetFile); + m_bWarpShaderLock = false; + LoadRandomPreset(0.0f); + m_bWarpShaderLock = true; + LoadPreset(szOldPreset, 0.0f); + m_bWarpShaderLock = bWarpLock; + } + break; + case '@': + // randomize comp shader + { + bool bCompLock = m_bCompShaderLock; + wchar_t szOldPreset[MAX_PATH]; + lstrcpyW(szOldPreset, m_szCurrentPresetFile); + m_bCompShaderLock = false; + LoadRandomPreset(0.0f); + m_bCompShaderLock = true; + LoadPreset(szOldPreset, 0.0f); + m_bCompShaderLock = bCompLock; + } + break; + + case 'a': + case 'A': + // load a random preset, a random warp shader, and a random comp shader. + // not quite as extreme as a mash-up. + { + bool bCompLock = m_bCompShaderLock; + bool bWarpLock = m_bWarpShaderLock; + m_bCompShaderLock = false; m_bWarpShaderLock = false; + LoadRandomPreset(0.0f); + m_bCompShaderLock = true; m_bWarpShaderLock = false; + LoadRandomPreset(0.0f); + m_bCompShaderLock = false; m_bWarpShaderLock = true; + LoadRandomPreset(0.0f); + m_bCompShaderLock = bCompLock; + m_bWarpShaderLock = bWarpLock; + } + break; + case 'd': + case 'D': + if (!m_bCompShaderLock && !m_bWarpShaderLock) { + m_bCompShaderLock = true; m_bWarpShaderLock = false; + AddError(WASABI_API_LNGSTRINGW(IDS_COMPSHADER_LOCKED), 3.0f, ERR_NOTIFY, false); + } else if (m_bCompShaderLock && !m_bWarpShaderLock) { + m_bCompShaderLock = false; m_bWarpShaderLock = true; + AddError(WASABI_API_LNGSTRINGW(IDS_WARPSHADER_LOCKED), 3.0f, ERR_NOTIFY, false); + } else if (!m_bCompShaderLock && m_bWarpShaderLock) { + m_bCompShaderLock = true; m_bWarpShaderLock = true; + AddError(WASABI_API_LNGSTRINGW(IDS_ALLSHADERS_LOCKED), 3.0f, ERR_NOTIFY, false); + } else { + m_bCompShaderLock = false; m_bWarpShaderLock = false; + AddError(WASABI_API_LNGSTRINGW(IDS_ALLSHADERS_UNLOCKED), 3.0f, ERR_NOTIFY, false); + } + break; + + // row 2 keys + // 'A' KEY IS FREE!! + // 'D' KEY IS FREE!! + /*case 'a': + m_pState->m_fVideoEchoAlpha -= 0.1f; + if (m_pState->m_fVideoEchoAlpha.eval(-1) < 0) m_pState->m_fVideoEchoAlpha = 0; + return 0; // we processed (or absorbed) the key + case 'A': + m_pState->m_fVideoEchoAlpha += 0.1f; + if (m_pState->m_fVideoEchoAlpha.eval(-1) > 1.0f) m_pState->m_fVideoEchoAlpha = 1.0f; + return 0; // we processed (or absorbed) the key + case 'd': + m_pState->m_fDecay += 0.01f; + if (m_pState->m_fDecay.eval(-1) > 1.0f) m_pState->m_fDecay = 1.0f; + return 0; // we processed (or absorbed) the key + case 'D': + m_pState->m_fDecay -= 0.01f; + if (m_pState->m_fDecay.eval(-1) < 0.9f) m_pState->m_fDecay = 0.9f; + return 0; // we processed (or absorbed) the key*/ + case 'h': + case 'H': + // instant hard cut + if (m_UI_mode == UI_MASHUP) + { + if (wParam=='h') + { + m_nMashPreset[m_nMashSlot] = m_nDirs + (warand() % (m_nPresets-m_nDirs)); + m_nLastMashChangeFrame[m_nMashSlot] = GetFrame() + MASH_APPLY_DELAY_FRAMES; // causes instant apply + } + else + { + for (int mash=0; mashm_nVideoEchoOrientation = (m_pState->m_nVideoEchoOrientation + 1) % 4; + return 0; // we processed (or absorbed) the key + case 'g': + m_pState->m_fGammaAdj -= 0.1f; + if (m_pState->m_fGammaAdj.eval(-1) < 0.0f) m_pState->m_fGammaAdj = 0.0f; + return 0; // we processed (or absorbed) the key + case 'G': + m_pState->m_fGammaAdj += 0.1f; + //if (m_pState->m_fGammaAdj > 1.0f) m_pState->m_fGammaAdj = 1.0f; + return 0; // we processed (or absorbed) the key + case 'j': + m_pState->m_fWaveScale *= 0.9f; + return 0; // we processed (or absorbed) the key + case 'J': + m_pState->m_fWaveScale /= 0.9f; + return 0; // we processed (or absorbed) the key + case 'k': + case 'K': + { + USHORT mask = 1 << (sizeof(SHORT)*8 - 1); // we want the highest-order bit + bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0; + + if (bShiftHeldDown) + m_nNumericInputMode = NUMERIC_INPUT_MODE_SPRITE_KILL; + else + m_nNumericInputMode = NUMERIC_INPUT_MODE_SPRITE; + m_nNumericInputNum = 0; + m_nNumericInputDigits = 0; + } + return 0; // we processed (or absorbed) the key + + // row 3/misc. keys + + case '[': + m_pState->m_fXPush -= 0.005f; + return 0; // we processed (or absorbed) the key + case ']': + m_pState->m_fXPush += 0.005f; + return 0; // we processed (or absorbed) the key + case '{': + m_pState->m_fYPush -= 0.005f; + return 0; // we processed (or absorbed) the key + case '}': + m_pState->m_fYPush += 0.005f; + return 0; // we processed (or absorbed) the key + case '<': + m_pState->m_fRot += 0.02f; + return 0; // we processed (or absorbed) the key + case '>': + m_pState->m_fRot -= 0.02f; + return 0; // we processed (or absorbed) the key + + case 's': // SAVE PRESET + case 'S': + if (m_UI_mode == UI_REGULAR) + { + //m_bPresetLockedByCode = true; + m_UI_mode = UI_SAVEAS; + + // enter WaitString mode + m_waitstring.bActive = true; + m_waitstring.bFilterBadChars = true; + m_waitstring.bDisplayAsCode = false; + m_waitstring.nSelAnchorPos = -1; + m_waitstring.nMaxLen = min(sizeof(m_waitstring.szText)-1, MAX_PATH - lstrlenW(GetPresetDir()) - 6); // 6 for the extension + null char. We set this because win32 LoadFile, MoveFile, etc. barf if the path+filename+ext are > MAX_PATH chars. + lstrcpyW(m_waitstring.szText, m_pState->m_szDesc); // initial string is the filename, minus the extension + WASABI_API_LNGSTRINGW_BUF(IDS_SAVE_AS,m_waitstring.szPrompt,512); + m_waitstring.szToolTip[0] = 0; + m_waitstring.nCursorPos = lstrlenW(m_waitstring.szText); // set the starting edit position + return 0; + } + break; + + case 'l': // LOAD PRESET + case 'L': + if (m_UI_mode == UI_LOAD) + { + m_UI_mode = UI_REGULAR; + return 0; // we processed (or absorbed) the key + + } + else if ( + m_UI_mode == UI_REGULAR || + m_UI_mode == UI_MENU) + { + UpdatePresetList(); // make sure list is completely ready + m_UI_mode = UI_LOAD; + m_bUserPagedUp = false; + m_bUserPagedDown = false; + return 0; // we processed (or absorbed) the key + + } + break; + + case 'm': + case 'M': + + if (m_UI_mode == UI_MENU) + m_UI_mode = UI_REGULAR; + else if (m_UI_mode == UI_REGULAR || m_UI_mode == UI_LOAD) + m_UI_mode = UI_MENU; + + return 0; // we processed (or absorbed) the key + + case '-': + SetCurrentPresetRating(m_pState->m_fRating - 1.0f); + return 0; // we processed (or absorbed) the key + case '+': + SetCurrentPresetRating(m_pState->m_fRating + 1.0f); + return 0; // we processed (or absorbed) the key + + case '*': + m_nNumericInputDigits = 0; + m_nNumericInputNum = 0; + return 0; + + } + + if (wParam == keyMappings[3] || wParam == keyMappings[4]) // 'y' or 'Y' + { + m_nNumericInputMode = NUMERIC_INPUT_MODE_CUST_MSG; + m_nNumericInputNum = 0; + m_nNumericInputDigits = 0; + return 0; // we processed (or absorbed) the key + } + + return 1; +} + +//---------------------------------------------------------------------- + +void CPlugin::RefreshTab2(HWND hwnd) +{ + ShowWindow(GetDlgItem(hwnd, IDC_BRIGHT_SLIDER), !m_bAutoGamma); + ShowWindow(GetDlgItem(hwnd, IDC_T1), !m_bAutoGamma); + ShowWindow(GetDlgItem(hwnd, IDC_T2), !m_bAutoGamma); + ShowWindow(GetDlgItem(hwnd, IDC_T3), !m_bAutoGamma); + ShowWindow(GetDlgItem(hwnd, IDC_T4), !m_bAutoGamma); + ShowWindow(GetDlgItem(hwnd, IDC_T5), !m_bAutoGamma); +} + +int CALLBACK MyEnumFontsProc( + CONST LOGFONT *lplf, // logical-font data + CONST TEXTMETRIC *lptm, // physical-font data + DWORD dwType, // font type + LPARAM lpData // application-defined data +) +{ + SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT3), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName)); + return 1; +} + +/* +void DoColors(HWND hwnd, int *r, int *g, int *b) +{ + static COLORREF acrCustClr[16]; + + CHOOSECOLOR cc; + ZeroMemory(&cc, sizeof(CHOOSECOLOR)); + cc.lStructSize = sizeof(CHOOSECOLOR); + cc.hwndOwner = hwnd;//NULL;//hSaverMainWindow; + cc.Flags = CC_RGBINIT | CC_FULLOPEN; + cc.rgbResult = RGB(*r,*g,*b); + cc.lpCustColors = (LPDWORD)acrCustClr; + if (ChooseColor(&cc)) + { + *r = GetRValue(cc.rgbResult); + *g = GetGValue(cc.rgbResult); + *b = GetBValue(cc.rgbResult); + } +}*/ + +wchar_t* FormImageCacheSizeString(wchar_t* itemStr, UINT sizeID) +{ + static wchar_t cacheBuf[128] = {0}; + StringCchPrintfW(cacheBuf, 128, L"%s %s", itemStr, WASABI_API_LNGSTRINGW(sizeID)); + return cacheBuf; +} + +//---------------------------------------------------------------------- + +BOOL CPlugin::MyConfigTabProc(int nPage, HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + // This is the only function you need to worry about for programming + // tabs 2 through 8 on the config panel. (Tab 1 contains settings + // that are common to all plugins, and the code is located in pluginshell.cpp). + // By default, only tab 2 is enabled; to enable tabes 3+, see + // 'Enabling Additional Tabs (pages) on the Config Panel' in DOCUMENTATION.TXT. + // You should always return 0 for this function. + // Note that you don't generally have to use critical sections or semaphores + // here; Winamp controls the plugin's message queue, and only gives it message + // in between frames. + // + // Incoming parameters: + // 'nPage' indicates which tab (aka 'property page') is currently showing: 2 through 5. + // 'hwnd' is the window handle of the property page (which is a dialog of its own, + // embedded in the config dialog). + // 'msg' is the windows message being sent. The main ones are: + // + // 1) WM_INITDIALOG: This means the page is being initialized, because the + // user clicked on it. When you get this message, you should initialize + // all the controls on the page, and set them to reflect the settings + // that are stored in member variables. + // + // 2) WM_DESTROY: This is sent when a tab disappears, either because another + // tab is about to be displayed, or because the user clicked OK or Cancel. + // In any case, you should read the current settings of all the controls + // on the page, and store them in member variables. (If the user clicked + // CANCEL, these values will not get saved to disk, but for simplicity, + // we always poll the controls here.) + // + // 3) WM_HELP: This is sent when the user clicks the '?' icon (in the + // titlebar of the config panel) and then clicks on a control. When you + // get this message, you should display a MessageBox telling the user + // a little bit about that control/setting. + // + // 4) WM_COMMAND: Advanced. This notifies you when the user clicks on a + // control. Use this if you need to do certain things when the user + // changes a setting. (For example, one control might only be enabled + // when a certain checkbox is enabled; you would use EnableWindow() for + // this.) + // + // For complete details on adding your own controls to one of the pages, please see + // 'Adding Controls to the Config Panel' in DOCUMENTATION.TXT. + + int t; + float val; + + if (nPage == 2) + { + switch(msg) + { + case WM_INITDIALOG: // initialize controls here + { + char buf[2048]; + int nPos, i; + HWND ctrl; + + //-------------- pixel shaders combo box --------------------- + ctrl = GetDlgItem( hwnd, IDC_SHADERS ); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_PS_AUTO_RECOMMENDED), -1); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_PS_DISABLED), MD2_PS_NONE); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_PS_SHADER_MODEL_2), MD2_PS_2_0); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_PS_SHADER_MODEL_3), MD2_PS_3_0); + SelectItemByPos(ctrl, 0); //as a safe default + SelectItemByValue(ctrl, m_nMaxPSVersion_ConfigPanel); + + //-------------- texture format combo box --------------------- + ctrl = GetDlgItem( hwnd, IDC_TEXFORMAT ); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_TX_8_BITS_PER_CHANNEL), 8); + //AddItem(ctrl, " 10 bits per channel", 10); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_TX_16_BITS_PER_CHANNEL), 16); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_TX_32_BITS_PER_CHANNEL), 32); + SelectItemByPos(ctrl, 0); //as a safe default + SelectItemByValue(ctrl, m_nTexBitsPerCh); + + //-------------- mesh size combo box --------------------- + ctrl = GetDlgItem( hwnd, IDC_MESHSIZECOMBO ); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_8X6_FAST), 8); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_16X12_FAST), 16); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_24X18), 24); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_32X24), 32); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_40X30), 40); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_48X36_DEFAULT), 48); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_64X48_SLOW), 64); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_80X60_SLOW), 80); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_96X72_SLOW), 96); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_128X96_SLOW), 128); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_160X120_SLOW), 160); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_192X144_SLOW), 192); + SelectItemByPos(ctrl, 0); //as a safe default + SelectItemByValue(ctrl, m_nGridX); + + //-------------- canvas stretch combo box --------------------- + ctrl = GetDlgItem( hwnd, IDC_STRETCH ); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_AUTO), 0); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_NONE_BEST_IMAGE_QUALITY), 100); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_1_25_X), 125); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_1_33_X), 133); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_1_5_X), 150); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_1_67_X), 167); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_2_X), 200); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_3_X), 300); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_4_X), 400); + SelectItemByPos(ctrl, 0); //as a safe default + SelectItemByValue(ctrl, m_nCanvasStretch); + + //-------------- texture size combo box --------------------- + for (i=0; i<5; i++) + { + int size = (int)pow(2., i+8); + sprintf(buf, " %4d x %4d ", size, size); + nPos = SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_ADDSTRING, 0, (LPARAM)buf); + SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETITEMDATA, nPos, size); + } + + // throw the "Auto" option in there + nPos = SendMessageW( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_NEAREST_POWER_OF_2)); + SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETITEMDATA, nPos, -2); + nPos = SendMessageW( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_EXACT_RECOMMENDED)); + SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETITEMDATA, nPos, -1); + + for (i=0; i<5+2; i++) + { + int size = SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_GETITEMDATA, i, 0); + if (size == m_nTexSizeX) + { + SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETCURSEL, i, 0); + } + } + + //---------16-bit brightness slider-------------- + + SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETRANGEMIN, + FALSE, (LPARAM)(0) ); + SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETRANGEMAX, + FALSE, (LPARAM)(4) ); + SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETPOS, + TRUE, (LPARAM)(m_n16BitGamma) ); + for (i=0; i<5; i++) + SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETTIC, 0, i); + + // append debug output filename to the checkbox's text + GetWindowText( GetDlgItem(hwnd, IDC_CB_DEBUGOUTPUT), buf, 256); + lstrcat(buf, DEBUGFILE); + SetWindowText( GetDlgItem(hwnd, IDC_CB_DEBUGOUTPUT), buf); + + // set checkboxes + CheckDlgButton(hwnd, IDC_CB_DEBUGOUTPUT, g_bDebugOutput); + //CheckDlgButton(hwnd, IDC_CB_PRESSF1, (!m_bShowPressF1ForHelp)); + //CheckDlgButton(hwnd, IDC_CB_TOOLTIPS, m_bShowMenuToolTips); + //CheckDlgButton(hwnd, IDC_CB_ALWAYS3D, m_bAlways3D); + //CheckDlgButton(hwnd, IDC_CB_FIXSLOWTEXT, m_bFixSlowText); + //CheckDlgButton(hwnd, IDC_CB_TOP, m_bAlwaysOnTop); + //CheckDlgButton(hwnd, IDC_CB_CLS, !m_bClearScreenAtStartup); + //CheckDlgButton(hwnd, IDC_CB_NOWARN, m_bWarningsDisabled); + CheckDlgButton(hwnd, IDC_CB_NOWARN2, m_bWarningsDisabled2); + //CheckDlgButton(hwnd, IDC_CB_ANISO, m_bAnisotropicFiltering); + CheckDlgButton(hwnd, IDC_CB_SCROLLON, m_bPresetLockOnAtStartup); + CheckDlgButton(hwnd, IDC_CB_SCROLLON2, m_bPreventScollLockHandling); + //CheckDlgButton(hwnd, IDC_CB_PINKFIX, m_bFixPinkBug); + CheckDlgButton(hwnd, IDC_CB_NORATING, !m_bEnableRating); + CheckDlgButton(hwnd, IDC_CB_AUTOGAMMA, m_bAutoGamma); + + RefreshTab2(hwnd); + } + break; // case WM_INITDIALOG + + case WM_COMMAND: + { + int id = LOWORD(wParam); + //g_ignore_tab2_clicks = 1; + switch (id) + { + case IDC_CB_NORATING: + m_bEnableRating = !DlgItemIsChecked(hwnd, IDC_CB_NORATING); + RefreshTab2(hwnd); + break; + + case IDC_CB_AUTOGAMMA: + m_bAutoGamma = DlgItemIsChecked(hwnd, IDC_CB_AUTOGAMMA); + RefreshTab2(hwnd); + break; + + } + //g_ignore_tab2_clicks = 0; + } // end WM_COMMAND case + break; + + case WM_DESTROY: // read controls here + { + ReadCBValue(hwnd, IDC_SHADERS , &m_nMaxPSVersion_ConfigPanel ); + ReadCBValue(hwnd, IDC_TEXFORMAT , &m_nTexBitsPerCh ); + ReadCBValue(hwnd, IDC_TEXSIZECOMBO , &m_nTexSizeX ); + ReadCBValue(hwnd, IDC_MESHSIZECOMBO, &m_nGridX ); + ReadCBValue(hwnd, IDC_STRETCH , &m_nCanvasStretch); + + // 16-bit-brightness slider - this one doesn't use item values... just item pos. + t = SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER ), TBM_GETPOS, 0, 0); + if (t != CB_ERR) m_n16BitGamma = t; + + // checkboxes + g_bDebugOutput = DlgItemIsChecked(hwnd, IDC_CB_DEBUGOUTPUT); + //m_bShowPressF1ForHelp = (!DlgItemIsChecked(hwnd, IDC_CB_PRESSF1)); + //m_bShowMenuToolTips = DlgItemIsChecked(hwnd, IDC_CB_TOOLTIPS); + //m_bClearScreenAtStartup = !DlgItemIsChecked(hwnd, IDC_CB_CLS); + //m_bAlways3D = DlgItemIsChecked(hwnd, IDC_CB_ALWAYS3D); + //m_bFixSlowText = DlgItemIsChecked(hwnd, IDC_CB_FIXSLOWTEXT); + //m_bAlwaysOnTop = DlgItemIsChecked(hwnd, IDC_CB_TOP); + //m_bWarningsDisabled = DlgItemIsChecked(hwnd, IDC_CB_NOWARN); + m_bWarningsDisabled2 = DlgItemIsChecked(hwnd, IDC_CB_NOWARN2); + //m_bAnisotropicFiltering = DlgItemIsChecked(hwnd, IDC_CB_ANISO); + m_bPresetLockOnAtStartup = DlgItemIsChecked(hwnd, IDC_CB_SCROLLON); + m_bPreventScollLockHandling = DlgItemIsChecked(hwnd, IDC_CB_SCROLLON2); + + //m_bFixPinkBug = DlgItemIsChecked(hwnd, IDC_CB_PINKFIX); + m_bEnableRating = !DlgItemIsChecked(hwnd, IDC_CB_NORATING); + m_bAutoGamma = DlgItemIsChecked(hwnd, IDC_CB_AUTOGAMMA); + + } + break; // case WM_DESTROY + + case WM_HELP: // give help box for controls here + if (lParam) + { + HELPINFO *ph = (HELPINFO*)lParam; + wchar_t title[1024], buf[2048], ctrl_name[1024]; + GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name)); + RemoveSingleAmpersands(ctrl_name); + buf[0] = 0; + + StringCbCopyW(title, sizeof(title), ctrl_name); + + switch(ph->iCtrlId) + { + case IDC_SHADERS: + case IDC_SHADERS_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_PIXEL_SHADERS, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_PIXEL_SHADERS_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_TEXFORMAT: + case IDC_TEXFORMAT_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_TEXFORMAT, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_TEXFORMAT_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_TEXSIZECOMBO: + case IDC_TEXSIZECOMBO_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_CANVAS_SIZE, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_CANVAS_SIZE_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_STRETCH: + case IDC_STRETCH_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_CANVAS_STRETCH, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_CANVAS_STRETCH_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_MESHSIZECOMBO: + case IDC_MESHSIZECOMBO_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_MESH_SIZE, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_MESH_SIZE_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_CB_ALWAYS3D: + WASABI_API_LNGSTRINGW_BUF(IDS_CB_ALWAYS3D, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_CB_NORATING: + WASABI_API_LNGSTRINGW_BUF(IDS_DISABLE_PRESET_RATING, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_DISABLE_PRESET_RATING_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_CB_NOWARN2: + WASABI_API_LNGSTRINGW_BUF(IDS_CB_NOWARN2, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_CB_SCROLLON: + WASABI_API_LNGSTRINGW_BUF(IDS_START_WITH_PRESET_LOCK_ON, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_START_WITH_PRESET_LOCK_ON_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_BRIGHT_SLIDER: + case IDC_BRIGHT_SLIDER_BOX: + case IDC_T1: + case IDC_T2: + case IDC_T3: + case IDC_T4: + case IDC_T5: + case IDC_CB_AUTOGAMMA: + GetWindowTextW(GetDlgItem(hwnd, IDC_BRIGHT_SLIDER_BOX), title, sizeof(title)/sizeof(*title)); + RemoveSingleAmpersands(title); + WASABI_API_LNGSTRINGW_BUF((ph->iCtrlId==IDC_CB_AUTOGAMMA?IDS_CB_AUTOGAMMA:IDS_BRIGHT_SLIDER), buf, sizeof(buf)/sizeof(*buf)); + break; + } + + if (buf[0]) + MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + break; // case WM_HELP + } + } + else if (nPage==3) + { + switch(msg) + { + case WM_INITDIALOG: + { + char buf[2048]; + HWND ctrl; + + //-------------- image cache max. bytes combo box --------------------- + ctrl = GetDlgItem( hwnd, IDC_MAX_BYTES ); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_AUTO), -1); + AddItem(ctrl, FormImageCacheSizeString(L" 0", IDS_MB), 0); + AddItem(ctrl, FormImageCacheSizeString(L" 1", IDS_MB), 1000000); + AddItem(ctrl, FormImageCacheSizeString(L" 2", IDS_MB), 2000000); + AddItem(ctrl, FormImageCacheSizeString(L" 3", IDS_MB), 3000000); + AddItem(ctrl, FormImageCacheSizeString(L" 4", IDS_MB), 4000000); + AddItem(ctrl, FormImageCacheSizeString(L" 6", IDS_MB), 6000000); + AddItem(ctrl, FormImageCacheSizeString(L" 9", IDS_MB), 8000000); + AddItem(ctrl, FormImageCacheSizeString(L" 10", IDS_MB), 10000000); + AddItem(ctrl, FormImageCacheSizeString(L" 12", IDS_MB), 12000000); + AddItem(ctrl, FormImageCacheSizeString(L" 14", IDS_MB), 14000000); + AddItem(ctrl, FormImageCacheSizeString(L" 16", IDS_MB), 16000000); + AddItem(ctrl, FormImageCacheSizeString(L" 20", IDS_MB), 20000000); + AddItem(ctrl, FormImageCacheSizeString(L" 24", IDS_MB), 24000000); + AddItem(ctrl, FormImageCacheSizeString(L" 28", IDS_MB), 28000000); + AddItem(ctrl, FormImageCacheSizeString(L" 32", IDS_MB), 32000000); + AddItem(ctrl, FormImageCacheSizeString(L" 40", IDS_MB), 40000000); + AddItem(ctrl, FormImageCacheSizeString(L" 48", IDS_MB), 48000000); + AddItem(ctrl, FormImageCacheSizeString(L" 56", IDS_MB), 56000000); + AddItem(ctrl, FormImageCacheSizeString(L" 64", IDS_MB), 64000000); + AddItem(ctrl, FormImageCacheSizeString(L" 80", IDS_MB), 80000000); + AddItem(ctrl, FormImageCacheSizeString(L" 96", IDS_MB), 96000000); + AddItem(ctrl, FormImageCacheSizeString(L" 128", IDS_MB), 128000000); + AddItem(ctrl, FormImageCacheSizeString(L" 160", IDS_MB), 160000000); + AddItem(ctrl, FormImageCacheSizeString(L" 192", IDS_MB), 192000000); + AddItem(ctrl, FormImageCacheSizeString(L" 224", IDS_MB), 224000000); + AddItem(ctrl, FormImageCacheSizeString(L" 256", IDS_MB), 256000000); + AddItem(ctrl, FormImageCacheSizeString(L" 384", IDS_MB), 384000000); + AddItem(ctrl, FormImageCacheSizeString(L" 512", IDS_MB), 512000000); + AddItem(ctrl, FormImageCacheSizeString(L" 768", IDS_MB), 768000000); + AddItem(ctrl, FormImageCacheSizeString(L" 1", IDS_GB), 1000000000); + AddItem(ctrl, FormImageCacheSizeString(L"1.25", IDS_GB), 1250000000); + AddItem(ctrl, FormImageCacheSizeString(L" 1.5", IDS_GB), 1500000000); + AddItem(ctrl, FormImageCacheSizeString(L"1.75", IDS_GB), 1750000000); + AddItem(ctrl, FormImageCacheSizeString(L" 2", IDS_GB), 2000000000); + SelectItemByPos (ctrl, 0); //as a safe default + SelectItemByValue(ctrl, m_nMaxBytes); + + //-------------- image cache max. # images combo box --------------------- + ctrl = GetDlgItem( hwnd, IDC_MAX_IMAGES ); + AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_AUTO), -1); + AddItem(ctrl, L" 0 ", 0); + AddItem(ctrl, L" 1 ", 1); + AddItem(ctrl, L" 2 ", 2); + AddItem(ctrl, L" 3 ", 3); + AddItem(ctrl, L" 4 ", 4); + AddItem(ctrl, L" 6 ", 6); + AddItem(ctrl, L" 8 ", 8); + AddItem(ctrl, L" 10 ", 10); + AddItem(ctrl, L" 12 ", 12); + AddItem(ctrl, L" 14 ", 14); + AddItem(ctrl, L" 16 ", 16); + AddItem(ctrl, L" 20 ", 20); + AddItem(ctrl, L" 24 ", 24); + AddItem(ctrl, L" 28 ", 28); + AddItem(ctrl, L" 32 ", 32); + AddItem(ctrl, L" 40 ", 40); + AddItem(ctrl, L" 48 ", 48); + AddItem(ctrl, L" 56 ", 56); + AddItem(ctrl, L" 64 ", 64); + AddItem(ctrl, L" 80 ", 80); + AddItem(ctrl, L" 96 ", 96); + AddItem(ctrl, L" 128 ",128); + AddItem(ctrl, L" 160 ",160); + AddItem(ctrl, L" 192 ",192); + AddItem(ctrl, L" 224 ",224); + AddItem(ctrl, L" 256 ",256); + AddItem(ctrl, L" 384 ",384); + AddItem(ctrl, L" 512 ",512); + AddItem(ctrl, L" 768 ",768); + AddItem(ctrl, L" 1024 ",1024); + AddItem(ctrl, L" 1536 ",1536); + AddItem(ctrl, L" 2048 ",2048); + SelectItemByPos (ctrl, 0); //as a safe default + SelectItemByValue(ctrl, m_nMaxImages); + + //sprintf(buf, " %3.2f", m_fStereoSep); + //SetWindowText( GetDlgItem( hwnd, IDC_3DSEP ), buf ); + + sprintf(buf, " %2.1f", m_fSongTitleAnimDuration); + SetWindowText(GetDlgItem( hwnd, IDC_SONGTITLEANIM_DURATION), buf); + sprintf(buf, " %2.1f", m_fTimeBetweenRandomSongTitles); + SetWindowText(GetDlgItem(hwnd, IDC_RAND_TITLE), buf); + sprintf(buf, " %2.1f", m_fTimeBetweenRandomCustomMsgs); + SetWindowText(GetDlgItem(hwnd, IDC_RAND_MSG), buf); + + CheckDlgButton(hwnd, IDC_CB_TITLE_ANIMS, m_bSongTitleAnims); + } + break; + case WM_COMMAND: + { + int id = LOWORD(wParam); + //g_ignore_tab2_clicks = 1; + switch (id) + { + case ID_SPRITE: + { + wchar_t szPath[512], szFile[512]; + lstrcpyW(szPath, GetConfigIniFile()); + wchar_t *p = wcsrchr(szPath, L'\\'); + if (p != NULL) + { + *(p+1) = 0; + lstrcpyW(szFile, szPath); + lstrcatW(szFile, IMG_INIFILE); + intptr_t ret = (intptr_t)ShellExecuteW(NULL, L"open", szFile, NULL, szPath, SW_SHOWNORMAL); + if (ret <= 32) + { + wchar_t* str = WASABI_API_LNGSTRINGW(IDS_ERROR_IN_SHELLEXECUTE); + MessageBoxW(hwnd, str, str, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + } + } + break; + + case ID_MSG: + { + wchar_t szPath[512], szFile[512]; + lstrcpyW(szPath, GetConfigIniFile()); + wchar_t *p = wcsrchr(szPath, L'\\'); + if (p != NULL) + { + *(p+1) = 0; + lstrcpyW(szFile, szPath); + lstrcatW(szFile, MSG_INIFILE); + intptr_t ret = (intptr_t)ShellExecuteW(NULL, L"open", szFile, NULL, szPath, SW_SHOWNORMAL); + if (ret <= 32) + { + wchar_t* str = WASABI_API_LNGSTRINGW(IDS_ERROR_IN_SHELLEXECUTE); + MessageBoxW(hwnd, str, str, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + } + } + break; + } + } + /*if (LOWORD(wParam)==IDLEFT) + DoColors(hwnd, &m_cLeftEye3DColor[0], &m_cLeftEye3DColor[1], &m_cLeftEye3DColor[2]); + if (LOWORD(wParam)==IDRIGHT) + DoColors(hwnd, &m_cRightEye3DColor[0], &m_cRightEye3DColor[1], &m_cRightEye3DColor[2]); + */ + break; + case WM_DESTROY: + { + ReadCBValue(hwnd, IDC_MAX_BYTES , &m_nMaxBytes ); + ReadCBValue(hwnd, IDC_MAX_IMAGES , &m_nMaxImages ); + + char buf[2048]; + + GetWindowText( GetDlgItem( hwnd, IDC_SONGTITLEANIM_DURATION ), buf, sizeof(buf)); + if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1) + m_fSongTitleAnimDuration = val; + GetWindowText( GetDlgItem( hwnd, IDC_RAND_TITLE ), buf, sizeof(buf)); + if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1) + m_fTimeBetweenRandomSongTitles = val; + GetWindowText( GetDlgItem( hwnd, IDC_RAND_MSG ), buf, sizeof(buf)); + if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1) + m_fTimeBetweenRandomCustomMsgs = val; + + m_bSongTitleAnims = DlgItemIsChecked(hwnd, IDC_CB_TITLE_ANIMS); + } + break; + case WM_HELP: // give help box for controls here + if (lParam) + { + HELPINFO *ph = (HELPINFO*)lParam; + wchar_t title[1024], buf[2048], ctrl_name[1024]; + GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name)); + RemoveSingleAmpersands(ctrl_name); + buf[0] = 0; + + StringCbCopyW(title, sizeof(title), ctrl_name); + + switch(ph->iCtrlId) + { + case IDC_MAX_IMAGES: + case IDC_MAX_IMAGES_CAPTION: + case IDC_MAX_BYTES: + case IDC_MAX_BYTES_CAPTION: + WASABI_API_LNGSTRINGW_BUF(IDS_MAX_IMAGES_BYTES, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_MAX_IMAGES_BYTES_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case ID_SPRITE: + WASABI_API_LNGSTRINGW_BUF(IDS_SPRITE, buf, sizeof(buf)/sizeof(*buf)); + break; + + case ID_MSG: + WASABI_API_LNGSTRINGW_BUF(IDS_MSG, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_SONGTITLEANIM_DURATION: + case IDC_SONGTITLEANIM_DURATION_LABEL: + GetWindowTextW(GetDlgItem(hwnd, IDC_SONGTITLEANIM_DURATION_LABEL), title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_SONGTITLEANIM_DURATION_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_RAND_TITLE: + case IDC_RAND_TITLE_LABEL: + WASABI_API_LNGSTRINGW_BUF(IDS_RAND_TITLE, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_RAND_TITLE_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_RAND_MSG: + case IDC_RAND_MSG_LABEL: + WASABI_API_LNGSTRINGW_BUF(IDS_RAND_MSG, title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_RAND_MSG_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_CB_TITLE_ANIMS: + WASABI_API_LNGSTRINGW_BUF(IDS_TITLE_ANIMS_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + } + + if (buf[0]) + MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + break; // case WM_HELP + } + } + else if (nPage==4) + { + switch(msg) + { + case WM_INITDIALOG: + { + char buf[2048]; + + // soft cuts + sprintf(buf, " %2.1f", m_fTimeBetweenPresets); + SetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME ), buf ); + sprintf(buf, " %2.1f", m_fTimeBetweenPresetsRand); + SetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME_RANDOM ), buf ); + sprintf(buf, " %2.1f", m_fBlendTimeUser); + SetWindowText( GetDlgItem( hwnd, IDC_BLEND_USER ), buf ); + sprintf(buf, " %2.1f", m_fBlendTimeAuto); + SetWindowText( GetDlgItem( hwnd, IDC_BLEND_AUTO ), buf ); + + // hard cuts + sprintf(buf, " %2.1f", m_fHardCutHalflife); + SetWindowText( GetDlgItem( hwnd, IDC_HARDCUT_BETWEEN_TIME ), buf ); + + int n = (int)((m_fHardCutLoudnessThresh - 1.25f) * 10.0f); + if (n<0) n = 0; + if (n>20) n = 20; + SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETRANGEMIN, FALSE, (LPARAM)(0) ); + SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETRANGEMAX, FALSE, (LPARAM)(20) ); + SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETPOS, TRUE, (LPARAM)(n) ); + + CheckDlgButton(hwnd, IDC_CB_HARDCUTS, m_bHardCutsDisabled); + } + break; + case WM_DESTROY: + { + char buf[2048]; + + // soft cuts + GetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME ), buf, sizeof(buf)); + if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1) + m_fTimeBetweenPresets = val; + GetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME_RANDOM ), buf, sizeof(buf)); + if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1) + m_fTimeBetweenPresetsRand = val; + GetWindowText( GetDlgItem( hwnd, IDC_BLEND_AUTO ), buf, sizeof(buf)); + if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1) + m_fBlendTimeAuto = val; + GetWindowText( GetDlgItem( hwnd, IDC_BLEND_USER ), buf, sizeof(buf)); + if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1) + m_fBlendTimeUser = val; + + // hard cuts + GetWindowText( GetDlgItem( hwnd, IDC_HARDCUT_BETWEEN_TIME ), buf, sizeof(buf)); + if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1) + m_fHardCutHalflife = val; + + t = SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS ), TBM_GETPOS, 0, 0); + if (t != CB_ERR) m_fHardCutLoudnessThresh = 1.25f + t/10.0f; + + m_bHardCutsDisabled = DlgItemIsChecked(hwnd, IDC_CB_HARDCUTS); + } + break; + case WM_HELP: + if (lParam) + { + HELPINFO *ph = (HELPINFO*)lParam; + wchar_t title[1024], buf[2048], ctrl_name[1024]; + GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name)); + RemoveSingleAmpersands(ctrl_name); + buf[0] = 0; + + StringCbCopyW(title, sizeof(title), ctrl_name); + + switch(ph->iCtrlId) + { + case IDC_BETWEEN_TIME: + case IDC_BETWEEN_TIME_LABEL: + GetWindowTextW(GetDlgItem(hwnd, IDC_BETWEEN_TIME_LABEL), title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_BETWEEN_TIME_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_BETWEEN_TIME_RANDOM: + case IDC_BETWEEN_TIME_RANDOM_LABEL: + GetWindowTextW(GetDlgItem(hwnd, IDC_BETWEEN_TIME_RANDOM_LABEL), title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_BETWEEN_TIME_RANDOM_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_BLEND_AUTO: + case IDC_BLEND_AUTO_LABEL: + GetWindowTextW(GetDlgItem(hwnd, IDC_BLEND_AUTO_LABEL), title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_BLEND_AUTO_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_BLEND_USER: + case IDC_BLEND_USER_LABEL: + GetWindowTextW(GetDlgItem(hwnd, IDC_BLEND_USER_LABEL), title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_BLEND_USER_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_HARDCUT_BETWEEN_TIME: + case IDC_HARDCUT_BETWEEN_TIME_LABEL: + GetWindowTextW(GetDlgItem(hwnd, IDC_HARDCUT_BETWEEN_TIME_LABEL), title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_HARDCUT_BETWEEN_TIME_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_HARDCUT_LOUDNESS: + case IDC_HARDCUT_LOUDNESS_LABEL: + case IDC_HARDCUT_LOUDNESS_MIN: + case IDC_HARDCUT_LOUDNESS_MAX: + GetWindowTextW(GetDlgItem(hwnd, IDC_HARDCUT_LOUDNESS_LABEL), title, sizeof(title)/sizeof(*title)); + WASABI_API_LNGSTRINGW_BUF(IDS_HARDCUT_LOUDNESS_TEXT, buf, sizeof(buf)/sizeof(*buf)); + break; + + case IDC_CB_HARDCUTS: + WASABI_API_LNGSTRINGW_BUF(IDS_CB_HARDCUTS, buf, sizeof(buf)/sizeof(*buf)); + break; + } + + if (buf[0]) + MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } + break; + } + } + return false; +} + +//---------------------------------------------------------------------- + +void CPlugin::Randomize() +{ + srand((int)(GetTime()*100)); + //m_fAnimTime = (warand() % 51234L)*0.01f; + m_fRandStart[0] = (warand() % 64841L)*0.01f; + m_fRandStart[1] = (warand() % 53751L)*0.01f; + m_fRandStart[2] = (warand() % 42661L)*0.01f; + m_fRandStart[3] = (warand() % 31571L)*0.01f; + + //CState temp; + //temp.Randomize(warand() % NUM_MODES); + //m_pState->StartBlend(&temp, m_fAnimTime, m_fBlendTimeUser); +} + +//---------------------------------------------------------------------- + +void CPlugin::SetMenusForPresetVersion(int WarpPSVersion, int CompPSVersion) +{ + int MaxPSVersion = max(WarpPSVersion, CompPSVersion); + + m_menuPreset.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_WARP_SHADER), WarpPSVersion > 0); + m_menuPreset.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_COMPOSITE_SHADER), CompPSVersion > 0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_SUSTAIN_LEVEL), WarpPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_TEXTURE_WRAP), WarpPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_GAMMA_ADJUSTMENT), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_HUE_SHADER), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_VIDEO_ECHO_ALPHA), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_VIDEO_ECHO_ZOOM), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_VIDEO_ECHO_ORIENTATION), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_FILTER_INVERT), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_FILTER_BRIGHTEN), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_FILTER_DARKEN), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_FILTER_SOLARIZE), CompPSVersion==0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT), MaxPSVersion > 0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR1_MIN_COLOR_VALUE), MaxPSVersion > 0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR1_MAX_COLOR_VALUE), MaxPSVersion > 0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR2_MIN_COLOR_VALUE), MaxPSVersion > 0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR2_MAX_COLOR_VALUE), MaxPSVersion > 0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR3_MIN_COLOR_VALUE), MaxPSVersion > 0); + m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR3_MAX_COLOR_VALUE), MaxPSVersion > 0); +} + +void CPlugin::BuildMenus() +{ + wchar_t buf[1024]; + + m_pCurMenu = &m_menuPreset;//&m_menuMain; + + m_menuPreset .Init(WASABI_API_LNGSTRINGW(IDS_EDIT_CURRENT_PRESET)); + m_menuMotion .Init(WASABI_API_LNGSTRINGW(IDS_MOTION)); + m_menuCustomShape.Init(WASABI_API_LNGSTRINGW(IDS_DRAWING_CUSTOM_SHAPES)); + m_menuCustomWave .Init(WASABI_API_LNGSTRINGW(IDS_DRAWING_CUSTOM_WAVES)); + m_menuWave .Init(WASABI_API_LNGSTRINGW(IDS_DRAWING_SIMPLE_WAVEFORM)); + m_menuAugment .Init(WASABI_API_LNGSTRINGW(IDS_DRAWING_BORDERS_MOTION_VECTORS)); + m_menuPost .Init(WASABI_API_LNGSTRINGW(IDS_POST_PROCESSING_MISC)); + for (int i=0; im_szPerFrameInit, MENUITEMTYPE_STRING, + WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_PRESET_INIT_CODE_TT, buf, 1024), + 256, 0, &OnUserEditedPresetInit, sizeof(m_pState->m_szPerFrameInit), 0); + + m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_PER_FRAME_EQUATIONS), + &m_pState->m_szPerFrameExpr, MENUITEMTYPE_STRING, + WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_PER_FRAME_EQUATIONS_TT, buf, 1024), + 256, 0, &OnUserEditedPerFrame, sizeof(m_pState->m_szPerFrameExpr), 0); + + m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_PER_VERTEX_EQUATIONS), + &m_pState->m_szPerPixelExpr, MENUITEMTYPE_STRING, + WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_PER_VERTEX_EQUATIONS_TT, buf, 1024), + 256, 0, &OnUserEditedPerPixel, sizeof(m_pState->m_szPerPixelExpr), 0); + + m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_WARP_SHADER), + &m_pState->m_szWarpShadersText, MENUITEMTYPE_STRING, + WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_WARP_SHADER_TT, buf, 1024), + 256, 0, &OnUserEditedWarpShaders, sizeof(m_pState->m_szWarpShadersText), 0); + + m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_COMPOSITE_SHADER), + &m_pState->m_szCompShadersText, MENUITEMTYPE_STRING, + WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_COMPOSITE_SHADER_TT, buf, 1024), + 256, 0, &OnUserEditedCompShaders, sizeof(m_pState->m_szCompShadersText), 0); + + m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_UPGRADE_PRESET_PS_VERSION), + (void*)UI_UPGRADE_PIXEL_SHADER, MENUITEMTYPE_UIMODE, + WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_UPGRADE_PRESET_PS_VERSION_TT, buf, 1024), + 0, 0, NULL, UI_UPGRADE_PIXEL_SHADER, 0); + + m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_DO_A_PRESET_MASH_UP), + (void*)UI_MASHUP, MENUITEMTYPE_UIMODE, + WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_DO_A_PRESET_MASH_UP_TT, buf, 1024), + 0, 0, NULL, UI_MASHUP, 0); + + //------------------------------------------- + + // menu items + #define MEN_T(id) WASABI_API_LNGSTRINGW(id) + #define MEN_TT(id) WASABI_API_LNGSTRINGW_BUF(id, buf, 1024) + + m_menuWave.AddItem(MEN_T(IDS_MENU_WAVE_TYPE), &m_pState->m_nWaveMode, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_WAVE_TYPE_TT), 0, NUM_WAVES-1); + m_menuWave.AddItem(MEN_T(IDS_MENU_SIZE), &m_pState->m_fWaveScale, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_SIZE_TT)); + m_menuWave.AddItem(MEN_T(IDS_MENU_SMOOTH), &m_pState->m_fWaveSmoothing,MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_SMOOTH_TT), 0.0f, 0.9f); + m_menuWave.AddItem(MEN_T(IDS_MENU_MYSTERY_PARAMETER), &m_pState->m_fWaveParam, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_MYSTERY_PARAMETER_TT), -1.0f, 1.0f); + m_menuWave.AddItem(MEN_T(IDS_MENU_POSITION_X), &m_pState->m_fWaveX, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_POSITION_X_TT), 0, 1); + m_menuWave.AddItem(MEN_T(IDS_MENU_POSITION_Y), &m_pState->m_fWaveY, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_POSITION_Y_TT), 0, 1); + m_menuWave.AddItem(MEN_T(IDS_MENU_COLOR_RED), &m_pState->m_fWaveR, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_RED_TT), 0, 1); + m_menuWave.AddItem(MEN_T(IDS_MENU_COLOR_GREEN), &m_pState->m_fWaveG, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_GREEN_TT), 0, 1); + m_menuWave.AddItem(MEN_T(IDS_MENU_COLOR_BLUE), &m_pState->m_fWaveB, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_BLUE_TT), 0, 1); + m_menuWave.AddItem(MEN_T(IDS_MENU_OPACITY), &m_pState->m_fWaveAlpha, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_OPACITY_TT), 0.001f, 100.0f); + m_menuWave.AddItem(MEN_T(IDS_MENU_USE_DOTS), &m_pState->m_bWaveDots, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_USE_DOTS_TT)); + m_menuWave.AddItem(MEN_T(IDS_MENU_DRAW_THICK), &m_pState->m_bWaveThick, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_DRAW_THICK_TT)); + m_menuWave.AddItem(MEN_T(IDS_MENU_MODULATE_OPACITY_BY_VOLUME), &m_pState->m_bModWaveAlphaByVolume, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_MODULATE_OPACITY_BY_VOLUME_TT)); + m_menuWave.AddItem(MEN_T(IDS_MENU_MODULATION_TRANSPARENT_VOLUME), &m_pState->m_fModWaveAlphaStart, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_MODULATION_TRANSPARENT_VOLUME_TT), 0.0f, 2.0f); + m_menuWave.AddItem(MEN_T(IDS_MENU_MODULATION_OPAQUE_VOLUME), &m_pState->m_fModWaveAlphaEnd, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_MODULATION_OPAQUE_VOLUME_TT), 0.0f, 2.0f); + m_menuWave.AddItem(MEN_T(IDS_MENU_ADDITIVE_DRAWING), &m_pState->m_bAdditiveWaves, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ADDITIVE_DRAWING_TT)); + m_menuWave.AddItem(MEN_T(IDS_MENU_COLOR_BRIGHTENING), &m_pState->m_bMaximizeWaveColor, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_COLOR_BRIGHTENING_TT)); + + m_menuAugment.AddItem(MEN_T(IDS_MENU_OUTER_BORDER_THICKNESS), &m_pState->m_fOuterBorderSize, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OUTER_BORDER_THICKNESS_TT), 0, 0.5f); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_RED_OUTER), &m_pState->m_fOuterBorderR, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_RED_OUTER_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_GREEN_OUTER), &m_pState->m_fOuterBorderG, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_GREEN_OUTER_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_BLUE_OUTER), &m_pState->m_fOuterBorderB, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_BLUE_OUTER_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_OPACITY_OUTER), &m_pState->m_fOuterBorderA, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OPACITY_OUTER_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_INNER_BORDER_THICKNESS), &m_pState->m_fInnerBorderSize, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_INNER_BORDER_THICKNESS_TT), 0, 0.5f); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_RED_OUTER), &m_pState->m_fInnerBorderR, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_RED_INNER_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_GREEN_OUTER), &m_pState->m_fInnerBorderG, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_GREEN_INNER_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_BLUE_OUTER), &m_pState->m_fInnerBorderB, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_BLUE_INNER_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_OPACITY_OUTER), &m_pState->m_fInnerBorderA, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OPACITY_INNER_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_MOTION_VECTOR_OPACITY), &m_pState->m_fMvA, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_MOTION_VECTOR_OPACITY_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_NUM_MOT_VECTORS_X), &m_pState->m_fMvX, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_NUM_MOT_VECTORS_X_TT), 0, 64); + m_menuAugment.AddItem(MEN_T(IDS_MENU_NUM_MOT_VECTORS_Y), &m_pState->m_fMvY, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_NUM_MOT_VECTORS_Y_TT), 0, 48); + m_menuAugment.AddItem(MEN_T(IDS_MENU_OFFSET_X), &m_pState->m_fMvDX, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OFFSET_X_TT), -1, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_OFFSET_Y), &m_pState->m_fMvDY, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OFFSET_Y_TT), -1, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_TRAIL_LENGTH), &m_pState->m_fMvL, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_TRAIL_LENGTH_TT), 0, 5); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_RED_OUTER), &m_pState->m_fMvR, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_RED_MOTION_VECTOR_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_GREEN_OUTER), &m_pState->m_fMvG, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_GREEN_MOTION_VECTOR_TT), 0, 1); + m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_BLUE_OUTER), &m_pState->m_fMvB, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_BLUE_MOTION_VECTOR_TT), 0, 1); + + m_menuMotion.AddItem(MEN_T(IDS_MENU_ZOOM_AMOUNT), &m_pState->m_fZoom, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_ZOOM_AMOUNT_TT)); + m_menuMotion.AddItem(MEN_T(IDS_MENU_ZOOM_EXPONENT), &m_pState->m_fZoomExponent, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_ZOOM_EXPONENT_TT)); + m_menuMotion.AddItem(MEN_T(IDS_MENU_WARP_AMOUNT), &m_pState->m_fWarpAmount, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_WARP_AMOUNT_TT)); + m_menuMotion.AddItem(MEN_T(IDS_MENU_WARP_SCALE), &m_pState->m_fWarpScale, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_WARP_SCALE_TT)); + m_menuMotion.AddItem(MEN_T(IDS_MENU_WARP_SPEED), &m_pState->m_fWarpAnimSpeed, MENUITEMTYPE_LOGFLOAT, MEN_TT(IDS_MENU_WARP_SPEED_TT)); + m_menuMotion.AddItem(MEN_T(IDS_MENU_ROTATION_AMOUNT), &m_pState->m_fRot, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_ROTATION_AMOUNT_TT), -1.00f, 1.00f); + m_menuMotion.AddItem(MEN_T(IDS_MENU_ROTATION_CENTER_OF_X), &m_pState->m_fRotCX, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_ROTATION_CENTER_OF_X_TT), -1.0f, 2.0f); + m_menuMotion.AddItem(MEN_T(IDS_MENU_ROTATION_CENTER_OF_Y), &m_pState->m_fRotCY, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_ROTATION_CENTER_OF_Y_TT), -1.0f, 2.0f); + m_menuMotion.AddItem(MEN_T(IDS_MENU_TRANSLATION_X), &m_pState->m_fXPush, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_TRANSLATION_X_TT), -1.0f, 1.0f); + m_menuMotion.AddItem(MEN_T(IDS_MENU_TRANSLATION_Y), &m_pState->m_fYPush, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_TRANSLATION_Y_TT), -1.0f, 1.0f); + m_menuMotion.AddItem(MEN_T(IDS_MENU_SCALING_X), &m_pState->m_fStretchX, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_SCALING_X_TT)); + m_menuMotion.AddItem(MEN_T(IDS_MENU_SCALING_Y), &m_pState->m_fStretchY, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_SCALING_Y_TT)); + + m_menuPost.AddItem(MEN_T(IDS_MENU_SUSTAIN_LEVEL), &m_pState->m_fDecay, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_SUSTAIN_LEVEL_TT), 0.50f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_DARKEN_CENTER), &m_pState->m_bDarkenCenter, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_DARKEN_CENTER_TT)); + m_menuPost.AddItem(MEN_T(IDS_MENU_GAMMA_ADJUSTMENT), &m_pState->m_fGammaAdj, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_GAMMA_ADJUSTMENT_TT), 1.0f, 8.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_HUE_SHADER), &m_pState->m_fShader, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_HUE_SHADER_TT), 0.0f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_VIDEO_ECHO_ALPHA), &m_pState->m_fVideoEchoAlpha, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_VIDEO_ECHO_ALPHA_TT), 0.0f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_VIDEO_ECHO_ZOOM), &m_pState->m_fVideoEchoZoom, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_VIDEO_ECHO_ZOOM_TT)); + m_menuPost.AddItem(MEN_T(IDS_MENU_VIDEO_ECHO_ORIENTATION), &m_pState->m_nVideoEchoOrientation, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_VIDEO_ECHO_ORIENTATION_TT), 0.0f, 3.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_TEXTURE_WRAP), &m_pState->m_bTexWrap, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_TEXTURE_WRAP_TT)); + //m_menuPost.AddItem("stereo 3D", &m_pState->m_bRedBlueStereo, MENUITEMTYPE_BOOL, "displays the image in stereo 3D; you need 3D glasses (with red and blue lenses) for this."); + m_menuPost.AddItem(MEN_T(IDS_MENU_FILTER_INVERT), &m_pState->m_bInvert, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_FILTER_INVERT_TT)); + m_menuPost.AddItem(MEN_T(IDS_MENU_FILTER_BRIGHTEN), &m_pState->m_bBrighten, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_FILTER_BRIGHTEN_TT)); + m_menuPost.AddItem(MEN_T(IDS_MENU_FILTER_DARKEN), &m_pState->m_bDarken, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_FILTER_DARKEN_TT)); + m_menuPost.AddItem(MEN_T(IDS_MENU_FILTER_SOLARIZE), &m_pState->m_bSolarize, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_FILTER_SOLARIZE_TT)); + m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT),&m_pState->m_fBlur1EdgeDarken, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT_TT), 0.0f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR1_MIN_COLOR_VALUE), &m_pState->m_fBlur1Min, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR1_MIN_COLOR_VALUE_TT), 0.0f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR1_MAX_COLOR_VALUE), &m_pState->m_fBlur1Max, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR1_MAX_COLOR_VALUE_TT), 0.0f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR2_MIN_COLOR_VALUE), &m_pState->m_fBlur2Min, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR2_MIN_COLOR_VALUE_TT), 0.0f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR2_MAX_COLOR_VALUE), &m_pState->m_fBlur2Max, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR2_MAX_COLOR_VALUE_TT), 0.0f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR3_MIN_COLOR_VALUE), &m_pState->m_fBlur3Min, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR3_MIN_COLOR_VALUE_TT), 0.0f, 1.0f); + m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR3_MAX_COLOR_VALUE), &m_pState->m_fBlur3Max, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR3_MAX_COLOR_VALUE_TT), 0.0f, 1.0f); + + for (i=0; im_wave[i].enabled, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ENABLED_TT)); // bool + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_NUMBER_OF_SAMPLES),&m_pState->m_wave[i].samples, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_NUMBER_OF_SAMPLES_TT), 2, 512); // 0-512 + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_L_R_SEPARATION), &m_pState->m_wave[i].sep, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_L_R_SEPARATION_TT), 0, 256); // 0-512 + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_SCALING), &m_pState->m_wave[i].scaling, MENUITEMTYPE_LOGFLOAT, MEN_TT(IDS_MENU_SCALING_TT)); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_SMOOTH), &m_pState->m_wave[i].smoothing, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_SMOOTHING_TT), 0, 1); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_COLOR_RED), &m_pState->m_wave[i].r, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_COLOR_RED_TT), 0, 1); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_COLOR_GREEN), &m_pState->m_wave[i].g, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_COLOR_GREEN_TT), 0, 1); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_COLOR_BLUE), &m_pState->m_wave[i].b, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_COLOR_BLUE_TT), 0, 1); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_OPACITY), &m_pState->m_wave[i].a, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OPACITY_WAVE_TT), 0, 1); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_USE_SPECTRUM), &m_pState->m_wave[i].bSpectrum, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_USE_SPECTRUM_TT)); // 0-5 [0=wave left, 1=wave center, 2=wave right; 3=spectrum left, 4=spec center, 5=spec right] + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_USE_DOTS), &m_pState->m_wave[i].bUseDots, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_USE_DOTS_WAVE_TT)); // bool + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_DRAW_THICK), &m_pState->m_wave[i].bDrawThick,MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_DRAW_THICK_WAVE_TT)); // bool + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_ADDITIVE_DRAWING), &m_pState->m_wave[i].bAdditive, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ADDITIVE_DRAWING_WAVE_TT)); // bool + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_EXPORT_TO_FILE), (void*)UI_EXPORT_WAVE, MENUITEMTYPE_UIMODE,MEN_TT(IDS_MENU_EXPORT_TO_FILE_TT), 0, 0, NULL, UI_EXPORT_WAVE, i); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_IMPORT_FROM_FILE), (void*)UI_IMPORT_WAVE, MENUITEMTYPE_UIMODE,MEN_TT(IDS_MENU_IMPORT_FROM_FILE_TT), 0, 0, NULL, UI_IMPORT_WAVE, i); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_EDIT_INIT_CODE), &m_pState->m_wave[i].m_szInit, MENUITEMTYPE_STRING,MEN_TT(IDS_MENU_EDIT_INIT_CODE_TT), 256, 0, &OnUserEditedWavecodeInit, sizeof(m_pState->m_wave[i].m_szInit), 0); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_EDIT_PER_FRAME_CODE), &m_pState->m_wave[i].m_szPerFrame, MENUITEMTYPE_STRING, MEN_TT(IDS_MENU_EDIT_PER_FRAME_CODE_TT), 256, 0, &OnUserEditedWavecode, sizeof(m_pState->m_wave[i].m_szPerFrame), 0); + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_EDIT_PER_POINT_CODE), &m_pState->m_wave[i].m_szPerPoint, MENUITEMTYPE_STRING, MEN_TT(IDS_MENU_EDIT_PER_POINT_CODE_TT), 256, 0, &OnUserEditedWavecode, sizeof(m_pState->m_wave[i].m_szPerPoint), 0); + } + + for (i=0; im_shape[i].enabled, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ENABLED_SHAPE_TT)); // bool + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_NUMBER_OF_INSTANCES), &m_pState->m_shape[i].instances,MENUITEMTYPE_INT, MEN_TT(IDS_MENU_NUMBER_OF_INSTANCES_TT), 1, 1024); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_NUMBER_OF_SIDES), &m_pState->m_shape[i].sides, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_NUMBER_OF_SIDES_TT), 3, 100); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_DRAW_THICK), &m_pState->m_shape[i].thickOutline, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_DRAW_THICK_SHAPE_TT)); // bool + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_ADDITIVE_DRAWING), &m_pState->m_shape[i].additive, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ADDITIVE_DRAWING_SHAPE_TT)); // bool + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_X_POSITION), &m_pState->m_shape[i].x, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_X_POSITION_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_Y_POSITION), &m_pState->m_shape[i].y, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_Y_POSITION_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_RADIUS), &m_pState->m_shape[i].rad, MENUITEMTYPE_LOGFLOAT, MEN_TT(IDS_MENU_RADIUS_TT)); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_ANGLE), &m_pState->m_shape[i].ang, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_ANGLE_TT), 0, 3.1415927f*2.0f); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_TEXTURED), &m_pState->m_shape[i].textured, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_TEXTURED_TT)); // bool + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_TEXTURE_ZOOM), &m_pState->m_shape[i].tex_zoom, MENUITEMTYPE_LOGFLOAT, MEN_TT(IDS_MENU_TEXTURE_ZOOM_TT)); // bool + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_TEXTURE_ANGLE), &m_pState->m_shape[i].tex_ang, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_TEXTURE_ANGLE_TT), 0, 3.1415927f*2.0f); // bool + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_INNER_COLOR_RED), &m_pState->m_shape[i].r, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_INNER_COLOR_RED_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_INNER_COLOR_GREEN), &m_pState->m_shape[i].g, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_INNER_COLOR_GREEN_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_INNER_COLOR_BLUE), &m_pState->m_shape[i].b, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_INNER_COLOR_BLUE_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_INNER_OPACITY), &m_pState->m_shape[i].a, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_INNER_OPACITY_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_OUTER_COLOR_RED), &m_pState->m_shape[i].r2, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OUTER_COLOR_RED_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_OUTER_COLOR_GREEN), &m_pState->m_shape[i].g2, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OUTER_COLOR_GREEN_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_OUTER_COLOR_BLUE), &m_pState->m_shape[i].b2, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OUTER_COLOR_BLUE_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_OUTER_OPACITY), &m_pState->m_shape[i].a2, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OUTER_OPACITY_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_BORDER_COLOR_RED), &m_pState->m_shape[i].border_r, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BORDER_COLOR_RED_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_BORDER_COLOR_GREEN), &m_pState->m_shape[i].border_g, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BORDER_COLOR_GREEN_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_BORDER_COLOR_BLUE), &m_pState->m_shape[i].border_b, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BORDER_COLOR_BLUE_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_BORDER_OPACITY), &m_pState->m_shape[i].border_a, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BORDER_OPACITY_TT), 0, 1); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_EXPORT_TO_FILE), NULL, MENUITEMTYPE_UIMODE, MEN_TT(IDS_MENU_EXPORT_TO_FILE_SHAPE_TT), 0, 0, NULL, UI_EXPORT_SHAPE, i); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_IMPORT_FROM_FILE), NULL, MENUITEMTYPE_UIMODE, MEN_TT(IDS_MENU_IMPORT_FROM_FILE_SHAPE_TT), 0, 0, NULL, UI_IMPORT_SHAPE, i); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_EDIT_INIT_CODE), &m_pState->m_shape[i].m_szInit, MENUITEMTYPE_STRING, MEN_TT(IDS_MENU_EDIT_INIT_CODE_SHAPE_TT), 256, 0, &OnUserEditedShapecodeInit, sizeof(m_pState->m_shape[i].m_szInit), 0); + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_EDIT_PER_FRAME_INSTANCE_CODE), &m_pState->m_shape[i].m_szPerFrame, MENUITEMTYPE_STRING, MEN_TT(IDS_MENU_EDIT_PER_FRAME_INSTANCE_CODE_TT), 256, 0, &OnUserEditedShapecode, sizeof(m_pState->m_shape[i].m_szPerFrame), 0); + //m_menuShapecode[i].AddItem("[ edit per-point code ]",&m_pState->m_shape[i].m_szPerPoint, MENUITEMTYPE_STRING, "IN: sample [0..1]; value1 [left ch], value2 [right ch], plus all vars for per-frame code / OUT: x,y; r,g,b,a; t1-t8", 256, 0, &OnUserEditedWavecode); + } +} + +void CPlugin::WriteRealtimeConfig() +{ + WritePrivateProfileIntW(m_bShowFPS, L"bShowFPS",GetConfigIniFile(), L"settings"); + WritePrivateProfileIntW(m_bShowRating, L"bShowRating",GetConfigIniFile(), L"settings"); + WritePrivateProfileIntW(m_bShowPresetInfo, L"bShowPresetInfo",GetConfigIniFile(), L"settings"); + WritePrivateProfileIntW(m_bShowSongTitle, L"bShowSongTitle",GetConfigIniFile(), L"settings"); + WritePrivateProfileIntW(m_bShowSongTime, L"bShowSongTime",GetConfigIniFile(), L"settings"); + WritePrivateProfileIntW(m_bShowSongLen, L"bShowSongLen",GetConfigIniFile(), L"settings"); +} + +void CPlugin::dumpmsg(wchar_t *s) +{ + #if _DEBUG + OutputDebugStringW(s); + if (s[0]) + { + int len = lstrlenW(s); + if (s[len-1] != L'\n') + OutputDebugStringW(L"\n"); + } + #endif +} + +void CPlugin::PrevPreset(float fBlendTime) +{ + if (m_bSequentialPresetOrder) + { + m_nCurrentPreset--; + if (m_nCurrentPreset < m_nDirs) + m_nCurrentPreset = m_nPresets-1; + if (m_nCurrentPreset >= m_nPresets) // just in case + m_nCurrentPreset = m_nDirs; + + wchar_t szFile[MAX_PATH]; + lstrcpyW(szFile, m_szPresetDir); // note: m_szPresetDir always ends with '\' + lstrcatW(szFile, m_presets[m_nCurrentPreset].szFilename.c_str()); + + LoadPreset(szFile, fBlendTime); + } + else + { + int prev = (m_presetHistoryPos-1 + PRESET_HIST_LEN) % PRESET_HIST_LEN; + if (m_presetHistoryPos != m_presetHistoryBackFence) + { + m_presetHistoryPos = prev; + LoadPreset( m_presetHistory[m_presetHistoryPos].c_str(), fBlendTime); + } + } +} + +void CPlugin::NextPreset(float fBlendTime) // if not retracing our former steps, it will choose a random one. +{ + LoadRandomPreset(fBlendTime); +} + +void CPlugin::LoadRandomPreset(float fBlendTime) +{ + // make sure file list is ok + if (m_nPresets - m_nDirs == 0) + { + if (m_nPresets - m_nDirs == 0) + { + // note: this error message is repeated in milkdropfs.cpp in DrawText() + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILE_FOUND_IN_X_MILK), m_szPresetDir); + AddError(buf, 6.0f, ERR_MISC, true); + + // also bring up the dir. navigation menu... + if (m_UI_mode == UI_REGULAR || m_UI_mode == UI_MENU) + { + m_UI_mode = UI_LOAD; + m_bUserPagedUp = false; + m_bUserPagedDown = false; + } + return; + } + } + + bool bHistoryEmpty = (m_presetHistoryFwdFence==m_presetHistoryBackFence); + + // if we have history to march back forward through, do that first + if (!m_bSequentialPresetOrder) + { + int next = (m_presetHistoryPos+1) % PRESET_HIST_LEN; + if (next != m_presetHistoryFwdFence && !bHistoryEmpty) + { + m_presetHistoryPos = next; + LoadPreset( m_presetHistory[m_presetHistoryPos].c_str(), fBlendTime); + return; + } + } + + // --TEMPORARY-- + // this comes in handy if you want to mass-modify a batch of presets; + // just automatically tweak values in Import, then they immediately get exported to a .MILK in a new dir. + /* + for (int i=0; i= m_nPresets) + m_nCurrentPreset = m_nDirs; + } + else + { + // pick a random file + if (!m_bEnableRating || (m_presets[m_nPresets - 1].fRatingCum < 0.1f))// || (m_nRatingReadProgress < m_nPresets)) + { + m_nCurrentPreset = m_nDirs + (warand() % (m_nPresets - m_nDirs)); + } + else + { + float cdf_pos = (warand() % 14345)/14345.0f*m_presets[m_nPresets - 1].fRatingCum; + + /* + char buf[512]; + sprintf(buf, "max = %f, rand = %f, \tvalues: ", m_presets[m_nPresets - 1].fRatingCum, cdf_pos); + for (int i=m_nDirs; i cdf_pos) + hi = mid; + else + lo = mid; + } + m_nCurrentPreset = hi; + } + } + } + + // m_pPresetAddr[m_nCurrentPreset] points to the preset file to load (w/o the path); + // first prepend the path, then load section [preset00] within that file + wchar_t szFile[MAX_PATH] = {0}; + lstrcpyW(szFile, m_szPresetDir); // note: m_szPresetDir always ends with '\' + lstrcatW(szFile, m_presets[m_nCurrentPreset].szFilename.c_str()); + + if (!bHistoryEmpty) + m_presetHistoryPos = (m_presetHistoryPos+1) % PRESET_HIST_LEN; + + LoadPreset(szFile, fBlendTime); +} + +void CPlugin::RandomizeBlendPattern() +{ + if (!m_vertinfo) + return; + + // note: we now avoid constant uniform blend b/c it's half-speed for shader blending. + // (both old & new shaders would have to run on every pixel...) + int mixtype = 1 + (warand()%3);//warand()%4; + + if (mixtype==0) + { + // constant, uniform blend + int nVert = 0; + for (int y=0; y<=m_nGridY; y++) + { + for (int x=0; x<=m_nGridX; x++) + { + m_vertinfo[nVert].a = 1; + m_vertinfo[nVert].c = 0; + nVert++; + } + } + } + else if (mixtype==1) + { + // directional wipe + float ang = FRAND*6.28f; + float vx = cosf(ang); + float vy = sinf(ang); + float band = 0.1f + 0.2f*FRAND; // 0.2 is good + float inv_band = 1.0f/band; + + int nVert = 0; + for (int y=0; y<=m_nGridY; y++) + { + float fy = (y/(float)m_nGridY)*m_fAspectY; + for (int x=0; x<=m_nGridX; x++) + { + float fx = (x/(float)m_nGridX)*m_fAspectX; + + // at t==0, mix rangse from -10..0 + // at t==1, mix ranges from 1..11 + + float t = (fx-0.5f)*vx + (fy-0.5f)*vy + 0.5f; + t = (t-0.5f)/sqrtf(2.0f) + 0.5f; + + m_vertinfo[nVert].a = inv_band * (1 + band); + m_vertinfo[nVert].c = -inv_band + inv_band*t;//(x/(float)m_nGridX - 0.5f)/band; + nVert++; + } + } + } + else if (mixtype==2) + { + // plasma transition + float band = 0.12f + 0.13f*FRAND;//0.02f + 0.18f*FRAND; + float inv_band = 1.0f/band; + + // first generate plasma array of height values + m_vertinfo[ 0].c = FRAND; + m_vertinfo[ m_nGridX].c = FRAND; + m_vertinfo[m_nGridY*(m_nGridX+1) ].c = FRAND; + m_vertinfo[m_nGridY*(m_nGridX+1) + m_nGridX].c = FRAND; + GenPlasma(0, m_nGridX, 0, m_nGridY, 0.25f); + + // then find min,max so we can normalize to [0..1] range and then to the proper 'constant offset' range. + float minc = m_vertinfo[0].c; + float maxc = m_vertinfo[0].c; + int x,y,nVert; + + nVert = 0; + for (y=0; y<=m_nGridY; y++) + { + for (x=0; x<=m_nGridX; x++) + { + if (minc > m_vertinfo[nVert].c) + minc = m_vertinfo[nVert].c; + if (maxc < m_vertinfo[nVert].c) + maxc = m_vertinfo[nVert].c; + nVert++; + } + } + + float mult = 1.0f/(maxc-minc); + nVert = 0; + for (y=0; y<=m_nGridY; y++) + { + for (x=0; x<=m_nGridX; x++) + { + float t = (m_vertinfo[nVert].c - minc)*mult; + m_vertinfo[nVert].a = inv_band * (1 + band); + m_vertinfo[nVert].c = -inv_band + inv_band*t; + nVert++; + } + } + } + else if (mixtype==3) + { + // radial blend + float band = 0.02f + 0.14f*FRAND + 0.34f*FRAND; + float inv_band = 1.0f/band; + float dir = (float)((warand()%2)*2 - 1); // 1=outside-in, -1=inside-out + + int nVert = 0; + for (int y=0; y<=m_nGridY; y++) + { + float dy = (y/(float)m_nGridY - 0.5f)*m_fAspectY; + for (int x=0; x<=m_nGridX; x++) + { + float dx = (x/(float)m_nGridX - 0.5f)*m_fAspectX; + float t = sqrtf(dx*dx + dy*dy)*1.41421f; + if (dir==-1) + t = 1-t; + + m_vertinfo[nVert].a = inv_band * (1 + band); + m_vertinfo[nVert].c = -inv_band + inv_band*t; + nVert++; + } + } + } +} + +void CPlugin::GenPlasma(int x0, int x1, int y0, int y1, float dt) +{ + int midx = (x0+x1)/2; + int midy = (y0+y1)/2; + float t00 = m_vertinfo[y0*(m_nGridX+1) + x0].c; + float t01 = m_vertinfo[y0*(m_nGridX+1) + x1].c; + float t10 = m_vertinfo[y1*(m_nGridX+1) + x0].c; + float t11 = m_vertinfo[y1*(m_nGridX+1) + x1].c; + + if (y1-y0 >= 2) + { + if (x0==0) + m_vertinfo[midy*(m_nGridX+1) + x0].c = 0.5f*(t00 + t10) + (FRAND*2-1)*dt*m_fAspectY; + m_vertinfo[midy*(m_nGridX+1) + x1].c = 0.5f*(t01 + t11) + (FRAND*2-1)*dt*m_fAspectY; + } + if (x1-x0 >= 2) + { + if (y0==0) + m_vertinfo[y0*(m_nGridX+1) + midx].c = 0.5f*(t00 + t01) + (FRAND*2-1)*dt*m_fAspectX; + m_vertinfo[y1*(m_nGridX+1) + midx].c = 0.5f*(t10 + t11) + (FRAND*2-1)*dt*m_fAspectX; + } + + if (y1-y0 >= 2 && x1-x0 >= 2) + { + // do midpoint & recurse: + t00 = m_vertinfo[midy*(m_nGridX+1) + x0].c; + t01 = m_vertinfo[midy*(m_nGridX+1) + x1].c; + t10 = m_vertinfo[y0*(m_nGridX+1) + midx].c; + t11 = m_vertinfo[y1*(m_nGridX+1) + midx].c; + m_vertinfo[midy*(m_nGridX+1) + midx].c = 0.25f*(t10 + t11 + t00 + t01) + (FRAND*2-1)*dt; + + GenPlasma(x0, midx, y0, midy, dt*0.5f); + GenPlasma(midx, x1, y0, midy, dt*0.5f); + GenPlasma(x0, midx, midy, y1, dt*0.5f); + GenPlasma(midx, x1, midy, y1, dt*0.5f); + } +} + +void CPlugin::LoadPreset(const wchar_t *szPresetFilename, float fBlendTime) +{ + // clear old error msg... + if (m_nFramesSinceResize > 4) + ClearErrors(ERR_PRESET); + + // make sure preset still exists. (might not if they are using the "back"/fwd buttons + // in RANDOM preset order and a file was renamed or deleted!) + if (GetFileAttributesW(szPresetFilename) == 0xFFFFFFFF) + { + const wchar_t *p = wcsrchr(szPresetFilename, L'\\'); + p = (p) ? p+1 : szPresetFilename; + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_PRESET_NOT_FOUND_X), p); + AddError(buf, 6.0f, ERR_PRESET, true); + return; + } + + if ( !m_bSequentialPresetOrder ) + { + // save preset in the history. keep in mind - maybe we are searching back through it already! + if ( m_presetHistoryFwdFence == m_presetHistoryPos ) + { + // we're at the forward frontier; add to history + m_presetHistory[m_presetHistoryPos] = szPresetFilename; + m_presetHistoryFwdFence = (m_presetHistoryFwdFence+1) % PRESET_HIST_LEN; + + // don't let the two fences touch + if (m_presetHistoryBackFence == m_presetHistoryFwdFence) + m_presetHistoryBackFence = (m_presetHistoryBackFence+1) % PRESET_HIST_LEN; + } + else + { + // we're retracing our steps, either forward or backward... + + } + } + + // if no preset was valid before, make sure there is no blend, because there is nothing valid to blend from. + if (!wcscmp(m_pState->m_szDesc, INVALID_PRESET_DESC)) + fBlendTime = 0; + + if (fBlendTime == 0) + { + // do it all NOW! + if (szPresetFilename != m_szCurrentPresetFile) //[sic] + lstrcpyW(m_szCurrentPresetFile, szPresetFilename); + + CState *temp = m_pState; + m_pState = m_pOldState; + m_pOldState = temp; + + DWORD ApplyFlags = STATE_ALL; + ApplyFlags ^= (m_bWarpShaderLock ? STATE_WARP : 0); + ApplyFlags ^= (m_bCompShaderLock ? STATE_COMP : 0); + + m_pState->Import(m_szCurrentPresetFile, GetTime(), m_pOldState, ApplyFlags); + + if (fBlendTime >= 0.001f) + { + RandomizeBlendPattern(); + m_pState->StartBlendFrom(m_pOldState, GetTime(), fBlendTime); + } + + m_fPresetStartTime = GetTime(); + m_fNextPresetTime = -1.0f; // flags UpdateTime() to recompute this + + // release stuff from m_OldShaders, then move m_shaders to m_OldShaders, then load the new shaders. + SafeRelease( m_OldShaders.comp.ptr ); + SafeRelease( m_OldShaders.warp.ptr ); + SafeRelease( m_OldShaders.comp.CT ); + SafeRelease( m_OldShaders.warp.CT ); + m_OldShaders = m_shaders; + ZeroMemory(&m_shaders, sizeof(PShaderSet)); + + LoadShaders(&m_shaders, m_pState, false); + + OnFinishedLoadingPreset(); + } + else + { + // set ourselves up to load the preset (and esp. compile shaders) a little bit at a time + SafeRelease( m_NewShaders.comp.ptr ); + SafeRelease( m_NewShaders.warp.ptr ); + ZeroMemory(&m_NewShaders, sizeof(PShaderSet)); + + DWORD ApplyFlags = STATE_ALL; + ApplyFlags ^= (m_bWarpShaderLock ? STATE_WARP : 0); + ApplyFlags ^= (m_bCompShaderLock ? STATE_COMP : 0); + + m_pNewState->Import(szPresetFilename, GetTime(), m_pOldState, ApplyFlags); + + m_nLoadingPreset = 1; // this will cause LoadPresetTick() to get called over the next few frames... + + m_fLoadingPresetBlendTime = fBlendTime; + lstrcpyW(m_szLoadingPreset, szPresetFilename); + } +} + +void CPlugin::OnFinishedLoadingPreset() +{ + // note: only used this if you loaded the preset *intact* (or mostly intact) + + SetMenusForPresetVersion( m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion ); + m_nPresetsLoadedTotal++; //only increment this on COMPLETION of the load. + + for (int mash=0; mash= 0.001f) + m_pState->StartBlendFrom(m_pOldState, GetTime(), m_fLoadingPresetBlendTime); + + m_fPresetStartTime = GetTime(); + m_fNextPresetTime = -1.0f; // flags UpdateTime() to recompute this + + // release stuff from m_OldShaders, then move m_shaders to m_OldShaders, then load the new shaders. + SafeRelease( m_OldShaders.comp.ptr ); + SafeRelease( m_OldShaders.warp.ptr ); + m_OldShaders = m_shaders; + m_shaders = m_NewShaders; + ZeroMemory(&m_NewShaders, sizeof(PShaderSet)); + + // end slow-preset-load mode + m_nLoadingPreset = 0; + + OnFinishedLoadingPreset(); + } + + if (m_nLoadingPreset > 0) + m_nLoadingPreset++; +} + +void CPlugin::SeekToPreset(wchar_t cStartChar) +{ + if (cStartChar >= L'a' && cStartChar <= L'z') + cStartChar -= L'a' - L'A'; + + for (int i = m_nDirs; i < m_nPresets; i++) + { + wchar_t ch = m_presets[i].szFilename.c_str()[0]; + if (ch >= L'a' && ch <= L'z') + ch -= L'a' - L'A'; + if (ch == cStartChar) + { + m_nPresetListCurPos = i; + return; + } + } +} + +void CPlugin::FindValidPresetDir() +{ + swprintf(m_szPresetDir, L"%spresets\\", m_szMilkdrop2Path ); + if (GetFileAttributesW(m_szPresetDir) != -1) + return; + lstrcpyW(m_szPresetDir, m_szMilkdrop2Path); + if (GetFileAttributesW(m_szPresetDir) != -1) + return; + lstrcpyW(m_szPresetDir, GetPluginsDirPath()); + if (GetFileAttributesW(m_szPresetDir) != -1) + return; + lstrcpyW(m_szPresetDir, L"c:\\program files\\winamp\\"); //getting desperate here + if (GetFileAttributesW(m_szPresetDir) != -1) + return; + lstrcpyW(m_szPresetDir, L"c:\\program files\\"); //getting desperate here + if (GetFileAttributesW(m_szPresetDir) != -1) + return; + lstrcpyW(m_szPresetDir, L"c:\\"); +} + +char* NextLine(char* p) +{ + // p points to the beginning of a line + // we'll return a pointer to the first char of the next line + // if we hit a NULL char before that, we'll return NULL. + if (!p) + return NULL; + + char* s = p; + while (*s != '\r' && *s != '\n' && *s != 0) + s++; + + while (*s == '\r' || *s == '\n') + s++; + + if (*s==0) + return NULL; + + return s; +} + +static unsigned int WINAPI __UpdatePresetList(void* lpVoid) +{ + // NOTE - this is run in a separate thread!!! + + DWORD flags = (DWORD)lpVoid; + bool bForce = (flags & 1) ? true : false; + bool bTryReselectCurrentPreset = (flags & 2) ? true : false; + + WIN32_FIND_DATAW fd; + ZeroMemory(&fd, sizeof(fd)); + HANDLE h = INVALID_HANDLE_VALUE; + + int nTry = 0; + bool bRetrying = false; + + EnterCriticalSection(&g_cs); +retry: + + // make sure the path exists; if not, go to winamp plugins dir + if (GetFileAttributesW(g_plugin.m_szPresetDir) == -1) + { + //FIXME... + g_plugin.FindValidPresetDir(); + } + + // if Mask (dir) changed, do a full re-scan; + // if not, just finish our old scan. + wchar_t szMask[MAX_PATH]; + swprintf(szMask, L"%s*.*", g_plugin.m_szPresetDir); // cuz dirnames could have extensions, etc. + if (bForce || !g_plugin.m_szUpdatePresetMask[0] || wcscmp(szMask, g_plugin.m_szUpdatePresetMask)) + { + // if old dir was "" or the dir changed, reset our search + if (h != INVALID_HANDLE_VALUE) + FindClose(h); + h = INVALID_HANDLE_VALUE; + g_plugin.m_bPresetListReady = false; + lstrcpyW(g_plugin.m_szUpdatePresetMask, szMask); + ZeroMemory(&fd, sizeof(fd)); + + g_plugin.m_nPresets = 0; + g_plugin.m_nDirs = 0; + g_plugin.m_presets.clear(); + + // find first .MILK file + //if( (hFile = _findfirst(szMask, &c_file )) != -1L ) // note: returns filename -without- path + if( (h = FindFirstFileW(g_plugin.m_szUpdatePresetMask, &fd )) == INVALID_HANDLE_VALUE ) // note: returns filename -without- path + { + // --> revert back to plugins dir + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILES_OR_DIRS_FOUND_IN_X), g_plugin.m_szPresetDir); + g_plugin.AddError(buf, 4.0f, ERR_MISC, true); + + if (bRetrying) + { + LeaveCriticalSection(&g_cs); + g_bThreadAlive = false; + _endthreadex(0); + return 0; + } + + g_plugin.FindValidPresetDir(); + + bRetrying = true; + goto retry; + } + + g_plugin.AddError(WASABI_API_LNGSTRINGW(IDS_SCANNING_PRESETS), 8.0f, ERR_SCANNING_PRESETS, false); + } + + if (g_plugin.m_bPresetListReady) + { + LeaveCriticalSection(&g_cs); + g_bThreadAlive = false; + _endthreadex(0); + return 0; + } + + int nMaxPSVersion = g_plugin.m_nMaxPSVersion; + wchar_t szPresetDir[MAX_PATH]; + lstrcpyW(szPresetDir, g_plugin.m_szPresetDir); + + LeaveCriticalSection(&g_cs); + + PresetList temp_presets; + int temp_nDirs = 0; + int temp_nPresets = 0; + + // scan for the desired # of presets, this call... + while (!g_bThreadShouldQuit && h != INVALID_HANDLE_VALUE) + { + bool bSkip = false; + bool bIsDir = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + float fRating = 0; + + wchar_t szFilename[512]; + lstrcpyW(szFilename, fd.cFileName); + + if (bIsDir) + { + // skip "." directory + if (wcscmp(fd.cFileName, L".")==0)// || lstrlen(ffd.cFileName) < 1) + bSkip = true; + else + swprintf(szFilename, L"*%s", fd.cFileName); + } + else + { + // skip normal files not ending in ".milk" + int len = lstrlenW(fd.cFileName); + if (len < 5 || wcsicmp(fd.cFileName + len - 5, L".milk") != 0) + bSkip = true; + + // if it is .milk, make sure we know how to run its pixel shaders - + // otherwise we don't want to show it in the preset list! + if (!bSkip) + { + // If the first line of the file is not "MILKDROP_PRESET_VERSION XXX", + // then it's a MilkDrop 1 era preset, so it is definitely runnable. (no shaders) + // Otherwise, check for the value "PSVERSION". It will be 0, 2, or 3. + // If missing, assume it is 2. + wchar_t szFullPath[MAX_PATH]; + swprintf(szFullPath, L"%s%s", szPresetDir, fd.cFileName); + FILE* f = _wfopen(szFullPath, L"r"); + if (!f) + bSkip = true; + else { + #define PRESET_HEADER_SCAN_BYTES 160 + char szLine[PRESET_HEADER_SCAN_BYTES]; + char *p = szLine; + + int bytes_to_read = sizeof(szLine)-1; + int count = fread(szLine, bytes_to_read, 1, f); + if (count < 1) { + fseek(f, SEEK_SET, 0); + count = fread(szLine, 1, bytes_to_read, f); + szLine[ count ] = 0; + } + else + szLine[bytes_to_read-1] = 0; + + bool bScanForPreset00AndRating = false; + bool bRatingKnown = false; + + // try to read the PSVERSION and the fRating= value. + // most presets (unless hand-edited) will have these right at the top. + // if not, [at least for fRating] use GetPrivateProfileFloat to search whole file. + // read line 1 + //p = NextLine(p);//fgets(p, sizeof(p)-1, f); + if (!strncmp(p, "MILKDROP_PRESET_VERSION", 23)) + { + p = NextLine(p);//fgets(p, sizeof(p)-1, f); + int ps_version = 2; + if (p && !strncmp(p, "PSVERSION", 9)) + { + sscanf(&p[10], "%d", &ps_version); + if (ps_version > nMaxPSVersion) + bSkip = true; + else + { + p = NextLine(p);//fgets(p, sizeof(p)-1, f); + bScanForPreset00AndRating = true; + } + } + } + else + { + // otherwise it's a MilkDrop 1 preset - we can run it. + bScanForPreset00AndRating = true; + } + + // scan up to 10 more lines in the file, looking for [preset00] and fRating=... + // (this is WAY faster than GetPrivateProfileFloat, when it works!) + int reps = (bScanForPreset00AndRating) ? 10 : 0; + for (int z=0; z 0) + fPrevPresetRatingCum += temp_presets[temp_nPresets-1].fRatingCum; + + PresetInfo x; + x.szFilename = szFilename; + x.fRatingThis = fRating; + x.fRatingCum = fPrevPresetRatingCum + fRating; + temp_presets.push_back(x); + + temp_nPresets++; + if (bIsDir) + temp_nDirs++; + } + + if (!FindNextFileW(h, &fd)) + { + FindClose(h); + h = INVALID_HANDLE_VALUE; + + break; + } + + // every so often, add some presets... + #define PRESET_UPDATE_INTERVAL 64 + if (temp_nPresets == 30 || ((temp_nPresets % PRESET_UPDATE_INTERVAL)==0)) + { + EnterCriticalSection(&g_cs); + + //g_plugin.m_presets = temp_presets; + for (int i=g_plugin.m_nPresets; i revert back to plugins dir + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILES_OR_DIRS_FOUND_IN_X), g_plugin.m_szPresetDir); + g_plugin.AddError(buf, 4.0f, ERR_MISC, true); + + if (bRetrying) + { + LeaveCriticalSection(&g_cs); + g_bThreadAlive = false; + _endthreadex(0); + return 0; + } + + g_plugin.FindValidPresetDir(); + + bRetrying = true; + goto retry; + } + + if (g_plugin.m_bPresetListReady) + { + g_plugin.MergeSortPresets(0, g_plugin.m_nPresets-1); + + // update cumulative ratings, since order changed... + g_plugin.m_presets[0].fRatingCum = g_plugin.m_presets[0].fRatingThis; + for (int i=0; i32, before returning. + // also make sure you enter the CS whenever you check on it! + // (thread will update preset list every so often, with the newest presets scanned in...) + while (g_bThreadAlive) + { + Sleep(30); + + EnterCriticalSection(&g_cs); + int nPresets = g_plugin.m_nPresets; + LeaveCriticalSection(&g_cs); + + if (nPresets >= 30) + break; + } + + if (g_bThreadAlive) + { + // the load still takes a while even at THREAD_PRIORITY_ABOVE_NORMAL, + // because it is waiting on the HDD so much... + // but the OS is smart, and the CPU stays nice and zippy in other threads =) + SetThreadPriority(g_hThread,THREAD_PRIORITY_ABOVE_NORMAL); //THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_HIGHEST, + } + } + + return; +} + +void CPlugin::MergeSortPresets(int left, int right) +{ + // note: left..right range is inclusive + int nItems = right-left+1; + + if (nItems > 2) + { + // recurse to sort 2 halves (but don't actually recurse on a half if it only has 1 element) + int mid = (left+right)/2; + /*if (mid != left) */ MergeSortPresets(left, mid); + /*if (mid+1 != right)*/ MergeSortPresets(mid+1, right); + + // then merge results + int a = left; + int b = mid + 1; + while (a <= mid && b <= right) + { + bool bSwap; + + // merge the sorted arrays; give preference to strings that start with a '*' character + int nSpecial = 0; + if (m_presets[a].szFilename.c_str()[0] == '*') nSpecial++; + if (m_presets[b].szFilename.c_str()[0] == '*') nSpecial++; + + if (nSpecial == 1) + { + bSwap = (m_presets[b].szFilename.c_str()[0] == '*'); + } + else + { + bSwap = (mystrcmpiW(m_presets[a].szFilename.c_str(), m_presets[b].szFilename.c_str()) > 0); + } + + if (bSwap) + { + PresetInfo temp = m_presets[b]; + for (int k=b; k>a; k--) + m_presets[k] = m_presets[k-1]; + m_presets[a] = temp; + mid++; + b++; + } + a++; + } + } + else if (nItems == 2) + { + // sort 2 items; give preference to 'special' strings that start with a '*' character + int nSpecial = 0; + if (m_presets[left].szFilename.c_str()[0] == '*') nSpecial++; + if (m_presets[right].szFilename.c_str()[0] == '*') nSpecial++; + + if (nSpecial == 1) + { + if (m_presets[right].szFilename.c_str()[0] == '*') + { + PresetInfo temp = m_presets[left]; + m_presets[left] = m_presets[right]; + m_presets[right] = temp; + } + } + else if (mystrcmpiW(m_presets[left].szFilename.c_str(), m_presets[right].szFilename.c_str()) > 0) + { + PresetInfo temp = m_presets[left]; + m_presets[left] = m_presets[right]; + m_presets[right] = temp; + } + } +} + +void CPlugin::WaitString_NukeSelection() +{ + if (m_waitstring.bActive && + m_waitstring.nSelAnchorPos != -1) + { + // nuke selection. note: start & end are INCLUSIVE. + int start = (m_waitstring.nCursorPos < m_waitstring.nSelAnchorPos) ? m_waitstring.nCursorPos : m_waitstring.nSelAnchorPos; + int end = (m_waitstring.nCursorPos > m_waitstring.nSelAnchorPos) ? m_waitstring.nCursorPos - 1 : m_waitstring.nSelAnchorPos - 1; + int len = (m_waitstring.bDisplayAsCode ? lstrlenA((char*)m_waitstring.szText) : lstrlenW(m_waitstring.szText)); + int how_far_to_shift = end - start + 1; + int num_chars_to_shift = len - end; // includes NULL char + + if (m_waitstring.bDisplayAsCode) + { + char* ptr = (char*)m_waitstring.szText; + for (int i=0; i m_waitstring.nSelAnchorPos) ? m_waitstring.nCursorPos - 1 : m_waitstring.nSelAnchorPos - 1; + int chars_to_copy = end - start + 1; + + if (m_waitstring.bDisplayAsCode) + { + char* ptr = (char*)m_waitstring.szText; + for (int i=0; i= m_waitstring.nMaxLen) + { + chars_to_insert = m_waitstring.nMaxLen - len - 1; + + // inform user + AddError(WASABI_API_LNGSTRINGW(IDS_STRING_TOO_LONG), 2.5f, ERR_MISC, true); + } + else + { + //m_fShowUserMessageUntilThisTime = GetTime(); // if there was an error message already, clear it + } + + int i; + if (m_waitstring.bDisplayAsCode) + { + char* ptr = (char*)m_waitstring.szText; + for (i=len; i >= m_waitstring.nCursorPos; i--) + *(ptr + i + chars_to_insert) = *(ptr + i); + for (i=0; i < chars_to_insert; i++) + *(ptr + i + m_waitstring.nCursorPos) = m_waitstring.szClipboard[i]; + } + else + { + for (i=len; i >= m_waitstring.nCursorPos; i--) + m_waitstring.szText[i + chars_to_insert] = m_waitstring.szText[i]; + for (i=0; i < chars_to_insert; i++) + m_waitstring.szText[i + m_waitstring.nCursorPos] = m_waitstring.szClipboardW[i]; + } + m_waitstring.nCursorPos += chars_to_insert; + } +} + +void CPlugin::WaitString_SeekLeftWord() +{ + // move to beginning of prior word + if (m_waitstring.bDisplayAsCode) + { + char* ptr = (char*)m_waitstring.szText; + while (m_waitstring.nCursorPos > 0 && + !IsAlphanumericChar(*(ptr + m_waitstring.nCursorPos-1))) + m_waitstring.nCursorPos--; + + while (m_waitstring.nCursorPos > 0 && + IsAlphanumericChar(*(ptr + m_waitstring.nCursorPos-1))) + m_waitstring.nCursorPos--; + } + else + { + while (m_waitstring.nCursorPos > 0 && + !IsAlphanumericChar(m_waitstring.szText[m_waitstring.nCursorPos-1])) + m_waitstring.nCursorPos--; + + while (m_waitstring.nCursorPos > 0 && + IsAlphanumericChar(m_waitstring.szText[m_waitstring.nCursorPos-1])) + m_waitstring.nCursorPos--; + } +} + +void CPlugin::WaitString_SeekRightWord() +{ + // move to beginning of next word + + //testing lotsa stuff + + if (m_waitstring.bDisplayAsCode) + { + int len = lstrlenA((char*)m_waitstring.szText); + + char* ptr = (char*)m_waitstring.szText; + while (m_waitstring.nCursorPos < len && + IsAlphanumericChar(*(ptr + m_waitstring.nCursorPos))) + m_waitstring.nCursorPos++; + + while (m_waitstring.nCursorPos < len && + !IsAlphanumericChar(*(ptr + m_waitstring.nCursorPos))) + m_waitstring.nCursorPos++; + } + else + { + int len = lstrlenW(m_waitstring.szText); + + while (m_waitstring.nCursorPos < len && + IsAlphanumericChar(m_waitstring.szText[m_waitstring.nCursorPos])) + m_waitstring.nCursorPos++; + + while (m_waitstring.nCursorPos < len && + !IsAlphanumericChar(m_waitstring.szText[m_waitstring.nCursorPos])) + m_waitstring.nCursorPos++; + } +} + +int CPlugin::WaitString_GetCursorColumn() +{ + if (m_waitstring.bDisplayAsCode) + { + int column = 0; + char* ptr = (char*)m_waitstring.szText; + while (m_waitstring.nCursorPos - column - 1 >= 0 && + *(ptr + m_waitstring.nCursorPos - column - 1) != LINEFEED_CONTROL_CHAR) + column++; + + return column; + } + else + { + return m_waitstring.nCursorPos; + } +} + +int CPlugin::WaitString_GetLineLength() +{ + int line_start = m_waitstring.nCursorPos - WaitString_GetCursorColumn(); + int line_length = 0; + + if (m_waitstring.bDisplayAsCode) + { + char* ptr = (char*)m_waitstring.szText; + while (*(ptr + line_start + line_length) != 0 && + *(ptr + line_start + line_length) != LINEFEED_CONTROL_CHAR) + line_length++; + } + else + { + while (m_waitstring.szText[line_start + line_length] != 0 && + m_waitstring.szText[line_start + line_length] != LINEFEED_CONTROL_CHAR) + line_length++; + } + + return line_length; +} + +void CPlugin::WaitString_SeekUpOneLine() +{ + int column = g_plugin.WaitString_GetCursorColumn(); + + if (column != m_waitstring.nCursorPos) + { + // seek to very end of previous line (cursor will be at the semicolon) + m_waitstring.nCursorPos -= column + 1; + + int new_column = g_plugin.WaitString_GetCursorColumn(); + + if (new_column > column) + m_waitstring.nCursorPos -= (new_column - column); + } +} + +void CPlugin::WaitString_SeekDownOneLine() +{ + int column = g_plugin.WaitString_GetCursorColumn(); + int newpos = m_waitstring.nCursorPos; + + char* ptr = (char*)m_waitstring.szText; + while (*(ptr + newpos) != 0 && *(ptr + newpos) != LINEFEED_CONTROL_CHAR) + newpos++; + + if (*(ptr + newpos) != 0) + { + m_waitstring.nCursorPos = newpos + 1; + + while ( column > 0 && + *(ptr + m_waitstring.nCursorPos) != LINEFEED_CONTROL_CHAR && + *(ptr + m_waitstring.nCursorPos) != 0) + { + m_waitstring.nCursorPos++; + column--; + } + } +} + +void CPlugin::SavePresetAs(wchar_t *szNewFile) +{ + // overwrites the file if it was already there, + // so you should check if the file exists first & prompt user to overwrite, + // before calling this function + + if (!m_pState->Export(szNewFile)) + { + // error + AddError(WASABI_API_LNGSTRINGW(IDS_ERROR_UNABLE_TO_SAVE_THE_FILE), 6.0f, ERR_PRESET, true); + } + else + { + // pop up confirmation + AddError(WASABI_API_LNGSTRINGW(IDS_SAVE_SUCCESSFUL), 3.0f, ERR_NOTIFY, false); + + // update m_pState->m_szDesc with the new name + lstrcpyW(m_pState->m_szDesc, m_waitstring.szText); + + // refresh file listing + UpdatePresetList(false,true); + } +} + +void CPlugin::DeletePresetFile(wchar_t *szDelFile) +{ + // NOTE: this function additionally assumes that m_nPresetListCurPos indicates + // the slot that the to-be-deleted preset occupies! + + // delete file + if (!DeleteFileW(szDelFile)) + { + // error + AddError(WASABI_API_LNGSTRINGW(IDS_ERROR_UNABLE_TO_DELETE_THE_FILE), 6.0f, ERR_MISC, true); + } + else + { + // pop up confirmation + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PRESET_X_DELETED), m_presets[m_nPresetListCurPos].szFilename.c_str()); + AddError(buf, 3.0f, ERR_NOTIFY, false); + + // refresh file listing & re-select the next file after the one deleted + int newPos = m_nPresetListCurPos; + UpdatePresetList(false,true); + m_nPresetListCurPos = max(0, min(m_nPresets-1, newPos)); + } +} + +void CPlugin::RenamePresetFile(wchar_t *szOldFile, wchar_t *szNewFile) +{ + // NOTE: this function additionally assumes that m_nPresetListCurPos indicates + // the slot that the to-be-renamed preset occupies! + + if (GetFileAttributesW(szNewFile) != -1) // check if file already exists + { + // error + AddError(WASABI_API_LNGSTRINGW(IDS_ERROR_A_FILE_ALREADY_EXISTS_WITH_THAT_FILENAME), 6.0f, ERR_PRESET, true); + + // (user remains in UI_LOAD_RENAME mode to try another filename) + } + else + { + // rename + if (!MoveFileW(szOldFile, szNewFile)) + { + // error + AddError(WASABI_API_LNGSTRINGW(IDS_ERROR_UNABLE_TO_RENAME_FILE), 6.0f, ERR_MISC, true); + } + else + { + // pop up confirmation + AddError(WASABI_API_LNGSTRINGW(IDS_RENAME_SUCCESSFUL), 3.0f, ERR_NOTIFY, false); + + // if this preset was the active one, update m_pState->m_szDesc with the new name + wchar_t buf[512]; + swprintf(buf, L"%s.milk", m_pState->m_szDesc); + if (wcscmp(m_presets[m_nPresetListCurPos].szFilename.c_str(), buf) == 0) + { + lstrcpyW(m_pState->m_szDesc, m_waitstring.szText); + } + + // refresh file listing & do a trick to make it re-select the renamed file + wchar_t buf2[512]; + lstrcpyW(buf2, m_waitstring.szText); + lstrcatW(buf2, L".milk"); + m_presets[m_nPresetListCurPos].szFilename = buf2; + UpdatePresetList(false,true,false); + + // jump to (highlight) the new file: + m_nPresetListCurPos = 0; + wchar_t* p = wcsrchr(szNewFile, L'\\'); + if (p) + { + p++; + for (int i=m_nDirs; i0) + { + for (k=0; k 5) f = 5; + + if (k==0) + m_presets[k].fRatingCum = f; + else + m_presets[k].fRatingCum = m_presets[k-1].fRatingCum + f; + + m_nRatingReadProgress++; + } +} +*/ + +void CPlugin::SetCurrentPresetRating(float fNewRating) +{ + if (!m_bEnableRating) + return; + + if (fNewRating < 0) fNewRating = 0; + if (fNewRating > 5) fNewRating = 5; + float change = (fNewRating - m_pState->m_fRating); + + // update the file on disk: + //char szPresetFileNoPath[512]; + //char szPresetFileWithPath[512]; + //sprintf(szPresetFileNoPath, "%s.milk", m_pState->m_szDesc); + //sprintf(szPresetFileWithPath, "%s%s.milk", GetPresetDir(), m_pState->m_szDesc); + WritePrivateProfileFloatW(fNewRating, L"fRating", m_szCurrentPresetFile, L"preset00"); + + // update the copy of the preset in memory + m_pState->m_fRating = fNewRating; + + // update the cumulative internal listing: + m_presets[m_nCurrentPreset].fRatingThis += change; + if (m_nCurrentPreset != -1)// && m_nRatingReadProgress >= m_nCurrentPreset) // (can be -1 if dir. changed but no new preset was loaded yet) + for (int i=m_nCurrentPreset; im_nCurrentPreset is out of range! + -soln: when adjusting rating: + 1. file to modify is m_szCurrentPresetFile + 2. only update CDF if m_nCurrentPreset is not -1 + -> set m_nCurrentPreset to -1 whenever dir. changes + -> set m_szCurrentPresetFile whenever you load a preset + */ + + // show a message + if (!m_bShowRating) + { + // see also: DrawText() in milkdropfs.cpp + m_fShowRatingUntilThisTime = GetTime() + 2.0f; + } +} + +void CPlugin::ReadCustomMessages() +{ + int n; + + // First, clear all old data + for (n=0; n 99) + nMsgNum = 99; + + if (nMsgNum < 0) + { + int count=0; + // choose randomly + for (nMsgNum=0; nMsgNum<100; nMsgNum++) + if (m_CustomMessage[nMsgNum].szText[0]) + count++; + + int sel = (warand()%count)+1; + count = 0; + for (nMsgNum=0; nMsgNum<100; nMsgNum++) + { + if (m_CustomMessage[nMsgNum].szText[0]) + count++; + if (count==sel) + break; + } + } + + if (nMsgNum < 0 || + nMsgNum >= MAX_CUSTOM_MESSAGES || + m_CustomMessage[nMsgNum].szText[0]==0) + { + return; + } + + int fontID = m_CustomMessage[nMsgNum].nFont; + + m_supertext.bRedrawSuperText = true; + m_supertext.bIsSongTitle = false; + lstrcpyW(m_supertext.szTextW, m_CustomMessage[nMsgNum].szText); + + // regular properties: + m_supertext.fFontSize = m_CustomMessage[nMsgNum].fSize; + m_supertext.fX = m_CustomMessage[nMsgNum].x + m_CustomMessage[nMsgNum].randx * ((warand()%1037)/1037.0f*2.0f - 1.0f); + m_supertext.fY = m_CustomMessage[nMsgNum].y + m_CustomMessage[nMsgNum].randy * ((warand()%1037)/1037.0f*2.0f - 1.0f); + m_supertext.fGrowth = m_CustomMessage[nMsgNum].growth; + m_supertext.fDuration = m_CustomMessage[nMsgNum].fTime; + m_supertext.fFadeTime = m_CustomMessage[nMsgNum].fFade; + + // overrideables: + if (m_CustomMessage[nMsgNum].bOverrideFace) + lstrcpyW(m_supertext.nFontFace, m_CustomMessage[nMsgNum].szFace); + else + lstrcpyW(m_supertext.nFontFace, m_CustomMessageFont[fontID].szFace); + m_supertext.bItal = (m_CustomMessage[nMsgNum].bOverrideItal) ? (m_CustomMessage[nMsgNum].bItal != 0) : (m_CustomMessageFont[fontID].bItal != 0); + m_supertext.bBold = (m_CustomMessage[nMsgNum].bOverrideBold) ? (m_CustomMessage[nMsgNum].bBold != 0) : (m_CustomMessageFont[fontID].bBold != 0); + m_supertext.nColorR = (m_CustomMessage[nMsgNum].bOverrideColorR) ? m_CustomMessage[nMsgNum].nColorR : m_CustomMessageFont[fontID].nColorR; + m_supertext.nColorG = (m_CustomMessage[nMsgNum].bOverrideColorG) ? m_CustomMessage[nMsgNum].nColorG : m_CustomMessageFont[fontID].nColorG; + m_supertext.nColorB = (m_CustomMessage[nMsgNum].bOverrideColorB) ? m_CustomMessage[nMsgNum].nColorB : m_CustomMessageFont[fontID].nColorB; + + // randomize color + m_supertext.nColorR += (int)(m_CustomMessage[nMsgNum].nRandR * ((warand()%1037)/1037.0f*2.0f - 1.0f)); + m_supertext.nColorG += (int)(m_CustomMessage[nMsgNum].nRandG * ((warand()%1037)/1037.0f*2.0f - 1.0f)); + m_supertext.nColorB += (int)(m_CustomMessage[nMsgNum].nRandB * ((warand()%1037)/1037.0f*2.0f - 1.0f)); + if (m_supertext.nColorR < 0) m_supertext.nColorR = 0; + if (m_supertext.nColorG < 0) m_supertext.nColorG = 0; + if (m_supertext.nColorB < 0) m_supertext.nColorB = 0; + if (m_supertext.nColorR > 255) m_supertext.nColorR = 255; + if (m_supertext.nColorG > 255) m_supertext.nColorG = 255; + if (m_supertext.nColorB > 255) m_supertext.nColorB = 255; + + // fix &'s for display: + /* + { + int pos = 0; + int len = lstrlen(m_supertext.szText); + while (m_supertext.szText[pos] && pos<255) + { + if (m_supertext.szText[pos] == '&') + { + for (int x=len; x>=pos; x--) + m_supertext.szText[x+1] = m_supertext.szText[x]; + len++; + pos++; + } + pos++; + } + }*/ + + m_supertext.fStartTime = GetTime(); +} + +void CPlugin::LaunchSongTitleAnim() +{ + m_supertext.bRedrawSuperText = true; + m_supertext.bIsSongTitle = true; + lstrcpyW(m_supertext.szTextW, m_szSongTitle); + //lstrcpy(m_supertext.szText, " "); + lstrcpyW(m_supertext.nFontFace, m_fontinfo[SONGTITLE_FONT].szFace); + m_supertext.fFontSize = (float)m_fontinfo[SONGTITLE_FONT].nSize; + m_supertext.bBold = m_fontinfo[SONGTITLE_FONT].bBold; + m_supertext.bItal = m_fontinfo[SONGTITLE_FONT].bItalic; + m_supertext.fX = 0.5f; + m_supertext.fY = 0.5f; + m_supertext.fGrowth = 1.0f; + m_supertext.fDuration = m_fSongTitleAnimDuration; + m_supertext.nColorR = 255; + m_supertext.nColorG = 255; + m_supertext.nColorB = 255; + + m_supertext.fStartTime = GetTime(); +} + +bool CPlugin::LaunchSprite(int nSpriteNum, int nSlot) +{ + char initcode[8192], code[8192], sectionA[64]; + char szTemp[8192]; + wchar_t img[512], section[64]; + + initcode[0] = 0; + code[0] = 0; + img[0] = 0; + swprintf(section, L"img%02d", nSpriteNum); + sprintf(sectionA, "img%02d", nSpriteNum); + + // 1. read in image filename + GetPrivateProfileStringW(section, L"img", L"", img, sizeof(img)-1, m_szImgIniFile); + if (img[0] == 0) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_ERROR_COULD_NOT_FIND_IMG_OR_NOT_DEFINED), nSpriteNum); + AddError(buf, 7.0f, ERR_MISC, false); + return false; + } + + if (img[1] != L':')// || img[2] != '\\') + { + // it's not in the form "x:\blah\billy.jpg" so prepend plugin dir path. + wchar_t temp[512]; + wcscpy(temp, img); + swprintf(img, L"%s%s", m_szMilkdrop2Path, temp); + } + + // 2. get color key + //unsigned int ck_lo = (unsigned int)GetPrivateProfileInt(section, "colorkey_lo", 0x00000000, m_szImgIniFile); + //unsigned int ck_hi = (unsigned int)GetPrivateProfileInt(section, "colorkey_hi", 0x00202020, m_szImgIniFile); + // FIRST try 'colorkey_lo' (for backwards compatibility) and then try 'colorkey' + unsigned int ck = (unsigned int)GetPrivateProfileIntW(section, L"colorkey_lo", 0x00000000, m_szImgIniFile/*GetConfigIniFile()*/); + ck = (unsigned int)GetPrivateProfileIntW(section, L"colorkey", ck, m_szImgIniFile/*GetConfigIniFile()*/); + + // 3. read in init code & per-frame code + for (int n=0; n<2; n++) + { + char *pStr = (n==0) ? initcode : code; + char szLineName[32]; + int len; + + int line = 1; + int char_pos = 0; + bool bDone = false; + + while (!bDone) + { + if (n==0) + sprintf(szLineName, "init_%d", line); + else + sprintf(szLineName, "code_%d", line); + + GetPrivateProfileString(sectionA, szLineName, "~!@#$", szTemp, 8192, AutoCharFn(m_szImgIniFile)); // fixme + len = lstrlen(szTemp); + + if ((strcmp(szTemp, "~!@#$")==0) || // if the key was missing, + (len >= 8191-char_pos-1)) // or if we're out of space + { + bDone = true; + } + else + { + sprintf(&pStr[char_pos], "%s%c", szTemp, LINEFEED_CONTROL_CHAR); + } + + char_pos += len + 1; + line++; + } + pStr[char_pos++] = 0; // null-terminate + } + + if (nSlot == -1) + { + // find first empty slot; if none, chuck the oldest sprite & take its slot. + int oldest_index = 0; + int oldest_frame = m_texmgr.m_tex[0].nStartFrame; + for (int x=0; x mysound.avg[i]) + rate = 0.2f; + else + rate = 0.5f; + rate = AdjustRateToFPS(rate, 30.0f, GetFps()); + mysound.avg[i] = mysound.avg[i]*rate + mysound.imm[i]*(1-rate); + + if (GetFrame() < 50) + rate = 0.9f; + else + rate = 0.992f; + rate = AdjustRateToFPS(rate, 30.0f, GetFps()); + mysound.long_avg[i] = mysound.long_avg[i]*rate + mysound.imm[i]*(1-rate); + + + // also get bass/mid/treble levels *relative to the past* + if (fabsf(mysound.long_avg[i]) < 0.001f) + mysound.imm_rel[i] = 1.0f; + else + mysound.imm_rel[i] = mysound.imm[i] / mysound.long_avg[i]; + + if (fabsf(mysound.long_avg[i]) < 0.001f) + mysound.avg_rel[i] = 1.0f; + else + mysound.avg_rel[i] = mysound.avg[i] / mysound.long_avg[i]; + } +} + +void CPlugin::GenWarpPShaderText(char *szShaderText, float decay, bool bWrap) +{ + // find the pixel shader body and replace it with custom code. + + lstrcpy(szShaderText, m_szDefaultWarpPShaderText); + char LF = LINEFEED_CONTROL_CHAR; + char *p = strrchr( szShaderText, '{' ); + if (!p) + return; + p++; + p += sprintf(p, "%c", 1); + + p += sprintf(p, " // sample previous frame%c", LF); + p += sprintf(p, " ret = tex2D( sampler%s_main, uv ).xyz;%c", bWrap ? L"" : L"_fc", LF); + p += sprintf(p, " %c", LF); + p += sprintf(p, " // darken (decay) over time%c", LF); + p += sprintf(p, " ret *= %.2f; //or try: ret -= 0.004;%c", decay, LF); + //p += sprintf(p, " %c", LF); + //p += sprintf(p, " ret.w = vDiffuse.w; // pass alpha along - req'd for preset blending%c", LF); + p += sprintf(p, "}%c", LF); +} + +void CPlugin::GenCompPShaderText(char *szShaderText, float brightness, float ve_alpha, float ve_zoom, int ve_orient, float hue_shader, bool bBrighten, bool bDarken, bool bSolarize, bool bInvert) +{ + // find the pixel shader body and replace it with custom code. + + lstrcpy(szShaderText, m_szDefaultCompPShaderText); + char LF = LINEFEED_CONTROL_CHAR; + char *p = strrchr( szShaderText, '{' ); + if (!p) + return; + p++; + p += sprintf(p, "%c", 1); + + if (ve_alpha > 0.001f) + { + int orient_x = (ve_orient % 2) ? -1 : 1; + int orient_y = (ve_orient >= 2) ? -1 : 1; + p += sprintf(p, " float2 uv_echo = (uv - 0.5)*%.3f*float2(%d,%d) + 0.5;%c", 1.0f/ve_zoom, orient_x, orient_y, LF); + p += sprintf(p, " ret = lerp( tex2D(sampler_main, uv).xyz, %c", LF); + p += sprintf(p, " tex2D(sampler_main, uv_echo).xyz, %c", LF); + p += sprintf(p, " %.2f %c", ve_alpha, LF); + p += sprintf(p, " ); //video echo%c", LF); + p += sprintf(p, " ret *= %.2f; //gamma%c", brightness, LF); + } + else + { + p += sprintf(p, " ret = tex2D(sampler_main, uv).xyz;%c", LF); + p += sprintf(p, " ret *= %.2f; //gamma%c", brightness, LF); + } + if (hue_shader >= 1.0f) + p += sprintf(p, " ret *= hue_shader; //old hue shader effect%c", LF); + else if (hue_shader > 0.001f) + p += sprintf(p, " ret *= %.2f + %.2f*hue_shader; //old hue shader effect%c", 1-hue_shader, hue_shader, LF); + + if (bBrighten) + p += sprintf(p, " ret = sqrt(ret); //brighten%c", LF); + if (bDarken) + p += sprintf(p, " ret *= ret; //darken%c", LF); + if (bSolarize) + p += sprintf(p, " ret = ret*(1-ret)*4; //solarize%c", LF); + if (bInvert) + p += sprintf(p, " ret = 1 - ret; //invert%c", LF); + //p += sprintf(p, " ret.w = vDiffuse.w; // pass alpha along - req'd for preset blending%c", LF); + p += sprintf(p, "}%c", LF); +} \ No newline at end of file diff --git a/vis_milk2/plugin.dsp b/vis_milk2/plugin.dsp new file mode 100644 index 0000000..e8ed2a9 --- /dev/null +++ b/vis_milk2/plugin.dsp @@ -0,0 +1,304 @@ +# Microsoft Developer Studio Project File - Name="plugin" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=plugin - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "plugin.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "plugin.mak" CFG="plugin - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "plugin - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "plugin - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "plugin - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "plugin_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\SDKs\DirectX_9_Oct_2004\Include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib d3dx9.lib d3d9.lib Delayimp.lib /nologo /dll /machine:I386 /out:"c:\program files\winamp\plugins\vis_milk2.dll" /libpath:"..\SDKs\DirectX_9_Oct_2004\lib" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "plugin - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLUGIN_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\SDKs\DirectX_9_Oct_2004\Include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib d3dx9.lib d3d9.lib delayimp.lib /nologo /dll /debug /machine:I386 /out:"c:\program files\winamp\plugins\vis_milk2.dll" /pdbtype:sept /libpath:"..\SDKs\DirectX_9_Oct_2004\lib" + +!ENDIF + +# Begin Target + +# Name "plugin - Win32 Release" +# Name "plugin - Win32 Debug" +# Begin Group "My Plugin Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\menu.cpp +# End Source File +# Begin Source File + +SOURCE=.\milkdropfs.cpp +# End Source File +# Begin Source File + +SOURCE=.\plugin.cpp +# End Source File +# Begin Source File + +SOURCE=.\plugin_icon.ico +# End Source File +# Begin Source File + +SOURCE=.\state.cpp +# End Source File +# Begin Source File + +SOURCE=.\support.cpp +# End Source File +# Begin Source File + +SOURCE=.\texmgr.cpp +# End Source File +# Begin Source File + +SOURCE=.\textmgr.cpp +# End Source File +# End Group +# Begin Group "My Plugin Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\defines.h +# End Source File +# Begin Source File + +SOURCE=.\md_defines.h +# End Source File +# Begin Source File + +SOURCE=.\menu.h +# End Source File +# Begin Source File + +SOURCE=.\plugin.h +# End Source File +# Begin Source File + +SOURCE=.\state.h +# End Source File +# Begin Source File + +SOURCE=.\support.h +# End Source File +# Begin Source File + +SOURCE=.\texmgr.h +# End Source File +# Begin Source File + +SOURCE=.\textmgr.h +# End Source File +# End Group +# Begin Group "Framework Files (do not edit)" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\config.cpp +# End Source File +# Begin Source File + +SOURCE=.\config2.cpp +# End Source File +# Begin Source File + +SOURCE=.\desktop_mode.cpp +# End Source File +# Begin Source File + +SOURCE=.\dxcontext.cpp +# End Source File +# Begin Source File + +SOURCE=.\dxcontext.h +# End Source File +# Begin Source File + +SOURCE=.\fft.cpp +# End Source File +# Begin Source File + +SOURCE=.\fft.h +# End Source File +# Begin Source File + +SOURCE=.\gstring.h +# End Source File +# Begin Source File + +SOURCE=.\icon_t.h +# End Source File +# Begin Source File + +SOURCE=.\plugin.rc +# End Source File +# Begin Source File + +SOURCE=.\pluginshell.cpp +# End Source File +# Begin Source File + +SOURCE=.\pluginshell.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\shell_defines.h +# End Source File +# Begin Source File + +SOURCE=.\utility.cpp +# End Source File +# Begin Source File + +SOURCE=.\utility.h +# End Source File +# Begin Source File + +SOURCE=.\vis.cpp +# End Source File +# Begin Source File + +SOURCE=.\vis.h +# End Source File +# End Group +# Begin Group "evallib" + +# PROP Default_Filter "*.c;*.h" +# Begin Source File + +SOURCE=.\evallib\CAL_TAB.C +# End Source File +# Begin Source File + +SOURCE=.\evallib\cal_tab.h +# End Source File +# Begin Source File + +SOURCE=.\evallib\cfunc.c +# End Source File +# Begin Source File + +SOURCE=.\evallib\Compiler.c +# End Source File +# Begin Source File + +SOURCE=.\evallib\Compiler.h +# End Source File +# Begin Source File + +SOURCE=.\evallib\eval.c +# End Source File +# Begin Source File + +SOURCE=.\evallib\eval.h +# End Source File +# Begin Source File + +SOURCE=.\evallib\Gettok.c +# End Source File +# Begin Source File + +SOURCE=.\evallib\LEX.H +# End Source File +# Begin Source File + +SOURCE=.\evallib\Lextab.c +# End Source File +# Begin Source File + +SOURCE=.\evallib\LLSAVE.C +# End Source File +# Begin Source File + +SOURCE=.\evallib\Yylex.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\DOCUMENTATION.TXT +# End Source File +# Begin Source File + +SOURCE=.\milkdrop.nsi +# End Source File +# Begin Source File + +SOURCE=.\temp.ico +# End Source File +# End Target +# End Project diff --git a/vis_milk2/plugin.h b/vis_milk2/plugin.h new file mode 100644 index 0000000..45fe854 --- /dev/null +++ b/vis_milk2/plugin.h @@ -0,0 +1,729 @@ +/* + 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. +*/ + +#ifndef __NULLSOFT_DX9_EXAMPLE_PLUGIN_H__ +#define __NULLSOFT_DX9_EXAMPLE_PLUGIN_H__ 1 + +#include "pluginshell.h" +#include "md_defines.h" +#include "menu.h" +#include "support.h" +#include "texmgr.h" +#include "state.h" +#include "../nu/Vector.h" + +#include "gstring.h" +#include "../ns-eel2/ns-eel.h" + + + +extern "C" int (*warand)(void); + +typedef enum { TEX_DISK, TEX_VS, TEX_BLUR0, TEX_BLUR1, TEX_BLUR2, TEX_BLUR3, TEX_BLUR4, TEX_BLUR5, TEX_BLUR6, TEX_BLUR_LAST } tex_code; +typedef enum { UI_REGULAR, UI_MENU, UI_LOAD, UI_LOAD_DEL, UI_LOAD_RENAME, UI_SAVEAS, UI_SAVE_OVERWRITE, UI_EDIT_MENU_STRING, UI_CHANGEDIR, UI_IMPORT_WAVE, UI_EXPORT_WAVE, UI_IMPORT_SHAPE, UI_EXPORT_SHAPE, UI_UPGRADE_PIXEL_SHADER, UI_MASHUP } ui_mode; +typedef struct { float rad; float ang; float a; float c; } td_vertinfo; // blending: mix = max(0,min(1,a*t + c)); +typedef char* CHARPTR; +LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +#define MY_FFT_SAMPLES 512 // for old [pre-vms] milkdrop sound analysis +typedef struct +{ + float imm[3]; // bass, mids, treble (absolute) + float imm_rel[3]; // bass, mids, treble (relative to song; 1=avg, 0.9~below, 1.1~above) + float avg[3]; // bass, mids, treble (absolute) + float avg_rel[3]; // bass, mids, treble (relative to song; 1=avg, 0.9~below, 1.1~above) + float long_avg[3]; // bass, mids, treble (absolute) + float fWave[2][576]; + float fSpecLeft[MY_FFT_SAMPLES]; +} td_mysounddata; + +typedef struct +{ + int bActive; + int bFilterBadChars; // if true, it will filter out any characters that don't belong in a filename, plus the & symbol (because it doesn't display properly with DrawText) + int bDisplayAsCode; // if true, semicolons will be followed by a newline, for display + int nMaxLen; // can't be more than 511 + int nCursorPos; + int nSelAnchorPos; // -1 if no selection made + int bOvertypeMode; + wchar_t szText[48000]; + wchar_t szPrompt[512]; + wchar_t szToolTip[512]; + char szClipboard[48000]; + wchar_t szClipboardW[48000]; +} td_waitstr; + +typedef struct +{ + int bBold; + int bItal; + wchar_t szFace[128]; + int nColorR; // 0..255 + int nColorG; // 0..255 + int nColorB; // 0..255 +} +td_custom_msg_font; + +enum +{ + MD2_PS_NONE = 0, + MD2_PS_2_0 = 2, + MD2_PS_2_X = 3, + MD2_PS_3_0 = 4, + MD2_PS_4_0 = 5, // not supported by milkdrop +}; +/* +typedef struct +{ + char szFace[256]; + int nSize; + int bBold; + int bItalic; +} td_titlefontinfo;*/ + +typedef struct +{ + int nFont; + float fSize; // 0..100 + float x; + float y; + float randx; + float randy; + float growth; + float fTime; // total time to display the message, in seconds + float fFade; // % (0..1) of the time that is spent fading in + + // overrides + int bOverrideBold; + int bOverrideItal; + int bOverrideFace; + int bOverrideColorR; + int bOverrideColorG; + int bOverrideColorB; + int nColorR; // 0..255 + int nColorG; // 0..255 + int nColorB; // 0..255 + int nRandR; + int nRandG; + int nRandB; + int bBold; + int bItal; + wchar_t szFace[128]; + + wchar_t szText[256]; +} +td_custom_msg; + +typedef struct +{ + int bRedrawSuperText; // true if it needs redraw + int bIsSongTitle; // false for custom message, true for song title + //char szText[256]; + wchar_t szTextW[256]; + wchar_t nFontFace[128]; + int bBold; + int bItal; + float fX; + float fY; + float fFontSize; // [0..100] for custom messages, [0..4] for song titles + float fGrowth; // applies to custom messages only + int nFontSizeUsed; // height IN PIXELS + float fStartTime; + float fDuration; + float fFadeTime; // applies to custom messages only; song title fade times are handled specially + int nColorR; + int nColorG; + int nColorB; +} +td_supertext; + +typedef struct +{ + wchar_t texname[256]; // ~filename, but without path or extension! + LPDIRECT3DBASETEXTURE9 texptr; + int w,h,d; + //D3DXHANDLE texsize_param; + bool bEvictable; + int nAge; // only valid if bEvictable is true + int nSizeInBytes; // only valid if bEvictable is true +} TexInfo; + +typedef struct +{ + GString texname; // just for ref + D3DXHANDLE texsize_param; + int w,h; +} TexSizeParamInfo; + +typedef struct +{ + LPDIRECT3DBASETEXTURE9 texptr; + bool bBilinear; + bool bWrap; +} SamplerInfo; + +typedef struct +{ + GString msg; + bool bBold; // true == red bkg; false == black bkg + float birthTime; + float expireTime; + int category; +} ErrorMsg; +typedef Vector ErrorMsgList; + +typedef Vector CShaderParamsList; + +class CShaderParams +{ +public: + // float4 handles: + D3DXHANDLE rand_frame ; + D3DXHANDLE rand_preset; + D3DXHANDLE const_handles[24]; + D3DXHANDLE q_const_handles[(NUM_Q_VAR+3)/4]; + D3DXHANDLE rot_mat[24]; + + typedef Vector TexSizeParamInfoList; + TexSizeParamInfoList texsize_params; + + // sampler stages for various PS texture bindings: + //int texbind_vs; + //int texbind_disk[32]; + //int texbind_voronoi; + //... + SamplerInfo m_texture_bindings[16]; // an entry for each sampler slot. These are ALIASES - DO NOT DELETE. + tex_code m_texcode[16]; // if ==TEX_VS, forget the pointer - texture bound @ that stage is the double-buffered VS. + + void Clear(); + void CacheParams(LPD3DXCONSTANTTABLE pCT, bool bHardErrors); + void OnTextureEvict(LPDIRECT3DBASETEXTURE9 texptr); + CShaderParams(); + ~CShaderParams(); +}; + +class VShaderInfo +{ +public: + IDirect3DVertexShader9* ptr; + LPD3DXCONSTANTTABLE CT; + CShaderParams params; + VShaderInfo() { ptr=NULL; CT=NULL; params.Clear(); } + ~VShaderInfo() { Clear(); } + void Clear(); +}; + +class PShaderInfo +{ +public: + IDirect3DPixelShader9* ptr; + LPD3DXCONSTANTTABLE CT; + CShaderParams params; + PShaderInfo() { ptr=NULL; CT=NULL; params.Clear(); } + ~PShaderInfo() { Clear(); } + void Clear(); +}; + +typedef struct +{ + VShaderInfo vs; + PShaderInfo ps; +} ShaderPairInfo; + +typedef struct +{ + PShaderInfo warp; + PShaderInfo comp; +} PShaderSet; + +typedef struct +{ + VShaderInfo warp; + VShaderInfo comp; +} VShaderSet; + +/* +typedef struct +{ + void* ptr; // to IDirect3DPixelShader9 or IDirect3DVertexShader9 + LPD3DXCONSTANTTABLE CT; + CShaderParams params; +} ShaderInfo; + +typedef struct +{ + ShaderInfo warp; + ShaderInfo comp; +} ShaderSet; +*/ + +typedef struct +{ + GString szFilename; // without path + float fRatingThis; + float fRatingCum; +} PresetInfo; +typedef Vector PresetList; + + +class CPlugin : public CPluginShell +{ +public: + + //====[ 1. members added to create this specific example plugin: ]================================================ + + /// CONFIG PANEL SETTINGS THAT WE'VE ADDED (TAB #2) + bool m_bFirstRun; + float m_fBlendTimeAuto; // blend time when preset auto-switches + float m_fBlendTimeUser; // blend time when user loads a new preset + float m_fTimeBetweenPresets; // <- this is in addition to m_fBlendTimeAuto + float m_fTimeBetweenPresetsRand; // <- this is in addition to m_fTimeBetweenPresets + bool m_bSequentialPresetOrder; + bool m_bHardCutsDisabled; + float m_fHardCutLoudnessThresh; + float m_fHardCutHalflife; + float m_fHardCutThresh; + //int m_nWidth; + //int m_nHeight; + //int m_nDispBits; + int m_nCanvasStretch; // 0=Auto, 100=None, 125 = 1.25X, 133, 150, 167, 200, 300, 400 (4X). + int m_nTexSizeX; // -1 = exact match to screen; -2 = nearest power of 2. + int m_nTexSizeY; + float m_fAspectX; + float m_fAspectY; + float m_fInvAspectX; + float m_fInvAspectY; + int m_nTexBitsPerCh; + int m_nGridX; + int m_nGridY; + + bool m_bShowPressF1ForHelp; + //char m_szMonitorName[256]; + bool m_bShowMenuToolTips; + int m_n16BitGamma; + bool m_bAutoGamma; + //int m_nFpsLimit; + //int m_cLeftEye3DColor[3]; + //int m_cRightEye3DColor[3]; + bool m_bEnableRating; + //bool m_bInstaScan; + bool m_bSongTitleAnims; + float m_fSongTitleAnimDuration; + float m_fTimeBetweenRandomSongTitles; + float m_fTimeBetweenRandomCustomMsgs; + int m_nSongTitlesSpawned; + int m_nCustMsgsSpawned; + + //bool m_bAlways3D; + //float m_fStereoSep; + //bool m_bAlwaysOnTop; + //bool m_bFixSlowText; + //bool m_bWarningsDisabled; // messageboxes + bool m_bWarningsDisabled2; // warnings/errors in upper-right corner (m_szUserMessage) + //bool m_bAnisotropicFiltering; + bool m_bPresetLockOnAtStartup; + bool m_bPreventScollLockHandling; + int m_nMaxPSVersion_ConfigPanel; // -1 = auto, 0 = disable shaders, 2 = ps_2_0, 3 = ps_3_0 + int m_nMaxPSVersion_DX9; // 0 = no shader support, 2 = ps_2_0, 3 = ps_3_0 + int m_nMaxPSVersion; // this one will be the ~min of the other two. 0/2/3. + int m_nMaxImages; + int m_nMaxBytes; + + /* + char m_szFontFace[NUM_FONTS][128]; + int m_nFontSize[NUM_FONTS]; + bool m_bFontBold[NUM_FONTS]; + bool m_bFontItalic[NUM_FONTS]; + char m_szTitleFontFace[128]; + int m_nTitleFontSize; // percentage of screen width (0..100) + bool m_bTitleFontBold; + bool m_bTitleFontItalic; + */ + HFONT m_gdi_title_font_doublesize; + LPD3DXFONT m_d3dx_title_font_doublesize; + + // PIXEL SHADERS + DWORD m_dwShaderFlags; // Shader compilation/linking flags + //ID3DXFragmentLinker* m_pFragmentLinker; // Fragment linker interface + //LPD3DXBUFFER m_pCompiledFragments; // Buffer containing compiled fragments + LPD3DXBUFFER m_pShaderCompileErrors; + VShaderSet m_fallbackShaders_vs; // *these are the only vertex shaders used for the whole app.* + PShaderSet m_fallbackShaders_ps; // these are just used when the preset's pixel shaders fail to compile. + PShaderSet m_shaders; // includes shader pointers and constant tables for warp & comp shaders, for cur. preset + PShaderSet m_OldShaders; // includes shader pointers and constant tables for warp & comp shaders, for prev. preset + PShaderSet m_NewShaders; // includes shader pointers and constant tables for warp & comp shaders, for coming preset + ShaderPairInfo m_BlurShaders[2]; + bool m_bWarpShaderLock; + bool m_bCompShaderLock; + //bool LoadShaderFromFile( char* szFile, char* szFn, char* szProfile, + // LPD3DXCONSTANTTABLE* ppConstTable, void** ppShader ); + #define SHADER_WARP 0 + #define SHADER_COMP 1 + #define SHADER_BLUR 2 + #define SHADER_OTHER 3 + bool LoadShaderFromMemory( const char* szShaderText, char* szFn, char* szProfile, + LPD3DXCONSTANTTABLE* ppConstTable, void** ppShader, int shaderType, bool bHardErrors ); + bool RecompileVShader(const char* szShadersText, VShaderInfo *si, int shaderType, bool bHardErrors); + bool RecompilePShader(const char* szShadersText, PShaderInfo *si, int shaderType, bool bHardErrors, int PSVersion); + bool EvictSomeTexture(); + typedef Vector TexInfoList; + TexInfoList m_textures; + bool m_bNeedRescanTexturesDir; + // vertex declarations: + IDirect3DVertexDeclaration9* m_pSpriteVertDecl; + IDirect3DVertexDeclaration9* m_pWfVertDecl; + IDirect3DVertexDeclaration9* m_pMyVertDecl; + + D3DXVECTOR4 m_rand_frame; // 4 random floats (0..1); randomized once per frame; fed to pixel shaders. + + // RUNTIME SETTINGS THAT WE'VE ADDED + float m_prev_time; + bool m_bTexSizeWasAutoPow2; + bool m_bTexSizeWasAutoExact; + bool m_bPresetLockedByUser; + bool m_bPresetLockedByCode; + float m_fAnimTime; + float m_fStartTime; + float m_fPresetStartTime; + float m_fNextPresetTime; + float m_fSnapPoint; + CState *m_pState; // points to current CState + CState *m_pOldState; // points to previous CState + CState *m_pNewState; // points to the coming CState - we're not yet blending to it b/c we're still compiling the shaders for it! + int m_nLoadingPreset; + wchar_t m_szLoadingPreset[MAX_PATH]; + float m_fLoadingPresetBlendTime; + int m_nPresetsLoadedTotal; //important for texture eviction age-tracking... + CState m_state_DO_NOT_USE[3]; // do not use; use pState and pOldState instead. + ui_mode m_UI_mode; // can be UI_REGULAR, UI_LOAD, UI_SAVEHOW, or UI_SAVEAS + + #define MASH_SLOTS 5 + #define MASH_APPLY_DELAY_FRAMES 1 + int m_nMashSlot; //0..MASH_SLOTS-1 + //char m_szMashDir[MASH_SLOTS][MAX_PATH]; + int m_nMashPreset[MASH_SLOTS]; + int m_nLastMashChangeFrame[MASH_SLOTS]; + + //td_playlist_entry *m_szPlaylist; // array of 128-char strings + //int m_nPlaylistCurPos; + //int m_nPlaylistLength; + //int m_nTrackPlaying; + //int m_nSongPosMS; + //int m_nSongLenMS; + bool m_bUserPagedUp; + bool m_bUserPagedDown; + float m_fMotionVectorsTempDx; + float m_fMotionVectorsTempDy; + + td_waitstr m_waitstring; + void WaitString_NukeSelection(); + void WaitString_Cut(); + void WaitString_Copy(); + void WaitString_Paste(); + void WaitString_SeekLeftWord(); + void WaitString_SeekRightWord(); + int WaitString_GetCursorColumn(); + int WaitString_GetLineLength(); + void WaitString_SeekUpOneLine(); + void WaitString_SeekDownOneLine(); + + int m_nPresets; // the # of entries in the file listing. Includes directories and then files, sorted alphabetically. + int m_nDirs; // the # of presets that are actually directories. Always between 0 and m_nPresets. + int m_nPresetListCurPos;// Index of the currently-HIGHLIGHTED preset (the user must press Enter on it to select it). + int m_nCurrentPreset; // Index of the currently-RUNNING preset. + // Note that this is NOT the same as the currently-highlighted preset! (that's m_nPresetListCurPos) + // Be careful - this can be -1 if the user changed dir. & a new preset hasn't been loaded yet. + wchar_t m_szCurrentPresetFile[512]; // w/o path. this is always valid (unless no presets were found) + PresetList m_presets; + void UpdatePresetList(bool bBackground=false, bool bForce=false, bool bTryReselectCurrentPreset=true); + wchar_t m_szUpdatePresetMask[MAX_PATH]; + bool m_bPresetListReady; + //void UpdatePresetRatings(); + //int m_nRatingReadProgress; // equals 'm_nPresets' if all ratings are read in & ready to go; -1 if uninitialized; otherwise, it's still reading them in, and range is: [0 .. m_nPresets-1] + bool m_bInitialPresetSelected; + + // PRESET HISTORY + #define PRESET_HIST_LEN (64+2) // make this 2 more than the # you REALLY want to be able to go back. + GString m_presetHistory[PRESET_HIST_LEN]; //circular + int m_presetHistoryPos; + int m_presetHistoryBackFence; + int m_presetHistoryFwdFence; + void PrevPreset(float fBlendTime); + void NextPreset(float fBlendTime); // if not retracing our former steps, it will choose a random one. + void OnFinishedLoadingPreset(); + + FFT myfft; + td_mysounddata mysound; + + // stuff for displaying text to user: + //int m_nTextHeightPixels; // this is for the menu/detail font; NOT the "fancy font" + //int m_nTextHeightPixels_Fancy; + bool m_bShowFPS; + bool m_bShowRating; + bool m_bShowPresetInfo; + bool m_bShowDebugInfo; + bool m_bShowSongTitle; + bool m_bShowSongTime; + bool m_bShowSongLen; + float m_fShowRatingUntilThisTime; + //float m_fShowUserMessageUntilThisTime; + //char m_szUserMessage[512]; + //bool m_bUserMessageIsError; + + #define ERR_ALL 0 + #define ERR_INIT 1 //specifically, loading a preset + #define ERR_PRESET 2 //specifically, loading a preset + #define ERR_MISC 3 + #define ERR_NOTIFY 4 // a simple notification - not an error at all. ("shuffle is now ON." etc.) + // NOTE: each NOTIFY msg clears all the old NOTIFY messages! + #define ERR_SCANNING_PRESETS 5 + ErrorMsgList m_errors; + void AddError(wchar_t* szMsg, float fDuration, int category=ERR_ALL, bool bBold=true); + void ClearErrors(int category=ERR_ALL); // 0=all categories + + char m_szDebugMessage[512]; + wchar_t m_szSongTitle [512]; + wchar_t m_szSongTitlePrev[512]; + //HFONT m_hfont[3]; // 0=fancy font (for song titles, preset name) + // 1=legible font (the main font) + // 2=tooltip font (for tooltips in the menu system) + //HFONT m_htitlefont[NUM_TITLE_FONTS]; // ~25 different sizes + // stuff for menu system: + CMilkMenu *m_pCurMenu; // should always be valid! + CMilkMenu m_menuPreset; + CMilkMenu m_menuWave; + CMilkMenu m_menuAugment; + CMilkMenu m_menuCustomWave; + CMilkMenu m_menuCustomShape; + CMilkMenu m_menuMotion; + CMilkMenu m_menuPost; + CMilkMenu m_menuWavecode[MAX_CUSTOM_WAVES]; + CMilkMenu m_menuShapecode[MAX_CUSTOM_SHAPES]; + bool m_bShowShaderHelp; + + + + wchar_t m_szMilkdrop2Path[MAX_PATH]; // ends in a backslash + wchar_t m_szMsgIniFile[MAX_PATH]; + wchar_t m_szImgIniFile[MAX_PATH]; + wchar_t m_szPresetDir[MAX_PATH]; + float m_fRandStart[4]; + + // DIRECTX 9: + IDirect3DTexture9 *m_lpVS[2]; + #define NUM_BLUR_TEX 6 + #if (NUM_BLUR_TEX>0) + IDirect3DTexture9 *m_lpBlur[NUM_BLUR_TEX]; // each is successively 1/2 size of prev. + int m_nBlurTexW[NUM_BLUR_TEX]; + int m_nBlurTexH[NUM_BLUR_TEX]; + #endif + int m_nHighestBlurTexUsedThisFrame; + IDirect3DTexture9 *m_lpDDSTitle; // CAREFUL: MIGHT BE NULL (if not enough mem)! + int m_nTitleTexSizeX, m_nTitleTexSizeY; + MYVERTEX *m_verts; + MYVERTEX *m_verts_temp; + td_vertinfo *m_vertinfo; + int *m_indices_strip; + int *m_indices_list; + + // for final composite grid: + #define FCGSX 32 // final composite gridsize - # verts - should be EVEN. + #define FCGSY 24 // final composite gridsize - # verts - should be EVEN. + // # of grid *cells* is two less, + // since we have redundant verts along the center line in X and Y (...for clean 'ang' interp) + MYVERTEX m_comp_verts[FCGSX*FCGSY]; + int m_comp_indices[(FCGSX-2)*(FCGSY-2)*2*3]; + + bool m_bMMX; + //bool m_bSSE; + bool m_bHasFocus; + bool m_bHadFocus; + bool m_bOrigScrollLockState; + //bool m_bMilkdropScrollLockState; // saved when focus is lost; restored when focus is regained + + int m_nNumericInputMode; // NUMERIC_INPUT_MODE_CUST_MSG, NUMERIC_INPUT_MODE_SPRITE + int m_nNumericInputNum; + int m_nNumericInputDigits; + td_custom_msg_font m_CustomMessageFont[MAX_CUSTOM_MESSAGE_FONTS]; + td_custom_msg m_CustomMessage[MAX_CUSTOM_MESSAGES]; + + texmgr m_texmgr; // for user sprites + + td_supertext m_supertext; // **contains info about current Song Title or Custom Message.** + + IDirect3DTexture9 *m_tracer_tex; + + int m_nFramesSinceResize; + + char m_szShaderIncludeText[32768]; // note: this still has char 13's and 10's in it - it's never edited on screen or loaded/saved with a preset. + int m_nShaderIncludeTextLen; // # of chars, not including the final NULL. + char m_szDefaultWarpVShaderText[32768]; // THIS HAS CHAR 13/10 CONVERTED TO LINEFEED_CONTROL_CHAR + char m_szDefaultWarpPShaderText[32768]; // THIS HAS CHAR 13/10 CONVERTED TO LINEFEED_CONTROL_CHAR + char m_szDefaultCompVShaderText[32768]; // THIS HAS CHAR 13/10 CONVERTED TO LINEFEED_CONTROL_CHAR + char m_szDefaultCompPShaderText[32768]; // THIS HAS CHAR 13/10 CONVERTED TO LINEFEED_CONTROL_CHAR + char m_szBlurVS[32768]; + char m_szBlurPSX[32768]; + char m_szBlurPSY[32768]; + //const char* GetDefaultWarpShadersText() { return m_szDefaultWarpShaderText; } + //const char* GetDefaultCompShadersText() { return m_szDefaultCompShaderText; } + void GenWarpPShaderText(char *szShaderText, float decay, bool bWrap); + void GenCompPShaderText(char *szShaderText, float brightness, float ve_alpha, float ve_zoom, int ve_orient, float hue_shader, bool bBrighten, bool bDarken, bool bSolarize, bool bInvert); + + //====[ 2. methods added: ]===================================================================================== + + void RefreshTab2(HWND hwnd); + void RenderFrame(int bRedraw); + void AlignWave(int nSamples); + + void DrawTooltip(wchar_t* str, int xR, int yB); + void RandomizeBlendPattern(); + void GenPlasma(int x0, int x1, int y0, int y1, float dt); + void LoadPerFrameEvallibVars(CState* pState); + void LoadCustomWavePerFrameEvallibVars(CState* pState, int i); + void LoadCustomShapePerFrameEvallibVars(CState* pState, int i, int instance); + void WriteRealtimeConfig(); // called on Finish() + void dumpmsg(wchar_t *s); + void Randomize(); + void LoadRandomPreset(float fBlendTime); + void LoadPreset(const wchar_t *szPresetFilename, float fBlendTime); + void LoadPresetTick(); + void FindValidPresetDir(); + //char* GetConfigIniFile() { return m_szConfigIniFile; }; + wchar_t* GetMsgIniFile() { return m_szMsgIniFile; }; + wchar_t* GetPresetDir() { return m_szPresetDir; }; + void SavePresetAs(wchar_t *szNewFile); // overwrites the file if it was already there. + void DeletePresetFile(wchar_t *szDelFile); + void RenamePresetFile(wchar_t *szOldFile, wchar_t *szNewFile); + void SetCurrentPresetRating(float fNewRating); + void SeekToPreset(wchar_t cStartChar); + bool ReversePropagatePoint(float fx, float fy, float *fx2, float *fy2); + int HandleRegularKey(WPARAM wParam); + bool OnResizeGraphicsWindow(); + bool OnResizeTextWindow(); + //bool InitFont(); + //void ToggleControlWindow(); // for Desktop Mode only + //void DrawUI(); + void ClearGraphicsWindow(); // for windowed mode only + //bool Update_Overlay(); + //void UpdatePlaylist(); + void LaunchCustomMessage(int nMsgNum); + void ReadCustomMessages(); + void LaunchSongTitleAnim(); + + bool RenderStringToTitleTexture(); + void ShowSongTitleAnim(/*IDirect3DTexture9* lpRenderTarget,*/ int w, int h, float fProgress); + void DrawWave(float *fL, float *fR); + void DrawCustomWaves(); + void DrawCustomShapes(); + void DrawSprites(); + void ComputeGridAlphaValues(); + //void WarpedBlit(); + // note: 'bFlipAlpha' just flips the alpha blending in fixed-fn pipeline - not the values for culling tiles. + void WarpedBlit_Shaders (int nPass, bool bAlphaBlend, bool bFlipAlpha, bool bCullTiles, bool bFlipCulling); + void WarpedBlit_NoShaders(int nPass, bool bAlphaBlend, bool bFlipAlpha, bool bCullTiles, bool bFlipCulling); + void ShowToUser_Shaders (int nPass, bool bAlphaBlend, bool bFlipAlpha, bool bCullTiles, bool bFlipCulling); + void ShowToUser_NoShaders(); + void BlurPasses(); + void GetSafeBlurMinMax(CState* pState, float* blur_min, float* blur_max); + void RunPerFrameEquations(int code); + void DrawUserSprites(); + void MergeSortPresets(int left, int right); + void BuildMenus(); + void SetMenusForPresetVersion(int WarpPSVersion, int CompPSVersion); + //void ResetWindowSizeOnDisk(); + bool LaunchSprite(int nSpriteNum, int nSlot); + void KillSprite(int iSlot); + void DoCustomSoundAnalysis(); + void DrawMotionVectors(); + + bool LoadShaders(PShaderSet* sh, CState* pState, bool bTick); + void UvToMathSpace(float u, float v, float* rad, float* ang); + void ApplyShaderParams(CShaderParams* p, LPD3DXCONSTANTTABLE pCT, CState* pState); + void RestoreShaderParams(); + bool AddNoiseTex(const wchar_t* szTexName, int size, int zoom_factor); + bool AddNoiseVol(const wchar_t* szTexName, int size, int zoom_factor); + + + //====[ 3. virtual functions: ]=========================================================================== + + virtual void OverrideDefaults(); + virtual void MyPreInitialize(); + virtual void MyReadConfig(); + virtual void MyWriteConfig(); + virtual int AllocateMyNonDx9Stuff(); + virtual void CleanUpMyNonDx9Stuff(); + virtual int AllocateMyDX9Stuff(); + virtual void CleanUpMyDX9Stuff(int final_cleanup); + virtual void MyRenderFn(int redraw); + virtual void MyRenderUI(int *upper_left_corner_y, int *upper_right_corner_y, int *lower_left_corner_y, int *lower_right_corner_y, int xL, int xR); + virtual LRESULT MyWindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam); + virtual BOOL MyConfigTabProc(int nPage, HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + virtual void OnAltK(); + + //====[ 4. methods from base class: ]=========================================================================== + /* + // 'GET' METHODS + // ------------------------------------------------------------ + int GetFrame(); // returns current frame # (starts at zero) + float GetTime(); // returns current animation time (in seconds) (starts at zero) (updated once per frame) + float GetFps(); // returns current estimate of framerate (frames per second) + eScrMode GetScreenMode(); // returns WINDOWED, FULLSCREEN, FAKE_FULLSCREEN, or NOT_YET_KNOWN (if called before or during OverrideDefaults()). + HWND GetWinampWindow(); // returns handle to Winamp main window + HINSTANCE GetInstance(); // returns handle to the plugin DLL module; used for things like loading resources (dialogs, bitmaps, icons...) that are built into the plugin. + char* GetPluginsDirPath(); // usually returns 'c:\\program files\\winamp\\plugins\\' + char* GetConfigIniFile(); // usually returns 'c:\\program files\\winamp\\plugins\\something.ini' - filename is determined from identifiers in 'defines.h' + + // GET METHODS THAT ONLY WORK ONCE DIRECTX IS READY + // ------------------------------------------------------------ + // The following 'Get' methods are only available after DirectX has been initialized. + // If you call these from OverrideDefaults, MyPreInitialize, or MyReadConfig, + // they will fail and return NULL (zero). + // ------------------------------------------------------------ + HWND GetPluginWindow(); // returns handle to the plugin window. NOT persistent; can change. + int GetWidth(); // returns width of plugin window interior, in pixels. + int GetHeight(); // returns height of plugin window interior, in pixels. + D3DFORMAT GetBackBufFormat(); // returns the pixelformat of the back buffer (probably D3DFMT_R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5, D3DFMT_A4R4G4B4, D3DFMT_R3G3B2, D3DFMT_A8R3G3B2, D3DFMT_X4R4G4B4, or D3DFMT_UNKNOWN) + D3DFORMAT GetBackBufZFormat(); // returns the pixelformat of the back buffer's Z buffer (probably D3DFMT_D16_LOCKABLE, D3DFMT_D32, D3DFMT_D15S1, D3DFMT_D24S8, D3DFMT_D16, D3DFMT_D24X8, D3DFMT_D24X4S4, or D3DFMT_UNKNOWN) + D3DCAPS8* GetCaps(); // returns a pointer to the D3DCAPS8 structer for the device. NOT persistent; can change. + LPDIRECT3DDEVICE8 GetDevice(); // returns a pointer to the DirectX 8 Device. NOT persistent; can change. + + // FONTS & TEXT + // ------------------------------------------------------------ + LPD3DXFONT GetFont(eFontIndex idx); // returns a handle to a D3DX font you can use to draw text on the screen + int GetFontHeight(eFontIndex idx); // returns the height of the font, in pixels + + // MISC + // ------------------------------------------------------------ + td_soundinfo m_sound; // a structure always containing the most recent sound analysis information; defined in pluginshell.h. + void SuggestHowToFreeSomeMem(); // gives the user a 'smart' messagebox that suggests how they can free up some video memory. + */ + //===================================================================================================================== +}; + +#endif \ No newline at end of file diff --git a/vis_milk2/plugin.rc b/vis_milk2/plugin.rc new file mode 100644 index 0000000..b181622 --- /dev/null +++ b/vis_milk2/plugin.rc @@ -0,0 +1,1501 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 390, 292 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "(window title will be assigned at runtime)" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK | WS_TABSTOP,6,7,324,255 + CONTROL "",IDC_RECT,"Static",SS_BLACKRECT | NOT WS_VISIBLE,8,20,320,240 + DEFPUSHBUTTON "OK",IDOK,335,19,50,13 + PUSHBUTTON "Cancel",IDCANCEL,335,35,50,13 + PUSHBUTTON "Defaults",ID_DEFAULTS,335,51,50,13 + PUSHBUTTON "View Docs",ID_DOCS,335,67,50,13 + PUSHBUTTON "View Website",ID_WEB,335,83,50,13 + CTEXT "For help on any setting, click the '?' in the upper-right\rcorner, and then click the item you need help with.",IDC_STATIC,6,268,186,19,SS_SUNKEN + CTEXT "(...'about' text will be placed in this box automatically, at runtime)",IDC_SZ_ABOUT,198,268,187,19,SS_SUNKEN +END + +IDD_PROPPAGE_2 DIALOGEX 0, 0, 320, 240 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "[ More Settings: ]",IDC_FS_BOX,0,3,319,236 + RTEXT "Canvas Stretch:",IDC_STRETCH_CAPTION,5,33,56,10 + COMBOBOX IDC_STRETCH,67,30,99,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "<-- use if your graphics chip (GPU) is slow !!",IDC_STATIC,169,33,144,8 + RTEXT "Mesh Size:",IDC_MESHSIZECOMBO_CAPTION,19,49,43,10 + COMBOBOX IDC_MESHSIZECOMBO,67,47,99,123,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "<-- decrease if your processor (CPU) is slow !!",IDC_STATIC,168,50,150,8 + RTEXT "Pixel Shaders:",IDC_SHADERS_CAPTION,13,67,49,10 + COMBOBOX IDC_SHADERS,67,64,99,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "<-- don't touch this.",IDC_STATIC,168,67,144,8 + RTEXT "Canvas Size:",IDC_TEXSIZECOMBO_CAPTION,19,84,43,10 + COMBOBOX IDC_TEXSIZECOMBO,67,81,99,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "<-- don't touch this.",IDC_STATIC,168,84,144,8 + CONTROL "Start milkdrop with preset lock [scroll lock key] ON",IDC_CB_SCROLLON, + "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,22,116,175,10 + CONTROL "Disable preset rating (...all presets have equal chance)",IDC_CB_NORATING, + "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,22,129,192,10 + CONTROL "Suppress all errors/warnings (for VJ'ing)",IDC_CB_NOWARN2, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,142,143,10 + CONTROL "Prevent milkdrop from controlling the scroll lock key [default: OFF]",IDC_CB_SCROLLON2, + "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,22,155,227,10 + GROUPBOX "Brightness control for 16-bit-color video modes",IDC_BRIGHT_SLIDER_BOX,8,182,180,49 + CONTROL "Slider1",IDC_BRIGHT_SLIDER,"msctls_trackbar32",WS_TABSTOP,25,193,89,14 + CTEXT "0\r\n(bright)",IDC_T1,20,207,25,17 + CTEXT "2\r\n(normal)",IDC_T3,54,207,28,18 + CTEXT "3",IDC_T4,83,207,8,10 + CTEXT "4\r\n(dark)",IDC_T5,91,207,30,18 + CONTROL "guess,\r\nbased on my video card",IDC_CB_AUTOGAMMA, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,129,194,54,30 + CONTROL "Scan presets instantly @ startup/dir. change (can cause a pause)",IDC_CB_INSTASCAN, + "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,207,197,100,17 + CONTROL "Stereo 3D mode Always ON",IDC_CB_ALWAYS3D,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,203,207,103,10 + CONTROL "Use anisotropic filtering (if available) instead of bilinear interpolation",IDC_CB_ANISO, + "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,203,203,99,10 + CTEXT "1",IDC_T2,46,207,8,10 + COMBOBOX IDC_TEXFORMAT,205,197,99,87,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + RTEXT "Texture Format:",IDC_TEXFORMAT_CAPTION,201,198,55,10,NOT WS_VISIBLE | WS_DISABLED +END + +IDD_PROPPAGE_1 DIALOGEX 0, 0, 320, 240 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "",IDC_STATIC,0,0,319,239 + RTEXT "Display Adapter:",IDC_DMS_ADAPTER_CAPTION,68,12,53,9 + COMBOBOX IDC_ADAPTER_DMS,126,9,185,191,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CTEXT "\rDESKTOP MODE\rsettings",IDC_DMS_LABEL,3,17,60,38 + RTEXT "Max Framerate:",IDC_DMS_MAXFPS_CAPTION,63,28,58,9 + COMBOBOX IDC_DMS_MAXFPS,126,25,81,106,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "More &Options",ID_DM_MORE,261,25,50,15 + RTEXT "Multisampling:",IDC_DMS_MULTISAMPLING_CAPTION,5,43,46,9,NOT WS_VISIBLE | WS_DISABLED + COMBOBOX IDC_DMSMS,56,41,81,123,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + CONTROL "Allow Page Tearing",IDC_CB_DMSPT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,43,77,10 + CONTROL "",IDC_STATIC,"Static",SS_GRAYRECT,0,58,318,1 + RTEXT "Display Adapter:",IDC_FS_ADAPTER_CAPTION,68,66,53,9 + COMBOBOX IDC_ADAPTER_FS,126,63,185,208,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CTEXT "FULLSCREEN settings",IDC_FS_LABEL,7,85,50,18 + RTEXT "Display Mode:",IDC_DISP_MODE_CAPTION,66,81,55,9 + COMBOBOX IDC_DISP_MODE,126,78,185,208,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + RTEXT "Max Framerate:",IDC_FS_MAXFPS_CAPTION,66,96,55,9 + COMBOBOX IDC_FS_MAXFPS,126,94,81,107,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + RTEXT "Multisampling:",IDC_FS_MULTISAMPLING_CAPTION,4,112,47,9,NOT WS_VISIBLE | WS_DISABLED + COMBOBOX IDC_FSMS,56,110,81,123,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + CONTROL "Allow Page Tearing",IDC_CB_FSPT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,112,77,10 + CONTROL "Use Fa&ke fullscreen mode",IDC_CB_FAKE,"Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,214,112,97,10 + CONTROL "",IDC_STATIC,"Static",SS_GRAYRECT,0,127,318,1 + RTEXT "Display Adapter:",IDC_W_ADAPTER_CAPTION,68,135,53,9 + COMBOBOX IDC_ADAPTER_W,126,132,185,208,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CTEXT "WINDOWED settings",IDC_W_LABEL,7,145,46,18 + RTEXT "Max Framerate:",IDC_W_MAXFPS_CAPTION,56,151,65,9 + COMBOBOX IDC_W_MAXFPS,126,148,81,107,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + RTEXT "Multisampling:",IDC_W_MULTISAMPLING_CAPTION,5,165,46,9,NOT WS_VISIBLE | WS_DISABLED + COMBOBOX IDC_WMS,56,163,81,123,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_DISABLED | WS_VSCROLL | WS_TABSTOP + CONTROL "Allow Page Tearing",IDC_CB_WPT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,165,77,10 + CONTROL "Integrate with winamp skin",IDC_CB_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,214,164,102,10 + CONTROL "",IDC_STATIC,"Static",SS_GRAYRECT,0,180,318,1 + LTEXT "Start in...",IDC_STATIC,9,192,61,8 + CONTROL "&Fullscreen",IDC_CB_FS,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,9,203,48,10 + CONTROL "&Desktop Mode",IDC_CB_DMS,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,9,215,61,10 + CONTROL "Sa&ve CPU by loosely enforcing Max Framerate",IDC_CB_SAVE_CPU, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,78,185,164,10 + CONTROL "Show '&Press F1 for Help' message at startup",IDC_CB_PRESS_F1_MSG, + "Button",BS_AUTOCHECKBOX | BS_TOP | WS_TABSTOP,78,195,159,10 + CONTROL "&Minimize Winamp when going fullscreen",IDC_CB_MIN, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,78,205,141,10 + CONTROL "Try to fix slow menus/text (uses more video memory)",IDC_CB_FIXSLOWTEXT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,78,215,183,10 + CONTROL "V&J MODE - show text, menus in a second window",IDC_CB_VJMODE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,78,225,173,10 + PUSHBUTTON "Dual&Head",ID_DUALHEAD,262,200,50,15 + PUSHBUTTON "&Select Fonts",ID_FONTS,262,217,50,15 +END + +IDD_PROPPAGE_3 DIALOGEX 0, 0, 320, 240 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Image cache:",IDC_BRIGHT_SLIDER_BOX2,5,4,140,83 + LTEXT "Max # Images:",IDC_MAX_IMAGES_CAPTION,16,17,49,10 + COMBOBOX IDC_MAX_IMAGES,74,14,60,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Max Video Mem:",IDC_MAX_BYTES_CAPTION,16,34,55,10 + COMBOBOX IDC_MAX_BYTES,74,31,60,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Note: cache settings are only relevant if you've put gobs of textures into your milkdrop2\\textures\\ folder. Otherwise, everything fits in 1 MB of VRAM.",IDC_STATIC,13,49,126,33 + PUSHBUTTON "Edit &Sprites",ID_SPRITE,11,93,82,15 + PUSHBUTTON "&Edit Custom Messages",ID_MSG,11,110,82,15 + GROUPBOX "Song Title Animations and Custom Messages",IDC_STATIC,5,130,169,104 + LTEXT "(seconds)",IDC_STATIC,137,140,33,9 + RTEXT "Duration of song title animations:",IDC_SONGTITLEANIM_DURATION_LABEL,20,153,110,10 + EDITTEXT IDC_SONGTITLEANIM_DURATION,136,151,32,13,ES_AUTOHSCROLL + RTEXT "Time between\r\nRANDOM song title anims",IDC_RAND_TITLE_LABEL,34,166,96,17 + EDITTEXT IDC_RAND_TITLE,136,169,32,13,ES_AUTOHSCROLL + RTEXT "Time between\r\nRANDOM custom messages",IDC_RAND_MSG_LABEL,34,185,96,17 + EDITTEXT IDC_RAND_MSG,136,188,32,13,ES_AUTOHSCROLL + CONTROL "Automatically show song title anims when song changes?",IDC_CB_TITLE_ANIMS, + "Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | BS_MULTILINE | WS_TABSTOP,41,207,114,18 + GROUPBOX "Colored-lens 3D glasses",IDC_STATIC,212,66,104,58,NOT WS_VISIBLE | WS_DISABLED + PUSHBUTTON "Set &right eye lens color",IDRIGHT,226,76,82,14,NOT WS_VISIBLE | WS_DISABLED + PUSHBUTTON "Set &left eye lens color",IDLEFT,216,83,82,14,NOT WS_VISIBLE | WS_DISABLED + RTEXT "Default stereo separation (normal=1):",IDC_3DSEP_LABEL,196,101,119,10,NOT WS_VISIBLE | WS_DISABLED + EDITTEXT IDC_3DSEP,260,97,32,13,ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED + GROUPBOX "VJ Mode",IDC_STATIC,188,129,127,63,NOT WS_VISIBLE | WS_DISABLED + CONTROL "Enable &VJ Mode (creates a second window for text input and output and leaves the graphics display text-free; use this in conjunction w/multimon for live shows)",IDC_CB_SEPTEXT, + "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,194,143,121,44 +END + +IDD_PROPPAGE_4 DIALOGEX 0, 0, 320, 240 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Soft Cuts (regular, periodic preset transitions/fades)",IDC_STATIC,5,7,187,96 + RTEXT "Time between auto preset changes:",IDC_BETWEEN_TIME_LABEL,20,25,116,10 + EDITTEXT IDC_BETWEEN_TIME,142,23,32,13,ES_AUTOHSCROLL + RTEXT "Additional random time:",IDC_BETWEEN_TIME_RANDOM_LABEL,33,39,103,10 + EDITTEXT IDC_BETWEEN_TIME_RANDOM,142,38,32,13,ES_AUTOHSCROLL + RTEXT "Auto preset blend time:",IDC_BLEND_AUTO_LABEL,34,55,102,10 + EDITTEXT IDC_BLEND_AUTO,142,53,32,13,ES_AUTOHSCROLL + RTEXT "User-solicited preset blend time:",IDC_BLEND_USER_LABEL,26,70,110,10 + EDITTEXT IDC_BLEND_USER,142,68,32,13,ES_AUTOHSCROLL + LTEXT "(seconds)",IDC_STATIC,142,83,33,10 + GROUPBOX "Hard Cuts (driven by major beats)",IDC_STATIC,5,106,187,91 + RTEXT "Average time between hard cuts:",IDC_HARDCUT_BETWEEN_TIME_LABEL,20,119,116,10 + EDITTEXT IDC_HARDCUT_BETWEEN_TIME,142,117,32,13,ES_AUTOHSCROLL + LTEXT "(seconds)",IDC_STATIC,142,132,33,10 + LTEXT "Loudness threshold:",IDC_HARDCUT_LOUDNESS_LABEL,31,139,71,9 + CTEXT "min",IDC_HARDCUT_LOUDNESS_MIN,37,151,14,9 + CONTROL "Slider1",IDC_HARDCUT_LOUDNESS,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,51,150,114,16 + CTEXT "max",IDC_HARDCUT_LOUDNESS_MAX,165,151,16,9 + CONTROL "&Disable hard cuts",IDC_CB_HARDCUTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,171,72,13 +END + +IDD_PROPPAGE_5 DIALOGEX 0, 0, 320, 240 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN +END + +#if defined(APSTUDIO_INVOKED) || defined(DISABLED) +#if defined(APSTUDIO_INVOKED) +IDD_PROPPAGE_6$(DISABLED) DIALOGEX 0, 0, 320, 240 +#else +IDD_PROPPAGE_6 DIALOGEX 0, 0, 320, 240 +#endif +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(DISABLED) +#if defined(APSTUDIO_INVOKED) +IDD_PROPPAGE_7$(DISABLED) DIALOGEX 0, 0, 320, 240 +#else +IDD_PROPPAGE_7 DIALOGEX 0, 0, 320, 240 +#endif +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN +END +#endif + +#if defined(APSTUDIO_INVOKED) || defined(DISABLED) +#if defined(APSTUDIO_INVOKED) +IDD_PROPPAGE_8$(DISABLED) DIALOGEX 0, 0, 320, 240 +#else +IDD_PROPPAGE_8 DIALOGEX 0, 0, 320, 240 +#endif +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN +END +#endif + +IDD_FONTDIALOG DIALOGEX 0, 0, 354, 175 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_NOPARENTNOTIFY +CAPTION "Select Fonts" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Typeset:",IDC_FONT_CAPTION,85,4,109,9 + LTEXT "Size:",IDC_FONTSIZE_CAPTION,217,4,50,10 + LTEXT "Bold",IDC_FONTOPTIONS_CAPTION,290,4,16,10 + LTEXT "Italics",IDC_FONTOPTIONS_CAPTION2,311,4,20,10 + LTEXT "AA",IDC_FONTOPTIONS_CAPTION3,336,4,11,10 + RTEXT "Simple font:",IDC_FONT_NAME_1,7,16,70,9 + COMBOBOX IDC_FONT1,85,13,127,291,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE1,217,13,65,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,293,16,9,9 + CONTROL "",IDC_FONTITAL1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,315,16,9,9 + CONTROL "",IDC_FONTAA1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,337,16,9,9 + RTEXT "Decorative font:",IDC_FONT_NAME_2,7,32,70,9 + COMBOBOX IDC_FONT2,85,29,127,291,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE2,217,29,65,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,293,32,9,9 + CONTROL "",IDC_FONTITAL2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,315,32,9,9 + CONTROL "",IDC_FONTAA2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,337,32,9,9 + RTEXT "Help screen:",IDC_FONT_NAME_3,7,48,70,9 + COMBOBOX IDC_FONT3,85,45,127,291,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE3,217,45,65,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,293,48,9,9 + CONTROL "",IDC_FONTITAL3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,315,48,9,9 + CONTROL "",IDC_FONTAA3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,337,48,9,9 + RTEXT "Playlist:",IDC_FONT_NAME_4,7,65,70,9 + COMBOBOX IDC_FONT4,85,61,127,291,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE4,217,61,65,87,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,293,64,9,9 + CONTROL "",IDC_FONTITAL4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,315,64,9,9 + CONTROL "",IDC_FONTAA4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,337,64,9,9 + RTEXT "Font 5:",IDC_FONT_NAME_5,7,80,70,9,NOT WS_VISIBLE + COMBOBOX IDC_FONT5,85,77,127,291,CBS_DROPDOWNLIST | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE5,217,77,65,87,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD5,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,293,80,9,9 + CONTROL "",IDC_FONTITAL5,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,315,80,9,9 + CONTROL "",IDC_FONTAA5,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,337,80,9,9 + RTEXT "Font 6:",IDC_FONT_NAME_6,7,96,70,9,NOT WS_VISIBLE + COMBOBOX IDC_FONT6,85,93,127,291,CBS_DROPDOWNLIST | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE6,217,93,65,87,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD6,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,293,96,9,9 + CONTROL "",IDC_FONTITAL6,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,315,96,9,9 + CONTROL "",IDC_FONTAA6,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,337,96,9,9 + RTEXT "Font 7:",IDC_FONT_NAME_7,7,112,70,9,NOT WS_VISIBLE + COMBOBOX IDC_FONT7,85,109,127,291,CBS_DROPDOWNLIST | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE7,217,109,65,87,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD7,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,293,112,9,9 + CONTROL "",IDC_FONTITAL7,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,315,112,9,9 + CONTROL "",IDC_FONTAA7,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,337,112,9,9 + RTEXT "Font 8:",IDC_FONT_NAME_8,7,128,70,9,NOT WS_VISIBLE + COMBOBOX IDC_FONT8,85,125,127,291,CBS_DROPDOWNLIST | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE8,217,125,65,87,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD8,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,293,128,9,9 + CONTROL "",IDC_FONTITAL8,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,315,128,9,9 + CONTROL "",IDC_FONTAA8,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,337,128,9,9 + RTEXT "Font 9:",IDC_FONT_NAME_9,7,144,70,9,NOT WS_VISIBLE + COMBOBOX IDC_FONT9,85,141,127,291,CBS_DROPDOWNLIST | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_FONTSIZE9,217,141,65,87,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_FONTBOLD9,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,293,144,9,9 + CONTROL "",IDC_FONTITAL9,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,315,144,9,9 + CONTROL "",IDC_FONTAA9,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,337,144,9,9 + CTEXT "Note: 'AA' stands for anti-aliasing (smoothing); not always available.",IDC_FONT_TEXT,7,160,235,8,SS_CENTERIMAGE + DEFPUSHBUTTON "OK",IDOK,246,158,50,13 + PUSHBUTTON "Cancel",IDCANCEL,300,158,50,13 +END + +IDD_DESKTOPMODE DIALOGEX 0, 0, 201, 105 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_NOPARENTNOTIFY | WS_EX_CONTEXTHELP +CAPTION "More Options for Desktop Mode" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "Show icons",IDC_CB_SHOW_ICONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,4,51,10 + CONTROL "Draw colored boxes around icon text labels",IDC_CB_BOX, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,16,154,10 + CONTROL "My desktop icons get occluded (covered) by the taskbar when I use Desktop Mode; fix it!",IDC_CB_MANUAL_SCOOT, + "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,4,28,184,18 + LTEXT "When Windows is in [5-6-5] 16-bit color and there is no\ralpha (transparency) channel, try drawing the icons using...",IDC_DM_ALPHA_FIX_CAPTION,4,50,193,17 + COMBOBOX IDC_DM_ALPHA_FIX,4,71,193,291,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,91,88,50,13 + PUSHBUTTON "Cancel",IDCANCEL,147,88,50,13 +END + +IDD_DUALHEAD DIALOGEX 0, 0, 304, 164 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_NOPARENTNOTIFY +CAPTION "Dualhead Options" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Typically, multimon (ie. multiple monitor) setups feature two separate video cards and two separate monitors; each resulting display has its own resolution, and the desktop spans across them in some fashion.",IDC_STATIC,4,4,296,26 + LTEXT "DualHead video cards, though, feature a single card that feeds two monitors. Some of these cards treat the two monitors separately, but some of them treat them as halves of a single double-width (~2048x768) or double-height (~1024x1536) 'virtual screen'.",IDC_STATIC,4,34,296,26 + GROUPBOX "For Desktop and *Fake* Fullscreen modes:",IDC_STATIC,4,64,150,96 + LTEXT "When a single virtual display spans two real screens Horizontally:",IDC_STATIC,10,75,137,18 + COMBOBOX IDC_H_PICK,16,96,104,91,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "When a single virtual display spans two real screens Vertically:",IDC_STATIC,10,113,137,18 + COMBOBOX IDC_V_PICK,16,134,104,67,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "As a result, graphics applications can't go 'fullscreen' on just one monitor, because it's really only half of the 'screen', from Windows' point of view.",IDC_STATIC,159,64,141,32 + LTEXT "This plug-in, however, will let you get away with it, when you're in Desktop Mode or *Fake* Fullscreen Mode; it just needs to know which half of the display (left/right or top/bottom) you want to use -- or both.",IDC_STATIC,159,100,141,42 + DEFPUSHBUTTON "OK",IDOK,196,147,50,13 + PUSHBUTTON "Cancel",IDCANCEL,250,147,50,13 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 385 + TOPMARGIN, 7 + BOTTOMMARGIN, 287 + END + + IDD_FONTDIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 350 + TOPMARGIN, 4 + BOTTOMMARGIN, 171 + END + + IDD_DESKTOPMODE, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 197 + TOPMARGIN, 4 + BOTTOMMARGIN, 101 + END + + IDD_DUALHEAD, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 300 + TOPMARGIN, 4 + BOTTOMMARGIN, 160 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_WINDOWED_CONTEXT_MENU MENU +BEGIN + POPUP "Options:" + BEGIN + MENUITEM "&Fullscreen\tAlt+Enter", ID_GO_FS + MENUITEM "&Desktop Mode\tAlt+D", ID_DESKTOP_MODE + MENUITEM SEPARATOR + MENUITEM "Show &Help\tF1", ID_SHOWHELP + MENUITEM "Show Playlist\tP", ID_SHOWPLAYLIST + MENUITEM SEPARATOR + MENUITEM "&Quit", ID_QUIT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_PLUGIN_ICON ICON "plugin_icon.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// TEXT +// + +IDR_TEXT1 TEXT "text1.bin" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,25,3,0 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Nullsoft, Inc." + VALUE "FileDescription", "Winamp Visualization Plug-in" + VALUE "FileVersion", "2, 25, 3, 0" + VALUE "InternalName", "Nullsoft Milkdrop v2" + VALUE "LegalCopyright", "Copyright © 2001-2013 Nullsoft, Inc." + VALUE "OriginalFilename", "vis_milk2.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", "1, 0, 0, 1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + 65535 "{C5D175F1-E4E4-47ee-B85C-4EDC6B026A35}" +END + +STRINGTABLE +BEGIN + IDS_ABOUT_STRING "%s by %s\n%s" + IDS_SZ_MENU_NAV_TOOLTIP "navigation: ESC: exit, Left Arrow: back, Right Arrow: select, UP/DOWN: change sel" + IDS_UNTITLED_MENU_ITEM "" + IDS_UNTITLED_MENU "" + IDS_ON "ON" + IDS_OFF "OFF" + IDS_USE_UP_DOWN_ARROW_KEYS + "(use up/down arrow keys, PGUP, PGDN to change value)" + IDS_CURRENT_VALUE_OF_X "Current value of %s:" + IDS_LOAD_FROM_FILE "Load from file: [note: preset's wave scaling, as well as q1-q8, will not be imported]" + IDS_SAVE_TO_FILE "Save to file: [note: preset's wave scaling, as well as q1-q8, will not be exported]" + IDS_ENTER_THE_NEW_STRING + "Enter the new string; hit CTRL+ENTER to apply or ESC to cancel." + IDS_MILKDROP_ERROR "MILKDROP ERROR" +END + +STRINGTABLE +BEGIN + IDS_THIS_PLUGIN_NEEDS_MUSIC_TO_RUN + "This plug-in cannot run without music.\n\nPlease play some music, through Winamp, and then try running the plug-in again." + IDS_NO_MUSIC_PLAYING "No Music Playing" + IDS_UNABLE_TO_READ_DATA_FILE_X "Unable to read the data file:\n %s" + IDS_COULD_NOT_CREATE_MY_VERTEX_DECLARATION + "Could not create my vertex declaration" + IDS_COULD_NOT_CREATE_WF_VERTEX_DECLARATION + "Could not create WF vertex declaration" + IDS_COULD_NOT_CREATE_SPRITE_VERTEX_DECLARATION + "Could not create sprite vertex declaration" + IDS_SHADER_MODEL_2 "shader model 2.0" + IDS_SHADER_MODEL_3 "shader model 3.0" + IDS_SHADER_MODEL_4 "shader model 4.0" + IDS_UKNOWN_CASE_X "(unknown case: %d)" + IDS_FAILED_TO_COMPILE_PIXEL_SHADERS_USING_X + "Failed to compile pixel shaders using %s [PSVersion=0x%X].\n\nAfter hitting OK here, please return to the config panel (ALT+K),\ngo to the second tab, and for the Pixel Shaders option, select Auto." + IDS_FAILED_TO_COMPILE_PIXEL_SHADERS_HARDWARE_MIS_REPORT + "Your hardware says that it supports %s [PSVersion=0x%X],\nbut it doesn't seem to do it properly -\nmaybe your display driver is just buggy.\n\nYou might want to try updating your display driver\nto the latest WHQL driver from the chipset manufacturer\n(Nvidia, ATI, etc.)." + IDS_COULD_NOT_COMPILE_FALLBACK_WV_SHADER + "Could not compile fallback warp vertex shader" + IDS_COULD_NOT_COMPILE_FALLBACK_CV_SHADER + "Could not compile fallback comp vertex shader" + IDS_COULD_NOT_COMPILE_FALLBACK_CP_SHADER + "Could not compile fallback comp pixel shader" + IDS_COULD_NOT_COMPILE_BLUR1_VERTEX_SHADER + "Could not compile blur1 vertex shader" +END + +STRINGTABLE +BEGIN + IDS_DXC_ERR_CAPSFAIL "DirectX initialization failed (GetDeviceCaps).\n\nThis means that no valid 3D-accelerated display adapter could be found\non your computer.\nIf you know this is not the case, it is possible that your graphics\nsubsystem is temporarily unstable; please try rebooting your computer,\nand then try to run the plug-in again. Otherwise, please install a\n3D-accelerated display adapter." + IDS_FS_DISPLAY_MODE_SELECTED_IS_INVALID + "The fullscreen display mode selected from the config panel\nwas invalid, for some reason. For now, the closest match\n(to the old selection) will be used.\n\nTo fix this, please return to the config panel and select a new\nfullscreen display mode.\n\nThe plug-in will now run using the best match..." + IDS_CREATEWINDOW_FAILED "CreateWindow failed" + IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS + "You are trying to enter fullscreen mode while running\nmultiple displays in a vertical or horizontal span,\nwithout using 'Fake Fullscreen Mode'. As a result,\n--the image will be stretched over both displays.--\n\nIf you would prefer the plug-in to appear on only one display\n(and still be free to operate on the other display),\nplease return to the config panel, enable 'Fake Fullscreen\nMode', click the 'DualHead' button to configure your DualHead\nsetup, and then try again.\n\nHit OK to proceed, or Cancel to exit now." + IDS_TIP "Tip" + IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS_2 + "You are trying to enter fullscreen mode while running\nmultiple displays in a vertical or horizontal span,\nbut the display mode you are entering does not stretch\nover both displays. As a result, --the image will only\nappear on one display, and the other display will be disabled.--\n\nThere are two alternatives:\n\n1. To make the fullscreen image appear on only ONE display\nAND still be free to operate on the other display,\nplease return to the config panel and enable 'Fake Fullscreen Mode',\nthen click 'DualHead' to select which screen you'd like the\nplug-in to occupy. (--RECOMMENDED--)\n\n2. To make the fullscreen image stretch across BOTH displays,\nreturn to the config panel and select a display mode that\nspans both displays (such as 2048 x 768, or 1024 x 1536).\n\nHit OK to continue, or Cancel to exit now." + IDS_UNABLE_TO_CREATE_DIRECTX_DEVICE + "Unable to create a DirectX device. (D3DERR_NOTAVAILABLE)\n\nThis could mean that you've chosen a combination of settings that is\nnot available on your video card. Try resetting the plug-in to its\ndefault settings (via the config panel's 'Default' button), and then\ntry running the plug-in again.\n\nYou might also want to close all other applications, to make sure they're\nnot interfering.\n\nIf you have made any changes to your graphics subsystem since your\nlast reboot (such as updating video drivers, installing new software,\netc.), or have witnessed any strange behaviors, TRY REBOOTING first.\n\n" + IDS_OLDER_DISPLAY_ADAPTER_CATENATION + "NOTE: If you are trying to run the plug-in on an older display adapter\n(such as a Voodoo3 card), try going to the config panel (ALT+K)\nand selecting a fullscreen display mode of a different color depth;\nand selecting a fullscreen display mode of a different color depth;\nsome of these older cards can only do 3D in particular color depths\n(such as 16-bit color, for the Voodoo 3).\n" + IDS_OLDER_DISPLAY_ADAPTER_CATENATION_2 + "NOTE: If you are trying to run the plug-in on an older display adapter\n(such as a Voodoo3 card), try changing the color depth that Windows\nis running in; some of these cards can only do 3D in particular color depths\n(such as 16-bit color, for the Voodoo3).\n" + IDS_DIRECTX_INIT_FAILED_X + "DirectX initialization failed (CreateDevice; code %d)\n\nOften this means you don't have enough free video memory.\n" + IDS_WINDOW_RESIZE_FAILED + "Window resize failed.\n\nOften this means the application ran out of video memory;\n perhaps you tried to make the window too large." + IDS_OUT_OF_VIDEO_MEMORY "OUT OF VIDEO MEMORY" + IDS_ERROR_CREATING_GDI_FONTS "Error creating GDI fonts" + IDS_ERROR_LOADING_MAIN_MENU "Error loading main menu" + IDS_ERROR_LOADING_CONTEXT_MENU "Error loading context menu" + IDS_ERROR_CREATING_DIRECT3D_DEVICE_FOR_VJ_MODE + "Error invoking Direct3D 9 for VJ mode;\nDirectX 9 could be missing or corrupt." +END + +STRINGTABLE +BEGIN + IDS_COULD_NOT_COMPILE_BLUR1_PIXEL_SHADER + "Could not compile blur1 pixel shader" + IDS_COULD_NOT_COMPILE_BLUR2_VERTEX_SHADER + "Could not compile blur2 vertex shader" + IDS_COULD_NOT_COMPILE_BLUR2_PIXEL_SHADER + "Could not compile blur2 pixel shader" + IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_SMALLER_DISPLAY + "Could not create internal canvas texture! (probably not enough video memory left)\ntry selecting a smaller display mode, or decreasing the color bit depth." + IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_NOT_ENOUGH_VID_MEM_RECOMMENDATION + "Could not create internal canvas texture! (probably not enough video memory left)\n\n\nRECOMMENDATION: SET THE INTERNAL CANVAS SIZE BACK TO 'AUTO' AND TRY AGAIN" + IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_NOT_ENOUGH_VID_MEM + "Could not create internal canvas texture! (probably not enough video memory left)\n" + IDS_SUCCESSFULLY_CREATED_VS0_VS1 + "Successfully created VS0/VS1 at %d x %d (ideal: %d x %d)" + IDS_ERROR_CREATING_BLUR_TEXTURES + "Error creating blur textures - probably not enough video memory." + IDS_COULD_NOT_CREATE_NOISE_TEXTURE "Could not create noise texture" + IDS_COULD_NOT_LOCK_NOISE_TEXTURE "Could not lock noise texture" + IDS_NOISE_TEXTURE_BYTE_LAYOUT_NOT_RECOGNISED + "Noise texture byte layout not recognized" + IDS_COULD_NOT_CREATE_3D_NOISE_TEXTURE "Could not create 3D noise texture" + IDS_COULD_NOT_LOCK_3D_NOISE_TEXTURE "Could not lock 3D noise texture" + IDS_3D_NOISE_TEXTURE_BYTE_LAYOUT_NOT_RECOGNISED + "3D noise texture byte layout not recognized" +END + +STRINGTABLE +BEGIN + IDS_MILKDROP_WARNING "MILKDROP WARNING" + IDS_ERROR_CREATING_DOUBLE_SIZED_GDI_TITLE_FONT + "Error creating double-sized GDI title font" + IDS_ERROR_CREATING_DOUBLE_SIZED_D3DX_TITLE_FONT + "Error creating double-sized d3dx title font" + IDS_RATING "Rating" + IDS_DISABLED "[disabled] " + IDS_ARE_YOU_SURE_YOU_WANT_TO_DELETE_PRESET + "Are you SURE you want to delete this preset? [y/N]" + IDS_PRESET_TO_DELETE "(preset to delete: %s)" + IDS_FILE_ALREADY_EXISTS_OVERWRITE_IT + "This file already exists. Overwrite it? [y/N]" + IDS_FILE_IN_QUESTION_X_MILK "(file in question: %s.milk)" + IDS_ERROR_NO_PRESET_FILE_FOUND_IN_X_MILK + "ERROR: No preset files found in %s*.milk" + IDS_LOAD_WHICH_PRESET_PLUS_COMMANDS + "Load which preset? (arrow keys to scroll; Esc/close, Enter/select, INS/rename; DEL/delete)" +END + +STRINGTABLE +BEGIN + IDS_ERROR_CREATING_SHADER "Error creating shader:\n" + IDS_PLEASE_EXIT_VIS_BEFORE_RUNNING_CONFIG_PANEL + "Please exit the visualizer before running the config panel." + IDS_FPS "fps" + IDS_PF_MONITOR "pf monitor" + IDS_PRESS_F9_TO_HIDE_SHADER_QREF + "-- press F9 to hide shader Quick Reference --\n" + IDS_PRESS_F9_TO_SHOW_SHADER_QREF + "-- press F9 to show shader Quick Reference --\n" + IDS_WARP_AND_COMPOSITE_SHADERS_LOCKED + "(keep in mind... warp and composite shaders were locked.)" + IDS_WARP_SHADER_LOCKED "(keep in mind... warp shader was locked.)" + IDS_COMPOSITE_SHADER_LOCKED + "(keep in mind... composite shader was locked.)" + IDS_PRESET_USES_HIGHEST_PIXEL_SHADER_VERSION + "This preset already uses the highest pixel shader version (%d) supported by your graphics chip." + IDS_PRESET_HAS_MIXED_VERSIONS_OF_SHADERS + "This preset has mixed versions of shaders in it." + IDS_UPGRADE_SHADERS_TO_USE_PS2 + "Do you want to upgrade all shaders to use (at least) pixel shader 2? [y/N]" + IDS_UPGRADE_SHADERS_TO_USE_PS3 + "Do you want to upgrade all shaders to use (at least) pixel shader 3? [y/N]" + IDS_PRESET_DOES_NOT_USE_PIXEL_SHADERS + "This preset does not currently use pixel shaders." +END + +STRINGTABLE +BEGIN + IDS_UPGRADE_TO_USE_PS2 "Do you want to upgrade it to use pixel shader 2? [y/N]" + IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET + " (WARNING: if you save it, other users with older graphics chips might not be able to use the preset." + IDS_PRESET_CURRENTLY_USES_PS2 "This preset currently uses pixel shader 2." + IDS_UPGRADE_TO_USE_PS3 "Do you want to upgrade it to use pixel shader 3? [y/N]" + IDS_PRESET_CURRENTLY_USES_PS3 "This preset currently uses pixel shader 3." + IDS_UPGRADE_TO_USE_PS4 "Do you want to upgrade it to use pixel shader 4? [y/N]" + IDS_WARNING_DO_NOT_FORGET_WARP_SHADER_WAS_LOCKED + " WARNING: do not forget WARP shader was LOCKED! " + IDS_WARNING_DO_NOT_FORGET_COMPOSITE_SHADER_WAS_LOCKED + " WARNING: do not forget COMPOSITE shader was LOCKED! " + IDS_PRESET_MASH_UP_TEXT1 + "Preset Mash-Up: use keys 1-5 to change bin;" + IDS_PRESET_CURRENTLY_USES_PS2X + "This preset currently uses pixel shader 2.X." + IDS_UPGRADE_TO_USE_PS2X "Do you want to upgrade it to use pixel shader 2.X? [y/N]" + IDS_PRESET_MASH_UP_TEXT2 + " up/down/a-z to browse presets for current bin;" + IDS_PRESET_MASH_UP_TEXT3 + " h to randomize preset (or H = all bins); " + IDS_PRESET_MASH_UP_TEXT4 " esc exits." + IDS_DIRECTORY_OF_X "Directory of: %s" +END + +STRINGTABLE +BEGIN + IDS_PAGE_X_OF_X " (page %d of %d) " + IDS_LOCKED " " + IDS_ILLEGAL_CHARACTER "(illegal character)" + IDS_STRING_TOO_LONG "(string too long)" + IDS_DIRECTORY_TO_JUMP_TO "Directory to jump to:" + IDS_ERROR_IMPORTING_BAD_FILENAME + "(error importing - bad filename, or file does not exist)" + IDS_ERROR_IMPORTING_BAD_FILENAME_OR_NOT_OVERWRITEABLE + "(error exporting - bad filename, or file can not be overwritten)" + IDS_INVALID_PATH "(invalid path)" + IDS_ENTER_THE_NEW_NAME_FOR_X "Enter the new name for ""%s"":" + IDS_PRESET_ORDER_IS_NOW_X "preset order is now %s" + IDS_SEQUENTIAL "SEQUENTIAL" + IDS_RANDOM "RANDOM" +END + +STRINGTABLE +BEGIN + IDS_SHUFFLE_IS_NOW_OFF "shuffle is now OFF" + IDS_SHUFFLE_IS_NOW_ON "shuffle is now ON" + IDS_COMPSHADER_LOCKED "COMP SHADER LOCKED." + IDS_WARPSHADER_LOCKED "WARP SHADER LOCKED." + IDS_ALLSHADERS_LOCKED "ALL SHADERS LOCKED." + IDS_ALLSHADERS_UNLOCKED "ALL SHADERS UNLOCKED." + IDS_PS_AUTO_RECOMMENDED " Auto (Recommended)" + IDS_PS_DISABLED " Disabled" + IDS_PS_SHADER_MODEL_2 " Shader Model 2" + IDS_PS_SHADER_MODEL_3 " Shader Model 3" + IDS_TX_8_BITS_PER_CHANNEL " 8 bits per channel" + IDS_TX_16_BITS_PER_CHANNEL " 16 bits - CAREFUL" + IDS_TX_32_BITS_PER_CHANNEL " 32 bits - CAREFUL" + IDS_160X120_SLOW "160 x 120 SLOW " + IDS_192X144_SLOW "192 x 144 SLOW " +END + +STRINGTABLE +BEGIN + IDS_SAVE_AS "Save as:" + IDS_AUTO " Auto " + IDS_8X6_FAST " 8 x 6 FAST " + IDS_16X12_FAST " 16 x 12 fast " + IDS_24X18 " 24 x 18 " + IDS_32X24 " 32 x 24 " + IDS_40X30 " 40 x 30 " + IDS_48X36_DEFAULT " 48 x 36 (default)" + IDS_64X48_SLOW " 64 x 48 " + IDS_80X60_SLOW " 80 x 60 slow " + IDS_96X72_SLOW " 96 x 72 SLOW " + IDS_128X96_SLOW "128 x 96 SLOW " + IDS_ERROR_IN_SHELLEXECUTE "error in ShellExecute" +END + +STRINGTABLE +BEGIN + IDS_NONE_BEST_IMAGE_QUALITY " None (best image quality) " + IDS_1_25_X " 1.25 X " + IDS_1_33_X " 1.33 X " + IDS_1_5_X " 1.5 X (...2x faster)" + IDS_1_67_X " 1.67 X (...3x faster)" + IDS_2_X " 2 X (...4x faster)" + IDS_3_X " 3 X (...9x faster)" + IDS_4_X " 4 X (...16x faster) " + IDS_NEAREST_POWER_OF_2 " Nearest power of 2 " + IDS_EXACT_RECOMMENDED " Exact (Recommended) " + IDS_PIXEL_SHADERS "Pixel Shaders" + IDS_PIXEL_SHADERS_TEXT "MilkDrop 1 did not use programmable pixel shaders - instead,\nit used the fixed-function graphics pipeline. If your graphics chip\nis older and doesn't support pixel shaders, or doesn't support the\nideal pixel shader version (2.0) for MilkDrop 2, then this should be\nauto-detected without a problem, and MilkDrop will simply skip over\nany presets that can't run on your graphics chip. (These presets will\nalso be hidden from view, in the preset list.)\n\nIf you'd like to force MilkDrop to try and allow higher (or lower)\nversions of pixel shaders, use this option.\n\nFinally, if you want to prevent MilkDrop from running any pixel shader 3,\npresets (because it's too slow for them), you can just set this option\nto version 2.0, and MilkDrop will avoid those presets." + IDS_TEXFORMAT "Texture Format" + IDS_TEXFORMAT_TEXT "This determines the precision of the colors that you see.\nHigher bit depths are better. A bit depth of 8, for example,\nmeans that in the graphics hardware, the image can have 2^8, or 256,\npossible shades (each) of red, green, and blue.\n\nA bit depth of 8 looks decent, but 16 is much better.\nHOWEVER, only high-end video cards (as of 2007) usually support\nit properly. Older cards can't do 'bilinear interpolation'\nwith 16-bit render targets, meaning that the image will get\nvery grainy and 'digital' looking, so PLEASE WATCH OUT FOR THIS.\n\n32 bits is excessive and slow, don't ever use it.\n\nNote that your monitor can only show 256 shades of each color;\nhowever, if the internal image (that is repeatedly warped and modified\nfrom frame to frame) has better color precision (~16 bits), then \nthe colors in the image will maintain their fidelity as they slowly\nerode and warp, over time." + IDS_CANVAS_SIZE "Canvas Size" + IDS_CANVAS_SIZE_TEXT "This sets the size of the image that milkdrop uses, internally,\nto drive the visuals. The bigger the value here, the crisper\nthe image you see. It's highly recommended that you set this\nto 'auto', which will determine the ideal image (texture) size\nautomatically. However, if you experience visual problems (such\nas black streaks or missing chunks in the image) due to low\nvideo memory, you might want to set this to a low value (like\n256x256 or 512x512).\n\n'Auto (exact)' means the internal texture size will exactly match\nthe number of pixels on the screen - this is the ideal case.\nIf that doesn't work, try 'Auto (nearest power of 2)' - some older\nvideo cards will have better luck with this option." +END + +STRINGTABLE +BEGIN + IDS_CANVAS_STRETCH "Canvas Stretch" + IDS_CANVAS_STRETCH_TEXT "MilkDrop works with an internal texture, or canvas, to do all of\nits graphics rendering. The speed (framerate) that MilkDrop runs\nat is inversely proportional to the number of pixels that are in\nthis canvas. So, to render things internally at a smaller resolution,\nbut stretch them up for display, you can use this option. It will\nmake the image look a bit softer and less crisp or detailed,\nbut - especially for older graphics hardware - things will run\nmuch faster.\n\nKeep in mind, a stretch factor of 2X, for example, means that there\nwill be half as manypixels to simulate on both the X and Y axes, \nso MilkDrop will actually run FOUR TIMES as fast. With a stretch\nfactor of 3X, it will run 9X as fast (hypothetically). And so on." + IDS_MAX_IMAGES_BYTES_TEXT + "This option is only relevant if you've put tons of new textures in your \nwinamp\\plugins\\milkdrop2\\textures directory. If you have (say you\nset up some kind of art kiosk with thousands of large images), this\noption lets you tweak how much video RAM MilkDrop will try to use to\ncache textures. The only point of cacheing textures is so that \nwhen loading a new preset, if the preset needs to load textures,\nif they were already loaded once and are still cached in memory, \nthe load will be much smoother.\n\nGo ahead and crank this up; MilkDrop's core internal textures will\nalways take precedence over disk textures anyway, so it's pretty safe." + IDS_MENU_EDIT_WARP_SHADER "[ edit warp shader ]" + IDS_MENU_EDIT_COMPOSITE_SHADER "[ edit composite shader ]" + IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT "blur1: edge darken amount" + IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT_TT + "keep this >0.25 to avoid edge artifacts, and <1.0 to avoid black borders." + IDS_MENU_BLUR1_MIN_COLOR_VALUE "blur1: min color value" + IDS_MENU_BLUR1_MIN_COLOR_VALUE_TT + "narrowing these to just the color range you need will greatly increase color fidelity in the blurred images." + IDS_MENU_BLUR1_MAX_COLOR_VALUE "blur1: max color value" + IDS_MENU_BLUR1_MAX_COLOR_VALUE_TT + "narrowing these to just the color range you need will greatly increase color fidelity in the blurred images." + IDS_MENU_BLUR2_MIN_COLOR_VALUE "blur2: min color value" + IDS_MENU_BLUR2_MIN_COLOR_VALUE_TT + "narrowing these to just the color range you need will greatly increase color fidelity in the blurred images. MUST BE SUBSET OF BLUR1 RANGE." + IDS_MENU_BLUR2_MAX_COLOR_VALUE "blur2: max color value" + IDS_MENU_BLUR2_MAX_COLOR_VALUE_TT + "narrowing these to just the color range you need will greatly increase color fidelity in the blurred images. MUST BE SUBSET OF BLUR1 RANGE." + IDS_MENU_BLUR3_MIN_COLOR_VALUE "blur3: min color value" +END + +STRINGTABLE +BEGIN + IDS_MESH_SIZE "Mesh Size" + IDS_MESH_SIZE_TEXT "MilkDrop uses a mesh of polygons to warp the image each frame.\nThis setting determines how finely subdivided that mesh is.\nA larger mesh size will mean finer resolution 'movement' in the\nimage; basically, it will look better. Watch out, though - \nonly crank this way up if you have a fast CPU." + IDS_CB_ALWAYS3D "Enable this to force all presets to be displayed in 3D mode.\n(Note that you need glasses with differently-colored lenses\n to see the effect.)" + IDS_DISABLE_PRESET_RATING "Disable preset rating" + IDS_DISABLE_PRESET_RATING_TEXT + "Check this to turn off the preset rating system. Normally, when MilkDrop\ngoes to randomly select a preset, it weights them based on their ratings.\nHowever, if you want all presets to have an equal chance of being chosen,\ncheck this box." + IDS_CB_NOWARN2 "Check this to disable any & all warning messages that appear in the\nupper-right corner of the screen." + IDS_START_WITH_PRESET_LOCK_ON "Start with preset lock ON" + IDS_START_WITH_PRESET_LOCK_ON_TEXT + "Check this to make MilkDrop automatically start in 'preset lock' mode,\nmeaning that the preset will not change until the user changes it\nmanually (either by pressing SPACE, hitting H for a hard cut, or by\nselecting a new preset from the 'L'oad menu).\n\nUse the SCROLL LOCK key while MilkDrop is running to toggle the preset\nlock on or off. When the SCROLL LOCK light is on, that means that the\npreset lock is also on, and vice versa." + IDS_BRIGHT_SLIDER "The brightness slider lets you control the overall brightness\nof the image. If the image is continually washed out to bright\npurple or white, you'll want to crank this down to (probably) zero.\nIf the image is chronically dark, crank this up.\n\nNote that the slider is not visible when the nearby 'guess'\ncheckbox is checked. Uncheck it to manually set the brightness.\n\nAlso note that this brightness adjustment is only a concern in\n16-bit color modes. (32-bit doesn't have this problem.) So,\nif you're running Windows in 16-bit color, this slider will affect\nwindowed, desktop, and 'fake' fullscreen modes. And if you've\nselected a 16-bit fullscreen display mode, it will affect that\ntoo." + IDS_CB_AUTOGAMMA "Check this option to ask milkdrop to make an educated guess\nfor the 'brightness control for 16-bit color' setting, based\non the vendor of your video card. This usually gets it, but\nnot always.\n\nThe slider is only visible when this option is unchecked.\n\nSee the help for the slider for more information." +END + +STRINGTABLE +BEGIN + IDS_SPRITE "Click this button to edit milk_img.ini, the file that defines\nall of the custom sprites you can invoke for display while\nmilkdrop is running. A sprite is an image that you can fade\nin or our, move around, and so on." + IDS_MSG "Click this button to edit milk_msg.ini, the file that you can\nconfigure to set up custom overlaid text messages that you can\ndisplay while milkdrop is running." + IDS_SONGTITLEANIM_DURATION_TEXT + "The duration, in seconds, of song title animations." + IDS_RAND_TITLE_TEXT "The mean (average) time, in seconds, between randomly-launched\nsong title animations. Set to a negative value to disable random\nlaunching." + IDS_RAND_MSG_TEXT "The mean (average) time, in seconds, between randomly-launched\ncustom messages (from milk_msg.ini). Set to a negative value\nto disable random launching." + IDS_TITLE_ANIMS_TEXT "Check this to automatically launch song title animations whenever\nthe track changes." + IDS_BETWEEN_TIME_TEXT "The minimum amount of time that elapses between preset changes\n(excluding hard cuts, which take priority). The old preset will\nbegin to blend or fade into a new preset after this amount of time,\nplus some random amount of time as specified below in the\n'additional random time' box. Add these two values together to\nget the maximum amount of time that will elapse between preset\nchanges." + IDS_BETWEEN_TIME_RANDOM_TEXT + "The additional random maximum # of seconds between preset fades\n(aka preset changes) (aka soft cuts)." + IDS_BLEND_AUTO_TEXT "The duration, in seconds, of a soft cut (a normal fade from one preset\nto another) that is initiated because some amount of time has passed.\nA value less than 1 will make for a very quick transition, while a value\naround 3 or 4 will allow you to see some interesting behavior during\nthe blend." + IDS_BLEND_USER_TEXT "The duration, in seconds, of a soft cut (a normal fade from one preset\nto another) that is initiated by you, when you press the 'H' key (for\na Hard cut). A value less than 1 will make for a very quick transition,\nwhile a value around 3 or 4 will allow you to see some interesting behavior\nduring the blend." + IDS_HARDCUT_BETWEEN_TIME_TEXT + "The amount of time, in seconds, between hard cuts. Hard cuts are\nset off by loud beats in the music, with (ideally) about this much\ntime in between them." + IDS_HARDCUT_LOUDNESS_TEXT + "Use this slider to adjust the sensitivity of the beat detection\nalgorithm used to detect the beats that cause hard cuts. A value\nclose to 'min' will cause the algorithm to be very sensitive (so\neven small beats will trigger it); a value close to 'max' will\ncause only the largest beats to trigger it." +END + +STRINGTABLE +BEGIN + IDS_CB_HARDCUTS "Check this to disable hard cuts; a loud beat\nwill never cause the preset to change." + IDS_EDIT_CURRENT_PRESET "--edit current preset" + IDS_MOTION "--MOTION" + IDS_DRAWING_CUSTOM_SHAPES "--drawing: custom shapes" + IDS_DRAWING_CUSTOM_WAVES "--drawing: custom waves" + IDS_DRAWING_SIMPLE_WAVEFORM "--drawing: simple waveform" + IDS_DRAWING_BORDERS_MOTION_VECTORS "--drawing: borders, motion vectors" + IDS_POST_PROCESSING_MISC "--post-processing, misc." + IDS_CUSTOM_WAVE_X "--custom wave %d" + IDS_CUSTOM_SHAPE_X "--custom shape %d" + IDS_MENU_EDIT_PRESET_INIT_CODE "[ edit preset initialization code ]" + IDS_MENU_EDIT_PRESET_INIT_CODE_TT + "read-only: zoom, rot, warp, cx, cy, dx, dy, sx, sy; decay, gamma;\n echo_zoom, echo_scale, echo_orient;\n ib_{size|r|g|b|a}, ob_{size|r|g|b|a}, mv_{x|y|dx|dy|l|r|g|b|a};\n wave_{r|g|b|a|x|y|mode|mystery|usedots|thick|additive|brighten};\n darken_center, wrap; invert, brighten, darken, solarize\n time, fps, frame, progress; {bass|mid|treb}[_att]\nwrite: q1-q8, monitor" + IDS_MENU_EDIT_PER_FRAME_EQUATIONS "[ edit per_frame equations ]" + IDS_MENU_EDIT_PER_FRAME_EQUATIONS_TT + "read-only: time, fps, frame, progress; {bass|mid|treb}[_att]\nread/write: zoom, rot, warp, cx, cy, dx, dy, sx, sy; q1-q8; monitor\n mv_{x|y|dx|dy|l|r|g|b|a}, ib_{size|r|g|b|a}, ob_{size|r|g|b|a};\n wave_{r|g|b|a|x|y|mode|mystery|usedots|thick|additive|brighten};\n darken_center, wrap; invert, brighten, darken, solarize\n decay, gamma, echo_zoom, echo_alpha, echo_orient" +END + +STRINGTABLE +BEGIN + IDS_MENU_ROTATION_AMOUNT_TT + "controls the amount of rotation. 0=none, 0.1=slightly right, -0.1=slightly clockwise, 0.1=CCW" + IDS_MENU_ROTATION_CENTER_OF_X " rot., center of (X)" + IDS_MENU_ROTATION_CENTER_OF_X_TT + "controls where the center of rotation is, horizontally. 0=left, 0.5=center, 1=right" + IDS_MENU_ROTATION_CENTER_OF_Y " rot., center of (Y)" + IDS_MENU_ROTATION_CENTER_OF_Y_TT + "controls where the center of rotation is, vertically. 0=top, 0.5=center, 1=bottom" + IDS_MENU_TRANSLATION_X "translation (X)" + IDS_MENU_TRANSLATION_X_TT + "controls amount of constant horizontal motion; -0.01 = slight shift right, 0=none, 0.01 = to left" + IDS_MENU_TRANSLATION_Y "translation (Y)" + IDS_MENU_TRANSLATION_Y_TT + "controls amount of constant vertical motion; -0.01 = slight shift downward, 0=none, 0.01 = upward" + IDS_MENU_SCALING_X "scaling (X)" + IDS_MENU_SCALING_X_TT "controls amount of constant horizontal stretching; 0.99=shrink, 1=normal, 1.01=stretch" + IDS_MENU_SCALING_Y "scaling (Y)" + IDS_MENU_SCALING_Y_TT "controls amount of constant vertical stretching; 0.99=shrink, 1=normal, 1.01=stretch" + IDS_MENU_SUSTAIN_LEVEL "sustain level" + IDS_MENU_SUSTAIN_LEVEL_TT + "controls the eventual fade to black; 1=no fade, 0.9=strong fade; 0.98=recommended." + IDS_MENU_DARKEN_CENTER "darken center" +END + +STRINGTABLE +BEGIN + IDS_MENU_DARKEN_CENTER_TT + "when ON, help keeps the image from getting too bright by continually dimming the center point" + IDS_MENU_GAMMA_ADJUSTMENT "gamma adjustment" + IDS_MENU_GAMMA_ADJUSTMENT_TT + "controls brightness; 1=normal, 2=double, 3=triple, etc." + IDS_MENU_HUE_SHADER "hue shader" + IDS_MENU_HUE_SHADER_TT "adds subtle color variations to the image. 0=off, 1=fully on" + IDS_MENU_VIDEO_ECHO_ALPHA "video echo: alpha" + IDS_MENU_VIDEO_ECHO_ALPHA_TT + "controls the opacity of the second graphics layer; 0=transparent (off), 0.5=half-mix, 1=opaque" + IDS_MENU_VIDEO_ECHO_ZOOM " video echo: zoom" + IDS_MENU_VIDEO_ECHO_ZOOM_TT + "controls the size of the second graphics layer" + IDS_MENU_VIDEO_ECHO_ORIENTATION " video echo: orientation" + IDS_MENU_VIDEO_ECHO_ORIENTATION_TT + "selects an orientation for the second graphics layer. 0=normal, 1=flip on x, 2=flip on y, 3=flip on both" + IDS_MENU_TEXTURE_WRAP "texture wrap" + IDS_MENU_TEXTURE_WRAP_TT + "sets whether or not screen elements can drift off of one side and onto the other" + IDS_MENU_FILTER_INVERT "filter: invert" +END + +STRINGTABLE +BEGIN + IDS_MENU_FILTER_INVERT_TT "inverts the colors in the image" + IDS_MENU_FILTER_BRIGHTEN "filter: brighten" + IDS_MENU_FILTER_BRIGHTEN_TT + "brightens the darker parts of the image (nonlinear; square root filter)" + IDS_MENU_FILTER_DARKEN "filter: darken" + IDS_MENU_FILTER_DARKEN_TT + "darkens the brighter parts of the image (nonlinear; squaring filter)" + IDS_MENU_FILTER_SOLARIZE "filter: solarize" + IDS_MENU_FILTER_SOLARIZE_TT "emphasizes mid-range colors" + IDS_MENU_ENABLED "enabled" + IDS_MENU_ENABLED_TT "enables or disables this custom waveform/spectrum" + IDS_MENU_NUMBER_OF_SAMPLES "number of samples" + IDS_MENU_NUMBER_OF_SAMPLES_TT + "the number of samples (points) that makes up the waveform" + IDS_MENU_L_R_SEPARATION "L/R separation" + IDS_MENU_L_R_SEPARATION_TT + "the offset between the left & right channels; useful for doing phase plots. Keep low (<32) when using w/spectrum." + IDS_MENU_SCALING "scaling" + IDS_MENU_SCALING_TT "the size of the wave (1=normal)" + IDS_MENU_SMOOTHING_TT "0=the raw wave; 1=a highly damped (smoothed) wave" +END + +STRINGTABLE +BEGIN + IDS_MENU_WAVE_TYPE "wave type" + IDS_MENU_WAVE_TYPE_TT "each value represents a different way of drawing the waveform" + IDS_MENU_SIZE "size" + IDS_MENU_SIZE_TT "relative size of the waveform" + IDS_MENU_SMOOTH "smoothing" + IDS_MENU_SMOOTH_TT "controls the smoothness of the waveform; 0=natural sound data (no smoothing), 0.9=max. smoothing" + IDS_MENU_MYSTERY_PARAMETER "mystery parameter" + IDS_MENU_MYSTERY_PARAMETER_TT + "what this one does is a secret (actually, its effect depends on the 'wave type'" + IDS_MENU_POSITION_X "position (X)" + IDS_MENU_POSITION_X_TT "position of the waveform: 0 = far left edge of screen, 0.5 = center, 1 = far right" + IDS_MENU_POSITION_Y "position (Y)" + IDS_MENU_POSITION_Y_TT "position of the waveform: 0 = very bottom of screen, 0.5 = center, 1 = top" + IDS_MENU_COLOR_RED "color (red)" + IDS_MENU_COLOR_RED_TT "amount of red color in the wave (0..1)" + IDS_MENU_COLOR_GREEN "color (green)" +END + +STRINGTABLE +BEGIN + IDS_MENU_COLOR_GREEN_TT "amount of green color in the wave (0..1)" + IDS_MENU_COLOR_BLUE "color (blue)" + IDS_MENU_COLOR_BLUE_TT "amount of blue color in the wave (0..1)" + IDS_MENU_OPACITY "opacity" + IDS_MENU_OPACITY_TT "opacity of the waveform; lower numbers = more transparent" + IDS_MENU_USE_DOTS "use dots" + IDS_MENU_USE_DOTS_TT "if true, the waveform is drawn as dots (instead of lines)" + IDS_MENU_DRAW_THICK "draw thick" + IDS_MENU_DRAW_THICK_TT "if true, the waveform's lines (or dots) are drawn with double thickness" + IDS_MENU_MODULATE_OPACITY_BY_VOLUME "modulate opacity by volume" + IDS_MENU_MODULATE_OPACITY_BY_VOLUME_TT + "if true, the waveform opacity is affected by the music's volume" + IDS_MENU_MODULATION_TRANSPARENT_VOLUME "modulation: transparent volume" + IDS_MENU_MODULATION_TRANSPARENT_VOLUME_TT + "when the relative volume hits this level, the wave becomes transparent. 1 = normal loudness, 0.5 = extremely quiet, 1.5 = extremely loud" + IDS_MENU_MODULATION_OPAQUE_VOLUME "modulation: opaque volume" + IDS_MENU_MODULATION_OPAQUE_VOLUME_TT + "when the relative volume hits this level, the wave becomes opaque. 1 = normal loudness, 0.5 = extremely quiet, 1.5 = extremely loud" + IDS_MENU_ADDITIVE_DRAWING "additive drawing" +END + +STRINGTABLE +BEGIN + IDS_MENU_ADDITIVE_DRAWING_TT + "if true, the wave is drawn additively, saturating the image at white" + IDS_MENU_COLOR_BRIGHTENING "color brightening" + IDS_MENU_COLOR_BRIGHTENING_TT + "if true, the red, green, and blue color components will be scaled up until at least one of them reaches 1.0" + IDS_MENU_OUTER_BORDER_THICKNESS "outer border thickness" + IDS_MENU_OUTER_BORDER_THICKNESS_TT + "thickness of the outer border drawn at the edges of the screen" + IDS_MENU_COLOR_RED_OUTER " color (red)" + IDS_MENU_COLOR_RED_OUTER_TT "amount of red color in the outer border" + IDS_MENU_COLOR_GREEN_OUTER " color (green)" + IDS_MENU_COLOR_GREEN_OUTER_TT "amount of green color in the outer border" + IDS_MENU_COLOR_BLUE_OUTER " color (blue)" + IDS_MENU_COLOR_BLUE_OUTER_TT "amount of blue color in the outer border" + IDS_MENU_OPACITY_OUTER " opacity" + IDS_MENU_OPACITY_OUTER_TT + "opacity of the outer border (0=transparent, 1=opaque)" + IDS_MENU_INNER_BORDER_THICKNESS "inner border thickness" +END + +STRINGTABLE +BEGIN + IDS_MENU_INNER_BORDER_THICKNESS_TT + "thickness of the inner border drawn at the edges of the screen" + IDS_MENU_COLOR_RED_INNER_TT "amount of red color in the inner border" + IDS_MENU_COLOR_GREEN_INNER_TT "amount of green color in the inner border" + IDS_MENU_COLOR_BLUE_INNER_TT "amount of blue color in the inner border" + IDS_MENU_OPACITY_INNER_TT + "opacity of the inner border (0=transparent, 1=opaque)" + IDS_MENU_MOTION_VECTOR_OPACITY "motion vector opacity" + IDS_MENU_MOTION_VECTOR_OPACITY_TT + "opacity of the motion vectors (0=transparent, 1=opaque)" + IDS_MENU_NUM_MOT_VECTORS_X " num. mot. vectors (X)" + IDS_MENU_NUM_MOT_VECTORS_X_TT "the number of motion vectors on the x-axis" + IDS_MENU_NUM_MOT_VECTORS_Y " num. mot. vectors (Y)" + IDS_MENU_NUM_MOT_VECTORS_Y_TT "the number of motion vectors on the y-axis" + IDS_MENU_OFFSET_X " offset (X)" + IDS_MENU_OFFSET_X_TT "horizontal placement offset of the motion vectors" + IDS_MENU_OFFSET_Y " offset (Y)" + IDS_MENU_OFFSET_Y_TT "vertical placement offset of the motion vectors" +END + +STRINGTABLE +BEGIN + IDS_MENU_TRAIL_LENGTH " trail length" + IDS_MENU_TRAIL_LENGTH_TT "the length of the motion vectors (1=normal)" + IDS_MENU_COLOR_RED_MOTION_VECTOR_TT + "amount of red color in the motion vectors" + IDS_MENU_COLOR_GREEN_MOTION_VECTOR_TT + "amount of green color in the motion vectors" + IDS_MENU_COLOR_BLUE_MOTION_VECTOR_TT + "amount of blue color in the motion vectors" + IDS_MENU_ZOOM_AMOUNT "zoom amount" + IDS_MENU_ZOOM_AMOUNT_TT "controls inward/outward motion. 0.9=zoom out, 1.0=no zoom, 1.1=zoom in" + IDS_MENU_ZOOM_EXPONENT " zoom exponent" + IDS_MENU_ZOOM_EXPONENT_TT "controls the curvature of the zoom; 1=normal" + IDS_MENU_WARP_AMOUNT "warp amount" + IDS_MENU_WARP_AMOUNT_TT "controls the magnitude of the warping; 0=none, 1=normal, 2=major warping..." + IDS_MENU_WARP_SCALE " warp scale" + IDS_MENU_WARP_SCALE_TT "controls the wavelength of the warp; 1=normal, less=turbulent, more=smoother" + IDS_MENU_WARP_SPEED " warp speed" + IDS_MENU_WARP_SPEED_TT "controls the speed of the warp; 1=normal, less=slower, more=faster" + IDS_MENU_ROTATION_AMOUNT "rotation amount" +END + +STRINGTABLE +BEGIN + IDS_MENU_BLUR3_MIN_COLOR_VALUE_TT + "narrowing these to just the color range you need will greatly increase color fidelity in the blurred images. MUST BE SUBSET OF BLUR1, BLUR2 RANGES." + IDS_MENU_BLUR3_MAX_COLOR_VALUE "blur3: max color value" + IDS_MENU_BLUR3_MAX_COLOR_VALUE_TT + "narrowing these to just the color range you need will greatly increase color fidelity in the blurred images. MUST BE SUBSET OF BLUR1, BLUR2 RANGES." + IDS_MENU_EDIT_PER_VERTEX_EQUATIONS "[ edit per_vertex equations ]" + IDS_MENU_EDIT_PER_VERTEX_EQUATIONS_TT + "read-only: x, y, rad, ang; time, fps, frame, progress; {bass|mid|treb}[_att]\nread/write: dx, dy, zoom, rot, warp, cx, cy, sx, sy, q1-q8" + IDS_MENU_EDIT_WARP_SHADER_TT + "This pixel shader drives the warping, color, etc. of the internal image each frame.\n" + IDS_MENU_EDIT_COMPOSITE_SHADER_TT + "This pixel shader drives the final presentation of the internal image to the screen each frame.\n" + IDS_MENU_EDIT_UPGRADE_PRESET_PS_VERSION + "upgrade preset's pixel shader version" + IDS_MENU_EDIT_UPGRADE_PRESET_PS_VERSION_TT + "Upgrades the preset to the next-available pixel shader version." + IDS_MENU_EDIT_DO_A_PRESET_MASH_UP "do a preset mash-up" + IDS_MENU_EDIT_DO_A_PRESET_MASH_UP_TT + "Mix qualities from many different presets to create a new one." + IDS_MENU_NUMBER_OF_INSTANCES "number of instances" + IDS_MENU_NUMBER_OF_INSTANCES_TT + "the number of times (num_inst) to draw this shape. Each instance will have a different value for 'instance' in the per-frame eqs (0,1,2...)" + IDS_MENU_EDIT_INIT_CODE_SHAPE_TT + "IN: time, frame, fps, progress; q1-q8 (from preset init); x,y,rad,ang; r,g,b,a; r2,g2,b2,a2; border_{r|g|b|a}; sides, thick, additive, textured\nOUT: t1-t8; x,y,rad,ang; r,g,b,a; r2,g2,b2,a2; border_{r|g|b|a}; sides, thick, additive, textured" + IDS_MENU_EDIT_PER_FRAME_INSTANCE_CODE + "[ edit per-frame(/per-instance) code ]" + IDS_MENU_EDIT_PER_FRAME_INSTANCE_CODE_TT + "IN: instance, num_inst, time, frame, fps, progress; q1-q8 (from preset init); x,y,rad,ang; r,g,b,a; r2,g2,b2,a2; border_{r|g|b|a}; sides, thick, additive, textured\nOUT: t1-t8; x,y,rad,ang; r,g,b,a; r2,g2,b2,a2; border_{r|g|b|a}; sides, thick, additive, textured" +END + +STRINGTABLE +BEGIN + IDS_MENU_OPACITY_WAVE_TT + "opacity of the waveform; 0=transparent, 1=opaque" + IDS_MENU_USE_SPECTRUM "use spectrum" + IDS_MENU_USE_SPECTRUM_TT + "if ON, the data in value1 and value2 will constitute a frequency spectrum (instead of waveform values)" + IDS_MENU_USE_DOTS_WAVE_TT + "if ON, the samples will be overdrawn 4X to make them thicker, bolder, and more visible" + IDS_MENU_DRAW_THICK_WAVE_TT + "if ON, the samples will be overdrawn 4X to make them thicker, bolder, and more visible" + IDS_MENU_ADDITIVE_DRAWING_WAVE_TT + "if ON, the samples will add color to sature the image toward white; otherwise, they replace what's there." + IDS_MENU_EXPORT_TO_FILE "--export to file" + IDS_MENU_EXPORT_TO_FILE_TT + "export the settings for this custom waveform to a file on disk" + IDS_MENU_IMPORT_FROM_FILE "--import from file" + IDS_MENU_IMPORT_FROM_FILE_TT + "import settings for a custom waveform from a file on disk" + IDS_MENU_EDIT_INIT_CODE "[ edit initialization code ]" + IDS_MENU_EDIT_INIT_CODE_TT + "IN: time, frame, fps, progress; samples; q1-q8 (from preset init) / OUT: t1-t8" + IDS_MENU_EDIT_PER_FRAME_CODE "[ edit per-frame code ]" + IDS_MENU_EDIT_PER_FRAME_CODE_TT + "IN: time, frame, fps, progress; samples; q1-q8, t1-t8; r,g,b,a; {bass|mid|treb}[_att] / OUT: r,g,b,a; samples; t1-t8" + IDS_MENU_EDIT_PER_POINT_CODE "[ edit per-point code ]" + IDS_MENU_EDIT_PER_POINT_CODE_TT + "IN: sample [0..1]; value1 [left ch], value2 [right ch], plus all vars for per-frame code / OUT: x,y; r,g,b,a; t1-t8" +END + +STRINGTABLE +BEGIN + IDS_MENU_ENABLED_SHAPE_TT "enables or disables this shape" + IDS_MENU_NUMBER_OF_SIDES "number of sides" + IDS_MENU_NUMBER_OF_SIDES_TT + "the default number of sides that make up the polygonal shape" + IDS_MENU_DRAW_THICK_SHAPE_TT + "if ON, the border will be overdrawn 4X to make it thicker, bolder, and more visible" + IDS_MENU_ADDITIVE_DRAWING_SHAPE_TT + "if ON, the shape will add color to sature the image toward white; otherwise, it will replace what's there." + IDS_MENU_X_POSITION "x position" + IDS_MENU_X_POSITION_TT "default x position of the shape (0..1; 0=left side, 1=right side)" + IDS_MENU_Y_POSITION "y position" + IDS_MENU_Y_POSITION_TT "default y position of the shape (0..1; 0=bottom, 1=top of screen)" + IDS_MENU_RADIUS "radius" + IDS_MENU_RADIUS_TT "default radius of the shape (0+)" + IDS_MENU_ANGLE "angle" + IDS_MENU_ANGLE_TT "default rotation angle of the shape (0...3.14*2)" + IDS_MENU_TEXTURED "textured" + IDS_MENU_TEXTURED_TT "if ON, the shape will be textured with the image from the previous frame" + IDS_MENU_TEXTURE_ZOOM "texture zoom" +END + +STRINGTABLE +BEGIN + IDS_MENU_TEXTURE_ZOOM_TT + "the portion of the previous frame's image to use with the shape" + IDS_MENU_TEXTURE_ANGLE "texture angle" + IDS_MENU_TEXTURE_ANGLE_TT + "the angle at which to rotate the previous frame's image before applying it to the shape" + IDS_MENU_INNER_COLOR_RED "inner color (red)" + IDS_MENU_INNER_COLOR_RED_TT + "default amount of red color toward the center of the shape (0..1)" + IDS_MENU_INNER_COLOR_GREEN "inner color (green)" + IDS_MENU_INNER_COLOR_GREEN_TT + "default amount of green color toward the center of the shape (0..1)" + IDS_MENU_INNER_COLOR_BLUE "inner color (blue)" + IDS_MENU_INNER_COLOR_BLUE_TT + "default amount of blue color toward the center of the shape (0..1)" + IDS_MENU_INNER_OPACITY "inner opacity" + IDS_MENU_INNER_OPACITY_TT + "default opacity of the center of the shape; 0=transparent, 1=opaque" + IDS_MENU_OUTER_COLOR_RED "outer color (red)" + IDS_MENU_OUTER_COLOR_RED_TT + "default amount of red color toward the outer edge of the shape (0..1)" + IDS_MENU_OUTER_COLOR_GREEN "outer color (green)" + IDS_MENU_OUTER_COLOR_GREEN_TT + "default amount of green color toward the outer edge of the shape (0..1)" + IDS_MENU_OUTER_COLOR_BLUE "outer color (blue)" +END + +STRINGTABLE +BEGIN + IDS_MENU_OUTER_COLOR_BLUE_TT + "default amount of blue color toward the outer edge of the shape (0..1)" + IDS_MENU_OUTER_OPACITY "outer opacity" + IDS_MENU_OUTER_OPACITY_TT + "default opacity of the outer edge of the shape; 0=transparent, 1=opaque" + IDS_MENU_BORDER_COLOR_RED "border color (red)" + IDS_MENU_BORDER_COLOR_RED_TT + "default amount of red color in the shape's border (0..1)" + IDS_MENU_BORDER_COLOR_GREEN "border color (green)" + IDS_MENU_BORDER_COLOR_GREEN_TT + "default amount of green color in the shape's border (0..1)" + IDS_MENU_BORDER_COLOR_BLUE "border color (blue)" + IDS_MENU_BORDER_COLOR_BLUE_TT + "default amount of blue color in the shape's border (0..1)" + IDS_MENU_BORDER_OPACITY "border opacity" + IDS_MENU_BORDER_OPACITY_TT + "default opacity of the shape's border; 0=transparent, 1=opaque" + IDS_MENU_EXPORT_TO_FILE_SHAPE_TT + "export the settings for this custom shape to a file on disk" + IDS_MENU_IMPORT_FROM_FILE_SHAPE_TT + "import settings for a custom shape from a file on disk" + IDS_ERROR_UNABLE_TO_SAVE_THE_FILE "ERROR: unable to save the file" +END + +STRINGTABLE +BEGIN + IDS_ERROR_PRESET_NOT_FOUND_X "ERROR: preset not found: %s" + IDS_ERROR_NO_PRESET_FILES_OR_DIRS_FOUND_IN_X + "ERROR: No preset files OR directories found in %s*.milk" + IDS_SCANNING_PRESETS " scanning presets... " + IDS_SPRITE_X_ERROR_COULD_NOT_FIND_IMG_OR_NOT_DEFINED + "sprite #%d error: could not find 'img=' setting, or sprite is not defined" + IDS_WARNING_PRESET_X_ERROR_IN_PRESET_INIT_CODE + "warning: preset ""%s"": error in 'preset_init' code" + IDS_WARNING_PRESET_X_ERROR_IN_PER_FRAME_CODE + "warning: preset ""%s"": error in 'per-frame' code" + IDS_WARNING_PRESET_X_ERROR_IN_PER_VERTEX_CODE + "warning: preset ""%s"": error in 'per-vertex' code" + IDS_HZ "Hz" + IDS_HELP_MINIMIZE_WINAMP "Help on 'Minimize Winamp...' checkbox" + IDS_HELP_MINIMIZE_WINAMP_HELP + "Enable this if you can sometimes see the Winamp window flickering\nthrough, when you run the plug-in fullscreen. Enabling this option\nwill force the Winamp window to minimize whenever the plug-in goes\nfullscreen on the same monitor that the Winamp window is on.\nThe Winamp window will be restored as soon as the plug-in returns\nfrom fullscreen mode.\n\nNote that this also applies for 'fake' fullscreen mode (as well as 'real'\nfullscreen mode).\n\nKeep in mind that when running graphically demanding applications\n(such as this plug-in), it's always good to minimize (or close) as many\nother applications as possible, even if they appear to be idle." + IDS_DIRECTX_MISSING_OR_CORRUPT_TEXT + "Failed to initialize DirectX 9.0 or later.\nMilkdrop requires d3dx9_31.dll to be installed.\n\nWould you like to be taken to:\nhttp://www.microsoft.com/download/details.aspx?id=35,\nwhere you can update DirectX 9.0?\n" + IDS_PARENT_DIRECTORY "parent directory" + IDS_RAND_TITLE "Time between random song title animation" + IDS_RAND_MSG "Time between random custom messages" + IDS_MAX_IMAGES_BYTES "Image cache settings" + IDS_PAGE_X " Page %d " +END + +STRINGTABLE +BEGIN + IDS_SAVE_SUCCESSFUL "[save successful]" + IDS_ERROR_UNABLE_TO_DELETE_THE_FILE "ERROR: unable to delete the file" + IDS_PRESET_X_DELETED "[preset ""%s"" deleted]" + IDS_ERROR_A_FILE_ALREADY_EXISTS_WITH_THAT_FILENAME + "ERROR: a file already exists with that filename" + IDS_ERROR_UNABLE_TO_RENAME_FILE "ERROR: unable to rename the file" + IDS_RENAME_SUCCESSFUL "[rename successful]" + IDS_SPRITE_X_WARNING_ERROR_IN_INIT_CODE + "sprite #%d warning: error in initialization code " + IDS_SPRITE_X_WARNING_ERROR_IN_PER_FRAME_CODE + "sprite #%d warning: error in per-frame code" + IDS_SPRITE_X_ERROR_BAD_SLOT_INDEX "sprite #%d error: bad slot index" + IDS_SPRITE_X_ERROR_IMAGE_FILE_MISSING_OR_CORRUPT + "sprite #%d error: image file missing or corrupt" + IDS_SPRITE_X_ERROR_OUT_OF_MEM + "sprite #%d error: out of memory, unable to load image" + IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_INIT_CODE + "warning: preset ""%s"": error in wave %d init code" +END + +STRINGTABLE +BEGIN + IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_PER_FRAME_CODE + "warning: preset ""%s"": error in wave %d per-frame code" + IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_PER_POINT_CODE + "warning: preset ""%s"": error in wave %d per-point code" + IDS_WARNING_PRESET_X_ERROR_IN_SHAPE_X_INIT_CODE + "warning: preset ""%s"": error in shape %d init code" + IDS_WARNING_PRESET_X_ERROR_IN_SHAPE_X_PER_FRAME_CODE + "warning: preset ""%s"": error in shape %d per-frame code" + IDS_CONFIG_PANEL_BUTTON_1 "Common Settings" + IDS_CONFIG_PANEL_BUTTON_2 "MORE SETTINGS" + IDS_CONFIG_PANEL_BUTTON_3 "Artist Tools" + IDS_CONFIG_PANEL_BUTTON_4 "Transitions" + IDS_CONFIG_PANEL_BUTTON_5 " " + IDS_CONFIG_PANEL_BUTTON_6 " " + IDS_CONFIG_PANEL_BUTTON_7 " " + IDS_CONFIG_PANEL_BUTTON_8 " " + IDS_EXTRA_FONT_1_NAME "Tooltips" + IDS_EXTRA_FONT_2_NAME "Animated Songtitles" + IDS_PRESS_F1_MSG "Press F1 for Help " + IDS_GRAPHICS_SUBSYSTEM_IS_TEMPORARILY_UNSTABLE + "One or more fullscreen display adapters are behaving strangely and will not\nreport a list of display modes. It's quite possible that your graphics subsystem\nis temporarily unstable.\n\nSUGGESTED ACTION: If you have modified your multimon setup or Windows,\ndisplay settings, or have updated any display drivers or installed\nany new programs, you should probably REBOOT YOUR COMPUTER before\ntrying to configure (or run) the plug-in again." +END + +STRINGTABLE +BEGIN + IDS_UNKNOWN "UNKNOWN" + IDS_DISABLED_PAGE_TEARING "(disabled/pg. tearing)" + IDS_NONE "(none)" + IDS_UNLIMITED "(unlimited)" + IDS_X_FRAME_SEC "%2d frames/sec" + IDS_HELP_ON_X_BUTTON "Help on '%s' button" + IDS_FONTS_HELP "Click this button to alter the fonts that are used to display text\nwhile the plug-in is running." + IDS_DUAL_HEAD_HELP "Click this button for special options concerning DualHead video cards\nthat are capable of running in double-width or double-height display\nmodes. DualHead cards that support this treat the two monitors as\none giant, double-width or double-height display.\n\nThis would usually mean that when going Fullscreen, the plug-in would be\nstretched over both monitors. However, when you run the plug-in in\nDesktop Mode or in *Fake* Fullscreen Mode, you can get around this,\nand allow the plug-in to run on just one monitor, leaving you free\nto work on the other." + IDS_MULTI_SAMPLING "Help on Multisampling" + IDS_MULTI_SAMPLING_HELP "This controls the level of full-scene anti-aliasing (blending)\nthat the display adapter uses. Only newer video cards will\ntend to support this feature. Anti-aliasing softens out the\n'jaggies' that you sometimes see at the pixel level, for example,\nat the silhouette of an object, or on a wireframe object.\n\nA level of '2X' would mean that 3D rendering/rasterization is done\ninternally *at double-resolution*, and then downsampled before final\ndisplay to the user. A level of '3X' would mean that the rendering\nis done at triple-resolution, and so on.\n\nNote that, due to limitations of the DirectX 8 API, the use of multisampling\ngenerally requires that page tearing be allowed; the one exception is 'true'\nfullscreen mode, where you can have the best of both worlds: you can disable\npage tearing and enable multisampling at the same time." + IDS_MAX_FRAMERATE "Help on Max Framerate" + IDS_MAX_FRAMERATE_HELP "This controls the maximum # of times the image will be updated, per second.\nFramerate is also commonly called ""FPS"", or ""frames per second.""\n\nIf the plug-in is running too quickly for your taste, you can lower the\nmaximum framerate to slow it down. You might also want to do this if\nthe plug-in is 'hogging the CPU' and slowing down other applications.\n\nTypically, a framerate of 30 looks good; 60 looks great. The human eye\nhas a hard time processing more than 60 fps, though.\n\nNote that if the animation is rendering below the maximum framerate here,\nyour CPU will likely be in 100%% use, leaving your computer somewhat\nunresponsive. If this is the case, try lowering the max. framerate\nuntil it takes effect, and then your computer should become more responsive.\n\nAlso keep in mind that it's a good idea to try and set the max. framerate\nto the current refresh rate of your monitor (e.g. 60 Hz, 72 Hz, etc.)\nor an integer factor of that number; for example, at a 72 Hz monitor\nrefresh rate, good max. framerates would be 2, 3, 4, 6, 8, 9, 12, 18,\n24, 36, or 72." + IDS_FAKE_FULLSCREEN "Help on 'fake' fullscreen mode" + IDS_FAKE_FULLSCREEN_HELP + "When this option is enabled, the display mode is never changed by\nthe plug-in; instead, the plug-in 'fakes' fullscreen mode by simply\nthe plug-in; instead, the plug-in 'fakes' fullscreen mode by simply\nthe window on top.\n\nDUALHEAD: Fake fullscreen mode can be especially handy when you have a\ndualhead display adapter that drives two monitors, but really just treats\nthem as one giant display (e.g. **the display mode is something like 2048x768\nor 1024x1536**), where regular fullscreen mode will take over both monitors,\ncreating a very large, stretched image. HOWEVER, if you use fake\nfullscreen mode, it can (if you want) take over just one monitor, leaving\nyou free to work on the other monitor. To choose which display to favor\n(or to span both), click the 'DualHead' button and follow the instructions\nthere.\n\nTASKBAR: Note that in fake fullscreen mode, the taskbar will still be visible\n(and usable) if the plug-in does not entirely cover all displays & all monitors.\nIf you don't like it, use 'true' fullscreen mode instead, or move the taskbar\n(...there should be a place to move it to, since the plug-in doesn't cover all\nof your displays). However, if the plug-in does cover all displays and all\nmonitors, the taskbar should be nicely hidden." + IDS_FULLSCREEN_ADAPTER "Help on fullscreen display adapter selection" + IDS_FULLSCREEN_ADAPTER_HELP + "This lets you select which display adapter (video card) you'd like to\nrun the plug-in on, when it goes fullscreen. If you only have one video\ncard and monitor in your system, you will only have one choice here; but\nif you have multiple video cards, or a multi-head video card (one card\nthat drives multiple monitors), there should be two or more choices here.\n\nNote that if you have trouble running in fullscreen mode with multiple\ndisplays, you might want to try the 'fake fullscreen mode' option.\nSee its help screen for more information." +END + +STRINGTABLE +BEGIN + IDS_WINDOWED_ADPATER "Help on windowed-mode display adapter selection" + IDS_WINDOWED_ADPATER_HELP + "This lets you select which display adapter (video card) you'd like to\nrun the plug-in on, when it runs in a window. If you only have one video\ncard and monitor in your system, you will only have one choice here; but\nif you have multiple video cards, or a multi-head video card (one card\nthat drives multiple monitors), there should be two or more choices here.\n\nThe default window position will be somewhere on the monitor for the\ndisplay adapter you choose here. You can drag the window to a different\nmonitor, but it is likely to be very slow, because the pixels will have\nto be copied, via Windows, from one display to the next, each frame.\n\nSo, for best performance in windowed mode, be sure to select the monitor\nyou want it to run on here, in advance, and avoid dragging the window to\nanother monitor at runtime." + IDS_DESKTOP_ADAPTER "Help on desktop-mode display adapter selection" + IDS_DESKTOP_ADAPTER_HELP + "This lets you select which display adapter (video card & monitor) you'd like to\nrun the plug-in on, when it runs in desktop mode, replacing your windows wallpaper.\nIf you only have one video card and monitor in your system, you will only have\none choice here; but if you have multiple video cards, or a multi-head video card\n(one card that drives multiple monitors), there should be two or more choices here." + IDS_HELP_ON_X_CHECKBOX "Help on '%s' checkbox" + IDS_HELP_ON_X_CHECKBOX_HELP + "When a new frame of animation is ready for display, the plug-in\nhas a choice of whether or not to synchronize the new frame to the\nmonitor's next vertical scan.\n\nIf there is no synchronization and the new frame is shown immediately,\nthen the update might occure in 'mid-scan', so for that 1/60th of a second,\nyou'll see the old frame toward the top of the monitor, and the new frame\ntoward the bottom, with a sharp line ('tear') somewhere in between. This\nis especially visible when solid objects on the screen are changing or\nmoving rapidly, from frame to frame.\n\nHowever, if the plug-in waits until the vertical scan is complete to update\nthe image, then at the start of the next vertical scan, the entire image\nwill be ready and will (hopefully) be presented without any tearing.\n\nAlthough page tearing will often cause visible artifacts, it will allow\nthe plug-in to run at its maximum possible framerate. Generally, though,\npage tearing is considered a bad thing, to be avoided when possible.\n\nNote that this synchronization (done by DirectX and your video driver)\nis usually approximate when running in windowed (or fake fullscreen) modes;\nthus, page tearing is often minimized but can't always be completely eliminated.\n\nNote that multisampling is usually only available when page tearing is\nallowed, due to limitations of the DirectX 8 API. The one exception is\n'true' fullscreen mode; there, you can disable page tearing and still use\nmultisampling. (But not in fake fullscreen, windowed, or desktop modes.)" + IDS_FORCE_INTO_FS_MODE_HELP + "Enable this to force the plug-in to start in fullscreen\n(or 'fake fullscreen') mode.\n\n(Note that if 'fake' fullscreen mode is enabled,\nthe plug-in will start in fake fullscreen mode.)" + IDS_FORCE_INTO_DESKTOP_MODE_HELP + "Enable this to force the plug-in to start in desktop mode." + IDS_HELP_ON_F1 "Help on 'Press F1...' checkbox" + IDS_HELP_ON_F1_HELP "Disable this to prevent the 'Press F1 for Help' message\nfrom appearing when the plug-in starts." + IDS_CB_SKIN_HELP "Check this box to 'skin' the plug-in's window frame when it runs\nin a window, so that it looks like the rest of the windows that\nmake up Winamp's interface.\n\nThis feature requires Winamp 2.90 or later; if the box is greyed\nout, it means you need a newer version of Winamp." + IDS_SAVE_CPU_CHECKBOX "Help on 'Save CPU' checkbox" + IDS_SAVE_CPU_CHECKBOX_HELP + "Check this box to lower the amount of CPU (processor) that the plug-in uses\nto monitor and limit the framerate.\n\nWhen this box is unchecked, the plug-in will extremely accurately limit the\nframerate, resulting in ultra-smooth animation. However, there is some cost\nin terms of CPU time - usually in the range of 0-20%%.\n\nWhen this box is checked, though, the plug-in uses a more lenient algorithm to\nlimit the framerate, which uses virtually no CPU time. However, the framerate\nwill not be as accurately limited (it might vary over time), and animation is\nnot guaranteed to be perfectly smooth.\n\nNote that you can further decrease CPU usage by:\n 1) decreasing the maximum framerate (via the 'Max Framerate' options)\n 2) allowing page tearing (via the 'Allow Page Tearing' checkboxes)" + IDS_FS_DISPLAY_MODE "Help on fullscreen display mode selection" + IDS_FS_DISPLAY_MODE_HELP + "This lets you select which display mode you'd like to use when you\nrun the plug-in fullscreen.\n\nThe first parameter is the pixel color format, which decides\nthe total number of possible colors in the rendered image.\nRGB-555 and RGB-565 are 16-bit color formats, which have poor\ncolor resolution but are often fast. RGB-888 is a 32-bit color\nformat; it often has superior image quality, but is often slower\nand takes up twice the video memory.\n\nThe next two parameters are the width and height of the display mode,\nin pixels, also known as the 'resolution'. Higher resolutions are\nusually slower and require more video memory, but look better.\n\nThe last parameter is the refresh rate: the rate at which the\n""monitor refreshes the image you see, in Hertz (cycles per second).\nHigher refresh rates tend to be easier on the eyes." +END + +STRINGTABLE +BEGIN + IDS_TRY_TO_FIX_SLOW_TEXT "Help on 'Try to fix slow text' checkbox" + IDS_TRY_TO_FIX_SLOW_TEXT_HELP + "Many video cards - even new ones - are very slow at drawing onscreen text.\nMost application render onscreen text overtop of the final image\n*every frame*, but since MilkDrop has so many menus, this can severely\ndrop the framerate.\n\nA workaround is invoked by checking this box. Instead of drawing the\ntext every frame, it is instead drawn to a second image buffer, and then\nonly updated when the text changes. That separate image buffer is then\noverlaid onto the final image for display, each frame. By not redrawing\nthe same text over and over, MilkDrop maintains a normal framerate.\n\nThis option is good for maintaining speed, but it uses a substantial amount\nof video memory. You should probably only use it if you have 32 megabytes\n(or more) of graphics memory. If there is not enough video memory to set\nup the offscreen image buffer for cacheing the text, it will not be created,\nand MilkDrop will behave as if the box was unchecked." + IDS_VJ_MODE "Help on VJ Mode" + IDS_VJ_MODE_HELP "VJ mode is used by those who want to show MilkDrop on one display\nwhile working with it on the other display. When VJ mode is on,\ntext is drawn into a second window, instead of being overlaid on\ntop of the graphics. This leaves the 'VJ' (the person running the\nvisuals for a concert, for example) able to navigate milkdrop's menus\nand edit presets while MilkDrop runs on a second display (likely\nrunning to a projector), without the ugly menus showing up.\n\nIMPORTANT: whichever windowed mode display adapter you have selected \ndetermines which monitor the separate text window appears on, and runs\nbest on. If you try dragging (moving) it to another monitor, performance\nwill be severely impacted; instead, exit MilkDrop, return to the config\npanel, and set the windowed mode display adapter to reflect the monitor\nyou want the separate text window to appear on." + IDS_HELP_ON_X "Help on '%s'" + IDS_DMS_LABEL_HELP "These settings control the behavior of the plug-in when it is running\nin 'desktop mode'. In desktop mode, the plug-in is visible in your\nWindows background, replacing your wallpaper with the animated plug-in." + IDS_FS_LABEL_HELP "These settings control the behavior of the plug-in when it is running\nin fullscreen mode. In fullscreen mode, the plug-in changes the display\nmode to whatever you indicate here, and then uses the entire display\nto render the image.\n\nFullscreen mode also gives the plug-in certain privileges within the\ngraphics subsystem (it enters 'exclusive mode'), so performance is\nusually quite improved." + IDS_W_LABEL_HELP "These settings control the behavior of the plug-in when it is running\nin a window. In windowed mode, the plug-in renders right into a window,\njust like any other application you might have running.\n\nWhen the plug-in starts, the default window position will be somewhere\non the monitor for the display adapter you choose here.\nYou *can* drag the window to a different monitor, but it is likely to be,\nVERY slow because the pixels will have to be copied, via Windows, from\none display to the next, each frame.\n\nSo, for best performance in windowed mode, be sure to select the monitor\nyou want it to run on here, in advance, and avoid dragging the window to\nanother monitor at runtime." + IDS_DM_MORE_HELP "Click here to bring up a dialog with\nadvanced settings for Desktop Mode." + IDS_INITCONFIG_FAILED "InitConfig() failed!" + IDS_UNABLE_TO_LOAD_TABS "Unable to load tabs!" + IDS_DOCUMENTATION_FILE_NOT_FOUND + "the documentation file:\n\n\t%s\n\ncould not be found." + IDS_ACCESS_TO_DOCUMENTATION_FILE_DENIED + "access to the documentation file:\n\n\t%s\n\nwas denied." + IDS_ACCESS_TO_DOCUMENTATION_FILE_FAILED_DUE_TO_NO_ASSOC + "the documentation file:\n\n\t%s\n\ncould not be accessed because there is no application\nassociated with documents of this type." + IDS_ACCESS_TO_DOCUMENTATION_FILE_FAILED_CODE_X + "the documentation file:\n\n\t%s\n\ncould not be accessed (error code: %d)" +END + +STRINGTABLE +BEGIN + IDS_ERROR_OPENING_DOCUMENTATION "Error Opening Documentation" + IDS_URL_COULD_NOT_OPEN "the URL\n\n\t%s\n\ncould not be opened." + IDS_ACCESS_TO_URL_WAS_DENIED "access to the URL\n\n\t%s\n\nwas denied." + IDS_ACCESS_TO_URL_FAILED_DUE_TO_NO_ASSOC + "the URL\n\n\t%s\n\ncould not be accessed because there is no application\nassociated with documents of this type." + IDS_ACCESS_TO_URL_FAILED_CODE_X + "the URL\n\n\t%s\n\ncould not be accessed (error code: %d)" + IDS_ERROR_OPENING_URL "Error Opening URL" + IDS_RESTORE_ALL_DEFAULTS + "Are you sure you want to restore the default settings?\n\nIf you click YES, the config panel will close and the defaults will be restored." + IDS_RESTORE_ALL_DEFAULTS_TITLE "Restore Default Settings?" + IDS_OK_HELP "Click this button to save your changes and return to Winamp." + IDS_CANCEL_HELP "Click this button to cancel any changes and return to Winamp." + IDS_RESTORE_DEFAULTS_HELP + "Click this button to restore all config panel settings\nto their 'factory' defaults and then return to Winamp." + IDS_DOCUMENTATION_BUTTON_HELP + "Click this button to view the documentation for this plug-in." + IDS_VIEW_ONLINE_DOCS_HELP + "Click this button to view the website (homepage) for this plug-in\nusing your default browser." + IDS_5_6_5_TEXTURE "a 5-6-5 texture (no transparency)" + IDS_5_5_5_TEXTURE "a 5-5-5 texture (w/1 bit of transparency)" + IDS_8_8_8_TEXTURE "an 8-8-8 texture (w/8 bits of transparency)" +END + +STRINGTABLE +BEGIN + IDS_NO_ALPHA_FALLBACK "Help on ""no alpha"" fallback options" + IDS_NO_ALPHA_FALLBACK_HELP + "If you run the plug-in in desktop mode and find that your\ndesktop icons are surrounded by black boxes, then you'll\nwant to experiment with this setting. The black box means\nthat 'alpha' (transparency) is not working, probably because\nyour current video mode (that Windows is running in) does\nnot have an alpha channel. To make a long story short,\njust try different options here if you get the 'black box'\neffect, and cross your fingers that one of these works.\n\nNote that the 5-6-5 option uses half as much video memory\nas the 8-8-8 option, so if they both work, use the 5-6-5." + IDS_CB_SHOW_ICONS_HELP "When you're running in desktop mode, this option lets you\nchoose to show or hide the icons that normally sit on your\ndesktop." + IDS_CB_BOX "Help on 'Draw colored boxes...' checkbox" + IDS_CB_BOX_HELP "This option lets you choose whether or not you want to\nsee a solid-colored box around each of the text labels\nfor the icons on your desktop, while the plug-in is running.\n\nIf you turn it off, the icon text labels might be harder\nto read (depending on the current image that the plug-in is\ngenerating), but the icons will also tend to dominate the\nscreen less." + IDS_CB_MANUAL_SCOOT "Help on icon occlusion checkbox" + IDS_CB_MANUAL_SCOOT_HELP + "Normally, when you put your Windows taskbar on the Top or Left\nedge of the screen, Windows nicely scoots your desktop icons out\nfrom underneath it, so that they remain visible.\n\nThis plug-in tries to do the same thing, but on a few video cards,\nthe desktop icons might still be occluded (covered) by the taskbar\nwhen you run the plug-in in Desktop Mode (and the taskbar sits along\nthe Top or Left edge of the screen.)\n\nIf this happens to you, try checking this box - it will try a\ndifferent algorithm for placing the icons, and should manage to\nscoot them out (down or to the right) from underneath the taskbar." + IDS_SPAN_BOTH_SCREENS "span both screens" + IDS_USE_LEFT_SCREEN_ONLY "use left screen only" + IDS_USE_RIGHT_SCREEN_ONLY "use right screen only" + IDS_USE_TOP_SCREEN_ONLY "use top screen only" + IDS_USE_BOTTOM_SCREEN_ONLY "use bottom screen only" + IDS_COULD_NOT_FIND_FILE_FOR_DESKTOP_MODE_X + "Could not find the following file:\n\n %s\n\n...which is required for this plug-in to work properly in Desktop Mode.\nPlease reinstall the plug-in." + IDS_MILKDROP_ERROR_FILE_MISSING "MILKDROP ERROR - FILE MISSING" + IDS_ERROR_CREATING_GDI_DESKTOP_FONT "Error creating GDI desktop font" + IDS_ERROR_CREATING_DESKTOP_FONT "Error creating desktop font" +END + +STRINGTABLE +BEGIN + IDS_ERROR_CREATING_TEXTURE_FOR_ICON_BITMAPS + "Error creating texture for icon bitmaps" + IDS_OUTDATED_VMS_DESKTOP_DLL_NEED_TO_REINSTALL + "It appears that you have an outdated copy of the file 'vms_desktop.dll'\nin your Winamp PLUGINS directory. Please reinstall the plug-in\nto bring this file up to date." + IDS_ERROR_CREATING_HOOK_PROC_DESKTOP_ICONS_NOT_AVAILABLE + "Error creating hook procedure;\ndesktop icons will not be available." + IDS_ERROR_UPDATING_ICON_BITMAPS + "Error updating icon bitmaps; the number of unique\nicon bitmaps on your desktop exceeded the maximum.\n\nAs a result, not all icons will look correct." + IDS_ERROR_UPDATING_ICON_BITMAPS_TOO_MANY_UNIQUE_ICON_BITMAPS + "Error updating icon bitmaps: there were a lot of unique icon bitmaps,\nbut the plug-in couldn't allocate enough extra texture(s) to hold them all,\nprobably because video memory is low.\n\nAs a result, not all icons will look correct." + IDS_ERROR_UPDATING_ICON_BITMAPS_COULD_NOT_GET_LEVEL_DESCRIPTION + "Error updating icon bitmaps:\ncouldn't get level description" + IDS_ERROR_UPDATING_ICON_BITMAPS_LOCKRECT_FAILED + "Error updating icon bitmaps:\nLockRect failed" + IDS_ERROR_UPDATING_ICON_BITMAPS_LR_PBITS_IS_NULL + "Error updating icon bitmaps:\nlr.pBits == NULL" + IDS_ERROR_UPDATING_ICON_BITMAPS_UNKNOWN_PIXEL_FORMAT + "Error updating icon bitmaps:\nunknown pixel format" + IDS_ERROR_UPDATING_ICON_BITMAPS_COULDNT_GET_HDC + "Error updating icon bitmaps:\ncouldn't get HDC" + IDS_ERROR_UPDATING_ICON_BITMAPS_CALL_TO_GETDIBITS_FAILED + "Error updating icon bitmaps:\ncall #1 to GetDIBits failed." + IDS_ERROR_UPDATING_ICON_BITMAPS_CALL_2_TO_GETDIBITS_FAILED + "Error updating icon bitmaps:\ncall #2 to GetDIBits failed." + IDS_ERROR_UPDATING_ICON_BITMAPS_GETICONINFO_FAILED + "Error updating icon bitmaps:\nGetIconInfo failed." + IDS_ERROR_UPDATING_ICON_BITMAPS_SHGETFILEINFO_FAILED + "Error updating icon bitmaps:\nSHGetFileInfo failed." + IDS_UNABLE_TO_REGISTER_WINDOW_CLASS + "Unable to register the window class;\nPLEASE RESTART WINAMP." + IDS_DIRECTX_INIT_FAILED "DirectX initialization failed; unknown color format" +END + +STRINGTABLE +BEGIN + IDS_VJ_MODE_INIT_ERROR "VJ mode init error: error determining color format\nfor currently-selected Windowed Mode display adapter." + IDS_ERROR_REGISTERING_WINDOW_CLASS_FOR_TEXT_WINDOW + "Error registering window class for text window" + IDS_ERROR_CREATING_VJ_WINDOW "Error creating VJ window" + IDS_ERROR_CREATING_D3D_DEVICE_FOR_VJ_MODE + "Error creating D3D device for VJ mode" + IDS_ERROR_CREATING_D3DX_FONTS "Error creating D3DX fonts" + IDS_UNABLE_TO_INIT_DXCONTEXT + "Unable to initialize DXContext;\nprobably out of memory." + IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG + "To free up some memory, please RESTART WINAMP, then return\n to the plug-in's config panel and try setting your\n WINDOWED MODE MULTISAMPLING back to 'NONE.'\n\nThen try running the plug-in again." + IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_2 + "To free up some memory, please RESTART WINAMP, then return\n to the plug-in's config panel and try setting your\n FAKE FULLSCREEN MODE MULTISAMPLING back to 'NONE.'\n\nThen try running the plug-in again." + IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_3 + "To free up some memory, please RESTART WINAMP, then return\n to the plug-in's config panel and try setting your\n FULLSCREEN MODE MULTISAMPLING back to 'NONE.'\n\nThen try running the plug-in again." + IDS_TO_FREE_UP_VIDEO_MEMORY + "To free up some video memory, try the following:\n\n1. Try closing all other applications that might be using video memory, especially:\n\n * WINDOWS MEDIA PLAYER\n * any video conferencing software, such as NETMEETING\n * any DVD playback, TV tuner, or TV capture software\n * any video editing software\n * any software that uses Overlays, such as Drempels Desktop\n * any audio dictation software, such as Dragon NaturallySpeaking\n * any other 3D programs currently running\n\n2. Also try returning to the config panel (ALT+K) and selecting a display mode\n that uses less video memory. 16-bit display modes use half as much memory\n as 32-bit display modes, and lower-resolution display modes (such as 640 x 480)\n use proportionally less video memory.\n\nAfter making these changes, please RESTART WINAMP before trying to run\nthe plug-in again." + IDS_TO_FREE_UP_VIDEO_MEMORY_2 + "To free up some video memory, try the following:\n\n1. Try closing all other applications that might be using video memory, especially:\n\n * WINDOWS MEDIA PLAYER\n * any video conferencing software, such as NETMEETING\n * any DVD playback, TV tuner, or TV capture software\n * any video editing software\n * any software that uses Overlays, such as Drempels Desktop\n * any audio dictation software, such as Dragon NaturallySpeaking\n * any other 3D programs currently running\n\n2. Also try changing your Windows display mode to a lesser bit depth\n (i.e. 16-bit color), or a smaller resolution.\n\nAfter making these changes, please RESTART WINAMP before trying to run\nthe plug-in again." + IDS_MILKDROP_SUGGESTION "MILKDROP SUGGESTION" + IDS_DIRECTX_MISSING_OR_CORRUPT "DirectX Missing or Corrupt" + IDS_ERROR_THE_PLUGIN_IS_ALREADY_RUNNING + "Error: the plug-in is already running." +END + +STRINGTABLE +BEGIN + IDS_MB "MB" + IDS_GB "GB" + IDS_MASHUP_GENERAL_POSTPROC " 1. general, postproc: " + IDS_MASHUP_MOTION_EQUATIONS " 2. motion, equations: " + IDS_MASHUP_WAVEFORMS_SHAPES " 3. waveforms, shapes: " + IDS_MASHUP_WARP_SHADER " 4. warp shader: " + IDS_MASHUP_COMP_SHADER " 5. comp shader: " + IDS_STRING615 " tex2D(sampler_billy, uv) sample pixel from billy.jpg (must be loaded)\n" + IDS_STRING616 " pre-body: sampler sampler_billy; //loads billy.jpg" + IDS_STRING617 " float4 texsize_billy; //.xy = width and height, .zw = 1/w, 1/h" + IDS_STRING618 " sampling textures:" + IDS_STRING619 " tex2D(sampler_main, uv) //sample pixel from prior frame" + IDS_STRING620 " tex2D(sampler_billy, uv) //sample pixel from billy.jpg (must be loaded)" + IDS_STRING621 " GetBlur1(uv) //sample blurred prior-frame pixel (also 2,3)" + IDS_STRING622 " inputs: float2 uv; //warped UV coordinates [0..1]" + IDS_STRING623 " float2 uv_orig; //original UV coordinates [0..1]" +END + +STRINGTABLE +BEGIN + IDS_STRING624 " float rad; //radius [0..1]" + IDS_STRING625 " float ang; //angle [0..PI*2]" + IDS_STRING626 " // + texsize, aspect, time, fps, rand_frame, rand_preset," + IDS_STRING627 " // q1-q32/_qa-_qh, bass, treb_att, vol... - see docs" + IDS_STRING628 " output: float3 ret; //the new pixel color (r,g,b)" + IDS_STRING629 " inputs: float2 uv; //UV coordinates [0..1]" + IDS_STRING630 " float rad; //radius [0..1]" + IDS_STRING631 " float ang; //angle [0..PI*2]" + IDS_STRING632 " float3 hue_shader //for MilkDrop 1 compatibility" + IDS_STRING633 " // + texsize, aspect, time, fps, rand_frame, rand_preset," + IDS_STRING634 " // q1-q32/_qa-_qh, bass, treb_att, vol... - see docs" + IDS_STRING635 " output: float3 ret; //display pixel color (r,g,b)" + IDS_UPGRADE_SHADERS_TO_USE_PS2X + "Do you want to upgrade all shaders to use (at least) pixel shader 2.X? [y/N]" + IDS_PRESS_ESC_TO_RETURN "Press ESC to return." + IDS_COULD_NOT_LOAD_TEXTURE_X "Could not load texture: %hs.%hs" + IDS_ERROR_COMPILING_X_X_SHADER "Error compiling %hs %hs shader:\n" +END + +STRINGTABLE +BEGIN + IDS_ERROR_PARSING_X_X_SHADER "Error parsing %hs %hs shader.\n" + IDS_UNABLE_TO_RESOLVE_TEXSIZE_FOR_A_TEXTURE_NOT_IN_USE + "Unable to resolve texsize for a texture that is not in use! (%hs)" + IDS_KEY_MAPPINGS "yYYyYzZ" +END + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/vis_milk2/plugin.vcproj b/vis_milk2/plugin.vcproj new file mode 100644 index 0000000..84f91e7 --- /dev/null +++ b/vis_milk2/plugin.vcproj @@ -0,0 +1,675 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vis_milk2/plugin_icon.ico b/vis_milk2/plugin_icon.ico new file mode 100644 index 0000000..a48a54f Binary files /dev/null and b/vis_milk2/plugin_icon.ico differ diff --git a/vis_milk2/pluginshell.cpp b/vis_milk2/pluginshell.cpp new file mode 100644 index 0000000..55ff69b --- /dev/null +++ b/vis_milk2/pluginshell.cpp @@ -0,0 +1,3685 @@ +/* + 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 + are ideal (given the current windows display mode or selected FS dispmode). + -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 + and overlap our waveform windows, so we'd never miss a brief high note. + -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 2nd 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] + -kiv: with embedded windows of any type (plugin, playlist, etc.) + you can't place the winamp main wnd over them. + -kiv: embedded windows are child windows and don't get the + 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 @ 1280x1024. + (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.h" +#include "pluginshell.h" +#include "utility.h" +#include "defines.h" +#include "shell_defines.h" +#include "resource.h" +#include "vis.h" +#include +#include "../Winamp/wa_ipc.h" +#include "../nu/AutoCharFn.h" +#include +#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; iGetAdapterCount(); + for (int i=0; iGetAdapterIdentifier(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; iGetHwnd() : 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 (i=0; iDrawText(NULL, "M", -1, &r, DT_CALCRECT, 0xFFFFFFFF); + if (h>0) m_fontinfo[i].nSize = h; + } + + return true; +} + +void CPluginShell::CleanUpFonts() +{ + for (int i=0; iGetLevelDesc(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; im_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; iDrawText(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; im_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(¶ms); + + if (!m_lpDX->StartOrRestartDevice(¶ms)) + { + // 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(¶ms); + + if (!m_lpDX->StartOrRestartDevice(¶ms)) + { + // 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(¶ms); + + if (!m_lpDX->StartOrRestartDevice(¶ms)) + { + // 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 + for (int i=0; i= 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 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); + while (h) //(..shouldn't be very many windows to iterate through here) + { + 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= 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 (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 (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; im_client_width - TEXT_MARGIN*2 - PLAYLIST_INNER_MARGIN*2); + + for (int i=0; iDrawTextW(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; iGetBitDepth() == 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; idwData & 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() && ix = 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 + // in a multimon setup, any windows that are overtop of the + // '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_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_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; + } + 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; im_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][]? + for (int octave=1; octave1) 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; n0) + 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 (ch=0; ch<2; ch++) + if (align_offset[ch]>0) + { + for (int i=0; iPluginShellVJModeWndProc(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 + // in a multimon setup, any windows that are overtop of the + // '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); +} \ No newline at end of file diff --git a/vis_milk2/pluginshell.h b/vis_milk2/pluginshell.h new file mode 100644 index 0000000..8486063 --- /dev/null +++ b/vis_milk2/pluginshell.h @@ -0,0 +1,371 @@ +/* + 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. +*/ + +#ifndef __NULLSOFT_DX9_PLUGIN_SHELL_H__ +#define __NULLSOFT_DX9_PLUGIN_SHELL_H__ 1 + +#include "shell_defines.h" +#include "dxcontext.h" +#include "fft.h" +#include "defines.h" +#include "textmgr.h" + +#include "icon_t.h" +#include "../nu/Vector.h" + +#define TIME_HIST_SLOTS 128 // # of slots used if fps > 60. half this many if fps==30. +#define MAX_SONGS_PER_PAGE 40 + +typedef struct +{ + wchar_t szFace[256]; + int nSize; // size requested @ font creation time + int bBold; + int bItalic; + int bAntiAliased; +} td_fontinfo; + +typedef struct +{ + float imm[2][3]; // bass, mids, treble, no damping, for each channel (long-term average is 1) + float avg[2][3]; // bass, mids, treble, some damping, for each channel (long-term average is 1) + float med_avg[2][3]; // bass, mids, treble, more damping, for each channel (long-term average is 1) + float long_avg[2][3]; // bass, mids, treble, heavy damping, for each channel (long-term average is 1) + float infinite_avg[2][3]; // bass, mids, treble: winamp's average output levels. (1) + float fWaveform[2][576]; // Not all 576 are valid! - only NUM_WAVEFORM_SAMPLES samples are valid for each channel (note: NUM_WAVEFORM_SAMPLES is declared in shell_defines.h) + float fSpectrum[2][NUM_FREQUENCIES]; // NUM_FREQUENCIES samples for each channel (note: NUM_FREQUENCIES is declared in shell_defines.h) +} td_soundinfo; // ...range is 0 Hz to 22050 Hz, evenly spaced. + +class CPluginShell +{ +public: + // GET METHODS + // ------------------------------------------------------------ + int GetFrame(); // returns current frame # (starts at zero) + float GetTime(); // returns current animation time (in seconds) (starts at zero) (updated once per frame) + float GetFps(); // returns current estimate of framerate (frames per second) + eScrMode GetScreenMode(); // returns WINDOWED, FULLSCREEN, FAKE_FULLSCREEN, DESKTOP, or NOT_YET_KNOWN (if called before or during OverrideDefaults()). + HWND GetWinampWindow(); // returns handle to Winamp main window + HINSTANCE GetInstance(); // returns handle to the plugin DLL module; used for things like loading resources (dialogs, bitmaps, icons...) that are built into the plugin. + wchar_t* GetPluginsDirPath(); // usually returns 'c:\\program files\\winamp\\plugins\\' + wchar_t* GetConfigIniFile(); // usually returns 'c:\\program files\\winamp\\plugins\\something.ini' - filename is determined from identifiers in 'defines.h' + char* GetConfigIniFileA(); +protected: + + // GET METHODS THAT ONLY WORK ONCE DIRECTX IS READY + // ------------------------------------------------------------ + // The following 'Get' methods are only available after DirectX has been initialized. + // If you call these from OverrideDefaults, MyPreInitialize, or MyReadConfig, + // they will return NULL (zero). + // ------------------------------------------------------------ + HWND GetPluginWindow(); // returns handle to the plugin window. NOT persistent; can change! + int GetWidth(); // returns width of plugin window interior, in pixels. Note: in windowed mode, this is a fudged, larger, aligned value, and on final display, it gets cropped. + int GetHeight(); // returns height of plugin window interior, in pixels. Note: in windowed mode, this is a fudged, larger, aligned value, and on final display, it gets cropped. + int GetBitDepth(); // returns 8, 16, 24 (rare), or 32 + LPDIRECT3DDEVICE9 GetDevice(); // returns a pointer to the DirectX 8 Device. NOT persistent; can change! + D3DCAPS9* GetCaps(); // returns a pointer to the D3DCAPS9 structer for the device. NOT persistent; can change. + D3DFORMAT GetBackBufFormat(); // returns the pixelformat of the back buffer (probably D3DFMT_R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5, D3DFMT_A4R4G4B4, D3DFMT_R3G3B2, D3DFMT_A8R3G3B2, D3DFMT_X4R4G4B4, or D3DFMT_UNKNOWN) + D3DFORMAT GetBackBufZFormat(); // returns the pixelformat of the back buffer's Z buffer (probably D3DFMT_D16_LOCKABLE, D3DFMT_D32, D3DFMT_D15S1, D3DFMT_D24S8, D3DFMT_D16, D3DFMT_D24X8, D3DFMT_D24X4S4, or D3DFMT_UNKNOWN) + char* GetDriverFilename(); // returns a text string with the filename of the current display adapter driver, such as "nv4_disp.dll" + char* GetDriverDescription(); // returns a text string describing the current display adapter, such as "NVIDIA GeForce4 Ti 4200" + + // FONTS & TEXT + // ------------------------------------------------------------ +public: + LPD3DXFONT GetFont(eFontIndex idx); // returns a D3DX font handle for drawing text; see shell_defines.h for the definition of the 'eFontIndex' enum. + int GetFontHeight(eFontIndex idx); // returns the height of the font, in pixels; see shell_defines.h for the definition of the 'eFontIndex' enum. + CTextManager m_text; +protected: + + // MISC + // ------------------------------------------------------------ + td_soundinfo m_sound; // a structure always containing the most recent sound analysis information; defined in pluginshell.h. + void SuggestHowToFreeSomeMem(); // gives the user a 'smart' messagebox that suggests how they can free up some video memory. + + // CONFIG PANEL SETTINGS + // ------------------------------------------------------------ + // *** only read/write these values during CPlugin::OverrideDefaults! *** + int m_start_fullscreen; // 0 or 1 + int m_start_desktop; // 0 or 1 + int m_fake_fullscreen_mode; // 0 or 1 + int m_max_fps_fs; // 1-120, or 0 for 'unlimited' + int m_max_fps_dm; // 1-120, or 0 for 'unlimited' + int m_max_fps_w; // 1-120, or 0 for 'unlimited' + int m_show_press_f1_msg; // 0 or 1 + int m_allow_page_tearing_w; // 0 or 1 + int m_allow_page_tearing_fs; // 0 or 1 + int m_allow_page_tearing_dm; // 0 or 1 + int m_minimize_winamp; // 0 or 1 + int m_desktop_show_icons; // 0 or 1 + int m_desktop_textlabel_boxes; // 0 or 1 + int m_desktop_manual_icon_scoot; // 0 or 1 + int m_desktop_555_fix; // 0 = 555, 1 = 565, 2 = 888 + int m_dualhead_horz; // 0 = both, 1 = left, 2 = right + int m_dualhead_vert; // 0 = both, 1 = top, 2 = bottom + int m_save_cpu; // 0 or 1 + int m_skin; // 0 or 1 + int m_fix_slow_text; // 0 or 1 + td_fontinfo m_fontinfo[NUM_BASIC_FONTS + NUM_EXTRA_FONTS]; + D3DDISPLAYMODE m_disp_mode_fs; // a D3DDISPLAYMODE struct that specifies the width, height, refresh rate, and color format to use when the plugin goes fullscreen. + + // PURE VIRTUAL FUNCTIONS (...must be implemented by derived classes) + // ------------------------------------------------------------ + virtual void OverrideDefaults() = 0; + virtual void MyPreInitialize() = 0; + virtual void MyReadConfig() = 0; + virtual void MyWriteConfig() = 0; + virtual int AllocateMyNonDx9Stuff() = 0; + virtual void CleanUpMyNonDx9Stuff() = 0; + virtual int AllocateMyDX9Stuff() = 0; + virtual void CleanUpMyDX9Stuff(int final_cleanup) = 0; + virtual void MyRenderFn(int redraw) = 0; + virtual void MyRenderUI(int *upper_left_corner_y, int *upper_right_corner_y, int *lower_left_corner_y, int *lower_right_corner_y, int xL, int xR) = 0; + virtual LRESULT MyWindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) = 0; + virtual BOOL MyConfigTabProc(int nPage, HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) = 0; + virtual void OnAltK() { }; // doesn't *have* to be implemented + +//===================================================================================================================== +private: + + // GENERAL PRIVATE STUFF + eScrMode m_screenmode; // // WINDOWED, FULLSCREEN, or FAKE_FULLSCREEN (i.e. running in a full-screen-sized window) + int m_frame; // current frame #, starting at zero + float m_time; // current animation time in seconds; starts at zero. + float m_fps; // current estimate of frames per second + HWND m_hWndWinamp; // handle to Winamp window + HINSTANCE m_hInstance; // handle to application instance + DXContext* m_lpDX; // pointer to DXContext object + wchar_t m_szPluginsDirPath[MAX_PATH]; // usually 'c:\\program files\\winamp\\plugins\\' + wchar_t m_szConfigIniFile[MAX_PATH]; // usually 'c:\\program files\\winamp\\plugins\\something.ini' - filename is determined from identifiers in 'defines.h' + char m_szConfigIniFileA[MAX_PATH]; // usually 'c:\\program files\\winamp\\plugins\\something.ini' - filename is determined from identifiers in 'defines.h' + + // FONTS + IDirect3DTexture9* m_lpDDSText; + LPD3DXFONT m_d3dx_font[NUM_BASIC_FONTS + NUM_EXTRA_FONTS]; + LPD3DXFONT m_d3dx_desktop_font; + HFONT m_font[NUM_BASIC_FONTS + NUM_EXTRA_FONTS]; + HFONT m_font_desktop; + + // PRIVATE CONFIG PANEL SETTINGS + D3DMULTISAMPLE_TYPE m_multisample_fullscreen; + D3DMULTISAMPLE_TYPE m_multisample_desktop; + D3DMULTISAMPLE_TYPE m_multisample_windowed; + GUID m_adapter_guid_fullscreen; + GUID m_adapter_guid_desktop; + GUID m_adapter_guid_windowed; + char m_adapter_devicename_fullscreen[256]; // these are also necessary sometimes, + char m_adapter_devicename_desktop[256]; // for example, when a laptop (single adapter) + char m_adapter_devicename_windowed[256]; // drives two displays! DeviceName will be \\.\Display1 and \\.\Display2 or something. + + // PRIVATE RUNTIME SETTINGS + int m_lost_focus; // ~mostly for fullscreen mode + int m_hidden; // ~mostly for windowed mode + int m_resizing; // ~mostly for windowed mode + int m_show_help; + int m_show_playlist; + int m_playlist_pos; // current selection on (plugin's) playlist menu + int m_playlist_pageups; // can be + or - + int m_playlist_top_idx; // used to track when our little playlist cache (m_playlist) needs updated. + int m_playlist_btm_idx; // used to track when our little playlist cache (m_playlist) needs updated. + int m_playlist_width_pixels; // considered invalid whenever 'm_playlist_top_idx' is -1. + wchar_t m_playlist[MAX_SONGS_PER_PAGE][256]; // considered invalid whenever 'm_playlist_top_idx' is -1. + int m_exiting; + int m_upper_left_corner_y; + int m_lower_left_corner_y; + int m_upper_right_corner_y; + int m_lower_right_corner_y; + int m_left_edge; + int m_right_edge; + int m_force_accept_WM_WINDOWPOSCHANGING; + + // PRIVATE - GDI STUFF + HMENU m_main_menu; + HMENU m_context_menu; + + // PRIVATE - DESKTOP MODE STUFF + //typedef std::list IconList; + typedef Vector IconList; + IconList m_icon_list; + IDirect3DTexture9* m_desktop_icons_texture[MAX_ICON_TEXTURES]; + HWND m_hWndProgMan; + HWND m_hWndDesktop; + HWND m_hWndDesktopListView; + char m_szDesktopFolder[MAX_PATH]; // *without* the final backslash + int m_desktop_icon_size; + int m_desktop_dragging; // '1' when user is dragging icons around + int m_desktop_box; // '1' when user is drawing a box + BYTE m_desktop_drag_pidl[1024]; // cast this to ITEMIDLIST + POINT m_desktop_drag_startpos; // applies to dragging or box-drawing + POINT m_desktop_drag_curpos; // applies to dragging or box-drawing + int m_desktop_wc_registered; + DWORD m_desktop_bk_color; + DWORD m_desktop_text_color; + DWORD m_desktop_sel_color; + DWORD m_desktop_sel_text_color; + int m_desktop_icon_state; // 0=uninit, 1=total refresh in progress, 2=ready, 3=update in progress + int m_desktop_icon_count; + int m_desktop_icon_update_frame; + CRITICAL_SECTION m_desktop_cs; + int m_desktop_icons_disabled; + int m_vms_desktop_loaded; + int m_desktop_hook_set; + bool m_bClearVJWindow; + + // PRIVATE - MORE TIMEKEEPING + protected: + double m_last_raw_time; + LARGE_INTEGER m_high_perf_timer_freq; // 0 if high-precision timer not available + private: + float m_time_hist[TIME_HIST_SLOTS]; // cumulative + int m_time_hist_pos; + LARGE_INTEGER m_prev_end_of_frame; + + // PRIVATE AUDIO PROCESSING DATA + FFT m_fftobj; + float m_oldwave[2][576]; // for wave alignment + int m_prev_align_offset[2]; // for wave alignment + int m_align_weights_ready; + +public: + CPluginShell(); + ~CPluginShell(); + + // called by vis.cpp, on behalf of Winamp: + int PluginPreInitialize(HWND hWinampWnd, HINSTANCE hWinampInstance); + int PluginInitialize(); + int PluginRender(unsigned char *pWaveL, unsigned char *pWaveR); + void PluginQuit(); + + void ToggleHelp(); + void TogglePlaylist(); + + void READ_FONT(int n); + void WRITE_FONT(int n); + + // config panel / windows messaging processes: + static LRESULT CALLBACK WindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK DesktopWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK VJModeWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK ConfigDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + static INT_PTR CALLBACK TabCtrlProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + static INT_PTR CALLBACK FontDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + static INT_PTR CALLBACK DesktopOptionsDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + static INT_PTR CALLBACK DualheadDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + +private: + void PushWindowToJustBeforeDesktop(HWND h); + void DrawAndDisplay(int redraw); + void ReadConfig(); + void WriteConfig(); + void DoTime(); + void AnalyzeNewSound(unsigned char *pWaveL, unsigned char *pWaveR); + void AlignWaves(); + int InitDirectX(); + void CleanUpDirectX(); + int InitGDIStuff(); + void CleanUpGDIStuff(); + int AllocateDX9Stuff(); + void CleanUpDX9Stuff(int final_cleanup); + int InitNondx9Stuff(); + void CleanUpNondx9Stuff(); + int InitVJStuff(RECT* pClientRect=NULL); + void CleanUpVJStuff(); + int AllocateFonts(IDirect3DDevice9 *pDevice); + void CleanUpFonts(); + void AllocateTextSurface(); + void ToggleDesktop(); + void OnUserResizeWindow(); + void OnUserResizeTextWindow(); + void PrepareFor2DDrawing_B(IDirect3DDevice9 *pDevice, int w, int h); + void RenderBuiltInTextMsgs(); + int GetCanvasMarginX(); // returns the # of pixels that exist on the canvas, on each side, that the user will never see. Mainly here for windowed mode, where sometimes, up to 15 pixels get cropped at edges of the screen. + int GetCanvasMarginY(); // returns the # of pixels that exist on the canvas, on each side, that the user will never see. Mainly here for windowed mode, where sometimes, up to 15 pixels get cropped at edges of the screen. +public: + void ToggleFullScreen(); + void DrawDarkTranslucentBox(RECT* pr); +protected: + void RenderPlaylist(); + void StuffParams(DXCONTEXT_PARAMS *pParams); + void EnforceMaxFPS(); + + // DESKTOP MODE FUNCTIONS (found in desktop_mode.cpp) + int InitDesktopMode(); + void CleanUpDesktopMode(); + int CreateDesktopIconTexture(IDirect3DTexture9** ppTex); + void DeselectDesktop(); + void UpdateDesktopBitmaps(); + int StuffIconBitmaps(int iStartIconIdx, int iTexNum, int *show_msgs); + void RenderDesktop(); + + // SEPARATE TEXT WINDOW (FOR VJ MODE) + int m_vj_mode; + int m_hidden_textwnd; + int m_resizing_textwnd; + protected: + HWND m_hTextWnd; + private: + int m_nTextWndWidth; + int m_nTextWndHeight; + bool m_bTextWindowClassRegistered; + LPDIRECT3D9 m_vjd3d9; + LPDIRECT3DDEVICE9 m_vjd3d9_device; + //HDC m_memDC; // memory device context + //HBITMAP m_memBM, m_oldBM; + //HBRUSH m_hBlackBrush; + + // WINDOWPROC FUNCTIONS + LRESULT PluginShellWindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam); // in windowproc.cpp + LRESULT PluginShellDesktopWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam); + LRESULT PluginShellVJModeWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam); + + // CONFIG PANEL FUNCTIONS: + BOOL PluginShellConfigDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + BOOL PluginShellConfigTab1Proc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + BOOL PluginShellFontDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + BOOL PluginShellDesktopOptionsDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + BOOL PluginShellDualheadDialogProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); + bool InitConfig(HWND hDialogWnd); + void EndConfig(); + void UpdateAdapters(int screenmode); + void UpdateFSAdapterDispModes(); // (fullscreen only) + void UpdateDispModeMultiSampling(int screenmode); + void UpdateMaxFps(int screenmode); + int GetCurrentlySelectedAdapter(int screenmode); + void SaveDisplayMode(); + void SaveMultiSamp(int screenmode); + void SaveAdapter(int screenmode); + void SaveMaxFps(int screenmode); + void OnTabChanged(int nNewTab); + LPDIRECT3DDEVICE9 GetTextDevice() { return (m_vjd3d9_device) ? m_vjd3d9_device : m_lpDX->m_lpDevice; } + + // CHANGES: + friend class CShaderParams; +}; + +#endif \ No newline at end of file diff --git a/vis_milk2/resource.h b/vis_milk2/resource.h new file mode 100644 index 0000000..fccefb5 --- /dev/null +++ b/vis_milk2/resource.h @@ -0,0 +1,877 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by plugin.rc +// +#define IDS_ABOUT_STRING 1 +#define IDS_SZ_MENU_NAV_TOOLTIP 2 +#define ID_DOCS 3 +#define IDS_UNTITLED_MENU_ITEM 3 +#define IDLEFT 4 +#define IDS_UNTITLED_MENU 4 +#define ID_WEB 5 +#define IDS_ON 5 +#define IDRIGHT 6 +#define IDS_OFF 6 +#define ID_DEFAULTS 7 +#define IDS_USE_UP_DOWN_ARROW_KEYS 7 +#define ID_MSG 8 +#define IDS_CURRENT_VALUE_OF_X 8 +#define ID_SPRITE 9 +#define IDS_LOAD_FROM_FILE 9 +#define IDS_SAVE_TO_FILE 10 +#define IDS_ENTER_THE_NEW_STRING 11 +#define IDS_MILKDROP_ERROR 14 +#define IDS_MILKDROP_WARNING 19 +#define IDS_ERROR_CREATING_DOUBLE_SIZED_GDI_TITLE_FONT 20 +#define IDS_ERROR_CREATING_DOUBLE_SIZED_D3DX_TITLE_FONT 21 +#define IDS_RATING 23 +#define IDS_DISABLED 24 +#define IDS_ARE_YOU_SURE_YOU_WANT_TO_DELETE_PRESET 26 +#define IDS_PRESET_TO_DELETE 27 +#define IDS_FILE_ALREADY_EXISTS_OVERWRITE_IT 28 +#define IDS_FILE_IN_QUESTION_X_MILK 29 +#define IDS_ERROR_NO_PRESET_FILE_FOUND_IN_X_MILK 30 +#define IDS_LOAD_WHICH_PRESET_PLUS_COMMANDS 31 +#define IDS_PAGE_X_OF_X 32 +#define IDS_LOCKED 33 +#define IDS_ILLEGAL_CHARACTER 37 +#define IDS_STRING_TOO_LONG 38 +#define IDS_DIRECTORY_TO_JUMP_TO 39 +#define IDS_ERROR_IMPORTING_BAD_FILENAME 40 +#define IDS_ERROR_IMPORTING_BAD_FILENAME_OR_NOT_OVERWRITEABLE 41 +#define IDS_INVALID_PATH 42 +#define IDS_ENTER_THE_NEW_NAME_FOR_X 43 +#define IDS_PRESET_ORDER_IS_NOW_X 44 +#define IDS_SEQUENTIAL 45 +#define IDS_RANDOM 46 +#define IDS_SAVE_AS 50 +#define IDS_AUTO 51 +#define IDS_8X6_FAST 52 +#define IDS_16X12_FAST 53 +#define IDS_24X18 54 +#define IDS_32X24 55 +#define IDS_40X30 56 +#define IDS_48X36_DEFAULT 57 +#define IDS_64X48_SLOW 58 +#define IDS_80X60_SLOW 59 +#define IDS_96X72_SLOW 60 +#define IDS_128X96_SLOW 61 +#define IDS_ERROR_IN_SHELLEXECUTE 62 +#define IDS_MESH_SIZE 65 +#define IDS_MESH_SIZE_TEXT 66 +#define IDS_CB_ALWAYS3D 67 +#define IDS_DISABLE_PRESET_RATING 70 +#define IDS_DISABLE_PRESET_RATING_TEXT 71 +#define IDS_CB_NOWARN2 73 +#define IDS_START_WITH_PRESET_LOCK_ON 76 +#define IDS_START_WITH_PRESET_LOCK_ON_TEXT 77 +#define IDS_BRIGHT_SLIDER 78 +#define IDS_CB_AUTOGAMMA 79 +#define IDS_SPRITE 80 +#define IDS_MSG 81 +#define IDS_SONGTITLEANIM_DURATION_TEXT 86 +#define IDS_RAND_TITLE_TEXT 87 +#define IDS_RAND_MSG_TEXT 88 +#define IDS_TITLE_ANIMS_TEXT 89 +#define IDS_BETWEEN_TIME_TEXT 90 +#define IDS_BETWEEN_TIME_RANDOM_TEXT 91 +#define IDS_BLEND_AUTO_TEXT 92 +#define IDS_BLEND_USER_TEXT 93 +#define IDS_HARDCUT_BETWEEN_TIME_TEXT 94 +#define IDS_HARDCUT_LOUDNESS_TEXT 95 +#define IDS_CB_HARDCUTS 96 +#define IDS_EDIT_CURRENT_PRESET 98 +#define IDS_MOTION 99 +#define IDS_DRAWING_CUSTOM_SHAPES 100 +#define IDD_DIALOG1 101 +#define IDD_CONFIG 101 +#define IDS_DRAWING_CUSTOM_WAVES 101 +#define IDD_PROPPAGE_1 102 +#define IDS_DRAWING_SIMPLE_WAVEFORM 102 +#define IDD_PROPPAGE_2 103 +#define IDS_DRAWING_BORDERS_MOTION_VECTORS 103 +#define IDS_POST_PROCESSING_MISC 104 +#define IDS_CUSTOM_WAVE_X 105 +#define IDS_CUSTOM_SHAPE_X 106 +#define IDS_MENU_EDIT_PRESET_INIT_CODE 107 +#define IDS_MENU_EDIT_PRESET_INIT_CODE_TT 108 +#define IDS_MENU_EDIT_PER_FRAME_EQUATIONS 109 +#define IDR_WINDOWED_CONTEXT_MENU 110 +#define IDS_MENU_EDIT_PER_FRAME_EQUATIONS_TT 110 +#define IDS_MENU_WAVE_TYPE 113 +#define IDD_PROPPAGE_3 114 +#define IDS_MENU_WAVE_TYPE_TT 114 +#define IDD_PROPPAGE_4 115 +#define IDS_MENU_SIZE 115 +#define IDD_PROPPAGE_5 116 +#define IDS_MENU_SIZE_TT 116 +#define IDD_PROPPAGE_6 117 +#define IDS_MENU_SMOOTH 117 +#define IDD_PROPPAGE_7 118 +#define IDS_MENU_SMOOTH_TT 118 +#define IDD_PROPPAGE_8 119 +#define IDS_MENU_MYSTERY_PARAMETER 119 +#define IDI_PLUGIN_ICON 120 +#define IDS_MENU_MYSTERY_PARAMETER_TT 120 +#define IDD_FONTDIALOG 121 +#define IDS_MENU_POSITION_X 121 +#define IDD_DESKTOPMODE 122 +#define IDS_MENU_POSITION_X_TT 122 +#define IDD_DUALHEAD 123 +#define IDS_MENU_POSITION_Y 123 +#define IDS_MENU_POSITION_Y_TT 124 +#define IDS_MENU_COLOR_RED 125 +#define IDS_MENU_COLOR_RED_TT 126 +#define IDS_MENU_COLOR_GREEN 127 +#define IDS_MENU_COLOR_GREEN_TT 128 +#define IDR_TEXT1 129 +#define IDS_MENU_COLOR_BLUE 129 +#define IDR_TEXT2 130 +#define IDS_MENU_COLOR_BLUE_TT 130 +#define IDS_MENU_OPACITY 131 +#define IDS_MENU_OPACITY_TT 132 +#define IDS_MENU_USE_DOTS 133 +#define IDS_MENU_USE_DOTS_TT 134 +#define IDS_MENU_DRAW_THICK 135 +#define IDS_MENU_DRAW_THICK_TT 136 +#define IDS_MENU_MODULATE_OPACITY_BY_VOLUME 137 +#define IDS_MENU_MODULATE_OPACITY_BY_VOLUME_TT 138 +#define IDS_MENU_MODULATION_TRANSPARENT_VOLUME 139 +#define IDS_MENU_MODULATION_TRANSPARENT_VOLUME_TT 140 +#define IDS_MENU_MODULATION_OPAQUE_VOLUME 141 +#define IDS_MENU_MODULATION_OPAQUE_VOLUME_TT 142 +#define IDS_MENU_ADDITIVE_DRAWING 143 +#define IDS_MENU_ADDITIVE_DRAWING_TT 144 +#define IDS_MENU_COLOR_BRIGHTENING 145 +#define IDS_MENU_COLOR_BRIGHTENING_TT 146 +#define IDS_MENU_OUTER_BORDER_THICKNESS 147 +#define IDS_MENU_OUTER_BORDER_THICKNESS_TT 148 +#define IDS_MENU_COLOR_RED_OUTER 149 +#define IDS_MENU_COLOR_RED_OUTER_TT 150 +#define IDS_MENU_COLOR_GREEN_OUTER 151 +#define IDS_MENU_COLOR_GREEN_OUTER_TT 152 +#define IDS_MENU_COLOR_BLUE_OUTER 153 +#define IDS_MENU_COLOR_BLUE_OUTER_TT 154 +#define IDS_MENU_OPACITY_OUTER 155 +#define IDS_MENU_OPACITY_OUTER_TT 156 +#define IDS_MENU_INNER_BORDER_THICKNESS 157 +#define IDS_MENU_INNER_BORDER_THICKNESS_TT 160 +#define IDS_MENU_COLOR_RED_INNER_TT 161 +#define IDS_MENU_COLOR_GREEN_INNER_TT 162 +#define IDS_MENU_COLOR_BLUE_INNER_TT 163 +#define IDS_MENU_OPACITY_INNER_TT 164 +#define IDS_MENU_MOTION_VECTOR_OPACITY 165 +#define IDS_MENU_MOTION_VECTOR_OPACITY_TT 167 +#define IDS_MENU_NUM_MOT_VECTORS_X 168 +#define IDS_MENU_NUM_MOT_VECTORS_X_TT 169 +#define IDS_MENU_NUM_MOT_VECTORS_Y 170 +#define IDS_MENU_NUM_MOT_VECTORS_Y_TT 171 +#define IDS_MENU_OFFSET_X 172 +#define IDS_MENU_OFFSET_X_TT 173 +#define IDS_MENU_OFFSET_Y 174 +#define IDS_MENU_OFFSET_Y_TT 175 +#define IDS_MENU_TRAIL_LENGTH 176 +#define IDS_MENU_TRAIL_LENGTH_TT 177 +#define IDS_MENU_COLOR_RED_MOTION_VECTOR_TT 178 +#define IDS_MENU_COLOR_GREEN_MOTION_VECTOR_TT 179 +#define IDS_MENU_COLOR_BLUE_MOTION_VECTOR_TT 180 +#define IDS_MENU_ZOOM_AMOUNT 181 +#define IDS_MENU_ZOOM_AMOUNT_TT 182 +#define IDS_MENU_ZOOM_EXPONENT 183 +#define IDS_MENU_ZOOM_EXPONENT_TT 184 +#define IDS_MENU_WARP_AMOUNT 185 +#define IDS_MENU_WARP_AMOUNT_TT 186 +#define IDS_MENU_WARP_SCALE 187 +#define IDS_MENU_WARP_SCALE_TT 188 +#define IDS_MENU_WARP_SPEED 189 +#define IDS_MENU_WARP_SPEED_TT 190 +#define IDS_MENU_ROTATION_AMOUNT 191 +#define IDS_MENU_ROTATION_AMOUNT_TT 192 +#define IDS_MENU_ROTATION_CENTER_OF_X 193 +#define IDS_MENU_ROTATION_CENTER_OF_X_TT 194 +#define IDS_MENU_ROTATION_CENTER_OF_Y 195 +#define IDS_MENU_ROTATION_CENTER_OF_Y_TT 196 +#define IDS_MENU_TRANSLATION_X 197 +#define IDS_MENU_TRANSLATION_X_TT 198 +#define IDS_MENU_TRANSLATION_Y 199 +#define IDS_MENU_TRANSLATION_Y_TT 200 +#define IDS_MENU_SCALING_X 201 +#define IDS_MENU_SCALING_X_TT 202 +#define IDS_MENU_SCALING_Y 203 +#define IDS_MENU_SCALING_Y_TT 204 +#define IDS_MENU_SUSTAIN_LEVEL 205 +#define IDS_MENU_SUSTAIN_LEVEL_TT 206 +#define IDS_MENU_DARKEN_CENTER 207 +#define IDS_MENU_DARKEN_CENTER_TT 208 +#define IDS_MENU_GAMMA_ADJUSTMENT 209 +#define IDS_MENU_GAMMA_ADJUSTMENT_TT 210 +#define IDS_MENU_HUE_SHADER 211 +#define IDS_MENU_HUE_SHADER_TT 212 +#define IDS_MENU_VIDEO_ECHO_ALPHA 213 +#define IDS_MENU_VIDEO_ECHO_ALPHA_TT 214 +#define IDS_MENU_VIDEO_ECHO_ZOOM 215 +#define IDS_MENU_VIDEO_ECHO_ZOOM_TT 216 +#define IDS_MENU_VIDEO_ECHO_ORIENTATION 217 +#define IDS_MENU_VIDEO_ECHO_ORIENTATION_TT 218 +#define IDS_MENU_TEXTURE_WRAP 219 +#define IDS_MENU_TEXTURE_WRAP_TT 220 +#define IDS_MENU_FILTER_INVERT 223 +#define IDS_MENU_FILTER_INVERT_TT 224 +#define IDS_MENU_FILTER_BRIGHTEN 225 +#define IDS_MENU_FILTER_BRIGHTEN_TT 226 +#define IDS_MENU_FILTER_DARKEN 227 +#define IDS_MENU_FILTER_DARKEN_TT 228 +#define IDS_MENU_FILTER_SOLARIZE 229 +#define IDS_MENU_FILTER_SOLARIZE_TT 230 +#define IDS_MENU_ENABLED 231 +#define IDS_MENU_ENABLED_TT 232 +#define IDS_MENU_NUMBER_OF_SAMPLES 233 +#define IDS_MENU_NUMBER_OF_SAMPLES_TT 234 +#define IDS_MENU_L_R_SEPARATION 235 +#define IDS_MENU_L_R_SEPARATION_TT 236 +#define IDS_MENU_SCALING 237 +#define IDS_MENU_SCALING_TT 238 +#define IDS_MENU_SMOOTHING_TT 239 +#define IDS_MENU_OPACITY_WAVE_TT 240 +#define IDS_MENU_USE_SPECTRUM 241 +#define IDS_MENU_USE_SPECTRUM_TT 242 +#define IDS_MENU_USE_DOTS_WAVE_TT 243 +#define IDS_MENU_DRAW_THICK_WAVE_TT 244 +#define IDS_MENU_ADDITIVE_DRAWING_WAVE_TT 245 +#define IDS_MENU_EXPORT_TO_FILE 246 +#define IDS_MENU_EXPORT_TO_FILE_TT 247 +#define IDS_MENU_IMPORT_FROM_FILE 248 +#define IDS_MENU_IMPORT_FROM_FILE_TT 249 +#define IDS_MENU_EDIT_INIT_CODE 250 +#define IDS_MENU_EDIT_INIT_CODE_TT 251 +#define IDS_MENU_EDIT_PER_FRAME_CODE 252 +#define IDS_MENU_EDIT_PER_FRAME_CODE_TT 253 +#define IDS_MENU_EDIT_PER_POINT_CODE 254 +#define IDS_MENU_EDIT_PER_POINT_CODE_TT 255 +#define IDS_MENU_ENABLED_SHAPE_TT 256 +#define IDS_MENU_NUMBER_OF_SIDES 257 +#define IDS_MENU_NUMBER_OF_SIDES_TT 258 +#define IDS_MENU_DRAW_THICK_SHAPE_TT 259 +#define IDS_MENU_ADDITIVE_DRAWING_SHAPE_TT 260 +#define IDS_MENU_X_POSITION 261 +#define IDS_MENU_X_POSITION_TT 262 +#define IDS_MENU_Y_POSITION 263 +#define IDS_MENU_Y_POSITION_TT 264 +#define IDS_MENU_RADIUS 265 +#define IDS_MENU_RADIUS_TT 266 +#define IDS_MENU_ANGLE 267 +#define IDS_MENU_ANGLE_TT 268 +#define IDS_MENU_TEXTURED 269 +#define IDS_MENU_TEXTURED_TT 270 +#define IDS_MENU_TEXTURE_ZOOM 271 +#define IDS_MENU_TEXTURE_ZOOM_TT 272 +#define IDS_MENU_TEXTURE_ANGLE 273 +#define IDS_MENU_TEXTURE_ANGLE_TT 274 +#define IDS_MENU_INNER_COLOR_RED 275 +#define IDS_MENU_INNER_COLOR_RED_TT 276 +#define IDS_MENU_INNER_COLOR_GREEN 277 +#define IDS_MENU_INNER_COLOR_GREEN_TT 278 +#define IDS_MENU_INNER_COLOR_BLUE 279 +#define IDS_MENU_INNER_COLOR_BLUE_TT 280 +#define IDS_MENU_INNER_OPACITY 281 +#define IDS_MENU_INNER_OPACITY_TT 282 +#define IDS_MENU_OUTER_COLOR_RED 283 +#define IDS_MENU_OUTER_COLOR_RED_TT 284 +#define IDS_MENU_OUTER_COLOR_GREEN 285 +#define IDS_MENU_OUTER_COLOR_GREEN_TT 286 +#define IDS_MENU_OUTER_COLOR_BLUE 287 +#define IDS_MENU_OUTER_COLOR_BLUE_TT 288 +#define IDS_MENU_OUTER_OPACITY 289 +#define IDS_MENU_OUTER_OPACITY_TT 290 +#define IDS_MENU_BORDER_COLOR_RED 291 +#define IDS_MENU_BORDER_COLOR_RED_TT 292 +#define IDS_MENU_BORDER_COLOR_GREEN 293 +#define IDS_MENU_BORDER_COLOR_GREEN_TT 294 +#define IDS_MENU_BORDER_COLOR_BLUE 295 +#define IDS_MENU_BORDER_COLOR_BLUE_TT 296 +#define IDS_MENU_BORDER_OPACITY 297 +#define IDS_MENU_BORDER_OPACITY_TT 298 +#define IDS_MENU_EXPORT_TO_FILE_SHAPE_TT 299 +#define IDS_MENU_IMPORT_FROM_FILE_SHAPE_TT 300 +#define IDS_ERROR_UNABLE_TO_SAVE_THE_FILE 303 +#define IDS_SAVE_SUCCESSFUL 304 +#define IDS_ERROR_UNABLE_TO_DELETE_THE_FILE 305 +#define IDS_PRESET_X_DELETED 306 +#define IDS_ERROR_A_FILE_ALREADY_EXISTS_WITH_THAT_FILENAME 307 +#define IDS_ERROR_UNABLE_TO_RENAME_FILE 308 +#define IDS_RENAME_SUCCESSFUL 309 +#define IDS_SPRITE_X_WARNING_ERROR_IN_INIT_CODE 310 +#define IDS_SPRITE_X_WARNING_ERROR_IN_PER_FRAME_CODE 311 +#define IDS_SPRITE_X_ERROR_BAD_SLOT_INDEX 312 +#define IDS_SPRITE_X_ERROR_IMAGE_FILE_MISSING_OR_CORRUPT 313 +#define IDS_SPRITE_X_ERROR_OUT_OF_MEM 314 +#define IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_INIT_CODE 319 +#define IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_PER_FRAME_CODE 320 +#define IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_PER_POINT_CODE 321 +#define IDS_WARNING_PRESET_X_ERROR_IN_SHAPE_X_INIT_CODE 322 +#define IDS_WARNING_PRESET_X_ERROR_IN_SHAPE_X_PER_FRAME_CODE 323 +#define IDS_CONFIG_PANEL_BUTTON_1 324 +#define IDS_CONFIG_PANEL_BUTTON_2 325 +#define IDS_CONFIG_PANEL_BUTTON_3 326 +#define IDS_CONFIG_PANEL_BUTTON_4 327 +#define IDS_CONFIG_PANEL_BUTTON_5 328 +#define IDS_CONFIG_PANEL_BUTTON_6 329 +#define IDS_CONFIG_PANEL_BUTTON_7 330 +#define IDS_CONFIG_PANEL_BUTTON_8 331 +#define IDS_EXTRA_FONT_1_NAME 332 +#define IDS_EXTRA_FONT_2_NAME 333 +#define IDS_PRESS_F1_MSG 334 +#define IDS_GRAPHICS_SUBSYSTEM_IS_TEMPORARILY_UNSTABLE 335 +#define IDS_UNKNOWN 336 +#define IDS_DISABLED_PAGE_TEARING 337 +#define IDS_NONE 338 +#define IDS_UNLIMITED 339 +#define IDS_X_FRAME_SEC 340 +#define IDS_HELP_ON_X_BUTTON 341 +#define IDS_FONTS_HELP 342 +#define IDS_DUAL_HEAD_HELP 343 +#define IDS_MULTI_SAMPLING 344 +#define IDS_MULTI_SAMPLING_HELP 345 +#define IDS_MAX_FRAMERATE 346 +#define IDS_MAX_FRAMERATE_HELP 347 +#define IDS_FAKE_FULLSCREEN 348 +#define IDS_FAKE_FULLSCREEN_HELP 349 +#define IDS_FULLSCREEN_ADAPTER 350 +#define IDS_FULLSCREEN_ADAPTER_HELP 351 +#define IDS_WINDOWED_ADPATER 352 +#define IDS_WINDOWED_ADPATER_HELP 353 +#define IDS_DESKTOP_ADAPTER 354 +#define IDS_DESKTOP_ADAPTER_HELP 355 +#define IDS_HELP_ON_X_CHECKBOX 356 +#define IDS_HELP_ON_X_CHECKBOX_HELP 357 +#define IDS_FORCE_INTO_FS_MODE_HELP 358 +#define IDS_FORCE_INTO_DESKTOP_MODE_HELP 359 +#define IDS_HELP_ON_F1 360 +#define IDS_HELP_ON_F1_HELP 361 +#define IDS_CB_SKIN_HELP 362 +#define IDS_SAVE_CPU_CHECKBOX 363 +#define IDS_SAVE_CPU_CHECKBOX_HELP 364 +#define IDS_FS_DISPLAY_MODE 365 +#define IDS_FS_DISPLAY_MODE_HELP 366 +#define IDS_TRY_TO_FIX_SLOW_TEXT 369 +#define IDS_TRY_TO_FIX_SLOW_TEXT_HELP 370 +#define IDS_VJ_MODE 371 +#define IDS_VJ_MODE_HELP 372 +#define IDS_HELP_ON_X 373 +#define IDS_DMS_LABEL_HELP 374 +#define IDS_FS_LABEL_HELP 375 +#define IDS_W_LABEL_HELP 376 +#define IDS_DM_MORE_HELP 377 +#define IDS_INITCONFIG_FAILED 378 +#define IDS_UNABLE_TO_LOAD_TABS 379 +#define IDS_DOCUMENTATION_FILE_NOT_FOUND 380 +#define IDS_ACCESS_TO_DOCUMENTATION_FILE_DENIED 381 +#define IDS_ACCESS_TO_DOCUMENTATION_FILE_FAILED_DUE_TO_NO_ASSOC 382 +#define IDS_ACCESS_TO_DOCUMENTATION_FILE_FAILED_CODE_X 383 +#define IDS_ERROR_OPENING_DOCUMENTATION 384 +#define IDS_URL_COULD_NOT_OPEN 385 +#define IDS_ACCESS_TO_URL_WAS_DENIED 386 +#define IDS_ACCESS_TO_URL_FAILED_DUE_TO_NO_ASSOC 387 +#define IDS_ACCESS_TO_URL_FAILED_CODE_X 388 +#define IDS_ERROR_OPENING_URL 389 +#define IDS_RESTORE_ALL_DEFAULTS 390 +#define IDS_RESTORE_ALL_DEFAULTS_TITLE 391 +#define IDS_OK_HELP 392 +#define IDS_CANCEL_HELP 393 +#define IDS_RESTORE_DEFAULTS_HELP 394 +#define IDS_DOCUMENTATION_BUTTON_HELP 395 +#define IDS_VIEW_ONLINE_DOCS_HELP 396 +#define IDS_5_6_5_TEXTURE 397 +#define IDS_5_5_5_TEXTURE 398 +#define IDS_8_8_8_TEXTURE 399 +#define IDS_NO_ALPHA_FALLBACK 400 +#define IDS_NO_ALPHA_FALLBACK_HELP 401 +#define IDS_CB_SHOW_ICONS_HELP 402 +#define IDS_CB_BOX 403 +#define IDS_CB_BOX_HELP 404 +#define IDS_CB_MANUAL_SCOOT 405 +#define IDS_CB_MANUAL_SCOOT_HELP 406 +#define IDS_SPAN_BOTH_SCREENS 407 +#define IDS_USE_LEFT_SCREEN_ONLY 408 +#define IDS_USE_RIGHT_SCREEN_ONLY 409 +#define IDS_USE_TOP_SCREEN_ONLY 410 +#define IDS_USE_BOTTOM_SCREEN_ONLY 411 +#define IDS_COULD_NOT_FIND_FILE_FOR_DESKTOP_MODE_X 412 +#define IDS_MILKDROP_ERROR_FILE_MISSING 413 +#define IDS_ERROR_CREATING_GDI_DESKTOP_FONT 414 +#define IDS_ERROR_CREATING_DESKTOP_FONT 415 +#define IDS_ERROR_CREATING_TEXTURE_FOR_ICON_BITMAPS 416 +#define IDS_OUTDATED_VMS_DESKTOP_DLL_NEED_TO_REINSTALL 417 +#define IDS_ERROR_CREATING_HOOK_PROC_DESKTOP_ICONS_NOT_AVAILABLE 418 +#define IDS_ERROR_UPDATING_ICON_BITMAPS 419 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_TOO_MANY_UNIQUE_ICON_BITMAPS 420 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_COULD_NOT_GET_LEVEL_DESCRIPTION 421 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_LOCKRECT_FAILED 422 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_LR_PBITS_IS_NULL 423 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_UNKNOWN_PIXEL_FORMAT 424 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_COULDNT_GET_HDC 425 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_CALL_TO_GETDIBITS_FAILED 426 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_CALL_2_TO_GETDIBITS_FAILED 427 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_GETICONINFO_FAILED 428 +#define IDS_ERROR_UPDATING_ICON_BITMAPS_SHGETFILEINFO_FAILED 429 +#define IDS_UNABLE_TO_REGISTER_WINDOW_CLASS 430 +#define IDS_DIRECTX_INIT_FAILED 431 +#define IDS_DXC_ERR_CAPSFAIL 432 +#define IDS_FS_DISPLAY_MODE_SELECTED_IS_INVALID 433 +#define IDS_CREATEWINDOW_FAILED 434 +#define IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS 435 +#define IDS_TIP 436 +#define IDS_TRYING_TO_ENTER_FS_MODE_WITH_MULTIPLE_DISPLAYS_2 437 +#define IDS_UNABLE_TO_CREATE_DIRECTX_DEVICE 438 +#define IDS_OLDER_DISPLAY_ADAPTER_CATENATION 439 +#define IDS_OLDER_DISPLAY_ADAPTER_CATENATION_2 440 +#define IDS_DIRECTX_INIT_FAILED_X 441 +#define IDS_WINDOW_RESIZE_FAILED 442 +#define IDS_OUT_OF_VIDEO_MEMORY 443 +#define IDS_ERROR_CREATING_GDI_FONTS 444 +#define IDS_ERROR_LOADING_MAIN_MENU 445 +#define IDS_ERROR_LOADING_CONTEXT_MENU 446 +#define IDS_ERROR_CREATING_DIRECT3D_DEVICE_FOR_VJ_MODE 447 +#define IDS_VJ_MODE_INIT_ERROR 448 +#define IDS_ERROR_REGISTERING_WINDOW_CLASS_FOR_TEXT_WINDOW 449 +#define IDS_ERROR_CREATING_VJ_WINDOW 450 +#define IDS_ERROR_CREATING_D3D_DEVICE_FOR_VJ_MODE 451 +#define IDS_ERROR_CREATING_D3DX_FONTS 452 +#define IDS_UNABLE_TO_INIT_DXCONTEXT 453 +#define IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG 454 +#define IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_2 455 +#define IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_3 456 +#define IDS_TO_FREE_UP_VIDEO_MEMORY 457 +#define IDS_TO_FREE_UP_VIDEO_MEMORY_2 458 +#define IDS_MILKDROP_SUGGESTION 459 +#define IDS_DIRECTX_MISSING_OR_CORRUPT 460 +#define IDS_ERROR_THE_PLUGIN_IS_ALREADY_RUNNING 463 +#define IDS_THIS_PLUGIN_NEEDS_MUSIC_TO_RUN 464 +#define IDS_NO_MUSIC_PLAYING 465 +#define IDS_UNABLE_TO_READ_DATA_FILE_X 466 +#define IDS_COULD_NOT_CREATE_MY_VERTEX_DECLARATION 467 +#define IDS_COULD_NOT_CREATE_WF_VERTEX_DECLARATION 468 +#define IDS_COULD_NOT_CREATE_SPRITE_VERTEX_DECLARATION 469 +#define IDS_SHADER_MODEL_2 470 +#define IDS_SHADER_MODEL_3 471 +#define IDS_SHADER_MODEL_4 472 +#define IDS_UKNOWN_CASE_X 473 +#define IDS_FAILED_TO_COMPILE_PIXEL_SHADERS_USING_X 474 +#define IDS_FAILED_TO_COMPILE_PIXEL_SHADERS_HARDWARE_MIS_REPORT 475 +#define IDS_COULD_NOT_COMPILE_FALLBACK_WV_SHADER 476 +#define IDS_COULD_NOT_COMPILE_FALLBACK_CV_SHADER 477 +#define IDS_COULD_NOT_COMPILE_FALLBACK_CP_SHADER 478 +#define IDS_COULD_NOT_COMPILE_BLUR1_VERTEX_SHADER 479 +#define IDS_COULD_NOT_COMPILE_BLUR1_PIXEL_SHADER 480 +#define IDS_COULD_NOT_COMPILE_BLUR2_VERTEX_SHADER 481 +#define IDS_COULD_NOT_COMPILE_BLUR2_PIXEL_SHADER 482 +#define IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_SMALLER_DISPLAY 483 +#define IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_NOT_ENOUGH_VID_MEM_RECOMMENDATION 484 +#define IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_NOT_ENOUGH_VID_MEM 485 +#define IDS_SUCCESSFULLY_CREATED_VS0_VS1 486 +#define IDS_ERROR_CREATING_BLUR_TEXTURES 487 +#define IDS_COULD_NOT_CREATE_NOISE_TEXTURE 488 +#define IDS_COULD_NOT_LOCK_NOISE_TEXTURE 489 +#define IDS_NOISE_TEXTURE_BYTE_LAYOUT_NOT_RECOGNISED 490 +#define IDS_COULD_NOT_CREATE_3D_NOISE_TEXTURE 491 +#define IDS_COULD_NOT_LOCK_3D_NOISE_TEXTURE 492 +#define IDS_3D_NOISE_TEXTURE_BYTE_LAYOUT_NOT_RECOGNISED 493 +#define IDS_ERROR_CREATING_SHADER 498 +#define IDS_PLEASE_EXIT_VIS_BEFORE_RUNNING_CONFIG_PANEL 499 +#define IDS_FPS 500 +#define IDS_PF_MONITOR 501 +#define IDS_PRESS_F9_TO_HIDE_SHADER_QREF 502 +#define IDS_PRESS_F9_TO_SHOW_SHADER_QREF 503 +#define IDS_WARP_AND_COMPOSITE_SHADERS_LOCKED 504 +#define IDS_WARP_SHADER_LOCKED 505 +#define IDS_COMPOSITE_SHADER_LOCKED 506 +#define IDS_PRESET_USES_HIGHEST_PIXEL_SHADER_VERSION 507 +#define IDS_PRESET_HAS_MIXED_VERSIONS_OF_SHADERS 508 +#define IDS_UPGRADE_SHADERS_TO_USE_PS2 509 +#define IDS_UPGRADE_SHADERS_TO_USE_PS3 510 +#define IDS_PRESET_DOES_NOT_USE_PIXEL_SHADERS 511 +#define IDS_UPGRADE_TO_USE_PS2 512 +#define IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET 513 +#define IDS_PRESET_CURRENTLY_USES_PS2 514 +#define IDS_UPGRADE_TO_USE_PS3 515 +#define IDS_PRESET_CURRENTLY_USES_PS3 516 +#define IDS_UPGRADE_TO_USE_PS4 517 +#define IDS_WARNING_DO_NOT_FORGET_WARP_SHADER_WAS_LOCKED 518 +#define IDS_WARNING_DO_NOT_FORGET_COMPOSITE_SHADER_WAS_LOCKED 519 +#define IDS_PRESET_MASH_UP_TEXT1 520 +#define IDS_PRESET_CURRENTLY_USES_PS2X 521 +#define IDS_UPGRADE_TO_USE_PS2X 522 +#define IDS_PRESET_MASH_UP_TEXT2 524 +#define IDS_PRESET_MASH_UP_TEXT3 525 +#define IDS_PRESET_MASH_UP_TEXT4 526 +#define IDS_DIRECTORY_OF_X 527 +#define IDS_SHUFFLE_IS_NOW_OFF 528 +#define IDS_SHUFFLE_IS_NOW_ON 529 +#define IDS_COMPSHADER_LOCKED 530 +#define IDS_WARPSHADER_LOCKED 531 +#define IDS_ALLSHADERS_LOCKED 532 +#define IDS_ALLSHADERS_UNLOCKED 533 +#define IDS_UPGRADE_TO_USE_PS2B 534 +#define IDS_PS_AUTO_RECOMMENDED 535 +#define IDS_PS_DISABLED 536 +#define IDS_PS_SHADER_MODEL_2 537 +#define IDS_PS_SHADER_MODEL_3 538 +#define IDS_TX_8_BITS_PER_CHANNEL 539 +#define IDS_TX_16_BITS_PER_CHANNEL 540 +#define IDS_TX_32_BITS_PER_CHANNEL 541 +#define IDS_160X120_SLOW 542 +#define IDS_192X144_SLOW 543 +#define IDS_NONE_BEST_IMAGE_QUALITY 544 +#define IDS_1_25_X 545 +#define IDS_1_33_X 546 +#define IDS_1_5_X 547 +#define IDS_1_67_X 548 +#define IDS_2_X 549 +#define IDS_3_X 550 +#define IDS_4_X 551 +#define IDS_NEAREST_POWER_OF_2 552 +#define IDS_EXACT_RECOMMENDED 553 +#define IDS_PIXEL_SHADERS 554 +#define IDS_PIXEL_SHADERS_TEXT 555 +#define IDS_TEXFORMAT 556 +#define IDS_TEXFORMAT_TEXT 557 +#define IDS_CANVAS_SIZE 558 +#define IDS_CANVAS_SIZE_TEXT 559 +#define IDS_CANVAS_STRETCH 560 +#define IDS_CANVAS_STRETCH_TEXT 561 +#define IDS_MAX_IMAGES_BYTES_TEXT 562 +#define IDS_MENU_EDIT_WARP_SHADER 563 +#define IDS_MENU_EDIT_COMPOSITE_SHADER 564 +#define IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT 565 +#define IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT_TT 566 +#define IDS_MENU_BLUR1_MIN_COLOR_VALUE 567 +#define IDS_MENU_BLUR1_MIN_COLOR_VALUE_TT 568 +#define IDS_MENU_BLUR1_MAX_COLOR_VALUE 569 +#define IDS_MENU_BLUR1_MAX_COLOR_VALUE_TT 570 +#define IDS_MENU_BLUR2_MIN_COLOR_VALUE 571 +#define IDS_MENU_BLUR2_MIN_COLOR_VALUE_TT 572 +#define IDS_MENU_BLUR2_MAX_COLOR_VALUE 573 +#define IDS_MENU_BLUR2_MAX_COLOR_VALUE_TT 574 +#define IDS_MENU_BLUR3_MIN_COLOR_VALUE 575 +#define IDS_MENU_BLUR3_MIN_COLOR_VALUE_TT 576 +#define IDS_MENU_BLUR3_MAX_COLOR_VALUE 577 +#define IDS_MENU_BLUR3_MAX_COLOR_VALUE_TT 578 +#define IDS_MENU_EDIT_PER_VERTEX_EQUATIONS 579 +#define IDS_MENU_EDIT_PER_VERTEX_EQUATIONS_TT 580 +#define IDS_MENU_EDIT_WARP_SHADER_TT 581 +#define IDS_MENU_EDIT_COMPOSITE_SHADER_TT 582 +#define IDS_MENU_EDIT_UPGRADE_PRESET_PS_VERSION 583 +#define IDS_MENU_EDIT_UPGRADE_PRESET_PS_VERSION_TT 584 +#define IDS_MENU_EDIT_DO_A_PRESET_MASH_UP 585 +#define IDS_MENU_EDIT_DO_A_PRESET_MASH_UP_TT 586 +#define IDS_MENU_NUMBER_OF_INSTANCES 587 +#define IDS_MENU_NUMBER_OF_INSTANCES_TT 588 +#define IDS_MENU_EDIT_INIT_CODE_SHAPE_TT 589 +#define IDS_MENU_EDIT_PER_FRAME_INSTANCE_CODE 590 +#define IDS_MENU_EDIT_PER_FRAME_INSTANCE_CODE_TT 591 +#define IDS_ERROR_PRESET_NOT_FOUND_X 592 +#define IDS_ERROR_NO_PRESET_FILES_OR_DIRS_FOUND_IN_X 593 +#define IDS_SCANNING_PRESETS 594 +#define IDS_SPRITE_X_ERROR_COULD_NOT_FIND_IMG_OR_NOT_DEFINED 595 +#define IDS_WARNING_PRESET_X_ERROR_IN_PRESET_INIT_CODE 596 +#define IDS_WARNING_PRESET_X_ERROR_IN_PER_FRAME_CODE 597 +#define IDS_WARNING_PRESET_X_ERROR_IN_PER_VERTEX_CODE 598 +#define IDS_HZ 599 +#define IDS_HELP_MINIMIZE_WINAMP 600 +#define IDS_HELP_MINIMIZE_WINAMP_HELP 601 +#define IDS_DIRECTX_MISSING_OR_CORRUPT_TEXT 602 +#define IDS_PARENT_DIRECTORY 603 +#define IDS_RAND_TITLE 604 +#define IDS_RAND_MSG 605 +#define IDS_MAX_IMAGES_BYTES 606 +#define IDS_PAGE_X 607 +#define IDS_MB 608 +#define IDS_GB 609 +#define IDS_MASHUP_GENERAL_POSTPROC 610 +#define IDS_MASHUP_MOTION_EQUATIONS 611 +#define IDS_MASHUP_WAVEFORMS_SHAPES 612 +#define IDS_MASHUP_WARP_SHADER 613 +#define IDS_MASHUP_COMP_SHADER 614 +#define IDS_STRING615 615 +#define IDS_STRING616 616 +#define IDS_STRING617 617 +#define IDS_STRNG618 618 +#define IDS_STRING618 618 +#define IDS_STRING619 619 +#define IDS_STRING620 620 +#define IDS_STRING621 621 +#define IDS_STRING622 622 +#define IDS_STRING623 623 +#define IDS_STRING624 624 +#define IDS_STRING625 625 +#define IDS_STRING626 626 +#define IDS_STRING627 627 +#define IDS_STRING628 628 +#define IDS_STRING629 629 +#define IDS_STRING630 630 +#define IDS_STRING631 631 +#define IDS_STRING632 632 +#define IDS_STRING633 633 +#define IDS_STRING634 634 +#define IDS_STRING635 635 +#define IDS_UPGRADE_SHADERS_TO_USE_PS2X 636 +#define IDS_PRESS_ESC_TO_RETURN 637 +#define IDS_COULD_NOT_LOAD_TEXTURE_X 638 +#define IDS_ERROR_COMPILING_X_X_SHADER 639 +#define IDS_ERROR_PARSING_X_X_SHADER 640 +#define IDS_UNABLE_TO_RESOLVE_TEXSIZE_FOR_A_TEXTURE_NOT_IN_USE 641 +#define IDS_KEY_MAPPINGS 642 +#define IDC_CB_FOG 1000 +#define IDC_CB_SUPERTEX 1001 +#define IDC_CB_HELP_MSG 1001 +#define IDC_CB_PRESS_F1_MSG 1001 +#define IDC_DISP_MODE 1003 +#define IDC_CB_FS 1004 +#define IDC_CB_PT 1005 +#define IDC_CB_WPT 1005 +#define IDC_SZ_ABOUT 1006 +#define IDC_CB_MIN 1006 +#define IDC_ADAPTER_W 1007 +#define IDC_ADAPTER_TEXT 1008 +#define IDC_ADAPTER_W_CAPTION 1008 +#define IDC_ADAPTER_FFS 1008 +#define IDC_ADAPTER_DMS 1008 +#define IDC_DISP_MODE_TEXT 1009 +#define IDC_DISP_MODE_CAPTION 1009 +#define IDC_ADAPTER_FS 1010 +#define IDC_ADAPTER_TEXT2 1011 +#define IDC_ADAPTER_FS_CAPTION 1011 +#define IDC_FS_ADAPTER_CAPTION 1011 +#define IDC_CB_TWOPASS 1012 +#define IDC_CB_FFSPT 1012 +#define IDC_CB_DMSPT 1012 +#define IDC_CB_TRANS_HAIR 1013 +#define IDC_ADAPTER_FS_CAPTION2 1013 +#define IDC_W_ADAPTER_CAPTION 1013 +#define IDC_FONT2b 1013 +#define IDC_FONT2 1013 +#define IDC_CB_3B 1014 +#define IDC_ADD_STUFF_HERE 1014 +#define IDC_FFS_ADAPTER_CAPTION 1014 +#define IDC_DMS_ADAPTER_CAPTION 1014 +#define IDC_CB_DEBUGOUTPUT 1014 +#define IDC_FONT3b 1014 +#define IDC_FONT3 1014 +#define IDC_MQ 1015 +#define IDC_CB_FAKE 1015 +#define IDC_TEXSIZECOMBO 1015 +#define IDC_FONT4b 1015 +#define IDC_FONT4 1015 +#define IDC_DISP_MODE_TEXT2 1016 +#define IDC_CB_NO_FAKE_TIPS 1016 +#define IDC_TAB1 1016 +#define IDC_TABS 1016 +#define IDC_CB_FSPT 1016 +#define IDC_FONTSIZE 1016 +#define IDC_CB_AUTOGAMMA 1016 +#define IDC_FONT5b 1016 +#define IDC_FONT5 1016 +#define IDC_WMS 1017 +#define IDC_MESHSIZECOMBO 1017 +#define IDC_FONTSIZE3 1017 +#define IDC_DISP_MODE_TEXT3 1018 +#define IDC_MULTISAMPLING_CAPTION2 1018 +#define IDC_FS_BOX 1018 +#define IDC_W_MULTISAMPLING_CAPTION 1018 +#define IDC_BETWEEN_TIME 1018 +#define IDC_FONTSIZE4 1018 +#define IDC_FSMS 1019 +#define IDC_CB_ALWAYS3D 1019 +#define IDC_BETWEEN_TIME_RANDOM 1019 +#define IDC_FONT6b 1019 +#define IDC_FONT6 1019 +#define IDC_DISP_MODE_TEXT4 1020 +#define IDC_MULTISAMPLING_CAPTION 1020 +#define IDC_FRACTAL_RES_CAPTION 1020 +#define IDC_INITIAL_WAVEMODE_CAPTION 1020 +#define IDC_CB_DMS 1020 +#define IDC_HARDCUT_BETWEEN_TIME 1020 +#define IDC_FONTSIZE5 1020 +#define IDC_CB_SCROLLON 1020 +#define IDC_FS_LIMIT 1021 +#define IDC_FS_MAXFPS 1021 +#define IDC_FONTOPTIONS 1021 +#define IDC_TEXFORMAT 1021 +#define IDC_DISP_MODE_TEXT5 1022 +#define IDC_FRAME_DELAY_CAPTION 1022 +#define IDC_FS_FRAME_DELAY_CAPTION 1022 +#define IDC_FS_MAXFPS_CAPTION 1022 +#define IDC_FONTOPTIONS3 1022 +#define IDC_SHADERS 1022 +#define IDC_W_LIMIT 1023 +#define IDC_W_MAXFPS 1023 +#define IDC_CB_NOWARN 1023 +#define IDC_BLEND_AUTO 1023 +#define IDC_CB_SCROLLON2 1023 +#define IDC_DISP_MODE_TEXT6 1024 +#define IDC_FRAME_DELAY_CAPTION2 1024 +#define IDC_G_BOX 1024 +#define IDC_W_FRAME_DELAY_CAPTION 1024 +#define IDC_W_MAXFPS_CAPTION 1024 +#define IDC_CB_NOWARN2 1024 +#define IDC_BLEND_USER 1024 +#define IDC_W_BOX 1025 +#define IDC_CB_SAVE_CPU 1025 +#define IDC_FONT7b 1025 +#define IDC_FONT7 1025 +#define IDC_CB_ANISO 1025 +#define IDC_TABS_PLACEHOLDER 1026 +#define IDC_FFSMS 1026 +#define IDC_DMSMS 1026 +#define IDC_CB_NORATING 1026 +#define IDC_MULTISAMPLING_CAPTION3 1027 +#define IDC_FFS_MULTISAMPLING_CAPTION 1027 +#define IDC_FONTSIZE2 1027 +#define IDC_DMS_MULTISAMPLING_CAPTION 1027 +#define IDC_CB_INSTASCAN 1027 +#define IDC_FRAME_DELAY_CAPTION3 1028 +#define IDC_FFS_FRAME_DELAY_CAPTION 1028 +#define IDC_FFS_MAXFPS_CAPTION 1028 +#define IDC_FONTOPTIONS2 1028 +#define IDC_DMS_MAXFPS_CAPTION 1028 +#define IDC_STRETCH 1028 +#define IDC_FFS_LIMIT 1029 +#define IDC_FFS_MAXFPS 1029 +#define IDC_DMS_MAXFPS 1029 +#define IDC_FONTSIZE6 1029 +#define IDC_MAX_IMAGES 1029 +#define IDC_RECT 1030 +#define IDC_CB_SKIN 1030 +#define IDC_MAX_BYTES 1030 +#define IDC_Q 1031 +#define IDC_FRACTAL_RES 1031 +#define IDC_INITIAL_WAVEMODE 1031 +#define IDC_FONT8b 1031 +#define IDC_FONT8 1031 +#define IDC_CB_MIN2 1031 +#define IDC_CB_FIXSLOWTEXT 1031 +#define IDC_HS_ANIM_SPEED 1032 +#define IDC_BETWEEN_TIME_LABEL 1032 +#define IDC_FONTSIZE7 1032 +#define IDC_FS_MULTISAMPLING_CAPTION 1033 +#define IDC_BETWEEN_TIME_RANDOM_LABEL 1033 +#define IDC_HS_ANIM_SPEED_CAPTION 1034 +#define IDC_BLEND_AUTO_LABEL 1034 +#define IDC_FONT9b 1034 +#define IDC_FONT9 1034 +#define IDC_BLEND_USER_LABEL 1035 +#define IDC_FONTSIZE8 1035 +#define IDC_FFS_LABEL 1036 +#define IDC_DMS_LABEL 1036 +#define IDC_BLEND_USER_LABEL2 1036 +#define IDC_BETWEEN_TIME_LABEL2 1036 +#define IDC_RAND_TITLE_LABEL 1036 +#define IDC_HARDCUT_BETWEEN_TIME_LABEL 1036 +#define IDC_FS_LABEL 1037 +#define IDC_BLEND_USER_LABEL3 1037 +#define IDC_RAND_MSG_LABEL 1037 +#define IDC_W_LABEL 1038 +#define IDC_FONTSIZE9 1038 +#define IDC_3DSEP_LABEL 1038 +#define ID_FONTS 1039 +#define IDC_BRIGHT_SLIDER 1039 +#define IDC_FONT_CAPTION 1040 +#define ID_DM_MORE 1040 +#define IDC_FONTSIZE_CAPTION 1041 +#define ID_DUALHEAD 1041 +#define IDC_FONTOPTIONS_CAPTION 1042 +#define IDC_SYSTEM_FONT 1043 +#define IDC_CB_SEPTEXT 1043 +#define IDC_FONT_NAME_2 1043 +#define IDC_DECORATIVE_FONT 1044 +#define IDC_HARDCUT_LOUDNESS 1044 +#define IDC_FONT_NAME_1 1044 +#define IDC_CB_HARDCUTS 1045 +#define IDC_TITLE_FONT 1045 +#define IDC_FONT_NAME_3 1045 +#define IDC_CB_BOX 1046 +#define IDC_SONGTITLEANIM_DURATION 1046 +#define IDC_FONT_NAME_4 1046 +#define IDC_DM_ALPHA_FIX 1047 +#define IDC_CB_TITLE_ANIMS 1047 +#define IDC_FONT_NAME_5 1047 +#define IDC_DM_ALPHA_FIX_CAPTION 1048 +#define IDC_V_PICK 1048 +#define IDC_RAND_TITLE 1048 +#define IDC_FONT_NAME_6 1048 +#define IDC_CB_MANUAL_SCOOT 1049 +#define IDC_T1 1049 +#define IDC_RAND_MSG 1049 +#define IDC_FONT_NAME_7 1049 +#define IDC_T3 1050 +#define IDC_CB_SHOW_ICONS 1050 +#define IDC_FONT_NAME_8 1050 +#define IDC_3DSEP 1050 +#define IDC_H_PICK 1051 +#define IDC_T5 1051 +#define IDC_FONT_NAME_9 1051 +#define IDC_T2 1052 +#define IDC_FONTOPTIONS_CAPTION2 1052 +#define IDC_T4 1053 +#define IDC_FONTOPTIONS_CAPTION3 1053 +#define IDC_FONT_TEXT 1054 +#define IDC_TEXSIZECOMBO_CAPTION 1054 +#define IDC_MESHSIZECOMBO_CAPTION 1055 +#define IDC_BRIGHT_SLIDER_BOX 1056 +#define IDC_SONGTITLEANIM_DURATION_LABEL 1057 +#define IDC_TEXFORMAT_CAPTION 1057 +#define IDC_HARDCUT_LOUDNESS_LABEL 1058 +#define IDC_SHADERS_CAPTION 1058 +#define IDC_FONTSIZE1 1059 +#define IDC_HARDCUT_LOUDNESS_MIN 1059 +#define IDC_BRIGHT_SLIDER_BOX2 1059 +#define IDC_HARDCUT_LOUDNESS_MAX 1060 +#define IDC_STRETCH_CAPTION 1060 +#define IDC_CB_VJMODE 1061 +#define IDC_MAX_IMAGES_CAPTION 1061 +#define IDC_MAX_BYTES_CAPTION 1062 +#define IDC_FONTBOLD1 1063 +#define IDC_FONTITAL1 1064 +#define IDC_FONTAA1 1065 +#define IDC_FONTBOLD2 1066 +#define IDC_FONTITAL2 1067 +#define IDC_FONTAA2 1068 +#define IDC_FONTBOLD3 1069 +#define IDC_FONTITAL3 1070 +#define IDC_FONTAA3 1071 +#define IDC_FONTBOLD4 1072 +#define IDC_FONTITAL4 1073 +#define IDC_FONTAA4 1074 +#define IDC_FONTBOLD5 1075 +#define IDC_FONTITAL5 1076 +#define IDC_FONTAA5 1077 +#define IDC_FONTBOLD6 1078 +#define IDC_FONTITAL6 1079 +#define IDC_FONTAA6 1080 +#define IDC_FONTBOLD7 1084 +#define IDC_FONTITAL7 1085 +#define IDC_FONTAA7 1086 +#define IDC_FONTBOLD8 1087 +#define IDC_FONTITAL8 1088 +#define IDC_FONTAA8 1089 +#define IDC_FONTBOLD9 1090 +#define IDC_FONTITAL9 1091 +#define IDC_FONTAA9 1092 +#define IDC_FONT1b 1093 +#define IDC_FONT1 1093 +#define ID_QUIT 40006 +#define ID_GO_FS 40007 +#define ID_SHOWHELP 40008 +#define ID_SHOWPLAYLIST 40009 +#define ID_DESKTOP_MODE 40010 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 131 +#define _APS_NEXT_COMMAND_VALUE 40011 +#define _APS_NEXT_CONTROL_VALUE 1062 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/vis_milk2/shell_defines.h b/vis_milk2/shell_defines.h new file mode 100644 index 0000000..c978ce7 --- /dev/null +++ b/vis_milk2/shell_defines.h @@ -0,0 +1,76 @@ +/* + 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. +*/ + +#ifndef __NULLSOFT_DX9_PLUGIN_SHELL_SHELL_DEFINES_H__ +#define __NULLSOFT_DX9_PLUGIN_SHELL_SHELL_DEFINES_H__ 1 + +#include + +#define DEFAULT_FULLSCREEN_WIDTH 640 +#define DEFAULT_FULLSCREEN_HEIGHT 480 +#define MAX_ICON_TEXTURES 8 +#define ICON_TEXTURE_SIZE 256 +#define DEFAULT_WINDOW_SIZE 0.625f // as a portion of the width or height of the screen (whichever is smaller) +#define DESKTOP_MODE_KEYBOARD_INPUT_WINDOW_CLASSNAME "DESKTOP MODE KEYBOARD INPUT WINDOW" +#define BGR2RGB(x) (((x>>16)&0xFF) | (x & 0xFF00) | ((x<<16)&0xFF0000)) + +#define NUM_BASIC_FONTS 4 +#define SYS_FONT 0 +#define DEC_FONT 1 +#define HELP_FONT 2 +#define DESK_FONT 3 +#define MAX_EXTRA_FONTS 5 +typedef enum +{ + SIMPLE_FONT = 0, // aka 'system' font; should be legible + DECORATIVE_FONT = 1, + HELPSCREEN_FONT = 2, + PLAYLIST_FONT = 3, + EXTRA_1 = 4, + EXTRA_2 = 5, + EXTRA_3 = 6, + EXTRA_4 = 7, + EXTRA_5 = 8 +} +eFontIndex; + +// for m_screenmode: +typedef enum +{ + NOT_YET_KNOWN = -1, + FULLSCREEN = 0, + WINDOWED = 1, + FAKE_FULLSCREEN = 2, + DESKTOP = 3 // doesn't use overlays! =) +} +eScrMode; + +#include "../Winamp/wa_ipc.h" + +#endif \ No newline at end of file diff --git a/vis_milk2/state.cpp b/vis_milk2/state.cpp new file mode 100644 index 0000000..8eefe30 --- /dev/null +++ b/vis_milk2/state.cpp @@ -0,0 +1,1947 @@ +/* + 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. +*/ + +#include "api.h" +#include "state.h" +#include "support.h" +#include "../ns-eel2/ns-eel.h" +#include "plugin.h" +#include "utility.h" +#include +#include +#include "resource.h" + +extern CPlugin g_plugin; // declared in main.cpp + +#define FRAND ((rand() % 7381)/7380.0f) + + + +// These are intended to replace GetPrivateProfileInt/FloatString, which are very slow +// for large files (they always start from the top). (really slow - some preset loads +// were taking 90 ms because of these!) +// The trick here is that we assume the file will be ordered correctly. If not - if +// the next line doesn't have the expected token - we rescan from the top. If the line +// is never found, we use the default value, and leave MyGetPos untouched. + +#include "../nu/Vector.h" +#include "gstring.h" + +typedef Vector VarNameList; +typedef Vector IntList; + + +FILE* fLastFilePtr = NULL; +void GetFast_CLEAR() { fLastFilePtr = NULL; } +bool _GetLineByName(FILE* f, const char* szVarName, char* szRet, int nMaxRetChars) +{ + // lines in the file look like this: szVarName=szRet + // OR: szVarName szRet + // the part of the line after the '=' sign (or space) goes into szRet. + // szVarName can't have any spaces in it. + + static int MyLineNum = 0; + static VarNameList line_varName; + static IntList line_value_bytepos; + + if (f != fLastFilePtr) + { + fLastFilePtr = f; + MyLineNum = 0; + line_varName.clear(); + line_value_bytepos.clear(); + + // start from beginning of file + fseek(f, 0, SEEK_SET); + + // scan each line in the file for "szVarName=value" pairs, and store info about them. + #define MAX_VARNAME_LEN 128 + char szThisLineVarName[MAX_VARNAME_LEN]; + while (1) + { + char ch; + int pos = 0; + do + { + ch = fgetc(f); + if (pos < MAX_VARNAME_LEN-3) + szThisLineVarName[pos++] = ch; + } + while ( ch != '\r' && + ch != '\n' && + ch != ' ' && + ch != '=' && + ch != EOF ); + if (ch == EOF) + break; + + if (ch == '=' || ch == ' ') + { + szThisLineVarName[pos-1] = 0; // replace '=' with a null char. + int bytepos = ftell(f); + + //add an entry + line_varName.push_back(szThisLineVarName); + line_value_bytepos.push_back( bytepos ); + + // eat chars up to linefeed or EOF + /* + do + { + ch = fgetc(f); + } + while (ch != '\r' && ch != '\n' && ch != EOF); + */ + fgets(szRet, nMaxRetChars-3, f); // reads chars up til the next linefeed. + } + if (ch == EOF) + break; + + // eat any extra linefeed chars. + do + { + ch = fgetc(f); + } + while ((ch == '\r' || ch == '\n') && ch != EOF); + if (ch == EOF) + break; + + // back up one char + fseek(f, -1, SEEK_CUR); + + // on to next line... + } + } + + // if current line isn't the one, check all the others... + if (MyLineNum < 0 || (size_t)MyLineNum >= line_varName.size() || strcmp(line_varName[MyLineNum].c_str(), szVarName) != 0) + { + int N = line_varName.size(); + for (int i=0; i 0 + m_fModWaveAlphaEnd = 0.95f; // when relative volume hits this level, alpha -> 1 + m_fWaveR = 1.0f; + m_fWaveG = 1.0f; + m_fWaveB = 1.0f; + m_fWaveX = 0.5f; + m_fWaveY = 0.5f; + m_bMaximizeWaveColor = true; + m_fMvX = 12.0f; + m_fMvY = 9.0f; + m_fMvDX = 0.0f; + m_fMvDY = 0.0f; + m_fMvL = 0.9f; + m_fMvR = 1.0f; + m_fMvG = 1.0f; + m_fMvB = 1.0f; + m_fMvA = 1.0f; + + for (int i=0; im_fVideoEchoAlphaOld = s_from->m_fVideoEchoAlpha.eval(-1); + s_to->m_nVideoEchoOrientationOld = s_from->m_nVideoEchoOrientation; + s_to->m_nOldWaveMode = s_from->m_nWaveMode; + + /* + s_to->m_fVideoEchoAlphaOld = s_from->m_fVideoEchoAlpha.eval(-1); + s_to->m_nVideoEchoOrientationOld = s_from->m_nVideoEchoOrientation; + + s_to->m_nOldWaveMode = s_from->m_nWaveMode; + s_to->m_nWaveMode = s_from->m_nWaveMode; + s_to->m_bAdditiveWaves = s_from->m_bAdditiveWaves; + s_to->m_nVideoEchoOrientation = s_from->m_nVideoEchoOrientation; + s_to->m_fWarpAnimSpeed = s_from->m_fWarpAnimSpeed; // would req. 10 phase-matches to blend this one!!! + s_to->m_bWaveDots = s_from->m_bWaveDots; + s_to->m_bWaveThick = s_from->m_bWaveThick; + s_to->m_bModWaveAlphaByVolume = s_from->m_bModWaveAlphaByVolume; + s_to->m_bMaximizeWaveColor = s_from->m_bMaximizeWaveColor; + s_to->m_bTexWrap = s_from->m_bTexWrap; + s_to->m_bDarkenCenter = s_from->m_bDarkenCenter; + s_to->m_bRedBlueStereo = s_from->m_bRedBlueStereo; + s_to->m_bBrighten = s_from->m_bBrighten; + s_to->m_bDarken = s_from->m_bDarken; + s_to->m_bSolarize = s_from->m_bSolarize; + s_to->m_bInvert = s_from->m_bInvert; + s_to->m_fRating = s_from->m_fRating; + */ + + // expr. eval. also copies over immediately (replaces prev.) + m_bBlending = true; + m_fBlendStartTime = fAnimTime; + m_fBlendDuration = fTimespan; + + /* + //for (int e=0; em_szPerFrameExpr); + lstrcpy(s_to->m_szPerFrameExpr, szTemp); + + lstrcpy(szTemp, m_szPerPixelExpr); + lstrcpy(m_szPerPixelExpr, s_to->m_szPerPixelExpr); + lstrcpy(s_to->m_szPerPixelExpr, szTemp); + + lstrcpy(szTemp, m_szPerFrameInit); + lstrcpy(m_szPerFrameInit, s_to->m_szPerFrameInit); + lstrcpy(s_to->m_szPerFrameInit, szTemp); + } + RecompileExpressions(); + s_to->RecompileExpressions(); + + lstrcpy(m_szDesc, s_to->m_szDesc); + //lstrcpy(m_szSection, s_to->m_szSection); + */ + + // CBlendableFloats & SuperValues blend over time + m_fGammaAdj .StartBlendFrom(&s_from->m_fGammaAdj , fAnimTime, fTimespan); + m_fVideoEchoZoom .StartBlendFrom(&s_from->m_fVideoEchoZoom , fAnimTime, fTimespan); + m_fVideoEchoAlpha.StartBlendFrom(&s_from->m_fVideoEchoAlpha, fAnimTime, fTimespan); + m_fDecay .StartBlendFrom(&s_from->m_fDecay , fAnimTime, fTimespan); + m_fWaveAlpha .StartBlendFrom(&s_from->m_fWaveAlpha , fAnimTime, fTimespan); + m_fWaveScale .StartBlendFrom(&s_from->m_fWaveScale , fAnimTime, fTimespan); + m_fWaveSmoothing .StartBlendFrom(&s_from->m_fWaveSmoothing , fAnimTime, fTimespan); + m_fWaveParam .StartBlendFrom(&s_from->m_fWaveParam , fAnimTime, fTimespan); + m_fWarpScale .StartBlendFrom(&s_from->m_fWarpScale , fAnimTime, fTimespan); + m_fZoomExponent .StartBlendFrom(&s_from->m_fZoomExponent , fAnimTime, fTimespan); + m_fShader .StartBlendFrom(&s_from->m_fShader , fAnimTime, fTimespan); + m_fModWaveAlphaStart.StartBlendFrom(&s_from->m_fModWaveAlphaStart, fAnimTime, fTimespan); + m_fModWaveAlphaEnd .StartBlendFrom(&s_from->m_fModWaveAlphaEnd, fAnimTime, fTimespan); + + m_fZoom .StartBlendFrom(&s_from->m_fZoom , fAnimTime, fTimespan); + m_fRot .StartBlendFrom(&s_from->m_fRot , fAnimTime, fTimespan); + m_fRotCX .StartBlendFrom(&s_from->m_fRotCX , fAnimTime, fTimespan); + m_fRotCY .StartBlendFrom(&s_from->m_fRotCY , fAnimTime, fTimespan); + m_fXPush .StartBlendFrom(&s_from->m_fXPush , fAnimTime, fTimespan); + m_fYPush .StartBlendFrom(&s_from->m_fYPush , fAnimTime, fTimespan); + m_fWarpAmount.StartBlendFrom(&s_from->m_fWarpAmount,fAnimTime, fTimespan); + m_fStretchX .StartBlendFrom(&s_from->m_fStretchX , fAnimTime, fTimespan); + m_fStretchY .StartBlendFrom(&s_from->m_fStretchY , fAnimTime, fTimespan); + m_fWaveR .StartBlendFrom(&s_from->m_fWaveR , fAnimTime, fTimespan); + m_fWaveG .StartBlendFrom(&s_from->m_fWaveG , fAnimTime, fTimespan); + m_fWaveB .StartBlendFrom(&s_from->m_fWaveB , fAnimTime, fTimespan); + m_fWaveX .StartBlendFrom(&s_from->m_fWaveX , fAnimTime, fTimespan); + m_fWaveY .StartBlendFrom(&s_from->m_fWaveY , fAnimTime, fTimespan); + m_fOuterBorderSize .StartBlendFrom(&s_from->m_fOuterBorderSize , fAnimTime, fTimespan); + m_fOuterBorderR .StartBlendFrom(&s_from->m_fOuterBorderR , fAnimTime, fTimespan); + m_fOuterBorderG .StartBlendFrom(&s_from->m_fOuterBorderG , fAnimTime, fTimespan); + m_fOuterBorderB .StartBlendFrom(&s_from->m_fOuterBorderB , fAnimTime, fTimespan); + m_fOuterBorderA .StartBlendFrom(&s_from->m_fOuterBorderA , fAnimTime, fTimespan); + m_fInnerBorderSize .StartBlendFrom(&s_from->m_fInnerBorderSize , fAnimTime, fTimespan); + m_fInnerBorderR .StartBlendFrom(&s_from->m_fInnerBorderR , fAnimTime, fTimespan); + m_fInnerBorderG .StartBlendFrom(&s_from->m_fInnerBorderG , fAnimTime, fTimespan); + m_fInnerBorderB .StartBlendFrom(&s_from->m_fInnerBorderB , fAnimTime, fTimespan); + m_fInnerBorderA .StartBlendFrom(&s_from->m_fInnerBorderA , fAnimTime, fTimespan); + m_fMvX .StartBlendFrom(&s_from->m_fMvX , fAnimTime, fTimespan); + m_fMvY .StartBlendFrom(&s_from->m_fMvY , fAnimTime, fTimespan); + m_fMvDX .StartBlendFrom(&s_from->m_fMvDX , fAnimTime, fTimespan); + m_fMvDY .StartBlendFrom(&s_from->m_fMvDY , fAnimTime, fTimespan); + m_fMvL .StartBlendFrom(&s_from->m_fMvL , fAnimTime, fTimespan); + m_fMvR .StartBlendFrom(&s_from->m_fMvR , fAnimTime, fTimespan); + m_fMvG .StartBlendFrom(&s_from->m_fMvG , fAnimTime, fTimespan); + m_fMvB .StartBlendFrom(&s_from->m_fMvB , fAnimTime, fTimespan); + m_fMvA .StartBlendFrom(&s_from->m_fMvA , fAnimTime, fTimespan); + m_fBlur1Min .StartBlendFrom(&s_from->m_fBlur1Min , fAnimTime, fTimespan); + m_fBlur2Min .StartBlendFrom(&s_from->m_fBlur2Min , fAnimTime, fTimespan); + m_fBlur3Min .StartBlendFrom(&s_from->m_fBlur3Min , fAnimTime, fTimespan); + m_fBlur1Max .StartBlendFrom(&s_from->m_fBlur1Max , fAnimTime, fTimespan); + m_fBlur2Max .StartBlendFrom(&s_from->m_fBlur2Max , fAnimTime, fTimespan); + m_fBlur3Max .StartBlendFrom(&s_from->m_fBlur3Max , fAnimTime, fTimespan); + m_fBlur1EdgeDarken .StartBlendFrom(&s_from->m_fBlur1EdgeDarken , fAnimTime, fTimespan); + + // if motion vectors were transparent before, don't morph the # in X and Y - just + // start in the right place, and fade them in. + bool bOldStateTransparent = (s_from->m_fMvA.eval(-1) < 0.001f); + bool bNewStateTransparent = (s_to->m_fMvA.eval(-1) < 0.001f); + if (!bOldStateTransparent && bNewStateTransparent) + { + s_from->m_fMvX = s_to->m_fMvX.eval(fAnimTime); + s_from->m_fMvY = s_to->m_fMvY.eval(fAnimTime); + s_from->m_fMvDX = s_to->m_fMvDX.eval(fAnimTime); + s_from->m_fMvDY = s_to->m_fMvDY.eval(fAnimTime); + s_from->m_fMvL = s_to->m_fMvL.eval(fAnimTime); + s_from->m_fMvR = s_to->m_fMvR.eval(fAnimTime); + s_from->m_fMvG = s_to->m_fMvG.eval(fAnimTime); + s_from->m_fMvB = s_to->m_fMvB.eval(fAnimTime); + } + if (bNewStateTransparent && !bOldStateTransparent) + { + s_to->m_fMvX = s_from->m_fMvX.eval(fAnimTime); + s_to->m_fMvY = s_from->m_fMvY.eval(fAnimTime); + s_to->m_fMvDX = s_from->m_fMvDX.eval(fAnimTime); + s_to->m_fMvDY = s_from->m_fMvDY.eval(fAnimTime); + s_to->m_fMvL = s_from->m_fMvL.eval(fAnimTime); + s_to->m_fMvR = s_from->m_fMvR.eval(fAnimTime); + s_to->m_fMvG = s_from->m_fMvG.eval(fAnimTime); + s_to->m_fMvB = s_from->m_fMvB.eval(fAnimTime); + } + +} + +void WriteCode(FILE* fOut, int i, char* pStr, char* prefix, bool bPrependApostrophe = false) +{ + char szLineName[32]; + int line = 1; + int start_pos = 0; + int char_pos = 0; + + while (pStr[start_pos] != 0) + { + while ( pStr[char_pos] != 0 && + pStr[char_pos] != LINEFEED_CONTROL_CHAR) + char_pos++; + + sprintf(szLineName, "%s%d", prefix, line); + + char ch = pStr[char_pos]; + pStr[char_pos] = 0; + //if (!WritePrivateProfileString(szSectionName,szLineName,&pStr[start_pos],szIniFile)) return false; + fprintf(fOut, "%s=%s%s\n", szLineName, bPrependApostrophe ? "`" : "", &pStr[start_pos]); + pStr[char_pos] = ch; + + if (pStr[char_pos] != 0) char_pos++; + start_pos = char_pos; + line++; + } +} + +bool CState::Export(const wchar_t *szIniFile) +{ + FILE *fOut = _wfopen(szIniFile, L"w"); + if (!fOut) return false; + + // IMPORTANT: THESE MUST BE THE FIRST TWO LINES. Otherwise it is assumed to be a MilkDrop 1-era preset. + if (m_nMaxPSVersion > 0) + { + fprintf(fOut, "MILKDROP_PRESET_VERSION=%d\n", CUR_MILKDROP_PRESET_VERSION); + fprintf(fOut, "PSVERSION=%d\n" ,m_nMaxPSVersion); // the max + fprintf(fOut, "PSVERSION_WARP=%d\n",m_nWarpPSVersion); + fprintf(fOut, "PSVERSION_COMP=%d\n",m_nCompPSVersion); + } + + // just for backwards compatibility; MilkDrop 1 can read MilkDrop 2 presets, minus the new features. + // (...this section name allows the GetPrivateProfile*() functions to still work on milkdrop 1) + fprintf(fOut, "[preset00]\n"); + + fprintf(fOut, "%s=%.3f\n", "fRating", m_fRating); + fprintf(fOut, "%s=%.3f\n", "fGammaAdj", m_fGammaAdj.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fDecay", m_fDecay.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fVideoEchoZoom", m_fVideoEchoZoom.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fVideoEchoAlpha", m_fVideoEchoAlpha.eval(-1)); + fprintf(fOut, "%s=%d\n", "nVideoEchoOrientation", m_nVideoEchoOrientation); + + fprintf(fOut, "%s=%d\n", "nWaveMode", m_nWaveMode); + fprintf(fOut, "%s=%d\n", "bAdditiveWaves", m_bAdditiveWaves); + fprintf(fOut, "%s=%d\n", "bWaveDots", m_bWaveDots); + fprintf(fOut, "%s=%d\n", "bWaveThick", m_bWaveThick); + fprintf(fOut, "%s=%d\n", "bModWaveAlphaByVolume", m_bModWaveAlphaByVolume); + fprintf(fOut, "%s=%d\n", "bMaximizeWaveColor", m_bMaximizeWaveColor); + fprintf(fOut, "%s=%d\n", "bTexWrap", m_bTexWrap ); + fprintf(fOut, "%s=%d\n", "bDarkenCenter", m_bDarkenCenter ); + fprintf(fOut, "%s=%d\n", "bRedBlueStereo", m_bRedBlueStereo ); + fprintf(fOut, "%s=%d\n", "bBrighten", m_bBrighten ); + fprintf(fOut, "%s=%d\n", "bDarken", m_bDarken ); + fprintf(fOut, "%s=%d\n", "bSolarize", m_bSolarize ); + fprintf(fOut, "%s=%d\n", "bInvert", m_bInvert ); + + fprintf(fOut, "%s=%.3f\n", "fWaveAlpha", m_fWaveAlpha.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fWaveScale", m_fWaveScale.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fWaveSmoothing", m_fWaveSmoothing.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fWaveParam", m_fWaveParam.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fModWaveAlphaStart", m_fModWaveAlphaStart.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fModWaveAlphaEnd", m_fModWaveAlphaEnd.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fWarpAnimSpeed", m_fWarpAnimSpeed); + fprintf(fOut, "%s=%.3f\n", "fWarpScale", m_fWarpScale.eval(-1)); + fprintf(fOut, "%s=%.5f\n", "fZoomExponent", m_fZoomExponent.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "fShader", m_fShader.eval(-1)); + + fprintf(fOut, "%s=%.5f\n", "zoom", m_fZoom .eval(-1)); + fprintf(fOut, "%s=%.5f\n", "rot", m_fRot .eval(-1)); + fprintf(fOut, "%s=%.3f\n", "cx", m_fRotCX .eval(-1)); + fprintf(fOut, "%s=%.3f\n", "cy", m_fRotCY .eval(-1)); + fprintf(fOut, "%s=%.5f\n", "dx", m_fXPush .eval(-1)); + fprintf(fOut, "%s=%.5f\n", "dy", m_fYPush .eval(-1)); + fprintf(fOut, "%s=%.5f\n", "warp", m_fWarpAmount.eval(-1)); + fprintf(fOut, "%s=%.5f\n", "sx", m_fStretchX .eval(-1)); + fprintf(fOut, "%s=%.5f\n", "sy", m_fStretchY .eval(-1)); + fprintf(fOut, "%s=%.3f\n", "wave_r", m_fWaveR .eval(-1)); + fprintf(fOut, "%s=%.3f\n", "wave_g", m_fWaveG .eval(-1)); + fprintf(fOut, "%s=%.3f\n", "wave_b", m_fWaveB .eval(-1)); + fprintf(fOut, "%s=%.3f\n", "wave_x", m_fWaveX .eval(-1)); + fprintf(fOut, "%s=%.3f\n", "wave_y", m_fWaveY .eval(-1)); + + fprintf(fOut, "%s=%.3f\n", "ob_size", m_fOuterBorderSize.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ob_r", m_fOuterBorderR.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ob_g", m_fOuterBorderG.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ob_b", m_fOuterBorderB.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ob_a", m_fOuterBorderA.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ib_size", m_fInnerBorderSize.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ib_r", m_fInnerBorderR.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ib_g", m_fInnerBorderG.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ib_b", m_fInnerBorderB.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "ib_a", m_fInnerBorderA.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "nMotionVectorsX", m_fMvX.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "nMotionVectorsY", m_fMvY.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "mv_dx", m_fMvDX.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "mv_dy", m_fMvDY.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "mv_l", m_fMvL.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "mv_r", m_fMvR.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "mv_g", m_fMvG.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "mv_b", m_fMvB.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "mv_a", m_fMvA.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "b1n", m_fBlur1Min.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "b2n", m_fBlur2Min.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "b3n", m_fBlur3Min.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "b1x", m_fBlur1Max.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "b2x", m_fBlur2Max.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "b3x", m_fBlur3Max.eval(-1)); + fprintf(fOut, "%s=%.3f\n", "b1ed", m_fBlur1EdgeDarken.eval(-1)); + + for (int i=0; i= MD2_PS_2_0) + WriteCode(fOut, i, m_szWarpShadersText, "warp_", true); + if (m_nCompPSVersion >= MD2_PS_2_0) + WriteCode(fOut, i, m_szCompShadersText, "comp_", true); + + fclose(fOut); + + return true; +} + +int CWave::Export(FILE* fOut, const wchar_t *szFile, int i) +{ + FILE* f2 = fOut; + if (!fOut) + { + f2 = _wfopen(szFile, L"w"); + if (!f2) return 0; + } + + fprintf(f2, "wavecode_%d_%s=%d\n", i, "enabled", enabled); + fprintf(f2, "wavecode_%d_%s=%d\n", i, "samples", samples); + fprintf(f2, "wavecode_%d_%s=%d\n", i, "sep", sep ); + fprintf(f2, "wavecode_%d_%s=%d\n", i, "bSpectrum", bSpectrum); + fprintf(f2, "wavecode_%d_%s=%d\n", i, "bUseDots", bUseDots); + fprintf(f2, "wavecode_%d_%s=%d\n", i, "bDrawThick", bDrawThick); + fprintf(f2, "wavecode_%d_%s=%d\n", i, "bAdditive", bAdditive); + fprintf(f2, "wavecode_%d_%s=%.5f\n", i, "scaling", scaling); + fprintf(f2, "wavecode_%d_%s=%.5f\n", i, "smoothing", smoothing); + fprintf(f2, "wavecode_%d_%s=%.3f\n", i, "r", r); + fprintf(f2, "wavecode_%d_%s=%.3f\n", i, "g", g); + fprintf(f2, "wavecode_%d_%s=%.3f\n", i, "b", b); + fprintf(f2, "wavecode_%d_%s=%.3f\n", i, "a", a); + + // READ THE CODE IN + char prefix[64]; + sprintf(prefix, "wave_%d_init", i); WriteCode(f2, i, m_szInit, prefix); + sprintf(prefix, "wave_%d_per_frame", i); WriteCode(f2, i, m_szPerFrame, prefix); + sprintf(prefix, "wave_%d_per_point", i); WriteCode(f2, i, m_szPerPoint, prefix); + + if (!fOut) + fclose(f2); // [sic] + + return 1; +} + +int CShape::Export(FILE* fOut, const wchar_t *szFile, int i) +{ + FILE* f2 = fOut; + if (!fOut) + { + f2 = _wfopen(szFile, L"w"); + if (!f2) return 0; + //fprintf(f2, "[%s]\n", szSection); + } + + fprintf(f2, "shapecode_%d_%s=%d\n", i, "enabled", enabled); + fprintf(f2, "shapecode_%d_%s=%d\n", i, "sides", sides); + fprintf(f2, "shapecode_%d_%s=%d\n", i, "additive", additive); + fprintf(f2, "shapecode_%d_%s=%d\n", i, "thickOutline",thickOutline); + fprintf(f2, "shapecode_%d_%s=%d\n", i, "textured", textured); + fprintf(f2, "shapecode_%d_%s=%d\n", i, "num_inst", instances); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "x", x); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "y", y); + fprintf(f2, "shapecode_%d_%s=%.5f\n", i, "rad", rad); + fprintf(f2, "shapecode_%d_%s=%.5f\n", i, "ang", ang); + fprintf(f2, "shapecode_%d_%s=%.5f\n", i, "tex_ang", tex_ang); + fprintf(f2, "shapecode_%d_%s=%.5f\n", i, "tex_zoom", tex_zoom); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "r", r); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "g", g); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "b", b); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "a", a); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "r2", r2); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "g2", g2); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "b2", b2); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "a2", a2); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "border_r", border_r); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "border_g", border_g); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "border_b", border_b); + fprintf(f2, "shapecode_%d_%s=%.3f\n", i, "border_a", border_a); + + char prefix[64]; + sprintf(prefix, "shape_%d_init", i); WriteCode(f2, i, m_szInit, prefix); + sprintf(prefix, "shape_%d_per_frame", i); WriteCode(f2, i, m_szPerFrame, prefix); + //sprintf(prefix, "shape_%d_per_point", i); WriteCode(f2, i, m_szPerPoint, prefix); + + if (!fOut) + fclose(f2); // [sic] + + return 1; +} + +void ReadCode(FILE* f, char* pStr, char* prefix) +{ + if (!pStr) + return; + pStr[0] = 0; + + // read in & compile arbitrary expressions + char szLineName[32]; + char szLine[MAX_BIGSTRING_LEN]; + int len; + + int line = 1; + int char_pos = 0; + bool bDone = false; + + while (!bDone) + { + sprintf(szLineName, "%s%d", prefix, line); + + GetFastString(szLineName, "~!@#$", szLine, MAX_BIGSTRING_LEN, f); // fixme + len = strlen(szLine); + + if ((strcmp(szLine, "~!@#$")==0) || // if the key was missing, + (len >= MAX_BIGSTRING_LEN-1-char_pos-1)) // or if we're out of space + { + bDone = true; + } + else + { + sprintf(&pStr[char_pos], "%s%c", (szLine[0]=='`') ? &szLine[1] : szLine, LINEFEED_CONTROL_CHAR); + if (szLine[0] == '`') + len--; + } + + char_pos += len + 1; + line++; + } + pStr[char_pos++] = 0; // null-terminate + + // read in & compile arbitrary expressions + /* + int n2 = 3 + MAX_CUSTOM_WAVES*3 + MAX_CUSTOM_SHAPES*2; + for (int n=0; n= MAX_BIGSTRING_LEN-1-char_pos-1)) // or if we're out of space + { + bDone = true; + } + else + { + sprintf(&pStr[char_pos], "%s%c", szLine, LINEFEED_CONTROL_CHAR); + } + + char_pos += len + 1; + line++; + } + pStr[char_pos++] = 0; // null-terminate + } + */ +} + +int CWave::Import(FILE* f, const wchar_t* szFile, int i) +{ + FILE* f2 = f; + if (!f) + { + f2 = _wfopen(szFile, L"rb"); + if (!f2) return 0; + GetFast_CLEAR(); + } + + char buf[64]; + sprintf(buf, "wavecode_%d_%s", i, "enabled" ); enabled = GetFastInt (buf, enabled , f2); + sprintf(buf, "wavecode_%d_%s", i, "samples" ); samples = GetFastInt (buf, samples , f2); + sprintf(buf, "wavecode_%d_%s", i, "sep" ); sep = GetFastInt (buf, sep , f2); + sprintf(buf, "wavecode_%d_%s", i, "bSpectrum" ); bSpectrum = GetFastInt (buf, bSpectrum , f2); + sprintf(buf, "wavecode_%d_%s", i, "bUseDots" ); bUseDots = GetFastInt (buf, bUseDots , f2); + sprintf(buf, "wavecode_%d_%s", i, "bDrawThick"); bDrawThick = GetFastInt (buf, bDrawThick, f2); + sprintf(buf, "wavecode_%d_%s", i, "bAdditive" ); bAdditive = GetFastInt (buf, bAdditive , f2); + sprintf(buf, "wavecode_%d_%s", i, "scaling" ); scaling = GetFastFloat(buf, scaling , f2); + sprintf(buf, "wavecode_%d_%s", i, "smoothing" ); smoothing = GetFastFloat(buf, smoothing , f2); + sprintf(buf, "wavecode_%d_%s", i, "r" ); r = GetFastFloat(buf, r , f2); + sprintf(buf, "wavecode_%d_%s", i, "g" ); g = GetFastFloat(buf, g , f2); + sprintf(buf, "wavecode_%d_%s", i, "b" ); b = GetFastFloat(buf, b , f2); + sprintf(buf, "wavecode_%d_%s", i, "a" ); a = GetFastFloat(buf, a , f2); + + // READ THE CODE IN + char prefix[64]; + sprintf(prefix, "wave_%d_init", i); ReadCode(f2, m_szInit, prefix); + sprintf(prefix, "wave_%d_per_frame", i); ReadCode(f2, m_szPerFrame, prefix); + sprintf(prefix, "wave_%d_per_point", i); ReadCode(f2, m_szPerPoint, prefix); + + if (!f) + fclose(f2); // [sic] + + return 1; +} + +int CShape::Import(FILE* f, const wchar_t* szFile, int i) +{ + FILE* f2 = f; + if (!f) + { + f2 = _wfopen(szFile, L"rb"); + if (!f2) return 0; + GetFast_CLEAR(); + } + + char buf[64]; + sprintf(buf, "shapecode_%d_%s", i, "enabled" ); enabled = GetFastInt (buf, enabled , f2); + sprintf(buf, "shapecode_%d_%s", i, "sides" ); sides = GetFastInt (buf, sides , f2); + sprintf(buf, "shapecode_%d_%s", i, "additive" ); additive = GetFastInt (buf, additive , f2); + sprintf(buf, "shapecode_%d_%s", i, "thickOutline"); thickOutline = GetFastInt (buf, thickOutline, f2); + sprintf(buf, "shapecode_%d_%s", i, "textured" ); textured = GetFastInt (buf, textured , f2); + sprintf(buf, "shapecode_%d_%s", i, "num_inst" ); instances = GetFastInt (buf, instances , f2); + sprintf(buf, "shapecode_%d_%s", i, "x" ); x = GetFastFloat(buf, x , f2); + sprintf(buf, "shapecode_%d_%s", i, "y" ); y = GetFastFloat(buf, y , f2); + sprintf(buf, "shapecode_%d_%s", i, "rad" ); rad = GetFastFloat(buf, rad , f2); + sprintf(buf, "shapecode_%d_%s", i, "ang" ); ang = GetFastFloat(buf, ang , f2); + sprintf(buf, "shapecode_%d_%s", i, "tex_ang" ); tex_ang = GetFastFloat(buf, tex_ang , f2); + sprintf(buf, "shapecode_%d_%s", i, "tex_zoom" ); tex_zoom = GetFastFloat(buf, tex_zoom , f2); + sprintf(buf, "shapecode_%d_%s", i, "r" ); r = GetFastFloat(buf, r , f2); + sprintf(buf, "shapecode_%d_%s", i, "g" ); g = GetFastFloat(buf, g , f2); + sprintf(buf, "shapecode_%d_%s", i, "b" ); b = GetFastFloat(buf, b , f2); + sprintf(buf, "shapecode_%d_%s", i, "a" ); a = GetFastFloat(buf, a , f2); + sprintf(buf, "shapecode_%d_%s", i, "r2" ); r2 = GetFastFloat(buf, r2 , f2); + sprintf(buf, "shapecode_%d_%s", i, "g2" ); g2 = GetFastFloat(buf, g2 , f2); + sprintf(buf, "shapecode_%d_%s", i, "b2" ); b2 = GetFastFloat(buf, b2 , f2); + sprintf(buf, "shapecode_%d_%s", i, "a2" ); a2 = GetFastFloat(buf, a2 , f2); + sprintf(buf, "shapecode_%d_%s", i, "border_r" ); border_r = GetFastFloat(buf, border_r , f2); + sprintf(buf, "shapecode_%d_%s", i, "border_g" ); border_g = GetFastFloat(buf, border_g , f2); + sprintf(buf, "shapecode_%d_%s", i, "border_b" ); border_b = GetFastFloat(buf, border_b , f2); + sprintf(buf, "shapecode_%d_%s", i, "border_a" ); border_a = GetFastFloat(buf, border_a , f2); + + // READ THE CODE IN + char prefix[64]; + sprintf(prefix, "shape_%d_init", i); ReadCode(f2, m_szInit, prefix); + sprintf(prefix, "shape_%d_per_frame", i); ReadCode(f2, m_szPerFrame, prefix); + + if (!f) + fclose(f2); // [sic] + + return 1; +} + +bool CState::Import(const wchar_t *szIniFile, float fTime, CState* pOldState, DWORD ApplyFlags) +{ + // if any ApplyFlags are missing, the settings will be copied from pOldState. =) + + if (!pOldState) + ApplyFlags = STATE_ALL; + + if (ApplyFlags!=STATE_ALL && this != pOldState) + { + assert(pOldState); + // in order to copy the old state, we have to byte copy it. + memcpy(this, pOldState, sizeof(CState)); + // clear all the copied code pointers, WITHOUT actually freeing it (since ptrs were copied) + // so that the Default() call below won't release pOldState's copied pointers. + // [all expressions will be recompiled @ end of this fn, whether we updated them or not] + FreeVarsAndCode(false); + } + + // apply defaults for the stuff we will overwrite. + Default(ApplyFlags);//RandomizePresetVars(); + + GetFast_CLEAR(); + + if ( (ApplyFlags & STATE_GENERAL) && // check for these 3 @ same time, + (ApplyFlags & STATE_MOTION) && // so a preset switch w/ warp/comp lock + (ApplyFlags & STATE_WAVE) // updates the name, but mash-ups don't. + ) + { + m_fPresetStartTime = fTime; + + // extract a description of the preset from the filename + { + // copy get the filename (without the path) + const wchar_t *p = wcsrchr(szIniFile, '\\'); + if (p==NULL) p = szIniFile; + lstrcpyW(m_szDesc, p+1); + + // next remove the extension + RemoveExtension(m_szDesc); + } + } + + FILE* f = _wfopen(szIniFile, L"rb"); + if (!f) + return false; + + int nMilkdropPresetVersion = GetFastInt("MILKDROP_PRESET_VERSION",100,f); + //if (ApplyFlags != STATE_ALL) + // nMilkdropPresetVersion = CUR_MILKDROP_PRESET_VERSION; //if we're mashing up, force it up to now + + + int nWarpPSVersionInFile; + int nCompPSVersionInFile; + if (nMilkdropPresetVersion < 200) { + nWarpPSVersionInFile = 0; + nCompPSVersionInFile = 0; + } + else if (nMilkdropPresetVersion == 200) { + nWarpPSVersionInFile = GetFastInt("PSVERSION", 2, f); + nCompPSVersionInFile = nWarpPSVersionInFile; + } + else { + nWarpPSVersionInFile = GetFastInt("PSVERSION_WARP", 2, f); + nCompPSVersionInFile = GetFastInt("PSVERSION_COMP", 2, f); + } + + // general: + if (ApplyFlags & STATE_GENERAL) + { + m_fRating = GetFastFloat("fRating",m_fRating,f); + m_fDecay = GetFastFloat("fDecay",m_fDecay.eval(-1),f); + m_fGammaAdj = GetFastFloat("fGammaAdj" ,m_fGammaAdj.eval(-1),f); + m_fVideoEchoZoom = GetFastFloat("fVideoEchoZoom",m_fVideoEchoZoom.eval(-1),f); + m_fVideoEchoAlpha = GetFastFloat("fVideoEchoAlpha",m_fVideoEchoAlpha.eval(-1),f); + m_nVideoEchoOrientation = GetFastInt ("nVideoEchoOrientation",m_nVideoEchoOrientation,f); + m_bRedBlueStereo = (GetFastInt ("bRedBlueStereo", m_bRedBlueStereo,f) != 0); + m_bBrighten = (GetFastInt ("bBrighten",m_bBrighten ,f) != 0); + m_bDarken = (GetFastInt ("bDarken" ,m_bDarken ,f) != 0); + m_bSolarize = (GetFastInt ("bSolarize",m_bSolarize ,f) != 0); + m_bInvert = (GetFastInt ("bInvert" ,m_bInvert ,f) != 0); + m_fShader = GetFastFloat("fShader",m_fShader.eval(-1),f); + m_fBlur1Min = GetFastFloat("b1n", m_fBlur1Min.eval(-1),f); + m_fBlur2Min = GetFastFloat("b2n", m_fBlur2Min.eval(-1),f); + m_fBlur3Min = GetFastFloat("b3n", m_fBlur3Min.eval(-1),f); + m_fBlur1Max = GetFastFloat("b1x", m_fBlur1Max.eval(-1),f); + m_fBlur2Max = GetFastFloat("b2x", m_fBlur2Max.eval(-1),f); + m_fBlur3Max = GetFastFloat("b3x", m_fBlur3Max.eval(-1),f); + m_fBlur1EdgeDarken = GetFastFloat("b1ed", m_fBlur1EdgeDarken.eval(-1),f); + } + + // wave: + if (ApplyFlags & STATE_WAVE) + { + m_nWaveMode = GetFastInt ("nWaveMode",m_nWaveMode,f); + m_bAdditiveWaves = (GetFastInt ("bAdditiveWaves",m_bAdditiveWaves,f) != 0); + m_bWaveDots = (GetFastInt ("bWaveDots",m_bWaveDots,f) != 0); + m_bWaveThick = (GetFastInt ("bWaveThick",m_bWaveThick,f) != 0); + m_bModWaveAlphaByVolume = (GetFastInt ("bModWaveAlphaByVolume",m_bModWaveAlphaByVolume,f) != 0); + m_bMaximizeWaveColor = (GetFastInt ("bMaximizeWaveColor" ,m_bMaximizeWaveColor,f) != 0); + m_fWaveAlpha = GetFastFloat("fWaveAlpha",m_fWaveAlpha.eval(-1),f); + m_fWaveScale = GetFastFloat("fWaveScale",m_fWaveScale.eval(-1),f); + m_fWaveSmoothing = GetFastFloat("fWaveSmoothing",m_fWaveSmoothing.eval(-1),f); + m_fWaveParam = GetFastFloat("fWaveParam",m_fWaveParam.eval(-1),f); + m_fModWaveAlphaStart = GetFastFloat("fModWaveAlphaStart",m_fModWaveAlphaStart.eval(-1),f); + m_fModWaveAlphaEnd = GetFastFloat("fModWaveAlphaEnd",m_fModWaveAlphaEnd.eval(-1),f); + m_fWaveR = GetFastFloat("wave_r",m_fRot.eval(-1),f); + m_fWaveG = GetFastFloat("wave_g",m_fRot.eval(-1),f); + m_fWaveB = GetFastFloat("wave_b",m_fRot.eval(-1),f); + m_fWaveX = GetFastFloat("wave_x",m_fRot.eval(-1),f); + m_fWaveY = GetFastFloat("wave_y",m_fRot.eval(-1),f); + m_fMvX = GetFastFloat("nMotionVectorsX", m_fMvX.eval(-1),f); + m_fMvY = GetFastFloat("nMotionVectorsY", m_fMvY.eval(-1),f); + m_fMvDX = GetFastFloat("mv_dx", m_fMvDX.eval(-1),f); + m_fMvDY = GetFastFloat("mv_dy", m_fMvDY.eval(-1),f); + m_fMvL = GetFastFloat("mv_l", m_fMvL.eval(-1),f); + m_fMvR = GetFastFloat("mv_r", m_fMvR.eval(-1),f); + m_fMvG = GetFastFloat("mv_g", m_fMvG.eval(-1),f); + m_fMvB = GetFastFloat("mv_b", m_fMvB.eval(-1),f); + m_fMvA = (GetFastInt ("bMotionVectorsOn",false,f) == 0) ? 0.0f : 1.0f; // for backwards compatibility + m_fMvA = GetFastFloat("mv_a", m_fMvA.eval(-1),f); + for (int i=0; i0) + g_plugin.GenWarpPShaderText(m_szWarpShadersText, m_fDecay.eval(-1), m_bTexWrap); +} +void CState::GenDefaultCompShader() +{ + if (m_nCompPSVersion>0) + g_plugin.GenCompPShaderText(m_szCompShadersText, m_fGammaAdj.eval(-1), m_fVideoEchoAlpha.eval(-1), m_fVideoEchoZoom.eval(-1), m_nVideoEchoOrientation, m_fShader.eval(-1), m_bBrighten, m_bDarken, m_bSolarize, m_bInvert); +} + +void CState::FreeVarsAndCode(bool bFree) +{ + // free the compiled expressions + if (m_pf_codehandle) + { + if (bFree) + NSEEL_code_free(m_pf_codehandle); + m_pf_codehandle = NULL; + } + if (m_pp_codehandle) + { + if (bFree) + NSEEL_code_free(m_pp_codehandle); + m_pp_codehandle = NULL; + } + + for (int i=0; i= sizeof(src). + + int i2 = 0; + int len = strlen(src); + int bComment = false; + for (int i=0; i m_fBlendStartTime + m_fBlendDuration) || (fTime < m_fBlendStartTime)) + { + m_bBlending = false; + } + + if (!m_bBlending) + { + return val; + } + else + { + float mix = (fTime - m_fBlendStartTime) / m_fBlendDuration; + return (m_fBlendFrom*(1.0f - mix) + val*mix); + } +} + +//-------------------------------------------------------------------------------- + +void CBlendableFloat::StartBlendFrom(CBlendableFloat *f_from, float fAnimTime, float fDuration) +{ + if (fDuration < 0.001f) + return; + + m_fBlendFrom = f_from->eval(fAnimTime); + m_bBlending = true; + m_fBlendStartTime = fAnimTime; + m_fBlendDuration = fDuration; +} \ No newline at end of file diff --git a/vis_milk2/state.h b/vis_milk2/state.h new file mode 100644 index 0000000..5474f2d --- /dev/null +++ b/vis_milk2/state.h @@ -0,0 +1,448 @@ +/* + 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. +*/ + +#ifndef _MILKDROP_STATE_ +#define _MILKDROP_STATE_ 1 + +#include +#include +#include +#include "gstring.h" +#include "texmgr.h" + +#include // for D3DXVECTOR3 + +//#include "evallib/eval.h" +#include "../ns-eel2/ns-eel.h" +#include "md_defines.h" + +// flags for CState::RecompileExpressions(): +#define RECOMPILE_PRESET_CODE 1 +#define RECOMPILE_WAVE_CODE 2 +#define RECOMPILE_SHAPE_CODE 4 + +#define NUM_Q_VAR 32 +#define NUM_T_VAR 8 + +#define MAX_BIGSTRING_LEN 32768 + +class CBlendableFloat +{ +public: + CBlendableFloat(); + ~CBlendableFloat(); + + float operator = (float f) { + val = f; + m_bBlending = false; + return val; + }; + float operator *= (float f) { + val *= f; + m_bBlending = false; + return val; + }; + float operator /= (float f) { + val /= f; + m_bBlending = false; + return val; + }; + float operator -= (float f) { + val -= f; + m_bBlending = false; + return val; + }; + float operator += (float f) { + val += f; + m_bBlending = false; + return val; + }; + + float eval(float fTime); // call this from animation code. if fTime < 0, it will return unblended 'val'. + void StartBlendFrom(CBlendableFloat *f_from, float fAnimTime, float fDuration); + +protected: + float val; + bool m_bBlending; + float m_fBlendStartTime; + float m_fBlendDuration; + float m_fBlendFrom; +}; + +class CShape +{ +public: + int Import(FILE* f, const wchar_t* szFile, int i); + int Export(FILE* f, const wchar_t* szFile, int i); + + int enabled; + int sides; + int additive; + int thickOutline; + int textured; + int instances; + float x,y,rad,ang; + float r,g,b,a; + float r2,g2,b2,a2; + float border_r,border_g,border_b,border_a; + float tex_ang, tex_zoom; + + char m_szInit[MAX_BIGSTRING_LEN]; // note: only executed once -> don't need to save codehandle + char m_szPerFrame[MAX_BIGSTRING_LEN]; + //char m_szPerPoint[MAX_BIGSTRING_LEN]; + NSEEL_CODEHANDLE m_pf_codehandle; + //int m_pp_codehandle; + + + // for per-frame expression evaluation: + NSEEL_VMCTX m_pf_eel; + double *var_pf_time, *var_pf_fps; + double *var_pf_frame; + double *var_pf_progress; + //double *var_pf_q1, *var_pf_q2, *var_pf_q3, *var_pf_q4, *var_pf_q5, *var_pf_q6, *var_pf_q7, *var_pf_q8; + //double *var_pf_t1, *var_pf_t2, *var_pf_t3, *var_pf_t4, *var_pf_t5, *var_pf_t6, *var_pf_t7, *var_pf_t8; + double* var_pf_q[NUM_Q_VAR]; + double* var_pf_t[NUM_T_VAR]; + double *var_pf_bass, *var_pf_mid, *var_pf_treb, *var_pf_bass_att, *var_pf_mid_att, *var_pf_treb_att; + double *var_pf_r, *var_pf_g, *var_pf_b, *var_pf_a; + double *var_pf_r2, *var_pf_g2, *var_pf_b2, *var_pf_a2; + double *var_pf_border_r, *var_pf_border_g, *var_pf_border_b, *var_pf_border_a; + double *var_pf_x, *var_pf_y, *var_pf_rad, *var_pf_ang; + double *var_pf_sides, *var_pf_textured, *var_pf_additive, *var_pf_thick, *var_pf_instances, *var_pf_instance; + double *var_pf_tex_zoom, *var_pf_tex_ang; + + // for per-point expression evaluation: + /* + NSEEL_VMCTX m_pp_eel; + double *var_pp_time, *var_pp_fps; + double *var_pp_frame; + double *var_pp_progress; + double *var_pp_q1, *var_pp_q2, *var_pp_q3, *var_pp_q4, *var_pp_q5, *var_pp_q6, *var_pp_q7, *var_pp_q8; + double *var_pp_t1, *var_pp_t2, *var_pp_t3, *var_pp_t4, *var_pp_t5, *var_pp_t6, *var_pp_t7, *var_pp_t8; + double *var_pp_bass, *var_pp_mid, *var_pp_treb, *var_pp_bass_att, *var_pp_mid_att, *var_pp_treb_att; + double *var_pp_r, *var_pp_g, *var_pp_b, *var_pp_a; + double *var_pp_r2, *var_pp_g2, *var_pp_b2, *var_pp_a2; + double *var_pp_border_r, *var_pp_border_g, *var_pp_border_b, *var_pp_border_a; + double *var_pp_x, *var_pp_y, *var_pp_rad, *var_pp_ang, *var_pp_sides; + */ + + double t_values_after_init_code[NUM_T_VAR]; +}; + +class CWave +{ +public: + int Import(FILE* f, const wchar_t *szFile, int i); + int Export(FILE* f, const wchar_t* szFile, int i); + + int enabled; + int samples; + int sep; + float scaling; + float smoothing; + float x,y,r,g,b,a; + int bSpectrum; + int bUseDots; + int bDrawThick; + int bAdditive; + + char m_szInit[MAX_BIGSTRING_LEN]; // note: only executed once -> don't need to save codehandle + char m_szPerFrame[MAX_BIGSTRING_LEN]; + char m_szPerPoint[MAX_BIGSTRING_LEN]; + NSEEL_CODEHANDLE m_pf_codehandle; + NSEEL_CODEHANDLE m_pp_codehandle; + + // for per-frame expression evaluation: + NSEEL_VMCTX m_pf_eel; + double *var_pf_time, *var_pf_fps; + double *var_pf_frame; + double *var_pf_progress; + //double *var_pf_q1, *var_pf_q2, *var_pf_q3, *var_pf_q4, *var_pf_q5, *var_pf_q6, *var_pf_q7, *var_pf_q8; + //double *var_pf_t1, *var_pf_t2, *var_pf_t3, *var_pf_t4, *var_pf_t5, *var_pf_t6, *var_pf_t7, *var_pf_t8; + double* var_pf_q[NUM_Q_VAR]; + double* var_pf_t[NUM_T_VAR]; + double *var_pf_bass, *var_pf_mid, *var_pf_treb, *var_pf_bass_att, *var_pf_mid_att, *var_pf_treb_att; + double *var_pf_r, *var_pf_g, *var_pf_b, *var_pf_a; + double *var_pf_samples; + + // for per-point expression evaluation: + NSEEL_VMCTX m_pp_eel; + double *var_pp_time, *var_pp_fps; + double *var_pp_frame; + double *var_pp_progress; + //double *var_pp_q1, *var_pp_q2, *var_pp_q3, *var_pp_q4, *var_pp_q5, *var_pp_q6, *var_pp_q7, *var_pp_q8; + //double *var_pp_t1, *var_pp_t2, *var_pp_t3, *var_pp_t4, *var_pp_t5, *var_pp_t6, *var_pp_t7, *var_pp_t8; + double* var_pp_q[NUM_Q_VAR]; + double* var_pp_t[NUM_T_VAR]; + double *var_pp_bass, *var_pp_mid, *var_pp_treb, *var_pp_bass_att, *var_pp_mid_att, *var_pp_treb_att; + double *var_pp_sample, *var_pp_value1, *var_pp_value2; + double *var_pp_x, *var_pp_y, *var_pp_r, *var_pp_g, *var_pp_b, *var_pp_a; + + double t_values_after_init_code[NUM_T_VAR]; +}; + +typedef struct +{ + int type; + int in_var; + int out_var; + float constant; + float min; + float max; + float in_scale; + float amp; // for sine functions + float freq; // for sine functions + float freq2; // for sine functions + float phase; // for sine functions + float phase2; // for sine functions +} td_modifier; + +//#define MAX_EVALS 8 + +#define INVALID_PRESET_DESC L"" // this should contain invalid filename chars, so there is never a conflict... + +#define STATE_GENERAL 1 // and postproc (old presets) or blur, etc. (new presets) +#define STATE_MOTION 2 // and equations +#define STATE_WAVE 4 // waves, shapes, motion vectors +#define STATE_WARP 8 +#define STATE_COMP 16 +#define STATE_ALL (32-1) + +#define CUR_MILKDROP_PRESET_VERSION 201 +// 200: milkdrop 2 +// 201: instead of just 1 variable for shader version, it tracks 2 (comp and warp) separately. + +class CState +{ +public: + CState(); + ~CState(); + + void Default(DWORD ApplyFlags=STATE_ALL); + void Randomize(int nMode); + void StartBlendFrom(CState *s_from, float fAnimTime, float fTimespan); + bool Import(const wchar_t *szIniFile, float fTime, CState* pOldState, DWORD ApplyFlags=STATE_ALL); + bool Export(const wchar_t *szIniFile); + void RecompileExpressions(int flags=0xFFFFFFFF, int bReInit=1); + void GenDefaultWarpShader(); + void GenDefaultCompShader(); + + wchar_t m_szDesc[512]; // this is just the filename, without a path or extension. + //char m_szSection[256]; + + int m_nMinPSVersion; // the min of the warp & comp values... + int m_nMaxPSVersion; // the max of the warp & comp values... + int m_nWarpPSVersion; // 0 = milkdrop 1 era (no PS), 2 = ps_2_0, 3 = ps_3_0 + int m_nCompPSVersion; // 0 = milkdrop 1 era (no PS), 2 = ps_2_0, 3 = ps_3_0 + float m_fRating; // 0..5 + // post-processing: + CBlendableFloat m_fGammaAdj; // +0 -> +1.0 (double), +2.0 (triple)... + CBlendableFloat m_fVideoEchoZoom; + CBlendableFloat m_fVideoEchoAlpha; + float m_fVideoEchoAlphaOld; + int m_nVideoEchoOrientation; + int m_nVideoEchoOrientationOld; + + // fps-dependant: + CBlendableFloat m_fDecay; // 1.0 = none, 0.95 = heavy decay + + // other: + int m_nWaveMode; + int m_nOldWaveMode; + bool m_bAdditiveWaves; + CBlendableFloat m_fWaveAlpha; + CBlendableFloat m_fWaveScale; + CBlendableFloat m_fWaveSmoothing; + bool m_bWaveDots; + bool m_bWaveThick; + CBlendableFloat m_fWaveParam; // -1..1; 0 is normal + bool m_bModWaveAlphaByVolume; + CBlendableFloat m_fModWaveAlphaStart; // when relative volume hits this level, alpha -> 0 + CBlendableFloat m_fModWaveAlphaEnd; // when relative volume hits this level, alpha -> 1 + float m_fWarpAnimSpeed; // 1.0 = normal, 2.0 = double, 0.5 = half, etc. + CBlendableFloat m_fWarpScale; + CBlendableFloat m_fZoomExponent; + CBlendableFloat m_fShader; // 0 = no color shader, 1 = full color shader + bool m_bMaximizeWaveColor; + bool m_bTexWrap; + bool m_bDarkenCenter; + bool m_bRedBlueStereo; + bool m_bBrighten; + bool m_bDarken; + bool m_bSolarize; + bool m_bInvert; + /* + bool m_bPlates; + int m_nPlates; + CBlendableFloat m_fPlateAlpha; // 0 = off, 0.1 = barely visible, 1.0 = solid + CBlendableFloat m_fPlateR; + CBlendableFloat m_fPlateG; + CBlendableFloat m_fPlateB; + CBlendableFloat m_fPlateWidth; // 1.0=normal, 2.0=double, etc. + CBlendableFloat m_fPlateLength; // 1.0=normal, 2.0=double, etc. + float m_fPlateSpeed; // 1.0=normal, 2.0=double, etc. + bool m_bPlatesAdditive; + */ + + // map controls: + CBlendableFloat m_fZoom; + CBlendableFloat m_fRot; + CBlendableFloat m_fRotCX; + CBlendableFloat m_fRotCY; + CBlendableFloat m_fXPush; + CBlendableFloat m_fYPush; + CBlendableFloat m_fWarpAmount; + CBlendableFloat m_fStretchX; + CBlendableFloat m_fStretchY; + CBlendableFloat m_fWaveR; + CBlendableFloat m_fWaveG; + CBlendableFloat m_fWaveB; + CBlendableFloat m_fWaveX; + CBlendableFloat m_fWaveY; + CBlendableFloat m_fOuterBorderSize; + CBlendableFloat m_fOuterBorderR; + CBlendableFloat m_fOuterBorderG; + CBlendableFloat m_fOuterBorderB; + CBlendableFloat m_fOuterBorderA; + CBlendableFloat m_fInnerBorderSize; + CBlendableFloat m_fInnerBorderR; + CBlendableFloat m_fInnerBorderG; + CBlendableFloat m_fInnerBorderB; + CBlendableFloat m_fInnerBorderA; + CBlendableFloat m_fMvX; + CBlendableFloat m_fMvY; + CBlendableFloat m_fMvDX; + CBlendableFloat m_fMvDY; + CBlendableFloat m_fMvL; + CBlendableFloat m_fMvR; + CBlendableFloat m_fMvG; + CBlendableFloat m_fMvB; + CBlendableFloat m_fMvA; + CBlendableFloat m_fBlur1Min; + CBlendableFloat m_fBlur2Min; + CBlendableFloat m_fBlur3Min; + CBlendableFloat m_fBlur1Max; + CBlendableFloat m_fBlur2Max; + CBlendableFloat m_fBlur3Max; + CBlendableFloat m_fBlur1EdgeDarken; + + CShape m_shape[MAX_CUSTOM_SHAPES]; + CWave m_wave[MAX_CUSTOM_WAVES]; + + // some random stuff for driving shaders: + void RandomizePresetVars(); + D3DXVECTOR4 m_rand_preset; // 4 random floats (0..1); randomized @ preset load; fed to pixel shaders. --FIXME (blending) + D3DXVECTOR3 m_xlate[20]; + D3DXVECTOR3 m_rot_base[20]; + D3DXVECTOR3 m_rot_speed[20]; + + //COscillator m_waveR; + //COscillator m_waveG; + //COscillator m_waveB; + //COscillator m_wavePosX; // 0 = centered + //COscillator m_wavePosY; // 0 = centered + + // for arbitrary function evaluation: + NSEEL_CODEHANDLE m_pf_codehandle; + NSEEL_CODEHANDLE m_pp_codehandle; + char m_szPerFrameInit[MAX_BIGSTRING_LEN]; + char m_szPerFrameExpr[MAX_BIGSTRING_LEN]; + char m_szPerPixelExpr[MAX_BIGSTRING_LEN]; + char m_szWarpShadersText[MAX_BIGSTRING_LEN]; // pixel shader code + char m_szCompShadersText[MAX_BIGSTRING_LEN]; // pixel shader code + void FreeVarsAndCode(bool bFree = true); + void RegisterBuiltInVariables(int flags); + void StripLinefeedCharsAndComments(char *src, char *dest); + + bool m_bBlending; + float m_fBlendStartTime; + float m_fBlendDuration; + float m_fBlendProgress; // 0..1; updated every frame based on StartTime and Duration. + + // for once-per-frame expression evaluation: [although, these vars are also shared w/preset init expr eval] + NSEEL_VMCTX m_pf_eel; + double *var_pf_zoom, *var_pf_zoomexp, *var_pf_rot, *var_pf_warp, *var_pf_cx, *var_pf_cy, *var_pf_dx, *var_pf_dy, *var_pf_sx, *var_pf_sy; + double *var_pf_time, *var_pf_fps; + double *var_pf_bass, *var_pf_mid, *var_pf_treb, *var_pf_bass_att, *var_pf_mid_att, *var_pf_treb_att; + double *var_pf_wave_a, *var_pf_wave_r, *var_pf_wave_g, *var_pf_wave_b, *var_pf_wave_x, *var_pf_wave_y, *var_pf_wave_mystery, *var_pf_wave_mode; + double *var_pf_decay; + double *var_pf_frame; + //double *var_pf_q1, *var_pf_q2, *var_pf_q3, *var_pf_q4, *var_pf_q5, *var_pf_q6, *var_pf_q7, *var_pf_q8; + double* var_pf_q[NUM_Q_VAR]; + double *var_pf_progress; + double *var_pf_ob_size, *var_pf_ob_r, *var_pf_ob_g, *var_pf_ob_b, *var_pf_ob_a; + double *var_pf_ib_size, *var_pf_ib_r, *var_pf_ib_g, *var_pf_ib_b, *var_pf_ib_a; + double *var_pf_mv_x; + double *var_pf_mv_y; + double *var_pf_mv_dx; + double *var_pf_mv_dy; + double *var_pf_mv_l; + double *var_pf_mv_r; + double *var_pf_mv_g; + double *var_pf_mv_b; + double *var_pf_mv_a; + double *var_pf_monitor; + double *var_pf_echo_zoom, *var_pf_echo_alpha, *var_pf_echo_orient; + // new in v1.04: + double *var_pf_wave_usedots, *var_pf_wave_thick, *var_pf_wave_additive, *var_pf_wave_brighten; + double *var_pf_darken_center, *var_pf_gamma, *var_pf_wrap; + double *var_pf_invert, *var_pf_brighten, *var_pf_darken, *var_pf_solarize; + double *var_pf_meshx, *var_pf_meshy; + double *var_pf_pixelsx, *var_pf_pixelsy; + double *var_pf_aspectx, *var_pf_aspecty; + double *var_pf_blur1min; + double *var_pf_blur2min; + double *var_pf_blur3min; + double *var_pf_blur1max; + double *var_pf_blur2max; + double *var_pf_blur3max; + double *var_pf_blur1_edge_darken; + + // for per-vertex expression evaluation: + NSEEL_VMCTX m_pv_eel; + double *var_pv_zoom, *var_pv_zoomexp, *var_pv_rot, *var_pv_warp, *var_pv_cx, *var_pv_cy, *var_pv_dx, *var_pv_dy, *var_pv_sx, *var_pv_sy; + double *var_pv_time, *var_pv_fps; + double *var_pv_bass, *var_pv_mid, *var_pv_treb, *var_pv_bass_att, *var_pv_mid_att, *var_pv_treb_att; + double *var_pv_x, *var_pv_y, *var_pv_rad, *var_pv_ang; + double *var_pv_frame; + //double *var_pv_q1, *var_pv_q2, *var_pv_q3, *var_pv_q4, *var_pv_q5, *var_pv_q6, *var_pv_q7, *var_pv_q8; + double* var_pv_q[NUM_Q_VAR]; + double *var_pv_progress; + double *var_pv_meshx, *var_pv_meshy; + double *var_pv_pixelsx, *var_pv_pixelsy; + double *var_pv_aspectx, *var_pv_aspecty; + + double q_values_after_init_code[NUM_Q_VAR]; + double monitor_after_init_code; + + float GetPresetStartTime() { return m_fPresetStartTime; } + float m_fPresetStartTime; +}; + +#endif \ No newline at end of file diff --git a/vis_milk2/support.cpp b/vis_milk2/support.cpp new file mode 100644 index 0000000..76696da --- /dev/null +++ b/vis_milk2/support.cpp @@ -0,0 +1,361 @@ +/* + 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. +*/ + +#include "support.h" +#include "utility.h" +#include "../Winamp/wa_ipc.h" + +bool g_bDebugOutput = false; +bool g_bDumpFileCleared = false; + +//--------------------------------------------------- +void PrepareFor3DDrawing( + IDirect3DDevice9 *pDevice, + int viewport_width, + int viewport_height, + float fov_in_degrees, + float near_clip, + float far_clip, + D3DXVECTOR3* pvEye, + D3DXVECTOR3* pvLookat, + D3DXVECTOR3* pvUp + ) +{ + // This function sets up DirectX up for 3D rendering. + // Only call it once per frame, as it is VERY slow. + // INPUTS: + // pDevice a pointer to the D3D device + // viewport_width the width of the client area of the window + // viewport_height the height of the client area of the window + // fov_in_degrees the field of view, in degrees + // near_clip the distance to the near clip plane; should be > 0! + // far_clip the distance to the far clip plane + // eye the eyepoint coordinates, in world space + // lookat the point toward which the eye is looking, in world space + // up a vector indicating which dir. is up; usually <0,1,0> + // + // What this function does NOT do: + // 1. set the current texture (SetTexture) + // 2. set up the texture stages for texturing (SetTextureStageState) + // 3. set the current vertex format (SetVertexShader) + // 4. set up the world matrix (SetTransform(D3DTS_WORLD, &my_world_matrix)) + + + // set up render state to some nice defaults: + { + // some defaults + pDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); + pDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE ); + pDevice->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL ); + pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); + pDevice->SetRenderState( D3DRS_CLIPPING, TRUE ); + pDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); + pDevice->SetRenderState( D3DRS_COLORVERTEX, TRUE ); + pDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD ); + pDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); + pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); + + // turn fog off + pDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); + pDevice->SetRenderState( D3DRS_RANGEFOGENABLE, FALSE ); + + // turn on high-quality bilinear interpolations + pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + pDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + pDevice->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); + } + + // set up view & projection matrices (but not the world matrix!) + { + // if the window is not square, instead of distorting the scene, + // clip it so that the longer dimension of the window has the + // regular FOV, and the shorter dimension has a reduced FOV. + float fov_x = fov_in_degrees * 3.1415927f/180.0f; + float fov_y = fov_in_degrees * 3.1415927f/180.0f; + float aspect = (float)viewport_height / (float)viewport_width; + if (aspect < 1) + fov_y *= aspect; + else + fov_x /= aspect; + + if (near_clip < 0.1f) + near_clip = 0.1f; + if (far_clip < near_clip + 1.0f) + far_clip = near_clip + 1.0f; + + D3DXMATRIX proj; + MakeProjectionMatrix(&proj, near_clip, far_clip, fov_x, fov_y); + pDevice->SetTransform(D3DTS_PROJECTION, &proj); + + D3DXMATRIX view; + pMatrixLookAtLH(&view, pvEye, pvLookat, pvUp); + pDevice->SetTransform(D3DTS_VIEW, &view); + + // Optimization note: "You can minimize the number of required calculations + // by concatenating your world and view matrices into a world-view matrix + // that you set as the world matrix, and then setting the view matrix + // to the identity." + //D3DXMatrixMultiply(&world, &world, &view); + //D3DXMatrixIdentity(&view); + } +} + +void PrepareFor2DDrawing(IDirect3DDevice9 *pDevice) +{ + // 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_FLAT ); + 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->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, 2.0f, -2.0f, 0.0f, 1.0f); + D3DXMatrixIdentity(&Identity); + + pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D); + pDevice->SetTransform(D3DTS_WORLD, &Identity); + pDevice->SetTransform(D3DTS_VIEW, &Identity); + } +} + +//--------------------------------------------------- + +void MakeWorldMatrix( D3DXMATRIX* pOut, + float xpos, float ypos, float zpos, + float sx, float sy, float sz, + float pitch, float yaw, float roll) +{ + /* + * The m_xPos, m_yPos, m_zPos variables contain the model's + * location in world coordinates. + * The m_fPitch, m_fYaw, and m_fRoll variables are floats that + * contain the model's orientation in terms of pitch, yaw, and roll + * angles, in radians. + */ + + D3DXMATRIX MatTemp; + D3DXMatrixIdentity(pOut); + + // 1. first, rotation + if (pitch || yaw || roll) + { + D3DXMATRIX MatRot; + D3DXMatrixIdentity(&MatRot); + + pMatrixRotationX(&MatTemp, pitch); // Pitch + pMatrixMultiply(&MatRot, &MatRot, &MatTemp); + pMatrixRotationY(&MatTemp, yaw); // Yaw + pMatrixMultiply(&MatRot, &MatRot, &MatTemp); + pMatrixRotationZ(&MatTemp, roll); // Roll + pMatrixMultiply(&MatRot, &MatRot, &MatTemp); + + pMatrixMultiply(pOut, pOut, &MatRot); + } + + // 2. then, scaling + pMatrixScaling(&MatTemp, sx, sy, sz); + pMatrixMultiply(pOut, pOut, &MatTemp); + + // 3. last, translation to final world pos. + pMatrixTranslation(&MatTemp, xpos, ypos, zpos); + pMatrixMultiply(pOut, pOut, &MatTemp); +} + +void MakeProjectionMatrix( D3DXMATRIX* pOut, + const float near_plane, // Distance to near clipping plane + const float far_plane, // Distance to far clipping plane + const float fov_horiz, // Horizontal field of view angle, in radians + const float fov_vert) // Vertical field of view angle, in radians +{ + float w = (float)1/tanf(fov_horiz*0.5f); // 1/tan(x) == cot(x) + float h = (float)1/tanf(fov_vert*0.5f); // 1/tan(x) == cot(x) + float Q = far_plane/(far_plane - near_plane); + + ZeroMemory(pOut, sizeof(D3DXMATRIX)); + pOut->_11 = w; + pOut->_22 = h; + pOut->_33 = Q; + pOut->_43 = -Q*near_plane; + pOut->_34 = 1; +} + +void GetWinampSongTitle(HWND hWndWinamp, wchar_t *szSongTitle, int nSize) +{ + szSongTitle[0] = 0; + lstrcpynW(szSongTitle, (wchar_t*)SendMessage(hWndWinamp, WM_WA_IPC, + SendMessage(hWndWinamp, WM_WA_IPC, 0 , IPC_GETLISTPOS), + IPC_GETPLAYLISTTITLEW), nSize); +} + +void GetWinampSongPosAsText(HWND hWndWinamp, wchar_t *szSongPos) +{ + // note: size(szSongPos[]) must be at least 64. + szSongPos[0] = 0; + int nSongPosMS = SendMessage(hWndWinamp,WM_USER,0,105); + if (nSongPosMS > 0) + { + wchar_t tmp[16]; + float time_s = nSongPosMS*0.001f; + int minutes = (int)(time_s/60); + time_s -= minutes*60; + int seconds = (int)time_s; + time_s -= seconds; + int dsec = (int)(time_s*100); + swprintf(tmp, L"%.02f", dsec/100.0f); + swprintf(szSongPos, L"%d:%02d%s", minutes, seconds, tmp+1); + } +} + +void GetWinampSongLenAsText(HWND hWndWinamp, wchar_t *szSongLen) +{ + // note: size(szSongLen[]) must be at least 64. + szSongLen[0] = 0; + int nSongLenMS = SendMessage(hWndWinamp,WM_USER,1,105)*1000; + if (nSongLenMS > 0) + { + int len_s = nSongLenMS/1000; + int minutes = len_s/60; + int seconds = len_s - minutes*60; + swprintf(szSongLen, L"%d:%02d", minutes, seconds); + } +} + +float GetWinampSongPos(HWND hWndWinamp) +{ + // returns answer in seconds + return (float)SendMessage(hWndWinamp,WM_USER,0,105)*0.001f; +} + +float GetWinampSongLen(HWND hWndWinamp) +{ + // returns answer in seconds + return (float)SendMessage(hWndWinamp,WM_USER,1,105); +} + +int GetDX9TexFormatBitsPerPixel(D3DFORMAT fmt) +{ + switch(fmt) + { + case D3DFMT_DXT1: // 64 bits for each 4x4 pixels = 4 bits per pixel. No Alpha channel. + return 4; // bytes per pixel + + case D3DFMT_DXT2: // 128 bits for each 4x4 pixels = 8 bits per pixel. RGB+A. + case D3DFMT_DXT3: // 128 bits for each 4x4 pixels = 8 bits per pixel. RGB+A. + case D3DFMT_DXT4: // 128 bits for each 4x4 pixels = 8 bits per pixel. RGB+A. + case D3DFMT_DXT5: // 128 bits for each 4x4 pixels = 8 bits per pixel. RGB+A. + case D3DFMT_R3G3B2: // 8-bit RGB texture format using 3 bits for red, 3 bits for green, and 2 bits for blue. + case D3DFMT_A8: // 8-bit alpha only. + case D3DFMT_A8P8: // 8-bit color indexed with 8 bits of alpha. + case D3DFMT_P8: // 8-bit color indexed. + case D3DFMT_L8: // 8-bit luminance only. + case D3DFMT_A4L4: // 8-bit using 4 bits each for alpha and luminance. + return 8; + + case D3DFMT_R5G6B5: // 16-bit RGB pixel format with 5 bits for red, 6 bits for green, and 5 bits for blue. + case D3DFMT_X1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color. + case D3DFMT_A1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color and 1 bit is reserved for alpha. + case D3DFMT_A4R4G4B4: // 16-bit ARGB pixel format with 4 bits for each channel. + case D3DFMT_R16F: + case D3DFMT_A8R3G3B2: // 16-bit ARGB texture format using 8 bits for alpha, 3 bits each for red and green, and 2 bits for blue. + case D3DFMT_X4R4G4B4: // 16-bit RGB pixel format using 4 bits for each color. + case D3DFMT_L16: // 16-bit luminance only. + case D3DFMT_A8L8: // 16-bit using 8 bits each for alpha and luminance. + case D3DFMT_CxV8U8: + case D3DFMT_V8U8: + case D3DFMT_L6V5U5: + return 16; + + case D3DFMT_G16R16F: + case D3DFMT_R32F: // 32-bit float format using 32 bits for the red channel. + case D3DFMT_A8R8G8B8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel. + case D3DFMT_X8R8G8B8: // 32-bit RGB pixel format, where 8 bits are reserved for each color. + case D3DFMT_A8B8G8R8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel. + case D3DFMT_X8B8G8R8: // 32-bit RGB pixel format, where 8 bits are reserved for each color. + case D3DFMT_G16R16: // 32-bit pixel format using 16 bits each for green and red. + case D3DFMT_A2R10G10B10: // 32-bit pixel format using 10 bits each for red, green, and blue, and 2 bits for alpha. + case D3DFMT_A2B10G10R10: // 32-bit pixel format using 10 bits for each color and 2 bits for alpha. + case D3DFMT_R8G8B8: // 24-bit RGB pixel format with 8 bits per channel. + case D3DFMT_X8L8V8U8: + case D3DFMT_Q8W8V8U8: + case D3DFMT_V16U16: + return 32; + + case D3DFMT_A16B16G16R16F: + case D3DFMT_A16B16G16R16: // 64-bit pixel format using 16 bits for each component. + case D3DFMT_G32R32F: // 64-bit float format using 32 bits for the red channel and 32 bits for the green channel. + return 64; + + case D3DFMT_A32B32G32R32F: + return 128; + } + + return 32; +} \ No newline at end of file diff --git a/vis_milk2/support.h b/vis_milk2/support.h new file mode 100644 index 0000000..e051614 --- /dev/null +++ b/vis_milk2/support.h @@ -0,0 +1,109 @@ +/* + 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. +*/ + +#ifndef __NULLSOFT_DX9_EXAMPLE_PLUGIN_SUPPORT_H__ +#define __NULLSOFT_DX9_EXAMPLE_PLUGIN_SUPPORT_H__ 1 + +#include + +void MakeWorldMatrix( D3DXMATRIX* pOut, + float xpos, float ypos, float zpos, + float sx, float sy, float sz, + float pitch, float yaw, float roll); +void MakeProjectionMatrix( D3DXMATRIX* pOut, + const float near_plane, // Distance to near clipping plane + const float far_plane, // Distance to far clipping plane + const float fov_horiz, // Horizontal field of view angle, in radians + const float fov_vert); // Vertical field of view angle, in radians +void PrepareFor3DDrawing( + IDirect3DDevice9 *pDevice, + int viewport_width, + int viewport_height, + float fov_in_degrees, + float near_clip, + float far_clip, + D3DXVECTOR3* pvEye, + D3DXVECTOR3* pvLookat, + D3DXVECTOR3* pvUp + ); +void PrepareFor2DDrawing(IDirect3DDevice9 *pDevice); + +// Define vertex formats you'll be using here: +// note: layout must match the vertex declaration in plugin.cpp! +typedef struct _MYVERTEX +{ + float x, y, z; // screen position + Z-buffer depth + DWORD Diffuse; // diffuse color + float tu, tv; // DYNAMIC + float tu_orig, tv_orig; // STATIC + float rad, ang; // STATIC +} MYVERTEX, *LPMYVERTEX; + +// note: layout must match the vertex declaration in plugin.cpp! +typedef struct _WFVERTEX +{ + float x, y, z; + DWORD Diffuse; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims) +} WFVERTEX, *LPWFVERTEX; + +// note: layout must match the vertex declaration in plugin.cpp! +typedef struct _SPRITEVERTEX +{ + 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 +} SPRITEVERTEX, *LPSPRITEVERTEX; + +// Also prepare vertex format descriptors for each +// of the 3 kinds of vertices we'll be using: +// note: D3DFVF_TEXCOORDSIZEm(n): m = the dimension, n = the index +// AVOID D3DFVF_TEXCOORDSIZE4 - I've seen probs (blending between shader and non-shader presets) on vaio laptop w/6200! +#define MYVERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE2(1) | D3DFVF_TEXCOORDSIZE2(2)) +#define WFVERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE ) +#define SPRITEVERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0) ) + +void GetWinampSongTitle(HWND hWndWinamp, wchar_t *szSongTitle, int nSize); +void GetWinampSongPosAsText(HWND hWndWinamp, wchar_t *szSongPos); +void GetWinampSongLenAsText(HWND hWndWinamp, wchar_t *szSongLen); +float GetWinampSongPos(HWND hWndWinamp); // returns answer in seconds +float GetWinampSongLen(HWND hWndWinamp); // returns answer in seconds + +//#define PROFILING +#ifdef PROFILING + #define PROFILE_BEGIN LARGE_INTEGER tx, freq, ty; QueryPerformanceCounter(&tx); QueryPerformanceFrequency(&freq); + #define PROFILE_END(s) { QueryPerformanceCounter(&ty); float dt = (float)((double)(ty.QuadPart - tx.QuadPart) / (double)freq.QuadPart); char buf[256]; sprintf(buf, " %s = %.1f ms\n", s, dt*1000 ); OutputDebugString(buf); tx = ty; } +#else + #define PROFILE_BEGIN + #define PROFILE_END(s) +#endif + +int GetDX9TexFormatBitsPerPixel(D3DFORMAT fmt); + +#endif \ No newline at end of file diff --git a/vis_milk2/temp.ico b/vis_milk2/temp.ico new file mode 100644 index 0000000..a48a54f Binary files /dev/null and b/vis_milk2/temp.ico differ diff --git a/vis_milk2/texmgr.cpp b/vis_milk2/texmgr.cpp new file mode 100644 index 0000000..8ff6bc9 --- /dev/null +++ b/vis_milk2/texmgr.cpp @@ -0,0 +1,752 @@ +/* + 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. +*/ + +#include "texmgr.h" +//#include "jpegstuff.h" +//#include "evallib/compiler.h" +#include "../ns-eel2/ns-eel.h" +#include "support.h" +#include "plugin.h" +#include "utility.h" +texmgr::texmgr() +{ +} + +texmgr::~texmgr() +{ + //Finish(); + // DO NOT RELEASE OR DELETE m_lpDD; CLIENT SHOULD DO THIS! +} + +void texmgr::Finish() +{ + for (int i=0; iRelease(); + m_tex[i].pSurface = NULL; + } + + FreeCode(i); + FreeVars(i); + */ + NSEEL_VM_free(m_tex[i].tex_eel_ctx); + } + + // DO NOT RELEASE OR DELETE m_lpDD; CLIENT SHOULD DO THIS! +} + +void texmgr::Init(LPDIRECT3DDEVICE9 lpDD) +{ + m_lpDD = lpDD; + + for (int i=0; i16 && h>16) + { + w /= 2; + h /= 2; + } + else + { + done = 1; + } + } + + break; + } + + if (done) + break; + + // TRY TO CREATE THE SURFACE IN SYSTEM MEMORY. + ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;//DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;// | DDSCAPS_3DDEVICE;// | DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY; + ddsd.dwWidth = w; + ddsd.dwHeight = h; + + m_tex[iSlot].pSurface = NULL; + //if (w<256 && h<256) + if (m_lpDD->CreateSurface( &ddsd, &m_tex[iSlot].pSurface, NULL ) == DD_OK) + break; + m_tex[iSlot].pSurface = NULL; + + loop++; + } + while (!done); + + if (m_tex[iSlot].pSurface == NULL) + return false; + + // find out (& remember) actual size created: + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + m_tex[iSlot].pSurface->GetSurfaceDesc(&ddsd); + m_tex[iSlot].tex_w = ddsd.dwWidth; + m_tex[iSlot].tex_h = ddsd.dwHeight; + m_tex[iSlot].scale_x = 1.0f; + m_tex[iSlot].scale_y = 1.0f; + + memcpy(&m_tex[iSlot].ddpf, &ddsd.ddpfPixelFormat, sizeof(DDPIXELFORMAT)); + + return true; +} +*/ + +int texmgr::LoadTex(wchar_t *szFilename, int iSlot, char *szInitCode, char *szCode, float time, int frame, unsigned int ck) +{ + if (iSlot < 0) return TEXMGR_ERR_BAD_INDEX; + if (iSlot >= NUM_TEX) return TEXMGR_ERR_BAD_INDEX; + + // first, if this texture is already loaded, just add another instance. + bool bTextureInstanced = false; + { + for (int x=0; xRelease(); + m_tex[iSlot].pSurface = NULL; + }*/ + KillTex(iSlot); + + wcscpy(m_tex[iSlot].szFileName, szFilename); + + D3DXIMAGE_INFO info; + HRESULT hr = pCreateTextureFromFileExW( + m_lpDD, + szFilename, + D3DX_DEFAULT, + D3DX_DEFAULT, + D3DX_DEFAULT, // create a mip chain + 0, + D3DFMT_UNKNOWN, + D3DPOOL_DEFAULT, + D3DX_DEFAULT, + D3DX_DEFAULT, + 0xFF000000 | ck, + &info, + NULL, + &m_tex[iSlot].pSurface + ); + + if (hr != D3D_OK) + { + switch(hr) + { + case E_OUTOFMEMORY: + case D3DERR_OUTOFVIDEOMEMORY: + return TEXMGR_ERR_OUTOFMEM; + default: + return TEXMGR_ERR_BADFILE; + } + } + + m_tex[iSlot].img_w = info.Width; + m_tex[iSlot].img_h = info.Height; + + /* + unsigned int w_img; + unsigned int h_img; + unsigned int img_color_channels; + + int ret = Begin_Jpeg_Read(szFilename, &w_img, &h_img, &img_color_channels); + switch(ret) + { + case JPEGSTUFF_ERR_SUCCESS: + break; + case JPEGSTUFF_ERR_OPENING: + return TEXMGR_ERR_OPENING; + break; + case JPEGSTUFF_ERR_MISC: + return TEXMGR_ERR_FORMAT; + break; + } + + sprintf(buf, "texmgr: w=%d, h=%d, channels=%d", w_img, h_img, img_color_channels); + //g_dumpmsg(buf); + + m_tex[iSlot].img_w = w_img; + m_tex[iSlot].img_h = h_img; + + if (img_color_channels != 3) + { + // error: not 24-bit! + //g_dumpmsg("texmgr: image not 24-bit"); + End_Jpeg_Read(); + return TEXMGR_ERR_IMAGE_NOT_24_BIT; + } + + if ((w_img > 2048) || + (h_img > 2048)) // RG + { + // error: too large! + //g_dumpmsg("texmgr: image too large"); + End_Jpeg_Read(); + return TEXMGR_ERR_IMAGE_TOO_LARGE; + } + + if (!TryCreateDDrawSurface(iSlot, w_img, h_img)) + { + //g_dumpmsg("texmgr: unable to create ddraw surface"); + End_Jpeg_Read(); + return TEXMGR_ERR_CREATESURFACE_FAILED; + } + + unsigned int w_tex = m_tex[iSlot].tex_w; + unsigned int h_tex = m_tex[iSlot].tex_h; + unsigned int bpp_tex = m_tex[iSlot].ddpf.dwRGBBitCount; + + sprintf(buf, "texmgr: created ddraw surface; %d x %d x %d", w_tex, h_tex, bpp_tex); + //g_dumpmsg(buf); + + DDSURFACEDESC2 ddsd; + ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof( ddsd ); + + if (m_tex[iSlot].pSurface->Lock(0, &ddsd, DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_NOSYSLOCK, 0) != DD_OK) + { + //g_dumpmsg("texmgr: unable to lock ddraw surface"); + End_Jpeg_Read(); + m_tex[iSlot].pSurface->Release(); + m_tex[iSlot].pSurface = NULL; + return TEXMGR_ERR_LOCKSURFACE_FAILED; + } + + // analyze surface pixel format + unsigned int zeroBits[3] = { 0, 0, 0 }; + unsigned int chopBits[3] = { 8, 8, 8 }; + unsigned int mask[3] = { ddsd.ddpfPixelFormat.dwRBitMask, ddsd.ddpfPixelFormat.dwGBitMask, ddsd.ddpfPixelFormat.dwBBitMask }; + + { + int x,y; + + for (x=0; x<3; x++) + { + for (y=0; y<32; y++) + { + if ((mask[x] & (1<>= zeroBits[x]; + for (y=0; y<32; y++) + { + if ((mask[x] & (1<> 16) & 0xFF; + unsigned int ck_g1 = (ck_lo >> 8 ) & 0xFF; + unsigned int ck_b1 = (ck_lo ) & 0xFF; + unsigned int ck_r2 = (ck_hi >> 16) & 0xFF; + unsigned int ck_g2 = (ck_hi >> 8 ) & 0xFF; + unsigned int ck_b2 = (ck_hi ) & 0xFF; + + // read jpeg in & store in directdraw surface + // 2. read image into texture + if (w_img > w_tex || h_img > h_tex) + { + // DOWNSAMPLING VERSION + + unsigned int new_w_img = min(w_tex, w_img); + unsigned int new_h_img = min(h_tex, h_img); + + { + char buf[256]; + sprintf(buf, "texmgr: downsampling image from %dx%d to %dx%d and storing in %dx%d texture.", w_img,h_img, new_w_img,new_h_img, w_tex,h_tex); + //g_dumpmsg(buf); + } + + int downsample_buf[2048*3]; + memset(downsample_buf, 0, sizeof(downsample_buf)); + + float input_lines_per_output_line = h_img/(float)new_h_img; + float lines = 0.0f; + unsigned int out_y = 0; + + for (int y=0; y<(int)h_img; y++) + { + unsigned int x; + + unsigned char *buf = Jpeg_Read_Next_Line(); + if (!buf) + { + End_Jpeg_Read(); + m_tex[iSlot].pSurface->Release(); + m_tex[iSlot].pSurface = NULL; + return TEXMGR_ERR_CORRUPT_JPEG; + } + + lines += 1.0f; + int portion = (int)(min(256, max(0, (input_lines_per_output_line - lines)*256))); + for (x=0; x> 4; + + if (portion < 256) + { + // commit this line (out_y) & start a new one + if (out_y < h_tex) + { + float input_cols_per_output_col = w_img/(float)new_w_img; + float cols = 0.0f; + int out_x = 0; + + int buf2[2048*3]; + memset(buf2, 0, new_w_img*3); + + for (x=0; x> 4; + buf2[out_x*3+1] += (downsample_buf[x*3+1] * portion) >> 4; + buf2[out_x*3+2] += (downsample_buf[x*3+2] * portion) >> 4; + + if (portion < 256) + { + cols -= input_cols_per_output_col; + portion = 256 - portion; + out_x++; + buf2[out_x*3 ] = (downsample_buf[x*3 ] * portion) >> 4; + buf2[out_x*3+1] = (downsample_buf[x*3+1] * portion) >> 4; + buf2[out_x*3+2] = (downsample_buf[x*3+2] * portion) >> 4; + } + } + + // now buf2[0..w_tex] has r,g,b colors in it (but scaled) -> SAVE TO TEXTURE. + float scale_factor = 1.0f / (float)(16 * 16 * input_cols_per_output_col * input_lines_per_output_line); + + if (bpp_tex == 16) + { + unsigned __int16 *dest16 = (unsigned __int16 *)ddsd.lpSurface; + unsigned int tex_offset = (ddsd.lPitch/2) * out_y; + for (x=0; x> chopBits[0]) & mask[0]) << zeroBits[0]) | + (((cg >> chopBits[1]) & mask[1]) << zeroBits[1]) | + (((cb >> chopBits[2]) & mask[2]) << zeroBits[2]); + if (!(cr >= ck_r1 && cr <= ck_r2 && + cg >= ck_g1 && cg <= ck_g2 && + cb >= ck_b1 && cb <= ck_b2)) + color |= ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; + dest16[tex_offset++] = color; + } + } + else if (bpp_tex == 32) + { + unsigned __int32 *dest32 = (unsigned __int32 *)ddsd.lpSurface; + unsigned int tex_offset = (ddsd.lPitch/4) * out_y; + for (x=0; x= ck_r1 && cr <= ck_r2 && + cg >= ck_g1 && cg <= ck_g2 && + cb >= ck_b1 && cb <= ck_b2)) + color |= ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; + dest32[tex_offset++] = color; + } + } + + out_y++; + + } + + // start next line: + lines -= input_lines_per_output_line; + portion = 256 - portion; + for (x=0; x> 4; + } + } + + m_tex[iSlot].scale_x = new_w_img/(float)w_img; + m_tex[iSlot].scale_y = new_h_img/(float)h_img; + m_tex[iSlot].img_w = new_w_img; + m_tex[iSlot].img_h = new_h_img; + w_img = new_w_img; + h_img = new_h_img; + } + else + { + // 1:1 VERSION + + if (bpp_tex == 16) + { + unsigned __int16 *dest16 = (unsigned __int16 *)ddsd.lpSurface; + for (int y=0; y<(int)h_img; y++) + { + unsigned char *buf = Jpeg_Read_Next_Line(); + if (!buf) + { + End_Jpeg_Read(); + m_tex[iSlot].pSurface->Release(); + m_tex[iSlot].pSurface = NULL; + return TEXMGR_ERR_CORRUPT_JPEG; + } + + unsigned int tex_offset = (ddsd.lPitch/2) * y; + for (unsigned int x=0; x> chopBits[0]) & mask[0]) << zeroBits[0]) | + (((cg >> chopBits[1]) & mask[1]) << zeroBits[1]) | + (((cb >> chopBits[2]) & mask[2]) << zeroBits[2]); + if (!(cr >= ck_r1 && cr <= ck_r2 && + cg >= ck_g1 && cg <= ck_g2 && + cb >= ck_b1 && cb <= ck_b2)) + color |= ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; + dest16[tex_offset++] = color; + } + } + } + else if (bpp_tex == 32) + { + unsigned __int32 *dest32 = (unsigned __int32 *)ddsd.lpSurface; + for (int y=0; y<(int)h_img; y++) + { + unsigned char *buf = Jpeg_Read_Next_Line(); + if (!buf) + { + End_Jpeg_Read(); + m_tex[iSlot].pSurface->Release(); + m_tex[iSlot].pSurface = NULL; + return TEXMGR_ERR_CORRUPT_JPEG; + } + + unsigned int tex_offset = (ddsd.lPitch/4) * y; + for (unsigned int x=0; x= ck_r1 && cr <= ck_r2 && + cg >= ck_g1 && cg <= ck_g2 && + cb >= ck_b1 && cb <= ck_b2)) + color |= ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; + dest32[tex_offset++] = color; + } + } + } + } + + m_tex[iSlot].pSurface->Unlock(0); + + End_Jpeg_Read(); + */ + } + + m_tex[iSlot].fStartTime = time; + m_tex[iSlot].nStartFrame = frame; + + int ret = TEXMGR_ERR_SUCCESS; + + // compile & run init. code: + if (!RunInitCode(iSlot, szInitCode)) + ret |= TEXMGR_WARN_ERROR_IN_INIT_CODE; + + // compile & save per-frame code: + strcpy(m_tex[iSlot].m_szExpr, szCode); + FreeCode(iSlot); + if (!RecompileExpressions(iSlot)) + ret |= TEXMGR_WARN_ERROR_IN_REG_CODE; + + //g_dumpmsg("texmgr: success"); + + return ret; +} + +void texmgr::KillTex(int iSlot) +{ + if (iSlot < 0) return; + if (iSlot >= NUM_TEX) return; + + // Free old resources: + if (m_tex[iSlot].pSurface) + { + // first, make sure no other sprites reference this texture! + int refcount = 0; + for (int x=0; xRelease(); + m_tex[iSlot].pSurface = NULL; + } + m_tex[iSlot].szFileName[0] = 0; + + FreeCode(iSlot); +} + +void texmgr::StripLinefeedCharsAndComments(char *src, char *dest) +{ + // replaces all LINEFEED_CONTROL_CHAR characters in src with a space in dest; + // also strips out all comments (beginning with '//' and going til end of line). + // Restriction: sizeof(dest) must be >= sizeof(src). + + int i2 = 0; + int len = strlen(src); + int bComment = false; + for (int i=0; im_szUserMessage, "warning: preset \"%s\": error in 'per_frame' code", m_szDesc); + //pg->m_fShowUserMessageUntilThisTime = pg->m_fAnimTime + 6.0f; + } + else + { + //g_dumpmsg(" -ok!"); + //pg->m_fShowUserMessageUntilThisTime = pg->m_fAnimTime; // clear any old error msg. + } + //resetVars(NULL); + + return (m_tex[iSlot].m_codehandle != 0); + + #endif + } + + return true; +} + +void texmgr::FreeVars(int iSlot) +{ + // free the built-in variables AND any user variables +} + +void texmgr::FreeCode(int iSlot) +{ + // free the compiled expressions + if (m_tex[iSlot].m_codehandle) + { + NSEEL_code_free(m_tex[iSlot].m_codehandle); + m_tex[iSlot].m_codehandle = NULL; + } +} + +void texmgr::RegisterBuiltInVariables(int iSlot) +{ + NSEEL_VMCTX eel_ctx = m_tex[iSlot].tex_eel_ctx; + NSEEL_VM_resetvars(eel_ctx); + + // input variables + m_tex[iSlot].var_time = NSEEL_VM_regvar(eel_ctx, "time"); + m_tex[iSlot].var_frame = NSEEL_VM_regvar(eel_ctx, "frame"); + m_tex[iSlot].var_fps = NSEEL_VM_regvar(eel_ctx, "fps"); + m_tex[iSlot].var_progress = NSEEL_VM_regvar(eel_ctx, "progress"); + m_tex[iSlot].var_bass = NSEEL_VM_regvar(eel_ctx, "bass"); + m_tex[iSlot].var_bass_att = NSEEL_VM_regvar(eel_ctx, "bass_att"); + m_tex[iSlot].var_mid = NSEEL_VM_regvar(eel_ctx, "mid"); + m_tex[iSlot].var_mid_att = NSEEL_VM_regvar(eel_ctx, "mid_att"); + m_tex[iSlot].var_treb = NSEEL_VM_regvar(eel_ctx, "treb"); + m_tex[iSlot].var_treb_att = NSEEL_VM_regvar(eel_ctx, "treb_att"); + + // output variables + m_tex[iSlot].var_x = NSEEL_VM_regvar(eel_ctx, "x"); + m_tex[iSlot].var_y = NSEEL_VM_regvar(eel_ctx, "y"); + m_tex[iSlot].var_sx = NSEEL_VM_regvar(eel_ctx, "sx"); + m_tex[iSlot].var_sy = NSEEL_VM_regvar(eel_ctx, "sy"); + m_tex[iSlot].var_repeatx = NSEEL_VM_regvar(eel_ctx, "repeatx"); + m_tex[iSlot].var_repeaty = NSEEL_VM_regvar(eel_ctx, "repeaty"); + m_tex[iSlot].var_rot = NSEEL_VM_regvar(eel_ctx, "rot"); + m_tex[iSlot].var_flipx = NSEEL_VM_regvar(eel_ctx, "flipx"); + m_tex[iSlot].var_flipy = NSEEL_VM_regvar(eel_ctx, "flipy"); + m_tex[iSlot].var_r = NSEEL_VM_regvar(eel_ctx, "r"); + m_tex[iSlot].var_g = NSEEL_VM_regvar(eel_ctx, "g"); + m_tex[iSlot].var_b = NSEEL_VM_regvar(eel_ctx, "b"); + m_tex[iSlot].var_a = NSEEL_VM_regvar(eel_ctx, "a"); + m_tex[iSlot].var_blendmode = NSEEL_VM_regvar(eel_ctx, "blendmode"); + m_tex[iSlot].var_done = NSEEL_VM_regvar(eel_ctx, "done"); + m_tex[iSlot].var_burn = NSEEL_VM_regvar(eel_ctx, "burn"); + +// resetVars(NULL); +} \ No newline at end of file diff --git a/vis_milk2/texmgr.h b/vis_milk2/texmgr.h new file mode 100644 index 0000000..b7b80c9 --- /dev/null +++ b/vis_milk2/texmgr.h @@ -0,0 +1,120 @@ +/* + 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. +*/ + +#ifndef GEISS_TEXTURE_MANAGER +#define GEISS_TEXTURE_MANAGER 1 + +#define NUM_TEX 16 + +#ifdef _DEBUG + #define D3D_DEBUG_INFO // declare this before including d3d9.h +#endif +#include +#include "../ns-eel2/ns-eel.h" +#include "md_defines.h" + +#define TEXMGR_ERROR_MASK 0x0F +#define TEXMGR_ERR_SUCCESS 0 +#define TEXMGR_ERR_BAD_INDEX 1 +/* +#define TEXMGR_ERR_OPENING 2 +#define TEXMGR_ERR_IMAGE_NOT_24_BIT 3 +#define TEXMGR_ERR_IMAGE_TOO_LARGE 4 +#define TEXMGR_ERR_CREATESURFACE_FAILED 5 +#define TEXMGR_ERR_LOCKSURFACE_FAILED 6 +#define TEXMGR_ERR_CORRUPT_JPEG 7 +*/ +#define TEXMGR_ERR_FORMAT 8 +#define TEXMGR_ERR_BADFILE 9 +#define TEXMGR_ERR_OUTOFMEM 10 +#define TEXMGR_WARNING_MASK 0xF0 +#define TEXMGR_WARN_ERROR_IN_INIT_CODE 0x10 +#define TEXMGR_WARN_ERROR_IN_REG_CODE 0x20 + +typedef struct +{ + LPDIRECT3DTEXTURE9 pSurface; + int img_w, img_h; + /* + int tex_w, tex_h; + float scale_x, scale_y; // the factors by which the original image was squished to become (img_w x img_h) texels in size. + DDPIXELFORMAT ddpf; + */ + wchar_t szFileName[512]; + float fStartTime; + int nStartFrame; + int nUserData; + + // stuff for expressions: + char m_szExpr[8192]; // for expression eval + NSEEL_CODEHANDLE m_codehandle; // for expression eval + // input variables for expression eval + double *var_time, *var_frame, *var_fps, *var_progress; + double *var_bass, *var_bass_att, *var_mid, *var_mid_att, *var_treb, *var_treb_att; + // output variables for expression eval + double *var_x, *var_y; + double *var_sx, *var_sy, *var_rot, *var_flipx, *var_flipy; + double *var_r, *var_g, *var_b, *var_a; + double *var_blendmode; + double *var_repeatx, *var_repeaty; + double *var_done, *var_burn; + NSEEL_VMCTX tex_eel_ctx; +} +td_tex; + +class texmgr +{ +public: + texmgr(); + ~texmgr(); + + // members + void Init(LPDIRECT3DDEVICE9 lpDD); // DirectDraw object + int LoadTex(wchar_t *szFilename, int iSlot, char *szInitCode, char *szCode, float time, int frame, unsigned int ck); + void KillTex(int iSlot); + void Finish(); + + // data + td_tex m_tex[NUM_TEX]; + +protected: + // members + //bool TryCreateDDrawSurface(int iSlot, int w, int h); + void FreeVars(int iSlot); + void FreeCode(int iSlot); + void RegisterBuiltInVariables(int iSlot); + bool RunInitCode(int iSlot, char *szInitCode); + bool RecompileExpressions(int iSlot); + void StripLinefeedCharsAndComments(char *src, char *dest); + + // data + LPDIRECT3DDEVICE9 m_lpDD; +}; + +#endif \ No newline at end of file diff --git a/vis_milk2/text1.bin b/vis_milk2/text1.bin new file mode 100644 index 0000000..86a2537 Binary files /dev/null and b/vis_milk2/text1.bin differ diff --git a/vis_milk2/textmgr.cpp b/vis_milk2/textmgr.cpp new file mode 100644 index 0000000..6c7058f --- /dev/null +++ b/vis_milk2/textmgr.cpp @@ -0,0 +1,696 @@ +/* + 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. +*/ + +#include "textmgr.h" +#include "support.h" +#include "utility.h" + +#define MAX_MSG_CHARS (65536*2) +#define SafeRelease(x) { if (x) {x->Release(); x=NULL;} } +wchar_t g_szMsgPool[2][MAX_MSG_CHARS]; + +/* + NOTES ON CTextManager + + *** -desktop mode was SLOOOW when songtitles are on!, esp. since anim. songtitles... + -> decided to cache output of ID3DXFont by rendering to a (vidmem) texture, + ** only when things change. ** That became CTextManager. + -uses GDI-based ID3DXFont to draw text to a 2nd (VIDEO MEMORY) surface, + but each frame, it only draws what is necessary (what's changed + since last frame). It then blits that image (additively) to + the back buffer each frame. (note that dark boxes wouldn't work + w/additive drawing, since they're black, so those have to be + manually drawn (as black boxes) by the plugin shell, AS WELL AS + entered into the CTextManager queue as dark boxes, to handle + erasure, dirty rectangles, etc.) + + PROS/CONS: + (+) Supports all GDI features: italics, kerning, international fonts, formatting, &, etc. + (-) takes a lot of memory + (-) if texture can't be created @ proper size, fonts will appear too big + -> so don't use texture at all, in that case. + -> at least this way it will work well on all newer cards [w/memory] + (-) it's still going to crawl *when the text changes*, + because d3dx will upload textures to vidmem & blit them *once for each change*. + + OTHER CONCERNS/KIV: + -what if m_lpDDSText can't be created @ actual size of window? + If it's bigger, that's ok; but if it's smaller, that should result + in a clipped area for the text - hmm.... +*/ + +CTextManager::CTextManager() +{ +} + +CTextManager::~CTextManager() +{ +} + +void CTextManager::Init(LPDIRECT3DDEVICE9 lpDevice, IDirect3DTexture9* lpTextSurface, int bAdditive) +{ + m_lpDevice = lpDevice; + m_lpTextSurface = lpTextSurface; + m_blit_additively = bAdditive; + + m_b = 0; + m_nMsg[0] = 0; + m_nMsg[1] = 0; + m_next_msg_start_ptr = g_szMsgPool[m_b]; +} + +void CTextManager::Finish() +{ +} + +void CTextManager::ClearAll() +{ + m_nMsg[m_b] = 0; + m_next_msg_start_ptr = g_szMsgPool[m_b]; +} + +void CTextManager::DrawBox(LPRECT pRect, DWORD boxColor) +{ + if (!pRect) + return; + + if ((m_nMsg[m_b] < MAX_MSGS) && + (DWORD)m_next_msg_start_ptr - (DWORD)g_szMsgPool[m_b] + 0 + 1 < MAX_MSG_CHARS) + { + *m_next_msg_start_ptr = 0; + + m_msg[m_b][m_nMsg[m_b]].msg = m_next_msg_start_ptr; + m_msg[m_b][m_nMsg[m_b]].pfont = NULL; + m_msg[m_b][m_nMsg[m_b]].rect = *pRect; + m_msg[m_b][m_nMsg[m_b]].flags = 0; + m_msg[m_b][m_nMsg[m_b]].color = 0xFFFFFFFF; + m_msg[m_b][m_nMsg[m_b]].bgColor = boxColor; + m_nMsg[m_b]++; + m_next_msg_start_ptr += 1; + } +} + +int CTextManager::DrawText(LPD3DXFONT pFont, char* szText, RECT* pRect, DWORD flags, DWORD color, bool bBox, DWORD boxColor) +{ + // these aren't supported by D3DX9: + flags &= ~(DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX); + + if (!(pFont && pRect && szText)) + return 0; + + if (flags & DT_CALCRECT) + return pFont->DrawText(NULL, szText, -1, pRect, flags, color); + + if (!m_lpDevice /*|| !m_lpTextSurface*/) + return 0; + + int len = strlen(szText); + + if ((m_nMsg[m_b] < MAX_MSGS) && + (DWORD)m_next_msg_start_ptr - (DWORD)g_szMsgPool[m_b] + len + 1 < MAX_MSG_CHARS) + { + wcscpy(m_next_msg_start_ptr, AutoWide(szText)); + + m_msg[m_b][m_nMsg[m_b]].msg = m_next_msg_start_ptr; + m_msg[m_b][m_nMsg[m_b]].pfont = pFont; + m_msg[m_b][m_nMsg[m_b]].rect = *pRect; + m_msg[m_b][m_nMsg[m_b]].flags = flags; + m_msg[m_b][m_nMsg[m_b]].color = color; + m_msg[m_b][m_nMsg[m_b]].bgColor = boxColor; + + // shrink rects on new frame's text strings; important for deletions + int h = pFont->DrawText(NULL, szText, len, &m_msg[m_b][m_nMsg[m_b]].rect, flags | DT_CALCRECT, color); + + m_nMsg[m_b]++; + m_next_msg_start_ptr += len + 1; + + if (bBox) + { + // adds a message with no text, but the rect is the same as the text, so it creates a black box + DrawBox(&m_msg[m_b][m_nMsg[m_b]-1].rect, boxColor); + // now swap it with the text that precedes it, so it draws first, and becomes a background + td_string x = m_msg[m_b][m_nMsg[m_b]-1]; + m_msg[m_b][m_nMsg[m_b]-1] = m_msg[m_b][m_nMsg[m_b]-2]; + m_msg[m_b][m_nMsg[m_b]-2] = x; + } + return h; + } + + // no room for more text? ok, but still return accurate info: + RECT r2 = *pRect; + int h = pFont->DrawText(NULL, szText, len, &r2, flags | DT_CALCRECT, color); + return h; +} + +int CTextManager::DrawTextW(LPD3DXFONT pFont, wchar_t* szText, RECT* pRect, DWORD flags, DWORD color, bool bBox, DWORD boxColor) +{ + // these aren't supported by D3DX9: + flags &= ~(DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX); + + if (!(pFont && pRect && szText)) + return 0; + + if (flags & DT_CALCRECT) + return pFont->DrawTextW(NULL, szText, -1, pRect, flags, color); + + if (!m_lpDevice /*|| !m_lpTextSurface*/) + return 0; + + int len = wcslen(szText); + + if ((m_nMsg[m_b] < MAX_MSGS) && + (DWORD)m_next_msg_start_ptr - (DWORD)g_szMsgPool[m_b] + len + 1 < MAX_MSG_CHARS) + { + wcscpy(m_next_msg_start_ptr, szText); + + m_msg[m_b][m_nMsg[m_b]].msg = m_next_msg_start_ptr; + m_msg[m_b][m_nMsg[m_b]].pfont = pFont; + m_msg[m_b][m_nMsg[m_b]].rect = *pRect; + m_msg[m_b][m_nMsg[m_b]].flags = flags; + m_msg[m_b][m_nMsg[m_b]].color = color; + m_msg[m_b][m_nMsg[m_b]].bgColor = boxColor; + + // shrink rects on new frame's text strings; important for deletions + int h = pFont->DrawTextW(NULL, szText, len, &m_msg[m_b][m_nMsg[m_b]].rect, flags | DT_CALCRECT, color); + + m_nMsg[m_b]++; + m_next_msg_start_ptr += len + 1; + + if (bBox) + { + // adds a message with no text, but the rect is the same as the text, so it creates a black box + DrawBox(&m_msg[m_b][m_nMsg[m_b]-1].rect, boxColor); + // now swap it with the text that precedes it, so it draws first, and becomes a background + td_string x = m_msg[m_b][m_nMsg[m_b]-1]; + m_msg[m_b][m_nMsg[m_b]-1] = m_msg[m_b][m_nMsg[m_b]-2]; + m_msg[m_b][m_nMsg[m_b]-2] = x; + } + return h; + } + + // no room for more text? ok, but still return accurate info: + RECT r2 = *pRect; + int h = pFont->DrawTextW(NULL, szText, len, &r2, flags | DT_CALCRECT, color); + return h; +} + +#define MATCH(i,j) ( m_msg[m_b][i].pfont == m_msg[1-m_b][j].pfont && \ + m_msg[m_b][i].flags == m_msg[1-m_b][j].flags && \ + m_msg[m_b][i].color == m_msg[1-m_b][j].color && \ + m_msg[m_b][i].bgColor == m_msg[1-m_b][j].bgColor && \ + memcmp(&m_msg[m_b][i].rect, &m_msg[1-m_b][j].rect, sizeof(RECT))==0 && \ + wcscmp(m_msg[m_b][i].msg, m_msg[1-m_b][j].msg)==0 ) + +void CTextManager::DrawNow() +{ + if (!m_lpDevice) + return; + + if (m_nMsg[m_b] > 0 || m_nMsg[1-m_b] > 0) // second condition req'd for clearing text in VJ mode + { + D3DXMATRIX Ortho2D; + pMatrixOrthoLH(&Ortho2D, 2.0f, -2.0f, 0.0f, 1.0f); + m_lpDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D); + + #define NUM_DIRTY_RECTS 3 + RECT dirty_rect[NUM_DIRTY_RECTS]; + int dirty_rects_ready = 0; + + int bRTT = (m_lpTextSurface==NULL) ? 0 : 1; + LPDIRECT3DSURFACE9 pBackBuffer=NULL;//, pZBuffer=NULL; + D3DSURFACE_DESC desc_backbuf, desc_text_surface; + + // clear added/deleted flags + void* last_dark_box = NULL; + for (int i=0; i0 && m_nMsg[1-m_b]==0)) + { + bRedrawText = 2; // redraw ALL + } + else + { + // try to synchronize the text strings from last frame + this frame, + // and label additions & deletions. algorithm will catch: + // -insertion of any # of items in one spot + // -deletion of any # of items from one spot + // -changes to 1 item + // -changes to 2 consecutive items + // (provided that the 2 text strings immediately bounding the + // additions/deletions/change(s) are left unchanged.) + // in any other case, all the text is just re-rendered. + + int i = 0; + int j = 0; + while (i < m_nMsg[m_b] && j < m_nMsg[1-m_b]) + { + // MATCH macro: first idx is record # for current stuff; second idx is record # for prev frame stuff. + if (MATCH(i,j)) + { + i++; + j++; + } + else + { + int continue_now = 0; + + // scan to see if something was added: + for (int i2=i+1; i2=m_nMsg[m_b]-chgd || j>=m_nMsg[1-m_b]-chgd) + { + // only a few items left in one of the lists -> just finish it + bRedrawText = 1; + break_now = 1; + break; + } + if (i just re-render whole thing + bRedrawText = 2; // redraw ALL + break; + } + } + + if (bRedrawText < 2) + { + while (i < m_nMsg[m_b]) + { + m_msg[m_b][i].added = 1; + bRedrawText = 1; + i++; + } + + while (j < m_nMsg[1-m_b]) + { + m_msg[1-m_b][j].deleted = 1; + bRedrawText = 1; + j++; + } + } + } + + // ------------------------------------------------------------ + + // 0. remember old render target & get surface descriptions + m_lpDevice->GetRenderTarget( 0, &pBackBuffer ); + pBackBuffer->GetDesc(&desc_backbuf); + + if (bRTT) + { + //if (m_lpDevice->GetDepthStencilSurface( &pZBuffer ) != D3D_OK) + // pZBuffer = NULL; // ok if return val != D3D_OK - just means there is no zbuffer. + if (m_lpTextSurface->GetLevelDesc(0, &desc_text_surface) != D3D_OK) + bRTT = 0; + + m_lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT ); + m_lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + + m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + m_lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + + m_lpDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); + } + else + { + desc_text_surface = desc_backbuf; + } + + if (bRTT && bRedrawText) + do + { + // 1. change render target + m_lpDevice->SetTexture(0, NULL); + + IDirect3DSurface9* pNewTarget = NULL; + if (m_lpTextSurface->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) + { + bRTT = 0; + break; + } + if (m_lpDevice->SetRenderTarget(0, pNewTarget) != D3D_OK) + { + pNewTarget->Release(); + bRTT = 0; + break; + } + //m_lpDevice->SetDepthStencilSurface( ??? ); + pNewTarget->Release(); + + m_lpDevice->SetTexture(0, NULL); + + // 2. clear to black + //m_lpDevice->SetTexture(0, NULL); + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + m_lpDevice->SetVertexShader( NULL ); + m_lpDevice->SetFVF( WFVERTEX_FORMAT ); + m_lpDevice->SetPixelShader( NULL ); + WFVERTEX v3[4]; + if (bRedrawText==2) + { + DWORD clearcolor = m_msg[m_b][j].bgColor;//0xFF000000;// | ((rand()%32)<<16) | ((rand()%32)<<8) | ((rand()%32)); + for (int i=0; i<4; i++) + { + v3[i].x = -1.0f + 2.0f*(i%2); + v3[i].y = -1.0f + 2.0f*(i/2); + v3[i].z = 0; + v3[i].Diffuse = clearcolor; + } + m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(WFVERTEX)); + } + else + { + // 1. erase (draw black box over) any old text items deleted. + // also, update the dirty rects; stuff that was ABOVE/BELOW these guys will need redrawn! + // (..picture them staggered) + for (int j=0; jDrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(WFVERTEX)); + + //---------------------------------- + + // special case: + // if something is erased, but it's totally inside a dark box, + // then don't add it to the dirty rectangle. + td_string* pDarkBox = (td_string*)m_msg[1-m_b][j].prev_dark_box_ptr; + int add_to_dirty_rect = 1; + while (pDarkBox && add_to_dirty_rect) + { + RECT t; + UnionRect(&t, &pDarkBox->rect, &m_msg[1-m_b][j].rect); + if (EqualRect(&t, &pDarkBox->rect)) + add_to_dirty_rect = 0; + pDarkBox = (td_string*)pDarkBox->prev_dark_box_ptr; + } + + // also, update dirty rects + // first, check to see if this shares area or a border w/any of the going dirty rects, + // and if so, expand that dirty rect. + if (add_to_dirty_rect) + { + int done = 0; + RECT t; + RECT r1 = m_msg[1-m_b][j].rect; + RECT r2 = m_msg[1-m_b][j].rect; + r2.top -= 1; + r2.left -= 1; + r2.right += 1; + r2.bottom += 1; + for (i=0; i dirty_rect[i].right) + dx = r1.left - dirty_rect[i].right; + else if (dirty_rect[i].left > r1.right) + dx = dirty_rect[i].left - r1.right; + + if (r1.top > dirty_rect[i].bottom) + dy = r1.top - dirty_rect[i].bottom; + else if (dirty_rect[i].top > r1.bottom) + dy = dirty_rect[i].top - r1.bottom; + + float dist = sqrtf((float)(dx*dx + dy*dy)); + if (i==0 || dist < nearest_dist) + { + nearest_dist = dist; + nearest_id = i; + } + } + //...and expand it to include this one. + UnionRect(&t, &r1, &dirty_rect[nearest_id]); + dirty_rect[nearest_id] = t; + } + } + } + + // 2. erase AND REDRAW any of *this* frame's text that falls in dirty rects + // from erasures of *prev* frame's deleted text: + for (j=0; jDrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(WFVERTEX)); + + m_msg[m_b][j].deleted = 1; + m_msg[m_b][j].added = 1; + bRedrawText = 1; + } + } + } + } + } + while (0); + + // 3. render text to TEXT surface + if (bRedrawText) + { + m_lpDevice->SetTexture(0, NULL); + m_lpDevice->SetTexture(1, NULL); + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + m_lpDevice->SetVertexShader( NULL ); + m_lpDevice->SetPixelShader( NULL ); + m_lpDevice->SetFVF( WFVERTEX_FORMAT ); + + for (int i=0; iDrawTextW(NULL, m_msg[m_b][i].msg, -1, &m_msg[m_b][i].rect, m_msg[m_b][i].flags, m_msg[m_b][i].color); + else if (m_msg[m_b][i].added || bRedrawText==2 || !bRTT) + { + WFVERTEX v3[4]; + float x0 = -1.0f + 2.0f*m_msg[m_b][i].rect.left/(float)desc_text_surface.Width; + float x1 = -1.0f + 2.0f*m_msg[m_b][i].rect.right/(float)desc_text_surface.Width; + float y0 = -1.0f + 2.0f*m_msg[m_b][i].rect.top/(float)desc_text_surface.Height; + float y1 = -1.0f + 2.0f*m_msg[m_b][i].rect.bottom/(float)desc_text_surface.Height; + for (int k=0; k<4; k++) + { + v3[k].x = (k%2) ? x0 : x1; + v3[k].y = (k/2) ? y0 : y1; + v3[k].z = 0; + v3[k].Diffuse = m_msg[m_b][i].bgColor;//0xFF303000; + } + m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(WFVERTEX)); + } + } + + if (bRTT) + { + // 4. restore render target + if (bRedrawText) + { + m_lpDevice->SetTexture(0, NULL); + m_lpDevice->SetRenderTarget( 0, pBackBuffer );//, pZBuffer ); + //m_lpDevice->SetDepthStencilSurface( pZBuffer ); + } + + // 5. blit text surface to backbuffer + m_lpDevice->SetTexture(0, m_lpTextSurface); + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, m_blit_additively ? TRUE : FALSE); + m_lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + m_lpDevice->SetRenderState(D3DRS_DESTBLEND, m_blit_additively ? D3DBLEND_ONE : D3DBLEND_ZERO); + m_lpDevice->SetVertexShader( NULL ); + m_lpDevice->SetPixelShader( NULL ); + m_lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + + SPRITEVERTEX v3[4]; + ZeroMemory(v3, sizeof(SPRITEVERTEX)*4); + float fx = desc_text_surface.Width / (float)desc_backbuf.Width ; + float fy = desc_text_surface.Height / (float)desc_backbuf.Height; + for (int i=0; i<4; i++) + { + v3[i].x = (i%2==0) ? -1 : -1 + 2*fx; + v3[i].y = (i/2==0) ? -1 : -1 + 2*fy; + v3[i].z = 0; + v3[i].tu = ((i%2==0) ? 0.0f : 1.0f) + 0.5f/desc_text_surface.Width; // FIXES BLURRY TEXT even when bilinear interp. is on (which can't be turned off on all cards!) + v3[i].tv = ((i/2==0) ? 0.0f : 1.0f) + 0.5f/desc_text_surface.Height; // FIXES BLURRY TEXT even when bilinear interp. is on (which can't be turned off on all cards!) + v3[i].Diffuse = 0xFFFFFFFF; + } + + DWORD oldblend[3]; + //m_lpDevice->GetTextureStageState(0, D3DTSS_MAGFILTER, &oldblend[0]); + //m_lpDevice->GetTextureStageState(1, D3DTSS_MINFILTER, &oldblend[1]); + //m_lpDevice->GetTextureStageState(2, D3DTSS_MIPFILTER, &oldblend[2]); + m_lpDevice->GetSamplerState(0, D3DSAMP_MAGFILTER, &oldblend[0]); + m_lpDevice->GetSamplerState(1, D3DSAMP_MINFILTER, &oldblend[1]); + m_lpDevice->GetSamplerState(2, D3DSAMP_MIPFILTER, &oldblend[2]); + m_lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + m_lpDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); + m_lpDevice->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_POINT); + + m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v3, sizeof(SPRITEVERTEX)); + + m_lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, oldblend[0]); + m_lpDevice->SetSamplerState(1, D3DSAMP_MINFILTER, oldblend[1]); + m_lpDevice->SetSamplerState(2, D3DSAMP_MIPFILTER, oldblend[2]); + + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + SafeRelease(pBackBuffer); + //SafeRelease(pZBuffer); + + m_lpDevice->SetTexture(0, NULL); + m_lpDevice->SetTexture(1, NULL); + m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + m_lpDevice->SetVertexShader( NULL ); + m_lpDevice->SetPixelShader( NULL ); + m_lpDevice->SetFVF( SPRITEVERTEX_FORMAT ); + + //D3DXMATRIX ident; + //D3DXMatrixIdentity(&ident); + //m_lpDevice->SetTransform(D3DTS_PROJECTION, &ident); + } + + // flip: + m_b = 1 - m_b; + + ClearAll(); +} \ No newline at end of file diff --git a/vis_milk2/textmgr.h b/vis_milk2/textmgr.h new file mode 100644 index 0000000..9a62461 --- /dev/null +++ b/vis_milk2/textmgr.h @@ -0,0 +1,91 @@ +/* + 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. +*/ + +#ifndef GEISS_TEXT_DRAWING_MANAGER +#define GEISS_TEXT_DRAWING_MANAGER 1 + +#ifdef _DEBUG + #define D3D_DEBUG_INFO // declare this before including d3d9.h +#endif +#include +#include +#include "md_defines.h" +#include "..\nu\AutoWide.h" + +#define MAX_MSGS 4096 + +typedef struct +{ + wchar_t* msg; // points to some character in g_szMsgPool[2][]. + LPD3DXFONT pfont; // note: iff this string is really a dark box, pfont will be NULL! + RECT rect; + DWORD flags; + DWORD color; + DWORD bgColor; + int added, deleted; // temporary; used during DrawNow() + void* prev_dark_box_ptr; // temporary; used during DrawNow() +} +td_string; + +class CTextManager +{ +public: + CTextManager(); + ~CTextManager(); + + // note: if you can't create lpTextSurface full-size, don't create it at all! + void Init(LPDIRECT3DDEVICE9 lpDevice, IDirect3DTexture9* lpTextSurface, int bAdditive); // note: ok if lpTextSurface==NULL; in that case, text will be drawn directly to screen (but not til end anyway). + void Finish(); + + // note: pFont must persist until DrawNow() is called! + int DrawText(LPD3DXFONT pFont, char* szText, RECT* pRect, DWORD flags, DWORD color, bool bBlackBox, DWORD boxColor=0xFF000000); // actually queues the text! + int DrawText(LPD3DXFONT pFont, char* szText, int len, RECT* pRect, DWORD flags, DWORD color, bool bBox, DWORD boxColor=0xFF000000) { + return DrawTextW(pFont, AutoWide(szText), pRect, flags, color, bBox, boxColor); + }; + int DrawTextW(LPD3DXFONT pFont, wchar_t* szText, RECT* pRect, DWORD flags, DWORD color, bool bBlackBox, DWORD boxColor=0xFF000000); // actually queues the text! + int DrawTextW(LPD3DXFONT pFont, wchar_t* szText, int len, RECT* pRect, DWORD flags, DWORD color, bool bBox, DWORD boxColor=0xFF000000) { + return DrawTextW(pFont, szText, pRect, flags, color, bBox, boxColor); + }; + void DrawBox(LPRECT pRect, DWORD boxColor); + void DrawDarkBox(LPRECT pRect) { DrawBox(pRect, 0xFF000000); } + void DrawNow(); + void ClearAll(); // automatically called @ end of DrawNow() + +protected: + LPDIRECT3DDEVICE9 m_lpDevice; + IDirect3DTexture9* m_lpTextSurface; + int m_blit_additively; + + int m_nMsg[2]; + td_string m_msg[2][MAX_MSGS]; + wchar_t* m_next_msg_start_ptr; + int m_b; +}; + +#endif \ No newline at end of file diff --git a/vis_milk2/utility.cpp b/vis_milk2/utility.cpp new file mode 100644 index 0000000..0eb3250 --- /dev/null +++ b/vis_milk2/utility.cpp @@ -0,0 +1,1255 @@ +/* + 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. +*/ + +#include "api.h" +#include "utility.h" +#include +#include +#include +#ifdef _DEBUG + #define D3D_DEBUG_INFO // declare this before including d3d9.h +#endif +#include +#include "../Winamp/wa_ipc.h" +#include "resource.h" +#include + +intptr_t myOpenURL(HWND hwnd, wchar_t *loc) +{ + if (loc) + { + bool override=false; + WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast(loc), reinterpret_cast(&override)); + if (!override) + return (intptr_t)ShellExecuteW(hwnd, L"open", loc, NULL, NULL, SW_SHOWNORMAL); + else + return 33; + } + return 33; +} + +float PowCosineInterp(float x, float pow) +{ + // input (x) & output should be in range 0..1. + // pow > 0: tends to push things toward 0 and 1 + // pow < 0: tends to push things toward 0.5. + + if (x<0) + return 0; + if (x>1) + return 1; + + int bneg = (pow < 0) ? 1 : 0; + if (bneg) + pow = -pow; + + if (pow>1000) pow=1000; + + int its = (int)pow; + for (int i=0; i 0) + { + _swscanf_l(string, L"%f", g_use_C_locale, &ret); + } + return ret; +} + +bool WritePrivateProfileFloatW(float f, wchar_t *szKeyName, wchar_t *szIniFile, wchar_t *szSectionName) +{ + wchar_t szValue[32]; + _swprintf_l(szValue, L"%f", g_use_C_locale, f); + return (WritePrivateProfileStringW(szSectionName, szKeyName, szValue, szIniFile) != 0); +} + +bool WritePrivateProfileIntW(int d, wchar_t *szKeyName, wchar_t *szIniFile, wchar_t *szSectionName) +{ + wchar_t szValue[32]; + swprintf(szValue, L"%d", d); + return (WritePrivateProfileStringW(szSectionName, szKeyName, szValue, szIniFile) != 0); +} + +void SetScrollLock(int bNewState, bool bPreventHandling) +{ + if(bPreventHandling) return; + + if (bNewState != (GetKeyState(VK_SCROLL) & 1)) + { + // Simulate a key press + keybd_event( VK_SCROLL, + 0x45, + KEYEVENTF_EXTENDEDKEY | 0, + 0 ); + + // Simulate a key release + keybd_event( VK_SCROLL, + 0x45, + KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, + 0); + } +} + +void RemoveExtension(wchar_t *str) +{ + wchar_t *p = wcsrchr(str, L'.'); + if (p) *p = 0; +} + +static void ShiftDown(wchar_t *str) +{ + while (*str) + { + str[0] = str[1]; + str++; + } +} + +void RemoveSingleAmpersands(wchar_t *str) +{ + while (*str) + { + if (str[0] == L'&') + { + if (str[1] == L'&') // two in a row: replace with single ampersand, move on + str++; + + ShiftDown(str); + } + else + str = CharNextW(str); + } +} + +void TextToGuid(char *str, GUID *pGUID) +{ + if (!str) return; + if (!pGUID) return; + + DWORD d[11]; + + sscanf(str, "%X %X %X %X %X %X %X %X %X %X %X", + &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7], &d[8], &d[9], &d[10]); + + pGUID->Data1 = (DWORD)d[0]; + pGUID->Data2 = (WORD)d[1]; + pGUID->Data3 = (WORD)d[2]; + pGUID->Data4[0] = (BYTE)d[3]; + pGUID->Data4[1] = (BYTE)d[4]; + pGUID->Data4[2] = (BYTE)d[5]; + pGUID->Data4[3] = (BYTE)d[6]; + pGUID->Data4[4] = (BYTE)d[7]; + pGUID->Data4[5] = (BYTE)d[8]; + pGUID->Data4[6] = (BYTE)d[9]; + pGUID->Data4[7] = (BYTE)d[10]; +} + +void GuidToText(GUID *pGUID, char *str, int nStrLen) +{ + // note: nStrLen should be set to sizeof(str). + if (!str) return; + if (!nStrLen) return; + str[0] = 0; + if (!pGUID) return; + + DWORD d[11]; + d[0] = (DWORD)pGUID->Data1; + d[1] = (DWORD)pGUID->Data2; + d[2] = (DWORD)pGUID->Data3; + d[3] = (DWORD)pGUID->Data4[0]; + d[4] = (DWORD)pGUID->Data4[1]; + d[5] = (DWORD)pGUID->Data4[2]; + d[6] = (DWORD)pGUID->Data4[3]; + d[7] = (DWORD)pGUID->Data4[4]; + d[8] = (DWORD)pGUID->Data4[5]; + d[9] = (DWORD)pGUID->Data4[6]; + d[10] = (DWORD)pGUID->Data4[7]; + + sprintf(str, "%08X %04X %04X %02X %02X %02X %02X %02X %02X %02X %02X", + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10]); +} + +/* +int GetPentiumTimeRaw(unsigned __int64 *cpu_timestamp) +{ + // returns 0 on failure, 1 on success + // warning: watch out for wraparound! + + // note: it's probably better to use QueryPerformanceFrequency + // and QueryPerformanceCounter()! + + // get high-precision time: + __try + { + unsigned __int64 *dest = (unsigned __int64 *)cpu_timestamp; + __asm + { + _emit 0xf // these two bytes form the 'rdtsc' asm instruction, + _emit 0x31 // available on Pentium I and later. + mov esi, dest + mov [esi ], eax // lower 32 bits of tsc + mov [esi+4], edx // upper 32 bits of tsc + } + return 1; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return 0; + } + + return 0; +} + +double GetPentiumTimeAsDouble(unsigned __int64 frequency) +{ + // returns < 0 on failure; otherwise, returns current cpu time, in seconds. + // warning: watch out for wraparound! + + // note: it's probably better to use QueryPerformanceFrequency + // and QueryPerformanceCounter()! + + if (frequency==0) + return -1.0; + + // get high-precision time: + __try + { + unsigned __int64 high_perf_time; + unsigned __int64 *dest = &high_perf_time; + __asm + { + _emit 0xf // these two bytes form the 'rdtsc' asm instruction, + _emit 0x31 // available on Pentium I and later. + mov esi, dest + mov [esi ], eax // lower 32 bits of tsc + mov [esi+4], edx // upper 32 bits of tsc + } + __int64 time_s = (__int64)(high_perf_time / frequency); // unsigned->sign conversion should be safe here + __int64 time_fract = (__int64)(high_perf_time % frequency); // unsigned->sign conversion should be safe here + // note: here, we wrap the timer more frequently (once per week) + // than it otherwise would (VERY RARELY - once every 585 years on + // a 1 GHz), to alleviate floating-point precision errors that start + // to occur when you get to very high counter values. + double ret = (time_s % (60*60*24*7)) + (double)time_fract/(double)((__int64)frequency); + return ret; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return -1.0; + } + + return -1.0; +} +*/ + +#ifdef _DEBUG + void OutputDebugMessage(char *szStartText, HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) + { + // note: this function does NOT log WM_MOUSEMOVE, WM_NCHITTEST, or WM_SETCURSOR + // messages, since they are so frequent. + // note: these identifiers were pulled from winuser.h + + //if (msg == WM_MOUSEMOVE || msg == WM_NCHITTEST || msg == WM_SETCURSOR) + // return; + + #ifdef _DEBUG + char buf[64]; + int matched = 1; + + sprintf(buf, "WM_"); + + switch(msg) + { + case 0x0001: lstrcat(buf, "CREATE"); break; + case 0x0002: lstrcat(buf, "DESTROY"); break; + case 0x0003: lstrcat(buf, "MOVE"); break; + case 0x0005: lstrcat(buf, "SIZE"); break; + case 0x0006: lstrcat(buf, "ACTIVATE"); break; + case 0x0007: lstrcat(buf, "SETFOCUS"); break; + case 0x0008: lstrcat(buf, "KILLFOCUS"); break; + case 0x000A: lstrcat(buf, "ENABLE"); break; + case 0x000B: lstrcat(buf, "SETREDRAW"); break; + case 0x000C: lstrcat(buf, "SETTEXT"); break; + case 0x000D: lstrcat(buf, "GETTEXT"); break; + case 0x000E: lstrcat(buf, "GETTEXTLENGTH"); break; + case 0x000F: lstrcat(buf, "PAINT"); break; + case 0x0010: lstrcat(buf, "CLOSE"); break; + case 0x0011: lstrcat(buf, "QUERYENDSESSION"); break; + case 0x0012: lstrcat(buf, "QUIT"); break; + case 0x0013: lstrcat(buf, "QUERYOPEN"); break; + case 0x0014: lstrcat(buf, "ERASEBKGND"); break; + case 0x0015: lstrcat(buf, "SYSCOLORCHANGE"); break; + case 0x0016: lstrcat(buf, "ENDSESSION"); break; + case 0x0018: lstrcat(buf, "SHOWWINDOW"); break; + case 0x001A: lstrcat(buf, "WININICHANGE"); break; + case 0x001B: lstrcat(buf, "DEVMODECHANGE"); break; + case 0x001C: lstrcat(buf, "ACTIVATEAPP"); break; + case 0x001D: lstrcat(buf, "FONTCHANGE"); break; + case 0x001E: lstrcat(buf, "TIMECHANGE"); break; + case 0x001F: lstrcat(buf, "CANCELMODE"); break; + case 0x0020: lstrcat(buf, "SETCURSOR"); break; + case 0x0021: lstrcat(buf, "MOUSEACTIVATE"); break; + case 0x0022: lstrcat(buf, "CHILDACTIVATE"); break; + case 0x0023: lstrcat(buf, "QUEUESYNC"); break; + case 0x0024: lstrcat(buf, "GETMINMAXINFO"); break; + case 0x0026: lstrcat(buf, "PAINTICON"); break; + case 0x0027: lstrcat(buf, "ICONERASEBKGND"); break; + case 0x0028: lstrcat(buf, "NEXTDLGCTL"); break; + case 0x002A: lstrcat(buf, "SPOOLERSTATUS"); break; + case 0x002B: lstrcat(buf, "DRAWITEM"); break; + case 0x002C: lstrcat(buf, "MEASUREITEM"); break; + case 0x002D: lstrcat(buf, "DELETEITEM"); break; + case 0x002E: lstrcat(buf, "VKEYTOITEM"); break; + case 0x002F: lstrcat(buf, "CHARTOITEM"); break; + case 0x0030: lstrcat(buf, "SETFONT"); break; + case 0x0031: lstrcat(buf, "GETFONT"); break; + case 0x0032: lstrcat(buf, "SETHOTKEY"); break; + case 0x0033: lstrcat(buf, "GETHOTKEY"); break; + case 0x0037: lstrcat(buf, "QUERYDRAGICON"); break; + case 0x0039: lstrcat(buf, "COMPAREITEM"); break; + case 0x0041: lstrcat(buf, "COMPACTING"); break; + case 0x0044: lstrcat(buf, "COMMNOTIFY"); break; + case 0x0046: lstrcat(buf, "WINDOWPOSCHANGING"); break; + case 0x0047: lstrcat(buf, "WINDOWPOSCHANGED"); break; + case 0x0048: lstrcat(buf, "POWER"); break; + case 0x004A: lstrcat(buf, "COPYDATA"); break; + case 0x004B: lstrcat(buf, "CANCELJOURNAL"); break; + + #if(WINVER >= 0x0400) + case 0x004E: lstrcat(buf, "NOTIFY"); break; + case 0x0050: lstrcat(buf, "INPUTLANGCHANGEREQUEST"); break; + case 0x0051: lstrcat(buf, "INPUTLANGCHANGE"); break; + case 0x0052: lstrcat(buf, "TCARD"); break; + case 0x0053: lstrcat(buf, "HELP"); break; + case 0x0054: lstrcat(buf, "USERCHANGED"); break; + case 0x0055: lstrcat(buf, "NOTIFYFORMAT"); break; + case 0x007B: lstrcat(buf, "CONTEXTMENU"); break; + case 0x007C: lstrcat(buf, "STYLECHANGING"); break; + case 0x007D: lstrcat(buf, "STYLECHANGED"); break; + case 0x007E: lstrcat(buf, "DISPLAYCHANGE"); break; + case 0x007F: lstrcat(buf, "GETICON"); break; + case 0x0080: lstrcat(buf, "SETICON"); break; + #endif + + case 0x0081: lstrcat(buf, "NCCREATE"); break; + case 0x0082: lstrcat(buf, "NCDESTROY"); break; + case 0x0083: lstrcat(buf, "NCCALCSIZE"); break; + case 0x0084: lstrcat(buf, "NCHITTEST"); break; + case 0x0085: lstrcat(buf, "NCPAINT"); break; + case 0x0086: lstrcat(buf, "NCACTIVATE"); break; + case 0x0087: lstrcat(buf, "GETDLGCODE"); break; + case 0x0088: lstrcat(buf, "SYNCPAINT"); break; + case 0x00A0: lstrcat(buf, "NCMOUSEMOVE"); break; + case 0x00A1: lstrcat(buf, "NCLBUTTONDOWN"); break; + case 0x00A2: lstrcat(buf, "NCLBUTTONUP"); break; + case 0x00A3: lstrcat(buf, "NCLBUTTONDBLCLK"); break; + case 0x00A4: lstrcat(buf, "NCRBUTTONDOWN"); break; + case 0x00A5: lstrcat(buf, "NCRBUTTONUP"); break; + case 0x00A6: lstrcat(buf, "NCRBUTTONDBLCLK"); break; + case 0x00A7: lstrcat(buf, "NCMBUTTONDOWN"); break; + case 0x00A8: lstrcat(buf, "NCMBUTTONUP"); break; + case 0x00A9: lstrcat(buf, "NCMBUTTONDBLCLK"); break; + case 0x0100: lstrcat(buf, "KEYDOWN"); break; + case 0x0101: lstrcat(buf, "KEYUP"); break; + case 0x0102: lstrcat(buf, "CHAR"); break; + case 0x0103: lstrcat(buf, "DEADCHAR"); break; + case 0x0104: lstrcat(buf, "SYSKEYDOWN"); break; + case 0x0105: lstrcat(buf, "SYSKEYUP"); break; + case 0x0106: lstrcat(buf, "SYSCHAR"); break; + case 0x0107: lstrcat(buf, "SYSDEADCHAR"); break; + case 0x0108: lstrcat(buf, "KEYLAST"); break; + + #if(WINVER >= 0x0400) + case 0x010D: lstrcat(buf, "IME_STARTCOMPOSITION"); break; + case 0x010E: lstrcat(buf, "IME_ENDCOMPOSITION"); break; + case 0x010F: lstrcat(buf, "IME_COMPOSITION"); break; + //case 0x010F: lstrcat(buf, "IME_KEYLAST"); break; + #endif + + case 0x0110: lstrcat(buf, "INITDIALOG"); break; + case 0x0111: lstrcat(buf, "COMMAND"); break; + case 0x0112: lstrcat(buf, "SYSCOMMAND"); break; + case 0x0113: lstrcat(buf, "TIMER"); break; + case 0x0114: lstrcat(buf, "HSCROLL"); break; + case 0x0115: lstrcat(buf, "VSCROLL"); break; + case 0x0116: lstrcat(buf, "INITMENU"); break; + case 0x0117: lstrcat(buf, "INITMENUPOPUP"); break; + case 0x011F: lstrcat(buf, "MENUSELECT"); break; + case 0x0120: lstrcat(buf, "MENUCHAR"); break; + case 0x0121: lstrcat(buf, "ENTERIDLE"); break; + #if(WINVER >= 0x0500) + case 0x0122: lstrcat(buf, "MENURBUTTONUP"); break; + case 0x0123: lstrcat(buf, "MENUDRAG"); break; + case 0x0124: lstrcat(buf, "MENUGETOBJECT"); break; + case 0x0125: lstrcat(buf, "UNINITMENUPOPUP"); break; + case 0x0126: lstrcat(buf, "MENUCOMMAND"); break; + #endif + + case 0x0132: lstrcat(buf, "CTLCOLORMSGBOX"); break; + case 0x0133: lstrcat(buf, "CTLCOLOREDIT"); break; + case 0x0134: lstrcat(buf, "CTLCOLORLISTBOX"); break; + case 0x0135: lstrcat(buf, "CTLCOLORBTN"); break; + case 0x0136: lstrcat(buf, "CTLCOLORDLG"); break; + case 0x0137: lstrcat(buf, "CTLCOLORSCROLLBAR"); break; + case 0x0138: lstrcat(buf, "CTLCOLORSTATIC"); break; + + //case 0x0200: lstrcat(buf, "MOUSEFIRST"); break; + case 0x0200: lstrcat(buf, "MOUSEMOVE"); break; + case 0x0201: lstrcat(buf, "LBUTTONDOWN"); break; + case 0x0202: lstrcat(buf, "LBUTTONUP"); break; + case 0x0203: lstrcat(buf, "LBUTTONDBLCLK"); break; + case 0x0204: lstrcat(buf, "RBUTTONDOWN"); break; + case 0x0205: lstrcat(buf, "RBUTTONUP"); break; + case 0x0206: lstrcat(buf, "RBUTTONDBLCLK"); break; + case 0x0207: lstrcat(buf, "MBUTTONDOWN"); break; + case 0x0208: lstrcat(buf, "MBUTTONUP"); break; + case 0x0209: lstrcat(buf, "MBUTTONDBLCLK"); break; + + #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) + case 0x020A: lstrcat(buf, "MOUSEWHEEL"); break; + case 0x020E: lstrcat(buf, "MOUSELAST"); break; + #else + //case 0x0209: lstrcat(buf, "MOUSELAST"); break; + #endif + + case 0x0210: lstrcat(buf, "PARENTNOTIFY"); break; + case 0x0211: lstrcat(buf, "ENTERMENULOOP"); break; + case 0x0212: lstrcat(buf, "EXITMENULOOP"); break; + + #if(WINVER >= 0x0400) + case 0x0213: lstrcat(buf, "NEXTMENU"); break; + case 0x0214: lstrcat(buf, "SIZING"); break; + case 0x0215: lstrcat(buf, "CAPTURECHANGED"); break; + case 0x0216: lstrcat(buf, "MOVING"); break; + case 0x0218: lstrcat(buf, "POWERBROADCAST"); break; + case 0x0219: lstrcat(buf, "DEVICECHANGE"); break; + #endif + + /* + case 0x0220: lstrcat(buf, "MDICREATE"); break; + case 0x0221: lstrcat(buf, "MDIDESTROY"); break; + case 0x0222: lstrcat(buf, "MDIACTIVATE"); break; + case 0x0223: lstrcat(buf, "MDIRESTORE"); break; + case 0x0224: lstrcat(buf, "MDINEXT"); break; + case 0x0225: lstrcat(buf, "MDIMAXIMIZE"); break; + case 0x0226: lstrcat(buf, "MDITILE"); break; + case 0x0227: lstrcat(buf, "MDICASCADE"); break; + case 0x0228: lstrcat(buf, "MDIICONARRANGE"); break; + case 0x0229: lstrcat(buf, "MDIGETACTIVE"); break; + */ + + case 0x0230: lstrcat(buf, "MDISETMENU"); break; + case 0x0231: lstrcat(buf, "ENTERSIZEMOVE"); break; + case 0x0232: lstrcat(buf, "EXITSIZEMOVE"); break; + case 0x0233: lstrcat(buf, "DROPFILES"); break; + case 0x0234: lstrcat(buf, "MDIREFRESHMENU"); break; + + + /* + #if(WINVER >= 0x0400) + case 0x0281: lstrcat(buf, "IME_SETCONTEXT"); break; + case 0x0282: lstrcat(buf, "IME_NOTIFY"); break; + case 0x0283: lstrcat(buf, "IME_CONTROL"); break; + case 0x0284: lstrcat(buf, "IME_COMPOSITIONFULL"); break; + case 0x0285: lstrcat(buf, "IME_SELECT"); break; + case 0x0286: lstrcat(buf, "IME_CHAR"); break; + #endif + #if(WINVER >= 0x0500) + case 0x0288: lstrcat(buf, "IME_REQUEST"); break; + #endif + #if(WINVER >= 0x0400) + case 0x0290: lstrcat(buf, "IME_KEYDOWN"); break; + case 0x0291: lstrcat(buf, "IME_KEYUP"); break; + #endif + */ + + #if(_WIN32_WINNT >= 0x0400) + case 0x02A1: lstrcat(buf, "MOUSEHOVER"); break; + case 0x02A3: lstrcat(buf, "MOUSELEAVE"); break; + #endif + + case 0x0300: lstrcat(buf, "CUT"); break; + case 0x0301: lstrcat(buf, "COPY"); break; + case 0x0302: lstrcat(buf, "PASTE"); break; + case 0x0303: lstrcat(buf, "CLEAR"); break; + case 0x0304: lstrcat(buf, "UNDO"); break; + case 0x0305: lstrcat(buf, "RENDERFORMAT"); break; + case 0x0306: lstrcat(buf, "RENDERALLFORMATS"); break; + case 0x0307: lstrcat(buf, "DESTROYCLIPBOARD"); break; + case 0x0308: lstrcat(buf, "DRAWCLIPBOARD"); break; + case 0x0309: lstrcat(buf, "PAINTCLIPBOARD"); break; + case 0x030A: lstrcat(buf, "VSCROLLCLIPBOARD"); break; + case 0x030B: lstrcat(buf, "SIZECLIPBOARD"); break; + case 0x030C: lstrcat(buf, "ASKCBFORMATNAME"); break; + case 0x030D: lstrcat(buf, "CHANGECBCHAIN"); break; + case 0x030E: lstrcat(buf, "HSCROLLCLIPBOARD"); break; + case 0x030F: lstrcat(buf, "QUERYNEWPALETTE"); break; + case 0x0310: lstrcat(buf, "PALETTEISCHANGING"); break; + case 0x0311: lstrcat(buf, "PALETTECHANGED"); break; + case 0x0312: lstrcat(buf, "HOTKEY"); break; + + #if(WINVER >= 0x0400) + case 0x0317: lstrcat(buf, "PRINT"); break; + case 0x0318: lstrcat(buf, "PRINTCLIENT"); break; + + case 0x0358: lstrcat(buf, "HANDHELDFIRST"); break; + case 0x035F: lstrcat(buf, "HANDHELDLAST"); break; + + case 0x0360: lstrcat(buf, "AFXFIRST"); break; + case 0x037F: lstrcat(buf, "AFXLAST"); break; + #endif + + case 0x0380: lstrcat(buf, "PENWINFIRST"); break; + case 0x038F: lstrcat(buf, "PENWINLAST"); break; + + default: + sprintf(buf, "unknown"); + matched = 0; + break; + } + + int n = strlen(buf); + int desired_len = 24; + int spaces_to_append = desired_len-n; + if (spaces_to_append>0) + { + for (int i=0; i PROMPT TO GO TO WEB. + wchar_t title[128]; + int ret = MessageBoxW(hwnd, + #ifndef D3D_SDK_VERSION + --- error; you need to #include --- + #endif + #if (D3D_SDK_VERSION==120) + // plugin was *built* using the DirectX 9.0 sdk, therefore, + // the dx9.0 runtime is missing or corrupt + "Failed to initialize DirectX 9.0 or later.\n" + "Milkdrop requires d3dx9_31.dll to be installed.\n" + "\n" + "Would you like to be taken to:\n" + "http://www.microsoft.com/download/details.aspx?id=35,\n" + "where you can update DirectX 9.0?\n" + XXXXXXX + #else + // plugin was *built* using some other version of the DirectX9 sdk, such as + // 9.1b; therefore, we don't know exactly what version to tell them they need + // to install; so we ask them to go get the *latest* version. + WASABI_API_LNGSTRINGW(IDS_DIRECTX_MISSING_OR_CORRUPT_TEXT) + #endif + , + WASABI_API_LNGSTRINGW_BUF(IDS_DIRECTX_MISSING_OR_CORRUPT, title, 128), + MB_YESNO|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + + if (ret==IDYES) + DownloadDirectX(hwnd); +} + +bool CheckForMMX() +{ + DWORD bMMX = 0; + DWORD *pbMMX = &bMMX; + __try { + __asm { + mov eax, 1 + cpuid + mov edi, pbMMX + mov dword ptr [edi], edx + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + bMMX = 0; + } + + if (bMMX & 0x00800000) // check bit 23 + return true; + + return false; +} + +bool CheckForSSE() +{ +#ifdef _WIN64 + return true; // All x64 processors support SSE +#else + /* + The SSE instruction set was introduced with the Pentium III and features: + * Additional MMX instructions such as min/max + * Prefetch and write-through instructions for optimizing data movement + from and to the L2/L3 caches and main memory + * 8 New 128 bit XMM registers (xmm0..xmm7) and corresponding 32 bit floating point + (single precision) instructions + */ + + DWORD bSSE = 0; + DWORD *pbSSE = &bSSE; + __try { + __asm + { + mov eax, 1 + cpuid + mov edi, pbSSE + mov dword ptr [edi], edx + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + bSSE = 0; + } + + if (bSSE & 0x02000000) // check bit 25 + return true; + + return false; +#endif +} + +void GetDesktopFolder(char *szDesktopFolder) // should be MAX_PATH len. +{ + // returns the path to the desktop folder, WITHOUT a trailing backslash. + szDesktopFolder[0] = 0; + ITEMIDLIST pidl; + ZeroMemory(&pidl, sizeof(pidl)); + if (!SHGetPathFromIDList(&pidl, szDesktopFolder)) + szDesktopFolder[0] = 0; +} + +void ExecutePidl(LPITEMIDLIST pidl, char *szPathAndFile, char *szWorkingDirectory, HWND hWnd) +{ + // This function was based on code by Jeff Prosise. + + // Note: for some reason, ShellExecuteEx fails when executing + // *shortcuts* (.lnk files) from the desktop, using their PIDLs. + // So, if that fails, we try again w/the plain old text filename + // (szPathAndFile). + + char szVerb[] = "open"; + char szFilename2[MAX_PATH]; + + sprintf(szFilename2, "%s.lnk", szPathAndFile); + + // -without the "no-verb" pass, + // certain icons still don't work (like shortcuts + // to IE, VTune...) + // -without the "context menu" pass, + // certain others STILL don't work (Netscape...) + // -without the 'ntry' pass, shortcuts (to folders/files) + // don't work + for (int verb_pass=0; verb_pass<2; verb_pass++) + { + for (int ntry=0; ntry<3; ntry++) + { + for (int context_pass=0; context_pass<2; context_pass++) + { + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.hwnd = hWnd; + sei.fMask = SEE_MASK_FLAG_NO_UI; + if (context_pass==1) + sei.fMask |= SEE_MASK_INVOKEIDLIST; + sei.lpVerb = (verb_pass) ? NULL : szVerb; + sei.lpDirectory = szWorkingDirectory; + sei.nShow = SW_SHOWNORMAL; + + if (ntry==0) + { + // this case works for most non-shortcuts + sei.fMask |= SEE_MASK_IDLIST; + sei.lpIDList = pidl; + } + else if (ntry==1) + { + // this case is required for *shortcuts to folders* to work + sei.lpFile = szPathAndFile; + } + else if (ntry==2) + { + // this case is required for *shortcuts to files* to work + sei.lpFile = szFilename2; + } + + if (ShellExecuteEx(&sei)) + return; + } + } + } +} + +WNDPROC g_pOldWndProc; +LPCONTEXTMENU2 g_pIContext2or3; + +LRESULT CALLBACK HookWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) +{ + //UINT uItem; + //TCHAR szBuf[MAX_PATH]; + + switch (msg) + { + case WM_DRAWITEM: + case WM_MEASUREITEM: + if(wp) break; // not menu related + case WM_INITMENUPOPUP: + g_pIContext2or3->HandleMenuMsg(msg, wp, lp); + return (msg==WM_INITMENUPOPUP ? 0 : TRUE); // handled + + /*case WM_MENUSELECT: + // if this is a shell item, get its descriptive text + uItem = (UINT) LOWORD(wp); + if(0 == (MF_POPUP & HIWORD(wp)) && uItem >= 1 && uItem <= 0x7fff) + { + g_pIContext2or3->GetCommandString(uItem-1, GCS_HELPTEXT, + NULL, szBuf, sizeof(szBuf)/sizeof(szBuf[0]) ); + + // set the status bar text + ((CFrameWnd*)(AfxGetApp()->m_pMainWnd))->SetMessageText(szBuf); + return 0; + } + break;*/ + + default: + break; + } + + // for all untreated messages, call the original wndproc + return ::CallWindowProc(g_pOldWndProc, hWnd, msg, wp, lp); +} + +BOOL DoExplorerMenu (HWND hwnd, LPITEMIDLIST pidlMain, POINT point) +{ + LPMALLOC pMalloc; + LPSHELLFOLDER psfFolder, psfNextFolder; + LPITEMIDLIST pidlItem, pidlNextItem, *ppidl; + LPCONTEXTMENU pContextMenu; + CMINVOKECOMMANDINFO ici; + UINT nCount, nCmd; + BOOL bResult; + HMENU hMenu; + + // + // Get pointers to the shell's IMalloc interface and the desktop's + // IShellFolder interface. + // + bResult = FALSE; + + if (!SUCCEEDED (SHGetMalloc (&pMalloc))) + return bResult; + + if (!SUCCEEDED (SHGetDesktopFolder (&psfFolder))) { + pMalloc->Release(); + return bResult; + } + + if (nCount = GetItemCount (pidlMain)) // nCount must be > 0 + { + // + // Initialize psfFolder with a pointer to the IShellFolder + // interface of the folder that contains the item whose context + // menu we're after, and initialize pidlItem with a pointer to + // the item's item ID. If nCount > 1, this requires us to walk + // the list of item IDs stored in pidlMain and bind to each + // subfolder referenced in the list. + // + pidlItem = pidlMain; + + while (--nCount) { + // + // Create a 1-item item ID list for the next item in pidlMain. + // + pidlNextItem = DuplicateItem (pMalloc, pidlItem); + if (pidlNextItem == NULL) { + psfFolder->Release(); + pMalloc->Release(); + return bResult; + } + + // + // Bind to the folder specified in the new item ID list. + // + if (!SUCCEEDED (psfFolder->BindToObject(pidlNextItem, NULL, IID_IShellFolder, (void**)&psfNextFolder))) // modified by RG + { + pMalloc->Free(pidlNextItem); + psfFolder->Release(); + pMalloc->Release(); + return bResult; + } + + // + // Release the IShellFolder pointer to the parent folder + // and set psfFolder equal to the IShellFolder pointer for + // the current folder. + // + psfFolder->Release(); + psfFolder = psfNextFolder; + + // + // Release the storage for the 1-item item ID list we created + // just a moment ago and initialize pidlItem so that it points + // to the next item in pidlMain. + // + pMalloc->Free(pidlNextItem); + pidlItem = GetNextItem (pidlItem); + } + + // + // Get a pointer to the item's IContextMenu interface and call + // IContextMenu::QueryContextMenu to initialize a context menu. + // + ppidl = &pidlItem; + if (SUCCEEDED (psfFolder->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)ppidl, IID_IContextMenu, NULL, (void**)&pContextMenu))) // modified by RG + { + // try to see if we can upgrade to an IContextMenu3 + // or IContextMenu2 interface pointer: + int level = 1; + void *pCM = NULL; + if (pContextMenu->QueryInterface(IID_IContextMenu3, &pCM) == NOERROR) + { + pContextMenu->Release(); + pContextMenu = (LPCONTEXTMENU)pCM; + level = 3; + } + else if (pContextMenu->QueryInterface(IID_IContextMenu2, &pCM) == NOERROR) + { + pContextMenu->Release(); + pContextMenu = (LPCONTEXTMENU)pCM; + level = 2; + } + + hMenu = CreatePopupMenu (); + if (SUCCEEDED (pContextMenu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_EXPLORE))) + { + ClientToScreen (hwnd, &point); + + // install the subclassing "hook", for versions 2 or 3 + if (level >= 2) + { + g_pOldWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (DWORD_PTR)HookWndProc); + g_pIContext2or3 = (LPCONTEXTMENU2)pContextMenu; // cast ok for ICMv3 + } + else + { + g_pOldWndProc = NULL; + g_pIContext2or3 = NULL; + } + + // + // Display the context menu. + // + nCmd = TrackPopupMenu (hMenu, TPM_LEFTALIGN | + TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, + point.x, point.y, 0, hwnd, NULL); + + // restore old wndProc + if (g_pOldWndProc) + { + SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)g_pOldWndProc); + } + + // + // If a command was selected from the menu, execute it. + // + if (nCmd >= 1 && nCmd <= 0x7fff) + { + ZeroMemory(&ici, sizeof(ici)); + ici.cbSize = sizeof (CMINVOKECOMMANDINFO); + //ici.fMask = 0; + ici.hwnd = hwnd; + ici.lpVerb = MAKEINTRESOURCE (nCmd - 1); + //ici.lpParameters = NULL; + //ici.lpDirectory = NULL; + ici.nShow = SW_SHOWNORMAL; + //ici.dwHotKey = 0; + //ici.hIcon = NULL; + + if (SUCCEEDED ( pContextMenu->InvokeCommand (&ici))) + bResult = TRUE; + } + /*else if (nCmd) + { + PostMessage(hwnd, WM_COMMAND, nCmd, NULL); // our command + }*/ + } + DestroyMenu (hMenu); + pContextMenu->Release(); + } + } + + // + // Clean up and return. + // + psfFolder->Release(); + pMalloc->Release(); + + return bResult; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Note: a special thanks goes out to Jeff Prosise for writing & publishing +// the following code! +// +// FUNCTION: GetItemCount +// +// DESCRIPTION: Computes the number of item IDs in an item ID list. +// +// INPUT: pidl = Pointer to an item ID list. +// +// RETURNS: Number of item IDs in the list. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +UINT GetItemCount (LPITEMIDLIST pidl) +{ + USHORT nLen; + UINT nCount; + + nCount = 0; + while ((nLen = pidl->mkid.cb) != 0) { + pidl = GetNextItem (pidl); + nCount++; + } + return nCount; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Note: a special thanks goes out to Jeff Prosise for writing & publishing +// the following code! +// +// FUNCTION: GetNextItem +// +// DESCRIPTION: Finds the next item in an item ID list. +// +// INPUT: pidl = Pointer to an item ID list. +// +// RETURNS: Pointer to the next item. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LPITEMIDLIST GetNextItem (LPITEMIDLIST pidl) +{ + USHORT nLen; + + if ((nLen = pidl->mkid.cb) == 0) + return NULL; + + return (LPITEMIDLIST) (((LPBYTE) pidl) + nLen); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Note: a special thanks goes out to Jeff Prosise for writing & publishing +// the following code! +// +// FUNCTION: DuplicateItem +// +// DESCRIPTION: Makes a copy of the next item in an item ID list. +// +// INPUT: pMalloc = Pointer to an IMalloc interface. +// pidl = Pointer to an item ID list. +// +// RETURNS: Pointer to an ITEMIDLIST containing the copied item ID. +// +// NOTES: It is the caller's responsibility to free the memory +// allocated by this function when the item ID is no longer +// needed. Example: +// +// pidlItem = DuplicateItem (pMalloc, pidl); +// . +// . +// . +// pMalloc->lpVtbl->Free (pMalloc, pidlItem); +// +// Failure to free the ITEMIDLIST will result in memory +// leaks. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LPITEMIDLIST DuplicateItem (LPMALLOC pMalloc, LPITEMIDLIST pidl) +{ + USHORT nLen; + LPITEMIDLIST pidlNew; + + nLen = pidl->mkid.cb; + if (nLen == 0) + return NULL; + + pidlNew = (LPITEMIDLIST) pMalloc->Alloc ( + nLen + sizeof (USHORT)); + if (pidlNew == NULL) + return NULL; + + CopyMemory (pidlNew, pidl, nLen); + *((USHORT*) (((LPBYTE) pidlNew) + nLen)) = 0; + + return pidlNew; +} + +//---------------------------------------------------------------------- +// A special thanks goes out to Jeroen-bart Engelen (Yeep) for providing +// his source code for getting the position & label information for all +// the icons on the desktop, as found below. See his article at +// http://www.digiwar.com/scripts/renderpage.php?section=2&subsection=2 +//---------------------------------------------------------------------- + +void FindDesktopWindows(HWND *desktop_progman, HWND *desktopview_wnd, HWND *listview_wnd) +{ + *desktop_progman = NULL; + *desktopview_wnd = NULL; + *listview_wnd = NULL; + + *desktop_progman = FindWindow(NULL, ("Program Manager")); + if(*desktop_progman == NULL) + { + //MessageBox(NULL, "Unable to get the handle to the Program Manager.", "Fatal error", MB_OK|MB_ICONERROR); + return; + } + + *desktopview_wnd = FindWindowEx(*desktop_progman, NULL, "SHELLDLL_DefView", NULL); + if(*desktopview_wnd == NULL) + { + //MessageBox(NULL, "Unable to get the handle to the desktopview.", "Fatal error", MB_OK|MB_ICONERROR); + return; + } + + // Thanks ef_ef_ef@yahoo.com for pointing out this works in NT 4 and not the way I did it originally. + *listview_wnd = FindWindowEx(*desktopview_wnd, NULL, "SysListView32", NULL); + if(*listview_wnd == NULL) + { + //MessageBox(NULL, "Unable to get the handle to the folderview.", "Fatal error", MB_OK|MB_ICONERROR); + return; + } +} + +//---------------------------------------------------------------------- + +int GetDesktopIconSize() +{ + int ret = 32; + + // reads the key: HKEY_CURRENT_USER\Control Panel, Desktop\WindowMetrics\Shell Icon Size + unsigned char buf[64]; + unsigned long len = sizeof(buf); + DWORD type; + HKEY key; + + if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel\\Desktop\\WindowMetrics", 0, KEY_READ, &key)) + { + if (ERROR_SUCCESS == RegQueryValueEx(key, "Shell Icon Size", NULL, &type, (unsigned char*)buf, &len) && + type == REG_SZ) + { + int x = _atoi_l((char*)buf, g_use_C_locale); + if (x>0 && x<=128) + ret = x; + } + + RegCloseKey(key); + } + + return ret; +} + +//---------------------------------------------------------------------- + +// handy functions for populating Combo Boxes: +int SelectItemByValue(HWND ctrl, DWORD value) +{ + int count = SendMessage(ctrl, CB_GETCOUNT, 0, 0); + for (int i=0; i this is a quick-fix, we should call FindFirstFile() on the system directory + d3dx9=NULL; + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_36.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_35.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_34.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_33.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_32.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_31.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_30.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_29.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_28.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_27.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_26.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_25.dll"); + if (!d3dx9) d3dx9 = LoadLibrary("d3dx9_24.dll"); + } + + if (d3dx9) + { + pCreateFontW = (D3DXCREATEFONTW) GetProcAddress(d3dx9,"D3DXCreateFontW"); + pMatrixMultiply = (D3DXMATRIXMULTIPLY) GetProcAddress(d3dx9,"D3DXMatrixMultiply"); + pMatrixTranslation = (D3DXMATRIXTRANSLATION)GetProcAddress(d3dx9,"D3DXMatrixTranslation"); + pMatrixScaling = (D3DXMATRIXSCALING)GetProcAddress(d3dx9,"D3DXMatrixScaling"); + pMatrixRotationX = (D3DXMATRIXROTATION)GetProcAddress(d3dx9,"D3DXMatrixRotationX"); + pMatrixRotationY = (D3DXMATRIXROTATION)GetProcAddress(d3dx9,"D3DXMatrixRotationY"); + pMatrixRotationZ = (D3DXMATRIXROTATION)GetProcAddress(d3dx9,"D3DXMatrixRotationZ"); + pCreateTextureFromFileExW = (D3DXCREATETEXTUREFROMFILEEXW)GetProcAddress(d3dx9,"D3DXCreateTextureFromFileExW"); + pMatrixOrthoLH = (D3DXMATRIXORTHOLH)GetProcAddress(d3dx9,"D3DXMatrixOrthoLH"); + pCompileShader = (D3DXCOMPILESHADER)GetProcAddress(d3dx9,"D3DXCompileShader"); + pMatrixLookAtLH = (D3DXMATRIXLOOKATLH)GetProcAddress(d3dx9,"D3DXMatrixLookAtLH"); + pCreateTexture = (D3DXCREATETEXTURE)GetProcAddress(d3dx9,"D3DXCreateTexture"); + + + + } + + return d3dx9; +} + +LRESULT GetWinampVersion(HWND winamp) +{ + static LRESULT version=0; + if (!version) + version=SendMessage(winamp,WM_WA_IPC,0,0); + return version; +} + +void* GetTextResource(UINT id, int no_fallback){ + void* data = 0; + HINSTANCE hinst = WASABI_API_LNG_HINST; + HRSRC rsrc = FindResource(hinst,MAKEINTRESOURCE(id),"TEXT"); + if(!rsrc && !no_fallback) rsrc = FindResource((hinst = WASABI_API_ORIG_HINST),MAKEINTRESOURCE(id),"TEXT"); + if(rsrc){ + HGLOBAL resourceHandle = LoadResource(hinst,rsrc); + data = LockResource(resourceHandle); + } + return data; +} \ No newline at end of file diff --git a/vis_milk2/utility.h b/vis_milk2/utility.h new file mode 100644 index 0000000..13d31e4 --- /dev/null +++ b/vis_milk2/utility.h @@ -0,0 +1,164 @@ +/* + 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. +*/ + +#ifndef __NULLSOFT_DX9_PLUGIN_SHELL_UTILITY_H__ +#define __NULLSOFT_DX9_PLUGIN_SHELL_UTILITY_H__ 1 + +#include +#include +#include +#include + +#define SafeRelease(x) { if (x) {x->Release(); x=NULL;} } +#define SafeDelete(x) { if (x) {delete x; x=NULL;} } +#define IsNullGuid(lpGUID) ( ((int*)lpGUID)[0]==0 && ((int*)lpGUID)[1]==0 && ((int*)lpGUID)[2]==0 && ((int*)lpGUID)[3]==0 ) +#define DlgItemIsChecked(hDlg, nIDDlgItem) ((SendDlgItemMessage(hDlg, nIDDlgItem, BM_GETCHECK, (WPARAM) 0, (LPARAM) 0) == BST_CHECKED) ? true : false) +#define CosineInterp(x) (0.5f - 0.5f*cosf((x) * 3.1415926535898f)) +#define InvCosineInterp(x) (acosf(1.0f - 2.0f*(x))/3.1415926535898f) +float PowCosineInterp(float x, float pow); +float AdjustRateToFPS(float per_frame_decay_rate_at_fps1, float fps1, float actual_fps); + +//int GetPrivateProfileInt - part of Win32 API +#define GetPrivateProfileBoolW(w,x,y,z) ((bool)(GetPrivateProfileIntW(w,x,y,z) != 0)) +#define GetPrivateProfileBOOLW(w,x,y,z) ((BOOL)(GetPrivateProfileIntW(w,x,y,z) != 0)) +float GetPrivateProfileFloatW(wchar_t *szSectionName, wchar_t *szKeyName, float fDefault, wchar_t *szIniFile); +bool WritePrivateProfileIntW(int d, wchar_t *szKeyName, wchar_t *szIniFile, wchar_t *szSectionName); +bool WritePrivateProfileFloatW(float f, wchar_t *szKeyName, wchar_t *szIniFile, wchar_t *szSectionName); + +extern _locale_t g_use_C_locale; +extern char keyMappings[8]; + +void SetScrollLock(int bNewState, bool bPreventHandling); +void RemoveExtension(wchar_t *str); +void RemoveSingleAmpersands(wchar_t *str); +void TextToGuid(char *str, GUID *pGUID); +void GuidToText(GUID *pGUID, char *str, int nStrLen); +//int GetPentiumTimeRaw(unsigned __int64 *cpu_timestamp); +//double GetPentiumTimeAsDouble(unsigned __int64 frequency); +#ifdef _DEBUG + void OutputDebugMessage(char *szStartText, HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); // only available in RELEASE builds! +#endif +void MissingDirectX(HWND hwnd); +bool CheckForMMX(); +bool CheckForSSE(); +void GetDesktopFolder(char *szDesktopFolder); // should be MAX_PATH len. + +#include "icon_t.h" +#include +#include + +BOOL DoExplorerMenu (HWND hwnd, LPCTSTR pszPath, POINT point); +BOOL DoExplorerMenu (HWND hwnd, LPITEMIDLIST pidl, POINT point); +UINT GetItemCount (LPITEMIDLIST pidl); +LPITEMIDLIST GetNextItem (LPITEMIDLIST pidl); +LPITEMIDLIST DuplicateItem (LPMALLOC pMalloc, LPITEMIDLIST pidl); +void FindDesktopWindows(HWND *desktop_progman, HWND *desktopview_wnd, HWND *listview_wnd); +void ExecutePidl(LPITEMIDLIST pidl, char *szPathAndFile, char *szWorkingDirectory, HWND hWnd); +int GetDesktopIconSize(); + +// handy functions for populating Combo Boxes: +inline void AddItem(HWND ctrl, const wchar_t* text, DWORD itemdata) { + LRESULT nPos = SendMessageW( ctrl, CB_ADDSTRING, 0, (LPARAM)text); + SendMessage( ctrl, CB_SETITEMDATA, nPos, itemdata); +} +inline void SelectItemByPos(HWND ctrl, int pos) { + SendMessage(ctrl, CB_SETCURSEL, pos, 0); +} +int SelectItemByValue(HWND ctrl, DWORD value); +bool ReadCBValue(HWND hwnd, DWORD ctrl_id, int* pRetValue); + +LRESULT GetWinampVersion(HWND winamp); +void* GetTextResource(UINT id, int no_fallback); + +HMODULE FindD3DX9(HWND winamp); + +intptr_t myOpenURL(HWND hwnd, wchar_t *loc); + +typedef HRESULT (WINAPI *D3DXCREATEFONTW)(LPDIRECT3DDEVICE9, INT, UINT, UINT, UINT, BOOL, DWORD, DWORD, DWORD, DWORD, LPCWSTR, LPD3DXFONT *); +extern D3DXCREATEFONTW pCreateFontW; + +typedef D3DXMATRIX *(WINAPI *D3DXMATRIXMULTIPLY)(D3DXMATRIX *pOut, CONST D3DXMATRIX *pM1, CONST D3DXMATRIX *pM2); +extern D3DXMATRIXMULTIPLY pMatrixMultiply; + +typedef D3DXMATRIX* (WINAPI *D3DXMATRIXTRANSLATION)( D3DXMATRIX *pOut, FLOAT x, FLOAT y, FLOAT z ); +extern D3DXMATRIXTRANSLATION pMatrixTranslation; + +typedef D3DXMATRIX* (WINAPI *D3DXMATRIXSCALING)( D3DXMATRIX *pOut, FLOAT sx, FLOAT sy, FLOAT sz ); +extern D3DXMATRIXSCALING pMatrixScaling; + +typedef D3DXMATRIX* (WINAPI *D3DXMATRIXROTATION)( D3DXMATRIX *pOut, FLOAT Angle ); +extern D3DXMATRIXROTATION pMatrixRotationX, pMatrixRotationY, pMatrixRotationZ; + +typedef HRESULT (WINAPI *D3DXCREATETEXTUREFROMFILEEXW)( + LPDIRECT3DDEVICE9 pDevice, + LPCWSTR pSrcFile, + UINT Width, + UINT Height, + UINT MipLevels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + DWORD Filter, + DWORD MipFilter, + D3DCOLOR ColorKey, + D3DXIMAGE_INFO* pSrcInfo, + PALETTEENTRY* pPalette, + LPDIRECT3DTEXTURE9* ppTexture); +extern D3DXCREATETEXTUREFROMFILEEXW pCreateTextureFromFileExW; + +typedef D3DXMATRIX* (WINAPI *D3DXMATRIXORTHOLH)(D3DXMATRIX *pOut, FLOAT w, FLOAT h, FLOAT zn, FLOAT zf); +extern D3DXMATRIXORTHOLH pMatrixOrthoLH; + +typedef HRESULT (WINAPI *D3DXCOMPILESHADER)( + LPCSTR pSrcData, + UINT SrcDataLen, + CONST D3DXMACRO* pDefines, + LPD3DXINCLUDE pInclude, + LPCSTR pFunctionName, + LPCSTR pProfile, + DWORD Flags, + LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs, + LPD3DXCONSTANTTABLE* ppConstantTable); +extern D3DXCOMPILESHADER pCompileShader; + +typedef D3DXMATRIX* (WINAPI *D3DXMATRIXLOOKATLH)( D3DXMATRIX *pOut, CONST D3DXVECTOR3 *pEye, CONST D3DXVECTOR3 *pAt, CONST D3DXVECTOR3 *pUp ); +extern D3DXMATRIXLOOKATLH pMatrixLookAtLH; + +typedef HRESULT (WINAPI *D3DXCREATETEXTURE)( + LPDIRECT3DDEVICE9 pDevice, + UINT Width, + UINT Height, + UINT MipLevels, + DWORD Usage, + D3DFORMAT Format, + D3DPOOL Pool, + LPDIRECT3DTEXTURE9* ppTexture); +extern D3DXCREATETEXTURE pCreateTexture; +#endif \ No newline at end of file diff --git a/vis_milk2/vis.cpp b/vis_milk2/vis.cpp new file mode 100644 index 0000000..a4e506e --- /dev/null +++ b/vis_milk2/vis.cpp @@ -0,0 +1,275 @@ +/* + 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. +*/ + +#include "api.h" +#include +#include "vis.h" +#include "plugin.h" +#include "defines.h" +#include "resource.h" +#include "utility.h" + +CPlugin g_plugin; +_locale_t g_use_C_locale = 0; +char keyMappings[8]; +bool g_bFullyExited = true; + +// wasabi based services for localisation support +api_service *WASABI_API_SVC = 0; +api_language *WASABI_API_LNG = 0; +api_application *WASABI_API_APP = 0; +api_syscb *WASABI_API_SYSCB = 0; +HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0; + +void config(struct winampVisModule *this_mod); // configuration dialog +int init(struct winampVisModule *this_mod); // initialization for module +int render1(struct winampVisModule *this_mod); // rendering for module 1 +void quit(struct winampVisModule *this_mod); // deinitialization for module + +// our only plugin module in this plugin: +winampVisModule mod1 = +{ + MODULEDESC, + NULL, // hwndParent + NULL, // hDllInstance + 0, // sRate + 0, // nCh + 0, // latencyMS - tells winamp how much in advance you want the audio data, + // in ms. + 10, // delayMS - if winamp tells the plugin to render a frame and it takes + // less than this # of milliseconds, winamp will sleep (go idle) + // for the remainder. In effect, this limits the framerate of + // the plugin. A value of 10 would cause a fps limit of ~100. + // Derivation: (1000 ms/sec) / (10 ms/frame) = 100 fps. + 0, // spectrumNch + 2, // waveformNch + { 0, }, // spectrumData + { 0, }, // waveformData + config, + init, + render1, + quit +}; + +// getmodule routine from the main header. Returns NULL if an invalid module was requested, +// otherwise returns either mod1, mod2 or mod3 depending on 'which'. +winampVisModule *getModule(int which) +{ + switch (which) + { + case 0: return &mod1; + //case 1: return &mod2; + //case 2: return &mod3; + default: return NULL; + } +} + +// Module header, includes version, description, and address of the module retriever function +winampVisHeader hdr = { VIS_HDRVER, DLLDESC, getModule }; + +// use this to get our own HINSTANCE since overriding DllMain(..) causes instant crashes (should see why) +static HINSTANCE GetMyInstance() +{ + MEMORY_BASIC_INFORMATION mbi = {0}; + if(VirtualQuery(GetMyInstance, &mbi, sizeof(mbi))) + return (HINSTANCE)mbi.AllocationBase; + return NULL; +} + +// this is the only exported symbol. returns our main header. +// if you are compiling C++, the extern "C" { is necessary, so we just #ifdef it +#ifdef __cplusplus +extern "C" { +#endif + __declspec( dllexport ) winampVisHeader *winampVisGetHeader(HWND hwndParent) + { + if(!WASABI_API_LNG_HINST) + { + // loader so that we can get the localisation service api for use + WASABI_API_SVC = (api_service*)SendMessage(hwndParent, WM_WA_IPC, 0, IPC_GET_API_SERVICE); + if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL; + + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID); + if (sf) WASABI_API_LNG = reinterpret_cast(sf->getInterface()); + + sf = WASABI_API_SVC->service_getServiceByGuid(applicationApiServiceGuid); + if (sf) WASABI_API_APP = reinterpret_cast(sf->getInterface()); + + sf = WASABI_API_SVC->service_getServiceByGuid(syscbApiServiceGuid); + if (sf) WASABI_API_SYSCB = reinterpret_cast(sf->getInterface()); + + // need to have this initialised before we try to do anything with localisation features + WASABI_API_START_LANG(GetMyInstance(),VisMilkdropLangGUID); + + /* added for v2.25 as a quick work around to allow partial + /* keyboard mappings (mainly coming from de-de requirements) + ** [yY][Y][yY][zZ] + ** 1 2 3 4 + ** + ** 1 - does yes for the 3 different prompt types + ** 2 - does Ctrl+Y for stopping display of custom message of song title + ** 3 - something for preset editing (not 100% sure what) + ** 4 - used for the previous track sent to Winamp + */ + WASABI_API_LNGSTRING_BUF(IDS_KEY_MAPPINGS, keyMappings, 8); + + // as we're under a different thread we need to set the locale + //WASABI_API_LNG->UseUserNumericLocale(); + g_use_C_locale = WASABI_API_LNG->Get_C_NumericLocale(); + } + + return &hdr; + } +#ifdef __cplusplus +} +#endif + +bool WaitUntilPluginFinished(HWND hWndWinamp) +{ + int slept = 0; + while (!g_bFullyExited && slept < 1000) + { + Sleep(50); + slept += 50; + } + + if (!g_bFullyExited) + { + wchar_t title[64]; + MessageBoxW(hWndWinamp, WASABI_API_LNGSTRINGW(IDS_ERROR_THE_PLUGIN_IS_ALREADY_RUNNING), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + return true; +} + +HWND GetDialogBoxParent(HWND winamp) +{ + HWND parent = (HWND)SendMessage(winamp, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT); + if (!parent || parent == (HWND)1) + return winamp; + return parent; +} + +// configuration. Passed this_mod, as a "this" parameter. Allows you to make one configuration +// function that shares code for all your modules (you don't HAVE to use it though, you can make +// config1(), config2(), etc...) +void config(struct winampVisModule *this_mod) +{ + if (!g_bFullyExited) + { + g_plugin.OnAltK(); + return; + } + + g_bFullyExited = false; + g_plugin.PluginPreInitialize(this_mod->hwndParent, this_mod->hDllInstance); + WASABI_API_DIALOGBOXPARAMW(IDD_CONFIG, GetDialogBoxParent(this_mod->hwndParent), g_plugin.ConfigDialogProc, (LPARAM)&g_plugin); + g_bFullyExited = true; +} + +int (*warand)(void) = 0; + +int fallback_rand_fn(void) { + return rand(); +} + +// initialization. Registers our window class, creates our window, etc. Again, this one works for +// both modules, but you could make init1() and init2()... +// returns 0 on success, 1 on failure. +int init(struct winampVisModule *this_mod) +{ + DWORD version = GetWinampVersion(mod1.hwndParent); + + if (!warand) + { + warand = (int (*)(void))SendMessage(this_mod->hwndParent, WM_WA_IPC, 0, IPC_GET_RANDFUNC); + if ((size_t)warand <= 1) + { + warand = fallback_rand_fn; + } + } + + if (!WaitUntilPluginFinished(this_mod->hwndParent)) + { + return 1; + } + + if (GetWinampVersion(mod1.hwndParent) < 0x4000) + { + // query winamp for its playback state + LRESULT ret = SendMessage(this_mod->hwndParent, WM_USER, 0, 104); + // ret=1: playing, ret=3: paused, other: stopped + + if (ret != 1) + { + wchar_t title[64]; + MessageBoxW(this_mod->hwndParent, WASABI_API_LNGSTRINGW(IDS_THIS_PLUGIN_NEEDS_MUSIC_TO_RUN), + WASABI_API_LNGSTRINGW_BUF(IDS_NO_MUSIC_PLAYING, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL ); + return 1; // failure + } + } + + g_bFullyExited = false; + + if (!g_plugin.PluginPreInitialize(this_mod->hwndParent, this_mod->hDllInstance)) + { + g_plugin.PluginQuit(); + g_bFullyExited = true; + return 1; + } + + if (!g_plugin.PluginInitialize()) + { + g_plugin.PluginQuit(); + g_bFullyExited = true; + return 1; + } + + return 0; // success +} + +// render function for oscilliscope. Returns 0 if successful, 1 if visualization should end. +int render1(struct winampVisModule *this_mod) +{ + if (g_plugin.PluginRender(this_mod->waveformData[0], this_mod->waveformData[1])) + return 0; // ok + else + return 1; // failed +} + +// cleanup (opposite of init()). Should destroy the window, unregister the window class, etc. +void quit(struct winampVisModule *this_mod) +{ + g_plugin.PluginQuit(); + g_bFullyExited = true; +} \ No newline at end of file diff --git a/vis_milk2/vis.h b/vis_milk2/vis.h new file mode 100644 index 0000000..cee91b3 --- /dev/null +++ b/vis_milk2/vis.h @@ -0,0 +1 @@ +#include "../Winamp/vis.h" \ No newline at end of file diff --git a/vis_milk2/vms_desktop.lib b/vis_milk2/vms_desktop.lib new file mode 100644 index 0000000..4009172 Binary files /dev/null and b/vis_milk2/vms_desktop.lib differ