Files
FC1/RenderDll/XRenderD3D8/D3DPShaders.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

591 lines
14 KiB
C++

/*=============================================================================
D3DPShaders.cpp : pixel shaders support for D3D.
Copyright (c) 2001 Crytek Studios. All Rights Reserved.
Revision history:
* Created by Khonich Andrey
=============================================================================*/
#include "stdafx.h"
#include "DriverD3D8.h"
#include "D3DCGPShader.h"
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
// init memory pool usage
#ifndef PS2
#ifndef _XBOX
_ACCESS_POOL;
#endif
#endif
TArray<CPShader *> CPShader::m_PShaders;
CPShader *CPShader::m_CurRC;
//=======================================================================
CPShader *CPShader::mfForName(char *name, bool bCGType)
{
int i;
for (i=0; i<m_PShaders.Num(); i++)
{
if (!m_PShaders[i])
continue;
if (!stricmp(name, m_PShaders[i]->m_Name.c_str()))
return m_PShaders[i];
}
char scrname[128];
char dir[128];
if (!bCGType)
{
sprintf(dir, "%sDeclarations/PShaders/", gcEf.m_HWPath);
sprintf(scrname, "%s%s.cryps", dir, name);
}
else
{
sprintf(dir, "%sDeclarations/CGPShaders/", gcEf.m_HWPath);
sprintf(scrname, "%s%s.crycg", dir, name);
}
FILE *fp = iSystem->GetIPak()->FOpen(scrname, "r");
if (!fp)
{
iLog->Log("WARNING: Couldn't find pixel shader '%s'", name);
iLog->Log("WARNING: Full file name: '%s'", scrname);
return NULL;
}
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int len = iSystem->GetIPak()->FTell(fp);
char *buf = new char [len+1];
iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET);
len = iSystem->GetIPak()->FRead(buf, 1, len, fp);
iSystem->GetIPak()->FClose(fp);
buf[len] = 0;
buf = gcEf.mfScriptPreprocessor(buf, dir, scrname);
CPShader *p = NULL;
if (!bCGType)
{
CPShader_D3D *pr = new CPShader_D3D;
pr->m_Name = name;
pr->m_Id = i;
m_PShaders.AddElem(pr);
pr->m_RefCounter = 1;
p = pr;
}
else
{
CPShader *pr;
pr = new CCGPShader_D3D;
pr->m_Name = name;
pr->m_Id = i;
m_PShaders.AddElem(pr);
pr->m_RefCounter = 1;
p = pr;
}
HANDLE statussrc = CreateFile(scrname,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (statussrc != INVALID_HANDLE_VALUE)
{
GetFileTime(statussrc,NULL,NULL,&p->m_WriteTime);
CloseHandle(statussrc);
}
p->mfCompile(buf);
delete [] buf;
return p;
}
//=============================================================================
void CPShader::mfClearAll(void)
{
for (int i=0; i<m_PShaders.Num(); i++)
{
CPShader *vp = m_PShaders[i];
if (vp)
delete vp;
}
m_PShaders.Free();
}
bool CPShader_D3D::mfCompile(char *scr)
{
char* name;
long cmd;
char *params;
char *data;
guard(CPShader_D3D::mfCompile);
enum {eScript=1, eParam};
static tokenDesc commands[] =
{
{eScript, "Script"},
{eParam, "Param"},
{0,0}
};
SShader *ef = gcEf.m_CurShader;
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
data = NULL;
if (name)
data = name;
else
if (params)
data = params;
switch (cmd)
{
case eScript:
{
if (!(gRenDev->GetFeatures() & RFT_HW_TS))
{
iLog->Log("Render device doesn't support texture shaders (Shader '%s')\n", ef->m_Name.c_str());
break;
}
int n = strlen(params);
m_pScript = new char[n+1];
memcpy(m_pScript, params, n);
m_pScript[n] = 0;
}
break;
case eParam:
gcEf.mfCompileParam(params, ef, &m_Params);
break;
}
}
unguard;
return 1;
}
void CPShader_D3D::mfDeleteParams(TArray<SParam> &Vars)
{
int i, j;
for (i=0; i<Vars.Num(); i++)
{
SParam *p = &Vars[i];
for (j=0; j<4; j++)
{
if (p->m_Comps[j])
{
delete p->m_Comps[j];
p->m_Comps[j] = NULL;
}
}
}
Vars.Free();
}
void CPShader_D3D::mfReset()
{
if (m_dwShader)
{
gcpRendD3D->mfGetD3DDevice()->DeletePixelShader(m_dwShader);
m_dwShader = 0;
}
m_bActive = false;
}
CPShader_D3D::~CPShader_D3D()
{
mfDeleteParams(m_Params);
SAFE_DELETE (m_pScript);
mfReset();
}
void CPShader_D3D::mfSetFloat4f(int reg, float *v)
{
HRESULT hr = gcpRendD3D->mfGetD3DDevice()->SetPixelShaderConstant(reg, v, 1);
}
#define GL_OFFSET_TEXTURE_2D_MATRIX_NV 0x86E1
void CPShader_D3D::mfSetParams(TArray<SParam>& Vars, TArray<SParam>* AddParams)
{
int i;
HRESULT hr = 0;
for (i=0; i<Vars.Num(); i++)
{
SParam *p = &Vars[i];
float *v = p->mfGet();
if (p->m_Reg != GL_OFFSET_TEXTURE_2D_MATRIX_NV)
hr = gcpRendD3D->mfGetD3DDevice()->SetPixelShaderConstant(p->m_Reg, v, 1);
else
{
//v[0] = v[3] = 0;
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVMAT00, FLOATtoDWORD(v[0]));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVMAT01, FLOATtoDWORD(v[1]));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVMAT10, FLOATtoDWORD(v[2]));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVMAT11, FLOATtoDWORD(v[3]));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVLSCALE, FLOATtoDWORD(4.0f));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVLOFFSET, FLOATtoDWORD(0.0f));
}
if (FAILED(hr))
return;
}
if (AddParams)
{
for (i=0; i<AddParams->Num(); i++)
{
SParam *p = &AddParams->Get(i);
float *v = p->mfGet();
if (p->m_Reg != GL_OFFSET_TEXTURE_2D_MATRIX_NV)
hr = gcpRendD3D->mfGetD3DDevice()->SetPixelShaderConstant(p->m_Reg, v, 1);
else
{
//v[0] = v[3] = 0;
v[0] *= CRenderer::CV_r_embm;
v[3] *= CRenderer::CV_r_embm;
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVMAT00, FLOATtoDWORD(v[0]));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVMAT01, FLOATtoDWORD(v[1]));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVMAT10, FLOATtoDWORD(v[2]));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVMAT11, FLOATtoDWORD(v[3]));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVLSCALE, FLOATtoDWORD(4.0f));
gcpRendD3D->mfGetD3DDevice()->SetTextureStageState(1, D3DTSS_BUMPENVLOFFSET, FLOATtoDWORD(0.0f));
}
if (FAILED(hr))
return;
}
}
}
bool CPShader_D3D::mfBind()
{
HRESULT hr;
if (!m_bActive)
mfActivate();
hr = gcpRendD3D->mfGetD3DDevice()->SetPixelShader( m_dwShader );
if (FAILED(hr))
return false;
return true;
}
bool CPShader_D3D::mfUnbind()
{
HRESULT hr;
hr = gcpRendD3D->mfGetD3DDevice()->SetPixelShader( NULL );
if (FAILED(hr))
return false;
return true;
}
#ifdef _XBOX
char * PSToXboxPS(const char * pInp)
{
size_t len = strlen(pInp);
char * p, *tmp;
char * pRet = p = new char[len+256];
const char * pFind = "_sat";
int lenFind = 4;
int nChar = 0;
int state = 0;
char cReg[16];
int iReg=0;
int AfterCom = 0;
bool bIsAlphaString = false;
int ChanelReg = 0;
while(*p++ = *pInp++)
{
if(*(pInp) != 0 && *(pInp) == 'p' && *(pInp+1) == 's')
*p++ = 'x';
}
for(p = pRet; *p; p++)
{
if(*p == '\n')
{
AfterCom = 0;
bIsAlphaString = false;
}
if(!AfterCom && *p == ',')
AfterCom = 1;
if(!AfterCom && *p == '.' && (*(p+1) == 'a') || (*(p+1) == 'A'))
bIsAlphaString = true;
if(state != 3 && state != 4)
{
if(state==0 && !AfterCom && pFind[nChar] == *p)
{
nChar++;
if(nChar >= lenFind)
{
for(int i = 1; *(p+i-1); i++)
*(p-lenFind+i) = *(p+i);
p -= lenFind;
nChar = 0;
state = 1;
}
}
else
{
nChar = 0;
if(state == 1)
{
if (*p != ' ' && *p != '\t')
state = 2;
}
if(state == 2)
{
if (*p != ' ' && *p != '\t' && *p != ',')
cReg[iReg++] = *p;
else
{
cReg[iReg] = 0;
char * ch = strchr(cReg, '.');
ChanelReg = 0;
if(ch)
{
if( *(ch+1) == 'a' || *(ch+1) == 'A')
ChanelReg = 2;
*ch = 0;
iReg = int(ch - cReg);
}
state = 3;
tmp = p;
AfterCom = 2;
}
}
}
}
else // if(state == 3 || state == 4)
{
if(AfterCom == 1 && cReg[nChar] == *p)
{
nChar++;
if(nChar >= iReg)
{
bool bSet = false;
if(!bIsAlphaString)
{
if(ChanelReg ==2)
{
}
else
if(*(p+1)=='.' && *(p+2)=='a')
{
}
else
bSet=true;
}
else // if(bIsAlphaString)
{
if(ChanelReg == 0)
{
if(*(p+1)=='.' && *(p+2)!='a')
{
bSet = true;
}
}
if(ChanelReg ==2)
{
bSet = true;
if(*(p+1)=='.' && *(p+2)!='a')
{
bSet = false;
}
}
}
if(bSet)
{
char * vp = strchr(p,0);
while (vp != p)
*(vp + lenFind) = *vp--;
p++;
for(int i=0; i<=lenFind-1; i++)
*p++ = pFind[i];
nChar = 0;
//iReg = 0;
state = 4;
//p = tmp-1;
}
}
}
else
nChar = 0;
if(*(p+1)==0 || (state==4 && (*(p+1)=='\n') ))
{
nChar = 0;
iReg = 0;
state = 0;
p = tmp-1;
}
}
}
strcpy(p-1, "\nxfc fog.a,r0,fog.rgb,zero,zero,zero,r0.a\n");
return pRet;
}
#endif //_XBOX
bool CPShader_D3D::mfActivate()
{
HRESULT hr;
if (m_bActive)
return true;
#ifdef _XBOX
LPXGBUFFER pCode;
LPXGBUFFER pBuffer = NULL;
if (!m_pScript)
return false;
m_bActive = 1;
#ifndef _XBOX
hr = XGAssembleShader(m_Name.c_str(), m_pScript, strlen(m_pScript), 0, NULL, &pCode, &pBuffer, NULL, NULL, NULL, 0);
#else //_XBOX
char * pScriptTmp = PSToXboxPS(m_pScript);
hr = XGAssembleShader(m_Name.c_str(), pScriptTmp, strlen(pScriptTmp), 0, NULL, &pCode, &pBuffer, NULL, NULL, NULL, 0);
delete [] pScriptTmp;
#endif ///_XBOX
if (FAILED(hr))
{
iLog->Log("CPShader_D3D::mfActivate: Couldn't assemble pixel shader '%s' (%s)\n", m_Name.c_str(), gcpRendD3D->D3DError(hr));
if( pBuffer != NULL)
{
TCHAR* pstr;
TCHAR strOut[4096];
TCHAR* pstrOut;
// Need to replace \n with \r\n so edit box shows newlines properly
pstr = (TCHAR*)pBuffer->GetBufferPointer();
strOut[0] = '\0';
pstrOut = strOut;
for( int i = 0; i < 4096; i++ )
{
if( *pstr == '\n' )
*pstrOut++ = '\r';
*pstrOut = *pstr;
if( *pstr == '\0' )
break;
if( i == 4095 )
*pstrOut = '\0';
pstrOut++;
pstr++;
}
// remove any blank lines at the end
while( strOut[lstrlen(strOut) - 1] == '\n' || strOut[lstrlen(strOut) - 1] == '\r' )
{
strOut[lstrlen(strOut) - 1] = '\0';
}
iLog->Log("ERROR: CPShader_D3D::mfActivate: Shader '%s' script error (%s)\n", strOut, m_Name.c_str());
SAFE_RELEASE( pBuffer );
}
return false;
}
// Create the pixel shader
if( FAILED( hr = gcpRendD3D->mfGetD3DDevice()->CreatePixelShader((D3DPIXELSHADERDEF *)pCode->GetBufferPointer(), &m_dwShader)))
{
iLog->Log("ERROR: CPShader_D3D::mfActivate: Couldn't create pixel shader '%s'\n", m_Name.c_str());
return false;
}
#else
LPD3DXBUFFER pCode;
LPD3DXBUFFER pBuffer = NULL;
if (!m_pScript)
return false;
m_bActive = 1;
// Assemble script (.nvp) and create shader
hr = D3DXAssembleShader( m_pScript, strlen(m_pScript), 0, NULL, &pCode, &pBuffer );
if (FAILED(hr))
{
iLog->Log("ERROR: CPShader_D3D::mfActivate: Couldn't assemble pixel shader '%s'\n", m_Name.c_str());
if( pBuffer != NULL)
{
TCHAR* pstr;
TCHAR strOut[4096];
TCHAR* pstrOut;
// Need to replace \n with \r\n so edit box shows newlines properly
pstr = (TCHAR*)pBuffer->GetBufferPointer();
strOut[0] = '\0';
pstrOut = strOut;
for( int i = 0; i < 4096; i++ )
{
if( *pstr == '\n' )
*pstrOut++ = '\r';
*pstrOut = *pstr;
if( *pstr == '\0' )
break;
if( i == 4095 )
*pstrOut = '\0';
pstrOut++;
pstr++;
}
// remove any blank lines at the end
while( strOut[lstrlen(strOut) - 1] == '\n' || strOut[lstrlen(strOut) - 1] == '\r' )
{
strOut[lstrlen(strOut) - 1] = '\0';
}
iLog->Log("ERROR: CPShader_D3D::mfActivate: Pixel shader '%s' script error (%s)\n", m_Name.c_str(), strOut);
SAFE_RELEASE( pBuffer );
}
return false;
}
// Create the pixel shader
hr = gcpRendD3D->mfGetD3DDevice()->CreatePixelShader( (DWORD*)pCode->GetBufferPointer(), &m_dwShader );
if (FAILED(hr))
{
iLog->Log("ERROR: CPShader_D3D::mfActivate: Couldn't create pixel shader '%s'\n", m_Name.c_str());
return false;
}
#endif
return true;
}
bool CPShader_D3D::mfSet(bool bStat, SShaderPassHW *slw)
{
if (!m_bActive)
{
if (!mfActivate())
return false;
}
if (!bStat)
{
if (CRenderer::CV_r_log >= 3)
gRenDev->Logv(SRendItem::m_RecurseLevel, "--- Reset PShader \"%s\"\n", m_Name.c_str());
mfUnbind();
}
else
{
if (CRenderer::CV_r_log >= 3)
gRenDev->Logv(SRendItem::m_RecurseLevel, "--- Set PShader \"%s\"\n", m_Name.c_str());
mfBind();
if (slw)
mfSetParams(m_Params, slw->m_RCParamsNoObj);
else
mfSetParams(m_Params, NULL);
}
return true;
}