@ -45,6 +45,7 @@
# include <components/nif/effect.hpp>
# include <components/nif/exception.hpp>
# include <components/nif/extra.hpp>
# include <components/nif/niffile.hpp>
# include <components/nif/node.hpp>
# include <components/nif/property.hpp>
# include <components/sceneutil/morphgeometry.hpp>
@ -318,6 +319,19 @@ namespace NifOsg
}
}
struct HandleNodeArgs
{
unsigned int mNifVersion ;
Resource : : ImageManager * mImageManager ;
SceneUtil : : TextKeyMap * mTextKeys ;
std : : vector < unsigned int > mBoundTextures = { } ;
int mAnimFlags = 0 ;
bool mSkipMeshes = false ;
bool mHasMarkers = false ;
bool mHasAnimatedParents = false ;
osg : : Node * mRootNode = nullptr ;
} ;
osg : : ref_ptr < osg : : Node > load ( Nif : : FileView nif , Resource : : ImageManager * imageManager )
{
const size_t numRoots = nif . numRoots ( ) ;
@ -340,8 +354,10 @@ namespace NifOsg
created - > setDataVariance ( osg : : Object : : STATIC ) ;
for ( const Nif : : Node * root : roots )
{
auto node = handleNode ( root , nullptr , nullptr , imageManager , std : : vector < unsigned int > ( ) , 0 , false ,
false , false , & textkeys - > mTextKeys ) ;
auto node = handleNode ( root , nullptr , nullptr ,
{ . mNifVersion = nif . getVersion ( ) ,
. mImageManager = imageManager ,
. mTextKeys = & textkeys - > mTextKeys } ) ;
created - > addChild ( node ) ;
}
if ( mHasNightDayLabel )
@ -597,12 +613,10 @@ namespace NifOsg
return node ;
}
osg : : ref_ptr < osg : : Node > handleNode ( const Nif : : Node * nifNode , const Nif : : Parent * parent , osg : : Group * parentNode ,
Resource : : ImageManager * imageManager , std : : vector < unsigned int > boundTextures , int animflags ,
bool skipMeshes , bool hasMarkers , bool hasAnimatedParents , SceneUtil : : TextKeyMap * textKeys ,
osg : : Node * rootNode = nullptr )
osg : : ref_ptr < osg : : Node > handleNode (
const Nif : : Node * nifNode , const Nif : : Parent * parent , osg : : Group * parentNode , HandleNodeArgs args )
{
if ( rootNode ! = nullptr & & Misc : : StringUtils : : ciEqual ( nifNode - > name , " Bounding Box " ) )
if ( args . mRootNode & & Misc : : StringUtils : : ciEqual ( nifNode - > name , " Bounding Box " ) )
return nullptr ;
osg : : ref_ptr < osg : : Group > node = createNode ( nifNode ) ;
@ -617,8 +631,8 @@ namespace NifOsg
if ( parentNode )
parentNode - > addChild ( node ) ;
if ( ! rootNode)
rootNode = node ;
if ( ! a rgs. mR ootNode)
a rgs. mR ootNode = node ;
// The original NIF record index is used for a variety of features:
// - finding the correct emitter node for a particle system
@ -637,10 +651,10 @@ namespace NifOsg
for ( const auto & e : extraCollection )
{
if ( e - > recType = = Nif : : RC_NiTextKeyExtraData & & t extKeys)
if ( e - > recType = = Nif : : RC_NiTextKeyExtraData & & args. mT extKeys)
{
const Nif : : NiTextKeyExtraData * tk = static_cast < const Nif : : NiTextKeyExtraData * > ( e . getPtr ( ) ) ;
extractTextKeys ( tk , * t extKeys) ;
extractTextKeys ( tk , * args. mT extKeys) ;
}
else if ( e - > recType = = Nif : : RC_NiStringExtraData )
{
@ -653,7 +667,7 @@ namespace NifOsg
if ( sd - > string = = " MRK " & & ! Loader : : getShowMarkers ( ) )
{
// Marker objects. These meshes are only visible in the editor.
h asMarkers = true ;
args. mH asMarkers = true ;
}
else if ( sd - > string = = " BONE " )
{
@ -665,10 +679,16 @@ namespace NifOsg
Misc : : OsgUserValues : : sExtraData , sd - > string . substr ( extraDataIdentifer . length ( ) ) ) ;
}
}
else if ( e - > recType = = Nif : : RC_BSXFlags )
{
auto bsxFlags = static_cast < const Nif : : NiIntegerExtraData * > ( e . getPtr ( ) ) ;
if ( bsxFlags - > data & 32 ) // Editor marker flag
args . mHasMarkers = true ;
}
}
if ( nifNode - > recType = = Nif : : RC_NiBSAnimationNode | | nifNode - > recType = = Nif : : RC_NiBSParticleNode )
animflags = nifNode - > flags ;
a rgs. mAnimF lags = nifNode - > flags ;
if ( nifNode - > recType = = Nif : : RC_NiSortAdjustNode )
{
@ -692,7 +712,7 @@ namespace NifOsg
// We still need to animate the hidden bones so the physics system can access them
if ( nifNode - > recType = = Nif : : RC_RootCollisionNode )
{
skipMeshes = true ;
arg s. mS kipMeshes = true ;
node - > setNodeMask ( Loader : : getHiddenNodeMask ( ) ) ;
}
@ -709,8 +729,8 @@ namespace NifOsg
}
if ( ! hasVisController )
skipMeshes = true ; // skip child meshes, but still create the child node hierarchy for animating
// collision shapes
arg s. mS kipMeshes = true ; // skip child meshes, but still create the child node hierarchy for
// animating collision shapes
node - > setNodeMask ( Loader : : getHiddenNodeMask ( ) ) ;
}
@ -720,37 +740,44 @@ namespace NifOsg
osg : : ref_ptr < SceneUtil : : CompositeStateSetUpdater > composite = new SceneUtil : : CompositeStateSetUpdater ;
applyNodeProperties ( nifNode , node , composite , imageManager, boundTextures , animf lags) ;
applyNodeProperties ( nifNode , node , composite , args. mImageManager , args . mBoundTextures , args . mAnimF lags) ;
const bool isGeometry = isTypeGeometry ( nifNode - > recType ) ;
if ( isGeometry & & ! skipMeshes)
if ( isGeometry & & ! arg s. mS kipMeshes)
{
const bool isMarker = hasMarkers & & Misc : : StringUtils : : ciStartsWith ( nifNode - > name , " tri editormarker " ) ;
if ( ! isMarker & & ! Misc : : StringUtils : : ciStartsWith ( nifNode - > name , " shadow " )
& & ! Misc : : StringUtils : : ciStartsWith ( nifNode - > name , " tri shadow " ) )
bool skip ;
if ( args . mNifVersion < = Nif : : NIFFile : : NIFVersion : : VER_MW )
{
skip = ( args . mHasMarkers & & Misc : : StringUtils : : ciStartsWith ( nifNode - > name , " tri editormarker " ) )
| | Misc : : StringUtils : : ciStartsWith ( nifNode - > name , " shadow " )
| | Misc : : StringUtils : : ciStartsWith ( nifNode - > name , " tri shadow " ) ;
}
else
skip = args . mHasMarkers & & Misc : : StringUtils : : ciStartsWith ( nifNode - > name , " EditorMarker " ) ;
if ( ! skip )
{
Nif : : NiSkinInstancePtr skin = static_cast < const Nif : : NiGeometry * > ( nifNode ) - > skin ;
if ( skin . empty ( ) )
handleGeometry ( nifNode , parent , node , composite , boundTextures , animflags ) ;
handleGeometry ( nifNode , parent , node , composite , args. mBoundTextures , args . mAnimF lags) ;
else
handleSkinnedGeometry ( nifNode , parent , node , composite , boundTextures , animflags ) ;
handleSkinnedGeometry ( nifNode , parent , node , composite , args. mBoundTextures , args . mAnimF lags) ;
if ( ! nifNode - > controller . empty ( ) )
handleMeshControllers ( nifNode , node , composite , boundTextures, animf lags) ;
handleMeshControllers ( nifNode , node , composite , args. mBoundTextures , args . mAnimF lags) ;
}
}
if ( nifNode - > recType = = Nif : : RC_NiParticles )
handleParticleSystem ( nifNode , parent , node , composite , a nimf lags) ;
handleParticleSystem ( nifNode , parent , node , composite , a rgs. mAnimF lags) ;
if ( composite - > getNumControllers ( ) > 0 )
{
osg : : Callback * cb = composite ;
if ( composite - > getNumControllers ( ) = = 1 )
cb = composite - > getController ( 0 ) ;
if ( a nimf lags & Nif : : NiNode : : AnimFlag_AutoPlay )
if ( a rgs. mAnimF lags & Nif : : NiNode : : AnimFlag_AutoPlay )
node - > addCullCallback ( cb ) ;
else
node - > addUpdateCallback (
@ -758,10 +785,10 @@ namespace NifOsg
}
bool isAnimated = false ;
handleNodeControllers ( nifNode , node , a nimf lags, isAnimated ) ;
h asAnimatedParents | = isAnimated ;
handleNodeControllers ( nifNode , node , a rgs. mAnimF lags, isAnimated ) ;
args. mH asAnimatedParents | = isAnimated ;
// Make sure empty nodes and animated shapes are not optimized away so the physics system can find them.
if ( isAnimated | | ( hasAnimatedParents & & ( ( skipMeshes | | h asMarkers) | | isGeometry ) ) )
if ( isAnimated | | ( args. mHasAnimatedParents & & ( ( args . mSkipMeshes | | args . mH asMarkers) | | isGeometry ) ) )
node - > setDataVariance ( osg : : Object : : DYNAMIC ) ;
// LOD and Switch nodes must be wrapped by a transform (the current node) to support transformations
@ -802,8 +829,7 @@ namespace NifOsg
const Nif : : Parent currentParent { * ninode , parent } ;
for ( const auto & child : children )
if ( ! child . empty ( ) )
handleNode ( child . getPtr ( ) , & currentParent , currentNode , imageManager , boundTextures , animflags ,
skipMeshes , hasMarkers , hasAnimatedParents , textKeys , rootNode ) ;
handleNode ( child . getPtr ( ) , & currentParent , currentNode , args ) ;
// Propagate effects to the the direct subgraph instead of the node itself
// This simulates their "affected node list" which Morrowind appears to replace with the subgraph (?)
@ -812,7 +838,7 @@ namespace NifOsg
if ( ! effect . empty ( ) )
{
osg : : ref_ptr < osg : : StateSet > effectStateSet = new osg : : StateSet ;
if ( handleEffect ( effect . getPtr ( ) , effectStateSet , i mageManager) )
if ( handleEffect ( effect . getPtr ( ) , effectStateSet , args. mI mageManager) )
for ( unsigned int i = 0 ; i < currentNode - > getNumChildren ( ) ; + + i )
currentNode - > getChild ( i ) - > getOrCreateStateSet ( ) - > merge ( * effectStateSet ) ;
}
@ -2143,6 +2169,8 @@ namespace NifOsg
textureSet , texprop - > clamp , node - > getName ( ) , stateset , imageManager , boundTextures ) ;
}
handleTextureControllers ( texprop , composite , imageManager , stateset , animflags ) ;
if ( texprop - > doubleSided ( ) )
stateset - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF ) ;
break ;
}
case Nif : : RC_BSShaderNoLightingProperty :
@ -2183,6 +2211,8 @@ namespace NifOsg
stateset - > addUniform ( new osg : : Uniform ( " useFalloff " , false ) ) ;
}
handleTextureControllers ( texprop , composite , imageManager , stateset , animflags ) ;
if ( texprop - > doubleSided ( ) )
stateset - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF ) ;
break ;
}
case Nif : : RC_BSLightingShaderProperty :
@ -2196,6 +2226,10 @@ namespace NifOsg
handleTextureSet ( texprop - > mTextureSet . getPtr ( ) , texprop - > mClamp , node - > getName ( ) , stateset ,
imageManager , boundTextures ) ;
handleTextureControllers ( texprop , composite , imageManager , stateset , animflags ) ;
if ( texprop - > doubleSided ( ) )
stateset - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF ) ;
if ( texprop - > treeAnim ( ) )
stateset - > addUniform ( new osg : : Uniform ( " useTreeAnim " , true ) ) ;
break ;
}
case Nif : : RC_BSEffectShaderProperty :
@ -2246,6 +2280,8 @@ namespace NifOsg
stateset - > addUniform ( new osg : : Uniform ( " useFalloff " , false ) ) ; // Should use the shader flag
stateset - > addUniform ( new osg : : Uniform ( " falloffParams " , texprop - > mFalloffParams ) ) ;
handleTextureControllers ( texprop , composite , imageManager , stateset , animflags ) ;
if ( texprop - > doubleSided ( ) )
stateset - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF ) ;
break ;
}
// unused by mw