mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
4801 lines
No EOL
181 KiB
C++
4801 lines
No EOL
181 KiB
C++
/*
|
|
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);
|
|
} |