1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "default.h"
7#include "builder.h"
8#include "geometry.h"
9#include "ray.h"
10#include "hit.h"
11
12namespace embree
13{
14 struct IntersectFunctionNArguments;
15 struct OccludedFunctionNArguments;
16
17 struct IntersectFunctionNArguments : public RTCIntersectFunctionNArguments
18 {
19 Geometry* geometry;
20 };
21
22 struct OccludedFunctionNArguments : public RTCOccludedFunctionNArguments
23 {
24 Geometry* geometry;
25 };
26
27 /*! Base class for set of acceleration structures. */
28 class AccelSet : public Geometry
29 {
30 public:
31 typedef RTCIntersectFunctionN IntersectFuncN;
32 typedef RTCOccludedFunctionN OccludedFuncN;
33 typedef void (*ErrorFunc) ();
34
35 struct IntersectorN
36 {
37 IntersectorN (ErrorFunc error = nullptr) ;
38 IntersectorN (IntersectFuncN intersect, OccludedFuncN occluded, const char* name);
39
40 operator bool() const { return name; }
41
42 public:
43 static const char* type;
44 IntersectFuncN intersect;
45 OccludedFuncN occluded;
46 const char* name;
47 };
48
49 public:
50
51 /*! construction */
52 AccelSet (Device* device, Geometry::GType gtype, size_t items, size_t numTimeSteps);
53
54 /*! makes the acceleration structure immutable */
55 virtual void immutable () {}
56
57 /*! build accel */
58 virtual void build () = 0;
59
60 /*! check if the i'th primitive is valid between the specified time range */
61 __forceinline bool valid(size_t i, const range<size_t>& itime_range) const
62 {
63 for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++)
64 if (!isvalid_non_empty(bounds(i,itime))) return false;
65
66 return true;
67 }
68
69 /*! Calculates the bounds of an item */
70 __forceinline BBox3fa bounds(size_t i, size_t itime = 0) const
71 {
72 BBox3fa box;
73 assert(i < size());
74 RTCBoundsFunctionArguments args;
75 args.geometryUserPtr = userPtr;
76 args.primID = (unsigned int)i;
77 args.timeStep = (unsigned int)itime;
78 args.bounds_o = (RTCBounds*)&box;
79 boundsFunc(&args);
80 return box;
81 }
82
83 /*! calculates the linear bounds of the i'th item at the itime'th time segment */
84 __forceinline LBBox3fa linearBounds(size_t i, size_t itime) const
85 {
86 BBox3fa box[2];
87 assert(i < size());
88 RTCBoundsFunctionArguments args;
89 args.geometryUserPtr = userPtr;
90 args.primID = (unsigned int)i;
91 args.timeStep = (unsigned int)(itime+0);
92 args.bounds_o = (RTCBounds*)&box[0];
93 boundsFunc(&args);
94 args.timeStep = (unsigned int)(itime+1);
95 args.bounds_o = (RTCBounds*)&box[1];
96 boundsFunc(&args);
97 return LBBox3fa(box[0],box[1]);
98 }
99
100 /*! calculates the build bounds of the i'th item, if it's valid */
101 __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const
102 {
103 const BBox3fa b = bounds(i);
104 if (bbox) *bbox = b;
105 return isvalid_non_empty(b);
106 }
107
108 /*! calculates the build bounds of the i'th item at the itime'th time segment, if it's valid */
109 __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const
110 {
111 const LBBox3fa bounds = linearBounds(i,itime);
112 bbox = bounds.bounds0; // use bounding box of first timestep to build BVH
113 return isvalid_non_empty(bounds);
114 }
115
116 /*! calculates the linear bounds of the i'th primitive for the specified time range */
117 __forceinline LBBox3fa linearBounds(size_t primID, const BBox1f& dt) const {
118 return LBBox3fa([&] (size_t itime) { return bounds(primID, itime); }, dt, time_range, fnumTimeSegments);
119 }
120
121 /*! calculates the linear bounds of the i'th primitive for the specified time range */
122 __forceinline bool linearBounds(size_t i, const BBox1f& time_range, LBBox3fa& bbox) const {
123 if (!valid(i, timeSegmentRange(time_range))) return false;
124 bbox = linearBounds(i, time_range);
125 return true;
126 }
127
128 /* gets version info of topology */
129 unsigned int getTopologyVersion() const {
130 return numPrimitives;
131 }
132
133 /* returns true if topology changed */
134 bool topologyChanged(unsigned int otherVersion) const {
135 return numPrimitives != otherVersion;
136 }
137
138 public:
139
140 /*! Intersects a single ray with the scene. */
141 __forceinline void intersect (RayHit& ray, unsigned int geomID, unsigned int primID, IntersectContext* context)
142 {
143 assert(primID < size());
144 assert(intersectorN.intersect);
145
146 int mask = -1;
147 IntersectFunctionNArguments args;
148 args.valid = &mask;
149 args.geometryUserPtr = userPtr;
150 args.context = context->user;
151 args.rayhit = (RTCRayHitN*)&ray;
152 args.N = 1;
153 args.geomID = geomID;
154 args.primID = primID;
155 args.geometry = this;
156
157 intersectorN.intersect(&args);
158 }
159
160 /*! Tests if single ray is occluded by the scene. */
161 __forceinline void occluded (Ray& ray, unsigned int geomID, unsigned int primID, IntersectContext* context)
162 {
163 assert(primID < size());
164 assert(intersectorN.occluded);
165
166 int mask = -1;
167 OccludedFunctionNArguments args;
168 args.valid = &mask;
169 args.geometryUserPtr = userPtr;
170 args.context = context->user;
171 args.ray = (RTCRayN*)&ray;
172 args.N = 1;
173 args.geomID = geomID;
174 args.primID = primID;
175 args.geometry = this;
176
177 intersectorN.occluded(&args);
178 }
179
180 /*! Intersects a packet of K rays with the scene. */
181 template<int K>
182 __forceinline void intersect (const vbool<K>& valid, RayHitK<K>& ray, unsigned int geomID, unsigned int primID, IntersectContext* context)
183 {
184 assert(primID < size());
185 assert(intersectorN.intersect);
186
187 vint<K> mask = valid.mask32();
188 IntersectFunctionNArguments args;
189 args.valid = (int*)&mask;
190 args.geometryUserPtr = userPtr;
191 args.context = context->user;
192 args.rayhit = (RTCRayHitN*)&ray;
193 args.N = K;
194 args.geomID = geomID;
195 args.primID = primID;
196 args.geometry = this;
197
198 intersectorN.intersect(&args);
199 }
200
201 /*! Tests if a packet of K rays is occluded by the scene. */
202 template<int K>
203 __forceinline void occluded (const vbool<K>& valid, RayK<K>& ray, unsigned int geomID, unsigned int primID, IntersectContext* context)
204 {
205 assert(primID < size());
206 assert(intersectorN.occluded);
207
208 vint<K> mask = valid.mask32();
209 OccludedFunctionNArguments args;
210 args.valid = (int*)&mask;
211 args.geometryUserPtr = userPtr;
212 args.context = context->user;
213 args.ray = (RTCRayN*)&ray;
214 args.N = K;
215 args.geomID = geomID;
216 args.primID = primID;
217 args.geometry = this;
218
219 intersectorN.occluded(&args);
220 }
221
222 public:
223 RTCBoundsFunction boundsFunc;
224 IntersectorN intersectorN;
225 };
226
227#define DEFINE_SET_INTERSECTORN(symbol,intersector) \
228 AccelSet::IntersectorN symbol() { \
229 return AccelSet::IntersectorN(intersector::intersect, \
230 intersector::occluded, \
231 TOSTRING(isa) "::" TOSTRING(symbol)); \
232 }
233}
234