test_s2d_raytrace.c (7825B)
1 /* Copyright (C) 2016-2021, 2023 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #define _POSIX_C_SOURCE 200112L /* nextafterf, exp2f, fabsf */ 17 18 #include "s2d.h" 19 #include "test_s2d_utils.h" 20 21 #include <rsys/float2.h> 22 #include <rsys/float3.h> 23 24 /******************************************************************************* 25 * Single segment test 26 ******************************************************************************/ 27 static void 28 test_single_segment(struct s2d_device* dev) 29 { 30 struct s2d_vertex_data vdata = S2D_VERTEX_DATA_NULL; 31 struct line_segments_desc desc; 32 struct s2d_hit hit = S2D_HIT_NULL; 33 struct s2d_hit hit3 = S2D_HIT_NULL; 34 struct s2d_scene* scn = NULL; 35 struct s2d_scene_view* view = NULL; 36 struct s2d_shape* shape = NULL; 37 struct s2d_attrib attr; 38 float vertices[4]; 39 float v0[2], v1[2]; 40 float pos[2]; 41 size_t a, i, j; 42 unsigned indices[2] = {0, 1}; 43 44 f2(vertices+0, -0.5f, -0.3f); 45 f2(vertices+2, -0.4f, 0.2f); 46 47 CHK(s2d_scene_create(dev, &scn) == RES_OK); 48 CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); 49 CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); 50 51 vdata.usage = S2D_POSITION; 52 vdata.type = S2D_FLOAT2; 53 vdata.get = line_segments_get_position; 54 desc.vertices = vertices; 55 desc.indices = indices; 56 CHK(s2d_line_segments_setup_indexed_vertices 57 (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK); 58 59 CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK); 60 61 line_segments_get_position(0, v0, &desc); 62 line_segments_get_position(1, v1, &desc); 63 64 CHK(s2d_scene_view_ref_put(view) == RES_OK); 65 CHK(s2d_shape_ref_put(shape) == RES_OK); 66 CHK(s2d_scene_ref_put(scn) == RES_OK); 67 68 /* Check accuracy on a configuration whose analytic distance is known */ 69 FOR_EACH(a, 0, 16) { 70 const float amplitude = exp2f((float)a); 71 const float eps = 1e-6f * amplitude; 72 FOR_EACH(i, 0, 1000) { 73 float A[2], B[2], AB[2], N[2]; 74 int n; 75 76 /* Randomly generate a segment AB */ 77 FOR_EACH(n, 0, 2) 78 A[n] = (rand_canonic() - 0.5f) * amplitude; 79 do { 80 FOR_EACH(n, 0, 2) B[n] = (rand_canonic() - 0.5f) * amplitude; 81 } while (f2_eq_eps(A, B, eps)); 82 83 f2_sub(AB, B, A); 84 f2(N, -AB[1], AB[0]); 85 f2_normalize(N, N); 86 87 f2_set(vertices + 0, A); 88 f2_set(vertices + 2, B); 89 90 CHK(s2d_scene_create(dev, &scn) == RES_OK); 91 CHK(s2d_shape_create_line_segments(dev, &shape) == RES_OK); 92 CHK(s2d_scene_attach_shape(scn, shape) == RES_OK); 93 94 vdata.usage = S2D_POSITION; 95 vdata.type = S2D_FLOAT2; 96 vdata.get = line_segments_get_position; 97 desc.vertices = vertices; 98 desc.indices = indices; 99 CHK(s2d_line_segments_setup_indexed_vertices 100 (shape, 1, line_segments_get_ids, 2, &vdata, 1, &desc) == RES_OK); 101 102 CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK); 103 104 FOR_EACH(j, 0, 1000) { 105 float proj[2]; /* Projection of pos on the line */ 106 float u, h, l; 107 float dir[3], range[2] = { 0, FLT_MAX }; 108 109 /* Randomly generate a pos not on the segment 110 * with know position wrt the problem: pos = A + u.AB + k.N */ 111 u = 1.2f * rand_canonic() - 0.1f; 112 h = (2 * rand_canonic() - 1) * amplitude; 113 f2_add(proj, A, f2_mulf(proj, AB, u)); 114 f2_add(pos, proj, f2_mulf(pos, N, h)); 115 116 /* Raytrace from pos towards proj */ 117 f2_mulf(dir, N, (h > 0 ? -1.f : 1.f)); 118 CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit) 119 == RES_OK); 120 dir[2] = rand_canonic() - 0.5f; 121 l = f3_normalize(dir, dir); 122 CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit3) 123 == RES_OK); 124 125 /* Check result */ 126 if(u < 0 || u > 1) { 127 if(!S2D_HIT_NONE(&hit) || !S2D_HIT_NONE(&hit3)) 128 CHK(u >= -FLT_EPSILON && u <= 1 + FLT_EPSILON); 129 } else { 130 if(S2D_HIT_NONE(&hit) || S2D_HIT_NONE(&hit3)) 131 CHK(u <= FLT_EPSILON || u >= 1 - FLT_EPSILON); 132 } 133 if(!S2D_HIT_NONE(&hit)) { 134 CHK(eq_epsf(hit.distance, fabsf(h), eps)); 135 CHK(s2d_primitive_get_attrib(&hit.prim, S2D_POSITION, hit.u, &attr) 136 == RES_OK); 137 CHK(f2_eq_eps(attr.value, proj, eps)); 138 } 139 if(!S2D_HIT_NONE(&hit3)) { 140 CHK(eq_epsf(hit3.distance, l * fabsf(h), eps)); 141 CHK(s2d_primitive_get_attrib(&hit3.prim, S2D_POSITION, hit3.u, &attr) 142 == RES_OK); 143 CHK(f2_eq_eps(attr.value, proj, eps)); 144 } 145 } 146 147 CHK(s2d_scene_view_ref_put(view) == RES_OK); 148 CHK(s2d_shape_ref_put(shape) == RES_OK); 149 CHK(s2d_scene_ref_put(scn) == RES_OK); 150 } 151 } 152 } 153 154 /******************************************************************************* 155 * Miscellaneous test 156 ******************************************************************************/ 157 static void 158 test_api(struct s2d_device* dev) 159 { 160 struct s2d_hit hit = S2D_HIT_NULL; 161 struct s2d_scene* scn = NULL; 162 struct s2d_scene_view* view = NULL; 163 float pos[3] = { 0 }, dir[3] = { 1 }, range[2] = { 0, 1 }; 164 165 CHK(s2d_scene_create(dev, &scn) == RES_OK); 166 CHK(s2d_scene_view_create(scn, S2D_TRACE, &view) == RES_OK); 167 168 CHK(s2d_scene_view_trace_ray(NULL, pos, dir, range, NULL, &hit) == RES_BAD_ARG); 169 CHK(s2d_scene_view_trace_ray(view, NULL, dir, range, NULL, &hit) == RES_BAD_ARG); 170 CHK(s2d_scene_view_trace_ray(view, pos, NULL, range, NULL, &hit) == RES_BAD_ARG); 171 CHK(s2d_scene_view_trace_ray(view, pos, dir, NULL, NULL, &hit) == RES_BAD_ARG); 172 CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, NULL) == RES_BAD_ARG); 173 CHK(s2d_scene_view_trace_ray(view, pos, dir, range, NULL, &hit) == RES_OK); 174 CHK(S2D_HIT_NONE(&hit)); 175 176 CHK(s2d_scene_view_trace_ray_3d(NULL, pos, dir, range, NULL, &hit) == RES_BAD_ARG); 177 CHK(s2d_scene_view_trace_ray_3d(view, NULL, dir, range, NULL, &hit) == RES_BAD_ARG); 178 CHK(s2d_scene_view_trace_ray_3d(view, pos, NULL, range, NULL, &hit) == RES_BAD_ARG); 179 CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, NULL, NULL, &hit) == RES_BAD_ARG); 180 CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, NULL) == RES_BAD_ARG); 181 CHK(s2d_scene_view_trace_ray_3d(view, pos, dir, range, NULL, &hit) == RES_OK); 182 CHK(S2D_HIT_NONE(&hit)); 183 184 CHK(s2d_scene_view_ref_put(view) == RES_OK); 185 CHK(s2d_scene_view_create(scn, S2D_SAMPLE, &view) == RES_OK); 186 CHK(s2d_scene_view_closest_point(view, pos, 1.f, NULL, &hit) == RES_BAD_OP); 187 188 CHK(s2d_scene_view_ref_put(view) == RES_OK); 189 CHK(s2d_scene_ref_put(scn) == RES_OK); 190 } 191 192 /******************************************************************************* 193 * Main function 194 ******************************************************************************/ 195 int 196 main(int argc, char** argv) 197 { 198 struct mem_allocator allocator; 199 struct s2d_device* dev = NULL; 200 (void)argc, (void)argv; 201 202 mem_init_proxy_allocator(&allocator, &mem_default_allocator); 203 CHK(s2d_device_create(NULL, &allocator, 1, &dev) == RES_OK); 204 205 test_api(dev); 206 test_single_segment(dev); 207 208 CHK(s2d_device_ref_put(dev) == RES_OK); 209 210 check_memory_allocator(&allocator); 211 mem_shutdown_proxy_allocator(&allocator); 212 CHK(mem_allocated_size() == 0); 213 return 0; 214 }