diff --git a/RenderSystems/GLSupport/include/GLSL/OgreGLSLPreprocessor.h b/RenderSystems/GLSupport/include/GLSL/OgreGLSLPreprocessor.h index 893aed41c80..877e83b1deb 100644 --- a/RenderSystems/GLSupport/include/GLSL/OgreGLSLPreprocessor.h +++ b/RenderSystems/GLSupport/include/GLSL/OgreGLSLPreprocessor.h @@ -207,9 +207,13 @@ namespace Ogre { /// A stack of 32 booleans packed into one value :) unsigned EnableOutput; unsigned EnableElif; + unsigned Passthrough; /// The list of macros defined so far std::forward_list MacroList; + /// List of define prefixes to pass through + std::vector PassthroughList; + /** * Private constructor to re-parse a single token. */ @@ -444,6 +448,14 @@ namespace Ogre { /// Destroy the preprocessor object virtual ~CPreprocessor (); + /** Define-prefixes from this list cause the #if directive not to be expanded + + useful to test GLSL extension support at runtime + @param lst the list. Supposed to contain string literals. Make sure that the memory pointed + is available throughout the lifetime of CPreprocessor otherwise. + */ + void setPassthroughDefines(const std::vector& lst) { PassthroughList = lst; } + /** * Define a macro without parameters. * @param iMacroName diff --git a/RenderSystems/GLSupport/src/GLSL/OgreGLSLPreprocessor.cpp b/RenderSystems/GLSupport/src/GLSL/OgreGLSLPreprocessor.cpp index fe045f2eaf5..94427ec8e84 100644 --- a/RenderSystems/GLSupport/src/GLSL/OgreGLSLPreprocessor.cpp +++ b/RenderSystems/GLSupport/src/GLSL/OgreGLSLPreprocessor.cpp @@ -989,6 +989,7 @@ namespace Ogre { EnableElif <<= 1; EnableOutput <<= 1; + Passthrough <<= 1; if (val) EnableOutput |= 1; else @@ -1118,6 +1119,22 @@ namespace Ogre { return true; } + static const char* strnstr(const char* haystack, size_t length, const char* needle) + { + size_t needle_length = strlen(needle); + for (size_t i = 0; i < length; i++) + { + if (i + needle_length > length) + { + return NULL; + } + if (strncmp(&haystack[i], needle, needle_length) == 0) + { + return &haystack[i]; + } + } + return NULL; + } CPreprocessor::Token CPreprocessor::HandleDirective (Token &iToken, int iLine) { @@ -1178,6 +1195,19 @@ namespace Ogre { } Done: + if (strncmp(directive, "if", 2) == 0) + { + for(auto def : PassthroughList) + { + if(strnstr(t.String, t.Length, def)) + { + Passthrough |= 1; + } + } + } + + bool passthrough = Passthrough & 1; + #define IS_DIRECTIVE(s) \ (dirlen == strlen(s) && (strncmp (directive, s, dirlen) == 0)) @@ -1188,9 +1218,9 @@ namespace Ogre { rc = HandleDefine (t, iLine); else if (IS_DIRECTIVE ("undef") && outputEnabled) rc = HandleUnDef (t, iLine); - else if (IS_DIRECTIVE ("ifdef")) + else if (IS_DIRECTIVE ("ifdef") && !passthrough) rc = HandleIfDef (t, iLine); - else if (IS_DIRECTIVE ("ifndef")) + else if (IS_DIRECTIVE ("ifndef") && !passthrough) { rc = HandleIfDef (t, iLine); if (rc) @@ -1199,19 +1229,18 @@ namespace Ogre { EnableElif ^= 1; } } - else if (IS_DIRECTIVE ("if")) + else if (IS_DIRECTIVE ("if") && !passthrough) rc = HandleIf (t, iLine); - else if (IS_DIRECTIVE ("elif")) + else if (IS_DIRECTIVE ("elif") && !passthrough) rc = HandleElif (t, iLine); - else if (IS_DIRECTIVE ("else")) + else if (IS_DIRECTIVE ("else") && !passthrough) rc = HandleElse (t, iLine); - else if (IS_DIRECTIVE ("endif")) + else if (IS_DIRECTIVE ("endif") && !passthrough) rc = HandleEndIf (t, iLine); else { - //Error (iLine, "Unknown preprocessor directive", &iToken); - //return Token (Token::TK_ERROR); + if(IS_DIRECTIVE ("endif")) Passthrough &= ~1; // Unknown preprocessor directive, roll back and pass through Line = old_line; @@ -1272,6 +1301,7 @@ namespace Ogre { BOL = true; EnableOutput = 1; EnableElif = 0; + Passthrough = 0; // Accumulate output into this token Token output (Token::TK_TEXT); diff --git a/RenderSystems/GLSupport/src/GLSL/OgreGLSLShaderCommon.cpp b/RenderSystems/GLSupport/src/GLSL/OgreGLSLShaderCommon.cpp index 2a19b3f4d4d..8b0d93264e5 100644 --- a/RenderSystems/GLSupport/src/GLSL/OgreGLSLShaderCommon.cpp +++ b/RenderSystems/GLSupport/src/GLSL/OgreGLSLShaderCommon.cpp @@ -57,8 +57,8 @@ namespace Ogre { // Preprocess the GLSL shader in order to get a clean source CPreprocessor cpp; + cpp.setPassthroughDefines({"GL_ARB", "GL_EXT", "GL_OES", "__VERSION__"}); // Define "predefined" macros. - // TODO: decide, should we define __VERSION__, and with what value. if(getLanguage() == "glsles") cpp.Define("GL_ES", 5, 1); diff --git a/Tests/RenderSystems/GLSupport/GLSLTests.cpp b/Tests/RenderSystems/GLSupport/GLSLTests.cpp index 4d5783ae70b..d3ddd056c01 100644 --- a/Tests/RenderSystems/GLSupport/GLSLTests.cpp +++ b/Tests/RenderSystems/GLSupport/GLSLTests.cpp @@ -61,6 +61,23 @@ TEST(CPreprocessorTests, MacroExpansion) free(out); } +TEST(CPreprocessorTests, Passthrough) +{ + CPreprocessor prep; + prep.setPassthroughDefines({"GL_ARB"}); + String src = "#ifdef GL_ARB_shader_texture_lod\n" + "textureCubeLod\n" + "#else\n" + "textureCube\n" + "#endif"; + + size_t olen; + char* out = prep.Parse(src.c_str(), src.size(), olen); + String str(out, olen); + EXPECT_EQ(src, str); + free(out); +} + TEST(CPreprocessorTests, IfDef) { CPreprocessor prep;