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