1 //
2 //   Copyright 2013 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 #ifndef OPENSUBDIV3_HBRHALFEDGE_H
26 #define OPENSUBDIV3_HBRHALFEDGE_H
27 
28 #include <assert.h>
29 #include <stddef.h>
30 #include <cstring>
31 #include <iostream>
32 
33 
34 #ifdef HBRSTITCH
35 #include "libgprims/stitch.h"
36 #include "libgprims/stitchInternal.h"
37 #endif
38 
39 #include "../version.h"
40 
41 namespace OpenSubdiv {
42 namespace OPENSUBDIV_VERSION {
43 
44 template <class T> class HbrFace;
45 template <class T> class HbrHalfedge;
46 template <class T> class HbrVertex;
47 template <class T> class HbrMesh;
48 
49 template <class T> std::ostream& operator<<(std::ostream& out, const HbrHalfedge<T>& edge);
50 
51 template <class T> class HbrHalfedge {
52 
53 private:
HbrHalfedge()54     HbrHalfedge(): opposite(0), incidentVertex(-1), vchild(-1), sharpness(0.0f)
55 #ifdef HBRSTITCH
56     , stitchccw(1), raystitchccw(1)
57 #endif
58     , coarse(1)
59     {
60     }
61 
HbrHalfedge(const HbrHalfedge &)62     HbrHalfedge(const HbrHalfedge &/* edge */) {}
63 
64     ~HbrHalfedge();
65 
66     void Clear();
67 
68     // Finish the initialization of the halfedge. Should only be
69     // called by HbrFace
70     void Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* origin, unsigned int *fvarbits, HbrFace<T>* face);
71 public:
72 
73     // Returns the opposite half edge
GetOpposite()74     HbrHalfedge<T>* GetOpposite() const { return opposite; }
75 
76     // Sets the opposite half edge
SetOpposite(HbrHalfedge<T> * opposite)77     void SetOpposite(HbrHalfedge<T>* opposite) { this->opposite = opposite; sharpness = opposite->sharpness; }
78 
79     // Returns the next clockwise halfedge around the incident face
GetNext()80     HbrHalfedge<T>* GetNext() const {
81         if (m_index == 4) {
82             const size_t edgesize = sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*);
83             if (lastedge) {
84                 return (HbrHalfedge<T>*) ((char*) this - (GetFace()->GetNumVertices() - 1) * edgesize);
85             } else {
86                 return (HbrHalfedge<T>*) ((char*) this + edgesize);
87             }
88         } else {
89             if (lastedge) {
90                 return (HbrHalfedge<T>*) ((char*) this - (m_index) * sizeof(HbrHalfedge<T>));
91             } else {
92                 return (HbrHalfedge<T>*) ((char*) this + sizeof(HbrHalfedge<T>));
93             }
94         }
95     }
96 
97     // Returns the previous counterclockwise halfedge around the incident face
GetPrev()98     HbrHalfedge<T>* GetPrev() const {
99         const size_t edgesize = (m_index == 4) ?
100             (sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*)) :
101             sizeof(HbrHalfedge<T>);
102         if (firstedge) {
103             return (HbrHalfedge<T>*) ((char*) this + (GetFace()->GetNumVertices() - 1) * edgesize);
104         } else {
105             return (HbrHalfedge<T>*) ((char*) this - edgesize);
106         }
107     }
108 
109     // Returns the incident vertex
GetVertex()110     HbrVertex<T>* GetVertex() const {
111         return GetMesh()->GetVertex(incidentVertex);
112         }
113 
114     // Returns the incident vertex
GetVertex(HbrMesh<T> * mesh)115     HbrVertex<T>* GetVertex(HbrMesh<T> *mesh) const {
116         return mesh->GetVertex(incidentVertex);
117     }
118 
119     // Returns the incident vertex
GetVertexID()120     int GetVertexID() const {
121         return incidentVertex;
122     }
123 
124     // Returns the source vertex
GetOrgVertex()125     HbrVertex<T>* GetOrgVertex() const {
126         return GetVertex();
127     }
128 
129     // Returns the source vertex
GetOrgVertex(HbrMesh<T> * mesh)130     HbrVertex<T>* GetOrgVertex(HbrMesh<T> *mesh) const {
131         return GetVertex(mesh);
132     }
133 
134     // Returns the source vertex id
GetOrgVertexID()135     int GetOrgVertexID() const {
136         return incidentVertex;
137     }
138 
139     // Changes the origin vertex. Generally not a good idea to do
SetOrgVertex(HbrVertex<T> * v)140     void SetOrgVertex(HbrVertex<T>* v) { incidentVertex = v->GetID(); }
141 
142     // Returns the destination vertex
GetDestVertex()143     HbrVertex<T>* GetDestVertex() const { return GetNext()->GetOrgVertex(); }
144 
145     // Returns the destination vertex
GetDestVertex(HbrMesh<T> * mesh)146     HbrVertex<T>* GetDestVertex(HbrMesh<T> *mesh) const { return GetNext()->GetOrgVertex(mesh); }
147 
148     // Returns the destination vertex ID
GetDestVertexID()149     int GetDestVertexID() const { return GetNext()->GetOrgVertexID(); }
150 
151     // Returns the incident facet
GetFace()152     HbrFace<T>* GetFace() const {
153         if (m_index == 4) {
154             // Pointer to face is stored after the data for the edge
155             return *(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>));
156         } else {
157             return (HbrFace<T>*) ((char*) this - (m_index) * sizeof(HbrHalfedge<T>) -
158                 offsetof(HbrFace<T>, edges));
159         }
160     }
161 
162     // Returns the mesh to which this edge belongs
GetMesh()163     HbrMesh<T>* GetMesh() const { return GetFace()->GetMesh(); }
164 
165     // Returns the face on the right
GetRightFace()166     HbrFace<T>* GetRightFace() const { return opposite ? opposite->GetLeftFace() : NULL; }
167 
168     // Return the face on the left of the halfedge
GetLeftFace()169     HbrFace<T>* GetLeftFace() const { return GetFace(); }
170 
171     // Returns whether this is a boundary edge
IsBoundary()172     bool IsBoundary() const { return opposite == 0; }
173 
174     // Tag the edge as being an infinitely sharp facevarying edge
SetFVarInfiniteSharp(int datum,bool infsharp)175     void SetFVarInfiniteSharp(int datum, bool infsharp) {
176         int intindex = datum >> 4;
177         unsigned int bits = infsharp << ((datum & 15) * 2);
178         getFVarInfSharp()[intindex] |= bits;
179         if (opposite) {
180             opposite->getFVarInfSharp()[intindex] |= bits;
181         }
182     }
183 
184     // Copy fvar infinite sharpness flags from another edge
CopyFVarInfiniteSharpness(HbrHalfedge<T> * edge)185     void CopyFVarInfiniteSharpness(HbrHalfedge<T>* edge) {
186         unsigned int *fvarinfsharp = getFVarInfSharp();
187         if (fvarinfsharp) {
188             const int fvarcount = GetMesh()->GetFVarCount();
189             int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
190 
191             if (edge->IsSharp(true)) {
192                 memset(fvarinfsharp, 0x55555555, fvarbitsSizePerEdge * sizeof(unsigned int));
193             } else {
194                 memcpy(fvarinfsharp, edge->getFVarInfSharp(), fvarbitsSizePerEdge * sizeof(unsigned int));
195             }
196         }
197     }
198 
199     // Returns whether the edge is infinitely sharp in facevarying for
200     // a particular facevarying datum
201     bool GetFVarInfiniteSharp(int datum);
202 
203     // Returns whether the edge is infinitely sharp in any facevarying
204     // datum
205     bool IsFVarInfiniteSharpAnywhere();
206 
207     // Get the sharpness relative to facevarying data
208     float GetFVarSharpness(int datum, bool ignoreGeometry=false);
209 
210     // Returns the (raw) sharpness of the edge
GetSharpness()211     float GetSharpness() const { return sharpness; }
212 
213     // Sets the sharpness of the edge
SetSharpness(float sharp)214     void SetSharpness(float sharp) { sharpness = sharp; if (opposite) opposite->sharpness = sharp; ClearMask(); }
215 
216     // Returns whether the edge is sharp at the current level of
217     // subdivision (next = false) or at the next level of subdivision
218     // (next = true).
IsSharp(bool next)219     bool IsSharp(bool next) const { return (next ? (sharpness > 0.0f) : (sharpness >= 1.0f)); }
220 
221     // Clears the masks of the adjacent edge vertices. Usually called
222     // when a change in edge sharpness occurs.
ClearMask()223     void ClearMask() { GetOrgVertex()->ClearMask(); GetDestVertex()->ClearMask(); }
224 
225     // Subdivide the edge into a vertex if needed and return
226     HbrVertex<T>* Subdivide();
227 
228     // Make sure the edge has its opposite face
229     void GuaranteeNeighbor();
230 
231     // True if the edge has a subdivided child vertex
HasChild()232     bool HasChild() const { return vchild!=-1; }
233 
234     // Remove the reference to subdivided vertex
RemoveChild()235     void RemoveChild() { vchild = -1; }
236 
237     // Sharpness constants
238     enum Mask {
239         k_Smooth = 0,
240         k_Sharp = 1,
241         k_InfinitelySharp = 10
242     };
243 
244 #ifdef HBRSTITCH
GetStitchEdge(int i)245     StitchEdge* GetStitchEdge(int i) {
246         StitchEdge **stitchEdge = getStitchEdges();
247         // If the stitch edge exists, the ownership is transferred to
248         // the caller. Make sure the opposite edge loses ownership as
249         // well.
250         if (stitchEdge[i]) {
251             if (opposite) {
252                 opposite->getStitchEdges()[i] = 0;
253             }
254             return StitchGetEdge(&stitchEdge[i]);
255         }
256         // If the stitch edge does not exist then we create one now.
257         // Make sure the opposite edge gets a copy of it too
258         else {
259             StitchGetEdge(&stitchEdge[i]);
260             if (opposite) {
261                 opposite->getStitchEdges()[i] = stitchEdge[i];
262             }
263             return stitchEdge[i];
264         }
265     }
266 
267     // If stitch edge exists, and this edge has no opposite, destroy
268     // it
DestroyStitchEdges(int stitchcount)269     void DestroyStitchEdges(int stitchcount) {
270         if (!opposite) {
271             StitchEdge **stitchEdge = getStitchEdges();
272             for (int i = 0; i < stitchcount; ++i) {
273                 if (stitchEdge[i]) {
274                     StitchFreeEdge(stitchEdge[i]);
275                     stitchEdge[i] = 0;
276                 }
277             }
278         }
279     }
280 
GetRayStitchEdge(int i)281     StitchEdge* GetRayStitchEdge(int i) {
282         return GetStitchEdge(i + 2);
283     }
284 
285     // Splits our split edge between our children. We'd better have
286     // subdivided this edge by this point
SplitStitchEdge(int i)287     void SplitStitchEdge(int i) {
288         StitchEdge* se = GetStitchEdge(i);
289         HbrHalfedge<T>* ea = GetOrgVertex()->Subdivide()->GetEdge(Subdivide());
290         HbrHalfedge<T>* eb = Subdivide()->GetEdge(GetDestVertex()->Subdivide());
291         StitchEdge **ease = ea->getStitchEdges();
292         StitchEdge **ebse = eb->getStitchEdges();
293         if (i >= 2) { // ray tracing stitches
294             if (!raystitchccw) {
295                 StitchSplitEdge(se, &ease[i], &ebse[i], false, 0, 0, 0);
296             } else {
297                 StitchSplitEdge(se, &ebse[i], &ease[i], true, 0, 0, 0);
298             }
299             ea->raystitchccw = eb->raystitchccw = raystitchccw;
300             if (eb->opposite) {
301                 eb->opposite->getStitchEdges()[i] = ebse[i];
302                 eb->opposite->raystitchccw = raystitchccw;
303             }
304             if (ea->opposite) {
305                 ea->opposite->getStitchEdges()[i] = ease[i];
306                 ea->opposite->raystitchccw = raystitchccw;
307             }
308         } else {
309             if (!stitchccw) {
310                 StitchSplitEdge(se, &ease[i], &ebse[i], false, 0, 0, 0);
311             } else {
312                 StitchSplitEdge(se, &ebse[i], &ease[i], true, 0, 0, 0);
313             }
314             ea->stitchccw = eb->stitchccw = stitchccw;
315             if (eb->opposite) {
316                 eb->opposite->getStitchEdges()[i] = ebse[i];
317                 eb->opposite->stitchccw = stitchccw;
318             }
319             if (ea->opposite) {
320                 ea->opposite->getStitchEdges()[i] = ease[i];
321                 ea->opposite->stitchccw = stitchccw;
322             }
323         }
324     }
325 
SplitRayStitchEdge(int i)326     void SplitRayStitchEdge(int i) {
327         SplitStitchEdge(i + 2);
328     }
329 
SetStitchEdge(int i,StitchEdge * edge)330     void SetStitchEdge(int i, StitchEdge* edge) {
331         StitchEdge **stitchEdges = getStitchEdges();
332         stitchEdges[i] = edge;
333         if (opposite) {
334             opposite->getStitchEdges()[i] = edge;
335         }
336     }
337 
SetRayStitchEdge(int i,StitchEdge * edge)338     void SetRayStitchEdge(int i, StitchEdge* edge) {
339         StitchEdge **stitchEdges = getStitchEdges();
340         stitchEdges[i+2] = edge;
341         if (opposite) {
342             opposite->getStitchEdges()[i+2] = edge;
343         }
344     }
345 
GetStitchData()346     void* GetStitchData() const {
347         if (stitchdatavalid) return GetMesh()->GetStitchData(this);
348         else return 0;
349     }
350 
SetStitchData(void * data)351     void SetStitchData(void* data) {
352         GetMesh()->SetStitchData(this, data);
353         stitchdatavalid = data ? 1 : 0;
354         if (opposite) {
355             opposite->GetMesh()->SetStitchData(opposite, data);
356             opposite->stitchdatavalid = stitchdatavalid;
357         }
358     }
359 
GetStitchCCW(bool raytraced)360     bool GetStitchCCW(bool raytraced) const { return raytraced ? raystitchccw : stitchccw; }
361 
ClearStitchCCW(bool raytraced)362     void ClearStitchCCW(bool raytraced) {
363         if (raytraced) {
364             raystitchccw = 0;
365             if (opposite) opposite->raystitchccw = 0;
366         } else {
367             stitchccw = 0;
368             if (opposite) opposite->stitchccw = 0;
369         }
370     }
371 
ToggleStitchCCW(bool raytraced)372     void ToggleStitchCCW(bool raytraced) {
373         if (raytraced) {
374             raystitchccw = 1 - raystitchccw;
375             if (opposite) opposite->raystitchccw = raystitchccw;
376         } else {
377             stitchccw = 1 - stitchccw;
378             if (opposite) opposite->stitchccw = stitchccw;
379         }
380     }
381 
382 #endif
383 
384     // Marks the edge as being "coarse" (belonging to the control
385     // mesh). Generally this distinction only needs to be made if
386     // we're worried about interpolateboundary behaviour
SetCoarse(bool c)387     void SetCoarse(bool c) { coarse = c; }
IsCoarse()388     bool IsCoarse() const { return coarse; }
389 
390     friend class HbrFace<T>;
391 
392 private:
393     HbrHalfedge<T>* opposite;
394     // Index of incident vertex
395     int incidentVertex;
396 
397     // Index of subdivided vertex child
398     int vchild;
399     float sharpness;
400 
401 #ifdef HBRSTITCH
402     unsigned short stitchccw:1;
403     unsigned short raystitchccw:1;
404     unsigned short stitchdatavalid:1;
405 #endif
406     unsigned short coarse:1;
407     unsigned short lastedge:1;
408     unsigned short firstedge:1;
409 
410     // If m_index = 0, 1, 2 or 3: we are the m_index edge of an
411     // incident face with 3 or 4 vertices.
412     // If m_index = 4: our incident face has more than 4 vertices, and
413     // we must do some extra math to determine what our actual index
414     // is. See getIndex()
415     unsigned short m_index:3;
416 
417     // Returns the index of the edge relative to its incident face.
418     // This relies on knowledge of the face's edge allocation pattern
getIndex()419     int getIndex() const {
420         if (m_index < 4) {
421             return m_index;
422         } else {
423             // We allocate room for up to 4 values (to handle tri or
424             // quad) in the edges array.  If there are more than that,
425             // they _all_ go in the faces' extraedges array.
426             HbrFace<T>* incidentFace = *(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>));
427             return int(((char *) this - incidentFace->extraedges) /
428                 (sizeof(HbrHalfedge<T>) + sizeof(HbrFace<T>*)));
429         }
430     }
431 
432     // Returns bitmask indicating whether a given facevarying datum
433     // for the edge is infinitely sharp. Each datum has two bits, and
434     // if those two bits are set to 3, it means the status has not
435     // been computed yet.
getFVarInfSharp()436     unsigned int *getFVarInfSharp() {
437         unsigned int *fvarbits = GetFace()->fvarbits;
438         if (fvarbits) {
439             int fvarbitsSizePerEdge = ((GetMesh()->GetFVarCount() + 15) / 16);
440             return fvarbits + getIndex() * fvarbitsSizePerEdge;
441         } else {
442             return 0;
443         }
444     }
445 
446 #ifdef HBRSTITCH
getStitchEdges()447     StitchEdge **getStitchEdges() {
448         return GetFace()->stitchEdges + GetMesh()->GetStitchCount() * getIndex();
449     }
450 #endif
451 
452 #ifdef HBR_ADAPTIVE
453 public:
454     struct adaptiveFlags {
455         unsigned isTransition:1;
456         unsigned isTriangleHead:1;
457         unsigned isWatertightCritical:1;
458 
adaptiveFlagsadaptiveFlags459         adaptiveFlags() : isTransition(0),isTriangleHead(0),isWatertightCritical(0) { }
460     };
461 
462     adaptiveFlags _adaptiveFlags;
463 
IsInsideHole()464     bool IsInsideHole() const {
465 
466         HbrFace<T> * left = GetLeftFace();
467         if (left and (not left->IsHole()))
468             return false;
469 
470         HbrFace<T> * right = GetRightFace();
471         if (right and (not right->IsHole()))
472             return false;
473 
474         return true;
475     }
476 
IsTransition()477     bool IsTransition() const { return _adaptiveFlags.isTransition; }
478 
IsTriangleHead()479     bool IsTriangleHead() const { return _adaptiveFlags.isTriangleHead; }
480 
IsWatertightCritical()481     bool IsWatertightCritical() const { return _adaptiveFlags.isWatertightCritical; }
482 #endif
483 };
484 
485 template <class T>
486 void
Initialize(HbrHalfedge<T> * opposite,int index,HbrVertex<T> * origin,unsigned int * fvarbits,HbrFace<T> * face)487 HbrHalfedge<T>::Initialize(HbrHalfedge<T>* opposite, int index, HbrVertex<T>* origin,
488     unsigned int *fvarbits, HbrFace<T>* face) {
489     HbrMesh<T> *mesh = face->GetMesh();
490     if (face->GetNumVertices() <= 4) {
491         m_index = index;
492     } else {
493         m_index = 4;
494         // Assumes upstream allocation ensured we have extra storage
495         // for pointer to face after the halfedge data structure
496         // itself
497         *(HbrFace<T>**)((char *) this + sizeof(HbrHalfedge<T>)) = face;
498     }
499 
500     this->opposite = opposite;
501     incidentVertex = origin->GetID();
502     lastedge = (index == face->GetNumVertices() - 1);
503     firstedge = (index == 0);
504     if (opposite) {
505         sharpness = opposite->sharpness;
506 #ifdef HBRSTITCH
507         StitchEdge **stitchEdges = face->stitchEdges +
508             mesh->GetStitchCount() * index;
509         for (int i = 0; i < mesh->GetStitchCount(); ++i) {
510             stitchEdges[i] = opposite->getStitchEdges()[i];
511         }
512         stitchccw = opposite->stitchccw;
513         raystitchccw = opposite->raystitchccw;
514         stitchdatavalid = 0;
515         if (stitchEdges && opposite->GetStitchData()) {
516             mesh->SetStitchData(this, opposite->GetStitchData());
517             stitchdatavalid = 1;
518         }
519 #endif
520         if (fvarbits) {
521             const int fvarcount = mesh->GetFVarCount();
522             int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
523             memcpy(fvarbits, opposite->getFVarInfSharp(), fvarbitsSizePerEdge * sizeof(unsigned int));
524         }
525     } else {
526         sharpness = 0.0f;
527 #ifdef HBRSTITCH
528         StitchEdge **stitchEdges = getStitchEdges();
529         for (int i = 0; i < mesh->GetStitchCount(); ++i) {
530             stitchEdges[i] = 0;
531         }
532         stitchccw = 1;
533         raystitchccw = 1;
534         stitchdatavalid = 0;
535 #endif
536         if (fvarbits) {
537             const int fvarcount = mesh->GetFVarCount();
538             int fvarbitsSizePerEdge = ((fvarcount + 15) / 16);
539             memset(fvarbits, 0xff, fvarbitsSizePerEdge * sizeof(unsigned int));
540         }
541     }
542 }
543 
544 template <class T>
~HbrHalfedge()545 HbrHalfedge<T>::~HbrHalfedge() {
546     Clear();
547 }
548 
549 template <class T>
550 void
Clear()551 HbrHalfedge<T>::Clear() {
552     if (opposite) {
553         opposite->opposite = 0;
554         if (vchild != -1) {
555             // Transfer ownership of the vchild to the opposite ptr
556             opposite->vchild = vchild;
557 
558             HbrVertex<T> *vchildVert = GetMesh()->GetVertex(vchild);
559             // Done this way just for assertion sanity
560             vchildVert->SetParent(static_cast<HbrHalfedge*>(0));
561             vchildVert->SetParent(opposite);
562             vchild = -1;
563         }
564         opposite = 0;
565     }
566     // Orphan the child vertex
567     else if (vchild != -1) {
568         HbrVertex<T> *vchildVert = GetMesh()->GetVertex(vchild);
569         vchildVert->SetParent(static_cast<HbrHalfedge*>(0));
570         vchild = -1;
571     }
572 }
573 
574 template <class T>
575 HbrVertex<T>*
Subdivide()576 HbrHalfedge<T>::Subdivide() {
577     HbrMesh<T>* mesh = GetMesh();
578     if (vchild != -1) return mesh->GetVertex(vchild);
579     // Make sure that our opposite doesn't "own" a subdivided vertex
580     // already. If it does, use that
581     if (opposite && opposite->vchild != -1) return mesh->GetVertex(opposite->vchild);
582     HbrVertex<T>* vchildVert = mesh->GetSubdivision()->Subdivide(mesh, this);
583     vchild = vchildVert->GetID();
584     vchildVert->SetParent(this);
585     return vchildVert;
586 }
587 
588 template <class T>
589 void
GuaranteeNeighbor()590 HbrHalfedge<T>::GuaranteeNeighbor() {
591     HbrMesh<T>* mesh = GetMesh();
592     mesh->GetSubdivision()->GuaranteeNeighbor(mesh, this);
593 }
594 
595 // Determines whether an edge is infinitely sharp as far as its
596 // facevarying data is concerned. Happens if the faces on both sides
597 // disagree on the facevarying data at either of the shared vertices
598 // on the edge.
599 template <class T>
600 bool
GetFVarInfiniteSharp(int datum)601 HbrHalfedge<T>::GetFVarInfiniteSharp(int datum) {
602 
603     // Check to see if already initialized
604     int intindex = datum >> 4;
605     int shift = (datum & 15) << 1;
606     unsigned int *fvarinfsharp = getFVarInfSharp();
607     unsigned int bits = (fvarinfsharp[intindex] >> shift) & 0x3;
608     if (bits != 3) {
609         assert (bits != 2);
610         return bits ? true : false;
611     }
612 
613     // If there is no face varying data it can't be infinitely sharp!
614     const int fvarwidth = GetMesh()->GetTotalFVarWidth();
615     if (!fvarwidth) {
616         bits = ~(0x3 << shift);
617         fvarinfsharp[intindex] &= bits;
618         if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
619         return false;
620     }
621 
622     // If either incident face is missing, it's a geometric boundary
623     // edge, and also a facevarying boundary edge
624     HbrFace<T>* left = GetLeftFace(), *right = GetRightFace();
625     if (!left || !right) {
626         bits = ~(0x2 << shift);
627         fvarinfsharp[intindex] &= bits;
628         if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
629         return true;
630     }
631 
632     // Look for the indices on each face which correspond to the
633     // origin and destination vertices of the edge
634     int lorg = -1, ldst = -1, rorg = -1, rdst = -1, i, nv;
635     HbrHalfedge<T>* e;
636     e = left->GetFirstEdge();
637     nv = left->GetNumVertices();
638     for (i = 0; i < nv; ++i) {
639         if (e->GetOrgVertex() == GetOrgVertex()) lorg = i;
640         if (e->GetOrgVertex() == GetDestVertex()) ldst = i;
641         e = e->GetNext();
642     }
643     e = right->GetFirstEdge();
644     nv = right->GetNumVertices();
645     for (i = 0; i < nv; ++i) {
646         if (e->GetOrgVertex() == GetOrgVertex()) rorg = i;
647         if (e->GetOrgVertex() == GetDestVertex()) rdst = i;
648         e = e->GetNext();
649     }
650     assert(lorg >= 0 && ldst >= 0 && rorg >= 0 && rdst >= 0);
651     // Compare the facevarying data to some tolerance
652     const int startindex = GetMesh()->GetFVarIndices()[datum];
653     const int width = GetMesh()->GetFVarWidths()[datum];
654     if (!right->GetFVarData(rorg).Compare(left->GetFVarData(lorg), startindex, width, 0.001f) ||
655         !right->GetFVarData(rdst).Compare(left->GetFVarData(ldst), startindex, width, 0.001f)) {
656         bits = ~(0x2 << shift);
657         fvarinfsharp[intindex] &= bits;
658         if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
659         return true;
660     }
661 
662     bits = ~(0x3 << shift);
663     fvarinfsharp[intindex] &= bits;
664     if (opposite) opposite->getFVarInfSharp()[intindex] &= bits;
665     return false;
666 }
667 
668 template <class T>
669 bool
IsFVarInfiniteSharpAnywhere()670 HbrHalfedge<T>::IsFVarInfiniteSharpAnywhere() {
671 
672     if (sharpness > k_Smooth) {
673         return true;
674     }
675 
676     for (int i = 0; i < GetMesh()->GetFVarCount(); ++i) {
677         if (GetFVarInfiniteSharp(i)) return true;
678     }
679     return false;
680 }
681 
682 template <class T>
683 float
GetFVarSharpness(int datum,bool ignoreGeometry)684 HbrHalfedge<T>::GetFVarSharpness(int datum, bool ignoreGeometry) {
685 
686     if (GetFVarInfiniteSharp(datum)) return k_InfinitelySharp;
687 
688     if (!ignoreGeometry) {
689         // If it's a geometrically sharp edge it's going to be a
690         // facevarying sharp edge too
691         if (sharpness > k_Smooth) {
692             SetFVarInfiniteSharp(datum, true);
693             return k_InfinitelySharp;
694         }
695     }
696     return k_Smooth;
697 }
698 
699 
700 template <class T>
701 std::ostream&
702 operator<<(std::ostream& out, const HbrHalfedge<T>& edge) {
703     if (edge.IsBoundary()) out << "boundary ";
704     out << "edge connecting ";
705     if (edge.GetOrgVertex())
706         out << *edge.GetOrgVertex();
707     else
708         out << "(none)";
709     out << " to ";
710     if (edge.GetDestVertex()) {
711         out << *edge.GetDestVertex();
712     } else {
713         out << "(none)";
714     }
715     return out;
716 }
717 
718 // Sorts half edges by the relative ordering of the incident faces'
719 // paths.
720 template <class T>
721 class HbrHalfedgeCompare {
722 public:
operator()723     bool operator() (const HbrHalfedge<T>* a, HbrHalfedge<T>* b) const {
724         return (a->GetFace()->GetPath() < b->GetFace()->GetPath());
725     }
726 };
727 
728 template <class T>
729 class HbrHalfedgeOperator {
730 public:
731     virtual void operator() (HbrHalfedge<T> &edge) = 0;
~HbrHalfedgeOperator()732     virtual ~HbrHalfedgeOperator() {}
733 };
734 
735 } // end namespace OPENSUBDIV_VERSION
736 using namespace OPENSUBDIV_VERSION;
737 
738 } // end namespace OpenSubdiv
739 
740 #endif /* OPENSUBDIV3_HBRHALFEDGE_H */
741