1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "primitive.h"
7
8namespace embree
9{
10 template<int M>
11 struct PointMi
12 {
13 /* Virtual interface to query information about the line segment type */
14 struct Type : public PrimitiveType
15 {
16 const char* name() const;
17 size_t sizeActive(const char* This) const;
18 size_t sizeTotal(const char* This) const;
19 size_t getBytes(const char* This) const;
20 };
21 static Type type;
22
23 public:
24 /* primitive supports multiple time segments */
25 static const bool singleTimeSegment = false;
26
27 /* Returns maximum number of stored line segments */
28 static __forceinline size_t max_size()
29 {
30 return M;
31 }
32
33 /* Returns required number of primitive blocks for N line segments */
34 static __forceinline size_t blocks(size_t N)
35 {
36 return (N + max_size() - 1) / max_size();
37 }
38
39 /* Returns required number of bytes for N line segments */
40 static __forceinline size_t bytes(size_t N)
41 {
42 return blocks(N) * sizeof(PointMi);
43 }
44
45 public:
46 /* Default constructor */
47 __forceinline PointMi() {}
48
49 /* Construction from vertices and IDs */
50 __forceinline PointMi(const vuint<M>& geomIDs, const vuint<M>& primIDs, Geometry::GType gtype, uint32_t numPrimitives)
51 : gtype((unsigned char)gtype),
52 numPrimitives(numPrimitives),
53 sharedGeomID(geomIDs[0]),
54 primIDs(primIDs)
55 {
56 assert(all(vuint<M>(geomID()) == geomIDs));
57 }
58
59 /* Returns a mask that tells which line segments are valid */
60 __forceinline vbool<M> valid() const {
61 return vint<M>(step) < vint<M>(numPrimitives);
62 }
63
64 /* Returns if the specified line segment is valid */
65 __forceinline bool valid(const size_t i) const
66 {
67 assert(i < M);
68 return i < numPrimitives;
69 }
70
71 /* Returns the number of stored line segments */
72 __forceinline size_t size() const {
73 return numPrimitives;
74 }
75
76 __forceinline unsigned int geomID(unsigned int i = 0) const {
77 return sharedGeomID;
78 }
79
80 __forceinline vuint<M>& primID() {
81 return primIDs;
82 }
83 __forceinline const vuint<M>& primID() const {
84 return primIDs;
85 }
86 __forceinline unsigned int primID(const size_t i) const {
87 assert(i < M);
88 return primIDs[i];
89 }
90
91 /* gather the line segments */
92 __forceinline void gather(Vec4vf<M>& p0, const Points* geom) const;
93 __forceinline void gather(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom) const;
94
95 __forceinline void gatheri(Vec4vf<M>& p0, const Points* geom, const int itime) const;
96 __forceinline void gatheri(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom, const int itime) const;
97
98 __forceinline void gather(Vec4vf<M>& p0, const Points* geom, float time) const;
99 __forceinline void gather(Vec4vf<M>& p0, Vec3vf<M>& n0, const Points* geom, float time) const;
100
101 /* Calculate the bounds of the line segments */
102 __forceinline const BBox3fa bounds(const Scene* scene, size_t itime = 0) const
103 {
104 BBox3fa bounds = empty;
105 for (size_t i = 0; i < M && valid(i); i++) {
106 const Points* geom = scene->get<Points>(geomID(i));
107 bounds.extend(geom->bounds(primID(i),itime));
108 }
109 return bounds;
110 }
111
112 /* Calculate the linear bounds of the primitive */
113 __forceinline LBBox3fa linearBounds(const Scene* scene, size_t itime) {
114 return LBBox3fa(bounds(scene, itime + 0), bounds(scene, itime + 1));
115 }
116
117 __forceinline LBBox3fa linearBounds(const Scene* const scene, size_t itime, size_t numTimeSteps)
118 {
119 LBBox3fa allBounds = empty;
120 for (size_t i = 0; i < M && valid(i); i++) {
121 const Points* geom = scene->get<Points>(geomID(i));
122 allBounds.extend(geom->linearBounds(primID(i), itime, numTimeSteps));
123 }
124 return allBounds;
125 }
126
127 __forceinline LBBox3fa linearBounds(const Scene* const scene, const BBox1f time_range)
128 {
129 LBBox3fa allBounds = empty;
130 for (size_t i = 0; i < M && valid(i); i++) {
131 const Points* geom = scene->get<Points>(geomID((unsigned int)i));
132 allBounds.extend(geom->linearBounds(primID(i), time_range));
133 }
134 return allBounds;
135 }
136
137 /* Fill line segment from line segment list */
138 template<typename PrimRefT>
139 __forceinline void fill(const PrimRefT* prims, size_t& begin, size_t end, Scene* scene)
140 {
141 Geometry::GType gty = scene->get(prims[begin].geomID())->getType();
142 vuint<M> geomID, primID;
143 vuint<M> v0;
144 const PrimRefT* prim = &prims[begin];
145
146 int numPrimitives = 0;
147 for (size_t i = 0; i < M; i++) {
148 if (begin < end) {
149 geomID[i] = prim->geomID();
150 primID[i] = prim->primID();
151 begin++;
152 numPrimitives++;
153 } else {
154 assert(i);
155 if (i > 0) {
156 geomID[i] = geomID[i - 1];
157 primID[i] = primID[i - 1];
158 }
159 }
160 if (begin < end)
161 prim = &prims[begin]; // FIXME: remove this line
162 }
163 new (this) PointMi(geomID, primID, gty, numPrimitives); // FIXME: use non temporal store
164 }
165
166 template<typename BVH, typename Allocator>
167 __forceinline static typename BVH::NodeRef createLeaf(BVH* bvh,
168 const PrimRef* prims,
169 const range<size_t>& set,
170 const Allocator& alloc)
171 {
172 size_t start = set.begin();
173 size_t items = PointMi::blocks(set.size());
174 size_t numbytes = PointMi::bytes(set.size());
175 PointMi* accel = (PointMi*)alloc.malloc1(numbytes, M * sizeof(float));
176 for (size_t i = 0; i < items; i++) {
177 accel[i].fill(prims, start, set.end(), bvh->scene);
178 }
179 return bvh->encodeLeaf((char*)accel, items);
180 };
181
182 __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& begin, size_t end, Scene* scene, size_t itime)
183 {
184 fill(prims, begin, end, scene);
185 return linearBounds(scene, itime);
186 }
187
188 __forceinline LBBox3fa fillMB(
189 const PrimRefMB* prims, size_t& begin, size_t end, Scene* scene, const BBox1f time_range)
190 {
191 fill(prims, begin, end, scene);
192 return linearBounds(scene, time_range);
193 }
194
195 template<typename BVH, typename SetMB, typename Allocator>
196 __forceinline static typename BVH::NodeRecordMB4D createLeafMB(BVH* bvh, const SetMB& prims, const Allocator& alloc)
197 {
198 size_t start = prims.object_range.begin();
199 size_t end = prims.object_range.end();
200 size_t items = PointMi::blocks(prims.object_range.size());
201 size_t numbytes = PointMi::bytes(prims.object_range.size());
202 PointMi* accel = (PointMi*)alloc.malloc1(numbytes, M * sizeof(float));
203 const typename BVH::NodeRef node = bvh->encodeLeaf((char*)accel, items);
204
205 LBBox3fa bounds = empty;
206 for (size_t i = 0; i < items; i++)
207 bounds.extend(accel[i].fillMB(prims.prims->data(), start, end, bvh->scene, prims.time_range));
208
209 return typename BVH::NodeRecordMB4D(node, bounds, prims.time_range);
210 };
211
212 /*! output operator */
213 friend __forceinline embree_ostream operator<<(embree_ostream cout, const PointMi& line)
214 {
215 return cout << "Line" << M << "i {" << line.v0 << ", " << line.geomID() << ", " << line.primID() << "}";
216 }
217
218 public:
219 unsigned char gtype;
220 unsigned char numPrimitives;
221 unsigned int sharedGeomID;
222
223 private:
224 vuint<M> primIDs; // primitive ID
225 };
226
227 template<>
228 __forceinline void PointMi<4>::gather(Vec4vf4& p0, const Points* geom) const
229 {
230 const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
231 const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
232 const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
233 const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
234 transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
235 }
236
237 template<>
238 __forceinline void PointMi<4>::gather(Vec4vf4& p0, Vec3vf4& n0, const Points* geom) const
239 {
240 const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
241 const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
242 const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
243 const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
244 transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
245 const vfloat4 b0 = vfloat4(geom->normal(primID(0)));
246 const vfloat4 b1 = vfloat4(geom->normal(primID(1)));
247 const vfloat4 b2 = vfloat4(geom->normal(primID(2)));
248 const vfloat4 b3 = vfloat4(geom->normal(primID(3)));
249 transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z);
250 }
251
252 template<>
253 __forceinline void PointMi<4>::gatheri(Vec4vf4& p0, const Points* geom, const int itime) const
254 {
255 const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
256 const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
257 const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
258 const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
259 transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
260 }
261
262 template<>
263 __forceinline void PointMi<4>::gatheri(Vec4vf4& p0, Vec3vf4& n0, const Points* geom, const int itime) const
264 {
265 const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
266 const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
267 const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
268 const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
269 transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w);
270 const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime));
271 const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime));
272 const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime));
273 const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime));
274 transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z);
275 }
276
277 template<>
278 __forceinline void PointMi<4>::gather(Vec4vf4& p0, const Points* geom, float time) const
279 {
280 float ftime;
281 const int itime = geom->timeSegment(time, ftime);
282
283 Vec4vf4 a0; gatheri(a0, geom, itime);
284 Vec4vf4 b0; gatheri(b0, geom, itime + 1);
285 p0 = lerp(a0, b0, vfloat4(ftime));
286 }
287
288 template<>
289 __forceinline void PointMi<4>::gather(Vec4vf4& p0, Vec3vf4& n0, const Points* geom, float time) const
290 {
291 float ftime;
292 const int itime = geom->timeSegment(time, ftime);
293
294 Vec4vf4 a0, b0;
295 Vec3vf4 norm0, norm1;
296 gatheri(a0, norm0, geom, itime);
297 gatheri(b0, norm1, geom, itime + 1);
298 p0 = lerp(a0, b0, vfloat4(ftime));
299 n0 = lerp(norm0, norm1, vfloat4(ftime));
300 }
301
302#if defined(__AVX__)
303
304 template<>
305 __forceinline void PointMi<8>::gather(Vec4vf8& p0, const Points* geom) const
306 {
307 const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
308 const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
309 const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
310 const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
311 const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4)));
312 const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5)));
313 const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6)));
314 const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7)));
315 transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
316 }
317
318 template<>
319 __forceinline void PointMi<8>::gather(Vec4vf8& p0, Vec3vf8& n0, const Points* geom) const
320 {
321 const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0)));
322 const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1)));
323 const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2)));
324 const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3)));
325 const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4)));
326 const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5)));
327 const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6)));
328 const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7)));
329 transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
330 const vfloat4 b0 = vfloat4(geom->normal(primID(0)));
331 const vfloat4 b1 = vfloat4(geom->normal(primID(1)));
332 const vfloat4 b2 = vfloat4(geom->normal(primID(2)));
333 const vfloat4 b3 = vfloat4(geom->normal(primID(3)));
334 const vfloat4 b4 = vfloat4(geom->normal(primID(4)));
335 const vfloat4 b5 = vfloat4(geom->normal(primID(5)));
336 const vfloat4 b6 = vfloat4(geom->normal(primID(6)));
337 const vfloat4 b7 = vfloat4(geom->normal(primID(7)));
338 transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z);
339 }
340
341 template<>
342 __forceinline void PointMi<8>::gatheri(Vec4vf8& p0, const Points* geom, const int itime) const
343 {
344 const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
345 const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
346 const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
347 const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
348 const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4), itime));
349 const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5), itime));
350 const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime));
351 const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime));
352 transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
353 }
354
355 template<>
356 __forceinline void PointMi<8>::gatheri(Vec4vf8& p0, Vec3vf8& n0, const Points* geom, const int itime) const
357 {
358 const vfloat4 a0 = vfloat4::loadu(geom->vertexPtr(primID(0), itime));
359 const vfloat4 a1 = vfloat4::loadu(geom->vertexPtr(primID(1), itime));
360 const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime));
361 const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime));
362 const vfloat4 a4 = vfloat4::loadu(geom->vertexPtr(primID(4), itime));
363 const vfloat4 a5 = vfloat4::loadu(geom->vertexPtr(primID(5), itime));
364 const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime));
365 const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime));
366 transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w);
367 const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime));
368 const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime));
369 const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime));
370 const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime));
371 const vfloat4 b4 = vfloat4(geom->normal(primID(4), itime));
372 const vfloat4 b5 = vfloat4(geom->normal(primID(5), itime));
373 const vfloat4 b6 = vfloat4(geom->normal(primID(6), itime));
374 const vfloat4 b7 = vfloat4(geom->normal(primID(7), itime));
375 transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z);
376 }
377
378 template<>
379 __forceinline void PointMi<8>::gather(Vec4vf8& p0, const Points* geom, float time) const
380 {
381 float ftime;
382 const int itime = geom->timeSegment(time, ftime);
383
384 Vec4vf8 a0;
385 gatheri(a0, geom, itime);
386 Vec4vf8 b0;
387 gatheri(b0, geom, itime + 1);
388 p0 = lerp(a0, b0, vfloat8(ftime));
389 }
390
391 template<>
392 __forceinline void PointMi<8>::gather(Vec4vf8& p0, Vec3vf8& n0, const Points* geom, float time) const
393 {
394 float ftime;
395 const int itime = geom->timeSegment(time, ftime);
396
397 Vec4vf8 a0, b0;
398 Vec3vf8 norm0, norm1;
399 gatheri(a0, norm0, geom, itime);
400 gatheri(b0, norm1, geom, itime + 1);
401 p0 = lerp(a0, b0, vfloat8(ftime));
402 n0 = lerp(norm0, norm1, vfloat8(ftime));
403 }
404#endif
405
406 template<int M>
407 typename PointMi<M>::Type PointMi<M>::type;
408
409 typedef PointMi<4> Point4i;
410 typedef PointMi<8> Point8i;
411
412} // namespace embree
413