aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Visualization/vis_milk2/milkdropfs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Visualization/vis_milk2/milkdropfs.cpp')
-rw-r--r--Src/Plugins/Visualization/vis_milk2/milkdropfs.cpp4801
1 files changed, 4801 insertions, 0 deletions
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