Path: blob/master/thirdparty/embree/kernels/subdiv/catmullclark_patch.h
9918 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "catmullclark_ring.h"6#include "bezier_curve.h"78namespace embree9{10template<typename Vertex, typename Vertex_t = Vertex>11class __aligned(64) CatmullClarkPatchT12{13public:14typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;15typedef typename CatmullClark1Ring::Type Type;1617array_t<CatmullClark1RingT<Vertex,Vertex_t>,4> ring;1819public:20__forceinline CatmullClarkPatchT () {}2122__forceinline CatmullClarkPatchT (const HalfEdge* first_half_edge, const char* vertices, size_t stride) {23init(first_half_edge,vertices,stride);24}2526__forceinline CatmullClarkPatchT (const HalfEdge* first_half_edge, const BufferView<Vec3fa>& vertices) {27init(first_half_edge,vertices.getPtr(),vertices.getStride());28}2930__forceinline void init (const HalfEdge* first_half_edge, const char* vertices, size_t stride)31{32for (unsigned i=0; i<4; i++)33ring[i].init(first_half_edge+i,vertices,stride);3435assert(verify());36}3738__forceinline size_t bytes() const {39return ring[0].bytes()+ring[1].bytes()+ring[2].bytes()+ring[3].bytes();40}4142__forceinline void serialize(void* ptr, size_t& ofs) const43{44for (size_t i=0; i<4; i++)45ring[i].serialize((char*)ptr,ofs);46}4748__forceinline void deserialize(void* ptr)49{50size_t ofs = 0;51for (size_t i=0; i<4; i++)52ring[i].deserialize((char*)ptr,ofs);53}5455__forceinline BBox3fa bounds() const56{57BBox3fa bounds (ring[0].bounds());58for (size_t i=1; i<4; i++)59bounds.extend(ring[i].bounds());60return bounds;61}6263__forceinline Type type() const64{65const int ty0 = ring[0].type() ^ CatmullClark1Ring::TYPE_CREASES;66const int ty1 = ring[1].type() ^ CatmullClark1Ring::TYPE_CREASES;67const int ty2 = ring[2].type() ^ CatmullClark1Ring::TYPE_CREASES;68const int ty3 = ring[3].type() ^ CatmullClark1Ring::TYPE_CREASES;69return (Type) ((ty0 & ty1 & ty2 & ty3) ^ CatmullClark1Ring::TYPE_CREASES);70}7172__forceinline bool isFinalResolution(float res) const {73return ring[0].isFinalResolution(res) && ring[1].isFinalResolution(res) && ring[2].isFinalResolution(res) && ring[3].isFinalResolution(res);74}7576static __forceinline void init_regular(const CatmullClark1RingT<Vertex,Vertex_t>& p0,77const CatmullClark1RingT<Vertex,Vertex_t>& p1,78CatmullClark1RingT<Vertex,Vertex_t>& dest0,79CatmullClark1RingT<Vertex,Vertex_t>& dest1)80{81assert(p1.face_valence > 2);82dest1.vertex_level = dest0.vertex_level = p0.edge_level;83dest1.face_valence = dest0.face_valence = 4;84dest1.edge_valence = dest0.edge_valence = 8;85dest1.border_index = dest0.border_index = -1;86dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];87dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;8889dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];90dest1.ring[1] = dest0.ring[7] = (Vertex_t)p1.ring[0];91dest1.ring[0] = dest0.ring[6] = (Vertex_t)p1.vtx;92dest1.ring[7] = dest0.ring[5] = (Vertex_t)p1.ring[4];93dest1.ring[6] = dest0.ring[4] = (Vertex_t)p0.ring[p0.edge_valence-1];94dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.edge_valence-2];95dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;96dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];9798dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;99dest1.crease_weight[0] = dest0.crease_weight[3] = p1.crease_weight[1];100dest1.crease_weight[3] = dest0.crease_weight[2] = 0.0f;101dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];102103if (p0.eval_unique_identifier <= p1.eval_unique_identifier)104{105dest0.eval_start_index = 3;106dest1.eval_start_index = 0;107dest0.eval_unique_identifier = p0.eval_unique_identifier;108dest1.eval_unique_identifier = p0.eval_unique_identifier;109}110else111{112dest0.eval_start_index = 1;113dest1.eval_start_index = 2;114dest0.eval_unique_identifier = p1.eval_unique_identifier;115dest1.eval_unique_identifier = p1.eval_unique_identifier;116}117}118119static __forceinline void init_border(const CatmullClark1RingT<Vertex,Vertex_t> &p0,120const CatmullClark1RingT<Vertex,Vertex_t> &p1,121CatmullClark1RingT<Vertex,Vertex_t> &dest0,122CatmullClark1RingT<Vertex,Vertex_t> &dest1)123{124dest1.vertex_level = dest0.vertex_level = p0.edge_level;125dest1.face_valence = dest0.face_valence = 3;126dest1.edge_valence = dest0.edge_valence = 6;127dest0.border_index = 2;128dest1.border_index = 4;129dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];130dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;131132dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];133dest1.ring[1] = dest0.ring[5] = (Vertex_t)p1.ring[0];134dest1.ring[0] = dest0.ring[4] = (Vertex_t)p1.vtx;135dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.border_index+1]; // dummy136dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;137dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];138139dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;140dest1.crease_weight[0] = dest0.crease_weight[2] = p1.crease_weight[1];141dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];142143if (p0.eval_unique_identifier <= p1.eval_unique_identifier)144{145dest0.eval_start_index = 1;146dest1.eval_start_index = 2;147dest0.eval_unique_identifier = p0.eval_unique_identifier;148dest1.eval_unique_identifier = p0.eval_unique_identifier;149}150else151{152dest0.eval_start_index = 2;153dest1.eval_start_index = 0;154dest0.eval_unique_identifier = p1.eval_unique_identifier;155dest1.eval_unique_identifier = p1.eval_unique_identifier;156}157}158159static __forceinline void init_regular(const Vertex_t ¢er, const Vertex_t center_ring[8], const unsigned int offset, CatmullClark1RingT<Vertex,Vertex_t> &dest)160{161dest.vertex_level = 0.0f;162dest.face_valence = 4;163dest.edge_valence = 8;164dest.border_index = -1;165dest.vtx = (Vertex_t)center;166dest.vertex_crease_weight = 0.0f;167for (size_t i=0; i<8; i++)168dest.ring[i] = (Vertex_t)center_ring[(offset+i)%8];169for (size_t i=0; i<4; i++)170dest.crease_weight[i] = 0.0f;171172dest.eval_start_index = (8-offset)>>1;173if (dest.eval_start_index >= dest.face_valence) dest.eval_start_index -= dest.face_valence;174assert( dest.eval_start_index < dest.face_valence );175dest.eval_unique_identifier = 0;176}177178__noinline void subdivide(array_t<CatmullClarkPatchT,4>& patch) const179{180ring[0].subdivide(patch[0].ring[0]);181ring[1].subdivide(patch[1].ring[1]);182ring[2].subdivide(patch[2].ring[2]);183ring[3].subdivide(patch[3].ring[3]);184185patch[0].ring[0].edge_level = 0.5f*ring[0].edge_level;186patch[0].ring[1].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);187patch[0].ring[2].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);188patch[0].ring[3].edge_level = 0.5f*ring[3].edge_level;189190patch[1].ring[0].edge_level = 0.5f*ring[0].edge_level;191patch[1].ring[1].edge_level = 0.5f*ring[1].edge_level;192patch[1].ring[2].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);193patch[1].ring[3].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);194195patch[2].ring[0].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);196patch[2].ring[1].edge_level = 0.5f*ring[1].edge_level;197patch[2].ring[2].edge_level = 0.5f*ring[2].edge_level;198patch[2].ring[3].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);199200patch[3].ring[0].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level);201patch[3].ring[1].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level);202patch[3].ring[2].edge_level = 0.5f*ring[2].edge_level;203patch[3].ring[3].edge_level = 0.5f*ring[3].edge_level;204205const bool regular0 = ring[0].has_last_face() && ring[1].face_valence > 2;206if (likely(regular0))207init_regular(patch[0].ring[0],patch[1].ring[1],patch[0].ring[1],patch[1].ring[0]);208else209init_border(patch[0].ring[0],patch[1].ring[1],patch[0].ring[1],patch[1].ring[0]);210211const bool regular1 = ring[1].has_last_face() && ring[2].face_valence > 2;212if (likely(regular1))213init_regular(patch[1].ring[1],patch[2].ring[2],patch[1].ring[2],patch[2].ring[1]);214else215init_border(patch[1].ring[1],patch[2].ring[2],patch[1].ring[2],patch[2].ring[1]);216217const bool regular2 = ring[2].has_last_face() && ring[3].face_valence > 2;218if (likely(regular2))219init_regular(patch[2].ring[2],patch[3].ring[3],patch[2].ring[3],patch[3].ring[2]);220else221init_border(patch[2].ring[2],patch[3].ring[3],patch[2].ring[3],patch[3].ring[2]);222223const bool regular3 = ring[3].has_last_face() && ring[0].face_valence > 2;224if (likely(regular3))225init_regular(patch[3].ring[3],patch[0].ring[0],patch[3].ring[0],patch[0].ring[3]);226else227init_border(patch[3].ring[3],patch[0].ring[0],patch[3].ring[0],patch[0].ring[3]);228229Vertex_t center = (ring[0].vtx + ring[1].vtx + ring[2].vtx + ring[3].vtx) * 0.25f;230231Vertex_t center_ring[8];232center_ring[0] = (Vertex_t)patch[3].ring[3].ring[0];233center_ring[7] = (Vertex_t)patch[3].ring[3].vtx;234center_ring[6] = (Vertex_t)patch[2].ring[2].ring[0];235center_ring[5] = (Vertex_t)patch[2].ring[2].vtx;236center_ring[4] = (Vertex_t)patch[1].ring[1].ring[0];237center_ring[3] = (Vertex_t)patch[1].ring[1].vtx;238center_ring[2] = (Vertex_t)patch[0].ring[0].ring[0];239center_ring[1] = (Vertex_t)patch[0].ring[0].vtx;240241init_regular(center,center_ring,0,patch[0].ring[2]);242init_regular(center,center_ring,2,patch[1].ring[3]);243init_regular(center,center_ring,4,patch[2].ring[0]);244init_regular(center,center_ring,6,patch[3].ring[1]);245246assert(patch[0].verify());247assert(patch[1].verify());248assert(patch[2].verify());249assert(patch[3].verify());250}251252bool verify() const {253return ring[0].hasValidPositions() && ring[1].hasValidPositions() && ring[2].hasValidPositions() && ring[3].hasValidPositions();254}255256__forceinline void init( FinalQuad& quad ) const257{258quad.vtx[0] = (Vertex_t)ring[0].vtx;259quad.vtx[1] = (Vertex_t)ring[1].vtx;260quad.vtx[2] = (Vertex_t)ring[2].vtx;261quad.vtx[3] = (Vertex_t)ring[3].vtx;262};263264friend __forceinline embree_ostream operator<<(embree_ostream o, const CatmullClarkPatchT &p)265{266o << "CatmullClarkPatch { " << embree_endl;267for (size_t i=0; i<4; i++)268o << "ring" << i << ": " << p.ring[i] << embree_endl;269o << "}" << embree_endl;270return o;271}272};273274typedef CatmullClarkPatchT<Vec3fa,Vec3fa_t> CatmullClarkPatch3fa;275276template<typename Vertex, typename Vertex_t = Vertex>277class __aligned(64) GeneralCatmullClarkPatchT278{279public:280typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;281typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring;282typedef BezierCurveT<Vertex> BezierCurve;283284static const unsigned SIZE = MAX_PATCH_VALENCE;285DynamicStackArray<GeneralCatmullClark1RingT<Vertex,Vertex_t>,8,SIZE> ring;286unsigned N;287288__forceinline GeneralCatmullClarkPatchT ()289: N(0) {}290291GeneralCatmullClarkPatchT (const HalfEdge* h, const char* vertices, size_t stride) {292init(h,vertices,stride);293}294295__forceinline GeneralCatmullClarkPatchT (const HalfEdge* first_half_edge, const BufferView<Vec3fa>& vertices) {296init(first_half_edge,vertices.getPtr(),vertices.getStride());297}298299__forceinline void init (const HalfEdge* h, const char* vertices, size_t stride)300{301unsigned int i = 0;302const HalfEdge* edge = h;303do {304ring[i].init(edge,vertices,stride);305edge = edge->next();306i++;307} while ((edge != h) && (i < SIZE));308N = i;309}310311__forceinline unsigned size() const {312return N;313}314315__forceinline bool isQuadPatch() const {316return (N == 4) && ring[0].only_quads && ring[1].only_quads && ring[2].only_quads && ring[3].only_quads;317}318319static __forceinline void init_regular(const CatmullClark1RingT<Vertex,Vertex_t>& p0,320const CatmullClark1RingT<Vertex,Vertex_t>& p1,321CatmullClark1RingT<Vertex,Vertex_t>& dest0,322CatmullClark1RingT<Vertex,Vertex_t>& dest1)323{324assert(p1.face_valence > 2);325dest1.vertex_level = dest0.vertex_level = p0.edge_level;326dest1.face_valence = dest0.face_valence = 4;327dest1.edge_valence = dest0.edge_valence = 8;328dest1.border_index = dest0.border_index = -1;329dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];330dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;331332dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];333dest1.ring[1] = dest0.ring[7] = (Vertex_t)p1.ring[0];334dest1.ring[0] = dest0.ring[6] = (Vertex_t)p1.vtx;335dest1.ring[7] = dest0.ring[5] = (Vertex_t)p1.ring[4];336dest1.ring[6] = dest0.ring[4] = (Vertex_t)p0.ring[p0.edge_valence-1];337dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.edge_valence-2];338dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;339dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];340341dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;342dest1.crease_weight[0] = dest0.crease_weight[3] = p1.crease_weight[1];343dest1.crease_weight[3] = dest0.crease_weight[2] = 0.0f;344dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];345346if (p0.eval_unique_identifier <= p1.eval_unique_identifier)347{348dest0.eval_start_index = 3;349dest1.eval_start_index = 0;350dest0.eval_unique_identifier = p0.eval_unique_identifier;351dest1.eval_unique_identifier = p0.eval_unique_identifier;352}353else354{355dest0.eval_start_index = 1;356dest1.eval_start_index = 2;357dest0.eval_unique_identifier = p1.eval_unique_identifier;358dest1.eval_unique_identifier = p1.eval_unique_identifier;359}360}361362363static __forceinline void init_border(const CatmullClark1RingT<Vertex,Vertex_t> &p0,364const CatmullClark1RingT<Vertex,Vertex_t> &p1,365CatmullClark1RingT<Vertex,Vertex_t> &dest0,366CatmullClark1RingT<Vertex,Vertex_t> &dest1)367{368dest1.vertex_level = dest0.vertex_level = p0.edge_level;369dest1.face_valence = dest0.face_valence = 3;370dest1.edge_valence = dest0.edge_valence = 6;371dest0.border_index = 2;372dest1.border_index = 4;373dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0];374dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f;375376dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1];377dest1.ring[1] = dest0.ring[5] = (Vertex_t)p1.ring[0];378dest1.ring[0] = dest0.ring[4] = (Vertex_t)p1.vtx;379dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.border_index+1]; // dummy380dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx;381dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2];382383dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f;384dest1.crease_weight[0] = dest0.crease_weight[2] = p1.crease_weight[1];385dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0];386387if (p0.eval_unique_identifier <= p1.eval_unique_identifier)388{389dest0.eval_start_index = 1;390dest1.eval_start_index = 2;391dest0.eval_unique_identifier = p0.eval_unique_identifier;392dest1.eval_unique_identifier = p0.eval_unique_identifier;393}394else395{396dest0.eval_start_index = 2;397dest1.eval_start_index = 0;398dest0.eval_unique_identifier = p1.eval_unique_identifier;399dest1.eval_unique_identifier = p1.eval_unique_identifier;400}401}402403static __forceinline void init_regular(const Vertex_t ¢er, const array_t<Vertex_t,2*SIZE>& center_ring, const float vertex_level, const unsigned int N, const unsigned int offset, CatmullClark1RingT<Vertex,Vertex_t> &dest)404{405assert(N<(MAX_RING_FACE_VALENCE));406assert(2*N<(MAX_RING_EDGE_VALENCE));407dest.vertex_level = vertex_level;408dest.face_valence = N;409dest.edge_valence = 2*N;410dest.border_index = -1;411dest.vtx = (Vertex_t)center;412dest.vertex_crease_weight = 0.0f;413for (unsigned i=0; i<2*N; i++) {414dest.ring[i] = (Vertex_t)center_ring[(2*N+offset+i-1)%(2*N)];415assert(isvalid(dest.ring[i]));416}417for (unsigned i=0; i<N; i++)418dest.crease_weight[i] = 0.0f;419420assert(offset <= 2*N);421dest.eval_start_index = (2*N-offset)>>1;422if (dest.eval_start_index >= dest.face_valence) dest.eval_start_index -= dest.face_valence;423424assert( dest.eval_start_index < dest.face_valence );425dest.eval_unique_identifier = 0;426}427428__noinline void subdivide(array_t<CatmullClarkPatch,SIZE>& patch, unsigned& N_o) const429{430N_o = N;431assert( N );432for (unsigned i=0; i<N; i++) {433unsigned ip1 = (i+1)%N; // FIXME: %434ring[i].subdivide(patch[i].ring[0]);435patch[i] .ring[0].edge_level = 0.5f*ring[i].edge_level;436patch[ip1].ring[3].edge_level = 0.5f*ring[i].edge_level;437438assert( patch[i].ring[0].hasValidPositions() );439440}441assert(N < 2*SIZE);442Vertex_t center = Vertex_t(0.0f);443array_t<Vertex_t,2*SIZE> center_ring;444float center_vertex_level = 2.0f; // guarantees that irregular vertices get always isolated also for non-quads445446for (unsigned i=0; i<N; i++)447{448unsigned ip1 = (i+1)%N; // FIXME: %449unsigned im1 = (i+N-1)%N; // FIXME: %450bool regular = ring[i].has_last_face() && ring[ip1].face_valence > 2;451if (likely(regular)) init_regular(patch[i].ring[0],patch[ip1].ring[0],patch[i].ring[1],patch[ip1].ring[3]);452else init_border (patch[i].ring[0],patch[ip1].ring[0],patch[i].ring[1],patch[ip1].ring[3]);453454assert( patch[i].ring[1].hasValidPositions() );455assert( patch[ip1].ring[3].hasValidPositions() );456457float level = 0.25f*(ring[im1].edge_level+ring[ip1].edge_level);458patch[i].ring[1].edge_level = patch[ip1].ring[2].edge_level = level;459center_vertex_level = max(center_vertex_level,level);460461center += ring[i].vtx;462center_ring[2*i+0] = (Vertex_t)patch[i].ring[0].vtx;463center_ring[2*i+1] = (Vertex_t)patch[i].ring[0].ring[0];464}465center /= float(N);466467for (unsigned int i=0; i<N; i++) {468init_regular(center,center_ring,center_vertex_level,N,2*i,patch[i].ring[2]);469470assert( patch[i].ring[2].hasValidPositions() );471}472}473474void init(CatmullClarkPatch& patch) const475{476assert(size() == 4);477ring[0].convert(patch.ring[0]);478ring[1].convert(patch.ring[1]);479ring[2].convert(patch.ring[2]);480ring[3].convert(patch.ring[3]);481}482483static void fix_quad_ring_order (array_t<CatmullClarkPatch,GeneralCatmullClarkPatchT::SIZE>& patches)484{485CatmullClark1Ring patches1ring1 = patches[1].ring[1];486patches[1].ring[1] = patches[1].ring[0]; // FIXME: optimize these assignments487patches[1].ring[0] = patches[1].ring[3];488patches[1].ring[3] = patches[1].ring[2];489patches[1].ring[2] = patches1ring1;490491CatmullClark1Ring patches2ring2 = patches[2].ring[2];492patches[2].ring[2] = patches[2].ring[0];493patches[2].ring[0] = patches2ring2;494CatmullClark1Ring patches2ring3 = patches[2].ring[3];495patches[2].ring[3] = patches[2].ring[1];496patches[2].ring[1] = patches2ring3;497498CatmullClark1Ring patches3ring3 = patches[3].ring[3];499patches[3].ring[3] = patches[3].ring[0];500patches[3].ring[0] = patches[3].ring[1];501patches[3].ring[1] = patches[3].ring[2];502patches[3].ring[2] = patches3ring3;503}504505__forceinline void getLimitBorder(BezierCurve curves[GeneralCatmullClarkPatchT::SIZE]) const506{507Vertex P0 = ring[0].getLimitVertex();508for (unsigned i=0; i<N; i++)509{510const unsigned i0 = i, i1 = i+1==N ? 0 : i+1;511const Vertex P1 = madd(1.0f/3.0f,ring[i0].getLimitTangent(),P0);512const Vertex P3 = ring[i1].getLimitVertex();513const Vertex P2 = madd(1.0f/3.0f,ring[i1].getSecondLimitTangent(),P3);514new (&curves[i]) BezierCurve(P0,P1,P2,P3);515P0 = P3;516}517}518519__forceinline void getLimitBorder(BezierCurve curves[2], const unsigned subPatch) const520{521const unsigned i0 = subPatch;522const Vertex t0_p = ring[i0].getLimitTangent();523const Vertex t0_m = ring[i0].getSecondLimitTangent();524525const unsigned i1 = subPatch+1 == N ? 0 : subPatch+1;526const Vertex t1_p = ring[i1].getLimitTangent();527const Vertex t1_m = ring[i1].getSecondLimitTangent();528529const unsigned i2 = subPatch == 0 ? N-1 : subPatch-1;530const Vertex t2_p = ring[i2].getLimitTangent();531const Vertex t2_m = ring[i2].getSecondLimitTangent();532533const Vertex b00 = ring[i0].getLimitVertex();534const Vertex b03 = ring[i1].getLimitVertex();535const Vertex b33 = ring[i2].getLimitVertex();536537const Vertex b01 = madd(1.0/3.0f,t0_p,b00);538const Vertex b11 = madd(1.0/3.0f,t0_m,b00);539540//const Vertex b13 = madd(1.0/3.0f,t1_p,b03);541const Vertex b02 = madd(1.0/3.0f,t1_m,b03);542543const Vertex b22 = madd(1.0/3.0f,t2_p,b33);544const Vertex b23 = madd(1.0/3.0f,t2_m,b33);545546new (&curves[0]) BezierCurve(b00,b01,b02,b03);547new (&curves[1]) BezierCurve(b33,b22,b11,b00);548}549550friend __forceinline embree_ostream operator<<(embree_ostream o, const GeneralCatmullClarkPatchT &p)551{552o << "GeneralCatmullClarkPatch { " << embree_endl;553for (unsigned i=0; i<p.N; i++)554o << "ring" << i << ": " << p.ring[i] << embree_endl;555o << "}" << embree_endl;556return o;557}558};559560typedef GeneralCatmullClarkPatchT<Vec3fa,Vec3fa_t> GeneralCatmullClarkPatch3fa;561}562563564