Apply clang-format to code base

This commit is contained in:
clang-format-bot 2022-09-22 21:26:05 +03:00 committed by ζeh Matt
parent f37d0be806
commit ddb0522bbf
No known key found for this signature in database
GPG key ID: 18CE582C71A225B0
2199 changed files with 118692 additions and 114392 deletions

View file

@ -6,15 +6,15 @@
namespace Shader
{
std::array<osg::ref_ptr<RemovedAlphaFunc>, GL_ALWAYS - GL_NEVER + 1> RemovedAlphaFunc::sInstances{
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};
std::array<osg::ref_ptr<RemovedAlphaFunc>, GL_ALWAYS - GL_NEVER + 1> RemovedAlphaFunc::sInstances{ nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
osg::ref_ptr<RemovedAlphaFunc> RemovedAlphaFunc::getInstance(GLenum func)
{
assert(func >= GL_NEVER && func <= GL_ALWAYS);
if (!sInstances[func - GL_NEVER])
sInstances[func - GL_NEVER] = new RemovedAlphaFunc(static_cast<osg::AlphaFunc::ComparisonFunction>(func), 1.0);
sInstances[func - GL_NEVER]
= new RemovedAlphaFunc(static_cast<osg::AlphaFunc::ComparisonFunction>(func), 1.0);
return sInstances[func - GL_NEVER];
}
}

View file

@ -17,15 +17,18 @@ namespace Shader
RemovedAlphaFunc()
: osg::AlphaFunc()
{}
{
}
RemovedAlphaFunc(ComparisonFunction func, float ref)
: osg::AlphaFunc(func, ref)
{}
{
}
RemovedAlphaFunc(const RemovedAlphaFunc& raf, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY)
: osg::AlphaFunc(raf, copyop)
{}
{
}
META_StateAttribute(Shader, RemovedAlphaFunc, ALPHAFUNC);
@ -37,4 +40,4 @@ namespace Shader
static std::array<osg::ref_ptr<RemovedAlphaFunc>, GL_ALWAYS - GL_NEVER + 1> sInstances;
};
}
#endif //OPENMW_COMPONENTS_REMOVEDALPHAFUNC_H
#endif // OPENMW_COMPONENTS_REMOVEDALPHAFUNC_H

View file

@ -1,20 +1,20 @@
#include "shadermanager.hpp"
#include <fstream>
#include <algorithm>
#include <sstream>
#include <regex>
#include <filesystem>
#include <set>
#include <unordered_map>
#include <chrono>
#include <osg/Program>
#include <osgViewer/Viewer>
#include <components/debug/debuglog.hpp>
#include <components/files/conversion.hpp>
#include <components/misc/strings/algorithm.hpp>
#include <components/misc/strings/format.hpp>
#include <components/settings/settings.hpp>
#include <components/files/conversion.hpp>
#include <filesystem>
#include <fstream>
#include <osg/Program>
#include <osgViewer/Viewer>
#include <regex>
#include <set>
#include <sstream>
#include <unordered_map>
namespace Shader
{
@ -26,14 +26,14 @@ namespace Shader
ShaderManager::~ShaderManager() = default;
void ShaderManager::setShaderPath(const std::filesystem::path &path)
void ShaderManager::setShaderPath(const std::filesystem::path& path)
{
mPath = path;
}
bool addLineDirectivesAfterConditionalBlocks(std::string& source)
{
for (size_t position = 0; position < source.length(); )
for (size_t position = 0; position < source.length();)
{
size_t foundPos = source.find("#endif", position);
foundPos = std::min(foundPos, source.find("#elif", position));
@ -74,12 +74,15 @@ namespace Shader
// Recursively replaces include statements with the actual source of the included files.
// Adjusts #line statements accordingly and detects cyclic includes.
// cycleIncludeChecker is the set of files that include this file directly or indirectly, and is intentionally not a reference to allow automatic cleanup.
static bool parseIncludes(const std::filesystem::path& shaderPath, std::string& source, const std::string& fileName, int& fileNumber, std::set<std::filesystem::path> cycleIncludeChecker,std::set<std::filesystem::path>& includedFiles)
// cycleIncludeChecker is the set of files that include this file directly or indirectly, and is intentionally not a
// reference to allow automatic cleanup.
static bool parseIncludes(const std::filesystem::path& shaderPath, std::string& source, const std::string& fileName,
int& fileNumber, std::set<std::filesystem::path> cycleIncludeChecker,
std::set<std::filesystem::path>& includedFiles)
{
includedFiles.insert(shaderPath / fileName);
// An include is cyclic if it is being included by itself
if (cycleIncludeChecker.insert(shaderPath/fileName).second == false)
if (cycleIncludeChecker.insert(shaderPath / fileName).second == false)
{
Log(Debug::Error) << "Shader " << fileName << " error: Detected cyclic #includes";
return false;
@ -136,14 +139,16 @@ namespace Shader
buffer << includeFstream.rdbuf();
std::string stringRepresentation = buffer.str();
if (!addLineDirectivesAfterConditionalBlocks(stringRepresentation)
|| !parseIncludes(shaderPath, stringRepresentation, includeFilename, fileNumber, cycleIncludeChecker, includedFiles))
|| !parseIncludes(
shaderPath, stringRepresentation, includeFilename, fileNumber, cycleIncludeChecker, includedFiles))
{
Log(Debug::Error) << "In file included from " << fileName << "." << lineNumber;
return false;
}
std::stringstream toInsert;
toInsert << "#line 0 " << includedFileNumber << "\n" << stringRepresentation << "\n#line " << lineNumber << " 0\n";
toInsert << "#line 0 " << includedFileNumber << "\n"
<< stringRepresentation << "\n#line " << lineNumber << " 0\n";
source.replace(foundPos, (end - foundPos + 1), toInsert.str());
}
@ -201,7 +206,8 @@ namespace Shader
lineNumber += std::count(source.begin() + lineDirectivePosition, source.begin() + overallEnd, '\n');
std::string replacement;
for (std::vector<std::string>::const_iterator element = listElements.cbegin(); element != listElements.cend(); element++)
for (std::vector<std::string>::const_iterator element = listElements.cbegin(); element != listElements.cend();
element++)
{
std::string contentInstance = content;
size_t foundIterator;
@ -214,18 +220,18 @@ namespace Shader
return true;
}
bool parseLinkDirective(std::string& source, std::string& linkTarget, const std::string& templateName, size_t foundPos)
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::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;
@ -252,7 +258,7 @@ namespace Shader
bool condition = !(linkConditionExpression.empty() || linkConditionExpression == "0");
if (linkMatch[3].str() == "!")
condition = !condition;
if (!condition)
linkTarget.clear();
}
@ -261,7 +267,9 @@ namespace Shader
return true;
}
bool parseDirectives(std::string& source, std::vector<std::string>& linkedShaderTemplateNames, const ShaderManager::DefineMap& defines, const ShaderManager::DefineMap& globalDefines, const std::string& templateName)
bool parseDirectives(std::string& source, std::vector<std::string>& linkedShaderTemplateNames,
const ShaderManager::DefineMap& defines, const ShaderManager::DefineMap& globalDefines,
const std::string& templateName)
{
const char escapeCharacter = '$';
size_t foundPos = 0;
@ -312,7 +320,7 @@ namespace Shader
Log(Debug::Error) << "Shader " << templateName << " error: Unexpected EOF";
return false;
}
std::string define = source.substr(foundPos+1, endPos - (foundPos+1));
std::string define = source.substr(foundPos + 1, endPos - (foundPos + 1));
ShaderManager::DefineMap::const_iterator defineFound = defines.find(define);
ShaderManager::DefineMap::const_iterator globalDefineFound = globalDefines.find(define);
if (define == "foreach")
@ -380,7 +388,7 @@ namespace Shader
mLastAutoRecompileTime = std::filesystem::file_time_type::clock::now();
}
void addShaderFiles(const std::string& templateName,const ShaderManager::DefineMap& defines )
void addShaderFiles(const std::string& templateName, const ShaderManager::DefineMap& defines)
{
const std::set<std::filesystem::path>& shaderFiles = templateIncludedFiles[templateName];
for (const std::filesystem::path& file : shaderFiles)
@ -389,9 +397,10 @@ namespace Shader
}
}
void update(ShaderManager& Manager,osgViewer::Viewer& viewer)
void update(ShaderManager& Manager, osgViewer::Viewer& viewer)
{
auto timeSinceLastCheckMillis = std::chrono::duration_cast<std::chrono::milliseconds>(std::filesystem::file_time_type::clock::now() - mLastAutoRecompileTime);
auto timeSinceLastCheckMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
std::filesystem::file_time_type::clock::now() - mLastAutoRecompileTime);
if ((mHotReloadEnabled && timeSinceLastCheckMillis.count() > 200) || mTriggerReload == true)
{
reloadTouchedShaders(Manager, viewer);
@ -402,7 +411,7 @@ namespace Shader
void reloadTouchedShaders(ShaderManager& Manager, osgViewer::Viewer& viewer)
{
bool threadsRunningToStop = false;
for (auto& [pathShaderToTest, shaderKeys]: mShaderFiles)
for (auto& [pathShaderToTest, shaderKeys] : mShaderFiles)
{
std::filesystem::file_time_type write_time = std::filesystem::last_write_time(pathShaderToTest);
@ -415,11 +424,13 @@ namespace Shader
viewer.stopThreading();
}
for (const auto& [templateName, shaderDefines]: shaderKeys)
for (const auto& [templateName, shaderDefines] : shaderKeys)
{
ShaderManager::ShaderMap::iterator shaderIt = Manager.mShaders.find(std::make_pair(templateName, shaderDefines));
ShaderManager::ShaderMap::iterator shaderIt
= Manager.mShaders.find(std::make_pair(templateName, shaderDefines));
ShaderManager::TemplateMap::iterator templateIt = Manager.mShaderTemplates.find(templateName); //Can't be Null, if we're here it means the template was added
ShaderManager::TemplateMap::iterator templateIt = Manager.mShaderTemplates.find(
templateName); // Can't be Null, if we're here it means the template was added
std::string& shaderSource = templateIt->second;
std::set<std::filesystem::path> insertedPaths;
std::filesystem::path path = (std::filesystem::path(Manager.mPath) / templateName);
@ -436,19 +447,20 @@ namespace Shader
int fileNumber = 1;
std::string source = buffer.str();
if (!addLineDirectivesAfterConditionalBlocks(source)
|| !parseIncludes(std::filesystem::path(Manager.mPath), source, templateName, fileNumber, {}, insertedPaths))
|| !parseIncludes(std::filesystem::path(Manager.mPath), source, templateName, fileNumber,
{}, insertedPaths))
{
break;
}
shaderSource = source;
std::vector<std::string> linkedShaderNames;
if (!Manager.createSourceFromTemplate(shaderSource, linkedShaderNames, templateName, shaderDefines))
if (!Manager.createSourceFromTemplate(
shaderSource, linkedShaderNames, templateName, shaderDefines))
{
break;
}
shaderIt->second->setShaderSource(shaderSource);
}
}
}
@ -458,7 +470,8 @@ namespace Shader
}
};
osg::ref_ptr<osg::Shader> ShaderManager::getShader(const std::string &templateName, const ShaderManager::DefineMap &defines, osg::Shader::Type shaderType)
osg::ref_ptr<osg::Shader> ShaderManager::getShader(
const std::string& templateName, const ShaderManager::DefineMap& defines, osg::Shader::Type shaderType)
{
std::unique_lock<std::mutex> lock(mMutex);
@ -501,7 +514,7 @@ namespace Shader
return nullptr;
}
osg::ref_ptr<osg::Shader> shader (new osg::Shader(shaderType));
osg::ref_ptr<osg::Shader> shader(new osg::Shader(shaderType));
shader->setShaderSource(shaderSource);
// Assign a unique prefix to allow the SharedStateManager to compare shaders efficiently.
// Append shader source filename for debugging.
@ -519,14 +532,17 @@ namespace Shader
return shaderIt->second;
}
osg::ref_ptr<osg::Program> ShaderManager::getProgram(osg::ref_ptr<osg::Shader> vertexShader, osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate)
osg::ref_ptr<osg::Program> ShaderManager::getProgram(osg::ref_ptr<osg::Shader> vertexShader,
osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate)
{
std::lock_guard<std::mutex> lock(mMutex);
ProgramMap::iterator found = mPrograms.find(std::make_pair(vertexShader, fragmentShader));
if (found == mPrograms.end())
{
if (!programTemplate) programTemplate = mProgramTemplate;
osg::ref_ptr<osg::Program> program = programTemplate ? cloneProgram(programTemplate) : osg::ref_ptr<osg::Program>(new osg::Program);
if (!programTemplate)
programTemplate = mProgramTemplate;
osg::ref_ptr<osg::Program> program
= programTemplate ? cloneProgram(programTemplate) : osg::ref_ptr<osg::Program>(new osg::Program);
program->addShader(vertexShader);
program->addShader(fragmentShader);
addLinkedShaders(vertexShader, program);
@ -550,21 +566,23 @@ namespace Shader
return DefineMap(mGlobalDefines);
}
void ShaderManager::setGlobalDefines(DefineMap & globalDefines)
void ShaderManager::setGlobalDefines(DefineMap& globalDefines)
{
mGlobalDefines = globalDefines;
for (const auto& [key, shader]: mShaders)
for (const auto& [key, shader] : mShaders)
{
std::string templateId = key.first;
ShaderManager::DefineMap defines = key.second;
if (shader == nullptr)
// 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.
// 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];
std::vector<std::string> 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.
// 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);
@ -572,7 +590,7 @@ namespace Shader
}
}
void ShaderManager::releaseGLObjects(osg::State *state)
void ShaderManager::releaseGLObjects(osg::State* state)
{
std::lock_guard<std::mutex> lock(mMutex);
for (const auto& [_, shader] : mShaders)
@ -584,7 +602,9 @@ namespace Shader
program->releaseGLObjects(state);
}
bool ShaderManager::createSourceFromTemplate(std::string& source, std::vector<std::string>& linkedShaderTemplateNames, const std::string& templateName, const ShaderManager::DefineMap& defines)
bool ShaderManager::createSourceFromTemplate(std::string& source,
std::vector<std::string>& linkedShaderTemplateNames, const std::string& templateName,
const ShaderManager::DefineMap& defines)
{
if (!parseDefines(source, defines, mGlobalDefines, templateName))
return false;
@ -593,7 +613,8 @@ namespace Shader
return true;
}
void ShaderManager::getLinkedShaders(osg::ref_ptr<osg::Shader> shader, const std::vector<std::string>& linkedShaderNames, const DefineMap& defines)
void ShaderManager::getLinkedShaders(
osg::ref_ptr<osg::Shader> shader, const std::vector<std::string>& linkedShaderNames, const DefineMap& defines)
{
mLinkedShaders.erase(shader);
if (linkedShaderNames.empty())
@ -624,9 +645,9 @@ namespace Shader
{
// Texture units from `8 - numberOfShadowMaps` to `8` are used for shadows, so we skip them here.
// TODO: Maybe instead of fixed texture units use `reserveGlobalTextureUnits` for shadows as well.
static const int numberOfShadowMaps = Settings::Manager::getBool("enable shadows", "Shadows") ?
std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8) :
0;
static const int numberOfShadowMaps = Settings::Manager::getBool("enable shadows", "Shadows")
? std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8)
: 0;
if (getAvailableTextureUnits() >= 8 && getAvailableTextureUnits() - 1 < 8)
mReservedTextureUnits = mMaxTextureUnits - (8 - numberOfShadowMaps);
}

View file

@ -1,20 +1,21 @@
#ifndef OPENMW_COMPONENTS_SHADERMANAGER_H
#define OPENMW_COMPONENTS_SHADERMANAGER_H
#include <string>
#include <map>
#include <mutex>
#include <vector>
#include <array>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include <osg/ref_ptr>
#include <osg/Shader>
#include <osg/Program>
#include <filesystem>
#include <osg/Program>
#include <osg/Shader>
namespace osgViewer {
namespace osgViewer
{
class Viewer;
}
@ -30,7 +31,7 @@ namespace Shader
ShaderManager();
~ShaderManager();
void setShaderPath(const std::filesystem::path &path);
void setShaderPath(const std::filesystem::path& path);
typedef std::map<std::string, std::string> DefineMap;
@ -40,9 +41,11 @@ namespace Shader
/// @param shaderType The type of shader (usually vertex or fragment shader).
/// @note May return nullptr on failure.
/// @note Thread safe.
osg::ref_ptr<osg::Shader> getShader(const std::string& templateName, const DefineMap& defines, osg::Shader::Type shaderType);
osg::ref_ptr<osg::Shader> getShader(
const std::string& templateName, const DefineMap& defines, osg::Shader::Type shaderType);
osg::ref_ptr<osg::Program> getProgram(osg::ref_ptr<osg::Shader> vertexShader, osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate=nullptr);
osg::ref_ptr<osg::Program> getProgram(osg::ref_ptr<osg::Shader> vertexShader,
osg::ref_ptr<osg::Shader> fragmentShader, const osg::Program* programTemplate = nullptr);
const osg::Program* getProgramTemplate() const { return mProgramTemplate; }
void setProgramTemplate(const osg::Program* program) { mProgramTemplate = program; }
@ -55,12 +58,15 @@ namespace Shader
/// Set the DefineMap used to construct all shaders
/// @param defines The DefineMap to use
/// @note This will change the source code for any shaders already created, potentially causing problems if they're being used to render a frame. It is recommended that any associated Viewers have their threading stopped while this function is running if any shaders are in use.
void setGlobalDefines(DefineMap & globalDefines);
/// @note This will change the source code for any shaders already created, potentially causing problems if
/// they're being used to render a frame. It is recommended that any associated Viewers have their threading
/// stopped while this function is running if any shaders are in use.
void setGlobalDefines(DefineMap& globalDefines);
void releaseGLObjects(osg::State* state);
bool createSourceFromTemplate(std::string& source, std::vector<std::string>& linkedShaderTemplateNames, const std::string& templateName, const ShaderManager::DefineMap& defines);
bool createSourceFromTemplate(std::string& source, std::vector<std::string>& linkedShaderTemplateNames,
const std::string& templateName, const ShaderManager::DefineMap& defines);
void setMaxTextureUnits(int maxTextureUnits) { mMaxTextureUnits = maxTextureUnits; }
int getMaxTextureUnits() const { return mMaxTextureUnits; }
@ -77,8 +83,10 @@ namespace Shader
void update(osgViewer::Viewer& viewer);
void setHotReloadEnabled(bool value);
void triggerShaderReload();
private:
void getLinkedShaders(osg::ref_ptr<osg::Shader> shader, const std::vector<std::string>& linkedShaderNames, const DefineMap& defines);
void getLinkedShaders(osg::ref_ptr<osg::Shader> shader, const std::vector<std::string>& linkedShaderNames,
const DefineMap& defines);
void addLinkedShaders(osg::ref_ptr<osg::Shader> shader, osg::ref_ptr<osg::Program> program);
std::filesystem::path mPath;
@ -90,13 +98,14 @@ namespace Shader
TemplateMap mShaderTemplates;
typedef std::pair<std::string, DefineMap> MapKey;
typedef std::map<MapKey, osg::ref_ptr<osg::Shader> > ShaderMap;
typedef std::map<MapKey, osg::ref_ptr<osg::Shader>> ShaderMap;
ShaderMap mShaders;
typedef std::map<std::pair<osg::ref_ptr<osg::Shader>, osg::ref_ptr<osg::Shader> >, osg::ref_ptr<osg::Program> > ProgramMap;
typedef std::map<std::pair<osg::ref_ptr<osg::Shader>, osg::ref_ptr<osg::Shader>>, osg::ref_ptr<osg::Program>>
ProgramMap;
ProgramMap mPrograms;
typedef std::vector<osg::ref_ptr<osg::Shader> > ShaderList;
typedef std::vector<osg::ref_ptr<osg::Shader>> ShaderList;
typedef std::map<osg::ref_ptr<osg::Shader>, ShaderList> LinkedShadersMap;
LinkedShadersMap mLinkedShaders;
@ -107,17 +116,19 @@ namespace Shader
int mMaxTextureUnits = 0;
int mReservedTextureUnits = 0;
std::unique_ptr<HotReloadManager> mHotReloadManager;
std::array<int, 2> mReservedTextureUnitsBySlot = {-1, -1};
std::array<int, 2> mReservedTextureUnitsBySlot = { -1, -1 };
};
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 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<std::string>& linkedShaderTemplateNames, const ShaderManager::DefineMap& defines,
const ShaderManager::DefineMap& globalDefines, const std::string& templateName);
bool parseDirectives(std::string& source, std::vector<std::string>& linkedShaderTemplateNames,
const ShaderManager::DefineMap& defines, const ShaderManager::DefineMap& globalDefines,
const std::string& templateName);
}
#endif

View file

@ -1,33 +1,33 @@
#include "shadervisitor.hpp"
#include <unordered_set>
#include <unordered_map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <osg/AlphaFunc>
#include <osg/BlendFunc>
#include <osg/Geometry>
#include <osg/ColorMaski>
#include <osg/GLExtensions>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/Multisample>
#include <osg/Texture>
#include <osg/ValueObject>
#include <osg/ColorMaski>
#include <osgParticle/ParticleSystem>
#include <osgUtil/TangentSpaceGenerator>
#include <components/debug/debuglog.hpp>
#include <components/misc/strings/algorithm.hpp>
#include <components/misc/osguservalues.hpp>
#include <components/stereo/stereomanager.hpp>
#include <components/misc/strings/algorithm.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/vfs/manager.hpp>
#include <components/sceneutil/riggeometry.hpp>
#include <components/sceneutil/morphgeometry.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/sceneutil/morphgeometry.hpp>
#include <components/sceneutil/riggeometry.hpp>
#include <components/sceneutil/riggeometryosgaextension.hpp>
#include <components/stereo/stereomanager.hpp>
#include <components/vfs/manager.hpp>
#include "removedalphafunc.hpp"
#include "shadermanager.hpp"
@ -35,14 +35,14 @@
namespace Shader
{
/**
* Miniature version of osg::StateSet used to track state added by the shader visitor which should be ignored when
* it's applied a second time, and removed when shaders are removed.
* Actual StateAttributes aren't kept as they're recoverable from the StateSet this is attached to - we just want
* the TypeMemberPair as that uniquely identifies which of those StateAttributes it was we're tracking.
* Not all StateSet features have been added yet - we implement an equivalently-named method to each of the StateSet
* methods called in createProgram, and implement new ones as they're needed.
* When expanding tracking to cover new things, ensure they're accounted for in ensureFFP.
*/
* Miniature version of osg::StateSet used to track state added by the shader visitor which should be ignored when
* it's applied a second time, and removed when shaders are removed.
* Actual StateAttributes aren't kept as they're recoverable from the StateSet this is attached to - we just want
* the TypeMemberPair as that uniquely identifies which of those StateAttributes it was we're tracking.
* Not all StateSet features have been added yet - we implement an equivalently-named method to each of the StateSet
* methods called in createProgram, and implement new ones as they're needed.
* When expanding tracking to cover new things, ensure they're accounted for in ensureFFP.
*/
class AddedState : public osg::Object
{
public:
@ -60,12 +60,12 @@ namespace Shader
void setMode(osg::StateAttribute::GLMode mode) { mModes.emplace(mode); }
void setAttribute(osg::StateAttribute::TypeMemberPair typeMemberPair) { mAttributes.emplace(typeMemberPair); }
void setAttribute(const osg::StateAttribute* attribute)
void setAttribute(const osg::StateAttribute* attribute) { mAttributes.emplace(attribute->getTypeMemberPair()); }
template <typename T>
void setAttribute(osg::ref_ptr<T> attribute)
{
mAttributes.emplace(attribute->getTypeMemberPair());
setAttribute(attribute.get());
}
template<typename T>
void setAttribute(osg::ref_ptr<T> attribute) { setAttribute(attribute.get()); }
void setAttributeAndModes(const osg::StateAttribute* attribute)
{
@ -73,18 +73,27 @@ namespace Shader
InterrogateModesHelper helper(this);
attribute->getModeUsage(helper);
}
template<typename T>
void setAttributeAndModes(osg::ref_ptr<T> attribute) { setAttributeAndModes(attribute.get()); }
template <typename T>
void setAttributeAndModes(osg::ref_ptr<T> attribute)
{
setAttributeAndModes(attribute.get());
}
void setTextureMode(unsigned int unit, osg::StateAttribute::GLMode mode) { mTextureModes[unit].emplace(mode); }
void setTextureAttribute(int unit, osg::StateAttribute::TypeMemberPair typeMemberPair) { mTextureAttributes[unit].emplace(typeMemberPair); }
void setTextureAttribute(int unit, osg::StateAttribute::TypeMemberPair typeMemberPair)
{
mTextureAttributes[unit].emplace(typeMemberPair);
}
void setTextureAttribute(unsigned int unit, const osg::StateAttribute* attribute)
{
mTextureAttributes[unit].emplace(attribute->getTypeMemberPair());
}
template<typename T>
void setTextureAttribute(unsigned int unit, osg::ref_ptr<T> attribute) { setTextureAttribute(unit, attribute.get()); }
template <typename T>
void setTextureAttribute(unsigned int unit, osg::ref_ptr<T> attribute)
{
setTextureAttribute(unit, attribute.get());
}
void setTextureAttributeAndModes(unsigned int unit, const osg::StateAttribute* attribute)
{
@ -92,13 +101,22 @@ namespace Shader
InterrogateModesHelper helper(this, unit);
attribute->getModeUsage(helper);
}
template<typename T>
void setTextureAttributeAndModes(unsigned int unit, osg::ref_ptr<T> attribute) { setTextureAttributeAndModes(unit, attribute.get()); }
template <typename T>
void setTextureAttributeAndModes(unsigned int unit, osg::ref_ptr<T> attribute)
{
setTextureAttributeAndModes(unit, attribute.get());
}
bool hasUniform(const std::string& name) { return mUniforms.count(name); }
bool hasMode(osg::StateAttribute::GLMode mode) { return mModes.count(mode); }
bool hasAttribute(const osg::StateAttribute::TypeMemberPair &typeMemberPair) { return mAttributes.count(typeMemberPair); }
bool hasAttribute(osg::StateAttribute::Type type, unsigned int member) { return hasAttribute(osg::StateAttribute::TypeMemberPair(type, member)); }
bool hasAttribute(const osg::StateAttribute::TypeMemberPair& typeMemberPair)
{
return mAttributes.count(typeMemberPair);
}
bool hasAttribute(osg::StateAttribute::Type type, unsigned int member)
{
return hasAttribute(osg::StateAttribute::TypeMemberPair(type, member));
}
bool hasTextureMode(int unit, osg::StateAttribute::GLMode mode)
{
auto it = mTextureModes.find(unit);
@ -109,11 +127,15 @@ namespace Shader
}
const std::set<osg::StateAttribute::TypeMemberPair>& getAttributes() { return mAttributes; }
const std::unordered_map<unsigned int, std::set<osg::StateAttribute::TypeMemberPair>>& getTextureAttributes() { return mTextureAttributes; }
const std::unordered_map<unsigned int, std::set<osg::StateAttribute::TypeMemberPair>>& getTextureAttributes()
{
return mTextureAttributes;
}
bool empty()
{
return mUniforms.empty() && mModes.empty() && mAttributes.empty() && mTextureModes.empty() && mTextureAttributes.empty();
return mUniforms.empty() && mModes.empty() && mAttributes.empty() && mTextureModes.empty()
&& mTextureAttributes.empty();
}
META_Object(Shader, AddedState)
@ -125,9 +147,13 @@ namespace Shader
InterrogateModesHelper(AddedState* tracker, unsigned int textureUnit = 0)
: mTracker(tracker)
, mTextureUnit(textureUnit)
{}
{
}
void usesMode(osg::StateAttribute::GLMode mode) override { mTracker->setMode(mode); }
void usesTextureMode(osg::StateAttribute::GLMode mode) override { mTracker->setTextureMode(mTextureUnit, mode); }
void usesTextureMode(osg::StateAttribute::GLMode mode) override
{
mTracker->setTextureMode(mTextureUnit, mode);
}
private:
AddedState* mTracker;
@ -162,7 +188,8 @@ namespace Shader
{
}
ShaderVisitor::ShaderVisitor(ShaderManager& shaderManager, Resource::ImageManager& imageManager, const std::string &defaultShaderPrefix)
ShaderVisitor::ShaderVisitor(
ShaderManager& shaderManager, Resource::ImageManager& imageManager, const std::string& defaultShaderPrefix)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mForceShaders(false)
, mAllowedToModifyStateSets(true)
@ -210,7 +237,8 @@ namespace Shader
if (!object.getUserDataContainer())
return object.getOrCreateUserDataContainer();
osg::ref_ptr<osg::UserDataContainer> newUserData = static_cast<osg::UserDataContainer *>(object.getUserDataContainer()->clone(osg::CopyOp::SHALLOW_COPY));
osg::ref_ptr<osg::UserDataContainer> newUserData
= static_cast<osg::UserDataContainer*>(object.getUserDataContainer()->clone(osg::CopyOp::SHALLOW_COPY));
object.setUserDataContainer(newUserData);
return newUserData.get();
}
@ -220,7 +248,7 @@ namespace Shader
if (!stateSet.getUserDataContainer())
return nullptr;
return static_cast<osg::StateSet *>(stateSet.getUserDataContainer()->getUserObject("removedState"));
return static_cast<osg::StateSet*>(stateSet.getUserDataContainer()->getUserObject("removedState"));
}
void updateRemovedState(osg::UserDataContainer& userData, osg::StateSet* removedState)
@ -251,7 +279,8 @@ namespace Shader
addedState->setName("addedState");
}
const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap", "bumpMap", "glossMap" };
const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap",
"specularMap", "decalMap", "bumpMap", "glossMap" };
bool isTextureNameRecognized(std::string_view name)
{
return std::find(std::begin(defaultTextures), std::end(defaultTextures), name) != std::end(defaultTextures);
@ -280,13 +309,13 @@ namespace Shader
const osg::Texture* normalMap = nullptr;
const osg::Texture* specularMap = nullptr;
const osg::Texture* bumpMap = nullptr;
for(unsigned int unit=0;unit<texAttributes.size();++unit)
for (unsigned int unit = 0; unit < texAttributes.size(); ++unit)
{
const osg::StateAttribute *attr = stateset->getTextureAttribute(unit, osg::StateAttribute::TEXTURE);
const osg::StateAttribute* attr = stateset->getTextureAttribute(unit, osg::StateAttribute::TEXTURE);
if (attr)
{
// If textures ever get removed in createProgram, expand this to check we're operating on main texture attribute list
// rather than the removed list
// If textures ever get removed in createProgram, expand this to check we're operating on main
// texture attribute list rather than the removed list
if (addedState && addedState->hasTextureMode(unit, GL_TEXTURE_2D))
continue;
@ -312,7 +341,8 @@ namespace Shader
mRequirements.back().mShaderRequired = true;
if (!writableStateSet)
writableStateSet = getWritableStateSet(node);
// normal maps are by default off since the FFP can't render them, now that we'll use shaders switch to On
// normal maps are by default off since the FFP can't render them, now that we'll use
// shaders switch to On
writableStateSet->setTextureMode(unit, GL_TEXTURE_2D, osg::StateAttribute::ON);
normalMap = texture;
}
@ -371,11 +401,12 @@ namespace Shader
}
// Avoid using the auto-detected normal map if it's already being used as a bump map.
// It's probably not an actual normal map.
bool hasNamesakeBumpMap = image && bumpMap && bumpMap->getImage(0) && image->getFileName() == bumpMap->getImage(0)->getFileName();
bool hasNamesakeBumpMap = image && bumpMap && bumpMap->getImage(0)
&& image->getFileName() == bumpMap->getImage(0)->getFileName();
if (!hasNamesakeBumpMap && image)
{
osg::ref_ptr<osg::Texture2D> normalMapTex (new osg::Texture2D(image));
osg::ref_ptr<osg::Texture2D> normalMapTex(new osg::Texture2D(image));
normalMapTex->setTextureSize(image->s(), image->t());
normalMapTex->setWrap(osg::Texture::WRAP_S, diffuseMap->getWrap(osg::Texture::WRAP_S));
normalMapTex->setWrap(osg::Texture::WRAP_T, diffuseMap->getWrap(osg::Texture::WRAP_T));
@ -400,13 +431,15 @@ namespace Shader
Misc::StringUtils::replaceLast(specularMapFileName, ".", mSpecularMapPattern + ".");
if (mImageManager.getVFS()->exists(specularMapFileName))
{
osg::ref_ptr<osg::Image> image (mImageManager.getImage(specularMapFileName));
osg::ref_ptr<osg::Texture2D> specularMapTex (new osg::Texture2D(image));
osg::ref_ptr<osg::Image> image(mImageManager.getImage(specularMapFileName));
osg::ref_ptr<osg::Texture2D> specularMapTex(new osg::Texture2D(image));
specularMapTex->setTextureSize(image->s(), image->t());
specularMapTex->setWrap(osg::Texture::WRAP_S, diffuseMap->getWrap(osg::Texture::WRAP_S));
specularMapTex->setWrap(osg::Texture::WRAP_T, diffuseMap->getWrap(osg::Texture::WRAP_T));
specularMapTex->setFilter(osg::Texture::MIN_FILTER, diffuseMap->getFilter(osg::Texture::MIN_FILTER));
specularMapTex->setFilter(osg::Texture::MAG_FILTER, diffuseMap->getFilter(osg::Texture::MAG_FILTER));
specularMapTex->setFilter(
osg::Texture::MIN_FILTER, diffuseMap->getFilter(osg::Texture::MIN_FILTER));
specularMapTex->setFilter(
osg::Texture::MAG_FILTER, diffuseMap->getFilter(osg::Texture::MAG_FILTER));
specularMapTex->setMaxAnisotropy(diffuseMap->getMaxAnisotropy());
specularMapTex->setName("specularMap");
@ -425,15 +458,18 @@ namespace Shader
if (osg::ref_ptr<osg::StateSet> removedState = getRemovedState(*stateset))
removedAttributes = removedState->getAttributeList();
for (const auto* attributeMap : std::initializer_list<const osg::StateSet::AttributeList*>{ &attributes, &removedAttributes })
for (const auto* attributeMap :
std::initializer_list<const osg::StateSet::AttributeList*>{ &attributes, &removedAttributes })
{
for (osg::StateSet::AttributeList::const_iterator it = attributeMap->begin(); it != attributeMap->end(); ++it)
for (osg::StateSet::AttributeList::const_iterator it = attributeMap->begin(); it != attributeMap->end();
++it)
{
if (addedState && attributeMap != &removedAttributes && addedState->hasAttribute(it->first))
continue;
if (it->first.first == osg::StateAttribute::MATERIAL)
{
// This should probably be moved out of ShaderRequirements and be applied directly now it's a uniform instead of a define
// This should probably be moved out of ShaderRequirements and be applied directly now it's a
// uniform instead of a define
if (!mRequirements.back().mMaterialOverridden || it->second.second & osg::StateAttribute::PROTECTED)
{
if (it->second.second & osg::StateAttribute::OVERRIDE)
@ -444,25 +480,25 @@ namespace Shader
int colorMode;
switch (mat->getColorMode())
{
case osg::Material::OFF:
colorMode = 0;
break;
case osg::Material::EMISSION:
colorMode = 1;
break;
default:
case osg::Material::AMBIENT_AND_DIFFUSE:
colorMode = 2;
break;
case osg::Material::AMBIENT:
colorMode = 3;
break;
case osg::Material::DIFFUSE:
colorMode = 4;
break;
case osg::Material::SPECULAR:
colorMode = 5;
break;
case osg::Material::OFF:
colorMode = 0;
break;
case osg::Material::EMISSION:
colorMode = 1;
break;
default:
case osg::Material::AMBIENT_AND_DIFFUSE:
colorMode = 2;
break;
case osg::Material::AMBIENT:
colorMode = 3;
break;
case osg::Material::DIFFUSE:
colorMode = 4;
break;
case osg::Material::SPECULAR:
colorMode = 5;
break;
}
mRequirements.back().mColorMode = colorMode;
@ -470,7 +506,8 @@ namespace Shader
}
else if (it->first.first == osg::StateAttribute::ALPHAFUNC)
{
if (!mRequirements.back().mAlphaTestOverridden || it->second.second & osg::StateAttribute::PROTECTED)
if (!mRequirements.back().mAlphaTestOverridden
|| it->second.second & osg::StateAttribute::PROTECTED)
{
if (it->second.second & osg::StateAttribute::OVERRIDE)
mRequirements.back().mAlphaTestOverridden = true;
@ -482,21 +519,23 @@ namespace Shader
}
else if (it->first.first == osg::StateAttribute::BLENDFUNC)
{
if (!mRequirements.back().mBlendFuncOverridden || it->second.second & osg::StateAttribute::PROTECTED)
if (!mRequirements.back().mBlendFuncOverridden
|| it->second.second & osg::StateAttribute::PROTECTED)
{
if (it->second.second & osg::StateAttribute::OVERRIDE)
mRequirements.back().mBlendFuncOverridden = true;
const osg::BlendFunc* blend = static_cast<const osg::BlendFunc*>(it->second.first.get());
mRequirements.back().mAdditiveBlending =
blend->getSource() == osg::BlendFunc::SRC_ALPHA && blend->getDestination() == osg::BlendFunc::ONE;
mRequirements.back().mAdditiveBlending = blend->getSource() == osg::BlendFunc::SRC_ALPHA
&& blend->getDestination() == osg::BlendFunc::ONE;
}
}
}
}
unsigned int alphaBlend = stateset->getMode(GL_BLEND);
if (alphaBlend != osg::StateAttribute::INHERIT && (!mRequirements.back().mAlphaBlendOverridden || alphaBlend & osg::StateAttribute::PROTECTED))
if (alphaBlend != osg::StateAttribute::INHERIT
&& (!mRequirements.back().mAlphaBlendOverridden || alphaBlend & osg::StateAttribute::PROTECTED))
{
if (alphaBlend & osg::StateAttribute::OVERRIDE)
mRequirements.back().mAlphaBlendOverridden = true;
@ -519,7 +558,7 @@ namespace Shader
mRequirements.pop_back();
}
void ShaderVisitor::createProgram(const ShaderRequirements &reqs)
void ShaderVisitor::createProgram(const ShaderRequirements& reqs)
{
if (!reqs.mShaderRequired && !mForceShaders)
{
@ -528,21 +567,21 @@ namespace Shader
}
/**
* The shader visitor is supposed to be idempotent and undoable.
* That means we need to back up state we've removed (so it can be restored and/or considered by further
* applications of the visitor) and track which state we added (so it can be removed and/or ignored by further
* applications of the visitor).
* Before editing writableStateSet in a way that explicitly removes state or might overwrite existing state, it
* should be copied to removedState, another StateSet, unless it's there already or was added by a previous
* application of the visitor (is in previousAddedState).
* If it's a new class of state that's not already handled by ReinstateRemovedStateVisitor::apply, make sure to
* add handling there.
* Similarly, any time new state is added to writableStateSet, the equivalent method should be called on
* addedState.
* If that method doesn't exist yet, implement it - we don't use a full StateSet as we only need to check
* existence, not equality, and don't need to actually get the value as we can get it from writableStateSet
* instead.
*/
* The shader visitor is supposed to be idempotent and undoable.
* That means we need to back up state we've removed (so it can be restored and/or considered by further
* applications of the visitor) and track which state we added (so it can be removed and/or ignored by further
* applications of the visitor).
* Before editing writableStateSet in a way that explicitly removes state or might overwrite existing state, it
* should be copied to removedState, another StateSet, unless it's there already or was added by a previous
* application of the visitor (is in previousAddedState).
* If it's a new class of state that's not already handled by ReinstateRemovedStateVisitor::apply, make sure to
* add handling there.
* Similarly, any time new state is added to writableStateSet, the equivalent method should be called on
* addedState.
* If that method doesn't exist yet, implement it - we don't use a full StateSet as we only need to check
* existence, not equality, and don't need to actually get the value as we can get it from writableStateSet
* instead.
*/
osg::Node& node = *reqs.mNode;
osg::StateSet* writableStateSet = nullptr;
if (mAllowedToModifyStateSets)
@ -555,12 +594,13 @@ namespace Shader
previousAddedState = new AddedState;
ShaderManager::DefineMap defineMap;
for (unsigned int i=0; i<sizeof(defaultTextures)/sizeof(defaultTextures[0]); ++i)
for (unsigned int i = 0; i < sizeof(defaultTextures) / sizeof(defaultTextures[0]); ++i)
{
defineMap[defaultTextures[i]] = "0";
defineMap[std::string(defaultTextures[i]) + std::string("UV")] = "0";
}
for (std::map<int, std::string>::const_iterator texIt = reqs.mTextures.begin(); texIt != reqs.mTextures.end(); ++texIt)
for (std::map<int, std::string>::const_iterator texIt = reqs.mTextures.begin(); texIt != reqs.mTextures.end();
++texIt)
{
defineMap[texIt->second] = "1";
defineMap[texIt->second + std::string("UV")] = std::to_string(texIt->first);
@ -601,10 +641,12 @@ namespace Shader
removedState->setAttribute(alphaFunc->first, alphaFunc->second);
}
// This prevents redundant glAlphaFunc calls while letting the shadows bin still see the test
writableStateSet->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
writableStateSet->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc),
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
addedState->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc));
// Blending won't work with A2C as we use the alpha channel for coverage. gl_SampleCoverage from ARB_sample_shading would save the day, but requires GLSL 130
// Blending won't work with A2C as we use the alpha channel for coverage. gl_SampleCoverage from
// ARB_sample_shading would save the day, but requires GLSL 130
if (mConvertAlphaTestToAlphaToCoverage && !reqs.mAlphaBlend)
{
writableStateSet->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, osg::StateAttribute::ON);
@ -613,7 +655,8 @@ namespace Shader
}
// Adjusting coverage isn't safe with blending on as blending requires the alpha to be intact.
// Maybe we could also somehow (e.g. userdata) detect when the diffuse map has coverage-preserving mip maps in the future
// Maybe we could also somehow (e.g. userdata) detect when the diffuse map has coverage-preserving mip maps
// in the future
if (!reqs.mAlphaBlend)
defineMap["adjustCoverage"] = "1";
@ -639,7 +682,8 @@ namespace Shader
writableStateSet->setAttribute(new osg::ColorMaski(1, false, false, false, false));
}
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT && !previousAddedState->hasMode(GL_ALPHA_TEST))
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT
&& !previousAddedState->hasMode(GL_ALPHA_TEST))
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
// This disables the deprecated fixed-function alpha test
writableStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
@ -665,8 +709,10 @@ namespace Shader
if (!node.getUserValue("shaderPrefix", shaderPrefix))
shaderPrefix = mDefaultShaderPrefix;
osg::ref_ptr<osg::Shader> vertexShader (mShaderManager.getShader(shaderPrefix + "_vertex.glsl", defineMap, osg::Shader::VERTEX));
osg::ref_ptr<osg::Shader> fragmentShader (mShaderManager.getShader(shaderPrefix + "_fragment.glsl", defineMap, osg::Shader::FRAGMENT));
osg::ref_ptr<osg::Shader> vertexShader(
mShaderManager.getShader(shaderPrefix + "_vertex.glsl", defineMap, osg::Shader::VERTEX));
osg::ref_ptr<osg::Shader> fragmentShader(
mShaderManager.getShader(shaderPrefix + "_fragment.glsl", defineMap, osg::Shader::FRAGMENT));
if (vertexShader && fragmentShader)
{
@ -674,9 +720,11 @@ namespace Shader
writableStateSet->setAttributeAndModes(program, osg::StateAttribute::ON);
addedState->setAttributeAndModes(program);
for (std::map<int, std::string>::const_iterator texIt = reqs.mTextures.begin(); texIt != reqs.mTextures.end(); ++texIt)
for (std::map<int, std::string>::const_iterator texIt = reqs.mTextures.begin();
texIt != reqs.mTextures.end(); ++texIt)
{
writableStateSet->addUniform(new osg::Uniform(texIt->second.c_str(), texIt->first), osg::StateAttribute::ON);
writableStateSet->addUniform(
new osg::Uniform(texIt->second.c_str(), texIt->first), osg::StateAttribute::ON);
addedState->addUniform(texIt->second);
}
}
@ -705,16 +753,16 @@ namespace Shader
writableStateSet = getWritableStateSet(node);
/**
* We might have been using shaders temporarily with the node (e.g. if a GlowUpdater applied a temporary
* environment map for a temporary enchantment).
* We therefore need to remove any state doing so added, and restore any that it removed.
* This is kept track of in createProgram in the StateSet's userdata.
* If new classes of state get added, handling it here is required - not all StateSet features are implemented
* in AddedState yet as so far they've not been necessary.
* Removed state requires no particular special handling as it's dealt with by merging StateSets.
* We don't need to worry about state in writableStateSet having the OVERRIDE flag as if it's in both, it's also
* in addedState, and gets removed first.
*/
* We might have been using shaders temporarily with the node (e.g. if a GlowUpdater applied a temporary
* environment map for a temporary enchantment).
* We therefore need to remove any state doing so added, and restore any that it removed.
* This is kept track of in createProgram in the StateSet's userdata.
* If new classes of state get added, handling it here is required - not all StateSet features are implemented
* in AddedState yet as so far they've not been necessary.
* Removed state requires no particular special handling as it's dealt with by merging StateSets.
* We don't need to worry about state in writableStateSet having the OVERRIDE flag as if it's in both, it's also
* in addedState, and gets removed first.
*/
// user data is normally shallow copied so shared with the original stateset - we'll need to copy before edits
osg::ref_ptr<osg::UserDataContainer> writableUserData;
@ -730,7 +778,8 @@ namespace Shader
writableUserData->removeUserObject(index);
// O(n log n) to use StateSet::removeX, but this is O(n)
for (auto itr = writableStateSet->getUniformList().begin(); itr != writableStateSet->getUniformList().end();)
for (auto itr = writableStateSet->getUniformList().begin();
itr != writableStateSet->getUniformList().end();)
{
if (addedState->hasUniform(itr->first))
writableStateSet->getUniformList().erase(itr++);
@ -753,7 +802,8 @@ namespace Shader
for (unsigned int unit = 0; unit < writableStateSet->getTextureModeList().size(); ++unit)
{
for (auto itr = writableStateSet->getTextureModeList()[unit].begin(); itr != writableStateSet->getTextureModeList()[unit].end();)
for (auto itr = writableStateSet->getTextureModeList()[unit].begin();
itr != writableStateSet->getTextureModeList()[unit].end();)
{
if (addedState->hasTextureMode(unit, itr->first))
writableStateSet->getTextureModeList()[unit].erase(itr++);
@ -769,17 +819,16 @@ namespace Shader
}
}
if (osg::ref_ptr<osg::StateSet> removedState = getRemovedState(*writableStateSet))
{
if (!writableUserData)
{
if (mAllowedToModifyStateSets)
writableUserData = writableStateSet->getUserDataContainer();
else
writableUserData = getWritableUserDataContainer(*writableStateSet);
if (mAllowedToModifyStateSets)
writableUserData = writableStateSet->getUserDataContainer();
else
writableUserData = getWritableUserDataContainer(*writableStateSet);
}
unsigned int index = writableUserData->getUserObjectIndex("removedState");
writableUserData->removeUserObject(index);
@ -796,7 +845,8 @@ namespace Shader
if (mAllowedToModifyStateSets && (useShader || generateTangents))
{
// make sure that all UV sets are there
for (std::map<int, std::string>::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end(); ++it)
for (std::map<int, std::string>::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end();
++it)
{
if (sourceGeometry.getTexCoordArray(it->first) == nullptr)
{
@ -807,7 +857,7 @@ namespace Shader
if (generateTangents)
{
osg::ref_ptr<osgUtil::TangentSpaceGenerator> generator (new osgUtil::TangentSpaceGenerator);
osg::ref_ptr<osgUtil::TangentSpaceGenerator> generator(new osgUtil::TangentSpaceGenerator);
generator->generate(&sourceGeometry, reqs.mTexStageRequiringTangents);
sourceGeometry.setTexCoordArray(7, generator->getTangentArray(), osg::Array::BIND_PER_VERTEX);
@ -880,7 +930,6 @@ namespace Shader
osgaRig->setSourceRigGeometry(sourceOsgaRigGeometry);
}
}
}
else
ensureFFP(drawable);
@ -899,12 +948,12 @@ namespace Shader
mAutoUseNormalMaps = use;
}
void ShaderVisitor::setNormalMapPattern(const std::string &pattern)
void ShaderVisitor::setNormalMapPattern(const std::string& pattern)
{
mNormalMapPattern = pattern;
}
void ShaderVisitor::setNormalHeightMapPattern(const std::string &pattern)
void ShaderVisitor::setNormalHeightMapPattern(const std::string& pattern)
{
mNormalHeightMapPattern = pattern;
}
@ -914,7 +963,7 @@ namespace Shader
mAutoUseSpecularMaps = use;
}
void ShaderVisitor::setSpecularMapPattern(const std::string &pattern)
void ShaderVisitor::setSpecularMapPattern(const std::string& pattern)
{
mSpecularMapPattern = pattern;
}
@ -961,7 +1010,7 @@ namespace Shader
unsigned int index = writableUserData->getUserObjectIndex("removedState");
writableUserData->removeUserObject(index);
for (const auto&[mode, value] : removedState->getModeList())
for (const auto& [mode, value] : removedState->getModeList())
writableStateSet->setMode(mode, value);
for (const auto& attribute : removedState->getAttributeList())
@ -969,7 +1018,7 @@ namespace Shader
for (unsigned int unit = 0; unit < removedState->getTextureModeList().size(); ++unit)
{
for (const auto&[mode, value] : removedState->getTextureModeList()[unit])
for (const auto& [mode, value] : removedState->getTextureModeList()[unit])
writableStateSet->setTextureMode(unit, mode, value);
}
}

View file

@ -21,7 +21,8 @@ namespace Shader
class ShaderVisitor : public osg::NodeVisitor
{
public:
ShaderVisitor(ShaderManager& shaderManager, Resource::ImageManager& imageManager, const std::string& defaultShaderPrefix);
ShaderVisitor(
ShaderManager& shaderManager, Resource::ImageManager& imageManager, const std::string& defaultShaderPrefix);
void setProgramTemplate(const osg::Program* programTemplate) { mProgramTemplate = programTemplate; }
@ -30,8 +31,10 @@ namespace Shader
void setForceShaders(bool force);
/// Set if we are allowed to modify StateSets encountered in the graph (default true).
/// @par If set to false, then instead of modifying, the StateSet will be cloned and this new StateSet will be assigned to the node.
/// @par This option is useful when the ShaderVisitor is run on a "live" subgraph that may have already been submitted for rendering.
/// @par If set to false, then instead of modifying, the StateSet will be cloned and this new StateSet will be
/// assigned to the node.
/// @par This option is useful when the ShaderVisitor is run on a "live" subgraph that may have already been
/// submitted for rendering.
void setAllowedToModifyStateSets(bool allowed);
/// Automatically use normal maps if a file with suitable name exists (see normal map pattern).