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

2754 lines
70 KiB
C++

/*=============================================================================
ShaderScript.cpp : loading/reloading/hashing of shader scipts.
Copyright (c) 2001 Crytek Studios. All Rights Reserved.
Revision history:
* Created by Honitch Andrey
=============================================================================*/
#include "RenderPCH.h"
#include "I3DEngine.h"
#include "CryHeaders.h"
#include "../RendElements/CREScreenCommon.h"
#if defined(WIN32) || defined(WIN64)
#include <direct.h>
#include <io.h>
#endif
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
extern char *gShObjectNotFound;
//=================================================================================================
void CShader::mfRefreshLayer(SShaderPass *sl, SShader *sh)
{
int i;
STexPic *tp;
for (i=0; i<sl->m_TUnits.Num(); i++)
{
SShaderTexUnit *tl = &sl->m_TUnits[i];
if (!(tp=tl->m_TexPic) || !tp->m_bBusy || tp->m_LoadFrame == gRenDev->GetFrameID())
continue;
tp->m_LoadFrame = gRenDev->GetFrameID();
if (tp->m_Bind >= TX_FIRSTBIND)
gRenDev->EF_LoadTexture(tp->m_SearchName.c_str(), tp->m_Flags, tp->m_Flags2 | FT2_RELOAD, tp->m_eTT, tp->m_fAmount1, tp->m_fAmount2, tp->m_Id);
}
}
void CPShader::mfReload(int nFlags)
{
if (m_FrameLoad == gRenDev->GetFrameID())
return;
m_FrameLoad = gRenDev->GetFrameID();
char name[256];
char dir[256];
if (!m_bCGType)
{
sprintf(dir, "%sDeclarations/PShaders/", gRenDev->m_cEF.m_HWPath);
sprintf(name, "%s.cryps", m_Name.c_str());
}
else
{
sprintf(dir, "%sDeclarations/CGPShaders/", gRenDev->m_cEF.m_HWPath);
sprintf(name, "%s.crycg", m_Name.c_str());
}
mfReloadScript(dir, name, nFlags, m_nMaskGen);
}
void CPShader::mfReloadScript(const char *szPath, const char *szName, int nFlags, uint64 nMaskGen)
{
#if !defined(PS2) && !defined (GC) && !defined (NULL_RENDERER)
const char *ext = GetExtension(szName);
char name1[256], name2[256];
char resName[256];
int i;
bool bCG = false;
if (!stricmp(ext, ".crycg"))
{
sprintf(name1, "%sDeclarations/CGPShaders/", gRenDev->m_cEF.m_HWPath);
bCG = true;
}
else
if (!stricmp(ext, ".cryps"))
{
sprintf(name1, "%sDeclarations/PShaders/", gRenDev->m_cEF.m_HWPath);
bCG = false;
}
else
return;
strcpy(name2, szPath);
ConvertDOSToUnixName(name1, name1);
ConvertDOSToUnixName(name2, name2);
int len = strlen(name2);
if (name2[len-1] != '/')
{
name2[len-1] = '/';
name2[len] = 0;
}
if (!stricmp(name1, name2))
{
char name[256];
StripExtension(szName, name);
for (i=0; i<m_PShaders.Num(); i++)
{
if (!m_PShaders[i])
continue;
if (!stricmp(name, m_PShaders[i]->m_Name.c_str()))
{
if (nMaskGen != -1)
{
if (nMaskGen != m_PShaders[i]->m_nMaskGen)
continue;
}
CPShader *ps = m_PShaders[i];
strcpy(resName, name1);
strcat(resName, szName);
FILETIME writetime;
FILE *statussrc = iSystem->GetIPak()->FOpen(resName, "rb");
if (statussrc)
{
writetime = iSystem->GetIPak()->GetModificationTime(statussrc);
iSystem->GetIPak()->FClose (statussrc);
if (CompareFileTime(&writetime, &ps->m_WriteTime)==0)
continue;
ps->m_WriteTime = writetime;
}
iLog->Log("Reload pixel shader '%s' (%I64x)", name, ps->m_nMaskGen);
ps->mfReset();
FILE *fp = iSystem->GetIPak()->FOpen(resName, "rb");
if (!fp)
{
Warning( 0,0,"WARNING: Couldn't find pixel shader '%s'", resName);
continue;
}
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;
gRenDev->m_cEF.m_Macros = ps->m_Macros;
buf = gRenDev->m_cEF.mfScriptPreprocessor(buf, name2, szName);
ps->mfCompile(buf);
delete [] buf;
if (nMaskGen != -1)
return;
}
}
}
#endif
}
void CVProgram::mfReload(int nFlags)
{
if (m_FrameLoad == gRenDev->GetFrameID())
return;
m_FrameLoad = gRenDev->GetFrameID();
char name[256];
char dir[256];
sprintf(dir, "%sDeclarations/CGVShaders/", gRenDev->m_cEF.m_HWPath);
sprintf(name, "%s.crycg", m_Name.c_str());
CVProgram::mfReloadScript(dir, name, nFlags, m_nMaskGen);
}
void CVProgram::mfReloadScript(const char *szPath, const char *szName, int nFlags, uint64 nMaskGen)
{
#if !defined(PS2) && !defined (GC) && !defined (NULL_RENDERER)
const char *ext = GetExtension(szName);
char name1[256], name2[256], resName[256];
int i;
if (!stricmp(ext, ".crycg"))
sprintf(name1, "%sDeclarations/CGVShaders/", gRenDev->m_cEF.m_HWPath);
else
return;
strcpy(name2, szPath);
ConvertDOSToUnixName(name1, name1);
ConvertDOSToUnixName(name2, name2);
int len = strlen(name2);
if (name2[len-1] != '/')
{
name2[len-1] = '/';
name2[len] = 0;
}
if (!stricmp(name1, name2))
{
char name[256];
StripExtension(szName, name);
for (i=0; i<m_VPrograms.Num(); i++)
{
if (!m_VPrograms[i])
continue;
if (!stricmp(name, m_VPrograms[i]->m_Name.c_str()))
{
if (nMaskGen != -1)
{
if (nMaskGen != m_VPrograms[i]->m_nMaskGen)
continue;
}
CVProgram *vp = m_VPrograms[i];
strcpy(resName, name1);
strcat(resName, szName);
FILETIME writetime;
FILE *statussrc = iSystem->GetIPak()->FOpen(resName, "rb");
if (statussrc)
{
writetime = iSystem->GetIPak()->GetModificationTime(statussrc);
iSystem->GetIPak()->FClose (statussrc);
if (CompareFileTime(&writetime, &vp->m_WriteTime) == 0)
continue;
vp->m_WriteTime = writetime;
}
iLog->Log("Reload vertex shader '%s' (%I64x)", name, vp->m_nMaskGen);
vp->mfReset();
FILE *fp = iSystem->GetIPak()->FOpen(resName, "rb");
if (!fp)
{
Warning( 0,0,"WARNING: Couldn't find vertex shader '%s'", resName);
continue;
}
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;
gRenDev->m_cEF.m_Macros = vp->m_Macros;
buf = gRenDev->m_cEF.mfScriptPreprocessor(buf, name2, szName);
vp->mfCompile(buf);
delete [] buf;
if (nMaskGen != -1)
return;
}
}
}
#endif
}
char *CShader::mfRescanScript(int type, int nInd, SShader *pSHOrg, uint64 nMaskGen)
{
char *pFinalScript = mfScriptForFileName(m_FileNames[type][nInd].c_str(), pSHOrg, nMaskGen);
if (!pFinalScript)
return NULL;
ShaderFilesMapItor itor = m_RefEfs[type]->begin();
TArray<SRefEfs *> REs;
TArray<const char *> REnames;
int ind = nInd;
while(itor != m_RefEfs[type]->end())
{
SRefEfs* re = itor->second;
if (re->m_Ind == nInd)
{
REs.AddElem(re);
REnames.AddElem(itor->first.c_str());
}
itor++;
}
for (int n=0; n<REs.Num(); n++)
{
delete [] REs[n];
m_RefEfs[type]->erase(REnames[n]);
}
char Er[256];
sprintf(Er, "File '%s' script error!\n", m_FileNames[type][nInd].c_str());
gShObjectNotFound = Er;
mfScanScript(pFinalScript, ind);
return pFinalScript;
}
bool CShader::mfReloadShaderScript(const char *szShaderName, int nFlags, SShader *pSH)
{
CRenderer *rd = gRenDev;
SRefEfsLoaded *fe;
char name[256];
strcpy(name, szShaderName);
strlwr(name);
LoadedShadersMapItor it = m_RefEfsLoaded.find(name);
if (it == m_RefEfsLoaded.end())
fe = NULL;
else
fe = &it->second;
if (!fe)
{
Warning( 0,0,"Attempt to reload non-loaded shader '%s'", szShaderName);
return false;
}
SShader *pSHOrg = fe->m_Ef;
int nD = -1;
int nDCount = 0;
if (pSHOrg && pSHOrg->m_DerivedShaders && pSHOrg->m_DerivedShaders->Num())
nDCount = pSHOrg->m_DerivedShaders->Num();
while (true)
{
if (nDCount)
{
nD++;
if (nD >= nDCount)
return true;
pSH = pSHOrg->m_DerivedShaders->Get(nD);
}
else
pSH = pSHOrg;
if (pSH->m_nRefreshFrame == m_nFrameForceReload)
{
if (nD < 0)
return true;
continue;
}
pSH->m_nRefreshFrame = m_nFrameForceReload;
for (int type=0; type<2; type++)
{
SRefEfs *fe;
ShaderFilesMapItor it;
it = m_RefEfs[type]->find(szShaderName);
if (it == m_RefEfs[type]->end())
fe = NULL;
else
fe = it->second;
if (!fe)
continue;
m_CurEfsNum = type;
if (m_nFrameReload[type][fe->m_Ind] != m_nFrameForceReload)
{
FILE *status = iSystem->GetIPak()->FOpen(m_FileNames[type][fe->m_Ind].c_str(), "rb");
if (!status)
return false;
FILETIME writetime = iSystem->GetIPak()->GetModificationTime(status);
iSystem->GetIPak()->FClose (status);
if (!(nFlags & FRO_FORCERELOAD))
{
if (CompareFileTime(&writetime, &pSH->m_WriteTime) == 0)
return true;
}
m_nFrameReload[type][fe->m_Ind] = m_nFrameForceReload;
m_WriteTime[type][fe->m_Ind] = writetime;
pSH->m_WriteTime = writetime;
char *pFinalScript;
if (!(pFinalScript=mfRescanScript(type, fe->m_Ind, pSHOrg, pSH ? pSH->m_nMaskGen : 0)))
continue;
delete [] pFinalScript;
}
m_CurEfsNum = 0;
m_bReload = true;
if (nDCount)
iLog->Log("Reload shader '%s(%I64x)'", szShaderName, pSH->m_nMaskGen);
else
iLog->Log("Reload shader '%s'", szShaderName);
SShader *ef = gRenDev->m_cEF.mfForName(szShaderName, eSH_Misc, SF_RELOAD, NULL, pSH ? pSH->m_nMaskGen : 0);
m_bReload = false;
if (nD < 0)
return true;
}
}
return false;
}
bool SShader::Reload(int nFlags)
{
int i, j;
if (nFlags & FRO_SHADERS)
{
gRenDev->m_cEF.mfReloadShaderScript(m_Name.c_str(), nFlags, this);
if (m_Flags & (EF_HASVSHADER | EF3_HASRCOMBINER | EF3_HASPSHADER))
{
for (i=0; i<m_HWTechniques.Num(); i++)
{
for (j=0; j<m_HWTechniques[i]->m_Passes.Num(); j++)
{
if (m_HWTechniques[i]->m_Passes[j].m_FShader)
m_HWTechniques[i]->m_Passes[j].m_FShader->mfReload(nFlags);
if (m_HWTechniques[i]->m_Passes[j].m_VProgram)
m_HWTechniques[i]->m_Passes[j].m_VProgram->mfReload(nFlags);
}
}
}
}
if (nFlags & FRO_SHADERTEXTURES)
{
for (i=0; i<m_Passes.Num(); i++)
{
gRenDev->m_cEF.mfRefreshLayer(&m_Passes[i], this);
}
for (i=0; i<m_HWTechniques.Num(); i++)
{
SShaderTechnique *hw = m_HWTechniques[i];
for (j=0; j<hw->m_Passes.Num(); j++)
{
gRenDev->m_cEF.mfRefreshLayer(&hw->m_Passes[j], this);
}
}
if (m_Templates)
{
for (i=0; i<m_Templates->m_TemplShaders.Num(); i++)
{
if (m_Templates->m_TemplShaders[i])
m_Templates->m_TemplShaders[i]->Reload(nFlags);
}
}
}
return true;
}
bool CShader::mfReloadAllShaders(int nFlags)
{
int i;
bool bState = true;
m_nFrameForceReload++;
for (i=0; i<m_Nums; i++)
{
SShader *sh = SShader::m_Shaders_known[i];
if (!sh)
continue;
if (!sh->Reload(nFlags))
bState = false;
}
#ifndef NULL_RENDERER
for (i=0; i<CPShader::m_PShaders.Num(); i++)
{
CPShader *ps = CPShader::m_PShaders[i];
if (!ps)
continue;
ps->mfReload(nFlags);
}
for (i=0; i<CVProgram::m_VPrograms.Num(); i++)
{
CVProgram *vs = CVProgram::m_VPrograms[i];
if (!vs)
continue;
vs->mfReload(nFlags);
}
#endif
return bState;
}
bool CShader::mfReloadShader(const char *szName, int nFlags)
{
SRefEfsLoaded *fe;
char name[256];
strcpy(name, szName);
strlwr(name);
LoadedShadersMapItor it = m_RefEfsLoaded.find(name);
if (it == m_RefEfsLoaded.end())
fe = NULL;
else
fe = &it->second;
if (!fe)
return false;
return fe->m_Ef->Reload(nFlags);
}
bool CShader::mfReloadShaderFile(const char *szName, int nFlags)
{
TArray<char *> ShNames;
char **EfNames = gRenDev->EF_GetShadersForFile(szName, -1);
if (EfNames)
{
int j = 0;
bool bRes = false;
while (EfNames[j])
{
ShNames.AddElem(EfNames[j]);
EfNames[j] = NULL;
j++;
}
for (j=0; j<ShNames.Num(); j++)
{
if (mfReloadShader(ShNames[j], nFlags))
bRes = true;
delete [] ShNames[j];
}
return bRes;
}
return false;
}
bool CShader::mfReloadFile(const char *szPath, const char *szName, int nFlags)
{
m_nFrameForceReload++;
const char *ext = GetExtension(szName);
char fName[256];
strcpy(fName, szPath);
strcat(fName, szName);
if (!strnicmp(ext, ".csl", 4))
{
return mfReloadShaderFile(fName, nFlags);
}
else
if (!stricmp(ext, ".csi"))
{
int i, j;
char path[256];
TArray<char *> CheckNames;
TArray<char *> AffectedFiles;
strcpy(path, szPath);
strcat(path, szName);
strlwr(path);
CheckNames.AddElem(path);
for (j=0; j<CheckNames.Num(); j++)
{
for (i=0; i<2; i++)
{
mfCheckAffectedFiles(m_ShadersPath[i], j, CheckNames, AffectedFiles);
}
}
for (i=1; i<CheckNames.Num(); i++)
{
SAFE_DELETE_ARRAY(CheckNames[i]);
}
if (!AffectedFiles.Num())
return false;
bool bRes = false;
for (i=0; i<AffectedFiles.Num(); i++)
{
if (mfReloadShaderFile(AffectedFiles[i], nFlags | FRO_FORCERELOAD))
bRes = true;
SAFE_DELETE_ARRAY(AffectedFiles[i]);
}
return bRes;
}
else
if (!stricmp(ext, ".crycg"))
{
char name[256];
strcpy(name, szPath);
strlwr(name);
if (strstr(name, "cgvshaders"))
CVProgram::mfReloadScript(szPath, szName, nFlags, -1);
else
if (strstr(name, "cgpshaders"))
CPShader::mfReloadScript(szPath, szName, nFlags, -1);
}
return false;
}
void CShader::mfCheckAffectedFiles(const char *ShadersPath, int nCheckFile, TArray<char *>& CheckNames, TArray<char *>& AffectedFiles)
{
struct _finddata_t fileinfo;
intptr_t handle;
int len;
FILE *fp;
char *buf;
char nmf[256];
char dirn[256], *ddir;
int i;
ddir = dirn;
strcpy(dirn, ShadersPath);
strcat(dirn, "*.*");
ConvertUnixToDosName(dirn, dirn);
handle = iSystem->GetIPak()->FindFirst (ddir, &fileinfo);
if (handle == -1)
return;
do
{
if (fileinfo.name[0] == '.')
continue;
if (fileinfo.attrib & _A_SUBDIR)
{
char next[256];
sprintf(next, "%s%s/", ShadersPath, fileinfo.name);
mfCheckAffectedFiles(next, nCheckFile, CheckNames, AffectedFiles);
continue;
}
strcpy(nmf, ShadersPath);
strcat(nmf, fileinfo.name);
len = strlen(nmf);
while (len && nmf[len] != '.')
len--;
if (len <= 0)
continue;
if (strnicmp(&nmf[len], ".csl", 4) && stricmp(&nmf[len], ".csi"))
continue;
if (nmf[len+4])
{
if (!stricmp(&nmf[len+4], "new"))
{
if (CRenderer::CV_r_usehwshaders!=2)
continue;
}
else
if (!stricmp(&nmf[len+4], "old"))
{
if (CRenderer::CV_r_usehwshaders!=1)
continue;
}
else
continue;
}
fp = iSystem->GetIPak()->FOpen(nmf, "rb");
if (!fp)
continue;
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int ln = iSystem->GetIPak()->FTell(fp);
if (!ln)
{
iSystem->GetIPak()->FClose(fp);
continue;
}
buf = new char [ln+1];
if (!buf)
{
iSystem->GetIPak()->FClose(fp);
iConsole->Exit("Can't allocate %d bytes for shader file '%s'\n", len+1, nmf);
}
buf[ln] = 0;
iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET);
iSystem->GetIPak()->FRead(buf, 1, ln, fp);
iSystem->GetIPak()->FClose(fp);
strlwr(buf);
char fname[256];
char fext[16];
_splitpath(CheckNames[nCheckFile], NULL, NULL, fname, fext);
strcat(fname, fext);
if (strstr(buf, fname))
{
ln = strlen(nmf)+1;
char *fullname = new char[ln];
strcpy(fullname, nmf);
strlwr(fullname);
if (!strnicmp(&nmf[len], ".csl", 4))
{
for (i=0; i<AffectedFiles.Num(); i++)
{
if (!strcmp(AffectedFiles[i], fullname))
break;
}
if (i == AffectedFiles.Num())
AffectedFiles.AddElem(fullname);
}
else
{
for (i=0; i<CheckNames.Num(); i++)
{
if (!strcmp(CheckNames[i], fullname))
break;
}
if (i == CheckNames.Num())
CheckNames.AddElem(fullname);
}
}
delete [] buf;
} while (iSystem->GetIPak()->FindNext( handle, &fileinfo ) != -1);
iSystem->GetIPak()->FindClose (handle);
}
//=============================================================================
static char *sEfNames[256];
char **CShader::mfListInScript (char *scr)
{
char* name;
long cmd;
char *params;
int num = 0;
float ver = 0;
char *buf;
enum {eShader=1, eVersion, eSubrScript};
static tokenDesc commands[] =
{
{eShader, "Shader"},
{eVersion, "Version"},
{eSubrScript, "SubrScript"},
{0,0}
};
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
switch (cmd)
{
case eVersion:
ver = shGetFloat(params);
if (ver != SHADER_VERSION)
{
Warning( 0,0,"Warning: Shader Script version (%f) must be %f\n", ver, SHADER_VERSION);
return NULL;
}
break;
case eShader:
buf = new char[strlen(name)+1];
strcpy(buf, name);
if (sEfNames[num])
delete [] sEfNames[num];
sEfNames[num++] = buf;
break;
}
}
sEfNames[num] = NULL;
return &sEfNames[0];
}
static SRefEfs *sFE;
void CShader::mfScanScript (char *scr, int n)
{
char* name;
long cmd;
char *params;
float ver = 0;
char *s = scr;
enum {eShader=1, eVersion, eSubrScript};
static tokenDesc commands[] =
{
{eShader, "Shader"},
{eVersion, "Version"},
{eSubrScript, "SubrScript"},
{0,0}
};
while ((cmd = shGetObject (&scr, commands, &name, &params)) >= 0)
{
switch (cmd)
{
case eVersion:
ver = shGetFloat(params);
if (ver != SHADER_VERSION)
{
Warning( 0,0,"Warning: Shader Script version (%f) must be %f\n", ver, SHADER_VERSION);
return;
}
break;
case eShader:
{
SRefEfs *fe;
char nameEf[256];
//StripExtension(name, nameEf);
strcpy(nameEf, name);
ConvertDOSToUnixName(nameEf, nameEf);
strlwr(nameEf);
ShaderFilesMapItor it = m_RefEfs[m_CurEfsNum]->find(nameEf);
if (it == m_RefEfs[m_CurEfsNum]->end())
fe = NULL;
else
fe = it->second;
if (fe)
{
Warning( 0,0,"Warning: Shader '%s' is duplicated\n", nameEf);
break;
}
fe = new SRefEfs;
fe->m_Ind = n;
fe->m_Offset = params - s;
fe->m_Size = strlen(params);
m_RefEfs[m_CurEfsNum]->insert(ShaderFilesMapItor::value_type(nameEf, fe));
}
break;
}
}
}
char *CShader::mfPreprCheckIncludes (char *buf, const char *drn, const char *name)
{
if (!strchr(buf, '#'))
return buf;
TArray <char> nBuf;
int len = strlen(buf)+1;
char tdrn[512];
strcpy(tdrn, drn);
int nPos = 0;
nBuf.Create(len);
memcpy(&nBuf[0], buf, len);
bool bFind = false;
int nIncl;
while (true)
{
char *pos = strchr(&nBuf[nPos], '#');
if (!pos)
break;
nIncl = pos - &nBuf[0];
if (strncmp(&pos[1], "include", 7))
{
nPos += pos - &nBuf[nPos] + 1;
continue;
}
nPos += pos - &nBuf[nPos] + 1 + 7;
while (nBuf[nPos] != '"')
{
if (nBuf[nPos] == 0 || nBuf[nPos] == 0xa)
{
Warning( 0,0,"Warning: Missing include name for shader file '%s'\n", name);
break;
}
nPos++;
}
char ni[512];
nPos++;
int nPrevPos = nPos;
bool bRes = true;
int n = strlen(tdrn);
strcpy(ni, tdrn);
while (nBuf[nPos] != '"')
{
if (nBuf[nPos] == 0 || nBuf[nPos] == 0xa || n == 128)
{
Warning( 0,0,"Warning: Missing or invalid include name for shader file '%s'\n", name);
bRes = false;
break;
}
ni[n] = nBuf[nPos];
n++;
nPos++;
}
if (!bRes)
{
nPos = nPrevPos;
continue;
}
ni[n] = 0;
nPos++;
FILE *fp = iSystem->GetIPak()->FOpen(ni, "rb");
if (!fp)
{
Warning( 0,0,"Warning: Missing include file '%s' for shader file '%s'\n", ni, name);
continue;
}
char drv[16], dirn[512], drnn[512];
_splitpath(ni, drv, dirn, NULL, NULL);
strcpy(drnn, drv);
strcat(drnn, dirn);
bFind = true;
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int li = iSystem->GetIPak()->FTell(fp);
int nPrev = nBuf.Num();
iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET);
char *pbuf = new char [li+1];
li = iSystem->GetIPak()->FRead(pbuf, 1, li, fp);
iSystem->GetIPak()->FClose(fp);
pbuf[li] = 0;
RemoveCR(pbuf);
char *npbuf = RemoveComments(pbuf);
assert(npbuf == pbuf);
npbuf = mfPreprCheckIncludes(pbuf, drnn, name);
if (pbuf != npbuf)
{
pbuf = npbuf;
li = strlen(pbuf);
}
nBuf.AddIndex(li-(nPos-nIncl));
memmove(&nBuf[nIncl+li], &nBuf[nPos], nPrev-nPos);
memcpy(&nBuf[nIncl], pbuf, li);
delete [] pbuf;
nPos = nIncl + li;
}
if (!bFind)
return buf;
char *b = new char [nBuf.Num()];
memcpy(b, &nBuf[0], nBuf.Num());
delete buf;
return b;
}
int CShader::mfRemoveScript_ifdef(char *posStart, char *posEnd, bool bRemoveAll, int nPos, char *buf, const char *fileName)
{
int nLevel = 0;
int nNewPos = -1;
while (true)
{
char *posS = strchr(&buf[nPos], '#');
if (!posS)
{
char dir[256];
strncpy(dir, posStart, posEnd-posStart+1);
dir[posEnd-posStart+1] = 0;
Warning( 0,0,"Couldn't find #endif directive for associated #ifdef %s for shader file %s", dir, fileName);
break;
}
if (posS[1]=='i' && posS[2]=='f')
{
nLevel++;
if (nNewPos < 0)
nNewPos = nPos;
nPos += posS - &buf[nPos] + 1;
continue;
}
if (!strncmp(&posS[1], "endif", 5))
{
if (!nLevel)
{
if (bRemoveAll)
{
char *b = posEnd;
while (b != posS)
{
if (*b != 0xa)
*b = 0x20;
b++;
}
}
memset(posS, 0x20202020, 6);
memset(posStart, 0x20202020, posEnd-posStart);
nPos += posS - &buf[nPos] + 1 + 6;
break;
}
nLevel--;
nPos += posS - &buf[nPos] + 1;
continue;
}
nPos += posS - &buf[nPos] + 1;
}
if (nNewPos > 0)
{
assert(nNewPos < nPos);
char ch = buf[nPos];
buf[nPos] = 0;
mfPreprCheckConditions(&buf[nNewPos], fileName);
buf[nPos] = ch;
}
return nPos;
}
char *CShader::mfPreprCheckConditions(char *buf, const char *nameFile)
{
if (!strchr(buf, '#'))
return buf;
int nPos = 0;
bool bAccept = false;
char *VP = gRenDev->GetVertexProfile(false);
char *PP = gRenDev->GetPixelProfile(false);
char *VPSup = gRenDev->GetVertexProfile(true);
char *PPSup = gRenDev->GetPixelProfile(true);
int nGPU = gRenDev->GetFeatures() & RFT_HW_MASK;
while (true)
{
char *posStart = strchr(&buf[nPos], '#');
if (!posStart)
break;
if (strncmp(&posStart[1], "ifdef", 5))
{
nPos += posStart - &buf[nPos] + 1;
continue;
}
nPos += posStart - &buf[nPos] + 1 + 5;
while (buf[nPos] == 0x20 || buf[nPos] == 0x9)
{
nPos++;
}
if (buf[nPos] == 0x20 || buf[nPos] == 0xa || buf[nPos] == 0)
{
Warning( 0,0,"Warning: Missing ifdef parameter for shader file '%s'\n", nameFile);
break;
}
char ni[512];
int n = 0;
ni[0] = 0;
while (buf[nPos] != 0x20 && buf[nPos] != 0xa && buf[nPos] != 0 && buf[nPos] != 0x9)
{
ni[n] = buf[nPos];
n++;
nPos++;
}
char *posEnd = &buf[nPos];
ni[n] = 0;
if (!stricmp(ni, "OTHER"))
{
if (bAccept)
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
else
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = false;
}
else
if (!strnicmp(ni, "PROFILE_VS", 10))
{
if (!stricmp(ni, VP))
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!strnicmp(ni, "PROFILE_PS", 10))
{
if (!stricmp(ni, PP))
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!strnicmp(ni, "SUPPORT_PROFILE_VS", 18))
{
if (!stricmp(&ni[8], VPSup))
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!strnicmp(ni, "SUPPORT_PROFILE_PS", 18))
{
if (!stricmp(&ni[8], PPSup))
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "DIRECT3D") || !stricmp(ni, "D3D"))
{
#if defined (DIRECT3D8) || defined (DIRECT3D9) || defined (XBOX)
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
#else
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
#endif
}
else
if (!stricmp(ni, "DIRECT3D8") || !stricmp(ni, "D3D8"))
{
#if defined (DIRECT3D8)
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
#else
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
#endif
}
else
if (!stricmp(ni, "DIRECT3D9") || !stricmp(ni, "D3D9"))
{
#if defined (DIRECT3D9)
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
#else
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
#endif
}
else
if (!stricmp(ni, "XBOX"))
{
#if defined (XBOX)
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
#else
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
#endif
}
else
if (!stricmp(ni, "OPENGL"))
{
#if defined (OPENGL)
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
#else
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
#endif
}
else
if (!stricmp(ni, "GAMECUBE") || !stricmp(ni, "GC"))
{
#if defined (GC)
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
#else
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
#endif
}
else
if (!stricmp(ni, "PS2"))
{
#if defined (PS2)
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
#else
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
#endif
}
else
if (!strnicmp(ni, "DEPTHMAP", 8))
{
if (gRenDev->GetFeatures() & RFT_DEPTHMAPS)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!strnicmp(ni, "SELFSHADOW", 10))
{
if (gRenDev->GetFeatures() & RFT_SHADOWMAP_SELFSHADOW)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "PROJECTEDENVBUMP"))
{
if (gRenDev->GetFeatures() & RFT_HW_ENVBUMPPROJECTED)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "NV1X") || !stricmp(ni, "NV10") || !stricmp(ni, "NV17") || !stricmp(ni, "GF2"))
{
if (nGPU == RFT_HW_GF2)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "NV2X") || !stricmp(ni, "NV20") || !stricmp(ni, "NV25") || !stricmp(ni, "GF3"))
{
if (nGPU == RFT_HW_GF3)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "NV3X") || !stricmp(ni, "NV30") || !stricmp(ni, "NV35") || !stricmp(ni, "GEFORCEFX"))
{
if (nGPU == RFT_HW_GFFX)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "NV4X") || !stricmp(ni, "NV40") || !stricmp(ni, "NV45"))
{
if (nGPU == RFT_HW_NV4X)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "R250") || !strnicmp(ni, "RADEON", 6))
{
if (nGPU == RFT_HW_RADEON)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "R300"))
{
if (nGPU == RFT_HW_RADEON)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "HDR"))
{
if (gRenDev->GetFeatures() & RFT_HW_HDR)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "HDR_FP16"))
{
if ((gRenDev->GetFeatures() & RFT_HW_HDR) && gRenDev->m_nHDRType == 1)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "PS30"))
{
if (gRenDev->m_nEnabled_PS30)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
else
if (!stricmp(ni, "PS2X"))
{
if (gRenDev->m_nEnabled_PS2X)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
if (!stricmp(ni, "PS30|PS2X"))
{
if (gRenDev->m_nEnabled_PS30 || gRenDev->m_nEnabled_PS2X)
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, false, nPos, buf, nameFile);
bAccept = true;
}
else
{
nPos = mfRemoveScript_ifdef(posStart, posEnd, true, nPos, buf, nameFile);
bAccept = false;
}
}
}
return buf;
}
char *CShader::mfPreprCheckMacros(char *buf, const char *nameFile)
{
/*FILE *fp = iSystem->GetIPak()->FOpen("test.txt", "r");
if (fp)
{
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int len = iSystem->GetIPak()->FTell(fp);
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;
}*/
if (!strchr(buf, '#'))
return buf;
TArray <char> nBuf;
int len = strlen(buf)+1;
TArray<char> macro;
nBuf.Create(len);
memcpy(&nBuf[0], buf, len);
bool bFind = false;
int nPos = 0;
int nIFDepth = 0;
while (true)
{
if (nBuf[nPos] == 0)
break;
char word[1024];
int nw = 0;
word[0] = 0;
while (nBuf[nPos] == 0x20 || nBuf[nPos] == 9 || nBuf[nPos] == 0xa || nBuf[nPos] == ',' || nBuf[nPos] == ';') { nPos++; }
int nPrevPos = nPos;
while (nBuf[nPos] != 0x20 && nBuf[nPos] != 9 && nBuf[nPos] != 0xa && nBuf[nPos] != ',' && nBuf[nPos] != ';' && nBuf[nPos] != 0)
{
word[nw++] = nBuf[nPos++];
}
word[nw] = 0;
if (word[0])
{
if (word[0] == '#')
{
if (!strcmp(&word[1], "if") || !strcmp(&word[1], "elif"))
{
if (word[1] == 'i')
{
bFind = true;
nIFDepth++;
}
else
{
if (!nIFDepth)
Warning( 0,0,"#elif without #if in shader file %s", nameFile);
}
int nStartIF = nPrevPos;
while (nBuf[nPos] == 0x20 || nBuf[nPos] == 9) { nPos++; }
int nLog = 0;
int nStartIFExp = nPos;
bool bCond[32];
byte bLogic[32];
while (true)
{
nw = 0;
while (nBuf[nPos] != 0x20 && nBuf[nPos] != 9 && nBuf[nPos] != 0xa && nBuf[nPos] != ',' && nBuf[nPos] != ';' && nBuf[nPos] != 0)
{
word[nw++] = nBuf[nPos++];
}
word[nw] = 0;
bool bNegative = false;
int n = 0;
if (word[0] == '!')
{
n = 1;
bNegative = true;
}
ShaderMacroItor it = m_Macros.find(&word[n]);
if (it != m_Macros.end())
bCond[nLog] = bNegative ? false : true;
else
bCond[nLog] = bNegative ? true : false;
while (nBuf[nPos] == 0x20 || nBuf[nPos] == 9) { nPos++; }
nLog++;
if (nBuf[nPos] != 0xa)
{
bLogic[nLog] = 0;
if (nBuf[nPos] == '|' && nBuf[nPos+1] == '|')
bLogic[nLog] = 1;
else
if (nBuf[nPos] == '&' && nBuf[nPos+1] == '&')
bLogic[nLog] = 2;
if (bLogic[nLog])
{
nPos += 2;
while (nBuf[nPos] == 0x20 || nBuf[nPos] == 9) { nPos++; }
}
}
if (nBuf[nPos] == 0xa)
break;
}
int nEndIFExp = nPos;
bool bResultCond = false;
for (int i=0; i<nLog; i++)
{
if (!i)
bResultCond = bCond[i];
else
if (bLogic[i] == 1)
bResultCond = bResultCond | bCond[i];
else
if (bLogic[i] == 2)
bResultCond = bResultCond & bCond[i];
}
char *posStart = NULL;
int nNewPos = nPos;
int nLevel = 0;
if (bResultCond)
{
while (true)
{
char *posS = strchr(&nBuf[nPos], '#');
if (!posS)
{
char dir[256];
strncpy(dir, &nBuf[nStartIFExp], nEndIFExp-nStartIFExp+1);
dir[nEndIFExp-nStartIFExp+1] = 0;
Warning( 0,0,"Couldn't find #endif directive for associated #if %s for shader file %s", dir, nameFile);
break;
}
if (posS[1]=='i' && posS[2]=='f' && (posS[3]==0x20 || posS[3]==9))
{
nLevel++;
nPos += posS - &nBuf[nPos] + 1 + 3;
continue;
}
if (!strncmp(&posS[1], "elif", 4) || !strncmp(&posS[1], "else", 4))
{
if (!nLevel && !posStart)
posStart = posS;
nPos += posS - &nBuf[nPos] + 1 + 5;
continue;
}
if (!strncmp(&posS[1], "endif", 5))
{
if (!nLevel)
{
memset(&nBuf[nStartIF], 0x20202020, nEndIFExp-nStartIF);
if (posStart)
memset(posStart, 0x20202020, posS-posStart);
else
memset(posS, 0x20202020, 6);
nPos += posS - &nBuf[nPos] + 1 + 6;
break;
}
nLevel--;
nPos += posS - &nBuf[nPos] + 1;
continue;
}
nPos += posS - &nBuf[nPos] + 1;
}
}
else
{
posStart = &nBuf[nStartIF];
while (true)
{
char *posS = strchr(&nBuf[nPos], '#');
if (!posS)
{
char dir[256];
strncpy(dir, &nBuf[nStartIFExp], nEndIFExp-nStartIFExp+1);
dir[nEndIFExp-nStartIFExp+1] = 0;
Warning( 0,0,"Couldn't find #endif directive for associated #if %s for shader file %s", dir, nameFile);
break;
}
if (posS[1]=='i' && posS[2]=='f' && (posS[3]==0x20 || posS[3]==9))
{
nLevel++;
nPos += posS - &nBuf[nPos] + 1 + 3;
continue;
}
if (!strncmp(&posS[1], "elif", 4) || !strncmp(&posS[1], "else", 4))
{
if (!nLevel)
{
nNewPos = posS - &nBuf[0];
memset(&nBuf[nStartIF], 0x20202020, nEndIFExp-nStartIF);
memset(posStart, 0x20202020, posS-posStart);
break;
}
nPos += posS - &nBuf[nPos] + 1 + 5;
continue;
}
if (!strncmp(&posS[1], "endif", 5))
{
if (!nLevel)
{
memset(&nBuf[nStartIF], 0x20202020, nEndIFExp-nStartIF);
memset(posStart, 0x20202020, posS-posStart);
memset(posS, 0x20202020, 6);
nPos += posS - &nBuf[nPos] + 1 + 6;
break;
}
nLevel--;
nPos += posS - &nBuf[nPos] + 1;
continue;
}
nPos += posS - &nBuf[nPos] + 1;
}
}
nPos = nNewPos;
continue;
}
else
if (!strcmp(word, "#else"))
{
if (!nIFDepth)
Warning( 0,0,"#else without #if in shader file %s", nameFile);
memset(&nBuf[nPrevPos], 0x20202020, nPos-nPrevPos);
continue;
}
else
if (!strcmp(word, "#endif"))
{
if (!nIFDepth)
Warning( 0,0,"#endif without #if in shader file %s", nameFile);
else
nIFDepth--;
memset(&nBuf[nPrevPos], 0x20202020, nPos-nPrevPos);
continue;
}
else
if (!strcmp(word, "#define"))
{
bFind = true;
nw = 0;
word[0] = 0;
macro.SetUse(0);
while (nBuf[nPos] == 0x20 || nBuf[nPos] == 9) { nPos++; }
while (nBuf[nPos] != 0x20 && nBuf[nPos] != 9 && nBuf[nPos] != 0xa && nBuf[nPos] != 0)
{
word[nw++] = nBuf[nPos++];
}
word[nw] = 0;
/*if (word[0] == '%')
{
int nnn = 0;
}*/
if (!word[0])
{
memset(&nBuf[nPrevPos], 0x20202020, nPos-nPrevPos);
continue;
}
while (nBuf[nPos] == 0x20 || nBuf[nPos] == 9) { nPos++; }
bool bAllowCR = false;
int bWasCR = 0;
while (nBuf[nPos] != 0)
{
if (nBuf[nPos] == 0xa)
{
if (!bAllowCR)
break;
if (nBuf[nPos] == 0xa)
bWasCR |= 1;
if (bWasCR == 1)
{
bAllowCR = false;
bWasCR = 0;
}
}
else
if (nBuf[nPos] == '\\')
{
bAllowCR = true;
nPos++;
continue;
}
else
if (bWasCR)
{
bAllowCR = false;
bWasCR = 0;
}
macro.AddElem(nBuf[nPos]);
nPos++;
}
if (!macro.Num())
macro.AddElem(' ');
macro.AddElem(0);
m_Macros.insert(ShaderMacroItor::value_type(word, &macro[0]));
memset(&nBuf[nPrevPos], 0x20202020, nPos-nPrevPos);
continue;
}
else
if (!strcmp(word, "#undefine"))
{
bFind = true;
nw = 0;
while (nBuf[nPos] == 0x20 || nBuf[nPos] == 9) { nPos++; }
while (nBuf[nPos] != 0x20 && nBuf[nPos] != 9 && nBuf[nPos] != 0xa && nBuf[nPos] != 0)
{
word[nw++] = nBuf[nPos++];
word[nw] = 0;
}
ShaderMacroItor it = m_Macros.find(word);
if (it == m_Macros.end())
Warning( 0,0,"Warning: Couldn't find macro '%s' in file '%s'\n", word, nameFile);
nBuf.Remove(nPrevPos, nPos-nPrevPos);
nPos = nPrevPos;
if (!word[0])
continue;
m_Macros.erase(word);
continue;
}
else
if (!strcmp(word, "#warning"))
{
nw = 0;
while (nBuf[nPos] == 0x20 || nBuf[nPos] == 9) { nPos++; }
while (nBuf[nPos] != 0xa && nBuf[nPos] != 0)
{
word[nw++] = nBuf[nPos++];
}
word[nw] = 0;
while (nPrevPos != nPos)
{
nBuf[nPrevPos++] = 0x20;
}
Warning( 0,0,"Warning: <SHADER>: '%s' (in %s)", word, nameFile);
continue;
}
}
if (!stricmp(word, "CGVProgram") || !stricmp(word, "CGPShader"))
{
SLocalMacros LM;
LM.m_nOffset = nPrevPos;
//char *pTmp = strstr(&nBuf[0], "CGVProgram");
//int nTmp = pTmp-&nBuf[0];
LM.m_Macros = new ShaderMacro;
*LM.m_Macros = m_Macros;
m_LocalMacros.AddElem(LM);
}
ShaderMacroItor it = m_Macros.find(word);
if (it != m_Macros.end())
{
bFind = true;
nBuf.Remove(nPrevPos, nPos-nPrevPos);
const char *macro = it->second.c_str();
int len = strlen(macro);
nBuf.AddIndex(len);
memmove(&nBuf[nPrevPos+len], &nBuf[nPrevPos], nBuf.Num()-nPrevPos-len);
memcpy(&nBuf[nPrevPos], macro, len);
nPos = nPrevPos;
}
}
}
if (!bFind)
return buf;
/*fp = fopen("test1.txt", "w");
if (fp)
{
fprintf(fp, &nBuf[0]);
fclose(fp);
}*/
//char *pTmp = strstr(&nBuf[0], "CGVProgram");
//int nTmp = pTmp-&nBuf[0];
char *b = new char [nBuf.Num()];
memcpy(b, &nBuf[0], nBuf.Num());
delete buf;
return b;
}
void CShader::mfStartScriptPreprocess()
{
m_Macros.clear();
for (int i=0; i<m_LocalMacros.Num(); i++)
{
delete m_LocalMacros[i].m_Macros;
}
m_LocalMacros.Free();
}
uint64 CShader::mfScriptPreprocessorMask(SShader *pSH, int nOffset)
{
uint64 nMask = 0;
int i;
for (i=0; i<m_LocalMacros.Num(); i++)
{
if (m_LocalMacros[i].m_nOffset == nOffset)
break;
}
if (i == m_LocalMacros.Num())
{
iLog->Log("Warning: couldn't find Local macros state for offset %d in shader '%s'", pSH->GetName());
return nMask;
}
m_Macros = *m_LocalMacros[i].m_Macros;
ShaderMacroItor itor=m_LocalMacros[i].m_Macros->begin();
while(itor!=m_LocalMacros[i].m_Macros->end())
{
if (itor->first[0] == '%')
{
const char *val = itor->second.c_str();
int len = strlen(val);
uint64 n;
if (len > 2 && val[0] == '0' && val[1] == 'x')
sscanf(&val[2], "%I64x", &n);
else
n = atoi(val);
if (!n)
iLog->Log("Warning: zero mask for parameter macro '%s' in shader '%s'", itor->first.c_str(), pSH->GetName());
if (n & nMask)
{
iLog->Log("Warning: mask 0x%I64x already exist for parameter macro in shader '%s'", n, itor->first.c_str(), pSH->GetName());
ShaderMacroItor itor=m_LocalMacros[i].m_Macros->begin();
while(itor!=m_LocalMacros[i].m_Macros->end())
{
if (itor->first[0] == '%')
{
const char *val = itor->second.c_str();
int len = strlen(val);
uint64 nn;
if (len > 2 && val[0] == '0' && val[1] == 'x')
sscanf(&val[2], "%I64x", &nn);
else
nn = atoi(val);
if (nn & n)
iLog->Log("Parameter: %s", itor->first.c_str());
}
itor++;
}
}
nMask |= n;
}
itor++;
}
return nMask;
}
char *CShader::mfScriptPreprocessor (char *buf, const char *drn, const char *name)
{
RemoveCR(buf);
buf = RemoveComments(buf);
buf = mfPreprCheckIncludes(buf, drn, name);
buf = mfPreprCheckConditions(buf, name);
buf = mfPreprCheckMacros(buf, name);
/*FILE *fp = fopen(name, "w");
if (fp)
{
fprintf(fp, buf);
fclose(fp);
}*/
#ifndef _XBOX
if (CRenderer::CV_r_shaderssave > 2)
{
char nn[256];
StripExtension(name, nn);
AddExtension(nn, ".csf");
FILE *fp = fopen(nn, "w");
if (fp)
{
fprintf(fp, buf);
fclose(fp);
}
}
#endif
return buf;
}
char *CShader::mfScriptForFileName(const char *name, SShader *shGen, uint64 nMaskGen)
{
FILE *fp = iSystem->GetIPak()->FOpen(name, "rb");
if (!fp)
return NULL;
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int len = iSystem->GetIPak()->FTell(fp);
if (!len)
{
iSystem->GetIPak()->FClose(fp);
return NULL;
}
TArray<char> custMacros;
if (shGen && shGen->m_ShaderGenParams)
{
int i;
//assert(nMaskGen);
SShaderGen *shG = shGen->m_ShaderGenParams;
assert(shG);
for (i=0; i<shG->m_BitMask.Num(); i++)
{
if (shG->m_BitMask[i]->m_Mask & nMaskGen)
{
char macro[256];
sprintf(macro, "#define %s 0x%I64x\n", shG->m_BitMask[i]->m_ParamName.c_str(), shG->m_BitMask[i]->m_Mask);
int size = strlen(macro);
int nOffs = custMacros.Num();
custMacros.Grow(size);
memcpy(&custMacros[nOffs], macro, size);
}
}
}
int size = custMacros.Num();
char *buf = new char [len+size+1];
if (!buf)
{
iSystem->GetIPak()->FClose(fp);
Warning( 0,0,"Error: Can't allocate %d bytes for shader file '%s'\n", len+1, name);
return NULL;
}
memcpy(buf, &custMacros[0], custMacros.Num());
iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET);
len = iSystem->GetIPak()->FRead(&buf[size], 1, len, fp);
iSystem->GetIPak()->FClose(fp);
buf[len+size] = 0;
char nmf[256], drn[256], drv[16], dirn[256], fln[256], extn[16];
_splitpath(name, drv, dirn, fln, extn);
strcpy(drn, drv);
strcat(drn, dirn);
strcpy(nmf, fln);
strcat(nmf, extn);
mfStartScriptPreprocess();
char *pFinalScript = mfScriptPreprocessor(buf, drn, nmf);
return pFinalScript;
}
int CShader::mfLoadSubdir (char *drn, int n)
{
struct _finddata_t fileinfo;
intptr_t handle;
int len;
char nmf[256];
char dirn[256], *ddir;
if (n == MAX_EF_FILES)
return n;
ddir = dirn;
strcpy(dirn, drn);
strcat(dirn, "*.*");
ConvertUnixToDosName(dirn, dirn);
/*{
handle = iSystem->GetIPak()->FindFirst ("Shaders\\HWScripts\\Declarations\\CGVShaders\\*.crycg", &fileinfo);
if (handle == -1)
{
assert(0);
}
do
{
if (fileinfo.name[0] == '.')
continue;
if (fileinfo.attrib & _A_SUBDIR)
continue;
strcpy(nmf, "Shaders\\HWScripts\\Declarations\\CGVShaders\\");
strcat(nmf, fileinfo.name);
FILE *fp = iSystem->GetIPak()->FOpen(nmf, "r");
if (!fp)
continue;
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int ln = iSystem->GetIPak()->FTell(fp);
if (!ln)
{
iSystem->GetIPak()->FClose(fp);
continue;
}
char *buf = new char [ln+1];
if (!buf)
{
iSystem->GetIPak()->FClose(fp);
}
iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET);
ln = iSystem->GetIPak()->FRead(buf, 1, ln, fp);
iSystem->GetIPak()->FClose(fp);
buf[ln] = 0;
TArray <char> aStr1;
TArray <char> aStr2;
char *buf1 = strstr(buf, "IN_");
char *buff1 = buf1;
if (buf1)
{
int nSpac = 0;
char *b = buf1-1;
while (*b == 0x20 || *b == 9)
{
nSpac++;
b--;
}
b++;
char str[256];
strcpy(str, "struct appin\n");
aStr1.Copy(str, strlen(str));
memcpy(str, b, nSpac);
strcpy(&str[nSpac], "{\n");
aStr1.Copy(str, strlen(str));
strcpy(&str[nSpac], " IN_P\n");
aStr1.Copy(str, strlen(str));
nSpac += 2;
buf1 += 3;
char s[64];
s[0] = 0;
int n = 0;
bool bFlush = true;
while (true)
{
if (buf1[0] == '_' || buf1[0] == '\n' || buf1[0] == 0xd || buf1[0] == 0x20 || buf1[0] == 9)
{
s[n] = 0;
bool bValid = true;
if (!strcmp(s, "C0"))
strcpy(&str[nSpac], "IN_C0\n");
else
if (!strcmp(s, "C1"))
strcpy(&str[nSpac], "IN_C1\n");
else
if (!strcmp(s, "N"))
strcpy(&str[nSpac], "IN_N\n");
else
if (!strcmp(s, "TN"))
strcpy(&str[nSpac], "IN_TN\n");
else
if (!strcmp(s, "T0"))
strcpy(&str[nSpac], "IN_T0\n");
else
if (!strcmp(s, "T1"))
strcpy(&str[nSpac], "IN_T1\n");
else
if (!strcmp(s, "T2"))
strcpy(&str[nSpac], "IN_T2\n");
else
if (!strcmp(s, "T3"))
strcpy(&str[nSpac], "IN_T3\n");
else
if (!strcmp(s, "T4"))
strcpy(&str[nSpac], "IN_T4\n");
else
if (!strcmp(s, "TANG"))
strcpy(&str[nSpac], "IN_TANG\n");
else
if (!strcmp(s, "P") || !strcmp(s, "TNORMVEC"))
bValid = false;
else
if (!strcmp(s, "TANGVECS") || !strcmp(s, "TNORMVEC"))
{
bFlush = false;
break;
}
else
{
assert(0);
bValid = 0;
}
if (bValid)
aStr1.Copy(str, strlen(str));
if (buf1[0] == '\n' || buf1[0] == 0xd || buf1[0] == 0x20 || buf1[0] == 9)
{
strcpy(&str[nSpac-2], "};\n");
aStr1.Copy(str, strlen(str));
break;
}
buf1++;
n = 0;
}
s[n++] = *buf1;
buf1++;
}
if (!bFlush)
continue;
}
char *buf2 = strstr(buf, "OUT_");
char *buff2 = buf2;
if (buf2)
{
int nSpac = 0;
char *b = buf2-1;
while (*b == 0x20 || *b == 9)
{
nSpac++;
b--;
}
b++;
char str[256];
memcpy(str, b, nSpac);
strcpy(&str[nSpac], "struct vertout\n");
aStr2.Copy(str, strlen(str));
strcpy(&str[nSpac], "{\n");
aStr2.Copy(str, strlen(str));
strcpy(&str[nSpac], " OUT_P\n");
aStr2.Copy(str, strlen(str));
nSpac += 2;
buf2 += 4;
char s[64];
s[0] = 0;
int n = 0;
while (true)
{
if (buf2[0] == '_' || buf2[0] == '\n' || buf2[0] == 0xd || buf2[0] == 0x20 || buf2[0] == 9)
{
s[n] = 0;
bool bValid = true;
if (!strcmp(s, "C0"))
strcpy(&str[nSpac], "OUT_C0\n");
else
if (!strcmp(s, "C1"))
strcpy(&str[nSpac], "OUT_C1\n");
else
if (!strcmp(s, "T0"))
strcpy(&str[nSpac], "OUT_T0\n");
else
if (!strcmp(s, "T02"))
strcpy(&str[nSpac], "OUT_T0_2\n");
else
if (!strcmp(s, "T1"))
strcpy(&str[nSpac], "OUT_T1\n");
else
if (!strcmp(s, "T12"))
strcpy(&str[nSpac], "OUT_T1_2\n");
else
if (!strcmp(s, "T2"))
strcpy(&str[nSpac], "OUT_T2\n");
else
if (!strcmp(s, "T22"))
strcpy(&str[nSpac], "OUT_T2_2\n");
else
if (!strcmp(s, "T3"))
strcpy(&str[nSpac], "OUT_T3\n");
else
if (!strcmp(s, "T32"))
strcpy(&str[nSpac], "OUT_T3_2\n");
else
if (!strcmp(s, "T4"))
strcpy(&str[nSpac], "OUT_T4\n");
else
if (!strcmp(s, "T5"))
strcpy(&str[nSpac], "OUT_T5\n");
else
if (!strcmp(s, "T6"))
strcpy(&str[nSpac], "OUT_T6\n");
else
if (!strcmp(s, "T7"))
strcpy(&str[nSpac], "OUT_T7\n");
else
if (!strcmp(s, "P"))
bValid = false;
else
{
assert(0);
bValid = 0;
}
if (bValid)
aStr2.Copy(str, strlen(str));
if (buf2[0] == '\n' || buf2[0] == 0xd || buf2[0] == 0x20 || buf2[0] == 9)
{
strcpy(&str[nSpac-2], "};\n");
aStr2.Copy(str, strlen(str));
break;
}
buf2++;
n = 0;
}
s[n++] = *buf2;
buf2++;
}
}
if (!buf1 || !buf2)
continue;
char *bufNew = new char[strlen(buf)+aStr1.Num()+aStr2.Num()];
memcpy(bufNew, buf, buff1-buf);
if (aStr1.Num())
memcpy(&bufNew[buff1-buf], &aStr1[0], aStr1.Num());
if (aStr2.Num())
memcpy(&bufNew[buff1-buf+aStr1.Num()], &aStr2[0], aStr2.Num());
strcpy(&bufNew[buff1-buf+aStr1.Num()+aStr2.Num()], buf2);
fp = iSystem->GetIPak()->FOpen(nmf, "w");
iSystem->GetIPak()->FWrite(bufNew, 1, strlen(bufNew), fp);
iSystem->GetIPak()->FClose(fp);
delete [] bufNew;
} while (iSystem->GetIPak()->FindNext( handle, &fileinfo ) != -1);
iSystem->GetIPak()->FindClose (handle);
}*/
/*{
handle = iSystem->GetIPak()->FindFirst ("Shaders\\HWScripts\\Declarations\\CGPShaders\\*.crycg", &fileinfo);
if (handle == -1)
{
assert(0);
}
do
{
if (fileinfo.name[0] == '.')
continue;
if (fileinfo.attrib & _A_SUBDIR)
continue;
strcpy(nmf, "Shaders\\HWScripts\\Declarations\\CGPShaders\\");
strcat(nmf, fileinfo.name);
FILE *fp = iSystem->GetIPak()->FOpen(nmf, "r");
if (!fp)
continue;
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int ln = iSystem->GetIPak()->FTell(fp);
if (!ln)
{
iSystem->GetIPak()->FClose(fp);
continue;
}
char *buf = new char [ln+1];
if (!buf)
{
iSystem->GetIPak()->FClose(fp);
}
iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET);
ln = iSystem->GetIPak()->FRead(buf, 1, ln, fp);
iSystem->GetIPak()->FClose(fp);
buf[ln] = 0;
TArray <char> aStr2;
char *buf2 = strstr(buf, "OUT_");
char *buff2 = buf2;
if (buf2)
{
int nSpac = 0;
char *b = buf2-1;
while (*b == 0x20 || *b == 9)
{
nSpac++;
b--;
}
b++;
char str[256];
strcpy(str, "struct vertout\n");
aStr2.Copy(str, strlen(str));
memcpy(str, b, nSpac);
strcpy(&str[nSpac], "{\n");
aStr2.Copy(str, strlen(str));
strcpy(&str[nSpac], " ");
nSpac += 2;
buf2 += 4;
char s[64];
s[0] = 0;
int n = 0;
while (true)
{
if (buf2[0] == '_' || buf2[0] == '\n' || buf2[0] == 0xd || buf2[0] == 0x20 || buf2[0] == 9)
{
s[n] = 0;
bool bValid = true;
if (!strcmp(s, "C0"))
strcpy(&str[nSpac], "OUT_C0\n");
else
if (!strcmp(s, "C1"))
strcpy(&str[nSpac], "OUT_C1\n");
else
if (!strcmp(s, "T0"))
strcpy(&str[nSpac], "OUT_T0\n");
else
if (!strcmp(s, "T02"))
strcpy(&str[nSpac], "OUT_T0_2\n");
else
if (!strcmp(s, "T1"))
strcpy(&str[nSpac], "OUT_T1\n");
else
if (!strcmp(s, "T12"))
strcpy(&str[nSpac], "OUT_T1_2\n");
else
if (!strcmp(s, "T2"))
strcpy(&str[nSpac], "OUT_T2\n");
else
if (!strcmp(s, "T22"))
strcpy(&str[nSpac], "OUT_T2_2\n");
else
if (!strcmp(s, "T3"))
strcpy(&str[nSpac], "OUT_T3\n");
else
if (!strcmp(s, "T32"))
strcpy(&str[nSpac], "OUT_T3_2\n");
else
if (!strcmp(s, "T4"))
strcpy(&str[nSpac], "OUT_T4\n");
else
if (!strcmp(s, "T5"))
strcpy(&str[nSpac], "OUT_T5\n");
else
if (!strcmp(s, "T6"))
strcpy(&str[nSpac], "OUT_T6\n");
else
if (!strcmp(s, "T7"))
strcpy(&str[nSpac], "OUT_T7\n");
else
if (!strcmp(s, "P"))
bValid = false;
else
{
assert(0);
bValid = 0;
}
if (bValid)
aStr2.Copy(str, strlen(str));
if (buf2[0] == '\n' || buf2[0] == 0xd || buf2[0] == 0x20 || buf2[0] == 9)
{
strcpy(&str[nSpac-2], "};\n");
aStr2.Copy(str, strlen(str));
break;
}
buf2++;
n = 0;
}
s[n++] = *buf2;
buf2++;
}
}
if (!buf2)
continue;
char *bufNew = new char[strlen(buf)+aStr2.Num()];
memcpy(bufNew, buf, buff2-buf);
if (aStr2.Num())
memcpy(&bufNew[buff2-buf], &aStr2[0], aStr2.Num());
strcpy(&bufNew[buff2-buf+aStr2.Num()], buf2);
fp = iSystem->GetIPak()->FOpen(nmf, "w");
iSystem->GetIPak()->FWrite(bufNew, 1, strlen(bufNew), fp);
iSystem->GetIPak()->FClose(fp);
delete [] bufNew;
} while (iSystem->GetIPak()->FindNext( handle, &fileinfo ) != -1);
iSystem->GetIPak()->FindClose (handle);
}*/
handle = iSystem->GetIPak()->FindFirst (ddir, &fileinfo);
if (handle == -1)
return n;
do
{
if (fileinfo.name[0] == '.')
continue;
if (fileinfo.attrib & _A_SUBDIR)
{
char ddd[256];
sprintf(ddd, "%s%s/", drn, fileinfo.name);
n = mfLoadSubdir(ddd, n);
continue;
}
strcpy(nmf, drn);
strcat(nmf, fileinfo.name);
len = strlen(nmf);
while (len && nmf[len] != '.')
len--;
if (len <= 0)
continue;
if (strnicmp(&nmf[len], ".csl", 4))
continue;
if (nmf[len+4])
{
if (!stricmp(&nmf[len+4], "new"))
{
if (CRenderer::CV_r_usehwshaders!=2)
continue;
}
else
if (!stricmp(&nmf[len+4], "old"))
{
if (CRenderer::CV_r_usehwshaders!=1)
continue;
}
else
continue;
}
char *pFinalScript = mfScriptForFileName(nmf, NULL, 0);
if (!pFinalScript)
continue;
char Er[1024];
sprintf(Er, "File '%s' script error!\n", nmf);
gShObjectNotFound = Er;
mfScanScript(pFinalScript, n);
gShObjectNotFound = NULL;
delete [] pFinalScript;
FILE *status = iSystem->GetIPak()->FOpen(nmf, "rb");
if (status)
{
FILETIME writetime = iSystem->GetIPak()->GetModificationTime(status);
iSystem->GetIPak()->FClose (status);
m_WriteTime[m_CurEfsNum][n] = writetime;
}
m_FileNames[m_CurEfsNum][n] = nmf;
m_nFrameReload[m_CurEfsNum][n] = m_nFrameForceReload;
n++;
if (n == MAX_EF_FILES)
return n;
} while (iSystem->GetIPak()->FindNext( handle, &fileinfo ) != -1);
iSystem->GetIPak()->FindClose (handle);
return n;
}
void CShader::mfLoadFromFiles (int num)
{
int n = 0;
char dir[256];
m_NumFiles[num] = 0;
m_CurEfsNum = num;
UsePath("", m_ShadersPath[num], dir);
ConvertDOSToUnixName(dir, dir);
if (m_RefEfs[num])
{
ShaderFilesMapItor itor=m_RefEfs[num]->begin();
while(itor!=m_RefEfs[num]->end())
{
SAFE_DELETE (itor->second);
itor++;
}
m_RefEfs[num]->clear();
SAFE_DELETE (m_RefEfs[num]);
}
if (num == 1)
strcpy(m_HWPath, dir);
if (!num)
iLog->Log("\n Load all common shader scripts (scanning directory '%s')...\n", dir);
else
if (num == 1)
iLog->Log("\n Load HW-specific shader scripts (scanning directory '%s')...\n", dir);
m_RefEfs[num] = new ShaderFilesMap;
n = mfLoadSubdir(dir, n);
if (!n)
{
Warning( 0,0,"Warning: Shaders couldn't be found in directory '%s'", dir);
m_NumFiles[num] = 0;
return;
}
if (n==MAX_EF_FILES)
{
Warning( 0,0,"Warning: MAX_EF_FILES were hit (truncation list)\n");
m_NumFiles[num] = n;
}
iLog->Log(" %d Shader files found.\n\n", n);
m_NumFiles[num] = n;
if (!m_NumFiles[num])
{
Warning( 0,0,"Warning: No Shaders text loaded!\n");
return;
}
}
char *CShader::mfFindInAllText (char *name, char *&pBuf, SShader *shGen, uint64 nMaskGen)
{
char *saved = NULL;
if (!m_RefEfs[m_CurEfsNum])
return NULL;
SRefEfs *fe;
ShaderFilesMapItor it = m_RefEfs[m_CurEfsNum]->find(name);
if (it == m_RefEfs[m_CurEfsNum]->end())
fe = NULL;
else
fe = it->second;
if (!fe)
return NULL;
if (fe)
{
char *pFinalScript;
if (m_nFrameReload[m_CurEfsNum][fe->m_Ind] != m_nFrameForceReload)
{
m_nFrameReload[m_CurEfsNum][fe->m_Ind] = m_nFrameForceReload;
pFinalScript = mfRescanScript(m_CurEfsNum, fe->m_Ind, shGen, nMaskGen);
delete [] pFinalScript;
ShaderFilesMapItor it = m_RefEfs[m_CurEfsNum]->find(name);
if (it == m_RefEfs[m_CurEfsNum]->end())
fe = NULL;
else
fe = it->second;
if (!fe)
return NULL;
}
pFinalScript = mfScriptForFileName(m_FileNames[m_CurEfsNum][fe->m_Ind].c_str(), shGen, nMaskGen);
if (!pFinalScript)
return NULL;
sFE = fe;
pBuf = pFinalScript;
if (!shGen)
{
pFinalScript[fe->m_Offset+fe->m_Size] = 0;
return &pFinalScript[fe->m_Offset];
}
return pFinalScript;
}
return NULL;
}
void CShader::mfRemoveFromHash(SShader *ef)
{
LoadedShadersMapItor it = m_RefEfsLoaded.find(ef->m_Name.c_str());
if (it != m_RefEfsLoaded.end())
{
m_RefEfsLoaded.erase(ef->m_Name.c_str());
}
}
void CShader::mfAddToHash(char *name, SShader *ef)
{
char nameEf[256];
strncpy(nameEf, name, 256);
strlwr(nameEf);
SRefEfsLoaded fe;
fe.m_Ef = ef;
m_RefEfsLoaded.insert(LoadedShadersMapItor::value_type(nameEf, fe));
ef->m_Name = nameEf;
}
void CShader::mfAddToHashLwr(char *nameEf, SShader *ef)
{
SRefEfsLoaded fe;
fe.m_Ef = ef;
m_RefEfsLoaded.insert(LoadedShadersMapItor::value_type(nameEf, fe));
ef->m_Name = nameEf;
}
SShader *CShader::mfSpawn (char *name, SShader *ef, SShader *efGen, uint64 nMaskGen)
{
char Er[1024];
char *BackEr;
char *txt;
int BackCurEfsNum;
char *pScriptBuf;
gShObjectNotFound = NULL;
BackCurEfsNum = m_CurEfsNum;
// First search in HW specific directory
m_CurEfsNum = 1;
txt = mfFindInAllText(name, pScriptBuf, efGen, nMaskGen);
if (!txt)
{
// At last search in Common directory
if (!txt)
{
m_CurEfsNum = 0;
txt = mfFindInAllText(name, pScriptBuf, efGen, nMaskGen);
}
}
if (txt)
{
// compile:
BackEr = gShObjectNotFound;
sprintf(Er, "Shader '%s' script error!\n", name);
gShObjectNotFound = Er;
m_pCurScript = pScriptBuf;
SShader *ef1;
if (efGen)
ef1 = mfCompileShader(ef, txt);
else
ef1 = mfCompile(ef, txt);
if (ef1)
ef1->m_WriteTime = m_WriteTime[m_CurEfsNum][sFE->m_Ind];
else
assert(0);
gShObjectNotFound = BackEr;
delete [] pScriptBuf;
m_CurEfsNum = BackCurEfsNum;
return ef1;
}
m_CurEfsNum = BackCurEfsNum;
if (CRenderer::CV_r_logloadshaders)
Warning( 0,0,"WARNING: Shader '%s' couldn't be found!", name);
return NULL;
}
SShader *CShader::mfForName (const char *nameSh, EShClass Class, int flags, const SInputShaderResources *Res, uint64 nMaskGen)
{
SShader *ef, *efGen, *ef1;
int id;
char name[256];
if (!nameSh || !nameSh[0])
{
Warning( 0,0,"Warning: CShader::mfForName: NULL name\n");
gRenDev->m_cEF.m_DefaultShader->AddRef();
return gRenDev->m_cEF.m_DefaultShader;
}
char nameEf[256];
mfShaderNameForAlias(nameSh, nameEf, 256);
ef = NULL;
efGen = NULL;
//StripExtension(nameEf, name);
strcpy(name, nameEf);
ConvertDOSToUnixName(name, name);
strlwr(name);
// Check if this shader already loaded
SRefEfsLoaded *fe, *feGen;
LoadedShadersMapItor it = m_RefEfsLoaded.find(name);
if (it == m_RefEfsLoaded.end())
fe = NULL;
else
fe = &it->second;
char nameNew[256];
if (fe && fe->m_Ef && fe->m_Ef->m_ShaderGenParams)
{
efGen = fe->m_Ef;
ef = efGen;
feGen = fe;
sprintf(nameNew, "%s(%I64x)", name, nMaskGen);
it = m_RefEfsLoaded.find(nameNew);
if (it == m_RefEfsLoaded.end())
fe = NULL;
else
fe = &it->second;
if (fe)
{
assert(fe->m_Ef->m_nMaskGen == nMaskGen);
assert(fe->m_Ef->m_pGenShader == efGen);
}
}
if (fe && !(flags & SF_RELOAD))
{
fe->m_Ef->AddRef();
fe->m_Ef->m_Flags |= flags;
return fe->m_Ef;
}
if (fe)
{
ef = fe->m_Ef;
ef->mfFree();
}
if (!ef)
{
ef = mfNewShader(Class, -1);
if (!ef)
return m_DefaultShader;
// Add current hash reference
mfAddToHashLwr(name, ef);
}
if (!efGen)
{
sprintf(nameNew, "Shaders\\%s.ext", name);
FILE *fp = iSystem->GetIPak()->FOpen(nameNew, "rb");
if (fp)
{
efGen = ef;
ef->m_ShaderGenParams = new SShaderGen;
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int ln = iSystem->GetIPak()->FTell(fp);
char *buf = new char [ln+1];
if (buf)
{
buf[ln] = 0;
iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET);
iSystem->GetIPak()->FRead(buf, 1, ln, fp);
iSystem->GetIPak()->FClose(fp);
mfCompileShaderGen(ef, ef->m_ShaderGenParams, buf);
}
else
{
efGen = NULL;
iSystem->GetIPak()->FClose(fp);
}
}
}
if (!(flags & SF_RELOAD))
{
if (efGen)
{
sprintf(nameNew, "%s(%I64x)", name, nMaskGen);
ef = mfNewShader(Class, -1);
if (!ef)
return m_DefaultShader;
// Add current hash reference
mfAddToHashLwr(nameNew, ef);
ef->m_nMaskGen = nMaskGen;
ef->m_pGenShader = efGen;
}
if (efGen && ef)
{
assert(efGen != ef);
if (!efGen->m_DerivedShaders)
efGen->m_DerivedShaders = new TArray<SShader *>;
efGen->m_DerivedShaders->AddElem(ef);
}
}
id = ef->m_Id;
#ifndef NULL_RENDERER
// Check for the new cryFX format
#ifdef USE_FX
sprintf(nameNew, "%sCryFX/%s.cryFX", m_ShadersPath[1], name);
FILE *fp = iSystem->GetIPak()->FOpen(nameNew, "rb");
if (fp)
{
iSystem->GetIPak()->FSeek(fp, 0, SEEK_END);
int len = iSystem->GetIPak()->FTell(fp);
TArray<char> custMacros;
if (efGen && efGen->m_ShaderGenParams)
{
int i;
SShaderGen *shG = efGen->m_ShaderGenParams;
for (i=0; i<shG->m_BitMask.Num(); i++)
{
if (shG->m_BitMask[i]->m_Mask & nMaskGen)
{
char macro[256];
sprintf(macro, "#define %s 0x%I64x\n", shG->m_BitMask[i]->m_ParamName.c_str(), shG->m_BitMask[i]->m_Mask);
int size = strlen(macro);
int nOffs = custMacros.Num();
custMacros.Grow(size);
memcpy(&custMacros[nOffs], macro, size);
}
}
}
int size = custMacros.Num();
char *buf = new char [len+size+1];
if (!buf)
{
iSystem->GetIPak()->FClose(fp);
Warning( 0,0,"Error: Can't allocate %d bytes for shader file '%s'\n", len+1, nameNew);
return NULL;
}
memcpy(buf, &custMacros[0], custMacros.Num());
iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET);
len = iSystem->GetIPak()->FRead(&buf[size], 1, len, fp);
iSystem->GetIPak()->FClose(fp);
buf[len+size] = 0;
RemoveCR(buf);
ef1 = mfParseFX(buf, ef, efGen, nMaskGen);
}
else
#endif
#endif
{
ef1 = mfSpawn(name, ef, efGen, nMaskGen);
}
if (ef1 == ef)
{
ef->m_Flags |= flags;
return ef;
}
ef->m_Flags |= EF_NOTFOUND;
ef->m_Passes.Reserve(1);
ef->m_Passes[0].mfAddNewTexUnits(1);
ef->m_Passes[0].m_TUnits[0].m_TexPic = gRenDev->m_TexMan->m_Text_NoTexture;
gRenDev->m_TexMan->m_Text_NoTexture->AddRef();
if (ef->m_Passes[0].m_TUnits[0].m_TexPic)
ef->m_Passes[0].m_TUnits[0].m_TexPic->m_Flags2 |= FT2_DIFFUSETEXTURE;
if (Res && Res->m_LMaterial)
ef->m_Flags |= EF_NEEDNORMALS;
ef->m_Flags |= EF_COMPILEDLAYERS | flags;
mfConstruct(ef);
ef->m_Passes[0].m_RenderState = GS_DEPTHWRITE;
return ef;
}