commit b6d9b307a4c735229076f321d9c8fdd9ad484dbe
parent 6a611f84688294e853355714e5a29972877cffc3
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 10 Sep 2015 11:33:31 +0200
Remove the shape_<compute_area|compute_volume|primitives_count> funcs
These functionalities are now supported by the scene rather than the
shape.
Diffstat:
10 files changed, 311 insertions(+), 794 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -67,7 +67,6 @@ set(S3D_FILES_SRC
s3d_instance.c
s3d_mesh.c
s3d_primitive.c
- s3d_sampler.c
s3d_scene.c
s3d_shape.c)
set(S3D_FILES_INC_API s3d.h)
diff --git a/src/s3d.h b/src/s3d.h
@@ -304,6 +304,24 @@ s3d_scene_sample
struct s3d_primitive* primitive, /* sampled primitive */
float uv[2]);
+/* Retrieve the number of scene primitives */
+S3D_API res_T
+s3d_scene_primitives_count
+ (struct s3d_scene* scn,
+ size_t* primitives_count);
+
+S3D_API res_T
+s3d_scene_compute_area
+ (struct s3d_scene* scn,
+ 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_scene_compute_volume
+ (struct s3d_scene* scn,
+ float* volume);
+
/*******************************************************************************
* Shape API - A shape defines a geometry that can be attached to *one* scene.
******************************************************************************/
@@ -352,25 +370,6 @@ S3D_API res_T
s3d_shape_flip_surface
(struct s3d_shape* shape);
-/* Get the number of primitives */
-S3D_API res_T
-s3d_shape_primitives_count
- (struct s3d_shape* shape,
- size_t* primitives_count);
-
-/* Return 0 if the shape is disabled */
-S3D_API res_T
-s3d_shape_compute_area
- (struct s3d_shape* shape,
- float* area);
-
-/* This function assumes that the shape defines a closed volume and that the
- * normals point into the volume. Return 0 if the shape is disabled */
-S3D_API res_T
-s3d_shape_compute_volume
- (struct s3d_shape* shape,
- float* volume);
-
/*******************************************************************************
* Primitive API - Define a geometric primitive of a shape
******************************************************************************/
diff --git a/src/s3d_instance.c b/src/s3d_instance.c
@@ -103,44 +103,6 @@ instance_ref_put(struct instance* inst)
ref_put(&inst->ref, instance_release);
}
-size_t
-instance_get_ntris(struct instance* inst)
-{
- struct list_node* node;
- size_t ntris = 0;
- LIST_FOR_EACH(node, &inst->scene->shapes) {
- struct s3d_shape* shape = CONTAINER_OF
- (node, struct s3d_shape, scene_attachment);
- switch(shape->type) {
- case GEOM_INSTANCE:
- ntris += instance_get_ntris(shape->data.instance);
- break;
- case GEOM_MESH:
- ntris += mesh_get_ntris(shape->data.mesh);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- }
- return ntris;
-}
-
-float
-instance_compute_area(struct instance* inst)
-{
- struct list_node* node;
- float area = 0.f;
- ASSERT(inst);
-
- /* TODO take into account the scale factor of the instance */
- LIST_FOR_EACH(node, &inst->scene->shapes) {
- struct s3d_shape* shape = CONTAINER_OF
- (node, struct s3d_shape, scene_attachment);
- ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */
- area += mesh_compute_area(shape->data.mesh);
- }
- return area;
-}
-
float
instance_compute_volume(struct instance* inst, const char flip_surface)
{
diff --git a/src/s3d_instance.h b/src/s3d_instance.h
@@ -57,18 +57,10 @@ extern LOCAL_SYM void
instance_ref_put
(struct instance* inst);
-extern LOCAL_SYM size_t
-instance_get_ntris
- (struct instance* inst);
-
-extern LOCAL_SYM float
-instance_compute_area
- (struct instance* inst);
-
extern LOCAL_SYM float
instance_compute_volume
(struct instance* inst,
- const char flip_surface); /* Flip the instance surfaces or not */
+ const char flip_surface);
#endif /* S3D_INSTANCE_H */
diff --git a/src/s3d_sampler.c b/src/s3d_sampler.c
@@ -1,582 +0,0 @@
-/* Copyright (C) |Meso|Star> 2015 (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_device_c.h"
-#include "s3d_scene_c.h"
-#include "s3d_shape_c.h"
-
-#include <rsys/dynamic_array_float.h>
-#include <rsys/dynamic_array_size_t.h>
-#include <rsys/float33.h>
-#include <rsys/logger.h>
-
-#include <algorithm>
-
-/* The sampler is used to compute uniform random variates of a shape */
-#if 0
-struct s3d_sampler {
- struct s3d_shape* shape; /* The shape to sample */
-
- /* Register the shape mesh to sample. For a SHAPE_INSTANCE, it lists the
- * instantiated shape mesh while for SHAPE_MESH it stores only one mesh, i.e.
- * the mesh of the shape. Actually, this cache is synchronised with the shape
- * data on s3d_sampler_begin_sampling invocation by creating meshes that get
- * a reference onto the shape mesh data. This makes the sampling robust to
- * shape updates until the s3d_sampler_end_sampling invocation */
- struct darray_mesh cached_meshes;
-
- /* Register the shape instance data. If the shape is not a SHAPE_INSTANCE,
- * the cached_instance is NULL. The cached instance data are synchronised on
- * s3d_sampler_begin invocation by copying the shape instance data to the
- * cache instance. This makes the sampling robust to the updates of shape
- * instance data until the s3d_sampler_end_sampling invocation */
- struct instance* cached_instance;
-
- /* List of cached_mesh CDF ordered with respect to the cached_mesh list, i.e.
- * the first value is the CDF of the first cached mesh, the second value the
- * CDF of the second cached mesh, etc.*/
- struct darray_float meshes_cdf;
- /* Map a cached mesh id to its 1st triangle CDF */
- struct darray_size_t mesh2triangle;
- /* List of triangle CDF ordered with respect to the cached_mesh list, i.e.
- * the first N values stores the CDF of the N triangles of the first cached
- * mesh, the next M values are the CDF of the M triangles of the second
- * cached mesh, etc. Use the mesh2triangle data structure to retrieve the
- * list of triangle CDF of a specific cached mesh */
- struct darray_float triangles_cdf;
-
- char is_sync; /* Define if the sampler is in a sampling process */
- ref_T ref;
-};
-
-/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-/* The `cache' get a reference onto the `mesh' data. Return 1 if the `cache'
- * *geometry* data are updated and 0 otherwise */
-static char
-cache_mesh(struct mesh* cache, struct mesh* mesh)
-{
- char upd_geom = 0;
- size_t i;
- ASSERT(cache && mesh);
-
- /* Get a reference onto the shape mesh indices */
- if(cache->indices != mesh->indices) {
- if(cache->indices) { /* Release previous cached indices */
- index_buffer_ref_put(cache->indices);
- cache->indices = NULL;
- }
- index_buffer_ref_get(mesh->indices);
- cache->indices = mesh->indices;
- upd_geom = 1;
- }
-
- /* Get a reference onto the shape mesh attribs */
- FOR_EACH(i, 0, S3D_ATTRIBS_COUNT__) {
- if(cache->attribs[i] == mesh->attribs[i])
- continue;
-
- if(i == S3D_POSITION)
- upd_geom = 1;
-
- if(cache->attribs[i]) { /* Release previous cached attribs */
- vertex_buffer_ref_put(cache->attribs[i]);
- cache->attribs[i] = NULL;
- }
-
- if(!mesh->attribs[i])
- continue;
-
- vertex_buffer_ref_get(mesh->attribs[i]);
- cache->attribs[i] = mesh->attribs[i];
- cache->attribs_type[i] = mesh->attribs_type[i];
- }
- cache->flip_surface = mesh->flip_surface;
- return upd_geom;
-}
-
-/* Release all cached meshes */
-static void
-sampler_clear_cached_meshes(struct s3d_sampler* sampler)
-{
- size_t i = 0;
- ASSERT(sampler);
- FOR_EACH(i, 0, darray_mesh_size_get(&sampler->cached_meshes))
- mesh_ref_put(darray_mesh_data_get(&sampler->cached_meshes)[i]);
- darray_mesh_clear(&sampler->cached_meshes);
-}
-
-/* Clean-up the CDF */
-static void
-sampler_clear_cdf(struct s3d_sampler* sampler)
-{
- ASSERT(sampler);
- darray_float_clear(&sampler->meshes_cdf);
- darray_float_clear(&sampler->triangles_cdf);
- darray_size_t_clear(&sampler->mesh2triangle);
-}
-
-/* Clean-up the synchronised data */
-static void
-sampler_clear(struct s3d_sampler* sampler)
-{
- ASSERT(sampler);
- sampler_clear_cached_meshes(sampler);
- sampler_clear_cdf(sampler);
- sampler->is_sync = 0;
-}
-
-/* Compute the CDF of the cached meshes */
-static res_T
-sampler_compute_cdf(struct s3d_sampler* sampler)
-{
- struct mesh** meshes = NULL;
- size_t* mesh2triangle = NULL;
- float* meshes_cdf = NULL;
- size_t imesh, nmeshes;
- size_t itri;
- float area = 0.f, rcp_area = 0.f;
- res_T res = RES_OK;
- ASSERT(sampler);
-
- /* Fetched cached meshes */
- meshes = darray_mesh_data_get(&sampler->cached_meshes);
- nmeshes = darray_mesh_size_get(&sampler->cached_meshes);
- ASSERT(nmeshes);
-
- /* Reserve meshes CDF memory space */
- sampler_clear_cdf(sampler);
- res = darray_float_resize(&sampler->meshes_cdf, nmeshes);
- if(res != RES_OK) goto error;
- res = darray_size_t_resize(&sampler->mesh2triangle, nmeshes);
- if(res != RES_OK) goto error;
-
- /* Fetch meshes CDF data */
- meshes_cdf = darray_float_data_get(&sampler->meshes_cdf);
- mesh2triangle = darray_size_t_data_get(&sampler->mesh2triangle);
-
- FOR_EACH(imesh, 0, nmeshes) {
- const size_t ntris = mesh_get_ntris(meshes[imesh]);
- const uint32_t* ids = mesh_get_ids(meshes[imesh]);
- const float* verts = mesh_get_pos(meshes[imesh]);
-
- mesh2triangle[imesh] = darray_float_size_get(&sampler->triangles_cdf);
- res = darray_float_reserve
- (&sampler->triangles_cdf, mesh2triangle[imesh] + ntris);
- if(res != RES_OK) goto error;
-
- FOR_EACH(itri, 0, ntris ) {
- int i;
- const float* positions[3];
- float edges[2][3], normal[3];
- float triangle_area;
-
- FOR_EACH(i, 0, 3) { /* Fetch vertex positions */
- const uint32_t id = ids[itri*3 + i];
- ASSERT(id < mesh_get_nverts(meshes[imesh]));
- positions[i] = verts + id * 3/*#coords*/;
- }
- /* Compute triangle area. Note that actually, we compute the double of
- * the triangle area since it saves computation times whithout affecting
- * the sampling result */
- f3_sub(edges[0], positions[1], positions[0]);
- f3_sub(edges[1], positions[2], positions[0]);
- f3_cross(normal, edges[0], edges[1]);
- triangle_area = f3_len(normal);
- /* TODO take into account the scale instance transformation in the
- * computation of the triangle area */
-
- /* Store the CDF value of the triangle `itri' */
- area += triangle_area;
- darray_float_push_back(&sampler->triangles_cdf, &area);
- }
- /* Store the CDF value of the mesh `imesh' */
- meshes_cdf[imesh] = area;
- }
-
- if(eq_eps(area, 0, 1.e-6f)) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Normalize the meshes/triangles CDF */
- rcp_area = 1.f / area;
- FOR_EACH(imesh, 0, nmeshes) {
- meshes_cdf[imesh] *= rcp_area;
- }
- FOR_EACH(itri, 0, darray_float_size_get(&sampler->triangles_cdf)) {
- darray_float_data_get(&sampler->triangles_cdf)[itri] *= rcp_area;
- }
-
-exit:
- return res;
-error:
- sampler_clear_cdf(sampler);
- goto exit;
-}
-
-/* Cache the sampler shape mesh */
-static res_T
-sampler_cache_mesh(struct s3d_sampler* sampler, char* upd_geom)
-{
- struct mesh* mesh;
- char is_enabled;
- res_T res = RES_OK;
- ASSERT(sampler && sampler->shape->type == SHAPE_MESH && upd_geom);
-
- if(!sampler->shape->data.mesh->indices
- || !sampler->shape->data.mesh->attribs[S3D_POSITION]) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(!(S3D(shape_is_enabled(sampler->shape, &is_enabled)), is_enabled)) {
- if(sampler->shape->dev->verbose) {
- logger_print(sampler->shape->dev->logger, LOG_ERROR,
- "Couldn't sample anything. The mesh to sample is disabled\n");
- }
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(darray_mesh_size_get(&sampler->cached_meshes)) {
- /* Fetch the cached entry */
- mesh = darray_mesh_data_get(&sampler->cached_meshes)[0];
- } else {
- /* 1st sync process => create the cached entry */
- res = mesh_create(sampler->shape->dev, &mesh);
- if(res != RES_OK) goto error;
- res = darray_mesh_push_back(&sampler->cached_meshes, &mesh);
- if(res != RES_OK) goto error;
- }
- /* Cache the instance mesh data */
- *upd_geom = cache_mesh(mesh, sampler->shape->data.mesh);
-
-exit:
- return res;
-error:
- sampler_clear_cached_meshes(sampler);
- goto exit;
-}
-
-/* Cache the sampler instance */
-static res_T
-sampler_cache_instance(struct s3d_sampler* sampler, char* upd_geom)
-{
- struct list_node* node;
- struct mesh* mesh;
- size_t ishape = 0;
- size_t nshapes;
- res_T res = RES_OK;
- ASSERT(sampler && sampler->shape->type == SHAPE_INSTANCE && upd_geom);
-
- /* Check that the instance is ready to be sampled, i.e. it is enabled */
- if(!sampler->shape->data.instance->geom.is_enabled) {
- if(sampler->shape->dev->verbose) {
- logger_print(sampler->shape->dev->logger, LOG_ERROR,
- "Couldn't sample anything. The instance to sample is disabled\n");
- }
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Setup the Id of the cached instance */
- sampler->cached_instance->id = sampler->shape->name.index;
-
- f33_set /* Cache the instance rotation */
- (sampler->cached_instance->transform,
- sampler->shape->data.instance->transform);
- f3_set /* Cache the instance translation */
- (sampler->cached_instance->transform + 9,
- sampler->shape->data.instance->transform + 9);
-
- LIST_FOR_EACH(node, &sampler->shape->data.instance->scene->shapes) {
- char is_enabled;
- struct s3d_shape* shape = CONTAINER_OF
- (node, struct s3d_shape, scene_attachment);
- ASSERT(shape->type == SHAPE_MESH);
-
- /* Discard disabled shapes */
- if(!(S3D(shape_is_enabled(shape, &is_enabled)), is_enabled))
- continue;
-
- /* Discard shapes with no geometry */
- if(!shape->data.mesh->indices
- || !shape->data.mesh->attribs[S3D_POSITION])
- continue;
-
- if(ishape < darray_mesh_size_get(&sampler->cached_meshes)) {
- /* Fetch the previous cache entry */
- mesh = darray_mesh_data_get(&sampler->cached_meshes)[ishape];
- } else {
- /* Create a new cache entry */
- res = mesh_create(sampler->shape->dev, &mesh);
- if(res != RES_OK) goto error;
- res = darray_mesh_push_back(&sampler->cached_meshes, &mesh);
- if(res != RES_OK) goto error;
- }
- mesh->id = shape->name.index; /* Setup the Id of the cached mesh */
- /* Cache the instance mesh data */
- *upd_geom = cache_mesh(mesh, shape->data.mesh) || *upd_geom;
- ++ishape;
- }
- nshapes = ishape;
-
- if(!nshapes) {
- if(sampler->shape->dev->verbose) {
- logger_print(sampler->shape->dev->logger, LOG_ERROR,
- "Couldn't sample anything. "
- "All instantiated shapes to sample are disabled\n");
- }
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Flush the "no more in use" cache entries */
- FOR_EACH(ishape, ishape, darray_mesh_size_get(&sampler->cached_meshes))
- mesh_ref_put(darray_mesh_data_get(&sampler->cached_meshes)[ishape]);
- darray_mesh_resize(&sampler->cached_meshes, nshapes);
-
- /* TODO take into account the scale transformation in the upd_geom flag */
- *upd_geom = *upd_geom || (nshapes != ishape);
-
-exit:
- return res;
-error:
- sampler_clear_cached_meshes(sampler);
- goto exit;
-}
-
-/* Synchronise the sampler with the shape data */
-static res_T
-sampler_sync(struct s3d_sampler* sampler)
-{
- char upd_geom = 0;
- res_T res = RES_OK;
- ASSERT(sampler);
-
- if(sampler->is_sync)
- return RES_BAD_OP;
-
- switch(sampler->shape->type) {
- case SHAPE_MESH: res = sampler_cache_mesh(sampler, &upd_geom); break;
- case SHAPE_INSTANCE: res = sampler_cache_instance(sampler, &upd_geom); break;
- default: FATAL("Unreachable code\n"); break;
- }
- if(res != RES_OK) goto error;
-
- if(upd_geom) {
- res = sampler_compute_cdf(sampler);
- if(res != RES_OK) goto error;
- }
- sampler->is_sync = 1;
-
-exit:
- return res;
-error:
- sampler_clear_cached_meshes(sampler);
- goto exit;
-}
-
-static void
-sampler_release(ref_T* ref)
-{
- struct s3d_sampler* sampler;
- struct s3d_shape* shape;
-
- ASSERT(ref);
- sampler = CONTAINER_OF(ref, struct s3d_sampler, ref);
- shape = sampler->shape;
-
- sampler_clear_cached_meshes(sampler);
- darray_mesh_release(&sampler->cached_meshes);
- darray_float_release(&sampler->triangles_cdf);
- darray_float_release(&sampler->meshes_cdf);
- darray_size_t_release(&sampler->mesh2triangle);
-
- if(sampler->cached_instance)
- instance_ref_put(sampler->cached_instance);
-
- MEM_RM(shape->dev->allocator, sampler);
- S3D(shape_ref_put(shape));
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-s3d_sampler_create(struct s3d_shape* shape, struct s3d_sampler** out_sampler)
-{
- struct s3d_sampler* sampler = NULL;
- res_T res = RES_OK;
-
- if(!out_sampler || !shape) {
- res = RES_BAD_ARG;
- goto error;
- }
- sampler = (struct s3d_sampler*)
- MEM_CALLOC(shape->dev->allocator, 1, sizeof(struct s3d_sampler));
- if(!sampler) {
- res = RES_MEM_ERR;
- goto error;
- }
- ref_init(&sampler->ref);
- S3D(shape_ref_get(shape));
- sampler->shape = shape;
- darray_mesh_init(shape->dev->allocator, &sampler->cached_meshes);
- darray_float_init(shape->dev->allocator, &sampler->triangles_cdf);
- darray_float_init(shape->dev->allocator, &sampler->meshes_cdf);
- darray_size_t_init(shape->dev->allocator, &sampler->mesh2triangle);
-
- if(shape->type == SHAPE_INSTANCE) {
- res = instance_create(shape->data.instance->scene, &sampler->cached_instance);
- if(res != RES_OK) goto error;
- }
-
-exit:
- if(out_sampler) *out_sampler = sampler;
- return res;
-error:
- if(sampler) {
- S3D(sampler_ref_put(sampler));
- sampler = NULL;
- }
- goto exit;
-}
-
-res_T
-s3d_sampler_ref_get(struct s3d_sampler* sampler)
-{
- if(!sampler) return RES_BAD_ARG;
- ref_get(&sampler->ref);
- return RES_OK;
-}
-
-res_T
-s3d_sampler_ref_put(struct s3d_sampler* sampler)
-{
- if(!sampler) return RES_BAD_ARG;
- ref_put(&sampler->ref, sampler_release);
- return RES_OK;
-}
-
-res_T
-s3d_sampler_begin_sampling(struct s3d_sampler* sampler)
-{
- if(!sampler) return RES_BAD_ARG;
- return sampler_sync(sampler);
-}
-
-res_T
-s3d_sampler_end_sampling(struct s3d_sampler* sampler)
-{
- if(!sampler) return RES_BAD_ARG;
- if(!sampler->is_sync) return RES_BAD_OP;
- sampler_clear(sampler);
- return RES_OK;
-}
-
-res_T
-s3d_sampler_get
- (struct s3d_sampler* sampler,
- const float u,
- const float v,
- const float w,
- struct s3d_primitive* primitive, /* sampled primitive */
- float uv[2])
-{
- const float* cdf_start = NULL;
- const float* cdf_stop = NULL;
- const float* cdf_found = NULL;
- double sqrt_v;
- struct mesh* mesh = NULL;
- size_t imesh;
- size_t imesh2tri;
- res_T res = RES_OK;
-
- if(!sampler || !primitive || !uv) {
- 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) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(!sampler->is_sync) {
- res = RES_BAD_OP;
- goto error;
- }
-
- /* Find which mesh is sampled */
- if(darray_float_size_get(&sampler->meshes_cdf) == 1) {
- imesh = 0;
- } else {
- cdf_start = darray_float_cdata_get(&sampler->meshes_cdf);
- cdf_stop = cdf_start + darray_float_size_get(&sampler->meshes_cdf);
- cdf_found = std::lower_bound(cdf_start, cdf_stop, u);
- ASSERT(cdf_found != cdf_stop);
- imesh = cdf_found - cdf_start;
- }
-
- imesh2tri = darray_size_t_data_get(&sampler->mesh2triangle)[imesh];
- mesh = darray_mesh_data_get(&sampler->cached_meshes)[imesh];
-
- /* Find which triangle is sampled into the mesh */
- cdf_start = darray_float_cdata_get(&sampler->triangles_cdf) + imesh2tri;
- cdf_stop = cdf_start + mesh_get_ntris(mesh);
- cdf_found = std::lower_bound(cdf_start, cdf_stop, u);
- ASSERT(cdf_found != cdf_stop);
-
- /* Setup the sampled primitive */
- primitive->mesh__ = mesh;
- primitive->inst__ = sampler->cached_instance;
- primitive->prim_id = (unsigned)(cdf_found - cdf_start);
- primitive->geom_id = mesh->id;
- primitive->inst_id = sampler->cached_instance
- ? sampler->cached_instance->id
- : S3D_INVALID_ID;
-
- /* Compute the sampled barycentric coordinate of the sampled primitive */
- sqrt_v = sqrt(v);
- uv[0] = (float)(1.0 - sqrt_v);
- uv[1] = (float)(w * sqrt_v);
-
-exit:
- return res;
-error:
- goto exit;
-}
-#endif
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -881,3 +881,153 @@ error:
goto exit;
}
+res_T
+s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count)
+{
+ struct list_node* node;
+ struct s3d_shape* shape;
+ struct geometry** pgeom;
+ struct geometry* geom;
+ size_t inst_count;
+ res_T res = RES_OK;
+
+ if(!scn || !prims_count) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(!scn->session_mask) {
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ *prims_count = 0;
+ LIST_FOR_EACH(node, &scn->shapes) {
+ shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
+ pgeom = htable_geom_find(&scn->cached_geoms, &shape);
+ ASSERT(pgeom != NULL);
+ geom = *pgeom;
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH:
+ *prims_count += mesh_get_ntris(geom->data.mesh);
+ break;
+ case GEOM_INSTANCE:
+ S3D(scene_primitives_count(geom->data.instance->scene, &inst_count));
+ *prims_count += inst_count;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+s3d_scene_compute_area(struct s3d_scene* scn, float* area)
+{
+ res_T res = RES_OK;
+
+ if(!scn || !area) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(!scn->session_mask) {
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ if((scn->session_mask & S3D_SAMPLE) != 0) {
+ /* Retrieve the overall scene area from the scene cumulative distribution
+ * function. Note that the CDF stores the cumulateive triangle area
+ * multiplied by 2; the real scene area is thus the CDF upper bound / 2 */
+ size_t len = darray_fltui_size_get(&scn->cdf);
+ if(!len) {
+ *area = 0.f;
+ } else {
+ *area = darray_fltui_cdata_get(&scn->cdf)[len - 1].flt * 0.5f;
+ }
+ } else {
+ struct list_node* node;
+ struct s3d_shape* shape;
+ struct geometry** pgeom;
+ struct geometry* geom;
+ float inst_area;
+
+ *area = 0.f;
+ LIST_FOR_EACH(node, &scn->shapes) {
+ shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
+ pgeom = htable_geom_find(&scn->cached_geoms, &shape);
+ ASSERT(pgeom != NULL);
+ geom = *pgeom;
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH:
+ *area += mesh_compute_area(geom->data.mesh);
+ break;
+ case GEOM_INSTANCE:
+ /* TODO take into account the instance scale factor */
+ S3D(scene_compute_area(geom->data.instance->scene, &inst_area));
+ *area += inst_area;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+s3d_scene_compute_volume(struct s3d_scene* scn, float* volume)
+{
+ struct list_node* node;
+ struct s3d_shape* shape;
+ struct geometry** pgeom;
+ struct geometry* geom;
+ res_T res = RES_OK;
+
+ if(!scn || !volume) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(!scn->session_mask) {
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ *volume = 0.f;
+ LIST_FOR_EACH(node, &scn->shapes) {
+ shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
+ pgeom = htable_geom_find(&scn->cached_geoms, &shape);
+ ASSERT(pgeom != NULL);
+ geom = *pgeom;
+
+ if(!geom->is_enabled) continue;
+
+ switch(geom->type) {
+ case GEOM_MESH:
+ *volume += mesh_compute_volume(geom->data.mesh, geom->flip_surface);
+ break;
+ case GEOM_INSTANCE:
+ *volume += instance_compute_volume(geom->data.instance, geom->flip_surface);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+
+}
diff --git a/src/s3d_shape.c b/src/s3d_shape.c
@@ -200,58 +200,6 @@ s3d_shape_flip_surface(struct s3d_shape* shape)
}
res_T
-s3d_shape_primitives_count(struct s3d_shape* shape, size_t* nprims)
-{
- if(!shape || !nprims) return RES_BAD_ARG;
- switch(shape->type) {
- case GEOM_MESH:
- *nprims = mesh_get_ntris(shape->data.mesh);
- break;
- case GEOM_INSTANCE:
- *nprims = instance_get_ntris(shape->data.instance);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- return RES_OK;
-}
-
-res_T
-s3d_shape_compute_area(struct s3d_shape* shape, float* area)
-{
- if(!shape || !area)
- return RES_BAD_ARG;
- switch(shape->type) {
- case GEOM_MESH:
- *area = mesh_compute_area(shape->data.mesh);
- break;
- case GEOM_INSTANCE:
- *area = instance_compute_area(shape->data.instance);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- return RES_OK;
-}
-
-res_T
-s3d_shape_compute_volume(struct s3d_shape* shape, float* volume)
-{
- if(!shape || !volume)
- return RES_BAD_ARG;
- switch(shape->type) {
- case GEOM_MESH:
- *volume = mesh_compute_volume
- (shape->data.mesh, shape->flip_surface);
- break;
- case GEOM_INSTANCE:
- *volume = instance_compute_volume
- (shape->data.instance, shape->flip_surface);
- break;
- default: FATAL("Unreachable code \n"); break;
- }
- return RES_OK;
-}
-
-res_T
s3d_instance_set_position
(struct s3d_shape* shape, const float position[3])
{
diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c
@@ -32,6 +32,57 @@
#include "s3d.h"
#include "test_s3d_utils.h"
+#include "test_s3d_cbox.h"
+
+#include <rsys/math.h>
+
+static const float cube_verts[] = {
+ 5.f, 5.f, 5.f,
+ 6.f, 5.f, 5.f,
+ 5.f, 6.f, 5.f,
+ 6.f, 6.f, 5.f,
+ 5.f, 5.f, 6.f,
+ 6.f, 5.f, 6.f,
+ 5.f, 6.f, 6.f,
+ 6.f, 6.f, 6.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]);
+
+static void
+cube_get_ids(const unsigned itri, unsigned ids[3], void* data)
+{
+ const unsigned id = itri * 3;
+ CHECK(data, NULL);
+ NCHECK(ids, NULL);
+ CHECK(itri < cube_ntris, 1);
+ ids[0] = cube_ids[id + 0];
+ ids[1] = cube_ids[id + 1];
+ ids[2] = cube_ids[id + 2];
+}
+
+static void
+cube_get_pos(const unsigned ivert, float pos[3], void* data)
+{
+ const unsigned i = ivert*3;
+ (void)data;
+ CHECK(data, NULL);
+ NCHECK(pos, NULL);
+ CHECK(ivert < cube_nverts, 1);
+ pos[0] = cube_verts[i + 0];
+ pos[1] = cube_verts[i + 1];
+ pos[2] = cube_verts[i + 2];
+}
int
main(int argc, char** argv)
@@ -41,9 +92,15 @@ main(int argc, char** argv)
struct s3d_scene* scn;
struct s3d_scene* scn2;
struct s3d_scene* scn3;
+ struct s3d_vertex_data attribs[2];
struct s3d_shape* shapes[4];
const size_t nshapes = sizeof(shapes)/sizeof(struct s3d_shape*);
+ void* data = (void*)&cbox_walls_desc;
+ const unsigned cbox_ntris = sizeof(cbox_walls_ids) / sizeof(unsigned[3]);
+ const unsigned cbox_nverts = sizeof(cbox_walls) / sizeof(float[3]);
size_t i;
+ size_t nprims;
+ float area, volume;
unsigned id;
int mask;
(void)argc, (void)argv;
@@ -124,8 +181,24 @@ main(int argc, char** argv)
CHECK(s3d_scene_attach_shape(scn2, shapes[1]), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shapes[2]), RES_OK);
CHECK(s3d_scene_begin_session(scn2, S3D_SAMPLE|S3D_TRACE), RES_OK);
+
+ CHECK(s3d_scene_compute_area(NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_compute_area(scn2, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_compute_area(NULL, &area), RES_BAD_ARG);
+ CHECK(s3d_scene_compute_area(scn2, &area), RES_OK);
+ CHECK(area, 0.f);
+
+ CHECK(s3d_scene_primitives_count(NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_primitives_count(scn2, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_primitives_count(NULL, &nprims), RES_BAD_ARG);
+ CHECK(s3d_scene_primitives_count(scn2, &nprims), RES_OK);
+ CHECK(nprims, 0);
+
CHECK(s3d_scene_end_session(scn2), RES_OK);
+ CHECK(s3d_scene_compute_area(scn2, &area), RES_BAD_OP);
+ CHECK(s3d_scene_primitives_count(scn2, &nprims), RES_BAD_OP);
+
CHECK(s3d_scene_instantiate(scn2, shapes + 3), RES_OK);
CHECK(s3d_scene_attach_shape(scn3, shapes[3]), RES_OK);
CHECK(s3d_scene_begin_session(scn3, S3D_SAMPLE|S3D_TRACE), RES_BAD_ARG);
@@ -145,6 +218,68 @@ main(int argc, char** argv)
CHECK(s3d_scene_ref_put(scn2), RES_OK);
CHECK(s3d_scene_ref_put(scn3), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn), RES_OK);
+ CHECK(s3d_scene_create(dev, &scn2), RES_OK);
+
+ attribs[0].type = S3D_FLOAT3;
+ attribs[0].usage = S3D_POSITION;
+ attribs[0].get = cbox_get_position;
+ attribs[1] = S3D_VERTEX_DATA_NULL;
+ CHECK(s3d_shape_create_mesh(dev, shapes + 0), RES_OK);
+ CHECK(s3d_mesh_setup_indexed_vertices
+ (shapes[0], cbox_ntris, cbox_get_ids, cbox_nverts, attribs, data), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK);
+
+ CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
+ CHECK(s3d_scene_compute_area(scn, &area), RES_OK);
+ CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
+ CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
+ CHECK(nprims, 10);
+ CHECK(s3d_scene_end_session(scn), RES_OK);
+
+ CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
+ CHECK(s3d_scene_compute_area(scn, &area), RES_OK);
+ CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
+ CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
+ CHECK(nprims, 10);
+ CHECK(s3d_scene_end_session(scn), RES_OK);
+
+ CHECK(s3d_scene_instantiate(scn, shapes + 1), RES_OK);
+ CHECK(s3d_scene_attach_shape(scn2, shapes[1]), RES_OK);
+
+ CHECK(s3d_scene_begin_session(scn2, S3D_TRACE), RES_OK);
+ CHECK(s3d_scene_compute_area(scn2, &area), RES_OK);
+ CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
+ CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
+ CHECK(nprims, 10);
+ CHECK(s3d_scene_end_session(scn2), RES_OK);
+
+ CHECK(s3d_scene_begin_session(scn2, S3D_SAMPLE), RES_OK);
+ CHECK(s3d_scene_compute_area(scn2, &area), RES_OK);
+ CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
+ CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
+ CHECK(nprims, 10);
+ CHECK(s3d_scene_end_session(scn2), RES_OK);
+
+ attribs[0].type = S3D_FLOAT3;
+ attribs[0].usage = S3D_POSITION;
+ attribs[0].get = cube_get_pos;
+ attribs[1] = S3D_VERTEX_DATA_NULL;
+ CHECK(s3d_mesh_setup_indexed_vertices
+ (shapes[0], cube_ntris, cube_get_ids, cube_nverts, attribs, NULL), RES_OK);
+
+ CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK);
+ CHECK(s3d_scene_compute_area(scn, &area), RES_OK);
+ CHECK(eq_epsf(area, 6.f, 1.e-6f), 1);
+ CHECK(s3d_scene_compute_volume(scn, &volume), RES_OK);
+ CHECK(eq_epsf(volume, 1.f, 1.e-6f), 1);
+ CHECK(s3d_scene_end_session(scn), RES_OK);
+
+ CHECK(s3d_scene_ref_put(scn), RES_OK);
+ CHECK(s3d_scene_ref_put(scn2), RES_OK);
+ CHECK(s3d_shape_ref_put(shapes[0]), RES_OK);
+ CHECK(s3d_shape_ref_put(shapes[1]), RES_OK);
+
CHECK(s3d_device_ref_put(dev), RES_OK);;
check_memory_allocator(&allocator);
diff --git a/src/test_s3d_shape.c b/src/test_s3d_shape.c
@@ -36,54 +36,6 @@
#include <rsys/math.h>
-static const float cube_verts[] = {
- 5.f, 5.f, 5.f,
- 6.f, 5.f, 5.f,
- 5.f, 6.f, 5.f,
- 6.f, 6.f, 5.f,
- 5.f, 5.f, 6.f,
- 6.f, 5.f, 6.f,
- 5.f, 6.f, 6.f,
- 6.f, 6.f, 6.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]);
-
-static void
-cube_get_ids(const unsigned itri, unsigned ids[3], void* data)
-{
- const unsigned id = itri * 3;
- CHECK(data, NULL);
- NCHECK(ids, NULL);
- CHECK(itri < cube_ntris, 1);
- ids[0] = cube_ids[id + 0];
- ids[1] = cube_ids[id + 1];
- ids[2] = cube_ids[id + 2];
-}
-
-static void
-cube_get_pos(const unsigned ivert, float pos[3], void* data)
-{
- const unsigned i = ivert*3;
- (void)data;
- CHECK(data, NULL);
- NCHECK(pos, NULL);
- CHECK(ivert < cube_nverts, 1);
- pos[0] = cube_verts[i + 0];
- pos[1] = cube_verts[i + 1];
- pos[2] = cube_verts[i + 2];
-}
-
int
main(int argc, char** argv)
{
@@ -93,10 +45,7 @@ main(int argc, char** argv)
struct s3d_shape* inst;
struct s3d_scene* scn;
struct s3d_vertex_data attribs[4];
- size_t nprims;
float pos[3];
- float area;
- float volume;
const unsigned cbox_ntris = sizeof(cbox_walls_ids) / sizeof(unsigned[3]);
const unsigned cbox_nverts = sizeof(cbox_walls) / sizeof(float[3]);
unsigned id;
@@ -126,20 +75,8 @@ main(int argc, char** argv)
CHECK(s3d_shape_is_attached(shape, &c), RES_OK);
CHECK(c, 0);
- CHECK(s3d_shape_primitives_count(NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_shape_primitives_count(shape, NULL), RES_BAD_ARG);
- CHECK(s3d_shape_primitives_count(NULL, &nprims), RES_BAD_ARG);
- CHECK(s3d_shape_primitives_count(shape, &nprims), RES_OK);
- CHECK(nprims, 0);
-
- CHECK(s3d_shape_compute_area(NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_shape_compute_area(shape, NULL), RES_BAD_ARG);
- CHECK(s3d_shape_compute_area(NULL, &area), RES_BAD_ARG);
- CHECK(s3d_shape_compute_area(shape, &area), RES_OK);
- CHECK(area, 0.f);
-
- CHECK(s3d_scene_attach_shape(NULL, NULL), RES_BAD_ARG);
- CHECK(s3d_scene_attach_shape(scn, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_attach_shape(NULL, NULL), RES_BAD_ARG);
+ CHECK(s3d_scene_attach_shape(scn, NULL), RES_BAD_ARG);
CHECK(s3d_scene_attach_shape(NULL, shape), RES_BAD_ARG);
CHECK(s3d_scene_attach_shape(scn, shape), RES_OK);
CHECK(s3d_shape_is_attached(shape, &c), RES_OK);
@@ -221,11 +158,6 @@ main(int argc, char** argv)
CHECK(s3d_mesh_setup_indexed_vertices
(shape, cbox_ntris, cbox_get_ids, cbox_nverts, attribs, data), RES_OK);
- CHECK(s3d_shape_primitives_count(shape, &nprims), RES_OK);
- CHECK(nprims, 10);
- CHECK(s3d_shape_compute_area(shape, &area), RES_OK);
- CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1);
-
attribs[0] = S3D_VERTEX_DATA_NULL;
CHECK(s3d_mesh_setup_indexed_vertices
(shape, cbox_ntris, cbox_get_ids, cbox_nverts, attribs, data), RES_BAD_ARG);
@@ -325,20 +257,6 @@ main(int argc, char** argv)
CHECK(s3d_shape_ref_put(inst), RES_OK);
CHECK(s3d_scene_ref_put(scn), RES_OK);
- attribs[0].type = S3D_FLOAT3;
- attribs[0].usage = S3D_POSITION;
- attribs[0].get = cube_get_pos;
- attribs[1] = S3D_VERTEX_DATA_NULL;
- CHECK(s3d_shape_create_mesh(dev, &shape), RES_OK);
- CHECK(s3d_mesh_setup_indexed_vertices
- (shape, cube_ntris, cube_get_ids, cube_nverts, attribs, NULL), RES_OK);
- CHECK(s3d_shape_primitives_count(shape, &nprims), RES_OK);
- CHECK(nprims, 12);
- CHECK(s3d_shape_compute_area(shape, &area), RES_OK);
- CHECK(eq_epsf(area, 6.f, 1.e-6f), 1);
- CHECK(s3d_shape_compute_volume(shape, &volume), RES_OK);
- CHECK(eq_epsf(volume, 1.f, 1.e-6f), 1);
- CHECK(s3d_shape_ref_put(shape), RES_OK);
CHECK(s3d_device_ref_put(dev), RES_OK);;
check_memory_allocator(&allocator);
diff --git a/src/test_s3d_trace_ray.c b/src/test_s3d_trace_ray.c
@@ -184,8 +184,6 @@ main(int argc, char** argv)
CHECK(s3d_shape_get_id(tall_block, &tall_block_id), RES_OK);
CHECK(s3d_mesh_setup_indexed_vertices
(tall_block, ntris, cbox_get_ids, nverts, attribs, &desc), RES_OK);
- CHECK(s3d_shape_primitives_count(tall_block, &nprims), RES_OK);
- CHECK(nprims, 10);
CHECK(s3d_scene_attach_shape(scn, tall_block), RES_OK);
/* Update the inst vertices */
@@ -199,14 +197,14 @@ main(int argc, char** argv)
CHECK(s3d_shape_get_id(short_block, &short_block_id), RES_OK);
CHECK(s3d_mesh_setup_indexed_vertices
(short_block, ntris, cbox_get_ids, nverts, attribs, &desc), RES_OK);
- CHECK(s3d_shape_primitives_count(short_block, &nprims), RES_OK);
- CHECK(nprims, 10);
CHECK(s3d_scene_attach_shape(scn, short_block), RES_OK);
/* Instantiate the scene */
CHECK(s3d_scene_instantiate(scn, &inst), RES_OK);
- CHECK(s3d_shape_primitives_count(inst, &nprims), RES_OK);
+ CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK);
+ CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK);
CHECK(nprims, 20);
+ CHECK(s3d_scene_end_session(scn), RES_OK);
CHECK(s3d_shape_get_id(inst, &inst_id), RES_OK);
/* Create the CBox walls */
@@ -218,11 +216,7 @@ main(int argc, char** argv)
CHECK(s3d_shape_get_id(walls, &walls_id), RES_OK);
CHECK(s3d_mesh_setup_indexed_vertices
(walls, ntris, cbox_get_ids, nverts, attribs, &desc), RES_OK);
- CHECK(s3d_shape_primitives_count(walls, &nprims), RES_OK);
- CHECK(nprims, 10);
CHECK(s3d_scene_attach_shape(scn, walls), RES_OK);
- CHECK(s3d_shape_primitives_count(inst, &nprims), RES_OK);
- CHECK(nprims, 30);
/* Check that the ids are all different */
NCHECK(walls_id, short_block_id);
@@ -258,6 +252,8 @@ main(int argc, char** argv)
CHECK(s3d_scene_attach_shape(scn, tall_block), RES_OK);
CHECK(s3d_scene_begin_session(scn2, S3D_TRACE), RES_OK);
+ CHECK(s3d_scene_primitives_count(scn2, &nprims), RES_OK);
+ CHECK(nprims, 30);
camera_init(&cam);
FOR_EACH(iy, 0, IMG_HEIGHT) {