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 | |
10 | namespace 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(a: BBox3ff(v0),b: BBox3ff(v1)); |
143 | return enlarge(a: (BBox3fa)b,b: maxRadiusScale*Vec3fa(max(a: v0.w,b: 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(i: index+0); |
151 | const Vec3ff v1 = vertex(i: 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(i: index+0,itime); |
160 | const Vec3ff v1 = vertex(i: 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(i: index+0); |
169 | const Vec3ff v1 = vertex(i: index+1); |
170 | const Vec3ff w0(xfmVector(s: space,a: (Vec3fa)v0),v0.w); |
171 | const Vec3ff w1(xfmVector(s: space,a: (Vec3fa)v1),v1.w); |
172 | return bounds(v0: w0,v1: 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(i: index+0,itime); |
180 | const Vec3ff v1 = vertex(i: index+1,itime); |
181 | const Vec3ff w0(xfmVector(s: space,a: (Vec3fa)v0),v0.w); |
182 | const Vec3ff w1(xfmVector(s: space,a: (Vec3fa)v1),v1.w); |
183 | return bounds(v0: w0,v1: 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, itime_range: make_range(begin: itime, end: 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(i: index+0,itime); if (unlikely(!isvalid4(v0))) return false; |
200 | const Vec3ff v1 = vertex(i: index+1,itime); if (unlikely(!isvalid4(v1))) return false; |
201 | if (min(a: v0.w,b: 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: itime+0),bounds(i,itime: 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,itime: 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: itime+0) || !valid(i,itime: 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(i: 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, i: 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, itime_range: timeSegmentRange(range: time_range))) return false; |
241 | bbox = linearBounds(primID: i, dt: 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(i: primID); |
272 | const Vec3fa v0 = vertex(i: vtxID+0); |
273 | const Vec3fa v1 = vertex(i: vtxID+1); |
274 | return v1-v0; |
275 | } |
276 | |
277 | Vec3fa computeDirection(unsigned int primID, size_t time) const |
278 | { |
279 | const unsigned vtxID = segment(i: primID); |
280 | const Vec3fa v0 = vertex(i: vtxID+0,itime: time); |
281 | const Vec3fa v1 = vertex(i: vtxID+1,itime: 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(i: j,bbox: &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(i: j,itime,bbox&: 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(i: j, itime_range: timeSegmentRange(range: t0t1))) continue; |
319 | const PrimRefMB prim(linearBounds(primID: j,dt: 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,dt: time_range); |
336 | } |
337 | |
338 | LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const { |
339 | return linearBounds(space,primID,dt: time_range); |
340 | } |
341 | }; |
342 | } |
343 | |
344 | DECLARE_ISA_FUNCTION(LineSegments*, createLineSegments, Device* COMMA Geometry::GType); |
345 | } |
346 | |