2019-06-13 13:37:00 +00:00
# include "objectpaging.hpp"
2020-04-30 13:37:00 +00:00
# include <unordered_map>
2019-06-13 13:37:00 +00:00
# include <osg/LOD>
# include <osg/Switch>
2022-03-29 21:47:37 +02:00
# include <osg/Sequence>
2019-06-13 13:37:00 +00:00
# include <osg/MatrixTransform>
2020-05-05 13:37:00 +00:00
# include <osg/Material>
2019-06-13 13:37:00 +00:00
# include <osgUtil/IncrementalCompileOperation>
2022-01-22 15:58:41 +01:00
# include <components/esm3/esmreader.hpp>
2019-06-13 13:37:00 +00:00
# include <components/misc/resourcehelpers.hpp>
# include <components/resource/scenemanager.hpp>
# include <components/sceneutil/optimizer.hpp>
2021-10-11 08:09:01 +00:00
# include <components/sceneutil/positionattitudetransform.hpp>
2019-06-13 13:37:00 +00:00
# include <components/sceneutil/clone.hpp>
2020-05-11 13:37:00 +00:00
# include <components/sceneutil/util.hpp>
# include <components/vfs/manager.hpp>
2019-06-13 13:37:00 +00:00
# include <osgParticle/ParticleProcessor>
# include <osgParticle/ParticleSystemUpdater>
2020-05-10 13:37:00 +00:00
# include <components/sceneutil/lightmanager.hpp>
2019-06-13 13:37:00 +00:00
# include <components/sceneutil/morphgeometry.hpp>
# include <components/sceneutil/riggeometry.hpp>
# include <components/settings/settings.hpp>
2020-05-05 13:37:00 +00:00
# include <components/misc/rng.hpp>
2019-06-13 13:37:00 +00:00
# include "apps/openmw/mwworld/esmstore.hpp"
# include "apps/openmw/mwbase/environment.hpp"
# include "apps/openmw/mwbase/world.hpp"
# include "vismask.hpp"
namespace MWRender
{
2020-05-11 13:37:00 +00:00
bool typeFilter ( int type , bool far )
2019-06-13 13:37:00 +00:00
{
switch ( type )
{
case ESM : : REC_STAT :
2020-05-11 13:37:00 +00:00
case ESM : : REC_ACTI :
2020-05-10 13:37:00 +00:00
case ESM : : REC_DOOR :
2020-05-11 13:37:00 +00:00
return true ;
2019-06-13 13:37:00 +00:00
case ESM : : REC_CONT :
2020-05-11 13:37:00 +00:00
return ! far ;
2020-05-10 13:37:00 +00:00
2019-06-13 13:37:00 +00:00
default :
return false ;
}
}
2020-05-03 13:37:00 +00:00
std : : string getModel ( int type , const std : : string & id , const MWWorld : : ESMStore & store )
2019-06-13 13:37:00 +00:00
{
switch ( type )
{
case ESM : : REC_STAT :
return store . get < ESM : : Static > ( ) . searchStatic ( id ) - > mModel ;
case ESM : : REC_ACTI :
return store . get < ESM : : Activator > ( ) . searchStatic ( id ) - > mModel ;
case ESM : : REC_DOOR :
return store . get < ESM : : Door > ( ) . searchStatic ( id ) - > mModel ;
case ESM : : REC_CONT :
return store . get < ESM : : Container > ( ) . searchStatic ( id ) - > mModel ;
2020-05-03 13:37:00 +00:00
default :
2022-03-30 09:27:00 +02:00
return { } ;
2019-06-13 13:37:00 +00:00
}
}
2020-05-10 13:37:00 +00:00
osg : : ref_ptr < osg : : Node > ObjectPaging : : getChunk ( float size , const osg : : Vec2f & center , unsigned char lod , unsigned int lodFlags , bool activeGrid , const osg : : Vec3f & viewPoint , bool compile )
2019-06-13 13:37:00 +00:00
{
2020-05-10 13:37:00 +00:00
if ( activeGrid & & ! mActiveGrid )
return nullptr ;
ChunkId id = std : : make_tuple ( center , size , activeGrid ) ;
2019-06-13 13:37:00 +00:00
osg : : ref_ptr < osg : : Object > obj = mCache - > getRefFromObjectCache ( id ) ;
if ( obj )
2021-09-10 15:58:57 +00:00
return static_cast < osg : : Node * > ( obj . get ( ) ) ;
2019-06-13 13:37:00 +00:00
else
{
2020-05-10 13:37:00 +00:00
osg : : ref_ptr < osg : : Node > node = createChunk ( size , center , activeGrid , viewPoint , compile ) ;
2019-06-13 13:37:00 +00:00
mCache - > addEntryToObjectCache ( id , node . get ( ) ) ;
return node ;
}
}
class CanOptimizeCallback : public SceneUtil : : Optimizer : : IsOperationPermissibleForObjectCallback
{
public :
2020-10-16 22:18:54 +04:00
bool isOperationPermissibleForObjectImplementation ( const SceneUtil : : Optimizer * optimizer , const osg : : Drawable * node , unsigned int option ) const override
2019-06-13 13:37:00 +00:00
{
return true ;
}
2020-10-16 22:18:54 +04:00
bool isOperationPermissibleForObjectImplementation ( const SceneUtil : : Optimizer * optimizer , const osg : : Node * node , unsigned int option ) const override
2019-06-13 13:37:00 +00:00
{
2020-05-16 13:37:00 +00:00
return ( node - > getDataVariance ( ) ! = osg : : Object : : DYNAMIC ) ;
2019-06-13 13:37:00 +00:00
}
} ;
class CopyOp : public osg : : CopyOp
{
public :
2020-05-16 13:37:00 +00:00
bool mOptimizeBillboards = true ;
float mSqrDistance = 0.f ;
2020-05-04 13:37:00 +00:00
osg : : Vec3f mViewVector ;
2021-05-09 14:10:35 +04:00
osg : : Node : : NodeMask mCopyMask = ~ 0u ;
2020-05-04 13:37:00 +00:00
mutable std : : vector < const osg : : Node * > mNodePath ;
2019-06-13 13:37:00 +00:00
2020-05-16 13:37:00 +00:00
void copy ( const osg : : Node * toCopy , osg : : Group * attachTo )
{
const osg : : Group * groupToCopy = toCopy - > asGroup ( ) ;
if ( toCopy - > getStateSet ( ) | | toCopy - > asTransform ( ) | | ! groupToCopy )
attachTo - > addChild ( operator ( ) ( toCopy ) ) ;
else
{
for ( unsigned int i = 0 ; i < groupToCopy - > getNumChildren ( ) ; + + i )
attachTo - > addChild ( operator ( ) ( groupToCopy - > getChild ( i ) ) ) ;
}
}
2020-10-16 22:18:54 +04:00
osg : : Node * operator ( ) ( const osg : : Node * node ) const override
2019-06-13 13:37:00 +00:00
{
2021-05-09 14:10:35 +04:00
if ( ! ( node - > getNodeMask ( ) & mCopyMask ) )
return nullptr ;
2020-05-16 13:37:00 +00:00
if ( const osg : : Drawable * d = node - > asDrawable ( ) )
return operator ( ) ( d ) ;
2019-06-13 13:37:00 +00:00
if ( dynamic_cast < const osgParticle : : ParticleProcessor * > ( node ) )
return nullptr ;
if ( dynamic_cast < const osgParticle : : ParticleSystemUpdater * > ( node ) )
return nullptr ;
if ( const osg : : Switch * sw = node - > asSwitch ( ) )
{
osg : : Group * n = new osg : : Group ;
for ( unsigned int i = 0 ; i < sw - > getNumChildren ( ) ; + + i )
if ( sw - > getValue ( i ) )
n - > addChild ( operator ( ) ( sw - > getChild ( i ) ) ) ;
n - > setDataVariance ( osg : : Object : : STATIC ) ;
return n ;
}
if ( const osg : : LOD * lod = dynamic_cast < const osg : : LOD * > ( node ) )
{
osg : : Group * n = new osg : : Group ;
for ( unsigned int i = 0 ; i < lod - > getNumChildren ( ) ; + + i )
2020-05-04 13:37:00 +00:00
if ( lod - > getMinRange ( i ) * lod - > getMinRange ( i ) < = mSqrDistance & & mSqrDistance < lod - > getMaxRange ( i ) * lod - > getMaxRange ( i ) )
2019-06-13 13:37:00 +00:00
n - > addChild ( operator ( ) ( lod - > getChild ( i ) ) ) ;
n - > setDataVariance ( osg : : Object : : STATIC ) ;
return n ;
}
2022-03-29 21:47:37 +02:00
if ( const osg : : Sequence * sq = dynamic_cast < const osg : : Sequence * > ( node ) )
{
osg : : Group * n = new osg : : Group ;
2022-03-31 21:55:14 +02:00
n - > addChild ( operator ( ) ( sq - > getChild ( sq - > getValue ( ) ! = - 1 ? sq - > getValue ( ) : 0 ) ) ) ;
2022-03-29 21:47:37 +02:00
n - > setDataVariance ( osg : : Object : : STATIC ) ;
return n ;
}
2019-06-13 13:37:00 +00:00
2020-05-04 13:37:00 +00:00
mNodePath . push_back ( node ) ;
2020-05-16 13:37:00 +00:00
osg : : Node * cloned = static_cast < osg : : Node * > ( node - > clone ( * this ) ) ;
2020-05-04 13:37:00 +00:00
cloned - > setDataVariance ( osg : : Object : : STATIC ) ;
cloned - > setUserDataContainer ( nullptr ) ;
cloned - > setName ( " " ) ;
mNodePath . pop_back ( ) ;
handleCallbacks ( node , cloned ) ;
return cloned ;
}
void handleCallbacks ( const osg : : Node * node , osg : : Node * cloned ) const
{
2020-05-16 13:37:00 +00:00
for ( const osg : : Callback * callback = node - > getCullCallback ( ) ; callback ! = nullptr ; callback = callback - > getNestedCallback ( ) )
2020-05-04 13:37:00 +00:00
{
if ( callback - > className ( ) = = std : : string ( " BillboardCallback " ) )
2020-05-12 13:37:00 +00:00
{
2020-05-16 13:37:00 +00:00
if ( mOptimizeBillboards )
2020-05-12 13:37:00 +00:00
{
2020-05-16 13:37:00 +00:00
handleBillboard ( cloned ) ;
continue ;
2020-05-12 13:37:00 +00:00
}
else
2020-05-16 13:37:00 +00:00
cloned - > setDataVariance ( osg : : Object : : DYNAMIC ) ;
2020-05-12 13:37:00 +00:00
}
2020-05-16 13:37:00 +00:00
if ( node - > getCullCallback ( ) - > getNestedCallback ( ) )
{
osg : : Callback * clonedCallback = osg : : clone ( callback , osg : : CopyOp : : SHALLOW_COPY ) ;
clonedCallback - > setNestedCallback ( nullptr ) ;
cloned - > addCullCallback ( clonedCallback ) ;
}
else
cloned - > addCullCallback ( const_cast < osg : : Callback * > ( callback ) ) ;
2020-05-04 13:37:00 +00:00
}
}
void handleBillboard ( osg : : Node * node ) const
{
osg : : Transform * transform = node - > asTransform ( ) ;
if ( ! transform ) return ;
osg : : MatrixTransform * matrixTransform = transform - > asMatrixTransform ( ) ;
if ( ! matrixTransform ) return ;
osg : : Matrix worldToLocal = osg : : Matrix : : identity ( ) ;
2020-06-26 09:49:26 +04:00
for ( auto pathNode : mNodePath )
if ( const osg : : Transform * t = pathNode - > asTransform ( ) )
2020-05-04 13:37:00 +00:00
t - > computeWorldToLocalMatrix ( worldToLocal , nullptr ) ;
worldToLocal = osg : : Matrix : : orthoNormal ( worldToLocal ) ;
osg : : Matrix billboardMatrix ;
osg : : Vec3f viewVector = - ( mViewVector + worldToLocal . getTrans ( ) ) ;
viewVector . normalize ( ) ;
osg : : Vec3f right = viewVector ^ osg : : Vec3f ( 0 , 0 , 1 ) ;
right . normalize ( ) ;
osg : : Vec3f up = right ^ viewVector ;
up . normalize ( ) ;
billboardMatrix . makeLookAt ( osg : : Vec3f ( 0 , 0 , 0 ) , viewVector , up ) ;
billboardMatrix . invert ( billboardMatrix ) ;
const osg : : Matrix & oldMatrix = matrixTransform - > getMatrix ( ) ;
float mag [ 3 ] ; // attempt to preserve scale
for ( int i = 0 ; i < 3 ; + + i )
mag [ i ] = std : : sqrt ( oldMatrix ( 0 , i ) * oldMatrix ( 0 , i ) + oldMatrix ( 1 , i ) * oldMatrix ( 1 , i ) + oldMatrix ( 2 , i ) * oldMatrix ( 2 , i ) ) ;
osg : : Matrix newMatrix ;
worldToLocal . setTrans ( 0 , 0 , 0 ) ;
newMatrix * = worldToLocal ;
newMatrix . preMult ( billboardMatrix ) ;
newMatrix . preMultScale ( osg : : Vec3f ( mag [ 0 ] , mag [ 1 ] , mag [ 2 ] ) ) ;
newMatrix . setTrans ( oldMatrix . getTrans ( ) ) ;
matrixTransform - > setMatrix ( newMatrix ) ;
2019-06-13 13:37:00 +00:00
}
2020-10-16 22:18:54 +04:00
osg : : Drawable * operator ( ) ( const osg : : Drawable * drawable ) const override
2019-06-13 13:37:00 +00:00
{
2021-05-09 14:10:35 +04:00
if ( ! ( drawable - > getNodeMask ( ) & mCopyMask ) )
return nullptr ;
2019-06-13 13:37:00 +00:00
if ( dynamic_cast < const osgParticle : : ParticleSystem * > ( drawable ) )
return nullptr ;
if ( const SceneUtil : : RigGeometry * rig = dynamic_cast < const SceneUtil : : RigGeometry * > ( drawable ) )
2020-04-30 13:37:00 +00:00
return operator ( ) ( rig - > getSourceGeometry ( ) ) ;
2019-06-13 13:37:00 +00:00
if ( const SceneUtil : : MorphGeometry * morph = dynamic_cast < const SceneUtil : : MorphGeometry * > ( drawable ) )
2020-04-30 13:37:00 +00:00
return operator ( ) ( morph - > getSourceGeometry ( ) ) ;
2019-06-13 13:37:00 +00:00
2020-04-30 13:37:00 +00:00
if ( getCopyFlags ( ) & DEEP_COPY_DRAWABLES )
{
2020-05-16 13:37:00 +00:00
osg : : Drawable * d = static_cast < osg : : Drawable * > ( drawable - > clone ( * this ) ) ;
2020-04-30 13:37:00 +00:00
d - > setDataVariance ( osg : : Object : : STATIC ) ;
d - > setUserDataContainer ( nullptr ) ;
d - > setName ( " " ) ;
return d ;
}
else
2020-05-16 13:37:00 +00:00
return const_cast < osg : : Drawable * > ( drawable ) ;
2019-06-13 13:37:00 +00:00
}
2020-10-16 22:18:54 +04:00
osg : : Callback * operator ( ) ( const osg : : Callback * callback ) const override
2019-06-13 13:37:00 +00:00
{
return nullptr ;
}
} ;
2020-05-10 13:37:00 +00:00
class RefnumSet : public osg : : Object
{
public :
RefnumSet ( ) { }
RefnumSet ( const RefnumSet & copy , const osg : : CopyOp & ) : mRefnums ( copy . mRefnums ) { }
META_Object ( MWRender , RefnumSet )
std : : set < ESM : : RefNum > mRefnums ;
} ;
2020-04-30 13:37:00 +00:00
class AnalyzeVisitor : public osg : : NodeVisitor
{
public :
2021-05-09 14:10:35 +04:00
AnalyzeVisitor ( osg : : Node : : NodeMask analyzeMask )
2020-04-30 13:37:00 +00:00
: osg : : NodeVisitor ( TRAVERSE_ALL_CHILDREN )
2021-05-09 14:10:35 +04:00
, mCurrentStateSet ( nullptr )
2021-05-09 15:43:13 +04:00
, mCurrentDistance ( 0.f )
2021-09-21 20:39:31 +00:00
{ setTraversalMask ( analyzeMask ) ; }
2020-04-30 13:37:00 +00:00
typedef std : : unordered_map < osg : : StateSet * , unsigned int > StateSetCounter ;
struct Result
{
StateSetCounter mStateSetCounter ;
unsigned int mNumVerts = 0 ;
} ;
2020-10-16 22:18:54 +04:00
void apply ( osg : : Node & node ) override
2020-04-30 13:37:00 +00:00
{
if ( node . getStateSet ( ) )
mCurrentStateSet = node . getStateSet ( ) ;
2021-05-09 15:43:13 +04:00
if ( osg : : Switch * sw = node . asSwitch ( ) )
{
for ( unsigned int i = 0 ; i < sw - > getNumChildren ( ) ; + + i )
if ( sw - > getValue ( i ) )
traverse ( * sw - > getChild ( i ) ) ;
return ;
}
if ( osg : : LOD * lod = dynamic_cast < osg : : LOD * > ( & node ) )
{
for ( unsigned int i = 0 ; i < lod - > getNumChildren ( ) ; + + i )
if ( lod - > getMinRange ( i ) * lod - > getMinRange ( i ) < = mCurrentDistance & & mCurrentDistance < lod - > getMaxRange ( i ) * lod - > getMaxRange ( i ) )
traverse ( * lod - > getChild ( i ) ) ;
return ;
}
2022-03-29 21:47:37 +02:00
if ( osg : : Sequence * sq = dynamic_cast < osg : : Sequence * > ( & node ) )
{
2022-03-31 21:55:14 +02:00
traverse ( * sq - > getChild ( sq - > getValue ( ) ! = - 1 ? sq - > getValue ( ) : 0 ) ) ;
2022-03-29 21:47:37 +02:00
return ;
}
2021-05-09 15:43:13 +04:00
2020-04-30 13:37:00 +00:00
traverse ( node ) ;
}
2020-10-16 22:18:54 +04:00
void apply ( osg : : Geometry & geom ) override
2020-04-30 13:37:00 +00:00
{
2020-09-01 10:06:31 +04:00
if ( osg : : Array * array = geom . getVertexArray ( ) )
mResult . mNumVerts + = array - > getNumElements ( ) ;
2020-04-30 13:37:00 +00:00
+ + mResult . mStateSetCounter [ mCurrentStateSet ] ;
+ + mGlobalStateSetCounter [ mCurrentStateSet ] ;
}
Result retrieveResult ( )
{
Result result = mResult ;
mResult = Result ( ) ;
mCurrentStateSet = nullptr ;
return result ;
}
2020-05-06 13:37:00 +00:00
void addInstance ( const Result & result )
{
for ( auto pair : result . mStateSetCounter )
mGlobalStateSetCounter [ pair . first ] + = pair . second ;
}
2020-04-30 13:37:00 +00:00
float getMergeBenefit ( const Result & result )
{
if ( result . mStateSetCounter . empty ( ) ) return 1 ;
float mergeBenefit = 0 ;
for ( auto pair : result . mStateSetCounter )
{
mergeBenefit + = mGlobalStateSetCounter [ pair . first ] ;
}
mergeBenefit / = result . mStateSetCounter . size ( ) ;
return mergeBenefit ;
}
Result mResult ;
osg : : StateSet * mCurrentStateSet ;
StateSetCounter mGlobalStateSetCounter ;
2021-05-09 15:43:13 +04:00
float mCurrentDistance ;
2020-04-30 13:37:00 +00:00
} ;
2020-05-05 13:37:00 +00:00
class DebugVisitor : public osg : : NodeVisitor
{
public :
DebugVisitor ( ) : osg : : NodeVisitor ( TRAVERSE_ALL_CHILDREN ) { }
2020-10-16 22:18:54 +04:00
void apply ( osg : : Drawable & node ) override
2020-05-05 13:37:00 +00:00
{
osg : : ref_ptr < osg : : Material > m ( new osg : : Material ) ;
osg : : Vec4f color ( Misc : : Rng : : rollProbability ( ) , Misc : : Rng : : rollProbability ( ) , Misc : : Rng : : rollProbability ( ) , 0.f ) ;
color . normalize ( ) ;
m - > setDiffuse ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( 0.1f , 0.1f , 0.1f , 1.f ) ) ;
m - > setAmbient ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( 0.1f , 0.1f , 0.1f , 1.f ) ) ;
m - > setColorMode ( osg : : Material : : OFF ) ;
m - > setEmission ( osg : : Material : : FRONT_AND_BACK , osg : : Vec4f ( color ) ) ;
osg : : ref_ptr < osg : : StateSet > stateset = node . getStateSet ( ) ? osg : : clone ( node . getStateSet ( ) , osg : : CopyOp : : SHALLOW_COPY ) : new osg : : StateSet ;
stateset - > setAttribute ( m ) ;
stateset - > addUniform ( new osg : : Uniform ( " colorMode " , 0 ) ) ;
2021-07-11 23:03:55 -07:00
stateset - > addUniform ( new osg : : Uniform ( " emissiveMult " , 1.f ) ) ;
2021-11-10 19:58:06 +03:00
stateset - > addUniform ( new osg : : Uniform ( " specStrength " , 1.f ) ) ;
2020-05-05 13:37:00 +00:00
node . setStateSet ( stateset ) ;
}
} ;
2020-05-11 13:37:00 +00:00
class AddRefnumMarkerVisitor : public osg : : NodeVisitor
{
public :
AddRefnumMarkerVisitor ( const ESM : : RefNum & refnum ) : osg : : NodeVisitor ( TRAVERSE_ALL_CHILDREN ) , mRefnum ( refnum ) { }
ESM : : RefNum mRefnum ;
2020-10-16 22:18:54 +04:00
void apply ( osg : : Geometry & node ) override
2020-05-11 13:37:00 +00:00
{
osg : : ref_ptr < RefnumMarker > marker ( new RefnumMarker ) ;
marker - > mRefnum = mRefnum ;
if ( osg : : Array * array = node . getVertexArray ( ) )
marker - > mNumVertices = array - > getNumElements ( ) ;
node . getOrCreateUserDataContainer ( ) - > addUserObject ( marker ) ;
}
} ;
2019-06-13 13:37:00 +00:00
ObjectPaging : : ObjectPaging ( Resource : : SceneManager * sceneManager )
: GenericResourceManager < ChunkId > ( nullptr )
, mSceneManager ( sceneManager )
2020-05-12 13:37:00 +00:00
, mRefTrackerLocked ( false )
2019-06-13 13:37:00 +00:00
{
2020-05-10 13:37:00 +00:00
mActiveGrid = Settings : : Manager : : getBool ( " object paging active grid " , " Terrain " ) ;
2021-09-08 19:59:53 +02:00
mDebugBatches = Settings : : Manager : : getBool ( " debug chunks " , " Terrain " ) ;
2020-04-30 13:37:00 +00:00
mMergeFactor = Settings : : Manager : : getFloat ( " object paging merge factor " , " Terrain " ) ;
2019-06-13 13:37:00 +00:00
mMinSize = Settings : : Manager : : getFloat ( " object paging min size " , " Terrain " ) ;
2020-05-05 13:37:00 +00:00
mMinSizeMergeFactor = Settings : : Manager : : getFloat ( " object paging min size merge factor " , " Terrain " ) ;
mMinSizeCostMultiplier = Settings : : Manager : : getFloat ( " object paging min size cost multiplier " , " Terrain " ) ;
2019-06-13 13:37:00 +00:00
}
2020-05-10 13:37:00 +00:00
osg : : ref_ptr < osg : : Node > ObjectPaging : : createChunk ( float size , const osg : : Vec2f & center , bool activeGrid , const osg : : Vec3f & viewPoint , bool compile )
2019-06-13 13:37:00 +00:00
{
osg : : Vec2i startCell = osg : : Vec2i ( std : : floor ( center . x ( ) - size / 2.f ) , std : : floor ( center . y ( ) - size / 2.f ) ) ;
osg : : Vec3f worldCenter = osg : : Vec3f ( center . x ( ) , center . y ( ) , 0 ) * ESM : : Land : : REAL_SIZE ;
osg : : Vec3f relativeViewPoint = viewPoint - worldCenter ;
2019-08-03 13:37:00 +00:00
std : : map < ESM : : RefNum , ESM : : CellRef > refs ;
2019-06-13 13:37:00 +00:00
std : : vector < ESM : : ESMReader > esm ;
const MWWorld : : ESMStore & store = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) ;
2021-01-12 12:39:19 +04:00
2019-06-13 13:37:00 +00:00
for ( int cellX = startCell . x ( ) ; cellX < startCell . x ( ) + size ; + + cellX )
{
for ( int cellY = startCell . y ( ) ; cellY < startCell . y ( ) + size ; + + cellY )
{
const ESM : : Cell * cell = store . get < ESM : : Cell > ( ) . searchStatic ( cellX , cellY ) ;
if ( ! cell ) continue ;
for ( size_t i = 0 ; i < cell - > mContextList . size ( ) ; + + i )
{
try
{
2021-05-15 15:38:17 +02:00
unsigned int index = cell - > mContextList [ i ] . index ;
2019-06-13 13:37:00 +00:00
if ( esm . size ( ) < = index )
esm . resize ( index + 1 ) ;
cell - > restore ( esm [ index ] , i ) ;
ESM : : CellRef ref ;
2021-01-22 15:48:37 +01:00
ref . mRefNum . unset ( ) ;
2021-07-07 08:18:38 +10:00
ESM : : MovedCellRef cMRef ;
cMRef . mRefNum . mIndex = 0 ;
2019-06-13 13:37:00 +00:00
bool deleted = false ;
2021-07-12 17:30:39 +02:00
bool moved = false ;
2022-04-08 17:08:18 +02:00
while ( ESM : : Cell : : getNextRef ( esm [ index ] , ref , deleted , cMRef , moved , ESM : : Cell : : GetNextRefMode : : LoadOnlyNotMoved ) )
2019-06-13 13:37:00 +00:00
{
2021-07-12 17:30:39 +02:00
if ( moved )
continue ;
2021-07-07 08:18:38 +10:00
2022-04-08 00:54:41 +02:00
if ( std : : find ( cell - > mMovedRefs . begin ( ) , cell - > mMovedRefs . end ( ) , ref . mRefNum ) ! = cell - > mMovedRefs . end ( ) )
continue ;
Misc : : StringUtils : : lowerCaseInPlace ( ref . mRefID ) ;
2020-05-16 13:37:00 +00:00
int type = store . findStatic ( ref . mRefID ) ;
2020-05-11 13:37:00 +00:00
if ( ! typeFilter ( type , size > = 2 ) ) continue ;
2019-08-03 13:37:00 +00:00
if ( deleted ) { refs . erase ( ref . mRefNum ) ; continue ; }
2021-05-15 02:29:50 +02:00
refs [ ref . mRefNum ] = std : : move ( ref ) ;
2019-06-13 13:37:00 +00:00
}
}
2021-04-19 15:43:00 +04:00
catch ( std : : exception & )
2019-06-13 13:37:00 +00:00
{
continue ;
}
}
2021-05-16 09:40:41 +02:00
for ( auto [ ref , deleted ] : cell - > mLeasedRefs )
2019-06-13 13:37:00 +00:00
{
2022-04-08 00:54:41 +02:00
if ( deleted )
{
refs . erase ( ref . mRefNum ) ;
continue ;
}
Misc : : StringUtils : : lowerCaseInPlace ( ref . mRefID ) ;
2020-05-16 13:37:00 +00:00
int type = store . findStatic ( ref . mRefID ) ;
2020-05-11 13:37:00 +00:00
if ( ! typeFilter ( type , size > = 2 ) ) continue ;
2021-05-15 02:29:50 +02:00
refs [ ref . mRefNum ] = std : : move ( ref ) ;
2019-06-13 13:37:00 +00:00
}
}
}
2020-05-16 13:37:00 +00:00
if ( activeGrid )
2019-08-03 13:37:00 +00:00
{
2020-06-25 21:46:07 +02:00
std : : lock_guard < std : : mutex > lock ( mRefTrackerMutex ) ;
2020-05-16 13:37:00 +00:00
for ( auto ref : getRefTracker ( ) . mBlacklist )
refs . erase ( ref ) ;
2019-08-03 13:37:00 +00:00
}
2019-06-13 13:37:00 +00:00
osg : : Vec2f minBound = ( center - osg : : Vec2f ( size / 2.f , size / 2.f ) ) ;
osg : : Vec2f maxBound = ( center + osg : : Vec2f ( size / 2.f , size / 2.f ) ) ;
2020-04-30 13:37:00 +00:00
struct InstanceList
{
std : : vector < const ESM : : CellRef * > mInstances ;
AnalyzeVisitor : : Result mAnalyzeResult ;
2020-05-05 13:37:00 +00:00
bool mNeedCompile = false ;
2020-04-30 13:37:00 +00:00
} ;
typedef std : : map < osg : : ref_ptr < const osg : : Node > , InstanceList > NodeMap ;
NodeMap nodes ;
2020-05-10 13:37:00 +00:00
osg : : ref_ptr < RefnumSet > refnumSet = activeGrid ? new RefnumSet : nullptr ;
2021-05-09 14:10:35 +04:00
// Mask_UpdateVisitor is used in such cases in NIF loader:
// 1. For collision nodes, which is not supposed to be rendered.
// 2. For nodes masked via Flag_Hidden (VisController can change this flag value at runtime).
// Since ObjectPaging does not handle VisController, we can just ignore both types of nodes.
constexpr auto copyMask = ~ Mask_UpdateVisitor ;
AnalyzeVisitor analyzeVisitor ( copyMask ) ;
2021-07-10 19:04:46 +02:00
analyzeVisitor . mCurrentDistance = ( viewPoint - worldCenter ) . length2 ( ) ;
2020-05-05 13:37:00 +00:00
float minSize = mMinSize ;
if ( mMinSizeMergeFactor )
minSize * = mMinSizeMergeFactor ;
2019-08-03 13:37:00 +00:00
for ( const auto & pair : refs )
2019-06-13 13:37:00 +00:00
{
2019-08-03 13:37:00 +00:00
const ESM : : CellRef & ref = pair . second ;
2019-06-13 13:37:00 +00:00
osg : : Vec3f pos = ref . mPos . asVec3 ( ) ;
if ( size < 1.f )
{
osg : : Vec3f cellPos = pos / ESM : : Land : : REAL_SIZE ;
2020-05-16 13:37:00 +00:00
if ( ( minBound . x ( ) > std : : floor ( minBound . x ( ) ) & & cellPos . x ( ) < minBound . x ( ) ) | | ( minBound . y ( ) > std : : floor ( minBound . y ( ) ) & & cellPos . y ( ) < minBound . y ( ) )
2021-08-09 22:05:12 +02:00
| | ( maxBound . x ( ) < std : : ceil ( maxBound . x ( ) ) & & cellPos . x ( ) > = maxBound . x ( ) ) | | ( maxBound . y ( ) < std : : ceil ( maxBound . y ( ) ) & & cellPos . y ( ) > = maxBound . y ( ) ) )
2019-06-13 13:37:00 +00:00
continue ;
}
2020-05-15 13:37:00 +00:00
float dSqr = ( viewPoint - pos ) . length2 ( ) ;
2020-05-11 13:37:00 +00:00
if ( ! activeGrid )
2020-05-04 13:37:00 +00:00
{
2020-06-25 21:46:07 +02:00
std : : lock_guard < std : : mutex > lock ( mSizeCacheMutex ) ;
2020-05-04 13:37:00 +00:00
SizeCache : : iterator found = mSizeCache . find ( pair . first ) ;
2020-05-16 13:37:00 +00:00
if ( found ! = mSizeCache . end ( ) & & found - > second < dSqr * minSize * minSize )
continue ;
2020-05-04 13:37:00 +00:00
}
2021-06-29 03:47:23 +02:00
if ( Misc : : ResourceHelpers : : isHiddenMarker ( ref . mRefID ) )
continue ;
2019-06-13 13:37:00 +00:00
2020-05-16 13:37:00 +00:00
int type = store . findStatic ( ref . mRefID ) ;
std : : string model = getModel ( type , ref . mRefID , store ) ;
2020-04-30 13:37:00 +00:00
if ( model . empty ( ) ) continue ;
model = " meshes/ " + model ;
2020-05-11 13:37:00 +00:00
2020-05-16 13:37:00 +00:00
if ( activeGrid & & type ! = ESM : : REC_STAT )
2020-05-11 13:37:00 +00:00
{
2020-04-30 13:37:00 +00:00
model = Misc : : ResourceHelpers : : correctActorModelPath ( model , mSceneManager - > getVFS ( ) ) ;
2020-05-16 13:37:00 +00:00
std : : string kfname = Misc : : StringUtils : : lowerCase ( model ) ;
if ( kfname . size ( ) > 4 & & kfname . compare ( kfname . size ( ) - 4 , 4 , " .nif " ) = = 0 )
2020-05-11 13:37:00 +00:00
{
2020-05-16 13:37:00 +00:00
kfname . replace ( kfname . size ( ) - 4 , 4 , " .kf " ) ;
if ( mSceneManager - > getVFS ( ) - > exists ( kfname ) )
continue ;
2020-05-11 13:37:00 +00:00
}
}
2020-05-05 13:37:00 +00:00
osg : : ref_ptr < const osg : : Node > cnode = mSceneManager - > getTemplate ( model , false ) ;
2019-06-13 13:37:00 +00:00
2020-05-11 13:37:00 +00:00
if ( activeGrid )
2020-05-11 13:37:00 +00:00
{
if ( cnode - > getNumChildrenRequiringUpdateTraversal ( ) > 0 | | SceneUtil : : hasUserDescription ( cnode , Constants : : NightDayLabel ) | | SceneUtil : : hasUserDescription ( cnode , Constants : : HerbalismLabel ) )
continue ;
else
refnumSet - > mRefnums . insert ( pair . first ) ;
}
2020-05-11 13:37:00 +00:00
{
2020-06-25 21:46:07 +02:00
std : : lock_guard < std : : mutex > lock ( mRefTrackerMutex ) ;
2020-05-12 13:37:00 +00:00
if ( getRefTracker ( ) . mDisabled . count ( pair . first ) )
2020-05-11 13:37:00 +00:00
continue ;
}
2020-05-15 13:37:00 +00:00
float radius2 = cnode - > getBound ( ) . radius2 ( ) * ref . mScale * ref . mScale ;
2020-05-16 13:37:00 +00:00
if ( radius2 < dSqr * minSize * minSize & & ! activeGrid )
2020-05-04 13:37:00 +00:00
{
2020-06-25 21:46:07 +02:00
std : : lock_guard < std : : mutex > lock ( mSizeCacheMutex ) ;
2020-05-16 13:37:00 +00:00
mSizeCache [ pair . first ] = radius2 ;
2019-06-13 13:37:00 +00:00
continue ;
2020-05-04 13:37:00 +00:00
}
2019-06-13 13:37:00 +00:00
2020-04-30 13:37:00 +00:00
auto emplaced = nodes . emplace ( cnode , InstanceList ( ) ) ;
if ( emplaced . second )
{
2020-05-03 13:37:00 +00:00
const_cast < osg : : Node * > ( cnode . get ( ) ) - > accept ( analyzeVisitor ) ; // const-trickery required because there is no const version of NodeVisitor
2020-04-30 13:37:00 +00:00
emplaced . first - > second . mAnalyzeResult = analyzeVisitor . retrieveResult ( ) ;
2020-05-05 13:37:00 +00:00
emplaced . first - > second . mNeedCompile = compile & & cnode - > referenceCount ( ) < = 3 ;
2020-04-30 13:37:00 +00:00
}
2020-05-06 13:37:00 +00:00
else
analyzeVisitor . addInstance ( emplaced . first - > second . mAnalyzeResult ) ;
2020-04-30 13:37:00 +00:00
emplaced . first - > second . mInstances . push_back ( & ref ) ;
2019-06-13 13:37:00 +00:00
}
2020-04-30 13:37:00 +00:00
osg : : ref_ptr < osg : : Group > group = new osg : : Group ;
osg : : ref_ptr < osg : : Group > mergeGroup = new osg : : Group ;
2021-01-13 13:33:46 +04:00
osg : : ref_ptr < Resource : : TemplateMultiRef > templateRefs = new Resource : : TemplateMultiRef ;
2020-05-05 13:37:00 +00:00
osgUtil : : StateToCompile stateToCompile ( 0 , nullptr ) ;
2020-05-16 13:37:00 +00:00
CopyOp copyop ;
2021-05-09 14:10:35 +04:00
copyop . mCopyMask = copyMask ;
2020-04-30 13:37:00 +00:00
for ( const auto & pair : nodes )
{
const osg : : Node * cnode = pair . first ;
const AnalyzeVisitor : : Result & analyzeResult = pair . second . mAnalyzeResult ;
float mergeCost = analyzeResult . mNumVerts * size ;
float mergeBenefit = analyzeVisitor . getMergeBenefit ( analyzeResult ) * mMergeFactor ;
bool merge = mergeBenefit > mergeCost ;
2020-05-05 13:37:00 +00:00
float minSizeMerged = mMinSize ;
float factor2 = mergeBenefit > 0 ? std : : min ( 1.f , mergeCost * mMinSizeCostMultiplier / mergeBenefit ) : 1 ;
float minSizeMergeFactor2 = ( 1 - factor2 ) * mMinSizeMergeFactor + factor2 ;
if ( minSizeMergeFactor2 > 0 )
minSizeMerged * = minSizeMergeFactor2 ;
2020-05-05 13:37:00 +00:00
2020-05-05 13:37:00 +00:00
unsigned int numinstances = 0 ;
2020-04-30 13:37:00 +00:00
for ( auto cref : pair . second . mInstances )
{
const ESM : : CellRef & ref = * cref ;
osg : : Vec3f pos = ref . mPos . asVec3 ( ) ;
2020-05-16 13:37:00 +00:00
if ( ! activeGrid & & minSizeMerged ! = minSize & & cnode - > getBound ( ) . radius2 ( ) * cref - > mScale * cref - > mScale < ( viewPoint - pos ) . length2 ( ) * minSizeMerged * minSizeMerged )
2020-05-15 13:37:00 +00:00
continue ;
2020-05-05 13:37:00 +00:00
2021-10-11 08:09:01 +00:00
osg : : Vec3f nodePos = pos - worldCenter ;
osg : : Quat nodeAttitude = osg : : Quat ( ref . mPos . rot [ 2 ] , osg : : Vec3f ( 0 , 0 , - 1 ) ) *
2020-04-30 13:37:00 +00:00
osg : : Quat ( ref . mPos . rot [ 1 ] , osg : : Vec3f ( 0 , - 1 , 0 ) ) *
2021-10-11 08:09:01 +00:00
osg : : Quat ( ref . mPos . rot [ 0 ] , osg : : Vec3f ( - 1 , 0 , 0 ) ) ;
osg : : Vec3f nodeScale = osg : : Vec3f ( ref . mScale , ref . mScale , ref . mScale ) ;
osg : : ref_ptr < osg : : Group > trans ;
if ( merge )
{
// Optimizer currently supports only MatrixTransforms.
osg : : Matrixf matrix ;
matrix . preMultTranslate ( nodePos ) ;
matrix . preMultRotate ( nodeAttitude ) ;
matrix . preMultScale ( nodeScale ) ;
trans = new osg : : MatrixTransform ( matrix ) ;
trans - > setDataVariance ( osg : : Object : : STATIC ) ;
}
else
{
trans = new SceneUtil : : PositionAttitudeTransform ;
SceneUtil : : PositionAttitudeTransform * pat = static_cast < SceneUtil : : PositionAttitudeTransform * > ( trans . get ( ) ) ;
pat - > setPosition ( nodePos ) ;
pat - > setScale ( nodeScale ) ;
pat - > setAttitude ( nodeAttitude ) ;
}
2020-04-30 13:37:00 +00:00
2021-10-23 08:31:46 +00:00
// DO NOT COPY AND PASTE THIS CODE. Cloning osg::Geometry without also cloning its contained Arrays is generally unsafe.
// In this specific case the operation is safe under the following two assumptions:
// - When Arrays are removed or replaced in the cloned geometry, the original Arrays in their place must outlive the cloned geometry regardless. (ensured by TemplateMultiRef)
// - Arrays that we add or replace in the cloned geometry must be explicitely forbidden from reusing BufferObjects of the original geometry. (ensured by needvbo() in optimizer.cpp)
2020-05-16 13:37:00 +00:00
copyop . setCopyFlags ( merge ? osg : : CopyOp : : DEEP_COPY_NODES | osg : : CopyOp : : DEEP_COPY_DRAWABLES : osg : : CopyOp : : DEEP_COPY_NODES ) ;
copyop . mOptimizeBillboards = ( size > 1 / 4.f ) ;
copyop . mNodePath . push_back ( trans ) ;
copyop . mSqrDistance = ( viewPoint - pos ) . length2 ( ) ;
copyop . mViewVector = ( viewPoint - worldCenter ) ;
copyop . copy ( cnode , trans ) ;
2020-06-18 16:16:16 +02:00
copyop . mNodePath . pop_back ( ) ;
2020-05-04 13:37:00 +00:00
2020-05-11 13:37:00 +00:00
if ( activeGrid )
{
if ( merge )
{
AddRefnumMarkerVisitor visitor ( ref . mRefNum ) ;
2020-05-16 13:37:00 +00:00
trans - > accept ( visitor ) ;
2020-05-11 13:37:00 +00:00
}
else
{
osg : : ref_ptr < RefnumMarker > marker = new RefnumMarker ; marker - > mRefnum = ref . mRefNum ;
2020-05-16 13:37:00 +00:00
trans - > getOrCreateUserDataContainer ( ) - > addUserObject ( marker ) ;
2020-05-11 13:37:00 +00:00
}
}
2020-05-16 13:37:00 +00:00
osg : : Group * attachTo = merge ? mergeGroup : group ;
attachTo - > addChild ( trans ) ;
2020-05-05 13:37:00 +00:00
+ + numinstances ;
}
if ( numinstances > 0 )
{
2021-10-23 08:31:46 +00:00
// add a ref to the original template to help verify the safety of shallow cloning operations
// in addition, we hint to the cache that it's still being used and should be kept in cache
2021-01-13 13:33:46 +04:00
templateRefs - > addRef ( cnode ) ;
2020-05-05 13:37:00 +00:00
if ( pair . second . mNeedCompile )
{
int mode = osgUtil : : GLObjectsVisitor : : COMPILE_STATE_ATTRIBUTES ;
if ( ! merge )
mode | = osgUtil : : GLObjectsVisitor : : COMPILE_DISPLAY_LISTS ;
stateToCompile . _mode = mode ;
const_cast < osg : : Node * > ( cnode ) - > accept ( stateToCompile ) ;
}
2020-04-30 13:37:00 +00:00
}
}
if ( mergeGroup - > getNumChildren ( ) )
2019-06-13 13:37:00 +00:00
{
SceneUtil : : Optimizer optimizer ;
2020-05-16 13:37:00 +00:00
if ( size > 1 / 8.f )
2019-06-13 13:37:00 +00:00
{
optimizer . setViewPoint ( relativeViewPoint ) ;
optimizer . setMergeAlphaBlending ( true ) ;
}
optimizer . setIsOperationPermissibleForObjectCallback ( new CanOptimizeCallback ) ;
unsigned int options = SceneUtil : : Optimizer : : FLATTEN_STATIC_TRANSFORMS | SceneUtil : : Optimizer : : REMOVE_REDUNDANT_NODES | SceneUtil : : Optimizer : : MERGE_GEOMETRY ;
2021-09-27 18:41:24 +00:00
2020-04-30 13:37:00 +00:00
optimizer . optimize ( mergeGroup , options ) ;
group - > addChild ( mergeGroup ) ;
2019-06-13 13:37:00 +00:00
2020-05-05 13:37:00 +00:00
if ( mDebugBatches )
{
DebugVisitor dv ;
mergeGroup - > accept ( dv ) ;
}
2020-05-12 13:37:00 +00:00
if ( compile )
{
stateToCompile . _mode = osgUtil : : GLObjectsVisitor : : COMPILE_DISPLAY_LISTS ;
mergeGroup - > accept ( stateToCompile ) ;
}
2020-04-30 13:37:00 +00:00
}
2019-06-13 13:37:00 +00:00
2020-05-05 13:37:00 +00:00
auto ico = mSceneManager - > getIncrementalCompileOperation ( ) ;
if ( ! stateToCompile . empty ( ) & & ico )
{
auto compileSet = new osgUtil : : IncrementalCompileOperation : : CompileSet ( group ) ;
compileSet - > buildCompileMap ( ico - > getContextSet ( ) , stateToCompile ) ;
ico - > add ( compileSet , false ) ;
}
2020-04-30 13:37:00 +00:00
group - > getBound ( ) ;
2019-06-13 13:37:00 +00:00
group - > setNodeMask ( Mask_Static ) ;
2020-05-10 13:37:00 +00:00
osg : : UserDataContainer * udc = group - > getOrCreateUserDataContainer ( ) ;
if ( activeGrid )
{
udc - > addUserObject ( refnumSet ) ;
group - > addCullCallback ( new SceneUtil : : LightListCallback ) ;
}
udc - > addUserObject ( templateRefs ) ;
2020-04-30 13:37:00 +00:00
2019-06-13 13:37:00 +00:00
return group ;
}
unsigned int ObjectPaging : : getNodeMask ( )
{
return Mask_Static ;
}
2020-05-08 13:37:00 +00:00
struct ClearCacheFunctor
2019-08-03 13:37:00 +00:00
{
2020-05-08 13:37:00 +00:00
void operator ( ) ( MWRender : : ChunkId id , osg : : Object * obj )
{
if ( intersects ( id , mPosition ) )
mToClear . insert ( id ) ;
}
bool intersects ( ChunkId id , osg : : Vec3f pos )
{
2020-05-11 13:37:00 +00:00
if ( mActiveGridOnly & & ! std : : get < 2 > ( id ) ) return false ;
2020-05-08 13:37:00 +00:00
pos / = ESM : : Land : : REAL_SIZE ;
2020-07-09 23:17:01 +02:00
clampToCell ( pos ) ;
2020-05-08 13:37:00 +00:00
osg : : Vec2f center = std : : get < 0 > ( id ) ;
float halfSize = std : : get < 1 > ( id ) / 2 ;
return pos . x ( ) > = center . x ( ) - halfSize & & pos . y ( ) > = center . y ( ) - halfSize & & pos . x ( ) < = center . x ( ) + halfSize & & pos . y ( ) < = center . y ( ) + halfSize ;
}
2020-07-09 23:17:01 +02:00
void clampToCell ( osg : : Vec3f & cellPos )
{
2021-11-06 07:30:28 +03:00
cellPos . x ( ) = std : : clamp < float > ( cellPos . x ( ) , mCell . x ( ) , mCell . x ( ) + 1 ) ;
cellPos . y ( ) = std : : clamp < float > ( cellPos . y ( ) , mCell . y ( ) , mCell . y ( ) + 1 ) ;
2020-07-09 23:17:01 +02:00
}
2020-05-08 13:37:00 +00:00
osg : : Vec3f mPosition ;
2020-07-09 23:17:01 +02:00
osg : : Vec2i mCell ;
2020-05-08 13:37:00 +00:00
std : : set < MWRender : : ChunkId > mToClear ;
2020-05-11 13:37:00 +00:00
bool mActiveGridOnly = false ;
2020-05-08 13:37:00 +00:00
} ;
2020-07-09 23:17:01 +02:00
bool ObjectPaging : : enableObject ( int type , const ESM : : RefNum & refnum , const osg : : Vec3f & pos , const osg : : Vec2i & cell , bool enabled )
2020-05-08 13:37:00 +00:00
{
2020-05-11 13:37:00 +00:00
if ( ! typeFilter ( type , false ) )
2020-05-08 13:37:00 +00:00
return false ;
{
2020-06-25 21:46:07 +02:00
std : : lock_guard < std : : mutex > lock ( mRefTrackerMutex ) ;
2020-05-12 13:37:00 +00:00
if ( enabled & & ! getWritableRefTracker ( ) . mDisabled . erase ( refnum ) ) return false ;
if ( ! enabled & & ! getWritableRefTracker ( ) . mDisabled . insert ( refnum ) . second ) return false ;
if ( mRefTrackerLocked ) return false ;
2020-05-08 13:37:00 +00:00
}
ClearCacheFunctor ccf ;
ccf . mPosition = pos ;
2020-07-09 23:17:01 +02:00
ccf . mCell = cell ;
2020-05-08 13:37:00 +00:00
mCache - > call ( ccf ) ;
2020-05-12 13:37:00 +00:00
if ( ccf . mToClear . empty ( ) ) return false ;
2021-05-15 19:50:01 +02:00
for ( const auto & chunk : ccf . mToClear )
2020-05-08 13:37:00 +00:00
mCache - > removeFromObjectCache ( chunk ) ;
return true ;
2019-08-03 13:37:00 +00:00
}
2020-07-09 23:17:01 +02:00
bool ObjectPaging : : blacklistObject ( int type , const ESM : : RefNum & refnum , const osg : : Vec3f & pos , const osg : : Vec2i & cell )
2020-05-11 13:37:00 +00:00
{
2020-05-11 13:37:00 +00:00
if ( ! typeFilter ( type , false ) )
2020-05-11 13:37:00 +00:00
return false ;
{
2020-06-25 21:46:07 +02:00
std : : lock_guard < std : : mutex > lock ( mRefTrackerMutex ) ;
2020-05-12 13:37:00 +00:00
if ( ! getWritableRefTracker ( ) . mBlacklist . insert ( refnum ) . second ) return false ;
if ( mRefTrackerLocked ) return false ;
2020-05-11 13:37:00 +00:00
}
ClearCacheFunctor ccf ;
ccf . mPosition = pos ;
2020-07-09 23:17:01 +02:00
ccf . mCell = cell ;
2020-05-11 13:37:00 +00:00
ccf . mActiveGridOnly = true ;
mCache - > call ( ccf ) ;
if ( ccf . mToClear . empty ( ) ) return false ;
2021-05-15 19:50:01 +02:00
for ( const auto & chunk : ccf . mToClear )
2020-05-11 13:37:00 +00:00
mCache - > removeFromObjectCache ( chunk ) ;
return true ;
}
2019-08-03 13:37:00 +00:00
void ObjectPaging : : clear ( )
{
2020-06-25 21:46:07 +02:00
std : : lock_guard < std : : mutex > lock ( mRefTrackerMutex ) ;
2020-05-12 13:37:00 +00:00
mRefTrackerNew . mDisabled . clear ( ) ;
mRefTrackerNew . mBlacklist . clear ( ) ;
mRefTrackerLocked = true ;
}
bool ObjectPaging : : unlockCache ( )
{
if ( ! mRefTrackerLocked ) return false ;
2020-05-08 13:37:00 +00:00
{
2020-06-25 21:46:07 +02:00
std : : lock_guard < std : : mutex > lock ( mRefTrackerMutex ) ;
2020-05-12 13:37:00 +00:00
mRefTrackerLocked = false ;
if ( mRefTracker = = mRefTrackerNew )
return false ;
else
mRefTracker = mRefTrackerNew ;
2020-05-08 13:37:00 +00:00
}
mCache - > clear ( ) ;
2020-05-12 13:37:00 +00:00
return true ;
2019-08-03 13:37:00 +00:00
}
2020-05-04 13:37:00 +00:00
2020-05-10 13:37:00 +00:00
struct GetRefnumsFunctor
{
GetRefnumsFunctor ( std : : set < ESM : : RefNum > & output ) : mOutput ( output ) { }
void operator ( ) ( MWRender : : ChunkId chunkId , osg : : Object * obj )
{
if ( ! std : : get < 2 > ( chunkId ) ) return ;
const osg : : Vec2f & center = std : : get < 0 > ( chunkId ) ;
bool activeGrid = ( center . x ( ) > mActiveGrid . x ( ) | | center . y ( ) > mActiveGrid . y ( ) | | center . x ( ) < mActiveGrid . z ( ) | | center . y ( ) < mActiveGrid . w ( ) ) ;
if ( ! activeGrid ) return ;
osg : : UserDataContainer * udc = obj - > getUserDataContainer ( ) ;
if ( udc & & udc - > getNumUserObjects ( ) )
{
RefnumSet * refnums = dynamic_cast < RefnumSet * > ( udc - > getUserObject ( 0 ) ) ;
if ( ! refnums ) return ;
mOutput . insert ( refnums - > mRefnums . begin ( ) , refnums - > mRefnums . end ( ) ) ;
}
}
osg : : Vec4i mActiveGrid ;
std : : set < ESM : : RefNum > & mOutput ;
} ;
void ObjectPaging : : getPagedRefnums ( const osg : : Vec4i & activeGrid , std : : set < ESM : : RefNum > & out )
{
GetRefnumsFunctor grf ( out ) ;
grf . mActiveGrid = activeGrid ;
mCache - > call ( grf ) ;
}
2020-05-04 13:37:00 +00:00
void ObjectPaging : : reportStats ( unsigned int frameNumber , osg : : Stats * stats ) const
{
stats - > setAttribute ( frameNumber , " Object Chunk " , mCache - > getCacheSize ( ) ) ;
}
2019-06-13 13:37:00 +00:00
}