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/pxr.h"
25 #include "pxr/usd/usdGeom/xformCache.h"
26 #include "pxr/usd/usdGeom/xform.h"
27 
28 #include "pxr/base/trace/trace.h"
29 
30 #include "pxr/base/tf/diagnostic.h"
31 
32 PXR_NAMESPACE_OPEN_SCOPE
33 
34 
35 
UsdGeomXformCache(const UsdTimeCode time)36 UsdGeomXformCache::UsdGeomXformCache(const UsdTimeCode time)
37     : _time(time)
38 {
39 }
40 
UsdGeomXformCache()41 UsdGeomXformCache::UsdGeomXformCache()
42     : _time(UsdTimeCode::Default())
43 {
44 }
45 
46 GfMatrix4d
GetLocalToWorldTransform(const UsdPrim & prim)47 UsdGeomXformCache::GetLocalToWorldTransform(const UsdPrim& prim)
48 {
49     TRACE_FUNCTION();
50     return *_GetCtm(prim);
51 }
52 
53 GfMatrix4d
GetParentToWorldTransform(const UsdPrim & prim)54 UsdGeomXformCache::GetParentToWorldTransform(const UsdPrim& prim)
55 {
56     TRACE_FUNCTION();
57     return *_GetCtm(prim.GetParent());
58 }
59 
60 bool
TransformMightBeTimeVarying(const UsdPrim & prim)61 UsdGeomXformCache::TransformMightBeTimeVarying(const UsdPrim &prim)
62 {
63     // Get or create an entry for the prim in the CTM cache.
64     // The validity of the ctm value itself is irrelevant here.
65     _Entry* entry = _GetCacheEntryForPrim(prim);
66     if (TF_VERIFY(entry))
67         return entry->query.TransformMightBeTimeVarying();
68 
69     // Being conservative and assuming that the trasnsform may vary over time.
70     // Poor performance is better than wrong results!
71     return true;
72 }
73 
74 bool
GetResetXformStack(const UsdPrim & prim)75 UsdGeomXformCache::GetResetXformStack(const UsdPrim &prim)
76 {
77     // Get or create an entry for the prim in the CTM cache.
78     // The validity of the ctm value itself is irrelevant here.
79     _Entry* entry = _GetCacheEntryForPrim(prim);
80     if (TF_VERIFY(entry))
81         return entry->query.GetResetXformStack();
82 
83     return false;
84 }
85 
86 bool
IsAttributeIncludedInLocalTransform(const UsdPrim & prim,const TfToken & attrName)87 UsdGeomXformCache::IsAttributeIncludedInLocalTransform(const UsdPrim &prim,
88                                                        const TfToken &attrName)
89 {
90     // Get or create an entry for the prim in the CTM cache.
91     // The validity of the ctm value itself is irrelevant here.
92     _Entry* entry = _GetCacheEntryForPrim(prim);
93     if (TF_VERIFY(entry))
94         return  entry->query.IsAttributeIncludedInLocalTransform(attrName);
95 
96     return false;
97 }
98 
99 UsdGeomXformCache::_Entry *
_GetCacheEntryForPrim(const UsdPrim & prim)100 UsdGeomXformCache::_GetCacheEntryForPrim(const UsdPrim &prim)
101 {
102     auto iresult = _ctmCache.insert({ prim, _Entry() });
103     _Entry *result = &iresult.first->second;
104     if (iresult.second) {
105         if (UsdGeomXformable xf = UsdGeomXformable(prim)) {
106             result->query = UsdGeomXformable::XformQuery(xf);
107         }
108         result->ctm.SetIdentity();
109         result->ctmIsValid = false;
110     }
111     return result;
112 }
113 
114 GfMatrix4d
GetLocalTransformation(const UsdPrim & prim,bool * resetsXformStack)115 UsdGeomXformCache::GetLocalTransformation(const UsdPrim &prim,
116                                           bool *resetsXformStack)
117 {
118     if(!resetsXformStack) {
119         TF_CODING_ERROR("'resetsXformStack' pointer is null.");
120         return GfMatrix4d(1);
121     }
122 
123     _Entry *entry = _GetCacheEntryForPrim(prim);
124     GfMatrix4d xform(1.);
125     if (TF_VERIFY(entry)) {
126         entry->query.GetLocalTransformation(&xform, _time);
127         *resetsXformStack = entry->query.GetResetXformStack();
128     } else {
129         *resetsXformStack = false;
130     }
131 
132     return xform;
133 }
134 
135 GfMatrix4d
ComputeRelativeTransform(const UsdPrim & prim,const UsdPrim & ancestor,bool * resetXformStack)136 UsdGeomXformCache::ComputeRelativeTransform(const UsdPrim &prim,
137                                             const UsdPrim &ancestor,
138                                             bool *resetXformStack)
139 {
140     GfMatrix4d xform(1.);
141 
142     if(!resetXformStack) {
143         TF_CODING_ERROR("'resetXformStack' pointer is null.");
144         return xform;
145     }
146 
147     for(UsdPrim p = prim; p && p != ancestor; p = p.GetParent()) {
148         xform *= GetLocalTransformation(p, resetXformStack);
149         if(*resetXformStack) {
150             break;
151         }
152     }
153     return xform;
154 }
155 
156 GfMatrix4d const*
_GetCtm(const UsdPrim & prim)157 UsdGeomXformCache::_GetCtm(const UsdPrim& prim)
158 {
159     // Local identity matrix to return by pointer.
160     static GfMatrix4d const IDENTITY(1.0);
161 
162     // Base case: check for the pseudo root, which is always implicitly
163     // identity.
164     if (!prim)
165         return &IDENTITY;
166 
167     // Check for a cached matrix.
168     _Entry* entry = _GetCacheEntryForPrim(prim);
169     if (entry->ctmIsValid)
170         return &entry->ctm;
171 
172     // Recursively compute the ctm.
173     GfMatrix4d xform(1.);
174     entry->query.GetLocalTransformation(&xform, _time);
175     bool resetsXformStack = entry->query.GetResetXformStack();
176 
177     xform = !resetsXformStack ? (xform * (*_GetCtm(prim.GetParent())))
178                                  : xform;
179 
180     // Return the address of the inserted Matrix.
181     entry->ctm = xform;
182     entry->ctmIsValid = true;
183 
184     return &entry->ctm;
185 }
186 
187 void
SetTime(UsdTimeCode time)188 UsdGeomXformCache::SetTime(UsdTimeCode time)
189 {
190     if (time == _time)
191         return;
192 
193     // Mark all cached CTMs as invalid, but leave the queries behind.
194     TF_FOR_ALL(it, _ctmCache) {
195         it->second.ctmIsValid = false;
196     }
197 
198     _time = time;
199 }
200 
201 void
Clear()202 UsdGeomXformCache::Clear() {
203     _ctmCache.clear();
204 }
205 
206 void
Swap(UsdGeomXformCache & other)207 UsdGeomXformCache::Swap(UsdGeomXformCache& other)
208 {
209     _ctmCache.swap(other._ctmCache);
210     std::swap(_time, other._time);
211 }
212 
213 PXR_NAMESPACE_CLOSE_SCOPE
214 
215