Added code to parse PLY file into attribute/property arrays
parent
36f4947c6c
commit
77be219c37
@ -0,0 +1,52 @@
|
||||
#ifndef PLY_H
|
||||
#define PLY_H
|
||||
|
||||
typedef enum {
|
||||
PLY_FORMAT_INVALID = -1,
|
||||
PLY_FORMAT_ASCII,
|
||||
PLY_FORMAT_LE,
|
||||
PLY_FORMAT_BE,
|
||||
} PlyFormatType;
|
||||
|
||||
typedef enum {
|
||||
PLY_HEADER_INVALID = -1,
|
||||
PLY_HEADER_COMMENT,
|
||||
PLY_HEADER_END,
|
||||
PLY_HEADER_ELEMENT,
|
||||
PLY_HEADER_PROPERTY,
|
||||
} PlyHeaderType;
|
||||
|
||||
typedef enum {
|
||||
PLY_TYPE_INVALID = -1,
|
||||
PLY_TYPE_CHAR,
|
||||
PLY_TYPE_UCHAR,
|
||||
PLY_TYPE_SHORT,
|
||||
PLY_TYPE_USHORT,
|
||||
PLY_TYPE_INT,
|
||||
PLY_TYPE_UINT,
|
||||
PLY_TYPE_FLOAT,
|
||||
PLY_TYPE_DOUBLE,
|
||||
} PlyPropertyType;
|
||||
|
||||
typedef struct PlyPropertyStruct {
|
||||
char* name;
|
||||
PlyPropertyType count;
|
||||
PlyPropertyType element;
|
||||
|
||||
void* elements;
|
||||
void* counts;
|
||||
struct PlyPropertyStruct* next;
|
||||
} PlyProperty;
|
||||
|
||||
typedef struct PlyElementStruct {
|
||||
char* name;
|
||||
int count;
|
||||
PlyProperty* properties;
|
||||
|
||||
struct PlyElementStruct* next;
|
||||
} PlyElement;
|
||||
|
||||
PlyElement* ply_load_mesh(char* filename);
|
||||
void ply_free_mesh(PlyElement* elements_head);
|
||||
|
||||
#endif
|
@ -0,0 +1,289 @@
|
||||
#include <stdlib.h>
|
||||
#include <ply.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
char* ply_formats[] = {
|
||||
"ascii",
|
||||
"binary_little_endian",
|
||||
"binary_big_endian"
|
||||
};
|
||||
|
||||
char* ply_header_items[] = {
|
||||
"comment",
|
||||
"end_header",
|
||||
"element",
|
||||
"property",
|
||||
};
|
||||
|
||||
char* ply_type_strings[] = {
|
||||
"char",
|
||||
"uchar",
|
||||
"short",
|
||||
"ushort",
|
||||
"int",
|
||||
"uint",
|
||||
"float",
|
||||
"double",
|
||||
};
|
||||
|
||||
size_t ply_type_sizes[] = {
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
8,
|
||||
};
|
||||
|
||||
PlyPropertyType ply_parse_type(const char* type_string) {
|
||||
for(uint32_t i = 0; i < sizeof(ply_type_strings)/sizeof(char*); i++) {
|
||||
if(strcmp(ply_type_strings[i], type_string) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return PLY_TYPE_INVALID;
|
||||
}
|
||||
|
||||
void ply_free_mesh(PlyElement* elements_head) {
|
||||
PlyElement* elem = elements_head;
|
||||
while(elem != NULL) {
|
||||
PlyProperty* prop = elem->properties;
|
||||
while(prop != NULL) {
|
||||
if(prop->count == PLY_TYPE_INVALID) {
|
||||
if(prop->elements != NULL) {
|
||||
free(prop->elements);
|
||||
}
|
||||
} else {
|
||||
if(prop->elements != NULL) {
|
||||
void** lists = prop->elements;
|
||||
for(int i = 0; i < elem->count; i++) {
|
||||
if(lists[i] != NULL) {
|
||||
free(lists[i]);
|
||||
}
|
||||
}
|
||||
free(prop->elements);
|
||||
}
|
||||
|
||||
if(prop->counts != NULL) {
|
||||
free(prop->counts);
|
||||
}
|
||||
|
||||
if(prop->name != NULL) {
|
||||
free(prop->name);
|
||||
}
|
||||
}
|
||||
PlyProperty* last = prop;
|
||||
prop = prop->next;
|
||||
free(last);
|
||||
}
|
||||
|
||||
if(elem->name != NULL) {
|
||||
free(elem->name);
|
||||
}
|
||||
|
||||
PlyElement* last = elem;
|
||||
elem = elem->next;
|
||||
free(last);
|
||||
}
|
||||
}
|
||||
|
||||
PlyElement* ply_load_mesh(char* filename) {
|
||||
FILE* ply = fopen(filename, "r");
|
||||
if(ply == NULL) {
|
||||
fprintf(stderr, "file not found %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t buffer[1024] = {0};
|
||||
char magic[] = {'p', 'l', 'y', '\n'};
|
||||
int read = fread(buffer, 1, sizeof(magic), ply);
|
||||
if(read != sizeof(magic)) {
|
||||
fprintf(stderr, "magic not read\n");
|
||||
goto close;
|
||||
} else if (memcmp(buffer, magic, sizeof(magic)) != 0) {
|
||||
fprintf(stderr, "magic not match\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
char* line = fgets((char*)buffer, 1024, ply);
|
||||
if(line == NULL) {
|
||||
fprintf(stderr, "file read err\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
char* format_str = "format ";
|
||||
if(memcmp(format_str, line, 7) != 0) {
|
||||
fprintf(stderr, "format start not found\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
char* format_start = &line[7];
|
||||
PlyFormatType format_id = PLY_FORMAT_INVALID;
|
||||
for(uint32_t i = 0; i < sizeof(ply_formats)/sizeof(char*); i++) {
|
||||
if(memcmp(format_start, ply_formats[i], strlen(ply_formats[i])) == 0) {
|
||||
format_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(format_id == PLY_FORMAT_INVALID) {
|
||||
fprintf(stderr, "unknown format %s\n", line);
|
||||
goto close;
|
||||
}
|
||||
|
||||
PlyElement* elements_head = NULL;
|
||||
PlyElement* element = NULL;
|
||||
|
||||
while(1) {
|
||||
char* line = fgets((char*)buffer, 1024, ply);
|
||||
PlyHeaderType header_id = PLY_HEADER_INVALID;
|
||||
for(uint32_t i = 0; i < sizeof(ply_header_items)/sizeof(char*); i++) {
|
||||
if(memcmp(line, ply_header_items[i], strlen(ply_header_items[i])) == 0) {
|
||||
header_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(header_id == PLY_FORMAT_INVALID) {
|
||||
fprintf(stderr, "unknown header line: %s\n", line);
|
||||
goto close;
|
||||
} else if (header_id == PLY_HEADER_COMMENT) {
|
||||
continue;
|
||||
} else if (header_id == PLY_HEADER_END) {
|
||||
break;
|
||||
} else if (header_id == PLY_HEADER_ELEMENT) {
|
||||
PlyElement* new_element = malloc(sizeof(PlyElement));
|
||||
new_element->next = NULL;
|
||||
new_element->properties = NULL;
|
||||
|
||||
char* first = strtok((char*)buffer, " ");
|
||||
(void)first;
|
||||
char* name = strtok(NULL, " ");
|
||||
char* count = strtok(NULL, " ");
|
||||
if(name == NULL || count == NULL) {
|
||||
fprintf(stderr, "BAD_ELEMENT: %s\n", line);
|
||||
goto clean;
|
||||
}
|
||||
unsigned long name_len = strlen(name) + 1;
|
||||
new_element->name = malloc(name_len);
|
||||
memcpy(new_element->name, name, name_len);
|
||||
|
||||
new_element->count = atoi(count);
|
||||
|
||||
if(elements_head == NULL) {
|
||||
elements_head = new_element;
|
||||
element = new_element;
|
||||
} else {
|
||||
element->next = new_element;
|
||||
element = new_element;
|
||||
}
|
||||
} else if (header_id == PLY_HEADER_PROPERTY) {
|
||||
if(element == NULL) {
|
||||
fprintf(stderr, "parsed property before any element\n");
|
||||
goto clean;
|
||||
}
|
||||
PlyProperty* new_property = malloc(sizeof(PlyProperty));
|
||||
new_property->name = NULL;
|
||||
new_property->count = PLY_TYPE_INVALID;
|
||||
new_property->element = PLY_TYPE_INVALID;
|
||||
new_property->next = NULL;
|
||||
new_property->elements = NULL;
|
||||
new_property->counts = NULL;
|
||||
|
||||
char* extra = strtok((char*)buffer, " ");
|
||||
(void)extra;
|
||||
|
||||
char* type_str = strtok(NULL, " ");
|
||||
if(strcmp(type_str, "list") == 0) {
|
||||
type_str = strtok(NULL, " ");
|
||||
new_property->count = ply_parse_type(type_str);
|
||||
type_str = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
new_property->element = ply_parse_type(type_str);
|
||||
|
||||
type_str = strtok(NULL, " ");
|
||||
char* name = strtok(type_str, "\n");
|
||||
if(name == NULL) {
|
||||
fprintf(stderr, "invalid property\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
unsigned long name_len = strlen(name) + 1;
|
||||
new_property->name = malloc(name_len);
|
||||
memcpy(new_property->name, name, name_len);
|
||||
|
||||
PlyProperty* cur = element->properties;
|
||||
if(cur == NULL) {
|
||||
element->properties = new_property;
|
||||
} else {
|
||||
while(cur->next != NULL) {
|
||||
cur = cur->next;
|
||||
}
|
||||
cur->next = new_property;
|
||||
}
|
||||
}
|
||||
|
||||
if(line == NULL) {
|
||||
goto close;
|
||||
}
|
||||
}
|
||||
|
||||
PlyElement* elem = elements_head;
|
||||
while(elem != NULL) {
|
||||
PlyProperty* prop = elem->properties;
|
||||
while(prop != NULL) {
|
||||
if(prop->count == PLY_TYPE_INVALID) {
|
||||
prop->elements = malloc(ply_type_sizes[prop->element]*elem->count);
|
||||
prop->counts = NULL;
|
||||
} else {
|
||||
prop->elements = malloc(sizeof(void*)*elem->count);
|
||||
prop->counts = malloc(sizeof(ply_type_sizes[prop->count])*elem->count);
|
||||
}
|
||||
prop = prop->next;
|
||||
}
|
||||
|
||||
for(int i = 0; i < elem->count; i++) {
|
||||
PlyProperty* prop = elem->properties;
|
||||
while(prop != NULL) {
|
||||
if(prop->count == PLY_TYPE_INVALID) {
|
||||
int read = fread(prop->elements + (i*ply_type_sizes[prop->element]), ply_type_sizes[prop->element], 1, ply);
|
||||
if(read != 1) {
|
||||
fprintf(stderr, "prop read error\n");
|
||||
goto clean;
|
||||
}
|
||||
} else {
|
||||
uint64_t size = 0;
|
||||
uint64_t read = fread(&size, ply_type_sizes[prop->count], 1, ply);
|
||||
if(read != 1) {
|
||||
fprintf(stderr, "prop read error\n");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
memcpy(prop->counts + (i*ply_type_sizes[prop->count]), &size, ply_type_sizes[prop->count]);
|
||||
void* elements = malloc(ply_type_sizes[prop->element]*size);
|
||||
read = fread(elements, ply_type_sizes[prop->element], size, ply);
|
||||
if(read != size) {
|
||||
fprintf(stderr, "prop read error\n");
|
||||
goto clean;
|
||||
}
|
||||
memcpy(prop->elements + (i*sizeof(void*)), &elements, sizeof(void*));
|
||||
}
|
||||
prop = prop->next;
|
||||
}
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
|
||||
fclose(ply);
|
||||
return elements_head;
|
||||
|
||||
clean:
|
||||
ply_free_mesh(elements_head);
|
||||
close:
|
||||
fclose(ply);
|
||||
return NULL;
|
||||
}
|
Loading…
Reference in New Issue