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