1 //
2 // Copyright 2019 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/usdImaging/plugin/sdrGlslfx/parserPlugin.h"
25 
26 #include "pxr/base/vt/array.h"
27 #include "pxr/base/gf/vec2f.h"
28 #include "pxr/base/gf/vec3f.h"
29 #include "pxr/base/gf/matrix4f.h"
30 #include "pxr/base/gf/matrix4d.h"
31 #include "pxr/base/tf/staticTokens.h"
32 #include "pxr/usd/ar/resolver.h"
33 #include "pxr/usd/ndr/nodeDiscoveryResult.h"
34 #include "pxr/usd/sdr/shaderNode.h"
35 #include "pxr/usd/sdr/shaderProperty.h"
36 #include "pxr/imaging/hio/glslfx.h"
37 
38 PXR_NAMESPACE_OPEN_SCOPE
39 
40 NDR_REGISTER_PARSER_PLUGIN(SdrGlslfxParserPlugin);
41 
42 TF_DEFINE_PRIVATE_TOKENS(
43     _tokens,
44 
45     // Discovery and source type
46     ((discoveryType, "glslfx"))
47     ((sourceType, "glslfx"))
48 );
49 
50 const NdrTokenVec&
GetDiscoveryTypes() const51 SdrGlslfxParserPlugin::GetDiscoveryTypes() const
52 {
53     static const NdrTokenVec _DiscoveryTypes = {_tokens->discoveryType};
54     return _DiscoveryTypes;
55 }
56 
57 const TfToken&
GetSourceType() const58 SdrGlslfxParserPlugin::GetSourceType() const
59 {
60     return _tokens->sourceType;
61 }
62 
63 static VtValue
ConvertToSdrCompatibleValueAndType(VtValue any,size_t * arraySize,TfToken * sdrType)64 ConvertToSdrCompatibleValueAndType(
65     VtValue any,
66     size_t * arraySize,
67     TfToken * sdrType)
68 {
69     // Unrecognized type by default
70     *sdrType = SdrPropertyTypes->Unknown;
71 
72     // Not an array by default.
73     *arraySize = 0;
74 
75     // XXX : Add support for the following sdr types:
76     //       String, Struct, Terminal and Vstruct.
77     // XXX : We could add some glslfx metadata to recognize if this GfVec3f
78     //       is an Sdr type Vector, Color, Point or a Normal..
79     if (any.IsHolding< std::vector<VtValue> >()) {
80 
81         std::vector<VtValue> const & anyVec = any.Get< std::vector<VtValue> >();
82 
83         // support for matrix
84         if (anyVec.size() == 16) {
85             if (anyVec[0].IsHolding<double>()) {
86                 GfMatrix4d retMat;
87                 double * m = retMat.GetArray();
88                 for(int i=0; i < 16; i++) {
89                     m[i] = anyVec[i].UncheckedGet<double>();
90                 }
91                 *sdrType = SdrPropertyTypes->Matrix;
92                 return VtValue(retMat);
93             }
94             else if (anyVec[0].IsHolding<float>()) {
95                 GfMatrix4f retMat;
96                 float * m = retMat.GetArray();
97                 for(int i=0; i < 16; i++) {
98                     m[i] = anyVec[i].UncheckedGet<float>();
99                 }
100                 *sdrType = SdrPropertyTypes->Matrix;
101                 return VtValue(retMat);
102             } else {
103                 return VtValue();
104             }
105 
106         // support for vectors length 1
107         } else if (anyVec.size() == 1) {
108             if (anyVec[0].IsHolding<double>()){
109                 // Sdr has no doubles, converting them to floats
110                 *sdrType = SdrPropertyTypes->Float;
111                 return VtValue( (float)anyVec[0].UncheckedGet<double>());
112 
113             } else if (anyVec[0].IsHolding<float>()){
114                 *sdrType = SdrPropertyTypes->Float;
115                 return VtValue( anyVec[0].UncheckedGet<float>());
116             }
117 
118         // support for vectors length 2
119         } else if (anyVec.size() == 2) {
120             VtFloatArray retVec(2);
121             for (int i = 0; i < 2; i++) {
122                 if (anyVec[i].IsHolding<double>()) {
123                     retVec[i] = anyVec[i].UncheckedGet<double>();
124                 } else if (anyVec[i].IsHolding<float>()) {
125                     retVec[i] = anyVec[i].UncheckedGet<float>();
126                 } else {
127                     return VtValue();
128                 }
129             }
130 
131             *sdrType = SdrPropertyTypes->Float;
132             *arraySize = 2;
133             return VtValue(retVec);
134 
135         } else if (anyVec.size() == 3) {
136             // support for vectors length 3
137             GfVec3f retVec;
138             for (int i = 0; i < 3; i++) {
139                 if (anyVec[i].IsHolding<double>()) {
140                     retVec[i] = anyVec[i].UncheckedGet<double>();
141                 } else if (anyVec[i].IsHolding<float>()) {
142                     retVec[i] = anyVec[i].UncheckedGet<float>();
143                 } else {
144                     return VtValue();
145                 }
146             }
147 
148             *sdrType = SdrPropertyTypes->Color;
149             return VtValue(retVec);
150 
151         // support for vectors length 4
152         } else if (anyVec.size() == 4) {
153             VtFloatArray retVec(4);
154             for (int i = 0; i < 4; i++) {
155                 if (anyVec[i].IsHolding<double>()) {
156                     retVec[i] = anyVec[i].UncheckedGet<double>();
157                 } else if (anyVec[i].IsHolding<float>()) {
158                     retVec[i] = anyVec[i].UncheckedGet<float>();
159                 } else {
160                     return VtValue();
161                 }
162             }
163 
164             *sdrType = SdrPropertyTypes->Float;
165             *arraySize = 4;
166             return VtValue(retVec);
167         }
168 
169     } else if (any.IsHolding<double>()){
170         // Sdr has no doubles, converting them to floats
171         *sdrType = SdrPropertyTypes->Float;
172         return VtValue( (float)any.UncheckedGet<double>());
173 
174     } else if (any.IsHolding<float>()){
175         *sdrType = SdrPropertyTypes->Float;
176         return VtValue( any.UncheckedGet<float>());
177 
178     } else if (any.IsHolding<int>()){
179         *sdrType = SdrPropertyTypes->Int;
180         return VtValue( any.UncheckedGet<int>());
181 
182     } else if (any.IsHolding<bool>()){
183         // Sdr has no bool, converting them to int
184         *sdrType = SdrPropertyTypes->Int;
185         return VtValue( (int)any.UncheckedGet<bool>());
186     }
187 
188     return any;
189 }
190 
191 NdrNodeUniquePtr
Parse(const NdrNodeDiscoveryResult & discoveryResult)192 SdrGlslfxParserPlugin::Parse(const NdrNodeDiscoveryResult& discoveryResult)
193 {
194     std::unique_ptr<HioGlslfx> glslfx;
195 
196     if (!discoveryResult.uri.empty()) {
197 #if AR_VERSION == 1
198         // Get the resolved URI to a location that can be read
199         // by the glslfx parser.
200         bool localFetchSuccessful = ArGetResolver().FetchToLocalResolvedPath(
201             discoveryResult.uri,
202             discoveryResult.resolvedUri
203         );
204 
205         if (!localFetchSuccessful) {
206             TF_WARN("Could not localize the glslfx at URI [%s] into"
207                     " a local path. An invalid Sdr node definition"
208                     " will be created.",
209                     discoveryResult.uri.c_str());
210             return NdrParserPlugin::GetInvalidNode(discoveryResult);
211         }
212 #endif
213 
214         glslfx = std::make_unique<HioGlslfx>(discoveryResult.resolvedUri);
215 
216     } else if (!discoveryResult.sourceCode.empty()) {
217         std::istringstream sourceCodeStream(discoveryResult.sourceCode);
218         glslfx = std::make_unique<HioGlslfx>(sourceCodeStream);
219 
220     } else {
221         TF_WARN("Invalid NdrNodeDiscoveryResult with identifier %s: both uri "
222             "and sourceCode are empty.", discoveryResult.identifier.GetText());
223 
224         return NdrParserPlugin::GetInvalidNode(discoveryResult);
225     }
226 
227     std::string errorString;
228     if (!glslfx->IsValid(&errorString)){
229         TF_WARN("Failed to parse glslfx at URI [%s] error [%s]",
230             discoveryResult.uri.c_str(),
231             errorString.c_str());
232     }
233 
234     NdrPropertyUniquePtrVec nodeProperties;
235 
236     HioGlslfxConfig::Parameters params = glslfx->GetParameters();
237     for (HioGlslfxConfig::Parameter const & p : params) {
238 
239         size_t arraySize = 0;
240         TfToken sdrType;
241         VtValue defaultValue = ConvertToSdrCompatibleValueAndType(
242             p.defaultValue,
243             &arraySize,
244             &sdrType);
245 
246         NdrTokenMap hints;
247         NdrOptionVec options;
248         NdrTokenMap localMetadata;
249         nodeProperties.push_back(
250             std::make_unique<SdrShaderProperty>(
251                 TfToken(p.name),
252                 sdrType,
253                 defaultValue,
254                 false,
255                 arraySize,
256                 localMetadata,
257                 hints,
258                 options
259             ));
260     }
261 
262     HioGlslfxConfig::Textures textures = glslfx->GetTextures();
263     for (HioGlslfxConfig::Texture const & t : textures) {
264 
265         size_t arraySize = 0;
266         TfToken sdrType;
267         VtValue defaultValue = ConvertToSdrCompatibleValueAndType(
268             t.defaultValue,
269             &arraySize,
270             &sdrType);
271 
272         // Check for a default value, or fallback to all black.
273         if (defaultValue.IsEmpty()) {
274             sdrType = SdrPropertyTypes->Color;
275             defaultValue = VtValue(GfVec3f(0.0,0.0,0.0));
276         }
277 
278         NdrTokenMap hints;
279         NdrOptionVec options;
280         NdrTokenMap localMetadata;
281         nodeProperties.push_back(
282             std::make_unique<SdrShaderProperty>(
283                 TfToken(t.name),
284                 sdrType,
285                 defaultValue,
286                 false,
287                 arraySize,
288                 localMetadata,
289                 hints,
290                 options
291             ));
292     }
293 
294     NdrTokenMap metadata = discoveryResult.metadata;
295     std::vector<std::string> primvarNames;
296     if (metadata.count(SdrNodeMetadata->Primvars)) {
297         primvarNames.push_back(metadata.at(SdrNodeMetadata->Primvars));
298     }
299 
300     HioGlslfxConfig::Attributes attributes = glslfx->GetAttributes();
301     for (HioGlslfxConfig::Attribute const & a : attributes) {
302         primvarNames.push_back(a.name);
303     }
304 
305     metadata[SdrNodeMetadata->Primvars] = TfStringJoin(primvarNames, "|");
306 
307     // XXX: Add support for reading metadata from glslfx and converting
308     //      to node metadata
309 
310     return std::make_unique<SdrShaderNode>(
311         discoveryResult.identifier,
312         discoveryResult.version,
313         discoveryResult.name,
314         discoveryResult.family,
315         _tokens->sourceType,
316         _tokens->sourceType,
317         discoveryResult.resolvedUri,
318         discoveryResult.resolvedUri,
319         std::move(nodeProperties),
320         metadata,
321         discoveryResult.sourceCode);
322 }
323 
324 PXR_NAMESPACE_CLOSE_SCOPE
325