diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index a0b1aca83c..ea971586ab 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 7d9372c718..9196c14902 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 fb612afc82..f84971c972 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 e512d74756..1b985e14b4 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 692e76cce7..7cb959d3ef 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 586a247a4b..ca09aa94be 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 6381155d0b..1a14bcaa66 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 }