test_s3d_scene_view_aabb.c (16177B)
1 /* Copyright (C) 2015-2023, 2026 |Méso|Star> (contact@meso-star.com) 2 * 3 * This file is part of Star-3D. 4 * 5 * Star-3D is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * Star-3D is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with Star-3D. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include "s3d.h" 19 #include "test_s3d_utils.h" 20 #include "test_s3d_cbox.h" 21 22 #include <rsys/float3.h> 23 24 /******************************************************************************* 25 * Helper functions 26 ******************************************************************************/ 27 static void 28 compute_mesh_aabb 29 (const float* pos, 30 const size_t nverts, 31 const unsigned* ids, 32 const size_t ntris, 33 float low[3], 34 float upp[3]) 35 { 36 size_t i; 37 38 CHK(low && upp && pos && nverts && ids && ntris); 39 f3_splat(low, FLT_MAX); 40 f3_splat(upp,-FLT_MAX); 41 42 FOR_EACH(i, 0, ntris*3) { 43 const float* vertex = pos + ids[i]*3; 44 f3_min(low, vertex, low); 45 f3_max(upp, vertex, upp); 46 } 47 } 48 49 static int 50 aabb_is_degenerated(const float low[3], const float upp[3]) 51 { 52 CHK(low && upp); 53 return low[0] > upp[0] 54 && low[1] > upp[1] 55 && low[2] > upp[2]; 56 } 57 58 /******************************************************************************* 59 * Instances 60 ******************************************************************************/ 61 static void 62 test_instances(struct s3d_device* dev) 63 { 64 struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL; 65 struct s3d_scene* scn = NULL; 66 struct s3d_scene* scn2 = NULL; 67 struct s3d_scene_view* view = NULL; 68 struct s3d_shape* sphere = NULL; 69 struct s3d_shape* tall_block = NULL; 70 struct s3d_shape* inst0 = NULL; 71 struct s3d_shape* inst1 = NULL; 72 struct cbox_desc desc; 73 float low[3], upp[3]; 74 float scn_low[3], scn_upp[3]; 75 float scn2_low[3], scn2_upp[3]; 76 float inst0_low[3], inst0_upp[3]; 77 float inst1_low[3], inst1_upp[3]; 78 float tall_block_low[3], tall_block_upp[3]; 79 float sphere_low[3], sphere_upp[3]; 80 float inst0_trans[3]; 81 float inst1_trans[3]; 82 float pos[3]; 83 float radius; 84 85 /* Create the tall block shape*/ 86 vdata.usage = S3D_POSITION; 87 vdata.type = S3D_FLOAT3; 88 vdata.get = cbox_get_position; 89 desc.vertices = cbox_tall_block; 90 desc.indices = cbox_block_ids; 91 CHK(s3d_shape_create_mesh(dev, &tall_block) == RES_OK); 92 CHK(s3d_mesh_setup_indexed_vertices(tall_block, cbox_block_ntris, cbox_get_ids, 93 cbox_block_nverts, &vdata, 1, &desc) == RES_OK); 94 compute_mesh_aabb(cbox_tall_block, cbox_block_nverts, cbox_block_ids, 95 cbox_block_ntris, tall_block_low, tall_block_upp); 96 97 /* Create the sphere and ensure that it is not contained into the block */ 98 pos[0] = tall_block_low[0] - 10.f; 99 pos[1] = (tall_block_upp[1] + tall_block_low[1]) * 0.5f; 100 pos[2] = (tall_block_upp[2] + tall_block_low[2]) * 0.5f; 101 radius = 1.f; 102 CHK(s3d_shape_create_sphere(dev, &sphere) == RES_OK); 103 CHK(s3d_sphere_setup(sphere, pos, radius) == RES_OK); 104 f3_subf(sphere_low, pos, radius); 105 f3_addf(sphere_upp, pos, radius); 106 107 /* Create the scene to instantiate */ 108 CHK(s3d_scene_create(dev, &scn) == RES_OK); 109 CHK(s3d_scene_attach_shape(scn, sphere) == RES_OK); 110 CHK(s3d_scene_attach_shape(scn, tall_block) == RES_OK); 111 112 /* Compute the AABB of the original scene */ 113 f3_min(scn_low, tall_block_low, sphere_low); 114 f3_max(scn_upp, tall_block_upp, sphere_upp); 115 116 /* Create two instances */ 117 inst0_trans[0] = -100.f; 118 inst0_trans[1] = 0.f; 119 inst0_trans[2] = -50.f; 120 inst1_trans[0] = 123.f; 121 inst1_trans[1] = 4.56f; 122 inst1_trans[2] = 0.789f; 123 CHK(s3d_scene_instantiate(scn, &inst0) == RES_OK); 124 CHK(s3d_scene_instantiate(scn, &inst1) == RES_OK); 125 CHK(s3d_instance_translate(inst0, S3D_WORLD_TRANSFORM, inst0_trans) == RES_OK); 126 CHK(s3d_instance_translate(inst1, S3D_WORLD_TRANSFORM, inst1_trans) == RES_OK); 127 f3_add(inst0_low, scn_low, inst0_trans); 128 f3_add(inst0_upp, scn_upp, inst0_trans); 129 f3_add(inst1_low, scn_low, inst1_trans); 130 f3_add(inst1_upp, scn_upp, inst1_trans); 131 132 /* Create the scene with the 2 instances */ 133 CHK(s3d_scene_create(dev, &scn2) == RES_OK); 134 CHK(s3d_scene_attach_shape(scn2, inst0) == RES_OK); 135 CHK(s3d_scene_attach_shape(scn2, inst1) == RES_OK); 136 137 /* Compute the AABB of the scene with instances */ 138 f3_min(scn2_low, inst0_low, inst1_low); 139 f3_max(scn2_upp, inst0_upp, inst1_upp); 140 141 /* Original scene */ 142 CHK(s3d_scene_view_create(scn, 0, &view) == RES_OK); 143 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 144 CHK(f3_eq_eps(scn_low, low, 1.e-6f)); 145 CHK(f3_eq_eps(scn_upp, upp, 1.e-6f)); 146 CHK(s3d_scene_view_ref_put(view) == RES_OK); 147 148 /* Retry the original scene to test the cache mechanism */ 149 CHK(s3d_scene_view_create(scn, 0, &view) == RES_OK); 150 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 151 CHK(f3_eq_eps(scn_low, low, 1.e-6f)); 152 CHK(f3_eq_eps(scn_upp, upp, 1.e-6f)); 153 CHK(s3d_scene_view_ref_put(view) == RES_OK); 154 155 /* Scene with the 2 instances */ 156 CHK(s3d_scene_view_create(scn2, 0, &view) == RES_OK); 157 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 158 CHK(f3_eq_eps(scn2_low, low, 1.e-6f)); 159 CHK(f3_eq_eps(scn2_upp, upp, 1.e-6f)); 160 CHK(s3d_scene_view_ref_put(view) == RES_OK); 161 162 /* Retry the scene with the 2 instances to check the cache mechanism */ 163 CHK(s3d_scene_view_create(scn2, 0, &view) == RES_OK); 164 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 165 CHK(f3_eq_eps(scn2_low, low, 1.e-6f)); 166 CHK(f3_eq_eps(scn2_upp, upp, 1.e-6f)); 167 CHK(s3d_scene_view_ref_put(view) == RES_OK); 168 169 /* Scene with only one instance */ 170 CHK(s3d_shape_enable(inst0, 0) == RES_OK); 171 CHK(s3d_scene_view_create(scn2, 0, &view) == RES_OK); 172 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 173 CHK(f3_eq_eps(inst1_low, low, 1.e-6f)); 174 CHK(f3_eq_eps(inst1_upp, upp, 1.e-6f)); 175 CHK(s3d_scene_view_ref_put(view) == RES_OK); 176 177 /* Scene whose instances have only the tall_block */ 178 CHK(s3d_shape_enable(inst0, 1) == RES_OK); 179 CHK(s3d_shape_enable(sphere, 0) == RES_OK); 180 f3_add(inst0_low, tall_block_low, inst0_trans); 181 f3_add(inst0_upp, tall_block_upp, inst0_trans); 182 f3_add(inst1_low, tall_block_low, inst1_trans); 183 f3_add(inst1_upp, tall_block_upp, inst1_trans); 184 f3_min(scn2_low, inst0_low, inst1_low); 185 f3_max(scn2_upp, inst0_upp, inst1_upp); 186 CHK(s3d_scene_view_create(scn2, 0, &view) == RES_OK); 187 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 188 CHK(f3_eq_eps(scn2_low, low, 1.e-6f)); 189 CHK(f3_eq_eps(scn2_upp, upp, 1.e-6f)); 190 CHK(s3d_scene_view_ref_put(view) == RES_OK); 191 192 /* Scene with one instance, one mesh and one sphere */ 193 CHK(s3d_scene_detach_shape(scn2, inst1) == RES_OK); 194 CHK(s3d_scene_attach_shape(scn2, sphere) == RES_OK); 195 CHK(s3d_scene_attach_shape(scn2, tall_block) == RES_OK); 196 f3_min(scn2_low, f3_min(scn2_low, tall_block_low, sphere_low), inst0_low); 197 f3_max(scn2_upp, f3_max(scn2_upp, tall_block_upp, sphere_upp), inst0_upp); 198 CHK(s3d_scene_view_create(scn2, 0, &view) == RES_OK); 199 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 200 CHK(f3_eq_eps(scn2_low, low, 1.e-6f)); 201 CHK(f3_eq_eps(scn2_upp, upp, 1.e-6f)); 202 CHK(s3d_scene_view_ref_put(view) == RES_OK); 203 204 /* Clean up */ 205 CHK(s3d_scene_ref_put(scn) == RES_OK); 206 CHK(s3d_scene_ref_put(scn2) == RES_OK); 207 CHK(s3d_shape_ref_put(sphere) == RES_OK); 208 CHK(s3d_shape_ref_put(tall_block) == RES_OK); 209 CHK(s3d_shape_ref_put(inst0) == RES_OK); 210 CHK(s3d_shape_ref_put(inst1) == RES_OK); 211 } 212 213 /******************************************************************************* 214 * Cornell box 215 ******************************************************************************/ 216 static void 217 test_cbox(struct s3d_device* dev) 218 { 219 struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL; 220 struct s3d_scene* scn = NULL; 221 struct s3d_scene_view* view = NULL; 222 struct s3d_shape* walls = NULL; 223 struct s3d_shape* tall_block = NULL; 224 struct s3d_shape* short_block = NULL; 225 struct cbox_desc desc; 226 float low[3], upp[3]; 227 float walls_low[3], walls_upp[3]; 228 float tall_block_low[3], tall_block_upp[3]; 229 float short_block_low[3], short_block_upp[3]; 230 float aabb_low[3], aabb_upp[3]; 231 232 /* Create the Star-3D scene and the Cornell box meshes */ 233 CHK(s3d_scene_create(dev, &scn) == RES_OK); 234 CHK(s3d_shape_create_mesh(dev, &walls) == RES_OK); 235 CHK(s3d_shape_create_mesh(dev, &tall_block) == RES_OK); 236 CHK(s3d_shape_create_mesh(dev, &short_block) == RES_OK); 237 238 vdata.usage = S3D_POSITION; 239 vdata.type = S3D_FLOAT3; 240 vdata.get = cbox_get_position; 241 242 /* Setup the Cornell box walls */ 243 desc.vertices = cbox_walls; 244 desc.indices = cbox_walls_ids; 245 CHK(s3d_mesh_setup_indexed_vertices(walls, cbox_walls_ntris, cbox_get_ids, 246 cbox_walls_nverts, &vdata, 1, &desc) == RES_OK); 247 compute_mesh_aabb(cbox_walls, cbox_walls_nverts, cbox_walls_ids, 248 cbox_walls_ntris, walls_low, walls_upp); 249 250 /* Setup the Cornell box tall block */ 251 desc.vertices = cbox_tall_block; 252 desc.indices = cbox_block_ids; 253 CHK(s3d_mesh_setup_indexed_vertices(tall_block, cbox_block_ntris, cbox_get_ids, 254 cbox_block_nverts, &vdata, 1, &desc) == RES_OK); 255 compute_mesh_aabb(cbox_tall_block, cbox_block_nverts, cbox_block_ids, 256 cbox_block_ntris, tall_block_low, tall_block_upp); 257 258 /* Setup the Cornell box short block */ 259 desc.vertices = cbox_short_block; 260 desc.indices = cbox_block_ids; 261 CHK(s3d_mesh_setup_indexed_vertices(short_block, cbox_block_ntris, cbox_get_ids, 262 cbox_block_nverts, &vdata, 1, &desc) == RES_OK); 263 compute_mesh_aabb(cbox_short_block, cbox_block_nverts, cbox_block_ids, 264 cbox_block_ntris, short_block_low, short_block_upp); 265 266 /* Tall block only */ 267 CHK(s3d_scene_attach_shape(scn, tall_block) == RES_OK); 268 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 269 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 270 CHK(f3_eq_eps(tall_block_low, low, 1.e-6f)); 271 CHK(f3_eq_eps(tall_block_upp, upp, 1.e-6f)); 272 CHK(s3d_scene_view_ref_put(view) == RES_OK); 273 274 /* Disabled tall block only */ 275 CHK(s3d_shape_enable(tall_block, 0) == RES_OK); 276 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 277 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 278 CHK(aabb_is_degenerated(low, upp)); 279 CHK(s3d_scene_view_ref_put(view) == RES_OK); 280 281 /* Tall block only with wo S3D_TRACE flag */ 282 CHK(s3d_shape_enable(tall_block, 1) == RES_OK); 283 CHK(s3d_scene_view_create(scn, 0, &view) == RES_OK); 284 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 285 CHK(f3_eq_eps(tall_block_low, low, 1.e-6f)); 286 CHK(f3_eq_eps(tall_block_upp, upp, 1.e-6f)); 287 CHK(s3d_scene_view_ref_put(view) == RES_OK); 288 289 /* All blocks */ 290 CHK(s3d_scene_attach_shape(scn, short_block) == RES_OK); 291 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 292 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 293 f3_min(aabb_low, tall_block_low, short_block_low); 294 f3_max(aabb_upp, tall_block_upp, short_block_upp); 295 CHK(f3_eq_eps(aabb_low, low, 1.e-6f)); 296 CHK(f3_eq_eps(aabb_upp, upp, 1.e-6f)); 297 CHK(s3d_scene_view_ref_put(view) == RES_OK); 298 299 /* Another try with all blocks to check the cache mechanism */ 300 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 301 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 302 CHK(f3_eq_eps(aabb_low, low, 1.e-6f)); 303 CHK(f3_eq_eps(aabb_upp, upp, 1.e-6f)); 304 CHK(s3d_scene_view_ref_put(view) == RES_OK); 305 306 /* All blocks but the tall block is disabled */ 307 CHK(s3d_shape_enable(tall_block, 0) == RES_OK); 308 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 309 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 310 CHK(f3_eq_eps(short_block_low, low, 1.e-6f)); 311 CHK(f3_eq_eps(short_block_upp, upp, 1.e-6f)); 312 CHK(s3d_scene_view_ref_put(view) == RES_OK); 313 314 /* All blocks but the short block is disabled */ 315 CHK(s3d_shape_enable(tall_block, 1) == RES_OK); 316 CHK(s3d_shape_enable(short_block, 0) == RES_OK); 317 CHK(s3d_scene_view_create(scn, 0, &view) == RES_OK); 318 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 319 CHK(f3_eq_eps(tall_block_low, low, 1.e-6f)); 320 CHK(f3_eq_eps(tall_block_upp, upp, 1.e-6f)); 321 CHK(s3d_scene_view_ref_put(view) == RES_OK); 322 323 /* The whole Cornell box */ 324 CHK(s3d_shape_enable(short_block, 1) == RES_OK); 325 CHK(s3d_scene_attach_shape(scn, walls) == RES_OK); 326 CHK(s3d_scene_view_create(scn, 0, &view) == RES_OK); 327 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 328 f3_min(aabb_low, f3_min(aabb_low, tall_block_low, short_block_low), walls_low); 329 f3_max(aabb_upp, f3_max(aabb_upp, tall_block_upp, short_block_upp), walls_upp); 330 CHK(f3_eq_eps(aabb_low, low, 1.e-6f)); 331 CHK(f3_eq_eps(aabb_upp, upp, 1.e-6f)); 332 CHK(s3d_scene_view_ref_put(view) == RES_OK); 333 334 /* Retry the whole Cornell box */ 335 CHK(s3d_scene_view_create(scn, 0, &view) == RES_OK); 336 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 337 CHK(f3_eq_eps(aabb_low, low, 1.e-6f)); 338 CHK(f3_eq_eps(aabb_upp, upp, 1.e-6f)); 339 CHK(s3d_scene_view_ref_put(view) == RES_OK); 340 341 /* Disable all */ 342 CHK(s3d_shape_enable(walls, 0) == RES_OK); 343 CHK(s3d_shape_enable(tall_block, 0) == RES_OK); 344 CHK(s3d_shape_enable(short_block, 0) == RES_OK); 345 CHK(s3d_scene_view_create(scn, 0, &view) == RES_OK); 346 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 347 CHK(aabb_is_degenerated(low, upp)); 348 CHK(s3d_scene_view_ref_put(view) == RES_OK); 349 350 /* Only the short block */ 351 CHK(s3d_shape_enable(walls, 1) == RES_OK); 352 CHK(s3d_shape_enable(tall_block, 1) == RES_OK); 353 CHK(s3d_shape_enable(short_block, 1) == RES_OK); 354 CHK(s3d_scene_detach_shape(scn, walls) == RES_OK); 355 CHK(s3d_scene_detach_shape(scn, tall_block) == RES_OK); 356 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 357 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 358 CHK(f3_eq_eps(short_block_low, low, 1.e-6f)); 359 CHK(f3_eq_eps(short_block_upp, upp, 1.e-6f)); 360 CHK(s3d_scene_view_ref_put(view) == RES_OK); 361 362 /* Only the short block */ 363 CHK(s3d_scene_clear(scn) == RES_OK); 364 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 365 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 366 CHK(aabb_is_degenerated(low, upp)); 367 CHK(s3d_scene_view_ref_put(view) == RES_OK); 368 369 /* Clean up the data */ 370 CHK(s3d_scene_ref_put(scn) == RES_OK); 371 CHK(s3d_shape_ref_put(walls) == RES_OK); 372 CHK(s3d_shape_ref_put(tall_block) == RES_OK); 373 CHK(s3d_shape_ref_put(short_block) == RES_OK); 374 } 375 376 /******************************************************************************* 377 * Test the API 378 ******************************************************************************/ 379 static void 380 test_api(struct s3d_device* dev) 381 { 382 struct s3d_scene* scn = NULL; 383 struct s3d_scene_view* view = NULL; 384 float low[3] = {0,0,0}; 385 float upp[3] = {0,0,0}; 386 387 CHK(s3d_scene_create(dev, &scn) == RES_OK); 388 CHK(s3d_scene_view_create(scn, 0, &view) == RES_OK); 389 390 CHK(s3d_scene_view_get_aabb(NULL, low, upp) == RES_BAD_ARG); 391 CHK(s3d_scene_view_get_aabb(view, NULL, upp) == RES_BAD_ARG); 392 CHK(s3d_scene_view_get_aabb(view, low, NULL) == RES_BAD_ARG); 393 CHK(s3d_scene_view_get_aabb(view, low, upp) == RES_OK); 394 CHK(aabb_is_degenerated(low, upp)); 395 396 CHK(s3d_scene_view_ref_put(view) == RES_OK); 397 CHK(s3d_scene_ref_put(scn) == RES_OK); 398 } 399 400 /******************************************************************************* 401 * Main function 402 ******************************************************************************/ 403 int 404 main(int argc, char** argv) 405 { 406 struct mem_allocator allocator; 407 struct s3d_device* dev = NULL; 408 (void)argc, (void)argv; 409 410 mem_init_proxy_allocator(&allocator, &mem_default_allocator); 411 CHK(s3d_device_create(NULL, &allocator, 1, &dev) == RES_OK); 412 413 test_api(dev); 414 test_cbox(dev); 415 test_instances(dev); 416 417 CHK(s3d_device_ref_put(dev) == RES_OK); 418 419 check_memory_allocator(&allocator); 420 mem_shutdown_proxy_allocator(&allocator); 421 CHK(mem_allocated_size() == 0); 422 return 0; 423 }