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