commit c1939428ea5f4a43ffb5708d6fbed14212a83ffd
parent 06c70c6a82b24504b8c347da0bb8730ef846ebb6
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Tue, 5 Jan 2021 17:43:43 +0100
Add a test on raytrace accuracy
Diffstat:
2 files changed, 207 insertions(+), 0 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -137,6 +137,7 @@ if(NOT NO_TEST)
new_test(test_s2d_closest_point)
new_test(test_s2d_device)
new_test(test_s2d_primitive)
+ new_test(test_s2d_raytrace)
new_test(test_s2d_sample)
new_test(test_s2d_shape)
new_test(test_s2d_scene)
diff --git a/src/test_s2d_raytrace.c b/src/test_s2d_raytrace.c
@@ -0,0 +1,206 @@
+/* Copyright (C) 2016-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * 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 "s2d.h"
+#include "test_s2d_utils.h"
+
+#include <rsys/float2.h>
+#include <rsys/float3.h>
+
+/*******************************************************************************
+ * Single segment test
+ ******************************************************************************/
+static void
+test_single_segment(struct s2d_device* dev)
+{
+ struct s2d_vertex_data vdata = S2D_VERTEX_DATA_NULL;
+ struct line_segments_desc desc;
+ struct s2d_hit hit = S2D_HIT_NULL;
+ struct s2d_hit hit3 = S2D_HIT_NULL;
+ struct s2d_scene* scn = NULL;
+ struct s2d_scene_view* view = NULL;
+ struct s2d_shape* shape = NULL;
+ struct s2d_attrib attr;
+ float vertices[4];
+ float v0[2], v1[2];
+ float pos[2];
+ size_t i, j;
+ unsigned indices[2] = {0, 1};
+
+ f2(vertices+0, -0.5f, -0.3f);
+ f2(vertices+2, -0.4f, 0.2f);
+
+ CHK(s2d_scene_create(dev, &scn) == RES_OK);
+ CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK);
+ CHK(s2d_scene_attach_shape(scn, shape) == RES_OK);
+
+ vdata.usage = S2D_POSITION;
+ vdata.type = S2D_FLOAT2;
+ vdata.get = line_segments_get_position;
+ desc.vertices = vertices;
+ desc.indices = indices;
+ CHK(s2d_line_segments_setup_indexed_vertices
+ (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK);
+
+ CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK);
+
+ line_segments_get_position(0, v0, &desc);
+ line_segments_get_position(1, v1, &desc);
+
+ CHK(s2d_scene_view_ref_put(view) == RES_OK);
+ CHK(s2d_shape_ref_put(shape) == RES_OK);
+ CHK(s2d_scene_ref_put(scn) == RES_OK);
+
+ FOR_EACH(i, 0, 100) {
+ float A[2], B[2], tmp[2];
+ const float amplitude = 10000;
+ const float eps = 1e-6f * amplitude;
+ /* Randomly generate a segment AB on the X axis */
+ A[0] = (rand_canonic() - 0.5f) * amplitude;
+ do B[0] = (rand_canonic() - 0.5f) * amplitude;
+ while(fabsf(A[0] - B[0]) < eps);
+ A[1] = B[1] = 0;
+
+ f2_set(vertices + 0, A);
+ f2_set(vertices + 2, B);
+
+ CHK(s2d_scene_create(dev, &scn) == RES_OK);
+ CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK);
+ CHK(s2d_scene_attach_shape(scn, shape) == RES_OK);
+
+ vdata.usage = S2D_POSITION;
+ vdata.type = S2D_FLOAT2;
+ vdata.get = line_segments_get_position;
+ desc.vertices = vertices;
+ desc.indices = indices;
+ CHK(s2d_line_segments_setup_indexed_vertices
+ (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK);
+
+ CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK);
+
+ FOR_EACH(j, 0, 100) {
+ float l;
+ float dir[3], range[2] = { 0, FLT_MAX };
+
+ /* Randomly generate a pos not on the segment */
+ pos[0] = (rand_canonic() - 0.5f) * amplitude;
+ do pos[1] = (rand_canonic() - 0.5f) * amplitude;
+ while (fabsf(pos[1]) < 1e-5);
+
+ /* Raytrace towards the X axis (can hit or miss the segment) */
+ f3(dir, 0, (pos[1] > 0 ? -1.f : 1.f), rand_canonic() - 0.5f);
+ CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit) == RES_OK);
+ l = f3_normalize(dir, dir);
+ CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit3) == RES_OK);
+
+ /* Check the result */
+ if((A[0] > pos[0] && B[0] > pos[0]) || (A[0] < pos[0] && B[0] < pos[0])) {
+ CHK(S2D_HIT_NONE(&hit));
+ CHK(S2D_HIT_NONE(&hit3));
+ } else {
+ float expected[2];
+ float d = f2_len(f2_sub(tmp, pos, expected));
+ f2(expected, pos[0], 0);
+ d = f2_len(f2_sub(tmp, pos, expected));
+ CHK(!S2D_HIT_NONE(&hit));
+ CHK(eq_epsf(hit.distance, d, eps));
+ CHK(eq_epsf(hit3.distance, d * l, eps));
+ CHK(s2d_primitive_get_attrib(&hit.prim, S2D_POSITION, hit.u, &attr) == RES_OK);
+ CHK(f2_eq_eps(attr.value, expected, eps));
+ CHK(s2d_primitive_get_attrib(&hit3.prim, S2D_POSITION, hit3.u, &attr) == RES_OK);
+ CHK(f2_eq_eps(attr.value, expected, eps));
+ }
+ }
+
+ CHK(s2d_scene_view_ref_put(view) == RES_OK);
+ CHK(s2d_shape_ref_put(shape) == RES_OK);
+ CHK(s2d_scene_ref_put(scn) == RES_OK);
+ }
+}
+
+/*******************************************************************************
+ * Miscellaneous test
+ ******************************************************************************/
+static void
+test_api(struct s2d_device* dev)
+{
+ struct s2d_hit hit = S2D_HIT_NULL;
+ struct s2d_scene* scn = NULL;
+ struct s2d_scene_view* view = NULL;
+ float pos[3] = { 0 }, dir[3] = { 1 }, range[2] = { 0, 1 };
+
+ CHK(s2d_scene_create(dev, &scn) == RES_OK);
+ CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK);
+
+ CHK(s2d_scene_view_trace_ray(NULL, pos, dir, range, NULL, &hit) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray(view, NULL, dir, range, NULL, &hit) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray(view, pos, NULL, range, NULL, &hit) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray(view, pos, dir, NULL, NULL, &hit) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, NULL) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit) == RES_OK);
+ CHK(S2D_HIT_NONE(&hit));
+
+ CHK(s2d_scene_view_trace_ray_3d(NULL, pos, dir, range, NULL, &hit) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray_3d(view, NULL, dir, range, NULL, &hit) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray_3d(view, pos, NULL, range, NULL, &hit) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, NULL, NULL, &hit) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, NULL) == RES_BAD_ARG);
+ CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit) == RES_OK);
+ CHK(S2D_HIT_NONE(&hit));
+
+ CHK(s2d_scene_view_ref_put(view) == RES_OK);
+ CHK(s2d_scene_view_create(scn, S2D_SAMPLE, &view) == RES_OK);
+ CHK(s2d_scene_view_closest_point(view, pos, 1.f, NULL, &hit) == RES_BAD_OP);
+
+ CHK(s2d_scene_view_ref_put(view) == RES_OK);
+ CHK(s2d_scene_ref_put(scn) == RES_OK);
+}
+
+/*******************************************************************************
+ * Main function
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct s2d_device* dev = NULL;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+ CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK);
+
+ test_api(dev);
+ test_single_segment(dev);
+
+ CHK(s2d_device_ref_put(dev) == RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}