/*============================================================================= 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 #if defined(WIN32) || defined(WIN64) #include #include #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::m_Shaders_known; TArray SShader::m_ShaderResources_known; TArray 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; iSize(); } 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; iSize(); } 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; im_Stencil); SAFE_DELETE(m_State); } for (i=0; imfFree(); } m_Passes.Free(); if (m_Deforms) { delete m_Deforms; m_Deforms = NULL; } for (i=0; im_Vars) delete [] hc->m_Vars; } m_HWConditions.Free(); if (m_Templates) { m_Templates->mfFree(this); m_Templates = NULL; } if (m_ShaderGenParams) { for (i=0; im_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; imfCopyConstruct(); } } if (src.m_HWTechniques.Num()) { m_HWTechniques.Create(src.m_HWTechniques.Num()); for (i=0; i; 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; im_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& 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; npm_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& 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; npm_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; im_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; im_TUnits.Num(); j++) { if (ps->m_TUnits[j].m_TexPic && ps->m_TUnits[j].m_TexPic->m_Bind < EFTT_MAX) nMask |= 1<m_TUnits[j].m_TexPic->m_Bind; } } for (n=0; nm_Passes.Num(); i++) { psHW = &pHT->m_Passes[i]; for (j=0; jm_TUnits.Num(); j++) { if (psHW->m_TUnits[j].m_TexPic && psHW->m_TUnits[j].m_TexPic->m_Bind < EFTT_MAX) nMask |= 1<m_TUnits[j].m_TexPic->m_Bind; } } } return nMask; } //================================================================================ void CShader::mfClearShaders (TArray &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; iLog("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; im_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; iLog("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; iLog("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; iname[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; jbegin(); 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; iGetIPak()->FClose(fp); } for (i=0; iGetIPak()->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; im_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 ''..."); ef = mfNewShader(eSH_Misc, -1); m_DefaultShader = ef; mfAddToHash("", 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& 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& Layers, int Stage) { int i, j; if (Stage == 0) { bool bOpaq = false;; for (i=0; iePT]++; } 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; im_nPreprocess |= FSPR_SCANLCM; Alpha[i] = Layers[i].m_eEvalAlpha; RGB[i] = Layers[i].m_eEvalRGB; for (j=0; jm_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 Pts; for (i=0; im_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; jePT) { 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; im_HWTechniques.Num(); i++) { for (j=0; jm_HWTechniques[i]->m_Pointers.Num(); j++) { Pts.AddElem(ef->m_HWTechniques[i]->m_Pointers[j]); } } for (i=0; iePT) { 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& Layers, int Stage) { int i, j; if (Stage == 0) { bool bOpaq = false;; for (i=0; im_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; im_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; im_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; im_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; im_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; im_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; im_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; nExit("MAX_TEMP_SHADERS hit\n"); return NULL; } for (n=0; n= 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 *p) { for (int n=0; nNum(); 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; im_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; im_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; im_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; im_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; im_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; im_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; im_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<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<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 Dir; int nNum = rfSrc->mfGetNumFiles(); rfSrc->mfGetDir(Dir); for (i=0; imfFileRead(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; }