1 //
2 // Copyright 2018 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/base/tf/staticTokens.h"
26 #include "pxr/base/tf/stringUtils.h"
27 #include "pxr/usd/sdr/shaderMetadataHelpers.h"
28 #include "pxr/usd/sdr/shaderProperty.h"
29 
30 #include <iostream>
31 
32 PXR_NAMESPACE_OPEN_SCOPE
33 
34 TF_DEFINE_PRIVATE_TOKENS(
35     _tokens,
36 
37     // Values for "widget" metadata that indicate the property is an
38     // asset identifier
39     ((filename, "filename"))            // OSL spec
40     ((fileInput, "fileInput"))          // Args spec
41     ((assetIdInput, "assetIdInput"))    // Pixar convention
42 
43     // Values for "renderType" metadata that indicate the property is a
44     // SdrPropertyTypes->Terminal
45     ((terminal, "terminal"))
46 );
47 
48 namespace ShaderMetadataHelpers
49 {
50     bool
IsTruthy(const TfToken & key,const NdrTokenMap & metadata)51     IsTruthy(const TfToken& key, const NdrTokenMap& metadata)
52     {
53         const NdrTokenMap::const_iterator search = metadata.find(key);
54 
55         // Absence of the option implies false
56         if (search == metadata.end()) {
57             return false;
58         }
59 
60         // Presence of the option without a value implies true
61         if (search->second.empty()) {
62             return true;
63         }
64 
65         // Copy string for modification below
66         std::string boolStr = search->second;
67 
68         // Turn into a lower case string
69         std::transform(boolStr.begin(), boolStr.end(), boolStr.begin(), ::tolower);
70 
71         if ((boolStr == "0") || (boolStr == "false") || (boolStr == "f")) {
72             return false;
73         }
74 
75         return true;
76     }
77 
78 
79     // -------------------------------------------------------------------------
80 
81 
82     std::string
StringVal(const TfToken & key,const NdrTokenMap & metadata,const std::string & defaultValue)83     StringVal(const TfToken& key, const NdrTokenMap& metadata,
84               const std::string& defaultValue)
85     {
86         const NdrTokenMap::const_iterator search = metadata.find(key);
87 
88         if (search != metadata.end()) {
89             return search->second;
90         }
91 
92         return defaultValue;
93     }
94 
95 
96     // -------------------------------------------------------------------------
97 
98 
99     TfToken
TokenVal(const TfToken & key,const NdrTokenMap & metadata,const TfToken & defaultValue)100     TokenVal(const TfToken& key, const NdrTokenMap& metadata,
101              const TfToken& defaultValue)
102     {
103         const NdrTokenMap::const_iterator search = metadata.find(key);
104 
105         if (search != metadata.end()) {
106             return TfToken(search->second);
107         }
108 
109         return defaultValue;
110     }
111 
112 
113     // -------------------------------------------------------------------------
114 
115 
116     int
IntVal(const TfToken & key,const NdrTokenMap & metadata,int defaultValue)117     IntVal(const TfToken& key, const NdrTokenMap& metadata,
118            int defaultValue)
119     {
120         const NdrTokenMap::const_iterator search = metadata.find(key);
121 
122         if (search == metadata.end()) {
123             return defaultValue;
124         }
125 
126         try {
127             return std::stoi(search->second);
128         } catch (...) {
129             return defaultValue;
130         }
131     }
132 
133 
134     // -------------------------------------------------------------------------
135 
136 
137     NdrStringVec
StringVecVal(const TfToken & key,const NdrTokenMap & metadata)138     StringVecVal(const TfToken& key, const NdrTokenMap& metadata)
139     {
140         const NdrTokenMap::const_iterator search = metadata.find(key);
141 
142         if (search != metadata.end()) {
143             return TfStringSplit(search->second, "|");
144         }
145 
146         return NdrStringVec();
147     }
148 
149 
150     // -------------------------------------------------------------------------
151 
152 
153     NdrTokenVec
TokenVecVal(const TfToken & key,const NdrTokenMap & metadata)154     TokenVecVal(const TfToken& key, const NdrTokenMap& metadata)
155     {
156         const NdrStringVec untokenized = StringVecVal(key, metadata);
157         NdrTokenVec tokenized;
158 
159         for (const std::string& item : untokenized) {
160             tokenized.emplace_back(TfToken(item));
161         }
162 
163         return tokenized;
164     }
165 
166 
167     // -------------------------------------------------------------------------
168 
169 
170     NdrOptionVec
OptionVecVal(const std::string & optionStr)171     OptionVecVal(const std::string& optionStr)
172     {
173         std::vector<std::string> tokens = TfStringSplit(optionStr, "|");
174 
175         // The input string should be formatted as one of the following:
176         //
177         //     list:   "option1|option2|option3|..."
178         //     mapper: "key1:value1|key2:value2|..."
179         //
180         // If it's a mapper, return the result as a list of key-value tuples to
181         // preserve order.
182 
183         NdrOptionVec options;
184 
185         for (const std::string& token : tokens) {
186             size_t colonPos = token.find(':');
187 
188             if (colonPos != std::string::npos) {
189                 options.emplace_back(std::make_pair(
190                     TfToken(token.substr(0, colonPos)),
191                     TfToken(token.substr(colonPos + 1)))
192                 );
193             } else {
194                 options.emplace_back(std::make_pair(
195                     TfToken(token),
196                     TfToken())
197                 );
198             }
199         }
200 
201         return options;
202     }
203 
204 
205     // -------------------------------------------------------------------------
206 
207 
208     std::string
CreateStringFromStringVec(const NdrStringVec & stringVec)209     CreateStringFromStringVec(const NdrStringVec& stringVec)
210     {
211         return TfStringJoin(stringVec, "|");
212     }
213 
214 
215     // -------------------------------------------------------------------------
216 
217 
218     bool
IsPropertyAnAssetIdentifier(const NdrTokenMap & metadata)219     IsPropertyAnAssetIdentifier(const NdrTokenMap& metadata)
220     {
221         const NdrTokenMap::const_iterator widgetSearch =
222             metadata.find(SdrPropertyMetadata->Widget);
223 
224         if (widgetSearch != metadata.end()) {
225             const TfToken widget = TfToken(widgetSearch->second);
226 
227             if ((widget == _tokens->assetIdInput) ||
228                 (widget == _tokens->filename) ||
229                 (widget == _tokens->fileInput)) {
230                 return true;
231             }
232         }
233 
234         return false;
235     }
236 
237     // -------------------------------------------------------------------------
238 
239     bool
IsPropertyATerminal(const NdrTokenMap & metadata)240     IsPropertyATerminal(const NdrTokenMap& metadata)
241     {
242         const NdrTokenMap::const_iterator renderTypeSearch =
243             metadata.find(SdrPropertyMetadata->RenderType);
244 
245         if (renderTypeSearch != metadata.end()) {
246             // If the property is a SdrPropertyTypes->Terminal, then the
247             // renderType value will be "terminal <terminalName>", where the
248             // <terminalName> is the specific kind of terminal.  To identify
249             // the property as a terminal, we only need to check that the first
250             // string in the renderType value specifies "terminal"
251             if (TfStringStartsWith(
252                 renderTypeSearch->second, _tokens->terminal)) {
253                 return true;
254             }
255         }
256 
257         return false;
258     }
259 
260     // -------------------------------------------------------------------------
261 
262     TfToken
GetRoleFromMetadata(const NdrTokenMap & metadata)263     GetRoleFromMetadata(const NdrTokenMap& metadata)
264     {
265         const NdrTokenMap::const_iterator roleSearch =
266             metadata.find(SdrPropertyMetadata->Role);
267 
268         if (roleSearch != metadata.end()) {
269             // If the value found is an allowed value, then we can return it
270             const TfToken role = TfToken(roleSearch->second);
271             if (std::find(SdrPropertyRole->allTokens.begin(),
272                           SdrPropertyRole->allTokens.end(),
273                           role) != SdrPropertyRole->allTokens.end()) {
274                 return role;
275             }
276         }
277         // Return an empty token if no "role" metadata or acceptable value found
278         return TfToken();
279     }
280 }
281 
282 PXR_NAMESPACE_CLOSE_SCOPE
283