Add OpenMW commits up to 14 Nov 2020
# Conflicts: # .travis.yml # apps/openmw/mwmechanics/tickableeffects.cpppull/593/head
commit
676481d061
@ -0,0 +1,166 @@
|
||||
#include "shadowsbin.hpp"
|
||||
#include <unordered_set>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/Material>
|
||||
#include <osgUtil/StateGraph>
|
||||
|
||||
using namespace osgUtil;
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
inline void accumulateState(T& currentValue, T newValue, bool& isOverride, unsigned int overrideFlags)
|
||||
{
|
||||
if (isOverride && !(overrideFlags & osg::StateAttribute::PROTECTED)) return;
|
||||
|
||||
if (overrideFlags & osg::StateAttribute::OVERRIDE)
|
||||
isOverride = true;
|
||||
|
||||
currentValue = newValue;
|
||||
}
|
||||
|
||||
inline void accumulateModeState(const osg::StateSet* ss, bool& currentValue, bool& isOverride, int mode)
|
||||
{
|
||||
const osg::StateSet::ModeList& l = ss->getModeList();
|
||||
osg::StateSet::ModeList::const_iterator mf = l.find(mode);
|
||||
if (mf == l.end())
|
||||
return;
|
||||
int flags = mf->second;
|
||||
bool newValue = flags & osg::StateAttribute::ON;
|
||||
accumulateState(currentValue, newValue, isOverride, ss->getMode(mode));
|
||||
}
|
||||
|
||||
inline bool materialNeedShadows(osg::Material* m)
|
||||
{
|
||||
// I'm pretty sure this needs to check the colour mode - vertex colours might override this value.
|
||||
return m->getDiffuse(osg::Material::FRONT).a() > 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
|
||||
ShadowsBin::ShadowsBin()
|
||||
{
|
||||
mNoTestStateSet = new osg::StateSet;
|
||||
mNoTestStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false));
|
||||
mNoTestStateSet->addUniform(new osg::Uniform("alphaTestShadows", false));
|
||||
|
||||
mShaderAlphaTestStateSet = new osg::StateSet;
|
||||
mShaderAlphaTestStateSet->addUniform(new osg::Uniform("alphaTestShadows", true));
|
||||
mShaderAlphaTestStateSet->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
|
||||
}
|
||||
|
||||
StateGraph* ShadowsBin::cullStateGraph(StateGraph* sg, StateGraph* root, std::unordered_set<StateGraph*>& uninterestingCache)
|
||||
{
|
||||
std::vector<StateGraph*> return_path;
|
||||
State state;
|
||||
StateGraph* sg_new = sg;
|
||||
do
|
||||
{
|
||||
if (uninterestingCache.find(sg_new) != uninterestingCache.end())
|
||||
break;
|
||||
return_path.push_back(sg_new);
|
||||
sg_new = sg_new->_parent;
|
||||
} while (sg_new && sg_new != root);
|
||||
|
||||
for(auto itr=return_path.rbegin(); itr!=return_path.rend(); ++itr)
|
||||
{
|
||||
const osg::StateSet* ss = (*itr)->getStateSet();
|
||||
if (!ss)
|
||||
continue;
|
||||
|
||||
accumulateModeState(ss, state.mAlphaBlend, state.mAlphaBlendOverride, GL_BLEND);
|
||||
accumulateModeState(ss, state.mAlphaTest, state.mAlphaTestOverride, GL_ALPHA_TEST);
|
||||
|
||||
const osg::StateSet::AttributeList& attributes = ss->getAttributeList();
|
||||
osg::StateSet::AttributeList::const_iterator found = attributes.find(std::make_pair(osg::StateAttribute::MATERIAL, 0));
|
||||
if (found != attributes.end())
|
||||
{
|
||||
const osg::StateSet::RefAttributePair& rap = found->second;
|
||||
accumulateState(state.mMaterial, static_cast<osg::Material*>(rap.first.get()), state.mMaterialOverride, rap.second);
|
||||
if (state.mMaterial && !materialNeedShadows(state.mMaterial))
|
||||
state.mMaterial = nullptr;
|
||||
}
|
||||
|
||||
// osg::FrontFace specifies triangle winding, not front-face culling. We can't safely reparent anything under it.
|
||||
found = attributes.find(std::make_pair(osg::StateAttribute::FRONTFACE, 0));
|
||||
if (found != attributes.end())
|
||||
state.mImportantState = true;
|
||||
|
||||
if ((*itr) != sg && !state.interesting())
|
||||
uninterestingCache.insert(*itr);
|
||||
}
|
||||
|
||||
if (!state.needShadows())
|
||||
return nullptr;
|
||||
|
||||
if (!state.needTexture() && !state.mImportantState)
|
||||
{
|
||||
for (RenderLeaf* leaf : sg->_leaves)
|
||||
{
|
||||
leaf->_parent = root;
|
||||
root->_leaves.push_back(leaf);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (state.mAlphaBlend)
|
||||
{
|
||||
sg_new = sg->find_or_insert(mShaderAlphaTestStateSet);
|
||||
for (RenderLeaf* leaf : sg->_leaves)
|
||||
{
|
||||
leaf->_parent = sg_new;
|
||||
sg_new->_leaves.push_back(leaf);
|
||||
}
|
||||
return sg_new;
|
||||
}
|
||||
return sg;
|
||||
}
|
||||
|
||||
bool ShadowsBin::State::needShadows() const
|
||||
{
|
||||
if (!mMaterial)
|
||||
return true;
|
||||
return materialNeedShadows(mMaterial);
|
||||
}
|
||||
|
||||
void ShadowsBin::sortImplementation()
|
||||
{
|
||||
// The cull visitor contains a stategraph.
|
||||
// When a stateset is pushed, it's added/found as a child of the current stategraph node, then that node becomes the new current stategraph node.
|
||||
// When a drawable is added, the current stategraph node is added to the current renderbin (if it's not there already) and the drawable is added as a renderleaf to the stategraph
|
||||
// This means our list only contains stategraph nodes with directly-attached renderleaves, but they might have parents with more state set that needs to be considered.
|
||||
if (!_stateGraphList.size())
|
||||
return;
|
||||
StateGraph* root = _stateGraphList[0];
|
||||
while (root->_parent)
|
||||
{
|
||||
root = root->_parent;
|
||||
const osg::StateSet* ss = root->getStateSet();
|
||||
if (ss->getMode(GL_NORMALIZE) & osg::StateAttribute::ON // that is root stategraph of renderingmanager cpp
|
||||
|| ss->getAttribute(osg::StateAttribute::VIEWPORT)) // fallback to rendertargets sg just in case
|
||||
break;
|
||||
if (!root->_parent)
|
||||
return;
|
||||
}
|
||||
StateGraph* noTestRoot = root->find_or_insert(mNoTestStateSet.get());
|
||||
// root is now a stategraph with useDiffuseMapForShadowAlpha disabled but minimal other state
|
||||
noTestRoot->_leaves.reserve(_stateGraphList.size());
|
||||
StateGraphList newList;
|
||||
std::unordered_set<StateGraph*> uninterestingCache;
|
||||
for (StateGraph* graph : _stateGraphList)
|
||||
{
|
||||
// Render leaves which shouldn't use the diffuse map for shadow alpha but do cast shadows become children of root, so graph is now empty. Don't add to newList.
|
||||
// Graphs containing just render leaves which don't cast shadows are discarded. Don't add to newList.
|
||||
// Graphs containing other leaves need to be in newList.
|
||||
StateGraph* graphToAdd = cullStateGraph(graph, noTestRoot, uninterestingCache);
|
||||
if (graphToAdd)
|
||||
newList.push_back(graphToAdd);
|
||||
}
|
||||
if (!noTestRoot->_leaves.empty())
|
||||
newList.push_back(noTestRoot);
|
||||
_stateGraphList = newList;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_SHADOWBIN_H
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_SHADOWBIN_H
|
||||
#include <unordered_set>
|
||||
#include <osgUtil/RenderBin>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Material;
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
|
||||
/// renderbin which culls redundant state for shadow map rendering
|
||||
class ShadowsBin : public osgUtil::RenderBin
|
||||
{
|
||||
private:
|
||||
osg::ref_ptr<osg::StateSet> mNoTestStateSet;
|
||||
osg::ref_ptr<osg::StateSet> mShaderAlphaTestStateSet;
|
||||
public:
|
||||
META_Object(SceneUtil, ShadowsBin)
|
||||
ShadowsBin();
|
||||
ShadowsBin(const ShadowsBin& rhs, const osg::CopyOp& copyop)
|
||||
: osgUtil::RenderBin(rhs, copyop)
|
||||
, mNoTestStateSet(rhs.mNoTestStateSet)
|
||||
, mShaderAlphaTestStateSet(rhs.mShaderAlphaTestStateSet)
|
||||
{}
|
||||
|
||||
void sortImplementation() override;
|
||||
|
||||
struct State
|
||||
{
|
||||
State()
|
||||
: mAlphaBlend(false)
|
||||
, mAlphaBlendOverride(false)
|
||||
, mAlphaTest(false)
|
||||
, mAlphaTestOverride(false)
|
||||
, mMaterial(nullptr)
|
||||
, mMaterialOverride(false)
|
||||
, mImportantState(false)
|
||||
{}
|
||||
|
||||
bool mAlphaBlend;
|
||||
bool mAlphaBlendOverride;
|
||||
bool mAlphaTest;
|
||||
bool mAlphaTestOverride;
|
||||
osg::Material* mMaterial;
|
||||
bool mMaterialOverride;
|
||||
bool mImportantState;
|
||||
bool needTexture() const { return mAlphaBlend || mAlphaTest; }
|
||||
bool needShadows() const;
|
||||
// A state is interesting if there's anything about it that might affect whether we can optimise child state
|
||||
bool interesting() const
|
||||
{
|
||||
return !needShadows() || needTexture() || mAlphaBlendOverride || mAlphaTestOverride || mMaterialOverride || mImportantState;
|
||||
}
|
||||
};
|
||||
|
||||
osgUtil::StateGraph* cullStateGraph(osgUtil::StateGraph* sg, osgUtil::StateGraph* root, std::unordered_set<osgUtil::StateGraph*>& uninteresting);
|
||||
|
||||
static void addPrototype(const std::string& name)
|
||||
{
|
||||
osg::ref_ptr<osgUtil::RenderBin> bin (new ShadowsBin);
|
||||
osgUtil::RenderBin::addRenderBinPrototype(name, bin);
|
||||
}
|
||||
};
|
||||
|
||||
class ShadowsBinAdder
|
||||
{
|
||||
public:
|
||||
ShadowsBinAdder(const std::string& name){ ShadowsBin::addPrototype(name); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,31 @@
|
||||
Models Settings
|
||||
###############
|
||||
|
||||
load unsupported nif files
|
||||
--------------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
Allow the engine to load arbitrary NIF files as long as they appear to be valid.
|
||||
|
||||
OpenMW has limited and **experimental** support for NIF files
|
||||
that Morrowind itself cannot load, which normally goes unused.
|
||||
|
||||
If enabled, this setting allows the NIF loader to make use of that functionality.
|
||||
|
||||
.. warning::
|
||||
You must keep in mind that since the mentioned support is experimental,
|
||||
loading unsupported NIF files may fail, and the degree of this failure may vary.
|
||||
|
||||
In milder cases, OpenMW will reject the file anyway because
|
||||
it lacks a definition for a certain record type that the file may use.
|
||||
|
||||
In more severe cases OpenMW's incomplete understanding of a record type
|
||||
can lead to memory corruption, freezes or even crashes.
|
||||
|
||||
**Do not enable** this if you're not so sure that you know what you're doing.
|
||||
|
||||
To help debug possible issues OpenMW will log its progress in loading
|
||||
every file that uses an unsupported NIF version.
|
Loading…
Reference in New Issue