aw_obj.c (26376B)
1 /* Copyright (C) 2014-2017, 2020-2023 Vincent Forest (vaplv@free.fr) 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 Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #define _POSIX_C_SOURCE 200112L /* strtok_r support */ 17 18 #include "aw_c.h" 19 20 #include <rsys/cstr.h> 21 #include <rsys/dynamic_array_double.h> 22 #include <rsys/logger.h> 23 #include <rsys/mem_allocator.h> 24 #include <rsys/ref_count.h> 25 #include <rsys/str.h> 26 #include <rsys/text_reader.h> 27 28 #include <float.h> /* DBL_MAX & DBL_MIN definition */ 29 #include <stdarg.h> 30 31 #ifdef COMPILER_CL 32 #pragma warning(push) 33 #pragma warning(disable:4706) /* Assignment within a condition */ 34 #endif 35 36 static const char* MSG_PREFIX_INFO = "load-obj:info: "; 37 static const char* MSG_PREFIX_ERROR = "load-obj:error: "; 38 static const char* MSG_PREFIX_WARNING = "load-obj:warning: "; 39 40 /* Generate the darray_vertex data structure */ 41 #define DARRAY_NAME vertex 42 #define DARRAY_DATA struct aw_obj_vertex 43 #include <rsys/dynamic_array.h> 44 45 /* Generate the darray_face data structure */ 46 #define DARRAY_NAME face 47 #define DARRAY_DATA struct aw_obj_face 48 #include <rsys/dynamic_array.h> 49 50 static const struct aw_obj_vertex VERTEX_NULL = { 51 AW_ID_NONE, AW_ID_NONE, AW_ID_NONE 52 }; 53 54 struct named_group { 55 struct str name; 56 size_t face_id; /* Index of the first group face */ 57 size_t faces_count; 58 }; 59 60 static INLINE void 61 named_group_init(struct mem_allocator* allocator, struct named_group* grp) 62 { 63 str_init(allocator, &grp->name); 64 } 65 66 static INLINE void 67 named_group_release(struct named_group* grp) 68 { 69 ASSERT(grp); 70 str_release(&grp->name); 71 } 72 73 static INLINE res_T 74 named_group_copy(struct named_group* dst, const struct named_group* src) 75 { 76 ASSERT(dst && src); 77 if(dst == src) return RES_OK; 78 dst->face_id = src->face_id; 79 dst->faces_count = src->faces_count; 80 return str_copy(&dst->name, &src->name); 81 } 82 83 static INLINE res_T 84 named_group_copy_and_release(struct named_group* dst, struct named_group* src) 85 { 86 ASSERT(dst && src); 87 if(dst == src) return RES_OK; 88 dst->face_id = src->face_id; 89 dst->faces_count = src->faces_count; 90 return str_copy_and_release(&dst->name, &src->name); 91 } 92 93 /* Generate the darray_named_group data structure */ 94 #define DARRAY_NAME named_group 95 #define DARRAY_DATA struct named_group 96 #define DARRAY_FUNCTOR_INIT named_group_init 97 #define DARRAY_FUNCTOR_RELEASE named_group_release 98 #define DARRAY_FUNCTOR_COPY named_group_copy 99 #define DARRAY_FUNCTOR_COPY_AND_RELEASE named_group_copy_and_release 100 #include <rsys/dynamic_array.h> 101 102 /* Generate the darray_smooth_group data structure */ 103 #define DARRAY_NAME smooth_group 104 #define DARRAY_DATA struct aw_obj_smooth_group 105 #include <rsys/dynamic_array.h> 106 107 /* Generate the darray_mtllib data structure */ 108 #define DARRAY_NAME mtllib 109 #define DARRAY_DATA struct str 110 #define DARRAY_FUNCTOR_INIT str_init 111 #define DARRAY_FUNCTOR_RELEASE str_release 112 #define DARRAY_FUNCTOR_COPY str_copy 113 #define DARRAY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release 114 #include <rsys/dynamic_array.h> 115 116 struct aw_obj { 117 struct darray_double positions; /* double4 */ 118 struct darray_double normals; /* double3 */ 119 struct darray_double texcoords; /* double3 */ 120 struct darray_vertex vertices; 121 struct darray_face faces; 122 struct darray_named_group groups; 123 struct darray_smooth_group smooth_groups; 124 struct darray_named_group usemtls; 125 struct darray_mtllib mtllibs; 126 127 size_t igroups_active; /* Index toward the first active group */ 128 129 ref_T ref; 130 struct mem_allocator* allocator; 131 struct logger* logger; 132 struct logger logger__; /* Default logger */ 133 int verbose; 134 }; 135 136 /******************************************************************************* 137 * Helper functions 138 ******************************************************************************/ 139 static INLINE void 140 log_msg 141 (const struct aw_obj* obj, 142 const enum log_type stream, 143 const char* msg, 144 va_list vargs) 145 { 146 ASSERT(obj && msg); 147 if(obj->verbose) { 148 res_T res; (void)res; 149 res = logger_vprint(obj->logger, stream, msg, vargs); 150 ASSERT(res == RES_OK); 151 } 152 } 153 154 static INLINE void 155 log_err(const struct aw_obj* obj, const char* msg, ...) 156 { 157 va_list vargs_list; 158 ASSERT(obj && msg); 159 160 va_start(vargs_list, msg); 161 log_msg(obj, LOG_ERROR, msg, vargs_list); 162 va_end(vargs_list); 163 } 164 165 static INLINE void 166 log_warn(const struct aw_obj* obj, const char* msg, ...) 167 { 168 va_list vargs_list; 169 ASSERT(obj && msg); 170 171 va_start(vargs_list, msg); 172 log_msg(obj, LOG_WARNING, msg, vargs_list); 173 va_end(vargs_list); 174 } 175 176 static INLINE void 177 flush_groups(struct aw_obj* obj) 178 { 179 size_t nfaces, ngrps; 180 ASSERT(obj); 181 182 nfaces = darray_face_size_get(&obj->faces); 183 if(!nfaces) return; /* No face to flush */ 184 185 ngrps = darray_named_group_size_get(&obj->groups); 186 if(!ngrps) return; /* No group */ 187 188 /* There should be an active group to flush if ngrps is not null */ 189 ASSERT(obj->igroups_active < ngrps); 190 191 /* Setup the number of faces of each active group */ 192 FOR_EACH(obj->igroups_active, obj->igroups_active, ngrps) { 193 struct named_group* grp; 194 grp = darray_named_group_data_get(&obj->groups) + obj->igroups_active; 195 ASSERT(grp->face_id <= nfaces); 196 grp->faces_count = nfaces - grp->face_id; 197 } 198 } 199 200 static INLINE void 201 flush_usemtl(struct aw_obj* obj) 202 { 203 struct named_group* mtl; 204 size_t nfaces, ngrps; 205 ASSERT(obj); 206 207 nfaces = darray_face_size_get(&obj->faces); 208 if(!nfaces) return; /* No face to flush */ 209 210 ngrps = darray_named_group_size_get(&obj->usemtls); 211 if(!ngrps) return; /* No group */ 212 213 /* Setup the number of faces of the current mtl */ 214 mtl = darray_named_group_data_get(&obj->usemtls) + (ngrps - 1); 215 ASSERT(mtl->face_id <= nfaces); 216 mtl->faces_count = nfaces - mtl->face_id; 217 } 218 219 static INLINE void 220 flush_smooth_group(struct aw_obj* obj) 221 { 222 struct aw_obj_smooth_group* grp; 223 size_t nfaces, ngrps; 224 ASSERT(obj); 225 226 nfaces = darray_face_size_get(&obj->faces); 227 if(!nfaces) return; /* No face to flush */ 228 229 ngrps = darray_smooth_group_size_get(&obj->smooth_groups); 230 if(!ngrps) return; /* No smooth group */ 231 232 /* Setup the number of faces of the current smoothed group */ 233 grp = darray_smooth_group_data_get(&obj->smooth_groups) + (ngrps - 1); 234 ASSERT(grp->face_id <= nfaces); 235 grp->faces_count = nfaces - grp->face_id; 236 } 237 238 static res_T 239 parse_doubleX_in_darray 240 (struct darray_double* darray, 241 const unsigned int count_min, 242 const unsigned int count_max, 243 const double default_value, 244 char** tk_ctx) 245 { 246 res_T res = RES_OK; 247 size_t i; 248 ASSERT(darray); 249 250 i = darray_double_size_get(darray); 251 252 res = darray_double_resize(darray, i + count_max); 253 if(res != RES_OK) goto error; 254 255 res = parse_doubleX(darray_double_data_get(darray) + i, count_min, count_max, 256 -DBL_MAX, DBL_MAX, default_value, tk_ctx); 257 if(res != RES_OK) goto error; 258 259 exit: 260 return res; 261 error: 262 darray_double_resize(darray, i); 263 goto exit; 264 } 265 266 static res_T 267 string_to_vertex_id 268 (const char* str, /* Input string */ 269 const size_t vertices_count, /* Current vertices count for a given attrib */ 270 size_t* id) /* Computed id */ 271 { 272 long id_long; 273 res_T res; 274 275 res = cstr_to_long(str, &id_long); 276 if(res != RES_OK) return res; 277 278 if(id_long > 0) { 279 /* The obj indexation starts at 1 rather than 0 => subtract 1 to the vertex 280 * attribute indices in order to match the C memory layout */ 281 *id = (size_t)(id_long - 1); 282 } else if(id_long < 0) { 283 /* One can count vertices back up the list from an element's position in 284 * the file. In this case the index is negative. For instance, a reference 285 * number of -1 indicates the vertex immediately above the element */ 286 *id = vertices_count - (size_t)labs(id_long); 287 } 288 if(*id >= vertices_count) 289 return RES_BAD_ARG; 290 return RES_OK; 291 } 292 293 static res_T 294 parse_face_vertex 295 (struct aw_obj* obj, 296 struct aw_obj_face* face, 297 char* str) 298 { 299 struct aw_obj_vertex vert = VERTEX_NULL; 300 char* tk1 = NULL; 301 char* tk2 = NULL; 302 char* tk3 = NULL; 303 char* tk_ctx = NULL; 304 size_t npositions = 0; 305 size_t nnormals = 0; 306 size_t ntexcoords = 0; 307 res_T res = RES_OK; 308 ASSERT(obj && face && str); 309 310 npositions = darray_double_size_get(&obj->positions) / 4; 311 nnormals = darray_double_size_get(&obj->normals) / 3; 312 ntexcoords = darray_double_size_get(&obj->texcoords) / 3; 313 314 #define CALL(Func) if(RES_OK != (res = Func)) goto error 315 316 /* Parse the position */ 317 tk1 = strtok_r(str, "/", &tk_ctx); 318 ASSERT(tk1); 319 CALL(string_to_vertex_id(tk1, npositions, &vert.position_id)); 320 321 tk2 = strtok_r(NULL, "/", &tk_ctx); 322 if(tk2) { 323 tk1 += strlen(tk1); 324 if(tk2 > tk1 + 3) { /* Unexpected N `/' separators with N > 2 */ 325 res = RES_BAD_ARG; 326 goto error; 327 } 328 329 if(tk2 == tk1 + 2) { /* `//' separator => No tex */ 330 /* Parse the normal */ 331 CALL(string_to_vertex_id(tk2, nnormals, &vert.normal_id)); 332 } else { 333 /* Parse the texcoords and */ 334 CALL(string_to_vertex_id(tk2, ntexcoords, &vert.texcoord_id)); 335 336 tk3 = strtok_r(NULL, "", &tk_ctx); 337 if(tk3) { 338 /* Parse the normal */ 339 CALL(string_to_vertex_id(tk3, nnormals, &vert.normal_id)); 340 } 341 } 342 } 343 344 /* Register the vertex */ 345 CALL(darray_vertex_push_back(&obj->vertices, &vert)); 346 ++face->vertices_count; 347 348 #undef CALL 349 exit: 350 return res; 351 error: 352 goto exit; 353 } 354 355 static res_T 356 parse_face(struct aw_obj* obj, char** tk_ctx) 357 { 358 struct aw_obj_face face; 359 char* tk = NULL; 360 res_T res = RES_OK; 361 ASSERT(obj && tk_ctx); 362 363 face.vertex_id = darray_vertex_size_get(&obj->vertices); 364 face.vertices_count = 0; 365 face.group_id = darray_named_group_size_get(&obj->groups) - 1; 366 face.smooth_group_id = darray_smooth_group_size_get(&obj->smooth_groups) - 1; 367 face.mtl_id = darray_named_group_size_get(&obj->usemtls) - 1; 368 369 while((tk = strtok_r(NULL, " \t", tk_ctx))) { 370 res = parse_face_vertex(obj, &face, tk); 371 if(res != RES_OK) goto error; 372 } 373 374 /* Register the face */ 375 res = darray_face_push_back(&obj->faces, &face); 376 if(res != RES_OK) goto error; 377 378 exit: 379 return res; 380 error: 381 /* Release the registered faces */ 382 CHK(darray_vertex_resize(&obj->vertices, face.vertex_id) == RES_OK); 383 goto exit; 384 } 385 386 static res_T 387 parse_group(struct aw_obj* obj, char** tk_ctx) 388 { 389 char* tk; 390 size_t ngrps = 0; 391 size_t igrp = 0; 392 res_T res = RES_OK; 393 ASSERT(obj && tk_ctx); 394 395 flush_groups(obj); 396 397 ngrps = igrp = darray_named_group_size_get(&obj->groups); 398 obj->igroups_active = igrp; 399 400 tk = strtok_r(NULL, " \t", tk_ctx); /* May be NULL */ 401 402 do { 403 struct named_group* grp = NULL; 404 405 /* Allocate a group */ 406 res = darray_named_group_resize(&obj->groups, igrp + 1); 407 if(res != RES_OK) goto error; 408 409 /* Fetch the group */ 410 grp = darray_named_group_data_get(&obj->groups) + igrp; 411 ++igrp; 412 413 /* Setup the group name */ 414 res = str_set(&grp->name, tk ? tk : "default"); 415 if(res != RES_OK) goto error; 416 417 /* Initialize the group face indices */ 418 grp->face_id = darray_face_size_get(&obj->faces); 419 grp->faces_count = 0; 420 } while((tk = strtok_r(NULL, " \t", tk_ctx))); 421 422 exit: 423 return res; 424 error: 425 /* Release the created groups */ 426 CHK(darray_named_group_resize(&obj->groups, ngrps) == RES_OK); 427 goto exit; 428 } 429 430 static res_T 431 parse_smooth_group(struct aw_obj* obj, char** tk_ctx) 432 { 433 struct aw_obj_smooth_group grp; 434 char* tk = NULL; 435 res_T res; 436 ASSERT(obj && tk_ctx); 437 438 flush_smooth_group(obj); 439 440 tk = strtok_r(NULL, " \t", tk_ctx); 441 if(!tk) return RES_BAD_ARG; 442 443 if(!strcmp(tk, "off")) { 444 grp.is_smoothed = 0; 445 } else if(!strcmp(tk, "on")) { 446 grp.is_smoothed = 1; 447 } else { 448 int i; 449 res = cstr_to_int(tk, &i); 450 if(res != RES_OK) return res; 451 grp.is_smoothed = i != 0; 452 } 453 454 /* Initialize the smoot group face indices */ 455 grp.face_id = darray_face_size_get(&obj->faces); 456 grp.faces_count = 0; 457 458 /* Register the smooth group */ 459 res = darray_smooth_group_push_back(&obj->smooth_groups, &grp); 460 if(res != RES_OK) return res; 461 462 return RES_OK; 463 } 464 465 static res_T 466 parse_mtllib(struct aw_obj* obj, char** tk_ctx) 467 { 468 char* tk = NULL; 469 size_t imtllib = 0; 470 size_t nmtllibs = 0; 471 res_T res = RES_OK; 472 ASSERT(obj && tk_ctx); 473 474 nmtllibs = imtllib = darray_mtllib_size_get(&obj->mtllibs); 475 476 tk = strtok_r(NULL, " \t", tk_ctx); 477 if(!tk) { 478 res = RES_BAD_ARG; 479 goto error; 480 } 481 482 do { 483 struct str* str = NULL; 484 485 /* Allocate the mtllib path */ 486 res = darray_mtllib_resize(&obj->mtllibs, imtllib + 1); 487 if(res != RES_OK) goto error; 488 489 /* Fetc the mtllib path */ 490 str = darray_mtllib_data_get(&obj->mtllibs) + imtllib; 491 ++imtllib; 492 493 /* Setup the mtllib name */ 494 res = str_set(str, tk); 495 if(res != RES_OK) goto error; 496 497 } while((tk = strtok_r(NULL, " \t", tk_ctx))); 498 499 exit: 500 return res; 501 error: 502 CHK(darray_mtllib_resize(&obj->mtllibs, nmtllibs) == RES_OK); 503 goto exit; 504 } 505 506 static res_T 507 parse_usemtl(struct aw_obj* obj, char** tk_ctx) 508 { 509 char* tk = NULL; 510 struct named_group* mtl = NULL; 511 size_t nmtls; 512 res_T res = RES_OK; 513 ASSERT(obj && tk_ctx); 514 515 flush_usemtl(obj); 516 517 tk = strtok_r(NULL, " \t", tk_ctx); /* Blanks are prohibited in mtl name */ 518 if(!tk) { 519 res = RES_BAD_ARG; 520 goto error; 521 } 522 523 nmtls = darray_named_group_size_get(&obj->usemtls); 524 525 /* Allocate the material */ 526 res = darray_named_group_resize(&obj->usemtls, nmtls + 1); 527 if(res != RES_OK) goto error; 528 529 /* Fetch the material */ 530 mtl = darray_named_group_data_get(&obj->usemtls) + nmtls; 531 532 /* Setup the material name */ 533 res = str_set(&mtl->name, tk); 534 if(res != RES_OK) goto error; 535 536 /* Initialize the material face indices */ 537 mtl->face_id = darray_face_size_get(&obj->faces); 538 mtl->faces_count = 0; 539 540 exit: 541 return res; 542 error: 543 if(mtl) darray_named_group_pop_back(&obj->usemtls); 544 goto exit; 545 } 546 547 static res_T 548 parse_obj_line(struct aw_obj* obj, struct txtrdr* txtrdr) 549 { 550 char* tk = NULL; 551 char* tk_ctx = NULL; 552 res_T res = RES_OK; 553 ASSERT(obj && txtrdr); 554 555 tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); 556 ASSERT(tk); /* A line should exist since it was parsed by txtrdr */ 557 558 if(!strcmp(tk, "v")) { /* Vertex position */ 559 res = parse_doubleX_in_darray(&obj->positions, 3, 4, 1.f, &tk_ctx); 560 } else if(!strcmp(tk, "vn")) { /* Vertex normal */ 561 res = parse_doubleX_in_darray(&obj->normals, 3, 3, 0.f, &tk_ctx); 562 } else if(!strcmp(tk, "vt")) { /* Vertex texture coordinates */ 563 res = parse_doubleX_in_darray(&obj->texcoords, 1, 3, 0.f, &tk_ctx); 564 } else if(!strcmp(tk, "f") || !strcmp(tk, "fo")) { /* face element */ 565 res = parse_face(obj, &tk_ctx); 566 } else if(!strcmp(tk, "g")) { /* Grouping */ 567 res = parse_group(obj, &tk_ctx); 568 } else if(!strcmp(tk, "s")) { /* Smooth group */ 569 res = parse_smooth_group(obj, &tk_ctx); 570 } else if(!strcmp(tk, "mtllib")) { /* Mtl library */ 571 res = parse_mtllib(obj, &tk_ctx); 572 } else if(!strcmp(tk, "usemtl")) { /* Use the mtl library */ 573 res = parse_usemtl(obj, &tk_ctx); 574 } else { 575 log_warn(obj, 576 "%s:%lu: warning: ignored or malformed directive `%s'.\n", 577 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 578 strtok_r(NULL, "", &tk_ctx); /* Discard remaining text */ 579 } 580 if(res != RES_OK) { 581 log_err(obj, "%s:%lu: parsing failed.\n", 582 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 583 goto error; 584 } 585 586 tk = strtok_r(NULL, "", &tk_ctx); 587 if(tk) { 588 log_err(obj, "%s:%lu: unexpected text `%s'.\n", 589 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 590 res = RES_BAD_ARG; 591 goto error; 592 } 593 594 exit: 595 return res; 596 error: 597 goto exit; 598 } 599 600 static res_T 601 load_stream(struct aw_obj* obj, FILE* stream, const char* stream_name) 602 { 603 struct txtrdr* txtrdr = NULL; 604 res_T res = RES_OK; 605 ASSERT(obj && stream && stream_name); 606 607 AW(obj_clear(obj)); 608 609 res = txtrdr_stream(obj->allocator, stream, stream_name, '#', &txtrdr); 610 if(res != RES_OK) { 611 log_err(obj, "Could not create the text reader.\n"); 612 goto error; 613 } 614 615 for(;;) { 616 res = txtrdr_read_line(txtrdr); 617 if(res != RES_OK) { 618 log_err(obj, "%s: could not read the line `%lu'.\n", 619 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 620 goto error; 621 } 622 623 if(!txtrdr_get_cline(txtrdr)) break; /* No more parsed line */ 624 625 res = parse_obj_line(obj, txtrdr); 626 if(res != RES_OK) goto error; 627 } 628 629 flush_groups(obj); 630 flush_smooth_group(obj); 631 flush_usemtl(obj); 632 exit: 633 if(txtrdr) txtrdr_ref_put(txtrdr); 634 return res; 635 error: 636 AW(obj_clear(obj)); 637 goto exit; 638 } 639 640 static void 641 obj_release(ref_T* ref) 642 { 643 struct aw_obj* obj = CONTAINER_OF(ref, struct aw_obj, ref); 644 ASSERT(ref); 645 darray_double_release(&obj->positions); 646 darray_double_release(&obj->normals); 647 darray_double_release(&obj->texcoords); 648 darray_vertex_release(&obj->vertices); 649 darray_face_release(&obj->faces); 650 darray_named_group_release(&obj->groups); 651 darray_named_group_release(&obj->usemtls); 652 darray_smooth_group_release(&obj->smooth_groups); 653 darray_mtllib_release(&obj->mtllibs); 654 if(obj->logger == &obj->logger__) logger_release(&obj->logger__); 655 MEM_RM(obj->allocator, obj); 656 } 657 658 /******************************************************************************* 659 * Exported functions 660 ******************************************************************************/ 661 res_T 662 aw_obj_create 663 (struct logger* logger, 664 struct mem_allocator* mem_allocator, 665 const int verbose, 666 struct aw_obj** obj_out) 667 { 668 struct mem_allocator* allocator; 669 struct aw_obj* obj = NULL; 670 res_T res = RES_OK; 671 672 if(!obj_out) { 673 res = RES_BAD_ARG; 674 goto error; 675 } 676 allocator = mem_allocator ? mem_allocator : &mem_default_allocator; 677 obj = MEM_CALLOC(allocator, 1, sizeof(struct aw_obj)); 678 if(!obj) { 679 res = RES_MEM_ERR; 680 goto error; 681 } 682 ref_init(&obj->ref); 683 obj->allocator = allocator; 684 obj->verbose = verbose; 685 darray_double_init(mem_allocator, &obj->positions); 686 darray_double_init(mem_allocator, &obj->normals); 687 darray_double_init(mem_allocator, &obj->texcoords); 688 darray_vertex_init(mem_allocator, &obj->vertices); 689 darray_face_init(mem_allocator, &obj->faces); 690 darray_named_group_init(mem_allocator, &obj->groups); 691 darray_named_group_init(mem_allocator, &obj->usemtls); 692 darray_smooth_group_init(mem_allocator, &obj->smooth_groups); 693 darray_mtllib_init(mem_allocator, &obj->mtllibs); 694 695 if(logger) { 696 obj->logger = logger; 697 } else { 698 res = setup_default_logger(obj->allocator, &obj->logger__, 699 MSG_PREFIX_INFO, MSG_PREFIX_ERROR, MSG_PREFIX_WARNING); 700 if(res != RES_OK) goto error; 701 obj->logger = &obj->logger__; 702 } 703 704 exit: 705 if(obj_out) 706 *obj_out = obj; 707 return res; 708 error: 709 if(obj) { 710 AW(obj_ref_put(obj)); 711 obj = NULL; 712 } 713 goto exit; 714 } 715 716 res_T 717 aw_obj_ref_get(struct aw_obj* obj) 718 { 719 if(!obj) return RES_BAD_ARG; 720 ref_get(&obj->ref); 721 return RES_OK; 722 } 723 724 res_T 725 aw_obj_ref_put(struct aw_obj* obj) 726 { 727 if(!obj) return RES_BAD_ARG; 728 ref_put(&obj->ref, obj_release); 729 return RES_OK; 730 } 731 732 res_T 733 aw_obj_load(struct aw_obj* obj, const char* filename) 734 { 735 FILE* fp = NULL; 736 res_T res = RES_OK; 737 738 if(!obj || !filename) { 739 res = RES_BAD_ARG; 740 goto error; 741 } 742 743 fp = fopen(filename, "r"); 744 if(!fp) { 745 log_err(obj, "Error opening `%s'.\n", filename); 746 res = RES_IO_ERR; 747 goto error; 748 } 749 750 res = load_stream(obj, fp, filename); 751 if(res != RES_OK) goto error; 752 753 exit: 754 if(fp) fclose(fp); 755 return res; 756 error: 757 goto exit; 758 } 759 760 res_T 761 aw_obj_load_stream(struct aw_obj* obj, FILE* stream, const char* stream_name) 762 { 763 res_T res = RES_OK; 764 765 if(!obj || !stream) { 766 res = RES_BAD_ARG; 767 goto error; 768 } 769 770 res = load_stream(obj, stream, stream_name ? stream_name : "stream"); 771 if(res != RES_OK) goto error; 772 773 exit: 774 return res; 775 error: 776 goto exit; 777 } 778 779 res_T 780 aw_obj_clear(struct aw_obj* obj) 781 { 782 if(!obj) return RES_BAD_ARG; 783 darray_double_clear(&obj->positions); 784 darray_double_clear(&obj->normals); 785 darray_double_clear(&obj->texcoords); 786 darray_vertex_clear(&obj->vertices); 787 darray_face_clear(&obj->faces); 788 darray_named_group_clear(&obj->groups); 789 darray_named_group_clear(&obj->usemtls); 790 darray_smooth_group_clear(&obj->smooth_groups); 791 darray_mtllib_clear(&obj->mtllibs); 792 obj->igroups_active = 0; 793 return RES_OK; 794 } 795 796 res_T 797 aw_obj_purge(struct aw_obj* obj) 798 { 799 if(!obj) return RES_BAD_ARG; 800 darray_double_purge(&obj->positions); 801 darray_double_purge(&obj->normals); 802 darray_double_purge(&obj->texcoords); 803 darray_vertex_purge(&obj->vertices); 804 darray_face_purge(&obj->faces); 805 darray_named_group_purge(&obj->groups); 806 darray_named_group_purge(&obj->usemtls); 807 darray_smooth_group_purge(&obj->smooth_groups); 808 darray_mtllib_purge(&obj->mtllibs); 809 obj->igroups_active = 0; 810 return RES_OK; 811 } 812 813 res_T 814 aw_obj_get_desc(const struct aw_obj* obj, struct aw_obj_desc* desc) 815 { 816 if(!obj || !desc) 817 return RES_BAD_ARG; 818 desc->faces_count = darray_face_size_get(&obj->faces); 819 desc->positions_count = darray_double_size_get(&obj->positions) / 4; 820 desc->normals_count = darray_double_size_get(&obj->normals) / 3; 821 desc->texcoords_count = darray_double_size_get(&obj->texcoords) / 3; 822 desc->groups_count = darray_named_group_size_get(&obj->groups); 823 desc->smooth_groups_count = darray_smooth_group_size_get(&obj->smooth_groups); 824 desc->usemtls_count = darray_named_group_size_get(&obj->usemtls); 825 desc->mtllibs_count = darray_mtllib_size_get(&obj->mtllibs); 826 return RES_OK; 827 } 828 829 res_T 830 aw_obj_get_face 831 (const struct aw_obj* obj, 832 const size_t iface, 833 struct aw_obj_face* face) 834 { 835 if(!obj || !face || iface >= darray_face_size_get(&obj->faces)) 836 return RES_BAD_ARG; 837 *face = darray_face_cdata_get(&obj->faces)[iface]; 838 return RES_OK; 839 } 840 841 res_T 842 aw_obj_get_group 843 (const struct aw_obj* obj, 844 const size_t igroup, 845 struct aw_obj_named_group* grp) 846 { 847 const struct named_group* src = NULL; 848 if(!obj || !grp || igroup >= darray_named_group_size_get(&obj->groups)) 849 return RES_BAD_ARG; 850 src = darray_named_group_cdata_get(&obj->groups) + igroup; 851 grp->name = str_cget(&src->name); 852 grp->face_id = src->face_id; 853 grp->faces_count = src->faces_count; 854 return RES_OK; 855 } 856 857 res_T 858 aw_obj_get_smooth_group 859 (const struct aw_obj* obj, 860 const size_t ismooth_group, 861 struct aw_obj_smooth_group* group) 862 { 863 if(!obj || !group 864 || ismooth_group >= darray_smooth_group_size_get(&obj->smooth_groups)) 865 return RES_BAD_ARG; 866 *group = darray_smooth_group_cdata_get(&obj->smooth_groups)[ismooth_group]; 867 return RES_OK; 868 } 869 870 res_T 871 aw_obj_get_mtl 872 (const struct aw_obj* obj, 873 const size_t imtl, 874 struct aw_obj_named_group* mtl) 875 { 876 const struct named_group* src; 877 if(!obj || !mtl || imtl >= darray_named_group_size_get(&obj->usemtls)) 878 return RES_BAD_ARG; 879 src = darray_named_group_cdata_get(&obj->usemtls) + imtl; 880 mtl->name = str_cget(&src->name); 881 mtl->face_id = src->face_id; 882 mtl->faces_count = src->faces_count; 883 return RES_OK; 884 } 885 886 res_T 887 aw_obj_get_mtllib 888 (const struct aw_obj* obj, 889 const size_t imtllib, 890 const char** mtllib) 891 { 892 const struct str* str; 893 if(!obj || !mtllib || imtllib >= darray_mtllib_size_get(&obj->mtllibs)) 894 return RES_BAD_ARG; 895 str = darray_mtllib_cdata_get(&obj->mtllibs) + imtllib; 896 *mtllib = str_cget(str); 897 return RES_OK; 898 } 899 900 res_T 901 aw_obj_get_vertex 902 (const struct aw_obj* obj, 903 const size_t ivertex, 904 struct aw_obj_vertex* vertex) 905 { 906 if(!obj || !vertex || ivertex >= darray_vertex_size_get(&obj->vertices)) 907 return RES_BAD_ARG; 908 *vertex = darray_vertex_cdata_get(&obj->vertices)[ivertex]; 909 return RES_OK; 910 } 911 912 res_T 913 aw_obj_get_vertex_data 914 (const struct aw_obj* obj, 915 const struct aw_obj_vertex* vertex, 916 struct aw_obj_vertex_data* vertex_data) 917 { 918 const double* data; 919 res_T res = RES_OK; 920 921 if(!obj || !vertex || !vertex_data) { 922 res = RES_BAD_ARG; 923 goto error; 924 } 925 if(vertex->position_id >= darray_double_size_get(&obj->positions) / 4) { 926 res = RES_BAD_ARG; 927 goto error; 928 } 929 if(vertex->texcoord_id != VERTEX_NULL.texcoord_id 930 && vertex->texcoord_id >= darray_double_size_get(&obj->texcoords) / 3) { 931 res = RES_BAD_ARG; 932 goto error; 933 } 934 if(vertex->normal_id != VERTEX_NULL.normal_id 935 && vertex->normal_id >= darray_double_size_get(&obj->normals) / 3) { 936 res = RES_BAD_ARG; 937 goto error; 938 } 939 940 /* Fetch vertex position */ 941 data = darray_double_cdata_get(&obj->positions) + vertex->position_id * 4; 942 vertex_data->position[0] = data[0]; 943 vertex_data->position[1] = data[1]; 944 vertex_data->position[2] = data[2]; 945 vertex_data->position[3] = data[3]; 946 947 /* Setup vertex texcoord */ 948 if(vertex->texcoord_id == VERTEX_NULL.texcoord_id) { 949 vertex_data->texcoord[0] = 0; 950 vertex_data->texcoord[1] = 0; 951 vertex_data->texcoord[2] = 0; 952 } else { 953 data = darray_double_cdata_get(&obj->texcoords) + vertex->texcoord_id * 3; 954 vertex_data->texcoord[0] = data[0]; 955 vertex_data->texcoord[1] = data[1]; 956 vertex_data->texcoord[2] = data[2]; 957 } 958 /* Setup vertex normal */ 959 if(vertex->normal_id == VERTEX_NULL.normal_id) { 960 vertex_data->normal[0] = 0; 961 vertex_data->normal[1] = 0; 962 vertex_data->normal[2] = 0; 963 } else { 964 data = darray_double_cdata_get(&obj->normals) + vertex->normal_id * 3; 965 vertex_data->normal[0] = data[0]; 966 vertex_data->normal[1] = data[1]; 967 vertex_data->normal[2] = data[2]; 968 } 969 970 exit: 971 return res; 972 error: 973 goto exit; 974 } 975 976 res_T 977 aw_obj_get_positions(const struct aw_obj* obj, const double** positions) 978 { 979 if(!obj || !positions) return RES_BAD_ARG; 980 *positions = darray_double_cdata_get(&obj->positions); 981 return RES_OK; 982 } 983 984 res_T 985 aw_obj_get_texcoords(const struct aw_obj* obj, const double** texcoords) 986 { 987 if(!obj || !texcoords) return RES_BAD_ARG; 988 *texcoords = darray_double_cdata_get(&obj->texcoords); 989 return RES_OK; 990 } 991 992 res_T 993 aw_obj_get_normals(const struct aw_obj* obj, const double** normals) 994 { 995 if(!obj || !normals) return RES_BAD_ARG; 996 *normals = darray_double_cdata_get(&obj->normals); 997 return RES_OK; 998 } 999 1000 #ifdef COMPILER_CL 1001 #pragma warning(pop) 1002 #endif 1003