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 /* Precalculated representation for M triangles. Stores for each
11 triangle a base vertex, two edges, and the geometry normal to
12 speed up intersection calculations */
13 template<int M>
14 struct TriangleM
15 {
16 public:
17 struct Type : public PrimitiveType
18 {
19 const char* name() const;
20 size_t sizeActive(const char* This) const;
21 size_t sizeTotal(const char* This) const;
22 size_t getBytes(const char* This) const;
23 };
24 static Type type;
25
26 public:
27
28 /* Returns maximum number of stored triangles */
29 static __forceinline size_t max_size() { return M; }
30
31 /* Returns required number of primitive blocks for N primitives */
32 static __forceinline size_t blocks(size_t N) { return (N+max_size()-1)/max_size(); }
33
34 public:
35
36 /* Default constructor */
37 __forceinline TriangleM() {}
38
39 /* Construction from vertices and IDs */
40 __forceinline TriangleM(const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const vuint<M>& geomIDs, const vuint<M>& primIDs)
41 : v0(v0), e1(v0-v1), e2(v2-v0), geomIDs(geomIDs), primIDs(primIDs) {}
42
43 /* Returns a mask that tells which triangles are valid */
44 __forceinline vbool<M> valid() const { return geomIDs != vuint<M>(-1); }
45
46 /* Returns true if the specified triangle is valid */
47 __forceinline bool valid(const size_t i) const { assert(i<M); return geomIDs[i] != -1; }
48
49 /* Returns the number of stored triangles */
50 __forceinline size_t size() const { return bsf(~movemask(valid())); }
51
52 /* Returns the geometry IDs */
53 __forceinline vuint<M>& geomID() { return geomIDs; }
54 __forceinline const vuint<M>& geomID() const { return geomIDs; }
55 __forceinline unsigned int geomID(const size_t i) const { assert(i<M); return geomIDs[i]; }
56
57 /* Returns the primitive IDs */
58 __forceinline vuint<M>& primID() { return primIDs; }
59 __forceinline const vuint<M>& primID() const { return primIDs; }
60 __forceinline unsigned int primID(const size_t i) const { assert(i<M); return primIDs[i]; }
61
62 /* Calculate the bounds of the triangle */
63 __forceinline BBox3fa bounds() const
64 {
65 Vec3vf<M> p0 = v0;
66 Vec3vf<M> p1 = v0-e1;
67 Vec3vf<M> p2 = v0+e2;
68 Vec3vf<M> lower = min(p0,p1,p2);
69 Vec3vf<M> upper = max(p0,p1,p2);
70 vbool<M> mask = valid();
71 lower.x = select(mask,lower.x,vfloat<M>(pos_inf));
72 lower.y = select(mask,lower.y,vfloat<M>(pos_inf));
73 lower.z = select(mask,lower.z,vfloat<M>(pos_inf));
74 upper.x = select(mask,upper.x,vfloat<M>(neg_inf));
75 upper.y = select(mask,upper.y,vfloat<M>(neg_inf));
76 upper.z = select(mask,upper.z,vfloat<M>(neg_inf));
77 return BBox3fa(Vec3fa(reduce_min(lower.x),reduce_min(lower.y),reduce_min(lower.z)),
78 Vec3fa(reduce_max(upper.x),reduce_max(upper.y),reduce_max(upper.z)));
79 }
80
81 /* Non temporal store */
82 __forceinline static void store_nt(TriangleM* dst, const TriangleM& src)
83 {
84 vfloat<M>::store_nt(&dst->v0.x,src.v0.x);
85 vfloat<M>::store_nt(&dst->v0.y,src.v0.y);
86 vfloat<M>::store_nt(&dst->v0.z,src.v0.z);
87 vfloat<M>::store_nt(&dst->e1.x,src.e1.x);
88 vfloat<M>::store_nt(&dst->e1.y,src.e1.y);
89 vfloat<M>::store_nt(&dst->e1.z,src.e1.z);
90 vfloat<M>::store_nt(&dst->e2.x,src.e2.x);
91 vfloat<M>::store_nt(&dst->e2.y,src.e2.y);
92 vfloat<M>::store_nt(&dst->e2.z,src.e2.z);
93 vuint<M>::store_nt(&dst->geomIDs,src.geomIDs);
94 vuint<M>::store_nt(&dst->primIDs,src.primIDs);
95 }
96
97 /* Fill triangle from triangle list */
98 __forceinline void fill(const PrimRef* prims, size_t& begin, size_t end, Scene* scene)
99 {
100 vuint<M> vgeomID = -1, vprimID = -1;
101 Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
102
103 for (size_t i=0; i<M && begin<end; i++, begin++)
104 {
105 const PrimRef& prim = prims[begin];
106 const unsigned geomID = prim.geomID();
107 const unsigned primID = prim.primID();
108 const TriangleMesh* __restrict__ const mesh = scene->get<TriangleMesh>(geomID);
109 const TriangleMesh::Triangle& tri = mesh->triangle(primID);
110 const Vec3fa& p0 = mesh->vertex(tri.v[0]);
111 const Vec3fa& p1 = mesh->vertex(tri.v[1]);
112 const Vec3fa& p2 = mesh->vertex(tri.v[2]);
113 vgeomID [i] = geomID;
114 vprimID [i] = primID;
115 v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
116 v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
117 v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
118 }
119 TriangleM::store_nt(this,TriangleM(v0,v1,v2,vgeomID,vprimID));
120 }
121
122 /* Updates the primitive */
123 __forceinline BBox3fa update(TriangleMesh* mesh)
124 {
125 BBox3fa bounds = empty;
126 vuint<M> vgeomID = -1, vprimID = -1;
127 Vec3vf<M> v0 = zero, v1 = zero, v2 = zero;
128
129 for (size_t i=0; i<M; i++)
130 {
131 if (unlikely(geomID(i) == -1)) break;
132 const unsigned geomId = geomID(i);
133 const unsigned primId = primID(i);
134 const TriangleMesh::Triangle& tri = mesh->triangle(primId);
135 const Vec3fa p0 = mesh->vertex(tri.v[0]);
136 const Vec3fa p1 = mesh->vertex(tri.v[1]);
137 const Vec3fa p2 = mesh->vertex(tri.v[2]);
138 bounds.extend(merge(BBox3fa(p0),BBox3fa(p1),BBox3fa(p2)));
139 vgeomID [i] = geomId;
140 vprimID [i] = primId;
141 v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
142 v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
143 v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
144 }
145 TriangleM::store_nt(this,TriangleM(v0,v1,v2,vgeomID,vprimID));
146 return bounds;
147 }
148
149 public:
150 Vec3vf<M> v0; // base vertex of the triangles
151 Vec3vf<M> e1; // 1st edge of the triangles (v0-v1)
152 Vec3vf<M> e2; // 2nd edge of the triangles (v2-v0)
153 private:
154 vuint<M> geomIDs; // geometry IDs
155 vuint<M> primIDs; // primitive IDs
156 };
157
158 template<int M>
159 typename TriangleM<M>::Type TriangleM<M>::type;
160
161 typedef TriangleM<4> Triangle4;
162}
163