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

2753 lines
77 KiB
C++

/*=============================================================================
ShaderCore.cpp : implementation of the Shaders manager.
Copyright (c) 2001 Crytek Studios. All Rights Reserved.
Revision history:
* Created by Honitch Andrey
=============================================================================*/
#include "RenderPCH.h"
#include "I3DEngine.h"
#include "CryHeaders.h"
#include <sys/stat.h>
#if defined(WIN32) || defined(WIN64)
#include <direct.h>
#include <io.h>
#elif defined(LINUX)
#endif
SShader *CShader::m_DefaultShader;
#ifndef NULL_RENDERER
SShader *CShader::m_ShaderVFog;
SShader *CShader::m_ShaderVFogCaust;
SShader *CShader::m_ShaderFog;
SShader *CShader::m_ShaderFogCaust;
SShader *CShader::m_ShaderFog_FP;
SShader *CShader::m_ShaderFogCaust_FP;
SShader *CShader::m_ShaderStateNoCull;
SShader *CShader::m_ZBuffPassShader;
SShader *CShader::m_ShadowMapShader;
SShader *CShader::m_ShaderHDRProcess;
SShader *CShader::m_GlareShader;
SShader *CShader::m_ShaderSunFlares;
SShader *CShader::m_ShaderLightStyles;
SShader *CShader::m_ShaderCGPShaders;
SShader *CShader::m_ShaderCGVProgramms;
#else
SShaderItem CShader::m_DefaultShaderItem;
#endif
int SArrayPointer::m_CurEnabled;
int SArrayPointer::m_LastEnabled;
int SArrayPointer::m_CurEnabledPass;
int SArrayPointer::m_LastEnabledPass;
TArray<SShader *> SShader::m_Shaders_known;
TArray<SRenderShaderResources *> SShader::m_ShaderResources_known;
TArray <CLightStyle *> CLightStyle::m_LStyles;
CVProgram *CVProgram::m_LastVP;
int CVProgram::m_LastTypeVP;
int CVProgram::m_LastLTypeVP;
CPShader *CPShader::m_LastVP;
int CPShader::m_LastTypeVP;
int CPShader::m_LastLTypeVP;
int CVProgram::m_FrameObj;
bool gbRgb;
//=================================================================================================
int SShader::GetTexId()
{
STexPic *tp = (STexPic *)GetBaseTexture(NULL, NULL);
if (!tp)
return -1;
return tp->GetTextureID();
}
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
int SShader::mfSize()
{
int i;
int nSize = sizeof(SShader);
nSize += m_Name.size();
if (m_Templates)
nSize += m_Templates->Size();
for (i=0; i<m_Passes.GetSize(); i++)
{
nSize += m_Passes[i].Size();
}
for (i=0; i<m_HWConditions.GetSize(); i++)
{
nSize += m_HWConditions[i].Size();
}
nSize += m_HWTechniques.GetSize() * sizeof(SShaderTechnique *);
for (i=0; i<m_HWTechniques.Num(); i++)
{
nSize += m_HWTechniques[i]->Size();
}
if (m_Deforms)
nSize += m_Deforms->GetSize() * sizeof(SDeform);
nSize += m_PublicParams.GetMemoryUsage();
if (m_NormGen)
nSize += m_NormGen->Size();
if (m_FogInfo)
nSize += m_FogInfo->Size();
if (m_Sky)
nSize += m_Sky->Size();
if (m_Flares)
nSize += m_Flares->Size();
nSize += sizeof(CRendElement *) * m_REs.GetSize();
for (i=0; i<m_REs.Num(); i++)
{
nSize += m_REs[i]->Size();
}
if (m_EvalLights)
nSize += m_EvalLights->Size();
if (m_State)
nSize += m_State->Size();
return nSize;
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
SSkyInfo::~SSkyInfo()
{
for (int i=0; i<3; i++)
{
if (m_SkyBox[i])
m_SkyBox[i]->Release(false);
}
}
void SShader::mfFree()
{
int i;
for (i=0; i<m_REs.Num(); i++)
{
SAFE_DELETE(m_REs[i]);
}
m_REs.Free();
SAFE_DELETE(m_EvalLights);
SAFE_DELETE(m_NormGen);
SAFE_DELETE(m_FogInfo);
SAFE_DELETE(m_Sky);
if (m_State)
{
SAFE_DELETE(m_State->m_Stencil);
SAFE_DELETE(m_State);
}
for (i=0; i<m_Passes.Num(); i++)
{
SShaderPass *sl = &m_Passes[i];
sl->mfFree();
}
m_Passes.Free();
if (m_Deforms)
{
delete m_Deforms;
m_Deforms = NULL;
}
for (i=0; i<m_HWTechniques.Num(); i++)
{
SAFE_DELETE(m_HWTechniques[i]);
}
m_HWTechniques.Free();
for (i=0; i<m_HWConditions.Num(); i++)
{
SHWConditions *hc = &m_HWConditions[i];
if (hc->m_Vars)
delete [] hc->m_Vars;
}
m_HWConditions.Free();
if (m_Templates)
{
m_Templates->mfFree(this);
m_Templates = NULL;
}
if (m_ShaderGenParams)
{
for (i=0; i<m_ShaderGenParams->m_BitMask.Num(); i++)
{
SShaderGenBit *shgb = m_ShaderGenParams->m_BitMask[i];
SAFE_DELETE(shgb);
}
SAFE_DELETE(m_ShaderGenParams);
}
m_PublicParams.Free();
m_Flags &= ~(EF_POLYGONOFFSET | EF_HASVSHADER);
m_Flags3 &= ~(EF3_CLIPPLANE | EF3_NODRAW);
m_DLDFlags = 0;
m_DefaultVProgram = NULL;
}
SShader::~SShader()
{
gRenDev->m_cEF.mfRemoveFromHash(this);
mfFree();
SShader::m_Shaders_known[m_Id] = NULL;
}
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4311 ) // I believe the int cast below is okay.
#endif
SShader& SShader::operator = (const SShader& src)
{
int i;
mfFree();
int Offs = (int)&(((SShader *)0)->m_Id);
byte *d = (byte *)this;
byte *s = (byte *)&src;
memcpy(&d[Offs], &s[Offs], sizeof(SShader)-Offs);
m_Name = src.m_Name;
if (src.m_REs.Num())
{
m_REs.Create(src.m_REs.Num());
for (i=0; i<src.m_REs.Num(); i++)
{
if (src.m_REs[i])
m_REs[i] = src.m_REs[i]->mfCopyConstruct();
}
}
if (src.m_HWTechniques.Num())
{
m_HWTechniques.Create(src.m_HWTechniques.Num());
for (i=0; i<src.m_HWTechniques.Num(); i++)
{
#ifdef DEBUGALLOC
#undef new
#endif
m_HWTechniques[i] = new SShaderTechnique;
#ifdef DEBUGALLOC
#define new DEBUG_CLIENTBLOCK
#endif
*m_HWTechniques[i] = *src.m_HWTechniques[i];
}
}
m_PublicParams.Copy(src.m_PublicParams);
if (src.m_Passes.Num())
{
m_Passes.Create(src.m_Passes.Num());
for (i=0; i<src.m_Passes.Num(); i++)
{
const SShaderPass *s = &src.m_Passes[i];
SShaderPass *d = &m_Passes[i];
*d = *s;
}
}
if (src.m_Deforms)
{
m_Deforms = new TArray<SDeform>;
m_Deforms->Create(src.m_Deforms->Num());
memcpy(&m_Deforms->Get(0), &src.m_Deforms->Get(0), sizeof(SDeform)*m_Deforms->Num());
}
if (src.m_HWConditions.Num())
{
m_HWConditions.Create(src.m_HWConditions.Num());
for (i=0; i<src.m_HWConditions.Num(); i++)
{
const SHWConditions *hc = &src.m_HWConditions[i];
SHWConditions *hcd = &m_HWConditions[i];
*hcd = *hc;
if (hc->m_Vars)
{
hcd->m_Vars = new CVarCond[hc->m_NumVars];
memcpy(hcd->m_Vars, hc->m_Vars, sizeof(CVarCond)*hc->m_NumVars);
}
}
}
m_Templates = NULL;
return *this;
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
SShaderPassHW::SShaderPassHW()
{
m_ePassType = eSHP_General;
m_VProgram = NULL;
m_FShader = NULL;
m_Deforms = NULL;
m_CGFSParamsNoObj = NULL;
m_CGFSParamsObj = NULL;
m_MatrixOps = NULL;
m_LightFlags = 0;
m_LMFlags = 0;
m_nAmbMaxLights = gRenDev->m_bDeviceSupports_PS2X ? NUM_PPLIGHTS_PERPASS_PS2X : NUM_PPLIGHTS_PERPASS_PS30;
}
STexPic *SShader::mfFindBaseTexture(TArray<SShaderPass>& Passes, int *nPass, int *nTU, int nT)
{
int np, nt;
STexPic *tx;
np = nt = -1;
bool bOpaq = ((m_Flags2 & EF2_HASOPAQUE) != 0);
for (np=0; np<Passes.Num(); np++)
{
bool bFound = false;
for (nt=0; nt<Passes[np].m_TUnits.Num(); nt++)
{
if (bOpaq)
{
if (Passes[np].m_TUnits[nt].m_nFlags & FTU_OPAQUE)
bFound = true;
}
else
{
if (!nT)
{
if ((Passes[np].m_TUnits[nt].m_TexPic && (Passes[np].m_TUnits[nt].m_TexPic->m_Flags2 & FT2_DIFFUSETEXTURE)) ||
(Passes[np].m_TUnits[nt].m_AnimInfo && (Passes[np].m_TUnits[nt].m_AnimInfo->m_TexPics[0]->m_Flags2 & FT2_DIFFUSETEXTURE)) )
bFound = true;
}
else
if (Passes[np].m_TUnits[nt].m_TexPic || Passes[np].m_TUnits[nt].m_AnimInfo)
bFound = true;
}
if (bFound)
break;
}
if (bFound)
break;
}
if (np==Passes.Num() || nt==Passes[np].m_TUnits.Num() || (!Passes[np].m_TUnits[nt].m_TexPic && !Passes[np].m_TUnits[nt].m_AnimInfo))
{
np = nt = -1;
tx = NULL;
}
else
{
if (Passes[np].m_TUnits[nt].m_TexPic)
tx = Passes[np].m_TUnits[nt].m_TexPic;
else
tx = Passes[np].m_TUnits[nt].m_AnimInfo->m_TexPics[0];
}
if (nPass)
*nPass = np;
if (nTU)
*nTU = nt;
return tx;
}
STexPic *SShader::mfFindBaseTexture(TArray<SShaderPassHW>& Passes, int *nPass, int *nTU, int nT)
{
int np, nt;
STexPic *tx;
np = nt = -1;
bool bOpaq = ((m_Flags2 & EF2_HASOPAQUE) != 0);
for (np=0; np<Passes.Num(); np++)
{
bool bFound = false;
for (nt=0; nt<Passes[np].m_TUnits.Num(); nt++)
{
if (bOpaq)
{
if (Passes[np].m_TUnits[nt].m_nFlags & FTU_OPAQUE)
bFound = true;
}
else
{
if (!nT)
{
if ((Passes[np].m_TUnits[nt].m_TexPic && (Passes[np].m_TUnits[nt].m_TexPic->m_Flags2 & FT2_DIFFUSETEXTURE)) ||
(Passes[np].m_TUnits[nt].m_AnimInfo && (Passes[np].m_TUnits[nt].m_AnimInfo->m_TexPics[0]->m_Flags2 & FT2_DIFFUSETEXTURE)) )
bFound = true;
}
else
if (Passes[np].m_TUnits[nt].m_TexPic || Passes[np].m_TUnits[nt].m_AnimInfo)
bFound = true;
}
if (bFound)
break;
}
if (bFound)
break;
}
if (np==Passes.Num() || nt==Passes[np].m_TUnits.Num() || (!Passes[np].m_TUnits[nt].m_TexPic && !Passes[np].m_TUnits[nt].m_AnimInfo))
{
np = nt = -1;
tx = NULL;
}
else
{
if (Passes[np].m_TUnits[nt].m_TexPic)
tx = Passes[np].m_TUnits[nt].m_TexPic;
else
tx = Passes[np].m_TUnits[nt].m_AnimInfo->m_TexPics[0];
}
if (nPass)
*nPass = np;
if (nTU)
*nTU = nt;
return tx;
}
ITexPic *SShader::GetBaseTexture(int *nPass, int *nTU)
{
for (int nT=0; nT<2; nT++)
{
STexPic *tx = mfFindBaseTexture(m_Passes, nPass, nTU, nT);
if (tx)
return tx;
for (int i=0; i<m_HWTechniques.Num(); i++)
{
SShaderTechnique *hw = m_HWTechniques[i];
tx = mfFindBaseTexture(hw->m_Passes, nPass, nTU, nT);
if (tx)
return tx;
}
}
if (nPass)
*nPass = -1;
if (nTU)
*nTU = -1;
return NULL;
}
unsigned int SShader::GetUsedTextureTypes (void)
{
uint nMask = 0;
int i, j, n;
SShaderPass *ps;
SShaderPassHW *psHW;
for (i=0; i<m_Passes.Num(); i++)
{
ps = &m_Passes[i];
for (j=0; j<ps->m_TUnits.Num(); j++)
{
if (ps->m_TUnits[j].m_TexPic && ps->m_TUnits[j].m_TexPic->m_Bind < EFTT_MAX)
nMask |= 1<<ps->m_TUnits[j].m_TexPic->m_Bind;
}
}
for (n=0; n<m_HWTechniques.Num(); n++)
{
SShaderTechnique *pHT = m_HWTechniques[n];
for (i=0; i<pHT->m_Passes.Num(); i++)
{
psHW = &pHT->m_Passes[i];
for (j=0; j<psHW->m_TUnits.Num(); j++)
{
if (psHW->m_TUnits[j].m_TexPic && psHW->m_TUnits[j].m_TexPic->m_Bind < EFTT_MAX)
nMask |= 1<<psHW->m_TUnits[j].m_TexPic->m_Bind;
}
}
}
return nMask;
}
//================================================================================
void CShader::mfClearShaders (TArray<SShader *> &Efs, int *Nums)
{
int i;
if (!(*Nums))
return;
for (i=0; i<*Nums; i++)
{
if (Efs[i])
{
if (CRenderer::CV_r_printmemoryleaks)
iLog->Log("Warning: CShader::mfClearAll: Shader %s was not deleted (%d)", Efs[i]->GetName(), Efs[i]->m_nRefCounter);
//Efs[i]->Release();
}
}
*Nums = 0;
}
SSunFlare::~SSunFlare()
{
if (m_Tex)
{
m_Tex->Release(false);
m_Tex = NULL;
}
}
void CShader::mfClearAll (void)
{
int i;
if (gRenDev->m_cEF.m_bInitialized)
{
mfClearShaders(SShader::m_Shaders_known, &m_Nums);
}
SShader::m_Shaders_known.Free();
for (i=0; i<SShader::m_ShaderResources_known.Num(); i++)
{
SRenderShaderResources *pSR = SShader::m_ShaderResources_known[i];
if (!pSR)
continue;
if (i)
{
if (CRenderer::CV_r_printmemoryleaks)
iLog->Log("Warning: CShader::mfClearAll: Shader resource 0x%x was not deleted", pSR);
}
delete pSR;
}
SShader::m_ShaderResources_known.Free();
CSunFlares::m_CurFlares = NULL;
for (i=0; i<CSunFlares::m_SunFlares.Num(); i++)
{
delete CSunFlares::m_SunFlares[i];
}
CSunFlares::m_SunFlares.Free();
for (i=0; i<SArrayPointer::m_Arrays.Num(); i++)
{
SArrayPointer *ap = SArrayPointer::m_Arrays[i];
delete ap;
}
SArrayPointer::m_Arrays.Free();
for (i=0; i<SParamComp::m_ParamComps.Num(); i++)
{
delete SParamComp::m_ParamComps[i];
}
SParamComp::m_ParamComps.Free();
#if !defined(PS2) && !defined (GC) && !defined (NULL_RENDERER)
SAFE_RELEASE(gRenDev->m_RP.m_RCDetail);
SAFE_RELEASE(gRenDev->m_RP.m_RCSprites_Heat);
SAFE_RELEASE(gRenDev->m_RP.m_RCSprites_FV);
SAFE_RELEASE(gRenDev->m_RP.m_RCSprites);
SAFE_RELEASE(gRenDev->m_RP.m_RCSun);
SAFE_RELEASE(gRenDev->m_RP.m_RCFog);
SAFE_RELEASE(gRenDev->m_RP.m_VPDetail);
SAFE_RELEASE(gRenDev->m_RP.m_VPFog);
SAFE_RELEASE(gRenDev->m_RP.m_VPTransformTexture);
SAFE_RELEASE(gRenDev->m_RP.m_VPPlantBendingSpr);
SAFE_RELEASE(gRenDev->m_RP.m_VPPlantBendingSpr_FV);
SAFE_RELEASE(gRenDev->m_RP.m_RCBlur);
SAFE_RELEASE(gRenDev->m_RP.m_VPBlur);
for (i=0; i<CVProgram::m_VPrograms.Num(); i++)
{
if (CVProgram::m_VPrograms[i] && CRenderer::CV_r_printmemoryleaks)
iLog->Log("Warning: CShader::mfClearAll: Vertex shader %s was not deleted", CVProgram::m_VPrograms[i]->m_Name.c_str());
delete CVProgram::m_VPrograms[i];
}
CVProgram::m_VPrograms.Free();
for (i=0; i<CPShader::m_PShaders.Num(); i++)
{
if (CPShader::m_PShaders[i] && CRenderer::CV_r_printmemoryleaks)
iLog->Log("Warning: CShader::mfClearAll: Pixel shader %s was not deleted", CPShader::m_PShaders[i]->m_Name.c_str());
delete CPShader::m_PShaders[i];
}
CPShader::m_PShaders.Free();
#endif
for (i=0; i<CLightStyle::m_LStyles.Num(); i++)
{
delete CLightStyle::m_LStyles[i];
}
CLightStyle::m_LStyles.Free();
for (i=0; i<SLightMaterial::known_materials.Num(); i++)
{
if (SLightMaterial::known_materials[i] && SLightMaterial::known_materials[i]->name[0] == '$')
iLog->Log("Warning: CShader::mfClearAll: Light material %s was not deleted (%d)", SLightMaterial::known_materials[i]->name, SLightMaterial::known_materials[i]->m_nRefCounter);
SAFE_DELETE(SLightMaterial::known_materials[i])
}
SLightMaterial::known_materials.Free();
gRenDev->m_cEF.m_bInitialized = false;
gRenDev->m_cEF.m_KnownTemplates.Free();
}
void CShader::mfShutdown(void)
{
int i, j;
mfStartScriptPreprocess();
mfUnregisterDefaultTemplates();
if (m_DefaultShader)
{
m_DefaultShader->Release(true);
m_DefaultShader = NULL;
}
#ifndef NULL_RENDERER
if (m_ShaderVFog)
{
m_ShaderVFog->Release(true);
m_ShaderVFog = NULL;
}
SAFE_RELEASE_FORCE(m_ShaderVFogCaust);
if (m_ShaderFog_FP != m_ShaderFog)
{
SAFE_RELEASE_FORCE(m_ShaderFog);
SAFE_RELEASE_FORCE(m_ShaderFog_FP);
}
else
{
SAFE_RELEASE_FORCE(m_ShaderFog);
m_ShaderFog_FP = NULL;
}
if (m_ShaderFogCaust_FP != m_ShaderFogCaust)
{
SAFE_RELEASE_FORCE(m_ShaderFogCaust);
SAFE_RELEASE_FORCE(m_ShaderFogCaust_FP);
}
else
{
SAFE_RELEASE_FORCE(m_ShaderFogCaust);
m_ShaderFogCaust_FP = NULL;
}
SAFE_RELEASE_FORCE(m_ShaderStateNoCull);
SAFE_RELEASE_FORCE(m_ZBuffPassShader);
SAFE_RELEASE_FORCE(m_ShadowMapShader);
SAFE_RELEASE_FORCE(m_ShaderHDRProcess);
SAFE_RELEASE_FORCE(m_GlareShader);
//SAFE_RELEASE_FORCE(m_ShaderSunFlares); // Releases in 3dengine
SAFE_RELEASE_FORCE(m_ShaderLightStyles);
#if !defined(PS2) && !defined(GC) && !defined (NULL_RENDERER)
SAFE_RELEASE_FORCE(m_ShaderCGPShaders);
SAFE_RELEASE_FORCE(m_ShaderCGVProgramms);
#endif
#endif
SAFE_RELEASE(gRenDev->m_RP.m_RCDetail);
SAFE_RELEASE(gRenDev->m_RP.m_RCSprites_Heat);
SAFE_RELEASE(gRenDev->m_RP.m_RCSprites_FV);
SAFE_RELEASE(gRenDev->m_RP.m_RCSprites);
SAFE_RELEASE(gRenDev->m_RP.m_RCSun);
SAFE_RELEASE(gRenDev->m_RP.m_RCFog);
SAFE_RELEASE(gRenDev->m_RP.m_VPDetail);
SAFE_RELEASE(gRenDev->m_RP.m_VPFog);
SAFE_RELEASE(gRenDev->m_RP.m_VPTransformTexture);
SAFE_RELEASE(gRenDev->m_RP.m_VPPlantBendingSpr);
SAFE_RELEASE(gRenDev->m_RP.m_RCBlur);
SAFE_RELEASE(gRenDev->m_RP.m_VPBlur);
for (i=0; i<2; i++)
{
for (j=0; j<MAX_EF_FILES; j++)
{
if (!m_FileNames[i][j].empty())
m_FileNames[i][j] = "";
}
if (m_RefEfs[i])
{
ShaderFilesMapItor itor=m_RefEfs[i]->begin();
while(itor!=m_RefEfs[i]->end())
{
SAFE_DELETE (itor->second);
itor++;
}
m_RefEfs[i]->clear();
SAFE_DELETE (m_RefEfs[i]);
}
}
/*LoadedShadersMapItor itor=m_RefEfsLoaded.begin();
while(itor!=m_RefEfsLoaded.end())
{
SAFE_DELETE (itor->second);
itor++;
}*/
m_RefEfsLoaded.clear();
}
SShader *CShader::mfCopyShader (SShader *ef)
{
SShader *efc;
efc = mfNewShader(eSH_Temp, -1);
if (!efc)
return NULL;
int id = efc->m_Id;
*efc = *ef;
efc->m_Id = id;
return efc;
}
void CShader::mfInit (void)
{
int i, j;
gRenDev->m_TexMan->LoadDefaultTextures();
if (!m_bInitialized)
{
//m_RefEfsLoaded.resize(1024);
strcpy(m_ShadersPath[0], "Shaders/Scripts/");
strcpy(m_ShadersPath[1], "Shaders/HWScripts/");
strcpy(m_ShadersCache, "Shaders/Cache/");
CShader::m_Nums = 0;
CShader::m_MaxNums = (MAX_SHADERS - 256) - 1;
CShader::m_FirstCopyNum = MAX_SHADERS - 256;
SShader::m_Shaders_known.Alloc(MAX_SHADERS);
memset(&SShader::m_Shaders_known[0], 0, sizeof(SShader *)*MAX_SHADERS);
m_AliasNames.Free();
fxParserInit();
#if !defined(NULL_RENDERER)
//FILE *fp = fxopen("Shaders/Aliases.txt", "r");
FILE *fp = iSystem->GetIPak()->FOpen("Shaders/Aliases.txt", "r");
if (fp)
{
while (!iSystem->GetIPak()->FEof(fp))
{
char name[128];
char alias[128];
char str[256];
iSystem->GetIPak()->FGets(str, 256, fp);
if (sscanf(str, "%s %s", alias, name) == 2)
{
SNameAlias na;
na.m_Alias = CName(alias, eFN_Add);
na.m_Name = CName(name, eFN_Add);
m_AliasNames.AddElem(na);
}
}
iSystem->GetIPak()->FClose(fp);
}
int nGPU = gRenDev->GetFeatures() & RFT_HW_MASK;
// load CustomAliases (by wat)
m_CustomAliasNames.Free();
fp = iSystem->GetIPak()->FOpen("Shaders/CustomAliases.txt", "r");
if (fp)
{
char arg[3][256];
bool bCond = true;
while (!iSystem->GetIPak()->FEof(fp))
{
char str[256];
iSystem->GetIPak()->FGets(str, 256, fp);
char * p = strchr(str, '=');
if(p)
{
memmove(p+2,p,strlen(p)+1);
str[p-str] = ' '; str[p-str+1] = '='; str[p-str+2] = ' ';
}
int nArgs = sscanf(str, "%s %s %s", arg[0], arg[1], arg[2]);
// parser comments
for(int i = 0; i<nArgs; i++)
if(arg[i][0] == ';')
{
nArgs = i;
break;
}
// parser aliases
if(nArgs == 2 && bCond)
{
SNameAlias na;
na.m_Alias = CName(arg[0], eFN_Add);
na.m_Name = CName(arg[1], eFN_Add);
//if(m_CustomAliasNames.Find(na) == -1)
m_CustomAliasNames.AddElem(na);
}
// parser conditions vars.
else if(nArgs == 3 && arg[1][0] == '=')
{
ICVar * pVar = iConsole->GetCVar(arg[0]);
if(pVar)
{
if( pVar->GetType()== CVAR_INT && pVar->GetIVal() != atoi(arg[2]))
bCond = false;
if( pVar->GetType()== CVAR_FLOAT && pVar->GetFVal() != float(atof(arg[2])))
bCond = false;
}
else
if(!strnicmp(arg[0], "GPU", 3))
{
if(!strnicmp(arg[2], "NV1X", 4) && nGPU != RFT_HW_GF2)
bCond = false;
else
if(!strnicmp(arg[2], "NV2X", 4) && nGPU != RFT_HW_GF3)
bCond = false;
else
if(!strnicmp(arg[2], "R300", 4) && nGPU != RFT_HW_RADEON)
bCond = false;
else
if(!strnicmp(arg[2], "NV4X", 4) && nGPU != RFT_HW_NV4X)
bCond = false;
}
}
else if(arg[0][0] == '}')
bCond = true;
}
iSystem->GetIPak()->FClose(fp);
}
for (i=0; i<m_CustomAliasNames.Num(); i++)
{
CName nm = m_CustomAliasNames[i].m_Name;
bool bChanged = false;
for (j=i+1; j<m_CustomAliasNames.Num(); j++)
{
if (m_CustomAliasNames[j].m_Alias == nm)
{
m_CustomAliasNames[i].m_Name = m_CustomAliasNames[j].m_Name;
bChanged = true;
}
}
}
m_CustomAliasNames.Shrink();
/* Old version:
fp = iSystem->GetIPak()->FOpen("Shaders/CustomAliases.txt", "r");
if (fp)
{
while (!iSystem->GetIPak()->FEof(fp))
{
char name[128];
char alias[128];
char str[256];
iSystem->GetIPak()->FGets(str, 256, fp);
if (sscanf(str, "%s %s", alias, name) == 2)
{
SNameAlias na;
na.m_Alias = CName(alias, eFN_Add);
na.m_Name = CName(name, eFN_Add);
m_CustomAliasNames.AddElem(na);
}
}
iSystem->GetIPak()->FClose(fp);
}
*/
/*{
PackCache();
}*/
mfLoadFromFiles(0);
if (CRenderer::CV_r_usehwshaders)
mfLoadFromFiles(1);
m_CurEfsNum = 0;
#endif //NULL_RENDERER
mfSetDefaults();
m_bInitialized = true;
}
for (i=0; i<m_Nums; i++)
{
SShader *ef = SShader::m_Shaders_known[i];
if (ef)
{
for (int i=0; i<ef->m_REs.Num(); i++)
{
if (ef->m_REs[i])
ef->m_REs[i]->mfBuildGeometry(ef);
}
}
}
#if !defined(PS2) && !defined (GC)&& !defined (NULL_RENDERER)
gRenDev->m_RP.m_RCDetail = CPShader::mfForName("CGRCDetailAtten");
gRenDev->m_RP.m_RCSprites_Heat = CPShader::mfForName("CGRCHeat_TreesSprites");
gRenDev->m_RP.m_RCSprites_FV = CPShader::mfForName("CGRCTreeSprites_FV");
gRenDev->m_RP.m_RCSprites = CPShader::mfForName("CGRCTreeSprites");
gRenDev->m_RP.m_RCSun = CPShader::mfForName("CGRCSun");
gRenDev->m_RP.m_RCFog = CPShader::mfForName("CGRCFog");
gRenDev->m_RP.m_VPDetail = CVProgram::mfForName("CGVProgDetail");
gRenDev->m_RP.m_VPFog = CVProgram::mfForName("CGVProgFog");
gRenDev->m_RP.m_VPTransformTexture = CVProgram::mfForName("CGVProgTransformTexture");
gRenDev->m_RP.m_VPPlantBendingSpr = CVProgram::mfForName("CGVProgSimple_Plant_Bended_Sprite");
gRenDev->m_RP.m_VPPlantBendingSpr_FV = CVProgram::mfForName("CGVProgSimple_Plant_Bended_Sprite_FV");
gRenDev->m_RP.m_RCBlur = CPShader::mfForName("CGRCBlur");
gRenDev->m_RP.m_VPBlur = CVProgram::mfForName("CGVProgBlur");
if (gRenDev->GetFeatures() & RFT_HW_PS20)
{
gRenDev->m_RP.m_VPFur_NormGen = CVProgram::mfForName("CGVProgFur_NormGen");
gRenDev->m_RP.m_VPFur_OffsGen = CVProgram::mfForName("CGVProgFur_OffsGen");
gRenDev->m_RP.m_RCFur_NormGen = CPShader::mfForName("CGRCFur_NormGen");
gRenDev->m_RP.m_RCFur_OffsGen = CPShader::mfForName("CGRCFur_OffsGen");
}
#endif
}
void CShader::mfSetDefaults (void)
{
static byte b = 0;
SShader *ef;
if (!b)
iLog->Log("Construct Shader '<Default>'...");
ef = mfNewShader(eSH_Misc, -1);
m_DefaultShader = ef;
mfAddToHash("<Default>", ef);
ef->m_Passes.ReserveNew(1);
ef->m_Passes[0].mfAddNewTexUnits(1);
ef->m_Passes[0].m_TUnits[0].m_TexPic = gRenDev->m_TexMan->m_Text_White;
ef->m_Passes[0].m_RenderState = GS_DEPTHWRITE;
ef->m_Flags |= EF_SYSTEM;
mfConstruct(ef);
if (!b)
iLog->LogPlus("ok");
#ifndef NULL_RENDERER
if (!b)
iLog->Log("Construct Shader 'ZBuffPass'...");
ef = mfNewShader(eSH_Misc, -1);
m_ZBuffPassShader = ef;
mfAddToHash("ZBuffPass", ef);
ef->m_Passes.ReserveNew(1);
ef->m_Passes[0].mfAddNewTexUnits(1);
ef->m_Passes[0].m_TUnits[0].m_TexPic = NULL;
ef->m_Passes[0].m_RenderState = GS_DEPTHWRITE | GS_NOCOLMASK;
ef->m_eSort = eS_ZBuff;
ef->m_Passes[0].m_eEvalRGB=eERGB_Fixed;
ef->m_Passes[0].m_FixedColor.dcolor=0;
ef->m_Flags |= EF_SYSTEM;
mfConstruct(ef);
if (!b)
iLog->LogPlus("ok");
if (!b)
iLog->Log("Construct Shader 'ShadowMap'...");
ef = mfNewShader(eSH_Misc, -1);
m_ShadowMapShader = ef;
mfAddToHash("ShadowMap", ef); // maps shadows from shadow casters to the object
ef->m_Passes.ReserveNew(1);
ef->m_Passes[0].mfAddNewTexUnits(1);
ef->m_Passes[0].m_TUnits[0].m_TexPic = NULL;
ef->m_Passes[0].m_RenderState = GS_DEPTHWRITE | GS_NOCOLMASK;
ef->m_eSort = eS_ShadowMap;
ef->m_Flags |= EF_SYSTEM;
mfConstruct(ef);
if (!b)
iLog->LogPlus("ok");
// ef = mfForName("glassCM", eSH_Misc, EF_SYSTEM);
if (!b)
iLog->Log("Compile System Shader 'StateNoCull'...");
ef = mfForName("StateNoCull", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderStateNoCull = ef;
if (!b)
iLog->Log("Compile System Shader 'HDRProcess'...");
ef = mfForName("HDRProcess", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderHDRProcess = ef;
if (!b)
iLog->Log("Compile System Shader 'SunFlares'...");
ef = mfForName("SunFlares", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
{
iLog->LogPlus("ok");
iLog->Log(" %d Sun flares was parsed\n", CSunFlares::m_SunFlares.Num());
}
}
m_ShaderSunFlares = ef;
if (!b)
iLog->Log("Compile System Shader 'LightStyles'...");
ef = mfForName("LightStyles", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
{
iLog->LogPlus("ok");
iLog->Log(" %d Light styles was parsed\n", CLightStyle::m_LStyles.Num());
}
}
m_ShaderLightStyles = ef;
if (!b)
iLog->Log("Compile Glare Shader ...");
m_GlareShader = mfForName("Glare", eSH_Screen, EF_SYSTEM);
#else
m_DefaultShaderItem.m_pShader = m_DefaultShader;
m_DefaultShaderItem.m_pShaderResources = new SRenderShaderResources;
#endif
#if !defined(PS2) && !defined(GC) && !defined (NULL_RENDERER)
if (!b)
iLog->Log("Compile System HW Shader 'CGVProgramms'...");
ef = mfForName("CGVProgramms", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderCGVProgramms = ef;
if (!b)
iLog->Log("Compile System HW Shader 'CGPShaders'...");
ef = mfForName("CGPShaders", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderCGPShaders = ef;
#endif
#ifndef NULL_RENDERER
if (!b)
iLog->Log("Compile System Shader 'TemplFog'...");
ef = mfForName("TemplFog", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderFog = ef;
if (!b)
iLog->Log("Compile System Shader 'TemplVFog'...");
ef = mfForName("TemplVFog", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderVFog = ef;
if (!b)
iLog->Log("Compile System Shader 'TemplFog_FP'...");
ef = mfForName("TemplFog_FP", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderFog_FP = ef;
if (!b)
iLog->Log("Compile System Shader 'TemplFogCaustics'...");
ef = mfForName("TemplFogCaustics", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderFogCaust = ef;
if (!b)
iLog->Log("Compile System Shader 'TemplVFogCaustics'...");
ef = mfForName("TemplVFogCaustics", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderVFogCaust = ef;
if (!b)
iLog->Log("Compile System Shader 'TemplFogCaustics_FP'...");
ef = mfForName("TemplFogCaustics_FP", eSH_Misc, EF_SYSTEM);
if (!b)
{
if (!ef || (ef->m_Flags & EF_NOTFOUND))
iLog->LogPlus("Fail.\n");
else
iLog->LogPlus("ok");
}
m_ShaderFogCaust_FP = ef;
mfRegisterDefaultTemplates();
#endif
if (!b)
iLog->Log("\n");
b = 1;
//ef = mfForName("Illumination", eSH_Misc, EF_SYSTEM, NULL, 0x9f43);
//ef = mfForName("TemplIllum", eSH_Misc, EF_SYSTEM, NULL, 0x9703);
//ef = mfForName("TemplIllum", eSH_Misc, EF_SYSTEM, NULL, 0x9743);
m_bInitialized = true;
}
//===================================================================
static byte pCounts[eSrcPointer_Max];
static void sSetFillColHW(SShader *ef, int& flt, EEvalRGB RGB[64], EEvalAlpha Alpha[64], byte bus[64][8], TArray<SShaderPassHW>& Layers)
{
int i;
for (i=0; i<64; i++)
{
if (!bus[i][0])
break;
if (Alpha[i] != eEALPHA_FromClient || RGB[i] != eERGB_FromClient)
break;
}
if (!bus[i][0])
{
flt |= FLT_COL;
for (i=0; i<64; i++)
{
if (!bus[i][0])
break;
Layers[i].m_eEvalRGB = eERGB_NoFill;
Layers[i].m_eEvalAlpha = eEALPHA_NoFill;
}
}
}
static bool sNeedColorArray(EEvalRGB eRGB, EEvalAlpha eA)
{
if ((eRGB == eERGB_Fixed || eRGB == eERGB_Identity || eRGB == eERGB_NoFill || eRGB == eERGB_Wave || eRGB == eERGB_Object || eRGB == eERGB_OneMinusObject || eRGB == eERGB_RE || eRGB == eERGB_OneMinusRE || eRGB == eERGB_World || eRGB == eERGB_Noise || eRGB == eERGB_Comps) && (eA == eEALPHA_Fixed || eA == eEALPHA_Identity || eA == eEALPHA_NoFill || eA == eEALPHA_Wave || eA == eEALPHA_Object || eA == eEALPHA_OneMinusObject || eA == eEALPHA_RE || eA == eEALPHA_OneMinusRE || eA == eEALPHA_World || eA == eEALPHA_Noise || eA == eEALPHA_Comps))
return false;
return true;
}
void CShader::mfOptimizeShaderHW(SShader *ef, TArray<SShaderPassHW>& Layers, int Stage)
{
int i, j;
if (Stage == 0)
{
bool bOpaq = false;;
for (i=0; i<Layers.Num(); i++)
{
for (j=0; j<Layers[i].m_Pointers.Num(); j++)
{
pCounts[Layers[i].m_Pointers[j]->ePT]++;
}
if (!Layers[i].m_TUnits.Num())
continue;
if (Layers[i].m_RenderState & GS_DEPTHWRITE)
bOpaq = true;
if (!Layers[i].m_TUnits[0].m_eGenTC)
Layers[i].m_TUnits[0].m_eGenTC = eGTC_Base;
if ((Layers[i].m_RenderState & GS_BLEND_MASK) && (Layers[0].m_RenderState & GS_BLEND_MASK))
{
if (ef->m_eSort==eS_Unknown)
ef->m_eSort = (Layers[i].m_RenderState & GS_DEPTHWRITE) ? eS_SeeThrough : eS_Banner;
}
else
{
if (ef->m_eSort==eS_Unknown && !(Layers[i].m_RenderState & GS_NODEPTHTEST))
ef->m_eSort = eS_Opaque;
}
}
if (bOpaq && ef->m_eSort < eS_SeeThrough)
ef->m_Flags2 |= EF2_OPAQUE;
}
else
if (Stage == 1)
{
if (Layers.Num())
{
byte bus[64][8];
byte bEx[64];
EEvalAlpha Alpha[64];
EEvalRGB RGB[64];
memset(bEx, 0, 64);
memset(&bus[0][0], 0, 64*8);
for (i=0; i<Layers.Num(); i++)
{
if (Layers[i].m_Flags & SHPF_RADIOSITY)
ef->m_nPreprocess |= FSPR_SCANLCM;
Alpha[i] = Layers[i].m_eEvalAlpha;
RGB[i] = Layers[i].m_eEvalRGB;
for (j=0; j<Layers[i].m_TUnits.Num(); j++)
{
SShaderTexUnit *tl = &Layers[i].m_TUnits[j];
if (!tl)
continue;
//if (!ef->m_ePreprocess)
{
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_EnvCMap)
ef->m_nPreprocess |= FSPR_SCANCM;
else
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_EnvLCMap)
ef->m_nPreprocess |= FSPR_SCANLCM;
else
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_EnvTex)
ef->m_nPreprocess |= FSPR_SCANTEX;
else
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_EnvScr)
ef->m_nPreprocess |= FSPR_SCANSCR;
else // tiago: added
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_ScreenMap)
ef->m_nPreprocess |= FSPR_SCREENTEXMAP;
else // tiago: added
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_DofMap)
ef->m_nPreprocess |= FSPR_DOFMAP;
else
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_WaterMap)
ef->m_nPreprocess |= FSPR_SCANTEXWATER;
if (tl->m_TexPic)
{
if (tl->m_TexPic->m_Bind >= TO_CUSTOM_CUBE_MAP_FIRST && tl->m_TexPic->m_Bind <= TO_CUSTOM_CUBE_MAP_LAST)
ef->m_nPreprocess |= FSPR_CUSTOMCM;
else
if (tl->m_TexPic->m_Bind >= TO_CUSTOM_TEXTURE_FIRST && tl->m_TexPic->m_Bind <= TO_CUSTOM_TEXTURE_LAST)
ef->m_nPreprocess |= FSPR_CUSTOMTEXTURE;
}
}
bus[i][j] = tl->m_eGenTC;
bEx[bus[i][j]]++;
if (j)
bEx[bus[i][j]] |= 0x80;
}
}
int fl = ef->m_Flags;
int flt = 0;
if (ef->m_Flags & EF_NEEDNORMALS)
flt |= FLT_N;
if (bEx[eGTC_Base] && bEx[eGTC_LightMap] && !(bEx[eGTC_Base] & 0x80) && !(bEx[eGTC_LightMap] & 0x80))
{
flt |= FLT_SYSBASE | FLT_SYSLM;
}
else
{
if (bEx[eGTC_Base])
{
flt |= FLT_BASE;
for (i=0; i<64; i++)
{
if (!bus[i][0])
break;
for (j=0; j<8; j++)
{
if (bus[i][j] == eGTC_Base)
Layers[i].m_TUnits[j].m_eGenTC = eGTC_NoFill;
}
}
}
if (bEx[eGTC_LightMap])
{
flt |= FLT_LM;
for (i=0; i<64; i++)
{
if (!bus[i][0])
break;
for (j=0; j<8; j++)
{
if (bus[i][j] == eGTC_LightMap)
Layers[i].m_TUnits[j].m_eGenTC = eGTC_NoFill;
}
}
}
}
sSetFillColHW(ef, flt, RGB, Alpha, bus, Layers);
flt |= FLT_COL;
//==========================================================
// Find suitable vertex format for RenderElements
if ((flt & FLT_N))
m_bNeedNormal = true;
TArray<SArrayPointer *> Pts;
for (i=0; i<Layers.Num(); i++)
{
if (Layers[i].m_Deforms)
m_bNeedSysBuf = true;
for (j=0; j<Layers[i].m_TUnits.Num(); j++)
{
if (Layers[i].m_TUnits[j].m_TexPic && (Layers[i].m_TUnits[j].m_TexPic->m_eTT == eTT_Bumpmap))
Layers[i].m_LMFlags |= LMF_BUMPMATERIAL;
}
int nT = 0;
if (sNeedColorArray(Layers[i].m_eEvalRGB, Layers[i].m_eEvalAlpha))
m_bNeedCol = true;
for (j=0; j<Layers[i].m_Pointers.Num(); j++)
{
Pts.AddElem(Layers[i].m_Pointers[j]);
switch(Layers[i].m_Pointers[j]->ePT)
{
case eSrcPointer_Binormal:
case eSrcPointer_Tangent:
case eSrcPointer_TNormal:
Layers[i].m_Flags |= SHPF_TANGENTS;
break;
case eSrcPointer_TexLM:
Layers[i].m_Flags |= SHPF_LMTC;
m_nTC = max(m_nTC, 2);
break;
}
}
if (Layers[i].m_VProgram)
{
if (Layers[i].m_VProgram->mfHasPointer(eSrcPointer_Binormal))
{
Layers[i].m_Flags |= SHPF_TANGENTS;
m_bNeedTangents = true;
}
if (Layers[i].m_VProgram->mfHasPointer(eSrcPointer_TNormal))
{
Layers[i].m_Flags |= SHPF_TANGENTS;
m_bNeedTangents = true;
}
if (Layers[i].m_VProgram->mfHasPointer(eSrcPointer_Tangent))
{
Layers[i].m_Flags |= SHPF_TANGENTS;
m_bNeedTangents = true;
}
if (Layers[i].m_VProgram->mfHasPointer(eSrcPointer_Color))
m_bNeedCol = true;
if (Layers[i].m_VProgram->mfHasPointer(eSrcPointer_SecColor))
m_bNeedSecCol = true;
if (Layers[i].m_VProgram->mfHasPointer(eSrcPointer_Normal))
m_bNeedNormal = true;
for (int n=1; n>=0; n--)
{
if (Layers[i].m_VProgram->mfHasPointer((ESrcPointer)(eSrcPointer_Tex+n)))
{
m_nTC = max(m_nTC, n+1);
if (n)
Layers[i].m_Flags |= SHPF_LMTC;
break;
}
}
}
}
for (i=0; i<ef->m_HWTechniques.Num(); i++)
{
for (j=0; j<ef->m_HWTechniques[i]->m_Pointers.Num(); j++)
{
Pts.AddElem(ef->m_HWTechniques[i]->m_Pointers[j]);
}
}
for (i=0; i<Pts.Num(); i++)
{
switch (Pts[i]->ePT)
{
case eSrcPointer_Color:
m_bNeedCol = true;
break;
case eSrcPointer_SecColor:
m_bNeedSecCol = true;
break;
case eSrcPointer_NormLightVector:
case eSrcPointer_LightVector:
case eSrcPointer_HalfAngleVector:
case eSrcPointer_Attenuation:
case eSrcPointer_LAttenuationSpec0:
case eSrcPointer_LAttenuationSpec1:
case eSrcPointer_Refract:
case eSrcPointer_Project:
case eSrcPointer_ProjectTexture:
case eSrcPointer_ProjectAttenFromCamera:
m_bNeedSysBuf = true;
case eSrcPointer_Binormal:
case eSrcPointer_Tangent:
case eSrcPointer_TNormal:
m_bNeedTangents = true;
break;
case eSrcPointer_Normal:
m_bNeedNormal = true;
break;
case eSrcPointer_Tex:
m_nTC = max(m_nTC, 1);
break;
}
}
//==========================================================
if (ef->m_eSort <= eS_Opaque)
ef->m_Flags2 |= EF2_FOGOVERLAY1;
else
if (ef->m_Flags & EF_FOGSHADER)
ef->m_Flags2 |= EF2_FOGOVERLAY2;
}
}
}
void CShader::mfOptimizeShader(SShader *ef, TArray<SShaderPass>& Layers, int Stage)
{
int i, j;
if (Stage == 0)
{
bool bOpaq = false;;
for (i=0; i<Layers.Num(); i++)
{
if (!Layers[i].m_TUnits.Num())
continue;
if (!(Layers[i].m_RenderState & GS_BLEND_MASK))
bOpaq = true;
if (!Layers[i].m_TUnits[0].m_eGenTC)
Layers[i].m_TUnits[0].m_eGenTC = eGTC_Base;
if ((Layers[i].m_RenderState & GS_BLEND_MASK) && (Layers[0].m_RenderState & GS_BLEND_MASK))
{
if (ef->m_eSort==eS_Unknown)
ef->m_eSort = (Layers[i].m_RenderState & GS_DEPTHWRITE) ? eS_SeeThrough : eS_Banner;
}
else
{
if (ef->m_eSort==eS_Unknown && !(Layers[i].m_RenderState & GS_NODEPTHTEST))
ef->m_eSort = eS_Opaque;
}
}
if (bOpaq && ef->m_eSort != eS_SeeThrough)
ef->m_Flags2 |= EF2_OPAQUE;
}
else
if (Stage == 1)
{
if (Layers.Num())
{
for (i=0; i<Layers.Num(); i++)
{
for (j=0; j<Layers[i].m_TUnits.Num(); j++)
{
SShaderTexUnit *tl = &Layers[i].m_TUnits[j];
if (!tl)
continue;
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_EnvCMap)
ef->m_nPreprocess |= FSPR_SCANCM;
else
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_EnvLCMap)
ef->m_nPreprocess |= FSPR_SCANLCM;
else
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_EnvTex)
ef->m_nPreprocess |= FSPR_SCANTEX;
else
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_EnvScr)
ef->m_nPreprocess |= FSPR_SCANSCR;
else // tiago: added
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_ScreenMap)
ef->m_nPreprocess |= FSPR_SCREENTEXMAP;
else // tiago: added
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_DofMap)
ef->m_nPreprocess |= FSPR_DOFMAP;
else
if (tl->m_TexPic == gRenDev->m_TexMan->m_Text_WaterMap)
ef->m_nPreprocess |= FSPR_SCANTEXWATER;
if (tl->m_TexPic)
{
if (tl->m_TexPic->m_Bind >= TO_CUSTOM_CUBE_MAP_FIRST && tl->m_TexPic->m_Bind <= TO_CUSTOM_CUBE_MAP_LAST)
ef->m_nPreprocess |= FSPR_CUSTOMCM;
else
if (tl->m_TexPic->m_Bind >= TO_CUSTOM_TEXTURE_FIRST && tl->m_TexPic->m_Bind <= TO_CUSTOM_TEXTURE_LAST)
ef->m_nPreprocess |= FSPR_CUSTOMTEXTURE;
}
}
}
if (ef->m_REs.Num() && ef->m_REs[0]->mfGetType() == eDATA_AnimPolyBlend)
ef->m_Flags2 |= EF2_CUSTOMANIMTEX;
int fl = ef->m_Flags;
int flt = 0;
if (ef->m_Flags & EF_NEEDNORMALS)
flt |= FLT_N;
//==========================================================
// Find suitable vertex format for RenderElements
for (i=0; i<Layers.Num(); i++)
{
int nT = 0;
if (sNeedColorArray(Layers[i].m_eEvalRGB, Layers[i].m_eEvalAlpha))
m_bNeedCol = true;
for (j=0; j<Layers[i].m_TUnits.Num(); j++)
{
SShaderTexUnit *tl = &Layers[i].m_TUnits[j];
if (!tl)
continue;
if (tl->m_GTC || (tl->m_eGenTC != eGTC_Base && tl->m_eGenTC != eGTC_LightMap && tl->m_eGenTC != eGTC_NoFill && tl->m_eGenTC != eGTC_Projection))
continue;
nT++;
}
m_nTC = max(m_nTC, nT);
}
if (ef->m_eSort <= eS_Opaque)
ef->m_Flags2 |= EF2_FOGOVERLAY1;
else
if (ef->m_Flags & EF_FOGSHADER)
ef->m_Flags2 |= EF2_FOGOVERLAY2;
}
}
}
void CShader::mfConstruct (SShader *ef)
{
int i;
// Sky shader
if (ef->m_Flags & EF_SKY)
{
ef->m_eSort = eS_Sky;
}
// Fog shader
if (ef->m_Flags & EF_FOGSHADER)
ef->m_eSort = eS_FogShader;
// Default RGB/Alpha modes if not specified in script
i = 0;
if (ef->m_Passes.Num() && ef->m_Passes[0].m_TUnits.Num())
{
for (i=0; i<ef->m_Passes.Num(); i++)
{
if (!ef->m_Passes[i].m_TUnits[0].m_eColorOp)
ef->m_Passes[i].m_TUnits[0].m_eColorOp = eCO_MODULATE;
if (ef->m_Passes[i].m_eEvalRGB == eERGB_Fixed && (ef->m_Passes[i].m_FixedColor.dcolor & 0x00ffffff) == 0x00ffffff)
ef->m_Passes[i].m_eEvalRGB = eERGB_Identity;
if (ef->m_Passes[i].m_eEvalAlpha == eEALPHA_Fixed && ef->m_Passes[i].m_FixedColor.bcolor[3] == 255)
ef->m_Passes[i].m_eEvalAlpha = eEALPHA_Identity;
if (ef->m_REs.Num() && ef->m_REs[0]->mfGetType() == eDATA_AnimPolyBlend && ef->m_Passes[i].m_TUnits[0].m_AnimInfo)
ef->m_Passes[i].m_RenderState |= GS_TEXANIM;
}
}
if (ef->m_Deforms)
ef->m_Flags |= EF_NEEDNORMALS;
else
{
for (i=0; i<ef->m_Passes.Num(); i++)
{
if (!ef->m_Passes[i].m_TUnits.Num())
continue;
if (ef->m_Passes[i].m_TUnits[0].m_eGenTC > eGTC_Base)
ef->m_Flags |= EF_NEEDNORMALS;
}
}
i = ef->m_Passes.Num();
memset(pCounts, 0, eSrcPointer_Max);
for (i=0; i<ef->m_HWTechniques.Num(); i++)
{
mfOptimizeShaderHW(ef, ef->m_HWTechniques[i]->m_Passes, 0);
}
mfOptimizeShader(ef, ef->m_Passes, 0);
pCounts[eSrcPointer_LightVector]+=pCounts[eSrcPointer_LAttenuationSpec0];
pCounts[eSrcPointer_LightVector]+=pCounts[eSrcPointer_LAttenuationSpec1];
pCounts[eSrcPointer_LightVector]+=pCounts[eSrcPointer_HalfAngleVector];
pCounts[eSrcPointer_LightVector]+=pCounts[eSrcPointer_NormLightVector];
if (pCounts[eSrcPointer_LightVector] > 1)
ef->m_Flags3 |= EF3_PREPARELV;
if (pCounts[eSrcPointer_HalfAngleVector] > 1)
ef->m_Flags3 |= EF3_PREPAREHAV;
if (pCounts[eSrcPointer_LAttenuationSpec0] > 1)
ef->m_Flags3 |= EF3_PREPARELAS0;
if (pCounts[eSrcPointer_LAttenuationSpec1] > 1)
ef->m_Flags3 |= EF3_PREPARELAS1;
i = ef->m_Passes.Num();
if (ef->m_Flags & EF_SKY)
ef->m_Flags2 |= EF2_NOCASTSHADOWS;
m_bNeedSysBuf = false;
m_bNeedCol = false;
m_bNeedSecCol = false;
m_bNeedTangents = false;
m_bNeedNormal = false;
m_nTC = 0;
for (i=0; i<ef->m_HWTechniques.Num(); i++)
{
bool bTangs = m_bNeedTangents;
bool bNormal = m_bNeedNormal;
int nTC = m_nTC;
m_bNeedTangents = false;
m_bNeedNormal = false;
m_nTC = 0;
mfOptimizeShaderHW(ef, ef->m_HWTechniques[i]->m_Passes, 1);
if (m_bNeedTangents)
ef->m_HWTechniques[i]->m_Flags |= FHF_TANGENTS;
if (m_nTC > 1)
ef->m_HWTechniques[i]->m_Flags |= FHF_LMTC;
m_bNeedTangents = max(m_bNeedTangents, bTangs);
m_bNeedNormal = max(m_bNeedNormal, bNormal);
m_nTC = max(m_nTC, nTC);
}
mfOptimizeShader(ef, ef->m_Passes, 1);
int vf;
if (m_bNeedTangents)
{
ef->m_Flags |= EF_NEEDTANGENTS;
ef->m_LMFlags |= LMF_BUMPMATERIAL;
}
if (m_bNeedNormal || (ef->m_Flags2 & EF2_USELIGHTMATERIAL))
ef->m_Flags |= EF_NEEDNORMALS;
vf = VertFormatForComponents(m_bNeedCol, m_bNeedSecCol, m_bNeedNormal, m_nTC!=0);
ef->m_VertexFormatId = vf;
if (m_bNeedSysBuf)
ef->m_Flags3 |= EF3_NEEDSYSBUF;
//==========================================================
if (ef->m_eSort == eS_Unknown)
ef->m_eSort = eS_Opaque;
if (ef->m_REs.Num() && ef->m_REs[0]->mfGetType() == eDATA_AnimPolyBlend)
ef->m_Flags2 |= EF2_CUSTOMANIMTEX;
if (ef->m_eSort == eS_Unknown)
ef->m_eSort = eS_Opaque;
if (ef->m_eSort <= eS_Opaque)
ef->m_Flags2 |= EF2_FOGOVERLAY1;
else
if (ef->m_Flags & EF_FOGSHADER)
ef->m_Flags2 |= EF2_FOGOVERLAY2;
}
SShader *CShader::mfNewShader(EShClass Class, int num)
{
SShader *ef;
int n;
if (Class == eSH_Temp)
{
for (n=CShader::m_FirstCopyNum; n<MAX_SHADERS; n++)
{
if (!SShader::m_Shaders_known[n])
goto create;
}
iConsole->Exit("MAX_TEMP_SHADERS hit\n");
return NULL;
}
for (n=0; n<CShader::m_Nums; n++)
{
if (!SShader::m_Shaders_known[n])
goto create;
}
if ((n=CShader::m_Nums) >= CShader::m_MaxNums)
{
iConsole->Exit("MAX_SHADERS hit\n");
return NULL;
}
if (num<0)
CShader::m_Nums++;
else
n = num;
create:
#ifdef DEBUGALLOC
#undef new
#endif
ef = new SShader;
#ifdef DEBUGALLOC
#define new DEBUG_CLIENTBLOCK
#endif
if (!ef)
{
iConsole->Exit("CShader::mfNewShader: Couldn't allocate shader %d\n", n);
return m_DefaultShader;
}
SShader::m_Shaders_known[n] = ef;
ef->m_Id = n;
ef->m_nRefCounter = 1;
ef->m_eClass = Class;
return ef;
}
//=========================================================
bool CShader::mfUpdateMergeStatus(SShaderTechnique *hs, TArray<SCGParam4f> *p)
{
for (int n=0; n<p->Num(); n++)
{
if (p->Get(n).m_Flags & PF_DONTALLOW_DYNMERGE)
{
hs->m_Flags |= FHF_NOMERGE;
break;
}
}
if (hs->m_Flags & FHF_NOMERGE)
return true;
return false;
}
//=========================================================================
bool SShader::mfIsValidTime(CCObject *obj, float curtime)
{
int i, j;
SShaderTexUnit *shm;
SShaderPass *sfm;
if (m_REs.Num())
return m_REs[0]->mfIsValidTime(this, obj, curtime);
else
{
for (i=0; i<m_Passes.Num(); i++)
{
sfm = &m_Passes[i];
for (j=0; j<sfm->m_TUnits.Num(); j++)
{
shm = &sfm->m_TUnits[j];
if (!shm->m_AnimInfo)
continue;
if (shm->m_AnimInfo->m_Time && shm->m_AnimInfo->m_TexPics.Num())
{
float t = curtime - obj->m_StartTime;
int m = (int)(t / shm->m_AnimInfo->m_Time);
if (shm->m_AnimInfo->m_bLoop)
m = m % shm->m_AnimInfo->m_NumAnimTexs;
else
if (m < 0)
{
obj->m_StartTime = curtime;
m = 0;
}
int n = 0;
while (m)
{
STexPic *tx = shm->m_AnimInfo->m_TexPics[n];
if (!tx)
return false;
m--;
n++;
}
}
}
}
}
return true;
}
// Animating textures
void SShaderTexUnit::mfUpdate(void)
{
if (m_AnimInfo && m_AnimInfo->m_Time && gRenDev->m_bPauseTimer==0)
{
assert(gRenDev->m_RP.m_RealTime>=0);
uint m = (uint)(gRenDev->m_RP.m_RealTime / m_AnimInfo->m_Time) % m_AnimInfo->m_NumAnimTexs;
assert(m<(uint)m_AnimInfo->m_TexPics.Num());
m_TexPic = m_AnimInfo->m_TexPics[m];
}
}
void SShaderTexUnit::mfUpdateAnim(CCObject *obj, int o)
{
if (m_AnimInfo && m_AnimInfo->m_Time && m_AnimInfo->m_TexPics.Num())
{
float t = gRenDev->m_RP.m_RealTime - obj->m_StartTime;
int m = (int)(t / m_AnimInfo->m_Time);
m += o;
if (m < 0)
{
obj->m_StartTime = gRenDev->m_RP.m_RealTime;
m = 0;
}
if (m_AnimInfo->m_bLoop)
m = m % m_AnimInfo->m_NumAnimTexs;
int n = 0;
STexPic *tx = NULL;
while (m)
{
tx = m_AnimInfo->m_TexPics[n];
if (!tx)
{
//obj->m_ObjFlags |= FOB_NOTVISIBLE;
break;
}
n++;
m--;
}
m_TexPic = tx;
}
}
SEnvTexture *CShader::mfFindSuitableEnvLCMap(Vec3d& Pos, bool bMustExist, int RendFlags, float fDistToCam, CCObject *pObj)
{
double time0 = 0;
ticks(time0);
SEnvTexture *cm = NULL;
int i;
float dist = 999999;
int firstForUse = -1;
int firstFree = -1;
for (i=0; i<MAX_ENVLIGHTCUBEMAPS; i++)
{
SEnvTexture *cur = &gRenDev->m_TexMan->m_EnvLCMaps[i];
Vec3d delta = cur->m_CamPos - Pos;
float s = GetLengthSquared(delta);
if (s < dist)
{
dist = s;
firstForUse = i;
if (!dist)
break;
}
if (!cur->m_bReady && firstFree < 0)
firstFree = i;
}
if (bMustExist)
{
if (firstForUse >= 0)
{
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return &gRenDev->m_TexMan->m_EnvLCMaps[firstForUse];
}
else
return NULL;
}
float curTime = iTimer->GetCurrTime();
int nUpdate = -2;
dist = sqrtf(dist);
if (bMustExist)
nUpdate = -2;
else
if (dist > MAX_ENVLIGHTCUBEMAPSCANDIST_THRESHOLD)
{
if (firstFree >= 0)
nUpdate = firstFree;
else
nUpdate = -1;
}
else
{
float fTimeInterval = max(fDistToCam, 1.0f) * CRenderer::CV_r_envlcmupdateinterval;
float fDelta = curTime - gRenDev->m_TexMan->m_EnvLCMaps[firstForUse].m_TimeLastUsed;
if (fDelta > fTimeInterval)
nUpdate = firstForUse;
}
if (nUpdate == -2)
{
if (!bMustExist)
{
/*for (int i=0; i<6; i++)
{
if (gRenDev->m_TexMan->m_EnvLCMaps[firstForUse].m_nFrameCreated[i]>0 && gRenDev->GetFrameID()-gRenDev->m_TexMan->m_EnvLCMaps[firstForUse].m_nFrameCreated[i]>=CRenderer::CV_r_envlightcmupdatefrequence)
{
gRenDev->m_TexMan->m_EnvLCMaps[firstForUse].m_nFrameCreated[i] = -1;
//gRenDev->m_TexMan->GetAverageColor(&gRenDev->m_TexMan->m_EnvLCMaps[firstForUse], i);
}
}*/
}
// No need to update (Up to date)
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return &gRenDev->m_TexMan->m_EnvLCMaps[firstForUse];
}
if (nUpdate >= 0)
{
if (!(gRenDev->m_TexMan->m_EnvLCMaps[nUpdate].m_Tex->m_Flags & FT_ALLOCATED) || (fDistToCam <= MAX_ENVLIGHTCUBEMAPSCANDIST_UPDATE && gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime < 0.1f))
{
// Reuse old cube-map
if (!(gRenDev->m_TexMan->m_EnvLCMaps[nUpdate].m_Tex->m_Flags & FT_ALLOCATED) && pObj)
{
UCol Amb;
Amb.bcolor[0] = (byte)(pObj->m_AmbColor[0]*255.0f);
Amb.bcolor[1] = (byte)(pObj->m_AmbColor[1]*255.0f);
Amb.bcolor[2] = (byte)(pObj->m_AmbColor[2]*255.0f);
Amb.bcolor[3] = 255;
for (i=0; i<6; i++)
{
gRenDev->m_TexMan->m_EnvLCMaps[nUpdate].m_EnvColors[i].dcolor = Amb.dcolor;
}
}
int n = nUpdate;
gRenDev->m_TexMan->m_EnvLCMaps[n].m_TimeLastUsed = curTime;
gRenDev->m_TexMan->m_EnvLCMaps[n].m_CamPos = Pos;
gRenDev->m_TexMan->ScanEnvironmentCube(&gRenDev->m_TexMan->m_EnvLCMaps[n], RendFlags, CRenderer::CV_r_envlightcmsize, true);
}
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return &gRenDev->m_TexMan->m_EnvLCMaps[nUpdate];
}
// Find oldest slot
dist = 0;
int nOldest = -1;
for (i=0; i<MAX_ENVLIGHTCUBEMAPS; i++)
{
SEnvTexture *cur = &gRenDev->m_TexMan->m_EnvLCMaps[i];
if (dist < curTime-cur->m_TimeLastUsed && !cur->m_bInprogress)
{
dist = curTime - cur->m_TimeLastUsed;
nOldest = i;
}
}
if (nOldest < 0)
{
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return NULL;
}
int n = nOldest;
gRenDev->m_TexMan->m_EnvLCMaps[n].m_TimeLastUsed = curTime;
gRenDev->m_TexMan->m_EnvLCMaps[n].m_CamPos = Pos;
// Fill box colors by nearest cube
if (firstForUse >= 0)
{
for (i=0; i<6; i++)
{
gRenDev->m_TexMan->m_EnvLCMaps[n].m_EnvColors[i].dcolor = gRenDev->m_TexMan->m_EnvLCMaps[firstForUse].m_EnvColors[i].dcolor;
}
}
// Start with positive X
gRenDev->m_TexMan->m_EnvLCMaps[n].m_MaskReady = 0;
gRenDev->m_TexMan->ScanEnvironmentCube(&gRenDev->m_TexMan->m_EnvLCMaps[n], RendFlags, CRenderer::CV_r_envlightcmsize, true);
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return &gRenDev->m_TexMan->m_EnvLCMaps[n];
}
SEnvTexture *CShader::mfFindSuitableEnvCMap(Vec3d& Pos, bool bMustExist, int RendFlags, float fDistToCam)
{
double time0 = 0;
ticks(time0);
SEnvTexture *cm = NULL;
int i;
float dist = 999999;
int firstForUse = -1;
int firstFree = -1;
for (i=0; i<MAX_ENVCUBEMAPS; i++)
{
SEnvTexture *cur = &gRenDev->m_TexMan->m_EnvCMaps[i];
Vec3d delta = cur->m_CamPos - Pos;
float s = GetLengthSquared(delta);
if (s < dist)
{
dist = s;
firstForUse = i;
if (!dist)
break;
}
if (!(cur->m_Tex->m_Flags & FT_ALLOCATED) && firstFree < 0)
firstFree = i;
}
float curTime = iTimer->GetCurrTime();
int nUpdate = -2;
float fTimeInterval = fDistToCam * CRenderer::CV_r_envcmupdateinterval + CRenderer::CV_r_envcmupdateinterval*0.5f;
float fDelta = curTime - gRenDev->m_TexMan->m_EnvCMaps[firstForUse].m_TimeLastUsed;
if (bMustExist)
nUpdate = -2;
else
if (dist > MAX_ENVCUBEMAPSCANDIST_THRESHOLD)
{
if (firstFree >= 0)
nUpdate = firstFree;
else
nUpdate = -1;
}
else
if (fDelta > fTimeInterval)
nUpdate = firstForUse;
if (nUpdate == -2)
{
// No need to update (Up to date)
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return &gRenDev->m_TexMan->m_EnvCMaps[firstForUse];
}
if (nUpdate >= 0)
{
if (!(gRenDev->m_TexMan->m_EnvCMaps[nUpdate].m_Tex->m_Flags & FT_ALLOCATED) || gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime < 0.1f)
{
int n = nUpdate;
gRenDev->m_TexMan->m_EnvCMaps[n].m_TimeLastUsed = curTime;
gRenDev->m_TexMan->m_EnvCMaps[n].m_CamPos = Pos;
gRenDev->m_TexMan->ScanEnvironmentCube(&gRenDev->m_TexMan->m_EnvCMaps[n], RendFlags, -1, false);
}
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return &gRenDev->m_TexMan->m_EnvCMaps[nUpdate];
}
dist = 0;
firstForUse = -1;
for (i=0; i<MAX_ENVCUBEMAPS; i++)
{
SEnvTexture *cur = &gRenDev->m_TexMan->m_EnvCMaps[i];
if (dist < curTime-cur->m_TimeLastUsed && !cur->m_bInprogress)
{
dist = curTime - cur->m_TimeLastUsed;
firstForUse = i;
}
}
if (firstForUse < 0)
{
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return NULL;
}
int n = firstForUse;
gRenDev->m_TexMan->m_EnvCMaps[n].m_TimeLastUsed = curTime;
gRenDev->m_TexMan->m_EnvCMaps[n].m_CamPos = Pos;
gRenDev->m_TexMan->ScanEnvironmentCube(&gRenDev->m_TexMan->m_EnvCMaps[n], RendFlags, -1, false);
unticks(time0);
gRenDev->m_RP.m_PS.m_fEnvCMapUpdateTime += (float)(time0*1000.0*g_SecondsPerCycle);
return &gRenDev->m_TexMan->m_EnvCMaps[n];
}
Vec3d sDeltAngles(Vec3d Ang0, Vec3d Ang1)
{
Vec3d out;
for (int i=0; i<3; i++)
{
float a0 = Ang0[i];
a0 = (float)((360.0/65536) * ((int)(a0*(65536/360.0)) & 65535)); // angmod
float a1 = Ang1[i];
a1 = (float)((360.0/65536) * ((int)(a0*(65536/360.0)) & 65535));
out[i] = a0 - a1;
}
return out;
}
SEnvTexture *CShader::mfFindSuitableEnvTex(Vec3d& Pos, Vec3d& Angs, bool bMustExist, int RendFlags, bool bUseExistingREs, SShader *pSH, SRenderShaderResources *pRes, CCObject *pObj, bool bReflect, CRendElement *pRE)
{
SEnvTexture *cm = NULL;
int i;
float distO = 999999;
float adist = 999999;
int firstForUse = -1;
Vec3d objPos;
if (!pObj)
bReflect = false;
else
{
if (pRE)
pRE->mfCenter(objPos, pObj);
else
objPos = pObj->GetTranslation();
}
float dist = 999999;
for (i=0; i<MAX_ENVTEXTURES; i++)
{
SEnvTexture *cur = &gRenDev->m_TexMan->m_EnvTexts[i];
if (cur->m_bReflected != bReflect)
continue;
float s = GetLengthSquared((cur->m_CamPos - Pos));
Vec3d angDelta = sDeltAngles(Angs, cur->m_Angle);
float a = GetLengthSquared(angDelta);
float so = 0;
if (bReflect)
so = GetLengthSquared((cur->m_ObjPos - objPos));
if (s < dist && a < adist && so < distO)
{
dist = s;
adist = a;
distO = so;
firstForUse = i;
if (!so && !s && !a)
break;
}
}
if (bMustExist && firstForUse >= 0)
return &gRenDev->m_TexMan->m_EnvTexts[firstForUse];
if (bReflect)
dist = distO;
//return NULL;
float curTime = iTimer->GetCurrTime();
if (firstForUse >= 0 && dist <= MAX_ENVTEXSCANDIST)
{
if (!bMustExist && curTime - gRenDev->m_TexMan->m_EnvTexts[firstForUse].m_TimeLastUsed > CRenderer::CV_r_envtexupdateinterval)
{
int n = firstForUse;
gRenDev->m_TexMan->m_EnvTexts[n].m_TimeLastUsed = curTime;
gRenDev->m_TexMan->m_EnvTexts[n].m_CamPos = Pos;
gRenDev->m_TexMan->m_EnvTexts[n].m_Angle = Angs;
gRenDev->m_TexMan->m_EnvTexts[n].m_ObjPos = objPos;
gRenDev->m_TexMan->m_EnvTexts[n].m_bReflected = bReflect;
gRenDev->m_TexMan->ScanEnvironmentTexture(&gRenDev->m_TexMan->m_EnvTexts[firstForUse], pSH, pRes, RendFlags, bUseExistingREs);
}
return &gRenDev->m_TexMan->m_EnvTexts[firstForUse];
}
if (bMustExist)
return NULL;
dist = 0;
firstForUse = -1;
for (i=0; i<MAX_ENVTEXTURES; i++)
{
SEnvTexture *cur = &gRenDev->m_TexMan->m_EnvTexts[i];
if (dist < curTime-cur->m_TimeLastUsed && !cur->m_bInprogress)
{
dist = curTime - cur->m_TimeLastUsed;
firstForUse = i;
}
}
if (firstForUse < 0)
return NULL;
i = firstForUse;
gRenDev->m_TexMan->m_EnvTexts[i].m_TimeLastUsed = curTime;
gRenDev->m_TexMan->m_EnvTexts[i].m_CamPos = Pos;
gRenDev->m_TexMan->m_EnvTexts[i].m_ObjPos = objPos;
gRenDev->m_TexMan->m_EnvTexts[i].m_Angle = Angs;
gRenDev->m_TexMan->m_EnvTexts[i].m_bReflected = bReflect;
gRenDev->m_TexMan->ScanEnvironmentTexture(&gRenDev->m_TexMan->m_EnvTexts[i], pSH, pRes, RendFlags, bUseExistingREs);
return &gRenDev->m_TexMan->m_EnvTexts[i];
}
//=================================================================================================
static float sFRand()
{
return rand() / (FLOAT)RAND_MAX;
}
// Update TexGen and TexTransform matrices for current material texture
void SEfResTexture::Update(int nTU)
{
int i;
if (m_TexModificator.m_UpdateFlags & RBMF_NOUPDATE)
return;
gRenDev->m_RP.m_ShaderTexResources[nTU] = this;
int nFrameID = gRenDev->GetFrameID();
if (m_TexModificator.m_nFrameUpdated == nFrameID && m_TexModificator.m_nLastRecursionLevel == SRendItem::m_RecurseLevel)
{
gRenDev->m_RP.m_FlagsModificators |= m_TexModificator.m_UpdateFlags<<nTU;
return;
}
m_TexModificator.m_nFrameUpdated = nFrameID;
m_TexModificator.m_nLastRecursionLevel = SRendItem::m_RecurseLevel;
m_TexModificator.m_UpdateFlags = 0;
bool bTr = false;
bool bTranspose = false;
Plane Pl;
Plane PlTr;
if (m_TexModificator.m_Tiling[0] == 0)
m_TexModificator.m_Tiling[0] = 1.0f;
if (m_TexModificator.m_Tiling[1] == 0)
m_TexModificator.m_Tiling[1] = 1.0f;
if (m_TexModificator.m_eUMoveType != ETMM_NoChange || m_TexModificator.m_eVMoveType != ETMM_NoChange || m_TexModificator.m_eRotType != ETMR_NoChange
|| m_TexModificator.m_Offs[0]!=0.0f || m_TexModificator.m_Offs[1]!=0.0f || m_TexModificator.m_Tiling[0]!=1.0f || m_TexModificator.m_Tiling[1]!=1.0f)
{
m_TexModificator.m_TexMatrix.SetIdentity();
float fTime = gRenDev->m_RP.m_RealTime;
bTr = true;
switch(m_TexModificator.m_eRotType)
{
case ETMR_Fixed:
{
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix *
Matrix44(1,0,0,0,
0,1,0,0,
m_TexModificator.m_RotOscCenter[0],m_TexModificator.m_RotOscCenter[1],1,0,
0,0,0,1);
if (m_TexModificator.m_RotOscPhase[0])
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationX(Word2Degr(m_TexModificator.m_RotOscPhase[0])*PI/180.0f);
if (m_TexModificator.m_RotOscPhase[1])
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationY(Word2Degr(m_TexModificator.m_RotOscPhase[1])*PI/180.0f);
if (m_TexModificator.m_RotOscPhase[2])
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationZ(Word2Degr(m_TexModificator.m_RotOscPhase[2])*PI/180.0f);
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix *
Matrix44(1,0,0,0,
0,1,0,0,
-m_TexModificator.m_RotOscCenter[0],-m_TexModificator.m_RotOscCenter[1],1,0,
0,0,0,1);
}
break;
case ETMR_Constant:
{
fTime *= 1000.0f;
float fxAmp = Word2Degr(m_TexModificator.m_RotOscAmplitude[0]) * fTime * PI/180.0f;
float fyAmp = Word2Degr(m_TexModificator.m_RotOscAmplitude[1]) * fTime * PI/180.0f;
float fzAmp = Word2Degr(m_TexModificator.m_RotOscAmplitude[2]) * fTime * PI/180.0f;
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix *
Matrix44(1,0,0,0,
0,1,0,0,
m_TexModificator.m_RotOscCenter[0],m_TexModificator.m_RotOscCenter[1],1,0,
0,0,0,1);
if (fxAmp)
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationX(fxAmp);
if (fyAmp)
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationY(fyAmp);
if (fzAmp)
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationZ(fzAmp);
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix *
Matrix44(1,0,0,0,
0,1,0,0,
-m_TexModificator.m_RotOscCenter[0],-m_TexModificator.m_RotOscCenter[1],1,0,
0,0,0,1);
}
break;
case ETMR_Oscillated:
{
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix *
Matrix44(1,0,0,0,
0,1,0,0,
-m_TexModificator.m_RotOscCenter[0],-m_TexModificator.m_RotOscCenter[1],1,0,
0,0,0,1);
float S_X = fTime * Word2Degr(m_TexModificator.m_RotOscRate[0]);
float d_X = Word2Degr(m_TexModificator.m_RotOscAmplitude[0]) * cry_sinf(2.0f * PI * ((S_X - cry_floorf(S_X)) + Word2Degr(m_TexModificator.m_RotOscPhase[0])));
float S_Y = fTime * Word2Degr(m_TexModificator.m_RotOscRate[1]);
float d_Y = Word2Degr(m_TexModificator.m_RotOscAmplitude[1]) * cry_sinf(2.0f * PI * ((S_Y - cry_floorf(S_Y)) + Word2Degr(m_TexModificator.m_RotOscPhase[1])));
float S_Z = fTime * Word2Degr(m_TexModificator.m_RotOscRate[2]);
float d_Z = Word2Degr(m_TexModificator.m_RotOscAmplitude[2]) * cry_sinf(2.0f * PI * ((S_Z - cry_floorf(S_Z)) + Word2Degr(m_TexModificator.m_RotOscPhase[2])));
if (d_X)
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationX(d_X);
if (d_Y)
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationY(d_Y);
if (d_Z)
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationZ(d_Z);
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix *
Matrix44(1,0,0,0,
0,1,0,0,
-m_TexModificator.m_RotOscCenter[0],-m_TexModificator.m_RotOscCenter[1],1,0,
0,0,0,1);
}
break;
}
float Su = gRenDev->m_RP.m_RealTime * m_TexModificator.m_UOscRate;
float Sv = gRenDev->m_RP.m_RealTime * m_TexModificator.m_VOscRate;
switch(m_TexModificator.m_eUMoveType)
{
case ETMM_Pan:
{
float du = m_TexModificator.m_UOscAmplitude * cry_sinf(2.0f * PI * (Su - cry_floorf(Su)) + 2.f * PI * m_TexModificator.m_UOscPhase);
m_TexModificator.m_TexMatrix(2,0) = du;
}
break;
case ETMM_Fixed:
{
float du = m_TexModificator.m_Offs[0];
m_TexModificator.m_TexMatrix(2,0) = du;
}
break;
case ETMM_Constant:
{
float du = m_TexModificator.m_UOscAmplitude * Su; //(Su - cry_floorf(Su));
m_TexModificator.m_TexMatrix(2,0) = du;
}
break;
case ETMM_Jitter:
{
if( m_TexModificator.m_LastUTime < 1.0f || m_TexModificator.m_LastUTime > Su + 1.0f )
m_TexModificator.m_LastUTime = m_TexModificator.m_UOscPhase + cry_floorf(Su);
if( Su-m_TexModificator.m_LastUTime > 1.0f )
{
m_TexModificator.m_CurrentUJitter = sFRand() * m_TexModificator.m_UOscAmplitude;
m_TexModificator.m_LastUTime = m_TexModificator.m_UOscPhase + cry_floorf(Su);
}
m_TexModificator.m_TexMatrix(2,0) = m_TexModificator.m_CurrentUJitter;
}
break;
case ETMM_Stretch:
{
float du = m_TexModificator.m_UOscAmplitude * cry_sinf(2.0f * PI * (Su - cry_floorf(Su)) + 2.0f * PI * m_TexModificator.m_UOscPhase);
m_TexModificator.m_TexMatrix(0,0) = 1.0f+du;
}
break;
case ETMM_StretchRepeat:
{
float du = m_TexModificator.m_UOscAmplitude * cry_sinf(0.5f * PI * (Su - cry_floorf(Su)) + 2.0f * PI * m_TexModificator.m_UOscPhase);
m_TexModificator.m_TexMatrix(0,0) = 1.0f+du;
}
break;
}
switch(m_TexModificator.m_eVMoveType)
{
case ETMM_Pan:
{
float dv = m_TexModificator.m_VOscAmplitude * cry_sinf(2.0f * PI * (Sv - cry_floorf(Sv)) + 2.0f * PI * m_TexModificator.m_VOscPhase);
m_TexModificator.m_TexMatrix(2,1) = dv;
}
break;
case ETMM_Fixed:
{
float dv = m_TexModificator.m_Offs[1];
m_TexModificator.m_TexMatrix(2,1) = dv;
}
break;
case ETMM_Constant:
{
float dv = m_TexModificator.m_VOscAmplitude * Sv; //(Sv - cry_floorf(Sv));
m_TexModificator.m_TexMatrix(2,1) = dv;
}
break;
case ETMM_Jitter:
{
if( m_TexModificator.m_LastVTime < 1.0f || m_TexModificator.m_LastVTime > Sv + 1.0f )
m_TexModificator.m_LastVTime = m_TexModificator.m_VOscPhase + cry_floorf(Sv);
if( Sv-m_TexModificator.m_LastVTime > 1.0f )
{
m_TexModificator.m_CurrentVJitter = sFRand() * m_TexModificator.m_VOscAmplitude;
m_TexModificator.m_LastVTime = m_TexModificator.m_VOscPhase + cry_floorf(Sv);
}
m_TexModificator.m_TexMatrix(2,1) = m_TexModificator.m_CurrentVJitter;
}
break;
case ETMM_Stretch:
{
float dv = m_TexModificator.m_VOscAmplitude * cry_sinf(2.0f * PI * (Sv - cry_floorf(Sv)) + 2.0f * PI * m_TexModificator.m_VOscPhase);
m_TexModificator.m_TexMatrix(1,1) = 1.0f+dv;
}
break;
case ETMM_StretchRepeat:
{
float dv = m_TexModificator.m_VOscAmplitude * cry_sinf(0.5f * PI * (Sv - cry_floorf(Sv)) + 2.0f * PI * m_TexModificator.m_VOscPhase);
m_TexModificator.m_TexMatrix(1,1) = 1.0f+dv;
}
break;
}
if (m_TexModificator.m_Offs[0]!=0.0f || m_TexModificator.m_Offs[1]!=0.0f || m_TexModificator.m_Tiling[0]!=1.0f || m_TexModificator.m_Tiling[1]!=1.0f || m_TexModificator.m_Rot[0] || m_TexModificator.m_Rot[1] || m_TexModificator.m_Rot[2])
{
float du = m_TexModificator.m_Offs[0];
float dv = m_TexModificator.m_Offs[1];
float su = m_TexModificator.m_Tiling[0];
float sv = m_TexModificator.m_Tiling[1];
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix *
Matrix44(su,0,0,0,
0,sv,0,0,
du,dv,1,0,
0,0,0,1);
if (m_TexModificator.m_Rot[0])
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationX(Word2Degr(m_TexModificator.m_Rot[0])*PI/180.0f);
if (m_TexModificator.m_Rot[1])
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationY(Word2Degr(m_TexModificator.m_Rot[1])*PI/180.0f);
if (m_TexModificator.m_Rot[2])
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix * Matrix33::CreateRotationZ(Word2Degr(m_TexModificator.m_Rot[2])*PI/180.0f);
if (m_TexModificator.m_Rot[0] || m_TexModificator.m_Rot[1] || m_TexModificator.m_Rot[2])
m_TexModificator.m_TexMatrix = m_TexModificator.m_TexMatrix *
Matrix44(su,0,0,0,
0,sv,0,0,
-du,-dv,1,0,
0,0,0,1);
}
}
if (m_TexModificator.m_eTGType != ETG_Stream)
{
switch (m_TexModificator.m_eTGType)
{
case ETG_World:
{
m_TexModificator.m_UpdateFlags |= RBMF_TCGOL0;
for (i=0; i<4; i++)
{
memset(&Pl, 0, sizeof(Pl));
float *fPl = (float *)&Pl;
fPl[i] = 1.0f;
PlTr = TransformPlane2_NoTrans(gRenDev->m_RP.m_pCurObject->m_Matrix, Pl);
m_TexModificator.m_TexGenMatrix(i,0) = PlTr.n.x;
m_TexModificator.m_TexGenMatrix(i,1) = PlTr.n.y;
m_TexModificator.m_TexGenMatrix(i,2) = PlTr.n.z;
m_TexModificator.m_TexGenMatrix(i,3) = PlTr.d;
}
}
break;
case ETG_Camera:
{
m_TexModificator.m_UpdateFlags |= RBMF_TCGOL0;
for (i=0; i<4; i++)
{
memset(&Pl, 0, sizeof(Pl));
float *fPl = (float *)&Pl;
fPl[i] = 1.0f;
PlTr = TransformPlane2_NoTrans(gRenDev->m_ViewMatrix, Pl);
m_TexModificator.m_TexGenMatrix(i,0) = PlTr.n.x;
m_TexModificator.m_TexGenMatrix(i,1) = PlTr.n.y;
m_TexModificator.m_TexGenMatrix(i,2) = PlTr.n.z;
m_TexModificator.m_TexGenMatrix(i,3) = PlTr.d;
}
}
break;
case ETG_WorldEnvMap:
{
m_TexModificator.m_UpdateFlags |= RBMF_TCGRM0;
if (bTr)
m_TexModificator.m_TexMatrix = gRenDev->m_CameraMatrix * m_TexModificator.m_TexMatrix;
else
m_TexModificator.m_TexMatrix = gRenDev->m_CameraMatrix;
bTr = true;
if (m_TU.m_eTexType == eTT_Cubemap)
bTranspose = true;
}
break;
case ETG_CameraEnvMap:
{
m_TexModificator.m_UpdateFlags |= RBMF_TCGRM0;
}
break;
case ETG_SphereMap:
{
m_TexModificator.m_UpdateFlags |= RBMF_TCGSM0;
if (bTr)
m_TexModificator.m_TexMatrix = gRenDev->m_RP.m_pCurObject->m_Matrix * m_TexModificator.m_TexMatrix;
else
m_TexModificator.m_TexMatrix = gRenDev->m_RP.m_pCurObject->m_Matrix;
//bTr = true;
//bTranspose = true;
}
break;
case ETG_NormalMap:
{
m_TexModificator.m_UpdateFlags |= RBMF_TCGNM0;
}
break;
}
}
if (bTr)
{
m_TexModificator.m_UpdateFlags |= RBMF_TCM0;
if (m_TexModificator.m_bTexGenProjected)
{
m_TexModificator.m_TexMatrix(0,3) = m_TexModificator.m_TexMatrix(0,2);
m_TexModificator.m_TexMatrix(1,3) = m_TexModificator.m_TexMatrix(1,2);
m_TexModificator.m_TexMatrix(2,3) = m_TexModificator.m_TexMatrix(2,2);
m_TexModificator.m_TexMatrix(3,3) = m_TexModificator.m_TexMatrix(3,2);
}
else
{
m_TexModificator.m_TexMatrix(3,0) = m_TexModificator.m_TexMatrix(2,0);
m_TexModificator.m_TexMatrix(3,1) = m_TexModificator.m_TexMatrix(2,1);
}
if (bTranspose)
m_TexModificator.m_TexMatrix.Transpose();
}
if (!(m_TexModificator.m_UpdateFlags & (RBMF_TCG | RBMF_TCM)))
m_TexModificator.m_UpdateFlags |= RBMF_NOUPDATE;
gRenDev->m_RP.m_FlagsModificators |= m_TexModificator.m_UpdateFlags<<nTU;
}
void CShader::mfBeginFrame()
{
memset(&gRenDev->m_RP.m_PS, 0, sizeof(SPipeStat));
m_Frame++;
gRenDev->m_RP.m_Profile.Free();
gRenDev->m_RP.m_bStartPipeline = false;
gRenDev->m_RP.m_WasPortals = 0;
gRenDev->m_RP.m_CurPortal = 0;
gRenDev->m_RP.m_CurWarp = NULL;
gRenDev->m_RP.m_fMinDepthRange = 0;
gRenDev->m_RP.m_fMaxDepthRange = 1.0f;
SRendItem::m_RecurseLevel = 0;
}
// Shaders caching
//=================================================================
SShaderCache::~SShaderCache()
{
SAFE_DELETE(m_pRes);
}
bool CShader::CloseCacheFile(SShaderCache *pC)
{
SAFE_DELETE (pC);
return true;
}
SShaderCache *CShader::OpenCacheFile(const char *szName, float fVersion)
{
SShaderCache *pCache = new SShaderCache;
SShaderCacheHeader hd;
bool bValid = true;
CResFile *rf = new CResFile(szName, eFSD_id);
if (!rf->mfOpen(RA_READ))
{
rf->mfClose();
bValid = false;
}
else
{
rf->mfFileRead(0xffff, &hd);
if (hd.m_SizeOf != sizeof(SShaderCacheHeader))
bValid = false;
else
if (hd.m_MajorVer != (int)fVersion || hd.m_MinorVer != (int)(((float)fVersion - (float)(int)fVersion)*10.1f))
bValid = false;
else
if (rf->mfGetHolesSize()/rf->mfGetResourceSize()*100 > 20)
bValid = false;
rf->mfClose();
if (bValid)
{
if (!rf->mfOpen(RA_READ|RA_WRITE))
{
rf->mfClose();
bValid = false;
}
}
}
if (!bValid)
{
rf->mfOpen(RA_CREATE);
SDirEntry de;
de.ID = 0xffff;
de.earc = eARC_NONE;
de.size = sizeof(SShaderCacheHeader);
de.eid = eRI_BIN;
de.user.data = &hd;
hd.m_SizeOf = sizeof(SShaderCacheHeader);
hd.m_MinorVer = (int)(((float)fVersion - (float)(int)fVersion)*10.1f);
hd.m_MajorVer = (int)fVersion;
rf->mfFileAdd(&de);
rf->mfFlush();
}
pCache->m_pRes = rf;
pCache->m_Name = szName;
pCache->m_Header = hd;
return pCache;
}
bool CShader::FlushCacheFile(SShaderCache *pCache)
{
if (!pCache || !pCache->m_pRes)
return false;
pCache->m_pRes->mfFlush();
return true;
}
bool CShader::AddCacheItem(SShaderCache *pCache, SShaderCacheHeaderItem *pItem, byte *pData, int nLen, bool bFlush)
{
assert (pCache && pCache->m_pRes);
if (!pCache || !pCache->m_pRes)
return false;
assert(pItem->m_nVariables < 32);
byte *pNew = new byte[sizeof(SShaderCacheHeaderItem)+nLen];
memcpy(pNew, pItem, sizeof(SShaderCacheHeaderItem));
memcpy(&pNew[sizeof(SShaderCacheHeaderItem)], pData, nLen);
SDirEntry de;
de.ID = pItem->m_nMask;
de.earc = eARC_NONE;
de.size = nLen+sizeof(SShaderCacheHeaderItem);
de.eid = eRI_BIN;
de.user.data = pNew;
de.flags = RF_TEMPDATA;
pCache->m_pRes->mfFileAdd(&de);
if (bFlush)
pCache->m_pRes->mfFlush();
return true;
}
bool CShader::FreeCacheItem(SShaderCache *pCache, int nMask)
{
assert (pCache && pCache->m_pRes);
if (!pCache || !pCache->m_pRes)
return false;
CResFile *rf = pCache->m_pRes;
SDirEntry *de = rf->mfGetEntry(nMask);
if (!de)
return false;
SAFE_DELETE_ARRAY(de->user.data);
return true;
}
SShaderCacheHeaderItem *CShader::GetCacheItem(SShaderCache *pCache, int nMask)
{
assert (pCache && pCache->m_pRes);
if (!pCache || !pCache->m_pRes)
return NULL;
CResFile *rf = pCache->m_pRes;
SDirEntry *de = rf->mfGetEntry(nMask);
if (!de)
return NULL;
rf->mfFileRead(de);
void *pData = rf->mfFileGetBuf(de);
if (!pData)
return NULL;
return (SShaderCacheHeaderItem *) pData;
}
static void sConvert(const char *Path)
{
struct _finddata_t fileinfo;
intptr_t handle;
char nmf[256];
char nmfDst[256];
char dirn[256];
strcpy(dirn, Path);
strcat(dirn, "*.cgbin");
ConvertUnixToDosName(dirn, dirn);
handle = iSystem->GetIPak()->FindFirst (dirn, &fileinfo);
if (handle == -1)
return;
do
{
if (fileinfo.name[0] == '.')
continue;
if (fileinfo.attrib & _A_SUBDIR)
continue;
strcpy(nmf, Path);
strcat(nmf, fileinfo.name);
SShaderCacheHeader hd;
CResFile *rfSrc = new CResFile(nmf, eFSD_id);
if (!rfSrc->mfOpen(RA_READ))
{
rfSrc->mfClose();
continue;
}
int i;
StripExtension(nmf, nmfDst);
AddExtension(nmfDst, ".cgb");
CResFile *rfDst = new CResFile(nmfDst, eFSD_id);
rfDst->mfOpen(RA_CREATE);
TArray<SDirEntry *> Dir;
int nNum = rfSrc->mfGetNumFiles();
rfSrc->mfGetDir(Dir);
for (i=0; i<Dir.Num(); i++)
{
SDirEntry *d = Dir[i];
int size = rfSrc->mfFileRead(d);
void *pData = rfSrc->mfFileGetBuf(d);
if (pData)
{
d->size = size;
d->earc = eARC_NONE;
rfDst->mfFileAdd(d);
}
}
rfDst->mfFlush();
rfDst->mfClose();
rfSrc->mfClose();
} while (iSystem->GetIPak()->FindNext( handle, &fileinfo ) != -1);
iSystem->GetIPak()->FindClose (handle);
}
bool CShader::PackCache()
{
sConvert("Shaders\\Cache\\CGPShaders\\");
sConvert("Shaders\\Cache\\CGVShaders\\");
return true;
}