diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 74418a004b..7e42a49f66 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -55,6 +55,7 @@ if (GTEST_FOUND AND GMOCK_FOUND) shader/parsedefines.cpp shader/parsefors.cpp + shader/parselinks.cpp shader/shadermanager.cpp ../openmw/options.cpp diff --git a/apps/openmw_test_suite/shader/parsefors.cpp b/apps/openmw_test_suite/shader/parsefors.cpp index 330feb172d..4e64042365 100644 --- a/apps/openmw_test_suite/shader/parsefors.cpp +++ b/apps/openmw_test_suite/shader/parsefors.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace { @@ -16,6 +17,12 @@ namespace const std::string mName = "shader"; }; + static bool parseFors(std::string& source, const std::string& templateName) + { + std::vector dummy; + return parseDirectives(source, dummy, {}, {}, templateName); + } + TEST_F(ShaderParseForsTest, empty_should_succeed) { ASSERT_TRUE(parseFors(mSource, mName)); diff --git a/apps/openmw_test_suite/shader/parselinks.cpp b/apps/openmw_test_suite/shader/parselinks.cpp new file mode 100644 index 0000000000..2e3697ba50 --- /dev/null +++ b/apps/openmw_test_suite/shader/parselinks.cpp @@ -0,0 +1,100 @@ +#include + +#include +#include +#include + +namespace +{ + using namespace testing; + using namespace Shader; + + using DefineMap = ShaderManager::DefineMap; + + struct ShaderParseLinksTest : Test + { + std::string mSource; + std::vector mLinkTargets; + ShaderManager::DefineMap mDefines; + const std::string mName = "my_shader.glsl"; + + bool parseLinks() + { + return parseDirectives(mSource, mLinkTargets, mDefines, {}, mName); + } + }; + + TEST_F(ShaderParseLinksTest, empty_should_succeed) + { + ASSERT_TRUE(parseLinks()); + EXPECT_EQ(mSource, ""); + EXPECT_TRUE(mLinkTargets.empty()); + } + + TEST_F(ShaderParseLinksTest, should_fail_for_single_escape_symbol) + { + mSource = "$"; + ASSERT_FALSE(parseLinks()); + EXPECT_EQ(mSource, "$"); + EXPECT_TRUE(mLinkTargets.empty()); + } + + TEST_F(ShaderParseLinksTest, should_fail_on_first_found_escaped_not_valid_directive) + { + mSource = "$foo "; + ASSERT_FALSE(parseLinks()); + EXPECT_EQ(mSource, "$foo "); + EXPECT_TRUE(mLinkTargets.empty()); + } + + TEST_F(ShaderParseLinksTest, should_fail_on_absent_link_target) + { + mSource = "$link "; + ASSERT_FALSE(parseLinks()); + EXPECT_EQ(mSource, "$link "); + EXPECT_TRUE(mLinkTargets.empty()); + } + + TEST_F(ShaderParseLinksTest, should_not_require_newline) + { + mSource = "$link \"foo.glsl\""; + ASSERT_TRUE(parseLinks()); + EXPECT_EQ(mSource, ""); + ASSERT_EQ(mLinkTargets.size(), 1); + EXPECT_EQ(mLinkTargets[0], "foo.glsl"); + } + + TEST_F(ShaderParseLinksTest, should_require_quotes) + { + mSource = "$link foo.glsl"; + ASSERT_FALSE(parseLinks()); + EXPECT_EQ(mSource, "$link foo.glsl"); + EXPECT_EQ(mLinkTargets.size(), 0); + } + + TEST_F(ShaderParseLinksTest, should_be_replaced_with_empty_line) + { + mSource = "$link \"foo.glsl\"\nbar"; + ASSERT_TRUE(parseLinks()); + EXPECT_EQ(mSource, "\nbar"); + ASSERT_EQ(mLinkTargets.size(), 1); + EXPECT_EQ(mLinkTargets[0], "foo.glsl"); + } + + TEST_F(ShaderParseLinksTest, should_only_accept_on_true_condition) + { + mSource = +R"glsl( +$link "foo.glsl" if 1 +$link "bar.glsl" if 0 +)glsl"; + ASSERT_TRUE(parseLinks()); + EXPECT_EQ(mSource, +R"glsl( + + +)glsl"); + ASSERT_EQ(mLinkTargets.size(), 1); + EXPECT_EQ(mLinkTargets[0], "foo.glsl"); + } +} diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 30c7ed1b1d..1341baad60 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -142,11 +143,123 @@ namespace Shader return true; } - bool parseFors(std::string& source, const std::string& templateName) + bool parseForeachDirective(std::string& source, const std::string& templateName, size_t foundPos) + { + size_t iterNameStart = foundPos + strlen("$foreach") + 1; + size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); + if (iterNameEnd == std::string::npos) + { + Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; + 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) + { + Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; + return false; + } + std::string list = source.substr(listStart, listEnd - listStart); + std::vector listElements; + if (list != "") + Misc::StringUtils::split(list, listElements, ","); + + size_t contentStart = source.find_first_not_of("\n\r", listEnd); + size_t contentEnd = source.find("$endforeach", contentStart); + if (contentEnd == std::string::npos) + { + Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; + return false; + } + std::string content = source.substr(contentStart, contentEnd - contentStart); + + size_t overallEnd = contentEnd + std::string("$endforeach").length(); + + size_t lineDirectivePosition = source.rfind("#line", overallEnd); + int lineNumber; + if (lineDirectivePosition != std::string::npos) + { + size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); + size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); + std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); + lineNumber = std::stoi(lineNumberString); + } + else + { + lineDirectivePosition = 0; + lineNumber = 2; + } + lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + overallEnd, '\n'); + + 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 parseLinkDirective(std::string& source, std::string& linkTarget, const std::string& templateName, size_t foundPos) + { + size_t endPos = foundPos + 5; + size_t lineEnd = source.find_first_of('\n', endPos); + // If lineEnd = npos, this is the last line, so no need to check + std::string linkStatement = source.substr(endPos, lineEnd - endPos); + std::regex linkRegex( + R"r(\s*"([^"]+)"\s*)r" // Find any quoted string as the link name -> match[1] + R"r((if\s+)r" // Begin optional condition -> match[2] + R"r((!)?\s*)r" // Optional ! -> match[3] + R"r(([_a-zA-Z0-9]+)?)r" // The condition -> match[4] + R"r()?\s*)r" // End optional condition -> match[2] + ); + std::smatch linkMatch; + bool hasCondition = false; + std::string linkConditionExpression; + if (std::regex_match(linkStatement, linkMatch, linkRegex)) + { + linkTarget = linkMatch[1].str(); + hasCondition = !linkMatch[2].str().empty(); + linkConditionExpression = linkMatch[4].str(); + } + else + { + Log(Debug::Error) << "Shader " << templateName << " error: Expected a shader filename to link"; + return false; + } + if (linkTarget.empty()) + { + Log(Debug::Error) << "Shader " << templateName << " error: Empty link name"; + return false; + } + + if (hasCondition) + { + bool condition = !(linkConditionExpression.empty() || linkConditionExpression == "0"); + if (linkMatch[3].str() == "!") + condition = !condition; + + if (!condition) + linkTarget = ""; + } + + source.replace(foundPos, lineEnd - foundPos, ""); + return true; + } + + bool parseDirectives(std::string& source, std::vector& linkedShaderTemplateNames, const ShaderManager::DefineMap& defines, const ShaderManager::DefineMap& globalDefines, const std::string& templateName) { const char escapeCharacter = '$'; size_t foundPos = 0; - while ((foundPos = source.find(escapeCharacter)) != std::string::npos) + + while ((foundPos = source.find(escapeCharacter, foundPos)) != std::string::npos) { size_t endPos = source.find_first_of(" \n\r()[].;,", foundPos); if (endPos == std::string::npos) @@ -154,72 +267,25 @@ namespace Shader Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; return false; } - std::string command = source.substr(foundPos + 1, endPos - (foundPos + 1)); - if (command != "foreach") + std::string directive = source.substr(foundPos + 1, endPos - (foundPos + 1)); + if (directive == "foreach") { - Log(Debug::Error) << "Shader " << templateName << " error: Unknown shader directive: $" << command; - return false; + if (!parseForeachDirective(source, templateName, foundPos)) + return false; } - - size_t iterNameStart = endPos + 1; - size_t iterNameEnd = source.find_first_of(" \n\r()[].;,", iterNameStart); - if (iterNameEnd == std::string::npos) + else if (directive == "link") { - Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; - 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) - { - Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; - return false; - } - std::string list = source.substr(listStart, listEnd - listStart); - std::vector listElements; - if (list != "") - Misc::StringUtils::split (list, listElements, ","); - - size_t contentStart = source.find_first_not_of("\n\r", listEnd); - size_t contentEnd = source.find("$endforeach", contentStart); - if (contentEnd == std::string::npos) - { - Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF"; - return false; - } - std::string content = source.substr(contentStart, contentEnd - contentStart); - - size_t overallEnd = contentEnd + std::string("$endforeach").length(); - - size_t lineDirectivePosition = source.rfind("#line", overallEnd); - int lineNumber; - if (lineDirectivePosition != std::string::npos) - { - size_t lineNumberStart = lineDirectivePosition + std::string("#line ").length(); - size_t lineNumberEnd = source.find_first_not_of("0123456789", lineNumberStart); - std::string lineNumberString = source.substr(lineNumberStart, lineNumberEnd - lineNumberStart); - lineNumber = std::stoi(lineNumberString); + std::string linkTarget; + if (!parseLinkDirective(source, linkTarget, templateName, foundPos)) + return false; + if (!linkTarget.empty() && linkTarget != templateName) + linkedShaderTemplateNames.push_back(linkTarget); } else { - lineDirectivePosition = 0; - lineNumber = 2; + Log(Debug::Error) << "Shader " << templateName << " error: Unknown shader directive: $" << directive; + return false; } - lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + overallEnd, '\n'); - - 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; @@ -265,6 +331,10 @@ namespace Shader else forIterators.pop_back(); } + else if (define == "link") + { + source.replace(foundPos, 1, "$"); + } else if (std::find(forIterators.begin(), forIterators.end(), define) != forIterators.end()) { source.replace(foundPos, 1, "$"); @@ -288,7 +358,7 @@ namespace Shader osg::ref_ptr ShaderManager::getShader(const std::string &templateName, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType) { - std::lock_guard lock(mMutex); + std::unique_lock lock(mMutex); // read the template if we haven't already TemplateMap::iterator templateIt = mShaderTemplates.find(templateName); @@ -319,7 +389,8 @@ namespace Shader if (shaderIt == mShaders.end()) { std::string shaderSource = templateIt->second; - if (!parseDefines(shaderSource, defines, mGlobalDefines, templateName) || !parseFors(shaderSource, templateName)) + std::vector linkedShaderNames; + if (!createSourceFromTemplate(shaderSource, linkedShaderNames, templateName, defines)) { // Add to the cache anyway to avoid logging the same error over and over. mShaders.insert(std::make_pair(std::make_pair(templateName, defines), nullptr)); @@ -333,6 +404,10 @@ namespace Shader static unsigned int counter = 0; shader->setName(Misc::StringUtils::format("%u %s", counter++, templateName)); + lock.unlock(); + getLinkedShaders(shader, linkedShaderNames, defines); + lock.lock(); + shaderIt = mShaders.insert(std::make_pair(std::make_pair(templateName, defines), shader)).first; } return shaderIt->second; @@ -348,6 +423,9 @@ namespace Shader osg::ref_ptr program = programTemplate ? cloneProgram(programTemplate) : osg::ref_ptr(new osg::Program); program->addShader(vertexShader); program->addShader(fragmentShader); + addLinkedShaders(vertexShader, program); + addLinkedShaders(fragmentShader, program); + found = mPrograms.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader), program)).first; } return found->second; @@ -377,11 +455,14 @@ namespace Shader // I'm not sure how to handle a shader that was already broken as there's no way to get a potential replacement to the nodes that need it. continue; std::string shaderSource = mShaderTemplates[templateId]; - if (!parseDefines(shaderSource, defines, mGlobalDefines, templateId) || !parseFors(shaderSource, templateId)) + std::vector linkedShaderNames; + if (!createSourceFromTemplate(shaderSource, linkedShaderNames, templateId, defines)) // We just broke the shader and there's no way to force existing objects back to fixed-function mode as we would when creating the shader. // If we put a nullptr in the shader map, we just lose the ability to put a working one in later. continue; shader->setShaderSource(shaderSource); + + getLinkedShaders(shader, linkedShaderNames, defines); } } @@ -397,4 +478,35 @@ namespace Shader program->releaseGLObjects(state); } + bool ShaderManager::createSourceFromTemplate(std::string& source, std::vector& linkedShaderTemplateNames, const std::string& templateName, const ShaderManager::DefineMap& defines) + { + if (!parseDefines(source, defines, mGlobalDefines, templateName)) + return false; + if (!parseDirectives(source, linkedShaderTemplateNames, defines, mGlobalDefines, templateName)) + return false; + return true; + } + + void ShaderManager::getLinkedShaders(osg::ref_ptr shader, const std::vector& linkedShaderNames, const DefineMap& defines) + { + mLinkedShaders.erase(shader); + if (linkedShaderNames.empty()) + return; + + for (auto& linkedShaderName : linkedShaderNames) + { + auto linkedShader = getShader(linkedShaderName, defines, shader->getType()); + if (linkedShader) + mLinkedShaders[shader].emplace_back(linkedShader); + } + } + + void ShaderManager::addLinkedShaders(osg::ref_ptr shader, osg::ref_ptr program) + { + auto linkedIt = mLinkedShaders.find(shader); + if (linkedIt != mLinkedShaders.end()) + for (const auto& linkedShader : linkedIt->second) + program->addShader(linkedShader); + } + } diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 613f33b168..598dde85bb 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -51,7 +52,12 @@ namespace Shader void releaseGLObjects(osg::State* state); + bool createSourceFromTemplate(std::string& source, std::vector& linkedShaderTemplateNames, const std::string& templateName, const ShaderManager::DefineMap& defines); + private: + void getLinkedShaders(osg::ref_ptr shader, const std::vector& linkedShaderNames, const DefineMap& defines); + void addLinkedShaders(osg::ref_ptr shader, osg::ref_ptr program); + std::string mPath; DefineMap mGlobalDefines; @@ -67,15 +73,23 @@ namespace Shader typedef std::map, osg::ref_ptr >, osg::ref_ptr > ProgramMap; ProgramMap mPrograms; + typedef std::vector > ShaderList; + typedef std::map, ShaderList> LinkedShadersMap; + LinkedShadersMap mLinkedShaders; + std::mutex mMutex; osg::ref_ptr mProgramTemplate; }; - bool parseFors(std::string& source, const std::string& templateName); + bool parseForeachDirective(std::string& source, const std::string& templateName, size_t foundPos); + bool parseLinkDirective(std::string& source, std::string& linkTarget, const std::string& templateName, size_t foundPos); bool parseDefines(std::string& source, const ShaderManager::DefineMap& defines, const ShaderManager::DefineMap& globalDefines, const std::string& templateName); + + bool parseDirectives(std::string& source, std::vector& linkedShaderTemplateNames, const ShaderManager::DefineMap& defines, + const ShaderManager::DefineMap& globalDefines, const std::string& templateName); } #endif diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index 73929486cd..c873ada12f 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -16,6 +16,10 @@ set(SHADER_FILES depth.glsl objects_vertex.glsl objects_fragment.glsl + openmw_fragment.glsl + openmw_fragment.h.glsl + openmw_vertex.glsl + openmw_vertex.h.glsl terrain_vertex.glsl terrain_fragment.glsl lighting.glsl diff --git a/files/shaders/debug_vertex.glsl b/files/shaders/debug_vertex.glsl index a26d2573cf..094e866f9e 100644 --- a/files/shaders/debug_vertex.glsl +++ b/files/shaders/debug_vertex.glsl @@ -1,12 +1,12 @@ #version 120 -uniform mat4 projectionMatrix; +#include "openmw_vertex.glsl" centroid varying vec4 passColor; void main() { - gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); + gl_Position = mw_modelToClip(gl_Vertex); passColor = gl_Color; } diff --git a/files/shaders/groundcover_vertex.glsl b/files/shaders/groundcover_vertex.glsl index c8db4be000..2914552139 100644 --- a/files/shaders/groundcover_vertex.glsl +++ b/files/shaders/groundcover_vertex.glsl @@ -1,5 +1,7 @@ #version 120 +#include "openmw_vertex.h.glsl" + #if @useUBO #extension GL_ARB_uniform_buffer_object : require #endif @@ -46,7 +48,6 @@ uniform mat4 osg_ViewMatrixInverse; uniform mat4 osg_ViewMatrix; uniform float windSpeed; uniform vec3 playerPos; -uniform mat4 projectionMatrix; #if @groundcoverStompMode == 0 #else @@ -143,7 +144,7 @@ void main(void) if (length(gl_ModelViewMatrix * vec4(position, 1.0)) > @groundcoverFadeEnd) gl_Position = vec4(0.0, 0.0, 0.0, 1.0); else - gl_Position = projectionMatrix * viewPos; + gl_Position = mw_viewToClip(mw_viewStereoAdjust(viewPos)); linearDepth = getLinearDepth(gl_Position.z, viewPos.z); diff --git a/files/shaders/nv_default_vertex.glsl b/files/shaders/nv_default_vertex.glsl index 34d5415250..d27b9b2cbd 100644 --- a/files/shaders/nv_default_vertex.glsl +++ b/files/shaders/nv_default_vertex.glsl @@ -1,5 +1,7 @@ #version 120 +#include "openmw_vertex.h.glsl" + #if @useUBO #extension GL_ARB_uniform_buffer_object : require #endif @@ -8,8 +10,6 @@ #extension GL_EXT_gpu_shader4: require #endif -uniform mat4 projectionMatrix; - #if @diffuseMap varying vec2 diffuseMapUV; #endif @@ -38,9 +38,9 @@ varying vec3 passNormal; void main(void) { - gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); + gl_Position = mw_modelToClip(gl_Vertex); - vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); + vec4 viewPos = mw_modelToView(gl_Vertex); gl_ClipVertex = viewPos; euclideanDepth = length(viewPos.xyz); linearDepth = getLinearDepth(gl_Position.z, viewPos.z); diff --git a/files/shaders/nv_nolighting_vertex.glsl b/files/shaders/nv_nolighting_vertex.glsl index 617f0489a4..7b1f6961b4 100644 --- a/files/shaders/nv_nolighting_vertex.glsl +++ b/files/shaders/nv_nolighting_vertex.glsl @@ -1,6 +1,6 @@ #version 120 -uniform mat4 projectionMatrix; +#include "openmw_vertex.h.glsl" #if @diffuseMap varying vec2 diffuseMapUV; @@ -23,9 +23,9 @@ varying float passFalloff; void main(void) { - gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); + gl_Position = mw_modelToClip(gl_Vertex); - vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); + vec4 viewPos = mw_modelToView(gl_Vertex); gl_ClipVertex = viewPos; #if @radialFog euclideanDepth = length(viewPos.xyz); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 77c7fef391..df60d8ea49 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -1,5 +1,7 @@ #version 120 +#include "openmw_vertex.h.glsl" + #if @useUBO #extension GL_ARB_uniform_buffer_object : require #endif @@ -8,8 +10,6 @@ #extension GL_EXT_gpu_shader4: require #endif -uniform mat4 projectionMatrix; - #if @diffuseMap varying vec2 diffuseMapUV; #endif @@ -72,9 +72,9 @@ varying vec3 passNormal; void main(void) { - gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); + gl_Position = mw_modelToClip(gl_Vertex); - vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); + vec4 viewPos = mw_modelToView(gl_Vertex); gl_ClipVertex = viewPos; euclideanDepth = length(viewPos.xyz); diff --git a/files/shaders/openmw_fragment.glsl b/files/shaders/openmw_fragment.glsl new file mode 100644 index 0000000000..9de9e7afff --- /dev/null +++ b/files/shaders/openmw_fragment.glsl @@ -0,0 +1,26 @@ +#version 120 + +#include "openmw_fragment.h.glsl" + +uniform sampler2D reflectionMap; + +vec4 mw_sampleReflectionMap(vec2 uv) +{ + return texture2D(reflectionMap, uv); +} + +#if @refraction_enabled +uniform sampler2D refractionMap; +uniform sampler2D refractionDepthMap; + +vec4 mw_sampleRefractionMap(vec2 uv) +{ + return texture2D(refractionMap, uv); +} + +float mw_sampleRefractionDepthMap(vec2 uv) +{ + return texture2D(refractionDepthMap, uv).x; +} + +#endif \ No newline at end of file diff --git a/files/shaders/openmw_fragment.h.glsl b/files/shaders/openmw_fragment.h.glsl new file mode 100644 index 0000000000..c5bcf21c9d --- /dev/null +++ b/files/shaders/openmw_fragment.h.glsl @@ -0,0 +1,8 @@ +@link "openmw_fragment.glsl" + +vec4 mw_sampleReflectionMap(vec2 uv); + +#if @refraction_enabled +vec4 mw_sampleRefractionMap(vec2 uv); +float mw_sampleRefractionDepthMap(vec2 uv); +#endif \ No newline at end of file diff --git a/files/shaders/openmw_vertex.glsl b/files/shaders/openmw_vertex.glsl new file mode 100644 index 0000000000..cc14f3a0e3 --- /dev/null +++ b/files/shaders/openmw_vertex.glsl @@ -0,0 +1,35 @@ +#version 120 + +#include "openmw_vertex.h.glsl" + +uniform mat4 projectionMatrix; + +vec4 mw_modelToClip(vec4 pos) +{ + return projectionMatrix * mw_modelToView(pos); +} + +vec4 mw_modelToView(vec4 pos) +{ + return gl_ModelViewMatrix * pos; +} + +vec4 mw_viewToClip(vec4 pos) +{ + return projectionMatrix * pos; +} + +vec4 mw_viewStereoAdjust(vec4 pos) +{ + return pos; +} + +mat4 mw_viewMatrix() +{ + return gl_ModelViewMatrix; +} + +mat4 mw_projectionMatrix() +{ + return projectionMatrix; +} diff --git a/files/shaders/openmw_vertex.h.glsl b/files/shaders/openmw_vertex.h.glsl new file mode 100644 index 0000000000..00feb9310e --- /dev/null +++ b/files/shaders/openmw_vertex.h.glsl @@ -0,0 +1,8 @@ +@link "openmw_vertex.glsl" + +vec4 mw_modelToClip(vec4 pos); +vec4 mw_modelToView(vec4 pos); +vec4 mw_viewToClip(vec4 pos); +vec4 mw_viewStereoAdjust(vec4 pos); +mat4 mw_viewMatrix(); +mat4 mw_projectionMatrix(); \ No newline at end of file diff --git a/files/shaders/sky_vertex.glsl b/files/shaders/sky_vertex.glsl index 9c676140ac..8ff9c0f156 100644 --- a/files/shaders/sky_vertex.glsl +++ b/files/shaders/sky_vertex.glsl @@ -1,8 +1,9 @@ #version 120 +#include "openmw_vertex.h.glsl" + #include "skypasses.glsl" -uniform mat4 projectionMatrix; uniform int pass; varying vec4 passColor; @@ -10,7 +11,7 @@ varying vec2 diffuseMapUV; void main() { - gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); + gl_Position = mw_modelToClip(gl_Vertex); passColor = gl_Color; if (pass == PASS_CLOUDS) diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index b46b299e2b..7f248d5a6b 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -1,5 +1,7 @@ #version 120 +#include "openmw_vertex.h.glsl" + #if @useUBO #extension GL_ARB_uniform_buffer_object : require #endif @@ -8,8 +10,6 @@ #extension GL_EXT_gpu_shader4: require #endif -uniform mat4 projectionMatrix; - varying vec2 uv; varying float euclideanDepth; varying float linearDepth; @@ -31,9 +31,9 @@ varying vec3 passNormal; void main(void) { - gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); + gl_Position = mw_modelToClip(gl_Vertex); - vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); + vec4 viewPos = mw_modelToView(gl_Vertex); gl_ClipVertex = viewPos; euclideanDepth = length(viewPos.xyz); linearDepth = getLinearDepth(gl_Position.z, viewPos.z); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index eaf52c1189..1090531f23 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,5 +1,7 @@ #version 120 +#include "openmw_fragment.h.glsl" + #if @useUBO #extension GL_ARB_uniform_buffer_object : require #endif @@ -207,12 +209,6 @@ varying float linearDepth; uniform sampler2D normalMap; -uniform sampler2D reflectionMap; -#if REFRACTION -uniform sampler2D refractionMap; -uniform sampler2D refractionDepthMap; -#endif - uniform float osg_SimulationTime; uniform float near; @@ -299,14 +295,14 @@ void main(void) vec2 screenCoordsOffset = normal.xy * REFL_BUMP; #if REFRACTION - float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x) * radialise; - float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-screenCoordsOffset).x) * radialise; + float depthSample = linearizeDepth(mw_sampleRefractionDepthMap(screenCoords)) * radialise; + float depthSampleDistorted = linearizeDepth(mw_sampleRefractionDepthMap(screenCoords-screenCoordsOffset)) * radialise; float surfaceDepth = linearizeDepth(gl_FragCoord.z) * radialise; float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum screenCoordsOffset *= clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #endif // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb; + vec3 reflection = mw_sampleReflectionMap(screenCoords + screenCoordsOffset).rgb; // specular float specular = pow(max(dot(reflect(vVec, normal), lVec), 0.0),SPEC_HARDNESS) * shadow; @@ -324,7 +320,7 @@ void main(void) rainSpecular *= clamp(fresnel*6.0 + specular * sunSpec.w, 0.0, 1.0); // refraction - vec3 refraction = texture2D(refractionMap, screenCoords - screenCoordsOffset).rgb; + vec3 refraction = mw_sampleRefractionMap(screenCoords - screenCoordsOffset).rgb; vec3 rawRefraction = refraction; // brighten up the refraction underwater diff --git a/files/shaders/water_vertex.glsl b/files/shaders/water_vertex.glsl index 3a6c352ac8..b09d3b54ae 100644 --- a/files/shaders/water_vertex.glsl +++ b/files/shaders/water_vertex.glsl @@ -1,6 +1,6 @@ #version 120 -uniform mat4 projectionMatrix; +#include "openmw_vertex.h.glsl" varying vec4 position; varying float linearDepth; @@ -10,11 +10,11 @@ varying float linearDepth; void main(void) { - gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); + gl_Position = mw_modelToClip(gl_Vertex); position = gl_Vertex; - vec4 viewPos = gl_ModelViewMatrix * gl_Vertex; + vec4 viewPos = mw_modelToView(gl_Vertex); linearDepth = getLinearDepth(gl_Position.z, viewPos.z); setupShadowCoords(viewPos, normalize((gl_NormalMatrix * gl_Normal).xyz));