s3d_shape.c (10559B)
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_c.h" 18 #include "s3d_device_c.h" 19 #include "s3d_scene_c.h" 20 #include "s3d_shape_c.h" 21 22 #include <rsys/float33.h> 23 #include <rsys/mem_allocator.h> 24 25 /******************************************************************************* 26 * Helper functions 27 ******************************************************************************/ 28 static void 29 shape_release(ref_T* ref) 30 { 31 struct s3d_shape* shape; 32 struct s3d_device* dev; 33 ASSERT(ref); 34 shape = CONTAINER_OF(ref, struct s3d_shape, ref); 35 dev = shape->dev; 36 37 /* The shape should not be attached */ 38 if(shape->type != GEOM_NONE) { 39 switch(shape->type) { 40 case GEOM_MESH: 41 if(shape->data.mesh) mesh_ref_put(shape->data.mesh); 42 break; 43 case GEOM_INSTANCE: 44 if(shape->data.instance) instance_ref_put(shape->data.instance); 45 break; 46 case GEOM_SPHERE: 47 if(shape->data.sphere) sphere_ref_put(shape->data.sphere); 48 break; 49 default: FATAL("Unreachable code \n"); break; 50 } 51 } 52 flist_name_del(&dev->names, shape->id); 53 MEM_RM(dev->allocator, shape); 54 S3D(device_ref_put(dev)); 55 } 56 57 /******************************************************************************* 58 * Local functions 59 ******************************************************************************/ 60 res_T 61 shape_create(struct s3d_device* dev, struct s3d_shape** out_shape) 62 { 63 struct s3d_shape* shape = NULL; 64 res_T res = RES_OK; 65 66 if(!dev || !out_shape) { 67 res = RES_BAD_ARG; 68 goto error; 69 } 70 shape = (struct s3d_shape*)MEM_CALLOC 71 (dev->allocator, 1, sizeof(struct s3d_shape)); 72 if(!shape) { 73 res = RES_MEM_ERR; 74 goto error; 75 } 76 S3D(device_ref_get(dev)); 77 shape->dev = dev; 78 ref_init(&shape->ref); 79 shape->id = flist_name_add(&dev->names); 80 shape->type = GEOM_NONE; 81 shape->is_enabled = 1; 82 shape->flip_surface = 0; 83 84 exit: 85 if(out_shape) *out_shape = shape; 86 return res; 87 error: 88 if(shape) { 89 S3D(shape_ref_put(shape)); 90 shape = NULL; 91 } 92 goto exit; 93 } 94 95 /******************************************************************************* 96 * Exported s3d_shape functions 97 ******************************************************************************/ 98 res_T 99 s3d_shape_create_mesh 100 (struct s3d_device* dev, struct s3d_shape** out_shape) 101 { 102 struct s3d_shape* shape = NULL; 103 res_T res = RES_OK; 104 105 if(!dev || !out_shape) { 106 res = RES_BAD_ARG; 107 goto error; 108 } 109 110 res = shape_create(dev, &shape); 111 if(res != RES_OK) goto error; 112 113 shape->type = GEOM_MESH; 114 res = mesh_create(dev, &shape->data.mesh); 115 if(res != RES_OK) goto error; 116 117 exit: 118 if(out_shape) 119 *out_shape = shape; 120 return res; 121 error: 122 if(shape) { 123 S3D(shape_ref_put(shape)); 124 shape = NULL; 125 } 126 goto exit; 127 } 128 129 res_T 130 s3d_shape_create_sphere 131 (struct s3d_device* dev, struct s3d_shape** out_shape) 132 { 133 struct s3d_shape* shape = NULL; 134 res_T res = RES_OK; 135 136 if(!dev || !out_shape) { 137 res = RES_BAD_ARG; 138 goto error; 139 } 140 141 res = shape_create(dev, &shape); 142 if(res != RES_OK) goto error; 143 144 shape->type = GEOM_SPHERE; 145 res = sphere_create(dev, &shape->data.sphere); 146 if(res != RES_OK) goto error; 147 148 exit: 149 if(out_shape) 150 *out_shape = shape; 151 return res; 152 error: 153 if(shape) { 154 S3D(shape_ref_put(shape)); 155 shape = NULL; 156 } 157 goto exit; 158 } 159 160 res_T 161 s3d_shape_ref_get(struct s3d_shape* shape) 162 { 163 if(!shape) return RES_BAD_ARG; 164 ref_get(&shape->ref); 165 return RES_OK; 166 } 167 168 res_T 169 s3d_shape_ref_put(struct s3d_shape* shape) 170 { 171 if(!shape) return RES_BAD_ARG; 172 ref_put(&shape->ref, shape_release); 173 return RES_OK; 174 } 175 176 res_T 177 s3d_shape_get_id(const struct s3d_shape* shape, unsigned* id) 178 { 179 if(!shape || !id) return RES_BAD_ARG; 180 *id = shape->id.index; 181 return RES_OK; 182 } 183 184 res_T 185 s3d_shape_enable(struct s3d_shape* shape, const char enable) 186 { 187 if(!shape) return RES_BAD_ARG; 188 shape->is_enabled = enable; 189 return RES_OK; 190 } 191 192 res_T 193 s3d_shape_is_enabled(const struct s3d_shape* shape, char* is_enabled) 194 { 195 if(!shape || !is_enabled) return RES_BAD_ARG; 196 *is_enabled = shape->is_enabled; 197 return RES_OK; 198 } 199 200 res_T 201 s3d_shape_flip_surface(struct s3d_shape* shape) 202 { 203 if(!shape) return RES_BAD_ARG; 204 shape->flip_surface ^= 1; 205 return RES_OK; 206 } 207 208 res_T 209 s3d_instance_set_position 210 (struct s3d_shape* shape, const float position[3]) 211 { 212 float axis[3]; 213 if(!shape || shape->type != GEOM_INSTANCE || !position) 214 return RES_BAD_ARG; 215 shape->data.instance->transform[9] = 216 f3_dot(f33_row(axis, shape->data.instance->transform, 0), position); 217 shape->data.instance->transform[10] = 218 f3_dot(f33_row(axis, shape->data.instance->transform, 1), position); 219 shape->data.instance->transform[11] = 220 f3_dot(f33_row(axis, shape->data.instance->transform, 2), position); 221 return RES_OK; 222 } 223 224 res_T 225 s3d_instance_translate 226 (struct s3d_shape* shape, 227 const enum s3d_transform_space space, 228 const float translation[3]) 229 { 230 if(!shape || shape->type != GEOM_INSTANCE || !translation) 231 return RES_BAD_ARG; 232 if(space == S3D_LOCAL_TRANSFORM) { 233 float vec[3]; 234 f33_mulf3(vec, shape->data.instance->transform, translation); 235 f3_add 236 (shape->data.instance->transform + 9, 237 shape->data.instance->transform + 9, 238 vec); 239 } else if(space == S3D_WORLD_TRANSFORM) { 240 f3_add 241 (shape->data.instance->transform + 9, 242 shape->data.instance->transform + 9, 243 translation); 244 } else { 245 return RES_BAD_ARG; 246 } 247 return RES_OK; 248 } 249 250 res_T 251 s3d_instance_set_transform 252 (struct s3d_shape* shape, 253 const float transform[12]) 254 { 255 if(!shape || shape->type != GEOM_INSTANCE || !transform) 256 return RES_BAD_ARG; 257 memcpy(shape->data.instance->transform, transform, 12 * sizeof(float)); 258 return RES_OK; 259 } 260 261 res_T 262 s3d_instance_transform 263 (struct s3d_shape* shape, 264 const enum s3d_transform_space space, 265 const float transform[12]) 266 { 267 if(!shape || shape->type != GEOM_INSTANCE || !transform) 268 return RES_BAD_ARG; 269 if(space == S3D_LOCAL_TRANSFORM) { 270 f33_mulf33(shape->data.instance->transform, 271 transform, shape->data.instance->transform); 272 } else if(space == S3D_WORLD_TRANSFORM) { 273 f33_mulf33(shape->data.instance->transform, 274 shape->data.instance->transform, transform); 275 } else { 276 return RES_BAD_ARG; 277 } 278 return RES_OK; 279 } 280 281 res_T 282 s3d_sphere_setup 283 (struct s3d_shape* shape, 284 const float position[3], 285 const float radius) 286 { 287 if(!shape || !position || radius <= 0) 288 return RES_BAD_ARG; 289 f3_set(shape->data.sphere->pos, position); 290 shape->data.sphere->radius = radius; 291 return RES_OK; 292 } 293 294 res_T 295 s3d_sphere_set_hit_filter_function 296 (struct s3d_shape* shape, 297 s3d_hit_filter_function_T func, 298 void* data) 299 { 300 if(!shape || shape->type != GEOM_SPHERE) return RES_BAD_ARG; 301 shape->data.sphere->filter.func = func; 302 shape->data.sphere->filter.data = data; 303 return RES_OK; 304 } 305 306 res_T 307 s3d_sphere_get_hit_filter_data(struct s3d_shape* shape, void** data) 308 { 309 if(!shape || !data || shape->type != GEOM_SPHERE) return RES_BAD_ARG; 310 *data = shape->data.sphere->filter.data; 311 return RES_OK; 312 } 313 314 res_T 315 s3d_mesh_setup_indexed_vertices 316 (struct s3d_shape* shape, 317 const unsigned ntris, 318 void (*get_indices)(const unsigned itri, unsigned ids[3], void* ctx), 319 const unsigned nverts, 320 struct s3d_vertex_data attribs[], 321 const unsigned nattribs, 322 void* data) 323 { 324 if(!shape || shape->type != GEOM_MESH) 325 return RES_BAD_ARG; 326 return mesh_setup_indexed_vertices 327 (shape->data.mesh, ntris, get_indices, nverts, attribs, nattribs, data); 328 } 329 330 res_T 331 s3d_mesh_copy 332 (const struct s3d_shape* src, 333 struct s3d_shape* dst) 334 { 335 if(!src || !dst || src->type != GEOM_MESH || dst->type != GEOM_MESH) 336 return RES_BAD_ARG; 337 if(src == dst) return RES_OK; 338 339 dst->flip_surface = src->flip_surface; 340 dst->is_enabled = src->is_enabled; 341 mesh_copy_indexed_vertices(src->data.mesh, dst->data.mesh); 342 return RES_OK; 343 } 344 345 res_T 346 s3d_mesh_get_vertices_count(const struct s3d_shape* shape, unsigned* nverts) 347 { 348 if(!shape || !nverts || shape->type != GEOM_MESH) return RES_BAD_ARG; 349 *nverts = (unsigned)mesh_get_nverts(shape->data.mesh); 350 return RES_OK; 351 } 352 353 res_T 354 s3d_mesh_get_vertex_attrib 355 (const struct s3d_shape* shape, 356 const unsigned ivert, 357 const enum s3d_attrib_usage usage, 358 struct s3d_attrib* attrib) 359 { 360 const float* data; 361 unsigned i, dim; 362 if(!shape 363 || shape->type != GEOM_MESH 364 || (unsigned)usage >= S3D_ATTRIBS_COUNT__ 365 || !shape->data.mesh->attribs[usage] 366 || !attrib 367 || ivert >= (unsigned)mesh_get_nverts(shape->data.mesh)) 368 return RES_BAD_ARG; 369 370 attrib->usage = usage; 371 attrib->type = shape->data.mesh->attribs_type[usage]; 372 373 dim = s3d_type_get_dimension(attrib->type); 374 data = mesh_get_attr(shape->data.mesh, usage) + ivert * dim; 375 FOR_EACH(i, 0, dim) attrib->value[i] = data[i]; 376 return RES_OK; 377 } 378 379 res_T 380 s3d_mesh_get_triangles_count(const struct s3d_shape* shape, unsigned* ntris) 381 { 382 if(!shape || !ntris || shape->type != GEOM_MESH) return RES_BAD_ARG; 383 *ntris = (unsigned)mesh_get_ntris(shape->data.mesh); 384 return RES_OK; 385 } 386 387 res_T 388 s3d_mesh_get_triangle_indices 389 (const struct s3d_shape* shape, 390 const unsigned itri, 391 unsigned ids[3]) 392 { 393 const unsigned* data; 394 if(!shape 395 || shape->type != GEOM_MESH 396 || !ids 397 || itri >= (unsigned)mesh_get_ntris(shape->data.mesh)) 398 return RES_BAD_ARG; 399 400 data = mesh_get_ids(shape->data.mesh) + itri * 3; 401 ids[0] = data[0]; 402 ids[1] = data[1]; 403 ids[2] = data[2]; 404 return RES_OK; 405 } 406 407 res_T 408 s3d_mesh_set_hit_filter_function 409 (struct s3d_shape* shape, 410 s3d_hit_filter_function_T func, 411 void* data) 412 { 413 if(!shape || shape->type != GEOM_MESH) return RES_BAD_ARG; 414 shape->data.mesh->filter.func = func; 415 shape->data.mesh->filter.data = data; 416 return RES_OK; 417 } 418 419 res_T 420 s3d_mesh_get_hit_filter_data(struct s3d_shape* shape, void** data) 421 { 422 if(!shape || !data || shape->type != GEOM_MESH) return RES_BAD_ARG; 423 *data = shape->data.mesh->filter.data; 424 return RES_OK; 425 } 426