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