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 #include "pxr/usd/usdRi/statementsAPI.h"
25 #include "pxr/usd/usd/schemaRegistry.h"
26 #include "pxr/usd/usd/typed.h"
27 #include "pxr/usd/usd/tokens.h"
28 
29 #include "pxr/usd/sdf/types.h"
30 #include "pxr/usd/sdf/assetPath.h"
31 
32 PXR_NAMESPACE_OPEN_SCOPE
33 
34 // Register the schema with the TfType system.
TF_REGISTRY_FUNCTION(TfType)35 TF_REGISTRY_FUNCTION(TfType)
36 {
37     TfType::Define<UsdRiStatementsAPI,
38         TfType::Bases< UsdAPISchemaBase > >();
39 
40 }
41 
42 TF_DEFINE_PRIVATE_TOKENS(
43     _schemaTokens,
44     (StatementsAPI)
45 );
46 
47 /* virtual */
~UsdRiStatementsAPI()48 UsdRiStatementsAPI::~UsdRiStatementsAPI()
49 {
50 }
51 
52 /* static */
53 UsdRiStatementsAPI
Get(const UsdStagePtr & stage,const SdfPath & path)54 UsdRiStatementsAPI::Get(const UsdStagePtr &stage, const SdfPath &path)
55 {
56     if (!stage) {
57         TF_CODING_ERROR("Invalid stage");
58         return UsdRiStatementsAPI();
59     }
60     return UsdRiStatementsAPI(stage->GetPrimAtPath(path));
61 }
62 
63 
64 /* virtual */
_GetSchemaKind() const65 UsdSchemaKind UsdRiStatementsAPI::_GetSchemaKind() const
66 {
67     return UsdRiStatementsAPI::schemaKind;
68 }
69 
70 /* static */
71 bool
CanApply(const UsdPrim & prim,std::string * whyNot)72 UsdRiStatementsAPI::CanApply(
73     const UsdPrim &prim, std::string *whyNot)
74 {
75     return prim.CanApplyAPI<UsdRiStatementsAPI>(whyNot);
76 }
77 
78 /* static */
79 UsdRiStatementsAPI
Apply(const UsdPrim & prim)80 UsdRiStatementsAPI::Apply(const UsdPrim &prim)
81 {
82     if (prim.ApplyAPI<UsdRiStatementsAPI>()) {
83         return UsdRiStatementsAPI(prim);
84     }
85     return UsdRiStatementsAPI();
86 }
87 
88 /* static */
89 const TfType &
_GetStaticTfType()90 UsdRiStatementsAPI::_GetStaticTfType()
91 {
92     static TfType tfType = TfType::Find<UsdRiStatementsAPI>();
93     return tfType;
94 }
95 
96 /* static */
97 bool
_IsTypedSchema()98 UsdRiStatementsAPI::_IsTypedSchema()
99 {
100     static bool isTyped = _GetStaticTfType().IsA<UsdTyped>();
101     return isTyped;
102 }
103 
104 /* virtual */
105 const TfType &
_GetTfType() const106 UsdRiStatementsAPI::_GetTfType() const
107 {
108     return _GetStaticTfType();
109 }
110 
111 /*static*/
112 const TfTokenVector&
GetSchemaAttributeNames(bool includeInherited)113 UsdRiStatementsAPI::GetSchemaAttributeNames(bool includeInherited)
114 {
115     static TfTokenVector localNames;
116     static TfTokenVector allNames =
117         UsdAPISchemaBase::GetSchemaAttributeNames(true);
118 
119     if (includeInherited)
120         return allNames;
121     else
122         return localNames;
123 }
124 
125 PXR_NAMESPACE_CLOSE_SCOPE
126 
127 // ===================================================================== //
128 // Feel free to add custom code below this line. It will be preserved by
129 // the code generator.
130 //
131 // Just remember to wrap code in the appropriate delimiters:
132 // 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'.
133 // ===================================================================== //
134 // --(BEGIN CUSTOM CODE)--
135 
136 #include "typeUtils.h"
137 #include "pxr/usd/sdf/types.h"
138 #include "pxr/base/tf/envSetting.h"
139 #include <string>
140 
141 using std::string;
142 
143 PXR_NAMESPACE_OPEN_SCOPE
144 
145 TF_DEFINE_ENV_SETTING(
146     USDRI_STATEMENTS_READ_OLD_ATTR_ENCODING, true,
147     "If on, UsdRiStatementsAPI will read old-style attributes.  "
148     "Otherwise, primvars in the ri: namespace will be read instead.");
149 
150 TF_DEFINE_PRIVATE_TOKENS(
151     _tokens,
152     ((fullAttributeNamespace, "ri:attributes:"))
153     ((primvarAttrNamespace, "primvars:ri:attributes:"))
154     ((rootNamespace, "ri"))
155     ((attributeNamespace, "attributes"))
156     ((coordsys, "ri:coordinateSystem"))
157     ((scopedCoordsys, "ri:scopedCoordinateSystem"))
158     ((modelCoordsys, "ri:modelCoordinateSystems"))
159     ((modelScopedCoordsys, "ri:modelScopedCoordinateSystems"))
160 );
161 
162 static TfToken
_MakeRiAttrNamespace(const string & nameSpace,const string & attrName)163 _MakeRiAttrNamespace(const string &nameSpace, const string &attrName)
164 {
165     return TfToken(_tokens->fullAttributeNamespace.GetString() +
166                    nameSpace + ":" + attrName);
167 }
168 
169 UsdAttribute
CreateRiAttribute(const TfToken & name,const string & riType,const string & nameSpace)170 UsdRiStatementsAPI::CreateRiAttribute(
171     const TfToken& name,
172     const string &riType,
173     const string &nameSpace)
174 {
175     TfToken fullName = _MakeRiAttrNamespace(nameSpace, name.GetString());
176     SdfValueTypeName usdType = UsdRi_GetUsdType(riType);
177     return UsdGeomPrimvarsAPI(GetPrim())
178         .CreatePrimvar(fullName, usdType).GetAttr();
179 }
180 
181 UsdAttribute
CreateRiAttribute(const TfToken & name,const TfType & tfType,const string & nameSpace)182 UsdRiStatementsAPI::CreateRiAttribute(
183     const TfToken &name,
184     const TfType &tfType,
185     const string &nameSpace)
186 {
187     TfToken fullName = _MakeRiAttrNamespace(nameSpace, name.GetString());
188     SdfValueTypeName usdType = SdfSchema::GetInstance().FindType(tfType);
189     return UsdGeomPrimvarsAPI(GetPrim())
190         .CreatePrimvar(fullName, usdType).GetAttr();
191 }
192 
193 UsdAttribute
GetRiAttribute(const TfToken & name,const std::string & nameSpace)194 UsdRiStatementsAPI::GetRiAttribute(
195     const TfToken &name,
196     const std::string &nameSpace)
197 {
198     TfToken fullName = _MakeRiAttrNamespace(nameSpace, name.GetString());
199     if (UsdGeomPrimvar p = UsdGeomPrimvarsAPI(GetPrim()).GetPrimvar(fullName)) {
200         return p;
201     }
202     if (TfGetEnvSetting(USDRI_STATEMENTS_READ_OLD_ATTR_ENCODING)) {
203         return GetPrim().GetAttribute(fullName);
204     }
205     return UsdAttribute();
206 }
207 
208 std::vector<UsdProperty>
GetRiAttributes(const string & nameSpace) const209 UsdRiStatementsAPI::GetRiAttributes(
210     const string &nameSpace) const
211 {
212     std::vector<UsdProperty> validProps;
213 
214     // Read as primvars.
215     std::string const& ns = _tokens->fullAttributeNamespace.GetString();
216     for (UsdGeomPrimvar const& pv:
217          UsdGeomPrimvarsAPI(GetPrim()).GetPrimvars()) {
218         if (TfStringStartsWith(pv.GetPrimvarName().GetString(), ns)) {
219             validProps.push_back(pv.GetAttr());
220         }
221     }
222 
223     // If enabled, read the old-style encoding.
224     if (TfGetEnvSetting(USDRI_STATEMENTS_READ_OLD_ATTR_ENCODING)) {
225         const size_t numNewStylePrimvars = validProps.size();
226         std::vector<UsdProperty> props =
227             GetPrim().GetPropertiesInNamespace(_tokens->fullAttributeNamespace);
228         std::vector<string> names;
229         bool requestedNameSpace = (nameSpace != "");
230         for (UsdProperty const& prop: props) {
231             names = prop.SplitName();
232             if (requestedNameSpace && names[2] != nameSpace) {
233                 // wrong namespace
234                 continue;
235             }
236             // If we encounter the same Ri attribute name encoded as both
237             // a new and old style attribute, return only the new-style one.
238             bool foundAsPrimvar = false;
239             for (size_t i=0; i < numNewStylePrimvars; ++i) {
240                 const std::string &primvarName =
241                     validProps[i].GetName().GetString();
242                 std::size_t nsOffset = primvarName.find(":");
243                 if (nsOffset != std::string::npos &&
244                     primvarName.compare(nsOffset+1, std::string::npos,
245                                         prop.GetName().GetText()) == 0) {
246                     foundAsPrimvar = true;
247                     break;
248                 }
249             }
250             if (!foundAsPrimvar) {
251                 validProps.push_back(prop);
252             }
253         }
254     }
255 
256     return validProps;
257 }
258 
GetRiAttributeNameSpace(const UsdProperty & prop)259 TfToken UsdRiStatementsAPI::GetRiAttributeNameSpace(const UsdProperty &prop)
260 {
261     const std::vector<string> names = prop.SplitName();
262     // Parse primvar encoding.
263     if (TfStringStartsWith(prop.GetName(), _tokens->primvarAttrNamespace)) {
264         if (names.size() >= 5) {
265             // Primvar with N custom namespaces:
266             // "primvars:ri:attributes:$(NS_1):...:$(NS_N):$(NAME)"
267             return TfToken(TfStringJoin(names.begin() + 3, names.end()-1, ":"));
268         }
269         return TfToken();
270     }
271     // Optionally parse old-style attribute encoding.
272     if (TfStringStartsWith(prop.GetName(), _tokens->fullAttributeNamespace) &&
273         TfGetEnvSetting(USDRI_STATEMENTS_READ_OLD_ATTR_ENCODING)) {
274         if (names.size() >= 4) {
275             // Old-style attribute with N custom namespaces:
276             // "ri:attributes:$(NS_1):...:$(NS_N):$(NAME)"
277             return TfToken(TfStringJoin(names.begin() + 2, names.end()-1, ":"));
278         }
279     }
280     return TfToken();
281 }
282 
283 bool
IsRiAttribute(const UsdProperty & attr)284 UsdRiStatementsAPI::IsRiAttribute(const UsdProperty &attr)
285 {
286     // Accept primvar encoding.
287     if (TfStringStartsWith(attr.GetName(), _tokens->primvarAttrNamespace)) {
288         return true;
289     }
290     // Optionally accept old-style attribute encoding.
291     if (TfStringStartsWith(attr.GetName(), _tokens->fullAttributeNamespace) &&
292         TfGetEnvSetting(USDRI_STATEMENTS_READ_OLD_ATTR_ENCODING)) {
293         return true;
294     }
295     return false;
296 }
297 
298 std::string
MakeRiAttributePropertyName(const std::string & attrName)299 UsdRiStatementsAPI::MakeRiAttributePropertyName(const std::string &attrName)
300 {
301     std::vector<string> names = TfStringTokenize(attrName, ":");
302 
303     // If this is an already-encoded name, return it unchanged.
304     if (names.size() == 5 &&
305         TfStringStartsWith(attrName, _tokens->primvarAttrNamespace)) {
306         return attrName;
307     }
308     if (names.size() == 4 &&
309         TfStringStartsWith(attrName, _tokens->fullAttributeNamespace)) {
310         return attrName;
311     }
312 
313     // Attempt to parse namespaces in different forms.
314     if (names.size() == 1) {
315         names = TfStringTokenize(attrName, ".");
316     }
317     if (names.size() == 1) {
318         names = TfStringTokenize(attrName, "_");
319     }
320 
321     // Fallback to user namespace if no other exists.
322     if (names.size() == 1) {
323         names.insert(names.begin(), "user");
324     }
325 
326     string fullName =
327         _tokens->primvarAttrNamespace.GetString() +
328         names[0] + ":" + ( names.size() > 2 ?
329                            TfStringJoin(names.begin() + 1, names.end(), "_")
330                            : names[1]);
331 
332     return SdfPath::IsValidNamespacedIdentifier(fullName) ? fullName : string();
333 }
334 
335 void
SetCoordinateSystem(const std::string & coordSysName)336 UsdRiStatementsAPI::SetCoordinateSystem(const std::string &coordSysName)
337 {
338     UsdAttribute attr = GetPrim().CreateAttribute(_tokens->coordsys,
339                                                   SdfValueTypeNames->String,
340                                                   /* custom = */ false);
341     if (TF_VERIFY(attr)) {
342         attr.Set(coordSysName);
343 
344         UsdPrim currPrim = GetPrim();
345         while (currPrim && currPrim.GetPath() != SdfPath::AbsoluteRootPath()) {
346             if (currPrim.IsModel() && !currPrim.IsGroup() &&
347                 currPrim.GetPath() != SdfPath::AbsoluteRootPath()) {
348                 UsdRelationship rel =
349                     currPrim.CreateRelationship(_tokens->modelCoordsys,
350                                                 /* custom = */ false);
351                 if (TF_VERIFY(rel)) {
352                     // Order should not matter, since these are a set,
353                     // but historically we have appended these.
354                     rel.AddTarget(GetPrim().GetPath());
355                 }
356                 break;
357             }
358 
359             currPrim = currPrim.GetParent();
360         }
361     }
362 }
363 
364 std::string
GetCoordinateSystem() const365 UsdRiStatementsAPI::GetCoordinateSystem() const
366 {
367     std::string result;
368     UsdAttribute attr = GetPrim().GetAttribute(_tokens->coordsys);
369     if (attr) {
370         attr.Get(&result);
371     }
372     return result;
373 }
374 
375 bool
HasCoordinateSystem() const376 UsdRiStatementsAPI::HasCoordinateSystem() const
377 {
378     std::string result;
379     UsdAttribute attr = GetPrim().GetAttribute(_tokens->coordsys);
380     if (attr) {
381         return attr.Get(&result);
382     }
383     return false;
384 }
385 
386 void
SetScopedCoordinateSystem(const std::string & coordSysName)387 UsdRiStatementsAPI::SetScopedCoordinateSystem(const std::string &coordSysName)
388 {
389     UsdAttribute attr = GetPrim().CreateAttribute(_tokens->scopedCoordsys,
390                                                   SdfValueTypeNames->String,
391                                                   /* custom = */ false);
392     if (TF_VERIFY(attr)) {
393         attr.Set(coordSysName);
394 
395         UsdPrim currPrim = GetPrim();
396         while (currPrim) {
397             if (currPrim.IsModel() && !currPrim.IsGroup() &&
398                 currPrim.GetPath() != SdfPath::AbsoluteRootPath()) {
399                 UsdRelationship rel =
400                     currPrim.CreateRelationship(_tokens->modelScopedCoordsys,
401                                                 /* custom = */ false);
402                 if (TF_VERIFY(rel)) {
403                     rel.AddTarget(GetPrim().GetPath());
404                 }
405                 break;
406             }
407 
408             currPrim = currPrim.GetParent();
409         }
410     }
411 }
412 
413 std::string
GetScopedCoordinateSystem() const414 UsdRiStatementsAPI::GetScopedCoordinateSystem() const
415 {
416     std::string result;
417     UsdAttribute attr = GetPrim().GetAttribute(_tokens->scopedCoordsys);
418     if (attr) {
419         attr.Get(&result);
420     }
421     return result;
422 }
423 
424 bool
HasScopedCoordinateSystem() const425 UsdRiStatementsAPI::HasScopedCoordinateSystem() const
426 {
427     std::string result;
428     UsdAttribute attr = GetPrim().GetAttribute(_tokens->scopedCoordsys);
429     if (attr) {
430         return attr.Get(&result);
431     }
432     return false;
433 }
434 
435 bool
GetModelCoordinateSystems(SdfPathVector * targets) const436 UsdRiStatementsAPI::GetModelCoordinateSystems(SdfPathVector *targets) const
437 {
438     if (GetPrim().IsModel()) {
439         UsdRelationship rel =
440             GetPrim().GetRelationship(_tokens->modelCoordsys);
441         return rel && rel.GetForwardedTargets(targets);
442     }
443 
444     return true;
445 }
446 
447 bool
GetModelScopedCoordinateSystems(SdfPathVector * targets) const448 UsdRiStatementsAPI::GetModelScopedCoordinateSystems(SdfPathVector *targets) const
449 {
450     if (GetPrim().IsModel()) {
451         UsdRelationship rel =
452             GetPrim().GetRelationship(_tokens->modelScopedCoordsys);
453         return rel && rel.GetForwardedTargets(targets);
454     }
455 
456     return true;
457 }
458 
459 PXR_NAMESPACE_CLOSE_SCOPE
460