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 ba8ca7b0737e68716639b1688b14e9de7a8c3e4f
parent 8e782af7a7bef563c739a67806fec29bb643d92a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue,  1 Oct 2019 14:52:40 +0200

Merge branch 'feature_rt_accel_struct_conf' into develop

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/s3d.h | 46+++++++++++++++++++++++++++++++++++++++++++++-
Msrc/s3d_device.c | 12+++++++++++-
Msrc/s3d_geometry.c | 1+
Msrc/s3d_geometry.h | 1+
Msrc/s3d_scene_view.c | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/s3d_scene_view_c.h | 2++
Asrc/test_s3d_accel_struct_conf.c | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_s3d_scene_view.c | 12+++++++++++-
9 files changed, 436 insertions(+), 26 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -130,6 +130,7 @@ if(NOT NO_TEST) register_test(${_name} ${_name}) endfunction() + new_test(test_s3d_accel_struct_conf) new_test(test_s3d_device) new_test(test_s3d_sampler) new_test(test_s3d_sample_sphere) diff --git a/src/s3d.h b/src/s3d.h @@ -144,7 +144,7 @@ static const struct s3d_vertex_data S3D_VERTEX_DATA_NULL = S3D_VERTEX_DATA_NULL_ /* Intersection point */ struct s3d_hit { struct s3d_primitive prim; /* Intersected primitive */ - float normal[3]; /* Unnormalized geometry normal */ + float normal[3]; /* Un-normalized geometry normal */ float uv[2]; /* Barycentric coordinates of the hit onto `prim' */ float distance; /* Hit distance from the ray origin */ }; @@ -169,6 +169,41 @@ enum s3d_scene_view_flag { * intersects a shape or not */ #define S3D_HIT_NONE(Hit) ((Hit)->distance >= FLT_MAX) +/* Quality of the partitioning data structure used to accelerate geometry + * queries. The lowest the structure quality is, the fastest it is built. On + * the counterpart, a weak structure quality means that the partitioning of the + * geometry is sub-optimal, leading to lower geometry query performances. */ +enum s3d_accel_struct_quality { + S3D_ACCEL_STRUCT_QUALITY_LOW, + S3D_ACCEL_STRUCT_QUALITY_MEDIUM, + S3D_ACCEL_STRUCT_QUALITY_HIGH +}; + +/* Define the properties of the partitioning data structure used to accelerate + * geometry queries */ +enum s3d_accel_struct_flag { + /* Avoid optimisations that reduce arithmetic accuracy */ + S3D_ACCEL_STRUCT_FLAG_ROBUST = BIT(0), + /* Improve the building performances of the acceleration structure for + * dynamic scenes */ + S3D_ACCEL_STRUCT_FLAG_DYNAMIC = BIT(1), + /* Reduce the memory consumption of the acceleration structure */ + S3D_ACCEL_STRUCT_FLAG_COMPACT = BIT(2) +}; + +/* Configuration of the partitioning structure used to accelerate geometry + * queries */ +struct s3d_accel_struct_conf { + enum s3d_accel_struct_quality quality; + int mask; /* combination of s3d_accel_struct_flag */ +}; +#define S3D_ACCEL_STRUCT_CONF_DEFAULT__ { \ + S3D_ACCEL_STRUCT_QUALITY_MEDIUM, \ + S3D_ACCEL_STRUCT_FLAG_ROBUST \ +} +static const struct s3d_accel_struct_conf S3D_ACCEL_STRUCT_CONF_DEFAULT = + S3D_ACCEL_STRUCT_CONF_DEFAULT__; + /* Filter function data type. One can define such function to discard * intersections along a ray with respect to user defined criteria, e.g.: * masked/transparent primitive, etc. Return 0 or the intersection is not @@ -283,6 +318,15 @@ s3d_scene_view_create struct s3d_scene_view** scnview); S3D_API res_T +s3d_scene_view_create2 + (struct s3d_scene* scn, + const int mask, /* Combination of s3d_scene_view_flag */ + /* Ignored if (mask & S3D_TRACE) == 0 + * NULL <=> use S3D_ACCEL_STRUCT_CONF_DEFAULT */ + const struct s3d_accel_struct_conf* cfg, + struct s3d_scene_view** scnview); + +S3D_API res_T s3d_scene_view_ref_get (struct s3d_scene_view* scnview); diff --git a/src/s3d_device.c b/src/s3d_device.c @@ -88,8 +88,11 @@ s3d_device_create const int verbose, struct s3d_device** out_dev) { + char embree_opts[512]; struct s3d_device* dev = NULL; struct mem_allocator* allocator; + const int verbosity = MMAX(MMIN(verbose, 3), 0); + int sz; res_T res = RES_OK; if(!out_dev) { @@ -109,7 +112,14 @@ s3d_device_create flist_name_init(allocator, &dev->names); ref_init(&dev->ref); - dev->rtc = rtcNewDevice(verbose ? "verbose=1" : NULL); + sz = snprintf(embree_opts, sizeof(embree_opts), "verbose=%d", verbosity); + if((size_t)sz >= sizeof(embree_opts)) { + log_error(dev, "Could not setup the Embree option string.\n"); + res = RES_MEM_ERR; + goto error; + } + + dev->rtc = rtcNewDevice(embree_opts); if(dev->rtc == NULL) { const enum RTCError err = rtcGetDeviceError(NULL); log_error(dev, "Could not create the embree device -- %s.\n", diff --git a/src/s3d_geometry.c b/src/s3d_geometry.c @@ -167,6 +167,7 @@ geometry_create geom->data.mesh = NULL; geom->rtc = NULL; geom->rtc_id = RTC_INVALID_GEOMETRY_ID; + geom->rtc_build_quality = RTC_BUILD_QUALITY_MEDIUM; exit: *out_geom = geom; diff --git a/src/s3d_geometry.h b/src/s3d_geometry.h @@ -58,6 +58,7 @@ enum embree_attrib { struct geometry { unsigned name; /* Client side identifier */ RTCGeometry rtc; /* Embree geometry */ + enum RTCBuildQuality rtc_build_quality; /* BVH build quality */ unsigned rtc_id; /* Embree geometry identifier */ unsigned scene_prim_id_offset; /* Offset from local to scene prim_id */ diff --git a/src/s3d_scene_view.c b/src/s3d_scene_view.c @@ -232,21 +232,72 @@ hit_setup if(flip_surface) f3_minus(hit->normal, hit->normal); } +static INLINE enum RTCBuildQuality +accel_struct_quality_to_rtc_build_quality + (enum s3d_accel_struct_quality quality) +{ + enum RTCBuildQuality rtc_quality = RTC_BUILD_QUALITY_MEDIUM; + switch(quality) { + case S3D_ACCEL_STRUCT_QUALITY_LOW: + rtc_quality = RTC_BUILD_QUALITY_LOW; + break; + case S3D_ACCEL_STRUCT_QUALITY_MEDIUM: + rtc_quality = RTC_BUILD_QUALITY_MEDIUM; + break; + case S3D_ACCEL_STRUCT_QUALITY_HIGH: + rtc_quality = RTC_BUILD_QUALITY_HIGH; + break; + default: FATAL("Unreachable code\n"); break; + } + return rtc_quality; +} + +static INLINE int +accel_struct_mask_to_rtc_scene_flags(const int mask) +{ + int rtc_scene_flags = 0; + if(mask & S3D_ACCEL_STRUCT_FLAG_ROBUST) + rtc_scene_flags |= RTC_SCENE_FLAG_ROBUST; + if(mask & S3D_ACCEL_STRUCT_FLAG_DYNAMIC) + rtc_scene_flags |= RTC_SCENE_FLAG_DYNAMIC; + if(mask & S3D_ACCEL_STRUCT_FLAG_COMPACT) + rtc_scene_flags |= RTC_SCENE_FLAG_COMPACT; + return rtc_scene_flags; +} + static res_T embree_geometry_register (struct s3d_scene_view* scnview, - struct geometry* geom) + struct geometry* geom, + const struct s3d_accel_struct_conf* accel_struct_conf) { - ASSERT(scnview && geom); + enum RTCBuildQuality rtc_build_quality = RTC_BUILD_QUALITY_MEDIUM; + ASSERT(scnview && geom && accel_struct_conf); + + rtc_build_quality = accel_struct_quality_to_rtc_build_quality + (accel_struct_conf->quality); /* Create the Embree geometry if it is not valid */ if(geom->rtc != NULL) { - if(geom->type == GEOM_INSTANCE) { - /* If the geometry is an instance one have to update it if the - * instantiated geometry was updated. Currently, we have no simple way to - * know if the geometry was upd or not so we simply force the update. */ - rtcCommitGeometry(geom->rtc); - scnview->rtc_scn_update = 1; + switch(geom->type) { + case GEOM_MESH: + if(geom->rtc_build_quality != rtc_build_quality) { + /* Update the build quality of the geometry */ + rtcSetGeometryBuildQuality(geom->rtc, rtc_build_quality); + rtcCommitGeometry(geom->rtc); + geom->rtc_build_quality = rtc_build_quality; + scnview->rtc_scn_update = 1; + } + break; + case GEOM_INSTANCE: + /* If the geometry is an instance one have to update it if the + * instantiated geometry was updated. Currently, we have no simple way to + * know if the geometry was upd or not so we simply force the update. */ + rtcCommitGeometry(geom->rtc); + scnview->rtc_scn_update = 1; + break; + case GEOM_SPHERE: /* Do nothing */ break; + default: FATAL("Unreachable code\n"); break; } } else { switch(geom->type) { @@ -273,6 +324,12 @@ embree_geometry_register if(geom->rtc == NULL) return RES_UNKNOWN_ERR; + if(geom->type == GEOM_MESH) { + /* Set the build quality of the geometry */ + rtcSetGeometryBuildQuality(geom->rtc, rtc_build_quality); + geom->rtc_build_quality = rtc_build_quality; + } + /* Set the Star-3D representation of the geometry to the Embree geometry */ rtcSetGeometryUserData(geom->rtc, geom); @@ -385,13 +442,22 @@ embree_geometry_setup_transform } static INLINE res_T -scene_view_setup_embree(struct s3d_scene_view* scnview) +scene_view_setup_embree + (struct s3d_scene_view* scnview, + const struct s3d_accel_struct_conf* accel_struct_conf) { struct htable_geom_iterator it, end; int rtc_outdated = 0; + int rtc_scn_flags = 0; + enum RTCBuildQuality rtc_scn_build_quality = 0; res_T res = RES_OK; ASSERT(scnview); + rtc_scn_flags = accel_struct_mask_to_rtc_scene_flags + (accel_struct_conf->mask); + rtc_scn_build_quality = accel_struct_quality_to_rtc_build_quality + (accel_struct_conf->quality); + /* The rtc_scn could be already allocated since the scene views are cached */ if(!scnview->rtc_scn) { scnview->rtc_scn = rtcNewScene(scnview->scn->dev->rtc); @@ -399,8 +465,22 @@ scene_view_setup_embree(struct s3d_scene_view* scnview) res = rtc_error_to_res_T(rtcGetDeviceError(scnview->scn->dev->rtc)); goto error; } - rtcSetSceneFlags - (scnview->rtc_scn, RTC_SCENE_FLAG_ROBUST | RTC_SCENE_FLAG_DYNAMIC); + rtcSetSceneFlags(scnview->rtc_scn, rtc_scn_flags); + scnview->rtc_scn_flags = rtc_scn_flags; + rtc_outdated = 1; + } + + /* Check if the scene flags were updated */ + if(scnview->rtc_scn_flags != rtc_scn_flags) { + rtcSetSceneFlags(scnview->rtc_scn, rtc_scn_flags); + scnview->rtc_scn_flags = rtc_scn_flags; + rtc_outdated = 1; + } + + /* Check if the build quality was updated */ + if(scnview->rtc_scn_build_quality != rtc_scn_build_quality) { + rtcSetSceneBuildQuality(scnview->rtc_scn, rtc_scn_build_quality); + scnview->rtc_scn_build_quality = rtc_scn_build_quality; rtc_outdated = 1; } @@ -419,7 +499,7 @@ scene_view_setup_embree(struct s3d_scene_view* scnview) rtc_outdated = 1; /* Register the embree geometry */ - res = embree_geometry_register(scnview, geom); + res = embree_geometry_register(scnview, geom, accel_struct_conf); if(res != RES_OK) goto error; /* Flush the embree geometry states */ @@ -936,13 +1016,13 @@ scene_view_compute_volume static res_T scene_view_sync (struct s3d_scene_view* scnview, - const int mask) + const int mask, + const struct s3d_accel_struct_conf* accel_struct_conf) { struct htable_shape_iterator it, end; res_T res = RES_OK; - ASSERT(scnview); - ASSERT((mask & (S3D_TRACE|S3D_SAMPLE|S3D_GET_PRIMITIVE)) != 0); + ASSERT(scnview && accel_struct_conf); /* Commit the scene shape to the scnview */ htable_shape_begin(&scnview->scn->shapes, &it); @@ -971,7 +1051,7 @@ scene_view_sync /* Setup the scene for the S3D_TRACE scnview */ if((mask & S3D_TRACE) != 0) { - res = scene_view_setup_embree(scnview); + res = scene_view_setup_embree(scnview, accel_struct_conf); if(res != RES_OK) goto error; } /* Setup the scene for the S3D_SAMPLE scnview */ @@ -1019,6 +1099,7 @@ scene_view_create(struct s3d_scene* scn, struct s3d_scene_view** out_scnview) f3_splat(scnview->lower, FLT_MAX); f3_splat(scnview->upper,-FLT_MAX); ref_init(&scnview->ref); + scnview->rtc_scn_build_quality = RTC_BUILD_QUALITY_MEDIUM; CLBK_INIT(&scnview->on_shape_detach_cb); CLBK_SETUP(&scnview->on_shape_detach_cb, on_shape_detach, scnview); @@ -1104,7 +1185,19 @@ s3d_scene_view_create const int mask, struct s3d_scene_view** out_scnview) { + return s3d_scene_view_create2 + (scn, mask, &S3D_ACCEL_STRUCT_CONF_DEFAULT, out_scnview); +} + +res_T +s3d_scene_view_create2 + (struct s3d_scene* scn, + const int mask, + const struct s3d_accel_struct_conf* cfg, + struct s3d_scene_view** out_scnview) +{ struct s3d_scene_view* scnview = NULL; + const struct s3d_accel_struct_conf* accel_struct_conf = cfg; res_T res = RES_OK; if(!scn || !out_scnview) { @@ -1112,18 +1205,14 @@ s3d_scene_view_create 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; + if(!accel_struct_conf && (mask & S3D_TRACE)) { + accel_struct_conf = &S3D_ACCEL_STRUCT_CONF_DEFAULT; } res = scene_view_create(scn, &scnview); if(res != RES_OK) goto error; - res = scene_view_sync(scnview, mask); + res = scene_view_sync(scnview, mask, accel_struct_conf); if(res != RES_OK) goto error; exit: diff --git a/src/s3d_scene_view_c.h b/src/s3d_scene_view_c.h @@ -91,6 +91,8 @@ struct s3d_scene_view { int mask; /* Combination of enum s3d_scene_view_flag */ int rtc_scn_update; /* Define if Embree geometries were deleted/added */ int rtc_commit; /* Define whether or not the Embree scene was committed */ + int rtc_scn_flags; /* Flags used to configure the Embree scene */ + enum RTCBuildQuality rtc_scn_build_quality; /* Build quality of the BVH */ RTCScene rtc_scn; /* Embree scene */ ref_T ref; diff --git a/src/test_s3d_accel_struct_conf.c b/src/test_s3d_accel_struct_conf.c @@ -0,0 +1,252 @@ +/* Copyright (C) 2015-2019 |Meso|Star> (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/clock_time.h> +#include <rsys/math.h> +#include <string.h> + +/******************************************************************************* + * Mesh functions and data structure + ******************************************************************************/ +struct mesh { + double* pos; + size_t* ids; + size_t nverts; + size_t ntris; + struct mem_allocator* allocator; +}; + +static void +mesh_init_sphere + (struct mesh* sphere, + struct mem_allocator* allocator, + const size_t nthetas) +{ + const size_t nphis = (size_t)(((double)nthetas + 0.5) * 0.5); + const double step_theta = 2*PI / (double)nthetas; + const double step_phi = PI / (double)nphis; + size_t itheta, iphi; + size_t i; + + CHK(sphere && allocator && nthetas); + memset(sphere, 0, sizeof(*sphere)); + + sphere->nverts = nthetas * (nphis-1)/*#contour verts*/ + 2 /*polar verts*/; + sphere->ntris = 2*nthetas * (nphis-2)/*#contour tris*/ + 2*nthetas/*#polar tris*/; + sphere->allocator = allocator; + + CHK(sphere->pos = MEM_CALLOC(allocator, sphere->nverts, sizeof(double[3]))); + CHK(sphere->ids = MEM_CALLOC(allocator, sphere->ntris, sizeof(size_t[3]))); + + /* Build the contour vertices */ + i = 0; + FOR_EACH(itheta, 0, nthetas) { + const double theta = -PI + (double)itheta * step_theta; + const double cos_theta = cos(theta); + const double sin_theta = sin(theta); + FOR_EACH(iphi, 0, nphis-1) { + const double phi = -PI*0.5 + (double)(iphi + 1) * step_phi; + const double cos_phi = cos(phi); + const double sin_phi = sin(phi); + sphere->pos[i++] = cos_phi * cos_theta; + sphere->pos[i++] = cos_phi * sin_theta; + sphere->pos[i++] = sin_phi; + } + } + /* polar vertices */ + sphere->pos[i++] = 0.0; sphere->pos[i++] = 0.0; sphere->pos[i++] =-1.0; + sphere->pos[i++] = 0.0; sphere->pos[i++] = 0.0; sphere->pos[i++] = 1.0; + CHK(i == sphere->nverts*3); + + /* Define the indices of the contour primitives */ + i = 0; + FOR_EACH(itheta, 0, nthetas) { + const size_t itheta0 = itheta * (nphis - 1); + const size_t itheta1 = ((itheta + 1) % nthetas) * (nphis - 1); + FOR_EACH(iphi, 0, nphis-2) { + const size_t iphi0 = iphi + 0; + const size_t iphi1 = iphi + 1; + sphere->ids[i++] = itheta0 + iphi0; /* First triangle */ + sphere->ids[i++] = itheta0 + iphi1; + sphere->ids[i++] = itheta1 + iphi0; + sphere->ids[i++] = itheta1 + iphi0; /* Second triangle */ + sphere->ids[i++] = itheta0 + iphi1; + sphere->ids[i++] = itheta1 + iphi1; + } + } + /* Define the indices of the polar primitives */ + FOR_EACH(itheta, 0, nthetas) { + const size_t itheta0 = itheta * (nphis - 1); + const size_t itheta1 = ((itheta + 1) % nthetas) * (nphis - 1); + sphere->ids[i++] = nthetas * (nphis - 1); + sphere->ids[i++] = itheta0; + sphere->ids[i++] = itheta1; + sphere->ids[i++] = nthetas * (nphis - 1) + 1; + sphere->ids[i++] = itheta1 + (nphis - 2); + sphere->ids[i++] = itheta0 + (nphis - 2); + } + CHK(i == sphere->ntris*3); +} + +static void +mesh_release(struct mesh* mesh) +{ + CHK(mesh); + MEM_RM(mesh->allocator, mesh->pos); + MEM_RM(mesh->allocator, mesh->ids); +} + +static INLINE void +mesh_dump(const struct mesh* mesh, FILE* stream) +{ + size_t i; + CHK(mesh && stream); + FOR_EACH(i, 0, mesh->nverts) { + fprintf(stream, "v %g %g %g\n", + mesh->pos[i*3+0], + mesh->pos[i*3+1], + mesh->pos[i*3+2]); + } + FOR_EACH(i, 0, mesh->ntris) { + fprintf(stream, "f %lu %lu %lu\n", + (unsigned long)mesh->ids[i*3+0]+1, + (unsigned long)mesh->ids[i*3+1]+1, + (unsigned long)mesh->ids[i*3+2]+1); + } +} + +static void +mesh_get_pos(const unsigned ivert, float pos[3], void* ctx) +{ + const struct mesh* mesh = ctx; + CHK(pos && ctx && ivert < mesh->nverts); + pos[0] = (float)mesh->pos[ivert*3+0]; + pos[1] = (float)mesh->pos[ivert*3+1]; + pos[2] = (float)mesh->pos[ivert*3+2]; +} + +static void +mesh_get_tri(const unsigned itri, unsigned ids[3], void* ctx) +{ + const struct mesh* mesh = ctx; + CHK(ids && ctx && itri < mesh->ntris); + ids[0] = (unsigned)mesh->ids[itri*3+0]; + ids[1] = (unsigned)mesh->ids[itri*3+1]; + ids[2] = (unsigned)mesh->ids[itri*3+2]; +} + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +time_scene_view_creation + (struct s3d_scene* scn, + const struct s3d_accel_struct_conf* cfg, + const char* string) +{ + char dump[128]; + struct time t0, t1; + struct s3d_scene_view* view; + CHK(scn); + + time_current(&t0); + CHK(s3d_scene_view_create2(scn, S3D_TRACE, cfg, &view) == RES_OK); + time_sub(&t0, time_current(&t1), &t0); + time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump)); + printf("%s: %s\n", string, dump); + CHK(s3d_scene_view_ref_put(view) == RES_OK); +} + +/******************************************************************************* + * Main test function + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct mesh sphere; + struct s3d_device* dev; + struct s3d_shape* shape; + struct s3d_scene* scn; + struct s3d_scene_view* view; + struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL; + struct s3d_accel_struct_conf cfg = S3D_ACCEL_STRUCT_CONF_DEFAULT; + (void)argc, (void)argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + mesh_init_sphere(&sphere, &allocator, 256); + /*mesh_dump(&sphere, stdout);*/ + + CHK(s3d_device_create(NULL, &allocator, 1, &dev) == RES_OK); + CHK(s3d_scene_create(dev, &scn) == RES_OK); + CHK(s3d_shape_create_mesh(dev, &shape) == RES_OK); + CHK(s3d_scene_attach_shape(scn, shape) == RES_OK); + + vdata.usage = S3D_POSITION; + vdata.type = S3D_FLOAT3; + vdata.get = mesh_get_pos; + CHK(s3d_mesh_setup_indexed_vertices(shape, (unsigned)sphere.ntris, mesh_get_tri, + (unsigned)sphere.nverts, &vdata, 1, &sphere) == RES_OK); + + CHK(s3d_scene_view_create2(NULL, S3D_TRACE, NULL, &view) == RES_BAD_ARG); + CHK(s3d_scene_view_create2(scn, S3D_TRACE, NULL, NULL) == RES_BAD_ARG); + + time_scene_view_creation(scn, NULL, "All default"); + + cfg.quality = S3D_ACCEL_STRUCT_QUALITY_LOW; + cfg.mask = S3D_ACCEL_STRUCT_FLAG_ROBUST | S3D_ACCEL_STRUCT_FLAG_DYNAMIC; + time_scene_view_creation(scn, &cfg, "Low quality, robust & dynamic"); + + cfg.quality = S3D_ACCEL_STRUCT_QUALITY_MEDIUM; + cfg.mask = S3D_ACCEL_STRUCT_FLAG_COMPACT; + time_scene_view_creation(scn, &cfg, "Medium quality, compact"); + + cfg.quality = S3D_ACCEL_STRUCT_QUALITY_HIGH; + cfg.mask = S3D_ACCEL_STRUCT_FLAG_ROBUST | S3D_ACCEL_STRUCT_FLAG_COMPACT; + time_scene_view_creation(scn, &cfg, "High quality, compact & robust"); + + CHK(s3d_shape_ref_put(shape) == RES_OK); + CHK(s3d_scene_ref_put(scn) == RES_OK); + CHK(s3d_device_ref_put(dev) == RES_OK); + + mesh_release(&sphere); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} + diff --git a/src/test_s3d_scene_view.c b/src/test_s3d_scene_view.c @@ -131,6 +131,8 @@ test_miscellaneous { struct s3d_scene* scn; struct s3d_scene_view* scnview; + float V; + float A; int mask; CHK(s3d_scene_create(dev, &scn) == RES_OK); @@ -142,7 +144,6 @@ test_miscellaneous CHK(s3d_scene_view_create(NULL, S3D_SAMPLE, NULL) == RES_BAD_ARG); CHK(s3d_scene_view_create(scn, S3D_SAMPLE, NULL) == RES_BAD_ARG); CHK(s3d_scene_view_create(NULL, 0, &scnview) == RES_BAD_ARG); - CHK(s3d_scene_view_create(scn, 0, &scnview) == RES_BAD_ARG); CHK(s3d_scene_view_create(NULL, S3D_SAMPLE, &scnview) == RES_BAD_ARG); CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &scnview) == RES_OK); @@ -170,6 +171,15 @@ test_miscellaneous CHK((mask & S3D_GET_PRIMITIVE) == S3D_GET_PRIMITIVE); CHK(s3d_scene_view_ref_put(scnview) == RES_OK); + CHK(s3d_scene_detach_shape(scn, plane) == RES_OK); + CHK(s3d_scene_view_create(scn, 0, &scnview) == RES_OK); + CHK(s3d_scene_view_get_mask(scnview, &mask) == RES_OK); + CHK(mask == 0); + CHK(s3d_scene_view_compute_volume(scnview, &V) == RES_OK); + CHK(s3d_scene_view_compute_volume(scnview, &A) == RES_OK); + CHK(s3d_scene_view_ref_put(scnview) == RES_OK); + + printf("Cube volume = %g; Cube area = %g\n", V, A); CHK(s3d_scene_ref_put(scn) == RES_OK); }