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_scene.c (5611B)


      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_device_c.h"
     18 #include "s3d_scene_c.h"
     19 #include "s3d_scene_view_c.h"
     20 #include "s3d_shape_c.h"
     21 
     22 #include <rsys/list.h>
     23 #include <rsys/mem_allocator.h>
     24 
     25 /*******************************************************************************
     26  * Helper functions
     27  ******************************************************************************/
     28 static void
     29 scene_release(ref_T* ref)
     30 {
     31   struct s3d_scene* scn;
     32   struct s3d_device* dev;
     33   struct list_node* node;
     34   struct list_node* tmp;
     35 
     36   ASSERT(ref);
     37   scn = CONTAINER_OF(ref, struct s3d_scene, ref);
     38   dev = scn->dev;
     39   LIST_FOR_EACH_SAFE(node, tmp, &scn->scnviews) {
     40     scene_view_destroy(CONTAINER_OF(node, struct s3d_scene_view, node));
     41   }
     42   S3D(scene_clear(scn));
     43   htable_shape_release(&scn->shapes);
     44   MEM_RM(dev->allocator, scn);
     45   S3D(device_ref_put(dev));
     46 }
     47 
     48 /*******************************************************************************
     49  * Exported s3d_scene functions
     50  ******************************************************************************/
     51 res_T
     52 s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn)
     53 {
     54   struct s3d_scene* scn = NULL;
     55   res_T res = RES_OK;
     56 
     57   if(!dev || !out_scn) {
     58     res = RES_BAD_ARG;
     59     goto error;
     60   }
     61   scn = (struct s3d_scene*)MEM_CALLOC
     62     (dev->allocator, 1, sizeof(struct s3d_scene));
     63   if(!scn) {
     64     res = RES_MEM_ERR;
     65     goto error;
     66   }
     67   htable_shape_init(dev->allocator, &scn->shapes);
     68   SIG_INIT(&scn->sig_shape_detach);
     69   list_init(&scn->scnviews);
     70   ref_init(&scn->ref);
     71   S3D(device_ref_get(dev));
     72   scn->dev = dev;
     73 
     74 exit:
     75   if(out_scn) *out_scn = scn;
     76   return res;
     77 error:
     78   if(scn) {
     79     S3D(scene_ref_put(scn));
     80     scn = NULL;
     81   }
     82   goto exit;
     83 }
     84 
     85 res_T
     86 s3d_scene_ref_get(struct s3d_scene* scn)
     87 {
     88   if(!scn) return RES_BAD_ARG;
     89   ref_get(&scn->ref);
     90   return RES_OK;
     91 }
     92 
     93 res_T
     94 s3d_scene_ref_put(struct s3d_scene* scn)
     95 {
     96   if(!scn) return RES_BAD_ARG;
     97   ref_put(&scn->ref, scene_release);
     98   return RES_OK;
     99 }
    100 
    101 res_T
    102 s3d_scene_instantiate(struct s3d_scene* scn, struct s3d_shape** out_shape)
    103 {
    104   struct s3d_shape* shape = NULL;
    105   res_T res = RES_OK;
    106 
    107   if(!scn || !out_shape) {
    108     res = RES_BAD_ARG;
    109     goto error;
    110   }
    111 
    112   res = shape_create(scn->dev, &shape);
    113   if(res != RES_OK)
    114     goto error;
    115 
    116   shape->type = GEOM_INSTANCE;
    117   res = instance_create(scn, &shape->data.instance);
    118   if(res != RES_OK)
    119     goto error;
    120 
    121 exit:
    122   if(out_shape)
    123     *out_shape = shape;
    124   return res;
    125 error:
    126   if(shape) {
    127     S3D(shape_ref_put(shape));
    128     shape = NULL;
    129   }
    130   goto exit;
    131 }
    132 
    133 res_T
    134 s3d_scene_attach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
    135 {
    136   unsigned shape_id;
    137   res_T res = RES_OK;
    138 
    139   if(!scn || !shape)
    140     return RES_BAD_ARG;
    141   if(shape->type == GEOM_INSTANCE && shape->data.instance->scene == scn) {
    142     log_error(scn->dev,
    143       "%s: the instantiated scene cannot be attached to itself.\n", FUNC_NAME);
    144     return RES_BAD_ARG;
    145   }
    146 
    147   S3D(shape_get_id(shape, &shape_id));
    148   if(htable_shape_find(&scn->shapes, &shape_id) != NULL) {
    149     log_warning(scn->dev,
    150       "%s: the shape is already attached to the scene.\n", FUNC_NAME);
    151     return RES_OK;
    152   }
    153 
    154   res = htable_shape_set(&scn->shapes, &shape_id, &shape);
    155   if(res != RES_OK) {
    156     log_error(scn->dev,
    157       "%s: cannot attach the shape to the scene.\n", FUNC_NAME);
    158     return RES_OK;
    159   }
    160   S3D(shape_ref_get(shape));
    161   scn->instances_count += shape->type == GEOM_INSTANCE;
    162   return RES_OK;
    163 }
    164 
    165 res_T
    166 s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
    167 {
    168   size_t n;
    169   unsigned shape_id;
    170 
    171   if(!scn || !shape) return RES_BAD_ARG;
    172 
    173   S3D(shape_get_id(shape, &shape_id));
    174   if(htable_shape_find(&scn->shapes, &shape_id) == NULL) {
    175     log_error(scn->dev,
    176       "%s: the shape is not attached to the scene.\n", FUNC_NAME);
    177     return RES_BAD_ARG;
    178   }
    179 
    180   n = htable_shape_erase(&scn->shapes, &shape_id);
    181   ASSERT(n == 1); (void)n;
    182 
    183   SIG_BROADCAST(&scn->sig_shape_detach, scene_shape_cb_T, ARG2(scn, shape));
    184 
    185   S3D(shape_ref_put(shape));
    186   return RES_OK;
    187 }
    188 
    189 res_T
    190 s3d_scene_clear(struct s3d_scene* scn)
    191 {
    192   struct htable_shape_iterator it, end;
    193 
    194   if(!scn) return RES_BAD_ARG;
    195 
    196   htable_shape_begin(&scn->shapes, &it);
    197   htable_shape_end(&scn->shapes, &end);
    198   while(!htable_shape_iterator_eq(&it, &end)) {
    199     struct s3d_shape** pshape = htable_shape_iterator_data_get(&it);
    200     struct s3d_shape* shape = *pshape;
    201     SIG_BROADCAST(&scn->sig_shape_detach, scene_shape_cb_T, ARG2(scn, shape));
    202     S3D(shape_ref_put(shape));
    203     htable_shape_iterator_next(&it);
    204   }
    205   htable_shape_clear(&scn->shapes);
    206 
    207   return RES_OK;
    208 }
    209 
    210 res_T
    211 s3d_scene_get_device(struct s3d_scene* scn, struct s3d_device** dev)
    212 {
    213   if(!scn || !dev) return RES_BAD_ARG;
    214   *dev = scn->dev;
    215   return RES_OK;
    216 }
    217 
    218 res_T
    219 s3d_scene_get_shapes_count(struct s3d_scene* scn, size_t* nshapes)
    220 {
    221   if(!scn || !nshapes) return RES_BAD_ARG;
    222   *nshapes = htable_shape_size_get(&scn->shapes);
    223   return RES_OK;
    224 }