hermespy-rt

Minimalistic signal processing ray-tracer in C
git clone https://git.ea.contact/hermespy-rt
Log | Files | Refs

commit ac2e2edc450ebfa639408b5a889365359eaac1fc
parent 95df8e8e0a17bd4c4196056d2911e076f64ef3fd
Author: Egor Achkasov <eaachkasov@edu.hse.ru>
Date:   Tue, 25 Mar 2025 22:22:35 +0100

Implement Sionna xml reader; Add material string->material_index map; Minor refactor

Diffstat:
Mcompute_paths.c | 5+++--
Ainc/common.h | 16++++++++++++++++
Ainc/materials.h | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minc/scene.h | 121+++----------------------------------------------------------------------------
Mscene_fromSionna.c | 424++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
5 files changed, 411 insertions(+), 307 deletions(-)

diff --git a/compute_paths.c b/compute_paths.c @@ -1,5 +1,6 @@ -#include "compute_paths.h" /* for compute_paths */ -#include "scene.h" /* for HRT_Scene, HRT_mesh, HRT_Material */ +#include "inc/compute_paths.h" /* for compute_paths */ +#include "inc/scene.h" /* for HRT_Scene, HRT_mesh, HRT_Material */ +#include "inc/materials.h" /* for g_hrt_materials */ #include <stddef.h> /* for size_t */ #include <stdlib.h> /* for exit, malloc, free */ diff --git a/inc/common.h b/inc/common.h @@ -0,0 +1,16 @@ +#define IN +#define OUT + +#define FREE_POINTERS(...) \ + do { \ + void *ptrs[] = {__VA_ARGS__};\ + for (size_t i = 0; i < sizeof(ptrs) / sizeof(ptrs[0]); i++) \ + free(ptrs[i]); \ + } while (0) + +#define PERROR_CLEANUP_EXIT(msg, rc, ...) \ + do { \ + perror(msg); \ + FREE_POINTERS(__VA_ARGS__); \ + exit(rc); \ + } while (0) diff --git a/inc/materials.h b/inc/materials.h @@ -0,0 +1,152 @@ +#ifndef MATERIALS_H +#define MATERIALS_H + +#include "scene.h" /* for HRT_Material */ + +#include <stdint.h> /* for uint32_t */ +#include <string.h> /* for strncmp */ + +/* number of defined materials */ +#define NUM_G_MATERIALS 17 +HRT_Material g_hrt_materials[NUM_G_MATERIALS] = { + /* 0 */ + {3, "air", + 1.f, 0.f, 0.f, 0.001f, + 0.1f, 0.5f, 0.3f, 0.2f, + 2, 2}, + /* 1 */ + {8, "concrete", + 5.24f, 0.f, 0.0462f, 0.7822f, + 0.5f, 0.33f, 0.34f, 0.33f, + 4, 4}, + /* 2 */ + {5, "brick", + 3.91f, 0.f, 0.0238f, 0.16f, + 0.4f, 0.4f, 0.3f, 0.3f, + 3, 3}, + /* 3 */ + {12, "plasterboard", + 2.73f, 0.f, 0.0085f, 0.9395f, + 0.3f, 0.4f, 0.4f, 0.2f, + 3, 3}, + /* 4 */ + {4, "wood", + 1.99f, 0.f, 0.0047f, 1.0718f, + 0.2f, 0.5f, 0.3f, 0.2f, + 2, 2}, + /* 5 */ + {5, "glass", + 6.31f, 0.f, 0.0036f, 1.3394f, + 0.3f, 0.4f, 0.4f, 0.2f, + 3, 3}, + /* 6 */ + {5, "glass", + 5.79f, 0.f, 0.0004f, 1.658f, + 0.3f, 0.4f, 0.4f, 0.2f, + 3, 3}, + /* 7 */ + {13, "ceiling board", + 1.48f, 0.f, 0.0011f, 1.0750f, + 0.2f, 0.5f, 0.3f, 0.2f, + 2, 2}, + /* 8 */ + {13, "ceiling board", + 1.52f, 0.f, 0.0029f, 1.029f, + 0.2f, 0.5f, 0.3f, 0.2f, + 2, 2}, + /* 9 */ + {9, "chipboard", + 2.58f, 0.f, 0.0217f, 0.7800f, + 0.4f, 0.4f, 0.3f, 0.3f, + 3, 3}, + /* 10 */ + {7, "plywood", + 2.71f, 0.f, 0.33f, 0.f, + 0.3f, 0.5f, 0.3f, 0.2f, + 3, 3}, + /* 11 */ + {6, "marble", + 7.074f, 0.f, 0.0055f, + 0.9262f, 0.3f, 0.4f, 0.4f, 0.2f, + 3, 3}, + /* 12 */ + {10, "floorboard", + 3.66f, 0.f, 0.0044f, 1.3515f, + 0.3f, 0.4f, 0.4f, 0.2f, + 3, 3}, + /* 13 */ + {5, "metal", + 1.f, 0.f, 10000000.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 1, 1}, + /* 14 */ + {15, "very dry ground", + 3.f, 0.f, 0.00015f, 2.52f, + 0.4f, 0.3f, 0.4f, 0.3f, + 4, 4}, + /* 15 */ + {17, "medium dry ground", + 15.f, -0.1f, 0.035f, 1.63f, + 0.5f, 0.33f, 0.34f, 0.33f, + 4, 4}, + /* 16 */ + {10, "wet ground", + 30.f, -0.4f, 0.15f, 1.30f, + 0.5f, 0.33f, 0.34f, 0.33f, + 4, 4} +}; +typedef enum { + MATERIAL_AIR = 0, + MATERIAL_CONCRETE = 1, + MATERIAL_BRICK = 2, + MATERIAL_PLASTERBOARD = 3, + MATERIAL_WOOD = 4, + MATERIAL_GLASS1 = 5, + MATERIAL_GLASS2 = 6, + MATERIAL_CEILING_BOARD1 = 7, + MATERIAL_CEILING_BOARD2 = 8, + MATERIAL_CHIPBOARD = 9, + MATERIAL_PLYWOOD = 10, + MATERIAL_MARBLE = 11, + MATERIAL_FLOORBOARD = 12, + MATERIAL_METAL = 13, + MATERIAL_VERY_DRY_GROUND = 14, + MATERIAL_MEDIUM_DRY_GROUND = 15, + MATERIAL_WET_GROUND = 16 +} MaterialIndex; + +/* Map material name strings to material indices */ +typedef struct { + /* Material name. Null-terminated string. Lower case. */ + const char *name; + MaterialIndex index; +} MaterialMap; + +MaterialMap material_map[] = { + {"air", MATERIAL_AIR}, + {"concrete", MATERIAL_CONCRETE}, + {"brick", MATERIAL_BRICK}, + {"plasterboard", MATERIAL_PLASTERBOARD}, + {"wood", MATERIAL_WOOD}, + {"glass1", MATERIAL_GLASS1}, + {"glass2", MATERIAL_GLASS2}, + {"ceiling_board1", MATERIAL_CEILING_BOARD1}, + {"ceiling_board2", MATERIAL_CEILING_BOARD2}, + {"chipboard", MATERIAL_CHIPBOARD}, + {"plywood", MATERIAL_PLYWOOD}, + {"marble", MATERIAL_MARBLE}, + {"floorboard", MATERIAL_FLOORBOARD}, + {"metal", MATERIAL_METAL}, + {"very_dry_ground", MATERIAL_VERY_DRY_GROUND}, + {"medium_dry_ground", MATERIAL_MEDIUM_DRY_GROUND}, + {"wet_ground", MATERIAL_WET_GROUND} +}; + +MaterialIndex get_material_index(const char *name) { + for (uint32_t i = 0; i < NUM_G_MATERIALS; ++i) + if (strcmp(material_map[i].name, name) == 0) + return material_map[i].index; + return MATERIAL_AIR; /* Invalid material. Default to air */ +} + +#endif /* MATERIALS_H */ diff --git a/inc/scene.h b/inc/scene.h @@ -1,8 +1,7 @@ -#include <stdint.h> /* for uint32_t */ +#ifndef SCENE_H +#define SCENE_H -/*******************************************************************/ -/* Scene */ -/*******************************************************************/ +#include <stdint.h> /* for uint32_t */ typedef struct { /* Number of vertices */ @@ -24,10 +23,6 @@ typedef struct { HRT_Mesh *meshes; } HRT_Scene; -/*******************************************************************/ -/* Materials */ -/*******************************************************************/ - typedef struct { /* Number of characters in the name */ uint32_t name_sz; @@ -62,112 +57,4 @@ typedef struct { uint8_t s3_alpha; } HRT_Material; -/* number of defined materials */ -#define NUM_G_MATERIALS 17 -HRT_Material g_hrt_materials[NUM_G_MATERIALS] = { - /* 0 */ - {3, "air", - 1.f, 0.f, 0.f, 0.001f, - 0.1f, 0.5f, 0.3f, 0.2f, - 2, 2}, - /* 1 */ - {8, "concrete", - 5.24f, 0.f, 0.0462f, 0.7822f, - 0.5f, 0.33f, 0.34f, 0.33f, - 4, 4}, - /* 2 */ - {5, "brick", - 3.91f, 0.f, 0.0238f, 0.16f, - 0.4f, 0.4f, 0.3f, 0.3f, - 3, 3}, - /* 3 */ - {12, "plasterboard", - 2.73f, 0.f, 0.0085f, 0.9395f, - 0.3f, 0.4f, 0.4f, 0.2f, - 3, 3}, - /* 4 */ - {4, "wood", - 1.99f, 0.f, 0.0047f, 1.0718f, - 0.2f, 0.5f, 0.3f, 0.2f, - 2, 2}, - /* 5 */ - {5, "glass", - 6.31f, 0.f, 0.0036f, 1.3394f, - 0.3f, 0.4f, 0.4f, 0.2f, - 3, 3}, - /* 6 */ - {5, "glass", - 5.79f, 0.f, 0.0004f, 1.658f, - 0.3f, 0.4f, 0.4f, 0.2f, - 3, 3}, - /* 7 */ - {13, "ceiling board", - 1.48f, 0.f, 0.0011f, 1.0750f, - 0.2f, 0.5f, 0.3f, 0.2f, - 2, 2}, - /* 8 */ - {13, "ceiling board", - 1.52f, 0.f, 0.0029f, 1.029f, - 0.2f, 0.5f, 0.3f, 0.2f, - 2, 2}, - /* 9 */ - {9, "chipboard", - 2.58f, 0.f, 0.0217f, 0.7800f, - 0.4f, 0.4f, 0.3f, 0.3f, - 3, 3}, - /* 10 */ - {7, "plywood", - 2.71f, 0.f, 0.33f, 0.f, - 0.3f, 0.5f, 0.3f, 0.2f, - 3, 3}, - /* 11 */ - {6, "marble", - 7.074f, 0.f, 0.0055f, - 0.9262f, 0.3f, 0.4f, 0.4f, 0.2f, - 3, 3}, - /* 12 */ - {10, "floorboard", - 3.66f, 0.f, 0.0044f, 1.3515f, - 0.3f, 0.4f, 0.4f, 0.2f, - 3, 3}, - /* 13 */ - {5, "metal", - 1.f, 0.f, 10000000.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 1, 1}, - /* 14 */ - {15, "very dry ground", - 3.f, 0.f, 0.00015f, 2.52f, - 0.4f, 0.3f, 0.4f, 0.3f, - 4, 4}, - /* 15 */ - {17, "medium dry ground", - 15.f, -0.1f, 0.035f, 1.63f, - 0.5f, 0.33f, 0.34f, 0.33f, - 4, 4}, - /* 16 */ - {10, "wet ground", - 30.f, -0.4f, 0.15f, 1.30f, - 0.5f, 0.33f, 0.34f, 0.33f, - 4, 4} -}; -typedef enum { - MATERIAL_AIR = 0, - MATERIAL_CONCRETE = 1, - MATERIAL_BRICK = 2, - MATERIAL_PLASTERBOARD = 3, - MATERIAL_WOOD = 4, - MATERIAL_GLASS1 = 5, - MATERIAL_GLASS2 = 6, - MATERIAL_CEILING_BOARD1 = 7, - MATERIAL_CEILING_BOARD2 = 8, - MATERIAL_CHIPBOARD = 9, - MATERIAL_PLYWOOD = 10, - MATERIAL_MARBLE = 11, - MATERIAL_FLOORBOARD = 12, - MATERIAL_METAL = 13, - MATERIAL_VERY_DRY_GROUND = 14, - MATERIAL_MEDIUM_DRY_GROUND = 15, - MATERIAL_WET_GROUND = 16 -} MaterialIndex; - +#endif /* SCENE_H */ diff --git a/scene_fromSionna.c b/scene_fromSionna.c @@ -1,13 +1,13 @@ /* vim: set tabstop=2:softtabstop=2:shiftwidth=2:noexpandtab */ -#include "scene.h" /* for HRT_Scene, HRT_Mesh, HRT_Material */ +#include "inc/common.h" /* for IN, OUT, PERROR_CLEANUP_EXIT */ +#include "inc/scene.h" /* for HRT_Scene, HRT_Mesh, HRT_Material */ +#include "inc/materials.h" /* for g_hrt_materials, MATERIAL_CONCRETE */ #include <stdio.h> /* for FILE, fopen, fclose, fseek, fgets, sscanf, printf */ #include <stdlib.h> /* for malloc */ #include <stdint.h> /* for uint8_t, uint32_t */ #include <string.h> /* for strncmp, strrchr, strcmp */ -#include <dirent.h> /* for opendir, readdir, closedir, DT_REG */ - /** * Hardcoded scenes @@ -101,10 +101,8 @@ const char* scene_simpleReflector_filename = "simple_reflector.xml"; */ HRT_Mesh readPly(const char* filepath) { FILE* f = fopen(filepath, "rb"); - if (f == NULL) { - perror("Error: cannot open file"); - exit(8); - } + if (f == NULL) + PERROR_CLEANUP_EXIT("Error: cannot open file", 8); char buf[256]; HRT_Mesh mesh = { @@ -121,27 +119,20 @@ HRT_Mesh readPly(const char* filepath) { if (!strncmp(buf, "end_header", 10)) break; if (!strncmp(buf, "element vertex ", 15)) { - if (sscanf(buf, "element vertex %u", &mesh.num_vertices) != 1) { - perror("Error: cannot read number of vertices"); - exit(8); - } + if (sscanf(buf, "element vertex %u", &mesh.num_vertices) != 1) + PERROR_CLEANUP_EXIT("Error: cannot read number of vertices", 8); } else if (!strncmp(buf, "element face ", 13)) - if (sscanf(buf, "element face %u", &mesh.num_triangles) != 1) { - perror("Error: cannot read number of triangles"); - exit(8); - } + if (sscanf(buf, "element face %u", &mesh.num_triangles) != 1) + PERROR_CLEANUP_EXIT("Error: cannot read number of triangles", 8); } /* check if vertex and face elements are found */ - if (mesh.num_vertices == 0 || mesh.num_triangles == 0) { - perror("Error: PLY element vertex or element face not found"); - exit(8); + if (mesh.num_vertices == 0 || mesh.num_triangles == 0) + PERROR_CLEANUP_EXIT("Error: PLY element vertex or element face not found", 8); /* check if the numbers are not too big */ - } else if (mesh.num_vertices > 1000000 || mesh.num_triangles > 1000000) { - perror("Error: PLY element vertex or element face too big"); - exit(8); - } + else if (mesh.num_vertices > 1000000 || mesh.num_triangles > 1000000) + PERROR_CLEANUP_EXIT("Error: PLY element vertex or element face too big", 8); /* allocate memory for vertices and faces */ mesh.vs = (float*)malloc(3 * mesh.num_vertices * sizeof(float)); @@ -149,42 +140,26 @@ HRT_Mesh readPly(const char* filepath) { /* read vertices */ for (uint32_t i = 0; i != mesh.num_vertices * 3; i += 3) { - if (fread(&mesh.vs[i], sizeof(float), 3, f) != 3) { - perror("Error: cannot read vertex"); - goto free_and_error; - } + if (fread(&mesh.vs[i], sizeof(float), 3, f) != 3) + PERROR_CLEANUP_EXIT("Error: cannot read vertex", 8, mesh.vs, mesh.is); /* skip s and t */ - if (fseek(f, 8, SEEK_CUR) != 0) { - perror("Error: cannot skip s and t"); - goto free_and_error; - } + if (fseek(f, 8, SEEK_CUR) != 0) + PERROR_CLEANUP_EXIT("Error: cannot skip s and t", 8, mesh.vs, mesh.is); } /* read faces */ for (uint32_t i = 0; i != mesh.num_triangles * 3; i += 3) { uint8_t n; - if (fread(&n, sizeof(uint8_t), 1, f) != 1) { - perror("Error: cannot read number of vertices in face"); - goto free_and_error; - } - if (n != 3) { - perror("Error: face is not a triangle"); - goto free_and_error; - } - if (fread(&mesh.is[i], sizeof(uint32_t), 3, f) != 3) { - perror("Error: cannot read face"); - goto free_and_error; - } + if (fread(&n, sizeof(uint8_t), 1, f) != 1) + PERROR_CLEANUP_EXIT("Error: cannot read number of vertices in face", 8, mesh.vs, mesh.is); + if (n != 3) + PERROR_CLEANUP_EXIT("Error: face is not a triangle", 8, mesh.vs, mesh.is); + if (fread(&mesh.is[i], sizeof(uint32_t), 3, f) != 3) + PERROR_CLEANUP_EXIT("Error: cannot read face", 8, mesh.vs, mesh.is); } fclose(f); return mesh; - -free_and_error: - free(mesh.vs); - free(mesh.is); - fclose(f); - exit(8); } /** Read a scene config CSV file. @@ -203,79 +178,191 @@ free_and_error: * \param velocity Output array of velocities. Size [num_meshes * 3] */ void readCsv( - const char* filepath, - uint32_t* num_meshes, - char** mesh_filenames, - uint32_t* material_indicies, - float* velocity + IN const char* filepath, + OUT uint32_t* csv_num_meshes, + OUT char** csv_mesh_filenames, + OUT uint32_t* csv_material_indicies, + OUT float* csv_velocities ) { FILE* f = fopen(filepath, "r"); - if (f == NULL) { - perror("Error: cannot open file"); - exit(8); - } + if (!f) + PERROR_CLEANUP_EXIT("Error: cannot open file", 8); /* Check header */ char buf[256]; - if (fgets(buf, 256, f) == NULL) { - perror("Error: cannot read header"); - exit(8); - } - if (strncmp(buf, "name,material_index,velocity_x,velocity_y,velocity_z\n", 48)) { - perror("Error: invalid header"); - exit(8); - } + if (!fgets(buf, 256, f)) + PERROR_CLEANUP_EXIT("Error: cannot read header", 8); + if (strncmp(buf, "name,material_index,velocity_x,velocity_y,velocity_z\n", 48)) + PERROR_CLEANUP_EXIT("Error: invalid header", 8); /* Count number of lines */ - *num_meshes = 0; + *csv_num_meshes = 0; while (fgets(buf, 256, f)) - ++(*num_meshes); + ++(*csv_num_meshes); + if (*csv_num_meshes == 0) { + fclose(f); + return; + } /* Return to the beginning of the file */ rewind(f); /* Skip header */ - if (fgets(buf, 256, f) == NULL) { - perror("Error: cannot read header"); - exit(8); - } + if (!fgets(buf, 256, f)) + PERROR_CLEANUP_EXIT("Error: cannot read header", 8); /* Allocate memory for the arrays */ - mesh_filenames = (char**)malloc(*num_meshes * sizeof(char*)); - material_indicies = (uint32_t*)malloc(*num_meshes * sizeof(uint32_t)); - velocity = (float*)malloc(*num_meshes * 3 * sizeof(float)); + csv_mesh_filenames = (char**)malloc(*csv_num_meshes * sizeof(char*)); + csv_material_indicies = (uint32_t*)malloc(*csv_num_meshes * sizeof(uint32_t)); + csv_velocities = (float*)malloc(*csv_num_meshes * 3 * sizeof(float)); /* Read lines */ - for (uint32_t i = 0; i != *num_meshes; ++i) { + for (uint32_t i = 0; i != *csv_num_meshes; ++i) { /* Read line */ - if (fgets(buf, 256, f) == NULL) { - perror("Error: cannot read line"); - exit(8); - } + if (!fgets(buf, 256, f)) + PERROR_CLEANUP_EXIT("Error: cannot read line", 8); /* Parse line */ char name[50]; int rc = sscanf( buf, "%49[^,],%u,%f,%f,%f\n", name, - &material_indicies[i], - &velocity[i * 3], - &velocity[i * 3 + 1], - &velocity[i * 3 + 2] + &csv_material_indicies[i], + &csv_velocities[i * 3], + &csv_velocities[i * 3 + 1], + &csv_velocities[i * 3 + 2] ); - if (rc != 4) { - perror("Error: cannot parse line"); - exit(8); - } + if (rc != 4) + PERROR_CLEANUP_EXIT("Error: cannot parse line", 8); /* Copy name */ - mesh_filenames[i] = (char*)malloc(strlen(name) + 1); - if (mesh_filenames[i] == NULL) { - perror("Error: cannot allocate memory for mesh filename"); - exit(8); - } - strcpy(mesh_filenames[i], name); + csv_mesh_filenames[i] = (char*)malloc(strlen(name) + 1); + if (!csv_mesh_filenames[i]) + PERROR_CLEANUP_EXIT("Error: cannot allocate memory for mesh filename", 8); + strcpy(csv_mesh_filenames[i], name); } } +/** Read a Sionna scene XML file. + * + * Extracts each shape's name, file path and material. + * + * \param filepath Path to the XML file + * \param xml_num_meshes Output number of meshes in the XML file + * \param xml_mesh_filepaths Output array of mesh file paths (null-terminated strings) + * \param xml_mesh_names Output array of mesh names (null-terminated strings) + * \param xml_mesh_materials Output array of mesh materials (null-terminated strings) + */ +void readXml( + IN const char* filepath, + OUT uint32_t* xml_num_meshes, + OUT char*** xml_mesh_filepaths, + OUT char*** xml_mesh_names, + OUT char*** xml_mesh_materials +) +{ + FILE* f = fopen(filepath, "r"); + if (f == NULL) + PERROR_CLEANUP_EXIT("Error: cannot open the xml file", 8); + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + char* buf = (char*)malloc(fsize + 1); + if (!buf) + PERROR_CLEANUP_EXIT("Error: cannot allocate memory for the xml file", 8); + if (fread(buf, 1, fsize, f) != fsize) + PERROR_CLEANUP_EXIT("Error: cannot read the xml file", 8, buf); + buf[fsize] = '\0'; + + /* Count the amount of "<shape" entries */ + char** shape_positions = NULL; + *xml_num_meshes = 0; + char* pos = buf, *end; + while ((pos = strstr(pos, "<shape")) != NULL) { + ++*xml_num_meshes; + shape_positions = (char**)realloc(shape_positions, *xml_num_meshes * sizeof(char*)); + if (!shape_positions) + PERROR_CLEANUP_EXIT("Error: cannot reallocate memory for shape positions", 8, buf); + shape_positions[*xml_num_meshes - 1] = pos; + pos += 6; + } + if (*xml_num_meshes == 0) + PERROR_CLEANUP_EXIT("Error: no shapes found in the xml file", 8, buf); + if (!shape_positions) + PERROR_CLEANUP_EXIT("Error: cannot allocate memory for shape positions", 8, buf); + + /* Allocate memory for the mesh data */ + *xml_mesh_filepaths = (char**)malloc(*xml_num_meshes * sizeof(char*)); + *xml_mesh_names = (char**)malloc(*xml_num_meshes * sizeof(char*)); + *xml_mesh_materials = (char**)malloc(*xml_num_meshes * sizeof(char*)); + if (!*xml_mesh_filepaths || !*xml_mesh_names || !*xml_mesh_materials) + PERROR_CLEANUP_EXIT("Error: cannot allocate memory for mesh data", 8, buf); + + /* For each "<shape" entry, extract the name, file path and material */ + char *e_name, *e_filepath, *e_material; + for (uint32_t i = 0; i != *xml_num_meshes; ++i) { + pos = shape_positions[i] + 6; + + /* Find mesh name */ + if ((pos = strstr(pos, "name=\"")) == NULL) + PERROR_CLEANUP_EXIT("Error: cannot find mesh name", 8, + buf, shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + pos += 6; + end = strchr(pos, '\"'); + if (!end) + PERROR_CLEANUP_EXIT("Error: cannot find mesh name end", 8, + buf, shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + e_name = (char*)malloc(end - pos + 1); + if (!e_name) + PERROR_CLEANUP_EXIT("Error: cannot allocate memory for mesh name", 8, + buf, shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + strncpy(e_name, pos, end - pos); + e_name[end - pos] = '\0'; + + /* Find mesh file path */ + if (!(pos = strstr(pos, "<string name=\"filename\""))) + PERROR_CLEANUP_EXIT("Error: cannot find mesh file path", 8, buf, e_name, + shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + if (!(pos = strstr(pos, "value=\""))) + PERROR_CLEANUP_EXIT("Error: cannot find mesh file path value", 8, buf, e_name, + shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + pos += 7; + end = strchr(pos, '\"'); + if (!end) + PERROR_CLEANUP_EXIT("Error: cannot find mesh file path end", 8, buf, e_name, + shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + e_filepath = (char*)malloc(end - pos + 1); + if (!e_filepath) + PERROR_CLEANUP_EXIT("Error: cannot allocate memory for mesh file path", 8, buf, e_name, + shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + strncpy(e_filepath, pos, end - pos); + e_filepath[end - pos] = '\0'; + + /* Find mesh material */ + if (!(pos = strstr(pos, "id=\"mat-itu_"))) + PERROR_CLEANUP_EXIT("Error: cannot find mesh material", 8, buf, e_name, e_filepath, + shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + pos += 12; + end = strchr(pos, '\"'); + if (!end) + PERROR_CLEANUP_EXIT("Error: cannot find mesh material end", 8, buf, e_name, e_filepath, + shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + e_material = (char*)malloc(end - pos + 1); + if (!e_material) + PERROR_CLEANUP_EXIT("Error: cannot allocate memory for mesh material", 8, buf, e_name, e_filepath, + shape_positions, *xml_mesh_filepaths, *xml_mesh_names, *xml_mesh_materials); + strncpy(e_material, pos, end - pos); + e_material[end - pos] = '\0'; + + /* Save mesh data */ + (*xml_mesh_filepaths)[i] = e_filepath; + (*xml_mesh_names)[i] = e_name; + (*xml_mesh_materials)[i] = e_material; + } + + free(shape_positions); + free(buf); +} /* Read a Sionna .xml scene. Assumes meshes are in a "meshes" directory. * @@ -285,17 +372,26 @@ void readCsv( void readScene(const char* filepath, HRT_Scene* scene) { /* Check if filepath ends with ".xml" */ size_t filepath_len = strlen(filepath); - if (filepath_len > 4 && strcmp(filepath + filepath_len - 4, ".xml") != 0) { - perror("Error: scene file must end with .xml"); - exit(8); - } + if (filepath_len > 4 && strcmp(filepath + filepath_len - 4, ".xml") != 0) + PERROR_CLEANUP_EXIT("Error: scene file must end with .xml", 8); + + /* Read the xml file */ + uint32_t xml_num_meshes; + char** xml_mesh_filepaths; + char** xml_mesh_names; + char** xml_mesh_materials; + readXml( + filepath, + &xml_num_meshes, + &xml_mesh_filepaths, + &xml_mesh_names, + &xml_mesh_materials + ); /* Read the scene config CSV file */ char* csv_path = (char*)malloc(filepath_len + 1); - if (!csv_path) { - perror("Error: failed to allocate csv_path"); - exit(8); - } + if (!csv_path) + PERROR_CLEANUP_EXIT("Error: cannot allocate memory for csv_path", 8); strcpy(csv_path, filepath); strcpy(csv_path + filepath_len - 4, ".csv"); uint32_t csv_num_meshes; @@ -309,92 +405,47 @@ void readScene(const char* filepath, HRT_Scene* scene) { csv_material_indicies, csv_velocity ); - - /* Get the meshes directory path */ - const char* last_slash = strrchr(filepath, '/'); - size_t base_len = (last_slash ? (last_slash - filepath + 1) : 0); - char* dir_path = (char*)malloc(base_len + strlen("meshes/") + 1); - if (!dir_path) { - perror("Error: failed to allocate dir_path"); - exit(8); - } - if (base_len > 0) { - strncpy(dir_path, filepath, base_len); - dir_path[base_len] = '\0'; - } else - dir_path[0] = '\0'; /* No directory, start empty */ - strcat(dir_path, "meshes/"); - - /* Scan the directory for .ply files */ - DIR* dir = opendir(dir_path); - if (!dir) { - perror("Failed to open meshes directory"); - free(dir_path); - exit(8); - } - - /* Count the number of .ply files */ - uint32_t ply_count = 0; - struct dirent* entry; - while ((entry = readdir(dir))) { - if (entry->d_type != DT_REG) continue; - size_t name_len = strlen(entry->d_name); - if (name_len > 4 && strncmp(entry->d_name + name_len - 4, ".ply", 4) == 0) - ply_count++; - } - - /* Allocate memory for the meshes array */ - scene->num_meshes = ply_count; - scene->meshes = (HRT_Mesh*)malloc(ply_count * sizeof(HRT_Mesh)); - if (!scene->meshes && ply_count > 0) { - perror("Error: failed to allocate meshes array"); - free(dir_path); - closedir(dir); - exit(8); - } - - /* Read each .ply file */ - rewinddir(dir); // Reset directory pointer - uint32_t mesh_idx = 0; - while ((entry = readdir(dir)) && mesh_idx < ply_count) { - /* Continue if not a regular file or not a .ply file */ - size_t name_len = strlen(entry->d_name); - if ((entry->d_type != DT_REG) - || (name_len <= 4 || strcmp(entry->d_name + name_len - 4, ".ply"))) - continue; - - /* Construct full filepath for the .ply file */ - char* ply_path = (char*)malloc(strlen(dir_path) + name_len + 1); - if (!ply_path) { - perror("Error: failed to allocate ply_path"); - free(dir_path); - closedir(dir); - free(scene->meshes); - exit(8); - } - strcpy(ply_path, dir_path); - strcat(ply_path, entry->d_name); - - /* Read mesh */ - scene->meshes[mesh_idx] = readPly(ply_path); - - /* Get material index and velocity from the CSV file */ - for (uint32_t i = 0; i != csv_num_meshes; ++i) - if (strcmp(entry->d_name, csv_mesh_filenames[i]) == 0) { - scene->meshes[mesh_idx].material_index = csv_material_indicies[i]; - scene->meshes[mesh_idx].velocity[0] = csv_velocity[i * 3]; - scene->meshes[mesh_idx].velocity[1] = csv_velocity[i * 3 + 1]; - scene->meshes[mesh_idx].velocity[2] = csv_velocity[i * 3 + 2]; + free(csv_path); + + /* Read the meshes */ + + /* Get the scene directory path */ + size_t scene_dir_len = strrchr(filepath, '/') - filepath + 1; + /* if filepath is "/path/to/scene.xml", scene_dir is "/path/to/" */ + char* scene_dir = (char*)malloc(scene_dir_len + 7); + if (!scene_dir) + PERROR_CLEANUP_EXIT("Error: failed to allocate scene_dir", 8); + strncpy(scene_dir, filepath, scene_dir_len); + + /* For each ply file from the xml file */ + scene->num_meshes = xml_num_meshes; + scene->meshes = (HRT_Mesh*)malloc(xml_num_meshes * sizeof(HRT_Mesh)); + if (!scene->meshes && xml_num_meshes > 0) + PERROR_CLEANUP_EXIT("Error: failed to allocate meshes array", 8); + for (uint32_t i = 0; i != xml_num_meshes; ++i) { + /* Get the mesh file path */ + size_t mesh_filepath_len = scene_dir_len + strlen(xml_mesh_filepaths[i]); + char* mesh_filepath = (char*)malloc(mesh_filepath_len); + mesh_filepath[0] = '\0'; + strncat(mesh_filepath, scene_dir, scene_dir_len); + strncat(mesh_filepath + scene_dir_len, xml_mesh_filepaths[i], mesh_filepath_len - scene_dir_len); + /* Read the mesh */ + scene->meshes[i] = readPly(mesh_filepath); + free(mesh_filepath); + /* Set the material index from the material name from xml */ + scene->meshes[i].material_index = get_material_index(xml_mesh_materials[i]); + /* Set the material index and velocity from CSV if present */ + for (uint32_t j = 0; j != csv_num_meshes; ++j) + if (strcmp(xml_mesh_names[i], csv_mesh_filenames[j]) == 0) { + scene->meshes[i].material_index = csv_material_indicies[j]; + scene->meshes[i].velocity[0] = csv_velocity[j * 3]; + scene->meshes[i].velocity[1] = csv_velocity[j * 3 + 1]; + scene->meshes[i].velocity[2] = csv_velocity[j * 3 + 2]; break; } - - ++mesh_idx; - free(ply_path); } - // Cleanup - closedir(dir); - free(dir_path); + free(scene_dir); } @@ -428,10 +479,8 @@ int main(int argc, char *argv[]) { } FILE *fp = fopen("scene.hrt", "wb"); - if (fp == NULL) { - perror("Error: cannot open file"); - return 1; - } + if (!fp) + PERROR_CLEANUP_EXIT("Error: cannot open file", 8); /* MAGIC */ fwrite("HRT", 1, 3, fp); @@ -450,6 +499,5 @@ int main(int argc, char *argv[]) { } fclose(fp); - return 0; }