#define _GNU_SOURCE #include #include #include #include "objload.h" // TODO: !! vert_idx, norm_idx and uv_idx currently // must be present for all faces // TODO: face vertices is hard-coded to 3 #define OBJ_CHECK(x) do { \ OBJRES res = x; \ if(res != OBJ_SUCCESS) return res; \ } while(0) static OBJRES data_allocate(FILE *fp, objload_t *obj); static OBJRES data_load(FILE *fp, objload_t *obj); static OBJRES data_load_vert(char *line, float vertex[3]); static OBJRES data_load_norm(char *line, float normal[3]); static OBJRES data_load_uv(char *line, float uvcoord[2]); static OBJRES data_load_face(char *line, struct face face[3]); static OBJRES data_load_face_entry(char *entry, struct face *face); OBJRES obj_load(FILE *fp, objload_t *obj) { fseek(fp, 0, SEEK_SET); OBJ_CHECK(data_allocate(fp, obj)); fseek(fp, 0, SEEK_SET); OBJ_CHECK(data_load(fp, obj)); return OBJ_SUCCESS; } void obj_free(objload_t obj) { if(obj.nvert) free(obj.vertices); if(obj.nnorm) free(obj.normals); if(obj.nuv) free(obj.uvcoord); if(obj.nfaces) free(obj.faces); } OBJRES obj_transfer_raw(objload_t obj, struct obj_struct_metadata metadata, size_t *nvbo, void *vbo) { if(vbo == NULL) { *nvbo = obj.nfaces * 3; return OBJ_SUCCESS; } for(size_t i = 0; i < *nvbo; i++) { if(metadata.exist_flag & OBJ_STRUCT_VERT_EXISTS) { memcpy(vbo + metadata.vert_off, obj.vertices[obj.faces[i/3][i%3].vertidx -1], sizeof(*obj.vertices)); } if(metadata.exist_flag & OBJ_STRUCT_NORM_EXISTS) { memcpy(vbo + metadata.norm_off, obj.normals[obj.faces[i/3][i%3].normidx -1], sizeof(*obj.normals)); } if(metadata.exist_flag & OBJ_STRUCT_UVTX_EXISTS) { memcpy(vbo + metadata.uvtx_off, obj.uvcoord[obj.faces[i/3][i%3].uvidx -1], sizeof(*obj.uvcoord)); } vbo += metadata.full_sz; } return OBJ_SUCCESS; } static OBJRES data_allocate(FILE *fp, objload_t *obj) { char line[256] = {0}; while(fgets(line, sizeof(line), fp)) { // printf("%s\n", line); switch(line[0]) { case 'o': break; case 'v': switch(line[1]) { case ' ': obj->nvert++; break; case 'n': obj->nnorm++; break; case 't': obj->nuv++; break; default: return OBJ_LINE_UNKNOWN; } break; case 'f': obj->nfaces++; break; case 'l': case 'm': case 's': case 'u': break; // temporary return OBJ_NOT_SUPPORTED_LINE; case '#': case EOF: break; default: return OBJ_LINE_UNKNOWN; } } obj->vertices = calloc(obj->nvert, sizeof(*obj->vertices)); obj->normals = calloc(obj->nnorm, sizeof(*obj->normals)); obj->uvcoord = calloc(obj->nuv, sizeof(*obj->uvcoord)); obj->faces = calloc(obj->nfaces, sizeof(*obj->faces)); return OBJ_SUCCESS; } static OBJRES data_load(FILE *fp, objload_t *obj) { size_t vert_idx = 0; size_t norm_idx = 0; size_t uv_idx = 0; size_t face_idx = 0; char line[256] = {0}; while(fgets(line, sizeof(line), fp)) { switch(line[0]) { case 'v': switch(line[1]) { case ' ': data_load_vert(line, obj->vertices[vert_idx++]); break; case 'n': data_load_norm(line, obj->normals[norm_idx++]); break; case 't': data_load_uv(line, obj->uvcoord[uv_idx++]); break; default: break; } break; case 'f': data_load_face(line, obj->faces[face_idx++]); break; case '#': break; default: break; } } return OBJ_SUCCESS; } static OBJRES data_load_vert(char *line, float vertex[3]) { char *saveptr; strtok_r(line, " ", &saveptr); vertex[0] = strtof(strtok_r(NULL, " ", &saveptr), NULL); vertex[1] = strtof(strtok_r(NULL, " ", &saveptr), NULL); vertex[2] = strtof(strtok_r(NULL, " ", &saveptr), NULL); return OBJ_SUCCESS; } static OBJRES data_load_norm(char *line, float normal[3]) { char *saveptr; strtok_r(line, " ", &saveptr); normal[0] = strtof(strtok_r(NULL, " ", &saveptr), NULL); normal[1] = strtof(strtok_r(NULL, " ", &saveptr), NULL); normal[2] = strtof(strtok_r(NULL, " ", &saveptr), NULL); return OBJ_SUCCESS; } static OBJRES data_load_uv(char *line, float uvcoord[2]) { char *saveptr; strtok_r(line, " ", &saveptr); uvcoord[0] = strtof(strtok_r(NULL, " ", &saveptr), NULL); uvcoord[1] = strtof(strtok_r(NULL, " ", &saveptr), NULL); return OBJ_SUCCESS; } static OBJRES data_load_face(char *line, struct face face[3]) { char *saveptr; strtok_r(line, " ", &saveptr); data_load_face_entry(strtok_r(NULL, " ", &saveptr), &face[0]); data_load_face_entry(strtok_r(NULL, " ", &saveptr), &face[1]); data_load_face_entry(strtok_r(NULL, " ", &saveptr), &face[2]); return OBJ_SUCCESS; } static OBJRES data_load_face_entry(char *entry, struct face *face) { char *saveptr; face->vertidx = strtoull(strtok_r(entry, "/", &saveptr), NULL, 10); face->uvidx = strtoull(strtok_r(NULL, "/", &saveptr), NULL, 10); face->normidx = strtoull(strtok_r(NULL, "/", &saveptr), NULL, 10); return OBJ_SUCCESS; }