summaryrefslogtreecommitdiff
path: root/thirdparty/embree/kernels/subdiv/bilinear_patch.h
blob: cade104a6c3925b135e0c436790340947c317704 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "catmullclark_patch.h"
#include "bezier_curve.h"

namespace embree
{
  template<typename Vertex, typename Vertex_t = Vertex>
    class __aligned(64) BilinearPatchT
    {
      typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing;
      typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch;
      
    public:
      Vertex v[4];
      
    public:
      
      __forceinline BilinearPatchT () {}

      __forceinline BilinearPatchT (const HalfEdge* edge, const BufferView<Vertex>& vertices) {
        init(edge,vertices.getPtr(),vertices.getStride());
      }
      
      __forceinline BilinearPatchT (const HalfEdge* edge, const char* vertices, size_t stride) {
        init(edge,vertices,stride);
      }

      __forceinline void init (const HalfEdge* edge, const char* vertices, size_t stride)
      {
        v[0] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
        v[1] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
        v[2] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
        v[3] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next();
      }

      __forceinline BilinearPatchT (const CatmullClarkPatch& patch)
      {
        v[0] = patch.ring[0].getLimitVertex();
        v[1] = patch.ring[1].getLimitVertex();
        v[2] = patch.ring[2].getLimitVertex();
        v[3] = patch.ring[3].getLimitVertex();
      }

      __forceinline BBox<Vertex> bounds() const
      {
        
        BBox<Vertex> bounds (v[0]);
        bounds.extend(v[1]);
        bounds.extend(v[2]);
        bounds.extend(v[3]);
        return bounds;
      }
      
      __forceinline Vertex eval(const float uu, const float vv) const {
        return lerp(lerp(v[0],v[1],uu),lerp(v[3],v[2],uu),vv);
      }

      __forceinline Vertex eval_du(const float uu, const float vv) const {
        return lerp(v[1]-v[0],v[2]-v[3],vv);
      }

      __forceinline Vertex eval_dv(const float uu, const float vv) const {
        return lerp(v[3]-v[0],v[2]-v[1],uu);
      }

      __forceinline Vertex eval_dudu(const float uu, const float vv) const {
        return Vertex(zero);
      }

      __forceinline Vertex eval_dvdv(const float uu, const float vv) const {
        return Vertex(zero);
      }

      __forceinline Vertex eval_dudv(const float uu, const float vv) const {
        return (v[2]-v[3]) - (v[1]-v[0]);
      }

      __forceinline Vertex normal(const float uu, const float vv) const {
        return cross(eval_du(uu,vv),eval_dv(uu,vv));
      }
      
      __forceinline void eval(const float u, const float v, 
                              Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv,
                              const float dscale = 1.0f) const
      {
        if (P) {
          *P = eval(u,v); 
        }
        if (dPdu) {
          assert(dPdu); *dPdu = eval_du(u,v)*dscale; 
          assert(dPdv); *dPdv = eval_dv(u,v)*dscale; 
        }
        if (ddPdudu) {
          assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(dscale); 
          assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(dscale); 
          assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(dscale); 
        }
      }

      template<class vfloat>
      __forceinline Vec3<vfloat> eval(const vfloat& uu, const vfloat& vv) const
      {
        const vfloat x = lerp(lerp(v[0].x,v[1].x,uu),lerp(v[3].x,v[2].x,uu),vv);
        const vfloat y = lerp(lerp(v[0].y,v[1].y,uu),lerp(v[3].y,v[2].y,uu),vv);
        const vfloat z = lerp(lerp(v[0].z,v[1].z,uu),lerp(v[3].z,v[2].z,uu),vv);
        return Vec3<vfloat>(x,y,z);
      }

      template<class vfloat>
      __forceinline Vec3<vfloat> eval_du(const vfloat& uu, const vfloat& vv) const
      {
        const vfloat x = lerp(v[1].x-v[0].x,v[2].x-v[3].x,vv);
        const vfloat y = lerp(v[1].y-v[0].y,v[2].y-v[3].y,vv);
        const vfloat z = lerp(v[1].z-v[0].z,v[2].z-v[3].z,vv);
        return Vec3<vfloat>(x,y,z);
      }

      template<class vfloat>
      __forceinline Vec3<vfloat> eval_dv(const vfloat& uu, const vfloat& vv) const
      {
        const vfloat x = lerp(v[3].x-v[0].x,v[2].x-v[1].x,uu);
        const vfloat y = lerp(v[3].y-v[0].y,v[2].y-v[1].y,uu);
        const vfloat z = lerp(v[3].z-v[0].z,v[2].z-v[1].z,uu);
        return Vec3<vfloat>(x,y,z);
      }

      template<typename vfloat>
      __forceinline Vec3<vfloat> normal(const vfloat& uu, const vfloat& vv) const {
        return cross(eval_du(uu,vv),eval_dv(uu,vv));
      }

       template<class vfloat>
      __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv) const {
        return lerp(lerp(v[0][i],v[1][i],uu),lerp(v[3][i],v[2][i],uu),vv);
      }

      template<class vfloat>
      __forceinline vfloat eval_du(const size_t i, const vfloat& uu, const vfloat& vv) const {
        return lerp(v[1][i]-v[0][i],v[2][i]-v[3][i],vv);
      }

      template<class vfloat>
      __forceinline vfloat eval_dv(const size_t i, const vfloat& uu, const vfloat& vv) const {
        return lerp(v[3][i]-v[0][i],v[2][i]-v[1][i],uu);
      }
      
      template<class vfloat>
      __forceinline vfloat eval_dudu(const size_t i, const vfloat& uu, const vfloat& vv) const {
        return vfloat(zero);
      }

      template<class vfloat>
      __forceinline vfloat eval_dvdv(const size_t i, const vfloat& uu, const vfloat& vv) const {
        return vfloat(zero);
      }

      template<class vfloat>
      __forceinline vfloat eval_dudv(const size_t i, const vfloat& uu, const vfloat& vv) const {
        return (v[2][i]-v[3][i]) - (v[1][i]-v[0][i]);
      }

      template<typename vbool, typename vfloat>
      __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv, 
                              float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv,
                              const float dscale, const size_t dstride, const size_t N) const
      {
        if (P) {
          for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv));
        }
        if (dPdu) {
          for (size_t i=0; i<N; i++) {
            assert(dPdu); vfloat::store(valid,dPdu+i*dstride,eval_du(i,uu,vv)*dscale);
            assert(dPdv); vfloat::store(valid,dPdv+i*dstride,eval_dv(i,uu,vv)*dscale);
          }
        }
        if (ddPdudu) {
          for (size_t i=0; i<N; i++) {
            assert(ddPdudu); vfloat::store(valid,ddPdudu+i*dstride,eval_dudu(i,uu,vv)*sqr(dscale));
            assert(ddPdvdv); vfloat::store(valid,ddPdvdv+i*dstride,eval_dvdv(i,uu,vv)*sqr(dscale));
            assert(ddPdudv); vfloat::store(valid,ddPdudv+i*dstride,eval_dudv(i,uu,vv)*sqr(dscale));
          }
        }
      }
    };
  
  typedef BilinearPatchT<Vec3fa,Vec3fa_t> BilinearPatch3fa;
}