/*============================================================================= GLCGPShader.cpp : OpenGL cg fragment programs support. Copyright (c) 2001 Crytek Studios. All Rights Reserved. Revision history: * Created by Honitch Andrey =============================================================================*/ #include "RenderPCH.h" #include "DriverD3D9.h" #include "D3DCGPShader.h" #include "D3DCGVProgram.h" #ifndef PS2 #include #include #else #include "File.h" #endif #undef THIS_FILE static char THIS_FILE[] = __FILE__; //======================================================================= // init memory pool usage #ifndef PS2 _ACCESS_POOL; #endif vec4_t CCGPShader_D3D::m_CurParams[32]; TArray CPShader::m_PShaders; CPShader *CPShader::m_CurRC; CPShader *CPShader::mfForName(const char *name, std::vector& Structs, std::vector& Macros, char *entryFunc, EShaderVersion eSHV, uint64 nMaskGen) { int i; if (!name || !name[0]) return NULL; if (!(gRenDev->GetFeatures() & (RFT_HW_TS))) return NULL; for (i=0; im_Name.c_str()) && m_PShaders[i]->m_nMaskGen == nMaskGen) { m_PShaders[i]->m_nRefCounter++; return m_PShaders[i]; } } CPShader *p = NULL; { CPShader *pr = new CCGPShader_D3D; pr->m_Name = name; pr->m_Id = i; m_PShaders.AddElem(pr); pr->m_nRefCounter = 1; pr->m_nMaskGen = nMaskGen; p = pr; } if (eSHV == eSHV_PS_2_0) p->m_Flags |= PSFI_PS20ONLY; else if (eSHV == eSHV_PS_3_0) p->m_Flags |= PSFI_PS30ONLY; else if (eSHV == eSHV_PS_2_x) p->m_Flags |= PSFI_PS2XONLY; p->m_Flags |= PSFI_FX; CCGPShader_D3D *pr = (CCGPShader_D3D *)p; pr->mfConstructFX(Structs, Macros, entryFunc); return p; } void CCGPShader_D3D::mfConstructFX(std::vector& Structs, std::vector& Macros, char *entryFunc) { int i; char dir[128]; sprintf(dir, "%sDeclarations/CGPShaders/", gRenDev->m_cEF.m_HWPath); m_EntryFunc = entryFunc; for (i=0; iMacroName.c_str(), pr->Macro.c_str()); SFXStruct str; str.m_Name = ""; str.m_Struct = s; m_Functions.push_back(str); } for (i=0; im_cEF.mfCheckObjectDependParams(&m_ParamsNoObj, &m_ParamsObj); } void CCGPShader_D3D::mfAddFXParameter(SFXParam *pr, const char *ParamName, SShader *ef) { SCGParam4f CGpr; int i; char scr[256]; if (pr->m_Assign.size()) { const char *translatedParam = pr->m_Assign.c_str(); if (!stricmp(translatedParam, "Ambient")) translatedParam = "AmbLightColor"; else if (!stricmp(translatedParam, "Diffuse")) translatedParam = "DiffuseColor"; if (pr->m_nRows == 4) sprintf(scr, "Name=%s Comp '%s[0]' Comp '%s[1]' Comp '%s[2]' Comp '%s[3]'", ParamName, translatedParam, translatedParam, translatedParam, translatedParam); else if (pr->m_nRows == 3) sprintf(scr, "Name=%s Comp '%s[0]' Comp '%s[1]' Comp '%s[2]'", ParamName, translatedParam, translatedParam, translatedParam); else if (pr->m_nRows <= 1) sprintf(scr, "Name=%s Comp '%s'", ParamName, translatedParam); gRenDev->m_cEF.mfCompileCGParam(scr, ef, &m_ParamsNoObj); } else { SParamComp_Const pc; CGpr.m_Name = ParamName; switch(pr->m_Type) { case eType_FLOAT: pc.m_Val = pr->m_Value.m_Float; CGpr.m_Comps[0] = SParamComp::mfAdd(&pc); break; case eType_VECTOR: { for (i=0; i<3; i++) { pc.m_Val = pr->m_Value.m_Vector[i]; CGpr.m_Comps[i] = SParamComp::mfAdd(&pc); } } break; case eType_FCOLOR: { for (i=0; i<4; i++) { pc.m_Val = pr->m_Value.m_Color[i]; CGpr.m_Comps[i] = SParamComp::mfAdd(&pc); } } break; default: assert(0); } m_ParamsNoObj.AddElem(CGpr); } } bool CCGPShader_D3D::mfGetFXParamNameByID(int nParam, char *ParamName) { int i; ParamName[0] = 0; if (!m_Functions.size()) return false; if (!m_EntryFunc.GetIndex()) return false; for (i=0; i 0x20) { s++; } SkipCharacters(&s, kWhiteSpace); n = 0; while (*s > 0x20 && *s != ',' && *s != ')') { ParamName[n++] = *s++; } ParamName[n] = 0; break; } } return true; } struct SAliasName { bool bParam; std::string Name; std::string NameINT; }; struct SAliasSampler { SFXSampler *fxSampler; std::string NameINT; SAliasSampler() { fxSampler = NULL; } }; void CCGPShader_D3D::mfGatherFXParameters(const char *buf, SShaderPassHW *pSHPass, std::vector& Params, std::vector& Samplers, std::vector& Textures, SShader *ef) { assert(m_Insts.Num()); assert(!pSHPass->m_TUnits.Num()); if (!m_Insts.Num()) return; SCGInstance *cgi = &m_Insts[0]; if (!cgi->m_BindVars) return; int i, j; assert(*buf == '('); buf++; SAliasSampler samps[MAX_TMU]; int nMaxSampler = -1; std::vector Aliases; int nParam = 0; char PSParam[256]; while (true) { int n = 0; char szParam[128]; while(*buf <= 0x20 || *buf == ',') { buf++; } while(*buf > 0x20 && *buf != ',' && *buf != ')') { szParam[n++] = *buf++; } szParam[n] = 0; if (!n) break; for (i=0; im_Name.c_str(), szParam)) { SAliasName an; an.bParam = true; an.Name = szParam; if (mfGetFXParamNameByID(nParam, PSParam)) an.NameINT = PSParam; else { assert(0); an.NameINT = szParam; } Aliases.push_back(an); break; } } if (i == Params.size()) { for (i=0; im_Name.c_str(), szParam)) { SAliasName an; an.bParam = false; an.Name = szParam; if (mfGetFXParamNameByID(nParam, PSParam)) an.NameINT = PSParam; else { assert(0); an.NameINT = szParam; } Aliases.push_back(an); break; } } if (i == Samplers.size()) iLog->Log("Warning: Couldn't find declaration of parameter '%s' for vertex shader '%s' (Shader: %s)", szParam, m_EntryFunc.c_str(), ef->m_Name.c_str()); } nParam++; } for (i=0; im_BindVars->Num(); i++) { SCGBind *bn = &cgi->m_BindVars->Get(i); const char *param = bn->m_Name.c_str(); const char *paramINT = param; bool bSampler = (bn->m_dwBind & SHADER_BIND_SAMPLER) != 0; for (j=0; jNameINT == paramINT) { if (!bSampler) assert (al->bParam); else assert (!al->bParam); param = al->Name.c_str(); break; } } if (!bSampler) { for (j=0; jm_Name.c_str(), param)) { mfAddFXParameter(pr, paramINT, ef); break; } } if (j == Params.size()) { // const parameters aren't listed in Params // assert(0); } } else { for (j=0; jm_Name.c_str(), param)) { int nSampler = bn->m_dwBind & 0xf; nMaxSampler = max(nSampler, nMaxSampler); samps[nSampler].fxSampler = sm; samps[nSampler].NameINT = paramINT; break; } } if (j == Samplers.size()) assert(0); } } for (i=0; i<=nMaxSampler; i++) { SFXSampler *smp = samps[i].fxSampler; if (!smp) continue; assert(smp->m_nTextureID < Textures.size()); SFXTexture *tx = &Textures[smp->m_nTextureID]; #ifdef USE_FX gRenDev->m_cEF.mfParseFXTechnique_LoadShaderTexture(smp, tx, pSHPass, ef, i, eCO_NOSET, eCO_NOSET, DEF_TEXARG0, DEF_TEXARG0); #endif } } //========================================================================================= CPShader *CPShader::mfForName(const char *name, uint64 nMaskGen) { int i; if (!name || !name[0]) return NULL; if (!(gRenDev->GetFeatures() & (RFT_HW_RC | RFT_HW_TS | RFT_HW_PS20))) return NULL; for (i=0; im_Name.c_str()) && m_PShaders[i]->m_nMaskGen == nMaskGen) { m_PShaders[i]->m_nRefCounter++; return m_PShaders[i]; } } char scrname[128]; char dir[128]; sprintf(dir, "%sDeclarations/CGPShaders/", gRenDev->m_cEF.m_HWPath); sprintf(scrname, "%s%s.crycg", dir, name); FILE *fp = iSystem->GetIPak()->FOpen(scrname, "r"); if (!fp) { Warning( 0,scrname,"Couldn't find pixel shader '%s'",name ); iLog->Log("WARNING: Couldn't find pixel shader '%s'", name); iLog->Log("WARNING: Full file name: '%s'", scrname); return NULL; } iSystem->GetIPak()->FSeek(fp, 0, SEEK_END); int len = iSystem->GetIPak()->FTell(fp); char *buf = new char [len+1]; iSystem->GetIPak()->FSeek(fp, 0, SEEK_SET); len = iSystem->GetIPak()->FRead(buf, 1, len, fp); iSystem->GetIPak()->FClose(fp); buf[len] = 0; buf = gRenDev->m_cEF.mfScriptPreprocessor(buf, dir, scrname); CPShader *p = NULL; CPShader *pr; pr = new CCGPShader_D3D; pr->m_Name = name; pr->m_Id = i; m_PShaders.AddElem(pr); pr->m_nRefCounter = 1; pr->m_nMaskGen = nMaskGen; p = pr; FILE *handle = iSystem->GetIPak()->FOpen(scrname, "rb"); if (handle) { p->m_WriteTime = iSystem->GetIPak()->GetModificationTime(handle); iSystem->GetIPak()->FClose(handle); } p->mfCompile(buf); delete [] buf; if (CRenderer::CV_r_shadersprecache) p->mfPrecache(); return p; } void CPShader::mfClearAll(void) { for (int i=0; im_Mask = nMask; pi->m_LightMask = 0; m_Flags &= ~PSFI_WASGENERATED; mfActivate(); SAFE_DELETE(pi->m_BindVars); int nMaxLights = (gRenDev->m_bDeviceSupports_PS2X) ? NUM_PPLIGHTS_PERPASS_PS2X : NUM_PPLIGHTS_PERPASS_PS30; if (m_Flags & PSFI_WASGENERATED) { TArray Masks; int Types[5]; int nCombinations = 0; iLog->Log("Precache light shader %s(0x%I64x)\n", m_Name.c_str(), m_nMaskGen); // Light nums for (i=1; i<=nMaxLights; i++) { for (j=0; jm_LightMask = nLightMask; mfActivate(); SAFE_DELETE(pi->m_BindVars); nCombinations++; } } if (sIncrTypes(Types, 0, bSpec)) { if (sIncrTypes(Types, 1, bSpec)) { if (sIncrTypes(Types, 2, bSpec)) { if (sIncrTypes(Types, 3, bSpec)) { sIncrTypes(Types, 4, bSpec); } } } } } } if (pi->m_nCacheID >= 0) gRenDev->m_cEF.FlushCacheFile(m_InstCache[pi->m_nCacheID].m_pCache); iLog->Log("Precaching finished (%d combinations total, %d combinations failed)\n", nCombinations, m_nFailed); } m_Insts.DelElem(nInst); m_CurInst = nTempInst; m_Flags &= ~PSFI_PRECACHEPHASE; CRenderer::CV_r_shaderssave = nShSave; } void CCGPShader_D3D::mfPrecache() { bool bPrevFog = gRenDev->m_FS.m_bEnable; gRenDev->m_FS.m_bEnable = true; int Mask; if ((m_Flags & PSFI_NOFOG) || !(gRenDev->m_Features & RFT_FOGVP)) Mask = VPVST_NOFOG; else Mask = VPVST_FOGGLOBAL; int nLightMask = 0; if (m_Flags & PSFI_SUPPORTS_MULTILIGHTS) { if (CRenderer::CV_r_shadersprecache < 2) { mfPrecacheLights(Mask); if (gRenDev->m_Features & RFT_HW_HDR) { Mask |= VPVST_HDR; mfPrecacheLights(Mask); } if (gRenDev->m_bDeviceSupportsComprNormalmaps) { Mask &= ~VPVST_HDR; Mask |= VPVST_3DC; mfPrecacheLights(Mask); } } gRenDev->m_FS.m_bEnable = bPrevFog; return; } int Type = mfGetCGInstanceID(Mask, nLightMask); mfActivate(); if (gcpRendD3D->m_d3dCaps.MaxUserClipPlanes == 0) { Mask |= VPVST_CLIPPLANES3; Type = mfGetCGInstanceID(Mask, nLightMask); mfActivate(); } if (gRenDev->m_Features & RFT_HW_HDR) { Mask |= VPVST_HDR; Type = mfGetCGInstanceID(Mask, nLightMask); mfActivate(); } if ((m_Flags & PSFI_SUPPORTS_INSTANCING) && (gRenDev->m_Features & RFT_HW_PS30)) { Mask |= VPVST_INSTANCING_ROT | VPVST_INSTANCING_NOROT; Type = mfGetCGInstanceID(Mask, nLightMask); mfActivate(); if (Mask & VPVST_HDR) { Mask &= ~VPVST_HDR; Type = mfGetCGInstanceID(Mask, nLightMask); mfActivate(); } } gRenDev->m_FS.m_bEnable = bPrevFog; } void CCGPShader_D3D::mfReset() { int i; for (i=0; im_cEF.CloseCacheFile(m_InstCache[i].m_pCache); m_InstCache[i].m_pCache = NULL; } } m_InstCache.Free(); m_dwFrame++; } void CCGPShader_D3D::mfFree() { m_Flags = 0; if (m_CoreScript && !m_CoreScript->m_Name.GetIndex()) SAFE_RELEASE(m_CoreScript); if (m_SubroutinesScript && !m_SubroutinesScript->m_Name.GetIndex()) SAFE_RELEASE(m_SubroutinesScript); if (m_DeclarationsScript && !m_DeclarationsScript->m_Name.GetIndex()) SAFE_RELEASE(m_DeclarationsScript); if (m_InputParmsScript && !m_InputParmsScript->m_Name.GetIndex()) SAFE_RELEASE(m_InputParmsScript); m_ParamsNoObj.Free(); m_ParamsObj.Free(); mfReset(); } CCGPShader_D3D::~CCGPShader_D3D() { mfFree(); CPShader::m_PShaders[m_Id] = NULL; } void CCGPShader_D3D::Release() { m_nRefCounter--; if (!m_nRefCounter) delete this; } char *CCGPShader_D3D::mfGenerateScriptPS() { TArray newScr; int i; newScr.Copy("# define _PS\n", strlen("# define _PS\n")); if (m_CGProfileType == CG_PROFILE_PS_1_1) newScr.Copy("# define _PS_1_1\n", strlen("# define _PS_1_1\n")); if (m_Insts[m_CurInst].m_Mask & VPVST_HDR) { newScr.Copy("# define _HDR\n", strlen("# define _HDR\n")); //if (gcpRendD3D->m_nHDRType == 2) // newScr.Copy("# define _HDR_MRT\n", strlen("# define _HDR_MRT\n")); if (gcpRendD3D->m_nHDRType == 2) newScr.Copy("# define _HDR_ATI\n", strlen("# define _HDR_ATI\n")); if (CRenderer::CV_r_hdrfake) newScr.Copy("# define _HDR_FAKE\n", strlen("# define _HDR_FAKE\n")); if (m_Insts[m_CurInst].m_Mask & VPVST_HDRLM) newScr.Copy("# define _HDRLM\n", strlen("# define _HDRLM\n")); } if (m_Insts[m_CurInst].m_Mask & VPVST_3DC) { if (gcpRendD3D->m_bDeviceSupportsComprNormalmaps == 1) newScr.Copy("# define _3DC\n", strlen("# define _3DC\n")); else if (gcpRendD3D->m_bDeviceSupportsComprNormalmaps == 2) newScr.Copy("# define _V8U8\n", strlen("# define _V8U8\n")); else if (gcpRendD3D->m_bDeviceSupportsComprNormalmaps == 3) newScr.Copy("# define _CxV8U8\n", strlen("# define _CxV8U8\n")); if (m_Insts[m_CurInst].m_Mask & VPVST_3DC_A) newScr.Copy("# define _3DC_A\n", strlen("# define _3DC_A\n")); } if (m_Insts[m_CurInst].m_Mask & VPVST_SPECANTIALIAS) newScr.Copy("# define _SPEC_ANTIALIAS\n", strlen("# define _SPEC_ANTIALIAS\n")); if (m_Insts[m_CurInst].m_Mask & VPVST_INSTANCING_NOROT) newScr.Copy("# define _INST\n", strlen("# define _INST\n")); if (m_Flags & PSFI_SUPPORTS_MULTILIGHTS) { char str[256]; int nLights = m_Insts[m_CurInst].m_LightMask & 0xf; sprintf(str, "# define _NUM_LIGHTS %d\n", nLights); newScr.Copy(str, strlen(str)); for (int i=0; i> (SLMF_LTYPE_SHIFT + i*4)) & SLMF_TYPE_MASK; int nOnlySpec = ((m_Insts[m_CurInst].m_LightMask >> (SLMF_LTYPE_SHIFT + i*4)) & SLMF_ONLYSPEC) != 0; int nSpecOccl = ((m_Insts[m_CurInst].m_LightMask >> (SLMF_LTYPE_SHIFT + i*4)) & SLMF_SPECOCCLUSION) != 0; sprintf(str, "# define _LIGHT%d_TYPE %d\n", i, nLightType); newScr.Copy(str, strlen(str)); sprintf(str, "# define _LIGHT%d_ONLYSPEC %d\n", i, nOnlySpec); newScr.Copy(str, strlen(str)); sprintf(str, "# define _LIGHT%d_SPECOCCLUSION %d\n", i, nSpecOccl); newScr.Copy(str, strlen(str)); } } if (m_DeclarationsScript) newScr.Copy(m_DeclarationsScript->m_Script, strlen(m_DeclarationsScript->m_Script)); char *szInputParms = ""; if (m_InputParmsScript) szInputParms = m_InputParmsScript->m_Script; if (m_SubroutinesScript) newScr.Copy(m_SubroutinesScript->m_Script, strlen(m_SubroutinesScript->m_Script)); if (m_Functions.size()) { for (i=0; im_Script, strlen(m_CoreScript->m_Script)); if (!m_Functions.size()) { char *pExit = "return OUT;\n}"; newScr.Copy(pExit, strlen(pExit)); } newScr.AddElem(0); char *cgs = new char[newScr.Num()]; memcpy(cgs, &newScr[0], newScr.Num()); if (m_Flags & PSFI_AUTOENUMTC) { int n = 0; char *s = cgs; while (true) { s = strstr(s, "TEXCOORDN"); if (!s) break; s[8] = 0x30 + n; int m = -1; while (s[m] == 0x20 || s[m] == 0x8) {m--;} if (s[m] == ':') { m--; while (s[m] == 0x20 || s[m] == 0x8) {m--;} } if (s[m] == ']') { while (s[m] != '[') {m--;} char ss[16]; m++; int mm = 0; while (s[m] != ']') {ss[mm++] = s[m++];} ss[mm] = 0; n += atoi(ss); } else n++; } n = 0; s = cgs; while (true) { s = strstr(s, "register(sn)"); if (!s) break; char *ss = s; bool bIncr = true; while (ss != cgs) { if (ss[0] == 0xa) break; ss--; } if (ss != cgs) { ss--; while (ss != cgs) { if (ss[0] == 0xa) break; ss--; } if (ss != cgs) { SkipCharacters(&ss, kWhiteSpace); if (!strncmp(ss, "# ifdef", 7)) { ss += 7; SkipCharacters(&ss, kWhiteSpace); if (!strncmp(ss, "_3DC_A", 6) && !(m_Insts[m_CurInst].m_Mask & VPVST_3DC_A)) bIncr = false; else if (!strncmp(ss, "_SPEC_ANTIALIAS", 15) && !(m_Insts[m_CurInst].m_Mask & VPVST_SPECANTIALIAS)) bIncr = false; else if (!strncmp(ss, "_HDRLM", 6) && !(m_Insts[m_CurInst].m_Mask & VPVST_HDRLM)) bIncr = false; } } } if (bIncr) { s[10] = 0x30 + n; n++; } else s[10] = 0x37; } char *sNewStr = strstr(cgs, "main"); int nDepth = 0; if (sNewStr) { n = 0; while (true) { if (sNewStr[n] == '(') { nDepth++; } else if (sNewStr[n] == ')') { if (nDepth == 1) { n--; while (sNewStr[n] == 0x20 || sNewStr[n] == 9 || sNewStr[n] == 0xa) {n--;} if (sNewStr[n] == ',') sNewStr[n] = 0x20; break; } nDepth--; } n++; } } } return cgs; } char *CCGPShader_D3D::mfCreateAdditionalPS() { char *pScr = mfGenerateScriptPS(); if (!pScr) return NULL; char *sNewStr, *newScr; int Mask = m_Insts[m_CurInst].m_Mask; int n, len; // Calculate fog explicitly in the pixel shader if HDR is enabled sNewStr = pScr; while (true) { sNewStr = strstr(sNewStr, "main"); if (!sNewStr) break; n = 0; while (sNewStr[n]!=0x20 && sNewStr[n]!=8 && sNewStr[n]!=0xa && sNewStr[n] != '(') {n++;} while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==0xa) {n++;} if (sNewStr[n] == '(') { int m = 0; n++; while (true) { if (sNewStr[n]==')') { if (!m) break; m--; } if (sNewStr[n]=='(') m++; n++; } char *strFog = ", uniform float3 GlobalFogColor : register(c7)"; if (m_CGProfileType > CG_PROFILE_PS_1_1) strFog = ", uniform float3 GlobalFogColor : register(c31)"; len = strlen(strFog); int len2 = strlen(pScr)+1; newScr = new char[len+len2]; n = sNewStr-pScr+n; strncpy(newScr, pScr, n); strcpy(&newScr[n], strFog); strcpy(&newScr[n+len], &pScr[n]); delete [] pScr; pScr = newScr; break; } } return pScr; } void CCGPShader_D3D::mfCompileParam4f(char *scr, SShader *ef, TArray *Params) { gRenDev->m_cEF.mfCompileCGParam(scr, ef, Params); } bool CCGPShader_D3D::mfCompile(char *scr) { char* name; long cmd; char *params; char *data; enum {eScript=1, eParam4f, eNoFog, ePS20Only, ePS30Only, ePS2XOnly, eAutoEnumTC, eMainInput, eSubrScript, eDeclarationsScript, eCoreScript, eSupportsInstancing, eSupportsMultiLights, eNoSpecular, eMRT}; static tokenDesc commands[] = { {eScript, "Script"}, {eAutoEnumTC, "AutoEnumTC"}, {eParam4f, "Param4f"}, {eMainInput, "MainInput"}, {eDeclarationsScript, "DeclarationsScript"}, {eCoreScript, "CoreScript"}, {eSubrScript, "SubrScript"}, {eNoFog, "NoFog"}, {eMRT, "MRT"}, {ePS20Only, "PS20Only"}, {ePS30Only, "PS30Only"}, {ePS2XOnly, "PS2XOnly"}, {eNoSpecular, "NoSpecular"}, {eSupportsInstancing, "SupportsInstancing"}, {eSupportsMultiLights, "SupportsMultiLights"}, {0,0} }; mfFree(); SShader *ef = gRenDev->m_cEF.m_CurShader; while ((cmd = shGetObject (&scr, commands, &name, ¶ms)) > 0) { data = NULL; if (name) data = name; else if (params) data = params; switch (cmd) { case eMainInput: m_InputParmsScript = CCGVProgram_D3D::mfAddNewScript(name, params); break; case eDeclarationsScript: m_DeclarationsScript = CCGVProgram_D3D::mfAddNewScript(name, params); break; case eCoreScript: m_CoreScript = CCGVProgram_D3D::mfAddNewScript(name, params); break; case eSubrScript: m_SubroutinesScript = CCGVProgram_D3D::mfAddNewScript(name, params); break; case eParam4f: mfCompileParam4f(params, ef, &m_ParamsNoObj); break; case eNoFog: m_Flags |= PSFI_NOFOG; break; case eMRT: m_Flags |= PSFI_MRT; break; case eNoSpecular: m_Flags |= PSFI_NOSPECULAR; break; case eSupportsInstancing: m_Flags |= PSFI_SUPPORTS_INSTANCING; break; case eSupportsMultiLights: m_Flags |= PSFI_SUPPORTS_MULTILIGHTS; break; case eAutoEnumTC: m_Flags |= PSFI_AUTOENUMTC; break; case ePS20Only: m_Flags |= PSFI_PS20ONLY; break; case ePS30Only: m_Flags |= PSFI_PS30ONLY; break; case ePS2XOnly: m_Flags |= PSFI_PS2XONLY; break; } } gRenDev->m_cEF.mfCheckObjectDependParams(&m_ParamsNoObj, &m_ParamsObj); return 1; } void CCGPShader_D3D::mfSetVariables(TArray* Vars) { int i; for (i=0; iNum(); i++) { SCGParam4f *p = &Vars->Get(i); if (p->m_nComponents > 1) { float matr[4][4]; int nLast = i+p->m_nComponents; assert(nLast <= Vars->Num()); int n = 0; for (; iGet(i); float *v = Param->mfGet(); matr[n][0] = v[0]; matr[n][1] = v[1]; matr[n][2] = v[2]; matr[n][3] = v[3]; } i--; mfParameter(p, &matr[0][0], p->m_nComponents); } else { float *v = p->mfGet(); if (p->m_Flags & PF_INTEGER) mfParameter4i(p, v); else mfParameter4f(p, v); } } } void CCGPShader_D3D::mfSetVariables(bool bObj, TArray* Parms) { if (m_Insts[m_CurInst].m_pHandle == NULL || (INT_PTR)m_Insts[m_CurInst].m_pHandle == -1) return; //PROFILE_FRAME(Shader_PShadersParms); if (!bObj) { if (m_ParamsNoObj.Num()) mfSetVariables(&m_ParamsNoObj); if (m_Insts[m_CurInst].m_ParamsNoObj) mfSetVariables(m_Insts[m_CurInst].m_ParamsNoObj); } else { if (m_ParamsObj.Num()) mfSetVariables(&m_ParamsObj); if (m_Insts[m_CurInst].m_ParamsObj) mfSetVariables(m_Insts[m_CurInst].m_ParamsObj); } if (Parms) mfSetVariables(Parms); } void CCGPShader_D3D::mfGetSrcFileName(char *srcname, int nSize) { strncpy(srcname, gRenDev->m_cEF.m_HWPath, nSize); strncat(srcname, "Declarations/CGPShaders/", nSize); strncat(srcname, m_Name.c_str(), nSize); strncat(srcname, ".crycg", nSize); } void CCGPShader_D3D::mfGetDstFileName(char *dstname, int nSize, bool bUseASCIICache) { char *type; bool bFog = false; if (m_Flags & PSFI_AUTOENUMTC) { if (m_CGProfileType == CG_PROFILE_PS_2_X) { bFog = true; int nGPU = gRenDev->GetFeatures() & RFT_HW_MASK; if (nGPU == RFT_HW_GFFX) { if (CRenderer::CV_r_sm2xpath == 2) type = "D3D9_PS2A"; else type = "D3D9_PS2X"; } else type = "D3D9_PS2X"; } else type = "D3D9_Auto"; } else if (m_CGProfileType == CG_PROFILE_PS_1_1) type = "D3D9_PS11"; else if (m_CGProfileType == CG_PROFILE_PS_1_2) type = "D3D9_PS11"; else if (m_CGProfileType == CG_PROFILE_PS_1_3) type = "D3D9_PS11"; else if (m_CGProfileType == CG_PROFILE_PS_2_0) type = "D3D9_PS20"; else if (m_CGProfileType == CG_PROFILE_PS_3_0) type = "D3D9_PS30"; else if (m_CGProfileType == CG_PROFILE_PS_2_X) { int nGPU = gRenDev->GetFeatures() & RFT_HW_MASK; if (nGPU == RFT_HW_GFFX) { if (CRenderer::CV_r_sm2xpath == 2) type = "D3D9_PS2A"; else type = "D3D9_PS2X"; } else type = "D3D9_PS2X"; } else type = "Unknown"; char *fog; if ((m_Insts[m_CurInst].m_Mask & VPVST_FOGGLOBAL) || bFog) fog = "Fog"; else if (m_Insts[m_CurInst].m_Mask & VPVST_NOFOG) fog = "NoFog"; strncpy(dstname, gRenDev->m_cEF.m_ShadersCache, nSize); strncat(dstname, "CGPShaders/", nSize); strncat(dstname, m_Name.c_str(), nSize); if (type) { strncat(dstname, "$", nSize); strncat(dstname, type, nSize); } /*if ((m_Flags & PSFI_AUTOENUMTC) || m_CGProfileType == CG_PROFILE_PS_2_0 || m_CGProfileType == CG_PROFILE_PS_2_X) { if (D3DSHADER_VERSION_MAJOR(gcpRendD3D->m_d3dCaps.PixelShaderVersion) >= 2) { if (!(gcpRendD3D->m_d3dCaps.PS20Caps.Caps & D3DPS20CAPS_ARBITRARYSWIZZLE)) { strncat(dstname, "$", nSize); strncat(dstname, "20_NO_ASW", nSize); } } }*/ strncat(dstname, "$", nSize); strncat(dstname, fog, nSize); if (m_Insts[m_CurInst].m_Mask & VPVST_INSTANCING_NOROT) strncat(dstname, "$INST", nSize); if (m_Insts[m_CurInst].m_Mask & VPVST_HDR) { if (!(m_Insts[m_CurInst].m_Mask & VPVST_HDRREAL)) strncat(dstname, "$HDR", nSize); else strncat(dstname, "$HDR_REAL", nSize); if (gcpRendD3D->m_nHDRType == 2) strncat(dstname, "$MRT", nSize); } if (m_Insts[m_CurInst].m_Mask & VPVST_HDRLM) strncat(dstname, "$HDRLM", nSize); if (m_Insts[m_CurInst].m_Mask & VPVST_3DC) { if (gcpRendD3D->m_bDeviceSupportsComprNormalmaps == 1) strncat(dstname, "$3DC", nSize); else if (gcpRendD3D->m_bDeviceSupportsComprNormalmaps == 2) strncat(dstname, "$V8U8", nSize); else if (gcpRendD3D->m_bDeviceSupportsComprNormalmaps == 3) strncat(dstname, "$CxV8U8", nSize); } if (m_Insts[m_CurInst].m_Mask & VPVST_3DC_A) strncat(dstname, "$3DCA", nSize); if (m_Insts[m_CurInst].m_Mask & VPVST_SPECANTIALIAS) strncat(dstname, "$SA", nSize); if (bUseASCIICache && m_Insts[m_CurInst].m_LightMask) { char str[32]; sprintf(str, "$%x", m_Insts[m_CurInst].m_LightMask); strncat(dstname, str, nSize); } if (m_nMaskGen) { char str[32]; sprintf(str, "(%I64x)", m_nMaskGen); strncat(dstname, str, nSize); } strncat(dstname, ".cgps", nSize); } static char *sGetText(char **buf) { bool bBetween = false; SkipCharacters(buf, " "); if (**buf == ':') { ++*buf; SkipCharacters(buf, " "); if (**buf == ':') return NULL; } char *result = *buf; // now, we need to find the next whitespace to end the data char theChar; while ((theChar = **buf) != 0) { if (theChar <= 0x20) // space and control chars break; ++*buf; } **buf = 0; // null terminate it if (theChar) // skip the terminator ++*buf; return result; } bool CCGPShader_D3D::ActivateCacheItem(SShaderCacheHeaderItem *pItem) { int i; byte *pData = (byte *)pItem; pData += sizeof(SShaderCacheHeaderItem); SShaderCacheHeaderItemVar *pVars = (SShaderCacheHeaderItemVar *)pData; for (i=0; im_nVariables; i++) { if (!m_Insts[m_CurInst].m_BindVars) m_Insts[m_CurInst].m_BindVars = new TArray; SCGBind cgp; cgp.m_nComponents = pVars[i].m_nCount; cgp.m_Name = pVars[i].m_Name; cgp.m_dwBind = pVars[i].m_Reg; m_Insts[m_CurInst].m_BindVars->AddElem(cgp); } pData += pItem->m_nVariables*sizeof(SShaderCacheHeaderItemVar); HRESULT hr = gcpRendD3D->mfGetD3DDevice()->CreatePixelShader((DWORD*)pData, (IDirect3DPixelShader9 **)&m_Insts[m_CurInst].m_pHandle); if (FAILED(hr)) return false; return true; } bool CCGPShader_D3D::CreateCacheItem(int nMask, byte *pData, int nLen) { int i; int nVars = m_Insts[m_CurInst].m_BindVars ? m_Insts[m_CurInst].m_BindVars->Num() : 0; int nNewSize = nVars*sizeof(SShaderCacheHeaderItemVar)+nLen; byte *pNewData = new byte [nNewSize]; SShaderCacheHeaderItemVar *pVars = (SShaderCacheHeaderItemVar *)pNewData; for (i=0; iGet(i); memset(pVars[i].m_Name, 0, sizeof(pVars[i].m_Name)); strcpy(pVars[i].m_Name, bnd->m_Name.c_str()); pVars[i].m_nCount = bnd->m_nComponents; pVars[i].m_Reg = bnd->m_dwBind; } memcpy(&pNewData[nNewSize-nLen], pData, nLen); SShaderCacheHeaderItem h; h.m_nMask = nMask; h.m_nVariables = nVars; bool bRes = gRenDev->m_cEF.AddCacheItem(m_InstCache[m_Insts[m_CurInst].m_nCacheID].m_pCache, &h, pNewData, nNewSize, false); delete [] pNewData; if (!(m_Flags & PSFI_PRECACHEPHASE)) gRenDev->m_cEF.FlushCacheFile(m_InstCache[m_Insts[m_CurInst].m_nCacheID].m_pCache); return bRes; } // Compile pixel shader for the current instance properties bool CCGPShader_D3D::mfActivate() { PROFILE_FRAME(Shader_PShaderActivate); if (!m_Insts[m_CurInst].m_pHandle) { if (m_Flags & PSFI_PS30ONLY) { if (gRenDev->GetFeatures() & RFT_HW_PS30) m_CGProfileType = CG_PROFILE_PS_3_0; else if (gRenDev->GetFeatures() & RFT_HW_PS20) { if ((gRenDev->GetFeatures() & RFT_HW_MASK) == RFT_HW_GFFX) m_CGProfileType = CG_PROFILE_PS_2_X; else m_CGProfileType = CG_PROFILE_PS_2_0; } else m_CGProfileType = CG_PROFILE_PS_1_1; } else if (m_Flags & PSFI_PS2XONLY) { if (gRenDev->m_bDeviceSupports_PS2X) m_CGProfileType = CG_PROFILE_PS_2_X; else if (gRenDev->GetFeatures() & RFT_HW_PS20) { if ((gRenDev->GetFeatures() & RFT_HW_MASK) == RFT_HW_GFFX) m_CGProfileType = CG_PROFILE_PS_2_X; else m_CGProfileType = CG_PROFILE_PS_2_0; } else m_CGProfileType = CG_PROFILE_PS_1_1; } else if (m_Flags & PSFI_PS20ONLY) { if (gRenDev->GetFeatures() & RFT_HW_PS20) { if ((gRenDev->GetFeatures() & RFT_HW_MASK) == RFT_HW_GFFX) m_CGProfileType = CG_PROFILE_PS_2_X; else m_CGProfileType = CG_PROFILE_PS_2_0; } else m_CGProfileType = CG_PROFILE_PS_1_1; } else m_CGProfileType = CG_PROFILE_PS_1_1; if ((m_Insts[m_CurInst].m_Mask & VPVST_HDR) && m_CGProfileType == CG_PROFILE_PS_1_1) { // HDR requires at least PS2.0 shader profile if ((gRenDev->GetFeatures() & RFT_HW_MASK) == RFT_HW_GFFX) m_CGProfileType = CG_PROFILE_PS_2_X; else m_CGProfileType = CG_PROFILE_PS_2_0; } char strVer[128]; char strVer0[128]; sprintf(strVer, "//CGVER%.1f\n", CG_FP_CACHE_VER); bool bCreate = false; char namesrc[256]; char namedst[256]; char namedst1[256]; FILETIME writetimesrc,writetimedst; FILE *statussrc, *statusdst; statussrc = NULL; statusdst = NULL; mfGetSrcFileName(namesrc, 256); bool bUseACIICache = true; if (CRenderer::CV_r_shadersprecache < 2 && (m_Flags & PSFI_SUPPORTS_MULTILIGHTS)) bUseACIICache = false; mfGetDstFileName(namedst, 256, bUseACIICache); StripExtension(namedst, namedst1); // Use binary cache files for PS30 and PS20b shaders if (!bUseACIICache) { if (m_Insts[m_CurInst].m_nCacheID == -1) { AddExtension(namedst1, ".cgbin"); m_Insts[m_CurInst].m_nCacheID = mfGetCacheInstanceID(m_Insts[m_CurInst].m_Mask, namedst1); } SShaderCacheHeaderItem *pCacheItem = gRenDev->m_cEF.GetCacheItem(m_InstCache[m_Insts[m_CurInst].m_nCacheID].m_pCache, m_Insts[m_CurInst].m_LightMask); if (pCacheItem) { if (m_Flags & PSFI_PRECACHEPHASE) { gRenDev->m_cEF.FreeCacheItem(m_InstCache[m_Insts[m_CurInst].m_nCacheID].m_pCache, m_Insts[m_CurInst].m_LightMask); return true; } bool bRes = ActivateCacheItem(pCacheItem); gRenDev->m_cEF.FreeCacheItem(m_InstCache[m_Insts[m_CurInst].m_nCacheID].m_pCache, m_Insts[m_CurInst].m_LightMask); if (bRes) return true; pCacheItem = NULL; } bCreate = true; } else { AddExtension(namedst1, ".cgasm"); statusdst = iSystem->GetIPak()->FOpen(namedst1, "r"); } if (statusdst == NULL && bUseACIICache) { if (CRenderer::CV_r_shadersprecache == 3) bCreate = true; else { statusdst = iSystem->GetIPak()->FOpen(namedst, "r"); if (statusdst == NULL) bCreate = true; else if (!m_Functions.size()) { statussrc = iSystem->GetIPak()->FOpen(namesrc, "r"); writetimesrc = iSystem->GetIPak()->GetModificationTime(statussrc); writetimedst = iSystem->GetIPak()->GetModificationTime(statusdst);; if (CompareFileTime(&writetimesrc, &writetimedst) != 0) bCreate = true; iSystem->GetIPak()->FGets(strVer0, 128, statusdst); if (strcmp(strVer, strVer0)) bCreate = true; iSystem->GetIPak()->FClose(statussrc); } } } else strcpy(namedst, namedst1); create: char *pbuf = NULL; if (bCreate) { if (statusdst) { iSystem->GetIPak()->FClose(statusdst); statusdst = NULL; } m_Flags |= PSFI_WASGENERATED; char *scr = mfCreateAdditionalPS(); char *code = mfLoadCG(scr); delete [] scr; pbuf = code; // Create asm cache file if (bUseACIICache) { if (code) { FILE *fp = fopen(namedst, "wb"); if (fp) { fputs(strVer, fp); fputs(code, fp); fclose(fp); } if (!m_Functions.size()) { HANDLE hdst = CreateFile(namedst,GENERIC_WRITE,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL); FILE *hsrc = iSystem->GetIPak()->FOpen(namesrc, "r"); writetimesrc = iSystem->GetIPak()->GetModificationTime(hsrc); SetFileTime(hdst,NULL,NULL,&writetimesrc); iSystem->GetIPak()->FClose(hsrc); CloseHandle(hdst); } } m_Insts[m_CurInst].m_pHandle = NULL; statusdst = iSystem->GetIPak()->FOpen(namedst, "r"); } } if (statusdst) { iSystem->GetIPak()->FSeek(statusdst, 0, SEEK_END); int len = iSystem->GetIPak()->FTell(statusdst); iSystem->GetIPak()->FSeek(statusdst, 0, SEEK_SET); pbuf = new char [len+1]; iSystem->GetIPak()->FGets(strVer0, 128, statusdst); len = iSystem->GetIPak()->FRead(pbuf, 1, len, statusdst); pbuf[len] = 0; iSystem->GetIPak()->FClose(statusdst); statusdst = NULL; // Regenerate shader if hardware was changed if (!bCreate && (m_Flags & PSFI_AUTOENUMTC) && !(m_Flags & PSFI_SUPPORTS_MULTILIGHTS)) { if (strstr(pbuf, "ps_2_x")) { if (D3DSHADER_VERSION_MAJOR(gcpRendD3D->m_d3dCaps.PixelShaderVersion) < 2) { delete [] pbuf; bCreate = true; goto create; } else { int nGPU = gRenDev->GetFeatures() & RFT_HW_MASK; if (nGPU == RFT_HW_RADEON || nGPU == RFT_HW_NV4X) { delete [] pbuf; m_CGProfileType = CG_PROFILE_PS_2_0; bCreate = true; goto create; } } m_CGProfileType = CG_PROFILE_PS_2_X; } else if (strstr(pbuf, "ps_2_0")) { if (D3DSHADER_VERSION_MAJOR(gcpRendD3D->m_d3dCaps.PixelShaderVersion) < 2) { delete [] pbuf; bCreate = true; goto create; } else if ((gRenDev->GetFeatures() & RFT_HW_MASK) == RFT_HW_GFFX) { delete [] pbuf; m_CGProfileType = CG_PROFILE_PS_2_X; bCreate = true; goto create; } m_CGProfileType = CG_PROFILE_PS_2_0; } else if (strstr(pbuf, "ps_3_0")) { if (D3DSHADER_VERSION_MAJOR(gcpRendD3D->m_d3dCaps.PixelShaderVersion) < 3) { delete [] pbuf; bCreate = true; goto create; } m_CGProfileType = CG_PROFILE_PS_3_0; } else m_CGProfileType = CG_PROFILE_PS_1_1; } } assert(!m_Insts[m_CurInst].m_BindVars); if (pbuf) { RemoveCR(pbuf); LPD3DXBUFFER pCode = mfLoad(pbuf); // parse variables and constants from CG or HLSL object code int nComps = 1; char *scr = pbuf; char *token = strtok(scr, "//"); while (token) { if (m_CGProfileType == CG_PROFILE_PS_2_0 || m_CGProfileType == CG_PROFILE_PS_2_X || m_CGProfileType == CG_PROFILE_PS_3_0) { while (token[0]==0x20) {token++;} if (token[0] == '$') token++; char *szName = sGetText(&token); char *szReg = sGetText(&token); if (szReg[0] == 'c' && isdigit(szReg[1])) { SCGBind cgp; if (!m_Insts[m_CurInst].m_BindVars) m_Insts[m_CurInst].m_BindVars = new TArray; char *szSize = sGetText(&token); cgp.m_nComponents = atoi(szSize); cgp.m_Name = szName; cgp.m_dwBind = atoi(&szReg[1]); m_Insts[m_CurInst].m_BindVars->AddElem(cgp); } else if (szReg[0] == 's' && isdigit(szReg[1]) && (m_Flags & PSFI_FX)) { SCGBind cgp; if (!m_Insts[m_CurInst].m_BindVars) m_Insts[m_CurInst].m_BindVars = new TArray; char *szSize = sGetText(&token); cgp.m_nComponents = atoi(szSize); cgp.m_Name = szName; cgp.m_dwBind = atoi(&szReg[1]) | SHADER_BIND_SAMPLER; m_Insts[m_CurInst].m_BindVars->AddElem(cgp); } } else { if (!strncmp(token, "const", 5)) { token += 5; char *szhReg = sGetText(&token); char *szEqual = sGetText(&token); char *szF0 = sGetText(&token); char *szF1 = sGetText(&token); char *szF2 = sGetText(&token); char *szF3 = sGetText(&token); if (!m_Insts[m_CurInst].m_BindConstants) m_Insts[m_CurInst].m_BindConstants = new TArray; SCGBindConst cgp; cgp.m_nComponents = 1; cgp.m_Val[0] = (float)atof(szF0); cgp.m_Val[1] = (float)atof(szF1); cgp.m_Val[2] = (float)atof(szF2); cgp.m_Val[3] = (float)atof(szF3); cgp.m_dwBind = atoi(&szhReg[2]); m_Insts[m_CurInst].m_BindConstants->AddElem(cgp); } else if (!strncmp(token, "var", 3)) { token += 3; char *szType = sGetText(&token); char *szName = sGetText(&token); char *szvAttr = sGetText(&token); char *szhReg = sGetText(&token); if ((m_Flags & PSFI_FX) && !strncmp(szType, "sampler", 7)) { SCGBind cgp; if (!m_Insts[m_CurInst].m_BindVars) m_Insts[m_CurInst].m_BindVars = new TArray; cgp.m_nComponents = 1; cgp.m_Name = szName; assert (!strncmp(szhReg, "texunit", 7)); char *szSize = sGetText(&token); cgp.m_dwBind = atoi(szSize) | SHADER_BIND_SAMPLER; m_Insts[m_CurInst].m_BindVars->AddElem(cgp); } else if (szhReg) { if (szhReg[0] == 'c' && szhReg[1] == '[') { int len = strlen(szhReg); if (szhReg[len-1] == ',') { char *sznComps = sGetText(&token); nComps = atoi(sznComps); } else nComps = 1; char *szVarType = sGetText(&token); char *sznVar = sGetText(&token); if (!m_Insts[m_CurInst].m_BindVars) m_Insts[m_CurInst].m_BindVars = new TArray; SCGBind cgp; cgp.m_nComponents = nComps; cgp.m_Name = szName; cgp.m_dwBind = atoi(&szhReg[2]); m_Insts[m_CurInst].m_BindVars->AddElem(cgp); } else if (!strncmp(szhReg, "OFFSET_TEXTURE_MATRIX", 21)) { if (!m_Insts[m_CurInst].m_BindVars) m_Insts[m_CurInst].m_BindVars = new TArray; SCGBind cgp; cgp.m_nComponents = nComps; cgp.m_Name = szName; cgp.m_dwBind = GL_OFFSET_TEXTURE_2D_MATRIX_NV; cgp.m_dwBind |= (atoi(&szhReg[22])+1) << 28; m_Insts[m_CurInst].m_BindVars->AddElem(cgp); } } } } token = strtok(NULL, "//"); } if (m_Insts[m_CurInst].m_BindVars) { m_Insts[m_CurInst].m_BindVars->Shrink(); for (int i=0; iNum(); i++) { SCGBind *pBind = &m_Insts[m_CurInst].m_BindVars->Get(i); for (int j=i+1; jNum(); j++) { SCGBind *pBind0 = &m_Insts[m_CurInst].m_BindVars->Get(j); if (pBind0->m_Name == pBind->m_Name) { pBind->m_pNext = pBind0; break; } } } } assert(!m_Insts[m_CurInst].m_BindVars || m_Insts[m_CurInst].m_BindVars->Num()<=30); SAFE_DELETE_ARRAY(pbuf); if (pCode && !bUseACIICache) CreateCacheItem(m_Insts[m_CurInst].m_LightMask, (byte *)pCode->GetBufferPointer(), pCode->GetBufferSize()); SAFE_RELEASE(pCode); } if (!(m_Flags & PSFI_PRECACHEPHASE)) mfUnbind(); } if (!m_Insts[m_CurInst].m_pHandle) return false; return true; } bool CCGPShader_D3D::mfSet(bool bEnable, SShaderPassHW *slw, int nFlags) { //PROFILE_FRAME(Shader_PShaders); int Mask; CD3D9Renderer *rd = gcpRendD3D; if (!bEnable) { #ifdef DO_RENDERLOG if (CRenderer::CV_r_log == 4) rd->Logv(SRendItem::m_RecurseLevel, "--- Reset CGPShader \"%s\"\n", m_Name.c_str()); #endif m_LastVP = 0; mfUnbind(); return true; } else { if (slw && (slw->m_Flags & SHPF_ALLOW_SPECANTIALIAS) && CRenderer::CV_r_specantialias) { rd->m_RP.m_FlagsPerFlush |= RBSI_USE_SPECANTIALIAS; if (rd->m_RP.m_pShaderResources) { if (!rd->m_RP.m_pShaderResources->m_Textures[EFTT_PHONG]) rd->m_RP.m_pShaderResources->AddTextureMap(EFTT_PHONG); if (rd->m_RP.m_pShaderResources->m_Textures[EFTT_PHONG]->m_Amount != rd->m_RP.m_fCurSpecShininess) { if (rd->m_RP.m_pShaderResources->m_Textures[EFTT_PHONG]->m_TU.m_TexPic) rd->m_RP.m_pShaderResources->m_Textures[EFTT_PHONG]->m_TU.m_TexPic->Release(false); rd->m_RP.m_pShaderResources->m_Textures[EFTT_PHONG]->m_Amount = (byte)rd->m_RP.m_fCurSpecShininess; rd->m_RP.m_pShaderResources->m_Textures[EFTT_PHONG]->m_TU.m_TexPic = rd->EF_MakeSpecularTexture(rd->m_RP.m_fCurSpecShininess); } rd->EF_SelectTMU(CTexMan::m_nCurStages); rd->m_RP.m_pShaderResources->m_Textures[EFTT_PHONG]->m_TU.m_TexPic->Set(); CTexMan::m_nCurStages++; } } if ((m_Flags & PSFI_NOFOG) || !CRenderer::CV_r_vpfog || !(rd->m_Features & RFT_FOGVP)) Mask = VPVST_NOFOG; else Mask = VPVST_FOGGLOBAL; if (nFlags & PSF_INSTANCING) Mask |= VPVST_INSTANCING_NOROT; if (rd->m_RP.m_FlagsPerFlush & RBSI_USE_3DC) { Mask |= VPVST_3DC; if (rd->m_RP.m_FlagsPerFlush & RBSI_USE_3DC_A) Mask |= VPVST_3DC_A; } if (rd->m_RP.m_FlagsPerFlush & RBSI_USE_SPECANTIALIAS) Mask |= VPVST_SPECANTIALIAS; if (rd->m_RP.m_PersFlags & RBPF_HDR) { Mask |= VPVST_HDR; if (rd->m_RP.m_FlagsPerFlush & RBSI_USE_HDRLM) Mask |= VPVST_HDRLM; if (!CRenderer::CV_r_hdrfake) Mask |= VPVST_HDRREAL; } if (rd->m_RP.m_ClipPlaneEnabled == 1) Mask |= VPVST_CLIPPLANES3; int Type = mfGetCGInstanceID(Mask, rd->m_RP.m_ShaderLightMask); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) rd->Logv(SRendItem::m_RecurseLevel, "--- Set CGPShader \"%s\", LightMask: 0x%x, Mask: 0x%I64x (0x%x Type)\n", m_Name.c_str(), m_Insts[m_CurInst].m_LightMask, m_nMaskGen, Mask); #endif if ((INT_PTR)m_Insts[Type].m_pHandle == -1) { m_LastTypeVP = Mask; return false; } if (!m_Insts[Type].m_pHandle) { rd->m_RP.m_CurPS = this; if (!mfActivate()) { m_Insts[Type].m_pHandle = (CGprogram)-1; return false; } m_LastVP = NULL; } #ifdef DO_RENDERSTATS if (m_Frame != rd->m_nFrameUpdateID) { m_Frame = rd->m_nFrameUpdateID; rd->m_RP.m_PS.m_NumPShaders++; } #endif if (m_LastVP != this || m_LastTypeVP != Mask || m_LastLTypeVP != m_Insts[m_CurInst].m_LightMask) { rd->m_RP.m_PS.m_NumPShadChanges++; m_LastVP = this; m_LastTypeVP = Mask; m_LastLTypeVP = m_Insts[m_CurInst].m_LightMask; mfBind(); } rd->m_RP.m_PersFlags |= RBPF_PS1NEEDSET; if (slw && slw->m_CGFSParamsNoObj) mfSetVariables(false, slw->m_CGFSParamsNoObj); else mfSetVariables(false, NULL); } m_CurRC = this; return true; }