Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/embree/kernels/subdiv/patch.h
9913 views
1
// Copyright 2009-2021 Intel Corporation
2
// SPDX-License-Identifier: Apache-2.0
3
4
#pragma once
5
6
#include "catmullclark_patch.h"
7
#include "bilinear_patch.h"
8
#include "bspline_patch.h"
9
#include "bezier_patch.h"
10
#include "gregory_patch.h"
11
#include "tessellation_cache.h"
12
13
#if 1
14
#define PATCH_DEBUG_SUBDIVISION(ptr,x,y,z)
15
#else
16
#define PATCH_DEBUG_SUBDIVISION(ptr,x,y,z) \
17
{ \
18
size_t hex = (size_t)ptr; \
19
for (size_t i=0; i<4; i++) hex = hex ^ (hex >> 8); \
20
const float c = (float)(((hex >> 0) ^ (hex >> 4) ^ (hex >> 8) ^ (hex >> 12) ^ (hex >> 16))&0xf)/15.0f; \
21
if (P) *P = Vertex(0.5f+0.5f*x,0.5f+0.5f*y,0.5f+0.5f*z,0.0f); \
22
}
23
#endif
24
25
#define PATCH_MAX_CACHE_DEPTH 2
26
//#define PATCH_MIN_RESOLUTION 1 // FIXME: not yet completely implemented
27
#define PATCH_MAX_EVAL_DEPTH_IRREGULAR 10 // maximum evaluation depth at irregular vertices (has to be larger or equal than PATCH_MAX_CACHE_DEPTH)
28
#define PATCH_MAX_EVAL_DEPTH_CREASE 10 // maximum evaluation depth at crease features (has to be larger or equal than PATCH_MAX_CACHE_DEPTH)
29
#define PATCH_USE_GREGORY 1 // 0 = no gregory, 1 = fill, 2 = as early as possible
30
31
#if PATCH_USE_GREGORY==2
32
#define PATCH_USE_BEZIER_PATCH 1 // enable use of bezier instead of b-spline patches
33
#else
34
#define PATCH_USE_BEZIER_PATCH 0 // enable use of bezier instead of b-spline patches
35
#endif
36
37
#if PATCH_USE_BEZIER_PATCH
38
# define RegularPatch BezierPatch
39
# define RegularPatchT BezierPatchT<Vertex,Vertex_t>
40
#else
41
# define RegularPatch BSplinePatch
42
# define RegularPatchT BSplinePatchT<Vertex,Vertex_t>
43
#endif
44
45
#if PATCH_USE_GREGORY
46
#define IrregularFillPatch GregoryPatch
47
#define IrregularFillPatchT GregoryPatchT<Vertex,Vertex_t>
48
#else
49
#define IrregularFillPatch BilinearPatch
50
#define IrregularFillPatchT BilinearPatchT<Vertex,Vertex_t>
51
#endif
52
53
namespace embree
54
{
55
template<typename Vertex, typename Vertex_t = Vertex>
56
struct __aligned(64) PatchT
57
{
58
public:
59
60
typedef GeneralCatmullClarkPatchT<Vertex,Vertex_t> GeneralCatmullClarkPatch;
61
typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
62
typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
63
typedef BezierCurveT<Vertex> BezierCurve;
64
65
enum Type {
66
INVALID_PATCH = 0,
67
BILINEAR_PATCH = 1,
68
BSPLINE_PATCH = 2,
69
BEZIER_PATCH = 3,
70
GREGORY_PATCH = 4,
71
SUBDIVIDED_GENERAL_PATCH = 7,
72
SUBDIVIDED_QUAD_PATCH = 8,
73
EVAL_PATCH = 9,
74
};
75
76
struct Ref
77
{
78
__forceinline Ref(void* p = nullptr)
79
: ptr((size_t)p) {}
80
81
__forceinline operator bool() const { return ptr != 0; }
82
__forceinline operator size_t() const { return ptr; }
83
84
__forceinline Ref (Type ty, void* in)
85
: ptr(((size_t)in)+ty) { assert((((size_t)in) & 0xF) == 0); }
86
87
__forceinline Type type () const { return (Type)(ptr & 0xF); }
88
__forceinline void* object() const { return (void*) (ptr & ~0xF); }
89
90
size_t ptr;
91
};
92
93
struct EvalPatch
94
{
95
/* creates EvalPatch from a CatmullClarkPatch */
96
template<typename Allocator>
97
__noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch)
98
{
99
size_t ofs = 0, bytes = patch.bytes();
100
void* ptr = alloc(bytes);
101
patch.serialize(ptr,ofs);
102
assert(ofs == bytes);
103
return Ref(EVAL_PATCH, ptr);
104
}
105
};
106
107
struct BilinearPatch
108
{
109
/* creates BilinearPatch from a CatmullClarkPatch */
110
template<typename Allocator>
111
__noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
112
const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
113
return Ref(BILINEAR_PATCH, new (alloc(sizeof(BilinearPatch))) BilinearPatch(patch));
114
}
115
116
__forceinline BilinearPatch (const CatmullClarkPatch& patch)
117
: patch(patch) {}
118
119
/* creates BilinearPatch from 4 vertices */
120
template<typename Allocator>
121
__noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
122
return Ref(BILINEAR_PATCH, new (alloc(sizeof(BilinearPatch))) BilinearPatch(edge,vertices,stride));
123
}
124
125
__forceinline BilinearPatch (const HalfEdge* edge, const char* vertices, size_t stride)
126
: patch(edge,vertices,stride) {}
127
128
public:
129
BilinearPatchT<Vertex,Vertex_t> patch;
130
};
131
132
struct BSplinePatch
133
{
134
/* creates BSplinePatch from a half edge */
135
template<typename Allocator>
136
__noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
137
return Ref(BSPLINE_PATCH, new (alloc(sizeof(BSplinePatch))) BSplinePatch(edge,vertices,stride));
138
}
139
140
__forceinline BSplinePatch (const HalfEdge* edge, const char* vertices, size_t stride)
141
: patch(edge,vertices,stride) {}
142
143
/* creates BSplinePatch from a CatmullClarkPatch */
144
template<typename Allocator>
145
__noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
146
const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
147
return Ref(BSPLINE_PATCH, new (alloc(sizeof(BSplinePatch))) BSplinePatch(patch,border0,border1,border2,border3));
148
}
149
150
__forceinline BSplinePatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
151
: patch(patch,border0,border1,border2,border3) {}
152
153
public:
154
BSplinePatchT<Vertex,Vertex_t> patch;
155
};
156
157
struct BezierPatch
158
{
159
/* creates BezierPatch from a half edge */
160
template<typename Allocator>
161
__noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
162
return Ref(BEZIER_PATCH, new (alloc(sizeof(BezierPatch))) BezierPatch(edge,vertices,stride));
163
}
164
165
__forceinline BezierPatch (const HalfEdge* edge, const char* vertices, size_t stride)
166
: patch(edge,vertices,stride) {}
167
168
/* creates Bezier from a CatmullClarkPatch */
169
template<typename Allocator>
170
__noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
171
const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
172
return Ref(BEZIER_PATCH, new (alloc(sizeof(BezierPatch))) BezierPatch(patch,border0,border1,border2,border3));
173
}
174
175
__forceinline BezierPatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
176
: patch(patch,border0,border1,border2,border3) {}
177
178
public:
179
BezierPatchT<Vertex,Vertex_t> patch;
180
};
181
182
struct GregoryPatch
183
{
184
/* creates GregoryPatch from half edge */
185
template<typename Allocator>
186
__noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride) {
187
return Ref(GREGORY_PATCH, new (alloc(sizeof(GregoryPatch))) GregoryPatch(edge,vertices,stride));
188
}
189
190
__forceinline GregoryPatch (const HalfEdge* edge, const char* vertices, size_t stride)
191
: patch(CatmullClarkPatch(edge,vertices,stride)) {}
192
193
/* creates GregoryPatch from CatmullClarkPatch */
194
template<typename Allocator>
195
__noinline static Ref create(const Allocator& alloc, const CatmullClarkPatch& patch,
196
const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3) {
197
return Ref(GREGORY_PATCH, new (alloc(sizeof(GregoryPatch))) GregoryPatch(patch,border0,border1,border2,border3));
198
}
199
200
__forceinline GregoryPatch (const CatmullClarkPatch& patch, const BezierCurve* border0, const BezierCurve* border1, const BezierCurve* border2, const BezierCurve* border3)
201
: patch(patch,border0,border1,border2,border3) {}
202
203
public:
204
GregoryPatchT<Vertex,Vertex_t> patch;
205
};
206
207
struct SubdividedQuadPatch
208
{
209
template<typename Allocator>
210
__noinline static Ref create(const Allocator& alloc, Ref children[4]) {
211
return Ref(SUBDIVIDED_QUAD_PATCH, new (alloc(sizeof(SubdividedQuadPatch))) SubdividedQuadPatch(children));
212
}
213
214
__forceinline SubdividedQuadPatch(Ref children[4]) {
215
for (size_t i=0; i<4; i++) child[i] = children[i];
216
}
217
218
public:
219
Ref child[4];
220
};
221
222
struct SubdividedGeneralPatch
223
{
224
template<typename Allocator>
225
__noinline static Ref create(const Allocator& alloc, Ref* children, const unsigned N) {
226
return Ref(SUBDIVIDED_GENERAL_PATCH, new (alloc(sizeof(SubdividedGeneralPatch))) SubdividedGeneralPatch(children,N));
227
}
228
229
__forceinline SubdividedGeneralPatch(Ref* children, const unsigned N) : N(N) {
230
for (unsigned i=0; i<N; i++) child[i] = children[i];
231
}
232
233
unsigned N;
234
Ref child[MAX_PATCH_VALENCE];
235
};
236
237
/*! Default constructor. */
238
__forceinline PatchT () {}
239
240
template<typename Allocator>
241
__noinline static Ref create(const Allocator& alloc, const HalfEdge* edge, const char* vertices, size_t stride)
242
{
243
if (PATCH_MAX_CACHE_DEPTH == 0)
244
return nullptr;
245
246
Ref child(0);
247
switch (edge->patch_type) {
248
case HalfEdge::BILINEAR_PATCH: child = BilinearPatch::create(alloc,edge,vertices,stride); break;
249
case HalfEdge::REGULAR_QUAD_PATCH: child = RegularPatch::create(alloc,edge,vertices,stride); break;
250
#if PATCH_USE_GREGORY == 2
251
case HalfEdge::IRREGULAR_QUAD_PATCH: child = GregoryPatch::create(alloc,edge,vertices,stride); break;
252
#endif
253
default: {
254
GeneralCatmullClarkPatch patch(edge,vertices,stride);
255
child = PatchT::create(alloc,patch,edge,vertices,stride,0);
256
}
257
}
258
return child;
259
}
260
261
template<typename Allocator>
262
__noinline static Ref create(const Allocator& alloc, GeneralCatmullClarkPatch& patch, const HalfEdge* edge, const char* vertices, size_t stride, size_t depth)
263
{
264
/* convert into standard quad patch if possible */
265
if (likely(patch.isQuadPatch()))
266
{
267
CatmullClarkPatch qpatch; patch.init(qpatch);
268
return PatchT::create(alloc,qpatch,edge,vertices,stride,depth);
269
}
270
271
/* do only cache up to some depth */
272
if (depth >= PATCH_MAX_CACHE_DEPTH)
273
return nullptr;
274
275
/* subdivide patch */
276
unsigned N;
277
array_t<CatmullClarkPatch,GeneralCatmullClarkPatch::SIZE> patches;
278
patch.subdivide(patches,N);
279
280
if (N == 4)
281
{
282
Ref child[4];
283
#if PATCH_USE_GREGORY == 2
284
BezierCurve borders[GeneralCatmullClarkPatch::SIZE]; patch.getLimitBorder(borders);
285
BezierCurve border0l,border0r; borders[0].subdivide(border0l,border0r);
286
BezierCurve border1l,border1r; borders[1].subdivide(border1l,border1r);
287
BezierCurve border2l,border2r; borders[2].subdivide(border2l,border2r);
288
BezierCurve border3l,border3r; borders[3].subdivide(border3l,border3r);
289
GeneralCatmullClarkPatch::fix_quad_ring_order(patches);
290
child[0] = PatchT::create(alloc,patches[0],edge,vertices,stride,depth+1,&border0l,nullptr,nullptr,&border3r);
291
child[1] = PatchT::create(alloc,patches[1],edge,vertices,stride,depth+1,&border0r,&border1l,nullptr,nullptr);
292
child[2] = PatchT::create(alloc,patches[2],edge,vertices,stride,depth+1,nullptr,&border1r,&border2l,nullptr);
293
child[3] = PatchT::create(alloc,patches[3],edge,vertices,stride,depth+1,nullptr,nullptr,&border2r,&border3l);
294
#else
295
GeneralCatmullClarkPatch::fix_quad_ring_order(patches);
296
for (size_t i=0; i<4; i++)
297
child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
298
#endif
299
return SubdividedQuadPatch::create(alloc,child);
300
}
301
else
302
{
303
assert(N<MAX_PATCH_VALENCE);
304
Ref child[MAX_PATCH_VALENCE];
305
306
#if PATCH_USE_GREGORY == 2
307
BezierCurve borders[GeneralCatmullClarkPatch::SIZE];
308
patch.getLimitBorder(borders);
309
310
for (size_t i0=0; i0<N; i0++) {
311
const size_t i2 = i0==0 ? N-1 : i0-1;
312
BezierCurve border0l,border0r; borders[i0].subdivide(border0l,border0r);
313
BezierCurve border2l,border2r; borders[i2].subdivide(border2l,border2r);
314
child[i0] = PatchT::create(alloc,patches[i0],edge,vertices,stride,depth+1, &border0l, nullptr, nullptr, &border2r);
315
}
316
#else
317
for (size_t i=0; i<N; i++)
318
child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
319
#endif
320
return SubdividedGeneralPatch::create(alloc,child,N);
321
}
322
323
return nullptr;
324
}
325
326
static __forceinline bool final(const CatmullClarkPatch& patch, const typename CatmullClarkRing::Type type, size_t depth)
327
{
328
const size_t max_eval_depth = (type & CatmullClarkRing::TYPE_CREASES) ? PATCH_MAX_EVAL_DEPTH_CREASE : PATCH_MAX_EVAL_DEPTH_IRREGULAR;
329
//#if PATCH_MIN_RESOLUTION
330
// return patch.isFinalResolution(PATCH_MIN_RESOLUTION) || depth>=max_eval_depth;
331
//#else
332
return depth>=max_eval_depth;
333
//#endif
334
}
335
336
template<typename Allocator>
337
__noinline static Ref create(const Allocator& alloc, CatmullClarkPatch& patch, const HalfEdge* edge, const char* vertices, size_t stride, size_t depth,
338
const BezierCurve* border0 = nullptr, const BezierCurve* border1 = nullptr, const BezierCurve* border2 = nullptr, const BezierCurve* border3 = nullptr)
339
{
340
const typename CatmullClarkPatch::Type ty = patch.type();
341
if (unlikely(final(patch,ty,depth))) {
342
if (ty & CatmullClarkRing::TYPE_REGULAR) return RegularPatch::create(alloc,patch,border0,border1,border2,border3);
343
else return IrregularFillPatch::create(alloc,patch,border0,border1,border2,border3);
344
}
345
else if (ty & CatmullClarkRing::TYPE_REGULAR_CREASES) {
346
assert(depth > 0); return RegularPatch::create(alloc,patch,border0,border1,border2,border3);
347
}
348
#if PATCH_USE_GREGORY == 2
349
else if (ty & CatmullClarkRing::TYPE_GREGORY_CREASES) {
350
assert(depth > 0); return GregoryPatch::create(alloc,patch,border0,border1,border2,border3);
351
}
352
#endif
353
else if (depth >= PATCH_MAX_CACHE_DEPTH) {
354
return EvalPatch::create(alloc,patch);
355
}
356
357
else
358
{
359
Ref child[4];
360
array_t<CatmullClarkPatch,4> patches;
361
patch.subdivide(patches);
362
363
for (size_t i=0; i<4; i++)
364
child[i] = PatchT::create(alloc,patches[i],edge,vertices,stride,depth+1);
365
return SubdividedQuadPatch::create(alloc,child);
366
}
367
}
368
};
369
370
typedef PatchT<Vec3fa,Vec3fa_t> Patch3fa;
371
}
372
373