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