Ticket #3640: preprocessor_include_with_hotload_impl.patch
File preprocessor_include_with_hotload_impl.patch, 16.9 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/maps/skirmishes/Acropolis
30 30 <Contrast>0.96875</Contrast> 31 31 <Saturation>1</Saturation> 32 32 <Bloom>0.186523</Bloom> 33 <PostEffect> hdr</PostEffect>33 <PostEffect>smaa</PostEffect> 34 34 </Postproc> 35 35 </Environment> 36 36 <Camera> -
binaries/data/mods/public/shaders/effects/postproc/smaa.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <effect> 3 <technique> 4 <require shaders="glsl"/> 5 <pass shader="glsl/edge_detection"/> 6 <!--<pass shader="glsl/blending_weights"/>--> 7 <!--<pass shader="glsl/neighborhood_blending"/>--> 8 </technique> 9 </effect> 10 No newline at end of file -
binaries/data/mods/public/shaders/glsl/edge_detection.fs
1 #version 120 2 3 uniform sampler2D renderedTex; 4 5 varying vec2 v_tex; 6 7 void main(void) 8 { 9 gl_FragColor.rgb = texture2D(renderedTex, v_tex).rgb; 10 gl_FragColor.a = 1.0; 11 } 12 13 -
binaries/data/mods/public/shaders/glsl/edge_detection.vs
1 #version 110 2 3 #include "glsl/header.glsl" 4 5 #define Y X 6 7 varying vec2 v_tex; 8 9 attribute vec3 a_vertex; 10 attribute vec2 a_uv0; 11 12 void main() 13 { 14 vec2 tmp = vec2(Y); 15 gl_Position = vec4(a_vertex, 1.0); 16 v_tex = a_uv0; 17 } 18 No newline at end of file -
binaries/data/mods/public/shaders/glsl/edge_detection.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <program type="glsl"> 3 <vertex file="glsl/edge_detection.vs"> 4 <stream name="pos"/> 5 <stream name="uv0"/> 6 <attrib name="a_vertex" semantics="gl_Vertex"/> 7 <attrib name="a_uv0" semantics="gl_MultiTexCoord0"/> 8 </vertex> 9 <fragment file="glsl/edge_detection.fs"/> 10 </program> -
binaries/data/mods/public/shaders/glsl/header.glsl
1 #define X 1.0 2 3 void m() 4 { 5 } 6 No newline at end of file -
graphics/ShaderManager.cpp
60 60 CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const CShaderDefines& defines) 61 61 { 62 62 CacheKey key = { name, defines }; 63 std::map<CacheKey, CShaderProgramPtr>::iteratorit = m_ProgramCache.find(key);63 auto it = m_ProgramCache.find(key); 64 64 if (it != m_ProgramCache.end()) 65 65 return it->second; 66 66 … … 265 265 else 266 266 program = CShaderProgramPtr(CShaderProgram::ConstructARB(vertexFile, fragmentFile, defines, vertexUniforms, fragmentUniforms, streamFlags)); 267 267 268 // add included file listener 269 program->RegisterIncludedFilesObserver(std::bind(&CShaderManager::AddHotloadFile, this, std::placeholders::_1, program)); 270 268 271 program->Reload(); 269 272 270 273 // m_HotloadFiles[xmlFilename].insert(program); // TODO: should reload somehow when the XML changes … … 556 559 return m_EffectCache.size(); 557 560 } 558 561 562 void CShaderManager::AddHotloadFile(const VfsPath& filename, CShaderProgramPtr program) 563 { 564 m_HotloadFiles[filename].insert(program); 565 } 566 559 567 /*static*/ Status CShaderManager::ReloadChangedFileCB(void* param, const VfsPath& path) 560 568 { 561 569 return static_cast<CShaderManager*>(param)->ReloadChangedFile(path); … … 564 572 Status CShaderManager::ReloadChangedFile(const VfsPath& path) 565 573 { 566 574 // Find all shaders using this file 567 HotloadFilesMap::iteratorfiles = m_HotloadFiles.find(path);575 auto files = m_HotloadFiles.find(path); 568 576 if (files != m_HotloadFiles.end()) 569 577 { 570 578 // Reload all shaders using this file 571 for (std::set<std::weak_ptr<CShaderProgram> >::iterator it = files->second.begin(); it != files->second.end(); ++it)579 for_each(files->second.begin(), files->second.end(), [](const std::weak_ptr<CShaderProgram> p) 572 580 { 573 if ( std::shared_ptr<CShaderProgram> program = it->lock())581 if (auto program = p.lock()) 574 582 program->Reload(); 575 } 583 }); 576 584 } 577 585 578 586 // TODO: hotloading changes to shader XML files and effect XML files would be nice -
graphics/ShaderManager.h
72 72 */ 73 73 size_t GetNumEffectsLoaded(); 74 74 75 /** 76 * Associates file with program to be reloaded if file has changed 77 */ 78 void AddHotloadFile(const VfsPath&, CShaderProgramPtr program); 79 75 80 private: 76 81 77 82 struct CacheKey -
graphics/ShaderProgram.cpp
432 432 433 433 CPreprocessorWrapper preprocessor; 434 434 preprocessor.AddDefines(m_Defines); 435 preprocessor.RegisterIncludedFilesObserver(IncludedFileObserver); 435 436 436 437 #if CONFIG2_GLES 437 438 // GLES defines the macro "GL_ES" in its GLSL preprocessor, … … 890 891 { 891 892 ENSURE((m_StreamFlags & ~m_ValidStreams) == 0); 892 893 } 894 895 void CShaderProgram::RegisterIncludedFilesObserver(std::function<void(const VfsPath&)> fileObserver) 896 { 897 IncludedFileObserver = fileObserver; 898 } -
graphics/ShaderProgram.h
193 193 */ 194 194 void AssertPointersBound(); 195 195 196 /** 197 * Register observer to be notified on each included file 198 */ 199 void RegisterIncludedFilesObserver(std::function<void(const VfsPath&)>); 200 196 201 protected: 197 202 CShaderProgram(int streamflags); 198 203 … … 203 208 void BindClientStates(); 204 209 void UnbindClientStates(); 205 210 int m_ValidStreams; // which streams have been specified via VertexPointer etc since the last Bind 211 212 std::function<void(const VfsPath&)> IncludedFileObserver; 206 213 }; 207 214 208 215 #endif // INCLUDED_SHADERPROGRAM -
ps/Preprocessor.cpp
38 38 39 39 #include "ps/CLogger.h" 40 40 41 #include "ps/Filesystem.h" // to handle #include 42 41 43 // Limit max number of macro arguments to this 42 44 #define MAX_MACRO_ARGS 16 43 45 … … 224 226 return xt; 225 227 } 226 228 229 CPreprocessor::Macro *CPreprocessor::Macro::copy() 230 { 231 Token mainCopy; 232 233 // Copy buffer once 234 char *buffer = new char[this->Body.Length]; 235 strncpy(buffer, this->Body.String, this->Body.Length); 236 237 // Copy each subcomponent of Macro 238 Token body = Token(this->Body.Type, buffer, this->Body.Length); 239 Token name = Token(this->Name.Type, buffer, this->Name.Length); 240 Token value = Token(this->Value.Type, buffer + (this->Value.Buffer - this->Body.Buffer), this->Value.Length); 241 242 // FIXME: Ignore Args for now 243 244 Macro *macroCopy = new Macro(name); 245 macroCopy->Body = body; 246 macroCopy->Value = value; 247 248 return macroCopy; 249 } 250 227 251 //---------------------------------------------------------------------------// 228 252 229 253 static void DefaultError (void *iData, int iLine, const char *iError, … … 700 724 return false; 701 725 702 726 case Token::TK_KEYWORD: 703 727 { 704 728 // Try to expand the macro 705 729 Macro *m = IsDefined (*vt); 706 730 if (m != NULL && !m->Expanding) 707 731 { 708 732 Token x = ExpandMacro (*vt); … … 715 739 // Undefined macro, "expand" to 0 (mimic cpp behaviour) 716 740 oValue = 0; 717 741 break; 718 742 } 719 743 case Token::TK_TEXT: 720 744 case Token::TK_NUMBER: 721 745 if (!vt->GetValue (oValue)) … … 869 893 return t; 870 894 } 871 895 872 bool CPreprocessor::HandleDefine 896 bool CPreprocessor::HandleDefine(Token &iBody, int iLine) 873 897 { 874 898 // Create an additional preprocessor to process macro body 875 CPreprocessor cpp 899 CPreprocessor cpp(iBody, iLine); 876 900 877 Token t = cpp.GetToken 901 Token t = cpp.GetToken(false); 878 902 if (t.Type != Token::TK_KEYWORD) 879 903 { 880 Error 904 Error(iLine, "Macro name expected after #define"); 881 905 return false; 882 906 } 883 907 884 908 bool output_enabled = ((EnableOutput & (EnableOutput + 1)) == 0); 885 909 if (!output_enabled) 886 910 return true; 887 911 888 Macro *m = new Macro 912 Macro *m = new Macro(t); 889 913 m->Body = iBody; 890 t = cpp.GetArguments 914 t = cpp.GetArguments(m->NumArgs, m->Args, false); 891 915 while (t.Type == Token::TK_WHITESPACE) 892 t = cpp.GetToken 916 t = cpp.GetToken(false); 893 917 894 918 switch (t.Type) 895 919 { 896 897 898 899 t = Token(Token::TK_TEXT, "", 0);900 920 case Token::TK_NEWLINE: 921 case Token::TK_EOS: 922 // Assign "" to token 923 t = Token(Token::TK_TEXT, "", 0); 924 break; 901 925 902 903 904 926 case Token::TK_ERROR: 927 delete m; 928 return false; 905 929 906 907 908 ENSURE(t.String + t.Length == cpp.Source);909 910 930 default: 931 t.Type = Token::TK_TEXT; 932 ENSURE(t.String + t.Length == cpp.Source); 933 t.Length = cpp.SourceEnd - t.String; 934 break; 911 935 } 912 936 913 937 m->Value = t; … … 979 1003 return true; 980 1004 } 981 1005 1006 CPreprocessor::Token CPreprocessor::HandleInclude(Token &iBody, int iLine) 1007 { 1008 CPreprocessor cpp(iBody, iLine); 1009 1010 Token t = cpp.GetToken(false); 1011 1012 if (t.Type != Token::TK_STRING) 1013 { 1014 Error(iLine, "Expecting a file name after #include, got", &t); 1015 return Token(); 1016 } 1017 1018 std::string filename = std::string(t.String).substr(0, t.Length); 1019 ENSURE(filename.at(0) == '"' && filename.at(t.Length-1) == '"'); 1020 filename = filename.substr(1, t.Length - 2); // remove '"' symbols from the beginning and from the end of token 1021 1022 CVFSFile includedFile; 1023 const VfsPath includedFilePath(L"shaders/" + wstring_from_utf8(filename)); 1024 if (includedFile.Load(g_VFS, includedFilePath) != PSRETURN_OK) 1025 Error(iLine, "Warning: File not found", &t); 1026 IncludedFileObserver(includedFilePath); 1027 const CStr& input = includedFile.GetAsString(); 1028 1029 size_t len = 0; 1030 CPreprocessor preprocessor; 1031 ENSURE(input.size() > 0); 1032 //preprocessor.AddDefines(m_Defines); 1033 std::string includedSources = preprocessor.Parse(input.c_str(), input.size(), len); 1034 char *result = new char[len]; 1035 includedSources.copy(result, len); 1036 1037 // Copy macros 1038 Macro *m = preprocessor.MacroList; 1039 while (m) { 1040 Macro *copy = m->copy(); 1041 copy->Next = MacroList; 1042 MacroList = copy; 1043 m = m->Next; 1044 } 1045 1046 if (!result) 1047 { 1048 Error(iLine, "Problem during preprocessing of included file", &t); 1049 return Token(); 1050 } 1051 1052 do 1053 { 1054 t = cpp.GetToken(false); 1055 } while (t.Type == Token::TK_WHITESPACE || 1056 t.Type == Token::TK_COMMENT || 1057 t.Type == Token::TK_LINECOMMENT); 1058 1059 if (t.Type != Token::TK_EOS) 1060 Error(iLine, "Warning: Ignoring garbage after directive", &t); 1061 1062 return Token(Token::TK_STRING, result, len);; 1063 } 1064 982 1065 CPreprocessor::Token CPreprocessor::ExpandDefined (CPreprocessor *iParent, int iNumArgs, Token *iArgs) 983 1066 { 984 1067 if (iNumArgs != 1) … … 1113 1196 ((dirlen == sizeof (s) - 1) && (strncmp (directive, s, sizeof (s) - 1) == 0)) 1114 1197 1115 1198 bool rc; 1116 if (IS_DIRECTIVE 1117 rc = HandleDefine 1199 if (IS_DIRECTIVE("define")) 1200 rc = HandleDefine(t, iLine); 1118 1201 else if (IS_DIRECTIVE ("undef")) 1119 1202 rc = HandleUnDef (t, iLine); 1120 1203 else if (IS_DIRECTIVE ("ifdef")) … … 1125 1208 if (rc) 1126 1209 EnableOutput ^= 1; 1127 1210 } 1211 else if (IS_DIRECTIVE("include")) 1212 return HandleInclude(t, iLine); 1128 1213 else if (IS_DIRECTIVE ("if")) 1129 1214 rc = HandleIf (t, iLine); 1130 1215 else if (IS_DIRECTIVE ("else")) … … 1176 1261 1177 1262 void CPreprocessor::Define (const char *iMacroName, const char *iMacroValue) 1178 1263 { 1179 1264 Define (iMacroName, strlen(iMacroName), iMacroValue, strlen(iMacroValue)); 1180 1265 } 1181 1266 1182 1267 void CPreprocessor::Define (const char *iMacroName, long iMacroValue) 1183 1268 { 1184 1269 Define (iMacroName, strlen(iMacroName), iMacroValue); 1185 1270 } 1186 1271 1187 1272 bool CPreprocessor::Undef (const char *iMacroName, size_t iMacroNameLen) … … 1265 1350 1266 1351 if (output_enabled) 1267 1352 output.AppendNL (Line - old_line - t.CountNL ()); 1353 1268 1354 goto NextToken; 1269 1355 1270 1356 case Token::TK_LINECONT: … … 1311 1397 retval.Allocated = 0; 1312 1398 return retval.Buffer; 1313 1399 } 1400 1401 void CPreprocessor::RegisterIncludedFilesObserver(std::function<void(const VfsPath&)> fileObserver) 1402 { 1403 IncludedFileObserver = fileObserver; 1404 } -
ps/Preprocessor.h
35 35 #ifndef INCLUDED_CPREPROCESSOR 36 36 #define INCLUDED_CPREPROCESSOR 37 37 38 #include <functional> 39 40 // Forward declare VfsPath, which is typedefed Path 41 class Path; 42 typedef Path VfsPath; 43 38 44 /** 39 45 * This is a simplistic C/C++-like preprocessor. 40 46 * It takes an non-zero-terminated string on input and outputs a … … 200 206 201 207 /// Expand the macro value (will not work for functions) 202 208 Token Expand (int iNumArgs, Token *iArgs, Macro *iMacros); 209 210 /// Performs deep copy of this macro 211 Macro *copy(); 203 212 }; 204 213 205 214 friend class CPreprocessor::Macro; … … 217 226 /// The list of macros defined so far 218 227 Macro *MacroList; 219 228 229 /// Listener to be notified about new included files 230 std::function<void(const VfsPath&)> IncludedFileObserver; 231 220 232 /** 221 233 * Private constructor to re-parse a single token. 222 234 */ … … 278 290 */ 279 291 bool HandleIfDef (Token &iBody, int iLine); 280 292 293 /** 294 * Handle a \#include directive. 295 * @param iBody 296 * The body of the directive (everything after the directive 297 * until end of line). 298 * @param iLine 299 * The line where the directive begins (for error reports) 300 * @return 301 * Included text enclosed in a token 302 */ 303 Token HandleInclude (Token &iBody, int iLine); 304 281 305 /** 282 306 * Handle an \#if directive. 283 307 * @param iBody … … 508 532 */ 509 533 char *Parse (const char *iSource, size_t iLength, size_t &oLength); 510 534 535 /** 536 * Register observer to be notified on each included file 537 */ 538 void RegisterIncludedFilesObserver(std::function<void(const VfsPath&)>); 539 511 540 /** 512 541 * An error handler function type. 513 542 * The default implementation just drops a note to stderr and -
ps/PreprocessorWrapper.cpp
84 84 85 85 return ret; 86 86 } 87 88 void CPreprocessorWrapper::RegisterIncludedFilesObserver(std::function<void(const VfsPath&)> observer) 89 { 90 m_Preprocessor.RegisterIncludedFilesObserver(observer); 91 } -
ps/PreprocessorWrapper.h
37 37 38 38 CStr Preprocess(const CStr& input); 39 39 40 void RegisterIncludedFilesObserver(std::function<void(const VfsPath&)>); 41 40 42 private: 41 43 CPreprocessor m_Preprocessor; 42 44 };