commit 1a2901628e769475ad079776a5812c2fb205277a
parent 2bb9edf0c7fbe273d57c69b48af7b4ef39f46ddf
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 29 May 2017 15:05:11 +0200
Merge branch 'release-0.4'
Diffstat:
33 files changed, 3874 insertions(+), 1813 deletions(-)
diff --git a/README.md b/README.md
@@ -19,18 +19,19 @@ The main concept exposed by the Star-3D C API are *shapes*. A *shape*
represents a 3D object whose data is defined by the user and can be updated at
any time. A 3D environment is built by attaching one or several *shapes* to a
*scene*. To access the *scene* data through sampling, ray-tracing or indexing,
-one have to enable a *scene session* that commits the current *scene* geometry
-as the geometry to use. A *scene* can also be instantiated into one or several
-*shapes*, each with its own attributes (e.g. position, orientation, etc.).
-Since the *scene* geometry is stored once even though it is instantiated
-several times, this feature can be used to create extremely complex environment
-with a low memory footprint.
+one have to create a *scene view* that commits the current *scene* geometry
+as the geometry of the *view*. A *scene* can also be instantiated into one or
+several *shapes*, each with its own attributes (e.g. position, orientation,
+etc.). Since the *scene* geometry is stored once even though it is
+instantiated several times, this feature can be used to create extremely
+complex environment with a low memory footprint.
Star-3D is currently used in several softwares dealing with complex arbitrary
3D contents, ranging from graphics applications and thermal simulations to
electromagnetism. Please refer to these projects for informations on their
purpose.
+ * [Star-4V/S](https://gitlab.com/meso-star/star-4v_s.git)
* [Star-Display](https://gitlab.com/meso-star/star-display.git)
* [Star-GebhartFactor](https://gitlab.com/meso-star/star-gf.git)
* [Star-Schiff](https://gitlab.com/meso-star/star-schiff.git)
@@ -80,12 +81,11 @@ installed.
Once installed, the Star-3D library and its associated headers are deployed,
providing the whole environment required to develop C/C++ applications with
-Star-3D. The `<STAR3D_INSTALL_DIR>/include/star/s3d.h` header defines the
+Star-3D. The `<STAR3D_INSTALL_DIR>/include/star/s3d.h` header defines the
Star-3D Application Programming Interface (API). Refer to this
[file](https://gitlab.com/meso-star/star-3d/blob/master/src/s3d.h) for the API
reference documentation.
-
A Star-3D [CMake
package](https://cmake.org/cmake/help/v3.5/manual/cmake-packages.7.html) is
also installed to facilitate the use of Star-3D in projects relying on the
@@ -111,9 +111,32 @@ instance, on a GNU/Linux system:
with `<STAR3D_INSTALL_DIR>` the install directory of Star-3D and
`<MY_PROJECT_DIR>` the location of the `CMakeLists.txt` file.
+## Release notes
+
+### Version 0.4
+
+- Implement the `s3d_scene_view` API; it replaces the
+ `s3d_scene_<begin|end>_session` functions that were removed. A view registers
+ the state of the scene from which it is created. It is used to retrieve the
+ scene data through ray-tracing, sampling or indexing. Several views can be
+ created on the same scene.
+- Add the possibility to attach a same shape to several scenes.
+- Fix a memory overconsumption with instantiated shapes: the instantiated
+ back-end data were copied rather than shared.
+- Add the `s3d_scene_shapes_count` function that returns the overall number of
+ shapes in the scene.
+- Add the `s3d_instance_set_transform` and `s3d_instance_transform` functions
+ that sets or gets the transformation matrix of the instance, respectively.
+- Add the `s3d_primitive_get_transform` function that gets the transformation
+ matrix of a primitive.
+- Add the `s3d_primitive_has_attrib` function that returns if a primitive has a
+ specific attribute or not.
+- Add the `s3d_triangle_get_vertex_attrib` function that retrieves the
+ vertex attributes of a triangular primitive.
+
## License
-Star-3D is Copyright (C) |Meso|Star> 2015-2016 (<contact@meso-star.com>). It
+Star-3D is Copyright (C) |Meso|Star> 2015-2017 (<contact@meso-star.com>). It
is a free software released under the [OSI](http://opensource.org)-approved
CeCILL license. You are welcome to redistribute it under certain conditions;
refer to the COPYING files for details.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+# Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
#
# This software is a computer program whose purpose is to generate files used
# to build the Star-3D library.
@@ -68,6 +68,7 @@ set(S3D_FILES_SRC
s3d_mesh.c
s3d_primitive.c
s3d_scene.c
+ s3d_scene_view.c
s3d_shape.c)
set(S3D_FILES_INC_API s3d.h)
set(S3D_FILES_INC
@@ -78,6 +79,8 @@ set(S3D_FILES_INC
s3d_geometry.h
s3d_instance.h
s3d_mesh.h
+ s3d_scene_c.h
+ s3d_scene_view_c.h
s3d_shape_c.h)
set(S3D_FILES_DOC COPYING.fr COPYING.en README.md)
@@ -139,7 +142,10 @@ if(NOT NO_TEST)
new_test(test_s3d_primitive)
new_test(test_s3d_sampler)
new_test(test_s3d_scene)
+ new_test(test_s3d_scene_view)
new_test(test_s3d_shape)
+ new_test(test_s3d_trace_ray_instance)
+ new_test(test_s3d_seams)
build_test(test_s3d_trace_ray)
register_test(test_s3d_trace_ray_legacy test_s3d_trace_ray)
diff --git a/src/s3d.h b/src/s3d.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -105,8 +105,8 @@ struct s3d_primitive {
void* inst__;
};
-#define S3D_PRIMITIVE_NULL__ {\
- S3D_INVALID_ID, S3D_INVALID_ID, S3D_INVALID_ID, S3D_INVALID_ID, NULL, NULL\
+#define S3D_PRIMITIVE_NULL__ { \
+ S3D_INVALID_ID, S3D_INVALID_ID, S3D_INVALID_ID, S3D_INVALID_ID, NULL, NULL \
}
static const struct s3d_primitive S3D_PRIMITIVE_NULL = S3D_PRIMITIVE_NULL__;
@@ -150,16 +150,16 @@ struct s3d_hit {
};
/* Constant defining a NULL intersection. Should be used to initialize a hit */
-#define S3D_HIT_NULL__ {\
- { S3D_INVALID_ID, S3D_INVALID_ID, S3D_INVALID_ID, S3D_INVALID_ID, NULL, NULL },\
- { 0.f, 0.f, 0.f },\
- { 0.f, 0.f },\
- FLT_MAX\
+#define S3D_HIT_NULL__ { \
+ {S3D_INVALID_ID, S3D_INVALID_ID, S3D_INVALID_ID, S3D_INVALID_ID, NULL, NULL},\
+ {0.f, 0.f, 0.f}, \
+ {0.f, 0.f}, \
+ FLT_MAX \
}
static const struct s3d_hit S3D_HIT_NULL = S3D_HIT_NULL__;
-enum s3d_session_flag {
+enum s3d_scene_view_flag {
S3D_TRACE = BIT(0),
S3D_SAMPLE = BIT(1),
S3D_GET_PRIMITIVE = BIT(2)
@@ -175,16 +175,17 @@ enum s3d_session_flag {
* discarded and a value not equal to zero otherwise. */
typedef int
(*s3d_hit_filter_function_T)
- (const struct s3d_hit* hit,
- const float ray_org[3],
- const float ray_dir[3],
- void* ray_data, /* User data submitted on trace ray(s) invocation */
- void* filter_data); /* Data defined on the setup of the filter function */
+ (const struct s3d_hit* hit,
+ const float ray_org[3],
+ const float ray_dir[3],
+ void* ray_data, /* User data submitted on trace ray(s) invocation */
+ void* filter_data); /* Data defined on the setup of the filter function */
/* Forward declaration of s3d opaque data types */
struct s3d_device; /* Entry point of the library */
struct s3d_scene; /* Collection of shapes */
-struct s3d_shape; /* Untyped geometry */
+struct s3d_scene_view; /* Scene state */
+struct s3d_shape; /* Surfacic geometry */
/* Forward declaration of external data types */
struct logger;
@@ -242,9 +243,8 @@ s3d_scene_instantiate
(struct s3d_scene* scn,
struct s3d_shape** shape);
-/* Attach the shape to the scene. If the shape is already attached to the same
- * or another scene, nothing is performed and a RES_BAD_ARG error is returned.
- * On success, the scene gets a reference onto the attached shape */
+/* Attach the shape to the scene. On success, the scene gets a reference onto
+ * the attached shape */
S3D_API res_T
s3d_scene_attach_shape
(struct s3d_scene* scn,
@@ -263,49 +263,56 @@ S3D_API res_T
s3d_scene_clear
(struct s3d_scene* scn);
-/* Synchronize the scene geometry with the geometry of its attached shapes. If
- * a s3d_scene_begin_session is already active on `scn' or one of its attached
- * instance a RES_BAD_OP error is returned. On success neither another begin
- * session nor a clear or shape_detach can be invoked on `scn' and its attached
- * instances until s3d_scene_end_session is called. */
S3D_API res_T
-s3d_scene_begin_session
+s3d_scene_get_device
(struct s3d_scene* scn,
- const int session_mask); /* Combination of s3d_session_flag */
+ struct s3d_device** dev);
-/* End the session on the `scn' */
S3D_API res_T
-s3d_scene_end_session
- (struct s3d_scene* scn);
+s3d_scene_get_shapes_count
+ (struct s3d_scene* scn,
+ size_t* nshapes);
+/*******************************************************************************
+ * Scene view API - State of the scene geometry
+ ******************************************************************************/
S3D_API res_T
-s3d_scene_get_session_mask
+s3d_scene_view_create
(struct s3d_scene* scn,
+ const int mask, /* Combination of s3d_scene_view_flag */
+ struct s3d_scene_view** scnview);
+
+S3D_API res_T
+s3d_scene_view_ref_get
+ (struct s3d_scene_view* scnview);
+
+S3D_API res_T
+s3d_scene_view_ref_put
+ (struct s3d_scene_view* scnview);
+
+S3D_API res_T
+s3d_scene_view_get_mask
+ (struct s3d_scene_view* scnview,
int* mask);
-/* Trace a ray into the `scn' and return the closest intersection. The ray is
- * defined by `origin' + t*`direction' = 0 with t in [`range[0]', `range[1]').
- * Note that if range is degenerated (i.e. `range[0]' >= `range[1]') then the
- * ray is not traced and `hit' is set to S3D_HIT_NULL. Can be called only if an
- * S3D_TRACE session is active on `scn' */
S3D_API res_T
-s3d_scene_trace_ray
- (struct s3d_scene* scn,
+s3d_scene_view_trace_ray
+ (struct s3d_scene_view* scnview,
const float origin[3], /* Ray origin */
const float direction[3], /* Ray direction. Must be normalized */
const float range[2], /* In [0, INF)^2 */
void* ray_data, /* User ray data sent to the hit filter func. May be NULL */
struct s3d_hit* hit);
-/* Trace a bundle of rays into `scn' and return the closest intersection along
- * them. The rays are defined by `origin' + t*`direction' = 0 with t in
+/* Trace a bundle of rays into the scene and return the closest intersection
+ * along them. The rays are defined by `origin' + t*`direction' = 0 with t in
* [`range[0]', `range[1]'). Note that if a range is degenerated (i.e.
* `range[0]' >= `range[1]') then its associated ray is not traced and `hit' is
- * set to S3D_HIT_NULL. Can be called only if an S3D_TRACE session is active on
- * `scn' */
+ * set to S3D_HIT_NULL. Can be called only if the scnview was created with the
+ * S3D_TRACE flag. */
S3D_API res_T
-s3d_scene_trace_rays
- (struct s3d_scene* scn,
+s3d_scene_view_trace_rays
+ (struct s3d_scene_view* scnview,
const size_t nrays, /* # rays */
const int mask, /* Combination of s3d_ray_flag */
const float* origins, /* List of 3D ray origins */
@@ -315,59 +322,50 @@ s3d_scene_trace_rays
const size_t sizeof_ray_data, /* Size in Bytes of *one* ray data */
struct s3d_hit* hits);
-/* Uniformly sample the scene and returned the sampled primitive and its sample
- * uv position. Can be called only if a S3D_SAMPLE session is active on `scn'*/
+/* Uniformly sample the scene and return the sampled primitive and its sample
+ * uv position. Can be called only if the scnview was created with the
+ * S3D_SAMPLE flag */
S3D_API res_T
-s3d_scene_sample
- (struct s3d_scene* scn,
+s3d_scene_view_sample
+ (struct s3d_scene_view* scnview,
const float u, const float v, const float w, /* Random numbers in [0, 1) */
struct s3d_primitive* primitive, /* Sampled primitive */
float st[2]); /* Sampled parametric coordinates on the primitive */
-/* Retrieve a primitive from the scene. Can be called only if a
- * S3D_GET_PRIMITIVE session is active on `scn' */
+/* Retrieve a primitive from the scene. Can be called only if the scnview was
+ * created with the S3D_GET_PRIMITIVE flag */
S3D_API res_T
-s3d_scene_get_primitive
- (struct s3d_scene* scn,
+s3d_scene_view_get_primitive
+ (struct s3d_scene_view* scnview,
const unsigned iprim, /* in [0, #prims) */
struct s3d_primitive* prim);
-/* Retrieve the number of scene primitives. Can be called only if a sessio is
- * active on `scn' */
+/* Return the overall number of scene primitives */
S3D_API res_T
-s3d_scene_primitives_count
- (struct s3d_scene* scn,
+s3d_scene_view_primitives_count
+ (struct s3d_scene_view* scnview,
size_t* primitives_count);
-/* Compute the overall scene surface area. Can be called only if a session is
- * active on `scn' */
+/* Compute the overall scene surface area */
S3D_API res_T
-s3d_scene_compute_area
- (struct s3d_scene* scn,
+s3d_scene_view_compute_area
+ (struct s3d_scene_view* scnview,
float* area);
/* This function assumes that the scene defines a closed volume and that the
- * normals point into the volume. Can be called only if a session is active on
- * `scn' */
+ * normals point into the volume. */
S3D_API res_T
-s3d_scene_compute_volume
- (struct s3d_scene* scn,
+s3d_scene_view_compute_volume
+ (struct s3d_scene_view* scnview,
float* volume);
-/* Retrieve the Axis Aligned Bounding Box of the scene. Can be called only if a
- * session is active on `scn' */
+/* Retrieve the Axis Aligned Bounding Box of the scene */
S3D_API res_T
-s3d_scene_get_aabb
- (struct s3d_scene* scn,
+s3d_scene_view_get_aabb
+ (struct s3d_scene_view* scnview,
float lower[3], /* AABB lower bound */
float upper[3]); /* AABB upper bound */
-/* Retrieve the device from which the scene was created */
-S3D_API res_T
-s3d_scene_get_device
- (struct s3d_scene* scn,
- struct s3d_device** dev);
-
/*******************************************************************************
* Shape API - A shape defines a geometry that can be attached to *one* scene.
******************************************************************************/
@@ -389,7 +387,7 @@ s3d_shape_ref_put
* representation of the caller with a simple dynamic array */
S3D_API res_T
s3d_shape_get_id
- (struct s3d_shape* shape,
+ (const struct s3d_shape* shape,
unsigned* id);
/* Enable/disable the shape, i.e. it cannot be hit when its associated scene is
@@ -402,15 +400,9 @@ s3d_shape_enable
/* Return whether or not the shape is enabled, i.e. ray-traced. Default is 1 */
S3D_API res_T
s3d_shape_is_enabled
- (struct s3d_shape* shape,
+ (const struct s3d_shape* shape,
char* is_enabled);
-/* Define whether the shape is attached or not */
-S3D_API res_T
-s3d_shape_is_attached
- (struct s3d_shape* shape,
- char* is_attached);
-
/* Flip the surface orientation, i.e. flip the geometric normal of the surface */
S3D_API res_T
s3d_shape_flip_surface
@@ -452,6 +444,13 @@ s3d_primitive_get_transform
(const struct s3d_primitive* prim,
float transform[12]); /* 3x4 column major matrix */
+S3D_API res_T
+s3d_triangle_get_vertex_attrib
+ (const struct s3d_primitive* prim,
+ const size_t ivertex, /* in [0..3[ */
+ const enum s3d_attrib_usage usage,
+ struct s3d_attrib* attrib);
+
/*******************************************************************************
* Mesh API - Manage a triangular meshes
******************************************************************************/
@@ -517,7 +516,7 @@ s3d_mesh_get_hit_filter_data
* Instance API - An instance is a shape that encapsulates a scene and that
* supports a local to world transformation. Since the scene geometry is stored
* only a single time even though it is instantiated in several positions, one
- * can use this feature to create extremely large scene
+ * can use this feature to create extremely large scene.
******************************************************************************/
S3D_API res_T
s3d_instance_set_position
diff --git a/src/s3d_backend.h b/src/s3d_backend.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
diff --git a/src/s3d_buffer.h b/src/s3d_buffer.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
diff --git a/src/s3d_c.h b/src/s3d_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
diff --git a/src/s3d_device.c b/src/s3d_device.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -61,6 +61,7 @@ device_release(ref_T* ref)
struct s3d_device* dev;
ASSERT(ref);
dev = CONTAINER_OF(ref, struct s3d_device, ref);
+ ASSERT(flist_name_is_empty(&dev->names) == 1);
flist_name_release(&dev->names);
rtcDeleteDevice(dev->rtc);
MEM_RM(dev->allocator, dev);
diff --git a/src/s3d_device_c.h b/src/s3d_device_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
diff --git a/src/s3d_geometry.c b/src/s3d_geometry.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
diff --git a/src/s3d_geometry.h b/src/s3d_geometry.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -44,11 +44,22 @@ enum geometry_type {
GEOM_NONE = GEOM_TYPES_COUNT__
};
+enum embree_attrib {
+ EMBREE_ENABLE = BIT(0),
+ EMBREE_FILTER_FUNCTION = BIT(1),
+ EMBREE_INDICES = BIT(2),
+ EMBREE_TRANSFORM = BIT(4),
+ EMBREE_VERTICES = BIT(5)
+};
+
/* Backend geometry */
struct geometry {
unsigned name; /* Client side identifier */
unsigned irtc; /* Embree identifier */
unsigned scene_prim_id_offset; /* Offset from local to scene prim_id */
+
+ int embree_outdated_mask; /* Combination of embree_attrib */
+
char flip_surface; /* Is the geometry surface flipped? */
char is_enabled; /* Is the geometry enabled? */
diff --git a/src/s3d_instance.c b/src/s3d_instance.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -74,7 +74,6 @@ instance_create
}
f33_set_identity(inst->transform); /* rotation */
f3_splat(inst->transform + 9, 0.f); /* Translation */
- inst->update_transform = 0;
ref_init(&inst->ref);
S3D(scene_ref_get(scn));
inst->scene = scn;
@@ -103,21 +102,3 @@ instance_ref_put(struct instance* inst)
ref_put(&inst->ref, instance_release);
}
-float
-instance_compute_volume(struct instance* inst, const char flip_surface)
-{
- struct list_node* node;
- float volume = 0.f;
- ASSERT(inst);
-
- /* TODO take into account the scale factor of the instance */
- LIST_FOR_EACH(node, &inst->scene->shapes) {
- struct s3d_shape* shape = CONTAINER_OF
- (node, struct s3d_shape, scene_attachment);
- const char flip = flip_surface ^ shape->flip_surface;
- ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */
- volume += mesh_compute_volume(shape->data.mesh, flip);
- }
- return volume;
-}
-
diff --git a/src/s3d_instance.h b/src/s3d_instance.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -39,8 +39,11 @@
struct instance {
float transform[12]; /* local to world 3x4 column major matrix */
- char update_transform;
- struct s3d_scene* scene;
+ struct s3d_scene* scene; /* Instantiated scene */
+ /* Current view of the instantiated scene. Note that the instance does not
+ * own the scnview; the instance scnview lifetime is managed by the scnview
+ * into which the instance lies */
+ struct s3d_scene_view* scnview;
ref_T ref;
};
@@ -57,10 +60,5 @@ extern LOCAL_SYM void
instance_ref_put
(struct instance* inst);
-extern LOCAL_SYM float
-instance_compute_volume
- (struct instance* inst,
- const char flip_surface);
-
#endif /* S3D_INSTANCE_H */
diff --git a/src/s3d_mesh.c b/src/s3d_mesh.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -56,17 +56,11 @@ mesh_setup_indices
ntris_prev = (unsigned)mesh_get_ntris(mesh);
ASSERT(get_indices != S3D_KEEP || ntris == ntris_prev);
+ (void)ntris_prev;
if(get_indices == S3D_KEEP)
return;
- if(ntris == ntris_prev) {
- mesh->update_mask |= (INDEX_BUFFER & !mesh->resize_mask);
- } else {
- mesh->resize_mask |= INDEX_BUFFER;
- mesh->update_mask &= !INDEX_BUFFER;
- }
-
if(mesh->indices) { /* Release the old index buffer */
index_buffer_ref_put(mesh->indices);
mesh->indices = NULL;
@@ -102,7 +96,7 @@ mesh_setup_positions
void* data)
{
float* positions;
- unsigned ivert, nverts_prev;
+ unsigned ivert;
res_T res;
ASSERT(mesh && nverts && attr && attr->usage == S3D_POSITION);
@@ -112,14 +106,6 @@ mesh_setup_positions
return;
}
- nverts_prev = (unsigned)mesh_get_nverts(mesh);
- if(nverts == nverts_prev) {
- mesh->update_mask |= (VERTEX_BUFFER & ~mesh->resize_mask);
- } else {
- mesh->resize_mask |= VERTEX_BUFFER;
- mesh->update_mask &= !VERTEX_BUFFER;
- }
-
if(mesh->attribs[S3D_POSITION]) { /* Release the old vertex buffer */
vertex_buffer_ref_put(mesh->attribs[S3D_POSITION]);
mesh->attribs[S3D_POSITION] = NULL;
@@ -304,8 +290,6 @@ mesh_clear(struct mesh* mesh)
mesh->attribs[iattr] = NULL;
}
}
- mesh->resize_mask = 0;
- mesh->update_mask = 0;
darray_float_clear(&mesh->cdf);
}
@@ -549,26 +533,9 @@ mesh_compute_aabb(struct mesh* mesh, float lower[3], float upper[3])
void
mesh_copy_indexed_vertices(const struct mesh* src, struct mesh* dst)
{
- size_t ntris_src;
- size_t ntris_dst;
- size_t nverts_src;
- size_t nverts_dst;
int i;
ASSERT(src && dst && src != dst);
- ntris_src = mesh_get_ntris(src);
- ntris_dst = mesh_get_ntris(dst);
- nverts_src = mesh_get_nverts(src);
- nverts_dst = mesh_get_nverts(dst);
-
- /* Setup the index buffer masks */
- if(ntris_src == ntris_dst) {
- dst->update_mask = (INDEX_BUFFER & !dst->resize_mask);
- } else {
- dst->resize_mask |= INDEX_BUFFER;
- dst->update_mask &= !INDEX_BUFFER;
- }
-
/* Release the previous index buffer of dst */
if(dst->indices) {
index_buffer_ref_put(dst->indices);
@@ -580,14 +547,6 @@ mesh_copy_indexed_vertices(const struct mesh* src, struct mesh* dst)
dst->indices = src->indices;
}
- /* Setup the vertex buffer masks */
- if(nverts_src == nverts_dst) {
- dst->update_mask = (VERTEX_BUFFER & ~dst->resize_mask);
- } else {
- dst->resize_mask |= VERTEX_BUFFER;
- dst->update_mask &= !VERTEX_BUFFER;
- }
-
FOR_EACH(i, 0, S3D_ATTRIBS_COUNT__) {
/* Release the previous vertex buffers of dst */
if(dst->attribs[i]) {
diff --git a/src/s3d_mesh.h b/src/s3d_mesh.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -52,11 +52,6 @@
#define BUFFER_DARRAY darray_float
#include "s3d_buffer.h"
-enum buffer_type {
- INDEX_BUFFER = BIT(0),
- VERTEX_BUFFER = BIT(1)
-};
-
/* Filter function and its associated user defined data */
struct hit_filter {
s3d_hit_filter_function_T func;
@@ -70,8 +65,6 @@ struct mesh { /* Triangular mesh */
struct darray_float cdf;
struct hit_filter filter;
- int resize_mask; /* Combination of buffer_type */
- int update_mask; /* Combination of buffer_type */
struct s3d_device* dev;
ref_T ref;
};
diff --git a/src/s3d_primitive.c b/src/s3d_primitive.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -38,6 +38,19 @@
#include <rsys/float33.h>
/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static int
+check_primitive(const struct s3d_primitive* prim)
+{
+ return prim
+ && prim->geom_id != S3D_INVALID_ID
+ && prim->prim_id != S3D_INVALID_ID
+ && prim->mesh__ != NULL
+ && (prim->inst_id != S3D_INVALID_ID || prim->inst__ == NULL);
+}
+
+/*******************************************************************************
* Exported functions
******************************************************************************/
res_T
@@ -54,15 +67,8 @@ s3d_primitive_get_attrib
float w;
res_T res = RES_OK;
- if(!prim || usage == S3D_ATTRIBS_COUNT__ || !uv || !attrib)
- return RES_BAD_ARG;
-
- if(prim->geom_id == S3D_INVALID_ID
- || prim->prim_id == S3D_INVALID_ID
- || prim->mesh__ == NULL
- || (prim->inst_id != S3D_INVALID_ID && prim->inst__ == NULL)) {
+ if(!check_primitive(prim) || usage == S3D_ATTRIBS_COUNT__ || !uv || !attrib)
return RES_BAD_ARG;
- }
/* Unormalized barycentric coordinates */
w = CLAMP(1.f - uv[0] - uv[1], 0.f, 1.f);
@@ -163,8 +169,7 @@ s3d_primitive_has_attrib
const enum s3d_attrib_usage attr,
char* has_attrib)
{
- if(!prim
- || !has_attrib
+ if(!check_primitive(prim) || !has_attrib
|| (attr != S3D_GEOMETRY_NORMAL && (unsigned)attr >= S3D_ATTRIBS_COUNT__))
return RES_BAD_ARG;
@@ -187,7 +192,7 @@ s3d_primitive_sample
{
double sqrt_u;
- if(!prim || S3D_PRIMITIVE_EQ(prim, &S3D_PRIMITIVE_NULL) || !st)
+ if(!check_primitive(prim) || !st)
return RES_BAD_ARG;
/* Expecting canonic numbers */
@@ -211,7 +216,7 @@ s3d_primitive_compute_area(const struct s3d_primitive* prim, float* area)
float E0[3], E1[3], N[3];
struct geometry* geom;
- if(!prim || !area || S3D_PRIMITIVE_EQ(prim, &S3D_PRIMITIVE_NULL))
+ if(!check_primitive(prim) || !area)
return RES_BAD_ARG;
geom = (struct geometry*)prim->mesh__;
@@ -230,7 +235,7 @@ res_T
s3d_primitive_get_transform
(const struct s3d_primitive* prim, float transform[12])
{
- if(!prim || !transform)
+ if(!check_primitive(prim) || !transform)
return RES_BAD_ARG;
if(!prim->inst__) {
@@ -249,3 +254,65 @@ s3d_primitive_get_transform
return RES_OK;
}
+res_T
+s3d_triangle_get_vertex_attrib
+ (const struct s3d_primitive* prim,
+ const size_t ivertex,
+ const enum s3d_attrib_usage usage,
+ struct s3d_attrib* attrib)
+{
+ struct geometry* geom_mesh = NULL;
+ const float* transform = NULL;
+ const uint32_t* ids;
+
+ if(!check_primitive(prim) || ivertex > 2
+ || (unsigned)usage >= S3D_ATTRIBS_COUNT__
+ || !attrib) {
+ return RES_BAD_ARG;
+ }
+
+ geom_mesh = (struct geometry*)prim->mesh__;
+ ASSERT(prim->geom_id == geom_mesh->name);
+ ASSERT(geom_mesh->type == GEOM_MESH);
+
+ if(prim->inst__ != NULL) {
+ const struct geometry* geom_inst = (const struct geometry*)prim->inst__;
+ ASSERT(geom_inst->type == GEOM_INSTANCE);
+ ASSERT(prim->inst_id == geom_inst->name);
+ transform = geom_inst->data.instance->transform;
+ }
+
+ /* The mesh haven't the required mesh attrib */
+ if(!geom_mesh->data.mesh->attribs[usage]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Out of bound primitive index */
+ if(prim->prim_id >= mesh_get_ntris(geom_mesh->data.mesh)) {
+ return RES_BAD_ARG;
+ }
+ ids = mesh_get_ids(geom_mesh->data.mesh) + prim->prim_id * 3/*#triangle ids*/;
+ attrib->usage = usage;
+
+ if(usage != S3D_POSITION) {
+ const float* attr;
+ unsigned i, dim;
+ attrib->type = geom_mesh->data.mesh->attribs_type[usage];
+ /* Fetch attrib data */
+ dim = s3d_type_get_dimension(attrib->type);
+ attr = mesh_get_attr(geom_mesh->data.mesh, usage) + ids[ivertex] * dim;
+ FOR_EACH(i, 0, dim) attrib->value[i] = attr[i];
+ } else {
+ const float* pos;
+ attrib->type = S3D_FLOAT3;
+ /* Fetch data */
+ pos = mesh_get_pos(geom_mesh->data.mesh) + ids[ivertex] * 3;
+ f3_set(attrib->value, pos);
+ if(transform) { /* Transform the position from local to world space */
+ f33_mulf3(attrib->value, transform, attrib->value); /* Rotation */
+ f3_add(attrib->value, attrib->value, transform + 9); /* Translation */
+ }
+ }
+ return RES_OK;
+}
+
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -33,707 +33,31 @@
#include "s3d.h"
#include "s3d_device_c.h"
#include "s3d_scene_c.h"
+#include "s3d_scene_view_c.h"
#include "s3d_shape_c.h"
-#include <rsys/float3.h>
-#include <rsys/float33.h>
+#include <rsys/list.h>
#include <rsys/mem_allocator.h>
-#include <rsys/mutex.h>
-
-#include <algorithm>
-
-/* Flag used to define session enabled on instantiated scene */
-#define S3D_INSTANCE (BIT(sizeof(int)*8 - 1))
-
-struct ray_extended : public RTCRay {
- struct s3d_scene* scene;
- void* data; /* User defined data */
-};
/*******************************************************************************
* Helper functions
******************************************************************************/
-static INLINE void
-hit_setup(struct s3d_scene* scn, const RTCRay* ray, struct s3d_hit* hit)
-{
- float w;
- char flip_surface = 0;
-
- ASSERT(scn && hit && ray);
-
- if((unsigned)ray->geomID == RTC_INVALID_GEOMETRY_ID) { /* No hit */
- *hit = S3D_HIT_NULL;
- return;
- }
-
- f3_set(hit->normal, ray->Ng);
- hit->distance = ray->tfar;
-
- hit->uv[0] = ray->u;
- hit->uv[1] = ray->v;
- w = 1.f - hit->uv[0] - hit->uv[1];
- ASSERT(w <= 1.f); /* This may not occurs */
- if(w < 0.f) { /* Handle precision error */
- if(hit->uv[0] > hit->uv[1]) hit->uv[0] += w;
- else hit->uv[1] += w;
- w = 0.f;
- }
-
- /* Embree stores on the u and v ray parameters the barycentric coordinates of
- * the hit with respect to the second and third triangle vertices,
- * respectively. The following code computes the barycentric coordinates of
- * the hit for the first and second triangle vertices */
- hit->uv[1] = hit->uv[0];
- hit->uv[0] = w;
-
- if((unsigned)ray->instID == RTC_INVALID_GEOMETRY_ID) {
- struct geometry* geom_mesh;
- ASSERT((unsigned)ray->geomID < darray_geom_size_get(&scn->embree2geoms));
- geom_mesh = darray_geom_data_get(&scn->embree2geoms)[ray->geomID];
- hit->prim.mesh__ = geom_mesh;
- hit->prim.inst__ = NULL;
- hit->prim.prim_id = ray->primID;
- hit->prim.geom_id = geom_mesh->name;
- hit->prim.inst_id = S3D_INVALID_ID;
- hit->prim.scene_prim_id = /* Compute the "scene space" primitive id */
- hit->prim.prim_id /* Mesh space */
- + geom_mesh->scene_prim_id_offset; /* Scene space */
-
- } else { /* The hit shape is instantiated */
- /* Retrieve the hit instance */
- struct geometry* geom_inst;
- struct geometry* geom_mesh;
- ASSERT((unsigned)ray->instID < darray_geom_size_get(&scn->embree2geoms));
- geom_inst = darray_geom_data_get(&scn->embree2geoms)[ray->instID];
- geom_mesh = scene_get_mesh(geom_inst->data.instance->scene, ray->geomID);
- hit->prim.mesh__ = geom_mesh;
- hit->prim.inst__ = geom_inst;
- hit->prim.prim_id = ray->primID;
- hit->prim.geom_id = geom_mesh->name;
- hit->prim.inst_id = geom_inst->name;
- hit->prim.scene_prim_id = /* Compute the "scene space" */
- hit->prim.prim_id /* Mesh space */
- + geom_mesh->scene_prim_id_offset /* Inst space */
- + geom_inst->scene_prim_id_offset; /* Scene space */
-
- flip_surface = geom_inst->flip_surface;
- ASSERT(hit->prim.inst__);
- ASSERT(((struct geometry*)hit->prim.inst__)->type == GEOM_INSTANCE);
- }
- ASSERT(hit->prim.mesh__);
- ASSERT(((struct geometry*)hit->prim.mesh__)->type == GEOM_MESH);
-
- /* Flip geometric normal with respect to the flip surface flag */
- flip_surface ^= ((struct geometry*)hit->prim.mesh__)->flip_surface;
- if(flip_surface) f3_minus(hit->normal, hit->normal);
-}
-
-/* Wrapper between an Embree and a Star-3D filter function */
-static void
-filter_wrapper(void* user_ptr, RTCRay& ray)
-{
- struct s3d_hit hit;
- struct hit_filter* filter = (struct hit_filter*)user_ptr;
- struct ray_extended* ray_ex = static_cast<struct ray_extended*>(&ray);
-
- hit_setup(ray_ex->scene, &ray, &hit);
- if(filter->func(&hit, ray_ex->org, ray_ex->dir, ray_ex->data, filter->data)) {
- /* Discard the intersection */
- ray.geomID = RTC_INVALID_GEOMETRY_ID;
- }
-}
-
-static res_T
-scene_sync
- (struct s3d_scene* scn,
- const int mask);/* combination of s3d_session_flag & S3D_INSTANCE */
-
-static INLINE void
-scene_geometry_flush_enable_state
- (struct s3d_scene* scn,
- struct geometry* geom, /* Cached geometry */
- const struct s3d_shape* shape) /* New shape */
-{
- ASSERT(scn && geom && shape);
- if(geom->is_enabled == shape->is_enabled)
- return;
-
- geom->is_enabled = shape->is_enabled;
- if(geom->is_enabled) {
- rtcEnable(scn->rtc_scn, geom->irtc);
- } else {
- rtcDisable(scn->rtc_scn, geom->irtc);
- }
- scn->is_rtc_scn_outdated = 1;
-}
-
-static INLINE void
-scene_geometry_flush_filter_function
- (struct s3d_scene* scn,
- struct geometry* geom, /* Cached geometry */
- const struct s3d_shape* shape)
-{
- ASSERT(scn && geom && shape && geom->irtc != RTC_INVALID_GEOMETRY_ID);
- ASSERT(shape->type == GEOM_MESH);
-
- if(geom->data.mesh->filter.func == shape->data.mesh->filter.func
- && geom->data.mesh->filter.data == shape->data.mesh->filter.data)
- return; /* Up to date */
-
- geom->data.mesh->filter = shape->data.mesh->filter;
- if(!geom->data.mesh->filter.func) {
- rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, NULL);
- } else {
- rtcSetIntersectionFilterFunction(scn->rtc_scn, geom->irtc, filter_wrapper);
- rtcSetUserData(scn->rtc_scn, geom->irtc, &geom->data.mesh->filter);
- }
- scn->is_rtc_scn_outdated = 1;
-}
-
-static res_T
-scene_register_embree_geometry(struct s3d_scene* scn, struct geometry* geom)
-{
- ASSERT(scn && geom && (geom->type==GEOM_MESH || geom->type==GEOM_INSTANCE));
-
- /* Create the Embree geometry if it is not valid */
- if(geom->irtc == RTC_INVALID_GEOMETRY_ID) {
- switch(geom->type) {
- case GEOM_MESH:
- geom->irtc = rtcNewTriangleMesh(scn->rtc_scn, RTC_GEOMETRY_DYNAMIC,
- mesh_get_ntris(geom->data.mesh), mesh_get_nverts(geom->data.mesh));
- break;
- case GEOM_INSTANCE:
- geom->irtc = rtcNewInstance
- (scn->rtc_scn, geom->data.instance->scene->rtc_scn);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- if(geom->irtc == RTC_INVALID_GEOMETRY_ID)
- return RES_UNKNOWN_ERR;
-
- scn->is_rtc_scn_outdated = 1;
- }
-
- if(geom->irtc >= darray_geom_size_get(&scn->embree2geoms)) {
- const res_T res = darray_geom_resize(&scn->embree2geoms, geom->irtc + 1);
- if(res != RES_OK) {
- rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
- return res;
- }
- }
- geometry_ref_get(geom);
- darray_geom_data_get(&scn->embree2geoms)[geom->irtc] = geom;
- return RES_OK;
-}
-
-static INLINE void
-scene_geometry_flush_positions(struct s3d_scene* scn, struct geometry* geom)
-{
- ASSERT(scn && geom && geom->type == GEOM_MESH);
- ASSERT(geom->irtc != RTC_INVALID_GEOMETRY_ID);
- rtcSetBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER,
- mesh_get_pos(geom->data.mesh), 0, sizeof(float[3]));
- rtcUpdateBuffer(scn->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER);
- scn->is_rtc_scn_outdated = 1;
-}
-
-static INLINE void
-scene_geometry_flush_indices(struct s3d_scene* scn, struct geometry* geom)
-{
- ASSERT(scn && geom && geom->type == GEOM_MESH);
- ASSERT(geom->irtc != RTC_INVALID_GEOMETRY_ID);
- rtcSetBuffer(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER,
- mesh_get_ids(geom->data.mesh), 0, sizeof(uint32_t[3]));
- rtcUpdateBuffer(scn->rtc_scn, geom->irtc, RTC_INDEX_BUFFER);
- scn->is_rtc_scn_outdated = 1;
-}
-
-static void
-scene_session_clear(struct s3d_scene* scn)
-{
- struct geometry** geoms;
- size_t ngeoms;
- size_t i;
- ASSERT(scn);
-
- ngeoms = darray_geom_size_get(&scn->embree2geoms);
- geoms = darray_geom_data_get(&scn->embree2geoms);
- FOR_EACH(i, 0, ngeoms) {
- if(!geoms[i]) continue;
-
- if(geoms[i]->type == GEOM_INSTANCE)
- scene_session_clear(geoms[i]->data.instance->scene);
-
- geometry_ref_put(geoms[i]);
- }
- darray_geom_clear(&scn->embree2geoms);
- scn->session_mask = 0;
-}
-
-static res_T
-scene_register_mesh
- (struct s3d_scene* scn,
- struct s3d_shape* shape)
-{
- struct geometry** pgeom = NULL;
- struct geometry* geom = NULL;
- size_t iattr;
- char upd_pos, upd_ids;
-
- res_T res = RES_OK;
- ASSERT(shape && shape->type == GEOM_MESH);
-
- /* Retrieve the cached geometry */
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- if(pgeom) {
- geom = *pgeom;
- } else {
- res = geometry_create(scn->dev, &geom);
- if(res != RES_OK) goto error;
- res = mesh_create(scn->dev, &geom->data.mesh);
- if(res != RES_OK) goto error;
- geom->type = GEOM_MESH;
- res = htable_geom_set(&scn->cached_geoms, &shape, &geom);
- if(res != RES_OK) goto error;
- geom->name = shape->id.index;
- }
-
- /* Discard the geometry that is not geometrically valid */
- if(!shape->data.mesh->indices || !shape->data.mesh->attribs[S3D_POSITION]) {
- if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
- rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
- scn->is_rtc_scn_outdated = 1;
- }
- mesh_clear(geom->data.mesh);
- goto exit;
- }
-
- /* Define which geometry buffers were updated */
- upd_ids = geom->data.mesh->indices != shape->data.mesh->indices
- || ((shape->data.mesh->update_mask & INDEX_BUFFER) != 0);
- upd_pos = geom->data.mesh->attribs[S3D_POSITION] != shape->data.mesh->attribs[S3D_POSITION]
- || ((shape->data.mesh->update_mask & VERTEX_BUFFER) != 0);
-
- /* Get a reference onto the shape mesh indices */
- if(geom->data.mesh->indices != shape->data.mesh->indices) {
- if(geom->data.mesh->indices) {
- index_buffer_ref_put(geom->data.mesh->indices);
- geom->data.mesh->indices = NULL;
- }
- ASSERT(shape->data.mesh->indices);
- index_buffer_ref_get(shape->data.mesh->indices);
- geom->data.mesh->indices = shape->data.mesh->indices;
- }
-
- /* Get a reference onto the shape mesh attribs */
- FOR_EACH(iattr, 0, S3D_ATTRIBS_COUNT__) {
- if(geom->data.mesh->attribs[iattr] == shape->data.mesh->attribs[iattr])
- continue;
-
- if(geom->data.mesh->attribs[iattr]) {
- vertex_buffer_ref_put(geom->data.mesh->attribs[iattr]);
- geom->data.mesh->attribs[iattr] = NULL;
- }
- if(!shape->data.mesh->attribs[iattr])
- continue;
-
- vertex_buffer_ref_get(shape->data.mesh->attribs[iattr]);
- geom->data.mesh->attribs[iattr] = shape->data.mesh->attribs[iattr];
- geom->data.mesh->attribs_type[iattr] = shape->data.mesh->attribs_type[iattr];
- }
-
- /* The shape mesh was resize => the Embree geometry is no more valid */
- if(shape->data.mesh->resize_mask && geom->irtc != RTC_INVALID_GEOMETRY_ID) {
- rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
- scn->is_rtc_scn_outdated = 1;
- }
-
- res = scene_register_embree_geometry(scn, geom);
- if(res != RES_OK) goto error;
-
- if(upd_pos) { /* Update the Embree vertex buffer if necessary */
- scene_geometry_flush_positions(scn, geom);
- }
- if(upd_ids) { /* Update the Embree index buffer if necessary */
- scene_geometry_flush_indices(scn, geom);
- }
-
- /* Flush the remaining geometry states */
- scene_geometry_flush_enable_state(scn, geom, shape);
- scene_geometry_flush_filter_function(scn, geom, shape);
- geom->flip_surface = shape->flip_surface;
-
- /* Flush the shape mesh states */
- shape->data.mesh->resize_mask = 0;
- shape->data.mesh->update_mask = 0;
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-scene_register_instance
- (struct s3d_scene* scn,
- struct s3d_shape* shape,
- const int session_mask)
-{
- struct geometry** pgeom = NULL;
- struct geometry* geom = NULL;
- res_T res = RES_OK;
- ASSERT(scn && shape && shape->type == GEOM_INSTANCE);
-
- /* Recursuvely update the scene */
- res = scene_sync(shape->data.instance->scene,
- session_mask|S3D_INSTANCE);
- if(res != RES_OK) goto error;
-
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- /* Create the scene instance of the geometry if necessary */
- if(pgeom) {
- geom = *pgeom;
- } else {
- res = geometry_create(scn->dev, &geom);
- if(res != RES_OK) goto error;
- geom->type = GEOM_INSTANCE;
- res = instance_create(shape->data.instance->scene, &geom->data.instance);
- if(res != RES_OK) goto error;
- res = htable_geom_set(&scn->cached_geoms, &shape, &geom);
- if(res != RES_OK) goto error;
- geom->name = shape->id.index;
- }
- /* Update the cached instance states */
- ASSERT(geom->data.instance->scene == shape->data.instance->scene);
- f33_set(geom->data.instance->transform, shape->data.instance->transform);
- f3_set(geom->data.instance->transform + 9, shape->data.instance->transform + 9);
- geom->flip_surface = shape->flip_surface;
-
- /* The instance cannot contain instances, i.e. one instancing level is
- * supported */
- if(geom->data.instance->scene->instances_count != 0) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Create the Embree instance */
- res = scene_register_embree_geometry(scn, geom);
- if(res != RES_OK) goto error;
-
- /* Update the Embree instance transformation */
- if(shape->data.instance->update_transform) {
- rtcSetTransform
- (scn->rtc_scn,
- geom->irtc,
- RTC_MATRIX_COLUMN_MAJOR,
- geom->data.instance->transform);
- scn->is_rtc_scn_outdated = 1;
- }
-
- scene_geometry_flush_enable_state(scn, geom, shape);
- shape->data.instance->update_transform = 0; /* Flush instance state */
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-scene_detach_shape
- (struct s3d_scene* scn, struct s3d_shape* shape, const char* caller_name)
-{
- struct geometry** pgeom;
- ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment));
- ASSERT(shape->type == GEOM_MESH || shape->type == GEOM_INSTANCE);
-
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- if(pgeom) { /* Remove the cached shape mesh */
- struct geometry* geom = *pgeom;
- if(scn->session_mask != 0) {
- log_error(scn->dev,
- "%s: the shape is currently used in a scene session.\n", caller_name);
- return RES_BAD_OP;
- }
-
- if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
- rtcDeleteGeometry(scn->rtc_scn, geom->irtc);
- geom->irtc = RTC_INVALID_GEOMETRY_ID;
- scn->is_rtc_scn_outdated = 1;
- }
- geometry_ref_put(geom);
- htable_geom_erase(&scn->cached_geoms, &shape);
- }
- list_del(&shape->scene_attachment);
-
- if(shape->type == GEOM_INSTANCE) {
- ASSERT(scn->instances_count != 0);
- --scn->instances_count;
- }
-
- S3D(shape_ref_put(shape));
- return RES_OK;
-}
-
-static res_T
-scene_compute_cdf(struct s3d_scene* scn)
-{
- struct list_node* node;
- struct s3d_shape* shape;
- struct geometry** pgeom;
- struct geometry* geom;
- size_t len;
- float area = 0.f;
- res_T res = RES_OK;
- ASSERT(scn);
-
- darray_fltui_clear(&scn->cdf);
-
- LIST_FOR_EACH(node, &scn->shapes) {
- shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- ASSERT(pgeom != NULL);
- geom = *pgeom;
- struct fltui fltui;
-
- if(!geom->is_enabled) continue;
-
- switch(geom->type) {
- case GEOM_MESH:
- res = mesh_compute_cdf(geom->data.mesh);
- if(res != RES_OK) goto error;
- len = darray_float_size_get(&geom->data.mesh->cdf);
- if(len) {
- area += darray_float_cdata_get(&geom->data.mesh->cdf)[len - 1];
- }
- break;
- case GEOM_INSTANCE:
- res = scene_compute_cdf(geom->data.instance->scene);
- if(res != RES_OK) goto error;
- len = darray_fltui_size_get(&geom->data.instance->scene->cdf);
- if(len) {
- area += darray_fltui_cdata_get
- (&geom->data.instance->scene->cdf)[len - 1].flt;
- }
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- fltui.ui = geom->irtc;
- fltui.flt = area;
- if(len) {
- res = darray_fltui_push_back(&scn->cdf, &fltui);
- if(res != RES_OK) goto error;
- }
- }
-exit:
- return res;
-error:
- darray_fltui_clear(&scn->cdf);
- goto exit;
-}
-
-static void
-scene_compute_aabb(struct s3d_scene* scn)
-{
- struct list_node* node;
- struct s3d_shape* shape;
- struct geometry** pgeom;
- struct geometry* geom;
- struct instance* inst;
- float lower[3], upper[3];
-
- f3_splat(scn->lower, FLT_MAX);
- f3_splat(scn->upper,-FLT_MAX);
-
- LIST_FOR_EACH(node, &scn->shapes) {
- shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- ASSERT(pgeom != NULL);
- geom = *pgeom;
-
- if(!geom->is_enabled) continue;
-
- switch(geom->type) {
- case GEOM_MESH: mesh_compute_aabb(geom->data.mesh, lower, upper); break;
- case GEOM_INSTANCE:
- inst = geom->data.instance;
- scene_compute_aabb(inst->scene);
- /* Transform local scene AABB in world space */
- f33_mulf3(lower, inst->transform, inst->scene->lower);
- f33_mulf3(upper, inst->transform, inst->scene->upper);
- f3_add(lower, inst->transform + 9, lower);
- f3_add(upper, inst->transform + 9, upper);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- f3_min(scn->lower, scn->lower, lower);
- f3_max(scn->upper, scn->upper, upper);
- }
-}
-
-static FINLINE bool
-operator < (const struct fltui& it, const float val)
-{
- /* This operator is used by the std::lower_bound algorithm that returns an
- * iterator to the first element that is not less than val while one expect
- * an iterator on the first element that is not less *or equal* than val.
- * That's why we use <= rather than < */
- return it.flt <= val;
-}
-
-static res_T
-scene_compute_nprims_cdf
- (struct s3d_scene* scn,
- const char store_cdf)
-{
- struct list_node* node;
- struct s3d_shape* shape;
- struct geometry** pgeom;
- struct geometry* geom;
- size_t len;
- unsigned nprims;
- res_T res = RES_OK;
- ASSERT(scn);
-
- darray_nprims_cdf_clear(&scn->nprims_cdf);
-
- nprims = 0;
- LIST_FOR_EACH(node, &scn->shapes) {
- shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- ASSERT(pgeom != NULL);
- geom = *pgeom;
- struct nprims_cdf cdf;
-
- if(!geom->is_enabled) continue;
-
- geom->scene_prim_id_offset = nprims;
- switch(geom->type) {
- case GEOM_MESH:
- len = mesh_get_ntris(geom->data.mesh);
- nprims += (unsigned)len;
- break;
- case GEOM_INSTANCE:
- res = scene_compute_nprims_cdf(geom->data.instance->scene, store_cdf);
- if(res != RES_OK) goto error;
- len = darray_nprims_cdf_size_get(&geom->data.instance->scene->nprims_cdf);
- if(len) {
- nprims += darray_nprims_cdf_cdata_get
- (&geom->data.instance->scene->nprims_cdf)[len - 1].nprims;
- }
- break;
- default: FATAL("Unreachable code\n"); break;
- }
-
- cdf.nprims = nprims;
- cdf.irtc = geom->irtc;
- if(store_cdf && len) {
- res = darray_nprims_cdf_push_back(&scn->nprims_cdf, &cdf);
- if(res != RES_OK) goto error;
- }
- }
-exit:
- return res;
-error:
- darray_nprims_cdf_clear(&scn->nprims_cdf);
- goto exit;
-}
-
-static FINLINE bool
-operator < (const struct nprims_cdf& it, const size_t iprim)
-{
- /* This operator is used by the std::lower_bound algorithm that returns an
- * iterator to the first element that is not less than iprim while one expect
- * an iterator on the first element that is not less *or equal* than iprim.
- * That's why we use <= rather than < */
- return it.nprims <= iprim;
-}
-
-static res_T
-scene_sync(struct s3d_scene* scn, const int session_mask)
-{
- struct list_node* node;
- struct s3d_shape* shape;
- res_T res = RES_OK;
- ASSERT(scn);
-
- if((session_mask & S3D_INSTANCE) != 0
- && (scn->session_mask & S3D_INSTANCE) != 0) {
- /* The scene was already synced as an instance. Discard sync process */
- return RES_OK;
- } else if(scn->session_mask != 0) {
- /* The scene cannot be synced several times exepted if it is instantiated */
- res = RES_BAD_OP;
- goto error;
- }
-
- if((session_mask & S3D_INSTANCE) == 0 && scn->session_mask != 0) {
- res = RES_BAD_OP;
- goto error;
- }
-
- LIST_FOR_EACH(node, &scn->shapes) {
- shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
- switch(shape->type) {
- case GEOM_INSTANCE:
- /* One instancing level is supported */
- if((session_mask & S3D_INSTANCE) != 0) {
- res = RES_BAD_ARG;
- goto error;
- }
- res = scene_register_instance(scn, shape, session_mask);
- break;
- case GEOM_MESH:
- res = scene_register_mesh(scn, shape);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- if(res != RES_OK)
- goto error;
- }
- if((session_mask & S3D_SAMPLE) != 0) {
- res = scene_compute_cdf(scn);
- if(res != RES_OK) goto error;
- }
- if((session_mask & S3D_GET_PRIMITIVE) != 0) {
- res = scene_compute_nprims_cdf(scn, 1);
- } else {
- res = scene_compute_nprims_cdf(scn, 0);
- }
- if(res != RES_OK) goto error;
-
- if((session_mask & S3D_TRACE) != 0 && scn->is_rtc_scn_outdated) {
- rtcCommit(scn->rtc_scn);
- scn->is_rtc_scn_outdated = 0;
- }
- scn->session_mask = session_mask;
-
- scene_compute_aabb(scn);
-
-exit:
- return res;
-error:
- goto exit;
-}
-
static void
scene_release(ref_T* ref)
{
struct s3d_scene* scn;
struct s3d_device* dev;
+ struct list_node* node;
+ struct list_node* tmp;
+
ASSERT(ref);
scn = CONTAINER_OF(ref, struct s3d_scene, ref);
- S3D(scene_clear(scn));
dev = scn->dev;
- scene_session_clear(scn);
- if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn);
- htable_geom_release(&scn->cached_geoms);
- darray_geom_release(&scn->embree2geoms);
- darray_fltui_release(&scn->cdf);
- darray_nprims_cdf_release(&scn->nprims_cdf);
+ LIST_FOR_EACH_SAFE(node, tmp, &scn->scnviews) {
+ scene_view_destroy(CONTAINER_OF(node, struct s3d_scene_view, node));
+ }
+ S3D(scene_clear(scn));
+ htable_shape_release(&scn->shapes);
MEM_RM(dev->allocator, scn);
S3D(device_ref_put(dev));
}
@@ -757,24 +81,12 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn)
res = RES_MEM_ERR;
goto error;
}
- list_init(&scn->shapes);
- htable_geom_init(dev->allocator, &scn->cached_geoms);
- darray_geom_init(dev->allocator, &scn->embree2geoms);
- darray_fltui_init(dev->allocator, &scn->cdf);
- darray_nprims_cdf_init(dev->allocator, &scn->nprims_cdf);
+ htable_shape_init(dev->allocator, &scn->shapes);
+ SIG_INIT(&scn->sig_shape_detach);
+ list_init(&scn->scnviews);
ref_init(&scn->ref);
S3D(device_ref_get(dev));
scn->dev = dev;
- scn->session_mask = 0;
- scn->rtc_scn = rtcDeviceNewScene
- (dev->rtc, RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT | RTC_SCENE_ROBUST,
- RTC_INTERSECT1 | RTC_INTERSECT4);
- if(!scn->rtc_scn) {
- res = RES_MEM_ERR;
- goto error;
- }
- f3_splat(scn->lower, FLT_MAX);
- f3_splat(scn->upper,-FLT_MAX);
exit:
if(out_scn) *out_scn = scn;
@@ -838,587 +150,77 @@ error:
res_T
s3d_scene_attach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
{
+ unsigned shape_id;
+ res_T res = RES_OK;
+
if(!scn || !shape)
return RES_BAD_ARG;
- if(!is_list_empty(&shape->scene_attachment)) {
- log_error(scn->dev,
- "%s: the shape is already attached to a scene.\n", FUNC_NAME);
- return RES_BAD_ARG;
- }
if(shape->type == GEOM_INSTANCE && shape->data.instance->scene == scn) {
log_error(scn->dev,
"%s: the instantiated scene cannot be attached to itself.\n", FUNC_NAME);
return RES_BAD_ARG;
}
- list_add_tail(&scn->shapes, &shape->scene_attachment);
- S3D(shape_ref_get(shape));
- scn->instances_count += shape->type == GEOM_INSTANCE;
- return RES_OK;
-}
-
-res_T
-s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
-{
- res_T res = RES_OK;
- char is_attached;
-
- if(!scn || !shape) return RES_BAD_ARG;
- if(!(S3D(shape_is_attached(shape, &is_attached)), is_attached)) {
- log_error(scn->dev,
- "%s: the shape is not attached to a scene.\n", FUNC_NAME);
- return RES_BAD_ARG;
- }
-#ifndef NDEBUG
- { /* Check that the shape is attached to `scn' */
- struct list_node* node;
- char is_found = 0;
- LIST_FOR_EACH(node, &scn->shapes) {
- if(node == &shape->scene_attachment) {
- is_found = 1;
- break;
- }
- }
- ASSERT(is_found);
+ S3D(shape_get_id(shape, &shape_id));
+ if(htable_shape_find(&scn->shapes, &shape_id) != NULL) {
+ log_warning(scn->dev,
+ "%s: the shape is already attached to the scene.\n", FUNC_NAME);
+ return RES_OK;
}
-#endif
- res = scene_detach_shape(scn, shape, FUNC_NAME);
- if(res != RES_OK) return res;
- return RES_OK;
-}
-res_T
-s3d_scene_clear(struct s3d_scene* scn)
-{
- struct list_node* node, *tmp;
- if(!scn) return RES_BAD_ARG;
- if(scn->session_mask != 0) {
+ res = htable_shape_set(&scn->shapes, &shape_id, &shape);
+ if(res != RES_OK) {
log_error(scn->dev,
- "%s: cannot clear a scene with an active session.\n", FUNC_NAME);
- return RES_BAD_OP;
- }
- LIST_FOR_EACH_SAFE(node, tmp, &scn->shapes) {
- struct s3d_shape* shape = CONTAINER_OF
- (node, struct s3d_shape, scene_attachment);
- const res_T res = scene_detach_shape(scn, shape, FUNC_NAME);
- ASSERT(res == RES_OK); (void)res;
+ "%s: cannot attach the shape to the scene.\n", FUNC_NAME);
+ return RES_OK;
}
+ S3D(shape_ref_get(shape));
+ scn->instances_count += shape->type == GEOM_INSTANCE;
return RES_OK;
}
res_T
-s3d_scene_begin_session(struct s3d_scene* scn, const int session_mask)
-{
- if(!scn)
- return RES_BAD_ARG;
- if(!(session_mask&S3D_TRACE)
- && !(session_mask&S3D_SAMPLE)
- && !(session_mask&S3D_GET_PRIMITIVE)) {
- log_error(scn->dev, "%s: no valid session is defined.\n", FUNC_NAME);
- return RES_BAD_ARG;
- }
- return scene_sync(scn, session_mask);
-}
-
-res_T
-s3d_scene_end_session(struct s3d_scene* scn)
+s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
{
- if(!scn)
- return RES_BAD_ARG;
- if(scn->session_mask & S3D_INSTANCE) {
- log_error(scn->dev,
- "%s: the scene session was enabled through scene instantiation.\n",
- FUNC_NAME);
- return RES_BAD_OP;
- }
- if(!scn->session_mask) {
- log_error(scn->dev, "%s: the scene has no active session.\n", FUNC_NAME);
- return RES_BAD_OP;
- }
- scene_session_clear(scn);
- return RES_OK;
-}
+ size_t n;
+ unsigned shape_id;
-res_T
-s3d_scene_get_session_mask(struct s3d_scene* scn, int* session_mask)
-{
- if(!scn || !session_mask)
- return RES_BAD_ARG;
- *session_mask = scn->session_mask & (~S3D_INSTANCE);
- return RES_OK;
-}
+ if(!scn || !shape) return RES_BAD_ARG;
-res_T
-s3d_scene_trace_ray
- (struct s3d_scene* scn,
- const float org[3],
- const float dir[3],
- const float range[2],
- void* ray_data,
- struct s3d_hit* hit)
-{
- struct ray_extended ray_ex;
- if(!scn || !org || !dir || !range || !hit)
- return RES_BAD_ARG;
- if(!f3_is_normalized(dir)) {
+ S3D(shape_get_id(shape, &shape_id));
+ if(htable_shape_find(&scn->shapes, &shape_id) == NULL) {
log_error(scn->dev,
- "%s: unnormalized ray direction {%g, %g, %g}.\n",
- FUNC_NAME, SPLIT3(dir));
+ "%s: the shape is not attached to the scene.\n", FUNC_NAME);
return RES_BAD_ARG;
}
- if((scn->session_mask & S3D_TRACE) == 0) {
- log_error(scn->dev,
- "%s: no active S3D_TRACE session on the submitted scene.\n", FUNC_NAME);
- return RES_BAD_OP;
- }
- if(range[0] > range[1]) { /* Degenerated range <=> disabled ray */
- *hit = S3D_HIT_NULL;
- return RES_OK;
- }
- f3_set(ray_ex.org, org);
- f3_set(ray_ex.dir, dir);
- ray_ex.tnear = range[0];
- ray_ex.tfar = range[1];
- ray_ex.geomID = RTC_INVALID_GEOMETRY_ID;
- ray_ex.primID = RTC_INVALID_GEOMETRY_ID;
- ray_ex.instID = RTC_INVALID_GEOMETRY_ID;
- ray_ex.mask = 0xFFFFFFFF;
- ray_ex.time = 0.f;
- ray_ex.scene = scn;
- ray_ex.data = ray_data;
+ n = htable_shape_erase(&scn->shapes, &shape_id);
+ ASSERT(n == 1); (void)n;
- rtcIntersect(scn->rtc_scn, ray_ex);
-
- hit_setup(scn, &ray_ex, hit);
+ SIG_BROADCAST(&scn->sig_shape_detach, scene_shape_cb_T, ARG2(scn, shape));
+ S3D(shape_ref_put(shape));
return RES_OK;
}
res_T
-s3d_scene_trace_rays
- (struct s3d_scene* scn,
- const size_t nrays,
- const int mask,
- const float* origins,
- const float* directions,
- const float* ranges,
- void* rays_data,
- const size_t sizeof_ray_data,
- struct s3d_hit* hits)
+s3d_scene_clear(struct s3d_scene* scn)
{
- size_t iray;
- size_t iorg, idir, irange, idata;
- size_t org_step, dir_step, range_step, data_step;
- res_T res = RES_OK;
+ struct htable_shape_iterator it, end;
if(!scn) return RES_BAD_ARG;
- if(!nrays) return RES_OK;
-
- org_step = mask & S3D_RAYS_SINGLE_ORIGIN ? 0 : 3;
- dir_step = mask & S3D_RAYS_SINGLE_DIRECTION ? 0 : 3;
- range_step = mask & S3D_RAYS_SINGLE_RANGE ? 0 : 2;
- data_step = (mask & S3D_RAYS_SINGLE_DATA) || !rays_data ? 0 : sizeof_ray_data;
- iorg = idir = irange = idata = 0;
-
- FOR_EACH(iray, 0, nrays) {
- res = s3d_scene_trace_ray(scn, origins+iorg, directions+idir,
- ranges+irange, (char*)rays_data+idata, hits+iray);
- if(UNLIKELY(res != RES_OK)) break;
- iorg += org_step;
- idir += dir_step;
- irange += range_step;
- idata += data_step;
- }
- return res;
-}
-res_T
-s3d_scene_sample
- (struct s3d_scene* scn,
- const float u,
- const float v,
- const float w,
- struct s3d_primitive* primitive, /* sampled primitive */
- float st[2])
-{
- struct geometry* geom;
- const struct fltui* fltui_begin, *fltui_end, *fltui_found;
- const float* flt_begin, *flt_end, *flt_found;
- size_t igeom;
- float f;
- res_T res = RES_OK;
-
- if(!scn || !primitive || !st) {
- res = RES_BAD_ARG;
- goto error;
- }
- /* Expecting canonic numbers */
- if(u < 0.f || u >= 1.f || v < 0.f || v >= 1.f || w < 0.f || w >= 1.f) {
- log_error(scn->dev,
- "%s: the submitted numbers are not canonical, i.e. they are not in [0, 1[.\n",
- FUNC_NAME);
- res = RES_BAD_ARG;
- goto error;
- }
- if((scn->session_mask & S3D_SAMPLE) == 0) {
- log_error(scn->dev,
- "%s: no active S3D_SAMPLE session on the submitted scene.\n",
- FUNC_NAME);
- res = RES_BAD_OP;
- goto error;
- }
-
- /* Find the sampled geometry */
- if(darray_fltui_size_get(&scn->cdf) == 0) {
- /* No geometry to sample */
- *primitive = S3D_PRIMITIVE_NULL;
- goto exit;
- } else if(darray_fltui_size_get(&scn->cdf) == 1) {
- igeom = darray_fltui_cdata_get(&scn->cdf)[0].ui;
- f = u * darray_fltui_cdata_get(&scn->cdf)[0].flt;/* Map u to the CDF bounds */
- } else {
- fltui_begin = darray_fltui_cdata_get(&scn->cdf);
- fltui_end = fltui_begin + darray_fltui_size_get(&scn->cdf);
- f = u * fltui_end[-1].flt; /* Map u to the CDF bounds */
- fltui_found = std::lower_bound(fltui_begin, fltui_end, f);
- ASSERT(fltui_found != fltui_end);
- igeom = fltui_found->ui;
-
- /* Transform u to the geometry CDF bounds */
- if(fltui_found != fltui_begin)
- f -= fltui_found[-1].flt;
- }
- geom = darray_geom_data_get(&scn->embree2geoms)[igeom];
- ASSERT(geom);
-
- if(geom->type == GEOM_MESH) {
- primitive->inst__ = NULL;
- primitive->inst_id = S3D_INVALID_ID;
- primitive->scene_prim_id = 0;
- } else {
- /* Find the sampled instantiated geometry */
- ASSERT(geom->type == GEOM_INSTANCE);
- primitive->inst__ = geom;
- primitive->inst_id = geom->name;
- primitive->scene_prim_id = geom->scene_prim_id_offset;
- if(darray_fltui_size_get(&geom->data.instance->scene->cdf) == 1) {
- igeom = darray_fltui_cdata_get(&geom->data.instance->scene->cdf)[0].ui;
- } else {
- fltui_begin = darray_fltui_cdata_get(&geom->data.instance->scene->cdf);
- fltui_end = fltui_begin + darray_fltui_size_get(&geom->data.instance->scene->cdf);
- fltui_found = std::lower_bound(fltui_begin, fltui_end, f);
- ASSERT(fltui_found != fltui_end);
- igeom = fltui_found->ui;
-
- /* Transform u to the geometry CDF bounds */
- if(fltui_found != fltui_begin)
- f -= fltui_found[-1].flt;
- }
- geom = darray_geom_data_get
- (&geom->data.instance->scene->embree2geoms)[igeom];
- ASSERT(geom);
- }
- ASSERT(geom->type == GEOM_MESH);
-
- /* Find the sampled triangle */
- primitive->mesh__ = geom;
- primitive->geom_id = geom->name;
- primitive->scene_prim_id += geom->scene_prim_id_offset;
- flt_begin = darray_float_cdata_get(&geom->data.mesh->cdf);
- flt_end = flt_begin + darray_float_size_get(&geom->data.mesh->cdf);
- flt_found = std::lower_bound(flt_begin, flt_end, f);
- ASSERT(flt_found != flt_end);
-
- primitive->prim_id = (unsigned)(flt_found - flt_begin);
- primitive->scene_prim_id += primitive->prim_id;
- S3D(primitive_sample(primitive, v, w, st));
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-res_T
-s3d_scene_get_primitive
- (struct s3d_scene* scn, const unsigned iprim, struct s3d_primitive* prim)
-{
- struct geometry* geom;
- const struct nprims_cdf* begin, *end, *found;
- size_t nprims;
- size_t igeom;
- size_t i;
- res_T res = RES_OK;
-
- if(!scn || !prim) {
- res = RES_BAD_ARG;
- goto error;
- }
- if((scn->session_mask & S3D_GET_PRIMITIVE) == 0) {
- log_error(scn->dev,
- "%s: no active S3D_GET_PRIMITIVE session on the submitted scene.\n",
- FUNC_NAME);
- res = RES_BAD_OP;
- goto error;
- }
- S3D(scene_primitives_count(scn, &nprims));
- if(iprim >= nprims) {
- log_error(scn->dev,
- "%s: the primitive index %u exceeds the number of scene primitives %u.\n",
- FUNC_NAME, iprim, (unsigned)nprims);
- res = RES_BAD_ARG;
- goto error;
- }
-
- i = iprim;
- if(darray_nprims_cdf_size_get(&scn->nprims_cdf) == 1) {
- igeom = darray_nprims_cdf_cdata_get(&scn->nprims_cdf)[0].irtc;
- } else {
- begin = darray_nprims_cdf_cdata_get(&scn->nprims_cdf);
- end = begin + darray_nprims_cdf_size_get(&scn->nprims_cdf);
- found = std::lower_bound(begin, end, i);
- ASSERT(found != end);
- igeom = found->irtc;
- if(found != begin) {
- ASSERT(i >= found[-1].nprims);
- i -= found[-1].nprims;
- }
- }
- geom = darray_geom_data_get(&scn->embree2geoms)[igeom];
- ASSERT(geom);
-
- if(geom->type == GEOM_MESH) {
- prim->inst__ = NULL;
- prim->inst_id = S3D_INVALID_ID;
- prim->scene_prim_id = 0;
- } else {
- ASSERT(geom->type == GEOM_INSTANCE);
- prim->inst__ = geom;
- prim->inst_id = geom->name;
- prim->scene_prim_id = geom->scene_prim_id_offset;
- if(darray_nprims_cdf_size_get(&geom->data.instance->scene->nprims_cdf)==1) {
- igeom = darray_nprims_cdf_cdata_get
- (&geom->data.instance->scene->nprims_cdf)[0].irtc;
- } else {
- begin = darray_nprims_cdf_cdata_get
- (&geom->data.instance->scene->nprims_cdf);
- end = begin + darray_nprims_cdf_size_get
- (&geom->data.instance->scene->nprims_cdf);
- found = std::lower_bound(begin, end, i);
- ASSERT(found != end);
- igeom = found->irtc;
- if(found != begin) {
- ASSERT(i >= found[-1].nprims);
- i -= found[-1].nprims;
- }
- }
- geom = darray_geom_data_get
- (&geom->data.instance->scene->embree2geoms)[igeom];
- ASSERT(geom);
- }
- ASSERT(geom->type == GEOM_MESH);
- ASSERT(i < mesh_get_ntris(geom->data.mesh));
- prim->mesh__ = geom;
- prim->geom_id = geom->name;
- prim->prim_id = (unsigned)i;
- prim->scene_prim_id += geom->scene_prim_id_offset;
- prim->scene_prim_id += prim->prim_id;
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-res_T
-s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count)
-{
- res_T res = RES_OK;
-
- if(!scn || !prims_count) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(!scn->session_mask) {
- log_error(scn->dev,
- "%s: no active session on the submitted scene.\n", FUNC_NAME);
- res = RES_BAD_OP;
- goto error;
- }
- if((scn->session_mask & S3D_GET_PRIMITIVE) != 0) {
- const size_t len = darray_nprims_cdf_size_get(&scn->nprims_cdf);
- if(!len) {
- *prims_count = 0;
- } else {
- *prims_count = darray_nprims_cdf_cdata_get(&scn->nprims_cdf)[len - 1].nprims;
- }
- } else {
- struct list_node* node;
- struct s3d_shape* shape;
- struct geometry** pgeom;
- struct geometry* geom;
- size_t inst_count;
- *prims_count = 0;
- LIST_FOR_EACH(node, &scn->shapes) {
- shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- ASSERT(pgeom != NULL);
- geom = *pgeom;
-
- if(!geom->is_enabled) continue;
-
- switch(geom->type) {
- case GEOM_MESH:
- *prims_count += mesh_get_ntris(geom->data.mesh);
- break;
- case GEOM_INSTANCE:
- S3D(scene_primitives_count(geom->data.instance->scene, &inst_count));
- *prims_count += inst_count;
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- }
- }
-exit:
- return res;
-error:
- goto exit;
-}
-
-res_T
-s3d_scene_compute_area(struct s3d_scene* scn, float* out_area)
-{
- float area;
- res_T res = RES_OK;
-
- if(!scn || !out_area) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(!scn->session_mask) {
- log_error(scn->dev,
- "%s: no active session on the submitted scene.\n", FUNC_NAME);
- res = RES_BAD_OP;
- goto error;
- }
-
- if((scn->session_mask & S3D_SAMPLE) != 0) {
- /* Retrieve the overall scene area from the scene cumulative distribution
- * function. Note that the CDF stores the cumulative triangle area
- * multiplied by 2; the real scene area is thus the CDF upper bound / 2 */
- size_t len = darray_fltui_size_get(&scn->cdf);
- if(!len) {
- area = 0.f;
- } else {
- area = darray_fltui_cdata_get(&scn->cdf)[len - 1].flt * 0.5f;
- }
- } else {
- struct list_node* node;
- struct s3d_shape* shape;
- struct geometry** pgeom;
- struct geometry* geom;
- float inst_area;
-
- area = 0.f;
- LIST_FOR_EACH(node, &scn->shapes) {
- shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- ASSERT(pgeom != NULL);
- geom = *pgeom;
-
- if(!geom->is_enabled) continue;
-
- switch(geom->type) {
- case GEOM_MESH:
- area += mesh_compute_area(geom->data.mesh);
- break;
- case GEOM_INSTANCE:
- /* TODO take into account the instance scale factor */
- S3D(scene_compute_area(geom->data.instance->scene, &inst_area));
- area += inst_area;
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- }
- }
-
-exit:
- if(out_area) *out_area = area;
- return res;
-error:
- area = -1.f;
- goto exit;
-}
-
-res_T
-s3d_scene_compute_volume(struct s3d_scene* scn, float* out_volume)
-{
- struct list_node* node;
- struct s3d_shape* shape;
- struct geometry** pgeom;
- struct geometry* geom;
- float volume;
- res_T res = RES_OK;
-
- if(!scn || !out_volume) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(!scn->session_mask) {
- log_error(scn->dev,
- "%s: no active session on the submitted scene.\n", FUNC_NAME);
- res = RES_BAD_OP;
- goto error;
- }
-
- volume = 0.f;
- LIST_FOR_EACH(node, &scn->shapes) {
- shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
- pgeom = htable_geom_find(&scn->cached_geoms, &shape);
- ASSERT(pgeom != NULL);
- geom = *pgeom;
-
- if(!geom->is_enabled) continue;
-
- switch(geom->type) {
- case GEOM_MESH:
- volume += mesh_compute_volume(geom->data.mesh, geom->flip_surface);
- break;
- case GEOM_INSTANCE:
- volume += instance_compute_volume(geom->data.instance, geom->flip_surface);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- }
-
- if(volume < 0.f) {
- log_warning(scn->dev,
-"%s:\n"
-"\tthe volume is negative. The scene shapes might not represent closed 2D\n"
-"\tmanifold volumes, or their surface normal might not point inward the volume.\n",
- FUNC_NAME);
+ htable_shape_begin(&scn->shapes, &it);
+ htable_shape_end(&scn->shapes, &end);
+ while(!htable_shape_iterator_eq(&it, &end)) {
+ struct s3d_shape** pshape = htable_shape_iterator_data_get(&it);
+ struct s3d_shape* shape = *pshape;
+ SIG_BROADCAST(&scn->sig_shape_detach, scene_shape_cb_T, ARG2(scn, shape));
+ S3D(shape_ref_put(shape));
+ htable_shape_iterator_next(&it);
}
+ htable_shape_clear(&scn->shapes);
-exit:
- if(out_volume) *out_volume = volume;
- return res;
-error:
- volume = -1.f;
- goto exit;
-}
-
-res_T
-s3d_scene_get_aabb(struct s3d_scene* scn, float lower[3], float upper[3])
-{
- if(!scn || !lower || !upper) return RES_BAD_ARG;
- if(!scn->session_mask) {
- log_error(scn->dev,
- "%s: no active session on the submitted scene.\n", FUNC_NAME);
- return RES_BAD_OP;
- }
- f3_set(lower, scn->lower);
- f3_set(upper, scn->upper);
return RES_OK;
}
@@ -1430,3 +232,10 @@ s3d_scene_get_device(struct s3d_scene* scn, struct s3d_device** dev)
return RES_OK;
}
+res_T
+s3d_scene_get_shapes_count(struct s3d_scene* scn, size_t* nshapes)
+{
+ if(!scn || !nshapes) return RES_BAD_ARG;
+ *nshapes = htable_shape_size_get(&scn->shapes);
+ return RES_OK;
+}
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -33,77 +33,32 @@
#ifndef S3D_SCENE_C_H
#define S3D_SCENE_C_H
-#include "s3d_backend.h"
-
-#include <rsys/dynamic_array.h>
#include <rsys/hash_table.h>
#include <rsys/list.h>
#include <rsys/ref_count.h>
+#include <rsys/signal.h>
-/*
- * The geometry pointers must be initialized to NULL in order to define
- * which pointers are valid or not
- */
-static FINLINE void
-geom_ptr_init__(struct mem_allocator* alloc, struct geometry** geom)
-{
- (void)alloc; *geom = NULL;
-}
-
-/* Generate the darray_geom dynamic array */
-#define DARRAY_NAME geom
-#define DARRAY_DATA struct geometry*
-#define DARRAY_FUNCTOR_INIT geom_ptr_init__
-#include <rsys/dynamic_array.h>
-
-/* Generate the htable_geom hash table */
-#define HTABLE_NAME geom
-#define HTABLE_DATA struct geometry*
-#define HTABLE_KEY struct s3d_shape*
+/* Generate the htable_shape hash table */
+#define HTABLE_NAME shape
+#define HTABLE_DATA struct s3d_shape*
+#define HTABLE_KEY unsigned /* Id of the shape */
#include <rsys/hash_table.h>
-/* Generate the darray_fltui dynamic array */
-struct fltui { float flt; unsigned ui; };
-#define DARRAY_NAME fltui
-#define DARRAY_DATA struct fltui
-#include <rsys/dynamic_array.h>
-
-/* Generate the darray_geom_nprims array */
-struct nprims_cdf { unsigned nprims, irtc; };
-#define DARRAY_NAME nprims_cdf
-#define DARRAY_DATA struct nprims_cdf
-#include <rsys/dynamic_array.h>
+/* Declare the scene_shape_cb_T callback data type */
+CLBK(scene_shape_cb_T, ARG2
+ (const struct s3d_scene* scn,
+ const struct s3d_shape* shape));
struct s3d_scene {
- struct list_node shapes; /* List of attached shapes */
- struct htable_geom cached_geoms; /* Cached shape geometries */
- struct darray_geom embree2geoms; /* Shape geometries index by embree id */
- struct darray_fltui cdf; /* Unormalized CDF */
- struct darray_nprims_cdf nprims_cdf;
-
- float lower[3], upper[3]; /* AABB of the scene */
-
+ struct htable_shape shapes; /* List of attached shapes */
size_t instances_count; /* # instances in the scene */
+ struct list_node scnviews; /* Pool of available s3d_scene_view */
- RTCScene rtc_scn; /* Embree scene */
- char is_rtc_scn_outdated; /* Must the embree scene rebuild */
-
- int session_mask; /* Combination of enum s3d_session_flag */
+ signal_T sig_shape_detach;
struct s3d_device* dev;
ref_T ref;
};
-static FINLINE struct geometry*
-scene_get_mesh(struct s3d_scene* scn, const unsigned igeom)
-{
- struct geometry* geom;
- ASSERT(scn && igeom != RTC_INVALID_GEOMETRY_ID);
- ASSERT(igeom < darray_geom_size_get(&scn->embree2geoms));
- geom = darray_geom_data_get(&scn->embree2geoms)[igeom];
- ASSERT(geom);
- return geom;
-}
-
#endif /* S3D_SCENE_C_H */
diff --git a/src/s3d_scene_view.c b/src/s3d_scene_view.c
@@ -0,0 +1,1473 @@
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
+ *
+ * This software is a computer program whose purpose is to describe a
+ * virtual 3D environment that can be ray-traced and sampled both robustly
+ * and efficiently.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#include "s3d.h"
+#include "s3d_device_c.h"
+#include "s3d_scene_c.h"
+#include "s3d_scene_view_c.h"
+#include "s3d_shape_c.h"
+
+#include <rsys/float3.h>
+#include <rsys/float33.h>
+#include <rsys/mem_allocator.h>
+
+#include <algorithm>
+
+struct ray_extended : public RTCRay {
+ struct s3d_scene_view* scnview;
+ float ws_org[3]; /* World space ray origin */
+ float ws_dir[3]; /* World space ray direction */
+ void* data; /* User defined data */
+};
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static FINLINE int
+aabb_is_degenerated(const float lower[3], const float upper[3])
+{
+ ASSERT(lower && upper);
+ return lower[0] > upper[0] || lower[1] > upper[1] || lower[2] > upper[2];
+}
+
+static FINLINE bool
+operator < (const struct fltui& it, const float val)
+{
+ /* This operator is used by the std::lower_bound algorithm that returns an
+ * iterator to the first element that is not less than val while one expect
+ * an iterator on the first element that is not less *or equal* than val.
+ * That's why we use <= rather than < */
+ return it.flt <= val;
+}
+
+static FINLINE bool
+operator < (const struct nprims_cdf& it, const size_t iprim)
+{
+ /* This operator is used by the std::lower_bound algorithm that returns an
+ * iterator to the first element that is not less than iprim while one expect
+ * an iterator on the first element that is not less *or equal* than iprim.
+ * That's why we use <= rather than < */
+ return it.nprims <= iprim;
+}
+
+static INLINE void
+scene_view_destroy_geometry(struct s3d_scene_view* scnview, struct geometry* geom)
+{
+ ASSERT(geom);
+ if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
+ rtcDeleteGeometry(scnview->rtc_scn, geom->irtc);
+ geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ scnview->rtc_scn_update = 1; /* Notify the scene upd */
+ }
+ geometry_ref_put(geom);
+}
+
+static void
+on_shape_detach
+ (const struct s3d_scene* scn,
+ const struct s3d_shape* shape,
+ void* data)
+{
+ struct geometry** pgeom;
+ struct geometry* geom;
+ struct s3d_scene_view* scnview = (struct s3d_scene_view*)data;
+ unsigned shape_id;
+ ASSERT(scn && shape && data);
+ (void)scn;
+
+ S3D(shape_get_id(shape, &shape_id));
+ pgeom = htable_geom_find(&scnview->cached_geoms, &shape_id);
+
+ /* The scnview did not register a geometry for this shape. Ignore the signal */
+ if(!pgeom) return;
+
+ geom = *pgeom;
+ if(scnview->mask == 0) {
+ /* The scnview is NOT in use. Directly rm the cached geometry */
+ size_t n; (void)n;
+ scene_view_destroy_geometry(scnview, geom);
+ n = htable_geom_erase(&scnview->cached_geoms, &shape_id);
+ ASSERT(n == 1);
+ } else {
+ /* The scnview is in use. Delay the deletion of the cached geometry */
+ res_T res = darray_uint_push_back(&scnview->detached_shapes, &shape_id);
+ if(res != RES_OK) FATAL("Insufficient memory.\n");
+ }
+}
+
+static INLINE void
+hit_setup(struct s3d_scene_view* scnview, const RTCRay* ray, struct s3d_hit* hit)
+{
+ float w;
+ char flip_surface = 0;
+
+ ASSERT(scnview && hit && ray);
+
+ if((unsigned)ray->geomID == RTC_INVALID_GEOMETRY_ID) { /* No hit */
+ *hit = S3D_HIT_NULL;
+ return;
+ }
+
+ f3_set(hit->normal, ray->Ng);
+ hit->distance = ray->tfar;
+
+ hit->uv[0] = ray->u;
+ hit->uv[1] = ray->v;
+ w = 1.f - hit->uv[0] - hit->uv[1];
+ ASSERT(w <= 1.f); /* This may not occurs */
+ if(w < 0.f) { /* Handle precision error */
+ if(hit->uv[0] > hit->uv[1]) hit->uv[0] += w;
+ else hit->uv[1] += w;
+ w = 0.f;
+ }
+
+ /* Embree stores on the u and v ray parameters the barycentric coordinates of
+ * the hit with respect to the second and third triangle vertices,
+ * respectively. The following code computes the barycentric coordinates of
+ * the hit for the first and second triangle vertices */
+ hit->uv[1] = hit->uv[0];
+ hit->uv[0] = w;
+
+ if((unsigned)ray->instID == RTC_INVALID_GEOMETRY_ID) {
+ struct geometry* geom_mesh;
+ ASSERT((unsigned)ray->geomID < darray_geom_size_get(&scnview->embree2geoms));
+ geom_mesh = scene_view_geometry_from_embree_id(scnview, ray->geomID);
+ hit->prim.mesh__ = geom_mesh;
+ hit->prim.inst__ = NULL;
+ hit->prim.prim_id = ray->primID;
+ hit->prim.geom_id = geom_mesh->name;
+ hit->prim.inst_id = S3D_INVALID_ID;
+ hit->prim.scene_prim_id = /* Compute the "scene space" primitive id */
+ hit->prim.prim_id /* Mesh space */
+ + geom_mesh->scene_prim_id_offset; /* Scene space */
+
+ } else { /* The hit shape is instantiated */
+ /* Retrieve the hit instance */
+ struct geometry* geom_inst;
+ struct geometry* geom_mesh;
+ float transform[9];
+ ASSERT((unsigned)ray->instID < darray_geom_size_get(&scnview->embree2geoms));
+ geom_inst = scene_view_geometry_from_embree_id(scnview, ray->instID);
+ geom_mesh = scene_view_geometry_from_embree_id
+ (geom_inst->data.instance->scnview, ray->geomID);
+ hit->prim.mesh__ = geom_mesh;
+ hit->prim.inst__ = geom_inst;
+ hit->prim.prim_id = ray->primID;
+ hit->prim.geom_id = geom_mesh->name;
+ hit->prim.inst_id = geom_inst->name;
+ hit->prim.scene_prim_id = /* Compute the "scene space" */
+ hit->prim.prim_id /* Mesh space */
+ + geom_mesh->scene_prim_id_offset /* Inst space */
+ + geom_inst->scene_prim_id_offset; /* Scene space */
+
+ flip_surface = geom_inst->flip_surface;
+ ASSERT(hit->prim.inst__);
+ ASSERT(((struct geometry*)hit->prim.inst__)->type == GEOM_INSTANCE);
+
+ /* Transform the normal in world space */
+ f33_invtrans(transform, geom_inst->data.instance->transform);
+ f33_mulf3(hit->normal, transform, hit->normal);
+ }
+ ASSERT(hit->prim.mesh__);
+ ASSERT(((struct geometry*)hit->prim.mesh__)->type == GEOM_MESH);
+
+ /* Flip geometric normal with respect to the flip surface flag */
+ flip_surface ^= ((struct geometry*)hit->prim.mesh__)->flip_surface;
+ if(flip_surface) f3_minus(hit->normal, hit->normal);
+}
+
+/* Wrapper between an Embree and a Star-3D filter function */
+static void
+filter_wrapper(void* user_ptr, RTCRay& ray)
+{
+ struct s3d_hit hit;
+ struct hit_filter* filter = (struct hit_filter*)user_ptr;
+ struct ray_extended* ray_ex = static_cast<struct ray_extended*>(&ray);
+
+ hit_setup(ray_ex->scnview, &ray, &hit);
+ if(filter->func(&hit, ray_ex->ws_org, ray_ex->ws_dir, ray_ex->data, filter->data)) {
+ /* Discard the intersection */
+ ray.geomID = RTC_INVALID_GEOMETRY_ID;
+ }
+}
+
+static res_T
+embree_geometry_register
+ (struct s3d_scene_view* scnview,
+ struct geometry* geom)
+{
+ ASSERT(scnview && geom && (geom->type==GEOM_MESH || geom->type==GEOM_INSTANCE));
+
+ /* Create the Embree geometry if it is not valid */
+ if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
+ if(geom->type == GEOM_INSTANCE) {
+ /* If the geometry is an instance one have to update it if the
+ * instantiated geometry was updated. Currently, we have no simple way to
+ * know if the geometry was upd or not so we simply force the update. */
+ rtcUpdate(scnview->rtc_scn, geom->irtc);
+ }
+ } else {
+ switch(geom->type) {
+ case GEOM_MESH:
+ geom->irtc = rtcNewTriangleMesh(scnview->rtc_scn, RTC_GEOMETRY_DYNAMIC,
+ mesh_get_ntris(geom->data.mesh), mesh_get_nverts(geom->data.mesh));
+ break;
+ case GEOM_INSTANCE:
+ geom->irtc = rtcNewInstance2
+ (scnview->rtc_scn, geom->data.instance->scnview->rtc_scn);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(geom->irtc == RTC_INVALID_GEOMETRY_ID)
+ return RES_UNKNOWN_ERR;
+
+ scnview->rtc_scn_update = 1;
+ }
+
+ /* Register the embree geometry in the embree2geoms associative array */
+ if(geom->irtc >= darray_geom_size_get(&scnview->embree2geoms)) {
+ const res_T res = darray_geom_resize(&scnview->embree2geoms, geom->irtc+1);
+ if(res != RES_OK) {
+ rtcDeleteGeometry(scnview->rtc_scn, geom->irtc);
+ geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ return res;
+ }
+ }
+ darray_geom_data_get(&scnview->embree2geoms)[geom->irtc] = geom;
+ return RES_OK;
+}
+
+static INLINE void
+embree_geometry_setup_positions
+ (struct s3d_scene_view* scnview, struct geometry* geom)
+{
+ ASSERT(scnview && geom && geom->type == GEOM_MESH);
+ ASSERT(geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ rtcSetBuffer(scnview->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER,
+ mesh_get_pos(geom->data.mesh), 0, sizeof(float[3]));
+ rtcUpdateBuffer(scnview->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER);
+}
+
+static INLINE void
+embree_geometry_setup_indices
+ (struct s3d_scene_view* scnview, struct geometry* geom)
+{
+ ASSERT(scnview && geom && geom->type == GEOM_MESH);
+ ASSERT(geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ rtcSetBuffer(scnview->rtc_scn, geom->irtc, RTC_INDEX_BUFFER,
+ mesh_get_ids(geom->data.mesh), 0, sizeof(uint32_t[3]));
+ rtcUpdateBuffer(scnview->rtc_scn, geom->irtc, RTC_INDEX_BUFFER);
+}
+
+static INLINE void
+embree_geometry_setup_enable_state
+ (struct s3d_scene_view* scnview, struct geometry* geom)
+{
+ ASSERT(scnview && geom);
+ if(geom->is_enabled) {
+ rtcEnable(scnview->rtc_scn, geom->irtc);
+ } else {
+ rtcDisable(scnview->rtc_scn, geom->irtc);
+ }
+}
+
+static INLINE void
+embree_geometry_setup_filter_function
+ (struct s3d_scene_view* scnview, struct geometry* geom)
+{
+ ASSERT(scnview && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ ASSERT(geom->type == GEOM_MESH);
+
+ if(!geom->data.mesh->filter.func) {
+ rtcSetIntersectionFilterFunction(scnview->rtc_scn, geom->irtc, NULL);
+ } else {
+ rtcSetIntersectionFilterFunction(scnview->rtc_scn, geom->irtc, filter_wrapper);
+ rtcSetUserData(scnview->rtc_scn, geom->irtc, &geom->data.mesh->filter);
+ }
+}
+
+static INLINE void
+embree_geometry_setup_transform
+ (struct s3d_scene_view* scnview, struct geometry* geom)
+{
+ ASSERT(scnview && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID);
+ ASSERT(geom->type == GEOM_INSTANCE);
+ rtcSetTransform2
+ (scnview->rtc_scn,
+ geom->irtc,
+ RTC_MATRIX_COLUMN_MAJOR,
+ geom->data.instance->transform);
+ rtcUpdate(scnview->rtc_scn, geom->irtc);
+}
+
+static INLINE res_T
+scene_view_setup_embree(struct s3d_scene_view* scnview)
+{
+ struct htable_geom_iterator it, end;
+ const RTCSceneFlags rtc_scene_mask =
+ RTC_SCENE_DYNAMIC
+ | RTC_SCENE_INCOHERENT
+ | RTC_SCENE_ROBUST;
+ const RTCAlgorithmFlags rtc_algorithm_mask =
+ RTC_INTERSECT1
+ | RTC_INTERSECT4;
+ int rtc_outdated = 0;
+ res_T res = RES_OK;
+ ASSERT(scnview);
+
+ /* The rtc_scn could be already allocated since the scene views are cached */
+ if(!scnview->rtc_scn) {
+ scnview->rtc_scn = rtcDeviceNewScene
+ (scnview->scn->dev->rtc, rtc_scene_mask, rtc_algorithm_mask);
+ if(!scnview->rtc_scn) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ }
+
+ htable_geom_begin(&scnview->cached_geoms, &it);
+ htable_geom_end(&scnview->cached_geoms, &end);
+
+ while(!htable_geom_iterator_eq(&it, &end)) {
+ struct geometry** pgeom = htable_geom_iterator_data_get(&it);
+ struct geometry* geom = *pgeom;
+
+ htable_geom_iterator_next(&it);
+
+ /* Define whether or not the embree scene is outdated */
+ if(geom->embree_outdated_mask) rtc_outdated = 1;
+
+ /* Register the embree geometry */
+ res = embree_geometry_register(scnview, geom);
+ if(res != RES_OK) goto error;
+
+ /* Flush the embree geometry states */
+ if((geom->embree_outdated_mask & EMBREE_VERTICES) != 0)
+ embree_geometry_setup_positions(scnview, geom);
+ if((geom->embree_outdated_mask & EMBREE_INDICES) != 0)
+ embree_geometry_setup_indices(scnview, geom);
+ if((geom->embree_outdated_mask & EMBREE_ENABLE) != 0)
+ embree_geometry_setup_enable_state(scnview, geom);
+ if((geom->embree_outdated_mask & EMBREE_FILTER_FUNCTION) != 0)
+ embree_geometry_setup_filter_function(scnview, geom);
+ if((geom->embree_outdated_mask & EMBREE_TRANSFORM) != 0)
+ embree_geometry_setup_transform(scnview, geom);
+
+ geom->embree_outdated_mask = 0;
+ }
+
+ rtc_outdated = rtc_outdated || scnview->rtc_scn_update;
+
+ /* Commit the embree changes */
+ if(rtc_outdated) {
+ rtcCommit(scnview->rtc_scn);
+ scnview->rtc_scn_update = 0;
+ }
+
+exit:
+ return res;
+error:
+ if(scnview->rtc_scn) {
+ scnview->rtc_scn = NULL;
+ rtcDeleteScene(scnview->rtc_scn);
+ }
+ darray_geom_clear(&scnview->embree2geoms);
+ goto exit;
+}
+
+static res_T
+scene_view_register_mesh
+ (struct s3d_scene_view* scnview,
+ struct s3d_shape* shape)
+{
+ struct geometry** pgeom = NULL;
+ struct geometry* geom = NULL;
+ size_t iattr;
+ unsigned shape_id;
+
+ res_T res = RES_OK;
+ ASSERT(scnview && shape && shape->type == GEOM_MESH);
+
+ /* Retrieve the cached geometry */
+ S3D(shape_get_id(shape, &shape_id));
+ pgeom = htable_geom_find(&scnview->cached_geoms, &shape_id);
+ if(pgeom) {
+ geom = *pgeom;
+ } else {
+ res = geometry_create(scnview->scn->dev, &geom);
+ if(res != RES_OK) goto error;
+ res = mesh_create(scnview->scn->dev, &geom->data.mesh);
+ if(res != RES_OK) goto error;
+ geom->type = GEOM_MESH;
+ res = htable_geom_set(&scnview->cached_geoms, &shape_id, &geom);
+ if(res != RES_OK) goto error;
+ geom->name = shape->id.index;
+ }
+
+ /* Discard the geometry that is not geometrically valid */
+ if(!shape->data.mesh->indices || !shape->data.mesh->attribs[S3D_POSITION]) {
+ if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
+ rtcDeleteGeometry(scnview->rtc_scn, geom->irtc);
+ geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ }
+ mesh_clear(geom->data.mesh);
+ goto exit;
+ }
+
+ /* Get a reference onto the shape mesh indices */
+ if(geom->data.mesh->indices != shape->data.mesh->indices) {
+ geom->embree_outdated_mask |= EMBREE_INDICES;
+ if(geom->data.mesh->indices) { /* Release the previous index buffer */
+ index_buffer_ref_put(geom->data.mesh->indices);
+ geom->data.mesh->indices = NULL;
+ }
+ ASSERT(shape->data.mesh->indices);
+ index_buffer_ref_get(shape->data.mesh->indices);
+ geom->data.mesh->indices = shape->data.mesh->indices;
+ }
+
+ /* Get a reference onto the shape mesh attribs */
+ FOR_EACH(iattr, 0, S3D_ATTRIBS_COUNT__) {
+ geom->embree_outdated_mask |= EMBREE_VERTICES;
+ if(geom->data.mesh->attribs[iattr] == shape->data.mesh->attribs[iattr])
+ continue;
+
+ if(geom->data.mesh->attribs[iattr]) { /* Release the previous buffer */
+ vertex_buffer_ref_put(geom->data.mesh->attribs[iattr]);
+ geom->data.mesh->attribs[iattr] = NULL;
+ }
+ if(!shape->data.mesh->attribs[iattr])
+ continue;
+
+ vertex_buffer_ref_get(shape->data.mesh->attribs[iattr]);
+ geom->data.mesh->attribs[iattr] = shape->data.mesh->attribs[iattr];
+ geom->data.mesh->attribs_type[iattr] = shape->data.mesh->attribs_type[iattr];
+ }
+
+ /* Update the enable flag */
+ if(geom->is_enabled != shape->is_enabled) {
+ geom->is_enabled = shape->is_enabled;
+ geom->embree_outdated_mask |= EMBREE_ENABLE;
+ }
+
+ /* Update the filter function */
+ if(geom->data.mesh->filter.func != shape->data.mesh->filter.func
+ || geom->data.mesh->filter.data != shape->data.mesh->filter.data) {
+ geom->data.mesh->filter = shape->data.mesh->filter;
+ geom->embree_outdated_mask |= EMBREE_FILTER_FUNCTION;
+ }
+
+ if(geom->irtc != RTC_INVALID_GEOMETRY_ID) {
+ struct index_buffer* shape_ids = shape->data.mesh->indices;
+ struct index_buffer* geom_ids = geom->data.mesh->indices;
+ struct vertex_buffer* shape_verts = shape->data.mesh->attribs[S3D_POSITION];
+ struct vertex_buffer* geom_verts = geom->data.mesh->attribs[S3D_POSITION];
+ const size_t shape_nids = darray_u32_size_get(&shape_ids->data);
+ const size_t geom_nids = darray_u32_size_get(&geom_ids->data);
+ const size_t shape_nverts = darray_float_size_get(&shape_verts->data);
+ const size_t geom_nverts = darray_float_size_get(&geom_verts->data);
+
+ /* The shape mesh was resize => the Embree geometry is no more valid */
+ if(shape_nids != geom_nids || shape_nverts != geom_nverts) {
+ rtcDeleteGeometry(scnview->rtc_scn, geom->irtc);
+ geom->irtc = RTC_INVALID_GEOMETRY_ID;
+ }
+ }
+
+ geom->flip_surface = shape->flip_surface;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+scene_view_register_instance
+ (struct s3d_scene_view* scnview,
+ struct s3d_shape* shape,
+ const int mask)
+{
+ struct geometry** pgeom = NULL;
+ struct geometry* geom = NULL;
+ struct s3d_scene_view** pview = NULL;
+ struct s3d_scene_view* view = NULL;
+ unsigned shape_id;
+ res_T res = RES_OK;
+ ASSERT(scnview && shape && shape->type == GEOM_INSTANCE);
+
+ /* The instance cannot contain instances, i.e. one instancing level is
+ * supported */
+ if(shape->data.instance->scene->instances_count != 0) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Recursively create scnview on the scene to instantiate if necessary */
+ pview = htable_instview_find
+ (&scnview->instviews, &shape->data.instance->scene);
+ if(pview) {
+ view = *pview;
+ } else {
+ res = s3d_scene_view_create
+ (shape->data.instance->scene, mask, &view);
+ if(res != RES_OK) goto error;
+ res = htable_instview_set
+ (&scnview->instviews, &shape->data.instance->scene, &view);
+ if(res != RES_OK) goto error;
+ }
+
+ /* Create the scene instance of the geometry if necessary */
+ S3D(shape_get_id(shape, &shape_id));
+ pgeom = htable_geom_find(&scnview->cached_geoms, &shape_id);
+ if(pgeom) {
+ geom = *pgeom;
+ } else {
+ res = geometry_create(scnview->scn->dev, &geom);
+ if(res != RES_OK) goto error;
+ geom->type = GEOM_INSTANCE;
+ res = instance_create(shape->data.instance->scene, &geom->data.instance);
+ if(res != RES_OK) goto error;
+ res = htable_geom_set(&scnview->cached_geoms, &shape_id, &geom);
+ if(res != RES_OK) goto error;
+ geom->name = shape->id.index;
+ }
+ ASSERT(geom->data.instance->scene == shape->data.instance->scene);
+ geom->data.instance->scnview = view;
+
+ /* Update the Embree instance transformation if necessary */
+ if(!f33_eq(shape->data.instance->transform, geom->data.instance->transform)
+ || !f3_eq(shape->data.instance->transform+9, geom->data.instance->transform+9)) {
+ geom->embree_outdated_mask |= EMBREE_TRANSFORM;
+ f33_set(geom->data.instance->transform, shape->data.instance->transform);
+ f3_set(geom->data.instance->transform+9, shape->data.instance->transform+9);
+ }
+
+ /* Update the enable flag */
+ if(geom->is_enabled != shape->is_enabled) {
+ geom->is_enabled = shape->is_enabled;
+ geom->embree_outdated_mask |= EMBREE_TRANSFORM;
+ }
+
+ geom->flip_surface = shape->flip_surface;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+scene_view_compute_cdf(struct s3d_scene_view* scnview)
+{
+ struct htable_geom_iterator it, end;
+ size_t len;
+ float area = 0.f;
+ res_T res = RES_OK;
+ ASSERT(scnview);
+ ASSERT(darray_fltui_size_get(&scnview->cdf) == 0);
+
+ htable_geom_begin(&scnview->cached_geoms, &it);
+ htable_geom_end(&scnview->cached_geoms, &end);
+
+ while(!htable_geom_iterator_eq(&it, &end)) {
+ const unsigned* shape_id = htable_geom_iterator_key_get(&it);
+ struct geometry* geom = *htable_geom_iterator_data_get(&it);
+ struct fltui fltui;
+
+ htable_geom_iterator_next(&it);
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH:
+ res = mesh_compute_cdf(geom->data.mesh);
+ if(res != RES_OK) goto error;
+ len = darray_float_size_get(&geom->data.mesh->cdf);
+ if(len) {
+ area += darray_float_cdata_get(&geom->data.mesh->cdf)[len - 1];
+ }
+ break;
+ case GEOM_INSTANCE:
+ /* The instance CDF was computed during its scnview synchronisation */
+ len = darray_fltui_size_get(&geom->data.instance->scnview->cdf);
+ if(len) {
+ area += darray_fltui_cdata_get
+ (&geom->data.instance->scnview->cdf)[len - 1].flt;
+ }
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ fltui.ui = *shape_id;
+ fltui.flt = area;
+ if(len) {
+ res = darray_fltui_push_back(&scnview->cdf, &fltui);
+ if(res != RES_OK) goto error;
+ }
+ }
+exit:
+ return res;
+error:
+ darray_fltui_clear(&scnview->cdf);
+ goto exit;
+}
+
+static res_T
+scene_view_compute_nprims_cdf
+ (struct s3d_scene_view* scnview,
+ const char store_cdf)
+{
+ struct htable_geom_iterator it, end;
+ size_t len;
+ unsigned nprims;
+ res_T res = RES_OK;
+ ASSERT(scnview);
+ ASSERT(darray_nprims_cdf_size_get(&scnview->nprims_cdf) == 0);
+
+ htable_geom_begin(&scnview->cached_geoms, &it);
+ htable_geom_end(&scnview->cached_geoms, &end);
+
+ nprims = 0;
+ while(!htable_geom_iterator_eq(&it, &end)) {
+ const unsigned* shape_id = htable_geom_iterator_key_get(&it);
+ struct geometry* geom = *htable_geom_iterator_data_get(&it);
+ struct nprims_cdf cdf;
+
+ htable_geom_iterator_next(&it);
+
+ if(!geom->is_enabled) continue;
+
+ geom->scene_prim_id_offset = nprims;
+ switch(geom->type) {
+ case GEOM_MESH:
+ len = mesh_get_ntris(geom->data.mesh);
+ nprims += (unsigned)len;
+ break;
+ case GEOM_INSTANCE:
+ /* The instance CDF was computed during its scnview synchronisation */
+ len = darray_nprims_cdf_size_get
+ (&geom->data.instance->scnview->nprims_cdf);
+ if(len) {
+ nprims += darray_nprims_cdf_cdata_get
+ (&geom->data.instance->scnview->nprims_cdf)[len - 1].nprims;
+ }
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+
+ cdf.nprims = nprims;
+ cdf.ishape = *shape_id;
+ if(store_cdf && len) {
+ res = darray_nprims_cdf_push_back(&scnview->nprims_cdf, &cdf);
+ if(res != RES_OK) goto error;
+ }
+ }
+exit:
+ return res;
+error:
+ darray_nprims_cdf_clear(&scnview->nprims_cdf);
+ goto exit;
+}
+
+static void
+scene_view_compute_scene_aabb(struct s3d_scene_view* scnview)
+{
+ struct htable_geom_iterator it, end;
+ float lower[3], upper[3];
+
+ ASSERT(scnview->lower[0] == FLT_MAX && scnview->upper[0] == -FLT_MAX);
+ ASSERT(scnview->lower[1] == FLT_MAX && scnview->upper[1] == -FLT_MAX);
+ ASSERT(scnview->lower[2] == FLT_MAX && scnview->upper[2] == -FLT_MAX);
+
+ htable_geom_begin(&scnview->cached_geoms, &it);
+ htable_geom_end(&scnview->cached_geoms, &end);
+
+ while(!htable_geom_iterator_eq(&it, &end)) {
+ struct instance* inst;
+ struct geometry* geom = *htable_geom_iterator_data_get(&it);
+
+ htable_geom_iterator_next(&it);
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH: mesh_compute_aabb(geom->data.mesh, lower, upper); break;
+ case GEOM_INSTANCE:
+ /* Note that the instance AABB was computed during its scnview
+ * synchronisation. */
+ inst = geom->data.instance;
+ if(aabb_is_degenerated(inst->scnview->lower, inst->scnview->upper)) {
+ /* Empty scene */
+ f3_splat(lower, FLT_MAX);
+ f3_splat(upper,-FLT_MAX);
+ } else {
+ /* Transform local scene AABB bounds in world space */
+ f33_mulf3(lower, inst->transform, inst->scnview->lower);
+ f33_mulf3(upper, inst->transform, inst->scnview->upper);
+ f3_add(lower, inst->transform + 9, lower);
+ f3_add(upper, inst->transform + 9, upper);
+ /* Define the world space AABB of the transformed local scene AABB */
+ if(lower[0] > upper[0]) SWAP(float, lower[0], upper[0]);
+ if(lower[1] > upper[1]) SWAP(float, lower[1], upper[1]);
+ if(lower[2] > upper[2]) SWAP(float, lower[2], upper[2]);
+ }
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ f3_min(scnview->lower, scnview->lower, lower);
+ f3_max(scnview->upper, scnview->upper, upper);
+ }
+}
+
+float
+scene_view_compute_volume
+ (struct s3d_scene_view* scnview,
+ const char flip_surface)
+{
+ struct htable_geom_iterator it, end;
+ float volume;
+
+ ASSERT(scnview);
+ htable_geom_begin(&scnview->cached_geoms, &it);
+ htable_geom_end(&scnview->cached_geoms, &end);
+
+ volume = 0.f;
+ while(!htable_geom_iterator_eq(&it, &end)) {
+ struct geometry* geom = *htable_geom_iterator_data_get(&it);
+ const char flip = geom->flip_surface ^ flip_surface;
+
+ htable_geom_iterator_next(&it);
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH:
+ volume += mesh_compute_volume(geom->data.mesh, flip);
+ break;
+ case GEOM_INSTANCE:
+ volume += scene_view_compute_volume(geom->data.instance->scnview, flip);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ }
+
+ if(volume < 0.f) {
+ log_warning(scnview->scn->dev,
+"%s:\n"
+"\tthe volume is negative. The scene shapes might not represent closed 2D\n"
+"\tmanifold volumes, or their surface normal might not point inward the volume.\n",
+ FUNC_NAME);
+ }
+
+ return volume;
+}
+
+
+static res_T
+scene_view_sync
+ (struct s3d_scene_view* scnview,
+ const int mask)
+{
+ struct htable_shape_iterator it, end;
+ res_T res = RES_OK;
+
+ ASSERT(scnview);
+ ASSERT((mask & (S3D_TRACE|S3D_SAMPLE|S3D_GET_PRIMITIVE)) != 0);
+
+ /* Commit the scene shape to the scnview */
+ htable_shape_begin(&scnview->scn->shapes, &it);
+ htable_shape_end(&scnview->scn->shapes, &end);
+ while(!htable_shape_iterator_eq(&it, &end)) {
+ struct s3d_shape** pshape = htable_shape_iterator_data_get(&it);
+ struct s3d_shape* shape = *pshape;
+
+ switch(shape->type) {
+ case GEOM_INSTANCE:
+ res = scene_view_register_instance(scnview, shape, mask);
+ break;
+ case GEOM_MESH:
+ res = scene_view_register_mesh(scnview, shape);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(res != RES_OK) goto error;
+ htable_shape_iterator_next(&it);
+ }
+
+ scene_view_compute_scene_aabb(scnview);
+
+ /* Setup the scene for the S3D_TRACE scnview */
+ if((mask & S3D_TRACE) != 0) {
+ res = scene_view_setup_embree(scnview);
+ if(res != RES_OK) goto error;
+ }
+ /* Setup the scene for the S3D_SAMPLE scnview */
+ if((mask & S3D_SAMPLE) != 0) {
+ res = scene_view_compute_cdf(scnview);
+ if(res != RES_OK) goto error;
+ }
+ /* Setup the scene for the scene_primitive_id/S3D_GET_PRIMITIVE scnview */
+ res = scene_view_compute_nprims_cdf(scnview, (mask & S3D_GET_PRIMITIVE)!=0);
+ if(res != RES_OK) goto error;
+
+ scnview->mask = mask;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+scene_view_create(struct s3d_scene* scn, struct s3d_scene_view** out_scnview)
+{
+ struct s3d_scene_view* scnview = NULL;
+ res_T res = RES_OK;
+ ASSERT(scn && out_scnview);
+
+ if(!is_list_empty(&scn->scnviews)) {
+ /* Retrieve an already allocated scnview */
+ scnview = CONTAINER_OF(list_head(&scn->scnviews), struct s3d_scene_view, node);
+ list_del(&scnview->node);
+ ref_get(&scnview->ref);
+ } else {
+ scnview = (struct s3d_scene_view*)MEM_CALLOC
+ (scn->dev->allocator, 1, sizeof(struct s3d_scene_view));
+ if(!scnview) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ list_init(&scnview->node);
+ htable_geom_init(scn->dev->allocator, &scnview->cached_geoms);
+ darray_geom_init(scn->dev->allocator, &scnview->embree2geoms);
+ darray_fltui_init(scn->dev->allocator, &scnview->cdf);
+ darray_nprims_cdf_init(scn->dev->allocator, &scnview->nprims_cdf);
+ htable_instview_init(scn->dev->allocator, &scnview->instviews);
+ darray_uint_init(scn->dev->allocator, &scnview->detached_shapes);
+ f3_splat(scnview->lower, FLT_MAX);
+ f3_splat(scnview->upper,-FLT_MAX);
+ ref_init(&scnview->ref);
+
+ CLBK_INIT(&scnview->on_shape_detach_cb);
+ CLBK_SETUP(&scnview->on_shape_detach_cb, on_shape_detach, scnview);
+ SIG_CONNECT_CLBK(&scn->sig_shape_detach, &scnview->on_shape_detach_cb);
+ }
+ S3D(scene_ref_get(scn));
+ scnview->scn = scn;
+exit:
+ *out_scnview = scnview;
+ return res;
+error:
+ if(scnview) {
+ S3D(scene_view_ref_put(scnview));
+ scnview = NULL;
+ }
+ goto exit;
+}
+
+static void
+scene_view_release(ref_T* ref)
+{
+ struct htable_instview_iterator it_view, end_view;
+ struct htable_geom_iterator it_geom, end_geom;
+ struct s3d_scene_view* scnview = CONTAINER_OF(ref, struct s3d_scene_view, ref);
+ size_t i, n;
+ ASSERT(ref);
+
+ /* Release the scnview of the instances */
+ htable_instview_begin(&scnview->instviews, &it_view);
+ htable_instview_end(&scnview->instviews, &end_view);
+ while(!htable_instview_iterator_eq(&it_view, &end_view)) {
+ struct s3d_scene_view* view = *htable_instview_iterator_data_get(&it_view);
+ htable_instview_iterator_next(&it_view);
+ S3D(scene_view_ref_put(view));
+ }
+ htable_instview_clear(&scnview->instviews);
+
+ /* Reset the scnview of the cached instance. Note that this step is actually
+ * not necessary but this reset is "appreciated" in debug */
+ htable_geom_begin(&scnview->cached_geoms, &it_geom);
+ htable_geom_end(&scnview->cached_geoms, &end_geom);
+ while(!htable_geom_iterator_eq(&it_geom, &end_geom)) {
+ struct geometry* geom = *htable_geom_iterator_data_get(&it_geom);
+ htable_geom_iterator_next(&it_geom);
+ if(geom->type != GEOM_INSTANCE) continue;
+ geom->data.instance->scnview = NULL;
+ }
+
+ /* Remove the geometry of the shapes detached while the scnview was active */
+ n = darray_uint_size_get(&scnview->detached_shapes);
+ FOR_EACH(i, 0, n) {
+ const unsigned shape_id = darray_uint_cdata_get(&scnview->detached_shapes)[i];
+ struct geometry** pgeom = htable_geom_find(&scnview->cached_geoms, &shape_id);
+ struct geometry* geom = *pgeom;
+ size_t tmp; (void)tmp;
+ scene_view_destroy_geometry(scnview, geom);
+ tmp = htable_geom_erase(&scnview->cached_geoms, &shape_id);
+ ASSERT(tmp == 1);
+ }
+ darray_uint_clear(&scnview->detached_shapes);
+
+ /* Clear the scnview data structures excepted the cache of geometries that
+ * will be used to speed up the future scnview creation */
+ darray_geom_clear(&scnview->embree2geoms);
+ darray_fltui_clear(&scnview->cdf);
+ darray_nprims_cdf_clear(&scnview->nprims_cdf);
+ f3_splat(scnview->lower, FLT_MAX);
+ f3_splat(scnview->upper,-FLT_MAX);
+ scnview->mask = 0;
+
+ /* Do not physically release the memory space of the scnview. Add it to the
+ * available scnviews pool of the scene */
+ list_add(&scnview->scn->scnviews, &scnview->node);
+ S3D(scene_ref_put(scnview->scn));
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+s3d_scene_view_create
+ (struct s3d_scene* scn,
+ const int mask,
+ struct s3d_scene_view** out_scnview)
+{
+ struct s3d_scene_view* scnview = NULL;
+ res_T res = RES_OK;
+
+ if(!scn || !out_scnview) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(!(mask & S3D_TRACE)
+ && !(mask & S3D_SAMPLE)
+ && !(mask & S3D_GET_PRIMITIVE)) {
+ log_error(scn->dev, "%s: no valid scene view mask is defined.\n", FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = scene_view_create(scn, &scnview);
+ if(res != RES_OK) goto error;
+
+ res = scene_view_sync(scnview, mask);
+ if(res != RES_OK) goto error;
+
+exit:
+ if(out_scnview) *out_scnview = scnview;
+ return res;
+error:
+ if(scnview) {
+ S3D(scene_view_ref_put(scnview));
+ scnview = NULL;
+ }
+ goto exit;
+}
+
+res_T
+s3d_scene_view_ref_get(struct s3d_scene_view* scnview)
+{
+ if(!scnview) return RES_BAD_ARG;
+ ref_get(&scnview->ref);
+ return RES_OK;
+}
+
+res_T
+s3d_scene_view_ref_put(struct s3d_scene_view* scnview)
+{
+ if(!scnview) return RES_BAD_ARG;
+ ref_put(&scnview->ref, scene_view_release);
+ return RES_OK;
+}
+
+res_T
+s3d_scene_view_get_mask(struct s3d_scene_view* scnview, int* mask)
+{
+ if(!scnview || !mask) return RES_BAD_ARG;
+ *mask = scnview->mask;
+ return RES_OK;
+}
+
+res_T
+s3d_scene_view_trace_ray
+ (struct s3d_scene_view* scnview,
+ const float org[3],
+ const float dir[3],
+ const float range[2],
+ void* ray_data,
+ struct s3d_hit* hit)
+{
+ struct ray_extended ray_ex;
+ if(!scnview || !org || !dir || !range || !hit)
+ return RES_BAD_ARG;
+ if(!f3_is_normalized(dir)) {
+ log_error(scnview->scn->dev,
+ "%s: unnormalized ray direction {%g, %g, %g}.\n",
+ FUNC_NAME, SPLIT3(dir));
+ return RES_BAD_ARG;
+ }
+ if((scnview->mask & S3D_TRACE) == 0) {
+ log_error(scnview->scn->dev,
+ "%s: no active S3D_TRACE scnview on the submitted scnview.\n", FUNC_NAME);
+ return RES_BAD_OP;
+ }
+ if(range[0] > range[1]) { /* Degenerated range <=> disabled ray */
+ *hit = S3D_HIT_NULL;
+ return RES_OK;
+ }
+
+ f3_set(ray_ex.org, f3_set(ray_ex.ws_org, org));
+ f3_set(ray_ex.dir, f3_set(ray_ex.ws_dir, dir));
+ ray_ex.tnear = range[0];
+ ray_ex.tfar = range[1];
+ ray_ex.geomID = RTC_INVALID_GEOMETRY_ID;
+ ray_ex.primID = RTC_INVALID_GEOMETRY_ID;
+ ray_ex.instID = RTC_INVALID_GEOMETRY_ID;
+ ray_ex.mask = 0xFFFFFFFF;
+ ray_ex.time = 0.f;
+ ray_ex.scnview = scnview;
+ ray_ex.data = ray_data;
+
+ rtcIntersect(scnview->rtc_scn, ray_ex);
+
+ hit_setup(scnview, &ray_ex, hit);
+
+ return RES_OK;
+}
+
+res_T
+s3d_scene_view_trace_rays
+ (struct s3d_scene_view* scnview,
+ const size_t nrays,
+ const int mask,
+ const float* origins,
+ const float* directions,
+ const float* ranges,
+ void* rays_data,
+ const size_t sizeof_ray_data,
+ struct s3d_hit* hits)
+{
+ size_t iray;
+ size_t iorg, idir, irange, idata;
+ size_t org_step, dir_step, range_step, data_step;
+ res_T res = RES_OK;
+
+ if(!scnview) return RES_BAD_ARG;
+ if(!nrays) return RES_OK;
+
+ org_step = mask & S3D_RAYS_SINGLE_ORIGIN ? 0 : 3;
+ dir_step = mask & S3D_RAYS_SINGLE_DIRECTION ? 0 : 3;
+ range_step = mask & S3D_RAYS_SINGLE_RANGE ? 0 : 2;
+ data_step = (mask & S3D_RAYS_SINGLE_DATA) || !rays_data ? 0 : sizeof_ray_data;
+ iorg = idir = irange = idata = 0;
+
+ FOR_EACH(iray, 0, nrays) {
+ res = s3d_scene_view_trace_ray(scnview, origins+iorg, directions+idir,
+ ranges+irange, (char*)rays_data+idata, hits+iray);
+ if(UNLIKELY(res != RES_OK)) break;
+ iorg += org_step;
+ idir += dir_step;
+ irange += range_step;
+ idata += data_step;
+ }
+ return res;
+}
+
+res_T
+s3d_scene_view_sample
+ (struct s3d_scene_view* scnview,
+ const float u,
+ const float v,
+ const float w,
+ struct s3d_primitive* primitive, /* sampled primitive */
+ float st[2])
+{
+ struct geometry** pgeom;
+ struct geometry* geom;
+ const struct fltui* fltui_begin, *fltui_end, *fltui_found;
+ const float* flt_begin, *flt_end, *flt_found;
+ unsigned ishape;
+ float f;
+ res_T res = RES_OK;
+
+ if(!scnview || !primitive || !st) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ /* Expecting canonic numbers */
+ if(u < 0.f || u >= 1.f || v < 0.f || v >= 1.f || w < 0.f || w >= 1.f) {
+ log_error(scnview->scn->dev,
+ "%s: the submitted numbers are not canonical, i.e. they are not in [0, 1[.\n",
+ FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if((scnview->mask & S3D_SAMPLE) == 0) {
+ log_error(scnview->scn->dev,
+ "%s: no active S3D_SAMPLE scnview on the submitted scene.\n",
+ FUNC_NAME);
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ /* Find the sampled geometry */
+ if(darray_fltui_size_get(&scnview->cdf) == 0) {
+ /* No geometry to sample */
+ *primitive = S3D_PRIMITIVE_NULL;
+ goto exit;
+ } else if(darray_fltui_size_get(&scnview->cdf) == 1) {
+ ishape = darray_fltui_cdata_get(&scnview->cdf)[0].ui;
+ /* Map u to the CDF bounds */
+ f = u * darray_fltui_cdata_get(&scnview->cdf)[0].flt;
+ } else {
+ fltui_begin = darray_fltui_cdata_get(&scnview->cdf);
+ fltui_end = fltui_begin + darray_fltui_size_get(&scnview->cdf);
+ f = u * fltui_end[-1].flt; /* Map u to the CDF bounds */
+ fltui_found = std::lower_bound(fltui_begin, fltui_end, f);
+ ASSERT(fltui_found != fltui_end);
+ ishape = fltui_found->ui;
+
+ /* Transform u to the geometry CDF bounds */
+ if(fltui_found != fltui_begin)
+ f -= fltui_found[-1].flt;
+ }
+ pgeom = htable_geom_find(&scnview->cached_geoms, &ishape);
+ ASSERT(pgeom);
+ geom = *pgeom;
+
+ if(geom->type == GEOM_MESH) {
+ primitive->inst__ = NULL;
+ primitive->inst_id = S3D_INVALID_ID;
+ primitive->scene_prim_id = 0;
+ } else {
+ /* Find the sampled instantiated geometry */
+ ASSERT(geom->type == GEOM_INSTANCE);
+ primitive->inst__ = geom;
+ primitive->inst_id = geom->name;
+ primitive->scene_prim_id = geom->scene_prim_id_offset;
+ if(darray_fltui_size_get(&geom->data.instance->scnview->cdf) == 1) {
+ ishape = darray_fltui_cdata_get(&geom->data.instance->scnview->cdf)[0].ui;
+ } else {
+ fltui_begin = darray_fltui_cdata_get(&geom->data.instance->scnview->cdf);
+ fltui_end = fltui_begin + darray_fltui_size_get(&geom->data.instance->scnview->cdf);
+ fltui_found = std::lower_bound(fltui_begin, fltui_end, f);
+ ASSERT(fltui_found != fltui_end);
+ ishape = fltui_found->ui;
+
+ /* Transform u to the geometry CDF bounds */
+ if(fltui_found != fltui_begin)
+ f -= fltui_found[-1].flt;
+ }
+ pgeom = htable_geom_find(&geom->data.instance->scnview->cached_geoms, &ishape);
+ ASSERT(pgeom);
+ geom = *pgeom;
+ }
+ ASSERT(geom->type == GEOM_MESH);
+
+ /* Find the sampled triangle */
+ primitive->mesh__ = geom;
+ primitive->geom_id = geom->name;
+ primitive->scene_prim_id += geom->scene_prim_id_offset;
+ flt_begin = darray_float_cdata_get(&geom->data.mesh->cdf);
+ flt_end = flt_begin + darray_float_size_get(&geom->data.mesh->cdf);
+ flt_found = std::lower_bound(flt_begin, flt_end, f);
+ ASSERT(flt_found != flt_end);
+
+ primitive->prim_id = (unsigned)(flt_found - flt_begin);
+ primitive->scene_prim_id += primitive->prim_id;
+ S3D(primitive_sample(primitive, v, w, st));
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+s3d_scene_view_get_primitive
+ (struct s3d_scene_view* scnview,
+ const unsigned iprim,
+ struct s3d_primitive* prim)
+{
+ struct geometry** pgeom;
+ struct geometry* geom;
+ const struct nprims_cdf* begin, *end, *found;
+ size_t nprims;
+ unsigned ishape;
+ size_t i;
+ res_T res = RES_OK;
+
+ if(!scnview || !prim) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if((scnview->mask & S3D_GET_PRIMITIVE) == 0) {
+ log_error(scnview->scn->dev,
+ "%s: no active S3D_GET_PRIMITIVE scnview on the submitted scene.\n",
+ FUNC_NAME);
+ res = RES_BAD_OP;
+ goto error;
+ }
+ S3D(scene_view_primitives_count(scnview, &nprims));
+ if(iprim >= nprims) {
+ log_error(scnview->scn->dev,
+ "%s: the primitive index %u exceeds the number of scene primitives %u.\n",
+ FUNC_NAME, iprim, (unsigned)nprims);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ i = iprim;
+ if(darray_nprims_cdf_size_get(&scnview->nprims_cdf) == 1) {
+ ishape = darray_nprims_cdf_cdata_get(&scnview->nprims_cdf)[0].ishape;
+ } else {
+ begin = darray_nprims_cdf_cdata_get(&scnview->nprims_cdf);
+ end = begin + darray_nprims_cdf_size_get(&scnview->nprims_cdf);
+ found = std::lower_bound(begin, end, i);
+ ASSERT(found != end);
+ ishape = found->ishape;
+ if(found != begin) {
+ ASSERT(i >= found[-1].nprims);
+ i -= found[-1].nprims;
+ }
+ }
+ pgeom = htable_geom_find(&scnview->cached_geoms, &ishape);
+ ASSERT(pgeom);
+ geom = *pgeom;
+
+ if(geom->type == GEOM_MESH) {
+ prim->inst__ = NULL;
+ prim->inst_id = S3D_INVALID_ID;
+ prim->scene_prim_id = 0;
+ } else {
+ ASSERT(geom->type == GEOM_INSTANCE);
+ prim->inst__ = geom;
+ prim->inst_id = geom->name;
+ prim->scene_prim_id = geom->scene_prim_id_offset;
+ if(darray_nprims_cdf_size_get(&geom->data.instance->scnview->nprims_cdf)==1) {
+ ishape = darray_nprims_cdf_cdata_get
+ (&geom->data.instance->scnview->nprims_cdf)[0].ishape;
+ } else {
+ begin = darray_nprims_cdf_cdata_get
+ (&geom->data.instance->scnview->nprims_cdf);
+ end = begin + darray_nprims_cdf_size_get
+ (&geom->data.instance->scnview->nprims_cdf);
+ found = std::lower_bound(begin, end, i);
+ ASSERT(found != end);
+ ishape = found->ishape;
+ if(found != begin) {
+ ASSERT(i >= found[-1].nprims);
+ i -= found[-1].nprims;
+ }
+ }
+ pgeom = htable_geom_find(&geom->data.instance->scnview->cached_geoms, &ishape);
+ ASSERT(pgeom);
+ geom = *pgeom;
+ }
+ ASSERT(geom->type == GEOM_MESH);
+ ASSERT(i < mesh_get_ntris(geom->data.mesh));
+ prim->mesh__ = geom;
+ prim->geom_id = geom->name;
+ prim->prim_id = (unsigned)i;
+ prim->scene_prim_id += geom->scene_prim_id_offset;
+ prim->scene_prim_id += prim->prim_id;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+s3d_scene_view_primitives_count(struct s3d_scene_view* scnview, size_t* prims_count)
+{
+ res_T res = RES_OK;
+
+ if(!scnview || !prims_count) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if((scnview->mask & S3D_GET_PRIMITIVE) != 0) {
+ const size_t len = darray_nprims_cdf_size_get(&scnview->nprims_cdf);
+ if(!len) {
+ *prims_count = 0;
+ } else {
+ *prims_count = darray_nprims_cdf_cdata_get
+ (&scnview->nprims_cdf)[len - 1].nprims;
+ }
+ } else {
+ struct htable_geom_iterator it, end;
+ size_t inst_count;
+
+ htable_geom_begin(&scnview->cached_geoms, &it);
+ htable_geom_end(&scnview->cached_geoms, &end);
+ *prims_count = 0;
+ while(!htable_geom_iterator_eq(&it, &end)) {
+ struct geometry** pgeom = htable_geom_iterator_data_get(&it);
+ struct geometry* geom = *pgeom;
+ htable_geom_iterator_next(&it);
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH:
+ *prims_count += mesh_get_ntris(geom->data.mesh);
+ break;
+ case GEOM_INSTANCE:
+ S3D(scene_view_primitives_count(geom->data.instance->scnview, &inst_count));
+ *prims_count += inst_count;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ }
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+s3d_scene_view_compute_area(struct s3d_scene_view* scnview, float* out_area)
+{
+ float area;
+ res_T res = RES_OK;
+
+ if(!scnview || !out_area) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if((scnview->mask & S3D_SAMPLE) != 0) {
+ /* Retrieve the overall scene area from the scene cumulative distribution
+ * function. Note that the CDF stores the cumulative triangle area
+ * multiplied by 2; the real scene area is thus the CDF upper bound / 2 */
+ size_t len = darray_fltui_size_get(&scnview->cdf);
+ if(!len) {
+ area = 0.f;
+ } else {
+ area = darray_fltui_cdata_get(&scnview->cdf)[len - 1].flt * 0.5f;
+ }
+ } else {
+ struct htable_geom_iterator it, end;
+ float inst_area;
+
+ htable_geom_begin(&scnview->cached_geoms, &it);
+ htable_geom_end(&scnview->cached_geoms, &end);
+
+ area = 0.f;
+ while(!htable_geom_iterator_eq(&it, &end)) {
+ struct geometry** pgeom = htable_geom_iterator_data_get(&it);
+ struct geometry* geom = *pgeom;
+
+ htable_geom_iterator_next(&it);
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH:
+ area += mesh_compute_area(geom->data.mesh);
+ break;
+ case GEOM_INSTANCE:
+ /* TODO take into account the instance scale factor */
+ S3D(scene_view_compute_area(geom->data.instance->scnview, &inst_area));
+ area += inst_area;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ }
+ }
+
+exit:
+ if(out_area) *out_area = area;
+ return res;
+error:
+ area = -1.f;
+ goto exit;
+}
+
+res_T
+s3d_scene_view_compute_volume(struct s3d_scene_view* scnview, float* out_volume)
+{
+ if(!scnview || !out_volume) return RES_BAD_ARG;
+ *out_volume = scene_view_compute_volume(scnview, 0/*No initial flip_surface*/);
+ return RES_OK;
+}
+
+res_T
+s3d_scene_view_get_aabb(struct s3d_scene_view* scnview, float lower[3], float upper[3])
+{
+ if(!scnview || !lower || !upper) return RES_BAD_ARG;
+ f3_set(lower, scnview->lower);
+ f3_set(upper, scnview->upper);
+ return RES_OK;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+void
+scene_view_destroy(struct s3d_scene_view* scnview)
+{
+ htable_geom_iterator it, end;
+ ASSERT(scnview && !is_list_empty(&scnview->node)/*Not in use*/);
+ ASSERT(scnview->mask == 0);
+
+ /* Delete the cached geometries */
+ htable_geom_begin(&scnview->cached_geoms, &it);
+ htable_geom_end(&scnview->cached_geoms, &end);
+ while(!htable_geom_iterator_eq(&it, &end)) {
+ struct geometry** pgeom = htable_geom_iterator_data_get(&it);
+ struct geometry* geom = *pgeom;
+ scene_view_destroy_geometry(scnview, geom);
+ htable_geom_iterator_next(&it);
+ }
+
+ /* Delete the back-end scene */
+ if(scnview->rtc_scn) rtcDeleteScene(scnview->rtc_scn);
+
+ /* Release internal data structure */
+ htable_geom_release(&scnview->cached_geoms);
+ darray_geom_release(&scnview->embree2geoms);
+ darray_fltui_release(&scnview->cdf);
+ darray_nprims_cdf_release(&scnview->nprims_cdf);
+ htable_instview_release(&scnview->instviews);
+ darray_uint_release(&scnview->detached_shapes);
+
+ /* Remove the scnview from its pool */
+ list_del(&scnview->node);
+ CLBK_DISCONNECT(&scnview->on_shape_detach_cb);
+
+ /* Free the scnview memory space */
+ MEM_RM(scnview->scn->dev->allocator, scnview);
+}
+
diff --git a/src/s3d_scene_view_c.h b/src/s3d_scene_view_c.h
@@ -0,0 +1,133 @@
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
+ *
+ * This software is a computer program whose purpose is to describe a
+ * virtual 3D environment that can be ray-traced and sampled both robustly
+ * and efficiently.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#ifndef S3D_SCENE_VIEW_C_H
+#define S3D_SCENE_VIEW_C_H
+
+#include "s3d_backend.h"
+#include "s3d_scene_c.h"
+
+#include <rsys/dynamic_array.h>
+#include <rsys/dynamic_array_uint.h>
+#include <rsys/hash_table.h>
+#include <rsys/list.h>
+#include <rsys/ref_count.h>
+
+/* Forward declarations */
+struct s3d_scene_view;
+
+/*
+ * The geometry pointers must be initialized to NULL in order to define
+ * which pointers are valid or not
+ */
+static FINLINE void
+geom_ptr_init__(struct mem_allocator* alloc, struct geometry** geom)
+{
+ (void)alloc; *geom = NULL;
+}
+
+/* Generate the darray_geom dynamic array */
+#define DARRAY_NAME geom
+#define DARRAY_DATA struct geometry*
+#define DARRAY_FUNCTOR_INIT geom_ptr_init__
+#include <rsys/dynamic_array.h>
+
+/* Generate the htable_geom hash table */
+#define HTABLE_NAME geom
+#define HTABLE_DATA struct geometry*
+#define HTABLE_KEY unsigned /* Id of the shape */
+#include <rsys/hash_table.h>
+
+/* Generate the darray_fltui dynamic array */
+struct fltui { float flt; unsigned ui; };
+#define DARRAY_NAME fltui
+#define DARRAY_DATA struct fltui
+#include <rsys/dynamic_array.h>
+
+/* Generate the darray_geom_nprims array */
+struct nprims_cdf { unsigned nprims, ishape; };
+#define DARRAY_NAME nprims_cdf
+#define DARRAY_DATA struct nprims_cdf
+#include <rsys/dynamic_array.h>
+
+/* Generate the htable_instview hash table */
+#define HTABLE_NAME instview
+#define HTABLE_DATA struct s3d_scene_view*
+#define HTABLE_KEY struct s3d_scene*
+#include <rsys/hash_table.h>
+
+struct s3d_scene_view {
+ struct list_node node; /* Attachment point to the scene scene_views pool */
+
+ struct htable_geom cached_geoms; /* Cached shape geometries */
+ struct darray_geom embree2geoms; /* Embree index to geometry */
+ struct darray_fltui cdf; /* Unormalized CDF */
+ struct darray_nprims_cdf nprims_cdf;
+
+ /* Map an instantiated scene to its scene view */
+ struct htable_instview instviews;
+
+ /* Id of Shapes detached while the scnview is active */
+ struct darray_uint detached_shapes;
+
+ float lower[3], upper[3]; /* AABB of the scene */
+
+ /* Callback attached to the sig_shape_detach signal of scn */
+ scene_shape_cb_T on_shape_detach_cb;
+
+ int mask; /* Combination of enum s3d_scene_view_flag */
+ int rtc_scn_update; /* Define if Embree geometries were deleted/added */
+ RTCScene rtc_scn; /* Embree scene */
+
+ ref_T ref;
+ struct s3d_scene* scn;
+};
+
+extern LOCAL_SYM void
+scene_view_destroy
+ (struct s3d_scene_view* scnview);
+
+static FINLINE struct geometry*
+scene_view_geometry_from_embree_id
+ (struct s3d_scene_view* scnview,
+ const unsigned irtc)
+{
+ struct geometry* geom;
+ ASSERT(scnview && irtc != RTC_INVALID_GEOMETRY_ID);
+ ASSERT(irtc < darray_geom_size_get(&scnview->embree2geoms));
+ geom = darray_geom_data_get(&scnview->embree2geoms)[irtc];
+ ASSERT(geom);
+ return geom;
+}
+
+#endif /* S3D_SCENE_VIEW_C_H */
+
diff --git a/src/s3d_shape.c b/src/s3d_shape.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -52,7 +52,6 @@ shape_release(ref_T* ref)
dev = shape->dev;
/* The shape should not be attached */
- ASSERT(is_list_empty(&shape->scene_attachment));
if(shape->type != GEOM_NONE) {
switch(shape->type) {
case GEOM_MESH:
@@ -64,6 +63,7 @@ shape_release(ref_T* ref)
default: FATAL("Unreachable code \n"); break;
}
}
+ flist_name_del(&dev->names, shape->id);
MEM_RM(dev->allocator, shape);
S3D(device_ref_put(dev));
}
@@ -87,7 +87,6 @@ shape_create(struct s3d_device* dev, struct s3d_shape** out_shape)
res = RES_MEM_ERR;
goto error;
}
- list_init(&shape->scene_attachment);
S3D(device_ref_get(dev));
shape->dev = dev;
ref_init(&shape->ref);
@@ -160,7 +159,7 @@ s3d_shape_ref_put(struct s3d_shape* shape)
}
res_T
-s3d_shape_get_id(struct s3d_shape* shape, unsigned* id)
+s3d_shape_get_id(const struct s3d_shape* shape, unsigned* id)
{
if(!shape || !id) return RES_BAD_ARG;
*id = shape->id.index;
@@ -176,7 +175,7 @@ s3d_shape_enable(struct s3d_shape* shape, const char enable)
}
res_T
-s3d_shape_is_enabled(struct s3d_shape* shape, char* is_enabled)
+s3d_shape_is_enabled(const struct s3d_shape* shape, char* is_enabled)
{
if(!shape || !is_enabled) return RES_BAD_ARG;
*is_enabled = shape->is_enabled;
@@ -184,14 +183,6 @@ s3d_shape_is_enabled(struct s3d_shape* shape, char* is_enabled)
}
res_T
-s3d_shape_is_attached(struct s3d_shape* shape, char* is_attached)
-{
- if(!shape || !is_attached) return RES_BAD_ARG;
- *is_attached = !is_list_empty(&shape->scene_attachment);
- return RES_OK;
-}
-
-res_T
s3d_shape_flip_surface(struct s3d_shape* shape)
{
if(!shape) return RES_BAD_ARG;
@@ -212,7 +203,6 @@ s3d_instance_set_position
f3_dot(f33_row(axis, shape->data.instance->transform, 1), position);
shape->data.instance->transform[11] =
f3_dot(f33_row(axis, shape->data.instance->transform, 2), position);
- shape->data.instance->update_transform = 1;
return RES_OK;
}
@@ -231,13 +221,11 @@ s3d_instance_translate
(shape->data.instance->transform + 9,
shape->data.instance->transform + 9,
vec);
- shape->data.instance->update_transform = 1;
} else if(space == S3D_WORLD_TRANSFORM) {
f3_add
(shape->data.instance->transform + 9,
shape->data.instance->transform + 9,
translation);
- shape->data.instance->update_transform = 1;
} else {
return RES_BAD_ARG;
}
@@ -388,4 +376,3 @@ s3d_mesh_get_hit_filter_data(struct s3d_shape* shape, void** data)
return RES_OK;
}
-
diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -45,7 +45,6 @@
#include <limits.h>
struct s3d_shape {
- struct list_node scene_attachment;
struct fid id;
char flip_surface;
diff --git a/src/test_s3d_camera.h b/src/test_s3d_camera.h
@@ -0,0 +1,81 @@
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
+ *
+ * This software is a computer program whose purpose is to describe a
+ * virtual 3D environment that can be ray-traced and sampled both robustly
+ * and efficiently.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#ifndef TEST_S3D_CAMERA_H
+#define TEST_S3D_CAMERA_H
+
+#include <rsys/float3.h>
+
+struct camera {
+ float pos[3];
+ float x[3], y[3], z[3]; /* Basis */
+};
+
+static INLINE void
+camera_init
+ (struct camera* cam,
+ const float pos[3],
+ const float tgt[3],
+ const float up[3],
+ const float fov_x,
+ const float proj_ratio)
+{
+ float f = 0.f;
+ ASSERT(cam);
+
+ f3_set(cam->pos, pos);
+ f = f3_normalize(cam->z, f3_sub(cam->z, tgt, pos)); NCHECK(f, 0);
+ f = f3_normalize(cam->x, f3_cross(cam->x, cam->z, up)); NCHECK(f, 0);
+ f = f3_normalize(cam->y, f3_cross(cam->y, cam->z, cam->x)); NCHECK(f, 0);
+ f3_divf(cam->z, cam->z, (float)tan(fov_x*0.5f));
+ f3_divf(cam->y, cam->y, proj_ratio);
+}
+
+static INLINE void
+camera_ray
+ (const struct camera* cam,
+ const float pixel[2],
+ float org[3],
+ float dir[3])
+{
+ float x[3], y[3], f;
+ ASSERT(cam && pixel && org && dir);
+
+ f3_mulf(x, cam->x, pixel[0]*2.f - 1.f);
+ f3_mulf(y, cam->y, pixel[1]*2.f - 1.f);
+ f3_add(dir, f3_add(dir, x, y), cam->z);
+ f = f3_normalize(dir, dir); NCHECK(f, 0);
+ f3_set(org, cam->pos);
+}
+
+#endif /* TEST_S3D_CAMERA_H */
+
diff --git a/src/test_s3d_cbox.h b/src/test_s3d_cbox.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -36,7 +36,7 @@
#include <rsys/rsys.h>
#include <stdint.h>
-struct cbox_desc{
+struct cbox_desc {
const float* vertices;
const unsigned* indices;
};
diff --git a/src/test_s3d_device.c b/src/test_s3d_device.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
diff --git a/src/test_s3d_primitive.c b/src/test_s3d_primitive.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -34,6 +34,7 @@
#include "test_s3d_cbox.h"
#include "test_s3d_utils.h"
+#include <rsys/float2.h>
#include <rsys/float3.h>
#include <rsys/math.h>
@@ -80,17 +81,29 @@ plane_get_pos(const unsigned ivert, float pos[3], void* data)
pos[2] = plane_verts[i + 2];
}
+static void
+plane_get_uv(const unsigned ivert, float uv[2], void* data)
+{
+ const unsigned i = ivert*3;
+ (void)data;
+ NCHECK(uv, NULL);
+ CHECK(ivert < plane_nverts, 1);
+ uv[0] = -plane_verts[i + 0];
+ uv[1] = -plane_verts[i + 1];
+}
+
int
main(int argc, char** argv)
{
struct mem_allocator allocator;
struct s3d_device* dev;
struct s3d_scene* scn;
+ struct s3d_scene_view* scnview;
struct s3d_shape* walls;
struct s3d_shape* plane;
struct s3d_attrib attr;
struct s3d_primitive prim = S3D_PRIMITIVE_NULL;
- struct s3d_vertex_data attribs;
+ struct s3d_vertex_data attribs[2];
struct cbox_desc desc;
size_t nprims;
size_t i;
@@ -112,24 +125,28 @@ main(int argc, char** argv)
CHECK(s3d_shape_get_id(walls, &walls_id), RES_OK);
CHECK(s3d_scene_attach_shape(scn, walls), RES_OK);
- attribs.usage = S3D_POSITION;
- attribs.type = S3D_FLOAT3;
- attribs.get = cbox_get_position;
+ attribs[1].usage = S3D_ATTRIB_0;
+ attribs[1].type = S3D_FLOAT2;
+ attribs[1].get = plane_get_uv;
+
+ attribs[0].usage = S3D_POSITION;
+ attribs[0].type = S3D_FLOAT3;
+ attribs[0].get = cbox_get_position;
ntris = cbox_walls_ntris;
nverts = cbox_walls_nverts;
desc.vertices = cbox_walls;
desc.indices = cbox_walls_ids;
CHECK(s3d_mesh_setup_indexed_vertices
- (walls, ntris, cbox_get_ids, nverts, &attribs, 1, &desc), RES_OK);
+ (walls, ntris, cbox_get_ids, nverts, attribs, 1, &desc), RES_OK);
- attribs.get = plane_get_pos;
+ attribs[0].get = plane_get_pos;
CHECK(s3d_mesh_setup_indexed_vertices
- (plane, plane_ntris, plane_get_ids, plane_nverts, &attribs, 1, NULL), RES_OK);
+ (plane, plane_ntris, plane_get_ids, plane_nverts, attribs, 2, NULL), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
- CHECK(s3d_scene_sample(scn, 0, 0, 0, &prim, uv), RES_OK);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0, 0, 0, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_primitive_get_attrib(NULL, S3D_ATTRIBS_COUNT__, NULL, NULL), RES_BAD_ARG);
CHECK(s3d_primitive_get_attrib(&prim, S3D_ATTRIBS_COUNT__, NULL, NULL), RES_BAD_ARG);
@@ -181,12 +198,18 @@ main(int argc, char** argv)
CHECK(s3d_scene_clear(scn), RES_OK);
CHECK(s3d_scene_attach_shape(scn, plane), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_GET_PRIMITIVE), RES_OK);
- CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
CHECK(nprims, 2);
- CHECK(s3d_scene_get_primitive(scn, 0, &prim), RES_OK);
+ CHECK(s3d_scene_view_get_primitive(scnview, 0, &prim), RES_OK);
CHECK(S3D_PRIMITIVE_EQ(&prim, &S3D_PRIMITIVE_NULL), 0);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_primitive_has_attrib(&prim, S3D_ATTRIB_0, &b), RES_OK);
+ CHECK(b, 1);
+ CHECK(s3d_primitive_has_attrib(&prim, S3D_ATTRIB_1, &b), RES_OK);
+ CHECK(b, 0);
CHECK(s3d_primitive_compute_area(NULL, NULL), RES_BAD_ARG);
CHECK(s3d_primitive_compute_area(&prim, NULL), RES_BAD_ARG);
@@ -220,6 +243,47 @@ main(int argc, char** argv)
CHECK(uv[1] <= 1.f, 1);
}
+ #define GET_VERTEX_ATTR s3d_triangle_get_vertex_attrib
+ CHECK(GET_VERTEX_ATTR(NULL, 3, S3D_GEOMETRY_NORMAL, NULL), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(&prim, 3, S3D_GEOMETRY_NORMAL, NULL), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(NULL, 0, S3D_GEOMETRY_NORMAL, NULL), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(&prim, 0, S3D_GEOMETRY_NORMAL, NULL), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(NULL, 3, S3D_POSITION, NULL), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(&prim, 3, S3D_POSITION, NULL), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(NULL, 0, S3D_POSITION, NULL), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(&prim, 0, S3D_POSITION, NULL), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(NULL, 3, S3D_GEOMETRY_NORMAL, &attr), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(&prim, 3, S3D_GEOMETRY_NORMAL, &attr), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(NULL, 0, S3D_GEOMETRY_NORMAL, &attr), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(&prim, 0, S3D_GEOMETRY_NORMAL, &attr), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(NULL, 3, S3D_POSITION, &attr), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(&prim, 3, S3D_POSITION, &attr), RES_BAD_ARG);
+ CHECK(GET_VERTEX_ATTR(NULL, 0, S3D_POSITION, &attr), RES_BAD_ARG);
+
+ CHECK(GET_VERTEX_ATTR(&prim, 0, S3D_POSITION, &attr), RES_OK);
+ CHECK(attr.type, S3D_FLOAT3);
+ CHECK(f3_eq_eps(attr.value, plane_verts + plane_ids[0]*3, 1.e-6f), 1);
+ CHECK(GET_VERTEX_ATTR(&prim, 1, S3D_POSITION, &attr), RES_OK);
+ CHECK(attr.type, S3D_FLOAT3);
+ CHECK(f3_eq_eps(attr.value, plane_verts + plane_ids[1]*3, 1.e-6f), 1);
+ CHECK(GET_VERTEX_ATTR(&prim, 2, S3D_POSITION, &attr), RES_OK);
+ CHECK(attr.type, S3D_FLOAT3);
+ CHECK(f3_eq_eps(attr.value, plane_verts + plane_ids[2]*3, 1.e-6f), 1);
+
+ CHECK(GET_VERTEX_ATTR(&prim, 0, S3D_ATTRIB_0, &attr), RES_OK);
+ CHECK(attr.type, S3D_FLOAT2);
+ f2_minus(uv, plane_verts + plane_ids[0]*3);
+ CHECK(f2_eq_eps(attr.value, uv, 1.e-6f), 1);
+ CHECK(GET_VERTEX_ATTR(&prim, 1, S3D_ATTRIB_0, &attr), RES_OK);
+ CHECK(attr.type, S3D_FLOAT2);
+ f2_minus(uv, plane_verts + plane_ids[1]*3);
+ CHECK(f2_eq_eps(attr.value, uv, 1.e-6f), 1);
+ CHECK(GET_VERTEX_ATTR(&prim, 2, S3D_ATTRIB_0, &attr), RES_OK);
+ CHECK(attr.type, S3D_FLOAT2);
+ f2_minus(uv, plane_verts + plane_ids[2]*3);
+ CHECK(f2_eq_eps(attr.value, uv, 1.e-6f), 1);
+ #undef GET_VERTEX_ATTR
+
CHECK(s3d_device_ref_put(dev), RES_OK);
CHECK(s3d_scene_ref_put(scn), RES_OK);
CHECK(s3d_shape_ref_put(walls), RES_OK);
diff --git a/src/test_s3d_sampler.c b/src/test_s3d_sampler.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -53,6 +53,7 @@ main(int argc, char** argv)
struct s3d_device* dev;
struct s3d_scene* scn;
struct s3d_scene* scn2;
+ struct s3d_scene_view* scnview;
struct s3d_shape* cbox;
struct s3d_shape* walls;
struct s3d_shape* short_block;
@@ -87,24 +88,24 @@ main(int argc, char** argv)
CHECK(s3d_shape_get_id(short_block, &short_block_id), RES_OK);
CHECK(s3d_shape_get_id(tall_block, &tall_block_id), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
- CHECK(s3d_scene_sample(NULL, 0, 0, 0, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0, 0, 0, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_sample(NULL, 0, 0, 0, &prim, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0, 0, 0, &prim, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_sample(NULL, 0, 0, 0, NULL, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0, 0, 0, NULL, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(NULL, 0, 0, 0, &prim, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0, 0, 0, &prim, uv), RES_OK);
- CHECK(s3d_scene_sample(scn, -1, 0, 0, &prim, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0, -1, 0, &prim, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0, 0, -1, &prim, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 1, 0, 0, &prim, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0, 1, 0, &prim, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0, 0, 1, &prim, uv), RES_BAD_ARG);
- CHECK(s3d_scene_sample(scn, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_sample(NULL, 0, 0, 0, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0, 0, 0, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(NULL, 0, 0, 0, &prim, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0, 0, 0, &prim, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(NULL, 0, 0, 0, NULL, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0, 0, 0, NULL, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(NULL, 0, 0, 0, &prim, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0, 0, 0, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, -1, 0, 0, &prim, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0, -1, 0, &prim, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0, 0, -1, &prim, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 1, 0, 0, &prim, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0, 1, 0, &prim, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0, 0, 1, &prim, uv), RES_BAD_ARG);
+ CHECK(s3d_scene_view_sample(scnview, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
CHECK(S3D_PRIMITIVE_EQ(&prim, &S3D_PRIMITIVE_NULL), 1);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
attribs.usage = S3D_POSITION;
attribs.type = S3D_FLOAT3;
@@ -119,12 +120,11 @@ main(int argc, char** argv)
CHECK(s3d_scene_attach_shape(scn, walls), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_BAD_OP);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
- CHECK(s3d_scene_sample(scn, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
CHECK(s3d_primitive_get_attrib(&prim, S3D_POSITION, uv, &attr0), RES_OK);
- CHECK(s3d_scene_sample(scn, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
CHECK(s3d_primitive_get_attrib(&prim, S3D_POSITION, uv, &attr1), RES_OK);
prim1 = prim;
@@ -143,21 +143,19 @@ main(int argc, char** argv)
CHECK(attr1.type, S3D_FLOAT3);
CHECK(f3_eq_eps(attr0.value, attr1.value, 1.e-6f), 1);
- CHECK(s3d_scene_sample(scn, 0.3f, 0.1f, 0.2f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.3f, 0.1f, 0.2f, &prim, uv), RES_OK);
CHECK(s3d_primitive_get_attrib(&prim, S3D_POSITION, uv, &attr1), RES_OK);
NCHECK(f3_eq_eps(attr0.value, attr1.value, 1.e-6f), 1);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_shape_enable(walls, 0), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
- CHECK(s3d_scene_sample(scn, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
CHECK(S3D_PRIMITIVE_EQ(&prim, &S3D_PRIMITIVE_NULL), 1);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_shape_enable(walls, 1), RES_OK);
- CHECK(s3d_scene_sample(scn, 0.5f, 0.5f, 0.5f, &prim, uv), RES_BAD_OP);
-
ntris = sizeof(cbox_block_ids)/sizeof(unsigned[3]);
nverts = sizeof(cbox_short_block)/sizeof(float[3]);
desc.vertices = cbox_short_block;
@@ -168,35 +166,35 @@ main(int argc, char** argv)
CHECK(s3d_scene_attach_shape(scn, short_block), RES_OK);
CHECK(s3d_scene_attach_shape(scn, tall_block), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
- CHECK(s3d_scene_sample(scn, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
CHECK(s3d_primitive_get_attrib(&prim, S3D_POSITION, uv, &attr0), RES_OK);
desc.vertices = cbox_tall_block;
CHECK(s3d_mesh_setup_indexed_vertices
(tall_block, ntris, cbox_get_ids, nverts, &attribs, 1, &desc), RES_OK);
- CHECK(s3d_scene_sample(scn, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
CHECK(s3d_primitive_get_attrib(&prim, S3D_POSITION, uv, &attr1), RES_OK);
CHECK(f3_eq_eps(attr0.value, attr1.value, 1.e-6f), 1);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
- CHECK(s3d_scene_sample(scn, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
CHECK(s3d_primitive_get_attrib(&prim, S3D_POSITION, uv, &attr1), RES_OK);
NCHECK(f3_eq_eps(attr0.value, attr1.value, 1.e-6f), 1);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_shape_enable(cbox, 0), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_SAMPLE|S3D_TRACE), RES_OK);
- CHECK(s3d_scene_sample(scn2, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_create(scn2, S3D_SAMPLE|S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.5f, 0.5f, 0.5f, &prim, uv), RES_OK);
CHECK(S3D_PRIMITIVE_EQ(&prim, &S3D_PRIMITIVE_NULL), 1);
- CHECK(s3d_scene_end_session(scn2), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_shape_enable(cbox, 1), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_SAMPLE|S3D_TRACE), RES_OK);
+ CHECK(s3d_scene_view_create(scn2, S3D_SAMPLE|S3D_TRACE, &scnview), RES_OK);
FOR_EACH(i, 0, NSAMPS) {
const float u = rand_canonic();
const float v = rand_canonic();
const float w = rand_canonic();
- CHECK(s3d_scene_sample(scn2, u, v, w, &prim, uv), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, u, v, w, &prim, uv), RES_OK);
CHECK(s3d_primitive_get_attrib(&prim, S3D_POSITION, uv, &attr0), RES_OK);
CHECK(prim.inst_id, cbox_id);
@@ -206,9 +204,9 @@ main(int argc, char** argv)
CHECK(prim.prim_id < 10, 1);
CHECK(prim.scene_prim_id >= prim.prim_id, 1);
CHECK(prim.scene_prim_id < 30, 1);
-/* printf("%f %f %f\n", SPLIT3(attr0.value)); */
+ printf("%f %f %f\n", SPLIT3(attr0.value));
}
- CHECK(s3d_scene_end_session(scn2), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_device_ref_put(dev), RES_OK);
CHECK(s3d_scene_ref_put(scn), RES_OK);
diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -92,11 +92,14 @@ main(int argc, char** argv)
struct s3d_scene* scn;
struct s3d_scene* scn2;
struct s3d_scene* scn3;
+ struct s3d_scene_view* scnview;
+ struct s3d_scene_view* scnview2;
+ struct s3d_scene_view* scnview3;
struct s3d_vertex_data attribs;
struct s3d_shape* shapes[4];
const size_t nshapes = sizeof(shapes)/sizeof(struct s3d_shape*);
void* data = (void*)&cbox_walls_desc;
- size_t i;
+ size_t i, n;
size_t nprims;
float area, volume, lower[3], upper[3];
unsigned id;
@@ -116,22 +119,36 @@ main(int argc, char** argv)
CHECK(s3d_scene_create(dev, &scn2), RES_OK);
CHECK(s3d_scene_create(dev, &scn3), RES_OK);
+ CHECK(s3d_scene_get_shapes_count(NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_get_shapes_count(scn, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_get_shapes_count(NULL, &n), RES_BAD_ARG);
+ CHECK(s3d_scene_get_shapes_count(scn, &n), RES_OK);
+ CHECK(n, 0);
+
CHECK(s3d_scene_attach_shape(NULL, NULL), RES_BAD_ARG);
CHECK(s3d_scene_attach_shape(scn, NULL), RES_BAD_ARG);
CHECK(s3d_scene_attach_shape(NULL, shapes[0]), RES_BAD_ARG);
CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK);
- CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_BAD_ARG);
+ CHECK(s3d_scene_get_shapes_count(scn, &n), RES_OK);
+ CHECK(n, 1);
+ CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK);
+ CHECK(s3d_scene_get_shapes_count(scn, &n), RES_OK);
+ CHECK(n, 1);
CHECK(s3d_scene_detach_shape(NULL, NULL), RES_BAD_ARG);
CHECK(s3d_scene_detach_shape(scn, NULL), RES_BAD_ARG);
CHECK(s3d_scene_detach_shape(NULL, shapes[0]), RES_BAD_ARG);
CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_OK);
CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_BAD_ARG);
+ CHECK(s3d_scene_get_shapes_count(scn, &n), RES_OK);
+ CHECK(n, 0);
FOR_EACH(i, 1, nshapes) {
CHECK(s3d_scene_attach_shape(scn, shapes[i]), RES_OK);
CHECK(s3d_shape_ref_put(shapes[i]), RES_OK);
}
+ CHECK(s3d_scene_get_shapes_count(scn, &n), RES_OK);
+ CHECK(n, nshapes - 1);
CHECK(s3d_scene_instantiate(NULL, NULL), RES_BAD_ARG);
CHECK(s3d_scene_instantiate(scn, NULL), RES_BAD_ARG);
@@ -146,88 +163,85 @@ main(int argc, char** argv)
CHECK(s3d_scene_clear(NULL), RES_BAD_ARG);
CHECK(s3d_scene_clear(scn), RES_OK);
+ CHECK(s3d_scene_get_shapes_count(scn, &n), RES_OK);
+ CHECK(n, 0);
CHECK(s3d_scene_clear(scn), RES_OK);
CHECK(s3d_scene_instantiate(scn, shapes + 2), RES_OK);
CHECK(s3d_scene_attach_shape(scn, shapes[2]), RES_BAD_ARG);
- CHECK(s3d_scene_get_session_mask(NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_session_mask(scn, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_session_mask(NULL, &mask), RES_BAD_ARG);
- CHECK(s3d_scene_get_session_mask(scn, &mask), RES_OK);
- CHECK(mask, 0);
-
CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK);
- CHECK(s3d_scene_begin_session(NULL, 0), RES_BAD_ARG);
- CHECK(s3d_scene_begin_session(scn, 0), RES_BAD_ARG);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE|S3D_GET_PRIMITIVE), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_BAD_OP);
+ CHECK(s3d_scene_get_shapes_count(scn, &n), RES_OK);
+ CHECK(n, 1);
- CHECK(s3d_scene_get_session_mask(scn, &mask), RES_OK);
- CHECK(mask & S3D_TRACE, S3D_TRACE);
- CHECK(mask & S3D_SAMPLE, 0);
-
- CHECK(s3d_scene_clear(scn), RES_BAD_OP);
- CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_BAD_OP);
-
- CHECK(s3d_scene_end_session(NULL), RES_BAD_ARG);
- CHECK(s3d_scene_end_session(scn), RES_OK);
- CHECK(s3d_scene_end_session(scn), RES_BAD_OP);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_get_mask(scnview, &mask), RES_OK);
+ CHECK(mask, S3D_TRACE);
+ CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_OK);
+ CHECK(s3d_scene_clear(scn), RES_OK);
- CHECK(s3d_scene_get_session_mask(scn, &mask), RES_OK);
- CHECK(mask, 0);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
- CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK);
CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_OK);
CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shapes[1]), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shapes[2]), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_SAMPLE|S3D_TRACE), RES_OK);
-
- CHECK(s3d_scene_compute_area(NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_compute_area(scn2, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_compute_area(NULL, &area), RES_BAD_ARG);
- CHECK(s3d_scene_compute_area(scn2, &area), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn3, shapes[1]), RES_OK);
+
+ CHECK(s3d_scene_get_shapes_count(scn, &n), RES_OK);
+ CHECK(n, 1);
+ CHECK(s3d_scene_get_shapes_count(scn2, &n), RES_OK);
+ CHECK(n, 2);
+ CHECK(s3d_scene_get_shapes_count(scn3, &n), RES_OK);
+ CHECK(n, 1);
+
+ CHECK(s3d_scene_view_create(scn2, S3D_SAMPLE|S3D_TRACE, &scnview2), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn3, S3D_SAMPLE, &scnview3), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview3), RES_OK);
+
+ CHECK(s3d_scene_view_compute_area(NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_compute_area(scnview2, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_compute_area(NULL, &area), RES_BAD_ARG);
+ CHECK(s3d_scene_view_compute_area(scnview2, &area), RES_OK);
CHECK(area, 0.f);
- CHECK(s3d_scene_compute_volume(NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_compute_volume(scn2, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_compute_volume(NULL, &volume), RES_BAD_ARG);
- CHECK(s3d_scene_compute_volume(scn2, &volume), RES_OK);
+ CHECK(s3d_scene_view_compute_volume(NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_compute_volume(scnview2, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_compute_volume(NULL, &volume), RES_BAD_ARG);
+ CHECK(s3d_scene_view_compute_volume(scnview2, &volume), RES_OK);
CHECK(volume, 0.f);
- CHECK(s3d_scene_primitives_count(NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_primitives_count(scn2, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_primitives_count(NULL, &nprims), RES_BAD_ARG);
- CHECK(s3d_scene_primitives_count(scn2, &nprims), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_primitives_count(scnview2, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_primitives_count(NULL, &nprims), RES_BAD_ARG);
+ CHECK(s3d_scene_view_primitives_count(scnview2, &nprims), RES_OK);
CHECK(nprims, 0);
- CHECK(s3d_scene_get_aabb(NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_aabb(scn2, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_aabb(NULL, lower, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_aabb(scn2, lower, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_aabb(NULL, NULL, upper), RES_BAD_ARG);
- CHECK(s3d_scene_get_aabb(scn2, NULL, upper), RES_BAD_ARG);
- CHECK(s3d_scene_get_aabb(NULL, lower, upper), RES_BAD_ARG);
- CHECK(s3d_scene_get_aabb(scn2, lower, upper), RES_OK);
+ CHECK(s3d_scene_view_get_aabb(NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_aabb(scnview2, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_aabb(NULL, lower, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_aabb(scnview2, lower, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_aabb(NULL, NULL, upper), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_aabb(scnview2, NULL, upper), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_aabb(NULL, lower, upper), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_aabb(scnview2, lower, upper), RES_OK);
CHECK(lower[0] > upper[0], 1);
CHECK(lower[1] > upper[1], 1);
CHECK(lower[2] > upper[2], 1);
- CHECK(s3d_scene_end_session(scn2), RES_OK);
-
- CHECK(s3d_scene_compute_area(scn2, &area), RES_BAD_OP);
- CHECK(s3d_scene_compute_volume(scn2, &volume), RES_BAD_OP);
- CHECK(s3d_scene_primitives_count(scn2, &nprims), RES_BAD_OP);
- CHECK(s3d_scene_get_aabb(scn2, lower, upper), RES_BAD_OP);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview2), RES_OK);
CHECK(s3d_scene_instantiate(scn2, shapes + 3), RES_OK);
CHECK(s3d_scene_attach_shape(scn3, shapes[3]), RES_OK);
- CHECK(s3d_scene_begin_session(scn3, S3D_SAMPLE|S3D_TRACE), RES_BAD_ARG);
+ CHECK(s3d_scene_get_shapes_count(scn3, &n), RES_OK);
+ CHECK(n, 2);
+ CHECK(s3d_scene_view_create(scn3, S3D_SAMPLE|S3D_TRACE, &scnview3), RES_BAD_ARG);
CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_OK);
@@ -255,60 +269,56 @@ main(int argc, char** argv)
cbox_get_ids, cbox_walls_nverts, &attribs, 1, data), RES_OK);
CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
- CHECK(s3d_scene_compute_area(scn, &area), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_compute_area(scnview, &area), RES_OK);
CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
- CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
CHECK(nprims, 10);
- CHECK(s3d_scene_get_aabb(scn, lower, upper), RES_OK);
+ CHECK(s3d_scene_view_get_aabb(scnview, lower, upper), RES_OK);
CHECK(eq_epsf(lower[0], 0.f, 1.e-6f), 1);
CHECK(eq_epsf(lower[1], 0.f, 1.e-6f), 1);
CHECK(eq_epsf(lower[2], 0.f, 1.e-6f), 1);
CHECK(eq_epsf(upper[0], 552.f, 1.e-6f), 1);
CHECK(eq_epsf(upper[1], 559.f, 1.e-6f), 1);
CHECK(eq_epsf(upper[2], 548.f, 1.e-6f), 1);
- CHECK(s3d_scene_end_session(scn), RES_OK);
CHECK(s3d_scene_instantiate(scn, shapes + 1), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shapes[1]), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_TRACE), RES_OK);
- CHECK(s3d_scene_compute_area(scn2, &area), RES_OK);
+ CHECK(s3d_scene_view_create(scn2, S3D_GET_PRIMITIVE, &scnview2), RES_OK);
+ CHECK(s3d_scene_view_compute_area(scnview2, &area), RES_OK);
CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
- CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview2, &nprims), RES_OK);
CHECK(nprims, 10);
- CHECK(s3d_scene_get_aabb(scn, lower, upper), RES_OK);
+ CHECK(s3d_scene_view_get_aabb(scnview2, lower, upper), RES_OK);
CHECK(eq_epsf(lower[0], 0.f, 1.e-6f), 1);
CHECK(eq_epsf(lower[1], 0.f, 1.e-6f), 1);
CHECK(eq_epsf(lower[2], 0.f, 1.e-6f), 1);
CHECK(eq_epsf(upper[0], 552.f, 1.e-6f), 1);
CHECK(eq_epsf(upper[1], 559.f, 1.e-6f), 1);
CHECK(eq_epsf(upper[2], 548.f, 1.e-6f), 1);
- CHECK(s3d_scene_end_session(scn2), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_GET_PRIMITIVE), RES_OK);
- CHECK(s3d_scene_compute_area(scn2, &area), RES_OK);
+ CHECK(s3d_scene_view_compute_area(scnview, &area), RES_OK);
CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
- CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
- CHECK(nprims, 10);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
- CHECK(s3d_scene_get_primitive(NULL, 11, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_primitive(scn2, 11, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_primitive(NULL, 0, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_primitive(scn2, 0, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_get_primitive(NULL, 11, prims + 0), RES_BAD_ARG);
- CHECK(s3d_scene_get_primitive(scn2, 11, prims + 0), RES_BAD_ARG);
- CHECK(s3d_scene_get_primitive(NULL, 0, prims + 0), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_primitive(NULL, 11, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_primitive(scnview2, 11, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_primitive(NULL, 0, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_primitive(scnview2, 0, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_primitive(NULL, 11, prims + 0), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_primitive(scnview2, 11, prims + 0), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_primitive(NULL, 0, prims + 0), RES_BAD_ARG);
FOR_EACH(i, 0, nprims) {
size_t j;
- CHECK(s3d_scene_get_primitive(scn2, (unsigned)i, prims + i), RES_OK);
+ CHECK(s3d_scene_view_get_primitive(scnview2, (unsigned)i, prims + i), RES_OK);
CHECK(S3D_PRIMITIVE_EQ(prims + i, &S3D_PRIMITIVE_NULL), 0);
CHECK(prims[i].scene_prim_id, i);
FOR_EACH(j, 0, i)
CHECK(S3D_PRIMITIVE_EQ(prims + i, prims + j), 0);
}
- CHECK(s3d_scene_end_session(scn2), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview2), RES_OK);
attribs.type = S3D_FLOAT3;
attribs.usage = S3D_POSITION;
@@ -316,18 +326,18 @@ main(int argc, char** argv)
CHECK(s3d_mesh_setup_indexed_vertices
(shapes[0], cube_ntris, cube_get_ids, cube_nverts, &attribs, 1, NULL), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
- CHECK(s3d_scene_compute_area(scn, &area), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_compute_area(scnview, &area), RES_OK);
CHECK(eq_epsf(area, 6.f, 1.e-6f), 1);
- CHECK(s3d_scene_compute_volume(scn, &volume), RES_OK);
+ CHECK(s3d_scene_view_compute_volume(scnview, &volume), RES_OK);
CHECK(eq_epsf(volume, 1.f, 1.e-6f), 1);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_shape_flip_surface(shapes[0]), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_GET_PRIMITIVE), RES_OK);
- CHECK(s3d_scene_compute_volume(scn, &volume), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_compute_volume(scnview, &volume), RES_OK);
CHECK(eq_epsf(volume, -1.f, 1.e-6f), 1);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_scene_get_device(NULL, NULL), RES_BAD_ARG);
CHECK(s3d_scene_get_device(scn, NULL), RES_BAD_ARG);
diff --git a/src/test_s3d_scene_view.c b/src/test_s3d_scene_view.c
@@ -0,0 +1,1048 @@
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
+ *
+ * This software is a computer program whose purpose is to describe a
+ * virtual 3D environment that can be ray-traced and sampled both robustly
+ * and efficiently.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#include "s3d.h"
+#include "test_s3d_utils.h"
+
+#include <rsys/float3.h>
+#include <rsys/float2.h>
+
+#include <string.h>
+
+struct mesh_context {
+ const float* verts;
+ const unsigned* ids;
+};
+
+static int
+filter
+ (const struct s3d_hit* hit,
+ const float org[3],
+ const float dir[3],
+ void* ray_data,
+ void* filter_data)
+{
+ (void)org, (void)dir, (void)ray_data, (void)filter_data;
+ CHECK(S3D_HIT_NONE(hit), 0);
+ return hit->prim.prim_id % 2 == 0;
+}
+
+/*******************************************************************************
+ * Cube data
+ ******************************************************************************/
+static const float cube_verts[] = {
+ 0.f, 0.f, 0.f,
+ 1.f, 0.f, 0.f,
+ 0.f, 1.f, 0.f,
+ 1.f, 1.f, 0.f,
+ 0.f, 0.f, 1.f,
+ 1.f, 0.f, 1.f,
+ 0.f, 1.f, 1.f,
+ 1.f, 1.f, 1.f
+};
+static const unsigned cube_nverts = sizeof(cube_verts) / sizeof(float[3]);
+
+/* Front faces are CW. The normals point into the cube */
+static const unsigned cube_ids[] = {
+ 0, 2, 1, 1, 2, 3, /* Front */
+ 0, 4, 2, 2, 4, 6, /* Left */
+ 4, 5, 6, 6, 5, 7, /* Back */
+ 3, 7, 1, 1, 7, 5, /* Right */
+ 2, 6, 3, 3, 6, 7, /* Top */
+ 0, 1, 4, 4, 1, 5 /* Bottom */
+};
+static const unsigned cube_ntris = sizeof(cube_ids) / sizeof(unsigned[3]);
+
+/*******************************************************************************
+ * Plane data
+ ******************************************************************************/
+static const float plane_verts[] = {
+ 0.f, 0.f, 0.5f,
+ 1.f, 0.f, 0.5f,
+ 1.f, 1.f, 0.5f,
+ 0.f, 1.f, 0.5f
+};
+static const unsigned plane_nverts = sizeof(plane_verts) / sizeof(float[3]);
+
+static const unsigned plane_ids[] = { 0, 1, 2, 2, 3, 0 };
+static const unsigned plane_ntris = sizeof(plane_ids) / sizeof(unsigned[3]);
+
+/*******************************************************************************
+ * helper function
+ ******************************************************************************/
+static float
+rand_canonic(void)
+{
+ int r;
+ while((r = rand()) == RAND_MAX);
+ return (float)r / (float)RAND_MAX;
+}
+
+static void
+get_ids(const unsigned itri, unsigned ids[3], void* data)
+{
+ const unsigned id = itri * 3;
+ const struct mesh_context* ctx = data;
+ NCHECK(ctx, NULL);
+ NCHECK(ids, NULL);
+ ids[0] = ctx->ids[id + 0];
+ ids[1] = ctx->ids[id + 1];
+ ids[2] = ctx->ids[id + 2];
+}
+
+static void
+get_pos(const unsigned ivert, float pos[3], void* data)
+{
+ const unsigned i = ivert*3;
+ const struct mesh_context* ctx = data;
+ NCHECK(ctx, NULL);
+ NCHECK(pos, NULL);
+ pos[0] = ctx->verts[i + 0];
+ pos[1] = ctx->verts[i + 1];
+ pos[2] = ctx->verts[i + 2];
+}
+
+static void
+test_miscellaneous
+ (struct s3d_device* dev,
+ struct s3d_shape* cube,
+ struct s3d_shape* plane)
+{
+ struct s3d_scene* scn;
+ struct s3d_scene_view* scnview;
+ int mask;
+
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, cube), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, plane), RES_OK);
+
+ CHECK(s3d_scene_view_create(NULL, 0, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_create(scn, 0, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_create(NULL, S3D_SAMPLE, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_create(NULL, 0, &scnview), RES_BAD_ARG);
+ CHECK(s3d_scene_view_create(scn, 0, &scnview), RES_BAD_ARG);
+ CHECK(s3d_scene_view_create(NULL, S3D_SAMPLE, &scnview), RES_BAD_ARG);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+
+ CHECK(s3d_scene_view_get_mask(NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_mask(scnview, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_mask(NULL, &mask), RES_BAD_ARG);
+ CHECK(s3d_scene_view_get_mask(scnview, &mask), RES_OK);
+ CHECK(mask, S3D_SAMPLE);
+
+ CHECK(s3d_scene_view_ref_get(NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_ref_get(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE|S3D_GET_PRIMITIVE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_get_mask(scnview, &mask), RES_OK);
+ CHECK(mask & S3D_TRACE, S3D_TRACE);
+ CHECK(mask & S3D_GET_PRIMITIVE, S3D_GET_PRIMITIVE);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE|S3D_GET_PRIMITIVE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_get_mask(scnview, &mask), RES_OK);
+ CHECK(mask & S3D_SAMPLE, S3D_SAMPLE);
+ CHECK(mask & S3D_GET_PRIMITIVE, S3D_GET_PRIMITIVE);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+}
+
+static void
+test_trace_ray
+ (struct s3d_device* dev,
+ struct s3d_shape* cube,
+ struct s3d_shape* plane)
+{
+ struct s3d_scene* scn;
+ struct s3d_scene* scn2;
+ struct s3d_scene* scn3;
+ struct s3d_scene_view* scnview;
+ struct s3d_scene_view* scnview2;
+ struct s3d_scene_view* scnview3;
+ struct s3d_shape* inst0;
+ struct s3d_shape* inst1;
+ struct s3d_hit hit, hit2;
+ float org[3], dir[3], range[2];
+ unsigned icube;
+ unsigned iplane;
+ unsigned iinst0;
+ unsigned iinst1;
+
+ CHECK(s3d_shape_get_id(cube, &icube), RES_OK);
+ CHECK(s3d_shape_get_id(plane, &iplane), RES_OK);
+
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn2), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn3), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, plane), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, cube), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn2, cube), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn2, plane), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE|S3D_GET_PRIMITIVE, &scnview), RES_OK);
+
+ f3(org, 0.5f, 0.25f, 0.25f);
+ f3(dir, 0.f, 0.f, 1.f);
+ f2(range, 0.f, FLT_MAX);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_BAD_OP);
+
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview2), RES_OK);
+ CHECK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 0);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 0);
+
+ f3(dir, 0.f, 0.f, -1.f);
+ CHECK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 0);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, icube);
+ CHECK(hit.prim.prim_id, 0);
+ f3(dir, 0.f, 0.f, 1.f);
+
+ CHECK(s3d_shape_enable(plane, 0), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+
+ CHECK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 0);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 0);
+
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 0);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, icube);
+ CHECK(hit.prim.prim_id, 4);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview2), RES_OK);
+ CHECK(s3d_shape_enable(plane, 1), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn2, S3D_TRACE, &scnview2), RES_OK);
+
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit2), RES_OK);
+ CHECK(f3_eq(hit.normal, hit2.normal), 1);
+ CHECK(f2_eq(hit.uv, hit2.uv), 1);
+ CHECK(hit.distance, hit2.distance);
+ CHECK(S3D_PRIMITIVE_EQ(&hit.prim, &hit2.prim), 1);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 0);
+
+ CHECK(s3d_scene_detach_shape(scn2, plane), RES_OK);
+ CHECK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit2), RES_OK);
+ CHECK(f3_eq(hit.normal, hit2.normal), 1);
+ CHECK(f2_eq(hit.uv, hit2.uv), 1);
+ CHECK(hit.distance, hit2.distance);
+ CHECK(S3D_PRIMITIVE_EQ(&hit.prim, &hit2.prim), 1);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview2), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn2, S3D_TRACE, &scnview2), RES_OK);
+
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(f3_eq(hit.normal, hit2.normal), 1);
+ CHECK(f2_eq(hit.uv, hit2.uv), 1);
+ CHECK(hit.distance, hit2.distance);
+ CHECK(S3D_PRIMITIVE_EQ(&hit.prim, &hit2.prim), 1);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 0);
+
+ CHECK(s3d_scene_view_trace_ray(scnview2, org, dir, range, NULL, &hit2), RES_OK);
+ CHECK(hit2.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit2.prim.geom_id, icube);
+ CHECK(hit2.prim.prim_id, 4);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview2), RES_OK);
+
+ CHECK(s3d_scene_instantiate(scn2, &inst0), RES_OK);
+ CHECK(s3d_scene_instantiate(scn2, &inst1), RES_OK);
+ CHECK(s3d_shape_get_id(inst0, &iinst0), RES_OK);
+ CHECK(s3d_shape_get_id(inst1, &iinst1), RES_OK);
+ CHECK(s3d_instance_translate
+ (inst0, S3D_WORLD_TRANSFORM, f3(org,-2.f, 0.f, 0.f)), RES_OK);
+ CHECK(s3d_instance_translate
+ (inst1, S3D_WORLD_TRANSFORM, f3(org, 2.f, 0.f, 0.f)), RES_OK);
+
+ CHECK(s3d_scene_attach_shape(scn3, inst0), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn3, inst1), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, inst0), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, inst1), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn3, S3D_TRACE, &scnview3), RES_OK);
+
+ f3(org, 0.5f, 0.25f, 0.25f);
+ f3(dir, 0.f, 0.f, 1.f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 0);
+
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+
+ f3(org, -1.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, iinst0);
+ CHECK(hit.prim.geom_id, icube);
+ CHECK(hit.prim.prim_id, 4);
+
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit2), RES_OK);
+ CHECK(hit2.prim.inst_id, iinst0);
+ CHECK(hit2.prim.geom_id, icube);
+ CHECK(hit2.prim.prim_id, 4);
+
+ CHECK(f3_eq(hit.normal, hit2.normal), 1);
+ CHECK(f2_eq(hit.uv, hit2.uv), 1);
+ CHECK(hit.distance, hit2.distance);
+
+ CHECK(s3d_scene_clear(scn2), RES_OK);
+
+ f3(org, 2.5f, 0.25f, 0.25f);
+
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, iinst1);
+ CHECK(hit.prim.geom_id, icube);
+ CHECK(hit.prim.prim_id, 4);
+
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit2), RES_OK);
+ CHECK(hit2.prim.inst_id, iinst1);
+ CHECK(hit2.prim.geom_id, icube);
+ CHECK(hit2.prim.prim_id, 4);
+
+ CHECK(f3_eq(hit.normal, hit2.normal), 1);
+ CHECK(f2_eq(hit.uv, hit2.uv), 1);
+ CHECK(hit.distance, hit2.distance);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+
+ f3(org, -1.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, iinst0);
+ CHECK(hit.prim.geom_id, icube);
+ CHECK(hit.prim.prim_id, 4);
+
+ f3(org, 2.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, iinst1);
+ CHECK(hit.prim.geom_id, icube);
+ CHECK(hit.prim.prim_id, 4);
+
+ f3(org, 0.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 0);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+
+ CHECK(s3d_scene_attach_shape(scn2, plane), RES_OK);
+ CHECK(s3d_mesh_set_hit_filter_function(plane, filter, NULL), RES_OK);
+
+ f3(org, 0.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 0);
+
+ CHECK(s3d_scene_view_ref_put(scnview3), RES_OK);
+ CHECK(s3d_scene_view_create(scn3, S3D_TRACE, &scnview3), RES_OK);
+
+ f3(org, -1.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+
+ f3(org, -1.5f, 0.75f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, iinst0);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 1);
+
+ f3(org, 2.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+
+ f3(org, 2.5f, 0.75f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, iinst1);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 1);
+
+ f3(org, 0.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 0);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+
+ f3(org, 0.5f, 0.75f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 1);
+ CHECK(s3d_scene_view_trace_ray(scnview3, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ f3(org, 0.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, icube);
+ CHECK(hit.prim.prim_id, 4);
+ f3(org, 0.5f, 0.75f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, S3D_INVALID_ID);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 1);
+
+ f3(org, -1.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+ f3(org, -1.5f, 0.75f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, iinst0);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 1);
+
+ f3(org, 2.5f, 0.25f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(S3D_HIT_NONE(&hit), 1);
+ f3(org, 2.5f, 0.75f, 0.25f);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(hit.prim.inst_id, iinst1);
+ CHECK(hit.prim.geom_id, iplane);
+ CHECK(hit.prim.prim_id, 1);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview3), RES_OK);
+
+ CHECK(s3d_shape_ref_put(inst0), RES_OK);
+ CHECK(s3d_shape_ref_put(inst1), RES_OK);
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+ CHECK(s3d_scene_ref_put(scn2), RES_OK);
+ CHECK(s3d_scene_ref_put(scn3), RES_OK);
+}
+
+static void
+test_sample
+ (struct s3d_device* dev,
+ struct s3d_shape* cube,
+ struct s3d_shape* plane)
+{
+ #define NSAMPS 512
+ struct s3d_scene* scn;
+ struct s3d_scene* scn2;
+ struct s3d_scene* scn3;
+ struct s3d_scene_view* scnview;
+ struct s3d_scene_view* scnview3;
+ struct s3d_shape* inst0;
+ struct s3d_shape* inst1;
+ struct s3d_primitive prims[NSAMPS];
+ float u, v, w, st[2];
+ float pos[3];
+ unsigned icube;
+ unsigned iplane;
+ unsigned iinst0;
+ unsigned iinst1;
+ int nsamps_cube;
+ int nsamps_plane;
+ int nsamps_inst0;
+ int nsamps_inst1;
+ int i;
+
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn2), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn3), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, cube), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, plane), RES_OK);
+ CHECK(s3d_shape_get_id(cube, &icube), RES_OK);
+ CHECK(s3d_shape_get_id(plane, &iplane), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.f, 0.f, 0.f, &prims[0], st), RES_BAD_OP);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_sample(scnview, 0.f, 0.f, 0.f, &prims[0], st), RES_OK);
+ CHECK(prims[0].inst_id, S3D_INVALID_ID);
+ CHECK(prims[0].geom_id == icube || prims[0].geom_id == iplane, 1);
+
+ nsamps_cube = 0;
+ nsamps_plane = 0;
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st), RES_OK);
+ CHECK(prims[i].inst_id, S3D_INVALID_ID);
+ if(prims[i].geom_id == icube) {
+ ++nsamps_cube;
+ } else {
+ CHECK(prims[i].geom_id, iplane);
+ ++nsamps_plane;
+ }
+ }
+ NCHECK(nsamps_cube, 0);
+ NCHECK(nsamps_plane, 0);
+
+ CHECK(s3d_shape_enable(cube, 0), RES_OK);
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ struct s3d_primitive prim;
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview, u, v, w, &prim, st), RES_OK);
+ CHECK(S3D_PRIMITIVE_EQ(&prim, &prims[i]), 1);
+ }
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st), RES_OK);
+ CHECK(prims[i].inst_id, S3D_INVALID_ID);
+ CHECK(prims[i].geom_id, iplane);
+ }
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_shape_enable(cube, 1), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn2, cube), RES_OK);
+ CHECK(s3d_scene_instantiate(scn2, &inst0), RES_OK);
+ CHECK(s3d_scene_instantiate(scn2, &inst1), RES_OK);
+ CHECK(s3d_shape_get_id(inst0, &iinst0), RES_OK);
+ CHECK(s3d_shape_get_id(inst1, &iinst1), RES_OK);
+ CHECK(s3d_instance_translate
+ (inst0, S3D_WORLD_TRANSFORM, f3(pos,-2.f, 0.f, 0.f)), RES_OK);
+ CHECK(s3d_instance_translate
+ (inst1, S3D_WORLD_TRANSFORM, f3(pos, 2.f, 0.f, 0.f)), RES_OK);
+
+ CHECK(s3d_scene_attach_shape(scn, inst0), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, inst1), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn3, inst0), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn3, inst1), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn3, S3D_SAMPLE, &scnview3), RES_OK);
+
+ CHECK(s3d_scene_detach_shape(scn2, cube), RES_OK);
+
+ nsamps_cube = 0;
+ nsamps_inst0 = 0;
+ nsamps_inst1 = 0;
+ nsamps_plane = 0;
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st), RES_OK);
+ if(prims[i].inst_id != S3D_INVALID_ID) {
+ CHECK(prims[i].geom_id, icube);
+ if(prims[i].inst_id == iinst0) {
+ ++nsamps_inst0;
+ } else {
+ CHECK(prims[i].inst_id, iinst1);
+ ++nsamps_inst1;
+ }
+ } else {
+ if(prims[i].geom_id == icube) {
+ ++nsamps_cube;
+ } else {
+ CHECK(prims[i].geom_id, iplane);
+ ++nsamps_plane;
+ }
+ }
+
+ }
+ NCHECK(nsamps_cube, 0);
+ NCHECK(nsamps_inst0, 0);
+ NCHECK(nsamps_inst1, 0);
+ NCHECK(nsamps_plane, 0);
+
+ nsamps_inst0 = 0;
+ nsamps_inst1 = 0;
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview3, u, v, w, &prims[i], st), RES_OK);
+ CHECK(prims[i].geom_id, icube);
+ if(prims[i].inst_id == iinst0) {
+ ++nsamps_inst0;
+ } else {
+ CHECK(prims[i].inst_id, iinst1);
+ ++nsamps_inst1;
+ }
+ }
+ NCHECK(nsamps_inst0, 0);
+ NCHECK(nsamps_inst1, 0);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+
+ nsamps_cube = 0;
+ nsamps_plane = 0;
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st), RES_OK);
+ CHECK(prims[i].inst_id, S3D_INVALID_ID);
+ if(prims[i].geom_id == icube) {
+ ++nsamps_cube;
+ } else {
+ CHECK(prims[i].geom_id, iplane);
+ ++nsamps_plane;
+ }
+ }
+ NCHECK(nsamps_cube, 0);
+ NCHECK(nsamps_plane, 0);
+
+ nsamps_inst0 = 0;
+ nsamps_inst1 = 0;
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview3, u, v, w, &prims[i], st), RES_OK);
+ CHECK(prims[i].geom_id, icube);
+ if(prims[i].inst_id == iinst0) {
+ ++nsamps_inst0;
+ } else {
+ CHECK(prims[i].inst_id, iinst1);
+ ++nsamps_inst1;
+ }
+ }
+ NCHECK(nsamps_inst0, 0);
+ NCHECK(nsamps_inst1, 0);
+
+ CHECK(s3d_scene_attach_shape(scn2, plane), RES_OK);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview, u, v, w, &prims[i], st), RES_OK);
+ if(prims[i].inst_id != S3D_INVALID_ID) {
+ CHECK(prims[i].geom_id, iplane);
+ if(prims[i].inst_id == iinst0) {
+ ++nsamps_inst0;
+ } else {
+ CHECK(prims[i].inst_id, iinst1);
+ ++nsamps_inst1;
+ }
+ } else {
+ if(prims[i].geom_id == icube) {
+ ++nsamps_cube;
+ } else {
+ CHECK(prims[i].geom_id, iplane);
+ ++nsamps_plane;
+ }
+ }
+
+ }
+ NCHECK(nsamps_cube, 0);
+ NCHECK(nsamps_inst0, 0);
+ NCHECK(nsamps_inst1, 0);
+ NCHECK(nsamps_plane, 0);
+
+ nsamps_inst0 = 0;
+ nsamps_inst1 = 0;
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview3, u, v, w, &prims[i], st), RES_OK);
+ CHECK(prims[i].geom_id, icube);
+ if(prims[i].inst_id == iinst0) {
+ ++nsamps_inst0;
+ } else {
+ CHECK(prims[i].inst_id, iinst1);
+ ++nsamps_inst1;
+ }
+ }
+ NCHECK(nsamps_inst0, 0);
+ NCHECK(nsamps_inst1, 0);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview3), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn3, S3D_SAMPLE, &scnview3), RES_OK);
+ nsamps_inst0 = 0;
+ nsamps_inst1 = 0;
+ srand(0);
+ FOR_EACH(i, 0, NSAMPS) {
+ u = rand_canonic(), v = rand_canonic(), w = rand_canonic();
+ CHECK(s3d_scene_view_sample(scnview3, u, v, w, &prims[i], st), RES_OK);
+ CHECK(prims[i].geom_id, iplane);
+ if(prims[i].inst_id == iinst0) {
+ ++nsamps_inst0;
+ } else {
+ CHECK(prims[i].inst_id, iinst1);
+ ++nsamps_inst1;
+ }
+ }
+ NCHECK(nsamps_inst0, 0);
+ NCHECK(nsamps_inst1, 0);
+
+ CHECK(s3d_scene_view_ref_put(scnview3), RES_OK);
+
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+ CHECK(s3d_scene_ref_put(scn2), RES_OK);
+ CHECK(s3d_scene_ref_put(scn3), RES_OK);
+ CHECK(s3d_shape_ref_put(inst0), RES_OK);
+ CHECK(s3d_shape_ref_put(inst1), RES_OK);
+}
+
+static void
+test_get_primitive
+ (struct s3d_device* dev,
+ struct s3d_shape* cube,
+ struct s3d_shape* plane)
+{
+ struct s3d_scene* scn;
+ struct s3d_scene* scn2;
+ struct s3d_scene* scn3;
+ struct s3d_scene_view* scnview;
+ struct s3d_scene_view* scnview3;
+ struct s3d_shape* inst0;
+ struct s3d_shape* inst1;
+ struct s3d_primitive prim;
+ size_t nprims;
+ unsigned i;
+ unsigned icube;
+ unsigned iplane;
+ unsigned iinst0;
+ unsigned iinst1;
+ float pos[3];
+ int cube_prims[12];
+ int plane_prims[2];
+ int inst0_prims[12];
+ int inst1_prims[12];
+
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn2), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn3), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, cube), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, plane), RES_OK);
+ CHECK(s3d_shape_get_id(cube, &icube), RES_OK);
+ CHECK(s3d_shape_get_id(plane, &iplane), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_get_primitive(scnview, 0, &prim), RES_BAD_OP);
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
+ CHECK(nprims, 14);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
+ CHECK(nprims, 14);
+
+ memset(cube_prims, 0, sizeof(cube_prims));
+ memset(plane_prims, 0, sizeof(plane_prims));
+ FOR_EACH(i, 0, nprims) {
+ CHECK(s3d_scene_view_get_primitive(scnview, i, &prim), RES_OK);
+ CHECK(prim.inst_id, S3D_INVALID_ID);
+ CHECK(prim.scene_prim_id, i);
+ if(prim.geom_id == icube) {
+ cube_prims[prim.prim_id] = 1;
+ } else {
+ CHECK(prim.geom_id, iplane);
+ plane_prims[prim.prim_id] = 1;
+ }
+ }
+ FOR_EACH(i, 0, 12) CHECK(cube_prims[i], 1);
+ FOR_EACH(i, 0, 2) CHECK(plane_prims[i], 1);
+
+ CHECK(s3d_scene_detach_shape(scn, cube), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
+ CHECK(nprims, 14);
+ memset(cube_prims, 0, sizeof(cube_prims));
+ memset(plane_prims, 0, sizeof(plane_prims));
+ FOR_EACH(i, 0, nprims) {
+ CHECK(s3d_scene_view_get_primitive(scnview, i, &prim), RES_OK);
+ CHECK(prim.inst_id, S3D_INVALID_ID);
+ CHECK(prim.scene_prim_id, i);
+ if(prim.geom_id == icube) {
+ cube_prims[prim.prim_id] = 1;
+ } else {
+ CHECK(prim.geom_id, iplane);
+ plane_prims[prim.prim_id] = 1;
+ }
+ }
+ FOR_EACH(i, 0, 12) CHECK(cube_prims[i], 1);
+ FOR_EACH(i, 0, 2) CHECK(plane_prims[i], 1);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
+ CHECK(nprims, 2);
+ memset(plane_prims, 0, sizeof(plane_prims));
+ FOR_EACH(i, 0, nprims) {
+ CHECK(s3d_scene_view_get_primitive(scnview, i, &prim), RES_OK);
+ CHECK(prim.inst_id, S3D_INVALID_ID);
+ CHECK(prim.scene_prim_id, i);
+ CHECK(prim.geom_id, iplane);
+ plane_prims[prim.prim_id] = 1;
+ }
+ FOR_EACH(i, 0, 2) CHECK(plane_prims[i], 1);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_scene_attach_shape(scn, cube), RES_OK);
+
+ CHECK(s3d_scene_attach_shape(scn2, plane), RES_OK);
+ CHECK(s3d_scene_instantiate(scn2, &inst0), RES_OK);
+ CHECK(s3d_scene_instantiate(scn2, &inst1), RES_OK);
+ CHECK(s3d_shape_get_id(inst0, &iinst0), RES_OK);
+ CHECK(s3d_shape_get_id(inst1, &iinst1), RES_OK);
+ CHECK(s3d_instance_translate
+ (inst0, S3D_WORLD_TRANSFORM, f3(pos,-2.f, 0.f, 0.f)), RES_OK);
+ CHECK(s3d_instance_translate
+ (inst1, S3D_WORLD_TRANSFORM, f3(pos, 2.f, 0.f, 0.f)), RES_OK);
+
+ CHECK(s3d_scene_attach_shape(scn, inst0), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn3, inst0), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn3, inst1), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_create(scn3, S3D_GET_PRIMITIVE, &scnview3), RES_OK);
+
+ CHECK(s3d_scene_clear(scn2), RES_OK);
+
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
+ CHECK(nprims, 16);
+ memset(plane_prims, 0, sizeof(plane_prims));
+ memset(cube_prims, 0, sizeof(cube_prims));
+ memset(inst0_prims, 0, sizeof(inst0_prims));
+ FOR_EACH(i, 0, nprims) {
+ CHECK(s3d_scene_view_get_primitive(scnview, i, &prim), RES_OK);
+ if(prim.inst_id != S3D_INVALID_ID) {
+ CHECK(prim.inst_id, iinst0);
+ CHECK(prim.geom_id, iplane);
+ inst0_prims[prim.prim_id] = 1;
+ } else {
+ if(prim.geom_id == icube) {
+ cube_prims[prim.prim_id] = 1;
+ } else {
+ CHECK(prim.geom_id, iplane);
+ plane_prims[prim.prim_id] = 1;
+ }
+ }
+ }
+ FOR_EACH(i, 0, 12) CHECK(cube_prims[i], 1);
+ FOR_EACH(i, 0, 2) CHECK(plane_prims[i], 1);
+ FOR_EACH(i, 0, 2) CHECK(inst0_prims[i], 1);
+
+ CHECK(s3d_scene_view_primitives_count(scnview3, &nprims), RES_OK);
+ CHECK(nprims, 4);
+ memset(inst0_prims, 0, sizeof(inst0_prims));
+ memset(inst1_prims, 0, sizeof(inst1_prims));
+ FOR_EACH(i, 0, nprims) {
+ CHECK(s3d_scene_view_get_primitive(scnview3, i, &prim), RES_OK);
+ NCHECK(prim.inst_id, S3D_INVALID_ID);
+ CHECK(prim.geom_id, iplane);
+ if(prim.inst_id == iinst0) {
+ inst0_prims[prim.prim_id] = 1;
+ } else {
+ CHECK(prim.inst_id, iinst1);
+ inst1_prims[prim.prim_id] = 1;
+ }
+ }
+ FOR_EACH(i, 0, 2) CHECK(inst1_prims[i], 1);
+ FOR_EACH(i, 0, 2) CHECK(inst1_prims[i], 1);
+
+ CHECK(s3d_scene_view_ref_put(scnview3), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn3, S3D_GET_PRIMITIVE, &scnview3), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview3, &nprims), RES_OK);
+ CHECK(nprims, 0);
+ CHECK(s3d_scene_view_ref_put(scnview3), RES_OK);
+
+ CHECK(s3d_scene_attach_shape(scn2, cube), RES_OK);
+ CHECK(s3d_scene_view_create(scn3, S3D_GET_PRIMITIVE, &scnview3), RES_OK);
+
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
+ CHECK(nprims, 16);
+ memset(plane_prims, 0, sizeof(plane_prims));
+ memset(cube_prims, 0, sizeof(cube_prims));
+ memset(inst0_prims, 0, sizeof(inst0_prims));
+ FOR_EACH(i, 0, nprims) {
+ CHECK(s3d_scene_view_get_primitive(scnview, i, &prim), RES_OK);
+ if(prim.inst_id != S3D_INVALID_ID) {
+ CHECK(prim.inst_id, iinst0);
+ CHECK(prim.geom_id, iplane);
+ inst0_prims[prim.prim_id] = 1;
+ } else {
+ if(prim.geom_id == icube) {
+ cube_prims[prim.prim_id] = 1;
+ } else {
+ CHECK(prim.geom_id, iplane);
+ plane_prims[prim.prim_id] = 1;
+ }
+ }
+ }
+ FOR_EACH(i, 0, 12) CHECK(cube_prims[i], 1);
+ FOR_EACH(i, 0, 2) CHECK(plane_prims[i], 1);
+ FOR_EACH(i, 0, 2) CHECK(inst0_prims[i], 1);
+
+ CHECK(s3d_scene_view_primitives_count(scnview3, &nprims), RES_OK);
+ CHECK(nprims, 24);
+ memset(inst0_prims, 0, sizeof(inst0_prims));
+ memset(inst1_prims, 0, sizeof(inst1_prims));
+ FOR_EACH(i, 0, nprims) {
+ CHECK(s3d_scene_view_get_primitive(scnview3, i, &prim), RES_OK);
+ NCHECK(prim.inst_id, S3D_INVALID_ID);
+ CHECK(prim.geom_id, icube);
+ if(prim.inst_id == iinst0) {
+ inst0_prims[prim.prim_id] = 1;
+ } else {
+ CHECK(prim.inst_id, iinst1);
+ inst1_prims[prim.prim_id] = 1;
+ }
+ }
+ FOR_EACH(i, 0, 12) CHECK(inst1_prims[i], 1);
+ FOR_EACH(i, 0, 12) CHECK(inst1_prims[i], 1);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview3), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn, S3D_GET_PRIMITIVE, &scnview), RES_OK);
+
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
+ CHECK(nprims, 26);
+ memset(plane_prims, 0, sizeof(plane_prims));
+ memset(cube_prims, 0, sizeof(cube_prims));
+ memset(inst0_prims, 0, sizeof(inst0_prims));
+ FOR_EACH(i, 0, nprims) {
+ CHECK(s3d_scene_view_get_primitive(scnview, i, &prim), RES_OK);
+ if(prim.inst_id != S3D_INVALID_ID) {
+ CHECK(prim.inst_id, iinst0);
+ CHECK(prim.geom_id, icube);
+ inst0_prims[prim.prim_id] = 1;
+ } else {
+ if(prim.geom_id == icube) {
+ cube_prims[prim.prim_id] = 1;
+ } else {
+ CHECK(prim.geom_id, iplane);
+ plane_prims[prim.prim_id] = 1;
+ }
+ }
+ }
+ FOR_EACH(i, 0, 12) CHECK(cube_prims[i], 1);
+ FOR_EACH(i, 0, 2) CHECK(plane_prims[i], 1);
+ FOR_EACH(i, 0, 12) CHECK(inst0_prims[i], 1);
+
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+
+ CHECK(s3d_shape_ref_put(inst0), RES_OK);
+ CHECK(s3d_shape_ref_put(inst1), RES_OK);
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+ CHECK(s3d_scene_ref_put(scn2), RES_OK);
+ CHECK(s3d_scene_ref_put(scn3), RES_OK);
+}
+
+/*******************************************************************************
+ * Main test function
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct mesh_context ctx;
+ struct s3d_device* dev;
+ struct s3d_shape* cube;
+ struct s3d_shape* plane;
+ struct s3d_vertex_data vdata;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(s3d_device_create(NULL, &allocator, 1, &dev), RES_OK);
+
+ vdata.type = S3D_FLOAT3;
+ vdata.usage = S3D_POSITION;
+ vdata.get = get_pos;
+
+ ctx.ids = cube_ids;
+ ctx.verts = cube_verts;
+ CHECK(s3d_shape_create_mesh(dev, &cube), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices
+ (cube, cube_ntris, get_ids, cube_nverts, &vdata, 1, &ctx), RES_OK);
+
+ ctx.ids = plane_ids;
+ ctx.verts = plane_verts;
+ CHECK(s3d_shape_create_mesh(dev, &plane), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices
+ (plane, plane_ntris, get_ids, plane_nverts, &vdata, 1, &ctx), RES_OK);
+
+ test_miscellaneous(dev, cube, plane);
+ test_trace_ray(dev, cube, plane);
+ test_sample(dev, cube, plane);
+ test_get_primitive(dev, cube, plane);
+
+ CHECK(s3d_shape_ref_put(cube), RES_OK);
+ CHECK(s3d_shape_ref_put(plane), RES_OK);
+ CHECK(s3d_device_ref_put(dev), RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+ return 0;
+}
+
diff --git a/src/test_s3d_seams.c b/src/test_s3d_seams.c
@@ -0,0 +1,192 @@
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
+ *
+ * This software is a computer program whose purpose is to describe a
+ * virtual 3D environment that can be ray-traced and sampled both robustly
+ * and efficiently.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#include "s3d.h"
+#include "test_s3d_utils.h"
+
+#include <rsys/mem_allocator.h>
+#include <rsys/float33.h>
+#include <rsys/double33.h>
+
+struct desc {
+ const float* vertices;
+ const unsigned* indices;
+};
+
+/*******************************************************************************
+ * Callbacks
+ ******************************************************************************/
+static INLINE void
+get_ids(const unsigned itri, unsigned ids[3], void* data)
+{
+ const unsigned id = itri * 3;
+ struct desc* desc = data;
+ NCHECK(desc, NULL);
+ NCHECK(ids, NULL);
+ ids[0] = desc->indices[id + 0];
+ ids[1] = desc->indices[id + 1];
+ ids[2] = desc->indices[id + 2];
+}
+
+static INLINE void
+get_position(const unsigned ivert, float position[3], void* data)
+{
+ struct desc* desc = data;
+ NCHECK(desc, NULL);
+ NCHECK(position, NULL);
+ position[0] = desc->vertices[ivert * 3 + 0];
+ position[1] = desc->vertices[ivert * 3 + 1];
+ position[2] = desc->vertices[ivert * 3 + 2];
+}
+
+static INLINE void
+get_normal(const unsigned ivert, float normal[3], void* data)
+{
+ (void) ivert, (void) data;
+ NCHECK(normal, NULL);
+ normal[0] = 1.f;
+ normal[1] = 0.f;
+ normal[2] = 0.f;
+}
+
+static INLINE void
+get_uv(const unsigned ivert, float uv[2], void* data)
+{
+ (void) ivert, (void) data;
+ NCHECK(uv, NULL);
+ uv[0] = -1.f;
+ uv[1] = 1.f;
+}
+
+static INLINE void
+get_polygon_vertices(const size_t ivert, double position[2], void* ctx)
+{
+ const double* verts = ctx;
+ NCHECK(position, NULL);
+ NCHECK(ctx, NULL);
+ position[0] = verts[ivert * 2 + 0];
+ position[1] = verts[ivert * 2 + 1];
+}
+
+static const float SQUARE_EDGES__ [] = {
+ -0.1f, -0.1f, 0.f,
+ 0.1f, -0.1f, 0.f,
+ 0.1f, 0.1f, 0.f,
+ -0.1f, 0.1f, 0.f
+};
+static const unsigned SQUARE_NVERTS__ = sizeof(SQUARE_EDGES__) / sizeof(float[3]);
+static const unsigned SQUARE_TRG_IDS__ [] = { 0, 2, 1, 2, 0, 3 };
+static const unsigned SQUARE_NTRIS__ = sizeof(SQUARE_TRG_IDS__) / sizeof(unsigned[3]);
+static const struct desc SQUARE_DESC__ = { SQUARE_EDGES__, SQUARE_TRG_IDS__ };
+
+static int
+check_ray(int use_double)
+{
+ struct mem_allocator allocator;
+ struct s3d_device* dev;
+ struct s3d_hit hit;
+ struct s3d_scene* scn;
+ struct s3d_scene* scn2;
+ struct s3d_scene_view* scnview;
+ struct s3d_shape* square;
+ struct s3d_shape* inst;
+ struct s3d_vertex_data attribs;
+ float transformf[12];
+ double transform[12];
+ float range[2] = { 0.f, FLT_MAX };
+ float org[3] = {
+ 3.3492994308471680f, -9.7470426559448242f, 2.6555661803570274f
+ };
+ float dir[3] = {
+ -0.26465030351986046f, 0.77017831656345948f, 0.58033229924097962f
+ };
+ float pos[3];
+
+ if(use_double) {
+ d33_rotation_pitch(transform, PI);
+ f33_set_d33(transformf, transform);
+ } else {
+ f33_rotation_pitch(transformf, (float)PI);
+ }
+ f3_splat(transformf + 9, 0);
+ transformf[11] = 10;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(s3d_device_create(NULL, &allocator, 1, &dev), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn2), RES_OK);
+
+ attribs.usage = S3D_POSITION;
+ attribs.type = S3D_FLOAT3;
+ attribs.get = get_position;
+
+ CHECK(s3d_shape_create_mesh(dev, &square), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices(square, SQUARE_NTRIS__, get_ids,
+ SQUARE_NVERTS__, &attribs, 1, (void*) &SQUARE_DESC__), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, square), RES_OK);
+ s3d_scene_instantiate(scn, &inst);
+ CHECK(s3d_instance_set_transform(inst, transformf), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn2, inst), RES_OK);
+
+ CHECK(s3d_scene_view_create(scn2, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ printf("\nRaytrace using %s: ", use_double ? "double" : "float");
+ if (!S3D_HIT_NONE(&hit)) {
+ f3_add(pos, org, f3_mulf(pos, dir, hit.distance));
+ printf("Hit at [%g %g %g]\n",SPLIT3(pos));
+ } else {
+ printf("No hit\n");
+ }
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+ CHECK(s3d_scene_ref_put(scn2), RES_OK);
+ CHECK(s3d_device_ref_put(dev), RES_OK);
+ CHECK(s3d_shape_ref_put(square), RES_OK);
+ CHECK(s3d_shape_ref_put(inst), RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+
+ return S3D_HIT_NONE(&hit) ? RES_UNKNOWN_ERR : RES_OK;
+}
+
+int
+main(int argc, char** argv)
+{
+ (void)argc, (void)argv;
+ CHECK(check_ray(1), RES_OK);
+ CHECK(check_ray(0), RES_OK);
+ return 0;
+}
+
diff --git a/src/test_s3d_shape.c b/src/test_s3d_shape.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -87,25 +87,15 @@ main(int argc, char** argv)
CHECK(s3d_shape_get_id(shape, &id), RES_OK);
NCHECK(id, S3D_INVALID_ID);
- CHECK(s3d_shape_is_attached(NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_shape_is_attached(shape, NULL), RES_BAD_ARG);
- CHECK(s3d_shape_is_attached(NULL, &c), RES_BAD_ARG);
- CHECK(s3d_shape_is_attached(shape, &c), RES_OK);
- CHECK(c, 0);
-
CHECK(s3d_scene_attach_shape(NULL, NULL), RES_BAD_ARG);
CHECK(s3d_scene_attach_shape(scn, NULL), RES_BAD_ARG);
CHECK(s3d_scene_attach_shape(NULL, shape), RES_BAD_ARG);
CHECK(s3d_scene_attach_shape(scn, shape), RES_OK);
- CHECK(s3d_shape_is_attached(shape, &c), RES_OK);
- NCHECK(c, 0);
CHECK(s3d_scene_detach_shape(NULL, NULL), RES_BAD_ARG);
CHECK(s3d_scene_detach_shape(scn, NULL), RES_BAD_ARG);
CHECK(s3d_scene_detach_shape(NULL, shape), RES_BAD_ARG);
CHECK(s3d_scene_detach_shape(scn, shape), RES_OK);
- CHECK(s3d_shape_is_attached(shape, &c), RES_OK);
- CHECK(c, 0);
attribs[0].type = S3D_FLOAT3;
attribs[0].usage = S3D_POSITION;
diff --git a/src/test_s3d_trace_ray.c b/src/test_s3d_trace_ray.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly
@@ -31,6 +31,7 @@
* knowledge of the CeCILL license and that you accept its terms. */
#include "s3d.h"
+#include "test_s3d_camera.h"
#include "test_s3d_cbox.h"
#include "test_s3d_utils.h"
@@ -42,47 +43,6 @@
#define IMG_WIDTH 640
#define IMG_HEIGHT 480
-struct camera {
- float pos[3];
- float x[3], y[3], z[3]; /* Basis */
-};
-
-static void
-camera_init(struct camera* cam)
-{
- const float pos[3] = { 178.f, -1000.f, 273.f };
- const float tgt[3] = { 178.f, 0.f, 273.f };
- const float up[3] = { 0.f, 0.f, 1.f };
- const float proj_ratio = (float)IMG_WIDTH/(float)IMG_HEIGHT;
- const float fov_x = (float)PI * 0.25f;
- float f = 0.f;
- ASSERT(cam);
-
- f3_set(cam->pos, pos);
- f = f3_normalize(cam->z, f3_sub(cam->z, tgt, pos)); NCHECK(f, 0);
- f = f3_normalize(cam->x, f3_cross(cam->x, cam->z, up)); NCHECK(f, 0);
- f = f3_normalize(cam->y, f3_cross(cam->y, cam->z, cam->x)); NCHECK(f, 0);
- f3_divf(cam->z, cam->z, (float)tan(fov_x*0.5f));
- f3_divf(cam->y, cam->y, proj_ratio);
-}
-
-static void
-camera_ray
- (const struct camera* cam,
- const float pixel[2],
- float org[3],
- float dir[3])
-{
- float x[3], y[3], f;
- ASSERT(cam && pixel && org && dir);
-
- f3_mulf(x, cam->x, pixel[0]*2.f - 1.f);
- f3_mulf(y, cam->y, pixel[1]*2.f - 1.f);
- f3_add(dir, f3_add(dir, x, y), cam->z);
- f = f3_normalize(dir, dir); NCHECK(f, 0);
- f3_set(org, cam->pos);
-}
-
static int
filter_func
(const struct s3d_hit* hit,
@@ -104,10 +64,12 @@ int
main(int argc, char** argv)
{
struct mem_allocator allocator;
+ struct image img;
struct s3d_device* dev;
struct s3d_hit hit;
struct s3d_scene* scn;
struct s3d_scene* scn2;
+ struct s3d_scene_view* scnview;
struct s3d_shape* inst;
struct s3d_shape* walls;
struct s3d_shape* walls_copy;
@@ -117,13 +79,13 @@ main(int argc, char** argv)
struct s3d_primitive prims[30];
struct camera cam;
struct cbox_desc desc;
- unsigned char* img = NULL;
unsigned ntris, nverts;
size_t nprims;
size_t ix, iy;
float transform[12];
float vec[3];
float lower[3], upper[3];
+ float pos[3], tgt[3], up[3];
float org[3] = { 0.f, 0.f, 0.f };
float dir[3] = { 0.f, 1.f, 0.f };
float range[2] = { 0.f, FLT_MAX };
@@ -133,26 +95,18 @@ main(int argc, char** argv)
unsigned short_block_id;
size_t i;
char filter = 0;
- char* img_name = NULL;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- if(argc > 1) {
- if(!strcmp(argv[1], "filter")) {
- filter = 1;
- } else {
- img_name = argv[1];
- }
- }
- if(!img_name && argc > 2) {
- img_name = argv[2];
- }
- if(img_name) {
- img = MEM_ALLOC(&allocator, 3 * IMG_WIDTH * IMG_HEIGHT);
- NCHECK(img, NULL);
+ if(argc > 1 && !strcmp(argv[1], "filter")) {
+ filter = 1;
}
- CHECK(s3d_device_create(NULL, &allocator, 1, &dev), RES_OK);
+ image_init(&allocator, &img);
+ CHECK(image_setup
+ (&img, IMG_WIDTH, IMG_HEIGHT, IMG_WIDTH*3, IMAGE_RGB8, NULL), RES_OK);
+
+ CHECK(s3d_device_create(NULL, &allocator, 0, &dev), RES_OK);
CHECK(s3d_scene_create(dev, &scn), RES_OK);
attribs.usage = S3D_POSITION;
@@ -169,46 +123,45 @@ main(int argc, char** argv)
CHECK(s3d_scene_attach_shape(scn, walls), RES_OK);
CHECK(s3d_shape_ref_put(walls), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
- CHECK(s3d_scene_trace_ray(NULL, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, org, NULL, NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, org, NULL, NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, org, dir, NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, org, dir, NULL, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, NULL, NULL, range, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, NULL, NULL, range, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, org, NULL, range, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, org, NULL, range, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, NULL, dir, range, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, NULL, dir, range, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, org, dir, range, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, org, dir, range, NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, org, NULL, NULL, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, org, NULL, NULL, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, org, dir, NULL, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, org, dir, NULL, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, NULL, NULL, range, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, NULL, NULL, range, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, org, NULL, range, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, org, NULL, range, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, NULL, dir, range, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, NULL, dir, range, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(NULL, org, dir, range, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK);
- CHECK(s3d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_trace_ray(NULL, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, org, NULL, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, NULL, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, org, dir, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, NULL, NULL, range, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, NULL, NULL, range, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, org, NULL, range, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, NULL, range, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, NULL, dir, range, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, NULL, dir, range, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, org, dir, range, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, org, NULL, NULL, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, NULL, NULL, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, org, dir, NULL, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, NULL, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, NULL, NULL, range, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, NULL, NULL, range, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, org, NULL, range, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, NULL, range, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, NULL, dir, range, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, NULL, dir, range, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(NULL, org, dir, range, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_OK);
f3(dir, 1.f, 1.f, 1.f);
- CHECK(s3d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_BAD_ARG);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_trace_ray(scnview, org, dir, range, NULL, &hit), RES_BAD_ARG);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
f3(dir, 0.f, 1.f, 0.f);
- CHECK(s3d_scene_trace_ray(scn, org, dir, range, NULL, &hit), RES_BAD_OP);
CHECK(s3d_scene_clear(scn), RES_OK);
/* Update the inst with the CBox tall block mesh */
@@ -237,10 +190,10 @@ main(int argc, char** argv)
/* Instantiate the scene */
CHECK(s3d_scene_instantiate(scn, &inst), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
- CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
CHECK(nprims, 20);
- CHECK(s3d_scene_end_session(scn), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_shape_get_id(inst, &inst_id), RES_OK);
/* Create the CBox walls */
@@ -266,21 +219,12 @@ main(int argc, char** argv)
CHECK(s3d_instance_set_position(inst, org), RES_OK);
CHECK(s3d_shape_enable(inst, 0), RES_OK);
+ CHECK(s3d_scene_view_create(scn2, S3D_TRACE|S3D_SAMPLE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_TRACE), RES_BAD_OP);
- CHECK(s3d_scene_end_session(scn), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_TRACE), RES_OK);
- CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_BAD_OP);
- CHECK(s3d_scene_end_session(scn), RES_BAD_OP);
-
- CHECK(s3d_scene_clear(scn2), RES_BAD_OP);
- CHECK(s3d_scene_clear(scn), RES_BAD_OP);
-
- CHECK(s3d_scene_end_session(scn2), RES_OK);
CHECK(s3d_shape_enable(inst, 1), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_TRACE), RES_OK);
- CHECK(s3d_scene_end_session(scn2), RES_OK);
+ CHECK(s3d_scene_view_create(scn2, S3D_TRACE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
CHECK(s3d_shape_create_mesh(dev, &walls_copy), RES_OK);
CHECK(s3d_mesh_copy(walls, walls_copy), RES_OK);
@@ -296,11 +240,11 @@ main(int argc, char** argv)
CHECK(s3d_scene_attach_shape(scn, short_block), RES_OK);
CHECK(s3d_scene_attach_shape(scn, tall_block), RES_OK);
- CHECK(s3d_scene_begin_session(scn2, S3D_TRACE|S3D_GET_PRIMITIVE), RES_OK);
- CHECK(s3d_scene_primitives_count(scn2, &nprims), RES_OK);
+ CHECK(s3d_scene_view_create(scn2, S3D_TRACE|S3D_GET_PRIMITIVE, &scnview), RES_OK);
+ CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK);
CHECK(nprims, 30);
- CHECK(s3d_scene_get_aabb(scn2, lower, upper), RES_OK);
+ CHECK(s3d_scene_view_get_aabb(scnview, lower, upper), RES_OK);
CHECK(eq_epsf(lower[0], -100.f, 1.e-6f), 1);
CHECK(eq_epsf(lower[1], 0.f, 1.e-6f), 1);
CHECK(eq_epsf(lower[2], -2.f, 1.e-6f), 1);
@@ -310,7 +254,7 @@ main(int argc, char** argv)
FOR_EACH(i, 0, nprims) {
size_t j;
- CHECK(s3d_scene_get_primitive(scn2, (unsigned)i, prims + i), RES_OK);
+ CHECK(s3d_scene_view_get_primitive(scnview, (unsigned)i, prims + i), RES_OK);
CHECK(S3D_PRIMITIVE_EQ(prims + i, &S3D_PRIMITIVE_NULL), 0);
FOR_EACH(j, 0, i) {
CHECK(S3D_PRIMITIVE_EQ(prims + i, prims + j), 0);
@@ -323,7 +267,11 @@ main(int argc, char** argv)
CHECK(f3_eq(transform + 9, f3(vec, -100.f, 0.f, -2.f)), 1);
}
- camera_init(&cam);
+ f3(pos, 178.f, -1000.f, 273.f);
+ f3(tgt, 178.f, 0.f, 273.f);
+ f3(up, 0.f, 0.f, 1.f);
+ camera_init(&cam, pos, tgt, up, (float)PI*0.25f,
+ (float)IMG_WIDTH/(float)IMG_HEIGHT);
FOR_EACH(iy, 0, IMG_HEIGHT) {
float pixel[2];
@@ -333,17 +281,16 @@ main(int argc, char** argv)
pixel[0] = (float)ix/(float)IMG_WIDTH;
camera_ray(&cam, pixel, org, dir);
- CHECK(s3d_scene_trace_ray
- (scn2, org, dir, range, (void*)(uintptr_t)0xDEADBEEF, &hit), RES_OK);
+ CHECK(s3d_scene_view_trace_ray
+ (scnview, org, dir, range, (void*)(uintptr_t)0xDEADBEEF, &hit), RES_OK);
if(S3D_HIT_NONE(&hit)) {
- if(img) {
- img[ipix+0] = img[ipix+1] = img[ipix+2] = 0;
- }
+ ((uint8_t*)img.pixels)[ipix+0] = 0;
+ ((uint8_t*)img.pixels)[ipix+1] = 0;
+ ((uint8_t*)img.pixels)[ipix+2] = 0;
} else {
float N[3], len, dot, col[3] = { 1.f, 1.f, 1.f };
struct s3d_attrib attr;
- float pos[3];
CHECK(hit.prim.inst_id, inst_id);
CHECK(hit.prim.geom_id == walls_id
@@ -378,9 +325,6 @@ main(int argc, char** argv)
CHECK(hit.prim.scene_prim_id >= hit.prim.prim_id, 1);
CHECK(hit.prim.scene_prim_id < 30, 1);
- if(!img)
- continue;
-
if(hit.prim.geom_id == walls_id) {
if(hit.prim.prim_id == 4 || hit.prim.prim_id == 5) {
col[0] = 1.f, col[1] = 0.f, col[2] = 0.f;
@@ -393,21 +337,17 @@ main(int argc, char** argv)
if(dot < 0.f)
dot = f3_dot(f3_minus(N, N), dir);
- img[ipix+0] = (unsigned char)(dot * col[0] * 255.f);
- img[ipix+1] = (unsigned char)(dot * col[1] * 255.f);
- img[ipix+2] = (unsigned char)(dot * col[2] * 255.f);
+ ((uint8_t*)img.pixels)[ipix+0] = (unsigned char)(dot * col[0] * 255.f);
+ ((uint8_t*)img.pixels)[ipix+1] = (unsigned char)(dot * col[1] * 255.f);
+ ((uint8_t*)img.pixels)[ipix+2] = (unsigned char)(dot * col[2] * 255.f);
}
}
}
- CHECK(s3d_scene_end_session(scn2), RES_OK);
-
- if(img_name) {
- CHECK(image_ppm_write(img_name, IMG_WIDTH, IMG_HEIGHT, 3, img), RES_OK);
- }
-
- if(img)
- MEM_RM(&allocator, img);
+ CHECK(s3d_scene_view_ref_put(scnview), RES_OK);
+ CHECK(image_write_ppm_stream(&img, 0, stdout), RES_OK);
+ image_release(&img);
+
CHECK(s3d_device_ref_put(dev), RES_OK);
CHECK(s3d_shape_ref_put(inst), RES_OK);
CHECK(s3d_shape_ref_put(short_block), RES_OK);
diff --git a/src/test_s3d_trace_ray_instance.c b/src/test_s3d_trace_ray_instance.c
@@ -0,0 +1,344 @@
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
+ *
+ * This software is a computer program whose purpose is to describe a
+ * virtual 3D environment that can be ray-traced and sampled both robustly
+ * and efficiently.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#include "s3d.h"
+#include "test_s3d_camera.h"
+#include "test_s3d_cbox.h"
+#include "test_s3d_utils.h"
+
+#include <rsys/float2.h>
+#include <rsys/float3.h>
+#include <rsys/float33.h>
+#include <rsys/image.h>
+
+static const float quad_verts[] = {
+ -1.f, -1.f, 0.f,
+ -1.f, 1.f, 0.f,
+ 1.f, 1.f, 0.f,
+ 1.f, -1.f, 0.f
+};
+static const unsigned quad_nverts = sizeof(quad_verts)/sizeof(float[3]);
+static const unsigned quad_ids[] = { 0, 1, 3, 3, 1, 2 };
+static const unsigned quad_ntris = sizeof(quad_ids)/sizeof(unsigned[3]);
+
+struct ray {
+ float org[3];
+ float dir[3];
+};
+
+static int
+filter(const struct s3d_hit* hit,
+ const float ray_org[3],
+ const float ray_dir[3],
+ void* ray_data,
+ void* filter_data)
+{
+ struct ray* ray = ray_data;
+
+ NCHECK(hit, NULL);
+ NCHECK(ray_org, NULL);
+ NCHECK(ray_dir, NULL);
+ NCHECK(ray_data, NULL);
+ CHECK(filter_data, NULL);
+ CHECK(f3_eq(ray_org, ray->org), 1);
+ CHECK(f3_eq(ray_dir, ray->dir), 1);
+ return 0;
+}
+
+static void
+quad_get_ids(const unsigned itri, unsigned ids[3], void* data)
+{
+ const unsigned id = itri * 3;
+ NCHECK(ids, NULL);
+ CHECK(itri < quad_ntris, 1);
+ (void)data;
+ ids[0] = quad_ids[id + 0];
+ ids[1] = quad_ids[id + 1];
+ ids[2] = quad_ids[id + 2];
+}
+
+static void
+quad_get_pos(const unsigned ivert, float pos[3], void* data)
+{
+ const unsigned i = ivert*3;
+ NCHECK(pos, NULL);
+ CHECK(ivert < quad_nverts, 1);
+ (void)data;
+ pos[0] = quad_verts[i+0];
+ pos[1] = quad_verts[i+1];
+ pos[2] = quad_verts[i+2];
+}
+
+static void
+test_quad(struct s3d_device* dev)
+{
+ struct ray ray;
+ struct s3d_attrib attr;
+ struct s3d_hit hit[2];
+ struct s3d_scene* scn;
+ struct s3d_scene_view* view[2];
+ struct s3d_shape* quad;
+ struct s3d_shape* quad_inst;
+ struct s3d_vertex_data vdata;
+ unsigned quad_id;
+ unsigned quad_inst_id;
+ float transform[12];
+ float dir[3];
+ float range[2];
+
+ f33_rotation_pitch(transform, (float)PI);
+ f3_splat(transform+9, 0);
+
+ vdata.type = S3D_FLOAT3;
+ vdata.usage = S3D_POSITION;
+ vdata.get = quad_get_pos;
+ CHECK(s3d_shape_create_mesh(dev, &quad), RES_OK);
+ CHECK(s3d_mesh_set_hit_filter_function(quad, filter, NULL), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices
+ (quad, quad_ntris, quad_get_ids, quad_nverts, &vdata, 1, NULL), RES_OK);
+
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, quad), RES_OK);
+ CHECK(s3d_scene_instantiate(scn, &quad_inst), RES_OK);
+ CHECK(s3d_instance_set_transform(quad_inst, transform), RES_OK);
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, quad_inst), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &view[0]), RES_OK);
+
+ CHECK(s3d_scene_clear(scn), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, quad), RES_OK);
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &view[1]), RES_OK);
+
+ CHECK(s3d_shape_get_id(quad, &quad_id), RES_OK);
+ CHECK(s3d_shape_get_id(quad_inst, &quad_inst_id), RES_OK);
+
+ f3(ray.org, 0.f, 0.5f, -1.f);
+ f3(ray.dir, 0.f, 0.f, 1.f);
+ f2(range, 0.f, FLT_MAX);
+ CHECK(s3d_scene_view_trace_ray
+ (view[0], ray.org, ray.dir, range, &ray, &hit[0]), RES_OK);
+ CHECK(s3d_scene_view_trace_ray
+ (view[1], ray.org, ray.dir, range, &ray, &hit[1]), RES_OK);
+
+ CHECK(hit[0].prim.prim_id, 0);
+ CHECK(hit[1].prim.prim_id, 1);
+ CHECK(hit[0].prim.geom_id, quad_id);
+ CHECK(hit[1].prim.geom_id, quad_id);
+ CHECK(hit[0].prim.inst_id, quad_inst_id);
+ CHECK(hit[1].prim.inst_id, S3D_INVALID_ID);
+ CHECK(f3_eq_eps(hit[0].normal, f3_minus(dir, hit[1].normal), 1.e-6f), 1);
+ CHECK(eq_epsf(hit[0].distance, hit[1].distance, 1.e-6f), 1);
+
+ CHECK(s3d_primitive_get_attrib
+ (&hit[0].prim, S3D_GEOMETRY_NORMAL, hit[0].uv, &attr), RES_OK);
+ f3_normalize(attr.value, attr.value);
+ f3_normalize(hit[0].normal, hit[0].normal);
+ CHECK(f3_eq_eps(hit[0].normal, attr.value, 1.e-6f), 1);
+
+ CHECK(s3d_primitive_get_attrib
+ (&hit[1].prim, S3D_GEOMETRY_NORMAL, hit[1].uv, &attr), RES_OK);
+ f3_normalize(attr.value, attr.value);
+ f3_normalize(hit[1].normal, hit[1].normal);
+ CHECK(f3_eq_eps(hit[1].normal, attr.value, 1.e-6f), 1);
+
+ CHECK(s3d_scene_view_ref_put(view[0]), RES_OK);
+ CHECK(s3d_scene_view_ref_put(view[1]), RES_OK);
+
+ CHECK(s3d_shape_ref_put(quad_inst), RES_OK);
+ CHECK(s3d_shape_ref_put(quad), RES_OK);
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+}
+
+static void
+test_cbox(struct s3d_device* dev)
+{
+ struct image img;
+ struct camera cam;
+ struct cbox_desc cbox_desc;
+ struct s3d_scene* scn;
+ struct s3d_scene* cbox;
+ struct s3d_shape* shape;
+ struct s3d_vertex_data vdata;
+ struct s3d_scene_view* view;
+ float lower[3], upper[3], extend[3];
+ float size[2];
+ float pos[3], tgt[3], up[3];
+ float org[3], dir[3], range[2];
+ float proj_ratio;
+ unsigned walls_id;
+ const size_t img_sz[2] = { 640, 480 };
+ const size_t N = 8;
+ size_t x, y;
+
+ CHECK(s3d_scene_create(dev, &cbox), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+
+ vdata.usage = S3D_POSITION;
+ vdata.type = S3D_FLOAT3;
+ vdata.get = cbox_get_position;
+
+ /* Walls */
+ cbox_desc.vertices = cbox_walls;
+ cbox_desc.indices = cbox_walls_ids;
+ CHECK(s3d_shape_create_mesh(dev, &shape), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices(shape, cbox_walls_ntris, cbox_get_ids,
+ cbox_walls_nverts, &vdata, 1, &cbox_desc), RES_OK);
+ CHECK(s3d_scene_attach_shape(cbox, shape), RES_OK);
+ CHECK(s3d_shape_get_id(shape, &walls_id), RES_OK);
+ CHECK(s3d_shape_ref_put(shape), RES_OK);
+
+ /* Short block */
+ cbox_desc.vertices = cbox_short_block;
+ cbox_desc.indices = cbox_block_ids;
+ CHECK(s3d_shape_create_mesh(dev, &shape), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices(shape, cbox_block_ntris, cbox_get_ids,
+ cbox_block_nverts, &vdata, 1, &cbox_desc), RES_OK);
+ CHECK(s3d_scene_attach_shape(cbox, shape), RES_OK);
+ CHECK(s3d_shape_ref_put(shape), RES_OK);
+
+ /* Tall block */
+ cbox_desc.vertices = cbox_tall_block;
+ cbox_desc.indices = cbox_block_ids;
+ CHECK(s3d_shape_create_mesh(dev, &shape), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices(shape, cbox_block_ntris, cbox_get_ids,
+ cbox_block_nverts, &vdata, 1, &cbox_desc), RES_OK);
+ CHECK(s3d_scene_attach_shape(cbox, shape), RES_OK);
+ CHECK(s3d_shape_ref_put(shape), RES_OK);
+
+ /* Compute the cbox extends */
+ CHECK(s3d_scene_view_create(cbox, S3D_GET_PRIMITIVE, &view), RES_OK);
+ CHECK(s3d_scene_view_get_aabb(view, lower, upper), RES_OK);
+ CHECK(s3d_scene_view_ref_put(view), RES_OK);
+ f3_sub(extend, upper, lower);
+
+ /* Create instances */
+ size[0] = extend[0]*(float)N + (extend[0]*0.05f) * (float)(N-1);
+ size[1] = extend[2]*(float)N + (extend[2]*0.05f) * (float)(N-1);
+ pos[0] = -size[0] * 0.5f;
+ pos[1] = 0;
+ FOR_EACH(x, 0, N) {
+ pos[2] = -size[1] * 0.5f;
+ FOR_EACH(y, 0, N) {
+ CHECK(s3d_scene_instantiate(cbox, &shape), RES_OK);
+ CHECK(s3d_instance_set_position(shape, pos), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, shape), RES_OK);
+ CHECK(s3d_shape_ref_put(shape), RES_OK);
+ pos[2] += extend[2] * 1.05f;
+ }
+ pos[0] += extend[0] * 1.05f;
+ }
+
+ /* Setup point of view */
+ f3(pos, 0.f, -3000.f, 0.f);
+ f3(tgt, 0.f, 0.f, 0.f);
+ f3(up, 0.f, 0.f, 1.f);
+ proj_ratio = (float)img_sz[0] / (float)img_sz[1];
+ camera_init(&cam, pos, tgt, up, (float)PI*0.5f, proj_ratio);
+
+ image_init(NULL, &img);
+ CHECK(image_setup
+ (&img, img_sz[0], img_sz[1], img_sz[0]*3, IMAGE_RGB8, NULL), RES_OK);
+
+ /* Trace rays */
+ CHECK(s3d_scene_view_create(scn, S3D_TRACE, &view), RES_OK);
+ range[0] = 0.f;
+ range[1] = FLT_MAX;
+ FOR_EACH(y, 0, img_sz[1]) {
+ float pixel[2];
+ pixel[1] = (float)y / (float)img_sz[1];
+ FOR_EACH(x, 0, img_sz[0]) {
+ const size_t ipix = (y*img_sz[0] + x)*3/*RGB*/;
+ struct s3d_hit hit;
+
+ pixel[0] = (float)x/(float)img_sz[0];
+ camera_ray(&cam, pixel, org, dir);
+ CHECK(s3d_scene_view_trace_ray(view, org, dir, range, NULL, &hit), RES_OK);
+
+ if(S3D_HIT_NONE(&hit)) {
+ ((uint8_t*)img.pixels)[ipix+0] = 0;
+ ((uint8_t*)img.pixels)[ipix+1] = 0;
+ ((uint8_t*)img.pixels)[ipix+2] = 0;
+ } else {
+ float normal[3] = {0.f, 0.f, 0.f};
+ float col[3], dot;
+ float f = (float)hit.prim.inst_id / (float)(N*N);
+ f3(col, f, MMAX(0.f, 1.f-f), MMAX(0.f, 1.f-f));
+
+ if(hit.prim.geom_id == walls_id) {
+ if(hit.prim.prim_id == 4 || hit.prim.prim_id == 5) {
+ f3(col, col[0], 0.f, 0.f);
+ } else if(hit.prim.prim_id == 6 || hit.prim.prim_id == 7) {
+ f3(col, 0.f, col[1], 0.f);
+ }
+ }
+
+ f3_normalize(normal, hit.normal);
+ dot = absf(f3_dot(normal, dir));
+ ((uint8_t*)img.pixels)[ipix+0] = (uint8_t)(dot * col[0] * 255.f);
+ ((uint8_t*)img.pixels)[ipix+1] = (uint8_t)(dot * col[1] * 255.f);
+ ((uint8_t*)img.pixels)[ipix+2] = (uint8_t)(dot * col[2] * 255.f);
+ }
+ }
+ }
+ CHECK(s3d_scene_view_ref_put(view), RES_OK);
+
+ /* Write image */
+ CHECK(image_write_ppm_stream(&img, 0, stdout), RES_OK);
+ image_release(&img);
+
+ /* Release data */
+ CHECK(s3d_scene_ref_put(cbox), RES_OK);
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct s3d_device* dev;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+ CHECK(s3d_device_create(NULL, &allocator, 0, &dev), RES_OK);
+
+ test_quad(dev);
+ test_cbox(dev);
+
+ CHECK(s3d_device_ref_put(dev), RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+ return 0;
+}
diff --git a/src/test_s3d_utils.h b/src/test_s3d_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2015-2017 (contact@meso-star.com)
*
* This software is a computer program whose purpose is to describe a
* virtual 3D environment that can be ray-traced and sampled both robustly