1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "geometry.h"
7#include "buffer.h"
8
9namespace embree
10{
11 /*! Quad Mesh */
12 struct QuadMesh : public Geometry
13 {
14 /*! type of this geometry */
15 static const Geometry::GTypeMask geom_type = Geometry::MTY_QUAD_MESH;
16
17 /*! triangle indices */
18 struct Quad
19 {
20 uint32_t v[4];
21
22 /*! outputs triangle indices */
23 __forceinline friend embree_ostream operator<<(embree_ostream cout, const Quad& q) {
24 return cout << "Quad {" << q.v[0] << ", " << q.v[1] << ", " << q.v[2] << ", " << q.v[3] << " }";
25 }
26 };
27
28 public:
29
30 /*! quad mesh construction */
31 QuadMesh (Device* device);
32
33 /* geometry interface */
34 public:
35 void setMask(unsigned mask);
36 void setNumTimeSteps (unsigned int numTimeSteps);
37 void setVertexAttributeCount (unsigned int N);
38 void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num);
39 void* getBuffer(RTCBufferType type, unsigned int slot);
40 void updateBuffer(RTCBufferType type, unsigned int slot);
41 void commit();
42 bool verify();
43 void interpolate(const RTCInterpolateArguments* const args);
44 void addElementsToCount (GeometryCounts & counts) const;
45
46 template<int N>
47 void interpolate_impl(const RTCInterpolateArguments* const args)
48 {
49 unsigned int primID = args->primID;
50 float u = args->u;
51 float v = args->v;
52 RTCBufferType bufferType = args->bufferType;
53 unsigned int bufferSlot = args->bufferSlot;
54 float* P = args->P;
55 float* dPdu = args->dPdu;
56 float* dPdv = args->dPdv;
57 float* ddPdudu = args->ddPdudu;
58 float* ddPdvdv = args->ddPdvdv;
59 float* ddPdudv = args->ddPdudv;
60 unsigned int valueCount = args->valueCount;
61
62 /* calculate base pointer and stride */
63 assert((bufferType == RTC_BUFFER_TYPE_VERTEX && bufferSlot < numTimeSteps) ||
64 (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE && bufferSlot <= vertexAttribs.size()));
65 const char* src = nullptr;
66 size_t stride = 0;
67 if (bufferType == RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE) {
68 src = vertexAttribs[bufferSlot].getPtr();
69 stride = vertexAttribs[bufferSlot].getStride();
70 } else {
71 src = vertices[bufferSlot].getPtr();
72 stride = vertices[bufferSlot].getStride();
73 }
74
75 for (unsigned int i=0; i<valueCount; i+=N)
76 {
77 const vbool<N> valid = vint<N>((int)i)+vint<N>(step) < vint<N>(int(valueCount));
78 const size_t ofs = i*sizeof(float);
79 const Quad& tri = quad(primID);
80 const vfloat<N> p0 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[0]*stride+ofs]);
81 const vfloat<N> p1 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[1]*stride+ofs]);
82 const vfloat<N> p2 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[2]*stride+ofs]);
83 const vfloat<N> p3 = mem<vfloat<N>>::loadu(valid,(float*)&src[tri.v[3]*stride+ofs]);
84 const vbool<N> left = u+v <= 1.0f;
85 const vfloat<N> Q0 = select(left,p0,p2);
86 const vfloat<N> Q1 = select(left,p1,p3);
87 const vfloat<N> Q2 = select(left,p3,p1);
88 const vfloat<N> U = select(left,u,vfloat<N>(1.0f)-u);
89 const vfloat<N> V = select(left,v,vfloat<N>(1.0f)-v);
90 const vfloat<N> W = 1.0f-U-V;
91 if (P) {
92 mem<vfloat<N>>::storeu(valid,P+i,madd(W,Q0,madd(U,Q1,V*Q2)));
93 }
94 if (dPdu) {
95 assert(dPdu); mem<vfloat<N>>::storeu(valid,dPdu+i,select(left,Q1-Q0,Q0-Q1));
96 assert(dPdv); mem<vfloat<N>>::storeu(valid,dPdv+i,select(left,Q2-Q0,Q0-Q2));
97 }
98 if (ddPdudu) {
99 assert(ddPdudu); mem<vfloat<N>>::storeu(valid,ddPdudu+i,vfloat<N>(zero));
100 assert(ddPdvdv); mem<vfloat<N>>::storeu(valid,ddPdvdv+i,vfloat<N>(zero));
101 assert(ddPdudv); mem<vfloat<N>>::storeu(valid,ddPdudv+i,vfloat<N>(zero));
102 }
103 }
104 }
105
106 public:
107
108 /*! returns number of vertices */
109 __forceinline size_t numVertices() const {
110 return vertices[0].size();
111 }
112
113 /*! returns i'th quad */
114 __forceinline const Quad& quad(size_t i) const {
115 return quads[i];
116 }
117
118 /*! returns i'th vertex of itime'th timestep */
119 __forceinline const Vec3fa vertex(size_t i) const {
120 return vertices0[i];
121 }
122
123 /*! returns i'th vertex of itime'th timestep */
124 __forceinline const char* vertexPtr(size_t i) const {
125 return vertices0.getPtr(i);
126 }
127
128 /*! returns i'th vertex of itime'th timestep */
129 __forceinline const Vec3fa vertex(size_t i, size_t itime) const {
130 return vertices[itime][i];
131 }
132
133 /*! returns i'th vertex of itime'th timestep */
134 __forceinline const char* vertexPtr(size_t i, size_t itime) const {
135 return vertices[itime].getPtr(i);
136 }
137
138 /*! calculates the bounds of the i'th quad */
139 __forceinline BBox3fa bounds(size_t i) const
140 {
141 const Quad& q = quad(i);
142 const Vec3fa v0 = vertex(q.v[0]);
143 const Vec3fa v1 = vertex(q.v[1]);
144 const Vec3fa v2 = vertex(q.v[2]);
145 const Vec3fa v3 = vertex(q.v[3]);
146 return BBox3fa(min(v0,v1,v2,v3),max(v0,v1,v2,v3));
147 }
148
149 /*! calculates the bounds of the i'th quad at the itime'th timestep */
150 __forceinline BBox3fa bounds(size_t i, size_t itime) const
151 {
152 const Quad& q = quad(i);
153 const Vec3fa v0 = vertex(q.v[0],itime);
154 const Vec3fa v1 = vertex(q.v[1],itime);
155 const Vec3fa v2 = vertex(q.v[2],itime);
156 const Vec3fa v3 = vertex(q.v[3],itime);
157 return BBox3fa(min(v0,v1,v2,v3),max(v0,v1,v2,v3));
158 }
159
160 /*! check if the i'th primitive is valid at the itime'th timestep */
161 __forceinline bool valid(size_t i, size_t itime) const {
162 return valid(i, make_range(itime, itime));
163 }
164
165 /*! check if the i'th primitive is valid between the specified time range */
166 __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
167 {
168 const Quad& q = quad(i);
169 if (unlikely(q.v[0] >= numVertices())) return false;
170 if (unlikely(q.v[1] >= numVertices())) return false;
171 if (unlikely(q.v[2] >= numVertices())) return false;
172 if (unlikely(q.v[3] >= numVertices())) return false;
173
174 for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
175 {
176 if (!isvalid(vertex(q.v[0],itime))) return false;
177 if (!isvalid(vertex(q.v[1],itime))) return false;
178 if (!isvalid(vertex(q.v[2],itime))) return false;
179 if (!isvalid(vertex(q.v[3],itime))) return false;
180 }
181
182 return true;
183 }
184
185 /*! calculates the linear bounds of the i'th quad at the itimeGlobal'th time segment */
186 __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const {
187 return LBBox3fa(bounds(i,itime+0),bounds(i,itime+1));
188 }
189
190 /*! calculates the build bounds of the i'th primitive, if it's valid */
191 __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
192 {
193 const Quad& q = quad(i);
194 if (q.v[0] >= numVertices()) return false;
195 if (q.v[1] >= numVertices()) return false;
196 if (q.v[2] >= numVertices()) return false;
197 if (q.v[3] >= numVertices()) return false;
198
199 for (unsigned int t=0; t<numTimeSteps; t++)
200 {
201 const Vec3fa v0 = vertex(q.v[0],t);
202 const Vec3fa v1 = vertex(q.v[1],t);
203 const Vec3fa v2 = vertex(q.v[2],t);
204 const Vec3fa v3 = vertex(q.v[3],t);
205
206 if (unlikely(!isvalid(v0) || !isvalid(v1) || !isvalid(v2) || !isvalid(v3)))
207 return false;
208 }
209
210 if (bbox)
211 *bbox = bounds(i);
212
213 return true;
214 }
215
216 /*! calculates the build bounds of the i'th primitive at the itime'th time segment, if it's valid */
217 __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
218 {
219 const Quad& q = quad(i);
220 if (unlikely(q.v[0] >= numVertices())) return false;
221 if (unlikely(q.v[1] >= numVertices())) return false;
222 if (unlikely(q.v[2] >= numVertices())) return false;
223 if (unlikely(q.v[3] >= numVertices())) return false;
224
225 assert(itime+1 < numTimeSteps);
226 const Vec3fa a0 = vertex(q.v[0],itime+0); if (unlikely(!isvalid(a0))) return false;
227 const Vec3fa a1 = vertex(q.v[1],itime+0); if (unlikely(!isvalid(a1))) return false;
228 const Vec3fa a2 = vertex(q.v[2],itime+0); if (unlikely(!isvalid(a2))) return false;
229 const Vec3fa a3 = vertex(q.v[3],itime+0); if (unlikely(!isvalid(a3))) return false;
230 const Vec3fa b0 = vertex(q.v[0],itime+1); if (unlikely(!isvalid(b0))) return false;
231 const Vec3fa b1 = vertex(q.v[1],itime+1); if (unlikely(!isvalid(b1))) return false;
232 const Vec3fa b2 = vertex(q.v[2],itime+1); if (unlikely(!isvalid(b2))) return false;
233 const Vec3fa b3 = vertex(q.v[3],itime+1); if (unlikely(!isvalid(b3))) return false;
234
235 /* use bounds of first time step in builder */
236 bbox = BBox3fa(min(a0,a1,a2,a3),max(a0,a1,a2,a3));
237 return true;
238 }
239
240 /*! calculates the linear bounds of the i'th primitive for the specified time range */
241 __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
242 return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
243 }
244
245 /*! calculates the linear bounds of the i'th primitive for the specified time range */
246 __forceinline bool linearBounds(size_t i, const BBox1f& dt, LBBox3fa& bbox) const
247 {
248 if (!valid(i, timeSegmentRange(dt))) return false;
249 bbox = linearBounds(i, dt);
250 return true;
251 }
252
253 /*! get fast access to first vertex buffer */
254 __forceinline float * getCompactVertexArray () const {
255 return (float*) vertices0.getPtr();
256 }
257
258 /* gets version info of topology */
259 unsigned int getTopologyVersion() const {
260 return quads.modCounter;
261 }
262
263 /* returns true if topology changed */
264 bool topologyChanged(unsigned int otherVersion) const {
265 return quads.isModified(otherVersion); // || numPrimitivesChanged;
266 }
267
268 /* returns the projected area */
269 __forceinline float projectedPrimitiveArea(const size_t i) const {
270 const Quad& q = quad(i);
271 const Vec3fa v0 = vertex(q.v[0]);
272 const Vec3fa v1 = vertex(q.v[1]);
273 const Vec3fa v2 = vertex(q.v[2]);
274 const Vec3fa v3 = vertex(q.v[3]);
275 return areaProjectedTriangle(v0,v1,v3) +
276 areaProjectedTriangle(v1,v2,v3);
277 }
278
279 public:
280 BufferView<Quad> quads; //!< array of quads
281 BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer
282 vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep
283 vector<BufferView<char>> vertexAttribs; //!< vertex attribute buffers
284 };
285
286 namespace isa
287 {
288 struct QuadMeshISA : public QuadMesh
289 {
290 QuadMeshISA (Device* device)
291 : QuadMesh(device) {}
292
293 PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const
294 {
295 PrimInfo pinfo(empty);
296 for (size_t j=r.begin(); j<r.end(); j++)
297 {
298 BBox3fa bounds = empty;
299 if (!buildBounds(j,&bounds)) continue;
300 const PrimRef prim(bounds,geomID,unsigned(j));
301 pinfo.add_center2(prim);
302 prims[k++] = prim;
303 }
304 return pinfo;
305 }
306
307 PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const
308 {
309 PrimInfo pinfo(empty);
310 for (size_t j=r.begin(); j<r.end(); j++)
311 {
312 BBox3fa bounds = empty;
313 if (!buildBounds(j,itime,bounds)) continue;
314 const PrimRef prim(bounds,geomID,unsigned(j));
315 pinfo.add_center2(prim);
316 prims[k++] = prim;
317 }
318 return pinfo;
319 }
320
321 PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const
322 {
323 PrimInfoMB pinfo(empty);
324 for (size_t j=r.begin(); j<r.end(); j++)
325 {
326 if (!valid(j, timeSegmentRange(t0t1))) continue;
327 const PrimRefMB prim(linearBounds(j,t0t1),this->numTimeSegments(),this->time_range,this->numTimeSegments(),geomID,unsigned(j));
328 pinfo.add_primref(prim);
329 prims[k++] = prim;
330 }
331 return pinfo;
332 }
333 };
334 }
335
336 DECLARE_ISA_FUNCTION(QuadMesh*, createQuadMesh, Device*);
337}
338