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