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 }