star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.fr/star-3d.git
Log | Files | Refs | README | LICENSE

commit aa858e2ecf18ab9677ca7fd3f8f65357d3dcfbd4
parent 61ef1b92dea5c2dfcb3c3eda30d45b9d45034bfd
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 28 Jul 2016 15:23:29 +0200

Rename the whole session API in scene_view

Diffstat:
Mcmake/CMakeLists.txt | 7++++---
Msrc/s3d.h | 62+++++++++++++++++++++++++++++++-------------------------------
Msrc/s3d_instance.h | 2+-
Msrc/s3d_scene.c | 8++++----
Msrc/s3d_scene_c.h | 2+-
Asrc/s3d_scene_view.c | 1418+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/s3d_scene_view_c.h | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/s3d_session.c | 1418-------------------------------------------------------------------------------
Dsrc/s3d_session_c.h | 124-------------------------------------------------------------------------------
Msrc/test_s3d_primitive.c | 16++++++++--------
Msrc/test_s3d_sampler.c | 78+++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/test_s3d_scene.c | 122++++++++++++++++++++++++++++++++++++++++----------------------------------------
Asrc/test_s3d_scene_view.c | 1048+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/test_s3d_session.c | 1048-------------------------------------------------------------------------------
Msrc/test_s3d_trace_ray.c | 102++++++++++++++++++++++++++++++++++++++++----------------------------------------
15 files changed, 2790 insertions(+), 2789 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -68,7 +68,7 @@ set(S3D_FILES_SRC s3d_mesh.c s3d_primitive.c s3d_scene.c - s3d_session.c + s3d_scene_view.c s3d_shape.c) set(S3D_FILES_INC_API s3d.h) set(S3D_FILES_INC @@ -79,7 +79,8 @@ set(S3D_FILES_INC s3d_geometry.h s3d_instance.h s3d_mesh.h - s3d_session_c.h + s3d_scene_c.h + s3d_scene_view_c.h s3d_shape_c.h) set(S3D_FILES_DOC COPYING.fr COPYING.en README.md) @@ -141,7 +142,7 @@ if(NOT NO_TEST) new_test(test_s3d_primitive) new_test(test_s3d_sampler) new_test(test_s3d_scene) - new_test(test_s3d_session) + new_test(test_s3d_scene_view) new_test(test_s3d_shape) build_test(test_s3d_trace_ray) diff --git a/src/s3d.h b/src/s3d.h @@ -159,7 +159,7 @@ struct s3d_hit { 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) @@ -184,8 +184,8 @@ typedef int /* Forward declaration of s3d opaque data types */ struct s3d_device; /* Entry point of the library */ struct s3d_scene; /* Collection of shapes */ +struct s3d_scene_view; /* Scene state */ struct s3d_shape; /* Surfacic geometry */ -struct s3d_session; /* Scene state */ /* Forward declaration of external data types */ struct logger; @@ -270,30 +270,30 @@ s3d_scene_get_device struct s3d_device** dev); /******************************************************************************* - * Session API - View of the current scene geometry + * Scene view API - State of the scene geometry ******************************************************************************/ S3D_API res_T -s3d_session_create +s3d_scene_view_create (struct s3d_scene* scn, - const int session_mask, /* Combination of s3d_session_flag */ - struct s3d_session** session); + const int mask, /* Combination of s3d_scene_view_flag */ + struct s3d_scene_view** scnview); S3D_API res_T -s3d_session_ref_get - (struct s3d_session* session); +s3d_scene_view_ref_get + (struct s3d_scene_view* scnview); S3D_API res_T -s3d_session_ref_put - (struct s3d_session* session); +s3d_scene_view_ref_put + (struct s3d_scene_view* scnview); S3D_API res_T -s3d_session_get_mask - (struct s3d_session* session, +s3d_scene_view_get_mask + (struct s3d_scene_view* scnview, int* mask); S3D_API res_T -s3d_session_trace_ray - (struct s3d_session* session, +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 */ @@ -304,11 +304,11 @@ s3d_session_trace_ray * 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 the session was created with the + * set to S3D_HIT_NULL. Can be called only if the scnview was created with the * S3D_TRACE flag. */ S3D_API res_T -s3d_session_trace_rays - (struct s3d_session* session, +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 */ @@ -319,46 +319,46 @@ s3d_session_trace_rays struct s3d_hit* hits); /* Uniformly sample the scene and returned the sampled primitive and its sample - * uv position. Can be called only if the session was created with the + * uv position. Can be called only if the scnview was created with the * S3D_SAMPLE flag */ S3D_API res_T -s3d_session_sample - (struct s3d_session* session, +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 the session was +/* 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_session_get_primitive - (struct s3d_session* session, +s3d_scene_view_get_primitive + (struct s3d_scene_view* scnview, const unsigned iprim, /* in [0, #prims) */ struct s3d_primitive* prim); /* Return the overall number of scene primitives */ S3D_API res_T -s3d_session_primitives_count - (struct s3d_session* session, +s3d_scene_view_primitives_count + (struct s3d_scene_view* scnview, size_t* primitives_count); /* Compute the overall scene surface area */ S3D_API res_T -s3d_session_compute_area - (struct s3d_session* session, +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. */ S3D_API res_T -s3d_session_compute_volume - (struct s3d_session* session, +s3d_scene_view_compute_volume + (struct s3d_scene_view* scnview, float* volume); /* Retrieve the Axis Aligned Bounding Box of the scene */ S3D_API res_T -s3d_session_get_aabb - (struct s3d_session* session, +s3d_scene_view_get_aabb + (struct s3d_scene_view* scnview, float lower[3], /* AABB lower bound */ float upper[3]); /* AABB upper bound */ diff --git a/src/s3d_instance.h b/src/s3d_instance.h @@ -40,7 +40,7 @@ struct instance { float transform[12]; /* local to world 3x4 column major matrix */ struct s3d_scene* scene; /* Instantiated scene */ - struct s3d_session* session; /* Current session of the instance */ + struct s3d_scene_view* scnview; /* Current view of the instantiated scene */ ref_T ref; }; diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -33,7 +33,7 @@ #include "s3d.h" #include "s3d_device_c.h" #include "s3d_scene_c.h" -#include "s3d_session_c.h" +#include "s3d_scene_view_c.h" #include "s3d_shape_c.h" #include <rsys/list.h> @@ -53,8 +53,8 @@ scene_release(ref_T* ref) ASSERT(ref); scn = CONTAINER_OF(ref, struct s3d_scene, ref); dev = scn->dev; - LIST_FOR_EACH_SAFE(node, tmp, &scn->sessions) { - session_destroy(CONTAINER_OF(node, struct s3d_session, node)); + 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); @@ -83,7 +83,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) } htable_shape_init(dev->allocator, &scn->shapes); SIG_INIT(&scn->sig_shape_detach); - list_init(&scn->sessions); + list_init(&scn->scnviews); ref_init(&scn->ref); S3D(device_ref_get(dev)); scn->dev = dev; diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -52,7 +52,7 @@ CLBK(scene_shape_cb_T, ARG2 struct s3d_scene { struct htable_shape shapes; /* List of attached shapes */ size_t instances_count; /* # instances in the scene */ - struct list_node sessions; /* Pool of available s3d_sessions */ + struct list_node scnviews; /* Pool of available s3d_scene_view */ signal_T sig_shape_detach; diff --git a/src/s3d_scene_view.c b/src/s3d_scene_view.c @@ -0,0 +1,1418 @@ +/* Copyright (C) |Meso|Star> 2015-2016 (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; + void* data; /* User defined data */ +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +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_delete_geometry = 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; + 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); + } + 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->org, ray_ex->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) { + 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 = rtcNewInstance + (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; + } + + /* 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); + rtcSetTransform + (scnview->rtc_scn, + geom->irtc, + RTC_MATRIX_COLUMN_MAJOR, + geom->data.instance->transform); +} + + +static INLINE res_T +scene_view_setup_embree(struct s3d_scene_view* scnview) +{ + struct htable_geom_iterator it, end; + int rtc_outdated = scnview->rtc_delete_geometry; + res_T res = RES_OK; + ASSERT(scnview); + + 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; + } + + /* Commit the embree changes */ + if(rtc_outdated) { + rtcCommit(scnview->rtc_scn); + scnview->rtc_delete_geometry = 0; + } + +exit: + return res; +error: + 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* instance_scnview = 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 a scnview on the scene to instantiate */ + res = s3d_scene_view_create + (shape->data.instance->scene, mask, &instance_scnview); + if(res != RES_OK) goto error; + + S3D(shape_get_id(shape, &shape_id)); + pgeom = htable_geom_find(&scnview->cached_geoms, &shape_id); + /* Create the scene instance of the geometry if necessary */ + 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 = instance_scnview; + + /* 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** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + 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** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + 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** 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: 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; + /* Transform local scene AABB 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); + 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** pgeom = htable_geom_iterator_data_get(&it); + struct geometry* geom = *pgeom; + 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 { + const RTCSceneFlags rtc_scene_mask = + RTC_SCENE_DYNAMIC + | RTC_SCENE_INCOHERENT + | RTC_SCENE_ROBUST; + const RTCAlgorithmFlags rtc_algorithm_mask = + RTC_INTERSECT1 + | RTC_INTERSECT4; + + 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); + 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); + + scnview->rtc_scn = rtcDeviceNewScene + (scn->dev->rtc, rtc_scene_mask, rtc_algorithm_mask); + if(!scnview->rtc_scn) { + res = RES_MEM_ERR; + goto error; + } + + 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_geom_iterator it, end; + 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_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); + + if(geom->type == GEOM_INSTANCE) { + if(geom->data.instance->scnview) { + S3D(scene_view_ref_put(geom->data.instance->scnview)); + 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 n; (void)n; + scene_view_destroy_geometry(scnview, geom); + n = htable_geom_erase(&scnview->cached_geoms, &shape_id); + ASSERT(n == 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, 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.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); + 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,124 @@ +/* Copyright (C) |Meso|Star> 2015-2016 (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> + +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; + + /* 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; /* Combinatin of enum s3d_scene_view_flag */ + int rtc_delete_geometry; /* Define if Embree geometries were deleted */ + 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_session.c b/src/s3d_session.c @@ -1,1418 +0,0 @@ -/* Copyright (C) |Meso|Star> 2015-2016 (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_session_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_session* session; - void* data; /* User defined data */ -}; - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -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 -session_destroy_geometry(struct s3d_session* session, struct geometry* geom) -{ - ASSERT(geom); - if(geom->irtc != RTC_INVALID_GEOMETRY_ID) { - rtcDeleteGeometry(session->rtc_scn, geom->irtc); - geom->irtc = RTC_INVALID_GEOMETRY_ID; - session->rtc_delete_geometry = 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_session* session = (struct s3d_session*)data; - unsigned shape_id; - ASSERT(scn && shape && data); - (void)scn; - - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&session->cached_geoms, &shape_id); - - /* The session did not register a geometry for this shape. Ignore the signal */ - if(!pgeom) return; - - geom = *pgeom; - if(session->mask == 0) { - /* The session is NOT in use. Directly rm the cached geometry */ - size_t n; (void)n; - session_destroy_geometry(session, geom); - n = htable_geom_erase(&session->cached_geoms, &shape_id); - ASSERT(n == 1); - } else { - /* The session is in use. Delay the deletion of the cached geometry */ - res_T res = darray_uint_push_back(&session->detached_shapes, &shape_id); - if(res != RES_OK) FATAL("Insufficient memory.\n"); - } -} - -static INLINE void -hit_setup(struct s3d_session* session, const RTCRay* ray, struct s3d_hit* hit) -{ - float w; - char flip_surface = 0; - - ASSERT(session && 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(&session->embree2geoms)); - geom_mesh = session_geometry_from_embree_id(session, 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(&session->embree2geoms)); - geom_inst = session_geometry_from_embree_id(session, ray->instID); - geom_mesh = session_geometry_from_embree_id - (geom_inst->data.instance->session, 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->session, &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 -embree_geometry_register - (struct s3d_session* session, - struct geometry* geom) -{ - ASSERT(session && 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(session->rtc_scn, RTC_GEOMETRY_DYNAMIC, - mesh_get_ntris(geom->data.mesh), mesh_get_nverts(geom->data.mesh)); - break; - case GEOM_INSTANCE: - geom->irtc = rtcNewInstance - (session->rtc_scn, geom->data.instance->session->rtc_scn); - break; - default: FATAL("Unreachable code\n"); break; - } - if(geom->irtc == RTC_INVALID_GEOMETRY_ID) - return RES_UNKNOWN_ERR; - } - - /* Register the embree geometry in the embree2geoms associative array */ - if(geom->irtc >= darray_geom_size_get(&session->embree2geoms)) { - const res_T res = darray_geom_resize(&session->embree2geoms, geom->irtc+1); - if(res != RES_OK) { - rtcDeleteGeometry(session->rtc_scn, geom->irtc); - geom->irtc = RTC_INVALID_GEOMETRY_ID; - return res; - } - } - darray_geom_data_get(&session->embree2geoms)[geom->irtc] = geom; - return RES_OK; -} - -static INLINE void -embree_geometry_setup_positions - (struct s3d_session* session, struct geometry* geom) -{ - ASSERT(session && geom && geom->type == GEOM_MESH); - ASSERT(geom->irtc != RTC_INVALID_GEOMETRY_ID); - rtcSetBuffer(session->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER, - mesh_get_pos(geom->data.mesh), 0, sizeof(float[3])); - rtcUpdateBuffer(session->rtc_scn, geom->irtc, RTC_VERTEX_BUFFER); -} - -static INLINE void -embree_geometry_setup_indices - (struct s3d_session* session, struct geometry* geom) -{ - ASSERT(session && geom && geom->type == GEOM_MESH); - ASSERT(geom->irtc != RTC_INVALID_GEOMETRY_ID); - rtcSetBuffer(session->rtc_scn, geom->irtc, RTC_INDEX_BUFFER, - mesh_get_ids(geom->data.mesh), 0, sizeof(uint32_t[3])); - rtcUpdateBuffer(session->rtc_scn, geom->irtc, RTC_INDEX_BUFFER); -} - -static INLINE void -embree_geometry_setup_enable_state - (struct s3d_session* session, struct geometry* geom) -{ - ASSERT(session && geom); - if(geom->is_enabled) { - rtcEnable(session->rtc_scn, geom->irtc); - } else { - rtcDisable(session->rtc_scn, geom->irtc); - } -} - -static INLINE void -embree_geometry_setup_filter_function - (struct s3d_session* session, struct geometry* geom) -{ - ASSERT(session && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID); - ASSERT(geom->type == GEOM_MESH); - - if(!geom->data.mesh->filter.func) { - rtcSetIntersectionFilterFunction(session->rtc_scn, geom->irtc, NULL); - } else { - rtcSetIntersectionFilterFunction(session->rtc_scn, geom->irtc, filter_wrapper); - rtcSetUserData(session->rtc_scn, geom->irtc, &geom->data.mesh->filter); - } -} - -static INLINE void -embree_geometry_setup_transform - (struct s3d_session* session, struct geometry* geom) -{ - ASSERT(session && geom && geom->irtc != RTC_INVALID_GEOMETRY_ID); - ASSERT(geom->type == GEOM_INSTANCE); - rtcSetTransform - (session->rtc_scn, - geom->irtc, - RTC_MATRIX_COLUMN_MAJOR, - geom->data.instance->transform); -} - - -static INLINE res_T -session_setup_embree(struct s3d_session* session) -{ - struct htable_geom_iterator it, end; - int rtc_outdated = session->rtc_delete_geometry; - res_T res = RES_OK; - ASSERT(session); - - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->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(session, geom); - if(res != RES_OK) goto error; - - /* Flush the embree geometry states */ - if((geom->embree_outdated_mask & EMBREE_VERTICES) != 0) - embree_geometry_setup_positions(session, geom); - if((geom->embree_outdated_mask & EMBREE_INDICES) != 0) - embree_geometry_setup_indices(session, geom); - if((geom->embree_outdated_mask & EMBREE_ENABLE) != 0) - embree_geometry_setup_enable_state(session, geom); - if((geom->embree_outdated_mask & EMBREE_FILTER_FUNCTION) != 0) - embree_geometry_setup_filter_function(session, geom); - if((geom->embree_outdated_mask & EMBREE_TRANSFORM) != 0) - embree_geometry_setup_transform(session, geom); - - geom->embree_outdated_mask = 0; - } - - /* Commit the embree changes */ - if(rtc_outdated) { - rtcCommit(session->rtc_scn); - session->rtc_delete_geometry = 0; - } - -exit: - return res; -error: - darray_geom_clear(&session->embree2geoms); - goto exit; -} - -static res_T -session_register_mesh - (struct s3d_session* session, - struct s3d_shape* shape) -{ - struct geometry** pgeom = NULL; - struct geometry* geom = NULL; - size_t iattr; - unsigned shape_id; - - res_T res = RES_OK; - ASSERT(session && shape && shape->type == GEOM_MESH); - - /* Retrieve the cached geometry */ - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&session->cached_geoms, &shape_id); - if(pgeom) { - geom = *pgeom; - } else { - res = geometry_create(session->scn->dev, &geom); - if(res != RES_OK) goto error; - res = mesh_create(session->scn->dev, &geom->data.mesh); - if(res != RES_OK) goto error; - geom->type = GEOM_MESH; - res = htable_geom_set(&session->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(session->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(session->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 -session_register_instance - (struct s3d_session* session, - struct s3d_shape* shape, - const int session_mask) -{ - struct geometry** pgeom = NULL; - struct geometry* geom = NULL; - struct s3d_session* instance_session = NULL; - unsigned shape_id; - res_T res = RES_OK; - ASSERT(session && 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 a session on the scene to instantiate */ - res = s3d_session_create - (shape->data.instance->scene, session_mask, &instance_session); - if(res != RES_OK) goto error; - - S3D(shape_get_id(shape, &shape_id)); - pgeom = htable_geom_find(&session->cached_geoms, &shape_id); - /* Create the scene instance of the geometry if necessary */ - if(pgeom) { - geom = *pgeom; - } else { - res = geometry_create(session->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(&session->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->session = instance_session; - - /* 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 -session_compute_cdf(struct s3d_session* session) -{ - struct htable_geom_iterator it, end; - size_t len; - float area = 0.f; - res_T res = RES_OK; - ASSERT(session); - ASSERT(darray_fltui_size_get(&session->cdf) == 0); - - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->cached_geoms, &end); - - while(!htable_geom_iterator_eq(&it, &end)) { - const unsigned* shape_id = htable_geom_iterator_key_get(&it); - struct geometry** pgeom = htable_geom_iterator_data_get(&it); - struct geometry* geom = *pgeom; - 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 session synchronisation */ - len = darray_fltui_size_get(&geom->data.instance->session->cdf); - if(len) { - area += darray_fltui_cdata_get - (&geom->data.instance->session->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(&session->cdf, &fltui); - if(res != RES_OK) goto error; - } - } -exit: - return res; -error: - darray_fltui_clear(&session->cdf); - goto exit; -} - -static res_T -session_compute_nprims_cdf - (struct s3d_session* session, - const char store_cdf) -{ - struct htable_geom_iterator it, end; - size_t len; - unsigned nprims; - res_T res = RES_OK; - ASSERT(session); - ASSERT(darray_nprims_cdf_size_get(&session->nprims_cdf) == 0); - - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->cached_geoms, &end); - - nprims = 0; - while(!htable_geom_iterator_eq(&it, &end)) { - const unsigned* shape_id = htable_geom_iterator_key_get(&it); - struct geometry** pgeom = htable_geom_iterator_data_get(&it); - struct geometry* geom = *pgeom; - 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 session synchronisation */ - len = darray_nprims_cdf_size_get - (&geom->data.instance->session->nprims_cdf); - if(len) { - nprims += darray_nprims_cdf_cdata_get - (&geom->data.instance->session->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(&session->nprims_cdf, &cdf); - if(res != RES_OK) goto error; - } - } -exit: - return res; -error: - darray_nprims_cdf_clear(&session->nprims_cdf); - goto exit; -} - -static void -session_compute_scene_aabb(struct s3d_session* session) -{ - struct htable_geom_iterator it, end; - float lower[3], upper[3]; - - ASSERT(session->lower[0] == FLT_MAX && session->upper[0] == -FLT_MAX); - ASSERT(session->lower[1] == FLT_MAX && session->upper[1] == -FLT_MAX); - ASSERT(session->lower[2] == FLT_MAX && session->upper[2] == -FLT_MAX); - - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->cached_geoms, &end); - - while(!htable_geom_iterator_eq(&it, &end)) { - struct instance* inst; - 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: mesh_compute_aabb(geom->data.mesh, lower, upper); break; - case GEOM_INSTANCE: - /* Note that the instance AABB was computed during its session - * synchronisation. */ - inst = geom->data.instance; - /* Transform local scene AABB in world space */ - f33_mulf3(lower, inst->transform, inst->session->lower); - f33_mulf3(upper, inst->transform, inst->session->upper); - f3_add(lower, inst->transform + 9, lower); - f3_add(upper, inst->transform + 9, upper); - break; - default: FATAL("Unreachable code\n"); break; - } - f3_min(session->lower, session->lower, lower); - f3_max(session->upper, session->upper, upper); - } -} - -float -session_compute_volume - (struct s3d_session* session, - const char flip_surface) -{ - struct htable_geom_iterator it, end; - float volume; - - ASSERT(session); - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->cached_geoms, &end); - - volume = 0.f; - while(!htable_geom_iterator_eq(&it, &end)) { - struct geometry** pgeom = htable_geom_iterator_data_get(&it); - struct geometry* geom = *pgeom; - 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 += session_compute_volume(geom->data.instance->session, flip); - break; - default: FATAL("Unreachable code\n"); break; - } - } - - if(volume < 0.f) { - log_warning(session->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 -session_sync - (struct s3d_session* session, - const int mask) -{ - struct htable_shape_iterator it, end; - res_T res = RES_OK; - - ASSERT(session); - ASSERT((mask & (S3D_TRACE|S3D_SAMPLE|S3D_GET_PRIMITIVE)) != 0); - - /* Commit the scene shape to the session */ - htable_shape_begin(&session->scn->shapes, &it); - htable_shape_end(&session->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 = session_register_instance(session, shape, mask); - break; - case GEOM_MESH: - res = session_register_mesh(session, shape); - break; - default: FATAL("Unreachable code\n"); break; - } - if(res != RES_OK) goto error; - htable_shape_iterator_next(&it); - } - - session_compute_scene_aabb(session); - - /* Setup the scene for the S3D_TRACE session */ - if((mask & S3D_TRACE) != 0) { - res = session_setup_embree(session); - if(res != RES_OK) goto error; - } - /* Setup the scene for the S3D_SAMPLE session */ - if((mask & S3D_SAMPLE) != 0) { - res = session_compute_cdf(session); - if(res != RES_OK) goto error; - } - /* Setup the scene for the scene_primitive_id/S3D_GET_PRIMITIVE session */ - res = session_compute_nprims_cdf(session, (mask & S3D_GET_PRIMITIVE)!=0); - if(res != RES_OK) goto error; - - session->mask = mask; - -exit: - return res; -error: - goto exit; -} - -static res_T -session_create(struct s3d_scene* scn, struct s3d_session** out_session) -{ - struct s3d_session* session = NULL; - res_T res = RES_OK; - ASSERT(scn && out_session); - - if(!is_list_empty(&scn->sessions)) { - /* Retrieve an already allocated session */ - session = CONTAINER_OF(list_head(&scn->sessions), struct s3d_session, node); - list_del(&session->node); - ref_get(&session->ref); - } else { - const RTCSceneFlags rtc_scene_mask = - RTC_SCENE_DYNAMIC - | RTC_SCENE_INCOHERENT - | RTC_SCENE_ROBUST; - const RTCAlgorithmFlags rtc_algorithm_mask = - RTC_INTERSECT1 - | RTC_INTERSECT4; - - session = (struct s3d_session*)MEM_CALLOC - (scn->dev->allocator, 1, sizeof(struct s3d_session)); - if(!session) { - res = RES_MEM_ERR; - goto error; - } - list_init(&session->node); - htable_geom_init(scn->dev->allocator, &session->cached_geoms); - darray_geom_init(scn->dev->allocator, &session->embree2geoms); - darray_fltui_init(scn->dev->allocator, &session->cdf); - darray_nprims_cdf_init(scn->dev->allocator, &session->nprims_cdf); - darray_uint_init(scn->dev->allocator, &session->detached_shapes); - f3_splat(session->lower, FLT_MAX); - f3_splat(session->upper,-FLT_MAX); - ref_init(&session->ref); - - session->rtc_scn = rtcDeviceNewScene - (scn->dev->rtc, rtc_scene_mask, rtc_algorithm_mask); - if(!session->rtc_scn) { - res = RES_MEM_ERR; - goto error; - } - - CLBK_INIT(&session->on_shape_detach_cb); - CLBK_SETUP(&session->on_shape_detach_cb, on_shape_detach, session); - SIG_CONNECT_CLBK(&scn->sig_shape_detach, &session->on_shape_detach_cb); - } - S3D(scene_ref_get(scn)); - session->scn = scn; -exit: - *out_session = session; - return res; -error: - if(session) { - S3D(session_ref_put(session)); - session = NULL; - } - goto exit; -} - -static void -session_release(ref_T* ref) -{ - struct htable_geom_iterator it, end; - struct s3d_session* session = CONTAINER_OF(ref, struct s3d_session, ref); - size_t i, n; - ASSERT(ref); - - /* Release the session of the instances */ - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->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); - - if(geom->type == GEOM_INSTANCE) { - if(geom->data.instance->session) { - S3D(session_ref_put(geom->data.instance->session)); - geom->data.instance->session = NULL; - } - } - } - - /* Remove the geometry of the shapes detached while the session was active */ - n = darray_uint_size_get(&session->detached_shapes); - FOR_EACH(i, 0, n) { - const unsigned shape_id = darray_uint_cdata_get(&session->detached_shapes)[i]; - struct geometry** pgeom = htable_geom_find(&session->cached_geoms, &shape_id); - struct geometry* geom = *pgeom; - size_t n; (void)n; - session_destroy_geometry(session, geom); - n = htable_geom_erase(&session->cached_geoms, &shape_id); - ASSERT(n == 1); - } - darray_uint_clear(&session->detached_shapes); - - /* Clear the session data structures excepted the cache of geometries that - * will be used to speed up the future session creation */ - darray_geom_clear(&session->embree2geoms); - darray_fltui_clear(&session->cdf); - darray_nprims_cdf_clear(&session->nprims_cdf); - f3_splat(session->lower, FLT_MAX); - f3_splat(session->upper,-FLT_MAX); - session->mask = 0; - - /* Do not physically release the memory space of the session. Add it to the - * available sessions pool of the scene */ - list_add(&session->scn->sessions, &session->node); - S3D(scene_ref_put(session->scn)); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -s3d_session_create - (struct s3d_scene* scn, - const int session_mask, - struct s3d_session** out_session) -{ - struct s3d_session* session = NULL; - res_T res = RES_OK; - - if(!scn || !out_session) { - res = RES_BAD_ARG; - goto error; - } - - 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); - res = RES_BAD_ARG; - goto error; - } - - res = session_create(scn, &session); - if(res != RES_OK) goto error; - - res = session_sync(session, session_mask); - if(res != RES_OK) goto error; - -exit: - if(out_session) *out_session = session; - return res; -error: - if(session) { - S3D(session_ref_put(session)); - session = NULL; - } - goto exit; -} - -res_T -s3d_session_ref_get(struct s3d_session* session) -{ - if(!session) return RES_BAD_ARG; - ref_get(&session->ref); - return RES_OK; -} - -res_T -s3d_session_ref_put(struct s3d_session* session) -{ - if(!session) return RES_BAD_ARG; - ref_put(&session->ref, session_release); - return RES_OK; -} - -res_T -s3d_session_get_mask(struct s3d_session* session, int* mask) -{ - if(!session || !mask) return RES_BAD_ARG; - *mask = session->mask; - return RES_OK; -} - -res_T -s3d_session_trace_ray - (struct s3d_session* session, - 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(!session || !org || !dir || !range || !hit) - return RES_BAD_ARG; - if(!f3_is_normalized(dir)) { - log_error(session->scn->dev, - "%s: unnormalized ray direction {%g, %g, %g}.\n", - FUNC_NAME, SPLIT3(dir)); - return RES_BAD_ARG; - } - if((session->mask & S3D_TRACE) == 0) { - log_error(session->scn->dev, - "%s: no active S3D_TRACE session on the submitted session.\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.session = session; - ray_ex.data = ray_data; - - rtcIntersect(session->rtc_scn, ray_ex); - - hit_setup(session, &ray_ex, hit); - - return RES_OK; -} - -res_T -s3d_session_trace_rays - (struct s3d_session* session, - 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(!session) 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_session_trace_ray(session, 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_session_sample - (struct s3d_session* session, - 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(!session || !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(session->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((session->mask & S3D_SAMPLE) == 0) { - log_error(session->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(&session->cdf) == 0) { - /* No geometry to sample */ - *primitive = S3D_PRIMITIVE_NULL; - goto exit; - } else if(darray_fltui_size_get(&session->cdf) == 1) { - ishape = darray_fltui_cdata_get(&session->cdf)[0].ui; - /* Map u to the CDF bounds */ - f = u * darray_fltui_cdata_get(&session->cdf)[0].flt; - } else { - fltui_begin = darray_fltui_cdata_get(&session->cdf); - fltui_end = fltui_begin + darray_fltui_size_get(&session->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(&session->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->session->cdf) == 1) { - ishape = darray_fltui_cdata_get(&geom->data.instance->session->cdf)[0].ui; - } else { - fltui_begin = darray_fltui_cdata_get(&geom->data.instance->session->cdf); - fltui_end = fltui_begin + darray_fltui_size_get(&geom->data.instance->session->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->session->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_session_get_primitive - (struct s3d_session* session, - 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(!session || !prim) { - res = RES_BAD_ARG; - goto error; - } - if((session->mask & S3D_GET_PRIMITIVE) == 0) { - log_error(session->scn->dev, - "%s: no active S3D_GET_PRIMITIVE session on the submitted scene.\n", - FUNC_NAME); - res = RES_BAD_OP; - goto error; - } - S3D(session_primitives_count(session, &nprims)); - if(iprim >= nprims) { - log_error(session->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(&session->nprims_cdf) == 1) { - ishape = darray_nprims_cdf_cdata_get(&session->nprims_cdf)[0].ishape; - } else { - begin = darray_nprims_cdf_cdata_get(&session->nprims_cdf); - end = begin + darray_nprims_cdf_size_get(&session->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(&session->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->session->nprims_cdf)==1) { - ishape = darray_nprims_cdf_cdata_get - (&geom->data.instance->session->nprims_cdf)[0].ishape; - } else { - begin = darray_nprims_cdf_cdata_get - (&geom->data.instance->session->nprims_cdf); - end = begin + darray_nprims_cdf_size_get - (&geom->data.instance->session->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->session->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_session_primitives_count(struct s3d_session* session, size_t* prims_count) -{ - res_T res = RES_OK; - - if(!session || !prims_count) { - res = RES_BAD_ARG; - goto error; - } - if((session->mask & S3D_GET_PRIMITIVE) != 0) { - const size_t len = darray_nprims_cdf_size_get(&session->nprims_cdf); - if(!len) { - *prims_count = 0; - } else { - *prims_count = darray_nprims_cdf_cdata_get - (&session->nprims_cdf)[len - 1].nprims; - } - } else { - struct htable_geom_iterator it, end; - size_t inst_count; - - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->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(session_primitives_count(geom->data.instance->session, &inst_count)); - *prims_count += inst_count; - break; - default: FATAL("Unreachable code\n"); break; - } - } - } -exit: - return res; -error: - goto exit; -} - -res_T -s3d_session_compute_area(struct s3d_session* session, float* out_area) -{ - float area; - res_T res = RES_OK; - - if(!session || !out_area) { - res = RES_BAD_ARG; - goto error; - } - if((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(&session->cdf); - if(!len) { - area = 0.f; - } else { - area = darray_fltui_cdata_get(&session->cdf)[len - 1].flt * 0.5f; - } - } else { - struct htable_geom_iterator it, end; - float inst_area; - - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->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(session_compute_area(geom->data.instance->session, &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_session_compute_volume(struct s3d_session* session, float* out_volume) -{ - if(!session || !out_volume) return RES_BAD_ARG; - *out_volume = session_compute_volume(session, 0/*No initial flip_surface*/); - return RES_OK; -} - -res_T -s3d_session_get_aabb(struct s3d_session* session, float lower[3], float upper[3]) -{ - if(!session || !lower || !upper) return RES_BAD_ARG; - f3_set(lower, session->lower); - f3_set(upper, session->upper); - return RES_OK; -} - -/******************************************************************************* - * Local functions - ******************************************************************************/ -void -session_destroy(struct s3d_session* session) -{ - htable_geom_iterator it, end; - ASSERT(session && !is_list_empty(&session->node)/*Not in use*/); - ASSERT(session->mask == 0); - - /* Delete the cached geometries */ - htable_geom_begin(&session->cached_geoms, &it); - htable_geom_end(&session->cached_geoms, &end); - while(!htable_geom_iterator_eq(&it, &end)) { - struct geometry** pgeom = htable_geom_iterator_data_get(&it); - struct geometry* geom = *pgeom; - session_destroy_geometry(session, geom); - htable_geom_iterator_next(&it); - } - - /* Delete the back-end scene */ - if(session->rtc_scn) rtcDeleteScene(session->rtc_scn); - - /* Release internal data structure */ - htable_geom_release(&session->cached_geoms); - darray_geom_release(&session->embree2geoms); - darray_fltui_release(&session->cdf); - darray_nprims_cdf_release(&session->nprims_cdf); - darray_uint_release(&session->detached_shapes); - - /* Remove the session from its pool */ - list_del(&session->node); - CLBK_DISCONNECT(&session->on_shape_detach_cb); - - /* Free the session memory space */ - MEM_RM(session->scn->dev->allocator, session); -} - diff --git a/src/s3d_session_c.h b/src/s3d_session_c.h @@ -1,124 +0,0 @@ -/* Copyright (C) |Meso|Star> 2015-2016 (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_SESSION_C_H -#define S3D_SESSION_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_session; - -/* - * 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> - -struct s3d_session { - struct list_node node; /* Attachment point to the scene sessions 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; - - /* Id of Shapes detached while the session 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; /* Combinatin of enum s3d_session_flag */ - int rtc_delete_geometry; /* Define if Embree geometries were deleted */ - RTCScene rtc_scn; /* Embree scene */ - - ref_T ref; - struct s3d_scene* scn; -}; - -extern LOCAL_SYM void -session_destroy - (struct s3d_session* session); - -static FINLINE struct geometry* -session_geometry_from_embree_id - (struct s3d_session* session, - const unsigned irtc) -{ - struct geometry* geom; - ASSERT(session && irtc != RTC_INVALID_GEOMETRY_ID); - ASSERT(irtc < darray_geom_size_get(&session->embree2geoms)); - geom = darray_geom_data_get(&session->embree2geoms)[irtc]; - ASSERT(geom); - return geom; -} - -#endif /* S3D_SESSION_C_H */ - diff --git a/src/test_s3d_primitive.c b/src/test_s3d_primitive.c @@ -86,7 +86,7 @@ main(int argc, char** argv) struct mem_allocator allocator; struct s3d_device* dev; struct s3d_scene* scn; - struct s3d_session* session; + struct s3d_scene_view* scnview; struct s3d_shape* walls; struct s3d_shape* plane; struct s3d_attrib attr; @@ -128,9 +128,9 @@ main(int argc, char** argv) CHECK(s3d_mesh_setup_indexed_vertices (plane, plane_ntris, plane_get_ids, plane_nverts, &attribs, 1, NULL), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_sample(session, 0, 0, 0, &prim, uv), RES_OK); - CHECK(s3d_session_ref_put(session), 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); @@ -183,12 +183,12 @@ main(int argc, char** argv) CHECK(s3d_scene_clear(scn), RES_OK); CHECK(s3d_scene_attach_shape(scn, plane), RES_OK); - CHECK(s3d_session_create(scn, S3D_GET_PRIMITIVE, &session), RES_OK); - CHECK(s3d_session_primitives_count(session, &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_session_get_primitive(session, 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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); CHECK(s3d_primitive_compute_area(NULL, NULL), RES_BAD_ARG); CHECK(s3d_primitive_compute_area(&prim, NULL), RES_BAD_ARG); diff --git a/src/test_s3d_sampler.c b/src/test_s3d_sampler.c @@ -53,7 +53,7 @@ main(int argc, char** argv) struct s3d_device* dev; struct s3d_scene* scn; struct s3d_scene* scn2; - struct s3d_session* session; + struct s3d_scene_view* scnview; struct s3d_shape* cbox; struct s3d_shape* walls; struct s3d_shape* short_block; @@ -88,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_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_sample(NULL, 0, 0, 0, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 0, 0, 0, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_sample(NULL, 0, 0, 0, &prim, NULL), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 0, 0, 0, &prim, NULL), RES_BAD_ARG); - CHECK(s3d_session_sample(NULL, 0, 0, 0, NULL, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 0, 0, 0, NULL, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(NULL, 0, 0, 0, &prim, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 0, 0, 0, &prim, uv), RES_OK); - CHECK(s3d_session_sample(session, -1, 0, 0, &prim, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 0, -1, 0, &prim, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 0, 0, -1, &prim, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 1, 0, 0, &prim, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 0, 1, 0, &prim, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 0, 0, 1, &prim, uv), RES_BAD_ARG); - CHECK(s3d_session_sample(session, 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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); attribs.usage = S3D_POSITION; attribs.type = S3D_FLOAT3; @@ -120,11 +120,11 @@ main(int argc, char** argv) CHECK(s3d_scene_attach_shape(scn, walls), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); + CHECK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview), RES_OK); - CHECK(s3d_session_sample(session, 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_session_sample(session, 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,17 +143,17 @@ main(int argc, char** argv) CHECK(attr1.type, S3D_FLOAT3); CHECK(f3_eq_eps(attr0.value, attr1.value, 1.e-6f), 1); - CHECK(s3d_session_sample(session, 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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); CHECK(s3d_shape_enable(walls, 0), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_sample(session, 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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); CHECK(s3d_shape_enable(walls, 1), RES_OK); ntris = sizeof(cbox_block_ids)/sizeof(unsigned[3]); @@ -166,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_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_sample(session, 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_session_sample(session, 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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_sample(session, 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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); CHECK(s3d_shape_enable(cbox, 0), RES_OK); - CHECK(s3d_session_create(scn2, S3D_SAMPLE|S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_sample(session, 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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); CHECK(s3d_shape_enable(cbox, 1), RES_OK); - CHECK(s3d_session_create(scn2, S3D_SAMPLE|S3D_TRACE, &session), 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_session_sample(session, 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,7 +206,7 @@ main(int argc, char** argv) CHECK(prim.scene_prim_id < 30, 1); printf("%f %f %f\n", SPLIT3(attr0.value)); } - CHECK(s3d_session_ref_put(session), 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 @@ -92,9 +92,9 @@ main(int argc, char** argv) struct s3d_scene* scn; struct s3d_scene* scn2; struct s3d_scene* scn3; - struct s3d_session* session; - struct s3d_session* session2; - struct s3d_session* session3; + 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*); @@ -155,66 +155,66 @@ main(int argc, char** argv) CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK); - CHECK(s3d_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_get_mask(session, &mask), RES_OK); + 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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); - CHECK(s3d_session_create(scn, S3D_TRACE, &session), 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_session_ref_put(session), 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_attach_shape(scn3, shapes[1]), RES_OK); - CHECK(s3d_session_create(scn2, S3D_SAMPLE|S3D_TRACE, &session2), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_create(scn3, S3D_SAMPLE, &session3), RES_OK); - CHECK(s3d_session_ref_put(session3), RES_OK); + 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_session_compute_area(NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_compute_area(session2, NULL), RES_BAD_ARG); - CHECK(s3d_session_compute_area(NULL, &area), RES_BAD_ARG); - CHECK(s3d_session_compute_area(session2, &area), 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_session_compute_volume(NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_compute_volume(session2, NULL), RES_BAD_ARG); - CHECK(s3d_session_compute_volume(NULL, &volume), RES_BAD_ARG); - CHECK(s3d_session_compute_volume(session2, &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_session_primitives_count(NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_primitives_count(session2, NULL), RES_BAD_ARG); - CHECK(s3d_session_primitives_count(NULL, &nprims), RES_BAD_ARG); - CHECK(s3d_session_primitives_count(session2, &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_session_get_aabb(NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_aabb(session2, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_aabb(NULL, lower, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_aabb(session2, lower, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_aabb(NULL, NULL, upper), RES_BAD_ARG); - CHECK(s3d_session_get_aabb(session2, NULL, upper), RES_BAD_ARG); - CHECK(s3d_session_get_aabb(NULL, lower, upper), RES_BAD_ARG); - CHECK(s3d_session_get_aabb(session2, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_ref_put(session2), RES_OK); + 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_session_create(scn3, S3D_SAMPLE|S3D_TRACE, &session3), RES_BAD_ARG); + CHECK(s3d_scene_view_create(scn3, S3D_SAMPLE|S3D_TRACE, &scnview3), RES_BAD_ARG); CHECK(s3d_scene_detach_shape(scn, shapes[0]), RES_OK); @@ -242,12 +242,12 @@ 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_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_compute_area(session, &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_session_primitives_count(session, &nprims), RES_OK); + CHECK(s3d_scene_view_primitives_count(scnview, &nprims), RES_OK); CHECK(nprims, 10); - CHECK(s3d_session_get_aabb(session, 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); @@ -258,12 +258,12 @@ main(int argc, char** argv) CHECK(s3d_scene_instantiate(scn, shapes + 1), RES_OK); CHECK(s3d_scene_attach_shape(scn2, shapes[1]), RES_OK); - CHECK(s3d_session_create(scn2, S3D_GET_PRIMITIVE, &session2), RES_OK); - CHECK(s3d_session_compute_area(session2, &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_session_primitives_count(session2, &nprims), RES_OK); + CHECK(s3d_scene_view_primitives_count(scnview2, &nprims), RES_OK); CHECK(nprims, 10); - CHECK(s3d_session_get_aabb(session2, 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); @@ -271,27 +271,27 @@ main(int argc, char** argv) CHECK(eq_epsf(upper[1], 559.f, 1.e-6f), 1); CHECK(eq_epsf(upper[2], 548.f, 1.e-6f), 1); - CHECK(s3d_session_compute_area(session, &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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); - CHECK(s3d_session_get_primitive(NULL, 11, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_primitive(session2, 11, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_primitive(NULL, 0, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_primitive(session2, 0, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_primitive(NULL, 11, prims + 0), RES_BAD_ARG); - CHECK(s3d_session_get_primitive(session2, 11, prims + 0), RES_BAD_ARG); - CHECK(s3d_session_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_session_get_primitive(session2, (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_session_ref_put(session2), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview2), RES_OK); attribs.type = S3D_FLOAT3; attribs.usage = S3D_POSITION; @@ -299,18 +299,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_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_compute_area(session, &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_session_compute_volume(session, &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_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); CHECK(s3d_shape_flip_surface(shapes[0]), RES_OK); - CHECK(s3d_session_create(scn, S3D_GET_PRIMITIVE, &session), RES_OK); - CHECK(s3d_session_compute_volume(session, &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_session_ref_put(session), 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-2016 (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_session.c b/src/test_s3d_session.c @@ -1,1048 +0,0 @@ -/* Copyright (C) |Meso|Star> 2015-2016 (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_session* session; - 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_session_create(NULL, 0, NULL), RES_BAD_ARG); - CHECK(s3d_session_create(scn, 0, NULL), RES_BAD_ARG); - CHECK(s3d_session_create(NULL, S3D_SAMPLE, NULL), RES_BAD_ARG); - CHECK(s3d_session_create(scn, S3D_SAMPLE, NULL), RES_BAD_ARG); - CHECK(s3d_session_create(NULL, 0, &session), RES_BAD_ARG); - CHECK(s3d_session_create(scn, 0, &session), RES_BAD_ARG); - CHECK(s3d_session_create(NULL, S3D_SAMPLE, &session), RES_BAD_ARG); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - - CHECK(s3d_session_get_mask(NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_mask(session, NULL), RES_BAD_ARG); - CHECK(s3d_session_get_mask(NULL, &mask), RES_BAD_ARG); - CHECK(s3d_session_get_mask(session, &mask), RES_OK); - CHECK(mask, S3D_SAMPLE); - - CHECK(s3d_session_ref_get(NULL), RES_BAD_ARG); - CHECK(s3d_session_ref_get(session), RES_OK); - CHECK(s3d_session_ref_put(NULL), RES_BAD_ARG); - CHECK(s3d_session_ref_put(session), RES_OK); - CHECK(s3d_session_ref_put(session), RES_OK); - - CHECK(s3d_session_create(scn, S3D_TRACE|S3D_GET_PRIMITIVE, &session), RES_OK); - CHECK(s3d_session_get_mask(session, &mask), RES_OK); - CHECK(mask & S3D_TRACE, S3D_TRACE); - CHECK(mask & S3D_GET_PRIMITIVE, S3D_GET_PRIMITIVE); - CHECK(s3d_session_ref_put(session), RES_OK); - - CHECK(s3d_session_create(scn, S3D_SAMPLE|S3D_GET_PRIMITIVE, &session), RES_OK); - CHECK(s3d_session_get_mask(session, &mask), RES_OK); - CHECK(mask & S3D_SAMPLE, S3D_SAMPLE); - CHECK(mask & S3D_GET_PRIMITIVE, S3D_GET_PRIMITIVE); - CHECK(s3d_session_ref_put(session), 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_session* session; - struct s3d_session* session2; - struct s3d_session* session3; - 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_session_create(scn, S3D_SAMPLE|S3D_GET_PRIMITIVE, &session), 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_session_trace_ray(session, org, dir, range, NULL, &hit), RES_BAD_OP); - - CHECK(s3d_session_create(scn, S3D_TRACE, &session2), RES_OK); - CHECK(s3d_session_trace_ray(session2, 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_session_trace_ray(session2, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_create(scn, S3D_TRACE, &session), RES_OK); - - CHECK(s3d_session_trace_ray(session2, 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_session_trace_ray(session, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_ref_put(session2), RES_OK); - CHECK(s3d_shape_enable(plane, 1), RES_OK); - - CHECK(s3d_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_create(scn2, S3D_TRACE, &session2), RES_OK); - - CHECK(s3d_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(s3d_session_trace_ray(session2, 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_session_trace_ray(session2, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_ref_put(session2), RES_OK); - - CHECK(s3d_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_create(scn2, S3D_TRACE, &session2), RES_OK); - - CHECK(s3d_session_trace_ray(session, 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_session_trace_ray(session2, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_ref_put(session2), 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_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_create(scn3, S3D_TRACE, &session3), RES_OK); - - f3(org, 0.5f, 0.25f, 0.25f); - f3(dir, 0.f, 0.f, 1.f); - CHECK(s3d_session_trace_ray(session, 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_session_trace_ray(session3, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - - f3(org, -1.5f, 0.25f, 0.25f); - CHECK(s3d_session_trace_ray(session, 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_session_trace_ray(session3, 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_session_trace_ray(session, 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_session_trace_ray(session3, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_create(scn, S3D_TRACE, &session), RES_OK); - - f3(org, -1.5f, 0.25f, 0.25f); - CHECK(s3d_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - CHECK(s3d_session_trace_ray(session3, 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_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - CHECK(s3d_session_trace_ray(session3, 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_session_trace_ray(session, 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_session_trace_ray(session3, 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_session_trace_ray(session, 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_session_ref_put(session3), RES_OK); - CHECK(s3d_session_create(scn3, S3D_TRACE, &session3), RES_OK); - - f3(org, -1.5f, 0.25f, 0.25f); - CHECK(s3d_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - CHECK(s3d_session_trace_ray(session3, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - - f3(org, -1.5f, 0.75f, 0.25f); - CHECK(s3d_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - CHECK(s3d_session_trace_ray(session3, 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_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - CHECK(s3d_session_trace_ray(session3, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - - f3(org, 2.5f, 0.75f, 0.25f); - CHECK(s3d_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - CHECK(s3d_session_trace_ray(session3, 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_session_trace_ray(session, 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_session_trace_ray(session3, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - - f3(org, 0.5f, 0.75f, 0.25f); - CHECK(s3d_session_trace_ray(session, 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_session_trace_ray(session3, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - - CHECK(s3d_session_ref_put(session), RES_OK); - CHECK(s3d_session_create(scn, S3D_TRACE, &session), RES_OK); - f3(org, 0.5f, 0.25f, 0.25f); - CHECK(s3d_session_trace_ray(session, 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_session_trace_ray(session, 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_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - f3(org, -1.5f, 0.75f, 0.25f); - CHECK(s3d_session_trace_ray(session, 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_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(S3D_HIT_NONE(&hit), 1); - f3(org, 2.5f, 0.75f, 0.25f); - CHECK(s3d_session_trace_ray(session, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_ref_put(session3), 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_session* session; - struct s3d_session* session3; - 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_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_sample(session, 0.f, 0.f, 0.f, &prims[0], st), RES_BAD_OP); - CHECK(s3d_session_ref_put(session), RES_OK); - - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_sample(session, 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_session_sample(session, 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_session_sample(session, u, v, w, &prim, st), RES_OK); - CHECK(S3D_PRIMITIVE_EQ(&prim, &prims[i]), 1); - } - - CHECK(s3d_session_ref_put(session), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - - srand(0); - FOR_EACH(i, 0, NSAMPS) { - u = rand_canonic(), v = rand_canonic(), w = rand_canonic(); - CHECK(s3d_session_sample(session, u, v, w, &prims[i], st), RES_OK); - CHECK(prims[i].inst_id, S3D_INVALID_ID); - CHECK(prims[i].geom_id, iplane); - } - - CHECK(s3d_session_ref_put(session), 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_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_create(scn3, S3D_SAMPLE, &session3), 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_session_sample(session, 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_session_sample(session3, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), 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_session_sample(session, 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_session_sample(session3, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - - FOR_EACH(i, 0, NSAMPS) { - u = rand_canonic(), v = rand_canonic(), w = rand_canonic(); - CHECK(s3d_session_sample(session, 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_session_sample(session3, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_ref_put(session3), RES_OK); - - CHECK(s3d_session_create(scn3, S3D_SAMPLE, &session3), 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_session_sample(session3, 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_session_ref_put(session3), 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_session* session; - struct s3d_session* session3; - 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_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_get_primitive(session, 0, &prim), RES_BAD_OP); - CHECK(s3d_session_primitives_count(session, &nprims), RES_OK); - CHECK(nprims, 14); - CHECK(s3d_session_ref_put(session), RES_OK); - - CHECK(s3d_session_create(scn, S3D_GET_PRIMITIVE, &session), RES_OK); - CHECK(s3d_session_primitives_count(session, &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_session_get_primitive(session, 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_session_primitives_count(session, &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_session_get_primitive(session, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_create(scn, S3D_GET_PRIMITIVE, &session), RES_OK); - CHECK(s3d_session_primitives_count(session, &nprims), RES_OK); - CHECK(nprims, 2); - memset(plane_prims, 0, sizeof(plane_prims)); - FOR_EACH(i, 0, nprims) { - CHECK(s3d_session_get_primitive(session, 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_session_ref_put(session), 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_session_create(scn, S3D_GET_PRIMITIVE, &session), RES_OK); - CHECK(s3d_session_create(scn3, S3D_GET_PRIMITIVE, &session3), RES_OK); - - CHECK(s3d_scene_clear(scn2), RES_OK); - - CHECK(s3d_session_primitives_count(session, &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_session_get_primitive(session, 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_session_primitives_count(session3, &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_session_get_primitive(session3, 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_session_ref_put(session3), RES_OK); - - CHECK(s3d_session_create(scn3, S3D_GET_PRIMITIVE, &session3), RES_OK); - CHECK(s3d_session_primitives_count(session3, &nprims), RES_OK); - CHECK(nprims, 0); - CHECK(s3d_session_ref_put(session3), RES_OK); - - CHECK(s3d_scene_attach_shape(scn2, cube), RES_OK); - CHECK(s3d_session_create(scn3, S3D_GET_PRIMITIVE, &session3), RES_OK); - - CHECK(s3d_session_primitives_count(session, &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_session_get_primitive(session, 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_session_primitives_count(session3, &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_session_get_primitive(session3, 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_session_ref_put(session), RES_OK); - CHECK(s3d_session_ref_put(session3), RES_OK); - - CHECK(s3d_session_create(scn, S3D_GET_PRIMITIVE, &session), RES_OK); - - CHECK(s3d_session_primitives_count(session, &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_session_get_primitive(session, 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_session_ref_put(session), 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_trace_ray.c b/src/test_s3d_trace_ray.c @@ -108,7 +108,7 @@ main(int argc, char** argv) struct s3d_hit hit; struct s3d_scene* scn; struct s3d_scene* scn2; - struct s3d_session* session; + struct s3d_scene_view* scnview; struct s3d_shape* inst; struct s3d_shape* walls; struct s3d_shape* walls_copy; @@ -170,43 +170,43 @@ main(int argc, char** argv) CHECK(s3d_scene_attach_shape(scn, walls), RES_OK); CHECK(s3d_shape_ref_put(walls), RES_OK); - CHECK(s3d_session_create(scn, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_trace_ray(NULL, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, org, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, org, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, NULL, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, org, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, org, dir, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, NULL, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, NULL, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, org, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, org, NULL, range, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, NULL, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, NULL, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, org, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, org, dir, range, NULL, NULL), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, NULL, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, org, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, org, NULL, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, NULL, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, org, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, org, dir, NULL, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, NULL, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, NULL, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, org, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, org, NULL, range, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, NULL, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, NULL, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(NULL, org, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_trace_ray(session, org, dir, range, NULL, &hit), RES_OK); - CHECK(s3d_session_trace_ray(session, 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_session_trace_ray(session, org, dir, range, NULL, &hit), RES_BAD_ARG); - CHECK(s3d_session_ref_put(session), 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_clear(scn), RES_OK); @@ -237,10 +237,10 @@ main(int argc, char** argv) /* Instantiate the scene */ CHECK(s3d_scene_instantiate(scn, &inst), RES_OK); - CHECK(s3d_session_create(scn, S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_primitives_count(session, &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_session_ref_put(session), 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,12 +266,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_session_create(scn2, S3D_TRACE|S3D_SAMPLE, &session), RES_OK); - CHECK(s3d_session_ref_put(session), 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_shape_enable(inst, 1), RES_OK); - CHECK(s3d_session_create(scn2, S3D_TRACE, &session), RES_OK); - CHECK(s3d_session_ref_put(session), 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); @@ -287,11 +287,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_session_create(scn2, S3D_TRACE|S3D_GET_PRIMITIVE, &session), RES_OK); - CHECK(s3d_session_primitives_count(session, &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_session_get_aabb(session, 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); @@ -301,7 +301,7 @@ main(int argc, char** argv) FOR_EACH(i, 0, nprims) { size_t j; - CHECK(s3d_session_get_primitive(session, (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); @@ -324,8 +324,8 @@ main(int argc, char** argv) pixel[0] = (float)ix/(float)IMG_WIDTH; camera_ray(&cam, pixel, org, dir); - CHECK(s3d_session_trace_ray - (session, 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) { @@ -390,7 +390,7 @@ main(int argc, char** argv) } } } - CHECK(s3d_session_ref_put(session), RES_OK); + CHECK(s3d_scene_view_ref_put(scnview), RES_OK); if(img_name) { CHECK(image_ppm_write(img_name, IMG_WIDTH, IMG_HEIGHT, 3, img), RES_OK);