| 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 "bezier_curve.h" | 
| 8 |  | 
| 9 | namespace embree | 
| 10 | { | 
| 11 |   template<typename Vertex, typename Vertex_t = Vertex> | 
| 12 |     class __aligned(64) BilinearPatchT | 
| 13 |     { | 
| 14 |       typedef CatmullClark1RingT<Vertex,Vertex_t> CatmullClarkRing; | 
| 15 |       typedef CatmullClarkPatchT<Vertex,Vertex_t> CatmullClarkPatch; | 
| 16 |        | 
| 17 |     public: | 
| 18 |       Vertex v[4]; | 
| 19 |        | 
| 20 |     public: | 
| 21 |        | 
| 22 |       __forceinline BilinearPatchT () {} | 
| 23 |  | 
| 24 |       __forceinline BilinearPatchT (const HalfEdge* edge, const BufferView<Vertex>& vertices) { | 
| 25 |         init(edge,vertices: vertices.getPtr(),stride: vertices.getStride()); | 
| 26 |       } | 
| 27 |        | 
| 28 |       __forceinline BilinearPatchT (const HalfEdge* edge, const char* vertices, size_t stride) { | 
| 29 |         init(edge,vertices,stride); | 
| 30 |       } | 
| 31 |  | 
| 32 |       __forceinline void init (const HalfEdge* edge, const char* vertices, size_t stride) | 
| 33 |       { | 
| 34 |         v[0] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next(); | 
| 35 |         v[1] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next(); | 
| 36 |         v[2] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next(); | 
| 37 |         v[3] = Vertex::loadu(vertices+edge->getStartVertexIndex()*stride); edge = edge->next(); | 
| 38 |       } | 
| 39 |  | 
| 40 |       __forceinline BilinearPatchT (const CatmullClarkPatch& patch) | 
| 41 |       { | 
| 42 |         v[0] = patch.ring[0].getLimitVertex(); | 
| 43 |         v[1] = patch.ring[1].getLimitVertex(); | 
| 44 |         v[2] = patch.ring[2].getLimitVertex(); | 
| 45 |         v[3] = patch.ring[3].getLimitVertex(); | 
| 46 |       } | 
| 47 |  | 
| 48 |       __forceinline BBox<Vertex> bounds() const | 
| 49 |       { | 
| 50 |          | 
| 51 |         BBox<Vertex> bounds (v[0]); | 
| 52 |         bounds.extend(v[1]); | 
| 53 |         bounds.extend(v[2]); | 
| 54 |         bounds.extend(v[3]); | 
| 55 |         return bounds; | 
| 56 |       } | 
| 57 |        | 
| 58 |       __forceinline Vertex eval(const float uu, const float vv) const { | 
| 59 |         return lerp(lerp(v[0],v[1],uu),lerp(v[3],v[2],uu),vv); | 
| 60 |       } | 
| 61 |  | 
| 62 |       __forceinline Vertex eval_du(const float uu, const float vv) const { | 
| 63 |         return lerp(v[1]-v[0],v[2]-v[3],vv); | 
| 64 |       } | 
| 65 |  | 
| 66 |       __forceinline Vertex eval_dv(const float uu, const float vv) const { | 
| 67 |         return lerp(v[3]-v[0],v[2]-v[1],uu); | 
| 68 |       } | 
| 69 |  | 
| 70 |       __forceinline Vertex eval_dudu(const float uu, const float vv) const { | 
| 71 |         return Vertex(zero); | 
| 72 |       } | 
| 73 |  | 
| 74 |       __forceinline Vertex eval_dvdv(const float uu, const float vv) const { | 
| 75 |         return Vertex(zero); | 
| 76 |       } | 
| 77 |  | 
| 78 |       __forceinline Vertex eval_dudv(const float uu, const float vv) const { | 
| 79 |         return (v[2]-v[3]) - (v[1]-v[0]); | 
| 80 |       } | 
| 81 |  | 
| 82 |       __forceinline Vertex normal(const float uu, const float vv) const { | 
| 83 |         return cross(eval_du(uu,vv),eval_dv(uu,vv)); | 
| 84 |       } | 
| 85 |        | 
| 86 |       __forceinline void eval(const float u, const float v,  | 
| 87 |                               Vertex* P, Vertex* dPdu, Vertex* dPdv, Vertex* ddPdudu, Vertex* ddPdvdv, Vertex* ddPdudv, | 
| 88 |                               const float dscale = 1.0f) const | 
| 89 |       { | 
| 90 |         if (P) { | 
| 91 |           *P = eval(u,v);  | 
| 92 |         } | 
| 93 |         if (dPdu) { | 
| 94 |           assert(dPdu); *dPdu = eval_du(u,v)*dscale;  | 
| 95 |           assert(dPdv); *dPdv = eval_dv(u,v)*dscale;  | 
| 96 |         } | 
| 97 |         if (ddPdudu) { | 
| 98 |           assert(ddPdudu); *ddPdudu = eval_dudu(u,v)*sqr(x: dscale);  | 
| 99 |           assert(ddPdvdv); *ddPdvdv = eval_dvdv(u,v)*sqr(x: dscale);  | 
| 100 |           assert(ddPdudv); *ddPdudv = eval_dudv(u,v)*sqr(x: dscale);  | 
| 101 |         } | 
| 102 |       } | 
| 103 |  | 
| 104 |       template<class vfloat> | 
| 105 |       __forceinline Vec3<vfloat> eval(const vfloat& uu, const vfloat& vv) const | 
| 106 |       { | 
| 107 |         const vfloat x = lerp(lerp(v[0].x,v[1].x,uu),lerp(v[3].x,v[2].x,uu),vv); | 
| 108 |         const vfloat y = lerp(lerp(v[0].y,v[1].y,uu),lerp(v[3].y,v[2].y,uu),vv); | 
| 109 |         const vfloat z = lerp(lerp(v[0].z,v[1].z,uu),lerp(v[3].z,v[2].z,uu),vv); | 
| 110 |         return Vec3<vfloat>(x,y,z); | 
| 111 |       } | 
| 112 |  | 
| 113 |       template<class vfloat> | 
| 114 |       __forceinline Vec3<vfloat> eval_du(const vfloat& uu, const vfloat& vv) const | 
| 115 |       { | 
| 116 |         const vfloat x = lerp(v[1].x-v[0].x,v[2].x-v[3].x,vv); | 
| 117 |         const vfloat y = lerp(v[1].y-v[0].y,v[2].y-v[3].y,vv); | 
| 118 |         const vfloat z = lerp(v[1].z-v[0].z,v[2].z-v[3].z,vv); | 
| 119 |         return Vec3<vfloat>(x,y,z); | 
| 120 |       } | 
| 121 |  | 
| 122 |       template<class vfloat> | 
| 123 |       __forceinline Vec3<vfloat> eval_dv(const vfloat& uu, const vfloat& vv) const | 
| 124 |       { | 
| 125 |         const vfloat x = lerp(v[3].x-v[0].x,v[2].x-v[1].x,uu); | 
| 126 |         const vfloat y = lerp(v[3].y-v[0].y,v[2].y-v[1].y,uu); | 
| 127 |         const vfloat z = lerp(v[3].z-v[0].z,v[2].z-v[1].z,uu); | 
| 128 |         return Vec3<vfloat>(x,y,z); | 
| 129 |       } | 
| 130 |  | 
| 131 |       template<typename vfloat> | 
| 132 |       __forceinline Vec3<vfloat> normal(const vfloat& uu, const vfloat& vv) const { | 
| 133 |         return cross(eval_du(uu,vv),eval_dv(uu,vv)); | 
| 134 |       } | 
| 135 |  | 
| 136 |        template<class vfloat> | 
| 137 |       __forceinline vfloat eval(const size_t i, const vfloat& uu, const vfloat& vv) const { | 
| 138 |         return lerp(lerp(v[0][i],v[1][i],uu),lerp(v[3][i],v[2][i],uu),vv); | 
| 139 |       } | 
| 140 |  | 
| 141 |       template<class vfloat> | 
| 142 |       __forceinline vfloat eval_du(const size_t i, const vfloat& uu, const vfloat& vv) const { | 
| 143 |         return lerp(v[1][i]-v[0][i],v[2][i]-v[3][i],vv); | 
| 144 |       } | 
| 145 |  | 
| 146 |       template<class vfloat> | 
| 147 |       __forceinline vfloat eval_dv(const size_t i, const vfloat& uu, const vfloat& vv) const { | 
| 148 |         return lerp(v[3][i]-v[0][i],v[2][i]-v[1][i],uu); | 
| 149 |       } | 
| 150 |        | 
| 151 |       template<class vfloat> | 
| 152 |       __forceinline vfloat eval_dudu(const size_t i, const vfloat& uu, const vfloat& vv) const { | 
| 153 |         return vfloat(zero); | 
| 154 |       } | 
| 155 |  | 
| 156 |       template<class vfloat> | 
| 157 |       __forceinline vfloat eval_dvdv(const size_t i, const vfloat& uu, const vfloat& vv) const { | 
| 158 |         return vfloat(zero); | 
| 159 |       } | 
| 160 |  | 
| 161 |       template<class vfloat> | 
| 162 |       __forceinline vfloat eval_dudv(const size_t i, const vfloat& uu, const vfloat& vv) const { | 
| 163 |         return (v[2][i]-v[3][i]) - (v[1][i]-v[0][i]); | 
| 164 |       } | 
| 165 |  | 
| 166 |       template<typename vbool, typename vfloat> | 
| 167 |       __forceinline void eval(const vbool& valid, const vfloat& uu, const vfloat& vv,  | 
| 168 |                               float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, | 
| 169 |                               const float dscale, const size_t dstride, const size_t N) const | 
| 170 |       { | 
| 171 |         if (P) { | 
| 172 |           for (size_t i=0; i<N; i++) vfloat::store(valid,P+i*dstride,eval(i,uu,vv)); | 
| 173 |         } | 
| 174 |         if (dPdu) { | 
| 175 |           for (size_t i=0; i<N; i++) { | 
| 176 |             assert(dPdu); vfloat::store(valid,dPdu+i*dstride,eval_du(i,uu,vv)*dscale); | 
| 177 |             assert(dPdv); vfloat::store(valid,dPdv+i*dstride,eval_dv(i,uu,vv)*dscale); | 
| 178 |           } | 
| 179 |         } | 
| 180 |         if (ddPdudu) { | 
| 181 |           for (size_t i=0; i<N; i++) { | 
| 182 |             assert(ddPdudu); vfloat::store(valid,ddPdudu+i*dstride,eval_dudu(i,uu,vv)*sqr(x: dscale)); | 
| 183 |             assert(ddPdvdv); vfloat::store(valid,ddPdvdv+i*dstride,eval_dvdv(i,uu,vv)*sqr(x: dscale)); | 
| 184 |             assert(ddPdudv); vfloat::store(valid,ddPdudv+i*dstride,eval_dudv(i,uu,vv)*sqr(x: dscale)); | 
| 185 |           } | 
| 186 |         } | 
| 187 |       } | 
| 188 |     }; | 
| 189 |    | 
| 190 |   typedef BilinearPatchT<Vec3fa,Vec3fa_t> BilinearPatch3fa; | 
| 191 | } | 
| 192 |  |