diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b0fe98565..1370631bc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -785,6 +785,8 @@ namespace MWRender } else if (it->first == "General" && (it->second == "texture filtering" || it->second == "anisotropy")) updateTextureFiltering(); + else if (it->first == "Water") + mWater->processChangedSettings(changed); } } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 121b07654..4b936ba30 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -204,7 +204,7 @@ public: } }; -osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file) +osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file, const std::map& defineMap = std::map()) { osg::ref_ptr shader (new osg::Shader(type)); @@ -213,7 +213,17 @@ osg::ref_ptr readShader (osg::Shader::Type type, const std::string& inStream.open(boost::filesystem::path(file)); std::stringstream strstream; strstream << inStream.rdbuf(); - shader->setShaderSource(strstream.str()); + + std::string shaderSource = strstream.str(); + + for (std::map::const_iterator it = defineMap.begin(); it != defineMap.end(); ++it) + { + size_t pos = shaderSource.find(it->first); + if (pos != std::string::npos) + shaderSource.replace(pos, it->first.length(), it->second); + } + + shader->setShaderSource(shaderSource); return shader; } @@ -429,7 +439,44 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); + updateWaterMaterial(); +} + +void Water::updateWaterMaterial() +{ // TODO: add ingame setting for texture quality + if (mReflection) + { + mParent->removeChild(mReflection); + mReflection = NULL; + } + if (mRefraction) + { + mParent->removeChild(mRefraction); + mRefraction = NULL; + } + + if (Settings::Manager::getBool("shader", "Water")) + { + mReflection = new Reflection; + mReflection->setWaterLevel(mTop); + mReflection->setScene(mSceneRoot); + mParent->addChild(mReflection); + + if (Settings::Manager::getBool("refraction", "Water")) + { + mRefraction = new Refraction; + mRefraction->setWaterLevel(mTop); + mRefraction->setScene(mSceneRoot); + mParent->addChild(mRefraction); + } + + createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); + } + else + createSimpleWaterStateSet(mWaterGeode); + + updateVisible(); } void Water::createSimpleWaterStateSet(osg::Node* node) @@ -462,20 +509,19 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - node->addUpdateCallback(controller); + node->setUpdateCallback(controller); node->setStateSet(stateset); stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); } void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction) { - osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl")); + // use a define map to conditionally compile the shader + std::map defineMap; + defineMap.insert(std::make_pair(std::string("@refraction_enabled"), std::string(refraction ? "1" : "0"))); - osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl")); - - osg::ref_ptr program (new osg::Program); - program->addShader(vertexShader); - program->addShader(fragmentShader); + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl", defineMap)); + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl", defineMap)); osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); @@ -486,11 +532,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R normalMap->getImage()->flipVertical(); osg::ref_ptr shaderStateset = new osg::StateSet; - shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); shaderStateset->addUniform(new osg::Uniform("normalMap", 0)); shaderStateset->addUniform(new osg::Uniform("reflectionMap", 1)); - shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); - shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); shaderStateset->setTextureAttributeAndModes(0, normalMap, osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(1, reflection->getReflectionTexture(), osg::StateAttribute::ON); @@ -498,6 +541,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R { shaderStateset->setTextureAttributeAndModes(2, refraction->getRefractionTexture(), osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON); + shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); + shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); } else @@ -513,7 +558,18 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + osg::ref_ptr program (new osg::Program); + program->addShader(vertexShader); + program->addShader(fragmentShader); + shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); + node->setStateSet(shaderStateset); + node->setUpdateCallback(NULL); +} + +void Water::processChangedSettings(const Settings::CategorySettingVector& settings) +{ + updateWaterMaterial(); } Water::~Water() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 857f7fbb0..f77afbfee 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../mwworld/cellstore.hpp" namespace osg @@ -67,6 +69,8 @@ namespace MWRender /// @param refraction the refraction camera (optional) void createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction); + void updateWaterMaterial(); + public: Water(osg::Group* parent, osg::Group* sceneRoot, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, @@ -92,6 +96,7 @@ namespace MWRender void update(float dt); + void processChangedSettings(const Settings::CategorySettingVector& settings); }; } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 6f7b173bf..c04233fcf 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -1,8 +1,8 @@ #version 120 -// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) +#define REFRACTION @refraction_enabled -#define REFRACTION 1 +// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --