1 /*
2 The MIT License (MIT)
3
4 Copyright (c) 2015 - 2017 Light Transport Entertainment, Inc.
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 */
24
25 #ifdef __clang__
26 #pragma clang diagnostic push
27 #pragma clang diagnostic ignored "-Wold-style-cast"
28 #pragma clang diagnostic ignored "-Wreserved-id-macro"
29 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
30 #pragma clang diagnostic ignored "-Wcast-align"
31 #pragma clang diagnostic ignored "-Wpadded"
32 #pragma clang diagnostic ignored "-Wold-style-cast"
33 #pragma clang diagnostic ignored "-Wsign-conversion"
34 #pragma clang diagnostic ignored "-Wvariadic-macros"
35 #pragma clang diagnostic ignored "-Wc++11-extensions"
36 #pragma clang diagnostic ignored "-Wexit-time-destructors"
37 #if __has_warning("-Wcast-qual")
38 #pragma clang diagnostic ignored "-Wcast-qual"
39 #endif
40 #if __has_warning("-Wzero-as-null-pointer-constant")
41 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
42 #endif
43 #endif
44
45 #ifdef _MSC_VER
46 #pragma warning(push)
47 #pragma warning(disable : 4324)
48 #endif
49
50 #ifdef _WIN32
51 # define RTCORE_API extern "C" __declspec(dllexport)
52 #else
53 # define RTCORE_API extern "C" __attribute__ ((visibility ("default")))
54 #endif
55
56 #include "embree2/rtcore.h"
57 #include "embree2/rtcore_ray.h"
58
59 #ifdef __clang__
60 #pragma clang diagnostic pop
61 #endif
62
63 #ifdef _MSC_VER
64 #pragma warning(pop)
65 #endif
66
67 #include <cassert>
68 #include <map>
69 #include <sstream>
70 #include <string>
71 #include <vector>
72
73 #include "nanosg.h"
74
75 #include <stdint.h> // Use cstint for C++11 compiler.
76
77 namespace nanort_embree2 {
78
79 #ifdef __clang__
80 #if __has_warning("-Wzero-as-null-pointer-constant")
81 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
82 #endif
83 #endif
84
85 template <typename T>
lerp(T dst[3],const T v0[3],const T v1[3],const T v2[3],float u,float v)86 inline void lerp(T dst[3], const T v0[3], const T v1[3], const T v2[3], float u,
87 float v) {
88 dst[0] = (static_cast<T>(1.0) - u - v) * v0[0] + u * v1[0] + v * v2[0];
89 dst[1] = (static_cast<T>(1.0) - u - v) * v0[1] + u * v1[1] + v * v2[1];
90 dst[2] = (static_cast<T>(1.0) - u - v) * v0[2] + u * v1[2] + v * v2[2];
91 }
92
93 template <typename T>
vlength(const T v[3])94 inline T vlength(const T v[3]) {
95 const T d = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
96 if (std::fabs(d) > std::numeric_limits<T>::epsilon()) {
97 return std::sqrt(d);
98 } else {
99 return static_cast<T>(0.0);
100 }
101 }
102
103 template <typename T>
vnormalize(T dst[3],const T v[3])104 inline void vnormalize(T dst[3], const T v[3]) {
105 dst[0] = v[0];
106 dst[1] = v[1];
107 dst[2] = v[2];
108 const T len = vlength(v);
109 if (std::fabs(len) > std::numeric_limits<T>::epsilon()) {
110 const T inv_len = static_cast<T>(1.0) / len;
111 dst[0] *= inv_len;
112 dst[1] *= inv_len;
113 dst[2] *= inv_len;
114 }
115 }
116
117 template <typename T>
vcross(T dst[3],const T a[3],const T b[3])118 inline void vcross(T dst[3], const T a[3], const T b[3]) {
119 dst[0] = a[1] * b[2] - a[2] * b[1];
120 dst[1] = a[2] * b[0] - a[0] * b[2];
121 dst[2] = a[0] * b[1] - a[1] * b[0];
122 }
123
124 template <typename T>
vsub(T dst[3],const T a[3],const T b[3])125 inline void vsub(T dst[3], const T a[3], const T b[3]) {
126 dst[0] = a[0] - b[0];
127 dst[1] = a[1] - b[1];
128 dst[2] = a[2] - b[2];
129 }
130
131 template <typename T>
calculate_normal(T Nn[3],const T v0[3],const T v1[3],const T v2[3])132 inline void calculate_normal(T Nn[3], const T v0[3], const T v1[3],
133 const T v2[3]) {
134 T v10[3];
135 T v20[3];
136
137 vsub(v10, v1, v0);
138 vsub(v20, v2, v0);
139
140 T N[3];
141 vcross(N, v10, v20); // CCW
142 // vcross(N, v20, v10); // CC
143 vnormalize(Nn, N);
144 }
145
146 template <typename T = float>
147 class TriMesh {
148 public:
TriMesh(const size_t num_triangles,const size_t num_vertices)149 explicit TriMesh(const size_t num_triangles, const size_t num_vertices) {
150 // Embree uses 16 bytes stride
151 stride = sizeof(float) * 4;
152 vertices.resize(num_vertices * 4);
153 faces.resize(num_triangles * 3);
154 }
155
~TriMesh()156 ~TriMesh() {}
157
158 std::string name;
159
160 size_t stride;
161 std::vector<T> vertices; /// [xyz] * num_vertices
162 std::vector<unsigned int> faces; /// triangle x num_faces
163
164 T pivot_xform[4][4];
165
166 // --- Required methods in Scene::Traversal. ---
167
168 ///
169 /// Get the geometric normal and the shading normal at `face_idx' th face.
170 ///
GetNormal(T Ng[3],T Ns[3],const unsigned int face_idx,const T u,const T v) const171 void GetNormal(T Ng[3], T Ns[3], const unsigned int face_idx, const T u,
172 const T v) const {
173 (void)u;
174 (void)v;
175
176 // Compute geometric normal.
177 unsigned int f0, f1, f2;
178 T v0[3], v1[3], v2[3];
179
180 f0 = faces[3 * face_idx + 0];
181 f1 = faces[3 * face_idx + 1];
182 f2 = faces[3 * face_idx + 2];
183
184 v0[0] = vertices[3 * f0 + 0];
185 v0[1] = vertices[3 * f0 + 1];
186 v0[2] = vertices[3 * f0 + 2];
187
188 v1[0] = vertices[3 * f1 + 0];
189 v1[1] = vertices[3 * f1 + 1];
190 v1[2] = vertices[3 * f1 + 2];
191
192 v2[0] = vertices[3 * f2 + 0];
193 v2[1] = vertices[3 * f2 + 1];
194 v2[2] = vertices[3 * f2 + 2];
195
196 calculate_normal(Ng, v0, v1, v2);
197
198 // Use geometric normal.
199 Ns[0] = Ng[0];
200 Ns[1] = Ng[1];
201 Ns[2] = Ng[2];
202 }
203
204 // --- end of required methods in Scene::Traversal. ---
205 };
206
207 ///
208 /// Simple handle resource management.
209 ///
210 class HandleAllocator {
211 public:
212 // id = 0 is reserved.
HandleAllocator()213 HandleAllocator() : counter_(1) { (void)_pad_; }
~HandleAllocator()214 ~HandleAllocator() {}
215
216 ///
217 /// Allocates handle object.
218 ///
Allocate()219 uint32_t Allocate() {
220 uint32_t handle = 0;
221
222 if (!freeList_.empty()) {
223 // Reuse previously issued handle.
224 handle = freeList_.back();
225 freeList_.pop_back();
226 return handle;
227 }
228
229 handle = counter_;
230 assert(handle >= 1);
231 assert(handle < 0xFFFFFFFF);
232
233 counter_++;
234
235 return handle;
236 }
237
238 /// Release handle object.
Release(uint32_t handle)239 void Release(uint32_t handle) {
240 if (handle == counter_ - 1) {
241 if (counter_ > 1) {
242 counter_--;
243 }
244 } else {
245 assert(handle >= 1);
246 freeList_.push_back(handle);
247 }
248 }
249
250 private:
251 std::vector<uint32_t> freeList_;
252 uint32_t counter_;
253 uint32_t _pad_;
254 };
255
256 class Scene {
257 public:
Scene(RTCSceneFlags sflags,RTCAlgorithmFlags aflags)258 Scene(RTCSceneFlags sflags, RTCAlgorithmFlags aflags)
259 : scene_flags_(sflags), algorithm_flags_(aflags) {
260 (void)scene_flags_;
261 (void)algorithm_flags_;
262 }
263
~Scene()264 ~Scene() {
265 std::map<uint32_t, TriMesh<float> *>::iterator it(trimesh_map_.begin());
266 std::map<uint32_t, TriMesh<float> *>::iterator itEnd(trimesh_map_.end());
267
268 for (; it != itEnd; it++) {
269 delete it->second;
270 }
271 }
272
273 ///
274 /// Get scene bounding box.
275 ///
GetBounds(RTCBounds & bounds)276 void GetBounds(RTCBounds &bounds) {
277 float bmin[3], bmax[3];
278 trimesh_scene_.GetBoundingBox(bmin, bmax);
279 bounds.lower_x = bmin[0];
280 bounds.lower_y = bmin[1];
281 bounds.lower_z = bmin[2];
282
283 bounds.upper_x = bmax[0];
284 bounds.upper_y = bmax[1];
285 bounds.upper_z = bmax[2];
286 }
287
288 ///
289 ///
290 ///
NewTriMesh(size_t num_triangles,size_t num_vertices)291 uint32_t NewTriMesh(size_t num_triangles, size_t num_vertices) {
292 uint32_t geom_id = geom_ids_.Allocate();
293
294 TriMesh<float> *trimesh = new TriMesh<float>(num_triangles, num_vertices);
295
296 trimesh_map_[geom_id] = trimesh;
297
298 return geom_id;
299 }
300
GetTriMesh(const uint32_t geom_id)301 TriMesh<float> *GetTriMesh(const uint32_t geom_id) {
302 if (trimesh_map_.find(geom_id) != trimesh_map_.end()) {
303 return trimesh_map_[geom_id];
304 }
305 return NULL;
306 }
307
NumShapes()308 size_t NumShapes() { return trimesh_map_.size(); }
309
Build()310 void Build() {
311 std::map<uint32_t, TriMesh<float> *>::iterator it(trimesh_map_.begin());
312 std::map<uint32_t, TriMesh<float> *>::iterator itEnd(trimesh_map_.end());
313
314 for (; it != itEnd; it++) {
315 nanosg::Node<float, TriMesh<float> > node(it->second);
316
317 trimesh_scene_.AddNode(node);
318 }
319
320 trimesh_scene_.Commit();
321 }
322
Intersect(nanort::Ray<float> & ray,nanosg::Intersection<float> * isect_out,const bool cull_back_face)323 bool Intersect(nanort::Ray<float> &ray,
324 nanosg::Intersection<float> *isect_out,
325 const bool cull_back_face) {
326 return trimesh_scene_.Traverse(ray, isect_out, cull_back_face);
327 }
328
329 private:
330 RTCSceneFlags scene_flags_;
331 RTCAlgorithmFlags algorithm_flags_;
332 HandleAllocator geom_ids_;
333
334 nanosg::Scene<float, TriMesh<float> > trimesh_scene_;
335 std::vector<nanosg::Node<float, TriMesh<float> > > trimesh_nodes_;
336
337 // Records triangle mesh for geom_id
338 std::map<uint32_t, TriMesh<float> *> trimesh_map_;
339 };
340
341 class Device {
342 public:
Device(const std::string & config)343 Device(const std::string &config)
344 : config_(config), error_func_(NULL), user_ptr_(NULL) {}
345
~Device()346 ~Device() {}
347
SetErrorFunction(RTCErrorFunc2 func,void * user_ptr)348 void SetErrorFunction(RTCErrorFunc2 func, void *user_ptr) {
349 error_func_ = func;
350 user_ptr_ = user_ptr;
351 }
352
AddScene(Scene * scene)353 void AddScene(Scene *scene) { scene_map_[scene] = scene; }
354
DeleteScene(Scene * scene)355 bool DeleteScene(Scene *scene) {
356 if (scene_map_.find(scene) != scene_map_.end()) {
357 std::map<const Scene *, Scene *>::iterator it = scene_map_.find(scene);
358
359 scene_map_.erase(it);
360
361 delete scene;
362 return true;
363 }
364
365 return false;
366 }
367
368 private:
369 std::string config_;
370
371 std::map<const Scene *, Scene *> scene_map_;
372
373 // Callbacks
374 RTCErrorFunc2 error_func_;
375 void *user_ptr_;
376 };
377
378 class Context {
379 public:
Context()380 Context() {}
~Context()381 ~Context() {
382 std::map<const Device *, Device *>::iterator it(device_map_.begin());
383 std::map<const Device *, Device *>::iterator itEnd(device_map_.end());
384
385 for (; it != itEnd; it++) {
386 delete it->second;
387 it->second = NULL;
388 }
389 }
390
NewDevice(const char * config)391 Device *NewDevice(const char *config) {
392 std::string cfg;
393 if (config) {
394 cfg = std::string(config);
395 }
396
397 Device *device = new Device(cfg);
398
399 device_map_[device] = device;
400
401 return device;
402 }
403
DeleteDevice(Device * device)404 bool DeleteDevice(Device *device) {
405 if (device_map_.find(device) != device_map_.end()) {
406 std::map<const Device *, Device *>::iterator it =
407 device_map_.find(device);
408 device_map_.erase(it);
409
410 delete device;
411 return true;
412 }
413 return false;
414 }
415
DeleteScene(Scene * scene)416 bool DeleteScene(Scene *scene) {
417 // Assume scene is assigned to the device uniquely
418 std::map<const Device *, Device *>::iterator it(device_map_.begin());
419 std::map<const Device *, Device *>::iterator itEnd(device_map_.end());
420
421 for (; it != itEnd; it++) {
422 if (it->second->DeleteScene(scene)) {
423 return true;
424 }
425 }
426
427 return false;
428 }
429
SetError(const std::string & err)430 void SetError(const std::string &err) { error_ = err; }
431
432 private:
433 std::string error_;
434 std::map<const Device *, Device *> device_map_;
435 };
436
437 #ifdef __clang__
438 #pragma clang diagnostic push
439 #pragma clang diagnostic ignored "-Wexit-time-destructors"
440 #endif
441
GetContext()442 static Context &GetContext() {
443 static Context s_ctx;
444
445 return s_ctx;
446 }
447
448 #ifdef __clang__
449 #pragma clang diagnostic pop
450 #endif
451
452 // TODO(LTE): Lock to avoid thread-racing.
453
rtcNewDevice(const char * cfg=NULL)454 RTCORE_API RTCDevice rtcNewDevice(const char *cfg = NULL) {
455 Device *device = GetContext().NewDevice(cfg);
456
457 return reinterpret_cast<RTCDevice>(device);
458 }
459
rtcDeleteScene(RTCScene scene)460 RTCORE_API void rtcDeleteScene(RTCScene scene) {
461 Scene *s = reinterpret_cast<Scene *>(scene);
462
463 bool ret = GetContext().DeleteScene(s);
464
465 if (!ret) {
466 std::stringstream ss;
467 ss << "Invalid scene : " << scene << std::endl;
468 GetContext().SetError(ss.str());
469 }
470 }
471
rtcDeleteDevice(RTCDevice device)472 RTCORE_API void rtcDeleteDevice(RTCDevice device) {
473 #if 0
474 (void)device;
475 std::cout << "TODO: Implement rtcDeleteScene()" << std::endl;
476 #else
477 Device *dev = reinterpret_cast<Device *>(device);
478
479 bool ret = GetContext().DeleteDevice(dev);
480
481 if (!ret) {
482 std::stringstream ss;
483 ss << "Invalid device : " << device << std::endl;
484 GetContext().SetError(ss.str());
485 }
486 #endif
487 }
488
rtcDeviceSetErrorFunction2(RTCDevice device,RTCErrorFunc2 func,void * userPtr)489 RTCORE_API void rtcDeviceSetErrorFunction2(RTCDevice device, RTCErrorFunc2 func,
490 void *userPtr) {
491 Device *ptr = reinterpret_cast<Device *>(device);
492 ptr->SetErrorFunction(func, userPtr);
493 }
494
rtcDeviceNewScene(RTCDevice device,RTCSceneFlags flags,RTCAlgorithmFlags aflags)495 RTCORE_API RTCScene rtcDeviceNewScene(RTCDevice device, RTCSceneFlags flags,
496 RTCAlgorithmFlags aflags) {
497 Scene *scene = new Scene(flags, aflags);
498
499 Device *d = reinterpret_cast<Device *>(device);
500 d->AddScene(scene);
501
502 return reinterpret_cast<RTCScene>(scene);
503 }
504
rtcGetBounds(RTCScene scene,RTCBounds & bounds_o)505 RTCORE_API void rtcGetBounds(RTCScene scene, RTCBounds &bounds_o) {
506 Scene *s = reinterpret_cast<Scene *>(scene);
507 s->GetBounds(bounds_o);
508 }
509
510 #ifdef __clang__
511 #pragma clang diagnostic push
512 #pragma clang diagnostic ignored "-Wold-style-cast"
513 #endif
514
rtcIntersect(RTCScene scene,RTCRay & rtc_ray)515 RTCORE_API void rtcIntersect(RTCScene scene, RTCRay &rtc_ray) {
516 Scene *s = reinterpret_cast<Scene *>(scene);
517
518 nanort::Ray<float> ray;
519
520 ray.org[0] = rtc_ray.org[0];
521 ray.org[1] = rtc_ray.org[1];
522 ray.org[2] = rtc_ray.org[2];
523
524 ray.dir[0] = rtc_ray.dir[0];
525 ray.dir[1] = rtc_ray.dir[1];
526 ray.dir[2] = rtc_ray.dir[2];
527
528 // TODO(LTE): .time, .mask
529
530 ray.min_t = rtc_ray.tnear;
531 ray.max_t = rtc_ray.tfar;
532
533 nanosg::Intersection<float> isect;
534 // FIXME(LTE): Read RTC_CONFIG_BACKFACE_CULLING from Embree configuration
535 const bool cull_back_face = false;
536 const bool hit = s->Intersect(ray, &isect, cull_back_face);
537
538 // Overwrite members.
539 if (hit) {
540 rtc_ray.tfar = isect.t;
541 rtc_ray.u = isect.u;
542 rtc_ray.v = isect.v;
543 rtc_ray.geomID = isect.node_id;
544 rtc_ray.primID = isect.prim_id;
545 rtc_ray.instID =
546 RTC_INVALID_GEOMETRY_ID; // Instancing is not yet supported.
547 } else {
548 rtc_ray.geomID = RTC_INVALID_GEOMETRY_ID;
549 rtc_ray.primID = RTC_INVALID_GEOMETRY_ID;
550 rtc_ray.instID = RTC_INVALID_GEOMETRY_ID;
551 }
552
553 (void)ray;
554 }
555
556 #ifdef __clang__
557 #pragma clang diagnostic pop
558 #endif
559
rtcNewTriangleMesh(RTCScene scene,RTCGeometryFlags flags,size_t numTriangles,size_t numVertices,size_t numTimeSteps=1)560 RTCORE_API unsigned rtcNewTriangleMesh(
561 RTCScene scene, //!< the scene the mesh belongs to
562 RTCGeometryFlags flags, //!< geometry flags
563 size_t numTriangles, //!< number of triangles
564 size_t numVertices, //!< number of vertices
565 size_t numTimeSteps = 1 //!< number of motion blur time steps
566 ) {
567 if (numTimeSteps != 1) {
568 std::stringstream ss;
569 ss << "[rtcNewTriMesh] Motion blur is not supported. numTimeSteps : "
570 << numTimeSteps << std::endl;
571 GetContext().SetError(ss.str());
572 return 0;
573 }
574
575 if (numTriangles < 1) {
576 std::stringstream ss;
577 ss << "[rtcNewTriMesh] Invalid numTriangles : " << numTriangles
578 << std::endl;
579 GetContext().SetError(ss.str());
580 return 0;
581 }
582
583 if (numVertices < 1) {
584 std::stringstream ss;
585 ss << "[rtcNewTriMesh] Invalid numVertices : " << numVertices << std::endl;
586 GetContext().SetError(ss.str());
587 return 0;
588 }
589
590 // TODO(LTE): Acquire lock?
591 Scene *s = reinterpret_cast<Scene *>(scene);
592 assert(s);
593 const uint32_t geom_id = s->NewTriMesh(numTriangles, numVertices);
594
595 // TODO(LTE): Support flags.
596 (void)flags;
597
598 return geom_id;
599 }
600
rtcMapBuffer(RTCScene scene,unsigned geomID,RTCBufferType type)601 RTCORE_API void *rtcMapBuffer(RTCScene scene, unsigned geomID,
602 RTCBufferType type) {
603 if (type == RTC_VERTEX_BUFFER) {
604 } else if (type == RTC_INDEX_BUFFER) {
605 } else {
606 std::stringstream ss;
607 ss << "[rtcMapBuffer] Unsupported type : " << type << std::endl;
608 GetContext().SetError(ss.str());
609 return NULL;
610 }
611
612 // TODO(LTE): Acquire lock?
613 Scene *s = reinterpret_cast<Scene *>(scene);
614 assert(s);
615 TriMesh<float> *trimesh = s->GetTriMesh(geomID);
616 if (trimesh) {
617 if (type == RTC_VERTEX_BUFFER) {
618 return reinterpret_cast<void *>(trimesh->vertices.data());
619 } else if (type == RTC_INDEX_BUFFER) {
620 return reinterpret_cast<void *>(trimesh->faces.data());
621 }
622 } else {
623 std::stringstream ss;
624 ss << "[rtcMapBuffer] geomID : " << geomID << " not found in the scene."
625 << std::endl;
626 GetContext().SetError(ss.str());
627 return NULL;
628 }
629
630 return NULL; // never reach here.
631 }
632
rtcUnmapBuffer(RTCScene scene,unsigned geomID,RTCBufferType type)633 RTCORE_API void rtcUnmapBuffer(RTCScene scene, unsigned geomID,
634 RTCBufferType type) {
635 if (type == RTC_VERTEX_BUFFER) {
636 } else if (type == RTC_INDEX_BUFFER) {
637 } else {
638 std::stringstream ss;
639 ss << "[rtcUnmapBuffer] Unsupported type : " << type << std::endl;
640 GetContext().SetError(ss.str());
641 return;
642 }
643 // TODO(LTE): Release lock?
644 (void)scene;
645 (void)geomID;
646 }
647
rtcNewInstance2(RTCScene target,RTCScene source,size_t numTimeSteps=1)648 RTCORE_API unsigned rtcNewInstance2(
649 RTCScene target, //!< the scene the instance belongs to
650 RTCScene source, //!< the scene to instantiate
651 size_t numTimeSteps =
652 1) { //!< number of timesteps, one matrix per timestep
653 if (numTimeSteps != 1) {
654 std::stringstream ss;
655 ss << "[rtcNewInstance2] numTimeSteps must be 1" << std::endl;
656 GetContext().SetError(ss.str());
657 return 0;
658 }
659
660 // TODO(LTE): Implement
661 (void)target;
662 (void)source;
663
664 return 0;
665 }
666
rtcSetTransform2(RTCScene scene,unsigned int geomID,RTCMatrixType layout,const float * xfm,size_t timeStep=0)667 RTCORE_API void rtcSetTransform2(
668 RTCScene scene, //!< scene handle
669 unsigned int geomID, //!< ID of geometry
670 RTCMatrixType layout, //!< layout of transformation matrix
671 const float *xfm, //!< pointer to transformation matrix
672 size_t timeStep = 0 //!< timestep to set the matrix for
673 ) {
674 // TODO(LTE): Implement
675 (void)scene;
676 (void)geomID;
677 (void)layout;
678 (void)xfm;
679 (void)timeStep;
680 }
681
rtcUpdate(RTCScene scene,unsigned geomID)682 RTCORE_API void rtcUpdate(RTCScene scene, unsigned geomID) {
683 // TODO(LTE): Implement
684 (void)scene;
685 (void)geomID;
686 }
687
rtcCommit(RTCScene scene)688 RTCORE_API void rtcCommit(RTCScene scene) {
689 Scene *s = reinterpret_cast<Scene *>(scene);
690 assert(s);
691
692 s->Build();
693 }
694
695 } // namespace nanort_embree2
696