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


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