/*============================================================================= D3DCGVPrograms.cpp : Direct3D cg vertex programs support. Copyright (c) 2001 Crytek Studios. All Rights Reserved. Revision history: * Created by Honitch Andrey =============================================================================*/ #include "RenderPCH.h" #include "DriverD3D9.h" #include "D3DCGVProgram.h" #ifndef PS2 #include #include #else #include "File.h" #endif #undef THIS_FILE static char THIS_FILE[] = __FILE__; TArray CVProgram::m_VPrograms; vec4_t CCGVProgram_D3D::m_CurParams[256]; int CCGVProgram_D3D::m_nResetDeviceFrame = -1; //======================================================================= CVProgram *CVProgram::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_VS))) return NULL; for (i=0; im_Name.c_str()) && m_VPrograms[i]->m_nMaskGen == nMaskGen) { m_VPrograms[i]->m_nRefCounter++; return m_VPrograms[i]; } } CVProgram *p = NULL; { CVProgram *pr = new CCGVProgram_D3D; pr->m_Name = name; pr->m_Id = i; m_VPrograms.AddElem(pr); pr->m_nRefCounter = 1; pr->m_nMaskGen = nMaskGen; p = pr; } if (eSHV == eSHV_VS_2_0) p->m_Flags |= VPFI_VS20ONLY; else if (eSHV == eSHV_VS_3_0) p->m_Flags |= VPFI_VS30ONLY; p->m_Flags |= VPFI_FX; CCGVProgram_D3D *pr = (CCGVProgram_D3D *)p; pr->mfConstructFX(Structs, Macros, entryFunc); return p; } void CCGVProgram_D3D::mfConstructFX(std::vector& Structs, std::vector& Macros, char *entryFunc) { int i; char dir[128]; sprintf(dir, "%sDeclarations/CGVShaders/", 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 CCGVProgram_D3D::mfAddFXParameter(SFXParam *pr, const char *ParamName, SShader *ef) { SCGMatrix mt; SCGParam4f CGpr; int i; char scr[256]; if (pr->m_Assign.size()) { // Ignore composite matrix if (!strnicmp(pr->m_Assign.c_str(), "WorldViewProjection", strlen("WorldViewProjection")) || !strnicmp(pr->m_Assign.c_str(), "ViewProjection", strlen("ViewProjection"))) mt.m_eCGParamType = ECGP_Matr_ViewProj; else if (!stricmp(pr->m_Assign.c_str(), "World")) mt.m_eCGParamType = ECGP_Matr_World; else if (!stricmp(pr->m_Assign.c_str(), "WorldView") || !stricmp(pr->m_Assign.c_str(), "View")) mt.m_eCGParamType = ECGP_Matr_View; else if (!stricmp(pr->m_Assign.c_str(), "WorldViewInverse") || !stricmp(pr->m_Assign.c_str(), "ViewInverse")) mt.m_eCGParamType = ECGP_Matr_View_I; else if (!strnicmp(pr->m_Assign.c_str(), "ObjMatrix", strlen("ObjMatrix"))) mt.m_eCGParamType = ECGP_Matr_Obj; else if (!strnicmp(pr->m_Assign.c_str(), "InvObjMatrix", strlen("InvObjMatrix"))) mt.m_eCGParamType = ECGP_Matr_Obj_I; else if (!strnicmp(pr->m_Assign.c_str(), "TranspObjMatrix", strlen("TranspObjMatrix"))) mt.m_eCGParamType = ECGP_Matr_Obj_T; else if (!stricmp(pr->m_Assign.c_str(), "InvTranspObjMatrix")) mt.m_eCGParamType = ECGP_Matr_Obj_IT; if (mt.m_eCGParamType != ECGP_Unknown) { assert(pr->m_nRows == 4 && pr->m_nColumns == 4); mt.m_Name = ParamName; m_MatrixObj.AddElem(mt); } else { const char *translatedParam = pr->m_Assign.c_str(); scr[0] = 0; if (pr->m_nRows == 3) { if (!strnicmp(translatedParam, "OSCameraPos", strlen("OSCameraPos"))) sprintf(scr, "Name=%s Comp '%s pos 0' Comp '%s pos 1' Comp '%s pos 2'", ParamName, translatedParam, translatedParam, translatedParam); else sprintf(scr, "Name=%s Comp '%s[0]' Comp '%s[1]' Comp '%s[2]'", ParamName, translatedParam, translatedParam, translatedParam); } else 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 <= 1) sprintf(scr, "Name=%s Comp '%s'", ParamName, translatedParam); if (scr[0]) gRenDev->m_cEF.mfCompileCGParam(scr, ef, &m_ParamsNoObj); else assert(0); } } 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 CCGVProgram_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 SVSAliasName { bool bParam; std::string NameINT; std::string Name; }; struct SVSAliasSampler { SFXSampler *fxSampler; std::string NameINT; SVSAliasSampler() { fxSampler = NULL; } }; void CCGVProgram_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++; SVSAliasSampler samps[MAX_TMU]; int nMaxSampler = -1; std::vector Aliases; int nParam = 0; char VSParam[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)) { SVSAliasName an; an.bParam = true; an.Name = szParam; if (mfGetFXParamNameByID(nParam, VSParam)) an.NameINT = VSParam; else { assert(0); an.NameINT = szParam; } Aliases.push_back(an); break; } } if (i == Params.size()) { for (i=0; im_Name.c_str(), szParam)) { SVSAliasName an; an.bParam = false; an.Name = szParam; if (mfGetFXParamNameByID(nParam, VSParam)) an.NameINT = VSParam; 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()) 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; 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 } } int CCGVProgram_D3D::mfVertexFormat(bool &bUseTangents, bool &bUseLM) { int nVFormat = VERTEX_FORMAT_P3F; bool bNormal = false; bool bTangent = false; bool bTC0 = false; bool bTC1 = false; bool bCol = false; bool bSecCol = false; int i, j; if (m_Functions.size() && m_EntryFunc.GetIndex()) { for (i=0; i 0x20) { pSTR0[n++] = *s++; } pSTR0[n] = 0; for (j=0; j 0x20 && *ss != ':') { ss--; } int n = 0; char str[64]; ss++; while (*ss > 0x20 && *ss != ';') { str[n++] = *ss++; } str[n] = 0; if (!stricmp(str, "COLOR0")) bCol = true; else if (!stricmp(str, "COLOR1")) bSecCol = true; else if (!stricmp(str, "TEXCOORD0")) bTC0 = true; else if (!stricmp(str, "TEXCOORD1")) bTC1 = true; else if (!stricmp(str, "NORMAL")) bNormal = true; else if (!strnicmp(str, "TANGENT", 7) || !strnicmp(str, "BINORMAL", 8) || !strnicmp(str, "BLENDWEIGHT", 11)) bTangent = true; s++; } break; } else { iLog->Log("Error: Wrong VertexShader '%s' function '%s'", m_Name.c_str(), m_EntryFunc.c_str()); break; } } } } bUseLM = bTC1; bUseTangents = bTangent; nVFormat = VertFormatForComponents(bCol, bSecCol, bNormal, bTC0); return nVFormat; } //========================================================================================= CVProgram *CVProgram::mfForName(const char *name, uint64 nMaskGen) { int i; if (!name || !name[0]) return NULL; if (!(gRenDev->GetFeatures() & (RFT_HW_VS))) return NULL; for (i=0; im_Name.c_str()) && m_VPrograms[i]->m_nMaskGen == nMaskGen) { m_VPrograms[i]->m_nRefCounter++; return m_VPrograms[i]; } } char scrname[128]; char dir[128]; sprintf(dir, "%sDeclarations/CGVShaders/", gRenDev->m_cEF.m_HWPath); sprintf(scrname, "%s%s.crycg", dir, name); FILE *fp = iSystem->GetIPak()->FOpen(scrname, "r"); if (!fp) { Warning( 0,0,"Couldn't find vertex shader '%s'", name); 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); CVProgram *p = NULL; { CVProgram *pr = new CCGVProgram_D3D; pr->m_Name = name; pr->m_Id = i; m_VPrograms.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; } //======================================================================= TArray CCGVProgram_D3D::m_CGScripts; void SCGScript::mfRemoveFromList() { 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 CCGVProgram_D3D::mfFree() { m_Flags = 0; if (m_Script && !m_Script->m_Name.GetIndex()) SAFE_RELEASE(m_Script); 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); if (m_PosScript && !m_PosScript->m_Name.GetIndex()) SAFE_RELEASE(m_PosScript); m_Pointers.Free(); m_ParamsNoObj.Free(); m_ParamsObj.Free(); m_MatrixObj.Free(); mfReset(); } CCGVProgram_D3D::~CCGVProgram_D3D() { mfFree(); CVProgram::m_VPrograms[m_Id] = NULL; } void CCGVProgram_D3D::Release() { m_nRefCounter--; if (!m_nRefCounter) delete this; } bool CCGVProgram_D3D::mfHasPointer(ESrcPointer ePtr) { for (int i=0; iePT == ePtr) return true; } return false; } static char *sAdditionalVP[][2][16] = { { { { "return OUT;\n" "}\n" }, { "float fCameraSpacePosZ = dot(ModelViewProj._31_32_33_34, vPos);\n" "OUT.FogC = clamp((Fog.y - Fog.x*fCameraSpacePosZ), g_VSCONST_0_025_05_1.x, g_VSCONST_0_025_05_1.w);\n" "return OUT;\n" "}\n" }, { "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "float fCameraSpacePosZ = dot(ModelViewProj._31_32_33_34, vPos);\n" "OUT.FogC = clamp((Fog.y - Fog.x*fCameraSpacePosZ), g_VSCONST_0_025_05_1.x, g_VSCONST_0_025_05_1.w);\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "return OUT;\n" "}\n" }, { "return OUT;\n" "}\n" }, { "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" } }, { { "OUT.FogC = vPos.w;\n" "return OUT;\n" "}\n" }, { "float fCameraSpacePosZ = dot(ModelViewProj._31_32_33_34, vPos);\n" "OUT.FogC = clamp((Fog.y - Fog.x*fCameraSpacePosZ), g_VSCONST_0_025_05_1.x, g_VSCONST_0_025_05_1.w);\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "float fCameraSpacePosZ = dot(ModelViewProj._31_32_33_34, vPos);\n" "OUT.FogC = clamp((Fog.y - Fog.x*fCameraSpacePosZ), g_VSCONST_0_025_05_1.x, g_VSCONST_0_025_05_1.w);\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" } } }, // Instancing support { { { "return OUT;\n" "}\n" }, { "float fCameraSpacePosZ = dot(_CompMatrix[2], vPos);\n" "OUT.FogC = clamp((Fog.y - Fog.x*fCameraSpacePosZ), g_VSCONST_0_025_05_1.x, g_VSCONST_0_025_05_1.w);\n" "return OUT;\n" "}\n" }, { "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "float fCameraSpacePosZ = dot(_CompMatrix[2], vPos);\n" "OUT.FogC = clamp((Fog.y - Fog.x*fCameraSpacePosZ), g_VSCONST_0_025_05_1.x, g_VSCONST_0_025_05_1.w);\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "return OUT;\n" "}\n" }, { "return OUT;\n" "}\n" }, { "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" } }, { { "OUT.FogC = vPos.w;\n" "return OUT;\n" "}\n" }, { "float fCameraSpacePosZ = dot(_CompMatrix[2], vPos);\n" "OUT.FogC = clamp((Fog.y - Fog.x*fCameraSpacePosZ), g_VSCONST_0_025_05_1.x, g_VSCONST_0_025_05_1.w);\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "float fCameraSpacePosZ = dot(_CompMatrix[2], vPos);\n" "OUT.FogC = clamp((Fog.y - Fog.x*fCameraSpacePosZ), g_VSCONST_0_025_05_1.x, g_VSCONST_0_025_05_1.w);\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" }, { "OUT.FogC = vPos.w;\n" "OUT.Tex3.z = dot(vPos, ClipPlane);\n" "OUT.Tex3.xyw = vPos.w;\n" "return OUT;\n" "}\n" } } }, }; SCGScript *CCGVProgram_D3D::mfGenerateScriptVP(CVProgram *pPosVP) { TArray newScr; int i; newScr.Copy("# define _VS\n", strlen("# define _VS\n")); if (m_Insts[m_CurInst].m_Mask & VPVST_HDR) newScr.Copy("# define _HDR\n", strlen("# define _HDR\n")); if (m_Insts[m_CurInst].m_Mask & VPVST_INSTANCING_ROT) newScr.Copy("# define _INST_R\n", strlen("# define _INST_R\n")); else if (m_Insts[m_CurInst].m_Mask & VPVST_INSTANCING_NOROT) newScr.Copy("# define _INST_NR\n", strlen("# define _INST_NR\n")); if (m_Insts[m_CurInst].m_Mask & VPVST_FOGGLOBAL) { newScr.Copy("# define _FOG\n", strlen("# define _FOG\n")); newScr.Copy("# define _FOG_LIN\n", strlen("# define _FOG_LIN\n")); } if (m_Flags & VPFI_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; SCGScript *posScr = m_PosScript; char str[4096]; char sStr[4096]; if (posScr && posScr->m_Name != m_Insts[m_CurInst].m_PosScriptName) { strcpy(str, szInputParms); szInputParms = str; if (pPosVP && pPosVP->m_bCGType) { CCGVProgram_D3D *pVPD3D = (CCGVProgram_D3D *)pPosVP; for (int i=0; im_ParamsNoObj.Num(); i++) { if (!strstr(str, pVPD3D->m_ParamsNoObj[i].m_Name.c_str())) { strcat(str, ", uniform float4 "); strcat(str, pVPD3D->m_ParamsNoObj[i].m_Name.c_str()); } } for (int i=0; im_ParamsObj.Num(); i++) { if (!strstr(str, pVPD3D->m_ParamsObj[i].m_Name.c_str())) { strcat(str, ", uniform float4 "); strcat(str, pVPD3D->m_ParamsObj[i].m_Name.c_str()); } } } } if (m_SubroutinesScript) newScr.Copy(m_SubroutinesScript->m_Script, strlen(m_SubroutinesScript->m_Script)); if (m_Functions.size()) { for (i=0; im_PosScript; if (CName(pPosVP->m_Name.c_str(), eFN_Find) != m_Insts[m_CurInst].m_PosScriptName) { SCGScript *pS = mfAddNewScript(m_Insts[m_CurInst].m_PosScriptName.c_str(), NULL); if (pS) pScr = pS; } if (pScr) newScr.Copy(pScr->m_Script, strlen(pScr->m_Script)); } if (m_CoreScript) newScr.Copy(m_CoreScript->m_Script, strlen(m_CoreScript->m_Script)); if (!m_Functions.size()) { char *pExit = "return OUT;\n}"; newScr.Copy(pExit, strlen(pExit)); } newScr.AddElem(0); if (m_Flags & VPFI_AUTOENUMTC) { int n = 0; char *s = &newScr[0]; 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++; } char *sNewStr = strstr(&newScr[0], "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++; } } } SCGScript *cgs = mfAddNewScript(NULL, &newScr[0]); return cgs; } //=============================================================================== // TexGen / TexTransform modifications static char *sEyeSpaceCamVecVP = { "float4 tcEPos = mul(ModelView, vPos);\n" "float3 tcCamVec = normalize(tcEPos.xyz);\n" }; static char *sEyeSpaceNormal = { "float3 tcNormal = normalize(mul((float3x3)ModelViewIT, IN.TNormal.xyz));\n" }; static char *sReflectVec = { "float3 tcRef = reflect(tcCamVec, tcNormal.xyz);\n" }; static char *sSphereMapGenScriptVP[] = { sEyeSpaceCamVecVP, sEyeSpaceNormal, sReflectVec, { "float3 tcEm = tcRef + float3(0,0,1);\n" "tcEm.x = 2 * sqrt(dot(tcEm, tcEm));\n" "float4 tcSM = {0,0,0,1};\n" "tcSM.xy = tcRef.xy/tcEm.x + 0.5;\n" }, NULL }; static char *sReflectionMapGenScriptVP[] = { sEyeSpaceCamVecVP, sEyeSpaceNormal, sReflectVec, { "float4 tcRM;\n" "tcRM.xyz = tcRef.xyz;\n" "tcRM.w = vPos.w;\n" }, NULL }; static char *sNormalMapGenScriptVP[] = { sEyeSpaceNormal, { "float4 tcNM;\n" "tcNM.xyz = tcNormal.xyz;\n" "tcNM.w = vPos.w;\n" }, NULL }; char *CCGVProgram_D3D::mfGenerateTCScript(char *Script, int nt) { int tcGOLMask = VPVST_TCGOL0< 3) break; } while (sNStr[n]!=0xa && sNStr[n]!=0) {sNStr[n]=0x20; n++;} break; } sNStr[n]=0x20; n++; } } n = 0; while (sNewStr[n]!=0xa && sNewStr[n]!=0) {sNewStr[n]=0x20; n++;} // Add texgen code to the final VP char **pNewScripts = NULL; sStr1[0] = 0; if (m_Insts[m_CurInst].m_Mask & tcGOLMask) sprintf(sStr1, "float4 tcOL%d = mul(%s, vPos);\n", nt, sMTCG); else if (m_Insts[m_CurInst].m_Mask & tcGRMMask) pNewScripts = sReflectionMapGenScriptVP; else if (m_Insts[m_CurInst].m_Mask & tcGSMMask) pNewScripts = sSphereMapGenScriptVP; else if (m_Insts[m_CurInst].m_Mask & tcGNMMask) pNewScripts = sNormalMapGenScriptVP; if (pNewScripts) { n = 0; while(pNewScripts[n]) { if (!strstr(Script, pNewScripts[n])) { strcat(sStr1, pNewScripts[n]); } n++; } } if (m_Insts[m_CurInst].m_Mask & tcMMask) { if (m_Insts[m_CurInst].m_Mask & tcGOLMask) sprintf(sStr, "%s %s = mul(%s, tcOL%d);\n", sStr1, sOTex, sMTCM, nt); else if (m_Insts[m_CurInst].m_Mask & tcGRMMask) sprintf(sStr, "%s %s = mul(%s, tcRM);\n", sStr1, sOTex, sMTCM); else if (m_Insts[m_CurInst].m_Mask & tcGSMMask) sprintf(sStr, "%s %s = mul(%s, tcSM);\n", sStr1, sOTex, sMTCM); else if (m_Insts[m_CurInst].m_Mask & tcGNMMask) sprintf(sStr, "%s %s = mul(%s, tcNM);\n", sStr1, sOTex, sMTCM); else sprintf(sStr, "%s = mul(%s, %s);\n", sOTex, sMTCM, sINTex); } else { if (m_Insts[m_CurInst].m_Mask & tcGOLMask) sprintf(sStr, "%s %s = tcOL%d;\n", sStr1, sOTex, nt); else if (m_Insts[m_CurInst].m_Mask & tcGRMMask) sprintf(sStr, "%s %s = tcRM;\n", sStr1, sOTex); else if (m_Insts[m_CurInst].m_Mask & tcGSMMask) sprintf(sStr, "%s %s = tcSM;\n", sStr1, sOTex); else if (m_Insts[m_CurInst].m_Mask & tcGNMMask) sprintf(sStr, "%s %s = tcNM;\n", sStr1, sOTex); } size_t len = strlen(sStr); size_t len2 = strlen(Script)+1; char *newScr2 = new char[len+len2]; n = sNewStr-Script; strncpy(newScr2, Script, n); strcpy(&newScr2[n], sStr); strcpy(&newScr2[n+len], &Script[n]); delete [] Script; Script = newScr2; if (m_Insts[m_CurInst].m_Mask & (tcGOLMask | tcMMask | tcGRMMask | tcGSMMask | tcGNMMask)) { sNewStr = strstr(Script, "main"); if (sNewStr) { 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++; } sStr[0] = 0; if (m_Insts[m_CurInst].m_Mask & tcMMask) sprintf(sStr, ", uniform float4x4 %s\n", sMTCM); if (m_Insts[m_CurInst].m_Mask & tcGOLMask) { sprintf(sStr1, ", uniform float4x4 %s\n", sMTCG); strcat(sStr, sStr1); } if (m_Insts[m_CurInst].m_Mask & (tcGRMMask | tcGSMMask)) { if (!bCamPos) { sprintf(sStr1, ", uniform float4 CameraPos\n"); strcat(sStr, sStr1); } if (!bModV) { sprintf(sStr1, ", uniform float4x4 ModelView\n"); strcat(sStr, sStr1); } if (!bModVIT) { sprintf(sStr1, ", uniform float4x4 ModelViewIT\n"); strcat(sStr, sStr1); } } if (m_Insts[m_CurInst].m_Mask & tcGNMMask) { if (!bModVIT) { sprintf(sStr1, ", uniform float4x4 ModelViewIT\n"); strcat(sStr, sStr1); } } len = strlen(sStr); size_t len2 = strlen(Script)+1; char *newScr2 = new char[len+len2]; n = sNewStr-Script+n; strncpy(newScr2, Script, n); strcpy(&newScr2[n], sStr); strcpy(&newScr2[n+len], &Script[n]); delete [] Script; Script = newScr2; } } } if (m_Insts[m_CurInst].m_Mask & (tcGRMMask | tcGNMMask | tcGSMMask)) { if (!strstr(Script, "BLENDWEIGHT")) { while (true) { sNewStr = strstr(Script, "appin"); 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] == '{') { n++; while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==0xa) {n++;} len = strlen("float3 TNormal : BLENDWEIGHT;\n"); size_t len2 = strlen(Script)+1; char *newScr2 = new char[len+len2]; n = sNewStr-Script+n; strncpy(newScr2, Script, n); strcpy(&newScr2[n], "float3 TNormal : BLENDWEIGHT;\n"); strcpy(&newScr2[n+len], &Script[n]); delete [] Script; Script = newScr2; break; } } } } } } return Script; } char *CCGVProgram_D3D::mfCreateAdditionalVP(CVProgram *pPosVP) { SCGScript *pScript = m_Script; if (!pScript) pScript = mfGenerateScriptVP(pPosVP); if (!pScript) return NULL; const char *scr = pScript->m_Script; if (m_Flags & VPFI_FX) return (char *)scr; size_t len; int n; char *sNewStr = pScript->m_Script; int Mask = m_Insts[m_CurInst].m_Mask; if (Mask & VPVST_CLIPPLANES3) { char *s = strstr(sNewStr, "vertout"); if (s && strstr(s, "TEXCOORD3")) { //m_Flags |= VPFI_NOFAKECLIPPLANE; Mask &= ~VPVST_CLIPPLANES3; } } sNewStr = pScript->m_Script; while (true) { sNewStr = strstr(sNewStr, "return"); if (!sNewStr) { len = strlen(pScript->m_Script)+1; sNewStr = new char[len]; strcpy(sNewStr, pScript->m_Script); return sNewStr; } n = 0; while (sNewStr[n] && sNewStr[n]!=0x20 && sNewStr[n]!=8 && sNewStr[n]!=9 && sNewStr[n]!=0xa) {n++;} while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==9 || sNewStr[n]==0xa) {n++;} if (!strncmp(&sNewStr[n], "OUT", 3)) break; sNewStr += n; } n = sNewStr - pScript->m_Script; len = strlen(pScript->m_Script)+1; int nScr = 0; int nInst = 0; if (gRenDev->m_Features & RFT_FOGVP) nScr = 1; if (Mask & (VPVST_INSTANCING_ROT | VPVST_INSTANCING_NOROT)) nInst = 1; int lenN = strlen(sAdditionalVP[nInst][nScr][Mask&7]); int newSize = n+1+lenN; char *newScr = new char [newSize]; strncpy(newScr, scr, n); strcpy(&newScr[n], sAdditionalVP[nInst][nScr][Mask&7]); if ((Mask & VPVST_NOISE) && !strstr(newScr, "register(c30)")) { sNewStr = newScr; while (true) { sNewStr = strstr(sNewStr, "main"); if (!sNewStr) break; n = 0; while (sNewStr[n]!=0x20 && sNewStr[n]!=8 && sNewStr[n]!=9 && sNewStr[n]!=0xa && sNewStr[n] != '(') {n++;} while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==9 || 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++; } len = strlen(", uniform float4 pg[66] : register(c30)"); size_t len2 = strlen(newScr)+1; char *newScr2 = new char[len+len2]; n = sNewStr-newScr+n; strncpy(newScr2, newScr, n); strcpy(&newScr2[n], ", uniform float4 pg[66] : register(c30)"); strcpy(&newScr2[n+len], &newScr[n]); delete [] newScr; newScr = newScr2; break; } } } if (((Mask & (VPVST_FOGGLOBAL | VPVST_HDR)) || m_CGProfileType == CG_PROFILE_VS_3_0) && !(m_Flags & VPFI_NOFOG)) { sNewStr = newScr; while (true) { sNewStr = strstr(sNewStr, "main"); if (!sNewStr) break; n = 0; while (sNewStr[n]!=0x20 && sNewStr[n]!=8 && sNewStr[n]!=9 && sNewStr[n]!=0xa && sNewStr[n] != '(') {n++;} while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==9 || 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++; } len = strlen(", uniform float3 Fog : register(c29)"); int len2 = strlen(newScr)+1; char *newScr2 = new char[len+len2]; n = sNewStr-newScr+n; strncpy(newScr2, newScr, n); strcpy(&newScr2[n], ", uniform float3 Fog : register(c29)"); strcpy(&newScr2[n+len], &newScr[n]); delete [] newScr; newScr = newScr2; break; } } } if (gRenDev->m_Features & RFT_FOGVP) { sNewStr = newScr; while (true) { sNewStr = strstr(sNewStr, "vertout"); if (!sNewStr) break; n = 0; while (sNewStr[n]!=0x20 && sNewStr[n]!=9 && sNewStr[n]!=8 && sNewStr[n]!=0xa && sNewStr[n] != '{') {n++;} while (sNewStr[n]==0x20 || sNewStr[n]==9 || sNewStr[n]==8 || sNewStr[n]==0xa) {n++;} if (sNewStr[n] == '{') { n++; while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==9 || sNewStr[n]==0xa) {n++;} len = strlen("float FogC : FOG;\n"); int len2 = strlen(newScr)+1; char *newScr2 = new char[len+len2]; n = sNewStr-newScr+n; strncpy(newScr2, newScr, n); strcpy(&newScr2[n], "float FogC : FOG;\n"); strcpy(&newScr2[n+len], &newScr[n]); delete [] newScr; newScr = newScr2; } break; } } if (Mask & VPVST_CLIPPLANES3) { sNewStr = newScr; while (true) { sNewStr = strstr(sNewStr, "main"); if (!sNewStr) break; n = 0; while (sNewStr[n]!=0x20 && sNewStr[n]!=8 && sNewStr[n]!=9 && sNewStr[n]!=0xa && sNewStr[n] != '(') {n++;} while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==9 || 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++; } len = strlen(", uniform float4 ClipPlane : register(c14)"); int len2 = strlen(newScr)+1; char *newScr2 = new char[len+len2]; n = sNewStr-newScr+n; strncpy(newScr2, newScr, n); strcpy(&newScr2[n], ", uniform float4 ClipPlane : register(c14)"); strcpy(&newScr2[n+len], &newScr[n]); delete [] newScr; newScr = newScr2; } break; } sNewStr = newScr; if (!strstr(sNewStr, "float4 Tex3")) { while (true) { sNewStr = strstr(sNewStr, "vertout"); if (!sNewStr) break; n = 0; while (sNewStr[n] != '{' && sNewStr[n]!=0) {n++;} if (sNewStr[n] == '{') { n++; while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==9 || sNewStr[n]==0xa) {n++;} len = strlen("float4 Tex3 : TEXCOORD3;\n"); int len2 = strlen(newScr)+1; char *newScr2 = new char[len+len2]; n = sNewStr-newScr+n; strncpy(newScr2, newScr, n); strcpy(&newScr2[n], "float4 Tex3 : TEXCOORD3;\n"); strcpy(&newScr2[n+len], &newScr[n]); delete [] newScr; newScr = newScr2; } break; } } } sNewStr = newScr; while (true) { sNewStr = strstr(sNewStr, "main"); if (!sNewStr) break; n = 0; while (sNewStr[n]!=0x20 && sNewStr[n]!=8 && sNewStr[n]!=9 && sNewStr[n]!=0xa && sNewStr[n] != '(') {n++;} while (sNewStr[n]==0x20 || sNewStr[n]==8 || sNewStr[n]==9 || 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++; } len = strlen(", uniform float4 g_VSCONST_0_025_05_1 : register(c28)"); int len2 = strlen(newScr)+1; char *newScr2 = new char[len+len2]; n = sNewStr-newScr+n; strncpy(newScr2, newScr, n); strcpy(&newScr2[n], ", uniform float4 g_VSCONST_0_025_05_1 : register(c28)"); strcpy(&newScr2[n+len], &newScr[n]); delete [] newScr; newScr = newScr2; break; } } if (Mask & VPVST_TCMASK) { for (int i=0; i<4; i++) { newScr = mfGenerateTCScript(newScr, i); } } if (pScript != m_Script) pScript->Release(); return newScr; } void CCGVProgram_D3D::mfCompileParam4f(char *scr, SShader *ef, TArray *Params) { gRenDev->m_cEF.mfCompileCGParam(scr, ef, Params); } void CCGVProgram_D3D::mfCompileParamStateMatrix(char *scr, SShader *ef, TArray *Params) { char* name; long cmd; char *params; char *data; enum {eType=1, eName}; static tokenDesc commands[] = { {eType, "Type"}, {eName, "Name"}, {0,0} }; SCGMatrix pr; while ((cmd = shGetObject (&scr, commands, &name, ¶ms)) > 0) { data = NULL; if (name) data = name; else if (params) data = params; switch (cmd) { case eName: pr.m_Name = data; break; case eType: if (!stricmp(data, "ViewProj")) pr.m_eCGParamType = ECGP_Matr_ViewProj; else if (!stricmp(data, "View")) pr.m_eCGParamType = ECGP_Matr_View; else if (!stricmp(data, "View_I")) pr.m_eCGParamType = ECGP_Matr_View_I; else if (!stricmp(data, "View_T")) pr.m_eCGParamType = ECGP_Matr_View_T; else if (!stricmp(data, "View_IT")) pr.m_eCGParamType = ECGP_Matr_View_IT; else pr.m_eCGParamType = ECGP_Unknown; } } if (pr.m_eCGParamType != ECGP_Unknown && pr.m_Name.GetIndex()) { Params->AddElem(pr); } } void CCGVProgram_D3D::mfCompileVertAttributes(char *scr, SShader *ef) { char* name; long cmd; char *params; char *data; enum {eVertArray=1}; static tokenDesc commands[] = { {eVertArray, "VertArray"}, {0,0} }; while ((cmd = shGetObject (&scr, commands, &name, ¶ms)) > 0) { data = NULL; if (name) data = name; else if (params) data = params; switch (cmd) { case eVertArray: { if (!data || !data[0]) { Warning( 0,0,"Missing parameters for VertArray in Shader '%s'\n", ef->m_Name.c_str()); break; } gRenDev->m_cEF.mfCompileArrayPointer(m_Pointers, params, ef); } break; } } } bool CCGVProgram_D3D::mfCompile(char *scr) { char* name; long cmd; char *params; char *data; enum {eScript=1, eParam4f, eVertAttributes, eParamStateMatrix, eDefaultPos, eNoFog, eVS20Only, eVS30Only, eAutoEnumTC, eProjected, eNoise, eUnifiedPosScript, eMainInput, eDeclarationsScript, ePositionScript, eCoreScript, eSubrScript, eSupportsInstancing, eSupportsMultiLights, eInst_Param4f, eNoSpecular}; static tokenDesc commands[] = { {eScript, "Script"}, {eAutoEnumTC, "AutoEnumTC"}, {eParam4f, "Param4f"}, {eParamStateMatrix, "ParamStateMatrix"}, {eVertAttributes, "VertAttributes"}, {eMainInput, "MainInput"}, {eDeclarationsScript, "DeclarationsScript"}, {ePositionScript, "PositionScript"}, {eCoreScript, "CoreScript"}, {eSubrScript, "SubrScript"}, {eNoFog, "NoFog"}, {eVS20Only, "VS20Only"}, {eVS30Only, "VS30Only"}, {eProjected, "Projected"}, {eNoise, "Noise"}, {eUnifiedPosScript, "UnifiedPosScript"}, {eDefaultPos, "DefaultPos"}, {eNoSpecular, "NoSpecular"}, {eSupportsInstancing, "SupportsInstancing"}, {eSupportsMultiLights, "SupportsMultiLights"}, {eInst_Param4f, "Inst_Param4f"}, {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 eVertAttributes: mfCompileVertAttributes(params, ef); break; case eMainInput: m_InputParmsScript = mfAddNewScript(name, params); break; case eDeclarationsScript: m_DeclarationsScript = mfAddNewScript(name, params); break; case ePositionScript: if (strchr(params, ';')) m_PosScript = mfAddNewScript(name, params); else { m_PosScript = mfAddNewScript(params, NULL); if (!m_PosScript) m_PosScript = mfAddNewScript("PosCommon", NULL); } break; case eCoreScript: m_CoreScript = mfAddNewScript(name, params); break; case eSubrScript: m_SubroutinesScript = mfAddNewScript(name, params); break; case eParam4f: mfCompileParam4f(params, ef, &m_ParamsNoObj); break; case eInst_Param4f: mfCompileParam4f(params, ef, &m_Params_Inst); break; case eParamStateMatrix: mfCompileParamStateMatrix(params, ef, &m_MatrixObj); break; case eUnifiedPosScript: m_Flags |= VPFI_UNIFIEDPOS; break; case eNoFog: m_Flags |= VPFI_NOFOG; break; case eNoSpecular: m_Flags |= VPFI_NOSPECULAR; break; case eSupportsInstancing: m_Flags |= VPFI_SUPPORTS_INSTANCING; break; case eSupportsMultiLights: m_Flags |= VPFI_SUPPORTS_MULTILIGHTS; break; case eProjected: if (gRenDev->GetFeatures() & RFT_HW_ENVBUMPPROJECTED) m_Flags |= VPFI_PROJECTED; break; case eVS20Only: m_Flags |= VPFI_VS20ONLY; break; case eVS30Only: m_Flags |= VPFI_VS30ONLY; break; case eAutoEnumTC: m_Flags |= VPFI_AUTOENUMTC; break; case eNoise: m_Flags |= VPFI_NOISE; break; case eDefaultPos: m_Flags |= VPFI_DEFAULTPOS; break; case eScript: { SAFE_RELEASE(m_Script); m_Script = mfAddNewScript(NULL, data); } break; } } int i; for (i=0; im_eCGParamType == ECGP_Matr_ViewProj) break; } if (i == m_MatrixObj.Num()) { SCGMatrix m; m.m_eCGParamType = ECGP_Matr_ViewProj; m.m_Name = "ModelViewProj"; m_MatrixObj.AddElemNoCache(m); } gRenDev->m_cEF.mfCheckObjectDependParams(&m_ParamsNoObj, &m_ParamsObj); return 1; } /* returns a random floating point number between 0.0 and 1.0 */ static float frand() { return (float) (rand() / (float) RAND_MAX); } /* returns a random floating point number between -1.0 and 1.0 */ static float sfrand() { return (float) (rand() * 2.0f/ (float) RAND_MAX) - 1.0f; } void CCGVProgram_D3D::mfGetSrcFileName(char *srcname, int nSize) { strncpy(srcname, gRenDev->m_cEF.m_HWPath, nSize); strncat(srcname, "Declarations/CGVShaders/", nSize); strncat(srcname, m_Name.c_str(), nSize); strncat(srcname, ".crycg", nSize); } void CCGVProgram_D3D::mfGetDstFileName(char *dstname, int nSize, bool bUseASCIICache) { char *type; if (m_Flags & VPFI_AUTOENUMTC) type = "D3D9_Auto"; else if (m_CGProfileType == CG_PROFILE_VS_1_1) type = "D3D9_VS11"; else if (m_CGProfileType == CG_PROFILE_VS_2_0) type = "D3D9_VS20"; else if (m_CGProfileType == CG_PROFILE_VS_2_X) type = "D3D9_VS2X"; else if (m_CGProfileType == CG_PROFILE_VS_3_0) type = "D3D9_VS30"; else type = "Unknown"; char *fog = ""; if ((m_Insts[m_CurInst].m_Mask & VPVST_FOGGLOBAL) || m_CGProfileType == CG_PROFILE_VS_3_0) fog = "Fog"; else if (m_Insts[m_CurInst].m_Mask & VPVST_NOFOG) { if (gRenDev->m_Features & RFT_FOGVP) fog = "Fog0"; else fog = "NoFog"; } char *cp; if (m_Insts[m_CurInst].m_Mask & VPVST_CLIPPLANES3) cp = "CP"; else cp = "NoCP"; char *pr = ""; if (m_Flags & VPFI_PROJECTED) pr = "Proj"; strncpy(dstname, gRenDev->m_cEF.m_ShadersCache, nSize); strncat(dstname, "CGVShaders/", nSize); strncat(dstname, m_Name.c_str(), nSize); strncat(dstname, "$", nSize); strncat(dstname, type, nSize); strncat(dstname, "$", nSize); strncat(dstname, fog, nSize); strncat(dstname, "$", nSize); strncat(dstname, cp, nSize); if (m_Insts[m_CurInst].m_Mask & VPVST_INSTANCING_NOROT) strncat(dstname, "$INST_NR", nSize); else if (m_Insts[m_CurInst].m_Mask & VPVST_INSTANCING_ROT) strncat(dstname, "$INST_R", nSize); if (m_Insts[m_CurInst].m_Mask & VPVST_HDR) strncat(dstname, "$HDR", nSize); if (pr[0]) { strncat(dstname, "$", nSize); strncat(dstname, pr, nSize); } strncat(dstname, "$", nSize); strncat(dstname, m_Insts[m_CurInst].m_PosScriptName.c_str(), nSize); for (int i=0; i<4; i++) { char str[64]; if (m_Insts[m_CurInst].m_Mask & (VPVST_TCM0<m_Mask = nMask; pi->m_LightMask = 0; pi->m_PosScriptName = m_PosScript ? m_PosScript->m_Name : "None"; m_Flags &= ~VPFI_WASGENERATED; mfActivate(pPosVP); SAFE_DELETE(pi->m_BindVars); int nMaxLights = (gRenDev->m_bDeviceSupports_PS2X) ? NUM_PPLIGHTS_PERPASS_PS2X : NUM_PPLIGHTS_PERPASS_PS30; if (m_Flags & VPFI_WASGENERATED) { TArray Masks; int Types[5]; int nCombinations = 0; iLog->Log("Precache light shader %s(0x%I64x)\n", m_Name.c_str(), m_nMaskGen); m_nFailed = 0; // Light nums for (i=1; i<=nMaxLights; i++) { for (j=0; jm_LightMask = nLightMask; mfActivate(pPosVP); 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 &= ~VPFI_PRECACHEPHASE; CRenderer::CV_r_shaderssave = nShSave; } void CCGVProgram_D3D::mfPrecache() { bool bPrevFog = gRenDev->m_FS.m_bEnable; gRenDev->m_FS.m_bEnable = true; int Mask; if ((m_Flags & VPFI_NOFOG) || !CRenderer::CV_r_vpfog || !(gRenDev->m_Features & RFT_FOGVP)) Mask = VPVST_NOFOG; else Mask = VPVST_FOGGLOBAL; int nLightMask = 0; if (m_Flags & VPFI_SUPPORTS_MULTILIGHTS) { if (CRenderer::CV_r_shadersprecache < 2) { mfPrecacheLights(Mask); if (gRenDev->m_Features & RFT_HW_HDR) { Mask |= VPVST_HDR; mfPrecacheLights(Mask); } } gRenDev->m_FS.m_bEnable = bPrevFog; return; } CVProgram *pPosVP = this; int Id = mfGetCGInstanceID(Mask, pPosVP, nLightMask); mfActivate(pPosVP); if (gRenDev->m_Features & RFT_HW_HDR) { Mask |= VPVST_HDR; Id = mfGetCGInstanceID(Mask, pPosVP, nLightMask); mfActivate(pPosVP); } if ((gRenDev->m_Features & RFT_HW_PS30) && (m_Flags & VPFI_SUPPORTS_INSTANCING)) { Mask |= VPVST_INSTANCING_NOROT; Id = mfGetCGInstanceID(Mask, pPosVP, nLightMask); mfActivate(pPosVP); if (Mask & VPVST_HDR) { Mask &= ~VPVST_HDR; Id = mfGetCGInstanceID(Mask, pPosVP, nLightMask); mfActivate(pPosVP); } Mask &= ~(VPVST_INSTANCING_NOROT | VPVST_HDR); } if (gcpRendD3D->m_d3dCaps.MaxUserClipPlanes == 0) { Mask |= VPVST_CLIPPLANES3; Id = mfGetCGInstanceID(Mask, pPosVP, nLightMask); mfActivate(pPosVP); } gRenDev->m_FS.m_bEnable = bPrevFog; } bool CCGVProgram_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()->CreateVertexShader((DWORD*)pData, (IDirect3DVertexShader9 **)&m_Insts[m_CurInst].m_pHandle); if (FAILED(hr)) return false; return true; } bool CCGVProgram_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 & VPFI_PRECACHEPHASE)) gRenDev->m_cEF.FlushCacheFile(m_InstCache[m_Insts[m_CurInst].m_nCacheID].m_pCache); return bRes; } struct STempStr { char name[128]; int nComponents; int nId; }; // Compile vertex shader for the current instance properties bool CCGVProgram_D3D::mfActivate(CVProgram *pPosVP) { PROFILE_FRAME(Shader_VShaderActivate); CD3D9Renderer *r = gcpRendD3D; LPDIRECT3DDEVICE9 dv = r->mfGetD3DDevice(); if (!m_Insts[m_CurInst].m_CGProgram) { int VS20Profile = CG_PROFILE_VS_2_0; if ((gRenDev->GetFeatures() & RFT_HW_MASK) == RFT_HW_GFFX || (gRenDev->GetFeatures() & RFT_HW_MASK) == RFT_HW_NV4X) VS20Profile = CG_PROFILE_VS_2_X; if (m_Flags & VPFI_VS30ONLY) { if (gRenDev->GetFeatures() & RFT_HW_PS30) m_CGProfileType = CG_PROFILE_VS_3_0; else if (gRenDev->GetFeatures() & RFT_HW_PS20) m_CGProfileType = VS20Profile; else m_CGProfileType = CG_PROFILE_VS_1_1; } else if (m_Flags & VPFI_VS20ONLY) { if (gRenDev->GetFeatures() & RFT_HW_PS20) m_CGProfileType = VS20Profile; else m_CGProfileType = CG_PROFILE_VS_1_1; } else m_CGProfileType = CG_PROFILE_VS_1_1; if (m_Insts[m_CurInst].m_Mask & (VPVST_INSTANCING_NOROT | VPVST_INSTANCING_ROT)) { if (m_CGProfileType < CG_PROFILE_VS_2_0) m_CGProfileType = VS20Profile; } bool bCreate = false; char namesrc[256]; char namedst[256]; char namedst1[256]; char strVer[128]; char strVer0[128]; sprintf(strVer, "//CGVER%.1f\n", CG_VP_CACHE_VER); FILETIME writetimesrc,writetimedst; FILE *statussrc, *statusdst; statussrc = NULL; statusdst = NULL; mfGetSrcFileName(namesrc, 256); CCGVProgram_D3D *pVP = (CCGVProgram_D3D *)pPosVP; bool bUseACIICache = true; if (CRenderer::CV_r_shadersprecache < 2 && (m_Flags & VPFI_SUPPORTS_MULTILIGHTS)) bUseACIICache = false; mfGetDstFileName(namedst, 256, bUseACIICache); StripExtension(namedst, namedst1); // Use binary cache files for PS30 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 & VPFI_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 |= VPFI_WASGENERATED; char *scr = mfCreateAdditionalVP(pPosVP); char *code = mfLoadCG(scr); delete [] scr; pbuf = code; // Create asm cache file if (bUseACIICache) { if (code) { char *str = new char [strlen(code)+1]; strcpy(str, code); char *s = strstr(str, "oFog.x"); if (s) memcpy(s, "oFog ", 6); 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); } } #ifndef WIN64 // NOTE: AMD64 port: find the 64-bit CG runtime if (m_Insts[m_CurInst].m_CGProgram) cgDestroyProgram(m_Insts[m_CurInst].m_CGProgram); #endif m_Insts[m_CurInst].m_CGProgram = 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 & VPFI_AUTOENUMTC)) { if (strstr(pbuf, "vs_2_x")) { if (D3DSHADER_VERSION_MAJOR(gcpRendD3D->m_d3dCaps.VertexShaderVersion) < 2) { SAFE_DELETE_ARRAY(pbuf); bCreate = true; goto create; } else { int nGPU = gRenDev->GetFeatures() & RFT_HW_MASK; if (nGPU == RFT_HW_RADEON || nGPU == RFT_HW_NV4X) { SAFE_DELETE_ARRAY(pbuf); m_CGProfileType = CG_PROFILE_VS_2_0; bCreate = true; goto create; } } m_CGProfileType = CG_PROFILE_VS_2_X; } else if (strstr(pbuf, "vs_2_0")) { if (D3DSHADER_VERSION_MAJOR(gcpRendD3D->m_d3dCaps.VertexShaderVersion) < 2) { SAFE_DELETE_ARRAY(pbuf); bCreate = true; goto create; } else if ((gRenDev->GetFeatures() & RFT_HW_MASK) == RFT_HW_GFFX) { SAFE_DELETE_ARRAY(pbuf); m_CGProfileType = CG_PROFILE_VS_2_X; bCreate = true; goto create; } m_CGProfileType = CG_PROFILE_VS_2_0; } else if (strstr(pbuf, "vs_3_0")) { if (D3DSHADER_VERSION_MAJOR(gcpRendD3D->m_d3dCaps.VertexShaderVersion) < 3) { SAFE_DELETE_ARRAY(pbuf); bCreate = true; goto create; } m_CGProfileType = CG_PROFILE_VS_3_0; } else m_CGProfileType = CG_PROFILE_VS_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, "//"); TArray FoundNames; int i; while (token) { while (token[0]==0x20) {token++;} if (token[0] == '$') token++; char *szName = sGetText(&token); char *szReg = sGetText(&token); if (szReg[0] == 'c' && isdigit(szReg[1])) { if (!m_Insts[m_CurInst].m_BindVars) m_Insts[m_CurInst].m_BindVars = new TArray; SCGBind cgp; 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); } token = strtok(NULL, "//"); } for (i=0; i= 0) m_Insts[m_CurInst].m_BindVars->Get(FoundNames[i].nId).m_nComponents = FoundNames[i].nComponents; } 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 & VPFI_PRECACHEPHASE)) mfUnbind(); if (m_CGProfileType = CG_PROFILE_VS_3_0) { if (bUseACIICache) { int nnn = 0; } } } if (!m_Insts[m_CurInst].m_CGProgram) return false; return true; } void CCGVProgram_D3D::mfSetGlobalParams() { vec4_t v; CD3D9Renderer *r = gcpRendD3D; LPDIRECT3DDEVICE9 dv = r->mfGetD3DDevice(); if (!(r->m_Features & RFT_HW_VS)) return; if (m_nResetDeviceFrame != r->m_nFrameReset) { m_nResetDeviceFrame = r->m_nFrameReset; // create a perlin noise permuation table vec4_t c[66]; int i; // want reproducable behaviour for debug //srand(1); for(i=0; i<32; i++) { c[i][3] = (float)i; Vec3d v; v[0] = frand(); v[1] = frand(); v[2] = frand(); v.Normalize(); c[i][0] = v[0]; c[i][1] = v[1]; c[i][2] = v[2]; } for(i=0; i<32; i++) { // choose two entries at random and swap int j = (rand() >> 4) & 31; // lower bits of rand() are bogus sometimes Exchange (c[j][3], c[i][3]); c[i+32][0] = c[i][0]; c[i+32][1] = c[i][1]; c[i+32][2] = c[i][2]; } for(i=0; i<64; i++) { dv->SetVertexShaderConstantF(30+i, &c[i][0], 1); } dv->SetVertexShaderConstantF(30+i, &c[0][0], 1); dv->SetVertexShaderConstantF(30+i+1, &c[1][0], 1); } SParamComp_Fog p; p.m_Type = 2; v[0] = p.mfGet(); p.m_Type = 3; v[1] = p.mfGet(); v[2] = 0; v[3] = 0; int n = VSCONST_FOG; //if (m_CurParams[n][0] != v[0] || m_CurParams[n][1] != v[1] || m_CurParams[n][2] != v[2] || m_CurParams[n][3] != v[3]) { m_CurParams[n][0] = v[0]; m_CurParams[n][1] = v[1]; m_CurParams[n][2] = v[2]; m_CurParams[n][3] = v[3]; dv->SetVertexShaderConstantF(n, v, 1); } v[0] = 0; v[1] = 0.25f; v[2] = 0.5f; v[3] = 1.0f; n = VSCONST_0_025_05_1; //if (m_CurParams[n][0] != v[0] || m_CurParams[n][1] != v[1] || m_CurParams[n][2] != v[2] || m_CurParams[n][3] != v[3]) { m_CurParams[n][0] = v[0]; m_CurParams[n][1] = v[1]; m_CurParams[n][2] = v[2]; m_CurParams[n][3] = v[3]; dv->SetVertexShaderConstantF(n, v, 1); } if ((gRenDev->m_Features & RFT_HW_HDR) || (r->m_Features & RFT_HW_PS30)) { n = PSCONST_HDR_FOGCOLOR; //if (m_CurParams[n][0] != v[0] || m_CurParams[n][1] != v[1] || m_CurParams[n][2] != v[2] || m_CurParams[n][3] != v[3]) { m_CurParams[n][0] = r->m_FS.m_FogColor[0]; m_CurParams[n][1] = r->m_FS.m_FogColor[1]; m_CurParams[n][2] = r->m_FS.m_FogColor[2]; m_CurParams[n][3] = r->m_FS.m_FogColor[3]; dv->SetPixelShaderConstantF(n, &r->m_FS.m_FogColor[0], 1); } } } void CCGVProgram_D3D::mfSetVariables(TArray* Vars) { int i; for (i=0; iNum(); i++) { SCGParam4f *p = &Vars->Get(i); if (p->m_nComponents > 1) { float matr[16][4]; int nLast = i+p->m_nComponents; int n = 0; SCGParam4f *pMatr = p; for (; iGet(i); float *v = p->mfGet(); matr[n][0] = v[0]; matr[n][1] = v[1]; matr[n][2] = v[2]; matr[n][3] = v[3]; } i--; mfParameter(pMatr, &matr[0][0], pMatr->m_nComponents); } else { float *v = p->mfGet(); if (p->m_Flags & PF_INTEGER) mfParameter4i(p, v); else mfParameter4f(p, v); } } } void CCGVProgram_D3D::mfSetVariables(bool bObj, TArray* Parms) { if (m_Insts[m_CurInst].m_pHandle == 0 || (INT_PTR)m_Insts[m_CurInst].m_pHandle == -1) return; //PROFILE_FRAME(Shader_VShadersParms); 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((TArray *)Parms); } bool CCGVProgram_D3D::mfSet(bool bStat, SShaderPassHW *slw, int nFlags) { //PROFILE_FRAME(Shader_VShaders); CD3D9Renderer *rd = gcpRendD3D; if (!bStat) { #ifdef DO_RENDERLOG if (CRenderer::CV_r_log == 4) rd->Logv(SRendItem::m_RecurseLevel, "--- Reset CGVProgram \"%s\"\n", m_Name.c_str()); #endif m_LastVP = 0; mfUnbind(); return true; } rd->m_RP.m_CurVP = this; int Mask; if ((m_Flags & VPFI_NOFOG) || !CRenderer::CV_r_vpfog || !(rd->m_Features & RFT_FOGVP)) Mask = VPVST_NOFOG; else Mask = VPVST_FOGGLOBAL; if (nFlags & (VPF_INSTANCING_NOROTATE | VPF_INSTANCING_ROTATE)) { if (nFlags & VPF_INSTANCING_NOROTATE) Mask |= VPVST_INSTANCING_NOROT; else Mask |= VPVST_INSTANCING_ROT; } if (rd->m_RP.m_PersFlags & RBPF_HDR) Mask |= VPVST_HDR; if (rd->m_RP.m_ClipPlaneEnabled == 1) Mask |= VPVST_CLIPPLANES3; Mask |= (rd->m_RP.m_FlagsModificators & VPVST_TCMASK); CVProgram *pPosVP = this; if (m_Flags & VPFI_UNIFIEDPOS) { CVProgram *pVP = NULL; if (rd->m_RP.m_pRE && rd->m_RP.m_pRE->m_LastVP) pVP = rd->m_RP.m_pRE->m_LastVP; else if (rd->m_RP.m_RendPass) pVP = rd->m_RP.m_LastVP; else if (rd->m_RP.m_pShader->m_DefaultVProgram) pVP = rd->m_RP.m_pShader->m_DefaultVProgram; if (pVP && pVP->m_bCGType) { pPosVP = pVP; if (pVP->m_Flags & VPFI_NOISE) Mask |= VPVST_NOISE; } } int Id = mfGetCGInstanceID(Mask, pPosVP, rd->m_RP.m_ShaderLightMask); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) rd->Logv(SRendItem::m_RecurseLevel, "--- Set CGVProgram \"%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[Id].m_CGProgram == -1) return false; if (!m_Insts[Id].m_CGProgram) { if (!mfActivate(pPosVP)) { m_Insts[Id].m_pHandle = (void *)-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_NumVShaders++; } #endif if (m_LastVP != this || m_LastTypeVP != Mask || m_LastLTypeVP != m_Insts[m_CurInst].m_LightMask) { rd->m_RP.m_PS.m_NumVShadChanges++; m_LastVP = this; m_LastTypeVP = Mask; m_LastLTypeVP = m_Insts[m_CurInst].m_LightMask; // set the vertex shader mfBind(); } rd->m_RP.m_PersFlags |= RBPF_VSNEEDSET; if (!(nFlags & VPF_DONTSETMATRICES)) mfSetStateMatrices(); if (!(m_Flags & VPFI_UNIFIEDPOS)) rd->m_RP.m_LastVP = this; return true; }