commit 8b67ac22b1ee7846d9f8aeb5673993aa81bb8578
parent c3f825a19c9f22ec12fdf220052213455081f67a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 23 Feb 2021 10:13:06 +0100
Add the "htrdr_geometry.<c|h>" files to htrdr-core
Manage the geometry in htrdr-core by moving most of the geometry code
from htrdr_atmosphere_ground to htrdr_geometry. The only
specificity provided by htrdr_atmosphere_ground is now the
geometry repetition along the X and Y axes.
Diffstat:
4 files changed, 830 insertions(+), 566 deletions(-)
diff --git a/cmake/core/CMakeLists.txt b/cmake/core/CMakeLists.txt
@@ -74,12 +74,13 @@ configure_file(${HTRDR_SOURCE_DIR}/core/htrdr_version.h.in
# Configure and define targets
################################################################################
set(HTRDR_CORE_FILES_SRC
+ htrdr.c
htrdr_args.c
htrdr_buffer.c
- htrdr.c
htrdr_camera.c
htrdr_cie_xyz.c
htrdr_draw_map.c
+ htrdr_geometry.c
htrdr_log.c
htrdr_materials.c
htrdr_ran_wlen.c
@@ -87,13 +88,14 @@ set(HTRDR_CORE_FILES_SRC
htrdr_slab.c
htrdr_spectral.c)
set(HTRDR_CORE_FILES_INC
+ htrdr.h
htrdr_accum.h
htrdr_buffer.h
htrdr_camera.h
htrdr_c.h
htrdr_cie_xyz.h
htrdr_draw_map.h
- htrdr.h
+ htrdr_geometry.c
htrdr_interface.h
htrdr_log.h
htrdr_materials.h
diff --git a/src/atmosphere/htrdr_atmosphere_ground.c b/src/atmosphere/htrdr_atmosphere_ground.c
@@ -15,76 +15,32 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#define _POSIX_C_SOURCE 200112L /* strtok_r support */
#include "atmosphere/htrdr_atmosphere_ground.h"
-#include "core/htrdr.h"
-#include "core/htrdr_interface.h"
#include "core/htrdr_log.h"
-#include "core/htrdr_materials.h"
+#include "core/htrdr_geometry.h"
#include "core/htrdr_slab.h"
-#include <aw.h>
#include <star/s3d.h>
-#include <rsys/clock_time.h>
#include <rsys/cstr.h>
-#include <rsys/dynamic_array_double.h>
-#include <rsys/dynamic_array_size_t.h>
-#include <rsys/double2.h>
#include <rsys/double3.h>
-#include <rsys/float2.h>
-#include <rsys/float3.h>
-#include <rsys/hash_table.h>
+#include <rsys/mem_allocator.h>
#include <rsys/ref_count.h>
-#include <string.h> /* strtok_r */
-
-/* Define the hash table that maps an Obj vertex id to its position into the
- * vertex buffer */
-#define HTABLE_NAME vertex
-#define HTABLE_KEY size_t /* Obj vertex id */
-#define HTABLE_DATA size_t
-#include <rsys/hash_table.h>
-
-/* Define the hash table that maps the Star-3D shape id to its interface */
-#define HTABLE_NAME interface
-#define HTABLE_KEY unsigned /* Star-3D shape id */
-#define HTABLE_DATA struct htrdr_interface
-#include <rsys/hash_table.h>
-
-struct mesh {
- const struct darray_double* positions;
- const struct darray_size_t* indices;
-};
-static const struct mesh MESH_NULL;
-
-struct ray_context {
- float range[2];
- struct s3d_hit hit_prev;
- int id[2];
-};
-#define RAY_CONTEXT_NULL__ {{0,INF}, S3D_HIT_NULL__, {0,0}}
-static const struct ray_context RAY_CONTEXT_NULL = RAY_CONTEXT_NULL__;
-
-struct trace_ground_context {
- struct s3d_scene_view* view;
- struct ray_context context;
+struct trace_slab_context {
+ struct htrdr_geometry* geom;
+ const struct s3d_hit* hit_prev;
struct s3d_hit* hit;
};
-static const struct trace_ground_context TRACE_GROUND_CONTEXT_NULL = {
- NULL, RAY_CONTEXT_NULL__, NULL
-};
+#define TRACE_SLAB_CONTEXT_NULL__ { NULL, NULL, NULL }
+static const struct trace_slab_context TRACE_SLAB_CONTEXT_NULL =
+ TRACE_SLAB_CONTEXT_NULL__;
struct htrdr_atmosphere_ground {
- struct s3d_scene_view* view;
- float lower[3]; /* Ground lower bound */
- float upper[3]; /* Ground upper bound */
+ struct htrdr_geometry* geom;
int repeat; /* Make the ground infinite in X and Y */
-
- struct htable_interface interfaces; /* Map a Star3D shape to its interface */
-
struct htrdr* htrdr;
ref_T ref;
};
@@ -92,462 +48,25 @@ struct htrdr_atmosphere_ground {
/*******************************************************************************
* Helper functions
******************************************************************************/
-/* Check that `hit' roughly lies on an edge. For triangular primitives, a
- * simple but approximative way is to test that its position have at least one
- * barycentric coordinate roughly equal to 0 or 1. */
-static FINLINE int
-hit_on_edge(const struct s3d_hit* hit)
-{
- const float on_edge_eps = 1.e-4f;
- float w;
- ASSERT(hit && !S3D_HIT_NONE(hit));
- w = 1.f - hit->uv[0] - hit->uv[1];
- return eq_epsf(hit->uv[0], 0.f, on_edge_eps)
- || eq_epsf(hit->uv[0], 1.f, on_edge_eps)
- || eq_epsf(hit->uv[1], 0.f, on_edge_eps)
- || eq_epsf(hit->uv[1], 1.f, on_edge_eps)
- || eq_epsf(w, 0.f, on_edge_eps)
- || eq_epsf(w, 1.f, on_edge_eps);
-}
-
-static int
-ground_filter
- (const struct s3d_hit* hit,
- const float ray_org[3],
- const float ray_dir[3],
- void* ray_data,
- void* filter_data)
-{
- const struct ray_context* ray_ctx = ray_data;
- (void)ray_org, (void)ray_dir, (void)filter_data;
-
- if(!ray_ctx) return 0;
-
- if(S3D_PRIMITIVE_EQ(&hit->prim, &ray_ctx->hit_prev.prim)) return 1;
-
- if(!S3D_HIT_NONE(&ray_ctx->hit_prev) && eq_epsf(hit->distance, 0, 1.e-1f)) {
- /* If the targeted point is near of the origin, check that it lies on an
- * edge/vertex shared by the 2 primitives. */
- return hit_on_edge(&ray_ctx->hit_prev) && hit_on_edge(hit);
- }
-
- return hit->distance <= ray_ctx->range[0]
- || hit->distance >= ray_ctx->range[1];
-}
-
static INLINE res_T
-trace_ground
+trace_slab
(const double org[3],
const double dir[3],
const double range[2],
void* context,
int* hit)
{
- struct trace_ground_context* ctx = context;
- float ray_org[3];
- float ray_dir[3];
- float ray_range[2];
+ struct trace_slab_context* ctx = context;
res_T res = RES_OK;
ASSERT(org && dir && range && context && hit);
- f3_set_d3(ray_org, org);
- f3_set_d3(ray_dir, dir);
- f2_set_d2(ray_range, range);
-
- res = s3d_scene_view_trace_ray
- (ctx->view, ray_org, ray_dir, ray_range, &ctx->context, ctx->hit);
+ res = htrdr_geometry_trace_ray
+ (ctx->geom, org, dir, range, ctx->hit_prev, ctx->hit);
if(res != RES_OK) return res;
*hit = !S3D_HIT_NONE(ctx->hit);
return RES_OK;
}
-
-static res_T
-parse_shape_interface
- (struct htrdr* htrdr,
- struct htrdr_materials* mats,
- const char* name,
- struct htrdr_interface* interf)
-{
- struct str str;
- char* mtl_name0 = NULL;
- char* mtl_name1 = NULL;
- char* mtl_name2 = NULL;
- char* mtl_name_front = NULL;
- char* mtl_name_thin = NULL;
- char* mtl_name_back = NULL;
- char* tk_ctx = NULL;
- int has_front = 0;
- int has_thin = 0;
- int has_back = 0;
- res_T res = RES_OK;
- ASSERT(htrdr && mats && name && interf);
-
- str_init(htrdr_get_allocator(htrdr), &str);
-
- /* Locally copy the string to parse */
- res = str_set(&str, name);
- if(res != RES_OK) {
- htrdr_log_err(htrdr,
- "Could not locally copy the shape material string `%s' -- %s.\n",
- name, res_to_cstr(res));
- goto error;
- }
-
- /* Reset the interface */
- memset(interf, 0, sizeof(*interf));
-
- /* Parse the name of the front/back/thin materials */
- mtl_name0 = strtok_r(str_get(&str), ":", &tk_ctx);
- mtl_name1 = strtok_r(NULL, ":", &tk_ctx);
- mtl_name2 = strtok_r(NULL, ":", &tk_ctx);
- ASSERT(mtl_name0); /* This can't be NULL */
- mtl_name_front = mtl_name0;
- if(mtl_name2) {
- mtl_name_thin = mtl_name1;
- mtl_name_back = mtl_name2;
- } else {
- mtl_name_thin = NULL;
- mtl_name_back = mtl_name1;
- }
-
- if(!mtl_name_back) {
- htrdr_log_err(htrdr,
- "The back material name is missing `%s'.\n", name);
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Fetch the interface material if any */
- if(mtl_name_thin) {
- has_thin = htrdr_materials_find_mtl(mats, mtl_name_thin, &interf->mtl_thin);
- if(!has_thin) {
- htrdr_log_err(htrdr,
- "Invalid interface `%s'. The interface material `%s' is unknown.\n",
- name, mtl_name_thin);
- res = RES_BAD_ARG;
- goto error;
- }
- }
-
- /* Fetch the front material */
- has_front = htrdr_materials_find_mtl(mats, mtl_name_front, &interf->mtl_front);
- if(!has_front) {
- htrdr_log_err(htrdr,
- "Invalid interface `%s'. The front material `%s' is unknown.\n",
- name, mtl_name_front);
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Fetch the back material */
- has_back = htrdr_materials_find_mtl(mats, mtl_name_back, &interf->mtl_back);
- if(!has_back) {
- htrdr_log_err(htrdr,
- "Invalid interface `%s'. The back material `%s' is unknown.\n",
- name, mtl_name_back);
- res = RES_BAD_ARG;
- goto error;
- }
-
-exit:
- str_release(&str);
- return res;
-error:
- *interf = HTRDR_INTERFACE_NULL;
- goto exit;
-}
-static res_T
-setup_mesh
- (struct htrdr* htrdr,
- const char* filename,
- struct aw_obj* obj,
- struct aw_obj_named_group* mtl,
- struct darray_double* positions,
- struct darray_size_t* indices,
- struct htable_vertex* vertices) /* Scratch data structure */
-{
- size_t iface;
- res_T res = RES_OK;
- ASSERT(htrdr && filename && obj && mtl && positions && indices && vertices);
-
- darray_double_clear(positions);
- darray_size_t_clear(indices);
- htable_vertex_clear(vertices);
-
- FOR_EACH(iface, mtl->face_id, mtl->face_id+mtl->faces_count) {
- struct aw_obj_face face;
- size_t ivertex;
-
- AW(obj_get_face(obj, iface, &face));
- if(face.vertices_count != 3) {
- htrdr_log_err(htrdr,
- "The obj `%s' has non-triangulated polygons "
- "while currently only triangular meshes are supported.\n",
- filename);
- res = RES_BAD_ARG;
- goto error;
- }
-
- FOR_EACH(ivertex, 0, face.vertices_count) {
- struct aw_obj_vertex vertex;
- size_t id;
- size_t* pid;
-
- AW(obj_get_vertex(obj, face.vertex_id + ivertex, &vertex));
- pid = htable_vertex_find(vertices, &vertex.position_id);
- if(pid) {
- id = *pid;
- } else {
- struct aw_obj_vertex_data vdata;
-
- id = darray_double_size_get(positions) / 3;
-
- res = darray_double_resize(positions, id*3 + 3);
- if(res != RES_OK) {
- htrdr_log_err(htrdr,
- "Could not locally copy the vertex position -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
- AW(obj_get_vertex_data(obj, &vertex, &vdata));
- darray_double_data_get(positions)[id*3+0] = vdata.position[0];
- darray_double_data_get(positions)[id*3+1] = vdata.position[1];
- darray_double_data_get(positions)[id*3+2] = vdata.position[2];
-
- res = htable_vertex_set(vertices, &vertex.position_id, &id);
- if(res != RES_OK) {
- htrdr_log_err(htrdr,
- "Could not register the vertex position -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
- }
-
- res = darray_size_t_push_back(indices, &id);
- if(res != RES_OK) {
- htrdr_log_err(htrdr,
- "Could not locally copy the face index -- %s\n",
- res_to_cstr(res));
- goto error;
- }
- }
- }
-exit:
- return res;
-error:
- darray_double_clear(positions);
- darray_size_t_clear(indices);
- htable_vertex_clear(vertices);
- goto exit;
-}
-
-static void
-get_position(const unsigned ivert, float position[3], void* ctx)
-{
- const struct mesh* mesh = ctx;
- const double* pos = NULL;
- ASSERT(mesh);
- ASSERT(ivert < darray_double_size_get(mesh->positions) / 3);
- pos = darray_double_cdata_get(mesh->positions) + ivert*3;
- position[0] = (float)pos[0];
- position[1] = (float)pos[1];
- position[2] = (float)pos[2];
-}
-
-static void
-get_indices(const unsigned itri, unsigned indices[3], void* ctx)
-{
- const struct mesh* mesh = ctx;
- const size_t* ids = NULL;
- ASSERT(mesh);
- ASSERT(itri < darray_size_t_size_get(mesh->indices) / 3);
- ids = darray_size_t_cdata_get(mesh->indices) + itri*3;
- indices[0] = (unsigned)ids[0];
- indices[1] = (unsigned)ids[1];
- indices[2] = (unsigned)ids[2];
-}
-
-static res_T
-create_s3d_shape
- (struct htrdr* htrdr,
- const struct darray_double* positions,
- const struct darray_size_t* indices,
- struct s3d_shape** out_shape)
-{
- struct s3d_shape* shape = NULL;
- struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL;
- struct mesh mesh = MESH_NULL;
- res_T res = RES_OK;
- ASSERT(htrdr && positions && indices && out_shape);
- ASSERT(darray_double_size_get(positions) != 0);
- ASSERT(darray_size_t_size_get(indices) != 0);
- ASSERT(darray_double_size_get(positions)%3 == 0);
- ASSERT(darray_size_t_size_get(indices)%3 == 0);
-
- mesh.positions = positions;
- mesh.indices = indices;
-
- res = s3d_shape_create_mesh(htrdr_get_s3d(htrdr), &shape);
- if(res != RES_OK) {
- htrdr_log_err(htrdr, "Error creating a Star-3D shape -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
- vdata.usage = S3D_POSITION;
- vdata.type = S3D_FLOAT3;
- vdata.get = get_position;
-
- res = s3d_mesh_setup_indexed_vertices
- (shape, (unsigned int)(darray_size_t_size_get(indices)/3), get_indices,
- (unsigned int)(darray_double_size_get(positions)/3), &vdata, 1, &mesh);
- if(res != RES_OK){
- htrdr_log_err(htrdr, "Could not setup the Star-3D shape -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
- res = s3d_mesh_set_hit_filter_function(shape, ground_filter, NULL);
- if(res != RES_OK) {
- htrdr_log_err(htrdr,
- "Could not setup the Star-3D hit filter function of the ground geometry "
- "-- %s.\n", res_to_cstr(res));
- goto error;
- }
-
-exit:
- *out_shape = shape;
- return res;
-error:
- if(shape) {
- S3D(shape_ref_put(shape));
- shape = NULL;
- }
- goto exit;
-}
-
-static res_T
-setup_ground
- (struct htrdr_atmosphere_ground* ground,
- struct htrdr_materials* mats,
- const char* obj_filename)
-{
- struct aw_obj_desc desc;
- struct htable_vertex vertices;
- struct darray_double positions;
- struct darray_size_t indices;
- struct aw_obj* obj = NULL;
- struct s3d_shape* shape = NULL;
- struct s3d_scene* scene = NULL;
- size_t iusemtl;
-
- res_T res = RES_OK;
- ASSERT(ground && mats && obj_filename);
-
- htable_vertex_init(htrdr_get_allocator(ground->htrdr), &vertices);
- darray_double_init(htrdr_get_allocator(ground->htrdr), &positions);
- darray_size_t_init(htrdr_get_allocator(ground->htrdr), &indices);
-
- res = aw_obj_create
- (htrdr_get_logger(ground->htrdr),
- htrdr_get_allocator(ground->htrdr),
- htrdr_get_verbosity_level(ground->htrdr),
- &obj);
- if(res != RES_OK) {
- htrdr_log_err(ground->htrdr, "Could not create the obj loader -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
- res = s3d_scene_create(htrdr_get_s3d(ground->htrdr), &scene);
- if(res != RES_OK) {
- htrdr_log_err(ground->htrdr, "Could not create the Star-3D scene -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
- /* Load the geometry data */
- res = aw_obj_load(obj, obj_filename);
- if(res != RES_OK) goto error;
-
- /* Fetch the descriptor of the loaded geometry */
- AW(obj_get_desc(obj, &desc));
-
- if(desc.usemtls_count == 0) {
- htrdr_log_err(ground->htrdr, "The obj `%s' has no material.\n", obj_filename);
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Setup the geometry */
- FOR_EACH(iusemtl, 0, desc.usemtls_count) {
- struct aw_obj_named_group mtl;
- struct htrdr_interface interf;
- unsigned ishape;
-
- AW(obj_get_mtl(obj, iusemtl , &mtl));
-
- res = parse_shape_interface(ground->htrdr, mats, mtl.name, &interf);
- if(res != RES_OK) goto error;
-
- res = setup_mesh
- (ground->htrdr, obj_filename, obj, &mtl, &positions, &indices, &vertices);
- if(res != RES_OK) goto error;
-
- res = create_s3d_shape(ground->htrdr, &positions, &indices, &shape);
- if(res != RES_OK) goto error;
-
- S3D(shape_get_id(shape, &ishape));
- res = htable_interface_set(&ground->interfaces, &ishape, &interf);
- if(res != RES_OK) {
- htrdr_log_err(ground->htrdr,
- "Could not map the Star-3D shape to its Star-Materials -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
- res = s3d_scene_attach_shape(scene, shape);
- if(res != RES_OK) {
- htrdr_log_err(ground->htrdr,
- "Could not attach a Star-3D shape to the Star-3D scene -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
- S3D(shape_ref_put(shape));
- shape = NULL;
- }
-
- res = s3d_scene_view_create(scene, S3D_GET_PRIMITIVE|S3D_TRACE, &ground->view);
- if(res != RES_OK) {
- htrdr_log_err(ground->htrdr,
- "Could not create the Star-3D scene view -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
- res = s3d_scene_view_get_aabb(ground->view, ground->lower, ground->upper);
- if(res != RES_OK) {
- htrdr_log_err(ground->htrdr,
- "Could not get the bounding box of the geometry -- %s.\n",
- res_to_cstr(res));
- goto error;
- }
-
-exit:
- if(obj) AW(obj_ref_put(obj));
- if(shape) S3D(shape_ref_put(shape));
- if(scene) S3D(scene_ref_put(scene));
- htable_vertex_release(&vertices);
- darray_double_release(&positions);
- darray_size_t_release(&indices);
- return res;
-error:
- goto exit;
-}
-
static void
release_ground(ref_T* ref)
{
@@ -555,8 +74,7 @@ release_ground(ref_T* ref)
struct htrdr* htrdr;
ASSERT(ref);
ground = CONTAINER_OF(ref, struct htrdr_atmosphere_ground, ref);
- if(ground->view) S3D(scene_view_ref_put(ground->view));
- htable_interface_release(&ground->interfaces);
+ if(ground->geom) htrdr_geometry_ref_put(ground->geom);
htrdr = ground->htrdr;
MEM_RM(htrdr_get_allocator(ground->htrdr), ground);
htrdr_ref_put(htrdr);
@@ -573,9 +91,7 @@ htrdr_atmosphere_ground_create
const int repeat_ground, /* Infinitely repeat the ground in X and Y */
struct htrdr_atmosphere_ground** out_ground)
{
- char buf[128];
struct htrdr_atmosphere_ground* ground = NULL;
- struct time t0, t1;
res_T res = RES_OK;
ASSERT(htrdr && out_ground);
@@ -589,26 +105,19 @@ htrdr_atmosphere_ground_create
}
ref_init(&ground->ref);
ground->repeat = repeat_ground;
- f3_splat(ground->lower, (float)INF);
- f3_splat(ground->upper,-(float)INF);
- htable_interface_init(htrdr_get_allocator(htrdr), &ground->interfaces);
htrdr_ref_get(htrdr);
ground->htrdr = htrdr;
if(!obj_filename) goto exit;
if(!mats) {
+ htrdr_log_err(htrdr, "%s: missing materials.\n", FUNC_NAME);
res = RES_BAD_ARG;
goto error;
}
- htrdr_log(ground->htrdr, "Loading ground geometry from `%s'.\n",obj_filename);
- time_current(&t0);
- res = setup_ground(ground, mats, obj_filename);
+ res = htrdr_geometry_create(ground->htrdr, obj_filename, mats, &ground->geom);
if(res != RES_OK) goto error;
- time_sub(&t0, time_current(&t1), &t0);
- time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf));
- htrdr_log(ground->htrdr, "Setup ground in %s\n", buf);
exit:
*out_ground = ground;
@@ -641,13 +150,8 @@ htrdr_atmosphere_ground_get_interface
const struct s3d_hit* hit,
struct htrdr_interface* out_interface)
{
- struct htrdr_interface* interf = NULL;
- ASSERT(ground && hit && out_interface);
-
- interf = htable_interface_find(&ground->interfaces, &hit->prim.geom_id);
- ASSERT(interf);
-
- *out_interface = *interf;
+ /* Simply wrap the geometry function */
+ htrdr_geometry_get_interface(ground->geom, hit, out_interface);
}
res_T
@@ -662,45 +166,28 @@ htrdr_atmosphere_ground_trace_ray
res_T res = RES_OK;
ASSERT(ground && org && dir && range && hit);
- if(!ground->view) { /* No ground geometry */
+ if(!ground->geom) { /* No ground geometry */
*hit = S3D_HIT_NULL;
goto exit;
}
if(!ground->repeat) {
- struct ray_context ray_ctx = RAY_CONTEXT_NULL;
- float ray_org[3];
- float ray_dir[3];
-
- f3_set_d3(ray_org, org);
- f3_set_d3(ray_dir, dir);
- f2_set_d2(ray_ctx.range, range);
- ray_ctx.hit_prev = prev_hit ? *prev_hit : S3D_HIT_NULL;
-
- res = s3d_scene_view_trace_ray
- (ground->view, ray_org, ray_dir, ray_ctx.range, &ray_ctx, hit);
- if(res != RES_OK) {
- htrdr_log_err(ground->htrdr,
- "%s: could not trace the ray against the ground geometry -- %s.\n",
- FUNC_NAME, res_to_cstr(res));
- goto error;
- }
+ res = htrdr_geometry_trace_ray
+ (ground->geom, org, dir, range, prev_hit, hit);
+ if(res != RES_OK) goto error;
} else {
- struct trace_ground_context slab_ctx = TRACE_GROUND_CONTEXT_NULL;
+ struct trace_slab_context slab_ctx = TRACE_SLAB_CONTEXT_NULL;
double low[3], upp[3];
+ htrdr_geometry_get_aabb(ground->geom, low, upp);
+
*hit = S3D_HIT_NULL;
- slab_ctx.view = ground->view;
- slab_ctx.context.range[0] = (float)range[0];
- slab_ctx.context.range[1] = (float)range[1];
- slab_ctx.context.hit_prev = prev_hit ? *prev_hit : S3D_HIT_NULL;
+ slab_ctx.geom = ground->geom;
+ slab_ctx.hit_prev = prev_hit;
slab_ctx.hit = hit;
- d3_set_f3(low, ground->lower);
- d3_set_f3(upp, ground->upper);
-
res = htrdr_slab_trace_ray(ground->htrdr, org, dir, range, low, upp,
- trace_ground, 32, &slab_ctx);
+ trace_slab, 32, &slab_ctx);
if(res != RES_OK) goto error;
}
@@ -717,51 +204,50 @@ htrdr_atmosphere_ground_find_closest_point
const double radius,
struct s3d_hit* hit)
{
- float query_pos[3];
- float query_radius;
- float ground_sz[3];
+ double query_pos[3];
+ double query_radius;
res_T res = RES_OK;
ASSERT(ground && pos && hit);
- if(!ground->view) { /* No ground geometry */
+ if(!ground->geom) { /* No ground geometry */
*hit = S3D_HIT_NULL;
goto exit;
}
- query_radius = (float)radius;
- f3_set_d3(query_pos, pos);
+ query_radius = radius;
+ d3_set(query_pos, pos);
if(ground->repeat) {
- float translation[2] = {0, 0};
+ double ground_low[3];
+ double ground_upp[3];
+ double ground_sz[3];
+ double translation[2] = {0, 0};
int64_t xy[2];
- ground_sz[0] = ground->upper[0] - ground->lower[0];
- ground_sz[1] = ground->upper[1] - ground->lower[1];
- ground_sz[2] = ground->upper[2] - ground->lower[2];
+
+ /* Define the size of the ground geometry pattern */
+ htrdr_geometry_get_aabb(ground->geom, ground_low, ground_upp);
+ ground_sz[0] = ground_upp[0] - ground_low[0];
+ ground_sz[1] = ground_upp[1] - ground_low[1];
+ ground_sz[2] = ground_upp[2] - ground_low[2];
/* Define the 2D index of the current ground instance. (0,0) is the index
* of the non instantiated ground */
- xy[0] = (int64_t)floor((query_pos[0] - ground->lower[0]) / ground_sz[0]);
- xy[1] = (int64_t)floor((query_pos[1] - ground->lower[1]) / ground_sz[1]);
+ xy[0] = (int64_t)floor((query_pos[0] - ground_low[0]) / ground_sz[0]);
+ xy[1] = (int64_t)floor((query_pos[1] - ground_low[1]) / ground_sz[1]);
/* Define the translation along the X and Y axis from world space to local
* ground geometry space */
- translation[0] = -(float)xy[0] * ground_sz[0];
- translation[1] = -(float)xy[1] * ground_sz[1];
+ translation[0] = -(double)xy[0] * ground_sz[0];
+ translation[1] = -(double)xy[1] * ground_sz[1];
/* Transform the query pos in local ground geometry space */
query_pos[0] += translation[0];
query_pos[1] += translation[1];
}
- /* Closest point query */
- res = s3d_scene_view_closest_point
- (ground->view, query_pos, query_radius, NULL, hit);
- if(res != RES_OK) {
- htrdr_log_err(ground->htrdr,
- "%s: could not query the closest point to the ground geometry -- %s.\n",
- FUNC_NAME, res_to_cstr(res));
- goto error;
- }
+ res = htrdr_geometry_find_closest_point
+ (ground->geom, query_pos, query_radius, hit);
+ if(res != RES_OK) goto error;
exit:
return res;
diff --git a/src/core/htrdr_geometry.c b/src/core/htrdr_geometry.c
@@ -0,0 +1,686 @@
+/* Copyright (C) 2018, 2019, 2020, 2021 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018, 2019, 2021 CNRS
+ * Copyright (C) 2018, 2019 Université Paul Sabatier
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#define _POSIX_C_SOURCE 200112L /* strtok_r support */
+
+#include "core/htrdr.h"
+#include "core/htrdr_geometry.h"
+#include "core/htrdr_interface.h"
+#include "core/htrdr_log.h"
+#include "core/htrdr_materials.h"
+#include "core/htrdr_slab.h"
+
+#include <aw.h>
+#include <star/s3d.h>
+
+#include <rsys/clock_time.h>
+#include <rsys/cstr.h>
+#include <rsys/dynamic_array_double.h>
+#include <rsys/dynamic_array_size_t.h>
+#include <rsys/double2.h>
+#include <rsys/double3.h>
+#include <rsys/float2.h>
+#include <rsys/float3.h>
+#include <rsys/hash_table.h>
+#include <rsys/ref_count.h>
+
+#include <string.h> /* strtok_r */
+
+/* Define the hash table that maps an Obj vertex id to its position into the
+ * vertex buffer */
+#define HTABLE_NAME vertex
+#define HTABLE_KEY size_t /* Obj vertex id */
+#define HTABLE_DATA size_t
+#include <rsys/hash_table.h>
+
+/* Define the hash table that maps the Star-3D shape id to its interface */
+#define HTABLE_NAME interface
+#define HTABLE_KEY unsigned /* Star-3D shape id */
+#define HTABLE_DATA struct htrdr_interface
+#include <rsys/hash_table.h>
+
+struct mesh {
+ const struct darray_double* positions;
+ const struct darray_size_t* indices;
+};
+static const struct mesh MESH_NULL;
+
+struct ray_context {
+ float range[2];
+ struct s3d_hit hit_prev;
+};
+#define RAY_CONTEXT_NULL__ {{0,INF}, S3D_HIT_NULL__}
+static const struct ray_context RAY_CONTEXT_NULL = RAY_CONTEXT_NULL__;
+
+struct htrdr_geometry {
+ struct s3d_scene_view* view;
+ float lower[3]; /* Ground lower bound */
+ float upper[3]; /* Ground upper bound */
+ int repeat; /* Make the geom infinite in X and Y */
+
+ struct htable_interface interfaces; /* Map a Star3D shape to its interface */
+
+ struct htrdr* htrdr;
+ ref_T ref;
+};
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+/* Check that `hit' roughly lies on an edge. For triangular primitives, a
+ * simple but approximative way is to test that its position have at least one
+ * barycentric coordinate roughly equal to 0 or 1. */
+static FINLINE int
+hit_on_edge(const struct s3d_hit* hit)
+{
+ const float on_edge_eps = 1.e-4f;
+ float w;
+ ASSERT(hit && !S3D_HIT_NONE(hit));
+ w = 1.f - hit->uv[0] - hit->uv[1];
+ return eq_epsf(hit->uv[0], 0.f, on_edge_eps)
+ || eq_epsf(hit->uv[0], 1.f, on_edge_eps)
+ || eq_epsf(hit->uv[1], 0.f, on_edge_eps)
+ || eq_epsf(hit->uv[1], 1.f, on_edge_eps)
+ || eq_epsf(w, 0.f, on_edge_eps)
+ || eq_epsf(w, 1.f, on_edge_eps);
+}
+
+static int
+geometry_filter
+ (const struct s3d_hit* hit,
+ const float ray_org[3],
+ const float ray_dir[3],
+ void* ray_data,
+ void* filter_data)
+{
+ const struct ray_context* ray_ctx = ray_data;
+ (void)ray_org, (void)ray_dir, (void)filter_data;
+
+ if(!ray_ctx) return 0;
+
+ if(S3D_PRIMITIVE_EQ(&hit->prim, &ray_ctx->hit_prev.prim)) return 1;
+
+ if(!S3D_HIT_NONE(&ray_ctx->hit_prev) && eq_epsf(hit->distance, 0, 1.e-1f)) {
+ /* If the targeted point is near of the origin, check that it lies on an
+ * edge/vertex shared by the 2 primitives. */
+ return hit_on_edge(&ray_ctx->hit_prev) && hit_on_edge(hit);
+ }
+
+ return hit->distance <= ray_ctx->range[0]
+ || hit->distance >= ray_ctx->range[1];
+}
+
+static res_T
+parse_shape_interface
+ (struct htrdr* htrdr,
+ struct htrdr_materials* mats,
+ const char* name,
+ struct htrdr_interface* interf)
+{
+ struct str str;
+ char* mtl_name0 = NULL;
+ char* mtl_name1 = NULL;
+ char* mtl_name2 = NULL;
+ char* mtl_name_front = NULL;
+ char* mtl_name_thin = NULL;
+ char* mtl_name_back = NULL;
+ char* tk_ctx = NULL;
+ int has_front = 0;
+ int has_thin = 0;
+ int has_back = 0;
+ res_T res = RES_OK;
+ ASSERT(htrdr && mats && name && interf);
+
+ str_init(htrdr_get_allocator(htrdr), &str);
+
+ /* Locally copy the string to parse */
+ res = str_set(&str, name);
+ if(res != RES_OK) {
+ htrdr_log_err(htrdr,
+ "Could not locally copy the shape material string `%s' -- %s.\n",
+ name, res_to_cstr(res));
+ goto error;
+ }
+
+ /* Reset the interface */
+ memset(interf, 0, sizeof(*interf));
+
+ /* Parse the name of the front/back/thin materials */
+ mtl_name0 = strtok_r(str_get(&str), ":", &tk_ctx);
+ mtl_name1 = strtok_r(NULL, ":", &tk_ctx);
+ mtl_name2 = strtok_r(NULL, ":", &tk_ctx);
+ ASSERT(mtl_name0); /* This can't be NULL */
+ mtl_name_front = mtl_name0;
+ if(mtl_name2) {
+ mtl_name_thin = mtl_name1;
+ mtl_name_back = mtl_name2;
+ } else {
+ mtl_name_thin = NULL;
+ mtl_name_back = mtl_name1;
+ }
+
+ if(!mtl_name_back) {
+ htrdr_log_err(htrdr,
+ "The back material name is missing `%s'.\n", name);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Fetch the interface material if any */
+ if(mtl_name_thin) {
+ has_thin = htrdr_materials_find_mtl(mats, mtl_name_thin, &interf->mtl_thin);
+ if(!has_thin) {
+ htrdr_log_err(htrdr,
+ "Invalid interface `%s'. The interface material `%s' is unknown.\n",
+ name, mtl_name_thin);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+ /* Fetch the front material */
+ has_front = htrdr_materials_find_mtl(mats, mtl_name_front, &interf->mtl_front);
+ if(!has_front) {
+ htrdr_log_err(htrdr,
+ "Invalid interface `%s'. The front material `%s' is unknown.\n",
+ name, mtl_name_front);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Fetch the back material */
+ has_back = htrdr_materials_find_mtl(mats, mtl_name_back, &interf->mtl_back);
+ if(!has_back) {
+ htrdr_log_err(htrdr,
+ "Invalid interface `%s'. The back material `%s' is unknown.\n",
+ name, mtl_name_back);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ str_release(&str);
+ return res;
+error:
+ *interf = HTRDR_INTERFACE_NULL;
+ goto exit;
+}
+
+static res_T
+setup_mesh
+ (struct htrdr* htrdr,
+ const char* filename,
+ struct aw_obj* obj,
+ struct aw_obj_named_group* mtl,
+ struct darray_double* positions,
+ struct darray_size_t* indices,
+ struct htable_vertex* vertices) /* Scratch data structure */
+{
+ size_t iface;
+ res_T res = RES_OK;
+ ASSERT(htrdr && filename && obj && mtl && positions && indices && vertices);
+
+ darray_double_clear(positions);
+ darray_size_t_clear(indices);
+ htable_vertex_clear(vertices);
+
+ FOR_EACH(iface, mtl->face_id, mtl->face_id+mtl->faces_count) {
+ struct aw_obj_face face;
+ size_t ivertex;
+
+ AW(obj_get_face(obj, iface, &face));
+ if(face.vertices_count != 3) {
+ htrdr_log_err(htrdr,
+ "The obj `%s' has non-triangulated polygons "
+ "while currently only triangular meshes are supported.\n",
+ filename);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ FOR_EACH(ivertex, 0, face.vertices_count) {
+ struct aw_obj_vertex vertex;
+ size_t id;
+ size_t* pid;
+
+ AW(obj_get_vertex(obj, face.vertex_id + ivertex, &vertex));
+ pid = htable_vertex_find(vertices, &vertex.position_id);
+ if(pid) {
+ id = *pid;
+ } else {
+ struct aw_obj_vertex_data vdata;
+
+ id = darray_double_size_get(positions) / 3;
+
+ res = darray_double_resize(positions, id*3 + 3);
+ if(res != RES_OK) {
+ htrdr_log_err(htrdr,
+ "Could not locally copy the vertex position -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+ AW(obj_get_vertex_data(obj, &vertex, &vdata));
+ darray_double_data_get(positions)[id*3+0] = vdata.position[0];
+ darray_double_data_get(positions)[id*3+1] = vdata.position[1];
+ darray_double_data_get(positions)[id*3+2] = vdata.position[2];
+
+ res = htable_vertex_set(vertices, &vertex.position_id, &id);
+ if(res != RES_OK) {
+ htrdr_log_err(htrdr,
+ "Could not register the vertex position -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+ }
+
+ res = darray_size_t_push_back(indices, &id);
+ if(res != RES_OK) {
+ htrdr_log_err(htrdr,
+ "Could not locally copy the face index -- %s\n",
+ res_to_cstr(res));
+ goto error;
+ }
+ }
+ }
+exit:
+ return res;
+error:
+ darray_double_clear(positions);
+ darray_size_t_clear(indices);
+ htable_vertex_clear(vertices);
+ goto exit;
+}
+
+static void
+get_position(const unsigned ivert, float position[3], void* ctx)
+{
+ const struct mesh* mesh = ctx;
+ const double* pos = NULL;
+ ASSERT(mesh);
+ ASSERT(ivert < darray_double_size_get(mesh->positions) / 3);
+ pos = darray_double_cdata_get(mesh->positions) + ivert*3;
+ position[0] = (float)pos[0];
+ position[1] = (float)pos[1];
+ position[2] = (float)pos[2];
+}
+
+static void
+get_indices(const unsigned itri, unsigned indices[3], void* ctx)
+{
+ const struct mesh* mesh = ctx;
+ const size_t* ids = NULL;
+ ASSERT(mesh);
+ ASSERT(itri < darray_size_t_size_get(mesh->indices) / 3);
+ ids = darray_size_t_cdata_get(mesh->indices) + itri*3;
+ indices[0] = (unsigned)ids[0];
+ indices[1] = (unsigned)ids[1];
+ indices[2] = (unsigned)ids[2];
+}
+
+static res_T
+create_s3d_shape
+ (struct htrdr* htrdr,
+ const struct darray_double* positions,
+ const struct darray_size_t* indices,
+ struct s3d_shape** out_shape)
+{
+ struct s3d_shape* shape = NULL;
+ struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL;
+ struct mesh mesh = MESH_NULL;
+ res_T res = RES_OK;
+ ASSERT(htrdr && positions && indices && out_shape);
+ ASSERT(darray_double_size_get(positions) != 0);
+ ASSERT(darray_size_t_size_get(indices) != 0);
+ ASSERT(darray_double_size_get(positions)%3 == 0);
+ ASSERT(darray_size_t_size_get(indices)%3 == 0);
+
+ mesh.positions = positions;
+ mesh.indices = indices;
+
+ res = s3d_shape_create_mesh(htrdr_get_s3d(htrdr), &shape);
+ if(res != RES_OK) {
+ htrdr_log_err(htrdr, "Error creating a Star-3D shape -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+ vdata.usage = S3D_POSITION;
+ vdata.type = S3D_FLOAT3;
+ vdata.get = get_position;
+
+ res = s3d_mesh_setup_indexed_vertices
+ (shape,
+ (unsigned int)(darray_size_t_size_get(indices)/3),
+ get_indices,
+ (unsigned int)(darray_double_size_get(positions)/3),
+ &vdata, 1,
+ &mesh);
+ if(res != RES_OK){
+ htrdr_log_err(htrdr, "Could not setup the Star-3D shape -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+ res = s3d_mesh_set_hit_filter_function(shape, geometry_filter, NULL);
+ if(res != RES_OK) {
+ htrdr_log_err(htrdr,
+ "Could not setup the Star-3D hit filter function of the geometry "
+ "-- %s.\n", res_to_cstr(res));
+ goto error;
+ }
+
+exit:
+ *out_shape = shape;
+ return res;
+error:
+ if(shape) {
+ S3D(shape_ref_put(shape));
+ shape = NULL;
+ }
+ goto exit;
+}
+
+static res_T
+setup_geometry
+ (struct htrdr_geometry* geom,
+ struct htrdr_materials* mats,
+ const char* obj_filename)
+{
+ struct aw_obj_desc desc;
+ struct htable_vertex vertices;
+ struct darray_double positions;
+ struct darray_size_t indices;
+ struct aw_obj* obj = NULL;
+ struct s3d_shape* shape = NULL;
+ struct s3d_scene* scene = NULL;
+ size_t iusemtl;
+
+ res_T res = RES_OK;
+ ASSERT(geom && mats && obj_filename);
+
+ htable_vertex_init(htrdr_get_allocator(geom->htrdr), &vertices);
+ darray_double_init(htrdr_get_allocator(geom->htrdr), &positions);
+ darray_size_t_init(htrdr_get_allocator(geom->htrdr), &indices);
+
+ res = aw_obj_create
+ (htrdr_get_logger(geom->htrdr),
+ htrdr_get_allocator(geom->htrdr),
+ htrdr_get_verbosity_level(geom->htrdr),
+ &obj);
+ if(res != RES_OK) {
+ htrdr_log_err(geom->htrdr, "Could not create the obj loader -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+ res = s3d_scene_create(htrdr_get_s3d(geom->htrdr), &scene);
+ if(res != RES_OK) {
+ htrdr_log_err(geom->htrdr, "Could not create the Star-3D scene -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+ /* Load the geometry data */
+ res = aw_obj_load(obj, obj_filename);
+ if(res != RES_OK) goto error;
+
+ /* Fetch the descriptor of the loaded geometry */
+ AW(obj_get_desc(obj, &desc));
+
+ if(desc.usemtls_count == 0) {
+ htrdr_log_err(geom->htrdr, "The obj `%s' has no material.\n", obj_filename);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Setup the geometry */
+ FOR_EACH(iusemtl, 0, desc.usemtls_count) {
+ struct aw_obj_named_group mtl;
+ struct htrdr_interface interf;
+ unsigned ishape;
+
+ AW(obj_get_mtl(obj, iusemtl , &mtl));
+
+ res = parse_shape_interface(geom->htrdr, mats, mtl.name, &interf);
+ if(res != RES_OK) goto error;
+
+ res = setup_mesh
+ (geom->htrdr, obj_filename, obj, &mtl, &positions, &indices, &vertices);
+ if(res != RES_OK) goto error;
+
+ res = create_s3d_shape(geom->htrdr, &positions, &indices, &shape);
+ if(res != RES_OK) goto error;
+
+ S3D(shape_get_id(shape, &ishape));
+ res = htable_interface_set(&geom->interfaces, &ishape, &interf);
+ if(res != RES_OK) {
+ htrdr_log_err(geom->htrdr,
+ "Could not map the Star-3D shape to its Star-Materials -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+ res = s3d_scene_attach_shape(scene, shape);
+ if(res != RES_OK) {
+ htrdr_log_err(geom->htrdr,
+ "Could not attach a Star-3D shape to the Star-3D scene -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+ S3D(shape_ref_put(shape));
+ shape = NULL;
+ }
+
+ res = s3d_scene_view_create(scene, S3D_GET_PRIMITIVE|S3D_TRACE, &geom->view);
+ if(res != RES_OK) {
+ htrdr_log_err(geom->htrdr,
+ "Could not create the Star-3D scene view -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+ res = s3d_scene_view_get_aabb(geom->view, geom->lower, geom->upper);
+ if(res != RES_OK) {
+ htrdr_log_err(geom->htrdr,
+ "Could not get the bounding box of the geometry -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+
+exit:
+ if(obj) AW(obj_ref_put(obj));
+ if(shape) S3D(shape_ref_put(shape));
+ if(scene) S3D(scene_ref_put(scene));
+ htable_vertex_release(&vertices);
+ darray_double_release(&positions);
+ darray_size_t_release(&indices);
+ return res;
+error:
+ goto exit;
+}
+
+static void
+release_ground(ref_T* ref)
+{
+ struct htrdr_geometry* geom;
+ struct htrdr* htrdr;
+ ASSERT(ref);
+ geom = CONTAINER_OF(ref, struct htrdr_geometry, ref);
+ if(geom->view) S3D(scene_view_ref_put(geom->view));
+ htable_interface_release(&geom->interfaces);
+ htrdr = geom->htrdr;
+ MEM_RM(htrdr_get_allocator(geom->htrdr), geom);
+ htrdr_ref_put(htrdr);
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+htrdr_geometry_create
+ (struct htrdr* htrdr,
+ const char* obj_filename, /* May be NULL */
+ struct htrdr_materials* mats,
+ struct htrdr_geometry** out_ground)
+{
+ char buf[128];
+ struct htrdr_geometry* geom = NULL;
+ struct time t0, t1;
+ res_T res = RES_OK;
+ ASSERT(htrdr && obj_filename && mats && out_ground);
+
+ geom = MEM_CALLOC(htrdr_get_allocator(htrdr), 1, sizeof(*geom));
+ if(!geom) {
+ res = RES_MEM_ERR;
+ htrdr_log_err(htrdr,
+ "%s: could not allocate the geom data structure -- %s.\n",
+ FUNC_NAME, res_to_cstr(res));
+ goto error;
+ }
+ ref_init(&geom->ref);
+ f3_splat(geom->lower, (float)INF);
+ f3_splat(geom->upper,-(float)INF);
+ htable_interface_init(htrdr_get_allocator(htrdr), &geom->interfaces);
+ htrdr_ref_get(htrdr);
+ geom->htrdr = htrdr;
+
+ htrdr_log(geom->htrdr, "Loading geometry from `%s'.\n", obj_filename);
+ time_current(&t0);
+ res = setup_geometry(geom, mats, obj_filename);
+ if(res != RES_OK) goto error;
+ time_sub(&t0, time_current(&t1), &t0);
+ time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf));
+ htrdr_log(geom->htrdr, "Setup geom in %s\n", buf);
+
+exit:
+ *out_ground = geom;
+ return res;
+error:
+ if(geom) {
+ htrdr_geometry_ref_put(geom);
+ geom = NULL;
+ }
+ goto exit;
+}
+
+void
+htrdr_geometry_ref_get(struct htrdr_geometry* geom)
+{
+ ASSERT(geom);
+ ref_get(&geom->ref);
+}
+
+void
+htrdr_geometry_ref_put(struct htrdr_geometry* geom)
+{
+ ASSERT(geom);
+ ref_put(&geom->ref, release_ground);
+}
+
+void
+htrdr_geometry_get_interface
+ (struct htrdr_geometry* geom,
+ const struct s3d_hit* hit,
+ struct htrdr_interface* out_interface)
+{
+ struct htrdr_interface* interf = NULL;
+ ASSERT(geom && hit && out_interface);
+
+ interf = htable_interface_find(&geom->interfaces, &hit->prim.geom_id);
+ ASSERT(interf);
+
+ *out_interface = *interf;
+}
+
+res_T
+htrdr_geometry_trace_ray
+ (struct htrdr_geometry* geom,
+ const double org[3],
+ const double dir[3], /* Must be normalized */
+ const double range[2],
+ const struct s3d_hit* prev_hit,
+ struct s3d_hit* hit)
+{
+ struct ray_context ray_ctx = RAY_CONTEXT_NULL;
+ float ray_org[3];
+ float ray_dir[3];
+ res_T res = RES_OK;
+ ASSERT(geom && org && dir && range && hit);
+
+ f3_set_d3(ray_org, org);
+ f3_set_d3(ray_dir, dir);
+ f2_set_d2(ray_ctx.range, range);
+ ray_ctx.hit_prev = prev_hit ? *prev_hit : S3D_HIT_NULL;
+
+ res = s3d_scene_view_trace_ray
+ (geom->view, ray_org, ray_dir, ray_ctx.range, &ray_ctx, hit);
+ if(res != RES_OK) {
+ htrdr_log_err(geom->htrdr,
+ "%s: could not trace the ray against the geometry -- %s.\n",
+ FUNC_NAME, res_to_cstr(res));
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+htrdr_geometry_find_closest_point
+ (struct htrdr_geometry* geom,
+ const double pos[3],
+ const double radius,
+ struct s3d_hit* hit)
+{
+ float query_pos[3];
+ float query_radius;
+ res_T res = RES_OK;
+ ASSERT(geom && pos && hit);
+
+ query_radius = (float)radius;
+ f3_set_d3(query_pos, pos);
+
+ /* Closest point query */
+ res = s3d_scene_view_closest_point
+ (geom->view, query_pos, query_radius, NULL, hit);
+ if(res != RES_OK) {
+ htrdr_log_err(geom->htrdr,
+ "%s: could not query the closest point to the geometry -- %s.\n",
+ FUNC_NAME, res_to_cstr(res));
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+void
+htrdr_geometry_get_aabb
+ (const struct htrdr_geometry* geom,
+ double lower[3],
+ double upper[3])
+{
+ ASSERT(geom && lower && upper);
+ d3_set_f3(lower, geom->lower);
+ d3_set_f3(upper, geom->upper);
+}
diff --git a/src/core/htrdr_geometry.h b/src/core/htrdr_geometry.h
@@ -0,0 +1,90 @@
+/* Copyright (C) 2018, 2019, 2020, 2021 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018, 2019, 2021 CNRS
+ * Copyright (C) 2018, 2019 Université Paul Sabatier
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef HTRDR_GEOMETRY_H
+#define HTRDR_GEOMETRY_H
+
+#include "core/htrdr.h"
+
+/* Forware declarations */
+struct htrdr;
+struct htrdr_geometry;
+struct htrdr_interface;
+struct htrdr_materials;
+struct s3d_hit;
+struct ssf_bsdf;
+
+BEGIN_DECLS
+
+HTRDR_CORE_API res_T
+htrdr_geometry_create
+ (struct htrdr* htrdr,
+ const char* obj_filename,
+ struct htrdr_materials* mats, /* Library of materials */
+ struct htrdr_geometry** geometry);
+
+HTRDR_CORE_API void
+htrdr_geometry_ref_get
+ (struct htrdr_geometry* geom);
+
+HTRDR_CORE_API void
+htrdr_geometry_ref_put
+ (struct htrdr_geometry* geom);
+
+HTRDR_CORE_API void
+htrdr_geometry_get_interface
+ (struct htrdr_geometry* geom,
+ const struct s3d_hit* hit,
+ struct htrdr_interface* interface);
+
+HTRDR_CORE_API res_T
+htrdr_geometry_create_bsdf
+ (struct htrdr_geometry* geom,
+ const size_t ithread,
+ const double wavelength,
+ const double pos[3],
+ const double dir[3], /* Incoming ray */
+ const struct s3d_hit* hit,
+ struct htrdr_interface* interf, /* NULL <=> do not return the interface */
+ struct ssf_bsdf** bsdf);
+
+HTRDR_CORE_API res_T
+htrdr_geometry_trace_ray
+ (struct htrdr_geometry* geom,
+ const double ray_origin[3],
+ const double ray_direction[3], /* Must be normalized */
+ const double ray_range[2],
+ const struct s3d_hit* prev_hit,/* Previous hit. Avoid self hit. May be NULL*/
+ struct s3d_hit* hit);
+
+HTRDR_CORE_API res_T
+htrdr_geometry_find_closest_point
+ (struct htrdr_geometry* geom,
+ const double position[3],
+ const double radius,
+ struct s3d_hit* hit);
+
+HTRDR_CORE_API void
+htrdr_geometry_get_aabb
+ (const struct htrdr_geometry* geom,
+ double lower[3],
+ double upper[3]);
+
+END_DECLS
+
+#endif /* HTRDR_GEOMETRY_H */
+