star-3d

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

s3d_shape.c (10586B)


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