star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.com/star-3d.git
Log | Files | Refs | README | LICENSE

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 }