PageRenderTime 143ms CodeModel.GetById 23ms app.highlight 104ms RepoModel.GetById 1ms app.codeStats 1ms

/xbmc/visualizations/Milkdrop/vis_milkdrop/milkdropfs.cpp

http://github.com/xbmc/xbmc
C++ | 3791 lines | 2280 code | 486 blank | 1025 comment | 356 complexity | 787dd83e37422f1a7c78d74f419bf83e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2  LICENSE
   3  -------
   4Copyright 2005 Nullsoft, Inc.
   5All rights reserved.
   6
   7Redistribution and use in source and binary forms, with or without modification, 
   8are permitted provided that the following conditions are met:
   9
  10  * Redistributions of source code must retain the above copyright notice,
  11    this list of conditions and the following disclaimer. 
  12
  13  * Redistributions in binary form must reproduce the above copyright notice,
  14    this list of conditions and the following disclaimer in the documentation
  15    and/or other materials provided with the distribution. 
  16
  17  * Neither the name of Nullsoft nor the names of its contributors may be used to 
  18    endorse or promote products derived from this software without specific prior written permission. 
  19 
  20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
  21IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  22FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
  23CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  26IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
  27OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28
  29*/
  30#include "plugin.h"
  31//#include "resource.h"
  32#include "support.h"
  33#include "evallib\eval.h"		// for math. expr. eval - thanks Francis! (in SourceOffSite, it's the 'vis_avs\evallib' project.)
  34#include "evallib\compiler.h"
  35#include "utility.h"
  36
  37#include <stdlib.h>
  38#include <stdio.h>
  39//#include <ddraw.h>
  40//#include <d3dcaps.h>
  41#include <assert.h>
  42#include <math.h>
  43//#include <shellapi.h>
  44
  45
  46
  47#define D3DCOLOR_RGBA_01(r,g,b,a) D3DCOLOR_RGBA(((int)(r*255)),((int)(g*255)),((int)(b*255)),((int)(a*255)))
  48#define FRAND ((rand() % 7381)/7380.0f)
  49//#define D3D_OVERLOADS
  50
  51#define VERT_CLIP 0.75f		// warning: top/bottom can get clipped if you go < 0.65!
  52
  53//extern CPlugin* g_plugin;		// declared in main.cpp
  54//extern bool g_bDebugOutput;		// declared in support.cpp
  55
  56int g_title_font_sizes[] =  
  57{ 
  58    // NOTE: DO NOT EXCEED 64 FONTS HERE.
  59	6,  8,  10, 12, 14, 16,      
  60	20, 26, 32, 38, 44, 50, 56,
  61	64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 
  62	160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 
  63	480, 512	/**/
  64};	
  65
  66//#define COMPILE_MULTIMON_STUBS 1
  67//#include <multimon.h>
  68
  69// This function evaluates whether the floating-point
  70// control Word is set to single precision/round to nearest/
  71// exceptions disabled. If not, the
  72// function changes the control Word to set them and returns
  73// TRUE, putting the old control Word value in the passback
  74// location pointed to by pwOldCW.
  75BOOL MungeFPCW( WORD *pwOldCW )
  76{
  77    BOOL ret = FALSE;
  78    WORD wTemp, wSave;
  79 
  80    __asm fstcw wSave
  81    if (wSave & 0x300 ||            // Not single mode
  82        0x3f != (wSave & 0x3f) ||   // Exceptions enabled
  83        wSave & 0xC00)              // Not round to nearest mode
  84    {
  85        __asm
  86        {
  87            mov ax, wSave
  88            and ax, not 300h    ;; single mode
  89            or  ax, 3fh         ;; disable all exceptions
  90            and ax, not 0xC00   ;; round to nearest mode
  91            mov wTemp, ax
  92            fldcw   wTemp
  93        }
  94        ret = TRUE;
  95    }
  96    if (pwOldCW) *pwOldCW = wSave;
  97    return ret;
  98}
  99 
 100
 101void RestoreFPCW(WORD wSave)
 102{
 103    __asm fldcw wSave
 104}
 105
 106int GetNumToSpawn(float fTime, float fDeltaT, float fRate, float fRegularity, int iNumSpawnedSoFar)
 107{
 108    // PARAMETERS
 109    // ------------
 110    // fTime:          sum of all fDeltaT's so far (excluding this one)
 111    // fDeltaT:        time window for this frame
 112    // fRate:          avg. rate (spawns per second) of generation
 113    // fRegularity:    regularity of generation 
 114	//					0.0: totally chaotic
 115	//					0.2: getting chaotic / very jittered
 116	//					0.4: nicely jittered
 117	//					0.6: slightly jittered
 118	//					0.8: almost perfectly regular
 119	//					1.0: perfectly regular
 120    // iNumSpawnedSoFar: the total number of spawnings so far
 121    //
 122    // RETURN VALUE
 123    // ------------
 124    // The number to spawn for this frame (add this to your net count!).
 125    //
 126	// COMMENTS
 127	// ------------
 128	// The spawn values returned will, over time, match
 129	// (within 1%) the theoretical totals expected based on the
 130	// amount of time passed and the average generation rate.
 131	//
 132	// UNRESOLVED ISSUES
 133	// -----------------
 134	// actual results of mixed gen. (0 < reg < 1) are about 1% too low
 135    // in the long run (vs. analytical expectations).  Decided not
 136	// to bother fixing it since it's only 1% (and VERY consistent).
 137    
 138    
 139    float fNumToSpawnReg;
 140    float fNumToSpawnIrreg;
 141    float fNumToSpawn;
 142    
 143    // compute # spawned based on regular generation
 144    fNumToSpawnReg = ((fTime + fDeltaT) * fRate) - iNumSpawnedSoFar;
 145    
 146    // compute # spawned based on irregular (random) generation
 147    if (fDeltaT <= 1.0f / fRate)
 148    {
 149        // case 1: avg. less than 1 spawn per frame
 150        if ((rand() % 16384)/16384.0f < fDeltaT * fRate)
 151            fNumToSpawnIrreg = 1.0f;
 152        else
 153            fNumToSpawnIrreg = 0.0f;
 154    }
 155    else
 156    {
 157        // case 2: avg. more than 1 spawn per frame
 158        fNumToSpawnIrreg = fDeltaT * fRate;
 159        fNumToSpawnIrreg *= 2.0f*(rand() % 16384)/16384.0f;
 160    }
 161    
 162    // get linear combo. of regular & irregular
 163    fNumToSpawn = fNumToSpawnReg*fRegularity + fNumToSpawnIrreg*(1.0f - fRegularity);
 164
 165	// round to nearest integer for result
 166    return (int)(fNumToSpawn + 0.49f);
 167}
 168
 169
 170/*
 171char szHelp[] = 
 172{
 173	// note: this is a string-of-null-terminated-strings; the whole thing ends with a double null termination.
 174	// each substring will be drawn on its own line, and the strings are drawn in BOTTOM-UP order..
 175	// (this is just an effort to keep the file size low)
 176	"ESC: exit\0"
 177
 178    " \0"
 179	"F9: toggle stereo 3D mode\0"
 180	"F8: change directory/drive\0"
 181	"F7: refresh milk_msg.ini\0"
 182	"F6: show preset rating\0"
 183	"F5: show fps\0"
 184	"F4: show preset name\0"
 185	"F2,F3: show song title,length\0"
 186	"F1: show help\0"
 187
 188    " \0"
 189	"N: show per-frame variable moNitor\0"
 190	"S: save preset\0"
 191	"M: (preset editing) menu\0"
 192
 193    " \0"
 194	"scroll lock: locks current preset\0"
 195	"+/-: rate current preset\0"
 196	"L: load specific preset\0"
 197	"R: toggle random(/sequential) preset order\0"
 198	"H: instant Hard cut (to next preset)\0"
 199	"spacebar: transition to next preset\0"
 200
 201    " \0"
 202	"left/right arrows: seek 5 sec. [+SHIFT=seek 30]\0"
 203	"up/down arrows: adjust volume\0"
 204	"P: playlist\0"
 205	"U: toggle shuffle\0"
 206	"z/x/c/v/b: prev/play/pause/stop/next\0"
 207
 208    " \0"
 209    "Y/K: enter custom message/sprite mode [see docs!]\0"
 210	"##: show custom message/sprite (##=00-99)\0"
 211	"T: launch song title animation\0"
 212
 213    "\0\0"
 214};
 215*/
 216
 217
 218bool CPlugin::OnResizeTextWindow()
 219{
 220	/*
 221    if (!m_hTextWnd)
 222		return false;
 223
 224	RECT rect;
 225	GetClientRect(m_hTextWnd, &rect);
 226
 227	if (rect.right - rect.left != m_nTextWndWidth ||
 228		rect.bottom - rect.top != m_nTextWndHeight)
 229	{
 230		m_nTextWndWidth = rect.right - rect.left;
 231		m_nTextWndHeight = rect.bottom - rect.top;
 232
 233		// first, resize fonts if necessary
 234		//if (!InitFont())
 235			//return false;
 236
 237		// then resize the memory bitmap used for double buffering
 238		if (m_memDC)
 239		{
 240			SelectObject(m_memDC, m_oldBM);	// delete our doublebuffer
 241			DeleteObject(m_memDC);
 242			DeleteObject(m_memBM);	
 243			m_memDC = NULL;
 244			m_memBM = NULL;
 245			m_oldBM = NULL;
 246		}
 247		
 248		HDC hdc = GetDC(m_hTextWnd);
 249		if (!hdc) return false;
 250
 251		m_memDC = CreateCompatibleDC(hdc);
 252		m_memBM = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
 253		m_oldBM = (HBITMAP)SelectObject(m_memDC,m_memBM);
 254		
 255		ReleaseDC(m_hTextWnd, hdc);
 256
 257		// save new window pos
 258		WriteRealtimeConfig();
 259	}*/
 260
 261	return true;
 262}
 263
 264
 265void CPlugin::ClearGraphicsWindow()
 266{
 267	// clear the window contents, to avoid a 1-pixel-thick border of noise that sometimes sticks around
 268    /*
 269	RECT rect;
 270	GetClientRect(GetPluginWindow(), &rect);
 271
 272	HDC hdc = GetDC(GetPluginWindow());
 273	FillRect(hdc, &rect, m_hBlackBrush);
 274	ReleaseDC(GetPluginWindow(), hdc);
 275    */
 276}
 277
 278/*
 279bool CPlugin::OnResizeGraphicsWindow()
 280{
 281    // NO LONGER NEEDED, SINCE PLUGIN SHELL CREATES A NEW DIRECTX
 282    // OBJECT WHENEVER WINDOW IS RESIZED.
 283}
 284*/
 285
 286bool CPlugin::RenderStringToTitleTexture()	// m_szSongMessage
 287{
 288#if 0
 289    if (!m_lpDDSTitle)  // this *can* be NULL, if not much video mem!
 290        return false;
 291
 292	if (m_supertext.szText[0]==0)
 293		return false;
 294
 295    LPDIRECT3DDEVICE8 lpDevice = GetDevice();
 296    if (!lpDevice)
 297        return false;
 298
 299	char szTextToDraw[512];
 300	sprintf(szTextToDraw, " %s ", m_supertext.szText);  //add a space @ end for italicized fonts; and at start, too, because it's centered!
 301	
 302    // Remember the original backbuffer and zbuffer
 303    LPDIRECT3DSURFACE8 pBackBuffer, pZBuffer;
 304    lpDevice->GetRenderTarget( &pBackBuffer );
 305//    lpDevice->GetDepthStencilSurface( &pZBuffer );
 306
 307    // set render target to m_lpDDSTitle
 308    {
 309	    lpDevice->SetTexture(0, NULL);
 310
 311        IDirect3DSurface8* pNewTarget = NULL;
 312        if (m_lpDDSTitle->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) 
 313        {
 314            SafeRelease(pBackBuffer);
 315//            SafeRelease(pZBuffer);
 316            return false;
 317        }
 318        lpDevice->SetRenderTarget(pNewTarget, NULL);
 319        pNewTarget->Release();
 320
 321	    lpDevice->SetTexture(0, NULL);
 322    }
 323
 324	// clear the texture to black
 325    {
 326        lpDevice->SetVertexShader( WFVERTEX_FORMAT );
 327        lpDevice->SetTexture(0, NULL);
 328
 329        lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
 330
 331        // set up a quad
 332        WFVERTEX verts[4];
 333        for (int i=0; i<4; i++)
 334        {
 335            verts[i].x = (i%2==0) ? -1 : 1;
 336            verts[i].y = (i/2==0) ? -1 : 1;
 337            verts[i].z = 0;
 338            verts[i].Diffuse = 0xFF000000;
 339        }
 340
 341        lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(WFVERTEX));
 342    }
 343
 344    /*// 1. clip title if too many chars
 345	if (m_supertext.bIsSongTitle)
 346	{
 347		// truncate song title if too long; don't clip custom messages, though!
 348		int clip_chars = 32;
 349        int user_title_size = GetFontHeight(SONGTITLE_FONT);
 350
 351        #define MIN_CHARS 8         // max clip_chars *for BIG FONTS*
 352        #define MAX_CHARS 64        // max clip chars *for tiny fonts*
 353        float t = (user_title_size-10)/(float)(128-10);
 354        t = min(1,max(0,t));
 355        clip_chars = (int)(MAX_CHARS - (MAX_CHARS-MIN_CHARS)*t);
 356
 357		if ((int)strlen(szTextToDraw) > clip_chars+3)
 358			lstrcpy(&szTextToDraw[clip_chars], "...");
 359	}*/
 360
 361    bool ret = true;
 362
 363	// use 2 lines; must leave room for bottom of 'g' characters and such!
 364	RECT rect;
 365	rect.left   = 0;
 366	rect.right  = m_nTitleTexSizeX;
 367	rect.top    = m_nTitleTexSizeY* 1/21;  // otherwise, top of '%' could be cut off (1/21 seems safe)
 368	rect.bottom = m_nTitleTexSizeY*17/21;  // otherwise, bottom of 'g' could be cut off (18/21 seems safe, but we want some leeway)
 369
 370    if (!m_supertext.bIsSongTitle)
 371    {
 372        // custom msg -> pick font to use that will best fill the texture
 373
 374        HFONT gdi_font = NULL;
 375        LPD3DXFONT d3dx_font = NULL;
 376
 377        int lo = 0;
 378	    int hi = sizeof(g_title_font_sizes)/sizeof(int) - 1;
 379    
 380        // limit the size of the font used:
 381
 382        //int user_title_size = GetFontHeight(SONGTITLE_FONT);
 383        //while (g_title_font_sizes[hi] > user_title_size*2 && hi>4)
 384        //    hi--;
 385
 386        RECT temp;
 387	    while (1)//(lo < hi-1)
 388	    {
 389		    int mid = (lo+hi)/2;
 390
 391		    // create new gdi font at 'mid' size:
 392            gdi_font = CreateFont(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);
 393            if (gdi_font) 
 394            {
 395                // create new d3dx font at 'mid' size:
 396                if (D3DXCreateFont(lpDevice, gdi_font, &d3dx_font) == D3D_OK)
 397                {
 398                    if (lo == hi-1)
 399                        break;      // DONE; but the 'lo'-size font is ready for use!
 400
 401                    // compute size of text if drawn w/font of THIS size:
 402		            temp = rect;
 403		            int h = d3dx_font->DrawText(szTextToDraw, -1, &temp, DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX, 0xFFFFFFFF);
 404
 405                    // adjust & prepare to reiterate:
 406		            if (temp.right >= rect.right || h > rect.bottom-rect.top)
 407			            hi = mid;
 408		            else
 409			            lo = mid;
 410
 411                    SafeRelease(d3dx_font);
 412                }
 413        
 414                DeleteObject(gdi_font); gdi_font=NULL;
 415            }
 416	    }
 417
 418        if (gdi_font && d3dx_font)
 419        {
 420	        // do actual drawing + set m_supertext.nFontSizeUsed; use 'lo' size
 421            int h = d3dx_font->DrawText(szTextToDraw, -1, &temp, DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX | DT_CENTER, 0xFFFFFFFF);
 422	        temp.left   = 0;
 423	        temp.right  = m_nTitleTexSizeX;  // now allow text to go all the way over, since we're actually drawing!
 424            temp.top    = m_nTitleTexSizeY/2 - h/2;
 425            temp.bottom = m_nTitleTexSizeY/2 + h/2;
 426	        m_supertext.nFontSizeUsed = d3dx_font->DrawText(szTextToDraw, -1, &temp, DT_SINGLELINE | DT_NOPREFIX | DT_CENTER, 0xFFFFFFFF);
 427	        
 428            ret = true;
 429        }
 430        else
 431        {
 432            ret = false;
 433        }
 434
 435        // clean up font:
 436        SafeRelease(d3dx_font);
 437        if (gdi_font) DeleteObject(gdi_font); gdi_font=NULL;
 438    }
 439    else // song title
 440    {
 441        RECT temp = rect;
 442
 443	    // do actual drawing + set m_supertext.nFontSizeUsed; use 'lo' size
 444        int h = m_d3dx_title_font_doublesize->DrawText(szTextToDraw, -1, &temp, DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX | DT_CENTER | DT_END_ELLIPSIS, 0xFFFFFFFF);
 445	    temp.left   = 0;
 446	    temp.right  = m_nTitleTexSizeX;  // now allow text to go all the way over, since we're actually drawing!
 447        temp.top    = m_nTitleTexSizeY/2 - h/2;
 448        temp.bottom = m_nTitleTexSizeY/2 + h/2;
 449	    m_supertext.nFontSizeUsed = m_d3dx_title_font_doublesize->DrawText(szTextToDraw, -1, &temp, DT_SINGLELINE | DT_NOPREFIX | DT_CENTER | DT_END_ELLIPSIS, 0xFFFFFFFF);
 450    }
 451
 452    // Change the rendertarget back to the original setup
 453    lpDevice->SetTexture(0, NULL);
 454    lpDevice->SetRenderTarget( pBackBuffer, NULL );
 455    SafeRelease(pBackBuffer);
 456    SafeRelease(pZBuffer);
 457
 458	return ret;
 459#endif
 460	return false;
 461}
 462
 463void CPlugin::LoadPerFrameEvallibVars(CState* pState)
 464{
 465    // load the 'var_pf_*' variables in this CState object with the correct values.
 466    // for vars that affect pixel motion, that means evaluating them at time==-1,
 467    //    (i.e. no blending w/blendto value); the blending of the file dx/dy 
 468    //    will be done *after* execution of the per-vertex code.
 469    // for vars that do NOT affect pixel motion, evaluate them at the current time,
 470    //    so that if they're blending, both states see the blended value.
 471
 472    // 1. vars that affect pixel motion: (eval at time==-1)
 473	*pState->var_pf_zoom		= (double)pState->m_fZoom.eval(-1);//GetTime()); 
 474	*pState->var_pf_zoomexp		= (double)pState->m_fZoomExponent.eval(-1);//GetTime());
 475	*pState->var_pf_rot			= (double)pState->m_fRot.eval(-1);//GetTime());  
 476	*pState->var_pf_warp		= (double)pState->m_fWarpAmount.eval(-1);//GetTime()); 
 477	*pState->var_pf_cx			= (double)pState->m_fRotCX.eval(-1);//GetTime());	
 478	*pState->var_pf_cy			= (double)pState->m_fRotCY.eval(-1);//GetTime()); 
 479	*pState->var_pf_dx			= (double)pState->m_fXPush.eval(-1);//GetTime());
 480	*pState->var_pf_dy			= (double)pState->m_fYPush.eval(-1);//GetTime());
 481	*pState->var_pf_sx			= (double)pState->m_fStretchX.eval(-1);//GetTime());
 482	*pState->var_pf_sy			= (double)pState->m_fStretchY.eval(-1);//GetTime());
 483	// read-only:
 484	*pState->var_pf_time		= (double)(GetTime() - m_fStartTime);
 485	*pState->var_pf_fps         = (double)GetFps();
 486	*pState->var_pf_bass		= (double)mysound.imm_rel[0];
 487	*pState->var_pf_mid			= (double)mysound.imm_rel[1];
 488	*pState->var_pf_treb		= (double)mysound.imm_rel[2];
 489	*pState->var_pf_bass_att	= (double)mysound.avg_rel[0];
 490	*pState->var_pf_mid_att		= (double)mysound.avg_rel[1];
 491	*pState->var_pf_treb_att	= (double)mysound.avg_rel[2];
 492	*pState->var_pf_frame		= (double)GetFrame();
 493	//*pState->var_pf_monitor     = 0;   -leave this as it was set in the per-frame INIT code!
 494	*pState->var_pf_q1          = pState->q_values_after_init_code[0];//0.0f;
 495	*pState->var_pf_q2          = pState->q_values_after_init_code[1];//0.0f;
 496	*pState->var_pf_q3          = pState->q_values_after_init_code[2];//0.0f;
 497	*pState->var_pf_q4          = pState->q_values_after_init_code[3];//0.0f;
 498	*pState->var_pf_q5          = pState->q_values_after_init_code[4];//0.0f;
 499	*pState->var_pf_q6          = pState->q_values_after_init_code[5];//0.0f;
 500	*pState->var_pf_q7          = pState->q_values_after_init_code[6];//0.0f;
 501	*pState->var_pf_q8          = pState->q_values_after_init_code[7];//0.0f;
 502    *pState->var_pf_monitor     = pState->monitor_after_init_code;
 503	*pState->var_pf_progress    = (GetTime() - m_fPresetStartTime) / (m_fNextPresetTime - m_fPresetStartTime);
 504
 505	// 2. vars that do NOT affect pixel motion: (eval at time==now)
 506	*pState->var_pf_decay		= (double)pState->m_fDecay.eval(GetTime());
 507	*pState->var_pf_wave_a		= (double)pState->m_fWaveAlpha.eval(GetTime());
 508	*pState->var_pf_wave_r		= (double)pState->m_fWaveR.eval(GetTime());
 509	*pState->var_pf_wave_g		= (double)pState->m_fWaveG.eval(GetTime());
 510	*pState->var_pf_wave_b		= (double)pState->m_fWaveB.eval(GetTime());
 511	*pState->var_pf_wave_x		= (double)pState->m_fWaveX.eval(GetTime());
 512	*pState->var_pf_wave_y		= (double)pState->m_fWaveY.eval(GetTime());
 513	*pState->var_pf_wave_mystery= (double)pState->m_fWaveParam.eval(GetTime());
 514	*pState->var_pf_wave_mode   = (double)pState->m_nWaveMode;	//?!?! -why won't it work if set to pState->m_nWaveMode???
 515	*pState->var_pf_ob_size		= (double)pState->m_fOuterBorderSize.eval(GetTime());
 516	*pState->var_pf_ob_r		= (double)pState->m_fOuterBorderR.eval(GetTime());
 517	*pState->var_pf_ob_g		= (double)pState->m_fOuterBorderG.eval(GetTime());
 518	*pState->var_pf_ob_b		= (double)pState->m_fOuterBorderB.eval(GetTime());
 519	*pState->var_pf_ob_a		= (double)pState->m_fOuterBorderA.eval(GetTime());
 520	*pState->var_pf_ib_size		= (double)pState->m_fInnerBorderSize.eval(GetTime());
 521	*pState->var_pf_ib_r		= (double)pState->m_fInnerBorderR.eval(GetTime());
 522	*pState->var_pf_ib_g		= (double)pState->m_fInnerBorderG.eval(GetTime());
 523	*pState->var_pf_ib_b		= (double)pState->m_fInnerBorderB.eval(GetTime());
 524	*pState->var_pf_ib_a		= (double)pState->m_fInnerBorderA.eval(GetTime());
 525	*pState->var_pf_mv_x        = (double)pState->m_fMvX.eval(GetTime());
 526	*pState->var_pf_mv_y        = (double)pState->m_fMvY.eval(GetTime());
 527	*pState->var_pf_mv_dx       = (double)pState->m_fMvDX.eval(GetTime());
 528	*pState->var_pf_mv_dy       = (double)pState->m_fMvDY.eval(GetTime());
 529	*pState->var_pf_mv_l        = (double)pState->m_fMvL.eval(GetTime());
 530	*pState->var_pf_mv_r        = (double)pState->m_fMvR.eval(GetTime());
 531	*pState->var_pf_mv_g        = (double)pState->m_fMvG.eval(GetTime());
 532	*pState->var_pf_mv_b        = (double)pState->m_fMvB.eval(GetTime());
 533	*pState->var_pf_mv_a        = (double)pState->m_fMvA.eval(GetTime());
 534	*pState->var_pf_echo_zoom   = (double)pState->m_fVideoEchoZoom.eval(GetTime());
 535	*pState->var_pf_echo_alpha  = (double)pState->m_fVideoEchoAlpha.eval(GetTime());
 536	*pState->var_pf_echo_orient = (double)pState->m_nVideoEchoOrientation;
 537    // new in v1.04:
 538    *pState->var_pf_wave_usedots  = (double)pState->m_bWaveDots;
 539    *pState->var_pf_wave_thick    = (double)pState->m_bWaveThick;
 540    *pState->var_pf_wave_additive = (double)pState->m_bAdditiveWaves;
 541    *pState->var_pf_wave_brighten = (double)pState->m_bMaximizeWaveColor;
 542    *pState->var_pf_darken_center = (double)pState->m_bDarkenCenter;
 543    *pState->var_pf_gamma         = (double)pState->m_fGammaAdj.eval(GetTime());
 544    *pState->var_pf_wrap          = (double)pState->m_bTexWrap;
 545    *pState->var_pf_invert        = (double)pState->m_bInvert;
 546    *pState->var_pf_brighten      = (double)pState->m_bBrighten;
 547    *pState->var_pf_darken        = (double)pState->m_bDarken;
 548    *pState->var_pf_solarize      = (double)pState->m_bSolarize;
 549    *pState->var_pf_meshx         = (double)m_nGridX;
 550    *pState->var_pf_meshy         = (double)m_nGridY;
 551}
 552
 553void CPlugin::RunPerFrameEquations()
 554{
 555	// run per-frame calculations
 556
 557	int num_reps = (m_pState->m_bBlending) ? 2 : 1;
 558	for (int rep=0; rep<num_reps; rep++)
 559	{
 560		CState *pState;
 561
 562		if (rep==0)
 563			pState = m_pState;
 564		else
 565			pState = m_pOldState;
 566
 567		// values that will affect the pixel motion (and will be automatically blended 
 568		//	LATER, when the results of 2 sets of these params creates 2 different U/V
 569		//  meshes that get blended together.)
 570        LoadPerFrameEvallibVars(pState);
 571
 572		// also do just a once-per-frame init for the *per-**VERTEX*** *READ-ONLY* variables
 573		// (the non-read-only ones will be reset/restored at the start of each vertex)
 574		*pState->var_pv_time		= *pState->var_pf_time;	
 575		*pState->var_pv_fps         = *pState->var_pf_fps;
 576		*pState->var_pv_frame		= *pState->var_pf_frame;
 577		*pState->var_pv_progress    = *pState->var_pf_progress;
 578		*pState->var_pv_bass		= *pState->var_pf_bass;	
 579		*pState->var_pv_mid			= *pState->var_pf_mid;		
 580		*pState->var_pv_treb		= *pState->var_pf_treb;	
 581		*pState->var_pv_bass_att	= *pState->var_pf_bass_att;
 582		*pState->var_pv_mid_att		= *pState->var_pf_mid_att;	
 583		*pState->var_pv_treb_att	= *pState->var_pf_treb_att;
 584        *pState->var_pv_meshx       = (double)m_nGridX;
 585        *pState->var_pv_meshy       = (double)m_nGridY;
 586        //*pState->var_pv_monitor     = *pState->var_pf_monitor;
 587
 588		// execute once-per-frame expressions:
 589#ifndef _NO_EXPR_
 590		if (pState->m_pf_codehandle)
 591		{
 592			resetVars(pState->m_pf_vars);
 593			if (pState->m_pf_codehandle)
 594			{
 595				executeCode(pState->m_pf_codehandle);
 596			}
 597			resetVars(NULL);
 598		}
 599#endif
 600
 601        // save some things for next frame:
 602        pState->monitor_after_init_code = *pState->var_pf_monitor;
 603
 604        // save some things for per-vertex code:
 605        *pState->var_pv_q1		    = *pState->var_pf_q1;
 606		*pState->var_pv_q2		    = *pState->var_pf_q2;
 607		*pState->var_pv_q3		    = *pState->var_pf_q3;
 608		*pState->var_pv_q4		    = *pState->var_pf_q4;
 609		*pState->var_pv_q5		    = *pState->var_pf_q5;
 610		*pState->var_pv_q6		    = *pState->var_pf_q6;
 611		*pState->var_pv_q7		    = *pState->var_pf_q7;
 612		*pState->var_pv_q8		    = *pState->var_pf_q8;
 613
 614        // (a few range checks:)
 615        *pState->var_pf_gamma     = max(0    , min(    8, *pState->var_pf_gamma    ));
 616        *pState->var_pf_echo_zoom = max(0.001, min( 1000, *pState->var_pf_echo_zoom));
 617
 618		if (m_pState->m_bRedBlueStereo || m_bAlways3D)
 619		{
 620			// override wave colors
 621			*pState->var_pf_wave_r = 0.35f*(*pState->var_pf_wave_r) + 0.65f;
 622			*pState->var_pf_wave_g = 0.35f*(*pState->var_pf_wave_g) + 0.65f;
 623			*pState->var_pf_wave_b = 0.35f*(*pState->var_pf_wave_b) + 0.65f;
 624		}
 625	}
 626
 627	if (m_pState->m_bBlending)
 628	{
 629		// For all variables that do NOT affect pixel motion, blend them NOW,
 630        // so later the user can just access m_pState->m_pf_whatever.  
 631		double mix  = (double)CosineInterp(m_pState->m_fBlendProgress);
 632		double mix2 = 1.0 - mix;
 633        *m_pState->var_pf_decay        = mix*(*m_pState->var_pf_decay       ) + mix2*(*m_pOldState->var_pf_decay       );
 634        *m_pState->var_pf_wave_a       = mix*(*m_pState->var_pf_wave_a      ) + mix2*(*m_pOldState->var_pf_wave_a      );
 635        *m_pState->var_pf_wave_r       = mix*(*m_pState->var_pf_wave_r      ) + mix2*(*m_pOldState->var_pf_wave_r      );
 636        *m_pState->var_pf_wave_g       = mix*(*m_pState->var_pf_wave_g      ) + mix2*(*m_pOldState->var_pf_wave_g      );
 637        *m_pState->var_pf_wave_b       = mix*(*m_pState->var_pf_wave_b      ) + mix2*(*m_pOldState->var_pf_wave_b      );
 638        *m_pState->var_pf_wave_x       = mix*(*m_pState->var_pf_wave_x      ) + mix2*(*m_pOldState->var_pf_wave_x      );
 639        *m_pState->var_pf_wave_y       = mix*(*m_pState->var_pf_wave_y      ) + mix2*(*m_pOldState->var_pf_wave_y      );
 640        *m_pState->var_pf_wave_mystery = mix*(*m_pState->var_pf_wave_mystery) + mix2*(*m_pOldState->var_pf_wave_mystery);
 641		// wave_mode: exempt (integer)
 642        *m_pState->var_pf_ob_size      = mix*(*m_pState->var_pf_ob_size     ) + mix2*(*m_pOldState->var_pf_ob_size     ); 
 643        *m_pState->var_pf_ob_r         = mix*(*m_pState->var_pf_ob_r        ) + mix2*(*m_pOldState->var_pf_ob_r        );
 644        *m_pState->var_pf_ob_g         = mix*(*m_pState->var_pf_ob_g        ) + mix2*(*m_pOldState->var_pf_ob_g        );
 645        *m_pState->var_pf_ob_b         = mix*(*m_pState->var_pf_ob_b        ) + mix2*(*m_pOldState->var_pf_ob_b        );
 646        *m_pState->var_pf_ob_a         = mix*(*m_pState->var_pf_ob_a        ) + mix2*(*m_pOldState->var_pf_ob_a        );
 647        *m_pState->var_pf_ib_size      = mix*(*m_pState->var_pf_ib_size     ) + mix2*(*m_pOldState->var_pf_ib_size     );
 648        *m_pState->var_pf_ib_r         = mix*(*m_pState->var_pf_ib_r        ) + mix2*(*m_pOldState->var_pf_ib_r        );
 649        *m_pState->var_pf_ib_g         = mix*(*m_pState->var_pf_ib_g        ) + mix2*(*m_pOldState->var_pf_ib_g        );
 650        *m_pState->var_pf_ib_b         = mix*(*m_pState->var_pf_ib_b        ) + mix2*(*m_pOldState->var_pf_ib_b        );
 651        *m_pState->var_pf_ib_a         = mix*(*m_pState->var_pf_ib_a        ) + mix2*(*m_pOldState->var_pf_ib_a        );
 652        *m_pState->var_pf_mv_x         = mix*(*m_pState->var_pf_mv_x        ) + mix2*(*m_pOldState->var_pf_mv_x        );
 653        *m_pState->var_pf_mv_y         = mix*(*m_pState->var_pf_mv_y        ) + mix2*(*m_pOldState->var_pf_mv_y        );
 654        *m_pState->var_pf_mv_dx        = mix*(*m_pState->var_pf_mv_dx       ) + mix2*(*m_pOldState->var_pf_mv_dx       );
 655        *m_pState->var_pf_mv_dy        = mix*(*m_pState->var_pf_mv_dy       ) + mix2*(*m_pOldState->var_pf_mv_dy       );
 656        *m_pState->var_pf_mv_l         = mix*(*m_pState->var_pf_mv_l        ) + mix2*(*m_pOldState->var_pf_mv_l        );
 657        *m_pState->var_pf_mv_r         = mix*(*m_pState->var_pf_mv_r        ) + mix2*(*m_pOldState->var_pf_mv_r        );
 658        *m_pState->var_pf_mv_g         = mix*(*m_pState->var_pf_mv_g        ) + mix2*(*m_pOldState->var_pf_mv_g        );
 659        *m_pState->var_pf_mv_b         = mix*(*m_pState->var_pf_mv_b        ) + mix2*(*m_pOldState->var_pf_mv_b        );
 660        *m_pState->var_pf_mv_a         = mix*(*m_pState->var_pf_mv_a        ) + mix2*(*m_pOldState->var_pf_mv_a        );
 661		*m_pState->var_pf_echo_zoom    = mix*(*m_pState->var_pf_echo_zoom   ) + mix2*(*m_pOldState->var_pf_echo_zoom   );
 662		*m_pState->var_pf_echo_alpha   = mix*(*m_pState->var_pf_echo_alpha  ) + mix2*(*m_pOldState->var_pf_echo_alpha  );
 663        *m_pState->var_pf_echo_orient  = (mix < 0.5f) ? *m_pOldState->var_pf_echo_orient : *m_pState->var_pf_echo_orient;
 664        // added in v1.04:
 665        *m_pState->var_pf_wave_usedots = (mix < 0.5f) ? *m_pOldState->var_pf_wave_usedots  : *m_pState->var_pf_wave_usedots ;
 666        *m_pState->var_pf_wave_thick   = (mix < 0.5f) ? *m_pOldState->var_pf_wave_thick    : *m_pState->var_pf_wave_thick   ;
 667        *m_pState->var_pf_wave_additive= (mix < 0.5f) ? *m_pOldState->var_pf_wave_additive : *m_pState->var_pf_wave_additive;
 668        *m_pState->var_pf_wave_brighten= (mix < 0.5f) ? *m_pOldState->var_pf_wave_brighten : *m_pState->var_pf_wave_brighten;
 669        *m_pState->var_pf_darken_center= (mix < 0.5f) ? *m_pOldState->var_pf_darken_center : *m_pState->var_pf_darken_center;
 670        *m_pState->var_pf_gamma        = mix*(*m_pState->var_pf_gamma       ) + mix2*(*m_pOldState->var_pf_gamma       );
 671        *m_pState->var_pf_wrap         = (mix < 0.5f) ? *m_pOldState->var_pf_wrap          : *m_pState->var_pf_wrap         ;
 672        *m_pState->var_pf_invert       = (mix < 0.5f) ? *m_pOldState->var_pf_invert        : *m_pState->var_pf_invert       ;
 673        *m_pState->var_pf_brighten     = (mix < 0.5f) ? *m_pOldState->var_pf_brighten      : *m_pState->var_pf_brighten     ;
 674        *m_pState->var_pf_darken       = (mix < 0.5f) ? *m_pOldState->var_pf_darken        : *m_pState->var_pf_darken       ;
 675        *m_pState->var_pf_solarize     = (mix < 0.5f) ? *m_pOldState->var_pf_solarize      : *m_pState->var_pf_solarize     ;
 676    }
 677}
 678
 679void CPlugin::RenderFrame(int bRedraw)
 680{
 681	int i;
 682
 683    float fDeltaT = 1.0f/GetFps();
 684
 685	// update time
 686    /*
 687    float fDeltaT = (GetFrame()==0) ? 1.0f/30.0f : GetTime() - m_prev_time;
 688	DWORD dwTime		= GetTickCount();
 689	float fDeltaT		= (dwTime - m_dwPrevTickCount)*0.001f;
 690	if (GetFrame() > 64)
 691	{
 692		fDeltaT = (fDeltaT)*0.2f + 0.8f*(1.0f/m_fps);
 693		if (fDeltaT > 2.0f/m_fps)
 694		{
 695			char buf[64];
 696			sprintf(buf, "fixing time gap of %5.3f seconds", fDeltaT);
 697			dumpmsg(buf);
 698
 699			fDeltaT = 1.0f/m_fps;
 700		}
 701	}
 702	m_dwPrevTickCount	= dwTime;
 703	GetTime()			+= fDeltaT;
 704    */
 705
 706	if (GetFrame()==0) 
 707	{
 708		m_fStartTime = GetTime();
 709		m_fPresetStartTime = GetTime();
 710	}
 711
 712	if (m_fNextPresetTime < 0)
 713	{
 714		float dt = m_fTimeBetweenPresetsRand * (rand()%1000)*0.001f;
 715		m_fNextPresetTime = GetTime() + m_fBlendTimeAuto + m_fTimeBetweenPresets + dt;
 716	}
 717
 718	/*
 719    if (m_bPresetLockedByUser || m_bPresetLockedByCode)
 720	{
 721		// if the user has the preset LOCKED, or if they're in the middle of 
 722		// saving it, then keep extending the time at which the auto-switch will occur
 723		// (by the length of this frame).
 724
 725		m_fPresetStartTime += fDeltaT;
 726		m_fNextPresetTime += fDeltaT;
 727	}*/
 728
 729	// update fps
 730	/*
 731	if (GetFrame() < 4)
 732	{
 733		m_fps = 0.0f;
 734	}
 735	else if (GetFrame() <= 64)
 736	{
 737		m_fps = GetFrame() / (float)(GetTime() - m_fTimeHistory[0]);
 738	}
 739	else
 740	{
 741		m_fps = 64.0f / (float)(GetTime() - m_fTimeHistory[m_nTimeHistoryPos]);
 742	}
 743	m_fTimeHistory[m_nTimeHistoryPos] = GetTime();
 744	m_nTimeHistoryPos = (m_nTimeHistoryPos + 1) % 64;
 745    */
 746
 747	// limit fps, if necessary
 748    /*
 749	if (m_nFpsLimit > 0 && (GetFrame() % 64) == 0 && GetFrame() > 64)
 750	{
 751		float spf_now     = 1.0f / m_fps;
 752		float spf_desired = 1.0f / (float)m_nFpsLimit;
 753
 754		float new_sleep = m_fFPSLimitSleep + (spf_desired - spf_now)*1000.0f;
 755		
 756		if (GetFrame() <= 128)
 757			m_fFPSLimitSleep = new_sleep;
 758		else
 759			m_fFPSLimitSleep = m_fFPSLimitSleep*0.8f + 0.2f*new_sleep;
 760		
 761		if (m_fFPSLimitSleep < 0) m_fFPSLimitSleep = 0;
 762		if (m_fFPSLimitSleep > 100) m_fFPSLimitSleep = 100;
 763
 764		//sprintf(m_szUserMessage, "sleep=%f", m_fFPSLimitSleep);
 765		//m_fShowUserMessageUntilThisTime = GetTime() + 3.0f;
 766	}
 767
 768	static float deficit;
 769	if (GetFrame()==0) deficit = 0;
 770	float ideal_sleep = (m_fFPSLimitSleep + deficit);
 771	int actual_sleep = (int)ideal_sleep;
 772	if (actual_sleep > 0)
 773		Sleep(actual_sleep);
 774	deficit = ideal_sleep - actual_sleep; 
 775	if (deficit < 0) deficit = 0;	// just in case
 776	if (deficit > 1) deficit = 1;	// just in case
 777    */
 778
 779	// randomly change the preset, if it's time
 780	if (m_fNextPresetTime < GetTime())
 781	{
 782		LoadRandomPreset(m_fBlendTimeAuto);
 783	}
 784/*
 785	// randomly spawn Song Title, if time
 786	if (m_fTimeBetweenRandomSongTitles > 0 && 
 787		!m_supertext.bRedrawSuperText &&
 788		GetTime() >= m_supertext.fStartTime + m_supertext.fDuration + 1.0f/GetFps())
 789	{		
 790		int n = GetNumToSpawn(GetTime(), fDeltaT, 1.0f/m_fTimeBetweenRandomSongTitles, 0.5f, m_nSongTitlesSpawned);
 791		if (n > 0)
 792		{
 793			LaunchSongTitleAnim();
 794			m_nSongTitlesSpawned += n;
 795		}
 796	}
 797
 798	// randomly spawn Custom Message, if time
 799	if (m_fTimeBetweenRandomCustomMsgs > 0 && 
 800		!m_supertext.bRedrawSuperText &&
 801		GetTime() >= m_supertext.fStartTime + m_supertext.fDuration + 1.0f/GetFps())
 802	{		
 803		int n = GetNumToSpawn(GetTime(), fDeltaT, 1.0f/m_fTimeBetweenRandomCustomMsgs, 0.5f, m_nCustMsgsSpawned);
 804		if (n > 0)
 805		{
 806			LaunchCustomMessage(-1);
 807			m_nCustMsgsSpawned += n;
 808		}
 809	}
 810*/
 811	// update m_fBlendProgress;
 812	if (m_pState->m_bBlending)
 813	{
 814		m_pState->m_fBlendProgress = (GetTime() - m_pState->m_fBlendStartTime) / m_pState->m_fBlendDuration;
 815		if (m_pState->m_fBlendProgress > 1.0f)
 816		{
 817			m_pState->m_bBlending = false;
 818		}
 819	}
 820
 821	// handle hard cuts here (just after new sound analysis)
 822	static float m_fHardCutThresh;
 823	if (GetFrame() == 0)
 824		m_fHardCutThresh = m_fHardCutLoudnessThresh*2.0f;
 825	if (GetFps() > 1.0f && !m_bHardCutsDisabled && !m_bPresetLockedByUser && !m_bPresetLockedByCode)
 826	{
 827		if (mysound.imm_rel[0] + mysound.imm_rel[1] + mysound.imm_rel[2] > m_fHardCutThresh*3.0f)
 828		{
 829			LoadRandomPreset(0.0f);
 830			m_fHardCutThresh *= 2.0f;
 831		}
 832		else
 833		{
 834			float halflife_modified = m_fHardCutHalflife*0.5f;
 835			//thresh = (thresh - 1.5f)*0.99f + 1.5f;		
 836			float k = -0.69315f / halflife_modified;
 837			float single_frame_multiplier = powf(2.7183f, k / GetFps());
 838			m_fHardCutThresh = (m_fHardCutThresh - m_fHardCutLoudnessThresh)*single_frame_multiplier + m_fHardCutLoudnessThresh;
 839		}
 840	}
 841
 842	// smooth & scale the audio data, according to m_state, for display purposes
 843	float scale = m_pState->m_fWaveScale.eval(GetTime()) / 128.0f;
 844	mysound.fWave[0][0] *= scale;
 845	mysound.fWave[1][0] *= scale;
 846	float mix2 = m_pState->m_fWaveSmoothing.eval(GetTime());
 847	float mix1 = scale*(1.0f - mix2);
 848	for (i=1; i<576; i++)
 849	{
 850		mysound.fWave[0][i] = mysound.fWave[0][i]*mix1 + mysound.fWave[0][i-1]*mix2;
 851		mysound.fWave[1][i] = mysound.fWave[1][i]*mix1 + mysound.fWave[1][i-1]*mix2;
 852	}
 853
 854	RunPerFrameEquations();
 855
 856	// restore any lost surfaces
 857	//m_lpDD->RestoreAllSurfaces();
 858
 859    LPDIRECT3DDEVICE9 lpDevice = GetDevice();
 860    if (!lpDevice)
 861        return;
 862
 863    // Remember the original backbuffer and zbuffer
 864    LPDIRECT3DSURFACE9 pBackBuffer, pZBuffer;
 865    lpDevice->GetRenderTarget(0, &pBackBuffer );
 866    lpDevice->GetDepthStencilSurface( &pZBuffer );
 867
 868	D3DSURFACE_DESC	desc; 
 869	pBackBuffer->GetDesc(&desc);
 870
 871	m_backBufferWidth = desc.Width;
 872	m_backBufferHeight = desc.Height;
 873
 874    // set up render state
 875    {
 876        DWORD texaddr = (*m_pState->var_pf_wrap) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
 877        lpDevice->SetRenderState(D3DRS_WRAP0, 0);
 878        lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, texaddr);
 879        lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, texaddr);
 880        lpDevice->SetSamplerState(0, D3DSAMP_ADDRESSW, texaddr);
 881        
 882        lpDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
 883	      lpDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
 884        lpDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
 885        lpDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
 886        lpDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
 887        lpDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
 888        lpDevice->SetRenderState( D3DRS_COLORVERTEX, TRUE );
 889        lpDevice->SetRenderState( D3DRS_FILLMODE,  D3DFILL_SOLID );
 890        lpDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
 891	    lpDevice->SetRenderState( D3DRS_AMBIENT, 0xFFFFFFFF );  //?
 892//        lpDevice->SetRenderState( D3DRS_CLIPPING, TRUE );
 893
 894        // set min/mag/mip filtering modes; use anisotropy if available.
 895        if (m_bAnisotropicFiltering && (GetCaps()->TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC))
 896	        lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
 897//        else if (GetCaps()->TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)
 898		else
 899	        lpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
 900//        else
 901//            SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_POINT);
 902
 903        if (m_bAnisotropicFiltering && (GetCaps()->TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC))
 904	        lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
 905		else
 906//        else if (GetCaps()->TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)
 907	        lpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
 908  //      else
 909//	        SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
 910
 911        lpDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR );
 912
 913        // note: this texture stage state setup works for 0 or 1 texture.
 914        // if you set a texture, it will be modulated with the current diffuse color.
 915        // if you don't set a texture, it will just use the current diffuse color.
 916        lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
 917	      lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
 918	      lpDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
 919        lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
 920	      lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
 921        lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
 922        lpDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
 923
 924	    if (GetCaps()->RasterCaps & D3DPRASTERCAPS_DITHER)
 925	    	lpDevice->SetRenderState(D3DRS_DITHERENABLE, FALSE);    
 926	    /* WISO: if (GetCaps()->RasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES)
 927		    lpDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);*/
 928
 929        // NOTE: don't forget to call SetTexture and SetVertexShader before drawing!
 930        // Examples:
 931        //      SPRITEVERTEX verts[4];          // has texcoords
 932        //   	lpDevice->SetTexture(0, m_sprite_tex);
 933        //      lpDevice->SetVertexShader( SPRITEVERTEX_FORMAT );
 934        //      
 935        //      WFVERTEX verts[4];              // no texcoords
 936        //   	lpDevice->SetTexture(0, NULL);
 937        //      lpDevice->SetVertexShader( WFVERTEX_FORMAT );
 938    }
 939
 940    // render string to m_lpDDSTitle, if necessary
 941	if (m_supertext.bRedrawSuperText)
 942	{
 943		if (!RenderStringToTitleTexture())
 944            m_supertext.fStartTime = -1.0f;
 945	    m_supertext.bRedrawSuperText = false;
 946	}
 947
 948    // set up to render [from NULL] to VS0 (for motion vectors).
 949    {
 950	    lpDevice->SetTexture(0, NULL);
 951
 952        IDirect3DSurface9* pNewTarget = NULL;
 953        if (m_lpVS[0]->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) 
 954            return;
 955        lpDevice->SetRenderTarget(0, pNewTarget);
 956        pNewTarget->Release();
 957		lpDevice->SetDepthStencilSurface( NULL );
 958
 959	    lpDevice->SetTexture(0, NULL);
 960    }
 961
 962    // draw motion vectors to VS0
 963    DrawMotionVectors();
 964
 965    // set up to render [from VS0] to VS1.
 966    {
 967	    lpDevice->SetTexture(0, NULL);
 968
 969        IDirect3DSurface9* pNewTarget = NULL;
 970        if (m_lpVS[1]->GetSurfaceLevel(0, &pNewTarget) != D3D_OK) 
 971            return;
 972        lpDevice->SetRenderTarget(0, pNewTarget);
 973		lpDevice->SetDepthStencilSurface( NULL );
 974        pNewTarget->Release();
 975    }
 976
 977	// do the warping for this frame
 978	if (GetCaps()->RasterCaps & D3DPRASTERCAPS_DITHER)
 979	    lpDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE);    
 980	/* WISO: if (GetCaps()->RasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES)
 981		lpDevice->SetRenderState(D3DRS_EDGEANTIALIAS, FALSE);*/
 982	WarpedBlitFromVS0ToVS1();
 983	if (GetCaps()->RasterCaps & D3DPRASTERCAPS_DITHER)
 984	    lpDevice->SetRenderState(D3DRS_DITHERENABLE, FALSE);    
 985	/*if (GetCaps()->RasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES)
 986		lpDevice->SetRenderState(D3DRS_EDGEANTIALIAS, TRUE);*/
 987
 988	// draw audio data
 989    DrawCustomShapes(); // draw these first; better for feedback if the waves draw *over* them.
 990	DrawCustomWaves();
 991	DrawWave(mysound.fWave[0], mysound.fWave[1]);
 992	DrawSprites();
 993
 994	// if song title animation just ended, render it into the VS:
 995	if (m_supertext.fStartTime >= 0 &&
 996		GetTime() >= m_supertext.fStartTime + m_supertext.fDuration &&
 997		!m_supertext.bRedrawSuperText)
 998	{
 999		m_supertext.fStartTime = -1.0f;	// 'off' state
1000		ShowSongTitleAnim(m_nTexSize, m_nTexSize, 1.0f);
1001	}
1002
1003  // Change the rendertarget back to the original setup
1004  lpDevice->SetTexture(0, NULL);
1005  // WISO: lpDevice->SetRenderTarget( pBackBuffer, pZBuffer );
1006  lpDevice->SetRenderTarget(0, pBackBuffer);
1007  lpDevice->SetDepthStencilSurface( pZBuffer );
1008
1009  SafeRelease(pBackBuffer);
1010  SafeRelease(pZBuffer);
1011
1012	/* WISO: if (GetCaps()->RasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES)
1013		lpDevice->SetRenderState(D3DRS_EDGEANTIALIAS, FALSE);*/
1014
1015	// show it to user
1016	ShowToUser(bRedraw);
1017
1018
1019	// finally, render song title animation to back buffer
1020	if (m_supertext.fStartTime >= 0 &&
1021		GetTime() < m_supertext.fStartTime + m_supertext.fDuration &&
1022		!m_supertext.bRedrawSuperText)
1023	{
1024		float fProgress = (GetTime() - m_supertext.fStartTime) / m_supertext.fDuration;
1025		ShowSongTitleAnim(GetWidth(), GetHeight(), fProgress);
1026	}
1027
1028	DrawUserSprites();
1029
1030	// flip buffers
1031	IDirect3DTexture9* pTemp = m_lpVS[0];
1032	m_lpVS[0] = m_lpVS[1];
1033	m_lpVS[1] = pTemp;
1034
1035	/* WISO: if (GetCaps()->RasterCaps & D3DPRASTERCAPS_ANTIALIASEDGES)
1036		lpDevice->SetRenderState(D3DRS_EDGEANTIALIAS, FALSE);*/
1037	if (GetCaps()->RasterCaps & D3DPRASTERCAPS_DITHER)
1038	    lpDevice->SetRenderState(D3DRS_DITHERENABLE, FALSE);    
1039}
1040
1041
1042void CPlugin::DrawMotionVectors()
1043{
1044	// FLEXIBLE MOTION VECTOR FIELD
1045	if ((float)*m_pState->var_pf_mv_a >= 0.001f)
1046	{
1047        //-------------------------------------------------------
1048        LPDIRECT3DDEVICE9 lpDevice = GetDevice();
1049        if (!lpDevice)
1050            return;
1051
1052        lpDevice->SetTexture(0, NULL);
1053        lpDevice->SetFVF(WFVERTEX_FORMAT);
1054        //-------------------------------------------------------
1055
1056		int x,y;
1057
1058		int nX = (int)(*m_pState->var_pf_mv_x);// + 0.999f);
1059		int nY = (int)(*m_pState->var_pf_mv_y);// + 0.999f);
1060		float dx = (float)*m_pState->var_pf_mv_x - nX;
1061		float dy = (float)*m_pState->var_pf_mv_y - nY;
1062		if (nX > 64) { nX = 64; dx = 0; }
1063		if (nY > 48) { nY = 48; dy = 0; }
1064		
1065		if (nX > 0 && nY > 0)
1066		{
1067			/*
1068			float dx2 = m_fMotionVectorsTempDx;//(*m_pState->var_pf_mv_dx) * 0.05f*GetTime();		// 0..1 range
1069			float dy2 = m_fMotionVectorsTempDy;//(*m_pState->var_pf_mv_dy) * 0.05f*GetTime();		// 0..1 range
1070			if (GetFps() > 2.0f && GetFps() < 300.0f)
1071			{
1072				dx2 += (float)(*m_pState->var_pf_mv_dx) * 0.05f / GetFps();
1073				dy2 += (float)(*m_pState->var_pf_mv_dy) * 0.05f / GetFps();
1074			}
1075			if (dx2 > 1.0f) dx2 -= (int)dx2;
1076			if (dy2 > 1.0f) dy2 -= (int)dy2;
1077			if (dx2 < 0.0f) dx2 = 1.0f - (-dx2 - (int)(-dx2));
1078			if (dy2 < 0.0f) dy2 = 1.0f - (-dy2 - (int)(-dy2));
1079			// hack: when there is only 1 motion vector on the screem, to keep it in
1080			//       the center, we gradually migrate it toward 0.5.
1081			dx2 = dx2*0.995f + 0.5f*0.005f;	
1082			dy2 = dy2*0.995f + 0.5f*0.005f;
1083			// safety catch
1084			if (dx2 < 0 || dx2 > 1 || dy2 < 0 || dy2 > 1)
1085			{
1086				dx2 = 0.5f;
1087				dy2 = 0.5f;
1088			}
1089			m_fMotionVectorsTempDx = dx2;
1090			m_fMotionVectorsTempDy = dy2;*/
1091			float dx2 = (float)(*m_pState->var_pf_mv_dx);
1092			float dy2 = (float)(*m_pState->var_pf_mv_dy);
1093
1094			float len_mult = (float)*m_pState->var_pf_mv_l;
1095			if (dx < 0) dx = 0;
1096			if (dy < 0) dy = 0;
1097			if (dx > 1) dx = 1;
1098			if (dy > 1) dy = 1;
1099			//dx = dx * 1.0f/(float)nX;
1100			//dy = dy * 1.0f/(float)nY;
1101			float inv_texsize = 1.0f/(float)m_nTexSize;
1102			float min_len = 1.0f*inv_texsize;
1103
1104
1105			WFVERTEX v[(64+1)*2];
1106			ZeroMemory(v, sizeof(WFVERTEX)*(64+1)*2);
1107			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);
1108			for (x=1; x<(nX+1)*2; x++)
1109				v[x].Diffuse = v[0].Diffuse;
1110
1111			lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
1112			lpDevice->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);
1113			lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
1114
1115			for (y=0; y<nY; y++)
1116			{
1117				float fy = (y + 0.25f)/(float)(nY + dy + 0.25f - 1.0f);
1118
1119				// now move by offset
1120				fy -= dy2;
1121
1122				if (fy > 0.0001f && fy < 0.9999f)
1123				{
1124					int n = 0;
1125					for (x=0; x<nX; x++)
1126					{
1127						//float fx = (x + 0.25f)/(float)(nX + dx + 0.25f - 1.0f);
1128						float fx = (x + 0.25f)/(float)(nX + dx + 0.25f - 1.0f);
1129
1130						// now move by offset
1131						fx += dx2;
1132
1133						if (fx > 0.0001f && fx < 0.9999f)
1134						{
1135							float fx2, fy2;
1136							ReversePropagatePoint(fx, fy, &fx2, &fy2);	// NOTE: THIS IS REALLY A REVERSE-PROPAGATION
1137							//fx2 = fx*2 - fx2;
1138							//fy2 = fy*2 - fy2;
1139							//fx2 = fx + 1.0f/(float)m_nTexSize;
1140							//fy2 = 1-(fy + 1.0f/(float)m_nTexSize);
1141
1142							// enforce minimum trail lengths:
1143							{	
1144								float dx = (fx2 - fx);
1145								float dy = (fy2 - fy);
1146								dx *= len_mult;
1147								dy *= len_mult;
1148								float len = sqrtf(dx*dx + dy*dy);
1149
1150								if (len > min_len)
1151								{
1152
1153								}
1154								else if (len > 0.00000001f)
1155								{
1156									len = min_len/len;
1157									dx *= len;
1158									dy *= len;
1159								}
1160								else
1161								{
1162									dx = min_len;
1163									dy = min_len;
1164								}
1165									
1166								fx2 = fx + dx;
1167								fy2 = fy + dy;
1168							}
1169							/**/
1170
1171							v[n].x = fx * 2.0f - 1.0f;
1172							v[n].y = fy * 2.0f - 1.0f;
1173							v[n+1].x = fx2 * 2.0f - 1.0f;
1174							v[n+1].y = fy2 * 2.0f - 1.0f; 
1175
1176							// actually, project it in the reverse direction
1177							//v[n+1].x = v[n].x*2.0f - v[n+1].x;// + dx*2; 
1178							//v[n+1].y = v[n].y*2.0f - v[n+1].y;// + dy*2; 
1179							//v[n].x += dx*2;
1180							//v[n].y += dy*2;
1181
1182							n += 2;
1183						}
1184					}
1185
1186					// draw it
1187					if (n != 0)
1188						lpDevice->DrawPrimitiveUP(D3DPT_LINELIST, n/2, v, sizeof(WFVERTEX));
1189				}
1190			}
1191
1192			lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1193		}
1194	}
1195}
1196
1197/*
1198void CPlugin::UpdateSongInfo()
1199{
1200	if (m_bShowSongTitle || m_bSongTitleAnims)
1201	{
1202		char szOldSongMessage[512];
1203		strcpy(szOldSongMessage, m_szSongMessage);
1204
1205		if (::GetWindowText(m_hWndParent, m_szSongMessage, sizeof(m_szSongMessage)))
1206		{
1207			// remove ' - Winamp' at end
1208			if (strlen(m_szSongMessage) > 9)
1209			{
1210				int check_pos = strlen(m_szSongMessage) - 9;
1211				if (strcmp(" - Winamp", (char *)(m_szSongMessage + check_pos)) == 0)
1212					m_szSongMessage[check_pos] = 0;
1213			}
1214
1215			// remove ' - Winamp [Paused]' at end
1216			if (strlen(m_szSongMessage) > 18)
1217			{
1218				int check_pos = strlen(m_szSongMessage) - 18;
1219				if (strcmp(" - Winamp [Paused]", (char *)(m_szSongMessage + check_pos)) == 0)
1220					m_szSongMessage[check_pos] = 0;
1221			}
1222
1223			// remove song # and period from beginning
1224			char *p = m_szSongMessage;
1225			while (*p >= '0' && *p <= '9') p++;
1226			if (*p == '.' && *(p+1) == ' ')
1227			{
1228				p += 2;
1229				int pos = 0;
1230				while (*p != 0)
1231				{
1232					m_szSongMessage[pos++] = *p;
1233					p++;
1234				}
1235				m_szSongMessage[pos++] = 0;
1236			}
1237
1238			// fix &'s for display
1239			/*
1240			{
1241				int pos = 0;
1242				int len = strlen(m_szSongMessage);
1243				while (m_szSongMessage[pos])
1244				{
1245					if (m_szSongMessage[pos] == '&')
1246					{
1247						for (int x=len; x>=pos; x--)
1248							m_szSongMessage[x+1] = m_szSongMessage[x];
1249						len++;
1250						pos++;
1251					}
1252					pos++;
1253				}
1254			}*/
1255/*
1256			if (m_bSongTitleAnims && 
1257				((strcmp(szOldSongMessage, m_szSongMessage) != 0) || (GetFrame()==0)))
1258			{
1259				// launch song title animation
1260				LaunchSongTitleAnim();
1261
1262				/*
1263				m_supertext.bRedrawSuperText = true;
1264				m_supertext.bIsSongTitle = true;
1265				strcpy(m_supertext.szText, m_szSongMessage);
1266				strcpy(m_supertext.nFontFace, m_szTitleFontFace);
1267				m_supertext.fFontSize   = (float)m_nTitleFontSize;
1268				m_supertext.bBold       = m_bTitleFontBold;
1269				m_supertext.bItal       = m_bTitleFontItalic;
1270				m_supertext.fX          = 0.5f;
1271				m_supertext.fY          = 0.5f;
1272				m_supertext.fGrowth     = 1.0f;
1273				m_supertext.fDuration   = m_fSongTitleAnimDuration;
1274				m_supertext.nColorR     = 255;
1275				m_supertext.nColorG     = 255;
1276				m_supertext.nColorB     = 255;
1277
1278				m_supertext.fStartTime  = GetTime(); 
1279				*/
1280/*			}
1281		}
1282		else
1283		{
1284			sprintf(m_szSongMessage, "<couldn't get song title>");
1285		}
1286	}
1287
1288	m_nTrackPlaying = SendMessage(m_hWndParent,WM_USER, 0, 125);
1289
1290	// append song time
1291	if (m_bShowSongTime && m_nSongPosMS >= 0)
1292	{
1293		float time_s = m_nSongPosMS*0.001f;
1294		
1295		int minutes = (int)(time_s/60);
1296		time_s -= minutes*60;
1297		int seconds = (int)time_s;
1298		time_s -= seconds;
1299		int dsec = (int)(time_s*100);
1300
1301		sprintf(m_szSongTime, "%d:%02d.%02d", minutes, seconds, dsec);
1302	}
1303
1304	// append song length
1305	if (m_bShowSongLen && m_nSongLenMS > 0)
1306	{
1307		int len_s = m_nSongLenMS/1000;
1308		int minutes = len_s/60;
1309		int seconds = len_s - minutes*60;
1310
1311		char buf[512];
1312		sprintf(buf, " / %d:%02d", minutes, seconds);
1313		strcat(m_szSongTime, buf);
1314	}
1315}
1316*/
1317
1318bool CPlugin::ReversePropagatePoint(float fx, float fy, float *fx2, float *fy2)
1319{
1320	//float fy = y/(float)nMotionVectorsY;
1321	int   y0 = (int)(fy*m_nGridY);
1322	float dy = fy*m_nGridY - y0;
1323
1324	//float fx = x/(float)nMotionVectorsX;
1325	int   x0 = (int)(fx*m_nGridX);
1326	float dx = fx*m_nGridX - x0;
1327
1328	int x1 = x0 + 1;
1329	int y1 = y0 + 1;
1330
1331	if (x0 < 0) return false;
1332	if (y0 < 0) return false;
1333	//if (x1 < 0) return false;
1334	//if (y1 < 0) return false;
1335	//if (x0 > m_nGridX) return false;
1336	//if (y0 > m_nGridY) return false;
1337	if (x1 > m_nGridX) return false;
1338	if (y1 > m_nGridY) return false;
1339
1340	float tu, tv;
1341	tu  = m_verts[y0*(m_nGridX+1)+x0].tu * (1-dx)*(1-dy);
1342	tv  = m_verts[y0*(m_nGridX+1)+x0].tv * (1-dx)*(1-dy);
1343	tu += m_verts[y0*(m_nGridX+1)+x1].tu * (dx)*(1-dy);
1344	tv += m_verts[y0*(m_nGridX+1)+x1].tv * (dx)*(1-dy);
1345	tu += m_verts[y1*(m_nGridX+1)+x0].tu * (1-dx)*(dy);
1346	tv += m_verts[y1*(m_nGridX+1)+x0].tv * (1-dx)*(dy);
1347	tu += m_verts[y1*(m_nGridX+1)+x1].tu * (dx)*(dy);
1348	tv += m_verts[y1*(m_nGridX+1)+x1].tv * (dx)*(dy);
1349
1350	*fx2 = tu;
1351	*fy2 = 1.0f - tv;
1352	return true;
1353
1354}
1355
1356
1357void CPlugin::WarpedBlitFromVS0ToVS1()
1358{
1359	MungeFPCW(NULL);	// puts us in single-precision mode & disables exceptions
1360
1361    LPDIRECT3DDEVICE9 lpDevice = GetDevice();
1362    if (!lpDevice)
1363        return;
1364
1365	lpDevice->SetTexture(0, m_lpVS[0]);
1366  lpDevice->SetFVF( SPRITEVERTEX_FORMAT );
1367
1368	// warp stuff
1369	float fWarpTime = GetTime() * m_pState->m_fWarpAnimSpeed;
1370  float fWarpScale = m_pState->m_fWarpScale.eval(GetTime());
1371  float fWarpScaleInv = 1.0f;
1372  if(fWarpScale != 0.0f)
1373    fWarpScaleInv = 1.0f / fWarpScale;
1374	float f[4];
1375	f[0] = 11.68f + 4.0f*cosf(fWarpTime*1.413f + 10);
1376	f[1] =  8.77f + 3.0f*cosf(fWarpTime*1.113f + 7);
1377	f[2] = 10.54f + 3.0f*cosf(fWarpTime*1.233

Large files files are truncated, but you can click here to view the full file