1 // 2 // Copyright 2016 Pixar 3 // 4 // Licensed under the Apache License, Version 2.0 (the "Apache License") 5 // with the following modification; you may not use this file except in 6 // compliance with the Apache License and the following modification to it: 7 // Section 6. Trademarks. is deleted and replaced with: 8 // 9 // 6. Trademarks. This License does not grant permission to use the trade 10 // names, trademarks, service marks, or product names of the Licensor 11 // and its affiliates, except as required to comply with Section 4(c) of 12 // the License and to reproduce the content of the NOTICE file. 13 // 14 // You may obtain a copy of the Apache License at 15 // 16 // http://www.apache.org/licenses/LICENSE-2.0 17 // 18 // Unless required by applicable law or agreed to in writing, software 19 // distributed under the Apache License with the above modification is 20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 // KIND, either express or implied. See the Apache License for the specific 22 // language governing permissions and limitations under the Apache License. 23 // 24 #ifndef PXR_USD_USD_NOTICE_H 25 #define PXR_USD_USD_NOTICE_H 26 27 #include "pxr/pxr.h" 28 #include "pxr/usd/usd/api.h" 29 #include "pxr/usd/usd/common.h" 30 #include "pxr/usd/usd/object.h" 31 32 #include "pxr/usd/sdf/changeList.h" 33 #include "pxr/usd/sdf/path.h" 34 #include "pxr/base/tf/notice.h" 35 36 PXR_NAMESPACE_OPEN_SCOPE 37 38 39 /// \class UsdNotice 40 /// 41 /// Container class for Usd notices 42 /// 43 class UsdNotice { 44 public: 45 46 /// Base class for UsdStage notices. 47 class StageNotice : public TfNotice { 48 public: 49 USD_API 50 StageNotice(const UsdStageWeakPtr &stage); 51 USD_API 52 virtual ~StageNotice(); 53 54 /// Return the stage associated with this notice. GetStage()55 const UsdStageWeakPtr &GetStage() const { return _stage; } 56 57 private: 58 UsdStageWeakPtr _stage; 59 }; 60 61 /// \class StageContentsChanged 62 /// 63 /// Ultra-conservative notice sent when the given UsdStage's contents 64 /// have changed in any way. This notice is sent when \em any authoring 65 /// is performed in any of the stage's participatory layers, in the 66 /// thread performing the authoring, \em after the affected UsdStage 67 /// has reconfigured itself in response to the authored changes. 68 /// 69 /// Receipt of this notice should cause clients to disregard any cached 70 /// values for properties or metadata. It does not \em necessarily imply 71 /// invalidation of UsdPrim s. 72 /// 73 class StageContentsChanged : public StageNotice { 74 public: StageContentsChanged(const UsdStageWeakPtr & stage)75 explicit StageContentsChanged(const UsdStageWeakPtr& stage) 76 : StageNotice(stage) {} 77 USD_API virtual ~StageContentsChanged(); 78 }; 79 80 /// \class ObjectsChanged 81 /// 82 /// Notice sent in response to authored changes that affect UsdObjects. 83 /// 84 /// The kinds of object changes are divided into two categories: "resync" 85 /// and "changed-info". "Resyncs" are potentially structural changes that 86 /// invalidate entire subtrees of UsdObjects (including prims and 87 /// properties). For example, if the path "/foo" is resynced, then all 88 /// subpaths like "/foo/bar" and "/foo/bar.baz" may be arbitrarily changed. 89 /// In contrast, "changed-info" means that a nonstructural change has 90 /// occurred, like an attribute value change or a value change to a metadata 91 /// field not related to composition. 92 /// 93 /// When a prim is resynced, say "/foo/bar", it might have been created or 94 /// destroyed. In that case "/foo"'s list of children will have changed, 95 /// but we *do not* consider "/foo" to be resynced. If we did, it would 96 /// mean clients would have to consider all of "/foo/bar"'s siblings (and 97 /// their descendants) to be resynced which might be egregious 98 /// overinvalidation. 99 /// 100 /// This notice provides API for two client use-cases. Clients interested 101 /// in testing whether specific objects are affected by the changes should 102 /// use the AffectedObject() method (and the ResyncedObject() and 103 /// ChangedInfoOnly() methods). Clients that wish to reason about all 104 /// changes as a whole should use the GetResyncedPaths() and 105 /// GetChangedInfoOnlyPaths() methods. 106 /// 107 class ObjectsChanged : public StageNotice { 108 using _PathsToChangesMap = 109 std::map<SdfPath, std::vector<const SdfChangeList::Entry*>>; 110 111 friend class UsdStage; ObjectsChanged(const UsdStageWeakPtr & stage,const _PathsToChangesMap * resyncChanges,const _PathsToChangesMap * infoChanges)112 ObjectsChanged(const UsdStageWeakPtr &stage, 113 const _PathsToChangesMap *resyncChanges, 114 const _PathsToChangesMap *infoChanges) 115 : StageNotice(stage) 116 , _resyncChanges(resyncChanges) 117 , _infoChanges(infoChanges) {} 118 public: 119 USD_API virtual ~ObjectsChanged(); 120 121 /// Return true if \p obj was possibly affected by the layer changes 122 /// that generated this notice. This is the case if either the object 123 /// is subject to a resync or has changed info. Equivalent to: 124 /// \code 125 /// ResyncedObject(obj) or ChangedInfoOnly(obj) 126 /// \endcode AffectedObject(const UsdObject & obj)127 bool AffectedObject(const UsdObject &obj) const { 128 return ResyncedObject(obj) || ChangedInfoOnly(obj); 129 } 130 131 /// Return true if \p obj was resynced by the layer changes that 132 /// generated this notice. This is the case if the object's path or an 133 /// ancestor path is present in GetResyncedPrimPaths(). 134 USD_API bool ResyncedObject(const UsdObject &obj) const; 135 136 /// Return true if \p obj was changed but not resynced by the layer 137 /// changes that generated this notice. 138 USD_API bool ChangedInfoOnly(const UsdObject &obj) const; 139 140 /// \class PathRange 141 /// An iterable range of paths to objects that have changed. 142 /// 143 /// Users may use this object in range-based for loops, or use the 144 /// iterators to access additional information about each changed 145 /// object. 146 class PathRange 147 { 148 public: 149 /// \class iterator 150 class iterator : public boost::iterator_adaptor< 151 iterator, // crtp base, 152 _PathsToChangesMap::const_iterator, // base iterator 153 const SdfPath& // value type 154 > 155 { 156 public: iterator()157 iterator() 158 : iterator_adaptor_(base_type()) {} 159 160 /// Return the set of changed fields in layers that affected 161 /// the object at the path specified by this iterator. See 162 /// UsdNotice::ObjectsChanged::GetChangedFields for more 163 /// details. 164 USD_API TfTokenVector GetChangedFields() const; 165 166 /// Return true if the object at the path specified by this 167 /// iterator has any changed fields, false otherwise. See 168 /// UsdNotice::ObjectsChanged::HasChangedFields for more 169 /// details. 170 USD_API bool HasChangedFields() const; 171 172 private: 173 friend class PathRange; 174 friend class boost::iterator_core_access; 175 iterator(base_type baseIter)176 iterator(base_type baseIter) 177 : iterator_adaptor_(baseIter) {} dereference()178 inline reference dereference() const { 179 return base()->first; 180 } 181 }; 182 183 using const_iterator = iterator; 184 PathRange()185 PathRange() : _changes(nullptr) { } 186 187 /// Explicit conversion to SdfPathVector for convenience SdfPathVector()188 explicit operator SdfPathVector() const { 189 return SdfPathVector(begin(), end()); 190 } 191 192 /// Return true if this range contains any paths, false otherwise. empty()193 bool empty() const { 194 return !_changes || _changes->empty(); 195 } 196 197 /// Return the number of paths in this range. size()198 size_t size() const { 199 return _changes ? _changes->size() : 0; 200 } 201 202 /// Return iterator to the start of this range. begin()203 iterator begin() const { 204 return iterator(_changes->cbegin()); 205 } 206 207 /// Return iterator to the start of this range. cbegin()208 const_iterator cbegin() const { 209 return iterator(_changes->cbegin()); 210 } 211 212 /// Return the end iterator for this range. end()213 iterator end() const { 214 return iterator(_changes->cend()); 215 } 216 217 /// Return the end iterator for this range. cend()218 const_iterator cend() const { 219 return iterator(_changes->cend()); 220 } 221 222 /// Return an iterator to the specified \p path in this range if 223 /// it exists, or end() if it does not. This is potentially more 224 /// efficient than std::find(begin(), end()). find(const SdfPath & path)225 const_iterator find(const SdfPath& path) const { 226 return const_iterator(_changes->find(path)); 227 } 228 229 private: 230 friend class ObjectsChanged; PathRange(const _PathsToChangesMap * changes)231 explicit PathRange(const _PathsToChangesMap* changes) 232 : _changes(changes) 233 { } 234 235 const _PathsToChangesMap* _changes; 236 }; 237 238 /// Return the set of paths that are resynced in lexicographical order. 239 /// Resyncs imply entire subtree invalidation of all descendant prims 240 /// and properties, so this set is minimal regarding ancestors and 241 /// descendants. For example, if the path '/foo' appears in this set, 242 /// the entire subtree at '/foo' is resynced so the path '/foo/bar' will 243 /// not appear, but it should be considered resynced. 244 USD_API PathRange GetResyncedPaths() const; 245 246 /// Return the set of paths that have only info changes (those that do 247 /// not affect the structure of cached UsdPrims on a UsdStage) in 248 /// lexicographical order. Info changes do not imply entire subtree 249 /// invalidation, so this set is not minimal regarding ancestors and 250 /// descendants, as opposed to GetResyncedPaths(). For example, both 251 /// the paths '/foo' and '/foo/bar' may appear in this set. 252 USD_API PathRange GetChangedInfoOnlyPaths() const; 253 254 /// Return the set of changed fields in layers that affected \p obj. 255 /// 256 /// This set will be empty for objects whose paths are not in 257 /// GetResyncedPaths() or GetChangedInfoOnlyPaths(). 258 /// 259 /// If a field is present in this set, it does not necessarily mean the 260 /// composed value of that field on \p obj has changed. For example, if 261 /// a metadata value on \p obj is overridden in a stronger layer and 262 /// is changed in a weaker layer, that field will appear in this set. 263 /// However, since the value in the stronger layer did not change, 264 /// the composed value returned by GetMetadata() will not have changed. 265 USD_API TfTokenVector GetChangedFields(const UsdObject &obj) const; 266 267 /// \overload 268 USD_API TfTokenVector GetChangedFields(const SdfPath &path) const; 269 270 /// Return true if there are any changed fields that affected \p obj, 271 /// false otherwise. See GetChangedFields for more details. 272 USD_API bool HasChangedFields(const UsdObject &obj) const; 273 274 /// \overload 275 USD_API bool HasChangedFields(const SdfPath &path) const; 276 277 private: 278 const _PathsToChangesMap *_resyncChanges; 279 const _PathsToChangesMap *_infoChanges; 280 }; 281 282 /// \class StageEditTargetChanged 283 /// 284 /// Notice sent when a stage's EditTarget has changed. Sent in the 285 /// thread that changed the target. 286 /// 287 class StageEditTargetChanged : public StageNotice { 288 public: StageEditTargetChanged(const UsdStageWeakPtr & stage)289 explicit StageEditTargetChanged(const UsdStageWeakPtr &stage) 290 : StageNotice(stage) {} 291 USD_API virtual ~StageEditTargetChanged(); 292 }; 293 294 /// \class LayerMutingChanged 295 /// 296 /// Notice sent after a set of layers have been newly muted or unmuted. 297 /// Note this does not necessarily mean the specified layers are currently 298 /// loaded. 299 /// 300 /// LayerMutingChanged notice is sent before any UsdNotice::ObjectsChanged 301 /// or UsdNotice::StageContentsChanged notices are sent resulting from 302 /// muting or unmuting of layers. 303 /// 304 /// Note that LayerMutingChanged notice is sent even if the 305 /// muting/unmuting layer does not belong to the current stage, or is a 306 /// layer that does belong to the current stage but is not yet loaded 307 /// because it is behind an unloaded payload or unselected variant. 308 class LayerMutingChanged : public StageNotice { 309 public: LayerMutingChanged(const UsdStageWeakPtr & stage,const std::vector<std::string> & mutedLayers,const std::vector<std::string> & unmutedLayers)310 explicit LayerMutingChanged(const UsdStageWeakPtr &stage, 311 const std::vector<std::string>& mutedLayers, 312 const std::vector<std::string>& unmutedLayers) 313 : StageNotice(stage), 314 _mutedLayers(mutedLayers), 315 _unMutedLayers(unmutedLayers) {} 316 317 USD_API virtual ~LayerMutingChanged(); 318 319 /// Returns the identifier of the layers that were muted. 320 /// 321 /// The stage's resolver context must be bound when looking up 322 /// layers using the returned identifiers to ensure the same layers 323 /// that would be used by the stage are found. GetMutedLayers()324 const std::vector<std::string>& GetMutedLayers() const { 325 return _mutedLayers; 326 } 327 328 /// Returns the identifier of the layers that were unmuted. 329 /// 330 /// The stage's resolver context must be bound when looking up 331 /// layers using the returned identifiers to ensure the same layers 332 /// that would be used by the stage are found. GetUnmutedLayers()333 const std::vector<std::string>& GetUnmutedLayers() const { 334 return _unMutedLayers; 335 } 336 337 private: 338 const std::vector<std::string>& _mutedLayers; 339 const std::vector<std::string>& _unMutedLayers; 340 }; 341 342 }; 343 344 345 PXR_NAMESPACE_CLOSE_SCOPE 346 347 #endif // PXR_USD_USD_NOTICE_H 348