From 9141a8d8014a236eec3c2e557bf71731ef05deb8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Mar 2015 22:52:20 +0100 Subject: [PATCH] Fully implement NiStencilProperty (Feature #1057) --- apps/nifosgtest/test.cpp | 3 ++ components/nif/property.hpp | 2 +- components/nifosg/nifloader.cpp | 53 +++++++++++++++++++++++++++------ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 0da95d13d..253b5f99d 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -102,6 +102,9 @@ int main(int argc, char** argv) Nif::NIFFilePtr nif(new Nif::NIFFile(resourceMgr.get(argv[1]), std::string(argv[1]))); + // For NiStencilProperty + osg::DisplaySettings::instance()->setMinimumNumStencilBits(8); + osgViewer::Viewer viewer; osg::ref_ptr root(new osg::Group()); diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 2633b16c5..96156c6d8 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -221,7 +221,7 @@ struct S_StencilProperty 4 TEST_GREATER 5 TEST_NOT_EQUAL 6 TEST_GREATER_EQUAL - 7 TEST_ALWAYS + 7 TEST_NEVER (though nifskope comment says TEST_ALWAYS, but ingame it is TEST_NEVER) */ int compareFunc; unsigned stencilRef; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 2ed91d467..45619b21b 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -116,6 +116,40 @@ namespace } } + osg::Stencil::Function getStencilFunction(int func) + { + switch (func) + { + case 0: return osg::Stencil::NEVER; + case 1: return osg::Stencil::LESS; + case 2: return osg::Stencil::EQUAL; + case 3: return osg::Stencil::LEQUAL; + case 4: return osg::Stencil::GREATER; + case 5: return osg::Stencil::NOTEQUAL; + case 6: return osg::Stencil::GEQUAL; + case 7: return osg::Stencil::NEVER; // NifSkope says this is GL_ALWAYS, but in MW it's GL_NEVER + default: + std::cerr << "Unexpected stencil function: " << func << std::endl; + return osg::Stencil::NEVER; + } + } + + osg::Stencil::Operation getStencilOperation(int op) + { + switch (op) + { + case 0: return osg::Stencil::KEEP; + case 1: return osg::Stencil::ZERO; + case 2: return osg::Stencil::REPLACE; + case 3: return osg::Stencil::INCR; + case 4: return osg::Stencil::DECR; + case 5: return osg::Stencil::INVERT; + default: + std::cerr << "Unexpected stencil operation: " << op << std::endl; + return osg::Stencil::KEEP; + } + } + // Collect all properties affecting the given node that should be applied to an osg::Material. void collectMaterialProperties(const Nif::Node* nifNode, std::vector& out) { @@ -1095,16 +1129,17 @@ namespace NifOsg stateset->setMode(GL_CULL_FACE, stencilprop->data.drawMode == 3 ? osg::StateAttribute::OFF : osg::StateAttribute::ON); - // TODO: - // Stencil settings not enabled yet, not sure if the original engine is actually using them, - // since they might conflict with Morrowind's stencil shadows. - /* - osg::Stencil* stencil = new osg::Stencil; - stencil->setFunction(func, stencilprop->data.stencilRef, stencilprop->data.stencilMask); + if (stencilprop->data.enabled != 0) + { + osg::Stencil* stencil = new osg::Stencil; + stencil->setFunction(getStencilFunction(stencilprop->data.compareFunc), stencilprop->data.stencilRef, stencilprop->data.stencilMask); + stencil->setStencilFailOperation(getStencilOperation(stencilprop->data.failAction)); + stencil->setStencilPassAndDepthFailOperation(getStencilOperation(stencilprop->data.zFailAction)); + stencil->setStencilPassAndDepthPassOperation(getStencilOperation(stencilprop->data.zPassAction)); - stateset->setMode(GL_STENCIL_TEST, stencilprop->data.enabled != 0 ? osg::StateAttribute::ON - : osg::StateAttribute::OFF); - */ + stateset->setAttributeAndModes(stencil, osg::StateAttribute::ON); + } + break; } case Nif::RC_NiWireframeProperty: {