DYT/Tool/OpenSceneGraph-3.6.5/include/osgEarth/Revisioning
2024-12-25 07:49:36 +08:00

188 lines
6.0 KiB
C++

/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2020 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef OSGEARTH_REVISIONING_H
#define OSGEARTH_REVISIONING_H 1
#include <osgEarth/Common>
#include <osg/observer_ptr>
#include <vector>
#include <atomic>
namespace osgEarth { namespace Util
{
/**
* A tracking revision. See "class Revisioned" below for details.
*/
struct Revision // header-only; no export
{
Revision() : _value(-1) { }
Revision(int init) : _value(init) { }
void reset() { _value = -1; }
operator int() const { return _value; }
int operator ++() { return ++_value; }
int operator --() { return --_value; }
private:
int _value;
};
/**
* Base class for a revisioned object. A Revisioned object is one that keeps track
* of its state with a version number. Other objects can then hold a Revision object
* (see above) and use it to see if they are up to date with this object, thereby
* enabling passive data model synchronization.
*
* A Revisioned object is useful in the case where one or many objects want to
* track the state of a single object. If you want the opposite - where one
* object tracks the state of a multitude (or a hierarchy) of data model objects,
* use TrackDirty instead.
*/
class Revisioned /* no export; header-only */
{
public:
/**
* Marks this object as dirty by increasing the revision number.
* If the object has parents, it will mark those dirty as well.
*/
void dirty()
{
++_revision;
}
/**
* Synchronizes the external revision number with this revision, effectively
* bringing the external object up to date.
*/
virtual void sync( Revision& externalRevision ) const
{
externalRevision = _revision;
}
/**
* Returns true if the external object is at a different revision that this object.
*/
bool outOfSyncWith( const Revision& externalRevision) const
{
return !inSyncWith( externalRevision );
}
/**
* Returns true if the external object is at the same revision as this object.
*/
virtual bool inSyncWith( const Revision& externalRevision ) const
{
return _alwaysDirty ? false : _revision == externalRevision;
}
Revisioned() : _alwaysDirty(false) { }
/** dtor */
virtual ~Revisioned() { }
/** Marks this object as always being dirty (i.e. inSyncWith() will always return false) */
void setAlwaysDirty( bool value )
{
_alwaysDirty = value;
}
private:
Revision _revision;
bool _alwaysDirty;
};
/**
* A DirtyNotifier object is an object that can mark itself, and optionally
* its dependent parents, dirty. This is analagous to OSG's "dirtyBound"
* concept that can propagate up through a scene graph.
*
* The use case is when you want to detect changes somewhere in an object
* group or hierarchy, and then update something based on the modular
* changes. This is the opposite of the Revisioned pattern (in which many
* objects are tracking the state of one.)
*
* Note: objects always start out dirty.
*/
class OSGEARTH_EXPORT DirtyNotifier
{
public:
DirtyNotifier();
virtual ~DirtyNotifier() { }
/**
* Marks the object dirty and notifies parents
*/
virtual void setDirty();
/**
* Marks the object not dirty.
*/
virtual void resetDirty() { _counter->_count = 0; }
/**
* Is this object dirty?
*/
virtual bool isDirty() const { return _counter->_count > 0; }
/**
* Adds a dependent parent that will be dirtied if this object if dirtied.
*/
virtual void addParent( DirtyNotifier* parent );
/**
* Removes a dependent parent previously added by addParent.
*/
virtual void removeParent( DirtyNotifier* parent );
private:
// this pattern is used to we can track parents with an observer pointer.
struct DirtyCounter : public osg::Referenced
{
DirtyCounter(DirtyNotifier* owner) : _owner(owner), _count(1) { }
DirtyNotifier* _owner;
int _count;
};
osg::ref_ptr<DirtyCounter> _counter;
std::vector< osg::observer_ptr<DirtyCounter> > _parents;
};
/**
* A simple but thread-safe "dirty" object that support only one client.
*/
template<typename T>
struct SimpleMutable
{
SimpleMutable() : _dirty(1) { }
SimpleMutable(const T& value) : _value(value), _dirty(1) { }
operator const T&() const { return _value; }
const T* operator ->() const { return &_value; }
SimpleMutable& operator = (const T& value) { _value = value; _dirty.exchange(1); return *this; }
bool changed(bool reset=true) const { unsigned r = reset? _dirty.exchange(0) : (unsigned)_dirty; return r==1; }
void clean() { _dirty.exchange(0); }
private:
T _value;
mutable std::atomic_int _dirty;
};
} }
#endif // OSGEARTH_REVISIONING_H