1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "bezier_curve.h"
7
8namespace embree
9{
10 namespace isa
11 {
12 template<typename V>
13 struct TensorLinearQuadraticBezierSurface
14 {
15 QuadraticBezierCurve<V> L;
16 QuadraticBezierCurve<V> R;
17
18 __forceinline TensorLinearQuadraticBezierSurface() {}
19
20 __forceinline TensorLinearQuadraticBezierSurface(const TensorLinearQuadraticBezierSurface<V>& curve)
21 : L(curve.L), R(curve.R) {}
22
23 __forceinline TensorLinearQuadraticBezierSurface& operator= (const TensorLinearQuadraticBezierSurface& other) {
24 L = other.L; R = other.R; return *this;
25 }
26
27 __forceinline TensorLinearQuadraticBezierSurface(const QuadraticBezierCurve<V>& L, const QuadraticBezierCurve<V>& R)
28 : L(L), R(R) {}
29
30 __forceinline BBox<V> bounds() const {
31 return merge(L.bounds(),R.bounds());
32 }
33 };
34
35 template<>
36 struct TensorLinearQuadraticBezierSurface<Vec2fa>
37 {
38 QuadraticBezierCurve<vfloat4> LR;
39
40 __forceinline TensorLinearQuadraticBezierSurface() {}
41
42 __forceinline TensorLinearQuadraticBezierSurface(const TensorLinearQuadraticBezierSurface<Vec2fa>& curve)
43 : LR(curve.LR) {}
44
45 __forceinline TensorLinearQuadraticBezierSurface& operator= (const TensorLinearQuadraticBezierSurface& other) {
46 LR = other.LR; return *this;
47 }
48
49 __forceinline TensorLinearQuadraticBezierSurface(const QuadraticBezierCurve<vfloat4>& LR)
50 : LR(LR) {}
51
52 __forceinline BBox<Vec2fa> bounds() const
53 {
54 const BBox<vfloat4> b = LR.bounds();
55 const BBox<Vec2fa> bl(Vec2fa(b.lower),Vec2fa(b.upper));
56 const BBox<Vec2fa> br(Vec2fa(shuffle<2,3,2,3>(b.lower)),Vec2fa(shuffle<2,3,2,3>(b.upper)));
57 return merge(bl,br);
58 }
59 };
60
61 template<typename V>
62 struct TensorLinearCubicBezierSurface
63 {
64 CubicBezierCurve<V> L;
65 CubicBezierCurve<V> R;
66
67 __forceinline TensorLinearCubicBezierSurface() {}
68
69 __forceinline TensorLinearCubicBezierSurface(const TensorLinearCubicBezierSurface& curve)
70 : L(curve.L), R(curve.R) {}
71
72 __forceinline TensorLinearCubicBezierSurface& operator= (const TensorLinearCubicBezierSurface& other) {
73 L = other.L; R = other.R; return *this;
74 }
75
76 __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<V>& L, const CubicBezierCurve<V>& R)
77 : L(L), R(R) {}
78
79 template<template<typename T> class SourceCurve>
80 __forceinline static TensorLinearCubicBezierSurface fromCenterAndNormalCurve(const SourceCurve<Vec3ff>& center, const SourceCurve<Vec3fa>& normal)
81 {
82 SourceCurve<Vec3ff> vcurve = center;
83 SourceCurve<Vec3fa> ncurve = normal;
84
85 /* here we construct a patch which follows the curve l(t) =
86 * p(t) +/- r(t)*normalize(cross(n(t),dp(t))) */
87
88 const Vec3ff p0 = vcurve.eval(0.0f);
89 const Vec3ff dp0 = vcurve.eval_du(0.0f);
90 //const Vec3ff ddp0 = vcurve.eval_dudu(0.0f); // ddp0 is assumed to be 0
91
92 const Vec3fa n0 = ncurve.eval(0.0f);
93 const Vec3fa dn0 = ncurve.eval_du(0.0f);
94
95 const Vec3ff p1 = vcurve.eval(1.0f);
96 const Vec3ff dp1 = vcurve.eval_du(1.0f);
97 //const Vec3ff ddp1 = vcurve.eval_dudu(1.0f); // ddp1 is assumed to be 0
98
99 const Vec3fa n1 = ncurve.eval(1.0f);
100 const Vec3fa dn1 = ncurve.eval_du(1.0f);
101
102 const Vec3fa bt0 = cross(n0,dp0);
103 const Vec3fa dbt0 = cross(dn0,dp0);// + cross(n0,ddp0);
104
105 const Vec3fa bt1 = cross(n1,dp1);
106 const Vec3fa dbt1 = cross(dn1,dp1);// + cross(n1,ddp1);
107
108 const Vec3fa k0 = normalize(bt0);
109 const Vec3fa dk0 = dnormalize(bt0,dbt0);
110
111 const Vec3fa k1 = normalize(bt1);
112 const Vec3fa dk1 = dnormalize(bt1,dbt1);
113
114 const Vec3fa l0 = p0 - p0.w*k0;
115 const Vec3fa dl0 = dp0 - (dp0.w*k0 + p0.w*dk0);
116
117 const Vec3fa r0 = p0 + p0.w*k0;
118 const Vec3fa dr0 = dp0 + (dp0.w*k0 + p0.w*dk0);
119
120 const Vec3fa l1 = p1 - p1.w*k1;
121 const Vec3fa dl1 = dp1 - (dp1.w*k1 + p1.w*dk1);
122
123 const Vec3fa r1 = p1 + p1.w*k1;
124 const Vec3fa dr1 = dp1 + (dp1.w*k1 + p1.w*dk1);
125
126 const float scale = 1.0f/3.0f;
127 CubicBezierCurve<V> L(l0,l0+scale*dl0,l1-scale*dl1,l1);
128 CubicBezierCurve<V> R(r0,r0+scale*dr0,r1-scale*dr1,r1);
129 return TensorLinearCubicBezierSurface(L,R);
130 }
131
132 __forceinline BBox<V> bounds() const {
133 return merge(L.bounds(),R.bounds());
134 }
135
136 __forceinline BBox3fa accurateBounds() const {
137 return merge(L.accurateBounds(),R.accurateBounds());
138 }
139
140 __forceinline CubicBezierCurve<Interval1f> reduce_v() const {
141 return merge(CubicBezierCurve<Interval<V>>(L),CubicBezierCurve<Interval<V>>(R));
142 }
143
144 __forceinline LinearBezierCurve<Interval1f> reduce_u() const {
145 return LinearBezierCurve<Interval1f>(L.bounds(),R.bounds());
146 }
147
148 __forceinline TensorLinearCubicBezierSurface<float> xfm(const V& dx) const {
149 return TensorLinearCubicBezierSurface<float>(L.xfm(dx),R.xfm(dx));
150 }
151
152 __forceinline TensorLinearCubicBezierSurface<vfloatx> vxfm(const V& dx) const {
153 return TensorLinearCubicBezierSurface<vfloatx>(L.vxfm(dx),R.vxfm(dx));
154 }
155
156 __forceinline TensorLinearCubicBezierSurface<float> xfm(const V& dx, const V& p) const {
157 return TensorLinearCubicBezierSurface<float>(L.xfm(dx,p),R.xfm(dx,p));
158 }
159
160 __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space) const {
161 return TensorLinearCubicBezierSurface(L.xfm(space),R.xfm(space));
162 }
163
164 __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p) const {
165 return TensorLinearCubicBezierSurface(L.xfm(space,p),R.xfm(space,p));
166 }
167
168 __forceinline TensorLinearCubicBezierSurface<Vec3fa> xfm(const LinearSpace3fa& space, const Vec3fa& p, const float s) const {
169 return TensorLinearCubicBezierSurface(L.xfm(space,p,s),R.xfm(space,p,s));
170 }
171
172 __forceinline TensorLinearCubicBezierSurface clip_u(const Interval1f& u) const {
173 return TensorLinearCubicBezierSurface(L.clip(u),R.clip(u));
174 }
175
176 __forceinline TensorLinearCubicBezierSurface clip_v(const Interval1f& v) const {
177 return TensorLinearCubicBezierSurface(clerp(L,R,V(v.lower)),clerp(L,R,V(v.upper)));
178 }
179
180 __forceinline TensorLinearCubicBezierSurface clip(const Interval1f& u, const Interval1f& v) const {
181 return clip_v(v).clip_u(u);
182 }
183
184 __forceinline void split_u(TensorLinearCubicBezierSurface& left, TensorLinearCubicBezierSurface& right, const float u = 0.5f) const
185 {
186 CubicBezierCurve<V> L0,L1; L.split(L0,L1,u);
187 CubicBezierCurve<V> R0,R1; R.split(R0,R1,u);
188 new (&left ) TensorLinearCubicBezierSurface(L0,R0);
189 new (&right) TensorLinearCubicBezierSurface(L1,R1);
190 }
191
192 __forceinline TensorLinearCubicBezierSurface<Vec2vfx> vsplit_u(vboolx& valid, const BBox1f& u) const {
193 valid = true; clear(valid,VSIZEX-1);
194 return TensorLinearCubicBezierSurface<Vec2vfx>(L.split(u),R.split(u));
195 }
196
197 __forceinline V eval(const float u, const float v) const {
198 return clerp(L,R,V(v)).eval(u);
199 }
200
201 __forceinline V eval_du(const float u, const float v) const {
202 return clerp(L,R,V(v)).eval_dt(u);
203 }
204
205 __forceinline V eval_dv(const float u, const float v) const {
206 return (R-L).eval(u);
207 }
208
209 __forceinline void eval(const float u, const float v, V& p, V& dpdu, V& dpdv) const
210 {
211 V p0, dp0du; L.eval(u,p0,dp0du);
212 V p1, dp1du; R.eval(u,p1,dp1du);
213 p = lerp(p0,p1,v);
214 dpdu = lerp(dp0du,dp1du,v);
215 dpdv = p1-p0;
216 }
217
218 __forceinline TensorLinearQuadraticBezierSurface<V> derivative_u() const {
219 return TensorLinearQuadraticBezierSurface<V>(L.derivative(),R.derivative());
220 }
221
222 __forceinline CubicBezierCurve<V> derivative_v() const {
223 return R-L;
224 }
225
226 __forceinline V axis_u() const {
227 return (L.end()-L.begin())+(R.end()-R.begin());
228 }
229
230 __forceinline V axis_v() const {
231 return (R.begin()-L.begin())+(R.end()-L.end());
232 }
233
234 friend embree_ostream operator<<(embree_ostream cout, const TensorLinearCubicBezierSurface& a)
235 {
236 return cout << "TensorLinearCubicBezierSurface" << embree_endl
237 << "{" << embree_endl
238 << " L = " << a.L << ", " << embree_endl
239 << " R = " << a.R << embree_endl
240 << "}";
241 }
242
243 friend __forceinline TensorLinearCubicBezierSurface clerp(const TensorLinearCubicBezierSurface& a, const TensorLinearCubicBezierSurface& b, const float t) {
244 return TensorLinearCubicBezierSurface(clerp(a.L,b.L,V(t)), clerp(a.R,b.R,V(t)));
245 }
246 };
247
248 template<>
249 struct TensorLinearCubicBezierSurface<Vec2fa>
250 {
251 CubicBezierCurve<vfloat4> LR;
252
253 __forceinline TensorLinearCubicBezierSurface() {}
254
255 __forceinline TensorLinearCubicBezierSurface(const TensorLinearCubicBezierSurface& curve)
256 : LR(curve.LR) {}
257
258 __forceinline TensorLinearCubicBezierSurface& operator= (const TensorLinearCubicBezierSurface& other) {
259 LR = other.LR; return *this;
260 }
261
262 __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<vfloat4>& LR)
263 : LR(LR) {}
264
265 __forceinline TensorLinearCubicBezierSurface(const CubicBezierCurve<Vec2fa>& L, const CubicBezierCurve<Vec2fa>& R)
266 : LR(shuffle<0,1,0,1>(vfloat4(L.v0),vfloat4(R.v0)),shuffle<0,1,0,1>(vfloat4(L.v1),vfloat4(R.v1)),shuffle<0,1,0,1>(vfloat4(L.v2),vfloat4(R.v2)),shuffle<0,1,0,1>(vfloat4(L.v3),vfloat4(R.v3))) {}
267
268 __forceinline CubicBezierCurve<Vec2fa> getL() const {
269 return CubicBezierCurve<Vec2fa>(Vec2fa(LR.v0),Vec2fa(LR.v1),Vec2fa(LR.v2),Vec2fa(LR.v3));
270 }
271
272 __forceinline CubicBezierCurve<Vec2fa> getR() const {
273 return CubicBezierCurve<Vec2fa>(Vec2fa(shuffle<2,3,2,3>(LR.v0)),Vec2fa(shuffle<2,3,2,3>(LR.v1)),Vec2fa(shuffle<2,3,2,3>(LR.v2)),Vec2fa(shuffle<2,3,2,3>(LR.v3)));
274 }
275
276 __forceinline BBox<Vec2fa> bounds() const
277 {
278 const BBox<vfloat4> b = LR.bounds();
279 const BBox<Vec2fa> bl(Vec2fa(b.lower),Vec2fa(b.upper));
280 const BBox<Vec2fa> br(Vec2fa(shuffle<2,3,2,3>(b.lower)),Vec2fa(shuffle<2,3,2,3>(b.upper)));
281 return merge(bl,br);
282 }
283
284 __forceinline BBox1f bounds(const Vec2fa& axis) const
285 {
286 const CubicBezierCurve<vfloat4> LRx = LR;
287 const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
288 const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(axis)),LRx,shuffle<1>(vfloat4(axis))*LRy);
289 const BBox<vfloat4> Lb = LRa.bounds();
290 const BBox<vfloat4> Rb(shuffle<3>(Lb.lower),shuffle<3>(Lb.upper));
291 const BBox<vfloat4> b = merge(Lb,Rb);
292 return BBox1f(b.lower[0],b.upper[0]);
293 }
294
295 __forceinline TensorLinearCubicBezierSurface<float> xfm(const Vec2fa& dx) const
296 {
297 const CubicBezierCurve<vfloat4> LRx = LR;
298 const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
299 const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(dx)),LRx,shuffle<1>(vfloat4(dx))*LRy);
300 return TensorLinearCubicBezierSurface<float>(CubicBezierCurve<float>(LRa.v0[0],LRa.v1[0],LRa.v2[0],LRa.v3[0]),
301 CubicBezierCurve<float>(LRa.v0[2],LRa.v1[2],LRa.v2[2],LRa.v3[2]));
302 }
303
304 __forceinline TensorLinearCubicBezierSurface<float> xfm(const Vec2fa& dx, const Vec2fa& p) const
305 {
306 const vfloat4 pxyxy = shuffle<0,1,0,1>(vfloat4(p));
307 const CubicBezierCurve<vfloat4> LRx = LR-pxyxy;
308 const CubicBezierCurve<vfloat4> LRy(shuffle<1,0,3,2>(LR.v0),shuffle<1,0,3,2>(LR.v1),shuffle<1,0,3,2>(LR.v2),shuffle<1,0,3,2>(LR.v3));
309 const CubicBezierCurve<vfloat4> LRa = cmadd(shuffle<0>(vfloat4(dx)),LRx,shuffle<1>(vfloat4(dx))*LRy);
310 return TensorLinearCubicBezierSurface<float>(CubicBezierCurve<float>(LRa.v0[0],LRa.v1[0],LRa.v2[0],LRa.v3[0]),
311 CubicBezierCurve<float>(LRa.v0[2],LRa.v1[2],LRa.v2[2],LRa.v3[2]));
312 }
313
314 __forceinline TensorLinearCubicBezierSurface clip_u(const Interval1f& u) const {
315 return TensorLinearCubicBezierSurface(LR.clip(u));
316 }
317
318 __forceinline TensorLinearCubicBezierSurface clip_v(const Interval1f& v) const
319 {
320 const CubicBezierCurve<vfloat4> LL(shuffle<0,1,0,1>(LR.v0),shuffle<0,1,0,1>(LR.v1),shuffle<0,1,0,1>(LR.v2),shuffle<0,1,0,1>(LR.v3));
321 const CubicBezierCurve<vfloat4> RR(shuffle<2,3,2,3>(LR.v0),shuffle<2,3,2,3>(LR.v1),shuffle<2,3,2,3>(LR.v2),shuffle<2,3,2,3>(LR.v3));
322 return TensorLinearCubicBezierSurface(clerp(LL,RR,vfloat4(v.lower,v.lower,v.upper,v.upper)));
323 }
324
325 __forceinline TensorLinearCubicBezierSurface clip(const Interval1f& u, const Interval1f& v) const {
326 return clip_v(v).clip_u(u);
327 }
328
329 __forceinline void split_u(TensorLinearCubicBezierSurface& left, TensorLinearCubicBezierSurface& right, const float u = 0.5f) const
330 {
331 CubicBezierCurve<vfloat4> LR0,LR1; LR.split(LR0,LR1,u);
332 new (&left ) TensorLinearCubicBezierSurface(LR0);
333 new (&right) TensorLinearCubicBezierSurface(LR1);
334 }
335
336 __forceinline TensorLinearCubicBezierSurface<Vec2vfx> vsplit_u(vboolx& valid, const BBox1f& u) const {
337 valid = true; clear(valid,VSIZEX-1);
338 return TensorLinearCubicBezierSurface<Vec2vfx>(getL().split(u),getR().split(u));
339 }
340
341 __forceinline Vec2fa eval(const float u, const float v) const
342 {
343 const vfloat4 p = LR.eval(u);
344 return Vec2fa(lerp(shuffle<0,1,0,1>(p),shuffle<2,3,2,3>(p),v));
345 }
346
347 __forceinline Vec2fa eval_du(const float u, const float v) const
348 {
349 const vfloat4 dpdu = LR.eval_dt(u);
350 return Vec2fa(lerp(shuffle<0,1,0,1>(dpdu),shuffle<2,3,2,3>(dpdu),v));
351 }
352
353 __forceinline Vec2fa eval_dv(const float u, const float v) const
354 {
355 const vfloat4 p = LR.eval(u);
356 return Vec2fa(shuffle<2,3,2,3>(p)-shuffle<0,1,0,1>(p));
357 }
358
359 __forceinline void eval(const float u, const float v, Vec2fa& p, Vec2fa& dpdu, Vec2fa& dpdv) const
360 {
361 vfloat4 p0, dp0du; LR.eval(u,p0,dp0du);
362 p = Vec2fa(lerp(shuffle<0,1,0,1>(p0),shuffle<2,3,2,3>(p0),v));
363 dpdu = Vec2fa(lerp(shuffle<0,1,0,1>(dp0du),shuffle<2,3,2,3>(dp0du),v));
364 dpdv = Vec2fa(shuffle<2,3,2,3>(p0)-shuffle<0,1,0,1>(p0));
365 }
366
367 __forceinline TensorLinearQuadraticBezierSurface<Vec2fa> derivative_u() const {
368 return TensorLinearQuadraticBezierSurface<Vec2fa>(LR.derivative());
369 }
370
371 __forceinline CubicBezierCurve<Vec2fa> derivative_v() const {
372 return getR()-getL();
373 }
374
375 __forceinline Vec2fa axis_u() const
376 {
377 const CubicBezierCurve<Vec2fa> L = getL();
378 const CubicBezierCurve<Vec2fa> R = getR();
379 return (L.end()-L.begin())+(R.end()-R.begin());
380 }
381
382 __forceinline Vec2fa axis_v() const
383 {
384 const CubicBezierCurve<Vec2fa> L = getL();
385 const CubicBezierCurve<Vec2fa> R = getR();
386 return (R.begin()-L.begin())+(R.end()-L.end());
387 }
388
389 friend embree_ostream operator<<(embree_ostream cout, const TensorLinearCubicBezierSurface& a)
390 {
391 return cout << "TensorLinearCubicBezierSurface" << embree_endl
392 << "{" << embree_endl
393 << " L = " << a.getL() << ", " << embree_endl
394 << " R = " << a.getR() << embree_endl
395 << "}";
396 }
397 };
398
399 typedef TensorLinearCubicBezierSurface<float> TensorLinearCubicBezierSurface1f;
400 typedef TensorLinearCubicBezierSurface<Vec2fa> TensorLinearCubicBezierSurface2fa;
401 typedef TensorLinearCubicBezierSurface<Vec3fa> TensorLinearCubicBezierSurface3fa;
402 }
403}
404