1 | // Copyright 2009-2021 Intel Corporation |
2 | // SPDX-License-Identifier: Apache-2.0 |
3 | |
4 | #pragma once |
5 | |
6 | #include "catmullclark_ring.h" |
7 | #include "bezier_curve.h" |
8 | |
9 | namespace embree |
10 | { |
11 | template<typename Vertex, typename Vertex_t = Vertex> |
12 | class __aligned(64) CatmullClarkPatchT |
13 | { |
14 | public: |
15 | typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring; |
16 | typedef typename CatmullClark1Ring::Type Type; |
17 | |
18 | array_t<CatmullClark1RingT<Vertex,Vertex_t>,4> ring; |
19 | |
20 | public: |
21 | __forceinline CatmullClarkPatchT () {} |
22 | |
23 | __forceinline CatmullClarkPatchT (const HalfEdge* first_half_edge, const char* vertices, size_t stride) { |
24 | init(first_half_edge,vertices,stride); |
25 | } |
26 | |
27 | __forceinline CatmullClarkPatchT (const HalfEdge* first_half_edge, const BufferView<Vec3fa>& vertices) { |
28 | init(first_half_edge,vertices.getPtr(),vertices.getStride()); |
29 | } |
30 | |
31 | __forceinline void init (const HalfEdge* first_half_edge, const char* vertices, size_t stride) |
32 | { |
33 | for (unsigned i=0; i<4; i++) |
34 | ring[i].init(first_half_edge+i,vertices,stride); |
35 | |
36 | assert(verify()); |
37 | } |
38 | |
39 | __forceinline size_t bytes() const { |
40 | return ring[0].bytes()+ring[1].bytes()+ring[2].bytes()+ring[3].bytes(); |
41 | } |
42 | |
43 | __forceinline void serialize(void* ptr, size_t& ofs) const |
44 | { |
45 | for (size_t i=0; i<4; i++) |
46 | ring[i].serialize((char*)ptr,ofs); |
47 | } |
48 | |
49 | __forceinline void deserialize(void* ptr) |
50 | { |
51 | size_t ofs = 0; |
52 | for (size_t i=0; i<4; i++) |
53 | ring[i].deserialize((char*)ptr,ofs); |
54 | } |
55 | |
56 | __forceinline BBox3fa bounds() const |
57 | { |
58 | BBox3fa bounds (ring[0].bounds()); |
59 | for (size_t i=1; i<4; i++) |
60 | bounds.extend(ring[i].bounds()); |
61 | return bounds; |
62 | } |
63 | |
64 | __forceinline Type type() const |
65 | { |
66 | const int ty0 = ring[0].type() ^ CatmullClark1Ring::TYPE_CREASES; |
67 | const int ty1 = ring[1].type() ^ CatmullClark1Ring::TYPE_CREASES; |
68 | const int ty2 = ring[2].type() ^ CatmullClark1Ring::TYPE_CREASES; |
69 | const int ty3 = ring[3].type() ^ CatmullClark1Ring::TYPE_CREASES; |
70 | return (Type) ((ty0 & ty1 & ty2 & ty3) ^ CatmullClark1Ring::TYPE_CREASES); |
71 | } |
72 | |
73 | __forceinline bool isFinalResolution(float res) const { |
74 | return ring[0].isFinalResolution(res) && ring[1].isFinalResolution(res) && ring[2].isFinalResolution(res) && ring[3].isFinalResolution(res); |
75 | } |
76 | |
77 | static __forceinline void init_regular(const CatmullClark1RingT<Vertex,Vertex_t>& p0, |
78 | const CatmullClark1RingT<Vertex,Vertex_t>& p1, |
79 | CatmullClark1RingT<Vertex,Vertex_t>& dest0, |
80 | CatmullClark1RingT<Vertex,Vertex_t>& dest1) |
81 | { |
82 | assert(p1.face_valence > 2); |
83 | dest1.vertex_level = dest0.vertex_level = p0.edge_level; |
84 | dest1.face_valence = dest0.face_valence = 4; |
85 | dest1.edge_valence = dest0.edge_valence = 8; |
86 | dest1.border_index = dest0.border_index = -1; |
87 | dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0]; |
88 | dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f; |
89 | |
90 | dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1]; |
91 | dest1.ring[1] = dest0.ring[7] = (Vertex_t)p1.ring[0]; |
92 | dest1.ring[0] = dest0.ring[6] = (Vertex_t)p1.vtx; |
93 | dest1.ring[7] = dest0.ring[5] = (Vertex_t)p1.ring[4]; |
94 | dest1.ring[6] = dest0.ring[4] = (Vertex_t)p0.ring[p0.edge_valence-1]; |
95 | dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.edge_valence-2]; |
96 | dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx; |
97 | dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2]; |
98 | |
99 | dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f; |
100 | dest1.crease_weight[0] = dest0.crease_weight[3] = p1.crease_weight[1]; |
101 | dest1.crease_weight[3] = dest0.crease_weight[2] = 0.0f; |
102 | dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0]; |
103 | |
104 | if (p0.eval_unique_identifier <= p1.eval_unique_identifier) |
105 | { |
106 | dest0.eval_start_index = 3; |
107 | dest1.eval_start_index = 0; |
108 | dest0.eval_unique_identifier = p0.eval_unique_identifier; |
109 | dest1.eval_unique_identifier = p0.eval_unique_identifier; |
110 | } |
111 | else |
112 | { |
113 | dest0.eval_start_index = 1; |
114 | dest1.eval_start_index = 2; |
115 | dest0.eval_unique_identifier = p1.eval_unique_identifier; |
116 | dest1.eval_unique_identifier = p1.eval_unique_identifier; |
117 | } |
118 | } |
119 | |
120 | static __forceinline void init_border(const CatmullClark1RingT<Vertex,Vertex_t> &p0, |
121 | const CatmullClark1RingT<Vertex,Vertex_t> &p1, |
122 | CatmullClark1RingT<Vertex,Vertex_t> &dest0, |
123 | CatmullClark1RingT<Vertex,Vertex_t> &dest1) |
124 | { |
125 | dest1.vertex_level = dest0.vertex_level = p0.edge_level; |
126 | dest1.face_valence = dest0.face_valence = 3; |
127 | dest1.edge_valence = dest0.edge_valence = 6; |
128 | dest0.border_index = 2; |
129 | dest1.border_index = 4; |
130 | dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0]; |
131 | dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f; |
132 | |
133 | dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1]; |
134 | dest1.ring[1] = dest0.ring[5] = (Vertex_t)p1.ring[0]; |
135 | dest1.ring[0] = dest0.ring[4] = (Vertex_t)p1.vtx; |
136 | dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.border_index+1]; // dummy |
137 | dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx; |
138 | dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2]; |
139 | |
140 | dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f; |
141 | dest1.crease_weight[0] = dest0.crease_weight[2] = p1.crease_weight[1]; |
142 | dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0]; |
143 | |
144 | if (p0.eval_unique_identifier <= p1.eval_unique_identifier) |
145 | { |
146 | dest0.eval_start_index = 1; |
147 | dest1.eval_start_index = 2; |
148 | dest0.eval_unique_identifier = p0.eval_unique_identifier; |
149 | dest1.eval_unique_identifier = p0.eval_unique_identifier; |
150 | } |
151 | else |
152 | { |
153 | dest0.eval_start_index = 2; |
154 | dest1.eval_start_index = 0; |
155 | dest0.eval_unique_identifier = p1.eval_unique_identifier; |
156 | dest1.eval_unique_identifier = p1.eval_unique_identifier; |
157 | } |
158 | } |
159 | |
160 | static __forceinline void init_regular(const Vertex_t ¢er, const Vertex_t center_ring[8], const unsigned int offset, CatmullClark1RingT<Vertex,Vertex_t> &dest) |
161 | { |
162 | dest.vertex_level = 0.0f; |
163 | dest.face_valence = 4; |
164 | dest.edge_valence = 8; |
165 | dest.border_index = -1; |
166 | dest.vtx = (Vertex_t)center; |
167 | dest.vertex_crease_weight = 0.0f; |
168 | for (size_t i=0; i<8; i++) |
169 | dest.ring[i] = (Vertex_t)center_ring[(offset+i)%8]; |
170 | for (size_t i=0; i<4; i++) |
171 | dest.crease_weight[i] = 0.0f; |
172 | |
173 | dest.eval_start_index = (8-offset)>>1; |
174 | if (dest.eval_start_index >= dest.face_valence) dest.eval_start_index -= dest.face_valence; |
175 | assert( dest.eval_start_index < dest.face_valence ); |
176 | dest.eval_unique_identifier = 0; |
177 | } |
178 | |
179 | __noinline void subdivide(array_t<CatmullClarkPatchT,4>& patch) const |
180 | { |
181 | ring[0].subdivide(patch[0].ring[0]); |
182 | ring[1].subdivide(patch[1].ring[1]); |
183 | ring[2].subdivide(patch[2].ring[2]); |
184 | ring[3].subdivide(patch[3].ring[3]); |
185 | |
186 | patch[0].ring[0].edge_level = 0.5f*ring[0].edge_level; |
187 | patch[0].ring[1].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level); |
188 | patch[0].ring[2].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level); |
189 | patch[0].ring[3].edge_level = 0.5f*ring[3].edge_level; |
190 | |
191 | patch[1].ring[0].edge_level = 0.5f*ring[0].edge_level; |
192 | patch[1].ring[1].edge_level = 0.5f*ring[1].edge_level; |
193 | patch[1].ring[2].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level); |
194 | patch[1].ring[3].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level); |
195 | |
196 | patch[2].ring[0].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level); |
197 | patch[2].ring[1].edge_level = 0.5f*ring[1].edge_level; |
198 | patch[2].ring[2].edge_level = 0.5f*ring[2].edge_level; |
199 | patch[2].ring[3].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level); |
200 | |
201 | patch[3].ring[0].edge_level = 0.25f*(ring[0].edge_level+ring[2].edge_level); |
202 | patch[3].ring[1].edge_level = 0.25f*(ring[1].edge_level+ring[3].edge_level); |
203 | patch[3].ring[2].edge_level = 0.5f*ring[2].edge_level; |
204 | patch[3].ring[3].edge_level = 0.5f*ring[3].edge_level; |
205 | |
206 | const bool regular0 = ring[0].has_last_face() && ring[1].face_valence > 2; |
207 | if (likely(regular0)) |
208 | init_regular(patch[0].ring[0],patch[1].ring[1],patch[0].ring[1],patch[1].ring[0]); |
209 | else |
210 | init_border(p0: patch[0].ring[0],p1: patch[1].ring[1],dest0&: patch[0].ring[1],dest1&: patch[1].ring[0]); |
211 | |
212 | const bool regular1 = ring[1].has_last_face() && ring[2].face_valence > 2; |
213 | if (likely(regular1)) |
214 | init_regular(patch[1].ring[1],patch[2].ring[2],patch[1].ring[2],patch[2].ring[1]); |
215 | else |
216 | init_border(p0: patch[1].ring[1],p1: patch[2].ring[2],dest0&: patch[1].ring[2],dest1&: patch[2].ring[1]); |
217 | |
218 | const bool regular2 = ring[2].has_last_face() && ring[3].face_valence > 2; |
219 | if (likely(regular2)) |
220 | init_regular(patch[2].ring[2],patch[3].ring[3],patch[2].ring[3],patch[3].ring[2]); |
221 | else |
222 | init_border(p0: patch[2].ring[2],p1: patch[3].ring[3],dest0&: patch[2].ring[3],dest1&: patch[3].ring[2]); |
223 | |
224 | const bool regular3 = ring[3].has_last_face() && ring[0].face_valence > 2; |
225 | if (likely(regular3)) |
226 | init_regular(patch[3].ring[3],patch[0].ring[0],patch[3].ring[0],patch[0].ring[3]); |
227 | else |
228 | init_border(p0: patch[3].ring[3],p1: patch[0].ring[0],dest0&: patch[3].ring[0],dest1&: patch[0].ring[3]); |
229 | |
230 | Vertex_t center = (ring[0].vtx + ring[1].vtx + ring[2].vtx + ring[3].vtx) * 0.25f; |
231 | |
232 | Vertex_t center_ring[8]; |
233 | center_ring[0] = (Vertex_t)patch[3].ring[3].ring[0]; |
234 | center_ring[7] = (Vertex_t)patch[3].ring[3].vtx; |
235 | center_ring[6] = (Vertex_t)patch[2].ring[2].ring[0]; |
236 | center_ring[5] = (Vertex_t)patch[2].ring[2].vtx; |
237 | center_ring[4] = (Vertex_t)patch[1].ring[1].ring[0]; |
238 | center_ring[3] = (Vertex_t)patch[1].ring[1].vtx; |
239 | center_ring[2] = (Vertex_t)patch[0].ring[0].ring[0]; |
240 | center_ring[1] = (Vertex_t)patch[0].ring[0].vtx; |
241 | |
242 | init_regular(center,center_ring,0,patch[0].ring[2]); |
243 | init_regular(center,center_ring,2,patch[1].ring[3]); |
244 | init_regular(center,center_ring,4,patch[2].ring[0]); |
245 | init_regular(center,center_ring,6,patch[3].ring[1]); |
246 | |
247 | assert(patch[0].verify()); |
248 | assert(patch[1].verify()); |
249 | assert(patch[2].verify()); |
250 | assert(patch[3].verify()); |
251 | } |
252 | |
253 | bool verify() const { |
254 | return ring[0].hasValidPositions() && ring[1].hasValidPositions() && ring[2].hasValidPositions() && ring[3].hasValidPositions(); |
255 | } |
256 | |
257 | __forceinline void init( FinalQuad& quad ) const |
258 | { |
259 | quad.vtx[0] = (Vertex_t)ring[0].vtx; |
260 | quad.vtx[1] = (Vertex_t)ring[1].vtx; |
261 | quad.vtx[2] = (Vertex_t)ring[2].vtx; |
262 | quad.vtx[3] = (Vertex_t)ring[3].vtx; |
263 | }; |
264 | |
265 | friend __forceinline embree_ostream operator<<(embree_ostream o, const CatmullClarkPatchT &p) |
266 | { |
267 | o << "CatmullClarkPatch { " << embree_endl; |
268 | for (size_t i=0; i<4; i++) |
269 | o << "ring" << i << ": " << p.ring[i] << embree_endl; |
270 | o << "}" << embree_endl; |
271 | return o; |
272 | } |
273 | }; |
274 | |
275 | typedef CatmullClarkPatchT<Vec3fa,Vec3fa_t> CatmullClarkPatch3fa; |
276 | |
277 | template<typename Vertex, typename Vertex_t = Vertex> |
278 | class __aligned(64) GeneralCatmullClarkPatchT |
279 | { |
280 | public: |
281 | typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch; |
282 | typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClark1Ring; |
283 | typedef BezierCurveT<Vertex> BezierCurve; |
284 | |
285 | static const unsigned SIZE = MAX_PATCH_VALENCE; |
286 | DynamicStackArray<GeneralCatmullClark1RingT<Vertex,Vertex_t>,8,SIZE> ring; |
287 | unsigned N; |
288 | |
289 | __forceinline GeneralCatmullClarkPatchT () |
290 | : N(0) {} |
291 | |
292 | GeneralCatmullClarkPatchT (const HalfEdge* h, const char* vertices, size_t stride) { |
293 | init(h,vertices,stride); |
294 | } |
295 | |
296 | __forceinline GeneralCatmullClarkPatchT (const HalfEdge* first_half_edge, const BufferView<Vec3fa>& vertices) { |
297 | init(first_half_edge,vertices.getPtr(),vertices.getStride()); |
298 | } |
299 | |
300 | __forceinline void init (const HalfEdge* h, const char* vertices, size_t stride) |
301 | { |
302 | unsigned int i = 0; |
303 | const HalfEdge* edge = h; |
304 | do { |
305 | ring[i].init(edge,vertices,stride); |
306 | edge = edge->next(); |
307 | i++; |
308 | } while ((edge != h) && (i < SIZE)); |
309 | N = i; |
310 | } |
311 | |
312 | __forceinline unsigned size() const { |
313 | return N; |
314 | } |
315 | |
316 | __forceinline bool isQuadPatch() const { |
317 | return (N == 4) && ring[0].only_quads && ring[1].only_quads && ring[2].only_quads && ring[3].only_quads; |
318 | } |
319 | |
320 | static __forceinline void init_regular(const CatmullClark1RingT<Vertex,Vertex_t>& p0, |
321 | const CatmullClark1RingT<Vertex,Vertex_t>& p1, |
322 | CatmullClark1RingT<Vertex,Vertex_t>& dest0, |
323 | CatmullClark1RingT<Vertex,Vertex_t>& dest1) |
324 | { |
325 | assert(p1.face_valence > 2); |
326 | dest1.vertex_level = dest0.vertex_level = p0.edge_level; |
327 | dest1.face_valence = dest0.face_valence = 4; |
328 | dest1.edge_valence = dest0.edge_valence = 8; |
329 | dest1.border_index = dest0.border_index = -1; |
330 | dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0]; |
331 | dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f; |
332 | |
333 | dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1]; |
334 | dest1.ring[1] = dest0.ring[7] = (Vertex_t)p1.ring[0]; |
335 | dest1.ring[0] = dest0.ring[6] = (Vertex_t)p1.vtx; |
336 | dest1.ring[7] = dest0.ring[5] = (Vertex_t)p1.ring[4]; |
337 | dest1.ring[6] = dest0.ring[4] = (Vertex_t)p0.ring[p0.edge_valence-1]; |
338 | dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.edge_valence-2]; |
339 | dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx; |
340 | dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2]; |
341 | |
342 | dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f; |
343 | dest1.crease_weight[0] = dest0.crease_weight[3] = p1.crease_weight[1]; |
344 | dest1.crease_weight[3] = dest0.crease_weight[2] = 0.0f; |
345 | dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0]; |
346 | |
347 | if (p0.eval_unique_identifier <= p1.eval_unique_identifier) |
348 | { |
349 | dest0.eval_start_index = 3; |
350 | dest1.eval_start_index = 0; |
351 | dest0.eval_unique_identifier = p0.eval_unique_identifier; |
352 | dest1.eval_unique_identifier = p0.eval_unique_identifier; |
353 | } |
354 | else |
355 | { |
356 | dest0.eval_start_index = 1; |
357 | dest1.eval_start_index = 2; |
358 | dest0.eval_unique_identifier = p1.eval_unique_identifier; |
359 | dest1.eval_unique_identifier = p1.eval_unique_identifier; |
360 | } |
361 | } |
362 | |
363 | |
364 | static __forceinline void init_border(const CatmullClark1RingT<Vertex,Vertex_t> &p0, |
365 | const CatmullClark1RingT<Vertex,Vertex_t> &p1, |
366 | CatmullClark1RingT<Vertex,Vertex_t> &dest0, |
367 | CatmullClark1RingT<Vertex,Vertex_t> &dest1) |
368 | { |
369 | dest1.vertex_level = dest0.vertex_level = p0.edge_level; |
370 | dest1.face_valence = dest0.face_valence = 3; |
371 | dest1.edge_valence = dest0.edge_valence = 6; |
372 | dest0.border_index = 2; |
373 | dest1.border_index = 4; |
374 | dest1.vtx = dest0.vtx = (Vertex_t)p0.ring[0]; |
375 | dest1.vertex_crease_weight = dest0.vertex_crease_weight = 0.0f; |
376 | |
377 | dest1.ring[2] = dest0.ring[0] = (Vertex_t)p0.ring[1]; |
378 | dest1.ring[1] = dest0.ring[5] = (Vertex_t)p1.ring[0]; |
379 | dest1.ring[0] = dest0.ring[4] = (Vertex_t)p1.vtx; |
380 | dest1.ring[5] = dest0.ring[3] = (Vertex_t)p0.ring[p0.border_index+1]; // dummy |
381 | dest1.ring[4] = dest0.ring[2] = (Vertex_t)p0.vtx; |
382 | dest1.ring[3] = dest0.ring[1] = (Vertex_t)p0.ring[2]; |
383 | |
384 | dest1.crease_weight[1] = dest0.crease_weight[0] = 0.0f; |
385 | dest1.crease_weight[0] = dest0.crease_weight[2] = p1.crease_weight[1]; |
386 | dest1.crease_weight[2] = dest0.crease_weight[1] = p0.crease_weight[0]; |
387 | |
388 | if (p0.eval_unique_identifier <= p1.eval_unique_identifier) |
389 | { |
390 | dest0.eval_start_index = 1; |
391 | dest1.eval_start_index = 2; |
392 | dest0.eval_unique_identifier = p0.eval_unique_identifier; |
393 | dest1.eval_unique_identifier = p0.eval_unique_identifier; |
394 | } |
395 | else |
396 | { |
397 | dest0.eval_start_index = 2; |
398 | dest1.eval_start_index = 0; |
399 | dest0.eval_unique_identifier = p1.eval_unique_identifier; |
400 | dest1.eval_unique_identifier = p1.eval_unique_identifier; |
401 | } |
402 | } |
403 | |
404 | static __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) |
405 | { |
406 | assert(N<(MAX_RING_FACE_VALENCE)); |
407 | assert(2*N<(MAX_RING_EDGE_VALENCE)); |
408 | dest.vertex_level = vertex_level; |
409 | dest.face_valence = N; |
410 | dest.edge_valence = 2*N; |
411 | dest.border_index = -1; |
412 | dest.vtx = (Vertex_t)center; |
413 | dest.vertex_crease_weight = 0.0f; |
414 | for (unsigned i=0; i<2*N; i++) { |
415 | dest.ring[i] = (Vertex_t)center_ring[(2*N+offset+i-1)%(2*N)]; |
416 | assert(isvalid(dest.ring[i])); |
417 | } |
418 | for (unsigned i=0; i<N; i++) |
419 | dest.crease_weight[i] = 0.0f; |
420 | |
421 | assert(offset <= 2*N); |
422 | dest.eval_start_index = (2*N-offset)>>1; |
423 | if (dest.eval_start_index >= dest.face_valence) dest.eval_start_index -= dest.face_valence; |
424 | |
425 | assert( dest.eval_start_index < dest.face_valence ); |
426 | dest.eval_unique_identifier = 0; |
427 | } |
428 | |
429 | __noinline void subdivide(array_t<CatmullClarkPatch,SIZE>& patch, unsigned& N_o) const |
430 | { |
431 | N_o = N; |
432 | assert( N ); |
433 | for (unsigned i=0; i<N; i++) { |
434 | unsigned ip1 = (i+1)%N; // FIXME: % |
435 | ring[i].subdivide(patch[i].ring[0]); |
436 | patch[i] .ring[0].edge_level = 0.5f*ring[i].edge_level; |
437 | patch[ip1].ring[3].edge_level = 0.5f*ring[i].edge_level; |
438 | |
439 | assert( patch[i].ring[0].hasValidPositions() ); |
440 | |
441 | } |
442 | assert(N < 2*SIZE); |
443 | Vertex_t center = Vertex_t(0.0f); |
444 | array_t<Vertex_t,2*SIZE> center_ring; |
445 | float center_vertex_level = 2.0f; // guarantees that irregular vertices get always isolated also for non-quads |
446 | |
447 | for (unsigned i=0; i<N; i++) |
448 | { |
449 | unsigned ip1 = (i+1)%N; // FIXME: % |
450 | unsigned im1 = (i+N-1)%N; // FIXME: % |
451 | bool regular = ring[i].has_last_face() && ring[ip1].face_valence > 2; |
452 | if (likely(regular)) init_regular(patch[i].ring[0],patch[ip1].ring[0],patch[i].ring[1],patch[ip1].ring[3]); |
453 | else init_border (p0: patch[i].ring[0],p1: patch[ip1].ring[0],dest0&: patch[i].ring[1],dest1&: patch[ip1].ring[3]); |
454 | |
455 | assert( patch[i].ring[1].hasValidPositions() ); |
456 | assert( patch[ip1].ring[3].hasValidPositions() ); |
457 | |
458 | float level = 0.25f*(ring[im1].edge_level+ring[ip1].edge_level); |
459 | patch[i].ring[1].edge_level = patch[ip1].ring[2].edge_level = level; |
460 | center_vertex_level = max(a: center_vertex_level,b: level); |
461 | |
462 | center += ring[i].vtx; |
463 | center_ring[2*i+0] = (Vertex_t)patch[i].ring[0].vtx; |
464 | center_ring[2*i+1] = (Vertex_t)patch[i].ring[0].ring[0]; |
465 | } |
466 | center /= float(N); |
467 | |
468 | for (unsigned int i=0; i<N; i++) { |
469 | init_regular(center,center_ring,center_vertex_level,N,2*i,patch[i].ring[2]); |
470 | |
471 | assert( patch[i].ring[2].hasValidPositions() ); |
472 | } |
473 | } |
474 | |
475 | void init(CatmullClarkPatch& patch) const |
476 | { |
477 | assert(size() == 4); |
478 | ring[0].convert(patch.ring[0]); |
479 | ring[1].convert(patch.ring[1]); |
480 | ring[2].convert(patch.ring[2]); |
481 | ring[3].convert(patch.ring[3]); |
482 | } |
483 | |
484 | static void fix_quad_ring_order (array_t<CatmullClarkPatch,GeneralCatmullClarkPatchT::SIZE>& patches) |
485 | { |
486 | CatmullClark1Ring patches1ring1 = patches[1].ring[1]; |
487 | patches[1].ring[1] = patches[1].ring[0]; // FIXME: optimize these assignments |
488 | patches[1].ring[0] = patches[1].ring[3]; |
489 | patches[1].ring[3] = patches[1].ring[2]; |
490 | patches[1].ring[2] = patches1ring1; |
491 | |
492 | CatmullClark1Ring patches2ring2 = patches[2].ring[2]; |
493 | patches[2].ring[2] = patches[2].ring[0]; |
494 | patches[2].ring[0] = patches2ring2; |
495 | CatmullClark1Ring patches2ring3 = patches[2].ring[3]; |
496 | patches[2].ring[3] = patches[2].ring[1]; |
497 | patches[2].ring[1] = patches2ring3; |
498 | |
499 | CatmullClark1Ring patches3ring3 = patches[3].ring[3]; |
500 | patches[3].ring[3] = patches[3].ring[0]; |
501 | patches[3].ring[0] = patches[3].ring[1]; |
502 | patches[3].ring[1] = patches[3].ring[2]; |
503 | patches[3].ring[2] = patches3ring3; |
504 | } |
505 | |
506 | __forceinline void getLimitBorder(BezierCurve curves[GeneralCatmullClarkPatchT::SIZE]) const |
507 | { |
508 | Vertex P0 = ring[0].getLimitVertex(); |
509 | for (unsigned i=0; i<N; i++) |
510 | { |
511 | const unsigned i0 = i, i1 = i+1==N ? 0 : i+1; |
512 | const Vertex P1 = madd(1.0f/3.0f,ring[i0].getLimitTangent(),P0); |
513 | const Vertex P3 = ring[i1].getLimitVertex(); |
514 | const Vertex P2 = madd(1.0f/3.0f,ring[i1].getSecondLimitTangent(),P3); |
515 | new (&curves[i]) BezierCurve(P0,P1,P2,P3); |
516 | P0 = P3; |
517 | } |
518 | } |
519 | |
520 | __forceinline void getLimitBorder(BezierCurve curves[2], const unsigned subPatch) const |
521 | { |
522 | const unsigned i0 = subPatch; |
523 | const Vertex t0_p = ring[i0].getLimitTangent(); |
524 | const Vertex t0_m = ring[i0].getSecondLimitTangent(); |
525 | |
526 | const unsigned i1 = subPatch+1 == N ? 0 : subPatch+1; |
527 | const Vertex t1_p = ring[i1].getLimitTangent(); |
528 | const Vertex t1_m = ring[i1].getSecondLimitTangent(); |
529 | |
530 | const unsigned i2 = subPatch == 0 ? N-1 : subPatch-1; |
531 | const Vertex t2_p = ring[i2].getLimitTangent(); |
532 | const Vertex t2_m = ring[i2].getSecondLimitTangent(); |
533 | |
534 | const Vertex b00 = ring[i0].getLimitVertex(); |
535 | const Vertex b03 = ring[i1].getLimitVertex(); |
536 | const Vertex b33 = ring[i2].getLimitVertex(); |
537 | |
538 | const Vertex b01 = madd(1.0/3.0f,t0_p,b00); |
539 | const Vertex b11 = madd(1.0/3.0f,t0_m,b00); |
540 | |
541 | //const Vertex b13 = madd(1.0/3.0f,t1_p,b03); |
542 | const Vertex b02 = madd(1.0/3.0f,t1_m,b03); |
543 | |
544 | const Vertex b22 = madd(1.0/3.0f,t2_p,b33); |
545 | const Vertex b23 = madd(1.0/3.0f,t2_m,b33); |
546 | |
547 | new (&curves[0]) BezierCurve(b00,b01,b02,b03); |
548 | new (&curves[1]) BezierCurve(b33,b22,b11,b00); |
549 | } |
550 | |
551 | friend __forceinline embree_ostream operator<<(embree_ostream o, const GeneralCatmullClarkPatchT &p) |
552 | { |
553 | o << "GeneralCatmullClarkPatch { " << embree_endl; |
554 | for (unsigned i=0; i<p.N; i++) |
555 | o << "ring" << i << ": " << p.ring[i] << embree_endl; |
556 | o << "}" << embree_endl; |
557 | return o; |
558 | } |
559 | }; |
560 | |
561 | typedef GeneralCatmullClarkPatchT<Vec3fa,Vec3fa_t> GeneralCatmullClarkPatch3fa; |
562 | } |
563 | |