/* LIBBUBULLES IMPORT_OBJ some functions for importing bubulles from dot-OBJ files. https://git.tetalab.org/tTh/libbubulle/src/branch/master/tools/ http://fegemo.github.io/cefet-cg/attachments/obj-spec.pdf */ #include #include #include #include #include /* for basename(3) */ #include "../bubulles.h" #include "../edges.h" #include "objtrucs.h" extern int verbosity; /* --------------------------------------------------------------------- */ #define PSYCHOTIK 1 #define LINE_SZ 666 static BBList *bublist; static EdgeList *edges; static int dropped; static int linenumber; static char obj_filename[LINE_SZ+1]; /* --------------------------------------------------------------------- */ typedef struct { char *token; int id; } Tokens; enum token_id { T_comment=1, T_vertice, T_group, T_face, T_vt, T_vn, T_line, T_object, T_smoothing, T_usemtl, T_mtllib }; Tokens TokenList[] = { { "#", T_comment }, { "v", T_vertice }, { "g", T_group }, // to be verified ! { "f", T_face }, { "vt", T_vt }, // c'est quoi ce truc ? { "vn", T_vt }, // c'est quoi ce truc ? { "l", T_line }, { "o", T_object }, { "s", T_smoothing }, // mmmm.... { "usemtl", T_usemtl }, { "mtllib", T_mtllib }, /* and more to come... */ { NULL, 0 } }; /* --------------------------------------------------------------------- */ static int type_of_the_line(char *text) { Tokens *token; #if DEBUG_LEVEL > 1 fprintf(stderr, "%s is searching for '%s'\n", __func__, text); #endif for (token=TokenList; token->token; token++) { // fprintf(stderr, " %5s -> %d\n", token->token, token->id); if (!strcmp(token->token, text)) { return token->id; } } return -1; } /* --------------------------------------------------------------------- */ static int parse_vertice(char *cptr, float *px, float *py, float *pz) { float x, y, z; int foo; /* /!\ this function kill the input buffer */ foo = 0; cptr = strtok(NULL, " "); foo += sscanf(cptr, "%f", &x); cptr = strtok(NULL, " "); foo += sscanf(cptr, "%f", &y); cptr = strtok(NULL, " "); foo += sscanf(cptr, "%f", &z); if (3 == foo) { *px = x; *py = y; *pz = z; } return foo; } /* --------------------------------------------------------------------- */ /* new Mon 27 Mar 2023 12:08:18 AM CEST * * mmmm... complex thing to do... */ static int parse_face(char *cptr, int maxvert) { int ix, foo, a, b; int pts[3], valid; #if DEBUG_LEVEL fprintf(stderr, ">>> %s ( '%s' %d )\n", __func__, cptr, maxvert); #endif #if (0) fprintf(stderr, "parse_face"); for (foo=0; foo<16; foo++) { fprintf(stderr, " %02X", ((unsigned char *)cptr)[foo]); } fprintf(stderr, "\n"); #endif for (ix=0; ix<3; ix++) { cptr = strtok(NULL, " "); if (NULL == cptr) { fprintf(stderr, "incomplete face in %s\n", __func__); return -4; } if (1 != sscanf(cptr, "%d", &pts[ix])) { fprintf(stderr, "%s: err sscanf\n", __func__); exit(1); return -3; } } fprintf(stderr, " %s: pts %5d %5d %5d\n", __func__, pts[0], pts[1], pts[2]); valid = 1; /**** check the freshly read datas ****/ if ( pts[0]==pts[1] || pts[0]==pts[2] || pts[2]==pts[1] ) { fprintf(stderr, "%s: degenerated face ( %d %d %d )\n", __func__, pts[0], pts[1], pts[2]); dropped++; valid = 0; } if ( (pts[0]>maxvert) || (pts[1]>maxvert) || (pts[2]>maxvert) ) { fprintf(stderr, "%s: out of bound ( %d %d %d )\n", __func__, pts[0], pts[1], pts[2]); valid = 0; } /* * may be we can check the "degenerated cylinder" here ? */ if (valid) { for (ix=0; ix<3; ix++) { a = ix % 3; b = (ix+1) % 3; #if PSYCHOTIK foo = push_a_missing_edge(edges, pts[a], pts[b]); #else foo = push_an_edge(edges, pts[a], pts[b]); #endif if (foo) { fprintf(stderr, "%s: disaster #%d line %d\n", __func__, foo, linenumber); return -2; } } } if (dropped) fprintf(stderr, "%s: %d dropped\n", __func__, dropped); #if DEBUG_LEVEL > 1 fprintf(stderr, "<<< %s\n", __func__); #endif return 0; } /* --------------------------------------------------------------------- */ /* * The main procedure, who contains a lot of things. */ int try_to_read_an_OBJ_file(char *infname, char *ofname, int outstyle) { FILE *fpin; char line[LINE_SZ+1], *cptr, *token; float x, y, z; int foo, bar, tokenid; Bubulle bubulle; char *outfname, *baseptr; #if DEBUG_LEVEL fprintf(stderr, ">>> %s ( '%s' '%s' %d )\n", __func__, infname, ofname, outstyle); #endif #if PSYCHOTIK fprintf(stderr, " *** PSYCHOTIK MODE ENGAGED ***\n"); #endif /* get memory for generated output filename(s) */ if (NULL==(outfname=malloc(strlen(infname)+33)) ) { fprintf(stderr, "%s : not enough mem, sorry\n", __func__); return -666; } if (NULL==(fpin=fopen(infname, "r"))) { perror(infname); exit(1); } linenumber = 0; bublist = alloc_bubulles(infname, 800000, 0); if (NULL==bublist) { fprintf(stderr, "in %s, no mem for bubls, aborting...\n", __func__); abort(); } if (verbosity > 1) print_bublist_desc(bublist, 0); edges = alloc_edgelist("krkrkr", 3000000, 0); if (NULL==edges) { fprintf(stderr, "no mem for edges in %s, aborting...\n", __func__); abort(); } if (verbosity > 1) print_edgelist_desc(edges, 0); fprintf(stderr, " +-----------------------------------------\n"); while(NULL!=(cptr=fgets(line, LINE_SZ, fpin))) { if ('\n' != line[strlen(line)-1]) { fprintf(stderr, "%s: short read on %s line %d\n", __func__, infname, linenumber); // return -2; break; } line[strlen(line)-1] = '\0'; /* kill the newline */ if (verbosity>1) fprintf(stderr, "line read ==|%s|==\n", line); linenumber++; cptr = strtok(line, " "); if (NULL == cptr) { /* this is an empty line */ // fprintf(stderr, "no token ?\n"); continue; } if ('#' == cptr[0]) { // found a comment fprintf(stderr, " %s\n", cptr); continue; } token = cptr; tokenid = type_of_the_line(cptr); if (verbosity > 1) fprintf(stderr, "token '%s' --> %d\n", cptr, tokenid); memset(&bubulle, 0, sizeof(Bubulle)); switch (tokenid) { case T_comment: /* do nothing */ break; case T_vertice: x = y = z = 0.0; foo = parse_vertice(cptr, &x, &y, &z); if (3 != foo) { fprintf(stderr, "err %d parse vertice %s\n", foo, cptr); abort(); } bubulle.p.x = x; bubulle.p.y = y; bubulle.p.z = z; if (verbosity > 2) niceprint_bubulle(&bubulle, 0); foo = push_bubulle(bublist, &bubulle); if (foo) { fprintf(stderr, "err %d push bubulle\n", foo); abort(); } fprintf(stderr, "pushed %f %f %f (%d)\n", x, y, z, bublist->fidx); break; case T_face: /* experimental code here */ bar = bublist->fidx - 1; foo = parse_face(cptr, bar); if (foo) { fprintf(stderr, "line %d '%s' parseface -> %d\n", linenumber, cptr, foo); exit(1); } break; case T_object: cptr = strtok(NULL, " "); fprintf(stderr, "\tObject: %s\n", cptr); break; case T_group: cptr = strtok(NULL, " "); fprintf(stderr, "\tGroup: %s\n", cptr); break; case T_usemtl: cptr = strtok(NULL, " "); fprintf(stderr, "\tUsemtl: %s\n", cptr); break; case T_mtllib: cptr = strtok(NULL, " "); fprintf(stderr, "\tMtllib: %s\n", cptr); break; case T_line: cptr = strtok(NULL, " "); fprintf(stderr, "\tLine: %s\n", cptr); break; case T_smoothing: cptr = strtok(NULL, " "); if (verbosity) fprintf(stderr, "\tSmoothing: %s\n", cptr); break; case T_vt: cptr = strtok(NULL, " "); if (verbosity) fprintf(stderr, "\tvt ??? : %s\n", cptr); break; default: fprintf(stderr, "W: token %s -> %d ?\n", token, tokenid); break; } } fclose(fpin); fprintf(stderr, " +-----------------------------------------\n"); if(verbosity) { fprintf(stderr, "%s: %d vertices and %d edges loaded.\n", __func__, bublist->fidx, edges->fidx); } if (verbosity > 1) { print_bublist_desc(bublist, 0); print_edgelist_desc(edges, 0); } if (outstyle) { /* two ascii files */ strcpy(outfname, infname); cptr = rindex(outfname, '.'); fprintf(stderr, "rindex -> [%s]\n", cptr); strcpy(cptr, ".vertices"); bubulles_to_data(outfname, NULL, bublist, 0); // edges_to_data(file_edges, edges, 0); } else { /* one 'evblob' file */ if (NULL == ofname) { strcpy(outfname, infname); /* see manpage basename(3) */ baseptr = basename(outfname); // fprintf(stderr, "baseptr -> [%s]\n", baseptr); cptr = rindex(baseptr, '.'); strcpy(cptr, ".evblob"); fprintf(stderr, "baseptr-> [%s]\n", baseptr); cptr = baseptr; } else { cptr = ofname; fprintf(stderr, "writing to %s\n", cptr); } foo = x_write_vertedges(cptr, bublist, edges); if (foo) { fprintf(stderr, "Err #%d when writing edges&vertices file\n", foo); } } // Cleanup free(outfname); free_bubulles(bublist, 0); free_edgelist(edges, 0); return 0; } /* --------------------------------------------------------------------- */