| 1 | // Copyright 2009-2021 Intel Corporation | 
| 2 | // SPDX-License-Identifier: Apache-2.0 | 
| 3 |  | 
| 4 | #pragma once | 
| 5 |  | 
| 6 | #include "catmullclark_coefficients.h" | 
| 7 |  | 
| 8 | namespace embree | 
| 9 | { | 
| 10 |   class __aligned(32) HalfEdge | 
| 11 |   { | 
| 12 |     friend class SubdivMesh; | 
| 13 |     public: | 
| 14 |  | 
| 15 |     enum PatchType : char {  | 
| 16 |       BILINEAR_PATCH        = 0, //!< a bilinear patch | 
| 17 |       REGULAR_QUAD_PATCH    = 1, //!< a regular quad patch can be represented as a B-Spline | 
| 18 |       IRREGULAR_QUAD_PATCH  = 2, //!< an irregular quad patch can be represented as a Gregory patch | 
| 19 |       COMPLEX_PATCH         = 3  //!< these patches need subdivision and cannot be processed by the above fast code paths | 
| 20 |     }; | 
| 21 |      | 
| 22 |     enum VertexType : char {  | 
| 23 |       REGULAR_VERTEX           = 0, //!< regular vertex | 
| 24 |       NON_MANIFOLD_EDGE_VERTEX = 1, //!< vertex of a non-manifold edge | 
| 25 |     }; | 
| 26 |      | 
| 27 |     __forceinline friend PatchType max( const PatchType& ty0, const PatchType& ty1) { | 
| 28 |       return (PatchType) max(a: (int)ty0,b: (int)ty1); | 
| 29 |     } | 
| 30 |      | 
| 31 |     struct Edge  | 
| 32 |     { | 
| 33 |       /*! edge constructor */ | 
| 34 |       __forceinline Edge(const uint32_t v0, const uint32_t v1) | 
| 35 | 	: v0(v0), v1(v1) {} | 
| 36 |  | 
| 37 |       /*! create an 64 bit identifier that is unique for the not oriented edge */ | 
| 38 |       __forceinline operator uint64_t() const        | 
| 39 |       { | 
| 40 | 	uint32_t p0 = v0, p1 = v1; | 
| 41 | 	if (p0<p1) std::swap(a&: p0,b&: p1); | 
| 42 | 	return (((uint64_t)p0) << 32) | (uint64_t)p1; | 
| 43 |       } | 
| 44 |  | 
| 45 |     public: | 
| 46 |       uint32_t v0,v1;    //!< start and end vertex of the edge | 
| 47 |     }; | 
| 48 |  | 
| 49 |     HalfEdge ()  | 
| 50 |       : vtx_index(-1), next_half_edge_ofs(0), prev_half_edge_ofs(0), opposite_half_edge_ofs(0), edge_crease_weight(0),  | 
| 51 |       vertex_crease_weight(0), edge_level(0), patch_type(COMPLEX_PATCH), vertex_type(REGULAR_VERTEX) | 
| 52 |     { | 
| 53 |       static_assert(sizeof(HalfEdge) == 32, "invalid half edge size" ); | 
| 54 |     } | 
| 55 |   | 
| 56 |     __forceinline bool hasOpposite() const { return opposite_half_edge_ofs != 0; } | 
| 57 |     __forceinline void setOpposite(HalfEdge* opposite) { opposite_half_edge_ofs = int(opposite-this); } | 
| 58 |      | 
| 59 |     __forceinline       HalfEdge* next()       { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; } | 
| 60 |     __forceinline const HalfEdge* next() const { assert( next_half_edge_ofs != 0 ); return &this[next_half_edge_ofs]; } | 
| 61 |      | 
| 62 |     __forceinline       HalfEdge* prev()       { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; } | 
| 63 |     __forceinline const HalfEdge* prev() const { assert( prev_half_edge_ofs != 0 ); return &this[prev_half_edge_ofs]; } | 
| 64 |      | 
| 65 |     __forceinline       HalfEdge* opposite()       { assert( opposite_half_edge_ofs != 0 ); return &this[opposite_half_edge_ofs]; } | 
| 66 |     __forceinline const HalfEdge* opposite() const { assert( opposite_half_edge_ofs != 0 ); return &this[opposite_half_edge_ofs]; } | 
| 67 |      | 
| 68 |     __forceinline       HalfEdge* rotate()       { return opposite()->next(); } | 
| 69 |     __forceinline const HalfEdge* rotate() const { return opposite()->next(); } | 
| 70 |      | 
| 71 |     __forceinline unsigned int getStartVertexIndex() const { return vtx_index; } | 
| 72 |     __forceinline unsigned int getEndVertexIndex  () const { return next()->vtx_index; } | 
| 73 |     __forceinline Edge         getEdge            () const { return Edge(getStartVertexIndex(),getEndVertexIndex()); } | 
| 74 |     | 
| 75 |      | 
| 76 |     /*! tests if the start vertex of the edge is regular */ | 
| 77 |     __forceinline PatchType vertexType() const | 
| 78 |     { | 
| 79 |       const HalfEdge* p = this; | 
| 80 |       size_t face_valence = 0; | 
| 81 |       bool hasBorder = false; | 
| 82 |        | 
| 83 |       do | 
| 84 |       { | 
| 85 |         /* we need subdivision to handle edge creases */ | 
| 86 |         if (p->hasOpposite() && p->edge_crease_weight > 0.0f)  | 
| 87 |           return COMPLEX_PATCH; | 
| 88 |          | 
| 89 |         face_valence++; | 
| 90 |          | 
| 91 |         /* test for quad */ | 
| 92 |         const HalfEdge* pp = p; | 
| 93 |         pp = pp->next(); if (pp == p) return COMPLEX_PATCH; | 
| 94 |         pp = pp->next(); if (pp == p) return COMPLEX_PATCH; | 
| 95 |         pp = pp->next(); if (pp == p) return COMPLEX_PATCH; | 
| 96 |         pp = pp->next(); if (pp != p) return COMPLEX_PATCH; | 
| 97 |          | 
| 98 |         /* continue with next face */ | 
| 99 |         p = p->prev(); | 
| 100 |         if (likely(p->hasOpposite()))  | 
| 101 |           p = p->opposite(); | 
| 102 |          | 
| 103 |         /* if there is no opposite go the long way to the other side of the border */ | 
| 104 |         else | 
| 105 |         { | 
| 106 |           face_valence++; | 
| 107 |           hasBorder = true; | 
| 108 |           p = this; | 
| 109 |           while (p->hasOpposite())  | 
| 110 |             p = p->rotate(); | 
| 111 |         } | 
| 112 |       } while (p != this);  | 
| 113 |        | 
| 114 |       /* calculate vertex type */ | 
| 115 |       if (face_valence == 2 && hasBorder) { | 
| 116 |         if      (vertex_crease_weight == 0.0f      ) return REGULAR_QUAD_PATCH; | 
| 117 |         else if (vertex_crease_weight == float(inf)) return REGULAR_QUAD_PATCH; | 
| 118 |         else                                         return COMPLEX_PATCH; | 
| 119 |       } | 
| 120 |       else if (vertex_crease_weight != 0.0f)         return COMPLEX_PATCH; | 
| 121 |       else if (face_valence == 3 &&  hasBorder)      return REGULAR_QUAD_PATCH; | 
| 122 |       else if (face_valence == 4 && !hasBorder)      return REGULAR_QUAD_PATCH; | 
| 123 |       else                                           return IRREGULAR_QUAD_PATCH; | 
| 124 |     } | 
| 125 |  | 
| 126 |     /*! tests if this edge is part of a bilinear patch */ | 
| 127 |     __forceinline bool bilinearVertex() const { | 
| 128 |       return vertex_crease_weight == float(inf) && edge_crease_weight == float(inf); | 
| 129 |     } | 
| 130 |      | 
| 131 |     /*! calculates the type of the patch */ | 
| 132 |     __forceinline PatchType patchType() const  | 
| 133 |     { | 
| 134 |       const HalfEdge* p = this; | 
| 135 |       PatchType ret = REGULAR_QUAD_PATCH; | 
| 136 |       bool bilinear = true; | 
| 137 |        | 
| 138 |       ret = max(ty0: ret,ty1: p->vertexType()); | 
| 139 |       bilinear &= p->bilinearVertex(); | 
| 140 |       if ((p = p->next()) == this) return COMPLEX_PATCH; | 
| 141 |        | 
| 142 |       ret = max(ty0: ret,ty1: p->vertexType()); | 
| 143 |       bilinear &= p->bilinearVertex(); | 
| 144 |       if ((p = p->next()) == this) return COMPLEX_PATCH; | 
| 145 |        | 
| 146 |       ret = max(ty0: ret,ty1: p->vertexType()); | 
| 147 |       bilinear &= p->bilinearVertex(); | 
| 148 |       if ((p = p->next()) == this) return COMPLEX_PATCH; | 
| 149 |        | 
| 150 |       ret = max(ty0: ret,ty1: p->vertexType()); | 
| 151 |       bilinear &= p->bilinearVertex(); | 
| 152 |       if ((p = p->next()) != this) return COMPLEX_PATCH; | 
| 153 |        | 
| 154 |       if (bilinear) return BILINEAR_PATCH; | 
| 155 |       return ret; | 
| 156 |     } | 
| 157 |      | 
| 158 |     /*! tests if the face is a regular b-spline face */ | 
| 159 |     __forceinline bool isRegularFace() const { | 
| 160 |       return patch_type == REGULAR_QUAD_PATCH; | 
| 161 |     } | 
| 162 |      | 
| 163 |     /*! tests if the face can be diced (using bspline or gregory patch) */ | 
| 164 |     __forceinline bool isGregoryFace() const { | 
| 165 |       return patch_type == IRREGULAR_QUAD_PATCH || patch_type == REGULAR_QUAD_PATCH; | 
| 166 |     } | 
| 167 |      | 
| 168 |     /*! tests if the base vertex of this half edge is a corner vertex */ | 
| 169 |     __forceinline bool isCorner() const { | 
| 170 |       return !hasOpposite() && !prev()->hasOpposite(); | 
| 171 |     } | 
| 172 |  | 
| 173 |     /*! tests if the vertex is attached to any border */ | 
| 174 |     __forceinline bool vertexHasBorder() const  | 
| 175 |     { | 
| 176 |       const HalfEdge* p = this; | 
| 177 |       do { | 
| 178 |         if (!p->hasOpposite()) return true; | 
| 179 |         p = p->rotate(); | 
| 180 |       } while (p != this); | 
| 181 |       return false; | 
| 182 |     } | 
| 183 |      | 
| 184 |     /*! tests if the face this half edge belongs to has some border */ | 
| 185 |     __forceinline bool faceHasBorder() const  | 
| 186 |     { | 
| 187 |       const HalfEdge* p = this; | 
| 188 |       do { | 
| 189 |         if (p->vertexHasBorder() && (p->vertex_type != HalfEdge::NON_MANIFOLD_EDGE_VERTEX)) return true; | 
| 190 |         p = p->next(); | 
| 191 |       } while (p != this); | 
| 192 |       return false; | 
| 193 |     } | 
| 194 |      | 
| 195 |     /*! calculates conservative bounds of a catmull clark subdivision face */ | 
| 196 |     __forceinline BBox3fa bounds(const BufferView<Vec3fa>& vertices) const | 
| 197 |     { | 
| 198 |       BBox3fa bounds = this->get1RingBounds(vertices); | 
| 199 |       for (const HalfEdge* p=this->next(); p!=this; p=p->next()) | 
| 200 |         bounds.extend(other: p->get1RingBounds(vertices)); | 
| 201 |       return bounds; | 
| 202 |     } | 
| 203 |      | 
| 204 |     /*! tests if this is a valid patch */ | 
| 205 |     __forceinline bool valid(const BufferView<Vec3fa>& vertices) const | 
| 206 |     { | 
| 207 |       size_t N = 1; | 
| 208 |       if (!this->validRing(vertices)) return false; | 
| 209 |       for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++) { | 
| 210 |         if (!p->validRing(vertices)) return false; | 
| 211 |       } | 
| 212 |       return N >= 3 && N <= MAX_PATCH_VALENCE; | 
| 213 |     } | 
| 214 |      | 
| 215 |     /*! counts number of polygon edges  */ | 
| 216 |     __forceinline unsigned int numEdges() const | 
| 217 |     { | 
| 218 |       unsigned int N = 1; | 
| 219 |       for (const HalfEdge* p=this->next(); p!=this; p=p->next(), N++); | 
| 220 |       return N; | 
| 221 |     } | 
| 222 |  | 
| 223 |     /*! calculates face and edge valence */ | 
| 224 |     __forceinline void calculateFaceValenceAndEdgeValence(size_t& faceValence, size_t& edgeValence) const  | 
| 225 |     { | 
| 226 |       faceValence = 0; | 
| 227 |       edgeValence = 0; | 
| 228 |        | 
| 229 |       const HalfEdge* p = this; | 
| 230 |       do  | 
| 231 |       { | 
| 232 |          /* calculate bounds of current face */ | 
| 233 |         unsigned int numEdges = p->numEdges(); | 
| 234 |         assert(numEdges >= 3); | 
| 235 |         edgeValence += numEdges-2; | 
| 236 |          | 
| 237 |         faceValence++; | 
| 238 |         p = p->prev(); | 
| 239 |          | 
| 240 |         /* continue with next face */ | 
| 241 |         if (likely(p->hasOpposite()))  | 
| 242 |           p = p->opposite(); | 
| 243 |          | 
| 244 |         /* if there is no opposite go the long way to the other side of the border */ | 
| 245 |         else { | 
| 246 |           faceValence++; | 
| 247 |           edgeValence++; | 
| 248 |           p = this; | 
| 249 |           while (p->hasOpposite())  | 
| 250 |             p = p->opposite()->next(); | 
| 251 |         } | 
| 252 |          | 
| 253 |       } while (p != this);  | 
| 254 |     } | 
| 255 |  | 
| 256 |     /*! stream output */ | 
| 257 |     friend __forceinline std::ostream &operator<<(std::ostream &o, const HalfEdge &h) | 
| 258 |     { | 
| 259 |       return o << "{ "  <<  | 
| 260 |         "vertex = "  << h.vtx_index << ", "  << //" -> " << h.next()->vtx_index << ", " <<  | 
| 261 |         "prev = "  << h.prev_half_edge_ofs << ", "  <<  | 
| 262 |         "next = "  << h.next_half_edge_ofs << ", "  <<  | 
| 263 |         "opposite = "  << h.opposite_half_edge_ofs << ", "  <<  | 
| 264 |         "edge_crease = "  << h.edge_crease_weight << ", "  <<  | 
| 265 |         "vertex_crease = "  << h.vertex_crease_weight << ", "  <<  | 
| 266 |         //"edge_level = " << h.edge_level <<  | 
| 267 |         " }" ; | 
| 268 |     }  | 
| 269 |      | 
| 270 |   private: | 
| 271 |      | 
| 272 |     /*! calculates the bounds of the face associated with the half-edge */ | 
| 273 |     __forceinline BBox3fa getFaceBounds(const BufferView<Vec3fa>& vertices) const  | 
| 274 |     { | 
| 275 |       BBox3fa b = vertices[getStartVertexIndex()]; | 
| 276 |       for (const HalfEdge* p = next(); p!=this; p=p->next()) { | 
| 277 |         b.extend(other: vertices[p->getStartVertexIndex()]); | 
| 278 |       } | 
| 279 |       return b; | 
| 280 |     } | 
| 281 |      | 
| 282 |     /*! calculates the bounds of the 1-ring associated with the vertex of the half-edge */ | 
| 283 |     __forceinline BBox3fa get1RingBounds(const BufferView<Vec3fa>& vertices) const  | 
| 284 |     { | 
| 285 |       BBox3fa bounds = empty; | 
| 286 |       const HalfEdge* p = this; | 
| 287 |       do  | 
| 288 |       { | 
| 289 |         /* calculate bounds of current face */ | 
| 290 |         bounds.extend(other: p->getFaceBounds(vertices)); | 
| 291 |         p = p->prev(); | 
| 292 |          | 
| 293 |         /* continue with next face */ | 
| 294 |         if (likely(p->hasOpposite()))  | 
| 295 |           p = p->opposite(); | 
| 296 |          | 
| 297 |         /* if there is no opposite go the long way to the other side of the border */ | 
| 298 |         else { | 
| 299 |           p = this; | 
| 300 |           while (p->hasOpposite())  | 
| 301 |             p = p->opposite()->next(); | 
| 302 |         } | 
| 303 |          | 
| 304 |       } while (p != this);  | 
| 305 |        | 
| 306 |       return bounds; | 
| 307 |     } | 
| 308 |      | 
| 309 |     /*! tests if this is a valid face */ | 
| 310 |     __forceinline bool validFace(const BufferView<Vec3fa>& vertices, size_t& N) const  | 
| 311 |     { | 
| 312 |       const Vec3fa v = vertices[getStartVertexIndex()]; | 
| 313 |       if (!isvalid(v)) return false; | 
| 314 |       size_t n = 1; | 
| 315 |       for (const HalfEdge* p = next(); p!=this; p=p->next(), n++) { | 
| 316 |         const Vec3fa v = vertices[p->getStartVertexIndex()]; | 
| 317 |         if (!isvalid(v)) return false; | 
| 318 |       } | 
| 319 |       N += n-2; | 
| 320 |       return n >= 3 && n <= MAX_PATCH_VALENCE; | 
| 321 |     } | 
| 322 |      | 
| 323 |     /*! tests if this is a valid ring */ | 
| 324 |     __forceinline bool validRing(const BufferView<Vec3fa>& vertices) const  | 
| 325 |     { | 
| 326 |       size_t faceValence = 0; | 
| 327 |       size_t edgeValence = 0; | 
| 328 |        | 
| 329 |       const HalfEdge* p = this; | 
| 330 |       do  | 
| 331 |       { | 
| 332 |         /* calculate bounds of current face */ | 
| 333 |         if (!p->validFace(vertices,N&: edgeValence))  | 
| 334 |           return false; | 
| 335 |          | 
| 336 |         faceValence++; | 
| 337 |         p = p->prev(); | 
| 338 |          | 
| 339 |         /* continue with next face */ | 
| 340 |         if (likely(p->hasOpposite()))  | 
| 341 |           p = p->opposite(); | 
| 342 |          | 
| 343 |         /* if there is no opposite go the long way to the other side of the border */ | 
| 344 |         else { | 
| 345 |           faceValence++; | 
| 346 |           edgeValence++; | 
| 347 |           p = this; | 
| 348 |           while (p->hasOpposite())  | 
| 349 |             p = p->opposite()->next(); | 
| 350 |         } | 
| 351 |          | 
| 352 |       } while (p != this);  | 
| 353 |        | 
| 354 |       return faceValence <= MAX_RING_FACE_VALENCE && edgeValence <= MAX_RING_EDGE_VALENCE; | 
| 355 |     } | 
| 356 |      | 
| 357 |   private: | 
| 358 |     unsigned int vtx_index;         //!< index of edge start vertex | 
| 359 |     int next_half_edge_ofs;         //!< relative offset to next half edge of face | 
| 360 |     int prev_half_edge_ofs;         //!< relative offset to previous half edge of face | 
| 361 |     int opposite_half_edge_ofs;     //!< relative offset to opposite half edge | 
| 362 |      | 
| 363 |   public: | 
| 364 |     float edge_crease_weight;       //!< crease weight attached to edge | 
| 365 |     float vertex_crease_weight;     //!< crease weight attached to start vertex | 
| 366 |     float edge_level;               //!< subdivision factor for edge | 
| 367 |     PatchType patch_type;           //!< stores type of subdiv patch | 
| 368 |     VertexType vertex_type;         //!< stores type of the start vertex | 
| 369 |     char align[2]; | 
| 370 |   }; | 
| 371 | } | 
| 372 |  |