| 1 | // Copyright 2009-2021 Intel Corporation | 
| 2 | // SPDX-License-Identifier: Apache-2.0 | 
| 3 |  | 
| 4 | #pragma once | 
| 5 |  | 
| 6 | #include "primitive.h" | 
| 7 |  | 
| 8 | namespace 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: itime + 0), bounds(scene, itime: 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(other: 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(i: (unsigned int)i)); | 
| 132 |         allBounds.extend(other: 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(N: set.size()); | 
| 174 |       size_t numbytes = PointMi::bytes(N: 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(N: prims.object_range.size()); | 
| 201 |       size_t numbytes                  = PointMi::bytes(N: 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(other: 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& point) | 
| 214 |     { | 
| 215 |       return cout << "Point"  << M << "i {"  << point.geomID() << ", "  << point.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(a: geom->vertexPtr(i: primID(i: 0))); | 
| 231 |     const vfloat4 a1   = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 1))); | 
| 232 |     const vfloat4 a2   = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 2))); | 
| 233 |     const vfloat4 a3   = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 3))); | 
| 234 |     transpose(r0: a0, r1: a1, r2: a2, r3: a3, c0&: p0.x, c1&: p0.y, c2&: p0.z, c3&: 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(a: geom->vertexPtr(i: primID(i: 0))); | 
| 241 |     const vfloat4 a1   = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 1))); | 
| 242 |     const vfloat4 a2   = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 2))); | 
| 243 |     const vfloat4 a3   = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 3))); | 
| 244 |     transpose(r0: a0, r1: a1, r2: a2, r3: a3, c0&: p0.x, c1&: p0.y, c2&: p0.z, c3&: p0.w); | 
| 245 |     const vfloat4 b0 = vfloat4(geom->normal(i: primID(i: 0))); | 
| 246 |     const vfloat4 b1 = vfloat4(geom->normal(i: primID(i: 1))); | 
| 247 |     const vfloat4 b2 = vfloat4(geom->normal(i: primID(i: 2))); | 
| 248 |     const vfloat4 b3 = vfloat4(geom->normal(i: primID(i: 3))); | 
| 249 |     transpose(r0: b0, r1: b1, r2: b2, r3: b3, c0&: n0.x, c1&: n0.y, c2&: 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(a: geom->vertexPtr(i: primID(i: 0), itime)); | 
| 256 |     const vfloat4 a1 = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 1), itime)); | 
| 257 |     const vfloat4 a2 = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 2), itime)); | 
| 258 |     const vfloat4 a3 = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 3), itime)); | 
| 259 |     transpose(r0: a0, r1: a1, r2: a2, r3: a3, c0&: p0.x, c1&: p0.y, c2&: p0.z, c3&: 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(a: geom->vertexPtr(i: primID(i: 0), itime)); | 
| 266 |     const vfloat4 a1 = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 1), itime)); | 
| 267 |     const vfloat4 a2 = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 2), itime)); | 
| 268 |     const vfloat4 a3 = vfloat4::loadu(a: geom->vertexPtr(i: primID(i: 3), itime)); | 
| 269 |     transpose(r0: a0, r1: a1, r2: a2, r3: a3, c0&: p0.x, c1&: p0.y, c2&: p0.z, c3&: p0.w); | 
| 270 |     const vfloat4 b0 = vfloat4(geom->normal(i: primID(i: 0), itime)); | 
| 271 |     const vfloat4 b1 = vfloat4(geom->normal(i: primID(i: 1), itime)); | 
| 272 |     const vfloat4 b2 = vfloat4(geom->normal(i: primID(i: 2), itime)); | 
| 273 |     const vfloat4 b3 = vfloat4(geom->normal(i: primID(i: 3), itime)); | 
| 274 |     transpose(r0: b0, r1: b1, r2: b2, r3: b3, c0&: n0.x, c1&: n0.y, c2&: 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(p0&: a0, geom, itime); | 
| 284 |     Vec4vf4 b0; gatheri(p0&: b0, geom, itime: itime + 1); | 
| 285 |     p0 = lerp(v0: a0, v1: b0, t: 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(p0&: a0, n0&: norm0, geom, itime); | 
| 297 |     gatheri(p0&: b0, n0&: norm1, geom, itime: itime + 1); | 
| 298 |     p0 = lerp(v0: a0, v1: b0, t: vfloat4(ftime)); | 
| 299 |     n0 = lerp(v0: norm0, v1: norm1, t: 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 |  |