diff options
Diffstat (limited to 'Src/Plugins/Visualization/vis_milk2')
61 files changed, 46003 insertions, 0 deletions
diff --git a/Src/Plugins/Visualization/vis_milk2/DOCUMENTATION.TXT b/Src/Plugins/Visualization/vis_milk2/DOCUMENTATION.TXT new file mode 100644 index 00000000..3e98969e --- /dev/null +++ b/Src/Plugins/Visualization/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/Src/Plugins/Visualization/vis_milk2/api__vis_milk2.h b/Src/Plugins/Visualization/vis_milk2/api__vis_milk2.h new file mode 100644 index 00000000..8b25cfd5 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/api__vis_milk2.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_APIH +#define NULLSOFT_APIH + +#include <api/service/api_service.h> +#include "../Agave/Language/api_language.h" +#include <api/service/waServiceFactory.h> +#include <api/syscb/callbacks/browsercb.h> +#include <api/syscb/callbacks/syscb.h> +#include <api/syscb/api_syscb.h> +extern api_syscb *WASABI_API_SYSCB; +#define WASABI_API_SYSCB sysCallbackApi +#include <api/application/api_application.h> +extern api_application *applicationApi; +#define WASABI_API_APP applicationApi + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Visualization/vis_milk2/config.cpp b/Src/Plugins/Visualization/vis_milk2/config.cpp new file mode 100644 index 00000000..db418171 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/config.cpp @@ -0,0 +1,1589 @@ +/* + 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__vis_milk2.h" +#include "pluginshell.h" +#include "resource.h" +#include "utility.h" +#include "defines.h" +#include "shell_defines.h" +#include "vis.h" +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <multimon.h> +#include <commctrl.h> +#include <shellapi.h> +#include <strsafe.h> +#include <assert.h> + +#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; i<nAdapters && nDispAdapters<MAX_DISPLAY_ADAPTERS; i++) + { + if (g_lpDX->GetAdapterIdentifier(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; i<nDispAdapters; i++) + { + if (!found && + memcmp(&global_adapter_list[i].DeviceIdentifier, pGUID, sizeof(GUID))==0 && + !strcmp(global_adapter_list[i].DeviceName, deviceName) + ) + { + SendMessage( ctrl, CB_SETCURSEL, i, 0); + found = 1; + } + } + if (!found) + SendMessage( ctrl, CB_SETCURSEL, 0, 0); + } + + if (screenmode == FULLSCREEN) + UpdateFSAdapterDispModes(); + else + UpdateDispModeMultiSampling(screenmode); +} + +void CPluginShell::UpdateFSAdapterDispModes() // (fullscreen only) +{ + wchar_t szfmt[256], str[256]; + int i; + HWND hwnd_listbox = GetDlgItem( g_subwnd, IDC_DISP_MODE ); + + int nVideoModesTotal = 0; + if (!g_lpDX) return; + int nAdapterOrdinal = GetCurrentlySelectedAdapter(FULLSCREEN); + nVideoModesTotal = g_lpDX->GetAdapterModeCount(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<nVideoModesTotal; i++) + { + if (nAdded >= 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<g_num_disp_modes && !found; i++) + { + // we have to remap here, because the combo box SORTED the data: + int id = SendMessage( hwnd_listbox, CB_GETITEMDATA, i, 0); + + bool bDesiredBitDepth = ( + (g_disp_mode[id].Format == D3DFMT_R8G8B8 ) || + (g_disp_mode[id].Format == D3DFMT_A8R8G8B8) || + (g_disp_mode[id].Format == D3DFMT_X8R8G8B8) + ); + + bool bMatch = true; + + if (rep<=3 && desired_mode.Width!=g_disp_mode[id].Width) + bMatch = false; + if (rep<=3 && desired_mode.Height!=g_disp_mode[id].Height) + bMatch = false; + if ((rep==0 || rep==2) && desired_mode.RefreshRate!=g_disp_mode[id].RefreshRate) + bMatch = false; + if (rep<=1 && !bDesiredBitDepth) + bMatch = false; + + if (bMatch) + { + SendMessage( hwnd_listbox, CB_SETCURSEL, i, 0); + found = 1; + } + } + } + + // if no match could be found, select #0. + if (!found) + SendMessage( hwnd_listbox, CB_SETCURSEL, 0, 0); + } + else + */ + { + // find best match to prev. selection. + // do many passes until we find one, each time relaxing more constraints. + // outline of the passes: + + int bpp_desired = 0; + switch(desired_mode.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. -,-,-,- + for (int rep=0; rep<12 && !found; rep++) + { + for (int pass=0; pass<2 && !found; pass++) + { + for (i=0; i<g_num_disp_modes && !found; i++) + { + // we have to remap here, because the combo box SORTED the data: + int id = SendMessage( hwnd_listbox, CB_GETITEMDATA, i, 0); + + int bpp_this_mode = 0; + switch(g_disp_mode[id].Format) + { + case D3DFMT_R8G8B8 : bpp_this_mode = 32; break; + case D3DFMT_A8R8G8B8: bpp_this_mode = 32; break; + case D3DFMT_X8R8G8B8: bpp_this_mode = 32; break; + case D3DFMT_R5G6B5 : bpp_this_mode = 16; break; + case D3DFMT_X1R5G5B5: bpp_this_mode = 16; break; + case D3DFMT_A1R5G5B5: bpp_this_mode = 16; break; + case D3DFMT_A4R4G4B4: bpp_this_mode = 16; break; + case D3DFMT_R3G3B2 : bpp_this_mode = 8; break; + case D3DFMT_A8R3G3B2: bpp_this_mode = 16; break; + case D3DFMT_X4R4G4B4: bpp_this_mode = 16; break; + } + + bool bMatch = true; + + if (rep < 4) + { + if (desired_mode.Width != g_disp_mode[id].Width) + bMatch = false; + if (desired_mode.Height != g_disp_mode[id].Height) + bMatch = false; + } + else if (rep < 8) + { + if (DEFAULT_FULLSCREEN_WIDTH != g_disp_mode[id].Width) + bMatch = false; + if (DEFAULT_FULLSCREEN_HEIGHT != g_disp_mode[id].Height) + bMatch = false; + } + + if (((rep/2)%2)==0) + { + if (pass==0 && desired_mode.Format != g_disp_mode[id].Format) + bMatch = false; + else if (pass==1 && bpp_desired != bpp_this_mode) + bMatch = false; + } + + if (((rep%2)==0) && desired_mode.RefreshRate!=g_disp_mode[id].RefreshRate) + { + bMatch = false; + } + + if (bMatch) + { + SendMessage( hwnd_listbox, CB_SETCURSEL, i, 0); + found = 1; + } + } + } + } + + // if no match could be found, select #0. + if (!found) + SendMessage( hwnd_listbox, CB_SETCURSEL, 0, 0); + } + + UpdateDispModeMultiSampling(0); +} + +void CPluginShell::UpdateDispModeMultiSampling(int screenmode) +{ + int nSampleTypes = 0; + + HWND hwnd_listbox; + switch(screenmode) + { + case FULLSCREEN: hwnd_listbox = GetDlgItem(g_subwnd, IDC_FSMS); break; + case WINDOWED: hwnd_listbox = GetDlgItem(g_subwnd, IDC_WMS); break; + case DESKTOP: hwnd_listbox = GetDlgItem(g_subwnd, IDC_DMSMS); break; + } + + wchar_t str[256]; + int i; + + if (!g_lpDX) + return; + + if ((screenmode == WINDOWED && !m_allow_page_tearing_w) || + (screenmode == FULLSCREEN && m_fake_fullscreen_mode && !m_allow_page_tearing_fs) || + (screenmode == DESKTOP && !m_allow_page_tearing_dm)) + { + // page tearing not allowed -> 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<nSampleTypes; i++) + { + int id = SendMessage( hwnd_listbox, CB_GETITEMDATA, i, 0); + if (id==prev_seln) + { + SendMessage( hwnd_listbox, CB_SETCURSEL, i, 0); + return; + } + } + + SendMessage( hwnd_listbox, CB_SETCURSEL, 0, 0); + } +} + +void CPluginShell::UpdateMaxFps(int screenmode) +{ + // initialize sleep combo boxes + HWND ctrl; + switch(screenmode) + { + case FULLSCREEN: ctrl = GetDlgItem(g_subwnd, IDC_FS_MAXFPS ); break; + case WINDOWED: ctrl = GetDlgItem(g_subwnd, IDC_W_MAXFPS ); break; + //case FAKE_FULLSCREEN: ctrl = GetDlgItem(g_subwnd, IDC_FFS_MAXFPS); break; + case DESKTOP: ctrl = GetDlgItem(g_subwnd, IDC_DMS_MAXFPS); break; + } + + SendMessage( ctrl, CB_RESETCONTENT, 0, 0); + for (int j=0; j<=MAX_MAX_FPS; j++) + { + wchar_t buf[256]; + if (j==0) + WASABI_API_LNGSTRINGW_BUF(IDS_UNLIMITED, buf, 256); + else + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_X_FRAME_SEC), (j<MAX_MAX_FPS)?(MAX_MAX_FPS+1-j):(MAX_MAX_FPS+1-j)); + + SendMessageW( ctrl, CB_ADDSTRING, j, (LPARAM)buf); + } + + // set prev. selection + int max_fps; + switch(screenmode) + { + case FULLSCREEN: max_fps = m_max_fps_fs; break; + case WINDOWED: max_fps = m_max_fps_w; break; + //case FAKE_FULLSCREEN: max_fps = m_max_fps_fake_fs; break; + case DESKTOP: max_fps = m_max_fps_dm; break; + } + if (max_fps == 0) + SendMessage(ctrl, CB_SETCURSEL, 0, 0); + else + SendMessage(ctrl, CB_SETCURSEL, MAX_MAX_FPS-max_fps+1, 0); +} + +int CPluginShell::GetCurrentlySelectedAdapter(int screenmode) +{ + // returns the ordinal adapter #. + 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; + } + + int n = SendMessage(ctrl, CB_GETCURSEL, 0, 0); + //if (n != CB_ERR) + // n = SendMessage(ctrl, CB_GETITEMDATA, n, 0); + if (n != CB_ERR) + return n; + else + return D3DADAPTER_DEFAULT; +} + +void CPluginShell::SaveDisplayMode() +{ + //if (m_fake_fullscreen_mode) + // return; + + // read 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) + m_disp_mode_fs = g_disp_mode[n]; + } +} + +void CPluginShell::SaveMultiSamp(int screenmode) +{ + HWND ctrl; + switch(screenmode) + { + case FULLSCREEN: ctrl = GetDlgItem(g_subwnd, IDC_FSMS); break; + case WINDOWED: ctrl = GetDlgItem(g_subwnd, IDC_WMS); break; + //case FAKE_FULLSCREEN: ctrl = GetDlgItem(g_subwnd, IDC_FFSMS); break; + case DESKTOP: ctrl = GetDlgItem(g_subwnd, IDC_DMSMS); break; + } + + // if page tearing is disabled, then multisampling must be disabled, + // so ignore multisample selection + if (g_subwnd && g_nTab==0) + { + if (screenmode == WINDOWED && !m_allow_page_tearing_w) + return; + if (screenmode == DESKTOP && !m_allow_page_tearing_dm) + return; + if (screenmode == FULLSCREEN && m_fake_fullscreen_mode && !m_allow_page_tearing_fs) + return; + } + + // read windowed & fullscreen multisampling settings: + int n = SendMessage(ctrl , CB_GETCURSEL, 0, 0); + if (n != CB_ERR) + { + n = SendMessage( ctrl, CB_GETITEMDATA, n, 0); + if (n != CB_ERR) + { + switch(screenmode) + { + case FULLSCREEN: m_multisample_fullscreen = (D3DMULTISAMPLE_TYPE)n; break; + case WINDOWED: m_multisample_windowed = (D3DMULTISAMPLE_TYPE)n; break; + //case FAKE_FULLSCREEN: m_multisample_fake_fullscreen = (D3DMULTISAMPLE_TYPE)n; break; + case DESKTOP: m_multisample_desktop = (D3DMULTISAMPLE_TYPE)n; break; + } + } + } +} + +void CPluginShell::SaveMaxFps(int screenmode) +{ + HWND ctrl; + switch(screenmode) + { + case FULLSCREEN: ctrl = GetDlgItem(g_subwnd, IDC_FS_MAXFPS); break; + case WINDOWED: ctrl = GetDlgItem(g_subwnd, IDC_W_MAXFPS); break; + //case FAKE_FULLSCREEN: ctrl = GetDlgItem(g_subwnd, IDC_FFS_MAXFPS); break; + case DESKTOP: ctrl = GetDlgItem(g_subwnd, IDC_DMS_MAXFPS); break; + } + + // read max fps settings + int n = SendMessage(ctrl, CB_GETCURSEL, 0, 0); + if (n != CB_ERR) + { + if (n > 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/Src/Plugins/Visualization/vis_milk2/config2.cpp b/Src/Plugins/Visualization/vis_milk2/config2.cpp new file mode 100644 index 00000000..ce4abb10 --- /dev/null +++ b/Src/Plugins/Visualization/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__vis_milk2.h" +#include "pluginshell.h" +#include "resource.h" +#include "utility.h" +#include <strsafe.h> + +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; i<nMax; i++) + { + wchar_t buf[256]; + int s = g_nFontSize[nMax-1 - i]; + StringCbPrintfW(buf, sizeof(buf), L" %2d ", s); + SendMessageW(sizebox, CB_ADDSTRING, i, (LPARAM)buf); + if (s == fi->nSize) + 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/Src/Plugins/Visualization/vis_milk2/defines.h b/Src/Plugins/Visualization/vis_milk2/defines.h new file mode 100644 index 00000000..b7283f41 --- /dev/null +++ b/Src/Plugins/Visualization/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.25d" // appears at bottom of config panel +#define LONGNAMEW L"MilkDrop v2.25d" // 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.geisswerks.com/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-2023 Winamp SA" + +// 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/Src/Plugins/Visualization/vis_milk2/desktop_mode.cpp b/Src/Plugins/Visualization/vis_milk2/desktop_mode.cpp new file mode 100644 index 00000000..6b66f3c5 --- /dev/null +++ b/Src/Plugins/Visualization/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__vis_milk2.h" +#include "pluginshell.h" +#include "resource.h" +#include "utility.h" +#include "defines.h" +#include <shellapi.h> + +//---------------------------------------------------------------------- + +#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; i<MAX_ICON_TEXTURES; i++) + SafeRelease(m_desktop_icons_texture[i]); + SafeRelease(m_d3dx_desktop_font); + + if (m_desktop_wc_registered) + { + UnregisterClass(DESKTOP_MODE_KEYBOARD_INPUT_WINDOW_CLASSNAME, m_hInstance); + m_desktop_wc_registered = 0; + } + + if (m_font_desktop) + { + DeleteObject(m_font_desktop); + m_font_desktop = 0; + } + + m_icon_list.clear(); + + DeleteCriticalSection(&m_desktop_cs); + + if (m_vms_desktop_loaded) + { + char szVmsDesktopDll[MAX_PATH]; + sprintf(szVmsDesktopDll, "%s%s", GetPluginsDirPath(), VMS_DESKTOP_DLLNAME); + FreeLibrary(GetModuleHandle(szVmsDesktopDll)); + m_vms_desktop_loaded = 0; + } +} + +//---------------------------------------------------------------------- + +int CPluginShell::CreateDesktopIconTexture(IDirect3DTexture9** ppTex) +{ + // release old texture (shouldn't really be necessary) + if (*ppTex) + { + (*ppTex)->Release(); + *ppTex = NULL; + } + + // create new + int ntries = (m_lpDX->m_d3dpp.BackBufferFormat == D3DFMT_R5G6B5) ? 3 : 1; + for (int ntry=0; ntry<ntries; ntry++) + { + D3DFORMAT fmt = m_lpDX->m_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<h; y++) + for (int x=0; x<w; x++) + { + int in_offset = ((h-1-y)*w + x)*4; + int r = data[in_offset+2]; + int g = data[in_offset+1]; + int b = data[in_offset+0]; + + checksum[0] += r; + checksum[1] += g; + checksum[2] += b; + + int out_offset = (y0+y)*WIDTH + (x0+x); + if (bpp==16) + p16[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 + 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; y<h; y++) + for (int x=0; x<w; x++) + { + int in_offset = ((h-1-y)*w + x)*4; + int r = data[in_offset+2]; + int g = data[in_offset+1]; + int b = data[in_offset+0]; + + checksum[0] += r; + checksum[1] += g; + checksum[2] += b; + + if (r || g || b) + { + int out_offset = (y0+y)*WIDTH + (x0+x); + if (bpp==16) + p16[out_offset] &= ~start; + else + p32[out_offset] &= ~start; + } + } + } + else + { + if (*show_msgs) + MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_UPDATING_ICON_BITMAPS_CALL_2_TO_GETDIBITS_FAILED), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + *show_msgs = 0; + } + + // check for duplicate icon, and if found, reuse it + int done = 0; + IconList::iterator q; + for (q = m_icon_list.begin(); q != m_icon_list.end() && q != p; q++) + { + if (checksum[0] == q->checksum[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<unsigned long>(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; pass<nPasses; pass++) + { + // first, draw [blue backgrounds &] text labels + { + m_lpDX->m_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/Src/Plugins/Visualization/vis_milk2/dxcontext.cpp b/Src/Plugins/Visualization/vis_milk2/dxcontext.cpp new file mode 100644 index 00000000..6744a645 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/dxcontext.cpp @@ -0,0 +1,1419 @@ +/* + 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__vis_milk2.h" +#include "DXContext.h" +#include "utility.h" +#include "shell_defines.h" +#include "resource.h" +#define COMPILE_MULTIMON_STUBS 1 +#include <multimon.h> +#include <strsafe.h> + +// 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<MAX_DXC_ADAPTERS; i++) + m_orig_windowed_mode_format[i] = D3DFMT_UNKNOWN; + m_ordinal_adapter = D3DADAPTER_DEFAULT; + m_ignore_wm_destroy = 0; + m_hwnd_winamp = hWndWinamp; + m_minimize_winamp = minimize_winamp; + m_winamp_minimized = 0; + m_truly_exiting = 0; + m_bpp = 0; + m_frame_delay = 0; + StringCbCopyW(m_szIniFile, sizeof(m_szIniFile), szIniFile); + memset(&myWindowState,0,sizeof(myWindowState)); + m_szDriver[0] = 0; + m_szDesc[0] = 0; + + WNDCLASSW wc = {0}; + + // clear the error register + + m_lastErr = S_OK; + + // clear the active flag + + m_ready=FALSE; + + // Set up and register window class + + wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; // CS_DBLCLKS lets the window receive WM_LBUTTONDBLCLK, for toggling fullscreen mode... + wc.lpfnWndProc = (WNDPROC) pProc; + wc.cbWndExtra = sizeof(DWORD); + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PLUGIN_ICON));//NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = szClassName; + m_classAtom = RegisterClassW(&wc); + if (!m_classAtom) + { + wchar_t title[64]; + int y = GetLastError(); + m_lastErr = DXC_ERR_REGWIN; + MessageBoxW(m_hwnd, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_REGISTER_WINDOW_CLASS), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + Internal_CleanUp(); + return; + } + + StringCbCopy(m_szWindowCaption, sizeof(m_szWindowCaption), szWindowCaption); + m_hInstance = hInstance; + m_uWindowLong = uWindowLong; +} + +DXContext::~DXContext() +{ + Internal_CleanUp(); +} + +void DXContext::Internal_CleanUp() +{ + // clear active flag + m_ready=FALSE; + + // release 3D interfaces + SafeRelease(m_lpDevice); + SafeRelease(m_lpD3D); + + // destroy the window + if (m_truly_exiting) + { + // somebody else will destroy the window for us! + m_hwnd = NULL; + if (m_hmod_d3d9) + { + FreeLibrary(m_hmod_d3d9); + m_hmod_d3d9 = NULL; + } + + if (m_hmod_d3dx9) + { + m_hmod_d3dx9 = NULL; + } + } + + if (myWindowState.me) + { + DestroyWindow(myWindowState.me); + myWindowState.me = NULL; + m_hwnd = NULL; + } + else if (m_hwnd) + { + DestroyWindow(m_hwnd); + m_hwnd = NULL; + } + + // unregister window class. note: only works if window is already destroyed! + if (m_classAtom) + { + UnregisterClass(MAKEINTATOM(m_classAtom), m_hInstance); + m_classAtom = 0; + } + + RestoreWinamp(); +} + +void DXContext::GetSnappedClientSize() +{ + // Call this whenever you set m_REAL_client_width/height while in windowed mode, + // to compute an appropriate (oversized) internal canvas size. At the end of each + // frame, for display, the canvas will be centered & cropped. + m_client_width = m_REAL_client_width; + m_client_height = m_REAL_client_height; +#if (SNAP_WINDOWED_MODE_BLOCKSIZE >= 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; i<nCount; i++) + if (m_lpD3D->EnumAdapterModes(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 (int i=0; i<nValid && !found; i++) + { + bool bMatch = true; + + int bpp_this_mode = 0; + switch (list[i].Format) + { + case D3DFMT_R8G8B8 : bpp_this_mode = 32; break; + case D3DFMT_A8R8G8B8: bpp_this_mode = 32; break; + case D3DFMT_X8R8G8B8: bpp_this_mode = 32; break; + case D3DFMT_R5G6B5 : bpp_this_mode = 16; break; + case D3DFMT_X1R5G5B5: bpp_this_mode = 16; break; + case D3DFMT_A1R5G5B5: bpp_this_mode = 16; break; + case D3DFMT_A4R4G4B4: bpp_this_mode = 16; break; + case D3DFMT_R3G3B2 : bpp_this_mode = 8; break; + case D3DFMT_A8R3G3B2: bpp_this_mode = 16; break; + case D3DFMT_X4R4G4B4: bpp_this_mode = 16; break; + } + + if (rep < 4) + { + if (pdm->Width != 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; i<nAdapters; i++) + { + if ((m_lpD3D->GetAdapterIdentifier(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; i<min(nAdapters, MAX_DXC_ADAPTERS); i++) + { + // if this is the first call to Init, get the display mode's original color format, + // before we go changing it: + D3DDISPLAYMODE d3ddm; + if (FAILED(m_lpD3D->GetAdapterDisplayMode(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 + windowed_mode_desired_client_rect.left, // left + windowed_mode_desired_client_rect.top, // top + windowed_mode_desired_client_rect.right - windowed_mode_desired_client_rect.left, // temporary width + windowed_mode_desired_client_rect.bottom - windowed_mode_desired_client_rect.top, // 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_hwnd == NULL ) + return; + + + 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/Src/Plugins/Visualization/vis_milk2/dxcontext.h b/Src/Plugins/Visualization/vis_milk2/dxcontext.h new file mode 100644 index 00000000..15076f9c --- /dev/null +++ b/Src/Plugins/Visualization/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 <windows.h> +#include "shell_defines.h" + +#ifdef _DEBUG + #define D3D_DEBUG_INFO // declare this before including d3d9.h +#endif +#include <d3d9.h> +#include <d3dx9.h> + +#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/Src/Plugins/Visualization/vis_milk2/fft.cpp b/Src/Plugins/Visualization/vis_milk2/fft.cpp new file mode 100644 index 00000000..7c0a5129 --- /dev/null +++ b/Src/Plugins/Visualization/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 <math.h> +#include <memory.h> +#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<NFREQ/2; i++) + equalize[i] = scaling * logf( (float)(NFREQ/2-i)*inv_half_nfreq ); +} + +/*****************************************************************************/ + +void FFT::InitEnvelopeTable(float power) +{ + // this precomputation is for multiplying the waveform sample + // by a bell-curve-shaped envelope, so we don't see the ugly + // frequency response (oscillations) of a square filter. + + // a power of 1.0 will compute the FFT with exactly one convolution. + // a power of 2.0 is like doing it twice; the resulting frequency + // output will be smoothed out and the peaks will be "fatter". + // a power of 0.5 is closer to not using an envelope, and you start + // to get the frequency response of the square filter as 'power' + // approaches zero; the peaks get tighter and more precise, but + // you also see small oscillations around their bases. + + int i; + float mult = 1.0f/(float)m_samples_in * 6.2831853f; + + envelope = new float[m_samples_in]; + + if (power==1.0f) + for (i=0; i<m_samples_in; i++) + envelope[i] = 0.5f + 0.5f*sinf(i*mult - 1.5707963268f); + else + for (i=0; i<m_samples_in; i++) + envelope[i] = powf(0.5f + 0.5f*sinf(i*mult - 1.5707963268f), power); +} + +/*****************************************************************************/ + +void FFT::InitBitRevTable() +{ + int i,j,m,temp; + bitrevtable = new int[NFREQ]; + + for (i=0; i<NFREQ; i++) + bitrevtable[i] = i; + + for (i=0,j=0; i < NFREQ; i++) + { + if (j > 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<NFREQ; i++) + { + int idx = bitrevtable[i]; + if (idx < m_samples_in) + temp1[i] = in_wavedata[idx] * envelope[idx]; + else + temp1[i] = 0; + } + } + else + { + for (i=0; i<NFREQ; i++) + { + int idx = bitrevtable[i]; + if (idx < m_samples_in) + temp1[i] = in_wavedata[idx];// * envelope[idx]; + else + temp1[i] = 0; + } + } + memset(temp2, 0, sizeof(float)*NFREQ); + + // 2. perform FFT + float *real = temp1; + float *imag = temp2; + dftsize = 2; + t = 0; + while (dftsize <= NFREQ) + { + wpr = cossintable[t][0]; + wpi = cossintable[t][1]; + wr = 1.0f; + wi = 0.0f; + hdftsize = dftsize >> 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<NFREQ/2; i++) + out_spectraldata[i] = equalize[i] * sqrtf(temp1[i]*temp1[i] + temp2[i]*temp2[i]); + else + for (i=0; i<NFREQ/2; i++) + out_spectraldata[i] = sqrtf(temp1[i]*temp1[i] + temp2[i]*temp2[i]); +} + +/*****************************************************************************/
\ No newline at end of file diff --git a/Src/Plugins/Visualization/vis_milk2/fft.h b/Src/Plugins/Visualization/vis_milk2/fft.h new file mode 100644 index 00000000..5484b336 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/fft.h @@ -0,0 +1,60 @@ +/* + 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_FFT_H__ +#define __NULLSOFT_DX9_PLUGIN_SHELL_FFT_H__ 1 + +class FFT +{ +public: + FFT(); + ~FFT(); + void Init(int samples_in, int samples_out, int bEqualize=1, float envelope_power=1.0f); + void time_to_frequency_domain(float *in_wavedata, float *out_spectraldata); + int GetNumFreq() { return NFREQ; }; + void CleanUp(); +private: + int m_ready; + int m_samples_in; + int NFREQ; + + void InitEnvelopeTable(float power); + void InitEqualizeTable(); + void InitBitRevTable(); + void InitCosSinTable(); + + int *bitrevtable; + float *envelope; + float *equalize; + float *temp1; + float *temp2; + float (*cossintable)[2]; +}; + +#endif
\ No newline at end of file diff --git a/Src/Plugins/Visualization/vis_milk2/gstring.h b/Src/Plugins/Visualization/vis_milk2/gstring.h new file mode 100644 index 00000000..c7134645 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/gstring.h @@ -0,0 +1,229 @@ +#ifndef __GSTRING_SMART_STRING_CLASS__ +#define __GSTRING_SMART_STRING_CLASS__ 1 + +// This is just a streamlined version of std::string. +// It cleans itself up automatically, it can copy itself, +// test for equality, etc. +// and you can use .c_str() to get the string const, so it's +// sytactically the same (usage-wise) as std::string. +// Written by Ryan Geiss. + +#include <windows.h> + +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/Src/Plugins/Visualization/vis_milk2/icon_t.h b/Src/Plugins/Visualization/vis_milk2/icon_t.h new file mode 100644 index 00000000..c1f6e90f --- /dev/null +++ b/Src/Plugins/Visualization/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 <windows.h> +#include <shlobj.h> // 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/Src/Plugins/Visualization/vis_milk2/manifest.xml b/Src/Plugins/Visualization/vis_milk2/manifest.xml new file mode 100644 index 00000000..5f91bfcc --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/manifest.xml @@ -0,0 +1 @@ +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><description>Nullsoft Winamp Milkdrop 2 (So You Don't Have To Keep Hacking The Plug-in Dll</description><dependency><dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity></dependentAssembly></dependency></assembly>
\ No newline at end of file diff --git a/Src/Plugins/Visualization/vis_milk2/md_defines.h b/Src/Plugins/Visualization/vis_milk2/md_defines.h new file mode 100644 index 00000000..36003231 --- /dev/null +++ b/Src/Plugins/Visualization/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/Src/Plugins/Visualization/vis_milk2/menu.cpp b/Src/Plugins/Visualization/vis_milk2/menu.cpp new file mode 100644 index 00000000..be632314 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/menu.cpp @@ -0,0 +1,751 @@ +/* + 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__vis_milk2.h" +#include "state.h" // for CBlendableFloat - fix this +#include "menu.h" +#include "plugin.h" +#include <stdio.h> +#include <math.h> +#include <assert.h> +#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 && i<j) + { + pChild = pChild->m_pNext; + i++; + } + if (pChild) + return pChild->m_bEnabled; + + return false; +} + +//---------------------------------------- + +void CMilkMenu::EnableItem(wchar_t* szName, bool bEnable) +{ + //search submenus + int i = 0; + for (i=0; i<m_nChildMenus; i++) { + if (!wcscmp(m_ppChildMenu[i]->GetName(), 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; i<MAX_CHILD_MENUS; i++) + m_ppChildMenu[i] = NULL; + m_pFirstChildItem = NULL; + WASABI_API_LNGSTRINGW_BUF(IDS_UNTITLED_MENU,m_szMenuName,64); + m_nChildMenus = 0; + m_nChildItems = 0; + m_nCurSel = 0; + m_bEditingCurSel = false; + m_bEnabled = true; +} + +//---------------------------------------- + +void CMilkMenu::Init(wchar_t *szName) +{ + Reset(); + if (szName && szName[0]) + wcsncpy(m_szMenuName, szName, 64); +} + +void CMilkMenu::Finish() +{ + if (m_pFirstChildItem) + { + delete m_pFirstChildItem; + m_pFirstChildItem = NULL; + } +} + +//---------------------------------------- + +void CMilkMenu::AddChildMenu(CMilkMenu *pMenu) +{ + if (m_nChildMenus < MAX_CHILD_MENUS) + { + m_ppChildMenu[m_nChildMenus++] = pMenu; + pMenu->SetParentPointer(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; + int i = 0; + for (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<nRepeat; rep++) + { + if (m_nCurSel==0) + break; + do { + m_nCurSel--; + } while (m_nCurSel > 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<nRepeat; rep++) + { + if (m_nCurSel == m_nChildMenus + m_nChildItems - 1) + break; + do { + m_nCurSel++; + } while (m_nCurSel < m_nChildMenus + m_nChildItems - 1 && !ItemIsEnabled(m_nCurSel)); + } + if (m_nCurSel >= 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/Src/Plugins/Visualization/vis_milk2/menu.h b/Src/Plugins/Visualization/vis_milk2/menu.h new file mode 100644 index 00000000..2668032e --- /dev/null +++ b/Src/Plugins/Visualization/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 <windows.h> + +//---------------------------------------- + +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/Src/Plugins/Visualization/vis_milk2/milkdrop.nsi b/Src/Plugins/Visualization/vis_milk2/milkdrop.nsi new file mode 100644 index 00000000..c10333e6 --- /dev/null +++ b/Src/Plugins/Visualization/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/Src/Plugins/Visualization/vis_milk2/milkdrop_DX9.dsw b/Src/Plugins/Visualization/vis_milk2/milkdrop_DX9.dsw new file mode 100644 index 00000000..b5ebf318 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/milkdrop_DX9.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "plugin"=.\plugin.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Src/Plugins/Visualization/vis_milk2/milkdrop_DX9.sln b/Src/Plugins/Visualization/vis_milk2/milkdrop_DX9.sln new file mode 100644 index 00000000..e123bc29 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/milkdrop_DX9.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29709.97 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vis_milk2", "plugin.vcxproj", "{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 + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0BFB0275-73AE-400C-9070-5C0471284DD5} + EndGlobalSection +EndGlobal diff --git a/Src/Plugins/Visualization/vis_milk2/milkdropfs.cpp b/Src/Plugins/Visualization/vis_milk2/milkdropfs.cpp new file mode 100644 index 00000000..600f7202 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/milkdropfs.cpp @@ -0,0 +1,4801 @@ +/* + 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__vis_milk2.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 <assert.h> +#include <math.h> + +#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 <multimon.h> + +// 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; vi<NUM_Q_VAR; vi++) + *pState->var_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; rep<num_reps; rep++) + { + CState *pState; + + if (rep==0) + pState = m_pState; + else + pState = m_pOldState; + + // values that will affect the pixel motion (and will be automatically blended + // LATER, when the results of 2 sets of these params creates 2 different U/V + // meshes that get blended together.) + LoadPerFrameEvallibVars(pState); + + // also do just a once-per-frame init for the *per-**VERTEX*** *READ-ONLY* variables + // (the non-read-only ones will be reset/restored at the start of each vertex) + *pState->var_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; vi<NUM_Q_VAR; vi++) + *pState->var_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<nY; y++) + { + float fy = (y + 0.25f)/(float)(nY + dy + 0.25f - 1.0f); + + // now move by offset + fy -= dy2; + + if (fy > 0.0001f && fy < 0.9999f) + { + int n = 0; + for (x=0; x<nX; x++) + { + //float fx = (x + 0.25f)/(float)(nX + dx + 0.25f - 1.0f); + float fx = (x + 0.25f)/(float)(nX + dx + 0.25f - 1.0f); + + // now move by offset + fx += dx2; + + if (fx > 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, "<couldn't get song title>"); + } + } + + 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 (int i=0; i<passes; i++) + { + // hook up correct render target + if (m_lpBlur[i]->GetSurfaceLevel(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; rep<num_reps; rep++) + { + // to blend the two PV equations together, we simulate both to get the final UV coords, + // then we blend those final UV coords. We also write out an alpha value so that + // the second DRAW pass below (which might use a different shader) can do blending. + CState *pState; + + if (rep==0) + pState = m_pState; + else + pState = m_pOldState; + + // cache the doubles as floats so that computations are a bit faster + float fZoom = (float)(*pState->var_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; strip<m_nGridY*2; strip++) + { + int index = strip * (m_nGridX+2); + + for (poly=0; poly<m_nGridX+2; poly++) + { + int ref_vert = m_indices_strip[index]; + m_verts_temp[poly].x = m_verts[ref_vert].x; + m_verts_temp[poly].y = -m_verts[ref_vert].y; + m_verts_temp[poly].z = m_verts[ref_vert].z; + m_verts_temp[poly].tu = m_verts[ref_vert].tu; + m_verts_temp[poly].tv = m_verts[ref_vert].tv; + //m_verts_temp[poly].Diffuse = cDecay; this is done just once - see jsut above + index++; + } + lpDevice->DrawPrimitiveUP(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<m_nGridY; y++) + { + // copy verts & flip sign on Y + int ref_vert = y*(m_nGridX+1); + for (int i=0; i<(m_nGridX+1)*2; i++) + { + m_verts_temp[i].x = m_verts[ref_vert].x; + m_verts_temp[i].y = -m_verts[ref_vert].y; + m_verts_temp[i].z = m_verts[ref_vert].z; + m_verts_temp[i].tu = m_verts[ref_vert].tu; + m_verts_temp[i].tv = m_verts[ref_vert].tv; + m_verts_temp[i].Diffuse = (cDecay & 0x00FFFFFF) | (m_verts[ref_vert].Diffuse & 0xFF000000); + ref_vert++; + } + + // create (smart) indices + int count = 0; + int nVert = 0; + bool bWasNeeded; + ref_vert = (y)*(m_nGridX+1); + DWORD d1 = (m_verts[ref_vert ].Diffuse >> 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<m_nGridX; i++) + { + bool bIsNeeded; + DWORD d1 = (m_verts[ref_vert+1 ].Diffuse >> 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<m_nGridX/2; x++) + m_verts[y_offset + x].ang = new_ang; + + // send half of the polys + int primCount = m_nGridX*m_nGridY*2 / 2; // in this case, to draw HALF the polys + int src_idx = 0; + int src_idx_offset = half * primCount*3; + 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_offset + 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::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; rep<num_reps; rep++) + { + CState *pState = (rep==0) ? m_pState : m_pOldState; + float alpha_mult = 1; + if (num_reps==2) + alpha_mult = (rep==0) ? m_pState->m_fBlendProgress : (1-m_pState->m_fBlendProgress); + + for (int i=0; i<MAX_CUSTOM_SHAPES; i++) + { + if (pState->m_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; instance<pState->m_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) ); + + int j = 1; + for (j=1; j<sides+1; j++) + { + float t = (j-1)/(float)sides; + v[j].x = v[0].x + (float)*pState->m_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; 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 = v2[0].Diffuse; + } + + int its = ((int)(*pState->m_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; it<its; it++) + { + switch(it) + { + case 0: break; + case 1: for (j=0; j<sides+2; j++) v2[j].x += x_inc; break; // draw fat dots + case 2: for (j=0; j<sides+2; j++) v2[j].y += y_inc; break; // draw fat dots + case 3: for (j=0; j<sides+2; j++) v2[j].x -= x_inc; break; // draw fat dots + } + lpDevice->DrawPrimitiveUP(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]; + int vi = 0; + for (vi=0; vi<NUM_Q_VAR; vi++) + *pState->m_shape[i].var_pf_q[vi] = *pState->var_pf_q[vi]; + for (vi=0; vi<NUM_T_VAR; vi++) + *pState->m_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]; + int vi = 0; + for (vi=0; vi<NUM_Q_VAR; vi++) + *pState->m_wave[i].var_pf_q[vi] = *pState->var_pf_q[vi]; + for (vi=0; vi<NUM_T_VAR; vi++) + *pState->m_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; i<nVertsIn-1; i++) + { + i_above = i_above2; + i_above2 = min(nVertsIn-1,i+2); + vo[j] = vi[i]; + vo[j+1].x = (c1*vi[i_below].x + c2*vi[i].x + c3*vi[i_above].x + c4*vi[i_above2].x)*inv_sum; + vo[j+1].y = (c1*vi[i_below].y + c2*vi[i].y + c3*vi[i_above].y + c4*vi[i_above2].y)*inv_sum; + vo[j+1].z = 0; + vo[j+1].Diffuse = vi[i].Diffuse;//0xFFFF0080; + i_below = i; + j += 2; + } + vo[j++] = vi[nVertsIn-1]; + + return j; +} + +void CPlugin::DrawCustomWaves() +{ + LPDIRECT3DDEVICE9 lpDevice = GetDevice(); + if (!lpDevice) + return; + + lpDevice->SetTexture(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; rep<num_reps; rep++) + { + CState *pState = (rep==0) ? m_pState : m_pOldState; + float alpha_mult = 1; + if (num_reps==2) + alpha_mult = (rep==0) ? m_pState->m_fBlendProgress : (1-m_pState->m_fBlendProgress); + + for (int i=0; i<MAX_CUSTOM_WAVES; i++) + { + if (pState->m_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); + int vi = 0; + for (vi=0; vi<NUM_Q_VAR; vi++) + *pState->m_wave[i].var_pp_q[vi] = *pState->m_wave[i].var_pf_q[vi]; + for (vi=0; vi<NUM_T_VAR; vi++) + *pState->m_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<nSamples; j++) + { + tempdata[0][j] = pdata1[(int)(j*t)+j0]*mix2 + tempdata[0][j-1]*mix1; + tempdata[1][j] = pdata2[(int)(j*t)+j1]*mix2 + tempdata[1][j-1]*mix1; + } + // smooth again, backwards: [this fixes the asymmetry of the beginning & end..] + for (j=nSamples-2; 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; j<nSamples; j++) + { + tempdata[0][j] *= mult; + tempdata[1][j] *= mult; + } + + // 2. for each point, execute per-point code + + + // to do: + // -add any of the m_wave[i].xxx menu-accessible vars to the code? + WFVERTEX v[1024]; + float j_mult = 1.0f/(float)(nSamples-1); + for (j=0; j<nSamples; j++) + { + float t = j*j_mult; + float value1 = tempdata[0][j]; + float value2 = tempdata[1][j]; + *pState->m_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; it<its; it++) + { + switch(it) + { + case 0: break; + case 1: for (j=0; j<nSamples; j++) pVerts[j].x += x_inc; break; // draw fat dots + case 2: for (j=0; j<nSamples; j++) pVerts[j].y += y_inc; break; // draw fat dots + case 3: for (j=0; j<nSamples; j++) pVerts[j].x -= x_inc; break; // draw fat dots + } + lpDevice->DrawPrimitiveUP(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; it<its; it++) + { + int wave = (it==0) ? new_wavemode : m_pState->m_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; i<nVerts; i++) + { + float rad = 0.5f + 0.4f*fR[i+sample_offset] + fWaveParam2; + float ang = (i)*inv_nverts_minus_one*6.28f + GetTime()*0.2f; + if (i < nVerts/10) + { + float mix = i/(nVerts*0.1f); + mix = 0.5f - 0.5f*cosf(mix * 3.1416f); + float rad_2 = 0.5f + 0.4f*fR[i + nVerts + sample_offset] + fWaveParam2; + rad = rad_2*(1.0f-mix) + rad*(mix); + } + v[i].x = rad*cosf(ang) *m_fAspectY + fWavePosX; // 0.75 = adj. for aspect ratio + v[i].y = rad*sinf(ang) *m_fAspectX + fWavePosY; + //v[i].Diffuse = color; + } + } + + // dupe last vertex to connect the lines; skip if blending + if (!m_pState->m_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; i<nVerts; i++) + { + float rad = 0.53f + 0.43f*fR[i] + fWaveParam2; + float ang = fL[i+32] * 1.57f + GetTime()*2.3f; + v[i].x = rad*cosf(ang) *m_fAspectY + fWavePosX; // 0.75 = adj. for aspect ratio + v[i].y = rad*sinf(ang) *m_fAspectX + fWavePosY; + //v[i].Diffuse = color;//(D3DCOLOR_RGBA_01(cr, cg, cb, alpha*min(1, max(0, fL[i]))); + } + + break; + + case 2: + // centered spiro (alpha constant) + // aimed at not being so sound-responsive, but being very "nebula-like" + // difference is that alpha is constant (and faint), and waves a scaled way up + + switch(m_nTexSizeX) + { + case 256: alpha *= 0.07f; break; + case 512: alpha *= 0.09f; break; + case 1024: alpha *= 0.11f; break; + case 2048: alpha *= 0.13f; break; + } + + 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); + + for (i=0; i<nVerts; i++) + { + v[i].x = fR[i ] *m_fAspectY + fWavePosX;//((pR[i] ^ 128) - 128)/90.0f * ASPECT; // 0.75 = adj. for aspect ratio + v[i].y = fL[i+32] *m_fAspectX + fWavePosY;//((pL[i+32] ^ 128) - 128)/90.0f; + //v[i].Diffuse = color; + } + + break; + case 3: + // centered spiro (alpha tied to volume) + // aimed at having a strong audio-visual tie-in + // colors are always bright (no darks) + + switch(m_nTexSizeX) + { + case 256: alpha = 0.075f; break; + case 512: alpha = 0.150f; break; + case 1024: alpha = 0.220f; break; + case 2048: alpha = 0.330f; break; + } + + alpha *= 1.3f; + alpha *= powf(treble_rel, 2.0f); + 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); + + for (i=0; i<nVerts; i++) + { + v[i].x = fR[i ] *m_fAspectY + fWavePosX;//((pR[i] ^ 128) - 128)/90.0f * ASPECT; // 0.75 = adj. for aspect ratio + v[i].y = fL[i+32] *m_fAspectX + fWavePosY;//((pL[i+32] ^ 128) - 128)/90.0f; + //v[i].Diffuse = color; + } + break; + case 4: + // horizontal "script", left channel + + if (nVerts > 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; i<nVerts; i++) + { + v[i].x = -1.0f + 2.0f*(i*inv_nverts) + fWavePosX; + v[i].y = fL[i+sample_offset]*0.47f + fWavePosY;//((pL[i] ^ 128) - 128)/270.0f; + v[i].x += fR[i+25+sample_offset]*0.44f;//((pR[i+25] ^ 128) - 128)/290.0f; + //v[i].Diffuse = color; + + // momentum + if (i>1) + { + 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; i<nVerts; i++) + avg_y += v[i].y; + avg_y /= (float)nVerts; + avg_y *= 0.5f; // damp the movement + for (i=0; i<nVerts; i++) + v[i].y -= avg_y; + */ + } + + break; + + case 5: + // weird explosive complex # thingy + + switch(m_nTexSizeX) + { + case 256: alpha *= 0.07f; break; + case 512: alpha *= 0.09f; break; + case 1024: alpha *= 0.11f; break; + case 2048: alpha *= 0.13f; break; + } + + 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 cos_rot = cosf(GetTime()*0.3f); + float sin_rot = sinf(GetTime()*0.3f); + + for (i=0; i<nVerts; i++) + { + float x0 = (fR[i]*fL[i+32] + fL[i]*fR[i+32]); + float y0 = (fR[i]*fR[i] - fL[i+32]*fL[i+32]); + v[i].x = (x0*cos_rot - y0*sin_rot)*m_fAspectY + fWavePosX; + v[i].y = (x0*sin_rot + y0*cos_rot)*m_fAspectX + fWavePosY; + //v[i].Diffuse = color; + } + } + + break; + + case 6: + case 7: + case 8: + // 6: angle-adjustable left channel, with temporal wave alignment; + // fWaveParam2 controls the angle at which it's drawn + // fWavePosX slides the wave away from the center, transversely. + // fWavePosY does nothing + // + // 7: same, except there are two channels shown, and + // fWavePosY determines the separation distance. + // + // 8: same as 6, except using the spectrum analyzer (UNFINISHED) + // + nVerts /= 2; + + if (nVerts > 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; i<nVerts; i++) + { + v[i].x = edge_x[0] + dx*i + perp_dx*0.25f*fL[i + sample_offset]; + v[i].y = edge_y[0] + dy*i + perp_dy*0.25f*fL[i + sample_offset]; + //v[i].Diffuse = color; + } + else if (wave == 8) + //256 verts + for (i=0; i<nVerts; i++) + { + float f = 0.1f*logf(mysound.fSpecLeft[i*2] + mysound.fSpecLeft[i*2+1]); + v[i].x = edge_x[0] + dx*i + perp_dx*f; + v[i].y = edge_y[0] + dy*i + perp_dy*f; + //v[i].Diffuse = color; + } + else + { + float sep = powf(fWavePosY*0.5f + 0.5f, 2.0f); + for (i=0; i<nVerts; i++) + { + v[i].x = edge_x[0] + dx*i + perp_dx*(0.25f*fL[i + sample_offset] + sep); + v[i].y = edge_y[0] + dy*i + perp_dy*(0.25f*fL[i + sample_offset] + sep); + //v[i].Diffuse = color; + } + + //D3DPRIMITIVETYPE primtype = (*m_pState->var_pf_wave_usedots) ? D3DPT_POINTLIST : D3DPT_LINESTRIP; + //m_lpD3DDev->DrawPrimitive(primtype, D3DFVF_LVERTEX, (LPVOID)v, nVerts, NULL); + + for (i=0; i<nVerts; i++) + { + v[i+nVerts].x = edge_x[0] + dx*i + perp_dx*(0.25f*fR[i + sample_offset] - sep); + v[i+nVerts].y = edge_y[0] + dy*i + perp_dy*(0.25f*fR[i + sample_offset] - sep); + //v[i+nVerts].Diffuse = color; + } + + nBreak = nVerts; + nVerts *= 2; + } + } + + break; + } + + if (it==0) + { + nVerts1 = nVerts; + nBreak1 = nBreak; + alpha1 = alpha; + } + else + { + nVerts2 = nVerts; + nBreak2 = nBreak; + alpha2 = alpha; + } + } + + // v1[] is for the current waveform + // v2[] is for the old waveform (from prev. preset - only used if blending) + // nVerts1 is the # of vertices in v1 + // nVerts2 is the # of vertices in v2 + // nBreak1 is the index of the point at which to break the solid line in v1[] (-1 if no break) + // nBreak2 is the index of the point at which to break the solid line in v2[] (-1 if no break) + + float mix = CosineInterp(m_pState->m_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<nVerts1; i++) + { + float fIdx = i*m; + int nIdx = (int)fIdx; + float t = fIdx - nIdx; + if (nIdx == nBreak2-1) + { + x = v2[nIdx].x; + y = v2[nIdx].y; + nBreak1 = i+1; + } + else + { + x = v2[nIdx].x*(1-t) + v2[nIdx+1].x*(t); + y = v2[nIdx].y*(1-t) + v2[nIdx+1].y*(t); + } + v1[i].x = v1[i].x*(mix) + x*(mix2); + v1[i].y = v1[i].y*(mix) + y*(mix2); + } + } + + // determine alpha + if (nVerts2 > 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; i<nVerts1; i++) + { + v1[i].Diffuse = v1[0].Diffuse; + v1[i].y = -v1[i].y; + } + + // don't draw wave if (possibly blended) alpha is less than zero. + if (alpha1 < 0.004f) + goto SKIP_DRAW_WAVE; + + // TESSELLATE - smooth the wave, one time. + WFVERTEX* pVerts = v1; + WFVERTEX vTess[(576+3)*2]; + if (1) + { + if (nBreak1==-1) + { + nVerts1 = SmoothWave(v1, nVerts1, vTess); + } + else + { + int oldBreak = nBreak1; + nBreak1 = SmoothWave(v1, nBreak1, vTess); + nVerts1 = SmoothWave(&v1[oldBreak], nVerts1-oldBreak, &vTess[nBreak1]) + nBreak1; + } + pVerts = vTess; + } + + // draw primitives + { + //D3DPRIMITIVETYPE primtype = (*m_pState->var_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; it<drawing_its; it++) + { + int j; + + switch(it) + { + case 0: break; + case 1: for (j=0; j<nVerts1; j++) pVerts[j].x += x_inc; break; // draw fat dots + case 2: for (j=0; j<nVerts1; j++) pVerts[j].y += y_inc; break; // draw fat dots + case 3: for (j=0; j<nVerts1; j++) pVerts[j].x -= x_inc; break; // draw fat dots + } + + if (nBreak1 == -1) + { + if (*m_pState->var_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(); + int i = 0; + for (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 + int i = 0; + for (i=0; i<sizeof(p->m_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; i<N; i++) + { + TexSizeParamInfo* q = &(p->texsize_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; i<num_q_float4s; i++) + { + if (p->q_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 (int 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; j<FCGSY; j++) + { + for (int i=0; i<FCGSX; i++) + { + MYVERTEX* p = &m_comp_verts[i + j*FCGSX]; + float x = p->x*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/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-ppc-gcc.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-ppc-gcc.c new file mode 100644 index 00000000..19a09ba8 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-x64-macho.o b/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-x64-macho.o Binary files differnew file mode 100644 index 00000000..76e918ed --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-x64-macho.o diff --git a/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-x86-gcc.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-x86-gcc.c new file mode 100644 index 00000000..e7cd7e94 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-x86-msvc.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/asm-nseel-x86-msvc.c new file mode 100644 index 00000000..30c88c5c --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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/Src/Plugins/Visualization/vis_milk2/ns-eel2/ns-eel-addfuncs.h b/Src/Plugins/Visualization/vis_milk2/ns-eel2/ns-eel-addfuncs.h new file mode 100644 index 00000000..e653e0a1 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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/Src/Plugins/Visualization/vis_milk2/ns-eel2/ns-eel-int.h b/Src/Plugins/Visualization/vis_milk2/ns-eel2/ns-eel-int.h new file mode 100644 index 00000000..3718604a --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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 <windows.h> +#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/Src/Plugins/Visualization/vis_milk2/ns-eel2/ns-eel.h b/Src/Plugins/Visualization/vis_milk2/ns-eel2/ns-eel.h new file mode 100644 index 00000000..cb561377 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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 <stdlib.h> +#include <stdio.h> + +#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/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-caltab.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-caltab.c new file mode 100644 index 00000000..1d8a6d32 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-cfunc.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-cfunc.c new file mode 100644 index 00000000..57cb7c05 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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 <math.h> +#include <stdio.h> + + + +// 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<N; mti++) + { + mt[mti] = + (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 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<N-M;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + for (;kk<N-1;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+(M-N)] ^ (y >> 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/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-compiler.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-compiler.c new file mode 100644 index 00000000..da222179 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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 <string.h> +#include <math.h> +#include <stdio.h> +#include <ctype.h> + +#ifndef _WIN64 + #ifndef __ppc__ + #include <float.h> + #endif +#endif + +#ifdef __APPLE__ + #ifdef __LP64__ + #define EEL_USE_MPROTECT + #endif +#endif + +#ifdef EEL_USE_MPROTECT +#include <sys/mman.h> +#include <stdint.h> +#include <unistd.h> +#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 <fpu_control.h> +#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/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-eval.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-eval.c new file mode 100644 index 00000000..2dc1d063 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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 <string.h> +#include <ctype.h> +#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/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-lextab.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-lextab.c new file mode 100644 index 00000000..9d90b769 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-ram.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-ram.c new file mode 100644 index 00000000..d20dd449 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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 <math.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + + +#ifdef _WIN32 +#include <malloc.h> +#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/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-yylex.c b/Src/Plugins/Visualization/vis_milk2/ns-eel2/nseel-yylex.c new file mode 100644 index 00000000..605b4776 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/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; c<NBPW; c++) + if (l&(1<<c)) + ctx->llsave[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/Src/Plugins/Visualization/vis_milk2/plugin.cpp b/Src/Plugins/Visualization/vis_milk2/plugin.cpp new file mode 100644 index 00000000..e3d66a39 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/plugin.cpp @@ -0,0 +1,9653 @@ +/* + 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) + <AFTER BETA 3..> + 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 -<fixed major bug w/illegal mem access on song title launches; + could have been causing crashing madness @ startup on many systems> + d -<fixed bug w/saving 64x48 mesh size> + d -<fixed squashed shapes> + d -<fixed 'invert' variable> + d -<fixed squashed song titles + custom msgs> + ? -<might have fixed scroll lock stuff> + ? -<might have fixed crashing; could have been due to null ptr for failed creation of song title texture.> + ? -<also might have solved any remaining resize or exit bugs by callign SetTexture(NULL) + in DX8 cleanup.> + d -<fixed sizing issues with songtitle font.> + d -<fixed a potentially bogus call to deallocate memory on exit, when it was cleaning up the menus.> + d -<fixed more scroll lock issues> + d -<fixed broken Noughts & Crosses presets; max # of per-frame vars was one too few, after the additions of the new built-in variables.> + d -<hopefully fixed waveforms> + <AFTER BETA 4> + -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. + <AFTER BETA 6:> + -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. + <AFTER BETA 7:> + -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__vis_milk2.h" +#include "plugin.h" +#include "utility.h" +#include "support.h" +#include "resource.h" +#include "defines.h" +#include "shell_defines.h" +#include <assert.h> +#include <locale.h> +#include <process.h> // for beginthread, etc. +#include <shellapi.h> +#include <strsafe.h> +#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 = true; + //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; mash<MASH_SLOTS; mash++) + m_nLastMashChangeFrame[mash] = 0; + + //m_nTrackPlaying = 0; + //m_nSongPosMS = 0; + //m_nSongLenMS = 0; + m_bUserPagedUp = false; + m_bUserPagedDown = false; + m_fMotionVectorsTempDx = 0.0f; + m_fMotionVectorsTempDy = 0.0f; + + m_waitstring.bActive = false; + m_waitstring.bOvertypeMode = false; + m_waitstring.szClipboard[0] = 0; + + m_nPresets = 0; + m_nDirs = 0; + m_nPresetListCurPos = 0; + m_nCurrentPreset = -1; + m_szCurrentPresetFile[0] = 0; + m_szLoadingPreset[0] = 0; + //m_szPresetDir[0] = 0; // will be set @ end of this function + m_bPresetListReady = false; + m_szUpdatePresetMask[0] = 0; + //m_nRatingReadProgress = -1; + + myfft.Init(576, MY_FFT_SAMPLES, -1); + memset(&mysound, 0, sizeof(mysound)); + int i = 0; + for (i=0; i<PRESET_HIST_LEN; i++) + m_presetHistory[i] = L""; + m_presetHistoryPos = 0; + m_presetHistoryBackFence = 0; + m_presetHistoryFwdFence = 0; + + //m_nTextHeightPixels = -1; + //m_nTextHeightPixels_Fancy = -1; + m_bShowFPS = false; + m_bShowRating = false; + m_bShowPresetInfo = false; + m_bShowDebugInfo = false; + m_bShowSongTitle = false; + m_bShowSongTime = false; + m_bShowSongLen = false; + m_fShowRatingUntilThisTime = -1.0f; + ClearErrors(); + m_szDebugMessage[0] = 0; + m_szSongTitle[0] = 0; + m_szSongTitlePrev[0] = 0; + + m_lpVS[0] = NULL; + m_lpVS[1] = NULL; + #if (NUM_BLUR_TEX>0) + for (i=0; i<NUM_BLUR_TEX; i++) + m_lpBlur[i] = NULL; + #endif + m_lpDDSTitle = NULL; + m_nTitleTexSizeX = 0; + m_nTitleTexSizeY = 0; + m_verts = NULL; + m_verts_temp = NULL; + m_vertinfo = NULL; + m_indices_list = NULL; + m_indices_strip = NULL; + + m_bMMX = false; + m_bHasFocus = true; + m_bHadFocus = false; + m_bOrigScrollLockState = GetKeyState(VK_SCROLL) & 1; + // m_bMilkdropScrollLockState is derived at end of MyReadConfig() + + m_nNumericInputMode = NUMERIC_INPUT_MODE_CUST_MSG; + m_nNumericInputNum = 0; + m_nNumericInputDigits = 0; + //td_custom_msg_font m_CustomMessageFont[MAX_CUSTOM_MESSAGE_FONTS]; + //td_custom_msg m_CustomMessage[MAX_CUSTOM_MESSAGES]; + + //texmgr m_texmgr; // for user sprites + + m_supertext.bRedrawSuperText = false; + m_supertext.fStartTime = -1.0f; + + // --------------------other init-------------------- + + g_bDebugOutput = false; + g_bDumpFileCleared = false; + + swprintf(m_szMilkdrop2Path, L"%s%s", GetPluginsDirPath(), SUBDIR); + swprintf(m_szPresetDir, L"%spresets\\", m_szMilkdrop2Path ); + + // note that the config dir can be under Program Files or Application Data!! + wchar_t szConfigDir[MAX_PATH] = {0}; + lstrcpyW(szConfigDir, GetConfigIniFile()); + wchar_t* p = wcsrchr(szConfigDir, L'\\'); + if (p) *(p+1) = 0; + swprintf(m_szMsgIniFile, L"%s%s", szConfigDir, MSG_INIFILE ); + swprintf(m_szImgIniFile, L"%s%s", szConfigDir, IMG_INIFILE ); +} + +//---------------------------------------------------------------------- + +void CPlugin::MyReadConfig() +{ + // Read the user's settings from the .INI file. + // If you've added any controls to the config panel, read their value in + // from the .INI file here. + + // use this function declared in to read a value of this type: + // ----------------- ----------- ---------------------------- + // GetPrivateProfileInt Win32 API int + // GetPrivateProfileBool utility.h bool + // GetPrivateProfileBOOL utility.h BOOL + // GetPrivateProfileFloat utility.h float + // GetPrivateProfileString Win32 API string + + //ex: m_fog_enabled = GetPrivateProfileInt("settings","fog_enabled" ,m_fog_enabled ,GetConfigIniFile()); + + int n=0; + wchar_t *pIni = GetConfigIniFile(); + + m_bFirstRun = !GetPrivateProfileBoolW(L"settings",L"bConfigured" ,false,pIni); + m_bEnableRating = GetPrivateProfileBoolW(L"settings",L"bEnableRating",m_bEnableRating,pIni); + //m_bInstaScan = GetPrivateProfileBool("settings","bInstaScan",m_bInstaScan,pIni); + m_bHardCutsDisabled = GetPrivateProfileBoolW(L"settings",L"bHardCutsDisabled",m_bHardCutsDisabled,pIni); + g_bDebugOutput = GetPrivateProfileBoolW(L"settings",L"bDebugOutput",g_bDebugOutput,pIni); + //m_bShowSongInfo = GetPrivateProfileBool("settings","bShowSongInfo",m_bShowSongInfo,pIni); + //m_bShowPresetInfo=GetPrivateProfileBool("settings","bShowPresetInfo",m_bShowPresetInfo,pIni); + m_bShowPressF1ForHelp = GetPrivateProfileBoolW(L"settings",L"bShowPressF1ForHelp",m_bShowPressF1ForHelp,pIni); + //m_bShowMenuToolTips = GetPrivateProfileBool("settings","bShowMenuToolTips",m_bShowMenuToolTips,pIni); + m_bSongTitleAnims = GetPrivateProfileBoolW(L"settings",L"bSongTitleAnims",m_bSongTitleAnims,pIni); + + m_bShowFPS = GetPrivateProfileBoolW(L"settings",L"bShowFPS", m_bShowFPS ,pIni); + m_bShowRating = GetPrivateProfileBoolW(L"settings",L"bShowRating", m_bShowRating ,pIni); + m_bShowPresetInfo = GetPrivateProfileBoolW(L"settings",L"bShowPresetInfo",m_bShowPresetInfo ,pIni); + //m_bShowDebugInfo = GetPrivateProfileBool("settings","bShowDebugInfo", m_bShowDebugInfo ,pIni); + m_bShowSongTitle = GetPrivateProfileBoolW(L"settings",L"bShowSongTitle", m_bShowSongTitle ,pIni); + m_bShowSongTime = GetPrivateProfileBoolW(L"settings",L"bShowSongTime", m_bShowSongTime ,pIni); + m_bShowSongLen = GetPrivateProfileBoolW(L"settings",L"bShowSongLen", m_bShowSongLen ,pIni); + + //m_bFixPinkBug = GetPrivateProfileBool("settings","bFixPinkBug",m_bFixPinkBug,pIni); + int nTemp = GetPrivateProfileBoolW(L"settings",L"bFixPinkBug",-1,pIni); + if (nTemp == 0) + m_n16BitGamma = 0; + else if (nTemp == 1) + m_n16BitGamma = 2; + m_n16BitGamma = GetPrivateProfileIntW(L"settings",L"n16BitGamma",m_n16BitGamma,pIni); + m_bAutoGamma = GetPrivateProfileBoolW(L"settings",L"bAutoGamma",m_bAutoGamma,pIni); + //m_bAlways3D = GetPrivateProfileBool("settings","bAlways3D",m_bAlways3D,pIni); + //m_fStereoSep = GetPrivateProfileFloat("settings","fStereoSep",m_fStereoSep,pIni); + //m_bFixSlowText = GetPrivateProfileBool("settings","bFixSlowText",m_bFixSlowText,pIni); + //m_bAlwaysOnTop = GetPrivateProfileBool("settings","bAlwaysOnTop",m_bAlwaysOnTop,pIni); + //m_bWarningsDisabled = GetPrivateProfileBool("settings","bWarningsDisabled",m_bWarningsDisabled,pIni); + m_bWarningsDisabled2 = GetPrivateProfileBoolW(L"settings",L"bWarningsDisabled2",m_bWarningsDisabled2,pIni); + //m_bAnisotropicFiltering = GetPrivateProfileBool("settings","bAnisotropicFiltering",m_bAnisotropicFiltering,pIni); + m_bPresetLockOnAtStartup = GetPrivateProfileBoolW(L"settings",L"bPresetLockOnAtStartup",m_bPresetLockOnAtStartup,pIni); + m_bPreventScollLockHandling = GetPrivateProfileBoolW(L"settings",L"m_bPreventScollLockHandling",m_bPreventScollLockHandling,pIni); + + m_nCanvasStretch = GetPrivateProfileIntW(L"settings",L"nCanvasStretch" ,m_nCanvasStretch,pIni); + m_nTexSizeX = GetPrivateProfileIntW(L"settings",L"nTexSize" ,m_nTexSizeX ,pIni); + m_nTexSizeY = m_nTexSizeX; + m_bTexSizeWasAutoPow2 = (m_nTexSizeX == -2); + m_bTexSizeWasAutoExact = (m_nTexSizeX == -1); + m_nTexBitsPerCh = GetPrivateProfileIntW(L"settings", L"nTexBitsPerCh", m_nTexBitsPerCh, pIni); + m_nGridX = GetPrivateProfileIntW(L"settings",L"nMeshSize" ,m_nGridX ,pIni); + m_nGridY = m_nGridX*3/4; + m_nMaxPSVersion_ConfigPanel = GetPrivateProfileIntW(L"settings",L"MaxPSVersion",m_nMaxPSVersion_ConfigPanel,pIni); + m_nMaxImages = GetPrivateProfileIntW(L"settings",L"MaxImages",m_nMaxImages,pIni); + m_nMaxBytes = GetPrivateProfileIntW(L"settings",L"MaxBytes" ,m_nMaxBytes ,pIni); + + m_fBlendTimeUser = GetPrivateProfileFloatW(L"settings",L"fBlendTimeUser" ,m_fBlendTimeUser ,pIni); + m_fBlendTimeAuto = GetPrivateProfileFloatW(L"settings",L"fBlendTimeAuto" ,m_fBlendTimeAuto ,pIni); + m_fTimeBetweenPresets = GetPrivateProfileFloatW(L"settings",L"fTimeBetweenPresets" ,m_fTimeBetweenPresets ,pIni); + m_fTimeBetweenPresetsRand = GetPrivateProfileFloatW(L"settings",L"fTimeBetweenPresetsRand",m_fTimeBetweenPresetsRand,pIni); + m_fHardCutLoudnessThresh = GetPrivateProfileFloatW(L"settings",L"fHardCutLoudnessThresh" ,m_fHardCutLoudnessThresh ,pIni); + m_fHardCutHalflife = GetPrivateProfileFloatW(L"settings",L"fHardCutHalflife" ,m_fHardCutHalflife ,pIni); + m_fSongTitleAnimDuration = GetPrivateProfileFloatW(L"settings",L"fSongTitleAnimDuration" ,m_fSongTitleAnimDuration ,pIni); + m_fTimeBetweenRandomSongTitles = GetPrivateProfileFloatW(L"settings",L"fTimeBetweenRandomSongTitles" ,m_fTimeBetweenRandomSongTitles,pIni); + m_fTimeBetweenRandomCustomMsgs = GetPrivateProfileFloatW(L"settings",L"fTimeBetweenRandomCustomMsgs" ,m_fTimeBetweenRandomCustomMsgs,pIni); + + // -------- + + GetPrivateProfileStringW(L"settings",L"szPresetDir",m_szPresetDir,m_szPresetDir,sizeof(m_szPresetDir),pIni); + + ReadCustomMessages(); + + // bounds-checking: + if (m_nGridX > 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(); + int i = 0; + for (i=0; i<MAX_CUSTOM_WAVES; i++) + m_menuWavecode[i].Finish(); + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + m_menuShapecode[i].Finish(); + + SetScrollLock(m_bOrigScrollLockState, m_bPreventScollLockHandling); + + //dumpmsg("Finish: cleanup complete."); +} + +//---------------------------------------------------------------------- + +float SquishToCenter(float x, float fExp) +{ + if (x > 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; i<NUM_BLUR_TEX; i++) + { + // main VS = 1024 + // blur0 = 512 + // blur1 = 256 <- user sees this as "blur1" + // blur2 = 128 + // blur3 = 128 <- user sees this as "blur2" + // blur4 = 64 + // blur5 = 64 <- user sees this as "blur3" + if (!(i&1) || (i<2)) + { + w = max(16, w/2); + h = max(16, h/2); + } + int w2 = ((w+3)/16)*16; + int h2 = ((h+3)/4)*4; + bSuccess = (GetDevice()->CreateTexture(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; j<FCGSY; j++) + { + int j2 = j - j/(FCGSY/2); + float v = j2*fDivY; + v = SquishToCenter(v, 3.0f); + float sy = -((v-fHalfTexelH)*2-1);//fOnePlusInvHeight*v*2-1; + for (int i=0; i<FCGSX; i++) + { + int i2 = i - i/(FCGSX/2); + float u = i2*fDivX; + u = SquishToCenter(u, 3.0f); + float sx = (u-fHalfTexelW)*2-1;//fOnePlusInvWidth*u*2-1; + MYVERTEX* p = &m_comp_verts[i + j*FCGSX]; + p->x = 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]; + int y = 0; + for (y=0; y<FCGSY-1; y++) + { + if (y==FCGSY/2-1) + continue; + for (int x=0; x<FCGSX-1; x++) + { + if (x==FCGSX/2-1) + continue; + bool left_half = (x < FCGSX/2); + bool top_half = (y < FCGSY/2); + bool center_4 = ((x==FCGSX/2 || x==FCGSX/2-1) && (y==FCGSY/2 || y==FCGSY/2-1)); + + if ( ((int)left_half + (int)top_half + (int)center_4) % 2 ) + { + *(cur_index+0) = (y )*FCGSX + (x ); + *(cur_index+1) = (y )*FCGSX + (x+1); + *(cur_index+2) = (y+1)*FCGSX + (x+1); + *(cur_index+3) = (y+1)*FCGSX + (x+1); + *(cur_index+4) = (y+1)*FCGSX + (x ); + *(cur_index+5) = (y )*FCGSX + (x ); + } + else + { + *(cur_index+0) = (y+1)*FCGSX + (x ); + *(cur_index+1) = (y )*FCGSX + (x ); + *(cur_index+2) = (y )*FCGSX + (x+1); + *(cur_index+3) = (y )*FCGSX + (x+1); + *(cur_index+4) = (y+1)*FCGSX + (x+1); + *(cur_index+5) = (y+1)*FCGSX + (x ); + } + cur_index += 6; + } + } + + // ----------------- + + /*if (m_bFixSlowText && !m_bSeparateTextWindow) + { + if (pCreateTexture(GetDevice(), GetWidth(), GetHeight(), 1, D3DUSAGE_RENDERTARGET, GetBackBufFormat(), D3DPOOL_DEFAULT, &m_lpDDSText) != D3D_OK) + { + char buf[2048]; + dumpmsg("Init: -WARNING-:"); + sprintf(buf, "WARNING: Not enough video memory to make a dedicated text surface; \rtext will still be drawn directly to the back buffer.\r\rTo avoid seeing this error again, uncheck the 'fix slow text' option."); + dumpmsg(buf); + if (!m_bWarningsDisabled) + MessageBox(GetPluginWindow(), buf, "WARNING", MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + m_lpDDSText = NULL; + } + }*/ + + // ----------------- + + // reallocate the texture for font titles + custom msgs (m_lpDDSTitle) + { + m_nTitleTexSizeX = max(m_nTexSizeX, m_nTexSizeY); + m_nTitleTexSizeY = m_nTitleTexSizeX/4; + + //dumpmsg("Init: [re]allocating title surface"); + + // [DEPRECATED as of transition to dx9:] + // We could just create one title surface, but this is a problem because many + // systems can only call DrawText on DDSCAPS_OFFSCREENPLAIN surfaces, and can NOT + // draw text on a DDSCAPS_TEXTURE surface (it comes out garbled). + // So, we create one of each; we draw the text to the DDSCAPS_OFFSCREENPLAIN surface + // (m_lpDDSTitle[1]), then we blit that (once) to the DDSCAPS_TEXTURE surface + // (m_lpDDSTitle[0]), which can then be drawn onto the screen on polys. + + HRESULT hr; + + do + { + hr = pCreateTexture(GetDevice(), m_nTitleTexSizeX, m_nTitleTexSizeY, 1, D3DUSAGE_RENDERTARGET, GetBackBufFormat(), D3DPOOL_DEFAULT, &m_lpDDSTitle); + if (hr != D3D_OK) + { + if (m_nTitleTexSizeY < m_nTitleTexSizeX) + { + m_nTitleTexSizeY *= 2; + } + else + { + m_nTitleTexSizeX /= 2; + m_nTitleTexSizeY /= 2; + } + } + } + while (hr != D3D_OK && m_nTitleTexSizeX > 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<size; y++) { + LARGE_INTEGER q; + QueryPerformanceCounter(&q); + srand(q.LowPart ^ q.HighPart ^ warand()); + int x = 0; + for (x=0; x<size; x++) { + dst[x] = (((DWORD)(warand() % RANGE)+RANGE/2) << 24) | + (((DWORD)(warand() % RANGE)+RANGE/2) << 16) | + (((DWORD)(warand() % RANGE)+RANGE/2) << 8) | + (((DWORD)(warand() % RANGE)+RANGE/2) ); + } + // swap some pixels randomly, to improve 'randomness' + for (x=0; x<size; x++) + { + int x1 = (warand() ^ q.LowPart ) % size; + int x2 = (warand() ^ q.HighPart) % size; + DWORD temp = dst[x2]; + dst[x2] = dst[x1]; + dst[x1] = temp; + } + dst += dwords_per_line; + } + + // smoothing + if (zoom_factor > 1) + { + // first go ACROSS, blending cubically on X, but only on the main lines. + DWORD* dst = (DWORD*)r.pBits; + for (int y=0; y<size; y+=zoom_factor) + for (int x=0; x<size; x++) + if (x % zoom_factor) + { + int base_x = (x/zoom_factor)*zoom_factor + size; + int base_y = y*dwords_per_line; + DWORD y0 = dst[ base_y + ((base_x - zoom_factor ) % size) ]; + DWORD y1 = dst[ base_y + ((base_x ) % size) ]; + DWORD y2 = dst[ base_y + ((base_x + zoom_factor ) % size) ]; + DWORD y3 = dst[ base_y + ((base_x + zoom_factor*2) % size) ]; + + float t = (x % zoom_factor)/(float)zoom_factor; + + DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t); + + dst[ y*dwords_per_line + x ] = result; + } + + // next go down, doing cubic interp along Y, on every line. + for (int x=0; x<size; x++) + for (int y=0; y<size; y++) + if (y % zoom_factor) + { + int base_y = (y/zoom_factor)*zoom_factor + size; + DWORD y0 = dst[ ((base_y - zoom_factor ) % size)*dwords_per_line + x ]; + DWORD y1 = dst[ ((base_y ) % size)*dwords_per_line + x ]; + DWORD y2 = dst[ ((base_y + zoom_factor ) % size)*dwords_per_line + x ]; + DWORD y3 = dst[ ((base_y + zoom_factor*2) % size)*dwords_per_line + x ]; + + float t = (y % zoom_factor)/(float)zoom_factor; + + DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t); + + dst[ y*dwords_per_line + x ] = result; + } + + } + + // unlock texture + pNoiseTex->UnlockRect(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<size; z++) { + DWORD* dst = (DWORD*)r.pBits + z*dwords_per_slice; + for (int y=0; y<size; y++) { + LARGE_INTEGER q; + QueryPerformanceCounter(&q); + srand(q.LowPart ^ q.HighPart ^ warand()); + int x = 0; + for (x=0; x<size; x++) { + dst[x] = (((DWORD)(warand() % RANGE)+RANGE/2) << 24) | + (((DWORD)(warand() % RANGE)+RANGE/2) << 16) | + (((DWORD)(warand() % RANGE)+RANGE/2) << 8) | + (((DWORD)(warand() % RANGE)+RANGE/2) ); + } + // swap some pixels randomly, to improve 'randomness' + for (x=0; x<size; x++) + { + int x1 = (warand() ^ q.LowPart ) % size; + int x2 = (warand() ^ q.HighPart) % size; + DWORD temp = dst[x2]; + dst[x2] = dst[x1]; + dst[x1] = temp; + } + dst += dwords_per_line; + } + } + + // smoothing + if (zoom_factor > 1) + { + // first go ACROSS, blending cubically on X, but only on the main lines. + DWORD* dst = (DWORD*)r.pBits; + for (int z=0; z<size; z+=zoom_factor) + for (int y=0; y<size; y+=zoom_factor) + for (int x=0; x<size; x++) + if (x % zoom_factor) + { + int base_x = (x/zoom_factor)*zoom_factor + size; + int base_y = z*dwords_per_slice + y*dwords_per_line; + DWORD y0 = dst[ base_y + ((base_x - zoom_factor ) % size) ]; + DWORD y1 = dst[ base_y + ((base_x ) % size) ]; + DWORD y2 = dst[ base_y + ((base_x + zoom_factor ) % size) ]; + DWORD y3 = dst[ base_y + ((base_x + zoom_factor*2) % size) ]; + + float t = (x % zoom_factor)/(float)zoom_factor; + + DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t); + + dst[ z*dwords_per_slice + y*dwords_per_line + x ] = result; + } + + // next go down, doing cubic interp along Y, on the main slices. + for (int z=0; z<size; z+=zoom_factor) + for (int x=0; x<size; x++) + for (int y=0; y<size; y++) + if (y % zoom_factor) + { + int base_y = (y/zoom_factor)*zoom_factor + size; + int base_z = z*dwords_per_slice; + DWORD y0 = dst[ ((base_y - zoom_factor ) % size)*dwords_per_line + base_z + x ]; + DWORD y1 = dst[ ((base_y ) % size)*dwords_per_line + base_z + x ]; + DWORD y2 = dst[ ((base_y + zoom_factor ) % size)*dwords_per_line + base_z + x ]; + DWORD y3 = dst[ ((base_y + zoom_factor*2) % size)*dwords_per_line + base_z + x ]; + + float t = (y % zoom_factor)/(float)zoom_factor; + + DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t); + + dst[ y*dwords_per_line + base_z + x ] = result; + } + + // next go through, doing cubic interp along Z, everywhere. + for (int x=0; x<size; x++) + for (int y=0; y<size; y++) + for (int z=0; z<size; z++) + if (z % zoom_factor) + { + int base_y = y*dwords_per_line; + int base_z = (z/zoom_factor)*zoom_factor + size; + DWORD y0 = dst[ ((base_z - zoom_factor ) % size)*dwords_per_slice + base_y + x ]; + DWORD y1 = dst[ ((base_z ) % size)*dwords_per_slice + base_y + x ]; + DWORD y2 = dst[ ((base_z + zoom_factor ) % size)*dwords_per_slice + base_y + x ]; + DWORD y3 = dst[ ((base_z + zoom_factor*2) % size)*dwords_per_slice + base_y + x ]; + + float t = (z % zoom_factor)/(float)zoom_factor; + + DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t); + + dst[ z*dwords_per_slice + base_y + x ] = result; + } + + } + + // unlock texture + pNoiseTex->UnlockBox(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; i<N; i++) + if (global_CShaderParams_master_list[i] == this) + { + global_CShaderParams_master_list.erase(global_CShaderParams_master_list.begin() + i); + break; + } + + texsize_params.clear(); +} + +void CShaderParams::OnTextureEvict(LPDIRECT3DBASETEXTURE9 texptr) +{ + for (int i=0; i<sizeof(m_texture_bindings)/sizeof(m_texture_bindings[0]); i++) + if (m_texture_bindings[i].texptr == texptr) + m_texture_bindings[i].texptr = NULL; +} + +void CShaderParams::Clear() +{ + // float4 handles: + rand_frame = NULL; + rand_preset = NULL; + + ZeroMemory(rot_mat, sizeof(rot_mat)); + ZeroMemory(const_handles, sizeof(const_handles)); + ZeroMemory(q_const_handles, sizeof(q_const_handles)); + texsize_params.clear(); + + // sampler stages for various PS texture bindings: + for (int i=0; i<sizeof(m_texture_bindings)/sizeof(m_texture_bindings[0]); i++) + { + m_texture_bindings[i].texptr = NULL; + m_texcode[i] = TEX_DISK; + } +} + +bool CPlugin::EvictSomeTexture() +{ + // note: this won't evict a texture whose age is zero, + // or whose reported size is zero! + + #if _DEBUG + { + int nEvictableFiles = 0; + int nEvictableBytes = 0; + int N = m_textures.size(); + for (int i=0; i<N; i++) + if (m_textures[i].bEvictable && m_textures[i].texptr) + { + nEvictableFiles++; + nEvictableBytes += m_textures[i].nSizeInBytes; + } + char buf[1024]; + sprintf(buf, "evicting at %d textures, %.1f MB\n", nEvictableFiles, nEvictableBytes*0.000001f); + OutputDebugString(buf); + } + #endif + + int N = m_textures.size(); + + // find age gap + int newest = 99999999; + int oldest = 0; + bool bAtLeastOneFound = false; + int i = 0; + for (i=0; i<N; i++) + if (m_textures[i].bEvictable && m_textures[i].nSizeInBytes>0 && 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; i<N; i++) + if (m_textures[i].bEvictable && m_textures[i].nSizeInBytes>0 && 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; i<N; i++) + global_CShaderParams_master_list[i]->OnTextureEvict( m_textures[biggest_index].texptr ); + + // 2. erase the texture itself + SafeRelease(m_textures[biggest_index].texptr); + m_textures.erase(m_textures.begin() + 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 std::vector<GString> 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; i<sizeof(texture_exts)/sizeof(texture_exts[0]); i++) + if (!wcsicmp(texture_exts[i].c_str(), ext+1)) + { + // valid texture found - add it to the list. ("heart.jpg", for example) + texfiles.push_back( ffd.cFileName ); + continue; + } + } + while (FindNextFileW(hFindFile, &ffd)); + FindClose(hFindFile); + } + + if (texfiles.size() == 0) + return false; + + // then randomly pick one + if (prefix==NULL || prefix[0]==0) + { + // pick randomly from entire list + int i = warand() % texfiles.size(); + lstrcpyW(szRetTextureFilename, texfiles[i].c_str()); + } + else + { + // only pick from files w/the right prefix + StringVec temp_list; + int N = texfiles.size(); + int len = lstrlenW(prefix); + for (int i=0; i<N; i++) + if (!_wcsnicmp(prefix, texfiles[i].c_str(), len)) + temp_list.push_back(texfiles[i]); + N = temp_list.size(); + if (N==0) + return false; + // pick randomly from the subset + int i = warand() % temp_list.size(); + lstrcpyW(szRetTextureFilename, temp_list[i].c_str()); + } + return true; +} + +void CShaderParams::CacheParams(LPD3DXCONSTANTTABLE pCT, bool bHardErrors) +{ + Clear(); + + if (!pCT) + return; + + D3DXCONSTANTTABLE_DESC d; + pCT->GetDesc(&d); + + D3DXCONSTANT_DESC cd; + + #define MAX_RAND_TEX 16 + GString RandTexName[MAX_RAND_TEX]; + + // pass 1: find all the samplers (and texture bindings). + UINT i = 0; + for (i=0; i<d.Constants; i++) + { + D3DXHANDLE h = pCT->GetConstant(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 <szFileName> 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 <szRootName>.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; n<N; n++) { + if (!wcscmp(g_plugin.m_textures[n].texname, szRootName)) + { + // found a match - texture was already loaded + m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_textures[n].texptr; + // also bump its age down to zero! (for cache mgmt) + g_plugin.m_textures[n].nAge = g_plugin.m_nPresetsLoadedTotal; + break; + } + } + // if still not found, load it up / make a new texture + if (!m_texture_bindings[ cd.RegisterIndex ].texptr) + { + TexInfo x; + wcsncpy(x.texname, szRootName, 254); + x.texptr = NULL; + //x.texsize_param = NULL; + + // check if we need to evict anything from the cache, + // due to our own cache constraints... + while (1) + { + int nTexturesCached = 0; + int nBytesCached = 0; + int N = g_plugin.m_textures.size(); + for (int i=0; i<N; i++) + if (g_plugin.m_textures[i].bEvictable && g_plugin.m_textures[i].texptr) + { + nBytesCached += g_plugin.m_textures[i].nSizeInBytes; + nTexturesCached++; + } + if ( nTexturesCached < g_plugin.m_nMaxImages && + nBytesCached < g_plugin.m_nMaxBytes ) + break; + // otherwise, evict now - and loop until we are within the constraints + if (!g_plugin.EvictSomeTexture()) + break; // or if there was nothing to evict, just give up + } + + //load the texture + wchar_t szFilename[MAX_PATH]; + for (int z=0; z<sizeof(texture_exts)/sizeof(texture_exts[0]); z++) + { + swprintf(szFilename, L"%stextures\\%s.%s", g_plugin.m_szMilkdrop2Path, szRootName, texture_exts[z].c_str()); + if (GetFileAttributesW(szFilename) == 0xFFFFFFFF) + { + // try again, but in presets dir + swprintf(szFilename, L"%s%s.%s", g_plugin.m_szPresetDir, szRootName, texture_exts[z].c_str()); + if (GetFileAttributesW(szFilename) == 0xFFFFFFFF) + continue; + } + D3DXIMAGE_INFO desc; + + // keep trying to load it - if it fails due to memory, evict something and try again. + while (1) + { + HRESULT hr = pCreateTextureFromFileExW(g_plugin.GetDevice(), + szFilename, + D3DX_DEFAULT_NONPOW2, // w + D3DX_DEFAULT_NONPOW2, // h + D3DX_DEFAULT, // # mip levels to gen - all + 0, // usage flags + D3DFMT_UNKNOWN, + D3DPOOL_DEFAULT, + D3DX_DEFAULT, //filter + D3DX_DEFAULT, //mipfilter + 0, // color key + &desc, + NULL, //palette + (IDirect3DTexture9**)&x.texptr + ); + if (hr==D3DERR_OUTOFVIDEOMEMORY || hr==E_OUTOFMEMORY) + { + // out of memory - try evicting something old and/or big + if (g_plugin.EvictSomeTexture()) + continue; + } + + if (hr==D3D_OK) + { + x.w = desc.Width; + x.h = desc.Height; + x.d = desc.Depth; + x.bEvictable = true; + x.nAge = g_plugin.m_nPresetsLoadedTotal; + int nPixels = desc.Width*desc.Height*max(1,desc.Depth); + int BitsPerPixel = GetDX9TexFormatBitsPerPixel(desc.Format); + x.nSizeInBytes = nPixels*BitsPerPixel/8 + 16384; //plus some overhead + } + break; + } + } + + if (!x.texptr) + { + wchar_t buf[2048], title[64]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_COULD_NOT_LOAD_TEXTURE_X), szRootName, szExtsWithSlashes); + g_plugin.dumpmsg(buf); + if (bHardErrors) + MessageBoxW(g_plugin.GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + else { + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + } + return; + } + + g_plugin.m_textures.push_back(x); + m_texture_bindings[ cd.RegisterIndex ].texptr = x.texptr; + } + } + } + } + + // pass 2: bind all the float4's. "texsize_XYZ" params will be filled out via knowledge of loaded texture sizes. + for (i=0; i<d.Constants; i++) + { + D3DXHANDLE h = pCT->GetConstant(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 <szRootName>.tga or .jpg has already been loaded. + bool bTexFound = false; + int N = g_plugin.m_textures.size(); + for (int n=0; n<N; n++) { + if (!wcscmp(g_plugin.m_textures[n].texname, szRootName)) + { + // found a match - texture was loaded + TexSizeParamInfo y; + y.texname = szRootName; //for debugging + y.texsize_param = h; + y.w = g_plugin.m_textures[n].w; + y.h = g_plugin.m_textures[n].h; + texsize_params.push_back(y); + + bTexFound = true; + break; + } + } + + if (!bTexFound) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_RESOLVE_TEXSIZE_FOR_A_TEXTURE_NOT_IN_USE), cd.Name); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + } + } + else if (cd.Name[0] == '_' && cd.Name[1] == 'c') + { + int z; + if (sscanf(&cd.Name[2], "%d", &z)==1) + if (z >= 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 ( TexInfo &l_texture : m_textures ) + { + if ( l_texture.texptr ) + { + // notify all CShaderParams classes that we're releasing a bindable texture!! + for ( CShaderParams *l_shader_param : global_CShaderParams_master_list ) + l_shader_param->OnTextureEvict( l_texture.texptr ); + + SafeRelease( l_texture.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 (int i=0; i<NUM_BLUR_TEX; i++) + m_lpBlur[i] = NULL;//SafeRelease(m_lpBlur[i]); + #endif + + // NOTE: not necessary; shell does this for us. + /*if (GetDevice()) + { + GetDevice()->SetTexture(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; i < N; i++) + { + if (category == ERR_ALL || m_errors[i].category == category) + { + m_errors.erase(m_errors.begin() + i); + i--; + N--; + } + } +} + +void CPlugin::MyRenderUI( + int *upper_left_corner_y, // increment me! + int *upper_right_corner_y, // increment me! + int *lower_left_corner_y, // decrement me! + int *lower_right_corner_y, // decrement me! + int xL, + int xR + ) +{ + // draw text messages directly to the back buffer. + // when you draw text into one of the four corners, + // draw the text at the current 'y' value for that corner + // (one of the first 4 params to this function), + // and then adjust that y value so that the next time + // text is drawn in that corner, it gets drawn above/below + // the previous text (instead of overtop of it). + // when drawing into the upper or lower LEFT corners, + // left-align your text to 'xL'. + // when drawing into the upper or lower RIGHT corners, + // right-align your text to 'xR'. + + // note: try to keep the bounding rectangles on the text small; + // the smaller the area that has to be locked (to draw the text), + // the faster it will be. (on some cards, drawing text is + // ferociously slow, so even if it works okay on yours, it might + // not work on another video card.) + // note: if you want some text to be on the screen often, and the text + // won't be changing every frame, please consider the poor folks + // whose video cards hate that; in that case you should probably + // draw the text just once, to a texture, and then display the + // texture each frame. This is how the help screen is done; see + // pluginshell.cpp for example code. + + RECT r = {0}; + wchar_t buf[512] = {0}; + LPD3DXFONT pFont = GetFont(DECORATIVE_FONT); + int h = GetFontHeight(DECORATIVE_FONT); + + if (!pFont) + return; + + if (!GetFont(DECORATIVE_FONT)) + return; + + // 1. render text in upper-right corner - EXCEPT USER MESSAGE - it goes last b/c it draws a box under itself + // and it should be visible over everything else (usually an error msg) + { + // a) preset name + if (m_bShowPresetInfo) + { + SelectFont(DECORATIVE_FONT); + swprintf(buf, L"%s ", (m_nLoadingPreset != 0) ? m_pNewState->m_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<MASH_SLOTS; mash++) + { + // check validity + if (m_nMashPreset[mash] < m_nDirs) + m_nMashPreset[mash] = m_nDirs; + if (m_nMashPreset[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, + }; + + int pass = 0; + for (pass=0; pass<2; pass++) + { + box = orig_rect; + int w = 0; + int h = 0; + + int start_y = orig_rect.top; + for (int mash=0; mash<MASH_SLOTS; mash++) + { + int idx = m_nMashPreset[mash]; + + wchar_t buf[1024]; + swprintf(buf, L"%s%s", WASABI_API_LNGSTRINGW(mashNames[mash]), m_presets[idx].szFilename); + RECT r2 = orig_rect; + r2.top += h; + h += m_text.DrawTextW(GetFont(SIMPLE_FONT), buf, -1, &r2, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | (pass==0 ? DT_CALCRECT : 0), (mash==m_nMashSlot) ? PLAYLIST_COLOR_HILITE_TRACK : PLAYLIST_COLOR_NORMAL, false); + w = max(w, r2.right - r2.left); + } + if (pass==0) { + box.right = box.left + w; + box.bottom = box.top + h; + DrawDarkTranslucentBox(&box); + } + else + orig_rect.top += h; + } + + orig_rect.top += GetFontHeight(SIMPLE_FONT) + PLAYLIST_INNER_MARGIN; + + box = orig_rect; + box.right = box.left; + box.bottom = box.top; + + // draw a directory listing box right after... + for (pass=0; pass<2; pass++) + { + //if (pass==1) + // GetFont(SIMPLE_FONT)->Begin(); + + rect = orig_rect; + for (i=first_line; i<last_line; i++) + { + // remove the extension before displaying the filename. also pad w/spaces. + //lstrcpy(str, m_pPresetAddr[i]); + bool bIsDir = (m_presets[i].szFilename.c_str()[0] == '*'); + bool bIsRunning = false; + bool bIsSelected = (i == m_nMashPreset[m_nMashSlot]); + + if (bIsDir) + { + // directory + if (wcscmp(m_presets[i].szFilename.c_str()+1, L"..")==0) + swprintf(str2, L" [ %s ] (%s) ", m_presets[i].szFilename.c_str()+1, WASABI_API_LNGSTRINGW(IDS_PARENT_DIRECTORY)); + else + swprintf(str2, L" [ %s ] ", m_presets[i].szFilename.c_str()+1); + } + else + { + // preset file + lstrcpyW(str, m_presets[i].szFilename.c_str()); + RemoveExtension(str); + swprintf(str2, L" %s ", str); + + if (wcscmp(m_presets[m_nMashPreset[m_nMashSlot]].szFilename.c_str(), 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; + } + 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; i<last_line; i++) + { + // remove the extension before displaying the filename. also pad w/spaces. + //lstrcpy(str, m_pPresetAddr[i]); + bool bIsDir = (m_presets[i].szFilename.c_str()[0] == '*'); + bool bIsRunning = (i == m_nCurrentPreset);//false; + bool bIsSelected = (i == m_nPresetListCurPos); + + if (bIsDir) + { + // directory + if (wcscmp(m_presets[i].szFilename.c_str()+1, L"..")==0) + swprintf(str2, L" [ %s ] (%s) ", m_presets[i].szFilename.c_str()+1, WASABI_API_LNGSTRINGW(IDS_PARENT_DIRECTORY)); + else + swprintf(str2, L" [ %s ] ", m_presets[i].szFilename.c_str()+1); + } + else + { + // preset file + lstrcpyW(str, m_presets[i].szFilename.c_str()); + RemoveExtension(str); + swprintf(str2, L" %s ", str); + + //if (lstrcmp(m_pState->m_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<N; i++) + { + if (t >= 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.erase(m_errors.begin() + 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<nRepeat; rep++) + { + if (m_waitstring.nCursorPos == len) + { + lstrcatA((char*)m_waitstring.szText, buf); + len++; + } + else + { + char* ptr = (char*)m_waitstring.szText; + *(ptr + m_waitstring.nCursorPos) = buf[0]; + } + m_waitstring.nCursorPos++; + } + } + else + { + // insert mode: + char* ptr = (char*)m_waitstring.szText; + for (rep=0; rep<nRepeat; rep++) + { + for (int i=len; i>=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<nRepeat; rep++) + { + if (m_waitstring.nCursorPos == len) + { + lstrcatW(m_waitstring.szText, buf); + len++; + } + else + m_waitstring.szText[m_waitstring.nCursorPos] = buf[0]; + m_waitstring.nCursorPos++; + } + } + else + { + // insert mode: + for (rep=0; rep<nRepeat; rep++) + { + for (int i=len; i>=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<nRepeat; rep++) + if (m_waitstring.nCursorPos > 0) + m_waitstring.nCursorPos--; + return 0; // we processed (or absorbed) the key + + case VK_RIGHT: + for (rep=0; rep<nRepeat; rep++) + { + if (m_waitstring.bDisplayAsCode) + { + if (m_waitstring.nCursorPos < (int)lstrlenA((char*)m_waitstring.szText)) + m_waitstring.nCursorPos++; + } + else + { + if (m_waitstring.nCursorPos < (int)lstrlenW(m_waitstring.szText)) + m_waitstring.nCursorPos++; + } + } + return 0; // we processed (or absorbed) the key + + case VK_HOME: + m_waitstring.nCursorPos -= WaitString_GetCursorColumn(); + return 0; // we processed (or absorbed) the key + + case VK_END: + m_waitstring.nCursorPos += WaitString_GetLineLength() - WaitString_GetCursorColumn(); + return 0; // we processed (or absorbed) the key + + case VK_UP: + for (rep=0; rep<nRepeat; rep++) + WaitString_SeekUpOneLine(); + return 0; // we processed (or absorbed) the key + + case VK_DOWN: + for (rep=0; rep<nRepeat; rep++) + WaitString_SeekDownOneLine(); + return 0; // we processed (or absorbed) the key + + case VK_BACK: + if (m_waitstring.nSelAnchorPos != -1) + { + WaitString_NukeSelection(); + } + else if (m_waitstring.nCursorPos > 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; i<copy_chars; i++) + *(ptr + dst_pos+i) = *(ptr + src_pos+i); + } + else + { + for (int i=0; i<copy_chars; i++) + m_waitstring.szText[dst_pos+i] = m_waitstring.szText[src_pos+i]; + } + m_waitstring.nCursorPos -= gap; + } + return 0; // we processed (or absorbed) the key + + case VK_DELETE: + if (m_waitstring.nSelAnchorPos != -1) + { + WaitString_NukeSelection(); + } + else + { + if (m_waitstring.bDisplayAsCode) + { + int len = lstrlenA((char*)m_waitstring.szText); + char* ptr = (char*)m_waitstring.szText; + for (int i=m_waitstring.nCursorPos; i<=len - nRepeat; i++) + *(ptr + i) = *(ptr + i+nRepeat); + } + else + { + int len = lstrlenW(m_waitstring.szText); + for (int i=m_waitstring.nCursorPos; i<=len - nRepeat; i++) + m_waitstring.szText[i] = m_waitstring.szText[i+nRepeat]; + } + } + return 0; // we processed (or absorbed) the key + + case VK_RETURN: + if (m_UI_mode == UI_LOAD_RENAME) // rename (move) the file + { + // first add pathnames to filenames + wchar_t szOldFile[512]; + wchar_t szNewFile[512]; + lstrcpyW(szOldFile, GetPresetDir()); + lstrcpyW(szNewFile, GetPresetDir()); + lstrcatW(szOldFile, m_presets[m_nPresetListCurPos].szFilename.c_str()); + lstrcatW(szNewFile, m_waitstring.szText); + lstrcatW(szNewFile, L".milk"); + + RenamePresetFile(szOldFile, szNewFile); + } + else if (m_UI_mode == UI_IMPORT_WAVE || + m_UI_mode == UI_EXPORT_WAVE || + m_UI_mode == UI_IMPORT_SHAPE || + m_UI_mode == UI_EXPORT_SHAPE) + { + int bWave = (m_UI_mode == UI_IMPORT_WAVE || m_UI_mode == UI_EXPORT_WAVE); + int bImport = (m_UI_mode == UI_IMPORT_WAVE || m_UI_mode == UI_IMPORT_SHAPE); + + int i = m_pCurMenu->GetCurItem()->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<nRepeat; rep++) + m_nMashPreset[m_nMashSlot] = max(m_nMashPreset[m_nMashSlot]-1, m_nDirs); + m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_LOAD) + { + for (rep=0; rep<nRepeat; rep++) + if (m_nPresetListCurPos > 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<nRepeat; rep++) + m_nMashPreset[m_nMashSlot] = min(m_nMashPreset[m_nMashSlot]+1, m_nPresets-1); + m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_LOAD) + { + for (rep=0; rep<nRepeat; rep++) + if (m_nPresetListCurPos < m_nPresets - 1) + 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_SPACE: + if (m_UI_mode == UI_LOAD) + goto HitEnterFromLoadMenu; + if (!m_bPresetLockedByCode) + { + LoadRandomPreset(m_fBlendTimeUser); + return 0; // we processed (or absorbed) the key + } + break; + + case VK_PRIOR: + if (m_UI_mode == UI_LOAD || m_UI_mode == UI_MASHUP) + { + m_bUserPagedUp = true; + if (m_UI_mode == UI_MASHUP) + m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply + return 0; // we processed (or absorbed) the key + } + break; + case VK_NEXT: + if (m_UI_mode == UI_LOAD || m_UI_mode == UI_MASHUP) + { + m_bUserPagedDown = true; + if (m_UI_mode == UI_MASHUP) + m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply + return 0; // we processed (or absorbed) the key + } + break; + case VK_HOME: + if (m_UI_mode == UI_LOAD) + { + m_nPresetListCurPos = 0; + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_MASHUP) + { + m_nMashPreset[m_nMashSlot] = m_nDirs; + m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply + return 0; // we processed (or absorbed) the key + } + break; + case VK_END: + if (m_UI_mode == UI_LOAD) + { + m_nPresetListCurPos = m_nPresets - 1; + return 0; // we processed (or absorbed) the key + } + else if (m_UI_mode == UI_MASHUP) + { + m_nMashPreset[m_nMashSlot] = m_nPresets-1; + m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply + return 0; // we processed (or absorbed) the key + } + break; + + case VK_DELETE: + if (m_UI_mode == UI_LOAD) + { + if (m_presets[m_nPresetListCurPos].szFilename.c_str()[0] != '*') // can't delete directories + m_UI_mode = UI_LOAD_DEL; + return 0; // we processed (or absorbed) the key + } + else //if (m_nNumericInputDigits == 0) + { + if (m_nNumericInputMode == NUMERIC_INPUT_MODE_CUST_MSG) + { + m_nNumericInputDigits = 0; + m_nNumericInputNum = 0; + + // stop display of text message. + m_supertext.fStartTime = -1.0f; + return 0; // we processed (or absorbed) the key + } + else if (m_nNumericInputMode == NUMERIC_INPUT_MODE_SPRITE) + { + // kill newest sprite (regular DELETE key) + // oldest sprite (SHIFT + DELETE), + // or all sprites (CTRL + SHIFT + DELETE). + + m_nNumericInputDigits = 0; + m_nNumericInputNum = 0; + + 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 (bShiftHeldDown && bCtrlHeldDown) + { + for (int x=0; x<NUM_TEX; x++) + m_texmgr.KillTex(x); + } + else + { + int newest = -1; + int frame; + for (int x=0; x<NUM_TEX; x++) + { + if (m_texmgr.m_tex[x].pSurface) + { + if ((newest == -1) || + (!bShiftHeldDown && m_texmgr.m_tex[x].nStartFrame > 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<NUM_TEX; x++) + if (m_texmgr.m_tex[x].pSurface) + m_texmgr.KillTex(x); + return 0; + } + break; + /*case keyMappings[2]: // 'Y' + if (bCtrlHeldDown) // stop display of custom message or song title. + { + m_supertext.fStartTime = -1.0f; + return 0; + } + break;*/ + } + if (wParam == keyMappings[2]) // 'Y' + { + if (bCtrlHeldDown) // stop display of custom message or song title. + { + m_supertext.fStartTime = -1.0f; + return 0; + } + } + return 1; // end case WM_KEYDOWN + + case WM_KEYUP: + return 1; + break; + + default: + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + break; + } + + return 0; +}; + +//---------------------------------------------------------------------- + +int CPlugin::HandleRegularKey(WPARAM wParam) +{ + // here we handle all the normal keys for milkdrop- + // these are the hotkeys that are used when you're not + // in the middle of editing a string, navigating a menu, etc. + + // do not make references to virtual keys here; only + // straight WM_CHAR messages should be sent in. + + // return 0 if you process/absorb the key; otherwise return 1. + + if (m_UI_mode == UI_LOAD && ((wParam >= '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; x<NUM_TEX; x++) + if (m_texmgr.m_tex[x].nUserData == m_nNumericInputNum) + m_texmgr.KillTex(x); + } + + m_nNumericInputDigits = 0; + m_nNumericInputNum = 0; + } + } + return 0; // we processed (or absorbed) the key + + // row 1 keys + case 'q': + m_pState->m_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; mash<MASH_SLOTS; mash++) + { + m_nMashPreset[mash] = m_nDirs + (warand() % (m_nPresets-m_nDirs)); + m_nLastMashChangeFrame[mash] = GetFrame() + MASH_APPLY_DELAY_FRAMES; // causes instant apply + } + } + } + else + { + NextPreset(0); + m_fHardCutThresh *= 2.0f; // make it a little less likely that a random hard cut follows soon. + } + return 0; // we processed (or absorbed) the key + case 'f': + case 'F': + m_pState->m_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)); + int i = 0; + for (i=0; i<MAX_CUSTOM_WAVES; i++) + { + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_CUSTOM_WAVE_X), i+1); + m_menuWavecode[i].Init(buf); + } + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + { + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_CUSTOM_SHAPE_X), i+1); + m_menuShapecode[i].Init(buf); + } + + //------------------------------------------- + + // MAIN MENU / menu hierarchy + + m_menuPreset.AddChildMenu(&m_menuMotion); + m_menuPreset.AddChildMenu(&m_menuCustomShape); + m_menuPreset.AddChildMenu(&m_menuCustomWave); + m_menuPreset.AddChildMenu(&m_menuWave); + m_menuPreset.AddChildMenu(&m_menuAugment); + m_menuPreset.AddChildMenu(&m_menuPost); + + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + m_menuCustomShape.AddChildMenu(&m_menuShapecode[i]); + for (i=0; i<MAX_CUSTOM_WAVES; i++) + m_menuCustomWave.AddChildMenu(&m_menuWavecode[i]); + + // NOTE: all of the eval menuitems use a CALLBACK function to register the user's changes (see last param) + m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_PRESET_INIT_CODE), + &m_pState->m_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; i<MAX_CUSTOM_WAVES; i++) + { + // blending: do both; fade opacities in/out (w/exagerrated weighting) + m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_ENABLED), &m_pState->m_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; i<MAX_CUSTOM_SHAPES; i++) + { + // blending: do both; fade opacities in/out (w/exagerrated weighting) + m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_ENABLED), &m_pState->m_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; i++) + { + char szPresetFile[512]; + lstrcpy(szPresetFile, m_szPresetDir); // note: m_szPresetDir always ends with '\' + lstrcat(szPresetFile, m_pPresetAddr[i]); + //CState newstate; + m_state2.Import(szPresetFile, GetTime()); + + lstrcpy(szPresetFile, "c:\\t7\\"); + lstrcat(szPresetFile, m_pPresetAddr[i]); + m_state2.Export(szPresetFile); + } + */ + // --[END]TEMPORARY-- + + if (m_bSequentialPresetOrder) + { + m_nCurrentPreset++; + if (m_nCurrentPreset < m_nDirs || m_nCurrentPreset >= 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<m_nPresets; i++) + { + char buf2[32]; + sprintf(buf2, "%3.1f ", m_presets[i].fRatingCum); + lstrcat(buf, buf2); + } + dumpmsg(buf); + */ + + if (cdf_pos < m_presets[m_nDirs].fRatingCum) + { + m_nCurrentPreset = m_nDirs; + } + else + { + int lo = m_nDirs; + int hi = m_nPresets; + while (lo + 1 < hi) + { + int mid = (lo+hi)/2; + if (m_presets[mid].fRatingCum > 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<MASH_SLOTS; mash++) + m_nMashPreset[mash] = m_nCurrentPreset; +} + +void CPlugin::LoadPresetTick() +{ + if (m_nLoadingPreset == 2 || m_nLoadingPreset == 5) + { + // just loads one shader (warp or comp) then returns. + LoadShaders(&m_NewShaders, m_pNewState, true); + } + else if (m_nLoadingPreset == 8) + { + // finished loading the shaders - apply the preset! + lstrcpyW(m_szCurrentPresetFile, m_szLoadingPreset); + m_szLoadingPreset[0] = 0; + + CState *temp = m_pState; + m_pState = m_pOldState; + m_pOldState = temp; + + temp = m_pState; + m_pState = m_pNewState; + m_pNewState = temp; + + RandomizeBlendPattern(); + + //if (fBlendTime >= 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<reps; z++) + { + if (p && !strncmp(p, "[preset00]", 10)) + { + p = NextLine(p); + if (p && !strncmp(p, "fRating=", 8)) + { + _sscanf_l(&p[8], "%f", g_use_C_locale, &fRating); + bRatingKnown = true; + break; + } + } + p = NextLine(p); + } + + fclose(f); + + if (!bRatingKnown) + fRating = GetPrivateProfileFloatW(L"preset00", L"fRating", 3.0f, szFullPath); + fRating = max(0.0f, min(5.0f, fRating)); + } + } + } + + if (!bSkip) + { + float fPrevPresetRatingCum = 0; + if (temp_nPresets > 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<temp_nPresets; i++) + g_plugin.m_presets.push_back(temp_presets[i]); + g_plugin.m_nPresets = temp_nPresets; + g_plugin.m_nDirs = temp_nDirs; + + LeaveCriticalSection(&g_cs); + } + } + + if (g_bThreadShouldQuit) + { + // just abort... we are exiting the program or restarting the scan. + g_bThreadAlive = false; + _endthreadex(0); + return 0; + } + + EnterCriticalSection(&g_cs); + + //g_plugin.m_presets = temp_presets; + for (int i=g_plugin.m_nPresets; i<temp_nPresets; i++) + g_plugin.m_presets.push_back(temp_presets[i]); + g_plugin.m_nPresets = temp_nPresets; + g_plugin.m_nDirs = temp_nDirs; + g_plugin.m_bPresetListReady = true; + + if (g_plugin.m_bPresetListReady && g_plugin.m_nPresets == 0) + { + // no presets OR directories found - weird - but it happens. + // --> 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; i<g_plugin.m_nPresets; i++) + g_plugin.m_presets[i].fRatingCum = g_plugin.m_presets[i-1].fRatingCum + g_plugin.m_presets[i].fRatingThis; + + // clear the "scanning presets" msg + g_plugin.ClearErrors(ERR_SCANNING_PRESETS); + + // finally, try to re-select the most recently-used preset in the list + g_plugin.m_nPresetListCurPos = 0; + if (bTryReselectCurrentPreset) + { + if (g_plugin.m_szCurrentPresetFile[0]) + { + // try to automatically seek to the last preset loaded + wchar_t *p = wcsrchr(g_plugin.m_szCurrentPresetFile, L'\\'); + p = (p) ? (p+1) : g_plugin.m_szCurrentPresetFile; + for (int i=g_plugin.m_nDirs; i<g_plugin.m_nPresets; i++) + { + if (wcscmp(p, g_plugin.m_presets[i].szFilename.c_str())==0) { + g_plugin.m_nPresetListCurPos = i; + break; + } + } + } + } + } + + LeaveCriticalSection(&g_cs); + + g_bThreadAlive = false; + _endthreadex(0); + return 0; +} + +void CPlugin::UpdatePresetList(bool bBackground, bool bForce, bool bTryReselectCurrentPreset) +{ + // note: if dir changed, make sure bForce is true! + + if (bForce) + { + if (g_bThreadAlive) + CancelThread(3000); // flags it to exit; the param is the # of ms to wait before forcefully killing it + } + else + { + if (bBackground && (g_bThreadAlive || m_bPresetListReady)) + return; + if (!bBackground && m_bPresetListReady) + return; + } + + assert(!g_bThreadAlive); + + // spawn new thread: + DWORD flags = (bForce ? 1 : 0) | (bTryReselectCurrentPreset ? 2 : 0); + g_bThreadShouldQuit = false; + g_bThreadAlive = true; + g_hThread = (HANDLE)_beginthreadex(NULL,0,__UpdatePresetList,(void*)flags,0,0); + + if (!bBackground) + { + // crank up priority, wait for it to finish, and then return + SetThreadPriority(g_hThread,THREAD_PRIORITY_HIGHEST); //THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_HIGHEST, + + // wait for it to finish + while (g_bThreadAlive) + Sleep(30); + + assert(g_hThread != INVALID_HANDLE_VALUE); + CloseHandle(g_hThread); + g_hThread = INVALID_HANDLE_VALUE; + } + else + { + // it will just run in the background til it finishes. + // however, we want to wait until at least ~32 presets are found (or failure) before returning, + // so we know we have *something* in the preset list to start with. + + SetThreadPriority(g_hThread,THREAD_PRIORITY_HIGHEST); //THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_HIGHEST, + + // wait until either the thread exits, or # of presets is >32, 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<num_chars_to_shift; i++) + *(ptr + start + i) = *(ptr + start + i + how_far_to_shift); + } + else + { + for (int i=0; i<num_chars_to_shift; i++) + m_waitstring.szText[start + i] = m_waitstring.szText[start + i + how_far_to_shift]; + } + + // clear selection + m_waitstring.nCursorPos = start; + m_waitstring.nSelAnchorPos = -1; + } +} + +void CPlugin::WaitString_Cut() +{ + if (m_waitstring.bActive && + m_waitstring.nSelAnchorPos != -1) + { + WaitString_Copy(); + WaitString_NukeSelection(); + } +} + +void CPlugin::WaitString_Copy() +{ + if (m_waitstring.bActive && + m_waitstring.nSelAnchorPos != -1) + { + // 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 chars_to_copy = end - start + 1; + + if (m_waitstring.bDisplayAsCode) + { + char* ptr = (char*)m_waitstring.szText; + for (int i=0; i<chars_to_copy; i++) + m_waitstring.szClipboard[i] = *(ptr + start + i); + m_waitstring.szClipboard[chars_to_copy] = 0; + + char tmp[64000]; + ConvertLFCToCRsA(m_waitstring.szClipboard, tmp); + copyStringToClipboardA(tmp); + } + else + { + for (int i=0; i<chars_to_copy; i++) + m_waitstring.szClipboardW[i] = m_waitstring.szText[start + i]; + m_waitstring.szClipboardW[chars_to_copy] = 0; + + wchar_t tmp[64000]; + ConvertLFCToCRsW(m_waitstring.szClipboardW, tmp); + copyStringToClipboardW(tmp); + } + } +} + +void CPlugin::WaitString_Paste() +{ + // NOTE: if there is a selection, it is wiped out, and replaced with the clipboard contents. + + if (m_waitstring.bActive) + { + WaitString_NukeSelection(); + + if (m_waitstring.bDisplayAsCode) + { + char tmp[64000]; + lstrcpyA(tmp, getStringFromClipboardA()); + ConvertCRsToLFCA(tmp, m_waitstring.szClipboard); + } + else + { + wchar_t tmp[64000]; + lstrcpyW(tmp, getStringFromClipboardW()); + ConvertCRsToLFCW(tmp, m_waitstring.szClipboardW); + } + + int len; + int chars_to_insert; + + if (m_waitstring.bDisplayAsCode) + { + len = lstrlenA((char*)m_waitstring.szText); + chars_to_insert = lstrlenA(m_waitstring.szClipboard); + } + else + { + len = lstrlenW(m_waitstring.szText); + chars_to_insert = lstrlenW(m_waitstring.szClipboardW); + } + + if (len + chars_to_insert + 1 >= 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; i<m_nPresets; i++) + { + if (wcscmp(p, m_presets[i].szFilename.c_str())==0) { + m_nPresetListCurPos = i; + break; + } + } + } + } + + // exit waitstring mode (return to load menu) + m_UI_mode = UI_LOAD; + m_waitstring.bActive = false; + } +} + +/* +void CPlugin::UpdatePresetRatings() +{ + if (!m_bEnableRating) + return; + + if (m_nRatingReadProgress==-1 || m_nRatingReadProgress==m_nPresets) + return; + + int k; + + if (m_nRatingReadProgress==0 && m_nDirs>0) + { + for (k=0; k<m_nDirs; k++) + { + m_presets[m_nRatingReadProgress].fRatingCum = 0.0f; + m_nRatingReadProgress++; + } + + if (!m_bInstaScan) + return; + } + + int presets_per_frame = m_bInstaScan ? 4096 : 1; + int k1 = m_nRatingReadProgress; + int k2 = min(m_nRatingReadProgress + presets_per_frame, m_nPresets); + for (k=k1; k<k2; k++) + { + char szFullPath[512]; + sprintf(szFullPath, "%s%s", m_szPresetDir, m_presets[k].szFilename.c_str()); + float f = GetPrivateProfileFloat("preset00", "fRating", 3.0f, szFullPath); + if (f < 0) f = 0; + if (f > 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; i<m_nPresets; i++) + m_presets[i].fRatingCum += change; + + /* keep in view: + -test switching dirs w/o loading a preset, and trying to change the rating + ->m_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<MAX_CUSTOM_MESSAGE_FONTS; n++) + { + wcscpy(m_CustomMessageFont[n].szFace, L"arial"); + m_CustomMessageFont[n].bBold = false; + m_CustomMessageFont[n].bItal = false; + m_CustomMessageFont[n].nColorR = 255; + m_CustomMessageFont[n].nColorG = 255; + m_CustomMessageFont[n].nColorB = 255; + } + + for (n=0; n<MAX_CUSTOM_MESSAGES; n++) + { + m_CustomMessage[n].szText[0] = 0; + m_CustomMessage[n].nFont = 0; + m_CustomMessage[n].fSize = 50.0f; // [0..100] note that size is not absolute, but relative to the size of the window + m_CustomMessage[n].x = 0.5f; + m_CustomMessage[n].y = 0.5f; + m_CustomMessage[n].randx = 0; + m_CustomMessage[n].randy = 0; + m_CustomMessage[n].growth = 1.0f; + m_CustomMessage[n].fTime = 1.5f; + m_CustomMessage[n].fFade = 0.2f; + + m_CustomMessage[n].bOverrideBold = false; + m_CustomMessage[n].bOverrideItal = false; + m_CustomMessage[n].bOverrideFace = false; + m_CustomMessage[n].bOverrideColorR = false; + m_CustomMessage[n].bOverrideColorG = false; + m_CustomMessage[n].bOverrideColorB = false; + m_CustomMessage[n].bBold = false; + m_CustomMessage[n].bItal = false; + wcscpy(m_CustomMessage[n].szFace, L"arial"); + m_CustomMessage[n].nColorR = 255; + m_CustomMessage[n].nColorG = 255; + m_CustomMessage[n].nColorB = 255; + m_CustomMessage[n].nRandR = 0; + m_CustomMessage[n].nRandG = 0; + m_CustomMessage[n].nRandB = 0; + } + + // Then read in the new file + for (n=0; n<MAX_CUSTOM_MESSAGE_FONTS; n++) + { + wchar_t szSectionName[32]; + swprintf(szSectionName, L"font%02d", n); + + // get face, bold, italic, x, y for this custom message FONT + GetPrivateProfileStringW(szSectionName,L"face",L"arial",m_CustomMessageFont[n].szFace,sizeof(m_CustomMessageFont[n].szFace), m_szMsgIniFile); + m_CustomMessageFont[n].bBold = GetPrivateProfileBoolW(szSectionName,L"bold",m_CustomMessageFont[n].bBold, m_szMsgIniFile); + m_CustomMessageFont[n].bItal = GetPrivateProfileBoolW(szSectionName,L"ital",m_CustomMessageFont[n].bItal, m_szMsgIniFile); + m_CustomMessageFont[n].nColorR = GetPrivateProfileIntW (szSectionName,L"r" ,m_CustomMessageFont[n].nColorR, m_szMsgIniFile); + m_CustomMessageFont[n].nColorG = GetPrivateProfileIntW (szSectionName,L"g" ,m_CustomMessageFont[n].nColorG, m_szMsgIniFile); + m_CustomMessageFont[n].nColorB = GetPrivateProfileIntW (szSectionName,L"b" ,m_CustomMessageFont[n].nColorB, m_szMsgIniFile); + } + + for (n=0; n<MAX_CUSTOM_MESSAGES; n++) + { + wchar_t szSectionName[64]; + swprintf(szSectionName, L"message%02d", n); + + // get fontID, size, text, etc. for this custom message: + GetPrivateProfileStringW(szSectionName,L"text",L"",m_CustomMessage[n].szText,sizeof(m_CustomMessage[n].szText), m_szMsgIniFile); + if (m_CustomMessage[n].szText[0]) + { + m_CustomMessage[n].nFont = GetPrivateProfileIntW (szSectionName,L"font" ,m_CustomMessage[n].nFont, m_szMsgIniFile); + m_CustomMessage[n].fSize = GetPrivateProfileFloatW(szSectionName,L"size" ,m_CustomMessage[n].fSize, m_szMsgIniFile); + m_CustomMessage[n].x = GetPrivateProfileFloatW(szSectionName,L"x" ,m_CustomMessage[n].x, m_szMsgIniFile); + m_CustomMessage[n].y = GetPrivateProfileFloatW(szSectionName,L"y" ,m_CustomMessage[n].y, m_szMsgIniFile); + m_CustomMessage[n].randx = GetPrivateProfileFloatW(szSectionName,L"randx" ,m_CustomMessage[n].randx, m_szMsgIniFile); + m_CustomMessage[n].randy = GetPrivateProfileFloatW(szSectionName,L"randy" ,m_CustomMessage[n].randy, m_szMsgIniFile); + + m_CustomMessage[n].growth = GetPrivateProfileFloatW(szSectionName,L"growth",m_CustomMessage[n].growth, m_szMsgIniFile); + m_CustomMessage[n].fTime = GetPrivateProfileFloatW(szSectionName,L"time" ,m_CustomMessage[n].fTime, m_szMsgIniFile); + m_CustomMessage[n].fFade = GetPrivateProfileFloatW(szSectionName,L"fade" ,m_CustomMessage[n].fFade, m_szMsgIniFile); + m_CustomMessage[n].nColorR = GetPrivateProfileIntW (szSectionName,L"r" ,m_CustomMessage[n].nColorR, m_szMsgIniFile); + m_CustomMessage[n].nColorG = GetPrivateProfileIntW (szSectionName,L"g" ,m_CustomMessage[n].nColorG, m_szMsgIniFile); + m_CustomMessage[n].nColorB = GetPrivateProfileIntW (szSectionName,L"b" ,m_CustomMessage[n].nColorB, m_szMsgIniFile); + m_CustomMessage[n].nRandR = GetPrivateProfileIntW (szSectionName,L"randr" ,m_CustomMessage[n].nRandR, m_szMsgIniFile); + m_CustomMessage[n].nRandG = GetPrivateProfileIntW (szSectionName,L"randg" ,m_CustomMessage[n].nRandG, m_szMsgIniFile); + m_CustomMessage[n].nRandB = GetPrivateProfileIntW (szSectionName,L"randb" ,m_CustomMessage[n].nRandB, m_szMsgIniFile); + + // overrides: r,g,b,face,bold,ital + GetPrivateProfileStringW(szSectionName,L"face",L"",m_CustomMessage[n].szFace,sizeof(m_CustomMessage[n].szFace), m_szMsgIniFile); + m_CustomMessage[n].bBold = GetPrivateProfileIntW (szSectionName, L"bold", -1, m_szMsgIniFile); + m_CustomMessage[n].bItal = GetPrivateProfileIntW (szSectionName, L"ital", -1, m_szMsgIniFile); + m_CustomMessage[n].nColorR = GetPrivateProfileIntW (szSectionName, L"r" , -1, m_szMsgIniFile); + m_CustomMessage[n].nColorG = GetPrivateProfileIntW (szSectionName, L"g" , -1, m_szMsgIniFile); + m_CustomMessage[n].nColorB = GetPrivateProfileIntW (szSectionName, L"b" , -1, m_szMsgIniFile); + + m_CustomMessage[n].bOverrideFace = (m_CustomMessage[n].szFace[0] != 0); + m_CustomMessage[n].bOverrideBold = (m_CustomMessage[n].bBold != -1); + m_CustomMessage[n].bOverrideItal = (m_CustomMessage[n].bItal != -1); + m_CustomMessage[n].bOverrideColorR = (m_CustomMessage[n].nColorR != -1); + m_CustomMessage[n].bOverrideColorG = (m_CustomMessage[n].nColorG != -1); + m_CustomMessage[n].bOverrideColorB = (m_CustomMessage[n].nColorB != -1); + } + } +} + +void CPlugin::LaunchCustomMessage(int nMsgNum) +{ + if (nMsgNum > 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<NUM_TEX; x++) + { + if (!m_texmgr.m_tex[x].pSurface) + { + nSlot = x; + break; + } + else if (m_texmgr.m_tex[x].nStartFrame < oldest_frame) + { + oldest_index = x; + oldest_frame = m_texmgr.m_tex[x].nStartFrame; + } + } + + if (nSlot == -1) + { + nSlot = oldest_index; + m_texmgr.KillTex(nSlot); + } + } + + int ret = m_texmgr.LoadTex(img, nSlot, initcode, code, GetTime(), GetFrame(), ck); + m_texmgr.m_tex[nSlot].nUserData = nSpriteNum; + + wchar_t buf[1024]; + switch(ret & TEXMGR_ERROR_MASK) + { + case TEXMGR_ERR_SUCCESS: + switch(ret & TEXMGR_WARNING_MASK) + { + case TEXMGR_WARN_ERROR_IN_INIT_CODE: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_WARNING_ERROR_IN_INIT_CODE), nSpriteNum); + AddError(buf, 6.0f, ERR_MISC, true); + break; + case TEXMGR_WARN_ERROR_IN_REG_CODE: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_WARNING_ERROR_IN_PER_FRAME_CODE), nSpriteNum); + AddError(buf, 6.0f, ERR_MISC, true); + break; + default: + // success; no errors OR warnings. + break; + } + break; + case TEXMGR_ERR_BAD_INDEX: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_ERROR_BAD_SLOT_INDEX), nSpriteNum); + AddError(buf, 6.0f, ERR_MISC, true); + break; + /* + case TEXMGR_ERR_OPENING: sprintf(m_szUserMessage, "sprite #%d error: unable to open imagefile", nSpriteNum); break; + case TEXMGR_ERR_FORMAT: sprintf(m_szUserMessage, "sprite #%d error: file is corrupt or non-jpeg image", nSpriteNum); break; + case TEXMGR_ERR_IMAGE_NOT_24_BIT: sprintf(m_szUserMessage, "sprite #%d error: image does not have 3 color channels", nSpriteNum); break; + case TEXMGR_ERR_IMAGE_TOO_LARGE: sprintf(m_szUserMessage, "sprite #%d error: image is too large", nSpriteNum); break; + case TEXMGR_ERR_CREATESURFACE_FAILED: sprintf(m_szUserMessage, "sprite #%d error: createsurface() failed", nSpriteNum); break; + case TEXMGR_ERR_LOCKSURFACE_FAILED: sprintf(m_szUserMessage, "sprite #%d error: lock() failed", nSpriteNum); break; + case TEXMGR_ERR_CORRUPT_JPEG: sprintf(m_szUserMessage, "sprite #%d error: jpeg is corrupt", nSpriteNum); break; + */ + case TEXMGR_ERR_BADFILE: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_ERROR_IMAGE_FILE_MISSING_OR_CORRUPT), nSpriteNum); + AddError(buf, 6.0f, ERR_MISC, true); + break; + case TEXMGR_ERR_OUTOFMEM: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_ERROR_OUT_OF_MEM), nSpriteNum); + AddError(buf, 6.0f, ERR_MISC, true); + break; + } + + return (ret & TEXMGR_ERROR_MASK) ? false : true; +} + +void CPlugin::KillSprite(int iSlot) +{ + m_texmgr.KillTex(iSlot); +} + +void CPlugin::DoCustomSoundAnalysis() +{ + memcpy(mysound.fWave[0], m_sound.fWaveform[0], sizeof(float)*576); + memcpy(mysound.fWave[1], m_sound.fWaveform[1], sizeof(float)*576); + + // do our own [UN-NORMALIZED] fft + float fWaveLeft[576]; + int i = 0; + for (i=0; i<576; i++) + fWaveLeft[i] = m_sound.fWaveform[0][i]; + + memset(mysound.fSpecLeft, 0, sizeof(float)*MY_FFT_SAMPLES); + + myfft.time_to_frequency_domain(fWaveLeft, mysound.fSpecLeft); + //for (i=0; i<MY_FFT_SAMPLES; i++) fSpecLeft[i] = sqrtf(fSpecLeft[i]*fSpecLeft[i] + fSpecTemp[i]*fSpecTemp[i]); + + // sum spectrum up into 3 bands + + for (i=0; i<3; i++) + { + // note: only look at bottom half of spectrum! (hence divide by 6 instead of 3) + int start = MY_FFT_SAMPLES*i/6; + int end = MY_FFT_SAMPLES*(i+1)/6; + int j; + + mysound.imm[i] = 0; + + for (j=start; j<end; j++) + mysound.imm[i] += mysound.fSpecLeft[j]; + } + + // do temporal blending to create attenuated and super-attenuated versions + for (i=0; i<3; i++) + { + float rate; + + if (mysound.imm[i] > 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/Src/Plugins/Visualization/vis_milk2/plugin.dsp b/Src/Plugins/Visualization/vis_milk2/plugin.dsp new file mode 100644 index 00000000..e8ed2a95 --- /dev/null +++ b/Src/Plugins/Visualization/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/Src/Plugins/Visualization/vis_milk2/plugin.h b/Src/Plugins/Visualization/vis_milk2/plugin.h new file mode 100644 index 00000000..440205bb --- /dev/null +++ b/Src/Plugins/Visualization/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 <vector> + +#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 std::vector<ErrorMsg> ErrorMsgList; + +typedef std::vector<CShaderParams*> 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 std::vector<TexSizeParamInfo> 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 std::vector<PresetInfo> 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 std::vector<TexInfo> 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/Src/Plugins/Visualization/vis_milk2/plugin.rc b/Src/Plugins/Visualization/vis_milk2/plugin.rc new file mode 100644 index 00000000..aff9fb84 --- /dev/null +++ b/Src/Plugins/Visualization/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 +// +#include "../../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,25,4,0 + PRODUCTVERSION WINAMP_PRODUCTVER + 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", "Winamp SA" + VALUE "FileDescription", "Winamp Visualization Plug-in" + VALUE "FileVersion", "2,25,4,0" + VALUE "InternalName", "Nullsoft Milkdrop v2" + VALUE "LegalCopyright", "Copyright © 2001-2023 Winamp SA" + VALUE "OriginalFilename", "vis_milk2.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + 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 "<untitled menu item>" + IDS_UNTITLED_MENU "<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 "<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/Src/Plugins/Visualization/vis_milk2/plugin.vcxproj b/Src/Plugins/Visualization/vis_milk2/plugin.vcxproj new file mode 100644 index 00000000..67ca4c8d --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/plugin.vcxproj @@ -0,0 +1,419 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>vis_milk2</ProjectName> + <ProjectGuid>{881FB534-7396-485A-ADC2-6FBEBED7A0F4}</ProjectGuid> + <RootNamespace>vis_milk2</RootNamespace> + <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnableManifest>false</VcpkgEnableManifest> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgConfiguration>Debug</VcpkgConfiguration> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\..\;..\..\..\Wasabi;..\..\..\external_dependencies\microsoft_directx_sdk_2010\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_DEBUG;_WINDOWS;USE_VIS_HDR_HWND;STRSAFE_NO_DEPRECATE;NSEEL_REENTRANT_EXECUTION;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4473;4477;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <BufferSecurityCheck>true</BufferSecurityCheck> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>vms_desktop.lib;d3d9.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <AdditionalLibraryDirectories>..\..\..\external_dependencies\microsoft_directx_sdk_2010\Lib\$(PlatformShortName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <DelayLoadDLLs>vms_desktop.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(intDir)$(ProjectName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ + +xcopy /Y /D /S ..\..\..\resources\data\Milkdrop2 ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +xcopy /Y /D /S ..\..\..\resources\data\milk2_msg.ini ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +xcopy /Y /D /S ..\..\..\resources\data\milk2_img.ini ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +</Command> + <Message>Copy resources: Milkdrop2, milk2_msg.ini, milk2_img.ini to ..\..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\</Message> + </PostBuildEvent> + <ProjectReference> + <UseLibraryDependencyInputs>false</UseLibraryDependencyInputs> + </ProjectReference> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\..\;..\..\..\Wasabi;..\..\..\external_dependencies\microsoft_directx_sdk_2010\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;WIN64;_DEBUG;_WINDOWS;USE_VIS_HDR_HWND;STRSAFE_NO_DEPRECATE;NSEEL_REENTRANT_EXECUTION;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>false</MinimalRebuild> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4473;4477;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <BufferSecurityCheck>true</BufferSecurityCheck> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>vms_desktop.lib;d3d9.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <AdditionalLibraryDirectories>..\..\..\..\external_dependencies\microsoft_directx_sdk_2010\Lib\$(PlatformShortName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>true</GenerateDebugInformation> + <DelayLoadDLLs>vms_desktop.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(intDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ + +xcopy /Y /D /S ..\..\..\..\resources\data\Milkdrop2 ..\..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +xcopy /Y /D /S ..\..\..\..\resources\data\milk2_msg.ini ..\..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +xcopy /Y /D /S ..\..\..\..\resources\data\milk2_img.ini ..\..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +</Command> + <Message>Copy resources: Milkdrop2, milk2_msg.ini, milk2_img.ini to ..\..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> + <AdditionalIncludeDirectories>..\..\..\;..\..\..\Wasabi;..\..\..\external_dependencies\microsoft_directx_sdk_2010\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;NDEBUG;_WINDOWS;USE_VIS_HDR_HWND;STRSAFE_NO_DEPRECATE;NSEEL_REENTRANT_EXECUTION;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <CompileAs>Default</CompileAs> + <DisableSpecificWarnings>4473;4477;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>vms_desktop.lib;d3d9.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <AdditionalLibraryDirectories>..\..\..\external_dependencies\microsoft_directx_sdk_2010\Lib\$(PlatformShortName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>false</GenerateDebugInformation> + <DelayLoadDLLs>vms_desktop.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(intDir)$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D /S ..\..\..\resources\data\Milkdrop2 ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +xcopy /Y /D /S ..\..\..\resources\data\milk2_msg.ini ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +xcopy /Y /D /S ..\..\..\resources\data\milk2_img.ini ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +</Command> + <Message>Copy resources: Milkdrop2, milk2_msg.ini, milk2_img.ini to ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>MinSpace</Optimization> + <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> + <AdditionalIncludeDirectories>..\..\..\;..\..\..\Wasabi;..\..\..\external_dependencies\microsoft_directx_sdk_2010\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;WIN64;NDEBUG;_WINDOWS;USE_VIS_HDR_HWND;STRSAFE_NO_DEPRECATE;NSEEL_REENTRANT_EXECUTION;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <BufferSecurityCheck>true</BufferSecurityCheck> + <FunctionLevelLinking>true</FunctionLevelLinking> + <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope> + <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation> + <ObjectFileName>$(IntDir)</ObjectFileName> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>None</DebugInformationFormat> + <CompileAs>Default</CompileAs> + <DisableSpecificWarnings>4473;4477;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <Culture>0x0409</Culture> + </ResourceCompile> + <Link> + <AdditionalDependencies>vms_desktop.lib;d3d9.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <AdditionalLibraryDirectories>..\..\..\external_dependencies\microsoft_directx_sdk_2010\Lib\$(PlatformShortName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <GenerateDebugInformation>false</GenerateDebugInformation> + <DelayLoadDLLs>vms_desktop.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(intDir)$(TargetName).lib</ImportLibrary> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ +xcopy /Y /D /S ..\..\..\resources\data\Milkdrop2 ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +xcopy /Y /D /S ..\..\..\resources\data\milk2_msg.ini ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +xcopy /Y /D /S ..\..\..\resources\data\milk2_img.ini ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\Milkdrop2\ +</Command> + <Message>Copy resources: Milkdrop2, milk2_msg.ini, milk2_img.ini to ..\..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="ns-eel2\nseel-caltab.c" /> + <ClCompile Include="ns-eel2\nseel-cfunc.c" /> + <ClCompile Include="ns-eel2\nseel-compiler.c" /> + <ClCompile Include="ns-eel2\nseel-eval.c" /> + <ClCompile Include="ns-eel2\nseel-lextab.c" /> + <ClCompile Include="ns-eel2\nseel-ram.c" /> + <ClCompile Include="ns-eel2\nseel-yylex.c" /> + <ClCompile Include="config.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="config2.cpp" /> + <ClCompile Include="desktop_mode.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="dxcontext.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="fft.cpp" /> + <ClCompile Include="menu.cpp" /> + <ClCompile Include="milkdropfs.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="plugin.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="pluginshell.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="state.cpp" /> + <ClCompile Include="support.cpp" /> + <ClCompile Include="texmgr.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="textmgr.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="utility.cpp"> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">_MBCS;</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_MBCS;</PreprocessorDefinitions> + </ClCompile> + <ClCompile Include="vis.cpp" /> + </ItemGroup> + <ItemGroup> + <Image Include="plugin_icon.ico" /> + <Image Include="temp.ico" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\..\nu\AutoCharFn.h" /> + <ClInclude Include="api__vis_milk2.h" /> + <ClInclude Include="defines.h" /> + <ClInclude Include="dxcontext.h" /> + <ClInclude Include="fft.h" /> + <ClInclude Include="gstring.h" /> + <ClInclude Include="icon_t.h" /> + <ClInclude Include="md_defines.h" /> + <ClInclude Include="menu.h" /> + <ClInclude Include="plugin.h" /> + <ClInclude Include="pluginshell.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="shell_defines.h" /> + <ClInclude Include="state.h" /> + <ClInclude Include="support.h" /> + <ClInclude Include="texmgr.h" /> + <ClInclude Include="textmgr.h" /> + <ClInclude Include="utility.h" /> + <ClInclude Include="vis.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="plugin.rc" /> + </ItemGroup> + <ItemGroup> + <Text Include="DOCUMENTATION.TXT" /> + </ItemGroup> + <ItemGroup> + <None Include="milkdrop.nsi" /> + <None Include="text1.bin" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\tataki\tataki.vcxproj"> + <Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project> + </ProjectReference> + <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Visualization/vis_milk2/plugin.vcxproj.filters b/Src/Plugins/Visualization/vis_milk2/plugin.vcxproj.filters new file mode 100644 index 00000000..d271a059 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/plugin.vcxproj.filters @@ -0,0 +1,164 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="vis.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="utility.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="textmgr.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="texmgr.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="support.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="state.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pluginshell.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="plugin.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ns-eel2\nseel-yylex.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ns-eel2\nseel-ram.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ns-eel2\nseel-lextab.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ns-eel2\nseel-eval.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ns-eel2\nseel-compiler.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ns-eel2\nseel-cfunc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ns-eel2\nseel-caltab.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="milkdropfs.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="menu.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="fft.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dxcontext.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="desktop_mode.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="config2.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="config.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="api__vis_milk2.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="defines.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="dxcontext.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="fft.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="gstring.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="icon_t.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="md_defines.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="menu.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="plugin.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="pluginshell.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="shell_defines.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="state.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="support.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="vis.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="utility.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="textmgr.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="texmgr.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\nu\AutoCharFn.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <Image Include="temp.ico"> + <Filter>Image Files</Filter> + </Image> + <Image Include="plugin_icon.ico"> + <Filter>Image Files</Filter> + </Image> + </ItemGroup> + <ItemGroup> + <None Include="milkdrop.nsi" /> + <None Include="text1.bin" /> + </ItemGroup> + <ItemGroup> + <Text Include="DOCUMENTATION.TXT" /> + </ItemGroup> + <ItemGroup> + <Filter Include="Header Files"> + <UniqueIdentifier>{ce7fdde7-654e-45a5-b681-4fcbef840d29}</UniqueIdentifier> + </Filter> + <Filter Include="Ressource Files"> + <UniqueIdentifier>{4855ad07-70ea-4062-a58a-c2b86cd50226}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files"> + <UniqueIdentifier>{e2bc9640-36e0-4507-a344-217bd59e980a}</UniqueIdentifier> + </Filter> + <Filter Include="Image Files"> + <UniqueIdentifier>{afa2593b-8914-4582-8765-a249b22e82af}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="plugin.rc"> + <Filter>Ressource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/Plugins/Visualization/vis_milk2/plugin_icon.ico b/Src/Plugins/Visualization/vis_milk2/plugin_icon.ico Binary files differnew file mode 100644 index 00000000..a48a54f3 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/plugin_icon.ico diff --git a/Src/Plugins/Visualization/vis_milk2/pluginshell.cpp b/Src/Plugins/Visualization/vis_milk2/pluginshell.cpp new file mode 100644 index 00000000..cd79a410 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/pluginshell.cpp @@ -0,0 +1,3693 @@ +/* + 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__vis_milk2.h" +#include "pluginshell.h" +#include "utility.h" +#include "defines.h" +#include "shell_defines.h" +#include "resource.h" +#include "vis.h" +#include <multimon.h> +#include "../Winamp/wa_ipc.h" +#include "../nu/AutoCharFn.h" +#include <mmsystem.h> +#pragma comment(lib,"winmm.lib") // for timeGetTime + +// STATE VALUES & VERTEX FORMATS FOR HELP SCREEN TEXTURE: +#define TEXT_SURFACE_NOT_READY 0 +#define TEXT_SURFACE_REQUESTED 1 +#define TEXT_SURFACE_READY 2 +#define TEXT_SURFACE_ERROR 3 +typedef struct _HELPVERTEX +{ + float x, y; // screen position + float z; // Z-buffer depth + DWORD Diffuse; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims) + float tu, tv; // texture coordinates for texture #0 +} HELPVERTEX, *LPHELPVERTEX; +#define HELP_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) +typedef struct _SIMPLEVERTEX +{ + float x, y; // screen position + float z; // Z-buffer depth + DWORD Diffuse; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims) +} SIMPLEVERTEX, *LPSIMPLEVERTEX; +#define SIMPLE_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE) + +extern wchar_t* g_szHelp; +extern int g_szHelp_W; +extern winampVisModule mod1; + +// resides in vms_desktop.dll/lib: +void getItemData(int x); + + +CPluginShell::CPluginShell() +{ + // this should remain empty! +} + +CPluginShell::~CPluginShell() +{ + // this should remain empty! +} + +eScrMode CPluginShell::GetScreenMode() +{ + return m_screenmode; +} +int CPluginShell::GetFrame() +{ + return m_frame; +} +float CPluginShell::GetTime() +{ + return m_time; +} +float CPluginShell::GetFps() +{ + return m_fps; +} +HWND CPluginShell::GetPluginWindow() +{ + if (m_lpDX) return m_lpDX->GetHwnd(); else return NULL; +} +int CPluginShell::GetWidth() +{ + if (m_lpDX) return m_lpDX->m_client_width; else return 0; +} +int CPluginShell::GetHeight() +{ + if (m_lpDX) return m_lpDX->m_client_height; else return 0; +} +int CPluginShell::GetCanvasMarginX() +{ + if (m_lpDX && m_screenmode==WINDOWED) return (m_lpDX->m_client_width - m_lpDX->m_REAL_client_width)/2; else return 0; +} +int CPluginShell::GetCanvasMarginY() +{ + if (m_lpDX && m_screenmode==WINDOWED) return (m_lpDX->m_client_height - m_lpDX->m_REAL_client_height)/2; else return 0; +} +HWND CPluginShell::GetWinampWindow() +{ + return m_hWndWinamp; +} +HINSTANCE CPluginShell::GetInstance() +{ + return m_hInstance; +} +wchar_t* CPluginShell::GetPluginsDirPath() +{ + return m_szPluginsDirPath; +} +wchar_t* CPluginShell::GetConfigIniFile() +{ + return m_szConfigIniFile; +} +char* CPluginShell::GetConfigIniFileA() +{ + return m_szConfigIniFileA; +} +int CPluginShell::GetFontHeight(eFontIndex idx) +{ + if (idx >= 0 && idx < NUM_BASIC_FONTS + NUM_EXTRA_FONTS) return m_fontinfo[idx].nSize; else return 0; +} +int CPluginShell::GetBitDepth() +{ + return m_lpDX->GetBitDepth(); +} +LPDIRECT3DDEVICE9 CPluginShell::GetDevice() +{ + if (m_lpDX) return m_lpDX->m_lpDevice; else return NULL; +} +D3DCAPS9* CPluginShell::GetCaps() +{ + if (m_lpDX) return &(m_lpDX->m_caps); else return NULL; +} +D3DFORMAT CPluginShell::GetBackBufFormat() +{ + if (m_lpDX) return m_lpDX->m_current_mode.display_mode.Format; else return D3DFMT_UNKNOWN; +} +D3DFORMAT CPluginShell::GetBackBufZFormat() +{ + if (m_lpDX) return m_lpDX->GetZFormat(); else return D3DFMT_UNKNOWN; +} +LPD3DXFONT CPluginShell::GetFont(eFontIndex idx) +{ + if (idx >= 0 && idx < NUM_BASIC_FONTS + NUM_EXTRA_FONTS) return m_d3dx_font[idx]; else return NULL; +} +char* CPluginShell::GetDriverFilename() +{ + if (m_lpDX) return m_lpDX->GetDriver(); else return NULL; +} +char* CPluginShell::GetDriverDescription() +{ + if (m_lpDX) return m_lpDX->GetDesc(); else return NULL; +} + +int CPluginShell::InitNondx9Stuff() +{ + timeBeginPeriod(1); + m_fftobj.Init(576, NUM_FREQUENCIES); + if (!InitGDIStuff()) return false; + return AllocateMyNonDx9Stuff(); +} + +void CPluginShell::CleanUpNondx9Stuff() +{ + timeEndPeriod(1); + CleanUpMyNonDx9Stuff(); + CleanUpGDIStuff(); + m_fftobj.CleanUp(); +} + +int CPluginShell::InitGDIStuff() +{ + wchar_t title[64]; + // note: messagebox parent window should be NULL here, because lpDX is still NULL! + for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + { + if (!(m_font[i] = CreateFontW(m_fontinfo[i].nSize, 0, 0, 0, m_fontinfo[i].bBold ? 900 : 400, m_fontinfo[i].bItalic, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, m_fontinfo[i].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY, DEFAULT_PITCH, m_fontinfo[i].szFace))) + { + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_GDI_FONTS), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + } + + if (!(m_main_menu = WASABI_API_LOADMENU(IDR_WINDOWED_CONTEXT_MENU))) + { + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_LOADING_MAIN_MENU), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + if (!(m_context_menu = GetSubMenu(m_main_menu, 0))) + { + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_LOADING_CONTEXT_MENU), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + return true; +} + +void CPluginShell::CleanUpGDIStuff() +{ + for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + { + if (m_font[i]) + { + DeleteObject(m_font[i]); + m_font[i] = NULL; + } + } + + /*if (m_context_menu) + { + DestroyMenu(m_context_menu); + m_context_menu = NULL; + }*/ + + if (m_main_menu) + { + DestroyMenu(m_main_menu); + m_main_menu = NULL; + } + + //CleanUpMyGDIStuff(); +} + +int CPluginShell::InitVJStuff(RECT* pClientRect) +{ + wchar_t title[64]; + // Init VJ mode (second window for text): + if (m_vj_mode) + { + DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU; + POINT upper_left_corner; + upper_left_corner.x = 0; + upper_left_corner.y = 0; + + // Create direct 3d & get some infos + if (!(m_vjd3d9 = Direct3DCreate9(D3D_SDK_VERSION))) + { + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_DIRECT3D_DEVICE_FOR_VJ_MODE), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + // Get ordinal adapter # for the currently-selected Windowed Mode display adapter + int ordinal_adapter = D3DADAPTER_DEFAULT; + int nAdapters = m_vjd3d9->GetAdapterCount(); + for (int i=0; i<nAdapters; i++) + { + D3DADAPTER_IDENTIFIER9 temp; + if ((m_vjd3d9->GetAdapterIdentifier(i, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &temp) == D3D_OK) && + (memcmp(&temp.DeviceIdentifier, &m_adapter_guid_windowed, sizeof(GUID))==0)) + { + ordinal_adapter = i; + break; + } + } + + // Get current display mode for windowed-mode adapter: + D3DDISPLAYMODE dm; + if (D3D_OK != m_vjd3d9->GetAdapterDisplayMode(ordinal_adapter, &dm)) + { + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_VJ_MODE_INIT_ERROR), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + // And get the upper-left corner of the monitor for it: + HMONITOR hMon = m_vjd3d9->GetAdapterMonitor(ordinal_adapter); + if (hMon) + { + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(hMon, &mi)) + { + upper_left_corner.x = mi.rcWork.left; + upper_left_corner.y = mi.rcWork.top; + } + } + + // CREATE THE WINDOW + + RECT rect; + if (pClientRect) + { + rect = *pClientRect; + AdjustWindowRect(&rect, dwStyle, 0); // convert client->wnd + } + else + { + SetRect(&rect, 0, 0, 384, 384); + AdjustWindowRect(&rect, dwStyle, 0); // convert client->wnd + + rect.right -= rect.left; + rect.left = 0; + rect.bottom -= rect.top; + rect.top = 0; + + rect.top += upper_left_corner.y+32; + rect.left += upper_left_corner.x+32; + rect.right += upper_left_corner.x+32; + rect.bottom += upper_left_corner.y+32; + } + + WNDCLASS wc = {0}; + wc.lpfnWndProc = VJModeWndProc; // our window procedure + wc.hInstance = GetInstance(); // hInstance of DLL + wc.hIcon = LoadIcon(GetInstance(), MAKEINTRESOURCE(IDI_PLUGIN_ICON)); + wc.lpszClassName = TEXT_WINDOW_CLASSNAME; // our window class name + wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; // CS_DBLCLKS lets the window receive WM_LBUTTONDBLCLK, for toggling fullscreen mode... + wc.cbWndExtra = sizeof(DWORD); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); + + if (!RegisterClass(&wc)) + { + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_REGISTERING_WINDOW_CLASS_FOR_TEXT_WINDOW), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + m_bTextWindowClassRegistered = true; + + //DWORD nThreadID; + //CreateThread(NULL, 0, TextWindowThread, &rect, 0, &nThreadID); + + // Create the text window + m_hTextWnd = CreateWindowEx( + 0, + TEXT_WINDOW_CLASSNAME, // our window class name + TEXT_WINDOW_CLASSNAME, // use description for a window title + dwStyle, + rect.left, rect.top, // screen position (read from config) + rect.right - rect.left, rect.bottom - rect.top, // width & height of window (need to adjust client area later) + NULL, // parent window (winamp main window) + NULL, // no menu + GetInstance(), // hInstance of DLL + NULL + ); // no window creation data + + if (!m_hTextWnd) + { + MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_VJ_WINDOW), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + SetWindowLongPtr(m_hTextWnd, GWLP_USERDATA, (LONG_PTR)this); + + GetClientRect(m_hTextWnd, &rect); + m_nTextWndWidth = rect.right-rect.left; + m_nTextWndHeight = rect.bottom-rect.top; + + + // Create the device + D3DPRESENT_PARAMETERS pres_param; + ZeroMemory(&pres_param,sizeof(pres_param)); + pres_param.BackBufferCount = 0; + pres_param.BackBufferFormat = dm.Format; + pres_param.BackBufferWidth = rect.right - rect.left; + pres_param.BackBufferHeight = rect.bottom - rect.top; + pres_param.hDeviceWindow = m_hTextWnd; + pres_param.AutoDepthStencilFormat = D3DFMT_D16; + pres_param.EnableAutoDepthStencil = FALSE; + pres_param.SwapEffect = D3DSWAPEFFECT_DISCARD; + pres_param.MultiSampleType = D3DMULTISAMPLE_NONE; + pres_param.Flags = 0; + pres_param.FullScreen_RefreshRateInHz = 0; + pres_param.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//m_current_mode.allow_page_tearing ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//D3DPRESENT_INTERVAL_ONE; + //pres_param.FullScreen_PresentationInterval = 0; + pres_param.Windowed = TRUE; + + HRESULT hr; + if (D3D_OK != (hr = m_vjd3d9->CreateDevice(ordinal_adapter,//D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + m_hTextWnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &pres_param, + &m_vjd3d9_device))) + { + m_vjd3d9_device = NULL; + MessageBoxW(m_lpDX->GetHwnd(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_D3D_DEVICE_FOR_VJ_MODE), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + if (!AllocateFonts(m_vjd3d9_device)) + return false; + + if (m_fix_slow_text) // note that when not doing vj mode, m_lpDDSText is allocated in AllocateDX9Stuff + AllocateTextSurface(); + + m_text.Finish(); + m_text.Init(m_vjd3d9_device, m_lpDDSText, 0); + + m_bClearVJWindow = true; + } + + return true; +} + +void CPluginShell::CleanUpVJStuff() +{ + // ALWAYS set the textures to NULL before releasing textures, + // otherwise they might still have a hanging reference! + if (m_lpDX && m_lpDX->m_lpDevice) + { + for (int i=0; i<16; i++) + m_lpDX->m_lpDevice->SetTexture(i, NULL); + } + + if (m_vjd3d9_device) + { + for (int i=0; i<16; i++) + m_vjd3d9_device->SetTexture(i, NULL); + } + + if (!m_vj_mode) + return; + + // clean up VJ mode + { + CleanUpFonts(); + SafeRelease(m_lpDDSText); + + SafeRelease(m_vjd3d9_device); + SafeRelease(m_vjd3d9); + + if (m_hTextWnd) + { + //dumpmsg("Finish: destroying text window"); + DestroyWindow(m_hTextWnd); + m_hTextWnd = NULL; + //dumpmsg("Finish: text window destroyed"); + } + + if (m_bTextWindowClassRegistered) + { + //dumpmsg("Finish: unregistering text window class"); + UnregisterClass(TEXT_WINDOW_CLASSNAME,GetInstance()); // unregister window class + m_bTextWindowClassRegistered = false; + //dumpmsg("Finish: text window class unregistered"); + } + } +} + +int CPluginShell::AllocateFonts(IDirect3DDevice9* pDevice) +{ + // Create D3DX system font: + for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + if (pCreateFontW(pDevice, //m_font[i], + m_fontinfo[i].nSize, + m_fontinfo[i].nSize*4/10, + m_fontinfo[i].bBold ? 900 : 400, + 1, // mip levels + m_fontinfo[i].bItalic, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + m_fontinfo[i].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY, + DEFAULT_PITCH, + m_fontinfo[i].szFace, + &m_d3dx_font[i] + ) != D3D_OK) + { + wchar_t title[64]; + MessageBoxW(m_lpDX ? m_lpDX->GetHwnd() : NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_D3DX_FONTS), + WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + // get actual font heights + for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + { + RECT r; + SetRect(&r, 0, 0, 1024, 1024); + int h = m_d3dx_font[i]->DrawText(NULL, "M", -1, &r, DT_CALCRECT, 0xFFFFFFFF); + if (h>0) m_fontinfo[i].nSize = h; + } + + return true; +} + +void CPluginShell::CleanUpFonts() +{ + for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + SafeRelease(m_d3dx_font[i]); +} + +void CPluginShell::AllocateTextSurface() +{ + IDirect3DDevice9 *pDevice = m_vjd3d9_device ? m_vjd3d9_device : GetDevice(); + int w = m_vjd3d9_device ? m_nTextWndWidth : GetWidth() ; + int h = m_vjd3d9_device ? m_nTextWndHeight : GetHeight(); + + if (D3D_OK != pCreateTexture(pDevice, w, h, 1, D3DUSAGE_RENDERTARGET, GetBackBufFormat(), D3DPOOL_DEFAULT, &m_lpDDSText)) + m_lpDDSText = NULL; // OK if there's not enough mem for it! + else + { + // if m_lpDDSText doesn't cover enough of screen, cancel it. + D3DSURFACE_DESC desc; + if (D3D_OK == m_lpDDSText->GetLevelDesc(0, &desc)) + { + if ((desc.Width < 256 && w >= 256) || + (desc.Height < 256 && h >= 256) || + (desc.Width /(float)w < 0.74f) || + (desc.Height/(float)h < 0.74f) + ) + { + m_lpDDSText->Release(); + m_lpDDSText = NULL; + } + } + } +} + +int CPluginShell::AllocateDX9Stuff() +{ + if (!m_vj_mode) + { + AllocateFonts(m_lpDX->m_lpDevice); + if (m_fix_slow_text) // note that when not doing vj mode, m_lpDDSText is allocated in AllocateDX9Stuff + AllocateTextSurface(); + } + + /* + // Create D3DX system font: + for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + if (pCreateFontW(m_lpDX->m_lpDevice, + m_fontinfo[i].nSize, + m_fontinfo[i].nSize*4/10, + m_fontinfo[i].bBold ? 900 : 400, + 0, // mip levels + m_fontinfo[i].bItalic, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + m_fontinfo[i].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY, + DEFAULT_PITCH, + m_fontinfo[i].szFace, + &m_d3dx_font[i] + ) != D3D_OK) + { + MessageBox(m_lpDX->GetHwnd(), "Error creating D3DX fonts", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST); + return false; + } + + // get actual font heights + for (i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + { + RECT r; + SetRect(&r, 0, 0, 1024, 1024); + int h = m_d3dx_font[i]->DrawText(NULL, "M", -1, &r, DT_CALCRECT, 0xFFFFFFFF); + if (h>0) m_fontinfo[i].nSize = h; + } + */ + + if (m_screenmode == DESKTOP) + if (!InitDesktopMode()) + return false; + + int ret = AllocateMyDX9Stuff(); + + // invalidate various 'caches' here: + m_playlist_top_idx = -1; // invalidating playlist cache forces recompute of playlist width + //m_icon_list.clear(); // clear desktop mode icon list, so it has to read the bitmaps back in + + if (!m_vj_mode) + { + m_text.Finish(); + m_text.Init(GetDevice(), m_lpDDSText, 1); + } + + return ret; +} + +void CPluginShell::CleanUpDX9Stuff(int final_cleanup) +{ + // ALWAYS unbind the textures before releasing textures, + // otherwise they might still have a hanging reference! + if (m_lpDX && m_lpDX->m_lpDevice) + { + for (int i=0; i<16; i++) + m_lpDX->m_lpDevice->SetTexture(i, NULL); + } + + if (m_screenmode == DESKTOP) + CleanUpDesktopMode(); + + if (!m_vj_mode) + { + for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + SafeRelease(m_d3dx_font[i]); + SafeRelease(m_lpDDSText); + } + + CleanUpMyDX9Stuff(final_cleanup); +} + +void CPluginShell::OnUserResizeTextWindow() +{ + // Update window properties + RECT w, c; + GetWindowRect(m_hTextWnd, &w); + GetClientRect(m_hTextWnd, &c); + + WINDOWPLACEMENT wp; + ZeroMemory(&wp, sizeof(wp)); + wp.length = sizeof(wp); + GetWindowPlacement(m_hTextWnd, &wp); + + // convert client rect from client coords to screen coords: + // (window rect is already in screen coords...) + POINT p; + p.x = c.left; + p.y = c.top; + if (ClientToScreen(m_hTextWnd, &p)) + { + c.left += p.x; + c.right += p.x; + c.top += p.y; + c.bottom += p.y; + } + + if (wp.showCmd != SW_SHOWMINIMIZED) + { + if (m_nTextWndWidth != c.right-c.left || + m_nTextWndHeight != c.bottom-c.top) + { + CleanUpVJStuff(); + if (!InitVJStuff(&c)) + { + SuggestHowToFreeSomeMem(); + m_lpDX->m_ready = false; // flag to exit + return; + } + } + + // save the new window position: + //if (wp.showCmd==SW_SHOWNORMAL) + // SaveTextWindowPos(); + } +} + +void CPluginShell::OnUserResizeWindow() +{ + // Update window properties + RECT w, c; + GetWindowRect(m_lpDX->GetHwnd(), &w); + GetClientRect(m_lpDX->GetHwnd(), &c); + + WINDOWPLACEMENT wp; + ZeroMemory(&wp, sizeof(wp)); + wp.length = sizeof(wp); + GetWindowPlacement(m_lpDX->GetHwnd(), &wp); + + // convert client rect from client coords to screen coords: + // (window rect is already in screen coords...) + POINT p; + p.x = c.left; + p.y = c.top; + if (ClientToScreen(m_lpDX->GetHwnd(), &p)) + { + c.left += p.x; + c.right += p.x; + c.top += p.y; + c.bottom += p.y; + } + + if (wp.showCmd != SW_SHOWMINIMIZED) + { + int new_REAL_client_w = c.right-c.left; + int new_REAL_client_h = c.bottom-c.top; + + // kiv: could we just resize when the *snapped* w/h changes? slightly more ideal... + if (m_lpDX->m_REAL_client_width != new_REAL_client_w || + m_lpDX->m_REAL_client_height != new_REAL_client_h) + { + //CleanUpVJStuff(); + CleanUpDX9Stuff(0); + if (!m_lpDX->OnUserResizeWindow(&w, &c)) + { + // note: a basic warning messagebox will have already been given. + // now suggest specific advice on how to regain more video memory: + SuggestHowToFreeSomeMem(); + return; + } + if (!AllocateDX9Stuff()) + { + m_lpDX->m_ready = false; // flag to exit + return; + } + /*if (!InitVJStuff()) + { + m_lpDX->m_ready = false; // flag to exit + return; + }*/ + } + + // save the new window position: + if (wp.showCmd==SW_SHOWNORMAL) + m_lpDX->SaveWindow(); + } +} + +void CPluginShell::StuffParams(DXCONTEXT_PARAMS *pParams) +{ + pParams->screenmode = m_screenmode; + pParams->display_mode = m_disp_mode_fs; + pParams->nbackbuf = 1; + pParams->m_dualhead_horz = m_dualhead_horz; + pParams->m_dualhead_vert = m_dualhead_vert; + pParams->m_skin = (m_screenmode==WINDOWED) ? m_skin : 0; + switch (m_screenmode) + { + case WINDOWED: + pParams->allow_page_tearing = m_allow_page_tearing_w; + pParams->adapter_guid = m_adapter_guid_windowed; + pParams->multisamp = m_multisample_windowed; + strcpy(pParams->adapter_devicename, m_adapter_devicename_windowed); + break; + case FULLSCREEN: + case FAKE_FULLSCREEN: + pParams->allow_page_tearing = m_allow_page_tearing_fs; + pParams->adapter_guid = m_adapter_guid_fullscreen; + pParams->multisamp = m_multisample_fullscreen; + strcpy(pParams->adapter_devicename, m_adapter_devicename_fullscreen); + break; + case DESKTOP: + pParams->allow_page_tearing = m_allow_page_tearing_dm; + pParams->adapter_guid = m_adapter_guid_desktop; + pParams->multisamp = m_multisample_desktop; + strcpy(pParams->adapter_devicename, m_adapter_devicename_desktop); + break; + } + pParams->parent_window = (m_screenmode==DESKTOP) ? m_hWndDesktopListView : NULL; +} + +void CPluginShell::ToggleDesktop() +{ + CleanUpDX9Stuff(0); + + switch (m_screenmode) + { + case WINDOWED: + case FULLSCREEN: + case FAKE_FULLSCREEN: + m_screenmode = DESKTOP; + break; + case DESKTOP: + m_screenmode = WINDOWED; + break; + } + + DXCONTEXT_PARAMS params; + StuffParams(¶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 + int i = 0; + for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + m_d3dx_font[i] = NULL; + m_d3dx_desktop_font = NULL; + m_lpDDSText = NULL; + ZeroMemory(&m_sound, sizeof(td_soundinfo)); + for (int ch=0; ch<2; ch++) + for (i=0; i<3; i++) + { + m_sound.infinite_avg[ch][i] = m_sound.avg[ch][i] = m_sound.med_avg[ch][i] = m_sound.long_avg[ch][i] = 1.0f; + } + + // GENERAL PRIVATE STUFF + //m_screenmode: set at end (derived setting) + m_frame = 0; + m_time = 0; + m_fps = 30; + m_hWndWinamp = hWinampWnd; + m_hInstance = hWinampInstance; + m_lpDX = NULL; + m_szPluginsDirPath[0] = 0; // will be set further down + m_szConfigIniFile[0] = 0; // will be set further down + // m_szPluginsDirPath: + + wchar_t *p; + + if (hWinampWnd + && (p = (wchar_t *)SendMessage(hWinampWnd, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORYW)) + && p != (wchar_t *)1) + { + swprintf(m_szPluginsDirPath, L"%s\\", p); + } + else + { + // get path to INI file & read in prefs/settings right away, so DumpMsg works! + GetModuleFileNameW(m_hInstance, m_szPluginsDirPath, MAX_PATH); + wchar_t *p = m_szPluginsDirPath + wcslen(m_szPluginsDirPath); + while (p >= m_szPluginsDirPath && *p != L'\\') p--; + if (++p >= m_szPluginsDirPath) *p = 0; + } + + if (hWinampWnd + && (p = (wchar_t *)SendMessage(hWinampWnd, WM_WA_IPC, 0, IPC_GETINIDIRECTORYW)) + && p != (wchar_t *)1) + { + // load settings as well as coping with moving old settings to a contained folder + wchar_t m_szOldConfigIniFile[MAX_PATH] = {0}, temp[MAX_PATH] = {0}, temp2[MAX_PATH] = {0}; + swprintf(m_szOldConfigIniFile, L"%s\\Plugins\\%s", p, INIFILE); + swprintf(m_szConfigIniFile, L"%s\\Plugins\\%s%s", p, SUBDIR, INIFILE); + swprintf(temp, L"%s\\Plugins\\%s", p, SUBDIR); + swprintf(temp2, L"%s\\Plugins\\", p); + CreateDirectoryW(temp, NULL); + + if (PathFileExistsW(m_szOldConfigIniFile) && !PathFileExistsW(m_szConfigIniFile)) + { + MoveFileW(m_szOldConfigIniFile, m_szConfigIniFile); + + wchar_t m_szMsgIniFile[MAX_PATH] = {0}, m_szNewMsgIniFile[MAX_PATH] = {0}, + m_szImgIniFile[MAX_PATH] = {0}, m_szNewImgIniFile[MAX_PATH] = {0}, + m_szAdaptersFile[MAX_PATH] = {0}, m_szNewAdaptersFile[MAX_PATH] = {0}; + swprintf(m_szMsgIniFile, L"%s%s", temp2, MSG_INIFILE); + swprintf(m_szNewMsgIniFile, L"%s%s", temp, MSG_INIFILE); + swprintf(m_szImgIniFile, L"%s%s", temp2, IMG_INIFILE); + swprintf(m_szNewImgIniFile, L"%s%s", temp, IMG_INIFILE); + swprintf(m_szAdaptersFile, L"%s%s", temp2, ADAPTERSFILE); + swprintf(m_szNewAdaptersFile, L"%s%s", temp, ADAPTERSFILE); + + MoveFileW(m_szImgIniFile, m_szNewImgIniFile); + MoveFileW(m_szMsgIniFile, m_szNewMsgIniFile); + MoveFileW(m_szAdaptersFile, m_szNewAdaptersFile); + } + } + else + { + swprintf(m_szConfigIniFile, L"%s%s", m_szPluginsDirPath, INIFILE); + } + lstrcpyn(m_szConfigIniFileA,AutoCharFn(m_szConfigIniFile),MAX_PATH); + + // PRIVATE CONFIG PANEL SETTINGS + m_multisample_fullscreen = D3DMULTISAMPLE_NONE; + m_multisample_desktop = D3DMULTISAMPLE_NONE; + m_multisample_windowed = D3DMULTISAMPLE_NONE; + ZeroMemory(&m_adapter_guid_fullscreen, sizeof(GUID)); + ZeroMemory(&m_adapter_guid_desktop , sizeof(GUID)); + ZeroMemory(&m_adapter_guid_windowed , sizeof(GUID)); + m_adapter_devicename_windowed[0] = 0; + m_adapter_devicename_fullscreen[0] = 0; + m_adapter_devicename_desktop[0] = 0; + + + // PRIVATE RUNTIME SETTINGS + m_lost_focus = 0; + m_hidden = 0; + m_resizing = 0; + m_show_help = 0; + m_show_playlist = 0; + m_playlist_pos = 0; + m_playlist_pageups = 0; + m_playlist_top_idx = -1; + m_playlist_btm_idx = -1; + // m_playlist_width_pixels will be considered invalid whenever 'm_playlist_top_idx' is -1. + // m_playlist[256][256] will be considered invalid whenever 'm_playlist_top_idx' is -1. + m_exiting = 0; + m_upper_left_corner_y = 0; + m_lower_left_corner_y = 0; + m_upper_right_corner_y = 0; + m_lower_right_corner_y = 0; + m_left_edge = 0; + m_right_edge = 0; + m_force_accept_WM_WINDOWPOSCHANGING = 0; + + // PRIVATE - GDI STUFF + m_main_menu = NULL; + m_context_menu = NULL; + for (i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++) + m_font[i] = NULL; + m_font_desktop = NULL; + + // PRIVATE - DESKTOP MODE STUFF + m_icon_list.clear(); + for (i=0; i<MAX_ICON_TEXTURES; i++) + m_desktop_icons_texture[i] = NULL; + FindDesktopWindows(&m_hWndProgMan, &m_hWndDesktop, &m_hWndDesktopListView); + GetDesktopFolder(m_szDesktopFolder); + m_desktop_icon_size = 32; + m_desktop_dragging = 0; // '1' when user is dragging icons around + m_desktop_box = 0; // '1' when user is drawing a box + m_desktop_wc_registered = 0; + m_desktop_bk_color = 0xFF000000 | BGR2RGB(::GetSysColor(COLOR_BACKGROUND)); + m_desktop_text_color = 0xFF000000 | BGR2RGB(SendMessage(m_hWndDesktopListView, LVM_GETTEXTCOLOR, 0, 0)); + m_desktop_sel_color = 0xFF000000 | BGR2RGB(::GetSysColor(COLOR_HIGHLIGHT)); + m_desktop_sel_text_color = 0xFF000000 | BGR2RGB(::GetSysColor(COLOR_HIGHLIGHTTEXT)); + m_desktop_icon_state = 0; + m_desktop_icon_count = 0; + m_desktop_icon_update_frame = 0; + m_desktop_icons_disabled = 0; + m_vms_desktop_loaded = 0; + m_desktop_hook_set = 0; + + // PRIVATE - MORE TIMEKEEPING + m_last_raw_time = 0; + memset(m_time_hist, 0, sizeof(m_time_hist)); + m_time_hist_pos = 0; + if (!QueryPerformanceFrequency(&m_high_perf_timer_freq)) + m_high_perf_timer_freq.QuadPart = 0; + m_prev_end_of_frame.QuadPart = 0; + + // PRIVATE AUDIO PROCESSING DATA + //(m_fftobj needs no init) + memset(m_oldwave[0], 0, sizeof(float)*576); + memset(m_oldwave[1], 0, sizeof(float)*576); + m_prev_align_offset[0] = 0; + m_prev_align_offset[1] = 0; + m_align_weights_ready = 0; + + // SEPARATE TEXT WINDOW (FOR VJ MODE) + m_vj_mode = 0; + m_hidden_textwnd = 0; + m_resizing_textwnd = 0; + m_hTextWnd = NULL; + m_nTextWndWidth = 0; + m_nTextWndHeight = 0; + m_bTextWindowClassRegistered = false; + m_vjd3d9 = NULL; + m_vjd3d9_device = NULL; + + //----- + + m_screenmode = NOT_YET_KNOWN; + + OverrideDefaults(); + ReadConfig(); + + if (m_start_fullscreen) + { + m_screenmode = m_fake_fullscreen_mode ? FAKE_FULLSCREEN : FULLSCREEN; + if (m_screenmode == FULLSCREEN && SendMessage(GetWinampWindow(), WM_WA_IPC, 0, IPC_IS_PLAYING_VIDEO) > 1) + { + m_screenmode = FAKE_FULLSCREEN; + } + } + else if (m_start_desktop) + m_screenmode = DESKTOP; + else + m_screenmode = WINDOWED; + + MyPreInitialize(); + MyReadConfig(); + + //----- + + return TRUE; +} + +int CPluginShell::PluginInitialize() +{ + // note: initialize GDI before DirectX. Also separate them because + // when we change windowed<->fullscreen, or lose the device and restore it, + // we don't want to mess with any (persistent) GDI stuff. + + if (!InitDirectX()) return FALSE; // gives its own error messages + if (!InitNondx9Stuff()) return FALSE; // gives its own error messages + if (!AllocateDX9Stuff()) return FALSE; // gives its own error messages + if (!InitVJStuff()) return FALSE; + + return TRUE; +} + +void CPluginShell::PluginQuit() +{ + CleanUpVJStuff(); + CleanUpDX9Stuff(1); + CleanUpNondx9Stuff(); + CleanUpDirectX(); + + SetFocus(m_hWndWinamp); + SetActiveWindow(m_hWndWinamp); + SetForegroundWindow(m_hWndWinamp); +} + +wchar_t* BuildSettingName(wchar_t* name, int number){ +static wchar_t temp[64]; + swprintf(temp, L"%s%d", name, number); + return temp; +} + +void CPluginShell::READ_FONT(int n){ + GetPrivateProfileStringW(L"settings",BuildSettingName(L"szFontFace",n),m_fontinfo[n].szFace,m_fontinfo[n].szFace,sizeof(m_fontinfo[n].szFace), m_szConfigIniFile); + m_fontinfo[n].nSize = GetPrivateProfileIntW(L"settings",BuildSettingName(L"nFontSize",n),m_fontinfo[n].nSize ,m_szConfigIniFile); + m_fontinfo[n].bBold = GetPrivateProfileIntW(L"settings",BuildSettingName(L"bFontBold",n),m_fontinfo[n].bBold ,m_szConfigIniFile); + m_fontinfo[n].bItalic = GetPrivateProfileIntW(L"settings",BuildSettingName(L"bFontItalic",n),m_fontinfo[n].bItalic,m_szConfigIniFile); + m_fontinfo[n].bAntiAliased = GetPrivateProfileIntW(L"settings",BuildSettingName(L"bFontAA",n),m_fontinfo[n].bItalic,m_szConfigIniFile); +} + +void CPluginShell::ReadConfig() +{ + int old_ver = GetPrivateProfileIntW(L"settings",L"version" ,-1,m_szConfigIniFile); + int old_subver = GetPrivateProfileIntW(L"settings",L"subversion",-1,m_szConfigIniFile); + + // nuke old settings from prev. version: + if (old_ver < INT_VERSION) + return; + else if (old_subver < INT_SUBVERSION) + return; + + //D3DMULTISAMPLE_TYPE m_multisample_fullscreen; + //D3DMULTISAMPLE_TYPE m_multisample_desktop; + //D3DMULTISAMPLE_TYPE m_multisample_windowed; + m_multisample_fullscreen = (D3DMULTISAMPLE_TYPE)GetPrivateProfileIntW(L"settings",L"multisample_fullscreen",m_multisample_fullscreen,m_szConfigIniFile); + m_multisample_desktop = (D3DMULTISAMPLE_TYPE)GetPrivateProfileIntW(L"settings",L"multisample_desktop",m_multisample_desktop,m_szConfigIniFile); + m_multisample_windowed = (D3DMULTISAMPLE_TYPE)GetPrivateProfileIntW(L"settings",L"multisample_windowed" ,m_multisample_windowed ,m_szConfigIniFile); + + //GUID m_adapter_guid_fullscreen + //GUID m_adapter_guid_desktop + //GUID m_adapter_guid_windowed + char str[256]; + GetPrivateProfileString("settings","adapter_guid_fullscreen","",str,sizeof(str)-1,m_szConfigIniFileA); + TextToGuid(str, &m_adapter_guid_fullscreen); + GetPrivateProfileString("settings","adapter_guid_desktop","",str,sizeof(str)-1,m_szConfigIniFileA); + TextToGuid(str, &m_adapter_guid_desktop); + GetPrivateProfileString("settings","adapter_guid_windowed","",str,sizeof(str)-1,m_szConfigIniFileA); + TextToGuid(str, &m_adapter_guid_windowed); + GetPrivateProfileString("settings","adapter_devicename_fullscreen","",m_adapter_devicename_fullscreen,sizeof(m_adapter_devicename_fullscreen)-1,m_szConfigIniFileA); + GetPrivateProfileString("settings","adapter_devicename_desktop", "",m_adapter_devicename_desktop ,sizeof(m_adapter_devicename_desktop)-1,m_szConfigIniFileA); + GetPrivateProfileString("settings","adapter_devicename_windowed", "",m_adapter_devicename_windowed ,sizeof(m_adapter_devicename_windowed)-1,m_szConfigIniFileA); + + // FONTS + READ_FONT(0); + READ_FONT(1); + READ_FONT(2); + READ_FONT(3); +#if (NUM_EXTRA_FONTS >= 1) + READ_FONT(4); +#endif +#if (NUM_EXTRA_FONTS >= 2) + READ_FONT(5); +#endif +#if (NUM_EXTRA_FONTS >= 3) + READ_FONT(6); +#endif +#if (NUM_EXTRA_FONTS >= 4) + READ_FONT(7); +#endif +#if (NUM_EXTRA_FONTS >= 5) + READ_FONT(8); +#endif + + m_start_fullscreen = GetPrivateProfileIntW(L"settings",L"start_fullscreen",m_start_fullscreen,m_szConfigIniFile); + m_start_desktop = GetPrivateProfileIntW(L"settings",L"start_desktop" ,m_start_desktop ,m_szConfigIniFile); + m_fake_fullscreen_mode = GetPrivateProfileIntW(L"settings",L"fake_fullscreen_mode",m_fake_fullscreen_mode,m_szConfigIniFile); + m_max_fps_fs = GetPrivateProfileIntW(L"settings",L"max_fps_fs",m_max_fps_fs,m_szConfigIniFile); + m_max_fps_dm = GetPrivateProfileIntW(L"settings",L"max_fps_dm",m_max_fps_dm,m_szConfigIniFile); + m_max_fps_w = GetPrivateProfileIntW(L"settings",L"max_fps_w" ,m_max_fps_w ,m_szConfigIniFile); + m_show_press_f1_msg = GetPrivateProfileIntW(L"settings",L"show_press_f1_msg",m_show_press_f1_msg,m_szConfigIniFile); + m_allow_page_tearing_w = GetPrivateProfileIntW(L"settings",L"allow_page_tearing_w",m_allow_page_tearing_w,m_szConfigIniFile); + m_allow_page_tearing_fs= GetPrivateProfileIntW(L"settings",L"allow_page_tearing_fs",m_allow_page_tearing_fs,m_szConfigIniFile); + m_allow_page_tearing_dm= GetPrivateProfileIntW(L"settings",L"allow_page_tearing_dm",m_allow_page_tearing_dm,m_szConfigIniFile); + m_minimize_winamp = GetPrivateProfileIntW(L"settings",L"minimize_winamp",m_minimize_winamp,m_szConfigIniFile); + m_desktop_show_icons = GetPrivateProfileIntW(L"settings",L"desktop_show_icons",m_desktop_show_icons,m_szConfigIniFile); + m_desktop_textlabel_boxes = GetPrivateProfileIntW(L"settings",L"desktop_textlabel_boxes",m_desktop_textlabel_boxes,m_szConfigIniFile); + m_desktop_manual_icon_scoot = GetPrivateProfileIntW(L"settings",L"desktop_manual_icon_scoot",m_desktop_manual_icon_scoot,m_szConfigIniFile); + m_desktop_555_fix = GetPrivateProfileIntW(L"settings",L"desktop_555_fix",m_desktop_555_fix,m_szConfigIniFile); + m_dualhead_horz = GetPrivateProfileIntW(L"settings",L"dualhead_horz",m_dualhead_horz,m_szConfigIniFile); + m_dualhead_vert = GetPrivateProfileIntW(L"settings",L"dualhead_vert",m_dualhead_vert,m_szConfigIniFile); + m_save_cpu = GetPrivateProfileIntW(L"settings",L"save_cpu",m_save_cpu,m_szConfigIniFile); + m_skin = GetPrivateProfileIntW(L"settings",L"skin",m_skin,m_szConfigIniFile); + m_fix_slow_text = GetPrivateProfileIntW(L"settings",L"fix_slow_text",m_fix_slow_text,m_szConfigIniFile); + m_vj_mode = GetPrivateProfileBoolW(L"settings",L"vj_mode",m_vj_mode,m_szConfigIniFile); + + //D3DDISPLAYMODE m_fs_disp_mode + m_disp_mode_fs.Width = GetPrivateProfileIntW(L"settings",L"disp_mode_fs_w", m_disp_mode_fs.Width ,m_szConfigIniFile); + m_disp_mode_fs.Height = GetPrivateProfileIntW(L"settings",L"disp_mode_fs_h",m_disp_mode_fs.Height ,m_szConfigIniFile); + m_disp_mode_fs.RefreshRate = GetPrivateProfileIntW(L"settings",L"disp_mode_fs_r",m_disp_mode_fs.RefreshRate,m_szConfigIniFile); + m_disp_mode_fs.Format = (D3DFORMAT)GetPrivateProfileIntW(L"settings",L"disp_mode_fs_f",m_disp_mode_fs.Format ,m_szConfigIniFile); + + // note: we don't call MyReadConfig() yet, because we + // want to completely finish CPluginShell's preinit (and ReadConfig) + // before calling CPlugin's preinit and ReadConfig. +} + +void CPluginShell::WRITE_FONT(int n){ + WritePrivateProfileStringW(L"settings",BuildSettingName(L"szFontFace",n),m_fontinfo[n].szFace,m_szConfigIniFile); + WritePrivateProfileIntW(m_fontinfo[n].bBold, BuildSettingName(L"bFontBold",n), m_szConfigIniFile, L"settings"); + WritePrivateProfileIntW(m_fontinfo[n].bItalic,BuildSettingName(L"bFontItalic",n), m_szConfigIniFile, L"settings"); + WritePrivateProfileIntW(m_fontinfo[n].nSize, BuildSettingName(L"nFontSize",n), m_szConfigIniFile, L"settings"); + WritePrivateProfileIntW(m_fontinfo[n].bAntiAliased, BuildSettingName(L"bFontAA",n),m_szConfigIniFile, L"settings"); +} + +void CPluginShell::WriteConfig() +{ + //D3DMULTISAMPLE_TYPE m_multisample_fullscreen; + //D3DMULTISAMPLE_TYPE m_multisample_desktop; + //D3DMULTISAMPLE_TYPE m_multisample_windowed; + WritePrivateProfileIntW((int)m_multisample_fullscreen,L"multisample_fullscreen",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW((int)m_multisample_desktop ,L"multisample_desktop" ,m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW((int)m_multisample_windowed ,L"multisample_windowed" ,m_szConfigIniFile,L"settings"); + + //GUID m_adapter_guid_fullscreen + //GUID m_adapter_guid_desktop + //GUID m_adapter_guid_windowed + char str[256]; + GuidToText(&m_adapter_guid_fullscreen, str, sizeof(str)); + WritePrivateProfileString("settings","adapter_guid_fullscreen",str,m_szConfigIniFileA); + GuidToText(&m_adapter_guid_desktop, str, sizeof(str)); + WritePrivateProfileString("settings","adapter_guid_desktop",str,m_szConfigIniFileA); + GuidToText(&m_adapter_guid_windowed, str, sizeof(str)); + WritePrivateProfileString("settings","adapter_guid_windowed" ,str,m_szConfigIniFileA); + WritePrivateProfileString("settings","adapter_devicename_fullscreen",m_adapter_devicename_fullscreen,m_szConfigIniFileA); + WritePrivateProfileString("settings","adapter_devicename_desktop" ,m_adapter_devicename_desktop ,m_szConfigIniFileA); + WritePrivateProfileString("settings","adapter_devicename_windowed" ,m_adapter_devicename_windowed ,m_szConfigIniFileA); + + // FONTS + WRITE_FONT(0); + WRITE_FONT(1); + WRITE_FONT(2); + WRITE_FONT(3); +#if (NUM_EXTRA_FONTS >= 1) + WRITE_FONT(4); +#endif +#if (NUM_EXTRA_FONTS >= 2) + WRITE_FONT(5); +#endif +#if (NUM_EXTRA_FONTS >= 3) + WRITE_FONT(6); +#endif +#if (NUM_EXTRA_FONTS >= 4) + WRITE_FONT(7); +#endif +#if (NUM_EXTRA_FONTS >= 5) + WRITE_FONT(8); +#endif + + WritePrivateProfileIntW(m_start_fullscreen,L"start_fullscreen",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_start_desktop ,L"start_desktop" ,m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_fake_fullscreen_mode,L"fake_fullscreen_mode",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_max_fps_fs,L"max_fps_fs",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_max_fps_dm,L"max_fps_dm",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_max_fps_w ,L"max_fps_w" ,m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_show_press_f1_msg,L"show_press_f1_msg",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_allow_page_tearing_w,L"allow_page_tearing_w",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_allow_page_tearing_fs,L"allow_page_tearing_fs",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_allow_page_tearing_dm,L"allow_page_tearing_dm",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_minimize_winamp,L"minimize_winamp",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_desktop_show_icons,L"desktop_show_icons",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_desktop_textlabel_boxes,L"desktop_textlabel_boxes",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_desktop_manual_icon_scoot,L"desktop_manual_icon_scoot",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_desktop_555_fix,L"desktop_555_fix",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_dualhead_horz,L"dualhead_horz",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_dualhead_vert,L"dualhead_vert",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_save_cpu,L"save_cpu",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_skin,L"skin",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_fix_slow_text,L"fix_slow_text",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_vj_mode,L"vj_mode",m_szConfigIniFile,L"settings"); + + //D3DDISPLAYMODE m_fs_disp_mode + WritePrivateProfileIntW(m_disp_mode_fs.Width ,L"disp_mode_fs_w",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_disp_mode_fs.Height ,L"disp_mode_fs_h",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_disp_mode_fs.RefreshRate,L"disp_mode_fs_r",m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(m_disp_mode_fs.Format ,L"disp_mode_fs_f",m_szConfigIniFile,L"settings"); + + WritePrivateProfileIntW(INT_VERSION ,L"version" ,m_szConfigIniFile,L"settings"); + WritePrivateProfileIntW(INT_SUBVERSION ,L"subversion" ,m_szConfigIniFile,L"settings"); + + // finally, save the plugin's unique settings: + MyWriteConfig(); +} + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + +int CPluginShell::PluginRender(unsigned char *pWaveL, unsigned char *pWaveR)//, unsigned char *pSpecL, unsigned char *pSpecR) +{ + // return FALSE here to tell Winamp to terminate the plugin + + if (!m_lpDX || !m_lpDX->m_ready) + { + // note: 'm_ready' will go false when a device reset fatally fails + // (for example, when user resizes window, or toggles fullscreen.) + m_exiting = 1; + return false; // EXIT THE PLUGIN + } + + if (m_hTextWnd) + m_lost_focus = ((GetFocus() != GetPluginWindow()) && (GetFocus() != m_hTextWnd)); + else + m_lost_focus = (GetFocus() != GetPluginWindow()); + + if ((m_screenmode==WINDOWED && m_hidden) || + (m_screenmode==FULLSCREEN && m_lost_focus) || + (m_screenmode==WINDOWED && m_resizing) + ) + { + Sleep(30); + return true; + } + + // test for lost device + // (this happens when device is fullscreen & user alt-tabs away, + // or when monitor power-saving kicks in) + HRESULT hr = m_lpDX->m_lpDevice->TestCooperativeLevel(); + if (hr == D3DERR_DEVICENOTRESET) + { + // device WAS lost, and is now ready to be reset (and come back online): + CleanUpDX9Stuff(0); + if (m_lpDX->m_lpDevice->Reset(&m_lpDX->m_d3dpp) != D3D_OK) + { + // note: a basic warning messagebox will have already been given. + // now suggest specific advice on how to regain more video memory: + if (m_lpDX->m_lastErr == DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY) + SuggestHowToFreeSomeMem(); + return false; // EXIT THE PLUGIN + } + if (!AllocateDX9Stuff()) + return false; // EXIT THE PLUGIN + } + else if (hr != D3D_OK) + { + // device is lost, and not yet ready to come back; sleep. + Sleep(30); + return true; + } + + if (m_vjd3d9_device) + { + HRESULT hr = m_vjd3d9_device->TestCooperativeLevel(); + if (hr == D3DERR_DEVICENOTRESET) + { + RECT c; + GetClientRect(m_hTextWnd, &c); + + POINT p; + p.x = c.left; + p.y = c.top; + if (ClientToScreen(m_hTextWnd, &p)) + { + c.left += p.x; + c.right += p.x; + c.top += p.y; + c.bottom += p.y; + } + + CleanUpVJStuff(); + if (!InitVJStuff(&c)) + return false; // EXIT THE PLUGIN + } + } + + if (m_screenmode==DESKTOP) + { + PushWindowToJustBeforeDesktop(GetPluginWindow()); + } + + DoTime(); + AnalyzeNewSound(pWaveL, pWaveR); + AlignWaves(); + + DrawAndDisplay(0); + + EnforceMaxFPS(); + + m_frame++; + + return true; +} + +void CPluginShell::PushWindowToJustBeforeDesktop(HWND h) +{ + // if our window isn't already at the bottom of the Z order, + // freshly send it to HWND_BOTTOM. + + // this usually gives us the Program Manager window: + HWND hWndBottom = GetWindow(h, GW_HWNDLAST); + + // then, bottommost 'normal' window is usually the one just in front of it: + if (hWndBottom == m_hWndProgMan) + hWndBottom = GetWindow(hWndBottom, GW_HWNDPREV); + + if (hWndBottom != h) + { + m_force_accept_WM_WINDOWPOSCHANGING = 1; + SetWindowPos(h, HWND_BOTTOM, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); + m_force_accept_WM_WINDOWPOSCHANGING = 0; + } + + /* + HWND hDesktopBkgWnd = FindWindow("SHELLDLL_DefView", ""); + if (hDesktopBkgWnd) + { + HWND hWndInFrontOfIcons = GetWindow(h, GW_HWNDPREV); + if (hWndInFrontOfIcons != h) + { + m_force_accept_WM_WINDOWPOSCHANGING = 1; + SetWindowPos(hDesktopBkgWnd, h, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); + m_force_accept_WM_WINDOWPOSCHANGING = 0; + } + } + */ + + +} + +void CPluginShell::DrawAndDisplay(int redraw) +{ + int cx = m_vjd3d9_device ? m_nTextWndWidth : m_lpDX->m_client_width; + int cy = m_vjd3d9_device ? m_nTextWndHeight : m_lpDX->m_client_height; + if (m_lpDDSText) + { + D3DSURFACE_DESC desc; + if (D3D_OK == m_lpDDSText->GetLevelDesc(0, &desc)) + { + cx = min(cx, (int)desc.Width); + cy = min(cy, (int)desc.Height); + } + } + m_upper_left_corner_y = TEXT_MARGIN + GetCanvasMarginY(); + m_upper_right_corner_y = TEXT_MARGIN + GetCanvasMarginY(); + m_lower_left_corner_y = cy - TEXT_MARGIN - GetCanvasMarginY(); + m_lower_right_corner_y = cy - TEXT_MARGIN - GetCanvasMarginY(); + m_left_edge = TEXT_MARGIN + GetCanvasMarginX(); + m_right_edge = cx - TEXT_MARGIN - GetCanvasMarginX(); + + /*if (m_screenmode == DESKTOP || m_screenmode == FAKE_FULLSCREEN) + { + // check if taskbar is above plugin window; + // if so, scoot text & icons out of the way. + // [...should always be true for Desktop Mode, + // but it's like this for code simplicity.] + int taskbar_is_above_plugin_window = 1; + HWND h = FindWindow("Shell_TrayWnd", NULL); + 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<end; j++) + m_sound.imm[ch][i] += m_sound.fSpectrum[ch][j]; + m_sound.imm[ch][i] /= (float)(end-start); + } + } + + // some code to find empirical long-term averages for imm[0..2]: + /*{ + static float sum[3]; + static int count = 0; + + #define FRAMES_PER_SONG 300 // should be at least 200! + + if (m_frame < FRAMES_PER_SONG) + { + sum[0] = sum[1] = sum[2] = 0; + count = 0; + } + else + { + if (m_frame%FRAMES_PER_SONG == 0) + { + char buf[256]; + sprintf(buf, "%.4f, %.4f, %.4f (%d samples / ~%d songs)\n", + sum[0]/(float)(count), + sum[1]/(float)(count), + sum[2]/(float)(count), + count, + count/(FRAMES_PER_SONG-10) + ); + OutputDebugString(buf); + + // skip to next song + PostMessage(m_hWndWinamp,WM_COMMAND,40048,0); + } + else if (m_frame%FRAMES_PER_SONG == 5) + { + // then advance to 0-2 minutes into the song: + PostMessage(m_hWndWinamp,WM_USER,(20 + (warand()%65) + (rand()%65))*1000,106); + } + else if (m_frame%FRAMES_PER_SONG >= 10) + { + sum[0] += m_sound.imm[0]; + sum[1] += m_sound.imm[1]; + sum[2] += m_sound.imm[2]; + count++; + } + } + }*/ + + // multiply by long-term, empirically-determined inverse averages: + // (for a trial of 244 songs, 10 seconds each, somewhere in the 2nd or 3rd minute, + // the average levels were: 0.326781557 0.38087377 0.199888934 + for (int ch=0; ch<2; ch++) + { + m_sound.imm[ch][0] /= 0.326781557f;//0.270f; + m_sound.imm[ch][1] /= 0.380873770f;//0.343f; + m_sound.imm[ch][2] /= 0.199888934f;//0.295f; + } + + // do temporal blending to create attenuated and super-attenuated versions + for (int ch=0; ch<2; ch++) + { + for (i=0; i<3; i++) + { + // m_sound.avg[i] + { + float avg_mix; + if (m_sound.imm[ch][i] > m_sound.avg[ch][i]) + avg_mix = AdjustRateToFPS(0.2f, 14.0f, m_fps); + else + avg_mix = AdjustRateToFPS(0.5f, 14.0f, m_fps); + m_sound.avg[ch][i] = m_sound.avg[ch][i]*avg_mix + m_sound.imm[ch][i]*(1-avg_mix); + } + + // m_sound.med_avg[i] + // m_sound.long_avg[i] + { + float med_mix = 0.91f;//0.800f + 0.11f*powf(t, 0.4f); // primarily used for velocity_damping + float long_mix = 0.96f;//0.800f + 0.16f*powf(t, 0.2f); // primarily used for smoke plumes + med_mix = AdjustRateToFPS(med_mix, 14.0f, m_fps); + long_mix = AdjustRateToFPS(long_mix, 14.0f, m_fps); + m_sound.med_avg[ch][i] = m_sound.med_avg[ch][i]*(med_mix) + m_sound.imm[ch][i]*(1-med_mix); + m_sound.long_avg[ch][i] = m_sound.long_avg[ch][i]*(long_mix) + m_sound.imm[ch][i]*(1-long_mix); + } + } + } +} + +void CPluginShell::PrepareFor2DDrawing_B(IDirect3DDevice9 *pDevice, int w, int h) +{ + // New 2D drawing area will have x,y coords in the range <-1,-1> .. <1,1> + // +--------+ Y=-1 + // | | + // | screen | Z=0: front of scene + // | | Z=1: back of scene + // +--------+ Y=1 + // X=-1 X=1 + // NOTE: After calling this, be sure to then call (at least): + // 1. SetVertexShader() + // 2. SetTexture(), if you need it + // before rendering primitives! + // Also, be sure your sprites have a z coordinate of 0. + + pDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + pDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + pDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + pDevice->SetRenderState(D3DRS_LOCALVIEWER, FALSE); + pDevice->SetRenderState(D3DRS_COLORVERTEX, TRUE); + + pDevice->SetTexture(0, NULL); + pDevice->SetTexture(1, NULL); + pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);//D3DTEXF_LINEAR); + pDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT);//D3DTEXF_LINEAR); + pDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + pDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT); + pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + + pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); + pDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + // set up for 2D drawing: + { + D3DXMATRIX Ortho2D; + D3DXMATRIX Identity; + + pMatrixOrthoLH(&Ortho2D, (float)w, (float)h, 0.0f, 1.0f); + D3DXMatrixIdentity(&Identity); + + pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D); + pDevice->SetTransform(D3DTS_WORLD, &Identity); + pDevice->SetTransform(D3DTS_VIEW, &Identity); + } +} + +void CPluginShell::DrawDarkTranslucentBox(RECT* pr) +{ + // 'pr' is the rectangle that some text will occupy; + // a black box will be drawn around it, plus a bit of extra margin space. + + if (m_vjd3d9_device) + return; + + m_lpDX->m_lpDevice->SetVertexShader(NULL); + m_lpDX->m_lpDevice->SetPixelShader(NULL); + m_lpDX->m_lpDevice->SetFVF(SIMPLE_VERTEX_FORMAT); + m_lpDX->m_lpDevice->SetTexture(0, NULL); + + m_lpDX->m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + m_lpDX->m_lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + m_lpDX->m_lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + m_lpDX->m_lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); + + // set up a quad + SIMPLEVERTEX verts[4]; + for (int i=0; i<4; i++) + { + verts[i].x = (i%2==0) ? (float)(-m_lpDX->m_client_width /2 + pr->left) : + (float)(-m_lpDX->m_client_width /2 + pr->right); + verts[i].y = (i/2==0) ? (float)-(-m_lpDX->m_client_height/2 + pr->bottom) : + (float)-(-m_lpDX->m_client_height/2 + pr->top); + verts[i].z = 0; + verts[i].Diffuse = (m_screenmode==DESKTOP) ? 0xE0000000 : 0xD0000000; + } + + m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(SIMPLEVERTEX)); + + // undo unusual state changes: + m_lpDX->m_lpDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + m_lpDX->m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); +} + +void CPluginShell::RenderBuiltInTextMsgs() +{ + int _show_press_f1_NOW = (m_show_press_f1_msg && m_time < PRESS_F1_DUR); + + { + RECT r; + + if (m_show_help) + { + int y = m_upper_left_corner_y; + + SetRect(&r, 0, 0, GetWidth(), GetHeight()); + if(!g_szHelp_W) + m_d3dx_font[HELPSCREEN_FONT]->DrawTextA(NULL, (char*)g_szHelp, -1, &r, DT_CALCRECT, 0xFFFFFFFF); + else + m_d3dx_font[HELPSCREEN_FONT]->DrawTextW(NULL, g_szHelp, -1, &r, DT_CALCRECT, 0xFFFFFFFF); + + r.top += m_upper_left_corner_y; + r.left += m_left_edge; + r.right += m_left_edge + PLAYLIST_INNER_MARGIN*2; + r.bottom += m_upper_left_corner_y + PLAYLIST_INNER_MARGIN*2; + DrawDarkTranslucentBox(&r); + + r.top += PLAYLIST_INNER_MARGIN; + r.left += PLAYLIST_INNER_MARGIN; + r.right -= PLAYLIST_INNER_MARGIN; + r.bottom -= PLAYLIST_INNER_MARGIN; + if(!g_szHelp_W) + m_d3dx_font[HELPSCREEN_FONT]->DrawTextA(NULL, (char*)g_szHelp, -1, &r, 0, 0xFFFFFFFF); + else + m_d3dx_font[HELPSCREEN_FONT]->DrawTextW(NULL, g_szHelp, -1, &r, 0, 0xFFFFFFFF); + + m_upper_left_corner_y += r.bottom-r.top + PLAYLIST_INNER_MARGIN*3; + } + + // render 'Press F1 for Help' message in lower-right corner: + if (_show_press_f1_NOW) + { + int dx = (int)(160.0f * powf(m_time/(float)(PRESS_F1_DUR), (float)(PRESS_F1_EXP))); + SetRect(&r, m_left_edge, m_lower_right_corner_y - GetFontHeight(DECORATIVE_FONT), m_right_edge + dx, m_lower_right_corner_y); + m_lower_right_corner_y -= m_d3dx_font[DECORATIVE_FONT]->DrawTextW(NULL, WASABI_API_LNGSTRINGW(IDS_PRESS_F1_MSG), -1, &r, DT_RIGHT, 0xFFFFFFFF); + } + } +} + +void CPluginShell::RenderPlaylist() +{ + // draw playlist: + if (m_show_playlist) + { + RECT r; + int nSongs = SendMessage(m_hWndWinamp,WM_USER, 0, 124); + int now_playing = SendMessage(m_hWndWinamp,WM_USER, 0, 125); + + if (nSongs <= 0) + { + m_show_playlist = 0; + } + else + { + int playlist_vert_pixels = m_lower_left_corner_y - m_upper_left_corner_y; + int disp_lines = min(MAX_SONGS_PER_PAGE, (playlist_vert_pixels - PLAYLIST_INNER_MARGIN*2) / GetFontHeight(PLAYLIST_FONT)); + int total_pages = (nSongs) / disp_lines; + + if (disp_lines<=0) + return; + + // apply PgUp/PgDn keypresses since last time + m_playlist_pos -= m_playlist_pageups * disp_lines; + m_playlist_pageups = 0; + + if (m_playlist_pos < 0) + m_playlist_pos = 0; + if (m_playlist_pos >= nSongs) + m_playlist_pos = nSongs-1; + + // NOTE: 'dwFlags' is used for both DDRAW and DX9 + DWORD dwFlags = DT_SINGLELINE;// | DT_NOPREFIX | DT_WORD_ELLIPSIS; + DWORD color; + + int cur_page = (m_playlist_pos) / disp_lines; + int cur_line = (m_playlist_pos + disp_lines - 1) % disp_lines; + int new_top_idx = cur_page * disp_lines; + int new_btm_idx = new_top_idx + disp_lines; + wchar_t buf[1024] = {0}; + + // ask winamp for the song names, but DO IT BEFORE getting the DC, + // otherwise vaio will crash (~DDRAW port). + if (m_playlist_top_idx != new_top_idx || + m_playlist_btm_idx != new_btm_idx) + { + for (int i=0; i<disp_lines; i++) + { + int j = new_top_idx + i; + if (j < nSongs) + { + // clip max len. of song name to 240 chars, to prevent overflows + lstrcpynW(buf, (wchar_t*)SendMessage(m_hWndWinamp, WM_USER, j, IPC_GETPLAYLISTTITLEW), 240); + wsprintfW(m_playlist[i], L"%d. %s ", j+1, buf); // leave an extra space @ end, so italicized fonts don't get clipped + } + } + } + + // update playlist cache, if necessary: + if (m_playlist_top_idx != new_top_idx || + m_playlist_btm_idx != new_btm_idx) + { + m_playlist_top_idx = new_top_idx; + m_playlist_btm_idx = new_btm_idx; + m_playlist_width_pixels = 0; + + int max_w = min(m_right_edge - m_left_edge, m_lpDX->m_client_width - TEXT_MARGIN*2 - PLAYLIST_INNER_MARGIN*2); + + for (int i=0; i<disp_lines; i++) + { + int j = new_top_idx + i; + if (j < nSongs) + { + // clip max len. of song name to 240 chars, to prevent overflows + //strcpy(buf, (char*)SendMessage(m_hWndWinamp, WM_USER, j, 212)); + //buf[240] = 0; + //sprintf(m_playlist[i], "%d. %s ", j+1, buf); // leave an extra space @ end, so italicized fonts don't get clipped + + SetRect(&r, 0, 0, max_w, 1024); + m_d3dx_font[PLAYLIST_FONT]->DrawTextW(NULL, m_playlist[i], -1, &r, dwFlags | DT_CALCRECT, 0xFFFFFFFF); + int w = r.right-r.left; + if (w>0) + m_playlist_width_pixels = max(m_playlist_width_pixels, w); + } + else + { + m_playlist[i][0] = 0; + } + } + + if (m_playlist_width_pixels == 0 || + m_playlist_width_pixels > max_w) + m_playlist_width_pixels = max_w; + } + + int start = max(0, (cur_page)*disp_lines); + int end = min(nSongs, (cur_page+1)*disp_lines); + + // draw dark box around where the playlist will go: + + RECT r; + r.top = m_upper_left_corner_y; + r.left = m_left_edge; + r.right = m_left_edge + m_playlist_width_pixels + PLAYLIST_INNER_MARGIN*2; + r.bottom = m_upper_left_corner_y + (end-start)*GetFontHeight(PLAYLIST_FONT) + PLAYLIST_INNER_MARGIN*2; + DrawDarkTranslucentBox(&r); + + //m_d3dx_font[PLAYLIST_FONT]->Begin(); + + // draw playlist text + int y = m_upper_left_corner_y + PLAYLIST_INNER_MARGIN; + for (int i=start; i<end; i++) + { + SetRect(&r, m_left_edge + PLAYLIST_INNER_MARGIN, y, m_left_edge + PLAYLIST_INNER_MARGIN + m_playlist_width_pixels, y + GetFontHeight(PLAYLIST_FONT)); + + if (m_lpDX->GetBitDepth() == 8) + color = (i==m_playlist_pos) ? + (i==now_playing ? 0xFFFFFFFF : 0xFFFFFFFF) : + (i==now_playing ? 0xFFFFFFFF : 0xFF707070); + else + color = (i==m_playlist_pos) ? + (i==now_playing ? PLAYLIST_COLOR_BOTH : PLAYLIST_COLOR_HILITE_TRACK) : + (i==now_playing ? PLAYLIST_COLOR_PLAYING_TRACK : PLAYLIST_COLOR_NORMAL); + + y += m_d3dx_font[PLAYLIST_FONT]->DrawTextW(NULL, m_playlist[i-start], -1, &r, dwFlags, color); + } + + //m_d3dx_font[PLAYLIST_FONT]->End(); + } + } +} + +void CPluginShell::SuggestHowToFreeSomeMem() +{ + // This function is called when the plugin runs out of video memory; + // it lets you show a messagebox to the user so you can (intelligently) + // suggest how to free up some video memory, based on what settings + // they've chosen. + + wchar_t str[1024]; + + if (m_lpDX->m_current_mode.multisamp != D3DMULTISAMPLE_NONE) + { + if (m_lpDX->m_current_mode.screenmode == WINDOWED) + WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG, str, 2048); + else if (m_lpDX->m_current_mode.screenmode == FAKE_FULLSCREEN) + WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_2, str, 2048); + else + WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_3, str, 2048); + } + else + if (m_lpDX->m_current_mode.screenmode == FULLSCREEN) // true fullscreen + WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_VIDEO_MEMORY, str, 2048); + else // windowed, desktop mode, or fake fullscreen + WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_VIDEO_MEMORY, str, 2048); + + MessageBoxW(m_lpDX->GetHwnd(), str, WASABI_API_LNGSTRINGW(IDS_MILKDROP_SUGGESTION), MB_OK|MB_SETFOREGROUND|MB_TOPMOST); +} + +LRESULT CALLBACK CPluginShell::WindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) +{ + //if (uMsg==WM_GETDLGCODE) + // return DLGC_WANTALLKEYS|DLGC_WANTCHARS|DLGC_WANTMESSAGE; // this tells the embedwnd that we want keypresses to flow through to our client wnd. + + if (uMsg == WM_CREATE) + { + CREATESTRUCT *create = (CREATESTRUCT *)lParam; + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)create->lpCreateParams); + } + + CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hWnd,GWLP_USERDATA); + if (p) + return p->PluginShellWindowProc(hWnd, uMsg, wParam, lParam); + else + return DefWindowProcW(hWnd, uMsg, wParam, lParam); +} + +LRESULT CPluginShell::PluginShellWindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) +{ + USHORT mask = 1 << (sizeof(SHORT)*8 - 1); + //bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0; + bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0; + //bool bAltHeldDown: most keys come in under WM_SYSKEYDOWN when ALT is depressed. + + int i; +#ifdef _DEBUG + char caption[256] = "WndProc: frame 0, "; + if (m_frame > 0) + { + float time = m_time; + int hours = (int)(time/3600); + time -= hours*3600; + int minutes = (int)(time/60); + time -= minutes*60; + int seconds = (int)time; + time -= seconds; + int dsec = (int)(time*100); + sprintf(caption, "WndProc: frame %d, t=%dh:%02dm:%02d.%02ds, ", m_frame, hours, minutes, seconds, dsec); + } + + if (uMsg != WM_MOUSEMOVE && + uMsg != WM_NCHITTEST && + uMsg != WM_SETCURSOR && + uMsg != WM_COPYDATA && + uMsg != WM_USER) + OutputDebugMessage(caption, hWnd, uMsg, wParam, lParam); +#endif + + switch (uMsg) + { + case WM_USER: + if (m_screenmode == DESKTOP) + { + // this function resides in vms_desktop.dll; + // its response will come later, via the WM_COPYDATA + // message (See below). + //KIV: **THIS CALL CRASHES EXPLORER IN VISTA** + getItemData(wParam); + return 0; + } + break; + + case WM_COPYDATA: + if (m_screenmode == DESKTOP) + { + // this message is vms_desktop.dll's response to + // our call to getItemData(). + PCOPYDATASTRUCT c = (PCOPYDATASTRUCT)lParam; + if (c && (c->cbData % sizeof(icon_t) == 0)) + { + icon_t *pNewIcons = (icon_t*)c->lpData; + + EnterCriticalSection(&m_desktop_cs); + + if (m_desktop_icon_state == 1 && (c->dwData & 0x80000000)) // if doing a total refresh... + { + // ...we build the list from zero + int len = c->dwData & 0xFFFF; + for (int i=0; i<len; i++) + m_icon_list.push_back(pNewIcons[i]); + } + else if (m_desktop_icon_state == 3 && !(c->dwData & 0x80000000)) + { + // otherwise, we alter existing things in the list: + IconList::iterator p; + int start = c->dwData & 0xFFFF; + int len = c->dwData >> 16; + + int i = 0; + for (p = m_icon_list.begin(); p != m_icon_list.end() && i<start; p++) + i++; + for (; p != m_icon_list.end() && i<start+len; p++) + { + p->x = pNewIcons[i-start].x; + p->y = pNewIcons[i-start].y; + memcpy(p->name, pNewIcons[i-start].name, sizeof(p->name)); + memcpy(p->pidl, pNewIcons[i-start].pidl, sizeof(p->pidl)); + i++; + } + + m_desktop_icon_state = 2; + m_desktop_icon_update_frame = GetFrame(); + } + + LeaveCriticalSection(&m_desktop_cs); + } + + return 0; + } + break; + + case WM_ERASEBKGND: + // Repaint window when song is paused and image needs to be repainted: + if (SendMessage(m_hWndWinamp,WM_USER,0,104)!=1 && m_lpDX && m_lpDX->m_lpDevice && GetFrame() > 0) // WM_USER/104 return codes: 1=playing, 3=paused, other=stopped + { + m_lpDX->m_lpDevice->Present(NULL,NULL,NULL,NULL); + return 0; + } + break; + + case WM_WINDOWPOSCHANGING: + if ( + m_screenmode == DESKTOP + && (!m_force_accept_WM_WINDOWPOSCHANGING) + && m_lpDX && m_lpDX->m_ready + ) + { + // unless we requested it ourselves or it's init time, + // prevent the fake desktop window from moving around + // in the Z order! (i.e., keep it on the bottom) + + // without this code, when you click on the 'real' desktop + // 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_MOVE: + m_lpDX->SaveWindow(); + break; + case WM_SIZE: + // clear or set activity flag to reflect focus + if (m_lpDX && m_lpDX->m_ready && m_screenmode==WINDOWED && !m_resizing) + { + m_hidden = (SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam) ? TRUE : FALSE; + + if (SIZE_MAXIMIZED==wParam || SIZE_RESTORED==wParam) // the window has been maximized or restored + OnUserResizeWindow(); + } + break; + + case WM_ENTERSIZEMOVE: + m_resizing = 1; + break; + + case WM_EXITSIZEMOVE: + if (m_lpDX && m_lpDX->m_ready && m_screenmode==WINDOWED) + OnUserResizeWindow(); + m_lpDX->SaveWindow(); + m_resizing = 0; + break; + + case WM_GETMINMAXINFO: + { + // don't let the window get too small + MINMAXINFO* p = (MINMAXINFO*)lParam; + if (p->ptMinTrackSize.x < 64) + p->ptMinTrackSize.x = 64; + p->ptMinTrackSize.y = p->ptMinTrackSize.x*3/4; + } + return 0; + + case WM_MOUSEMOVE: + if (m_screenmode==DESKTOP && (m_desktop_dragging==1 || m_desktop_box==1)) + { + m_desktop_drag_curpos.x = LOWORD(lParam); + m_desktop_drag_curpos.y = HIWORD(lParam); + if (m_desktop_box==1) + { + // update selection based on box coords + RECT box, temp; + box.left = min(m_desktop_drag_curpos.x, m_desktop_drag_startpos.x); + box.right = max(m_desktop_drag_curpos.x, m_desktop_drag_startpos.x); + box.top = min(m_desktop_drag_curpos.y, m_desktop_drag_startpos.y); + box.bottom = max(m_desktop_drag_curpos.y, m_desktop_drag_startpos.y); + + IconList::iterator p; + for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) + { + p->selected = 0; + + if (IntersectRect(&temp, &box, &p->label_rect)) + p->selected = 1; + else if (IntersectRect(&temp, &box, &p->icon_rect)) + p->selected = 1; + } + } + + // repaint window manually, if winamp is paused + if (SendMessage(m_hWndWinamp,WM_USER,0,104) != 1) + { + PushWindowToJustBeforeDesktop(GetPluginWindow()); + DrawAndDisplay(1); + } + + //return 0; + } + m_lpDX->SaveWindow(); + break; + + case WM_LBUTTONUP: + if (m_screenmode==DESKTOP) + { + if (m_desktop_dragging) + { + m_desktop_dragging = 0; + + // move selected item(s) to new cursor position + int dx = LOWORD(lParam) - m_desktop_drag_startpos.x; + int dy = HIWORD(lParam) - m_desktop_drag_startpos.y; + + if (dx!=0 || dy!=0) + { + int idx=0; + IconList::iterator p; + for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) + { + if (p->selected) + { + SendMessage(m_hWndDesktopListView, LVM_SETITEMPOSITION, idx, MAKELPARAM(p->x + dx, p->y + dy)); + p->x += dx; + p->y += dy; + } + idx++; + } + } + + // repaint window manually, if winamp is paused + if (SendMessage(m_hWndWinamp,WM_USER,0,104) != 1) + { + PushWindowToJustBeforeDesktop(GetPluginWindow()); + DrawAndDisplay(1); + } + } + + if (m_desktop_box) + { + m_desktop_box = 0; + + // repaint window manually, if winamp is paused + if (SendMessage(m_hWndWinamp,WM_USER,0,104) != 1) + { + PushWindowToJustBeforeDesktop(GetPluginWindow()); + DrawAndDisplay(1); + } + } + + //return 0; + } + break; + + case WM_USER + 1666: + if (wParam == 1 && lParam == 15) + { + if (m_screenmode == FULLSCREEN || m_screenmode == FAKE_FULLSCREEN) + ToggleFullScreen(); + } + return 0; + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + // Toggle between Fullscreen and Windowed modes on double-click + // note: this requires the 'CS_DBLCLKS' windowclass style! + if (m_screenmode != DESKTOP) + { + SetFocus(hWnd); + if (uMsg==WM_LBUTTONDBLCLK && m_frame>0) + { + ToggleFullScreen(); + return 0; + } + } + else + { + POINT pt; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + int done = 0; + + for (int pass=0; pass<2 && !done; pass++) + { + IconList::iterator p; + for (p = m_icon_list.begin(); p != m_icon_list.end(); p++) + { + RECT *pr = (pass==0) ? &p->icon_rect : &p->label_rect; + int bottom_extend = (pass==0) ? 3 : 0; // accepts clicks in the 3-pixel gap between the icon and the text label. + if (pt.x >= pr->left && + pt.x <= pr->right && + pt.y >= pr->top && + pt.y <= pr->bottom + bottom_extend) + { + switch (uMsg) + { + case WM_RBUTTONUP: + //pt.x += m_lpDX->m_monitor_rect.left; + //pt.y += m_lpDX->m_monitor_rect.top; + DoExplorerMenu(GetPluginWindow(), (LPITEMIDLIST)p->pidl, pt); + break; + case WM_LBUTTONDBLCLK: + { + char buf[MAX_PATH]; + sprintf(buf, "%s\\%s", m_szDesktopFolder, p->name); + ExecutePidl((LPITEMIDLIST)p->pidl, buf, m_szDesktopFolder, GetPluginWindow()); + } + break; + case WM_LBUTTONDOWN: + m_desktop_dragging = 1; + memcpy(m_desktop_drag_pidl, p->pidl, sizeof(m_desktop_drag_pidl)); + m_desktop_drag_startpos.x = LOWORD(lParam); + m_desktop_drag_startpos.y = HIWORD(lParam); + m_desktop_drag_curpos.x = LOWORD(lParam); + m_desktop_drag_curpos.y = HIWORD(lParam); + if (!(wParam & MK_CONTROL)) // if CTRL not held down + { + if (!p->selected) + { + DeselectDesktop(); + p->selected = 1; + } + } + else + { + p->selected = 1-p->selected; + } + break; + case WM_RBUTTONDOWN: + DeselectDesktop(); + p->selected = 1; + break; + } + + done = 1; + break; + } + } + } + + if (!done) + { + // deselect all, unless they're CTRL+clicking and missed an icon. + if (uMsg!=WM_LBUTTONDOWN || !(wParam & MK_CONTROL)) + DeselectDesktop(); + + if (uMsg==WM_RBUTTONUP)// || uMsg==WM_RBUTTONDOWN) + { + // note: can't use GetMenu and TrackPopupMenu here because the hwnd param to TrackPopupMenu must belong to current application. + + // (before sending coords to desktop window, xform them into its client coords:) + POINT pt; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + ScreenToClient(m_hWndDesktopListView, &pt); + lParam = MAKELPARAM(pt.x + m_lpDX->m_monitor_rect.left, pt.y + m_lpDX->m_monitor_rect.top); + + PostMessage(m_hWndDesktopListView, uMsg, wParam, lParam); + //PostMessage(m_hWndDesktopListView, WM_CONTEXTMENU, (WPARAM)m_hWndDesktopListView, lParam); + } + else if (uMsg==WM_LBUTTONDOWN) + { + m_desktop_box = 1; + m_desktop_drag_startpos.x = LOWORD(lParam); + m_desktop_drag_startpos.y = HIWORD(lParam); + m_desktop_drag_curpos.x = LOWORD(lParam); + m_desktop_drag_curpos.y = HIWORD(lParam); + } + } + + // repaint window manually, if winamp is paused + if (SendMessage(m_hWndWinamp,WM_USER,0,104) != 1) + { + PushWindowToJustBeforeDesktop(GetPluginWindow()); + DrawAndDisplay(1); + } + + //return 0; + } + break; + + case WM_SETFOCUS: + // note: this msg never comes in when embedwnd is used, but that's ok, because that's only + // in Windowed mode, and m_lost_focus only makes us sleep when fullscreen. + m_lost_focus = 0; + break; + + case WM_KILLFOCUS: + // note: this msg never comes in when embedwnd is used, but that's ok, because that's only + // in Windowed mode, and m_lost_focus only makes us sleep when fullscreen. + m_lost_focus = 1; + break; + + case WM_SETCURSOR: + if ( + (m_screenmode == FULLSCREEN) || + (m_screenmode == FAKE_FULLSCREEN && m_lpDX->m_fake_fs_covers_all) + ) + { + // hide the cursor + SetCursor(NULL); + return TRUE; // prevent Windows from setting cursor to window class cursor + } + break; + + case WM_NCHITTEST: + // Prevent the user from selecting the menu in fullscreen mode + if (m_screenmode != WINDOWED) + return HTCLIENT; + break; + + case WM_SYSCOMMAND: + // Prevent *moving/sizing* and *entering standby mode* when in fullscreen mode + switch (wParam) + { + case SC_MOVE: + case SC_SIZE: + case SC_MAXIMIZE: + case SC_KEYMENU: + if (m_screenmode != WINDOWED) + return 1; + break; + case SC_MONITORPOWER: + if (m_screenmode == FULLSCREEN || m_screenmode == FAKE_FULLSCREEN) + return 1; + break; + } + break; + + case WM_CONTEXTMENU: + // launch popup context menu. see handler for WM_COMMAND also. + if (m_screenmode == DESKTOP) + { + // note: execution should never reach this point, + // because we don't pass WM_RBUTTONUP to DefWindowProc + // when in desktop mode! + return 0; + } + else if (m_screenmode == WINDOWED) // context menus only allowed in ~windowed modes + { + TrackPopupMenuEx(m_context_menu, TPM_VERTICAL, LOWORD(lParam), HIWORD(lParam), hWnd, NULL); + return 0; + } + break; + + case WM_COMMAND: + // handle clicks on items on context menu. + if (m_screenmode == WINDOWED) + { + switch (LOWORD(wParam)) + { + case ID_QUIT: + m_exiting = 1; + PostMessage(hWnd, WM_CLOSE, 0, 0); + return 0; + case ID_GO_FS: + if (m_frame > 0) + ToggleFullScreen(); + return 0; + case ID_DESKTOP_MODE: + if (m_frame > 0) + ToggleDesktop(); + return 0; + case ID_SHOWHELP: + ToggleHelp(); + return 0; + case ID_SHOWPLAYLIST: + TogglePlaylist(); + return 0; + } + // then allow the plugin to override any command: + if (MyWindowProc(hWnd, uMsg, wParam, lParam) == 0) + return 0; + } + break; + + /* + KEY HANDLING: the basic idea: + -in all cases, handle or capture: + -ZXCVBRS, zxcvbrs + -also make sure it's case-insensitive! (lowercase come through only as WM_CHAR; uppercase come in as both) + -(ALT+ENTER) + -(F1, ESC, UP, DN, Left, Right, SHIFT+l/r) + -(P for playlist) + -when playlist showing: steal J, HOME, END, PGUP, PGDN, UP, DOWN, ESC + -(BLOCK J, L) + -when integrated with winamp (using embedwnd), also handle these keys: + -j, l, L, CTRL+L [windowed mode only!] + -CTRL+P, CTRL+D + -CTRL+TAB + -ALT-E + -ALT+F (main menu) + -ALT+3 (id3) + */ + + case WM_SYSKEYDOWN: + if (wParam==VK_RETURN && m_frame > 0) + { + ToggleFullScreen(); + return 0; + } + // if in embedded mode (using winamp skin), pass ALT+ keys on to winamp + // ex: ALT+E, ALT+F, ALT+3... + if (m_screenmode==WINDOWED && m_lpDX->m_current_mode.m_skin) + return PostMessage(m_hWndWinamp, uMsg, wParam, lParam); // force-pass to winamp; required for embedwnd + break; + + case WM_SYSKEYUP: + if (m_screenmode==WINDOWED && m_lpDX->m_current_mode.m_skin) + return PostMessage(m_hWndWinamp, uMsg, wParam, lParam); // force-pass to winamp; required for embedwnd + break; + + case WM_SYSCHAR: + if ((wParam=='k' || wParam=='K')) + { + OnAltK(); + return 0; + } + if ((wParam=='d' || wParam=='D') && m_frame > 0) + { + ToggleDesktop(); + return 0; + } + break; + + case WM_CHAR: + // if playlist is showing, steal p/j keys from the plugin: + if (m_show_playlist) + { + switch (wParam) + { + case 'j': + case 'J': + m_playlist_pos = SendMessage(m_hWndWinamp,WM_USER, 0, 125); + return 0; + default: + { + int nSongs = SendMessage(m_hWndWinamp,WM_USER, 0, 124); + int found = 0; + int orig_pos = m_playlist_pos; + int inc = (wParam>='A' && wParam<='Z') ? -1 : 1; + while (1) + { + if (inc==1 && m_playlist_pos >= nSongs-1) + break; + if (inc==-1 && m_playlist_pos <= 0) + break; + + m_playlist_pos += inc; + + char buf[32]; + strncpy(buf, (char*)SendMessage(m_hWndWinamp, WM_USER, m_playlist_pos, 212), 31); + buf[31] = 0; + + // remove song # and period from beginning + char *p = buf; + while (*p >= '0' && *p <= '9') p++; + if (*p == '.' && *(p+1) == ' ') + { + p += 2; + int pos = 0; + while (*p != 0) + { + buf[pos++] = *p; + p++; + } + buf[pos++] = 0; + } + + int wParam2 = (wParam>='A' && wParam<='Z') ? (wParam + 'a'-'A') : (wParam + 'A'-'a'); + if (buf[0]==wParam || buf[0]==wParam2) + { + found = 1; + break; + } + } + + if (!found) + m_playlist_pos = orig_pos; + } + return 0; + } + } + + // then allow the plugin to override any keys: + if (MyWindowProc(hWnd, uMsg, wParam, lParam) == 0) + return 0; + + // finally, default key actions: + if (wParam == keyMappings[5] || wParam == keyMappings[6]) // 'z' or 'Z' + { + PostMessage(m_hWndWinamp,WM_COMMAND,40044,0); + return 0; + } + else + { + switch (wParam) + { + // WINAMP PLAYBACK CONTROL KEYS: + case 'x': + case 'X': + PostMessage(m_hWndWinamp,WM_COMMAND,40045,0); + return 0; + case 'c': + case 'C': + PostMessage(m_hWndWinamp,WM_COMMAND,40046,0); + return 0; + case 'v': + case 'V': + PostMessage(m_hWndWinamp,WM_COMMAND,40047,0); + return 0; + case 'b': + case 'B': + PostMessage(m_hWndWinamp,WM_COMMAND,40048,0); + return 0; + case 's': + case 'S': + //if (SendMessage(m_hWndWinamp,WM_USER,0,250)) + // sprintf(m_szUserMessage, "shuffle is now OFF"); // shuffle was on + //else + // sprintf(m_szUserMessage, "shuffle is now ON"); // shuffle was off + + // toggle shuffle + PostMessage(m_hWndWinamp,WM_COMMAND,40023,0); + return 0; + case 'r': + case 'R': + // toggle repeat + PostMessage(m_hWndWinamp,WM_COMMAND,40022,0); + return 0; + case 'p': + case 'P': + TogglePlaylist(); + return 0; + case 'l': + // note that this is actually correct; when you hit 'l' from the + // MAIN winamp window, you get an "open files" dialog; when you hit + // 'l' from the playlist editor, you get an "add files to playlist" dialog. + // (that sends IDC_PLAYLIST_ADDMP3==1032 to the playlist, which we can't + // do from here.) + PostMessage(m_hWndWinamp,WM_COMMAND,40029,0); + return 0; + case 'L': + PostMessage(m_hWndWinamp,WM_COMMAND,40187,0); + return 0; + case 'j': + PostMessage(m_hWndWinamp,WM_COMMAND,40194,0); + return 0; + } + + return 0;//DefWindowProc(hWnd,uMsg,wParam,lParam); + } + break; // end case WM_CHAR + + case WM_KEYUP: + + // allow the plugin to override any keys: + if (MyWindowProc(hWnd, uMsg, wParam, lParam) == 0) + return 0; + + /* + switch(wParam) + { + case VK_SOMETHING: + ... + break; + } + */ + + return 0; + break; + + case WM_KEYDOWN: + if (m_show_playlist) + { + switch (wParam) + { + case VK_ESCAPE: + if(m_show_playlist) + TogglePlaylist(); + //m_show_playlist = 0; + return 0; + + case VK_UP: + { + int nRepeat = lParam & 0xFFFF; + if (GetKeyState(VK_SHIFT) & mask) + m_playlist_pos -= 10*nRepeat; + else + m_playlist_pos -= nRepeat; + } + return 0; + + case VK_DOWN: + { + int nRepeat = lParam & 0xFFFF; + if (GetKeyState(VK_SHIFT) & mask) + m_playlist_pos += 10*nRepeat; + else + m_playlist_pos += nRepeat; + } + return 0; + + case VK_HOME: + m_playlist_pos = 0; + return 0; + + case VK_END: + m_playlist_pos = SendMessage(m_hWndWinamp,WM_USER, 0, 124) - 1; + return 0; + + case VK_PRIOR: + if (GetKeyState(VK_SHIFT) & mask) + m_playlist_pageups += 10; + else + m_playlist_pageups++; + return 0; + + case VK_NEXT: + if (GetKeyState(VK_SHIFT) & mask) + m_playlist_pageups -= 10; + else + m_playlist_pageups--; + return 0; + + case VK_RETURN: + SendMessage(m_hWndWinamp,WM_USER, m_playlist_pos, 121); // set sel + SendMessage(m_hWndWinamp,WM_COMMAND, 40045, 0); // play it + return 0; + } + } + + // allow the plugin to override any keys: + if (MyWindowProc(hWnd, uMsg, wParam, lParam) == 0) + return 0; + + switch (wParam) + { + case VK_F1: + m_show_press_f1_msg = 0; + ToggleHelp(); + return 0; + + case VK_ESCAPE: + if (m_show_help) + ToggleHelp(); + else + { + if (m_screenmode == FAKE_FULLSCREEN || m_screenmode == FULLSCREEN) + { + ToggleFullScreen(); + } + else if (m_screenmode == DESKTOP) + { + ToggleDesktop(); + } + // exit the program on escape + //m_exiting = 1; + //PostMessage(hWnd, WM_CLOSE, 0, 0); + } + return 0; + + case VK_UP: + // increase volume + { + int nRepeat = lParam & 0xFFFF; + for (i=0; i<nRepeat*2; i++) PostMessage(m_hWndWinamp,WM_COMMAND,40058,0); + } + return 0; + + case VK_DOWN: + // decrease volume + { + int nRepeat = lParam & 0xFFFF; + for (i=0; i<nRepeat*2; i++) PostMessage(m_hWndWinamp,WM_COMMAND,40059,0); + } + return 0; + + case VK_LEFT: + case VK_RIGHT: + { + bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0; + int cmd = (wParam == VK_LEFT) ? 40144 : 40148; + int nRepeat = lParam & 0xFFFF; + int reps = (bShiftHeldDown) ? 6*nRepeat : 1*nRepeat; + + for (int i=0; i<reps; i++) + PostMessage(m_hWndWinamp,WM_COMMAND,cmd,0); + } + return 0; + default: + // pass CTRL+A thru CTRL+Z, and also CTRL+TAB, to winamp, *if we're in windowed mode* and using an embedded window. + // be careful though; uppercase chars come both here AND to WM_CHAR handler, + // so we have to eat some of them here, to avoid them from acting twice. + if (m_screenmode==WINDOWED && m_lpDX && m_lpDX->m_current_mode.m_skin) + { + if (bCtrlHeldDown && ((wParam >= 'A' && wParam <= 'Z') || wParam==VK_TAB)) + { + PostMessage(m_hWndWinamp, uMsg, wParam, lParam); + return 0; + } + } + return 0; + } + + return 0; + break; + } + + return MyWindowProc(hWnd, uMsg, wParam, lParam);//DefWindowProc(hWnd, uMsg, wParam, lParam); + //return 0L; +} + +LRESULT CALLBACK CPluginShell::DesktopWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) +{ + CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hWnd,GWLP_USERDATA); + if (p) + return p->PluginShellDesktopWndProc(hWnd, uMsg, wParam, lParam); + else + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +LRESULT CPluginShell::PluginShellDesktopWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) +{ + //#ifdef _DEBUG + // OutputDebugMessage("kbfocus", hWnd, uMsg, wParam, lParam); + //#endif + + switch (uMsg) + { + case WM_KEYDOWN: + case WM_KEYUP: + case WM_CHAR: + case WM_SYSCHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + //PostMessage(GetPluginWindow(), uMsg, wParam, lParam); + PluginShellWindowProc(GetPluginWindow(), uMsg, wParam, lParam); + return 0; + break; + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +void CPluginShell::AlignWaves() +{ + // align waves, using recursive (mipmap-style) least-error matching + // note: NUM_WAVEFORM_SAMPLES must be between 32 and 576. + + int align_offset[2] = { 0, 0 }; + +#if (NUM_WAVEFORM_SAMPLES < 576) // [don't let this code bloat our DLL size if it's not going to be used] + + int nSamples = NUM_WAVEFORM_SAMPLES; + +#define MAX_OCTAVES 10 + + int octaves = (int)floorf(logf((float)(576-nSamples))/logf(2.0f)); + if (octaves < 4) + return; + if (octaves > MAX_OCTAVES) + octaves = MAX_OCTAVES; + + for (int ch=0; ch<2; ch++) + { + // only worry about matching the lower 'nSamples' samples + float temp_new[MAX_OCTAVES][576]; + float temp_old[MAX_OCTAVES][576]; + static float temp_weight[MAX_OCTAVES][576]; + static int first_nonzero_weight[MAX_OCTAVES]; + static int last_nonzero_weight[MAX_OCTAVES]; + int spls[MAX_OCTAVES]; + int space[MAX_OCTAVES]; + + memcpy(temp_new[0], m_sound.fWaveform[ch], sizeof(float)*576); + memcpy(temp_old[0], &m_oldwave[ch][m_prev_align_offset[ch]], sizeof(float)*nSamples); + spls[0] = 576; + space[0] = 576 - nSamples; + + // potential optimization: could reuse (instead of recompute) mip levels for m_oldwave[2][]? + int octave = 0; + for (octave=1; octave<octaves; octave++) + { + spls[octave] = spls[octave-1]/2; + space[octave] = space[octave-1]/2; + for (int n=0; n<spls[octave]; n++) + { + temp_new[octave][n] = 0.5f*(temp_new[octave-1][n*2] + temp_new[octave-1][n*2+1]); + temp_old[octave][n] = 0.5f*(temp_old[octave-1][n*2] + temp_old[octave-1][n*2+1]); + } + } + + if (!m_align_weights_ready) + { + m_align_weights_ready = 1; + for (octave=0; octave<octaves; octave++) + { + int compare_samples = spls[octave] - space[octave]; + int n = 0; + for (n=0; n<compare_samples; n++) + { + // start with pyramid-shaped pdf, from 0..1..0 + if (n < compare_samples/2) + temp_weight[octave][n] = n*2/(float)compare_samples; + else + temp_weight[octave][n] = (compare_samples-1 - n)*2/(float)compare_samples; + + // TWEAK how much the center matters, vs. the edges: + temp_weight[octave][n] = (temp_weight[octave][n] - 0.8f)*5.0f + 0.8f; + + // clip: + if (temp_weight[octave][n]>1) temp_weight[octave][n] = 1; + if (temp_weight[octave][n]<0) temp_weight[octave][n] = 0; + } + + n = 0; + while (temp_weight[octave][n] == 0 && n < compare_samples) + n++; + first_nonzero_weight[octave] = n; + + n = compare_samples-1; + while (temp_weight[octave][n] == 0 && n >= 0) + n--; + last_nonzero_weight[octave] = n; + } + } + + int n1 = 0; + int n2 = space[octaves-1]; + for (octave = octaves-1; octave>=0; octave--) + { + // for example: + // space[octave] == 4 + // spls[octave] == 36 + // (so we test 32 samples, w/4 offsets) + int compare_samples = spls[octave]-space[octave]; + + int lowest_err_offset = -1; + float lowest_err_amount = 0; + for (int n=n1; n<n2; n++) + { + float err_sum = 0; + //for (int i=0; i<compare_samples; i++) + for (int i=first_nonzero_weight[octave]; i<=last_nonzero_weight[octave]; i++) + { + float x = (temp_new[octave][i+n] - temp_old[octave][i]) * temp_weight[octave][i]; + if (x>0) + err_sum += x; + else + err_sum -= x; + } + + if (lowest_err_offset == -1 || err_sum < lowest_err_amount) + { + lowest_err_offset = n; + lowest_err_amount = err_sum; + } + } + + // now use 'lowest_err_offset' to guide bounds of search in next octave: + // space[octave] == 8 + // spls[octave] == 72 + // -say 'lowest_err_offset' was 2 + // -that corresponds to samples 4 & 5 of the next octave + // -also, expand about this by 2 samples? YES. + // (so we'd test 64 samples, w/8->4 offsets) + if (octave > 0) + { + n1 = lowest_err_offset*2 -1; + n2 = lowest_err_offset*2+2+1; + if (n1 < 0) n1=0; + if (n2 > space[octave-1]) n2 = space[octave-1]; + } + else + align_offset[ch] = lowest_err_offset; + } + } +#endif + memcpy(m_oldwave[0], m_sound.fWaveform[0], sizeof(float)*576); + memcpy(m_oldwave[1], m_sound.fWaveform[1], sizeof(float)*576); + m_prev_align_offset[0] = align_offset[0]; + m_prev_align_offset[1] = align_offset[1]; + + // finally, apply the results: modify m_sound.fWaveform[2][0..576] + // by scooting the aligned samples so that they start at m_sound.fWaveform[2][0]. + for (int ch=0; ch<2; ch++) + if (align_offset[ch]>0) + { + for (int i=0; i<nSamples; i++) + m_sound.fWaveform[ch][i] = m_sound.fWaveform[ch][i+align_offset[ch]]; + // zero the rest out, so it's visually evident that these samples are now bogus: + memset(&m_sound.fWaveform[ch][nSamples], 0, (576-nSamples)*sizeof(float)); + } +} + +LRESULT CALLBACK CPluginShell::VJModeWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam) +{ + CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hWnd,GWLP_USERDATA); + if (p) + return p->PluginShellVJModeWndProc(hWnd, uMsg, wParam, lParam); + else + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +LRESULT CPluginShell::PluginShellVJModeWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ +#ifdef _DEBUG + if (message != WM_MOUSEMOVE && + message != WM_NCHITTEST && + message != WM_SETCURSOR && + message != WM_COPYDATA && + message != WM_USER) + { + char caption[256] = "VJWndProc: frame 0, "; + if (m_frame > 0) + { + float time = m_time; + int hours = (int)(time/3600); + time -= hours*3600; + int minutes = (int)(time/60); + time -= minutes*60; + int seconds = (int)time; + time -= seconds; + int dsec = (int)(time*100); + sprintf(caption, "VJWndProc: frame %d, t=%dh:%02dm:%02d.%02ds, ", m_frame, hours, minutes, seconds, dsec); + } + OutputDebugMessage(caption, hwnd, message, wParam, lParam); + } +#endif + + switch (message) + { + case WM_KEYDOWN: + case WM_KEYUP: + case WM_CHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_SYSCHAR: + // pass keystrokes on to plugin! + return PluginShellWindowProc(GetPluginWindow(),message,wParam,lParam); + + case WM_ERASEBKGND: + // Repaint window when song is paused and image needs to be repainted: + if (SendMessage(m_hWndWinamp,WM_USER,0,104)!=1 && m_vjd3d9_device && GetFrame() > 0) // WM_USER/104 return codes: 1=playing, 3=paused, other=stopped + { + m_vjd3d9_device->Present(NULL,NULL,NULL,NULL); + return 0; + } + break; + + /* + case WM_WINDOWPOSCHANGING: + if (m_screenmode == DESKTOP) + { + LPWINDOWPOS pwp = (LPWINDOWPOS)lParam; + if (pwp) + pwp->flags |= SWP_NOOWNERZORDER | SWP_NOZORDER; + } + break; + + case WM_ACTIVATEAPP: + // *Very Important Handler!* + // -Without this code, the app would not work properly when running in true + // fullscreen mode on multiple monitors; it would auto-minimize whenever the + // user clicked on a window in another display. + if (wParam == 1 && + m_screenmode == DESKTOP && + m_frame > 0 && + !m_exiting + ) + { + return 0; + } + break; + + /* + case WM_NCACTIVATE: + // *Very Important Handler!* + // -Without this code, the app would not work properly when running in true + // fullscreen mode on multiple monitors; it would auto-minimize whenever the + // user clicked on a window in another display. + // (NOTE: main window also handles this message this way) + if (wParam == 0 && + m_screenmode == FULLSCREEN && + m_frame > 0 && + !m_exiting && + m_lpDX && + m_lpDX->m_ready + && m_lpDX->m_lpD3D && + m_lpDX->m_lpD3D->GetAdapterCount() > 1 + ) + { + return 0; + } + break; + */ + + /* + case WM_ACTIVATEAPP: + if (wParam == 1 && + m_screenmode == DESKTOP && + m_frame > 0 && + !m_exiting && + m_vjd3d9_device + ) + { + return 0; + } + break; + */ + + /* + case WM_WINDOWPOSCHANGING: + if ( + m_screenmode == DESKTOP + && (!m_force_accept_WM_WINDOWPOSCHANGING) + && m_lpDX && m_lpDX->m_ready + ) + { + // unless we requested it ourselves or it's init time, + // prevent the fake desktop window from moving around + // in the Z order! (i.e., keep it on the bottom) + + // without this code, when you click on the 'real' desktop + // 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/Src/Plugins/Visualization/vis_milk2/pluginshell.h b/Src/Plugins/Visualization/vis_milk2/pluginshell.h new file mode 100644 index 00000000..a7437374 --- /dev/null +++ b/Src/Plugins/Visualization/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 <vector> + +#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<icon_t> IconList; + typedef std::vector<icon_t> 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/Src/Plugins/Visualization/vis_milk2/resource.h b/Src/Plugins/Visualization/vis_milk2/resource.h new file mode 100644 index 00000000..fccefb5c --- /dev/null +++ b/Src/Plugins/Visualization/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/Src/Plugins/Visualization/vis_milk2/shell_defines.h b/Src/Plugins/Visualization/vis_milk2/shell_defines.h new file mode 100644 index 00000000..c978ce71 --- /dev/null +++ b/Src/Plugins/Visualization/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 <windows.h> + +#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/Src/Plugins/Visualization/vis_milk2/state.cpp b/Src/Plugins/Visualization/vis_milk2/state.cpp new file mode 100644 index 00000000..68b060f3 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/state.cpp @@ -0,0 +1,1961 @@ +/* + 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__vis_milk2.h" +#include "state.h" +#include "support.h" +#include "ns-eel2/ns-eel.h" +#include "plugin.h" +#include "utility.h" +#include <windows.h> +#include <locale.h> +#include "resource.h" +#include <vector> +#include <assert.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 "gstring.h" + +typedef std::vector<GStringA> VarNameList; +typedef std::vector<int > 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(); + int i = 0; + for (i=0; i<N; i++) + if (strcmp(line_varName[i].c_str(), szVarName) == 0) + { + MyLineNum = i; + break; + } + + // otherwise, szVarName not found in the file! + if (i==N) + return false; + } + + fseek(f, line_value_bytepos[MyLineNum], SEEK_SET); + + // now we know that we found and ate the '=' sign; return rest of the line. + int nChars = 0; + int pos = 0; + while (pos < nMaxRetChars-3) + { + char ch = fgetc(f); + if (ch == '\r' || ch == '\n' || ch==EOF) + break; + szRet[pos++] = ch; + }; + szRet[pos] = 0; + //fgets(szRet, nMaxRetChars-3, f); // reads chars up til the next linefeed. NAH - it also copies in the linefeed char... + + // move to next line + MyLineNum++; + //fseek(f, line_value_bytepos[MyLineNum], SEEK_SET); + + return true; +} + +int GetFastInt (const char* szVarName, int def, FILE* f) +{ + char buf[256]; + if (!_GetLineByName(f, szVarName, buf, 255)) + return def; + int ret; + if (sscanf(buf, "%d", &ret)==1) + return ret; + return def; +} + +float GetFastFloat (const char* szVarName, float def, FILE* f) +{ + char buf[256]; + if (!_GetLineByName(f, szVarName, buf, 255)) + return def; + float ret; + if (_sscanf_l(buf, "%f", g_use_C_locale, &ret)==1) + { + return ret; + } + return def; +} + +void GetFastString(const char* szVarName, const char* szDef, char* szRetLine, int nMaxChars, FILE* f) +{ + if (_GetLineByName(f, szVarName, szRetLine, nMaxChars-1)) + return; + // otherwise, copy the default string, being careful not to overflow dest buf. + // (avoid strncpy because it pads with zeroes all the way out to the max size.) + int x = 0; + while (szDef[x] && x < nMaxChars) + { + szRetLine[x] = szDef[x]; + x++; + } + szRetLine[x] = 0; +} + +CState::CState() +{ + //Default(); + + // this is the list of variables that can be used for a PER-FRAME calculation; + // it is a SUBSET of the per-vertex calculation variable list. + m_pf_codehandle = NULL; + m_pp_codehandle = NULL; + m_pf_eel = NSEEL_VM_alloc(); + m_pv_eel = NSEEL_VM_alloc(); + int i = 0; + for (i=0; i<MAX_CUSTOM_WAVES; i++) + { + m_wave[i].m_pf_codehandle = NULL; + m_wave[i].m_pp_codehandle = NULL; + m_wave[i].m_pf_eel=NSEEL_VM_alloc(); + m_wave[i].m_pp_eel=NSEEL_VM_alloc(); + } + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + { + m_shape[i].m_pf_codehandle = NULL; + m_shape[i].m_pf_eel=NSEEL_VM_alloc(); + //m_shape[i].m_pp_codehandle = NULL; + } + //RegisterBuiltInVariables(); +} + +CState::~CState() +{ + FreeVarsAndCode(); + NSEEL_VM_free(m_pf_eel); + NSEEL_VM_free(m_pv_eel); + int i = 0; + for (i=0; i<MAX_CUSTOM_WAVES; i++) + { + NSEEL_VM_free(m_wave[i].m_pf_eel); + NSEEL_VM_free(m_wave[i].m_pp_eel); + } + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + { + NSEEL_VM_free(m_shape[i].m_pf_eel); + } +} + +//-------------------------------------------------------------------------------- + +void CState::RegisterBuiltInVariables(int flags) +{ + if (flags & RECOMPILE_PRESET_CODE) + { + NSEEL_VM_resetvars(m_pf_eel); + var_pf_zoom = NSEEL_VM_regvar(m_pf_eel, "zoom"); // i/o + var_pf_zoomexp = NSEEL_VM_regvar(m_pf_eel, "zoomexp"); // i/o + var_pf_rot = NSEEL_VM_regvar(m_pf_eel, "rot"); // i/o + var_pf_warp = NSEEL_VM_regvar(m_pf_eel, "warp"); // i/o + var_pf_cx = NSEEL_VM_regvar(m_pf_eel, "cx"); // i/o + var_pf_cy = NSEEL_VM_regvar(m_pf_eel, "cy"); // i/o + var_pf_dx = NSEEL_VM_regvar(m_pf_eel, "dx"); // i/o + var_pf_dy = NSEEL_VM_regvar(m_pf_eel, "dy"); // i/o + var_pf_sx = NSEEL_VM_regvar(m_pf_eel, "sx"); // i/o + var_pf_sy = NSEEL_VM_regvar(m_pf_eel, "sy"); // i/o + var_pf_time = NSEEL_VM_regvar(m_pf_eel, "time"); // i + var_pf_fps = NSEEL_VM_regvar(m_pf_eel, "fps"); // i + var_pf_bass = NSEEL_VM_regvar(m_pf_eel, "bass"); // i + var_pf_mid = NSEEL_VM_regvar(m_pf_eel, "mid"); // i + var_pf_treb = NSEEL_VM_regvar(m_pf_eel, "treb"); // i + var_pf_bass_att = NSEEL_VM_regvar(m_pf_eel, "bass_att"); // i + var_pf_mid_att = NSEEL_VM_regvar(m_pf_eel, "mid_att"); // i + var_pf_treb_att = NSEEL_VM_regvar(m_pf_eel, "treb_att"); // i + var_pf_frame = NSEEL_VM_regvar(m_pf_eel, "frame"); + var_pf_decay = NSEEL_VM_regvar(m_pf_eel, "decay"); + var_pf_wave_a = NSEEL_VM_regvar(m_pf_eel, "wave_a"); + var_pf_wave_r = NSEEL_VM_regvar(m_pf_eel, "wave_r"); + var_pf_wave_g = NSEEL_VM_regvar(m_pf_eel, "wave_g"); + var_pf_wave_b = NSEEL_VM_regvar(m_pf_eel, "wave_b"); + var_pf_wave_x = NSEEL_VM_regvar(m_pf_eel, "wave_x"); + var_pf_wave_y = NSEEL_VM_regvar(m_pf_eel, "wave_y"); + var_pf_wave_mystery = NSEEL_VM_regvar(m_pf_eel, "wave_mystery"); + var_pf_wave_mode = NSEEL_VM_regvar(m_pf_eel, "wave_mode"); + int vi = 0; + for (vi=0; vi<NUM_Q_VAR; vi++) + { + char buf[16]; + sprintf(buf, "q%d", vi+1); + var_pf_q[vi] = NSEEL_VM_regvar(m_pf_eel, buf); + } + var_pf_progress = NSEEL_VM_regvar(m_pf_eel, "progress"); + var_pf_ob_size = NSEEL_VM_regvar(m_pf_eel, "ob_size"); + var_pf_ob_r = NSEEL_VM_regvar(m_pf_eel, "ob_r"); + var_pf_ob_g = NSEEL_VM_regvar(m_pf_eel, "ob_g"); + var_pf_ob_b = NSEEL_VM_regvar(m_pf_eel, "ob_b"); + var_pf_ob_a = NSEEL_VM_regvar(m_pf_eel, "ob_a"); + var_pf_ib_size = NSEEL_VM_regvar(m_pf_eel, "ib_size"); + var_pf_ib_r = NSEEL_VM_regvar(m_pf_eel, "ib_r"); + var_pf_ib_g = NSEEL_VM_regvar(m_pf_eel, "ib_g"); + var_pf_ib_b = NSEEL_VM_regvar(m_pf_eel, "ib_b"); + var_pf_ib_a = NSEEL_VM_regvar(m_pf_eel, "ib_a"); + var_pf_mv_x = NSEEL_VM_regvar(m_pf_eel, "mv_x"); + var_pf_mv_y = NSEEL_VM_regvar(m_pf_eel, "mv_y"); + var_pf_mv_dx = NSEEL_VM_regvar(m_pf_eel, "mv_dx"); + var_pf_mv_dy = NSEEL_VM_regvar(m_pf_eel, "mv_dy"); + var_pf_mv_l = NSEEL_VM_regvar(m_pf_eel, "mv_l"); + var_pf_mv_r = NSEEL_VM_regvar(m_pf_eel, "mv_r"); + var_pf_mv_g = NSEEL_VM_regvar(m_pf_eel, "mv_g"); + var_pf_mv_b = NSEEL_VM_regvar(m_pf_eel, "mv_b"); + var_pf_mv_a = NSEEL_VM_regvar(m_pf_eel, "mv_a"); + var_pf_monitor = NSEEL_VM_regvar(m_pf_eel, "monitor"); + var_pf_echo_zoom = NSEEL_VM_regvar(m_pf_eel, "echo_zoom"); + var_pf_echo_alpha = NSEEL_VM_regvar(m_pf_eel, "echo_alpha"); + var_pf_echo_orient = NSEEL_VM_regvar(m_pf_eel, "echo_orient"); + var_pf_wave_usedots = NSEEL_VM_regvar(m_pf_eel, "wave_usedots"); + var_pf_wave_thick = NSEEL_VM_regvar(m_pf_eel, "wave_thick"); + var_pf_wave_additive = NSEEL_VM_regvar(m_pf_eel, "wave_additive"); + var_pf_wave_brighten = NSEEL_VM_regvar(m_pf_eel, "wave_brighten"); + var_pf_darken_center = NSEEL_VM_regvar(m_pf_eel, "darken_center"); + var_pf_gamma = NSEEL_VM_regvar(m_pf_eel, "gamma"); + var_pf_wrap = NSEEL_VM_regvar(m_pf_eel, "wrap"); + var_pf_invert = NSEEL_VM_regvar(m_pf_eel, "invert"); + var_pf_brighten = NSEEL_VM_regvar(m_pf_eel, "brighten"); + var_pf_darken = NSEEL_VM_regvar(m_pf_eel, "darken"); + var_pf_solarize = NSEEL_VM_regvar(m_pf_eel, "solarize"); + var_pf_meshx = NSEEL_VM_regvar(m_pf_eel, "meshx"); + var_pf_meshy = NSEEL_VM_regvar(m_pf_eel, "meshy"); + var_pf_pixelsx = NSEEL_VM_regvar(m_pf_eel, "pixelsx"); + var_pf_pixelsy = NSEEL_VM_regvar(m_pf_eel, "pixelsy"); + var_pf_aspectx = NSEEL_VM_regvar(m_pf_eel, "aspectx"); + var_pf_aspecty = NSEEL_VM_regvar(m_pf_eel, "aspecty"); + var_pf_blur1min = NSEEL_VM_regvar(m_pf_eel, "blur1_min"); + var_pf_blur2min = NSEEL_VM_regvar(m_pf_eel, "blur2_min"); + var_pf_blur3min = NSEEL_VM_regvar(m_pf_eel, "blur3_min"); + var_pf_blur1max = NSEEL_VM_regvar(m_pf_eel, "blur1_max"); + var_pf_blur2max = NSEEL_VM_regvar(m_pf_eel, "blur2_max"); + var_pf_blur3max = NSEEL_VM_regvar(m_pf_eel, "blur3_max"); + var_pf_blur1_edge_darken = NSEEL_VM_regvar(m_pf_eel, "blur1_edge_darken"); + + // this is the list of variables that can be used for a PER-VERTEX calculation: + // ('vertex' meaning a vertex on the mesh) (as opposed to a once-per-frame calculation) + + NSEEL_VM_resetvars(m_pv_eel); + + var_pv_zoom = NSEEL_VM_regvar(m_pv_eel, "zoom"); // i/o + var_pv_zoomexp = NSEEL_VM_regvar(m_pv_eel, "zoomexp"); // i/o + var_pv_rot = NSEEL_VM_regvar(m_pv_eel, "rot"); // i/o + var_pv_warp = NSEEL_VM_regvar(m_pv_eel, "warp"); // i/o + var_pv_cx = NSEEL_VM_regvar(m_pv_eel, "cx"); // i/o + var_pv_cy = NSEEL_VM_regvar(m_pv_eel, "cy"); // i/o + var_pv_dx = NSEEL_VM_regvar(m_pv_eel, "dx"); // i/o + var_pv_dy = NSEEL_VM_regvar(m_pv_eel, "dy"); // i/o + var_pv_sx = NSEEL_VM_regvar(m_pv_eel, "sx"); // i/o + var_pv_sy = NSEEL_VM_regvar(m_pv_eel, "sy"); // i/o + var_pv_time = NSEEL_VM_regvar(m_pv_eel, "time"); // i + var_pv_fps = NSEEL_VM_regvar(m_pv_eel, "fps"); // i + var_pv_bass = NSEEL_VM_regvar(m_pv_eel, "bass"); // i + var_pv_mid = NSEEL_VM_regvar(m_pv_eel, "mid"); // i + var_pv_treb = NSEEL_VM_regvar(m_pv_eel, "treb"); // i + var_pv_bass_att = NSEEL_VM_regvar(m_pv_eel, "bass_att"); // i + var_pv_mid_att = NSEEL_VM_regvar(m_pv_eel, "mid_att"); // i + var_pv_treb_att = NSEEL_VM_regvar(m_pv_eel, "treb_att"); // i + var_pv_frame = NSEEL_VM_regvar(m_pv_eel, "frame"); + var_pv_x = NSEEL_VM_regvar(m_pv_eel, "x"); // i + var_pv_y = NSEEL_VM_regvar(m_pv_eel, "y"); // i + var_pv_rad = NSEEL_VM_regvar(m_pv_eel, "rad"); // i + var_pv_ang = NSEEL_VM_regvar(m_pv_eel, "ang"); // i + for (vi=0; vi<NUM_Q_VAR; vi++) + { + char buf[16]; + sprintf(buf, "q%d", vi+1); + var_pv_q[vi] = NSEEL_VM_regvar(m_pv_eel, buf); + } + var_pv_progress = NSEEL_VM_regvar(m_pv_eel, "progress"); + var_pv_meshx = NSEEL_VM_regvar(m_pv_eel, "meshx"); + var_pv_meshy = NSEEL_VM_regvar(m_pv_eel, "meshy"); + var_pv_pixelsx = NSEEL_VM_regvar(m_pv_eel, "pixelsx"); + var_pv_pixelsy = NSEEL_VM_regvar(m_pv_eel, "pixelsy"); + var_pv_aspectx = NSEEL_VM_regvar(m_pv_eel, "aspectx"); + var_pv_aspecty = NSEEL_VM_regvar(m_pv_eel, "aspecty"); + } + + if (flags & RECOMPILE_WAVE_CODE) + { + for (int i=0; i<MAX_CUSTOM_WAVES; i++) + { + NSEEL_VM_resetvars(m_wave[i].m_pf_eel); + m_wave[i].var_pf_time = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "time"); // i + m_wave[i].var_pf_fps = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "fps"); // i + m_wave[i].var_pf_frame = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "frame"); // i + m_wave[i].var_pf_progress = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "progress"); // i + int vi = 0; + for (vi=0; vi<NUM_Q_VAR; vi++) + { + char buf[16]; + sprintf(buf, "q%d", vi+1); + m_wave[i].var_pf_q[vi] = NSEEL_VM_regvar(m_wave[i].m_pf_eel, buf); + } + for (vi=0; vi<NUM_T_VAR; vi++) + { + char buf[16]; + sprintf(buf, "t%d", vi+1); + m_wave[i].var_pf_t[vi] = NSEEL_VM_regvar(m_wave[i].m_pf_eel, buf); + } + m_wave[i].var_pf_bass = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "bass"); // i + m_wave[i].var_pf_mid = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "mid"); // i + m_wave[i].var_pf_treb = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "treb"); // i + m_wave[i].var_pf_bass_att = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "bass_att"); // i + m_wave[i].var_pf_mid_att = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "mid_att"); // i + m_wave[i].var_pf_treb_att = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "treb_att"); // i + m_wave[i].var_pf_r = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "r"); // i/o + m_wave[i].var_pf_g = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "g"); // i/o + m_wave[i].var_pf_b = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "b"); // i/o + m_wave[i].var_pf_a = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "a"); // i/o + m_wave[i].var_pf_samples = NSEEL_VM_regvar(m_wave[i].m_pf_eel, "samples"); // i/o + + NSEEL_VM_resetvars(m_wave[i].m_pp_eel); + m_wave[i].var_pp_time = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "time"); // i + m_wave[i].var_pp_fps = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "fps"); // i + m_wave[i].var_pp_frame = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "frame"); // i + m_wave[i].var_pp_progress = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "progress"); // i + for (vi=0; vi<NUM_Q_VAR; vi++) + { + char buf[16]; + sprintf(buf, "q%d", vi+1); + m_wave[i].var_pp_q[vi] = NSEEL_VM_regvar(m_wave[i].m_pp_eel, buf); + } + for (vi=0; vi<NUM_T_VAR; vi++) + { + char buf[16]; + sprintf(buf, "t%d", vi+1); + m_wave[i].var_pp_t[vi] = NSEEL_VM_regvar(m_wave[i].m_pp_eel, buf); + } + m_wave[i].var_pp_bass = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "bass"); // i + m_wave[i].var_pp_mid = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "mid"); // i + m_wave[i].var_pp_treb = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "treb"); // i + m_wave[i].var_pp_bass_att = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "bass_att"); // i + m_wave[i].var_pp_mid_att = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "mid_att"); // i + m_wave[i].var_pp_treb_att = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "treb_att"); // i + m_wave[i].var_pp_sample = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "sample"); // i + m_wave[i].var_pp_value1 = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "value1"); // i + m_wave[i].var_pp_value2 = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "value2"); // i + m_wave[i].var_pp_x = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "x"); // i/o + m_wave[i].var_pp_y = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "y"); // i/o + m_wave[i].var_pp_r = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "r"); // i/o + m_wave[i].var_pp_g = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "g"); // i/o + m_wave[i].var_pp_b = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "b"); // i/o + m_wave[i].var_pp_a = NSEEL_VM_regvar(m_wave[i].m_pp_eel, "a"); // i/o + } + } + + if (flags & RECOMPILE_SHAPE_CODE) + { + for (int i=0; i<MAX_CUSTOM_SHAPES; i++) + { + NSEEL_VM_resetvars(m_shape[i].m_pf_eel); + m_shape[i].var_pf_time = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "time"); // i + m_shape[i].var_pf_fps = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "fps"); // i + m_shape[i].var_pf_frame = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "frame"); // i + m_shape[i].var_pf_progress = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "progress"); // i + int vi = 0; + for (vi=0; vi<NUM_Q_VAR; vi++) + { + char buf[16]; + sprintf(buf, "q%d", vi+1); + m_shape[i].var_pf_q[vi] = NSEEL_VM_regvar(m_shape[i].m_pf_eel, buf); + } + for (vi=0; vi<NUM_T_VAR; vi++) + { + char buf[16]; + sprintf(buf, "t%d", vi+1); + m_shape[i].var_pf_t[vi] = NSEEL_VM_regvar(m_shape[i].m_pf_eel, buf); + } + m_shape[i].var_pf_bass = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "bass"); // i + m_shape[i].var_pf_mid = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "mid"); // i + m_shape[i].var_pf_treb = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "treb"); // i + m_shape[i].var_pf_bass_att = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "bass_att"); // i + m_shape[i].var_pf_mid_att = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "mid_att"); // i + m_shape[i].var_pf_treb_att = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "treb_att"); // i + m_shape[i].var_pf_x = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "x"); // i/o + m_shape[i].var_pf_y = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "y"); // i/o + m_shape[i].var_pf_rad = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "rad"); // i/o + m_shape[i].var_pf_ang = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "ang"); // i/o + m_shape[i].var_pf_tex_ang = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "tex_ang"); // i/o + m_shape[i].var_pf_tex_zoom = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "tex_zoom"); // i/o + m_shape[i].var_pf_sides = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "sides"); // i/o + m_shape[i].var_pf_textured = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "textured"); // i/o + m_shape[i].var_pf_instance = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "instance"); // i/o + m_shape[i].var_pf_instances = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "num_inst"); // i/o + m_shape[i].var_pf_additive = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "additive"); // i/o + m_shape[i].var_pf_thick = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "thick"); // i/o + m_shape[i].var_pf_r = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "r"); // i/o + m_shape[i].var_pf_g = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "g"); // i/o + m_shape[i].var_pf_b = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "b"); // i/o + m_shape[i].var_pf_a = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "a"); // i/o + m_shape[i].var_pf_r2 = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "r2"); // i/o + m_shape[i].var_pf_g2 = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "g2"); // i/o + m_shape[i].var_pf_b2 = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "b2"); // i/o + m_shape[i].var_pf_a2 = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "a2"); // i/o + m_shape[i].var_pf_border_r = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "border_r"); // i/o + m_shape[i].var_pf_border_g = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "border_g"); // i/o + m_shape[i].var_pf_border_b = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "border_b"); // i/o + m_shape[i].var_pf_border_a = NSEEL_VM_regvar(m_shape[i].m_pf_eel, "border_a"); // i/o + } + } +} +void CState::Default(DWORD ApplyFlags) +{ + // DON'T FORGET TO ADD NEW VARIABLES TO BLEND FUNCTION, IMPORT, and EXPORT AS WELL!!!!!!!! + + 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. + ) + { + lstrcpyW(m_szDesc, INVALID_PRESET_DESC); + //lstrcpy(m_szSection, "n/a"); + + m_fPresetStartTime = -1; + } + + m_nMinPSVersion = 0; + m_nMaxPSVersion = 0; + + m_bBlending = false; + + // general: + if (ApplyFlags & STATE_GENERAL) + { + m_fRating = 3.0f; + m_fDecay = 0.98f; // 1.0 = none, 0.95 = heavy decay + m_fGammaAdj = 2.0f; // 1.0 = reg; +2.0 = double, +3.0 = triple... + m_fVideoEchoZoom = 2.0f; + m_fVideoEchoAlpha = 0.0f; + m_nVideoEchoOrientation = 0; // 0-3 + m_bRedBlueStereo = false; + m_bBrighten = false; + m_bDarken = false; + m_bTexWrap = true; + m_bDarkenCenter = false; + m_bSolarize = false; + m_bInvert = false; + m_fShader = 0.0f; + m_fBlur1Min = 0.0f; + m_fBlur2Min = 0.0f; + m_fBlur3Min = 0.0f; + m_fBlur1Max = 1.0f; + m_fBlur2Max = 1.0f; + m_fBlur3Max = 1.0f; + m_fBlur1EdgeDarken = 0.25f; + } + + + // wave: + if (ApplyFlags & STATE_WAVE) + { + m_nWaveMode = 0; + m_nOldWaveMode = -1; + m_bAdditiveWaves = false; + m_bWaveDots = false; + m_bWaveThick = false; + m_fWaveAlpha = 0.8f; + m_fWaveScale = 1.0f; + m_fWaveSmoothing = 0.75f; // 0 = no smoothing, 0.9 = HEAVY smoothing + m_fWaveParam = 0.0f; + m_bModWaveAlphaByVolume = false; + m_fModWaveAlphaStart = 0.75f; // when relative volume hits this level, alpha -> 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; + + int i = 0; + for (i=0; i<MAX_CUSTOM_WAVES; i++) + { + m_wave[i].enabled = 0; + m_wave[i].samples = 512; + m_wave[i].sep = 0; + m_wave[i].scaling = 1.0f; + m_wave[i].smoothing = 0.5f; + m_wave[i].r = 1.0f; + m_wave[i].g = 1.0f; + m_wave[i].b = 1.0f; + m_wave[i].a = 1.0f; + m_wave[i].bSpectrum = 0; + m_wave[i].bUseDots = 0; + m_wave[i].bDrawThick = 0; + m_wave[i].bAdditive = 0; + } + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + { + m_shape[i].enabled = 0; + m_shape[i].sides = 4; + m_shape[i].additive = 0; + m_shape[i].thickOutline = 0; + m_shape[i].textured = 0; + m_shape[i].instances = 1; + m_shape[i].tex_zoom = 1.0f; + m_shape[i].tex_ang = 0.0f; + m_shape[i].x = 0.5f; + m_shape[i].y = 0.5f; + m_shape[i].rad = 0.1f; + m_shape[i].ang = 0.0f; + m_shape[i].r = 1.0f; + m_shape[i].g = 0.0f; + m_shape[i].b = 0.0f; + m_shape[i].a = 1.0f; + m_shape[i].r2 = 0.0f; + m_shape[i].g2 = 1.0f; + m_shape[i].b2 = 0.0f; + m_shape[i].a2 = 0.0f; + m_shape[i].border_r = 1.0f; + m_shape[i].border_g = 1.0f; + m_shape[i].border_b = 1.0f; + m_shape[i].border_a = 0.1f; + } + for (i=0; i<MAX_CUSTOM_WAVES; i++) + { + m_wave[i].m_szInit[0] = 0; + m_wave[i].m_szPerFrame[0] = 0; + m_wave[i].m_szPerPoint[0] = 0; + } + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + { + m_shape[i].m_szInit[0] = 0; + m_shape[i].m_szPerFrame[0] = 0; + //m_shape[i].m_szPerPoint[0] = 0; + } + } + + // motion: + if (ApplyFlags & STATE_MOTION) + { + m_fWarpAnimSpeed = 1.0f; // additional timescaling for warp animation + m_fWarpScale = 1.0f; + m_fZoomExponent = 1.0f; + m_fZoom = 1.0f; + m_fRot = 0.0f; + m_fRotCX = 0.5f; + m_fRotCY = 0.5f; + m_fXPush = 0.0f; + m_fYPush = 0.0f; + m_fWarpAmount = 1.0f; + m_fStretchX = 1.0f; + m_fStretchY = 1.0f; + m_fOuterBorderSize = 0.01f; + m_fOuterBorderR = 0.0f; + m_fOuterBorderG = 0.0f; + m_fOuterBorderB = 0.0f; + m_fOuterBorderA = 0.0f; + m_fInnerBorderSize = 0.01f; + m_fInnerBorderR = 0.25f; + m_fInnerBorderG = 0.25f; + m_fInnerBorderB = 0.25f; + m_fInnerBorderA = 0.0f; + + // clear all code strings: + m_szPerFrameInit[0] = 0; + m_szPerFrameExpr[0] = 0; + m_szPerPixelExpr[0] = 0; + } + + // DON'T FORGET TO ADD NEW VARIABLES TO BLEND FUNCTION, IMPORT, and EXPORT AS WELL!!!!!!!! + // ALSO BE SURE TO REGISTER THEM ON THE MAIN MENU (SEE MILKDROP.CPP) + + // warp shader + if (ApplyFlags & STATE_WARP) + { + m_szWarpShadersText[0] = 0; + m_nWarpPSVersion = 0; + } + + // comp shader + if (ApplyFlags & STATE_COMP) + { + m_szCompShadersText[0] = 0; + m_nCompPSVersion = 0; + } + + RandomizePresetVars(); + + FreeVarsAndCode(); +} + +void CState::StartBlendFrom(CState *s_from, float fAnimTime, float fTimespan) +{ + CState *s_to = this; + + // bools, ints, and strings instantly change + + 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_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; e<MAX_EVALS; e++) + { + char szTemp[MAX_BIGSTRING_LEN]; + + lstrcpy(szTemp, m_szPerFrameExpr); + lstrcpy(m_szPerFrameExpr, s_to->m_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)); + + int i = 0; + for (i=0; i<MAX_CUSTOM_WAVES; i++) + m_wave[i].Export(fOut, L"dummy_filename", i); + + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + m_shape[i].Export(fOut, L"dummy_filename", i); + + // write out arbitrary expressions, one line at a time + WriteCode(fOut, i, m_szPerFrameInit, "per_frame_init_"); + WriteCode(fOut, i, m_szPerFrameExpr, "per_frame_"); + WriteCode(fOut, i, m_szPerPixelExpr, "per_pixel_"); + if (m_nWarpPSVersion >= 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<n2; n++) + { + char *pStr; + char prefix[64]; + char szLineName[32]; + char szLine[MAX_BIGSTRING_LEN]; + int len; + + int line = 1; + int char_pos = 0; + bool bDone = false; + + switch(n) + { + case 0: pStr = m_szPerFrameExpr; strcpy(prefix, "per_frame_"); break; + case 1: pStr = m_szPerPixelExpr; strcpy(prefix, "per_pixel_"); break; + case 2: pStr = m_szPerFrameInit; strcpy(prefix, "per_frame_init_"); break; + default: + if (n < 3 + 3*MAX_CUSTOM_WAVES) + { + int i = (n-3) / 3; + int j = (n-3) % 3; + switch(j) + { + case 0: pStr = m_wave[i].m_szInit; sprintf(prefix, "wave_%d_init", i); break; + case 1: pStr = m_wave[i].m_szPerFrame; sprintf(prefix, "wave_%d_per_frame", i); break; + case 2: pStr = m_wave[i].m_szPerPoint; sprintf(prefix, "wave_%d_per_point", i); break; + } + } + else + { + int i = (n-3-3*MAX_CUSTOM_WAVES) / 2; + int j = (n-3-3*MAX_CUSTOM_WAVES) % 2; + switch(j) + { + case 0: pStr = m_shape[i].m_szInit; sprintf(prefix, "shape_%d_init", i); break; + case 1: pStr = m_shape[i].m_szPerFrame; sprintf(prefix, "shape_%d_per_frame", i); break; + } + } + } + + while (!bDone) + { + sprintf(szLineName, "%s%d", prefix, line); + + GetPrivateProfileString(szSectionName, szLineName, "~!@#$", szLine, MAX_BIGSTRING_LEN, szIniFile); // 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, 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); + + int i = 0; + for (i=0; i<MAX_CUSTOM_WAVES; i++) + { + m_wave[i].Import(f, L"dummy_filename", i); + } + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + { + m_shape[i].Import(f, L"dummy_filename", i); + } + } + + // motion: + if (ApplyFlags & STATE_MOTION) + { + m_fZoom = GetFastFloat("zoom",m_fZoom.eval(-1),f); + m_fRot = GetFastFloat("rot",m_fRot.eval(-1),f); + m_fRotCX = GetFastFloat("cx",m_fRotCX.eval(-1),f); + m_fRotCY = GetFastFloat("cy",m_fRotCY.eval(-1),f); + m_fXPush = GetFastFloat("dx",m_fXPush.eval(-1),f); + m_fYPush = GetFastFloat("dy",m_fYPush.eval(-1),f); + m_fWarpAmount = GetFastFloat("warp",m_fWarpAmount.eval(-1),f); + m_fStretchX = GetFastFloat("sx",m_fStretchX.eval(-1),f); + m_fStretchY = GetFastFloat("sy",m_fStretchY.eval(-1),f); + m_bTexWrap = (GetFastInt ("bTexWrap", m_bTexWrap,f) != 0); + m_bDarkenCenter = (GetFastInt ("bDarkenCenter", m_bDarkenCenter,f) != 0); + m_fWarpAnimSpeed = GetFastFloat("fWarpAnimSpeed",m_fWarpAnimSpeed,f); + m_fWarpScale = GetFastFloat("fWarpScale",m_fWarpScale.eval(-1),f); + m_fZoomExponent = GetFastFloat("fZoomExponent",m_fZoomExponent.eval(-1),f); + m_fOuterBorderSize = GetFastFloat("ob_size",m_fOuterBorderSize.eval(-1),f); + m_fOuterBorderR = GetFastFloat("ob_r", m_fOuterBorderR.eval(-1),f); + m_fOuterBorderG = GetFastFloat("ob_g", m_fOuterBorderG.eval(-1),f); + m_fOuterBorderB = GetFastFloat("ob_b", m_fOuterBorderB.eval(-1),f); + m_fOuterBorderA = GetFastFloat("ob_a", m_fOuterBorderA.eval(-1),f); + m_fInnerBorderSize = GetFastFloat("ib_size",m_fInnerBorderSize.eval(-1),f); + m_fInnerBorderR = GetFastFloat("ib_r", m_fInnerBorderR.eval(-1),f); + m_fInnerBorderG = GetFastFloat("ib_g", m_fInnerBorderG.eval(-1),f); + m_fInnerBorderB = GetFastFloat("ib_b", m_fInnerBorderB.eval(-1),f); + m_fInnerBorderA = GetFastFloat("ib_a", m_fInnerBorderA.eval(-1),f); + //m_szPerFrameInit[0] = 0; + //m_szPerFrameExpr[0] = 0; + //m_szPerPixelExpr[0] = 0; + ReadCode(f, m_szPerFrameInit, "per_frame_init_"); + ReadCode(f, m_szPerFrameExpr, "per_frame_"); + ReadCode(f, m_szPerPixelExpr, "per_pixel_"); + } + + // warp shader + if (ApplyFlags & STATE_WARP) + { + //m_szWarpShadersText[0] = 0; + ReadCode(f, m_szWarpShadersText, "warp_"); + if (!m_szWarpShadersText[0]) + g_plugin.GenWarpPShaderText(m_szWarpShadersText, m_fDecay.eval(-1), m_bTexWrap); + m_nWarpPSVersion = nWarpPSVersionInFile; + } + + // comp shader + if (ApplyFlags & STATE_COMP) + { + //m_szCompShadersText[0] = 0; + ReadCode(f, m_szCompShadersText, "comp_"); + if (!m_szCompShadersText[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); + m_nCompPSVersion = nCompPSVersionInFile; + } + + m_nMaxPSVersion = max(m_nWarpPSVersion, m_nCompPSVersion); + m_nMinPSVersion = min(m_nWarpPSVersion, m_nCompPSVersion); + + + RecompileExpressions(); + + fclose(f); + + return true; +} + +void CState::GenDefaultWarpShader() +{ + if (m_nWarpPSVersion>0) + 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; + } + + int i = 0; + for (i=0; i<MAX_CUSTOM_WAVES; i++) + { + if (m_wave[i].m_pf_codehandle) + { + if (bFree) + NSEEL_code_free(m_wave[i].m_pf_codehandle); + m_wave[i].m_pf_codehandle = NULL; + } + if (m_wave[i].m_pp_codehandle) + { + if (bFree) + NSEEL_code_free(m_wave[i].m_pp_codehandle); + m_wave[i].m_pp_codehandle = NULL; + } + } + + for (i=0; i<MAX_CUSTOM_SHAPES; i++) + { + if (m_shape[i].m_pf_codehandle) + { + if (bFree) + NSEEL_code_free(m_shape[i].m_pf_codehandle); + m_shape[i].m_pf_codehandle = NULL; + } + /*if (m_shape[i].m_pp_codehandle) + { + freeCode(m_shape[i].m_pp_codehandle); + m_shape[i].m_pp_codehandle = NULL; + }*/ + } + + // free our text version of the expressions? - no! + //m_szPerFrameExpr[0] = 0; + //m_szPerPixelExpr[0] = 0; + + // free the old variable names & reregister the built-in variables (since they got nuked too) + RegisterBuiltInVariables(0xFFFFFFFF); +} + +void CState::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; i<len; i++) + { + if (bComment) + { + if (src[i] == LINEFEED_CONTROL_CHAR) + bComment = false; + } + else + { + if ((src[i] =='\\' && src[i+1] =='\\') || (src[i] =='/' && src[i+1] =='/')) + bComment = true; + else if (src[i] != LINEFEED_CONTROL_CHAR) + dest[i2++] = src[i]; + } + } + dest[i2] = 0; +} + +void CState::RecompileExpressions(int flags, int bReInit) +{ + // before we get started, if we redo the init code for the preset, we have to redo + // other things too, because q1-q8 could change. + if ((flags & RECOMPILE_PRESET_CODE) && bReInit) + { + flags |= RECOMPILE_WAVE_CODE; + flags |= RECOMPILE_SHAPE_CODE; + } + + // free old code handles + if (flags & RECOMPILE_PRESET_CODE) + { + if (m_pf_codehandle) + { + NSEEL_code_free(m_pf_codehandle); + m_pf_codehandle = NULL; + } + if (m_pp_codehandle) + { + NSEEL_code_free(m_pp_codehandle); + m_pp_codehandle = NULL; + } + } + if (flags & RECOMPILE_WAVE_CODE) + { + for (int i=0; i<MAX_CUSTOM_WAVES; i++) + { + if (m_wave[i].m_pf_codehandle) + { + NSEEL_code_free(m_wave[i].m_pf_codehandle); + m_wave[i].m_pf_codehandle = NULL; + } + if (m_wave[i].m_pp_codehandle) + { + NSEEL_code_free(m_wave[i].m_pp_codehandle); + m_wave[i].m_pp_codehandle = NULL; + } + } + } + if (flags & RECOMPILE_SHAPE_CODE) + { + for (int i=0; i<MAX_CUSTOM_SHAPES; i++) + { + if (m_shape[i].m_pf_codehandle) + { + NSEEL_code_free(m_shape[i].m_pf_codehandle); + m_shape[i].m_pf_codehandle = NULL; + } + /*if (m_shape[i].m_pp_codehandle) + { + freeCode(m_shape[i].m_pp_codehandle); + m_shape[i].m_pp_codehandle = NULL; + }*/ + } + } + + // if we're recompiling init code, clear vars to zero, and re-register built-in variables. + if (bReInit) + { + RegisterBuiltInVariables(flags); + } + + // QUICK FIX: if the code strings ONLY have spaces and linefeeds, erase them, + // because for some strange reason this causes errors in compileCode(). + int n2 = 3 + MAX_CUSTOM_WAVES*3 + MAX_CUSTOM_SHAPES*2; + for (int n=0; n<n2; n++) + { + char *pOrig; + switch(n) + { + case 0: pOrig = m_szPerFrameExpr; break; + case 1: pOrig = m_szPerPixelExpr; break; + case 2: pOrig = m_szPerFrameInit; break; + default: + if (n < 3 + 3*MAX_CUSTOM_WAVES) + { + int i = (n-3) / 3; + int j = (n-3) % 3; + switch(j) + { + case 0: pOrig = m_wave[i].m_szInit; break; + case 1: pOrig = m_wave[i].m_szPerFrame; break; + case 2: pOrig = m_wave[i].m_szPerPoint; break; + } + } + else + { + int i = (n-3-3*MAX_CUSTOM_WAVES) / 2; + int j = (n-3-3*MAX_CUSTOM_WAVES) % 2; + switch(j) + { + case 0: pOrig = m_shape[i].m_szInit; break; + case 1: pOrig = m_shape[i].m_szPerFrame; break; + } + } + } + char *p = pOrig; + while (*p==' ' || *p==LINEFEED_CONTROL_CHAR) p++; + if (*p == 0) pOrig[0] = 0; + } + + // COMPILE NEW CODE. + #ifndef _NO_EXPR_ + { + // clear any old error msg.: + //g_plugin.m_fShowUserMessageUntilThisTime = g_plugin.GetTime(); + + char buf[MAX_BIGSTRING_LEN*3]; + + if (flags & RECOMPILE_PRESET_CODE) + { + // 1. compile AND EXECUTE preset init code + StripLinefeedCharsAndComments(m_szPerFrameInit, buf); + if (buf[0] && bReInit) + { + NSEEL_CODEHANDLE pf_codehandle_init; + + if ( ! (pf_codehandle_init = NSEEL_code_compile(m_pf_eel, buf))) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_WARNING_PRESET_X_ERROR_IN_PRESET_INIT_CODE), m_szDesc); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + + for (int vi=0; vi<NUM_Q_VAR; vi++) + q_values_after_init_code[vi] = 0; + monitor_after_init_code = 0; + } + else + { + // now execute the code, save the values of q1..q32, and clean up the code! + + g_plugin.LoadPerFrameEvallibVars(g_plugin.m_pState); + + NSEEL_code_execute(pf_codehandle_init); + + for (int vi=0; vi<NUM_Q_VAR; vi++) + q_values_after_init_code[vi] = *var_pf_q[vi]; + monitor_after_init_code = *var_pf_monitor; + + NSEEL_code_free(pf_codehandle_init); + pf_codehandle_init = NULL; + } + } + + // 2. compile preset per-frame code + StripLinefeedCharsAndComments(m_szPerFrameExpr, buf); + if (buf[0]) + { + if ( ! (m_pf_codehandle = NSEEL_code_compile(m_pf_eel, buf))) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_WARNING_PRESET_X_ERROR_IN_PER_FRAME_CODE), m_szDesc); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + } + } + + // 3. compile preset per-pixel code + StripLinefeedCharsAndComments(m_szPerPixelExpr, buf); + if (buf[0]) + { + if ( ! (m_pp_codehandle = NSEEL_code_compile(m_pv_eel, buf))) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_WARNING_PRESET_X_ERROR_IN_PER_VERTEX_CODE), m_szDesc); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + } + } + + //resetVars(NULL); + } + + if (flags & RECOMPILE_WAVE_CODE) + { + for (int i=0; i<MAX_CUSTOM_WAVES; i++) + { + // 1. compile AND EXECUTE custom waveform init code + StripLinefeedCharsAndComments(m_wave[i].m_szInit, buf); + if (buf[0] && bReInit) + { + #ifndef _NO_EXPR_ + { + NSEEL_CODEHANDLE codehandle_temp; + if ( ! (codehandle_temp = NSEEL_code_compile(m_wave[i].m_pf_eel, buf))) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_INIT_CODE), m_szDesc, i); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + + int vi = 0; + for (vi=0; vi<NUM_Q_VAR; vi++) + *m_wave[i].var_pf_q[vi] = q_values_after_init_code[vi]; + for (vi=0; vi<NUM_T_VAR; vi++) + m_wave[i].t_values_after_init_code[vi] = 0; + } + else + { + // now execute the code, save the values of t1..t8, and clean up the code! + + g_plugin.LoadCustomWavePerFrameEvallibVars(g_plugin.m_pState, i); + // note: q values at this point will actually be same as + // q_values_after_init_code[], since no per-frame code + // has actually been executed yet! + + NSEEL_code_execute(codehandle_temp); + + for (int vi=0; vi<NUM_T_VAR; vi++) + m_wave[i].t_values_after_init_code[vi] = *m_wave[i].var_pf_t[vi]; + + NSEEL_code_free(codehandle_temp); + codehandle_temp = NULL; + } + } + #endif + } + + // 2. compile custom waveform per-frame code + StripLinefeedCharsAndComments(m_wave[i].m_szPerFrame, buf); + if (buf[0]) + { + #ifndef _NO_EXPR_ + if ( ! (m_wave[i].m_pf_codehandle = NSEEL_code_compile(m_wave[i].m_pf_eel, buf))) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_PER_FRAME_CODE), m_szDesc, i); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + } + #endif + } + + // 3. compile custom waveform per-point code + StripLinefeedCharsAndComments(m_wave[i].m_szPerPoint, buf); + if (buf[0]) + { + if ( ! (m_wave[i].m_pp_codehandle = NSEEL_code_compile(m_wave[i].m_pp_eel, buf))) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_WARNING_PRESET_X_ERROR_IN_WAVE_X_PER_POINT_CODE), m_szDesc, i); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + } + } + } + } + + if (flags & RECOMPILE_SHAPE_CODE) + { + for (int i=0; i<MAX_CUSTOM_SHAPES; i++) + { + // 1. compile AND EXECUTE custom shape init code + StripLinefeedCharsAndComments(m_shape[i].m_szInit, buf); + if (buf[0] && bReInit) + { + #ifndef _NO_EXPR_ + { + NSEEL_CODEHANDLE codehandle_temp; + if ( ! (codehandle_temp = NSEEL_code_compile(m_shape[i].m_pf_eel, buf))) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_WARNING_PRESET_X_ERROR_IN_SHAPE_X_INIT_CODE), m_szDesc, i); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + + int vi = 0; + for (vi=0; vi<NUM_Q_VAR; vi++) + *m_shape[i].var_pf_q[vi] = q_values_after_init_code[vi]; + for (vi=0; vi<NUM_T_VAR; vi++) + m_shape[i].t_values_after_init_code[vi] = 0; + } + else + { + // now execute the code, save the values of q1..q8, and clean up the code! + + g_plugin.LoadCustomShapePerFrameEvallibVars(g_plugin.m_pState, i, 0); + // note: q values at this point will actually be same as + // q_values_after_init_code[], since no per-frame code + // has actually been executed yet! + + NSEEL_code_execute(codehandle_temp); + + for (int vi=0; vi<NUM_T_VAR; vi++) + m_shape[i].t_values_after_init_code[vi] = *m_shape[i].var_pf_t[vi]; + + NSEEL_code_free(codehandle_temp); + codehandle_temp = NULL; + } + } + #endif + } + + // 2. compile custom shape per-frame code + StripLinefeedCharsAndComments(m_shape[i].m_szPerFrame, buf); + if (buf[0]) + { + #ifndef _NO_EXPR_ + if ( ! (m_shape[i].m_pf_codehandle = NSEEL_code_compile(m_shape[i].m_pf_eel, buf))) + { + wchar_t buf[1024]; + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_WARNING_PRESET_X_ERROR_IN_SHAPE_X_PER_FRAME_CODE), m_szDesc, i); + g_plugin.AddError(buf, 6.0f, ERR_PRESET, true); + } + #endif + } + + /* + // 3. compile custom shape per-point code + StripLinefeedCharsAndComments(m_shape[i].m_szPerPoint, buf); + if (buf[0]) + { + resetVars(m_shape[i].m_pp_vars); + #ifndef _NO_EXPR_ + if ( ! (m_shape[i].m_pp_codehandle = compileCode(buf))) + { + sprintf(g_plugin.m_szUserMessage, "warning: preset \"%s\": error in shape %d per-point code", m_szDesc, i); + g_plugin.m_fShowUserMessageUntilThisTime = g_plugin.GetTime() + 6.0f; + g_plugin.m_bUserMessageIsError = true; + } + #endif + resetVars(NULL); + } + */ + } + } + } + #endif +} + +void CState::RandomizePresetVars() +{ + m_rand_preset = D3DXVECTOR4(FRAND, FRAND, FRAND, FRAND); + + int k = 0; + do + { + for (int i=0; i<4; i++) + { + float xlate_mult = 1;//(j==0) ? 1 : 0; + float rot_mult = 0.9f*powf(k/8.0f, 3.2f); + m_xlate[k].x = (FRAND*2-1)*xlate_mult; + m_xlate[k].y = (FRAND*2-1)*xlate_mult; + m_xlate[k].z = (FRAND*2-1)*xlate_mult; + m_rot_base[k].x = FRAND*6.28f; + m_rot_base[k].y = FRAND*6.28f; + m_rot_base[k].z = FRAND*6.28f; + m_rot_speed[k].x = (FRAND*2-1)*rot_mult; + m_rot_speed[k].y = (FRAND*2-1)*rot_mult; + m_rot_speed[k].z = (FRAND*2-1)*rot_mult; + k++; + } + } + while (k < sizeof(m_xlate)/sizeof(m_xlate[0])); +} + +CBlendableFloat::CBlendableFloat() +{ + m_bBlending = false; +} + +CBlendableFloat::~CBlendableFloat() +{ +} + +//-------------------------------------------------------------------------------- + +float CBlendableFloat::eval(float fTime) +{ + if (fTime < 0) + { + return val; + } + + if (m_bBlending && (fTime > 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/Src/Plugins/Visualization/vis_milk2/state.h b/Src/Plugins/Visualization/vis_milk2/state.h new file mode 100644 index 00000000..968dd316 --- /dev/null +++ b/Src/Plugins/Visualization/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 <memory.h> +#include <stdlib.h> +#include <stdio.h> +#include "gstring.h" +#include "texmgr.h" + +#include <d3dx9math.h> // 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"<no description>" // 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/Src/Plugins/Visualization/vis_milk2/support.cpp b/Src/Plugins/Visualization/vis_milk2/support.cpp new file mode 100644 index 00000000..76696dae --- /dev/null +++ b/Src/Plugins/Visualization/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/Src/Plugins/Visualization/vis_milk2/support.h b/Src/Plugins/Visualization/vis_milk2/support.h new file mode 100644 index 00000000..e0516142 --- /dev/null +++ b/Src/Plugins/Visualization/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 <d3dx9.h> + +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/Src/Plugins/Visualization/vis_milk2/temp.ico b/Src/Plugins/Visualization/vis_milk2/temp.ico Binary files differnew file mode 100644 index 00000000..a48a54f3 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/temp.ico diff --git a/Src/Plugins/Visualization/vis_milk2/texmgr.cpp b/Src/Plugins/Visualization/vis_milk2/texmgr.cpp new file mode 100644 index 00000000..9face119 --- /dev/null +++ b/Src/Plugins/Visualization/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; i<NUM_TEX; i++) + { + KillTex(i); + /* + if (m_tex[i].pSurface) + { + m_tex[i].pSurface->Release(); + 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; i<NUM_TEX; i++) + { + m_tex[i].pSurface = NULL; + m_tex[i].szFileName[0] = 0; + m_tex[i].m_codehandle = NULL; + m_tex[i].m_szExpr[0] = 0; + m_tex[i].tex_eel_ctx = NSEEL_VM_alloc(); + } +} + +/* +bool texmgr::TryCreateDDrawSurface(int iSlot, int w, int h) +{ + int loop = 1; + int done = 0; + int scaling = false; + + do + { + //TEMP!!! + //w = 2048; + //h = 2048; + switch(loop) + { + case 0: + // first, try requesting surface w/original dimensions of image + break; + case 1: + // then, try next-highest-power-of-two for w,h + w = (int)powf(2.0f, ceilf(logf((float)w)/logf(2.0f))); + h = (int)powf(2.0f, ceilf(logf((float)h)/logf(2.0f))); + break; + case 2: + // then, try making it square + if (w < h) w = h; + if (h < w) h = w; + break; + default: + if (!scaling) + { + if (w<256 || h<256) + { + w *= 2; + h *= 2; + } + else + { + scaling = true; + } + } + else + { + if (w>16 && 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; x<NUM_TEX; x++) + if (m_tex[x].pSurface && _wcsicmp(m_tex[x].szFileName, szFilename)==0) + { + memcpy(&m_tex[iSlot], &m_tex[x], sizeof(td_tex)); + m_tex[iSlot].m_szExpr[0] = 0; + m_tex[iSlot].m_codehandle = 0; + + bTextureInstanced = true; + break; + } + } + + if (!bTextureInstanced) + { + // Free old resources: + /* + if (m_tex[iSlot].pSurface) + { + m_tex[iSlot].pSurface->Release(); + 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<<y)) == 0) + zeroBits[x]++; + else + break; + } + mask[x] >>= zeroBits[x]; + for (y=0; y<32; y++) + { + if ((mask[x] & (1<<y)) != 0) + chopBits[x]--; + } + } + } + + unsigned int ck_r1 = (ck_lo >> 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<w_img*3; x++) + downsample_buf[x] += ((int)buf[x] * portion) >> 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<w_img; x++) + { + cols += 1.0f; + int portion = (int)(min(256, max(0, (input_cols_per_output_col - cols)*256))); + 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; + + 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<new_w_img; x++) + { + unsigned int cr = (unsigned int)(buf2[x*3 ]*scale_factor); + unsigned int cg = (unsigned int)(buf2[x*3+1]*scale_factor); + unsigned int cb = (unsigned int)(buf2[x*3+2]*scale_factor); + unsigned int color = (((cr >> 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<new_w_img; x++) + { + unsigned int cr = (unsigned int)(buf2[x*3 ]*scale_factor); + unsigned int cg = (unsigned int)(buf2[x*3+1]*scale_factor); + unsigned int cb = (unsigned int)(buf2[x*3+2]*scale_factor); + unsigned int color = (cr << zeroBits[0]) | (cg << zeroBits[1]) | (cb << 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; + dest32[tex_offset++] = color; + } + } + + out_y++; + + } + + // start next line: + lines -= input_lines_per_output_line; + portion = 256 - portion; + for (x=0; x<w_img*3; x++) + downsample_buf[x] = ((int)buf[x] * portion) >> 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<w_img; x++) + { + unsigned int cr = buf[x*3 ]; + unsigned int cg = buf[x*3+1]; + unsigned int cb = buf[x*3+2]; + unsigned int color = (((cr >> 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<w_img; x++) + { + unsigned int cr = buf[x*3 ]; + unsigned int cg = buf[x*3+1]; + unsigned int cb = buf[x*3+2]; + unsigned int color = (cr << zeroBits[0]) | (cg << zeroBits[1]) | (cb << 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; + 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; x<NUM_TEX; x++) + if (m_tex[x].pSurface == m_tex[iSlot].pSurface) + refcount++; + + if (refcount==1) + m_tex[iSlot].pSurface->Release(); + 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; i<len; i++) + { + if (bComment) + { + if (src[i] == LINEFEED_CONTROL_CHAR) + bComment = false; + } + else + { + if ((src[i] =='\\' && src[i+1] =='\\') || (src[i] =='/' && src[i+1] =='/')) + bComment = true; + else if (src[i] != LINEFEED_CONTROL_CHAR) + dest[i2++] = src[i]; + } + } + dest[i2] = 0; +} + +bool texmgr::RunInitCode(int iSlot, char *szInitCode) +{ + // warning: destroys contents of m_tex[iSlot].m_szExpr, + // so be sure to call RunInitCode before writing or + // compiling that string! + + FreeCode(iSlot); + FreeVars(iSlot); + RegisterBuiltInVariables(iSlot); + + strcpy(m_tex[iSlot].m_szExpr, szInitCode); + bool ret = RecompileExpressions(iSlot); + + // set default values of output variables: + // (by not setting these every frame, we allow the values to persist from frame-to-frame.) + *(m_tex[iSlot].var_x) = 0.5; + *(m_tex[iSlot].var_y) = 0.5; + *(m_tex[iSlot].var_sx) = 1.0; + *(m_tex[iSlot].var_sy) = 1.0; + *(m_tex[iSlot].var_repeatx) = 1.0; + *(m_tex[iSlot].var_repeaty) = 1.0; + *(m_tex[iSlot].var_rot) = 0.0; + *(m_tex[iSlot].var_flipx) = 0.0; + *(m_tex[iSlot].var_flipy) = 0.0; + *(m_tex[iSlot].var_r) = 1.0; + *(m_tex[iSlot].var_g) = 1.0; + *(m_tex[iSlot].var_b) = 1.0; + *(m_tex[iSlot].var_a) = 1.0; + *(m_tex[iSlot].var_blendmode)= 0.0; + *(m_tex[iSlot].var_done) = 0.0; + *(m_tex[iSlot].var_burn) = 1.0; + + #ifndef _NO_EXPR_ + if (m_tex[iSlot].m_codehandle) + NSEEL_code_execute(m_tex[iSlot].m_codehandle); + #endif + + return ret; +} + +bool texmgr::RecompileExpressions(int iSlot) +{ + char *expr = m_tex[iSlot].m_szExpr; + + // QUICK FIX: if the string ONLY has spaces and linefeeds, erase it, + // because for some strange reason this would cause an error in compileCode(). + { + char *p = expr; + while (*p==' ' || *p==LINEFEED_CONTROL_CHAR) p++; + if (*p == 0) expr[0] = 0; + } + + // replace linefeed control characters with spaces, so they don't mess up the code compiler, + // and strip out any comments ('//') before sending to CompileCode(). + char buf[sizeof(m_tex[iSlot].m_szExpr)]; + StripLinefeedCharsAndComments(expr, buf); + + if (buf[0]) + { + #ifndef _NO_EXPR_ + //resetVars(m_tex[iSlot].m_vars); + //g_dumpmsg("texmgr: compiling string: "); + //g_dumpmsg(buf); + if ( ! (m_tex[iSlot].m_codehandle = NSEEL_code_compile(m_tex[iSlot].tex_eel_ctx, buf))) + { + //g_dumpmsg(" -error!"); + //MessageBox( NULL, "error in per-frame code", "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST ); + //sprintf(pg->m_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/Src/Plugins/Visualization/vis_milk2/texmgr.h b/Src/Plugins/Visualization/vis_milk2/texmgr.h new file mode 100644 index 00000000..78db5a74 --- /dev/null +++ b/Src/Plugins/Visualization/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 <d3d9.h> +#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/Src/Plugins/Visualization/vis_milk2/text1.bin b/Src/Plugins/Visualization/vis_milk2/text1.bin Binary files differnew file mode 100644 index 00000000..86a25375 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/text1.bin diff --git a/Src/Plugins/Visualization/vis_milk2/textmgr.cpp b/Src/Plugins/Visualization/vis_milk2/textmgr.cpp new file mode 100644 index 00000000..12fe540b --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/textmgr.cpp @@ -0,0 +1,700 @@ +/* + 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; i<m_nMsg[m_b]; i++) + { + m_msg[m_b][i].deleted = m_msg[m_b][i].added = 0; + m_msg[m_b][i].prev_dark_box_ptr = last_dark_box; + last_dark_box = (m_msg[m_b][i].pfont) ? last_dark_box : (void*)&m_msg[m_b][i]; + } + last_dark_box = NULL; + int j = 0; + for (j = 0; j<m_nMsg[1-m_b]; j++) + { + m_msg[1-m_b][j].deleted = m_msg[1-m_b][j].added = 0; + m_msg[1-m_b][j].prev_dark_box_ptr = last_dark_box; + last_dark_box = (m_msg[1-m_b][j].pfont) ? last_dark_box : (void*)&m_msg[1-m_b][j]; + } + + int bRedrawText = 0; + if (!bRTT || (m_nMsg[m_b]>0 && 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]; i2++) + if (MATCH(i2,j)) + { + for (int i3=i; i3<i2; i3++) + m_msg[m_b][i3].added = 1; + i = i2; + bRedrawText = 1; + continue_now = 1; + break; + } + if (continue_now) + continue; + + // scan to see if something was deleted: + for (int j2=j+1; j2<m_nMsg[1-m_b]; j2++) + if (MATCH(i,j2)) + { + for (int j3=j; j3<j2; j3++) + m_msg[1-m_b][j3].deleted = 1; + j = j2; + bRedrawText = 1; + continue_now = 1; + break; + } + if (continue_now) + continue; + + // scan to see if just a small group of 1-4 items were changed + // [and are followed by two identical items again] + int break_now = 0; + for (int chgd=1; chgd<=4; chgd++) + { + if (i>=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<m_nMsg[m_b]-chgd && j<m_nMsg[1-m_b]-chgd && MATCH(i+chgd, j+chgd)) + { + for (int k=0; k<chgd; k++) + { + m_msg[ m_b][i+k].added = 1; + m_msg[1-m_b][j+k].deleted = 1; + } + i += chgd; + j += chgd; + + bRedrawText = 1; + continue_now = 1; + break; + } + } + if (break_now) + break; + if (continue_now) + continue; + + // otherwise, nontrivial case -> 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)); + int i = 0; + for (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) + int j = 0; + for (j=0; j<m_nMsg[1-m_b]; j++) + { + // erase text from PREV frame if it was deleted. + if (m_msg[1-m_b][j].deleted) + { + float x0 = -1.0f + 2.0f*m_msg[1-m_b][j].rect.left/(float)desc_text_surface.Width; + float x1 = -1.0f + 2.0f*m_msg[1-m_b][j].rect.right/(float)desc_text_surface.Width; + float y0 = -1.0f + 2.0f*m_msg[1-m_b][j].rect.top/(float)desc_text_surface.Height; + float y1 = -1.0f + 2.0f*m_msg[1-m_b][j].rect.bottom/(float)desc_text_surface.Height; + int i = 0; + for (i=0; i<4; i++) + { + v3[i].x = (i%2) ? x0 : x1; + v3[i].y = (i/2) ? y0 : y1; + v3[i].z = 0; + v3[i].Diffuse = m_msg[m_b][j].bgColor;//0xFF000000;//0xFF300000; + } + m_lpDevice->DrawPrimitiveUP(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_rects_ready; i++) + { + if (IntersectRect(&t, &r2, &dirty_rect[i])) + { + // expand the dirty rect to include r1 + UnionRect(&t, &r1, &dirty_rect[i]); + dirty_rect[i] = t; + done = 1; + break; + } + } + if (done==1) continue; + + // if it's in a new spot, and there are still unused dirty rects, use those + if (dirty_rects_ready < NUM_DIRTY_RECTS) + { + dirty_rect[dirty_rects_ready] = r1; + dirty_rects_ready++; + continue; + } + + // otherwise, find the closest dirty rect... + float nearest_dist; + int nearest_id; + for (i=0; i<NUM_DIRTY_RECTS; i++) + { + int dx=0, dy=0; + + if (r1.left > 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; j<m_nMsg[m_b]; j++) + { + RECT t; + // note: none of these could be 'deleted' status yet. + if (!m_msg[m_b][j].added) + { + // check vs. dirty rects so far; if intersects any, erase + redraw this one. + for (int i=0; i<dirty_rects_ready; i++) + if (m_msg[m_b][j].pfont && // exclude dark boxes... //fixme? + IntersectRect(&t, &dirty_rect[i], &m_msg[m_b][j].rect)) + { + float x0 = -1.0f + 2.0f*m_msg[m_b][j].rect.left/(float)desc_text_surface.Width; + float x1 = -1.0f + 2.0f*m_msg[m_b][j].rect.right/(float)desc_text_surface.Width; + float y0 = -1.0f + 2.0f*m_msg[m_b][j].rect.top/(float)desc_text_surface.Height; + float y1 = -1.0f + 2.0f*m_msg[m_b][j].rect.bottom/(float)desc_text_surface.Height; + for (int i=0; i<4; i++) + { + v3[i].x = (i%2) ? x0 : x1; + v3[i].y = (i/2) ? y0 : y1; + v3[i].z = 0; + v3[i].Diffuse = m_msg[m_b][j].bgColor;//0xFF000000;//0xFF000030; + } + m_lpDevice->DrawPrimitiveUP(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; i<m_nMsg[m_b]; i++) + if (bRedrawText==2 || m_msg[m_b][i].added==1) + if (m_msg[m_b][i].pfont) // dark boxes have pfont==NULL + // warning: in DX9, the DT_WORD_ELLIPSIS and DT_NOPREFIX flags cause no text to render!! + m_msg[m_b][i].pfont->DrawTextW(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/Src/Plugins/Visualization/vis_milk2/textmgr.h b/Src/Plugins/Visualization/vis_milk2/textmgr.h new file mode 100644 index 00000000..9a62461c --- /dev/null +++ b/Src/Plugins/Visualization/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 <d3d9.h> +#include <d3dx9.h> +#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/Src/Plugins/Visualization/vis_milk2/utility.cpp b/Src/Plugins/Visualization/vis_milk2/utility.cpp new file mode 100644 index 00000000..a59f2e02 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/utility.cpp @@ -0,0 +1,1259 @@ +/* + 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__vis_milk2.h" +#include "utility.h" +#include <math.h> +#include <locale.h> +#include <windows.h> +#ifdef _DEBUG + #define D3D_DEBUG_INFO // declare this before including d3d9.h +#endif +#include <d3d9.h> +#include "../Winamp/wa_ipc.h" +#include "resource.h" +#include <shellapi.h> + +intptr_t myOpenURL(HWND hwnd, wchar_t *loc) +{ + if (loc) + { + bool override=false; + WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast<intptr_t>(loc), reinterpret_cast<intptr_t>(&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<its; i++) + { + if (bneg) + x = InvCosineInterp(x); + else + x = CosineInterp(x); + } + float x2 = (bneg) ? InvCosineInterp(x) : CosineInterp(x); + float dx = pow - its; + return ((1-dx)*x + (dx)*x2); +} + +float AdjustRateToFPS(float per_frame_decay_rate_at_fps1, float fps1, float actual_fps) +{ + // returns the equivalent per-frame decay rate at actual_fps + + // basically, do all your testing at fps1 and get a good decay rate; + // then, in the real application, adjust that rate by the actual fps each time you use it. + + float per_second_decay_rate_at_fps1 = powf(per_frame_decay_rate_at_fps1, fps1); + float per_frame_decay_rate_at_fps2 = powf(per_second_decay_rate_at_fps1, 1.0f/actual_fps); + + return per_frame_decay_rate_at_fps2; +} + +float GetPrivateProfileFloatW(wchar_t *szSectionName, wchar_t *szKeyName, float fDefault, wchar_t *szIniFile) +{ + wchar_t string[64]; + wchar_t szDefault[64]; + float ret = fDefault; + + _swprintf_l(szDefault, L"%f", g_use_C_locale, fDefault); + + if (GetPrivateProfileStringW(szSectionName, szKeyName, szDefault, string, 64, szIniFile) > 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<spaces_to_append; i++) + buf[n+i] = ' '; + buf[desired_len] = 0; + } + + char buf2[256]; + if (matched) + sprintf(buf2, "%shwnd=%08x, msg=%s, w=%08x, l=%08x\n", szStartText, hwnd, buf, wParam, lParam); + else + sprintf(buf2, "%shwnd=%08x, msg=unknown/0x%08x, w=%08x, l=%08x\n", szStartText, hwnd, msg, wParam, lParam); + OutputDebugString(buf2); + #endif + } +#endif + +void DownloadDirectX(HWND hwnd) +{ + wchar_t szUrl[] = L"http://www.microsoft.com/download/details.aspx?id=35"; + intptr_t ret = myOpenURL(NULL, szUrl); + if (ret <= 32) + { + wchar_t buf[1024]; + switch(ret) + { + case SE_ERR_FNF: + case SE_ERR_PNF: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_URL_COULD_NOT_OPEN), szUrl); + break; + case SE_ERR_ACCESSDENIED: + case SE_ERR_SHARE: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_WAS_DENIED), szUrl); + break; + case SE_ERR_NOASSOC: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_FAILED_DUE_TO_NO_ASSOC), szUrl); + break; + default: + swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ACCESS_TO_URL_FAILED_CODE_X), szUrl, ret); + break; + } + MessageBoxW(hwnd, buf, WASABI_API_LNGSTRINGW(IDS_ERROR_OPENING_URL), + MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL); + } +} + +void MissingDirectX(HWND hwnd) +{ + // DIRECTX MISSING OR CORRUPT -> PROMPT TO GO TO WEB. + wchar_t title[128]; + int ret = MessageBoxW(hwnd, + #ifndef D3D_SDK_VERSION + --- error; you need to #include <d3d9.h> --- + #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() +{ +#ifdef _WIN64 + return true; // All x64 processors support SSE +#else + 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; +#endif +} + +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, GWLP_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<count; i++) + { + DWORD value_i = SendMessage( ctrl, CB_GETITEMDATA, i, 0); + if (value_i == value) + { + SendMessage( ctrl, CB_SETCURSEL, i, 0); + return i; + } + } + return -1; +} + +bool ReadCBValue(HWND hwnd, DWORD ctrl_id, int* pRetValue) +{ + if (!pRetValue) + return false; + HWND ctrl = GetDlgItem( hwnd, ctrl_id ); + int t = SendMessage( ctrl, CB_GETCURSEL, 0, 0); + if (t == CB_ERR) + return false; + *pRetValue = (int)SendMessage( ctrl, CB_GETITEMDATA, t, 0); + return true; +} + +D3DXCREATEFONTW pCreateFontW=0; +D3DXMATRIXMULTIPLY pMatrixMultiply=0; +D3DXMATRIXTRANSLATION pMatrixTranslation=0; +D3DXMATRIXSCALING pMatrixScaling=0; +D3DXMATRIXROTATION pMatrixRotationX=0, pMatrixRotationY=0, pMatrixRotationZ=0; +D3DXCREATETEXTUREFROMFILEEXW pCreateTextureFromFileExW=0; +D3DXMATRIXORTHOLH pMatrixOrthoLH = 0; +D3DXCOMPILESHADER pCompileShader=0; +D3DXMATRIXLOOKATLH pMatrixLookAtLH=0; +D3DXCREATETEXTURE pCreateTexture=0; +//---------------------------------------------------------------------- +HMODULE FindD3DX9(HWND winamp) +{ + HMODULE d3dx9 = (HMODULE)SendMessage(winamp,WM_WA_IPC, 0, IPC_GET_D3DX9); + if (!d3dx9 || d3dx9 == (HMODULE)1) + { + + // TODO: benski> 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/Src/Plugins/Visualization/vis_milk2/utility.h b/Src/Plugins/Visualization/vis_milk2/utility.h new file mode 100644 index 00000000..13d31e4f --- /dev/null +++ b/Src/Plugins/Visualization/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 <windows.h> +#include <crtdefs.h> +#include <d3d9.h> +#include <d3dx9.h> + +#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 <shlobj.h> +#include <list> + +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/Src/Plugins/Visualization/vis_milk2/version.rc2 b/Src/Plugins/Visualization/vis_milk2/version.rc2 new file mode 100644 index 00000000..34b06514 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,25,4,0 + PRODUCTVERSION WINAMP_PRODUCTVER + 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", "Winamp SA" + VALUE "FileDescription", "Winamp Visualization Plug-in" + VALUE "FileVersion", "2,25,4,0" + VALUE "InternalName", "Nullsoft Milkdrop v2" + VALUE "LegalCopyright", "Copyright © 2001-2023 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "vis_milk2.dll" + VALUE "ProductName", "Winamp" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Src/Plugins/Visualization/vis_milk2/vis.cpp b/Src/Plugins/Visualization/vis_milk2/vis.cpp new file mode 100644 index 00000000..afc80edd --- /dev/null +++ b/Src/Plugins/Visualization/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__vis_milk2.h" +#include <windows.h> +#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<api_language*>(sf->getInterface()); + + sf = WASABI_API_SVC->service_getServiceByGuid(applicationApiServiceGuid); + if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface()); + + sf = WASABI_API_SVC->service_getServiceByGuid(syscbApiServiceGuid); + if (sf) WASABI_API_SYSCB = reinterpret_cast<api_syscb*>(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/Src/Plugins/Visualization/vis_milk2/vis.h b/Src/Plugins/Visualization/vis_milk2/vis.h new file mode 100644 index 00000000..cee91b3c --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/vis.h @@ -0,0 +1 @@ +#include "../Winamp/vis.h"
\ No newline at end of file diff --git a/Src/Plugins/Visualization/vis_milk2/vms_desktop.lib b/Src/Plugins/Visualization/vis_milk2/vms_desktop.lib Binary files differnew file mode 100644 index 00000000..40091729 --- /dev/null +++ b/Src/Plugins/Visualization/vis_milk2/vms_desktop.lib |