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 
25 #include "pxr/pxr.h"
26 #include "pxr/usd/pcp/composeSite.h"
27 #include "pxr/usd/pcp/layerStack.h"
28 #include "pxr/usd/sdf/layer.h"
29 #include "pxr/usd/sdf/layerUtils.h"
30 #include "pxr/usd/sdf/listOp.h"
31 #include "pxr/usd/sdf/primSpec.h"
32 
33 #include <functional>
34 
35 PXR_NAMESPACE_OPEN_SCOPE
36 
37 // Implementation notes:
38 //
39 // These go directly to SdfLayer's field API, skipping
40 // indirection through SdfSpecHandle identities.
41 //
42 // For arcs that refer to asset paths, these functions additionally
43 // compute the absolute form of the asset path, using the layer that
44 // expressed the opinion as the basis for relative paths.
45 
46 // SdfReference has custom data that is copied during composition, SdfPayload
47 // does not.
48 static void
_CopyCustomData(SdfReference * lhs,const SdfReference & rhs)49 _CopyCustomData(SdfReference *lhs, const SdfReference &rhs)
50 {
51     lhs->SetCustomData(rhs.GetCustomData());
52 }
53 
54 static void
_CopyCustomData(SdfPayload *,const SdfPayload &)55 _CopyCustomData(SdfPayload *, const SdfPayload&)
56 {
57     // do nothing
58 }
59 
60 // Payload and reference lists are composed in the same way.
61 template <class RefOrPayloadType>
62 static void
_PcpComposeSiteReferencesOrPayloads(TfToken const & field,PcpLayerStackRefPtr const & layerStack,SdfPath const & path,std::vector<RefOrPayloadType> * result,PcpSourceArcInfoVector * info)63 _PcpComposeSiteReferencesOrPayloads(TfToken const &field,
64                                     PcpLayerStackRefPtr const &layerStack,
65                                     SdfPath const &path,
66                                     std::vector<RefOrPayloadType> *result,
67                                     PcpSourceArcInfoVector *info )
68 {
69     // Sdf provides no convenient way to annotate each element of the result.
70     // So we use a map from element value to its annotation, which in this
71     // case is a PcpSourceArcInfo.
72     std::map<RefOrPayloadType, PcpSourceArcInfo> infoMap;
73 
74     const SdfLayerRefPtrVector& layers = layerStack->GetLayers();
75     SdfListOp<RefOrPayloadType> curListOp;
76 
77     result->clear();
78     for (size_t i = layers.size(); i-- != 0; ) {
79         const SdfLayerHandle& layer = layers[i];
80         if (layer->HasField(path, field, &curListOp)) {
81             const SdfLayerOffset* layerOffset =
82                 layerStack->GetLayerOffsetForLayer(i);
83 
84             // List-op composition callback computes absolute asset paths
85             // relative to the layer where they were expressed and combines
86             // layer offsets.
87             curListOp.ApplyOperations(result,
88                 [&layer, layerOffset, &infoMap](
89                     SdfListOpType opType, const RefOrPayloadType& refOrPayload)
90                 {
91                     // Fill in the result reference of payload with the anchored
92                     // asset path instead of the authored asset path. This
93                     // ensures that references or payloads with the same
94                     // relative asset path but anchored to different
95                     // locations will not be considered duplicates.
96                     const std::string &authoredAssetPath =
97                         refOrPayload.GetAssetPath();
98                     const std::string assetPath = authoredAssetPath.empty() ?
99                         authoredAssetPath :
100                         SdfComputeAssetPathRelativeToLayer(
101                             layer, authoredAssetPath);
102                     SdfLayerOffset resolvedLayerOffset = layerOffset ?
103                         *layerOffset * refOrPayload.GetLayerOffset() :
104                         refOrPayload.GetLayerOffset();
105                     RefOrPayloadType result( assetPath,
106                                              refOrPayload.GetPrimPath(),
107                                              resolvedLayerOffset);
108 
109                     _CopyCustomData(&result, refOrPayload);
110                     PcpSourceArcInfo& info = infoMap[result];
111                     info.layer = layer;
112                     info.layerOffset = refOrPayload.GetLayerOffset();
113                     info.authoredAssetPath = refOrPayload.GetAssetPath();
114                     return result;
115                 });
116         }
117     }
118 
119     // Fill in info.
120     info->clear();
121     info->reserve(result->size());
122     for (auto const &ref: *result) {
123         info->push_back(infoMap[ref]);
124     }
125 }
126 
127 void
PcpComposeSiteReferences(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,SdfReferenceVector * result,PcpSourceArcInfoVector * info)128 PcpComposeSiteReferences(PcpLayerStackRefPtr const &layerStack,
129                          SdfPath const &path,
130                          SdfReferenceVector *result,
131                          PcpSourceArcInfoVector *info )
132 {
133     _PcpComposeSiteReferencesOrPayloads(
134         SdfFieldKeys->References, layerStack, path, result, info);
135 }
136 
137 void
PcpComposeSitePayloads(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,SdfPayloadVector * result,PcpSourceArcInfoVector * info)138 PcpComposeSitePayloads(PcpLayerStackRefPtr const &layerStack,
139                        SdfPath const &path,
140                        SdfPayloadVector *result,
141                        PcpSourceArcInfoVector *info )
142 {
143     _PcpComposeSiteReferencesOrPayloads(
144         SdfFieldKeys->Payload, layerStack, path, result, info);
145 }
146 
147 SdfPermission
PcpComposeSitePermission(PcpLayerStackRefPtr const & layerStack,SdfPath const & path)148 PcpComposeSitePermission(PcpLayerStackRefPtr const &layerStack,
149                          SdfPath const &path)
150 {
151     SdfPermission perm = SdfPermissionPublic;
152     for (auto const &layer: layerStack->GetLayers()) {
153         if (layer->HasField(path, SdfFieldKeys->Permission, &perm))
154             break;
155     }
156     return perm;
157 }
158 
159 bool
PcpComposeSiteHasPrimSpecs(PcpLayerStackRefPtr const & layerStack,SdfPath const & path)160 PcpComposeSiteHasPrimSpecs(PcpLayerStackRefPtr const &layerStack,
161                            SdfPath const &path)
162 {
163     for (auto const &layer: layerStack->GetLayers()) {
164         if (layer->HasSpec(path)) {
165             return true;
166         }
167     }
168     return false;
169 }
170 
171 bool
PcpComposeSiteHasSymmetry(PcpLayerStackRefPtr const & layerStack,SdfPath const & path)172 PcpComposeSiteHasSymmetry(PcpLayerStackRefPtr const &layerStack,
173                           SdfPath const &path)
174 {
175     for (auto const &layer: layerStack->GetLayers()) {
176         if (layer->HasField(path, SdfFieldKeys->SymmetryFunction) ||
177             layer->HasField(path, SdfFieldKeys->SymmetryArguments)) {
178             return true;
179         }
180     }
181     return false;
182 }
183 
184 void
PcpComposeSitePrimSites(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,SdfSiteVector * result)185 PcpComposeSitePrimSites(PcpLayerStackRefPtr const &layerStack,
186                         SdfPath const &path,
187                         SdfSiteVector *result)
188 {
189     for (auto const &layer: layerStack->GetLayers()) {
190         if (layer->HasSpec(path))
191             result->push_back(SdfSite(layer, path));
192     }
193 }
194 
195 void
PcpComposeSiteRelocates(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,SdfRelocatesMap * result)196 PcpComposeSiteRelocates(PcpLayerStackRefPtr const &layerStack,
197                         SdfPath const &path,
198                         SdfRelocatesMap *result)
199 {
200     static const TfToken field = SdfFieldKeys->Relocates;
201 
202     SdfRelocatesMap relocMap;
203     TF_REVERSE_FOR_ALL(layer, layerStack->GetLayers()) {
204         if ((*layer)->HasField(path, field, &relocMap)) {
205             TF_FOR_ALL(reloc, relocMap) {
206                 SdfPath source = reloc->first .MakeAbsolutePath(path);
207                 SdfPath target = reloc->second.MakeAbsolutePath(path);
208                 (*result)[source] = target;
209             }
210         }
211     }
212 }
213 
214 // Helper for PcpComposeSiteInherits/Specializes/ overloads
215 // that want to provide source arc info with the layer that adds each result.
216 template <typename ResultType>
217 static void
_ComposeSiteListOpWithSourceInfo(const PcpLayerStackRefPtr & layerStack,const SdfPath & path,const TfToken & field,std::vector<ResultType> * result,PcpSourceArcInfoVector * info)218 _ComposeSiteListOpWithSourceInfo(const PcpLayerStackRefPtr &layerStack,
219                                  const SdfPath &path,
220                                  const TfToken &field,
221                                  std::vector<ResultType> *result,
222                                  PcpSourceArcInfoVector *info)
223 {
224     // Map of result value to source arc info. The same value may appear in
225     // multiple layers' list ops. This lets us make sure we find the strongest
226     // layer that added the value.
227     std::map<ResultType, PcpSourceArcInfo> infoMap;
228 
229     SdfListOp<ResultType> listOp;
230     TF_REVERSE_FOR_ALL(layer, layerStack->GetLayers()) {
231         if ((*layer)->HasField(path, field, &listOp)) {
232             listOp.ApplyOperations(result,
233                 [&layer, &infoMap](SdfListOpType opType, const ResultType &path)
234                 {
235                     // Just store the layer in the source arc info for the
236                     // result. We don't need the other data.
237                     infoMap[path].layer = *layer;
238                     return path;
239                 });
240         }
241     }
242 
243     // Construct the parallel array of source info to results.
244     info->reserve(result->size());
245     for (const ResultType &path: *result) {
246         info->push_back(infoMap[path]);
247     }
248 }
249 
250 void
PcpComposeSiteInherits(const PcpLayerStackRefPtr & layerStack,const SdfPath & path,SdfPathVector * result,PcpSourceArcInfoVector * info)251 PcpComposeSiteInherits( const PcpLayerStackRefPtr &layerStack,
252                         const SdfPath &path, SdfPathVector *result,
253                         PcpSourceArcInfoVector *info )
254 {
255     static const TfToken field = SdfFieldKeys->InheritPaths;
256     _ComposeSiteListOpWithSourceInfo(layerStack, path, field, result, info);
257 }
258 
259 void
PcpComposeSiteInherits(const PcpLayerStackRefPtr & layerStack,const SdfPath & path,SdfPathVector * result)260 PcpComposeSiteInherits( const PcpLayerStackRefPtr &layerStack,
261                         const SdfPath &path, SdfPathVector *result)
262 {
263     static const TfToken field = SdfFieldKeys->InheritPaths;
264 
265     SdfPathListOp inheritListOp;
266     TF_REVERSE_FOR_ALL(layer, layerStack->GetLayers()) {
267         if ((*layer)->HasField(path, field, &inheritListOp)) {
268             inheritListOp.ApplyOperations(result);
269         }
270     }
271 }
272 
273 void
PcpComposeSiteSpecializes(const PcpLayerStackRefPtr & layerStack,const SdfPath & path,SdfPathVector * result,PcpSourceArcInfoVector * info)274 PcpComposeSiteSpecializes(const PcpLayerStackRefPtr &layerStack,
275                           const SdfPath &path, SdfPathVector *result,
276                           PcpSourceArcInfoVector *info )
277 {
278     static const TfToken field = SdfFieldKeys->Specializes;
279     _ComposeSiteListOpWithSourceInfo(layerStack, path, field, result, info);
280 }
281 
282 void
PcpComposeSiteSpecializes(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,SdfPathVector * result)283 PcpComposeSiteSpecializes(PcpLayerStackRefPtr const &layerStack,
284                           SdfPath const &path, SdfPathVector *result)
285 {
286     static const TfToken field = SdfFieldKeys->Specializes;
287 
288     SdfPathListOp specializesListOp;
289     TF_REVERSE_FOR_ALL(layer, layerStack->GetLayers()) {
290         if ((*layer)->HasField(path, field, &specializesListOp)) {
291             specializesListOp.ApplyOperations(result);
292         }
293     }
294 }
295 
296 PCP_API
297 void
PcpComposeSiteVariantSets(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,std::vector<std::string> * result,PcpSourceArcInfoVector * info)298 PcpComposeSiteVariantSets(PcpLayerStackRefPtr const &layerStack,
299                           SdfPath const &path,
300                           std::vector<std::string> *result,
301                           PcpSourceArcInfoVector *info)
302 {
303     static const TfToken field = SdfFieldKeys->VariantSetNames;
304     _ComposeSiteListOpWithSourceInfo(layerStack, path, field, result, info);
305 }
306 
307 void
PcpComposeSiteVariantSets(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,std::vector<std::string> * result)308 PcpComposeSiteVariantSets(PcpLayerStackRefPtr const &layerStack,
309                           SdfPath const &path,
310                           std::vector<std::string> *result)
311 {
312     static const TfToken field = SdfFieldKeys->VariantSetNames;
313 
314     SdfStringListOp vsetListOp;
315     TF_REVERSE_FOR_ALL(layer, layerStack->GetLayers()) {
316         if ((*layer)->HasField(path, field, &vsetListOp)) {
317             vsetListOp.ApplyOperations(result);
318         }
319     }
320 }
321 
322 void
PcpComposeSiteVariantSetOptions(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,std::string const & vsetName,std::set<std::string> * result)323 PcpComposeSiteVariantSetOptions(PcpLayerStackRefPtr const &layerStack,
324                                 SdfPath const &path,
325                                 std::string const &vsetName,
326                                 std::set<std::string> *result)
327 {
328     static const TfToken field = SdfChildrenKeys->VariantChildren;
329 
330     const SdfPath vsetPath = path.AppendVariantSelection(vsetName, "");
331     TfTokenVector vsetNames;
332     for (auto const &layer: layerStack->GetLayers()) {
333         if (layer->HasField(vsetPath, field, &vsetNames)) {
334             TF_FOR_ALL(name, vsetNames) {
335                 result->insert(name->GetString());
336             }
337         }
338     }
339 }
340 
341 bool
PcpComposeSiteVariantSelection(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,std::string const & vsetName,std::string * result)342 PcpComposeSiteVariantSelection(PcpLayerStackRefPtr const &layerStack,
343                                SdfPath const &path,
344                                std::string const &vsetName,
345                                std::string *result)
346 {
347     static const TfToken field = SdfFieldKeys->VariantSelection;
348 
349     SdfVariantSelectionMap vselMap;
350     for (auto const &layer: layerStack->GetLayers()) {
351         if (layer->HasField(path, field, &vselMap)) {
352             SdfVariantSelectionMap::const_iterator i = vselMap.find(vsetName);
353             if (i != vselMap.end()) {
354                 *result = i->second;
355                 return true;
356             }
357         }
358     }
359     return false;
360 }
361 
362 void
PcpComposeSiteVariantSelections(PcpLayerStackRefPtr const & layerStack,SdfPath const & path,SdfVariantSelectionMap * result)363 PcpComposeSiteVariantSelections(PcpLayerStackRefPtr const &layerStack,
364                                 SdfPath const &path,
365                                 SdfVariantSelectionMap *result)
366 {
367     static const TfToken field = SdfFieldKeys->VariantSelection;
368 
369     SdfVariantSelectionMap vselMap;
370     for (auto const &layer: layerStack->GetLayers()) {
371         if (layer->HasField(path, field, &vselMap)) {
372             result->insert(vselMap.begin(), vselMap.end());
373         }
374     }
375 }
376 
377 void
PcpComposeSiteChildNames(SdfLayerRefPtrVector const & layers,SdfPath const & path,const TfToken & namesField,TfTokenVector * nameOrder,PcpTokenSet * nameSet,const TfToken * orderField)378 PcpComposeSiteChildNames(SdfLayerRefPtrVector const &layers,
379                          SdfPath const &path,
380                          const TfToken & namesField,
381                          TfTokenVector *nameOrder,
382                          PcpTokenSet *nameSet,
383                          const TfToken *orderField)
384 {
385     TF_REVERSE_FOR_ALL(layer, layers) {
386         VtValue namesVal = (*layer)->GetField(path, namesField);
387         if (namesVal.IsHolding<TfTokenVector>()) {
388             const TfTokenVector & names =
389                 namesVal.UncheckedGet<TfTokenVector>();
390             // Append names in order.  Skip names that are
391             // already in the nameSet.
392             TF_FOR_ALL(name, names) {
393                 if (nameSet->insert(*name).second) {
394                     nameOrder->push_back(*name);
395                 }
396             }
397         }
398         if (orderField) {
399             VtValue orderVal = (*layer)->GetField(path, *orderField);
400             if (orderVal.IsHolding<TfTokenVector>()) {
401                 SdfApplyListOrdering(nameOrder,
402                                      orderVal.UncheckedGet<TfTokenVector>());
403             }
404         }
405     }
406 }
407 
408 PXR_NAMESPACE_CLOSE_SCOPE
409