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 }