From 590531595b9033641be6d7661cd6757d5bdca96f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 10 Nov 2017 02:02:27 +0000 Subject: [PATCH] Create @foreach shader preprocessor macro in preparation for moving shadow setup out of shadermanager.cpp --- components/shader/shadermanager.cpp | 121 +++++++++++++++++++++++----- files/shaders/objects_fragment.glsl | 10 ++- files/shaders/objects_vertex.glsl | 11 ++- files/shaders/terrain_fragment.glsl | 10 ++- files/shaders/terrain_vertex.glsl | 19 +++-- files/shaders/water_fragment.glsl | 25 +++--- files/shaders/water_vertex.glsl | 12 ++- 7 files changed, 159 insertions(+), 49 deletions(-) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index a0b1aca83..ea971586a 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -74,13 +74,82 @@ namespace Shader return true; } + bool parseFors(std::string& source) + { + const char escapeCharacter = '$'; + size_t foundPos = 0; + while ((foundPos = source.find(escapeCharacter)) != std::string::npos) + { + size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos); + if (endPos == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string command = source.substr(foundPos + 1, endPos - (foundPos + 1)); + if (command != "foreach") + { + std::cerr << "Unknown shader directive: $" << command << std::endl; + return false; + } + + size_t iterNameStart = endPos + 1; + size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); + if (iterNameEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string iteratorName = "$" + source.substr(iterNameStart, iterNameEnd - iterNameStart); + + size_t listStart = iterNameEnd + 1; + size_t listEnd = source.find_first_of("\n\r", listStart); + if (listEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string list = source.substr(listStart, listEnd - listStart); + std::vector listElements; + boost::split(listElements, list, boost::is_any_of(",")); + + size_t contentStart = source.find_first_not_of("\n\r", listEnd); + size_t contentEnd = source.find("$endforeach", contentStart); + if (contentEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + std::string content = source.substr(contentStart, contentEnd - contentStart); + + size_t overallEnd = contentEnd + std::string("$endforeach").length(); + // This will be wrong if there are other #line directives, so that needs fixing + int lineNumber = std::count(source.begin(), source.begin() + overallEnd, '\n') + 2; + + std::string replacement = ""; + for (std::vector::const_iterator element = listElements.cbegin(); element != listElements.cend(); element++) + { + std::string contentInstance = content; + size_t foundIterator; + while ((foundIterator = contentInstance.find(iteratorName)) != std::string::npos) + contentInstance.replace(foundIterator, iteratorName.length(), *element); + replacement += contentInstance; + } + replacement += "\n#line " + std::to_string(lineNumber); + source.replace(foundPos, overallEnd - foundPos, replacement); + } + + return true; + } + bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines) { const char escapeCharacter = '@'; size_t foundPos = 0; + std::vector forIterators; while ((foundPos = source.find(escapeCharacter)) != std::string::npos) { - size_t endPos = source.find_first_of(" \n\r()[].;", foundPos); + size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos); if (endPos == std::string::npos) { std::cerr << "Unexpected EOF" << std::endl; @@ -88,7 +157,34 @@ namespace Shader } std::string define = source.substr(foundPos+1, endPos - (foundPos+1)); ShaderManager::DefineMap::const_iterator defineFound = defines.find(define); - if (defineFound == defines.end()) + if (define == "foreach") + { + source.replace(foundPos, 1, "$"); + size_t iterNameStart = endPos + 1; + size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); + if (iterNameEnd == std::string::npos) + { + std::cerr << "Unexpected EOF" << std::endl; + return false; + } + forIterators.push_back(source.substr(iterNameStart, iterNameEnd - iterNameStart)); + } + else if (define == "endforeach") + { + source.replace(foundPos, 1, "$"); + if (forIterators.empty()) + { + std::cerr << "endforeach without foreach" << std::endl; + return false; + } + else + forIterators.pop_back(); + } + else if (std::find(forIterators.begin(), forIterators.end(), define) != forIterators.end()) + { + source.replace(foundPos, 1, "$"); + } + else if (defineFound == defines.end()) { std::cerr << "Undefined " << define << std::endl; return false; @@ -113,23 +209,10 @@ namespace Shader if (shadows) { definesWithShadows.insert(std::make_pair(std::string("shadows_enabled"), std::string("1"))); - - /*definesWithShadows.insert(std::string("shadow_texture_unit_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_space_coordinate_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_space_coordinate_calculations"), std::string("")); - definesWithShadows.insert(std::string("shadow_texture_sampler_declarations"), std::string("")); - definesWithShadows.insert(std::string("shadow_texture_lookup_calculations"), std::string(""));*/ for (int i = 0; i < numShadowMaps; ++i) - { - definesWithShadows["shadow_texture_unit_declarations"] += "uniform int shadowTextureUnit" + std::to_string(i) + ";\n"; - definesWithShadows["shadow_space_coordinate_declarations"] += "varying vec4 shadowSpaceCoords" + std::to_string(i) + ";\n"; - - definesWithShadows["shadow_space_coordinate_calculations"] += "eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneT[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneR[shadowTextureUnit" + std::to_string(i) + "], gl_EyePlaneQ[shadowTextureUnit" + std::to_string(i) + "]);\n" - + "shadowSpaceCoords" + std::to_string(i) + " = viewPos * eyePlaneMat;\n"; - - definesWithShadows["shadow_texture_sampler_declarations"] += "uniform sampler2DShadow shadowTexture" + std::to_string(i) + ";\n"; - definesWithShadows["shadow_texture_lookup_calculations"] += "shadowing *= shadow2DProj(shadowTexture" + std::to_string(i) + ", shadowSpaceCoords" + std::to_string(i) + ").r;\n"; - } + definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ","; + // remove extra comma + definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(0, definesWithShadows["shadow_texture_unit_list"].length() - 1); } definesWithShadows.insert(defines.begin(), defines.end()); @@ -161,7 +244,7 @@ namespace Shader if (shaderIt == mShaders.end()) { std::string shaderSource = templateIt->second; - if (!parseDefines(shaderSource, definesWithShadows)) + if (!parseDefines(shaderSource, definesWithShadows) || !parseFors(shaderSource)) { // Add to the cache anyway to avoid logging the same error over and over. mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), nullptr)); diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 7d9372c71..9196c1490 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -58,8 +58,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_sampler_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -122,7 +124,9 @@ void main() float shadowing = 1.0; #if SHADOWS - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index fb612afc8..f84971c97 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -49,8 +49,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_unit_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -111,6 +113,9 @@ void main(void) #if SHADOWS // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat; - @shadow_space_coordinate_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach #endif // SHADOWS } diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index e512d7475..1b985e14b 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -28,8 +28,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_sampler_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -74,7 +76,9 @@ void main() float shadowing = 1.0; #if SHADOWS - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach #endif // SHADOWS #if !PER_PIXEL_LIGHTING diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 692e76cce..7cb959d3e 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -17,8 +17,10 @@ varying vec3 passViewPos; varying vec3 passNormal; #if SHADOWS - @shadow_texture_unit_declarations - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS #include "lighting.glsl" @@ -42,9 +44,12 @@ void main(void) uv = gl_MultiTexCoord0.xy; - #if SHADOWS - // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; - @shadow_space_coordinate_calculations - #endif // SHADOWS +#if SHADOWS + // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. + mat4 eyePlaneMat; + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach +#endif // SHADOWS } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 586a247a4..ca09aa94b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,5 +1,7 @@ #version 120 +//DUMPME + #define REFRACTION @refraction_enabled #define SHADOWS @shadows_enabled @@ -144,9 +146,10 @@ uniform vec3 nodePosition; uniform float rainIntensity; #if SHADOWS - @shadow_texture_sampler_declarations - - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform sampler2DShadow shadowTexture@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS float frustumDepth; @@ -165,15 +168,17 @@ void main(void) vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; - #if SHADOWS - float shadowing = 1.0; +#if SHADOWS + float shadowing = 1.0; - @shadow_texture_lookup_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + shadowing *= shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r; + @endforeach - float shadow = shadowing; - #else // NOT SHADOWS - float shadow = 1.0; - #endif // SHADOWS + float shadow = shadowing; +#else // NOT SHADOWS + float shadow = 1.0; +#endif // SHADOWS vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1.0-screenCoords.y); diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 6381155d0..1a14bcaa6 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -7,9 +7,10 @@ varying float depthPassthrough; #define SHADOWS @shadows_enabled #if SHADOWS - @shadow_texture_unit_declarations - - @shadow_space_coordinate_declarations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform int shadowTextureUnit@shadow_texture_unit_index; + varying vec4 shadowSpaceCoords@shadow_texture_unit_index; + @endforeach #endif // SHADOWS void main(void) @@ -33,6 +34,9 @@ void main(void) // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. mat4 eyePlaneMat; - @shadow_space_coordinate_calculations + @foreach shadow_texture_unit_index @shadow_texture_unit_list + eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); + shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + @endforeach #endif // SHADOWS }