star-3d

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

s3d_shape.c (10559B)


      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 "s3d_c.h"
     18 #include "s3d_device_c.h"
     19 #include "s3d_scene_c.h"
     20 #include "s3d_shape_c.h"
     21 
     22 #include <rsys/float33.h>
     23 #include <rsys/mem_allocator.h>
     24 
     25 /*******************************************************************************
     26  * Helper functions
     27  ******************************************************************************/
     28 static void
     29 shape_release(ref_T* ref)
     30 {
     31   struct s3d_shape* shape;
     32   struct s3d_device* dev;
     33   ASSERT(ref);
     34   shape = CONTAINER_OF(ref, struct s3d_shape, ref);
     35   dev = shape->dev;
     36 
     37   /* The shape should not be attached */
     38   if(shape->type != GEOM_NONE) {
     39     switch(shape->type) {
     40       case GEOM_MESH:
     41         if(shape->data.mesh) mesh_ref_put(shape->data.mesh);
     42         break;
     43       case GEOM_INSTANCE:
     44         if(shape->data.instance) instance_ref_put(shape->data.instance);
     45         break;
     46       case GEOM_SPHERE:
     47         if(shape->data.sphere) sphere_ref_put(shape->data.sphere);
     48         break;
     49       default: FATAL("Unreachable code \n"); break;
     50     }
     51   }
     52   flist_name_del(&dev->names, shape->id);
     53   MEM_RM(dev->allocator, shape);
     54   S3D(device_ref_put(dev));
     55 }
     56 
     57 /*******************************************************************************
     58  * Local functions
     59  ******************************************************************************/
     60 res_T
     61 shape_create(struct s3d_device* dev, struct s3d_shape** out_shape)
     62 {
     63   struct s3d_shape* shape = NULL;
     64   res_T res = RES_OK;
     65 
     66   if(!dev || !out_shape) {
     67     res = RES_BAD_ARG;
     68     goto error;
     69   }
     70   shape = (struct s3d_shape*)MEM_CALLOC
     71     (dev->allocator, 1, sizeof(struct s3d_shape));
     72   if(!shape) {
     73     res = RES_MEM_ERR;
     74     goto error;
     75   }
     76   S3D(device_ref_get(dev));
     77   shape->dev = dev;
     78   ref_init(&shape->ref);
     79   shape->id = flist_name_add(&dev->names);
     80   shape->type = GEOM_NONE;
     81   shape->is_enabled = 1;
     82   shape->flip_surface = 0;
     83 
     84 exit:
     85   if(out_shape) *out_shape = shape;
     86   return res;
     87 error:
     88   if(shape) {
     89     S3D(shape_ref_put(shape));
     90     shape = NULL;
     91   }
     92   goto exit;
     93 }
     94 
     95 /*******************************************************************************
     96  * Exported s3d_shape functions
     97  ******************************************************************************/
     98 res_T
     99 s3d_shape_create_mesh
    100   (struct s3d_device* dev, struct s3d_shape** out_shape)
    101 {
    102   struct s3d_shape* shape = NULL;
    103   res_T res = RES_OK;
    104 
    105   if(!dev || !out_shape) {
    106     res = RES_BAD_ARG;
    107     goto error;
    108   }
    109 
    110   res = shape_create(dev, &shape);
    111   if(res != RES_OK) goto error;
    112 
    113   shape->type = GEOM_MESH;
    114   res = mesh_create(dev, &shape->data.mesh);
    115   if(res != RES_OK) goto error;
    116 
    117 exit:
    118   if(out_shape)
    119     *out_shape = shape;
    120   return res;
    121 error:
    122   if(shape) {
    123     S3D(shape_ref_put(shape));
    124     shape = NULL;
    125   }
    126   goto exit;
    127 }
    128 
    129 res_T
    130 s3d_shape_create_sphere
    131   (struct s3d_device* dev, struct s3d_shape** out_shape)
    132 {
    133   struct s3d_shape* shape = NULL;
    134   res_T res = RES_OK;
    135 
    136   if(!dev || !out_shape) {
    137     res = RES_BAD_ARG;
    138     goto error;
    139   }
    140 
    141   res = shape_create(dev, &shape);
    142   if(res != RES_OK) goto error;
    143 
    144   shape->type = GEOM_SPHERE;
    145   res = sphere_create(dev, &shape->data.sphere);
    146   if(res != RES_OK) goto error;
    147 
    148 exit:
    149   if(out_shape)
    150     *out_shape = shape;
    151   return res;
    152 error:
    153   if(shape) {
    154     S3D(shape_ref_put(shape));
    155     shape = NULL;
    156   }
    157   goto exit;
    158 }
    159 
    160 res_T
    161 s3d_shape_ref_get(struct s3d_shape* shape)
    162 {
    163   if(!shape) return RES_BAD_ARG;
    164   ref_get(&shape->ref);
    165   return RES_OK;
    166 }
    167 
    168 res_T
    169 s3d_shape_ref_put(struct s3d_shape* shape)
    170 {
    171   if(!shape) return RES_BAD_ARG;
    172   ref_put(&shape->ref, shape_release);
    173   return RES_OK;
    174 }
    175 
    176 res_T
    177 s3d_shape_get_id(const struct s3d_shape* shape, unsigned* id)
    178 {
    179   if(!shape || !id) return RES_BAD_ARG;
    180   *id = shape->id.index;
    181   return RES_OK;
    182 }
    183 
    184 res_T
    185 s3d_shape_enable(struct s3d_shape* shape, const char enable)
    186 {
    187   if(!shape) return RES_BAD_ARG;
    188   shape->is_enabled = enable;
    189   return RES_OK;
    190 }
    191 
    192 res_T
    193 s3d_shape_is_enabled(const struct s3d_shape* shape, char* is_enabled)
    194 {
    195   if(!shape || !is_enabled) return RES_BAD_ARG;
    196   *is_enabled = shape->is_enabled;
    197   return RES_OK;
    198 }
    199 
    200 res_T
    201 s3d_shape_flip_surface(struct s3d_shape* shape)
    202 {
    203   if(!shape) return RES_BAD_ARG;
    204   shape->flip_surface ^= 1;
    205   return RES_OK;
    206 }
    207 
    208 res_T
    209 s3d_instance_set_position
    210   (struct s3d_shape* shape, const float position[3])
    211 {
    212   float axis[3];
    213   if(!shape || shape->type != GEOM_INSTANCE || !position)
    214     return RES_BAD_ARG;
    215   shape->data.instance->transform[9]  =
    216     f3_dot(f33_row(axis, shape->data.instance->transform, 0), position);
    217   shape->data.instance->transform[10] =
    218     f3_dot(f33_row(axis, shape->data.instance->transform, 1), position);
    219   shape->data.instance->transform[11] =
    220     f3_dot(f33_row(axis, shape->data.instance->transform, 2), position);
    221   return RES_OK;
    222 }
    223 
    224 res_T
    225 s3d_instance_translate
    226   (struct s3d_shape* shape,
    227    const enum s3d_transform_space space,
    228    const float translation[3])
    229 {
    230   if(!shape || shape->type != GEOM_INSTANCE || !translation)
    231     return RES_BAD_ARG;
    232   if(space == S3D_LOCAL_TRANSFORM) {
    233     float vec[3];
    234     f33_mulf3(vec, shape->data.instance->transform, translation);
    235     f3_add
    236       (shape->data.instance->transform + 9,
    237        shape->data.instance->transform + 9,
    238        vec);
    239   } else if(space == S3D_WORLD_TRANSFORM) {
    240     f3_add
    241       (shape->data.instance->transform + 9,
    242        shape->data.instance->transform + 9,
    243        translation);
    244   } else {
    245     return RES_BAD_ARG;
    246   }
    247   return RES_OK;
    248 }
    249 
    250 res_T
    251 s3d_instance_set_transform
    252   (struct s3d_shape* shape,
    253    const float transform[12])
    254 {
    255   if(!shape || shape->type != GEOM_INSTANCE || !transform)
    256     return RES_BAD_ARG;
    257   memcpy(shape->data.instance->transform, transform, 12 * sizeof(float));
    258   return RES_OK;
    259 }
    260 
    261 res_T
    262 s3d_instance_transform
    263   (struct s3d_shape* shape,
    264    const enum s3d_transform_space space,
    265    const float transform[12])
    266 {
    267   if(!shape || shape->type != GEOM_INSTANCE || !transform)
    268     return RES_BAD_ARG;
    269   if(space == S3D_LOCAL_TRANSFORM) {
    270     f33_mulf33(shape->data.instance->transform,
    271       transform, shape->data.instance->transform);
    272   } else if(space == S3D_WORLD_TRANSFORM) {
    273     f33_mulf33(shape->data.instance->transform,
    274       shape->data.instance->transform, transform);
    275   } else {
    276     return RES_BAD_ARG;
    277   }
    278   return RES_OK;
    279 }
    280 
    281 res_T
    282 s3d_sphere_setup
    283   (struct s3d_shape* shape,
    284    const float position[3],
    285    const float radius)
    286 {
    287   if(!shape || !position || radius <= 0)
    288     return RES_BAD_ARG;
    289   f3_set(shape->data.sphere->pos, position);
    290   shape->data.sphere->radius = radius;
    291   return RES_OK;
    292 }
    293 
    294 res_T
    295 s3d_sphere_set_hit_filter_function
    296   (struct s3d_shape* shape,
    297    s3d_hit_filter_function_T func,
    298    void* data)
    299 {
    300   if(!shape || shape->type != GEOM_SPHERE) return RES_BAD_ARG;
    301   shape->data.sphere->filter.func = func;
    302   shape->data.sphere->filter.data = data;
    303   return RES_OK;
    304 }
    305 
    306 res_T
    307 s3d_sphere_get_hit_filter_data(struct s3d_shape* shape, void** data)
    308 {
    309   if(!shape || !data || shape->type != GEOM_SPHERE) return RES_BAD_ARG;
    310   *data = shape->data.sphere->filter.data;
    311   return RES_OK;
    312 }
    313 
    314 res_T
    315 s3d_mesh_setup_indexed_vertices
    316   (struct s3d_shape* shape,
    317    const unsigned ntris,
    318    void (*get_indices)(const unsigned itri, unsigned ids[3], void* ctx),
    319    const unsigned nverts,
    320    struct s3d_vertex_data attribs[],
    321    const unsigned nattribs,
    322    void* data)
    323 {
    324   if(!shape || shape->type != GEOM_MESH)
    325     return RES_BAD_ARG;
    326   return mesh_setup_indexed_vertices
    327     (shape->data.mesh, ntris, get_indices, nverts, attribs, nattribs, data);
    328 }
    329 
    330 res_T
    331 s3d_mesh_copy
    332   (const struct s3d_shape* src,
    333    struct s3d_shape* dst)
    334 {
    335   if(!src || !dst || src->type != GEOM_MESH || dst->type != GEOM_MESH)
    336     return RES_BAD_ARG;
    337   if(src == dst) return RES_OK;
    338 
    339   dst->flip_surface = src->flip_surface;
    340   dst->is_enabled = src->is_enabled;
    341   mesh_copy_indexed_vertices(src->data.mesh, dst->data.mesh);
    342   return RES_OK;
    343 }
    344 
    345 res_T
    346 s3d_mesh_get_vertices_count(const struct s3d_shape* shape, unsigned* nverts)
    347 {
    348   if(!shape || !nverts || shape->type != GEOM_MESH) return RES_BAD_ARG;
    349   *nverts = (unsigned)mesh_get_nverts(shape->data.mesh);
    350   return RES_OK;
    351 }
    352 
    353 res_T
    354 s3d_mesh_get_vertex_attrib
    355   (const struct s3d_shape* shape,
    356    const unsigned ivert,
    357    const enum s3d_attrib_usage usage,
    358    struct s3d_attrib* attrib)
    359 {
    360   const float* data;
    361   unsigned i, dim;
    362   if(!shape
    363   || shape->type != GEOM_MESH
    364   || (unsigned)usage >= S3D_ATTRIBS_COUNT__
    365   || !shape->data.mesh->attribs[usage]
    366   || !attrib
    367   || ivert >= (unsigned)mesh_get_nverts(shape->data.mesh))
    368     return RES_BAD_ARG;
    369 
    370   attrib->usage = usage;
    371   attrib->type = shape->data.mesh->attribs_type[usage];
    372 
    373   dim = s3d_type_get_dimension(attrib->type);
    374   data = mesh_get_attr(shape->data.mesh, usage) + ivert * dim;
    375   FOR_EACH(i, 0, dim) attrib->value[i] = data[i];
    376   return RES_OK;
    377 }
    378 
    379 res_T
    380 s3d_mesh_get_triangles_count(const struct s3d_shape* shape, unsigned* ntris)
    381 {
    382   if(!shape || !ntris || shape->type != GEOM_MESH) return RES_BAD_ARG;
    383   *ntris = (unsigned)mesh_get_ntris(shape->data.mesh);
    384   return RES_OK;
    385 }
    386 
    387 res_T
    388 s3d_mesh_get_triangle_indices
    389   (const struct s3d_shape* shape,
    390    const unsigned itri,
    391    unsigned ids[3])
    392 {
    393   const unsigned* data;
    394   if(!shape
    395   || shape->type != GEOM_MESH
    396   || !ids
    397   || itri >= (unsigned)mesh_get_ntris(shape->data.mesh))
    398     return RES_BAD_ARG;
    399 
    400   data = mesh_get_ids(shape->data.mesh) + itri * 3;
    401   ids[0] = data[0];
    402   ids[1] = data[1];
    403   ids[2] = data[2];
    404   return RES_OK;
    405 }
    406 
    407 res_T
    408 s3d_mesh_set_hit_filter_function
    409   (struct s3d_shape* shape,
    410    s3d_hit_filter_function_T func,
    411    void* data)
    412 {
    413   if(!shape || shape->type != GEOM_MESH) return RES_BAD_ARG;
    414   shape->data.mesh->filter.func = func;
    415   shape->data.mesh->filter.data = data;
    416   return RES_OK;
    417 }
    418 
    419 res_T
    420 s3d_mesh_get_hit_filter_data(struct s3d_shape* shape, void** data)
    421 {
    422   if(!shape || !data || shape->type != GEOM_MESH) return RES_BAD_ARG;
    423   *data = shape->data.mesh->filter.data;
    424   return RES_OK;
    425 }
    426