diff --git a/include/ply.h b/include/ply.h new file mode 100644 index 0000000..03cdf86 --- /dev/null +++ b/include/ply.h @@ -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 diff --git a/src/main.c b/src/main.c index cd71da4..ab5e6c0 100644 --- a/src/main.c +++ b/src/main.c @@ -14,11 +14,14 @@ #include #include #include +#include #include #define CGLTF_IMPLEMENTATION #include +#include + typedef struct QueueIndicesStruct { uint32_t graphics_family; uint32_t graphics_index; @@ -3205,7 +3208,7 @@ VkResult draw_frame(VulkanContext* context, SceneContext* scene, uint32_t materi Object create_simple_mesh_object(Material* simple_mesh_material, VkPhysicalDeviceMemoryProperties memories, VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, uint32_t max_frames_in_flight, VkDescriptorPool pool) { Object zero = {}; - Mesh* mesh = load_simple_mesh(memories, device, vertices, 4, indices, 6, transfer_pool, transfer_queue); + Mesh* mesh = load_simple_mesh(memories, device, (struct Vertex*)vertices, 4, (uint16*)indices, 6, transfer_pool, transfer_queue); if(mesh == 0) { return zero; } @@ -3577,9 +3580,9 @@ void cleanup(GLFWwindow* window, VulkanContext* context) { } int main() { - struct VertexMesh* loaded_gltf = load_vertex_gltf("spaceship.glb"); - if(loaded_gltf == 0) { - fprintf(stderr, "failed to load gltf %s\n", "spaceship.glb"); + PlyElement* monkey = ply_load_mesh("monkey.ply"); + if(monkey == 0) { + fprintf(stderr, "failed to load %s\n", "monkey.ply"); return -1; } diff --git a/src/ply.c b/src/ply.c new file mode 100644 index 0000000..82dc8b0 --- /dev/null +++ b/src/ply.c @@ -0,0 +1,289 @@ +#include +#include +#include +#include + +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; +}