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