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/usdImaging/usdImagingGL/drawModeAdapter.h"
25 #include "pxr/usdImaging/usdImagingGL/package.h"
26 
27 #include "pxr/usdImaging/usdImaging/gprimAdapter.h"
28 #include "pxr/usdImaging/usdImaging/indexProxy.h"
29 #include "pxr/usdImaging/usdImaging/instancerContext.h"
30 #include "pxr/usdImaging/usdImaging/tokens.h"
31 
32 #include "pxr/imaging/hd/material.h"
33 
34 #include "pxr/imaging/hio/glslfx.h"
35 #include "pxr/imaging/hio/image.h"
36 #include "pxr/imaging/pxOsd/tokens.h"
37 
38 #include "pxr/usd/usdGeom/modelAPI.h"
39 #include "pxr/usd/sdr/registry.h"
40 #include "pxr/usd/sdr/shaderNode.h"
41 
42 #include "pxr/base/gf/matrix4f.h"
43 #include "pxr/base/tf/type.h"
44 
45 PXR_NAMESPACE_OPEN_SCOPE
46 
47 TF_DEFINE_PRIVATE_TOKENS(
48     _tokens,
49 
50     (material)
51 
52     (cardsUv)
53     (cardsTexAssign)
54 
55     (textureXPosColor)
56     (textureYPosColor)
57     (textureZPosColor)
58     (textureXNegColor)
59     (textureYNegColor)
60     (textureZNegColor)
61     (textureXPosOpacity)
62     (textureYPosOpacity)
63     (textureZPosOpacity)
64     (textureXNegOpacity)
65     (textureYNegOpacity)
66     (textureZNegOpacity)
67 
68     (worldtoscreen)
69 
70     (displayRoughness)
71 
72     (file)
73     (st)
74     (rgb)
75     (a)
76     (fallback)
77     (minFilter)
78     (magFilter)
79     (linear)
80     (linearMipmapLinear)
81 
82     (varname)
83     (result)
84     (activeTexCard)
85 );
86 
87 namespace {
88     enum AxesMask : uint8_t {
89         xPos = (1 << 0),
90         yPos = (1 << 1),
91         zPos = (1 << 2),
92         xNeg = (1 << 3),
93         yNeg = (1 << 4),
94         zNeg = (1 << 5),
95         xAxis = (xPos | xNeg),
96         yAxis = (yPos | yNeg),
97         zAxis = (zPos | zNeg),
98     };
99 }
100 
TF_REGISTRY_FUNCTION(TfType)101 TF_REGISTRY_FUNCTION(TfType)
102 {
103     typedef UsdImagingGLDrawModeAdapter Adapter;
104     TfType t = TfType::Define<Adapter, TfType::Bases<Adapter::BaseAdapter> >();
105     t.SetFactory< UsdImagingPrimAdapterFactory<Adapter> >();
106 }
107 
108 static SdfPath
_GetMaterialPath(UsdPrim const & prim)109 _GetMaterialPath(UsdPrim const& prim)
110 {
111     const SdfPath matPath = SdfPath(_tokens->material.GetString());
112     return prim.GetPath().AppendPath(matPath);
113 }
114 
UsdImagingGLDrawModeAdapter()115 UsdImagingGLDrawModeAdapter::UsdImagingGLDrawModeAdapter()
116     : UsdImagingPrimAdapter()
117     , _schemaColor(0)
118 {
119     // Look up the default color in the schema registry.
120     const UsdPrimDefinition *primDef =
121         UsdSchemaRegistry::GetInstance()
122         .FindAppliedAPIPrimDefinition(TfToken("GeomModelAPI"));
123     if (primDef) {
124         primDef->GetAttributeFallbackValue(
125             UsdGeomTokens->modelDrawModeColor, &_schemaColor);
126     }
127 }
128 
~UsdImagingGLDrawModeAdapter()129 UsdImagingGLDrawModeAdapter::~UsdImagingGLDrawModeAdapter()
130 {
131 }
132 
133 bool
ShouldCullChildren() const134 UsdImagingGLDrawModeAdapter::ShouldCullChildren() const
135 {
136     return true;
137 }
138 
139 bool
CanPopulateUsdInstance() const140 UsdImagingGLDrawModeAdapter::CanPopulateUsdInstance() const
141 {
142     return true;
143 }
144 
145 bool
IsSupported(UsdImagingIndexProxy const * index) const146 UsdImagingGLDrawModeAdapter::IsSupported(
147     UsdImagingIndexProxy const* index) const
148 {
149     return true;
150 }
151 
152 SdfPath
Populate(UsdPrim const & prim,UsdImagingIndexProxy * index,UsdImagingInstancerContext const * instancerContext)153 UsdImagingGLDrawModeAdapter::Populate(UsdPrim const& prim,
154                                     UsdImagingIndexProxy* index,
155                                     UsdImagingInstancerContext const*
156                                        instancerContext)
157 {
158     SdfPath cachePath = UsdImagingGprimAdapter::_ResolveCachePath(
159         prim.GetPath(), instancerContext);
160 
161     // The draw mode adapter only supports models or unloaded prims.
162     // This is enforced in UsdImagingDelegate::_IsDrawModeApplied.
163     if (!TF_VERIFY(prim.IsModel() || !prim.IsLoaded(), "<%s>",
164                    prim.GetPath().GetText())) {
165         return SdfPath();
166     }
167 
168     // There should have been a non-default draw mode applied for this
169     // adapter to be called; this is enforced in
170     // UsdImagingDelegate::_IsDrawModeApplied.
171     TfToken drawMode = GetModelDrawMode(prim);
172     if (drawMode == UsdGeomTokens->default_ && instancerContext) {
173         drawMode = instancerContext->instanceDrawMode;
174     }
175     if (!TF_VERIFY(drawMode != UsdGeomTokens->default_, "<%s>",
176         prim.GetPath().GetText())) {
177         return SdfPath();
178     }
179 
180     // If this object is instanced, we need to use the instancer adapter for the
181     // rprim, which will forward to the draw mode adapter but additionally
182     // handle instancer attributes like instance index.
183     UsdImagingPrimAdapterSharedPtr rprimAdapter =
184         (instancerContext && instancerContext->instancerAdapter) ?
185         instancerContext->instancerAdapter :
186         shared_from_this();
187 
188     // If this prim isn't instanced, cachePrim will be the same as "prim", but
189     // if it is instanced the instancer adapters expect us to pass in this
190     // prim, which should point to the instancer.
191     UsdPrim cachePrim = _GetPrim(cachePath.GetAbsoluteRootOrPrimPath());
192 
193     if (drawMode == UsdGeomTokens->origin ||
194         drawMode == UsdGeomTokens->bounds) {
195         // Origin and bounds both draw as basis curves
196         if (!index->IsRprimTypeSupported(HdPrimTypeTokens->basisCurves)) {
197             TF_WARN("Unable to display origin or bounds draw mode for model "
198                     "%s, basis curves not supported", cachePath.GetText());
199             return SdfPath();
200         }
201         index->InsertRprim(HdPrimTypeTokens->basisCurves,
202             cachePath, cachePrim, rprimAdapter);
203         HD_PERF_COUNTER_INCR(UsdImagingTokens->usdPopulatedPrimCount);
204     } else if (drawMode == UsdGeomTokens->cards) {
205         // Cards draw as a mesh
206         if (!index->IsRprimTypeSupported(HdPrimTypeTokens->mesh)) {
207             TF_WARN("Unable to display cards draw mode for model %s, "
208                     "meshes not supported", cachePath.GetText());
209             return SdfPath();
210         }
211         index->InsertRprim(HdPrimTypeTokens->mesh,
212             cachePath, cachePrim, rprimAdapter);
213         HD_PERF_COUNTER_INCR(UsdImagingTokens->usdPopulatedPrimCount);
214     } else {
215         TF_CODING_ERROR("Model <%s> has unsupported drawMode '%s'",
216             prim.GetPath().GetText(), drawMode.GetText());
217         return SdfPath();
218     }
219 
220     // As long as we're passing cachePrim to InsertRprim, we need to fix up
221     // the dependency map ourselves. For USD edit purposes, we depend on the
222     // prototype prim ("prim"), rather than the instancer prim.
223     // See similar code in GprimAdapter::_AddRprim.
224     if (instancerContext != nullptr) {
225         index->RemovePrimInfoDependency(cachePath);
226         index->AddDependency(cachePath, prim);
227     }
228 
229     // Additionally, insert the material.
230     SdfPath materialPath = _GetMaterialPath(prim);
231     if (index->IsSprimTypeSupported(HdPrimTypeTokens->material) &&
232         !index->IsPopulated(materialPath)) {
233         index->InsertSprim(HdPrimTypeTokens->material,
234             materialPath, prim, shared_from_this());
235         HD_PERF_COUNTER_INCR(UsdImagingTokens->usdPopulatedPrimCount);
236     }
237 
238     // Record the drawmode for use in UpdateForTime().
239     _drawModeMap.insert(std::make_pair(cachePath, drawMode));
240 
241     return cachePath;
242 }
243 
244 bool
_IsMaterialPath(SdfPath const & path) const245 UsdImagingGLDrawModeAdapter::_IsMaterialPath(SdfPath const& path) const
246 {
247     return path.GetNameToken() == _tokens->material;
248 }
249 
250 void
_RemovePrim(SdfPath const & cachePath,UsdImagingIndexProxy * index)251 UsdImagingGLDrawModeAdapter::_RemovePrim(SdfPath const& cachePath,
252                                        UsdImagingIndexProxy* index)
253 {
254     if (_IsMaterialPath(cachePath)) {
255         index->RemoveSprim(HdPrimTypeTokens->material, cachePath);
256     } else {
257         _drawModeMap.erase(cachePath);
258         index->RemoveRprim(cachePath);
259     }
260 }
261 
262 void
MarkDirty(UsdPrim const & prim,SdfPath const & cachePath,HdDirtyBits dirty,UsdImagingIndexProxy * index)263 UsdImagingGLDrawModeAdapter::MarkDirty(UsdPrim const& prim,
264                                      SdfPath const& cachePath,
265                                      HdDirtyBits dirty,
266                                      UsdImagingIndexProxy* index)
267 {
268     if (_IsMaterialPath(cachePath)) {
269         index->MarkSprimDirty(cachePath, dirty);
270     } else {
271         index->MarkRprimDirty(cachePath, dirty);
272     }
273 }
274 
275 void
MarkTransformDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)276 UsdImagingGLDrawModeAdapter::MarkTransformDirty(UsdPrim const& prim,
277                                               SdfPath const& cachePath,
278                                               UsdImagingIndexProxy* index)
279 {
280     if (!_IsMaterialPath(cachePath)) {
281         index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyTransform);
282     }
283 }
284 
285 void
MarkVisibilityDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)286 UsdImagingGLDrawModeAdapter::MarkVisibilityDirty(UsdPrim const& prim,
287                                                SdfPath const& cachePath,
288                                                UsdImagingIndexProxy* index)
289 {
290     if (!_IsMaterialPath(cachePath)) {
291         index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyVisibility);
292     }
293 }
294 
295 void
MarkMaterialDirty(UsdPrim const & prim,SdfPath const & cachePath,UsdImagingIndexProxy * index)296 UsdImagingGLDrawModeAdapter::MarkMaterialDirty(UsdPrim const& prim,
297                                                SdfPath const& cachePath,
298                                                UsdImagingIndexProxy* index)
299 {
300     if (_IsMaterialPath(cachePath)) {
301         index->MarkSprimDirty(cachePath, HdMaterial::DirtyResource);
302     } else {
303         // If the Usd material changed, it could mean the primvar set also
304         // changed Hydra doesn't currently manage detection and propagation of
305         // these changes, so we must mark the rprim dirty.
306         index->MarkRprimDirty(cachePath, HdChangeTracker::DirtyMaterialId);
307     }
308 }
309 
310 bool
_HasVaryingExtent(UsdPrim const & prim) const311 UsdImagingGLDrawModeAdapter::_HasVaryingExtent(UsdPrim const& prim) const
312 {
313     UsdAttribute attr;
314 
315     attr = prim.GetAttribute(UsdGeomTokens->extent);
316     if (attr && attr.ValueMightBeTimeVarying())
317         return true;
318 
319     attr = prim.GetAttribute(UsdGeomTokens->extentsHint);
320     if (attr && attr.ValueMightBeTimeVarying())
321         return true;
322 
323     return false;
324 }
325 
326 void
_ComputeGeometryData(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time,TfToken const & drawMode,VtValue * topology,VtValue * points,GfRange3d * extent,VtValue * uv,VtValue * assign) const327 UsdImagingGLDrawModeAdapter::_ComputeGeometryData(
328     UsdPrim const& prim,
329     SdfPath const& cachePath,
330     UsdTimeCode time,
331     TfToken const& drawMode,
332     VtValue* topology,
333     VtValue* points,
334     GfRange3d* extent,
335     VtValue* uv,
336     VtValue* assign) const
337 {
338     if (drawMode == UsdGeomTokens->origin) {
339         *extent = _ComputeExtent(prim,
340             _HasVaryingExtent(prim) ? time : UsdTimeCode::EarliestTime());
341         _GenerateOriginGeometry(topology, points, *extent);
342 
343     } else if (drawMode == UsdGeomTokens->bounds) {
344         *extent = _ComputeExtent(prim,
345             _HasVaryingExtent(prim) ? time : UsdTimeCode::EarliestTime());
346         _GenerateBoundsGeometry(topology, points, *extent);
347 
348     } else if (drawMode == UsdGeomTokens->cards) {
349         UsdGeomModelAPI model(prim);
350         if (!model) {
351             // The population rules in UsdImagingDelegate disallow this.
352             TF_CODING_ERROR("Prim has draw mode 'cards' but geom model "
353                             "API schema is not applied.");
354             return;
355         }
356 
357         TfToken cardGeometry;
358         model.GetModelCardGeometryAttr().Get(&cardGeometry);
359         if (cardGeometry == UsdGeomTokens->fromTexture) {
360             // In "fromTexture" mode, read all the geometry data in from
361             // the textures.
362             _GenerateCardsFromTextureGeometry(topology, points,
363                     uv, assign, extent, prim);
364 
365         } else {
366             // First compute the extents.
367             *extent = _ComputeExtent(prim,
368                 _HasVaryingExtent(prim) ? time : UsdTimeCode::EarliestTime());
369 
370             // Generate mask for suppressing axes with no textures
371             uint8_t axes_mask = 0;
372             const TfToken textureAttrs[6] = {
373                 UsdGeomTokens->modelCardTextureXPos,
374                 UsdGeomTokens->modelCardTextureYPos,
375                 UsdGeomTokens->modelCardTextureZPos,
376                 UsdGeomTokens->modelCardTextureXNeg,
377                 UsdGeomTokens->modelCardTextureYNeg,
378                 UsdGeomTokens->modelCardTextureZNeg,
379             };
380             const uint8_t mask[6] = {
381                 xPos, yPos, zPos, xNeg, yNeg, zNeg,
382             };
383             for (int i = 0; i < 6; ++i) {
384                 SdfAssetPath asset;
385                 prim.GetAttribute(textureAttrs[i]).Get(&asset, time);
386                 if (!asset.GetAssetPath().empty()) {
387                     axes_mask |= mask[i];
388                 }
389             }
390 
391             // If no textures are bound, generate the full geometry.
392             if (axes_mask == 0) { axes_mask = xAxis | yAxis | zAxis; }
393 
394             // Generate UVs.
395             _GenerateTextureCoordinates(uv, assign, axes_mask);
396 
397             // Generate geometry based on card type.
398             if (cardGeometry == UsdGeomTokens->cross) {
399                 _GenerateCardsCrossGeometry(topology, points, *extent,
400                     axes_mask);
401             } else if (cardGeometry == UsdGeomTokens->box) {
402                 _GenerateCardsBoxGeometry(topology, points, *extent,
403                     axes_mask);
404             } else {
405                 TF_CODING_ERROR("<%s> Unexpected card geometry mode %s",
406                     cachePath.GetText(), cardGeometry.GetText());
407             }
408 
409             // Issue warnings for zero-area faces that we're supposedly
410             // drawing.
411             _SanityCheckFaceSizes(cachePath, *extent, axes_mask);
412         }
413     } else {
414         TF_CODING_ERROR("<%s> Unexpected draw mode %s",
415             cachePath.GetText(), drawMode.GetText());
416     }
417 }
418 
419 /*virtual*/
420 VtValue
GetTopology(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const421 UsdImagingGLDrawModeAdapter::GetTopology(UsdPrim const& prim,
422                                          SdfPath const& cachePath,
423                                          UsdTimeCode time) const
424 {
425     TRACE_FUNCTION();
426     HF_MALLOC_TAG_FUNCTION();
427 
428     TfToken drawMode = UsdGeomTokens->default_;
429     _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
430     if (TF_VERIFY(it != _drawModeMap.end())) {
431         drawMode = it->second;
432     }
433 
434     VtValue topology;
435     VtValue points;
436     VtValue uv;
437     VtValue assign;
438     GfRange3d extent;
439     _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
440         &points, &extent, &uv, &assign);
441     return topology;
442 }
443 
444 /*virtual*/
445 GfRange3d
GetExtent(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const446 UsdImagingGLDrawModeAdapter::GetExtent(UsdPrim const& prim,
447                                        SdfPath const& cachePath,
448                                        UsdTimeCode time) const
449 {
450     TRACE_FUNCTION();
451     HF_MALLOC_TAG_FUNCTION();
452 
453     TfToken drawMode = UsdGeomTokens->default_;
454     _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
455     if (TF_VERIFY(it != _drawModeMap.end())) {
456         drawMode = it->second;
457     }
458 
459     VtValue topology;
460     VtValue points;
461     VtValue uv;
462     VtValue assign;
463     GfRange3d extent;
464     _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
465         &points, &extent, &uv, &assign);
466     return extent;
467 }
468 
469 
470 /*virtual*/
471 bool
GetDoubleSided(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const472 UsdImagingGLDrawModeAdapter::GetDoubleSided(UsdPrim const& prim,
473                                             SdfPath const& cachePath,
474                                             UsdTimeCode time) const
475 {
476     return false;
477 }
478 
479 /*virtual*/
480 VtValue
Get(UsdPrim const & prim,SdfPath const & cachePath,TfToken const & key,UsdTimeCode time,VtIntArray * outIndices) const481 UsdImagingGLDrawModeAdapter::Get(UsdPrim const& prim,
482                                  SdfPath const& cachePath,
483                                  TfToken const& key,
484                                  UsdTimeCode time,
485                                  VtIntArray *outIndices) const
486 {
487     TRACE_FUNCTION();
488 
489     VtValue value;
490     UsdGeomModelAPI model(prim);
491 
492     if (key == HdTokens->displayColor) {
493         VtVec3fArray color = VtVec3fArray(1);
494         GfVec3f drawModeColor;
495         if (model) {
496             model.GetModelDrawModeColorAttr().Get(&drawModeColor);
497         } else {
498             drawModeColor = _schemaColor;
499         }
500 
501         color[0] = drawModeColor;
502         value = color;
503 
504     } else if (key == HdTokens->displayOpacity) {
505         VtFloatArray opacity = VtFloatArray(1);
506 
507         // Full opacity.
508         opacity[0] = 1.0f;
509         value = opacity;
510 
511     } else if (key == HdTokens->widths) {
512         VtFloatArray widths = VtFloatArray(1);
513         widths[0] = 1.0f;
514         value = widths;
515 
516     } else if (key == HdTokens->points) {
517         TRACE_FUNCTION_SCOPE("points");
518         TfToken drawMode = UsdGeomTokens->default_;
519         _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
520         if (TF_VERIFY(it != _drawModeMap.end())) {
521             drawMode = it->second;
522         }
523 
524         VtValue topology;
525         VtValue points;
526         VtValue uv;
527         VtValue assign;
528         GfRange3d extent;
529         _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
530             &points, &extent, &uv, &assign);
531         return points;
532 
533     } else if (key == _tokens->cardsUv) {
534         TRACE_FUNCTION_SCOPE("cardsUV");
535         TfToken drawMode = UsdGeomTokens->default_;
536         _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
537         if (TF_VERIFY(it != _drawModeMap.end())) {
538             drawMode = it->second;
539         }
540 
541         VtValue topology;
542         VtValue points;
543         VtValue uv;
544         VtValue assign;
545         GfRange3d extent;
546         _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
547             &points, &extent, &uv, &assign);
548         return uv;
549 
550     } else if (key == _tokens->cardsTexAssign) {
551         TRACE_FUNCTION_SCOPE("cardsTexAssign");
552         TfToken drawMode = UsdGeomTokens->default_;
553         _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
554         if (TF_VERIFY(it != _drawModeMap.end())) {
555             drawMode = it->second;
556         }
557 
558         VtValue topology;
559         VtValue points;
560         VtValue uv;
561         VtValue assign;
562         GfRange3d extent;
563         _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
564             &points, &extent, &uv, &assign);
565         return assign;
566 
567     } else if (key == _tokens->displayRoughness) {
568         return VtValue(1.0f);
569     }
570 
571     return value;
572 }
573 
574 /*virtual*/
575 SdfPath
GetMaterialId(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const576 UsdImagingGLDrawModeAdapter::GetMaterialId(UsdPrim const& prim,
577                                            SdfPath const& cachePath,
578                                            UsdTimeCode time) const
579 {
580     return _GetMaterialPath(prim);
581 }
582 
583 /*virtual*/
584 VtValue
GetMaterialResource(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const585 UsdImagingGLDrawModeAdapter::GetMaterialResource(UsdPrim const& prim,
586                             SdfPath const& cachePath,
587                             UsdTimeCode time) const
588 {
589     if (!_IsMaterialPath(cachePath)) {
590         return BaseAdapter::GetMaterialResource(prim, cachePath, time);
591     }
592 
593     UsdGeomModelAPI model(prim);
594 
595     SdfAssetPath path(UsdImagingGLPackageDrawModeShader());
596 
597     SdrRegistry &shaderReg = SdrRegistry::GetInstance();
598     SdrShaderNodeConstPtr sdrNode =
599         shaderReg.GetShaderNodeFromAsset(
600             path,
601             NdrTokenMap(),
602             TfToken(),
603             HioGlslfxTokens->glslfx);
604 
605     // An sdr node representing the drawCards.glslfx should be added
606     // to the registry, so we don't expect this to fail.
607     if (!TF_VERIFY(sdrNode)) {
608         return VtValue();
609     }
610 
611     // Generate material network with a terminal that points to
612     // the DrawMode glslfx shader.
613     TfToken const& terminalType = HdMaterialTerminalTokens->surface;
614     HdMaterialNetworkMap networkMap;
615     HdMaterialNetwork& network = networkMap.map[terminalType];
616     HdMaterialNode terminal;
617     terminal.path = cachePath;
618     terminal.identifier = sdrNode->GetIdentifier();
619 
620     const TfToken textureNames[12] = {
621         _tokens->textureXPosColor,
622         _tokens->textureYPosColor,
623         _tokens->textureZPosColor,
624         _tokens->textureXNegColor,
625         _tokens->textureYNegColor,
626         _tokens->textureZNegColor,
627         _tokens->textureXPosOpacity,
628         _tokens->textureYPosOpacity,
629         _tokens->textureZPosOpacity,
630         _tokens->textureXNegOpacity,
631         _tokens->textureYNegOpacity,
632         _tokens->textureZNegOpacity
633     };
634 
635     if (model) {
636         const TfToken textureAttrs[6] = {
637             UsdGeomTokens->modelCardTextureXPos,
638             UsdGeomTokens->modelCardTextureYPos,
639             UsdGeomTokens->modelCardTextureZPos,
640             UsdGeomTokens->modelCardTextureXNeg,
641             UsdGeomTokens->modelCardTextureYNeg,
642             UsdGeomTokens->modelCardTextureZNeg,
643         };
644 
645         GfVec3f drawModeColor;
646         model.GetModelDrawModeColorAttr().Get(&drawModeColor);
647         VtValue fallback = VtValue(GfVec4f(
648             drawModeColor[0], drawModeColor[1], drawModeColor[2],
649             1.0f));
650 
651         for (int i = 0; i < 6; ++i) {
652             SdfAssetPath textureFile;
653             prim.GetAttribute(textureAttrs[i]).Get(&textureFile, time);
654             if (!textureFile.GetAssetPath().empty()) {
655                 SdfPath textureNodePath = _GetMaterialPath(prim)
656                     .AppendProperty(textureAttrs[i]);
657 
658                 // Make texture node
659                 HdMaterialNode textureNode;
660                 textureNode.path = textureNodePath;
661                 textureNode.identifier = UsdImagingTokens->UsdUVTexture;
662                 textureNode.parameters[_tokens->st] = _tokens->cardsUv;
663                 textureNode.parameters[_tokens->fallback] = fallback;
664                 textureNode.parameters[_tokens->file] = textureFile;
665                 textureNode.parameters[_tokens->minFilter] =
666                     _tokens->linearMipmapLinear;
667                 textureNode.parameters[_tokens->magFilter] =
668                     _tokens->linear;
669 
670                 // Insert connection between texture node and terminal color
671                 // input
672                 HdMaterialRelationship colorRel;
673                 colorRel.inputId = textureNode.path;
674                 colorRel.inputName = _tokens->rgb;
675                 colorRel.outputId = terminal.path;
676                 colorRel.outputName = textureNames[i];
677                 network.relationships.emplace_back(std::move(colorRel));
678 
679                 // Insert connection between texture node and terminal
680                 // opacity input
681                 HdMaterialRelationship opacityRel;
682                 opacityRel.inputId = textureNode.path;
683                 opacityRel.inputName = _tokens->a;
684                 opacityRel.outputId = terminal.path;
685                 opacityRel.outputName = textureNames[i + 6];
686                 network.relationships.emplace_back(std::move(opacityRel));
687 
688                 // Insert texture node
689                 network.nodes.emplace_back(std::move(textureNode));
690             } else {
691                 terminal.parameters[textureNames[i]] = drawModeColor;
692                 terminal.parameters[textureNames[i + 6]] = VtValue(1.f);
693             }
694         }
695     } else {
696         for (int i = 0; i < 6; ++i) {
697             terminal.parameters[textureNames[i]] = _schemaColor;
698             terminal.parameters[textureNames[i + 6]] = VtValue(1.f);
699         }
700     }
701 
702     // Adding a primvar reader for the card assignment
703     // Make primvar reader node
704     SdfPath primvarNodePath = _GetMaterialPath(prim)
705         .AppendProperty(_tokens->cardsTexAssign);
706     HdMaterialNode primvarNode;
707     primvarNode.path = primvarNodePath;
708     primvarNode.identifier = UsdImagingTokens->UsdPrimvarReader_int;
709     primvarNode.parameters[_tokens->varname] = _tokens->cardsTexAssign;
710     primvarNode.parameters[_tokens->fallback] = VtValue(0);
711 
712     // Insert connection between primvar reader node and terminal
713     HdMaterialRelationship relPrimvar;
714     relPrimvar.inputId = primvarNode.path;
715     relPrimvar.inputName = _tokens->result;
716     relPrimvar.outputId = terminal.path;
717     relPrimvar.outputName = _tokens->activeTexCard;
718     network.relationships.emplace_back(std::move(relPrimvar));
719 
720     // Insert primvar reader node
721     network.nodes.emplace_back(std::move(primvarNode));
722 
723     // Insert terminal and update material network
724     networkMap.terminals.push_back(terminal.path);
725     network.nodes.emplace_back(std::move(terminal));
726 
727     return VtValue(networkMap);
728 }
729 
730 void
_CheckForTextureVariability(UsdPrim const & prim,HdDirtyBits dirtyBits,HdDirtyBits * timeVaryingBits) const731 UsdImagingGLDrawModeAdapter::_CheckForTextureVariability(
732     UsdPrim const& prim, HdDirtyBits dirtyBits,
733     HdDirtyBits *timeVaryingBits) const
734 {
735     const std::array<TfToken, 6> textureAttrs = {
736         UsdGeomTokens->modelCardTextureXPos,
737         UsdGeomTokens->modelCardTextureYPos,
738         UsdGeomTokens->modelCardTextureZPos,
739         UsdGeomTokens->modelCardTextureXNeg,
740         UsdGeomTokens->modelCardTextureYNeg,
741         UsdGeomTokens->modelCardTextureZNeg,
742     };
743 
744     for (const TfToken& attr: textureAttrs) {
745         if (_IsVarying(prim, attr, dirtyBits,
746                        UsdImagingTokens->usdVaryingTexture,
747                        timeVaryingBits, false)) {
748             break;
749         }
750     }
751 }
752 
753 void
TrackVariability(UsdPrim const & prim,SdfPath const & cachePath,HdDirtyBits * timeVaryingBits,UsdImagingInstancerContext const * instancerContext) const754 UsdImagingGLDrawModeAdapter::TrackVariability(UsdPrim const& prim,
755                                             SdfPath const& cachePath,
756                                             HdDirtyBits* timeVaryingBits,
757                                             UsdImagingInstancerContext const*
758                                                instancerContext) const
759 {
760     if (_IsMaterialPath(cachePath)) {
761         _CheckForTextureVariability(prim, HdMaterial::DirtyResource,
762                                     timeVaryingBits);
763         return;
764     }
765 
766     // Discover time-varying transforms. If this card is instantiated on an
767     // instance, skip since the instance adapter will handle transforms
768     // and master roots always have identity transform.
769     if (!prim.IsInstance()) {
770         _IsTransformVarying(prim,
771             HdChangeTracker::DirtyTransform,
772             UsdImagingTokens->usdVaryingXform,
773             timeVaryingBits);
774     }
775 
776     // Discover time-varying visibility.
777     _IsVarying(prim,
778             UsdGeomTokens->visibility,
779             HdChangeTracker::DirtyVisibility,
780             UsdImagingTokens->usdVaryingVisibility,
781             timeVaryingBits,
782             true);
783 
784     // Discover time-varying extents. Look for time samples on either the
785     // extent or extentsHint attribute.
786     if (!_IsVarying(prim,
787             UsdGeomTokens->extent,
788             HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyExtent,
789             UsdImagingTokens->usdVaryingExtent,
790             timeVaryingBits,
791             false)) {
792         _IsVarying(prim,
793             UsdGeomTokens->extentsHint,
794             HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyExtent,
795             UsdImagingTokens->usdVaryingExtent,
796             timeVaryingBits,
797             false);
798     }
799 }
800 
801 void
UpdateForTime(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time,HdDirtyBits requestedBits,UsdImagingInstancerContext const * instancerContext) const802 UsdImagingGLDrawModeAdapter::UpdateForTime(UsdPrim const& prim,
803                                          SdfPath const& cachePath,
804                                          UsdTimeCode time,
805                                          HdDirtyBits requestedBits,
806                                          UsdImagingInstancerContext const*
807                                             instancerContext) const
808 {
809     if (_IsMaterialPath(cachePath)) {
810         // The draw mode material doesn't make use of UpdateForTime.
811         return;
812     }
813 
814     UsdImagingPrimvarDescCache* primvarDescCache = _GetPrimvarDescCache();
815     UsdGeomModelAPI model(prim);
816 
817     // Geometry aspect
818     HdPrimvarDescriptorVector& primvars =
819         primvarDescCache->GetPrimvars(cachePath);
820 
821     if (requestedBits & HdChangeTracker::DirtyWidths) {
822         _MergePrimvar(&primvars, UsdGeomTokens->widths,
823                       HdInterpolationConstant);
824     }
825 
826     if (requestedBits & HdChangeTracker::DirtyPrimvar) {
827         _MergePrimvar(&primvars, HdTokens->displayColor,
828                       HdInterpolationConstant, HdPrimvarRoleTokens->color);
829         _MergePrimvar(&primvars, HdTokens->displayOpacity,
830                       HdInterpolationConstant);
831     }
832 
833     // We compute all of the below items together, since their derivations
834     // aren't easily separable.
835     HdDirtyBits geometryBits = HdChangeTracker::DirtyTopology |
836                                HdChangeTracker::DirtyPoints |
837                                HdChangeTracker::DirtyPrimvar |
838                                HdChangeTracker::DirtyExtent;
839 
840     if (requestedBits & geometryBits) {
841         TfToken drawMode = UsdGeomTokens->default_;
842         _DrawModeMap::const_iterator it = _drawModeMap.find(cachePath);
843         if (TF_VERIFY(it != _drawModeMap.end())) {
844             drawMode = it->second;
845         }
846 
847         VtValue topology;
848         GfRange3d extent;
849         VtValue points;
850         VtValue uv;
851         VtValue assign;
852         _ComputeGeometryData(prim, cachePath, time, drawMode, &topology,
853             &points, &extent, &uv, &assign);
854 
855         if (drawMode == UsdGeomTokens->cards) {
856             // Merge "cardsUv" and "cardsTexAssign" primvars
857             _MergePrimvar(&primvars, _tokens->cardsUv,
858                 HdInterpolationVertex);
859             _MergePrimvar(&primvars, _tokens->cardsTexAssign,
860                 HdInterpolationUniform);
861 
862             // XXX: backdoor into the material system.
863             _MergePrimvar(&primvars, _tokens->displayRoughness,
864                 HdInterpolationConstant);
865         }
866 
867         // Merge "points" primvar
868         _MergePrimvar(&primvars,
869             HdTokens->points,
870             HdInterpolationVertex,
871             HdPrimvarRoleTokens->point);
872     }
873 }
874 
875 HdDirtyBits
ProcessPropertyChange(UsdPrim const & prim,SdfPath const & cachePath,TfToken const & propertyName)876 UsdImagingGLDrawModeAdapter::ProcessPropertyChange(UsdPrim const& prim,
877                                                    SdfPath const& cachePath,
878                                                    TfToken const& propertyName)
879 {
880     const std::array<TfToken, 6> textureAttrs = {
881         UsdGeomTokens->modelCardTextureXPos,
882         UsdGeomTokens->modelCardTextureYPos,
883         UsdGeomTokens->modelCardTextureZPos,
884         UsdGeomTokens->modelCardTextureXNeg,
885         UsdGeomTokens->modelCardTextureYNeg,
886         UsdGeomTokens->modelCardTextureZNeg,
887     };
888 
889     if (_IsMaterialPath(cachePath)) {
890         // Check if a texture has been changed.
891         for (const TfToken& attr : textureAttrs) {
892             if (propertyName == attr) {
893                 return HdMaterial::DirtyResource;
894             }
895         }
896         return HdChangeTracker::Clean;
897     }
898 
899     HdDirtyBits dirtyGeo =
900         HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyPoints |
901         HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyExtent;
902 
903     if (propertyName == UsdGeomTokens->modelDrawModeColor)
904         return HdChangeTracker::DirtyPrimvar;
905     else if (propertyName == UsdGeomTokens->modelCardGeometry ||
906              propertyName == UsdGeomTokens->extent ||
907              propertyName == UsdGeomTokens->extentsHint)
908         return dirtyGeo;
909     else if (propertyName == UsdGeomTokens->visibility ||
910              propertyName == UsdGeomTokens->purpose)
911         return HdChangeTracker::DirtyVisibility;
912     else if (UsdGeomXformable::IsTransformationAffectedByAttrNamed(
913                 propertyName))
914         return HdChangeTracker::DirtyTransform;
915 
916     // In "cards" mode the texture assignments change what geometry
917     // is generated.
918     for (const TfToken& attr : textureAttrs) {
919         if (propertyName == attr) {
920             return dirtyGeo;
921         }
922     }
923 
924     return HdChangeTracker::Clean;
925 }
926 
927 void
_GenerateOriginGeometry(VtValue * topo,VtValue * points,GfRange3d const & extents) const928 UsdImagingGLDrawModeAdapter::_GenerateOriginGeometry(
929     VtValue *topo, VtValue *points, GfRange3d const& extents) const
930 {
931     // Origin: vertices are (0,0,0); (1,0,0); (0,1,0); (0,0,1)
932     VtVec3fArray pt = VtVec3fArray(4);
933     pt[0] = GfVec3f(0,0,0);
934     pt[1] = GfVec3f(1,0,0);
935     pt[2] = GfVec3f(0,1,0);
936     pt[3] = GfVec3f(0,0,1);
937     *points = VtValue(pt);
938 
939     // segments are +X, +Y, +Z.
940     VtIntArray curveVertexCounts = VtIntArray(1);
941     curveVertexCounts[0] = 6;
942     VtIntArray curveIndices = VtIntArray(6);
943     const int indices[] = { 0, 1, 0, 2, 0, 3 };
944     for (int i = 0; i < 6; ++i) { curveIndices[i] = indices[i]; }
945 
946     HdBasisCurvesTopology topology(
947         HdTokens->linear, HdTokens->bezier, HdTokens->segmented,
948         curveVertexCounts, curveIndices);
949     *topo = VtValue(topology);
950 }
951 
952 void
_GenerateBoundsGeometry(VtValue * topo,VtValue * points,GfRange3d const & extents) const953 UsdImagingGLDrawModeAdapter::_GenerateBoundsGeometry(
954         VtValue *topo, VtValue *points, GfRange3d const& extents) const
955 {
956     // Bounding box: vertices are for(i: 0 -> 7) {
957     //   ((i & 1) ? z : -z) +
958     //   ((i & 2) ? y : -y) +
959     //   ((i & 4) ? x : -x)
960     // } ... where x is extents[1].x, -x is extents[0].x
961     GfVec3f min = GfVec3f(extents.GetMin()),
962             max = GfVec3f(extents.GetMax());
963     VtVec3fArray pt = VtVec3fArray(8);
964     for(int i = 0; i < 8; ++i) {
965         pt[i] = GfVec3f((i & 4) ? max[0] : min[0],
966                         (i & 2) ? max[1] : min[1],
967                         (i & 1) ? max[2] : min[2]);
968     }
969     *points = VtValue(pt);
970 
971     // Segments: CCW bottom face starting at (-x, -y, -z)
972     //           CCW top face starting at (-x, -y, z)
973     //           CCW vertical edges, starting at (-x, -y)
974     VtIntArray curveVertexCounts = VtIntArray(1);
975     curveVertexCounts[0] = 24;
976     VtIntArray curveIndices = VtIntArray(24);
977     const int indices[] = { /* bottom face */ 0, 4, 4, 6, 6, 2, 2, 0,
978                             /* top face */    1, 5, 5, 7, 7, 3, 3, 1,
979                             /* edge pairs */  0, 1, 4, 5, 6, 7, 2, 3 };
980     for (int i = 0; i < 24; ++i) { curveIndices[i] = indices[i]; }
981 
982     HdBasisCurvesTopology topology(
983         HdTokens->linear, HdTokens->bezier, HdTokens->segmented,
984         curveVertexCounts, curveIndices);
985     *topo = VtValue(topology);
986 }
987 
988 void
_GenerateCardsCrossGeometry(VtValue * topo,VtValue * points,GfRange3d const & extents,uint8_t axes_mask) const989 UsdImagingGLDrawModeAdapter::_GenerateCardsCrossGeometry(
990         VtValue *topo, VtValue *points, GfRange3d const& extents,
991         uint8_t axes_mask) const
992 {
993     // Generate one face per axis direction, for included axes.
994     const int numFaces = ((axes_mask & xAxis) ? 2 : 0) +
995                          ((axes_mask & yAxis) ? 2 : 0) +
996                          ((axes_mask & zAxis) ? 2 : 0);
997 
998     // Cards (Cross) vertices:
999     // - +/-X vertices (CCW wrt +X)
1000     // - +/-Y vertices (CCW wrt +Y)
1001     // - +/-Z vertices (CCW wrt +Z)
1002     GfVec3f min = GfVec3f(extents.GetMin()),
1003             max = GfVec3f(extents.GetMax()),
1004             mid = (min+max)/2.0f;
1005 
1006     VtVec3fArray pt = VtVec3fArray(numFaces * 4);
1007     int ptIdx = 0;
1008 
1009     if (axes_mask & xAxis) {
1010         // +X
1011         pt[ptIdx++] = GfVec3f(mid[0], max[1], max[2]);
1012         pt[ptIdx++] = GfVec3f(mid[0], min[1], max[2]);
1013         pt[ptIdx++] = GfVec3f(mid[0], min[1], min[2]);
1014         pt[ptIdx++] = GfVec3f(mid[0], max[1], min[2]);
1015 
1016         // -X
1017         pt[ptIdx++] = GfVec3f(mid[0], min[1], max[2]);
1018         pt[ptIdx++] = GfVec3f(mid[0], max[1], max[2]);
1019         pt[ptIdx++] = GfVec3f(mid[0], max[1], min[2]);
1020         pt[ptIdx++] = GfVec3f(mid[0], min[1], min[2]);
1021     }
1022 
1023     if (axes_mask & yAxis) {
1024         // +Y
1025         pt[ptIdx++] = GfVec3f(min[0], mid[1], max[2]);
1026         pt[ptIdx++] = GfVec3f(max[0], mid[1], max[2]);
1027         pt[ptIdx++] = GfVec3f(max[0], mid[1], min[2]);
1028         pt[ptIdx++] = GfVec3f(min[0], mid[1], min[2]);
1029 
1030         // -Y
1031         pt[ptIdx++] = GfVec3f(max[0], mid[1], max[2]);
1032         pt[ptIdx++] = GfVec3f(min[0], mid[1], max[2]);
1033         pt[ptIdx++] = GfVec3f(min[0], mid[1], min[2]);
1034         pt[ptIdx++] = GfVec3f(max[0], mid[1], min[2]);
1035     }
1036 
1037     if (axes_mask & zAxis) {
1038         // +Z
1039         pt[ptIdx++] = GfVec3f(max[0], max[1], mid[2]);
1040         pt[ptIdx++] = GfVec3f(min[0], max[1], mid[2]);
1041         pt[ptIdx++] = GfVec3f(min[0], min[1], mid[2]);
1042         pt[ptIdx++] = GfVec3f(max[0], min[1], mid[2]);
1043 
1044         // -Z
1045         pt[ptIdx++] = GfVec3f(min[0], max[1], mid[2]);
1046         pt[ptIdx++] = GfVec3f(max[0], max[1], mid[2]);
1047         pt[ptIdx++] = GfVec3f(max[0], min[1], mid[2]);
1048         pt[ptIdx++] = GfVec3f(min[0], min[1], mid[2]);
1049     }
1050 
1051     VtIntArray faceCounts = VtIntArray(numFaces);
1052     VtIntArray faceIndices = VtIntArray(numFaces * 4);
1053     for (int i = 0; i < numFaces; ++i) {
1054         faceCounts[i] = 4;
1055         faceIndices[i*4+0] = i*4+0;
1056         faceIndices[i*4+1] = i*4+1;
1057         faceIndices[i*4+2] = i*4+2;
1058         faceIndices[i*4+3] = i*4+3;
1059     }
1060 
1061     VtIntArray holeIndices(0);
1062 
1063     HdMeshTopology topology(
1064         PxOsdOpenSubdivTokens->none, PxOsdOpenSubdivTokens->rightHanded,
1065         faceCounts, faceIndices, holeIndices);
1066 
1067     *points = VtValue(pt);
1068     *topo = VtValue(topology);
1069 }
1070 
1071 void
_SanityCheckFaceSizes(SdfPath const & cachePath,GfRange3d const & extents,uint8_t axes_mask) const1072 UsdImagingGLDrawModeAdapter::_SanityCheckFaceSizes(SdfPath const& cachePath,
1073         GfRange3d const& extents, uint8_t axes_mask) const
1074 {
1075     GfVec3d min = extents.GetMin(),
1076             max = extents.GetMax();
1077     bool zeroX = (min[0] == max[0]);
1078     bool zeroY = (min[1] == max[1]);
1079     bool zeroZ = (min[2] == max[2]);
1080 
1081     if ((axes_mask & xAxis) && (zeroY || zeroZ)) {
1082         // XXX: validation
1083         TF_WARN("Cards rendering for <%s>: X+/X- faces have zero area.",
1084                 cachePath.GetText());
1085     }
1086     if ((axes_mask & yAxis) && (zeroX || zeroZ)) {
1087         // XXX: validation
1088         TF_WARN("Cards rendering for <%s>: Y+/Y- faces have zero area.",
1089                 cachePath.GetText());
1090     }
1091     if ((axes_mask & zAxis) && (zeroX || zeroY)) {
1092         // XXX: validation
1093         TF_WARN("Cards rendering for <%s>: Z+/Z- faces have zero area.",
1094                 cachePath.GetText());
1095     }
1096 }
1097 
1098 void
_GenerateCardsBoxGeometry(VtValue * topo,VtValue * points,GfRange3d const & extents,uint8_t axes_mask) const1099 UsdImagingGLDrawModeAdapter::_GenerateCardsBoxGeometry(
1100         VtValue *topo, VtValue *points, GfRange3d const& extents,
1101         uint8_t axes_mask) const
1102 {
1103     // Generate one face per axis direction, for included axes.
1104     const int numFaces = ((axes_mask & xAxis) ? 2 : 0) +
1105                          ((axes_mask & yAxis) ? 2 : 0) +
1106                          ((axes_mask & zAxis) ? 2 : 0);
1107 
1108     // Bounding box: vertices are for(i: 0 -> 7) {
1109     //   ((i & 1) ? z : -z) +
1110     //   ((i & 2) ? y : -y) +
1111     //   ((i & 4) ? x : -x)
1112     // } ... where x is extents[1].x, -x is extents[0].x
1113     GfVec3f min = GfVec3f(extents.GetMin()),
1114             max = GfVec3f(extents.GetMax());
1115 
1116     VtVec3fArray pt = VtVec3fArray(numFaces * 4);
1117     int ptIdx = 0;
1118 
1119     VtVec3fArray corners = VtVec3fArray(8);
1120     for(int i = 0; i < 8; ++i) {
1121         corners[i] = GfVec3f((i & 4) ? max[0] : min[0],
1122                              (i & 2) ? max[1] : min[1],
1123                              (i & 1) ? max[2] : min[2]);
1124     }
1125 
1126     if (axes_mask & xAxis) {
1127         // +X
1128         pt[ptIdx++] = corners[7];
1129         pt[ptIdx++] = corners[5];
1130         pt[ptIdx++] = corners[4];
1131         pt[ptIdx++] = corners[6];
1132 
1133         // -X
1134         pt[ptIdx++] = corners[1];
1135         pt[ptIdx++] = corners[3];
1136         pt[ptIdx++] = corners[2];
1137         pt[ptIdx++] = corners[0];
1138     }
1139 
1140     if (axes_mask & yAxis) {
1141         // +Y
1142         pt[ptIdx++] = corners[3];
1143         pt[ptIdx++] = corners[7];
1144         pt[ptIdx++] = corners[6];
1145         pt[ptIdx++] = corners[2];
1146 
1147         // -Y
1148         pt[ptIdx++] = corners[5];
1149         pt[ptIdx++] = corners[1];
1150         pt[ptIdx++] = corners[0];
1151         pt[ptIdx++] = corners[4];
1152     }
1153 
1154     if (axes_mask & zAxis) {
1155         // +Z
1156         pt[ptIdx++] = corners[7];
1157         pt[ptIdx++] = corners[3];
1158         pt[ptIdx++] = corners[1];
1159         pt[ptIdx++] = corners[5];
1160 
1161         // -Z
1162         pt[ptIdx++] = corners[2];
1163         pt[ptIdx++] = corners[6];
1164         pt[ptIdx++] = corners[4];
1165         pt[ptIdx++] = corners[0];
1166     }
1167 
1168     *points = VtValue(pt);
1169 
1170     VtIntArray faceCounts = VtIntArray(numFaces);
1171     VtIntArray faceIndices = VtIntArray(numFaces * 4);
1172     for (int i = 0; i < numFaces; ++i) {
1173         faceCounts[i] = 4;
1174         faceIndices[i*4+0] = i*4+0;
1175         faceIndices[i*4+1] = i*4+1;
1176         faceIndices[i*4+2] = i*4+2;
1177         faceIndices[i*4+3] = i*4+3;
1178     }
1179 
1180     VtIntArray holeIndices(0);
1181 
1182     HdMeshTopology topology(
1183         UsdGeomTokens->none, UsdGeomTokens->rightHanded,
1184         faceCounts, faceIndices, holeIndices);
1185 
1186     *points = VtValue(pt);
1187     *topo = VtValue(topology);
1188 }
1189 
1190 void
_GenerateCardsFromTextureGeometry(VtValue * topo,VtValue * points,VtValue * uv,VtValue * assign,GfRange3d * extents,UsdPrim const & prim) const1191 UsdImagingGLDrawModeAdapter::_GenerateCardsFromTextureGeometry(
1192         VtValue *topo, VtValue *points, VtValue *uv, VtValue *assign,
1193         GfRange3d *extents, UsdPrim const& prim) const
1194 {
1195     UsdGeomModelAPI model(prim);
1196     std::vector<std::pair<GfMatrix4d, int>> faces;
1197 
1198     // Compute the face matrix/texture assignment pairs.
1199     GfMatrix4d mat;
1200     if (_GetMatrixFromImageMetadata(
1201             model.GetModelCardTextureXPosAttr(), &mat))
1202         faces.push_back(std::make_pair(mat, xPos));
1203     if (_GetMatrixFromImageMetadata(
1204             model.GetModelCardTextureYPosAttr(), &mat))
1205         faces.push_back(std::make_pair(mat, yPos));
1206     if (_GetMatrixFromImageMetadata(
1207             model.GetModelCardTextureZPosAttr(), &mat))
1208         faces.push_back(std::make_pair(mat, zPos));
1209     if (_GetMatrixFromImageMetadata(
1210             model.GetModelCardTextureXNegAttr(), &mat))
1211         faces.push_back(std::make_pair(mat, xNeg));
1212     if (_GetMatrixFromImageMetadata(
1213             model.GetModelCardTextureYNegAttr(), &mat))
1214         faces.push_back(std::make_pair(mat, yNeg));
1215     if (_GetMatrixFromImageMetadata(
1216             model.GetModelCardTextureZNegAttr(), &mat))
1217         faces.push_back(std::make_pair(mat, zNeg));
1218 
1219     // Generate points, UV, and assignment primvars, plus index data.
1220     VtVec3fArray arr_pt = VtVec3fArray(faces.size() * 4);
1221     VtVec2fArray arr_uv = VtVec2fArray(faces.size() * 4);
1222     VtIntArray arr_assign = VtIntArray(faces.size());
1223     VtIntArray faceCounts = VtIntArray(faces.size());
1224     VtIntArray faceIndices = VtIntArray(faces.size() * 4);
1225 
1226     static const std::array<GfVec3f, 4> corners = {
1227         GfVec3f(-1, -1,  0), GfVec3f(-1,  1,  0),
1228         GfVec3f( 1,  1,  0), GfVec3f( 1, -1,  0) };
1229     static const std::array<GfVec2f, 4> std_uvs =
1230         std::array<GfVec2f, 4>(
1231             {GfVec2f(0,1), GfVec2f(0,0), GfVec2f(1,0), GfVec2f(1,1) });
1232 
1233     for(size_t i = 0; i < faces.size(); ++i) {
1234         GfMatrix4d screenToWorld = faces[i].first.GetInverse();
1235         faceCounts[i] = 4;
1236         arr_assign[i] = faces[i].second;
1237         for (size_t j = 0; j < 4; ++j) {
1238             faceIndices[i*4+j] = i*4+j;
1239             arr_pt[i*4+j] = screenToWorld.Transform(corners[j]);
1240             arr_uv[i*4+j] = std_uvs[j];
1241         }
1242     }
1243 
1244     // Create the topology object, and put our buffers in the out-values.
1245     VtIntArray holeIndices(0);
1246     HdMeshTopology topology(
1247         UsdGeomTokens->none, UsdGeomTokens->rightHanded,
1248         faceCounts, faceIndices, holeIndices);
1249 
1250     *topo = VtValue(topology);
1251     *points = VtValue(arr_pt);
1252     *uv = VtValue(arr_uv);
1253     *assign = VtValue(arr_assign);
1254 
1255     // Compute extents from points.
1256     extents->SetEmpty();
1257     for (size_t i = 0; i < faces.size()*4; ++i) {
1258         extents->UnionWith(arr_pt[i]);
1259     }
1260 }
1261 
1262 namespace
1263 {
1264 
1265 template <class Vec>
1266 bool
_ConvertToMatrix(const Vec & mvec,GfMatrix4d * mat)1267 _ConvertToMatrix(const Vec &mvec, GfMatrix4d *mat)
1268 {
1269     if (mvec.size() == 16) {
1270         mat->Set(mvec[ 0], mvec[ 1], mvec[ 2], mvec[ 3],
1271                  mvec[ 4], mvec[ 5], mvec[ 6], mvec[ 7],
1272                  mvec[ 8], mvec[ 9], mvec[10], mvec[11],
1273                  mvec[12], mvec[13], mvec[14], mvec[15]);
1274         return true;
1275     }
1276 
1277     TF_WARN(
1278         "worldtoscreen metadata expected 16 values, got %zu",
1279         mvec.size());
1280     return false;
1281 };
1282 
1283 }
1284 
1285 bool
_GetMatrixFromImageMetadata(UsdAttribute const & attr,GfMatrix4d * mat) const1286 UsdImagingGLDrawModeAdapter::_GetMatrixFromImageMetadata(
1287     UsdAttribute const& attr, GfMatrix4d *mat) const
1288 {
1289     // This function expects the input attribute to be an image asset path.
1290     SdfAssetPath asset;
1291     attr.Get(&asset);
1292 
1293     // If the literal path is empty, ignore this attribute.
1294     if (asset.GetAssetPath().empty()) {
1295         return false;
1296     }
1297 
1298     std::string file = asset.GetResolvedPath();
1299     // Fallback to the literal path if it couldn't be resolved.
1300     if (file.empty()) {
1301         file = asset.GetAssetPath();
1302     }
1303 
1304     HioImageSharedPtr img = HioImage::OpenForReading(file);
1305     if (!img) {
1306         return false;
1307     }
1308 
1309     // Read the "worldtoscreen" metadata. This metadata specifies a 4x4
1310     // matrix but may be given as any the following data types, since
1311     // some image formats may support certain metadata types but not others.
1312     //
1313     // - std::vector<float> or std::vector<double> with 16 elements
1314     //   in row major order.
1315     // - GfMatrix4f or GfMatrix4d
1316     VtValue worldtoscreen;
1317     if (img->GetMetadata(_tokens->worldtoscreen, &worldtoscreen)) {
1318         if (worldtoscreen.IsHolding<std::vector<float>>()) {
1319             return _ConvertToMatrix(
1320                 worldtoscreen.UncheckedGet<std::vector<float>>(), mat);
1321         }
1322         else if (worldtoscreen.IsHolding<std::vector<double>>()) {
1323             return _ConvertToMatrix(
1324                 worldtoscreen.UncheckedGet<std::vector<double>>(), mat);
1325         }
1326         else if (worldtoscreen.IsHolding<GfMatrix4f>()) {
1327             *mat = GfMatrix4d(worldtoscreen.UncheckedGet<GfMatrix4f>());
1328             return true;
1329         }
1330         else if (worldtoscreen.IsHolding<GfMatrix4d>()) {
1331             *mat = worldtoscreen.UncheckedGet<GfMatrix4d>();
1332             return true;
1333         }
1334         else {
1335             TF_WARN(
1336                 "worldtoscreen metadata holding unexpected type '%s'",
1337                 worldtoscreen.GetTypeName().c_str());
1338         }
1339     }
1340 
1341     return false;
1342 }
1343 
1344 static
1345 std::array<GfVec2f, 4>
_GetUVsForQuad(const bool flipU,bool flipV)1346 _GetUVsForQuad(const bool flipU, bool flipV)
1347 {
1348     return {
1349         GfVec2f(flipU ? 0.0 : 1.0, flipV ? 0.0 : 1.0),
1350         GfVec2f(flipU ? 1.0 : 0.0, flipV ? 0.0 : 1.0),
1351         GfVec2f(flipU ? 1.0 : 0.0, flipV ? 1.0 : 0.0),
1352         GfVec2f(flipU ? 0.0 : 1.0, flipV ? 1.0 : 0.0) };
1353 }
1354 
1355 void
_GenerateTextureCoordinates(VtValue * uv,VtValue * assign,uint8_t axes_mask) const1356 UsdImagingGLDrawModeAdapter::_GenerateTextureCoordinates(
1357         VtValue *uv, VtValue *assign, uint8_t axes_mask) const
1358 {
1359     // This function generates a UV quad per face, with the correct orientation,
1360     // and also uniform indices for each face specifying which texture to
1361     // sample.  The order is [X+, X-, Y+, Y-, Z+, Z-], possibly with some of
1362     // the axes omitted.
1363 
1364     static const std::array<GfVec2f, 4> uv_normal =
1365         _GetUVsForQuad(false, false);
1366     static const std::array<GfVec2f, 4> uv_flipped_s =
1367         _GetUVsForQuad(true, false);
1368     static const std::array<GfVec2f, 4> uv_flipped_t =
1369         _GetUVsForQuad(false, true);
1370     static const std::array<GfVec2f, 4> uv_flipped_st =
1371         _GetUVsForQuad(true, true);
1372 
1373     std::vector<const GfVec2f *> uv_faces;
1374     std::vector<int> face_assign;
1375     if (axes_mask & xAxis) {
1376         uv_faces.push_back(
1377             (axes_mask & xPos) ? uv_normal.data() : uv_flipped_s.data());
1378         face_assign.push_back((axes_mask & xPos) ? xPos : xNeg);
1379         uv_faces.push_back(
1380             (axes_mask & xNeg) ? uv_normal.data() : uv_flipped_s.data());
1381         face_assign.push_back((axes_mask & xNeg) ? xNeg : xPos);
1382     }
1383     if (axes_mask & yAxis) {
1384         uv_faces.push_back(
1385             (axes_mask & yPos) ? uv_normal.data() : uv_flipped_s.data());
1386         face_assign.push_back((axes_mask & yPos) ? yPos : yNeg);
1387         uv_faces.push_back(
1388             (axes_mask & yNeg) ? uv_normal.data() : uv_flipped_s.data());
1389         face_assign.push_back((axes_mask & yNeg) ? yNeg : yPos);
1390     }
1391     if (axes_mask & zAxis) {
1392         // (Z+) and (Z-) need to be flipped on the (t) axis instead of the (s)
1393         // axis when we're borrowing a texture from the other side of the axis.
1394         uv_faces.push_back(
1395             (axes_mask & zPos) ? uv_normal.data() : uv_flipped_t.data());
1396         face_assign.push_back((axes_mask & zPos) ? zPos : zNeg);
1397         uv_faces.push_back(
1398             (axes_mask & zNeg) ? uv_flipped_st.data() : uv_flipped_s.data());
1399         face_assign.push_back((axes_mask & zNeg) ? zNeg : zPos);
1400     }
1401 
1402     VtVec2fArray faceUV = VtVec2fArray(uv_faces.size() * 4);
1403     for (size_t i = 0; i < uv_faces.size(); ++i) {
1404         memcpy(&faceUV[i*4], uv_faces[i], 4 * sizeof(GfVec2f));
1405     }
1406     *uv = VtValue(faceUV);
1407 
1408     VtIntArray faceAssign = VtIntArray(face_assign.size());
1409     for (size_t i = 0; i < face_assign.size(); ++i) {
1410         faceAssign[i] = face_assign[i];
1411     }
1412     *assign = VtValue(faceAssign);
1413 }
1414 
1415 GfRange3d
_ComputeExtent(UsdPrim const & prim,const UsdTimeCode & timecode) const1416 UsdImagingGLDrawModeAdapter::_ComputeExtent(UsdPrim const& prim,
1417         const UsdTimeCode& timecode) const
1418 {
1419     HD_TRACE_FUNCTION();
1420     HF_MALLOC_TAG_FUNCTION();
1421 
1422     TfTokenVector purposes = { UsdGeomTokens->default_, UsdGeomTokens->proxy,
1423                                UsdGeomTokens->render };
1424 
1425     if (prim.IsLoaded()) {
1426         UsdGeomBBoxCache bboxCache(timecode, purposes, true);
1427         return bboxCache.ComputeUntransformedBound(prim).ComputeAlignedBox();
1428     } else {
1429         GfRange3d extent;
1430         UsdAttribute attr;
1431         VtVec3fArray extentsHint;
1432         // Get the extent either from the authored extent attribute of a
1433         // UsdGeomBoundable prim, or get the extentsHint attribute from the
1434         // prim.
1435         if (prim.IsA<UsdGeomBoundable>() &&
1436             (attr = UsdGeomBoundable(prim).GetExtentAttr()) &&
1437             attr.Get(&extentsHint, timecode) &&
1438             extentsHint.size() == 2) {
1439             extent = GfRange3d(extentsHint[0], extentsHint[1]);
1440         }
1441         else if ((attr = UsdGeomModelAPI(prim).GetExtentsHintAttr()) &&
1442             attr.Get(&extentsHint, timecode) &&
1443             extentsHint.size() >= 2) {
1444             // XXX: This code to merge the extentsHint values over a set of
1445             // purposes probably belongs in UsdGeomBBoxCache.
1446             const TfTokenVector &purposeTokens =
1447                 UsdGeomImageable::GetOrderedPurposeTokens();
1448             for (size_t i = 0; i < purposeTokens.size(); ++i) {
1449                 size_t idx = i*2;
1450                 // If extents are not available for the value of purpose,
1451                 // it implies that the rest of the bounds are empty.
1452                 if ((idx + 2) > extentsHint.size())
1453                     break;
1454                 // If this purpose isn't one we are interested in, skip it.
1455                 if (std::find(purposes.begin(), purposes.end(),
1456                               purposeTokens[i]) == purposes.end())
1457                     continue;
1458 
1459                 GfRange3d purposeExtent =
1460                     GfRange3d(extentsHint[idx], extentsHint[idx+1]);
1461                 // Extents for an unauthored geometry purpose may be empty,
1462                 // even though the extent for a later purpose may exist.
1463                 if (!purposeExtent.IsEmpty()) {
1464                     extent.ExtendBy(purposeExtent);
1465                 }
1466             }
1467         }
1468         return extent;
1469     }
1470 }
1471 
1472 /*virtual*/
1473 HdCullStyle
GetCullStyle(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time) const1474 UsdImagingGLDrawModeAdapter::GetCullStyle(UsdPrim const& prim,
1475                                           SdfPath const& cachePath,
1476                                           UsdTimeCode time) const
1477 {
1478     return HdCullStyleBack;
1479 }
1480 
1481 /*virtual*/
1482 GfMatrix4d
GetTransform(UsdPrim const & prim,SdfPath const & cachePath,UsdTimeCode time,bool ignoreRootTransform) const1483 UsdImagingGLDrawModeAdapter::GetTransform(UsdPrim const& prim,
1484                                           SdfPath const& cachePath,
1485                                           UsdTimeCode time,
1486                                           bool ignoreRootTransform) const
1487 {
1488     // If the draw mode is instantiated on an instance, prim will be
1489     // the instance prim, but we want to ignore transforms on that
1490     // prim since the instance adapter will handle them.
1491     if (prim.IsInstance()) {
1492         return GfMatrix4d(1.0);
1493     } else {
1494         return BaseAdapter::GetTransform(
1495             prim, prim.GetPath(), time, ignoreRootTransform);
1496     }
1497 }
1498 
1499 PXR_NAMESPACE_CLOSE_SCOPE
1500