diff --git a/CMakeLists.txt b/CMakeLists.txt index 663dbe4..81b0d17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable(wavefront_tests tests/unit/trim_test.cpp tests/unit/settings_test.cpp tests/unit/scan_test.cpp + tests/unit/parse_test.cpp ${APP_SOURCES} ) target_link_libraries(wavefront_tests PRIVATE diff --git a/src/parse.hpp b/src/parse.hpp index 3ca9caa..89f9f90 100644 --- a/src/parse.hpp +++ b/src/parse.hpp @@ -55,313 +55,15 @@ namespace wavefront { wavefront_face_data_result_t parse_face_data(const scan_result &scan_data); template - coordinate_data_t parse_coordinate_data(const scan_result &scan_data, const wavefront_face_data_result_t &face_data) { - using namespace std::string_literals; - coordinate_data_t result; - - const auto &position_data = scan_data.category_map.at("v"s); - for (const auto &position_index : face_data.index_position_set) { - std::array position_coordinates; - const auto &position_line_index = position_data.at(position_index); - const auto &position_line = scan_data.line_data.at(position_line_index); - - decltype(position_line.find_first_of(' ')) number_begin_pos = 2, number_end_pos; - for (std::size_t position_coordinate_index = 0; position_coordinate_index < 3; position_coordinate_index++) { - if (number_begin_pos >= position_line.size()) { - throw parse_error(std::format( - "[{}]: {}", - position_line_index, - std::format("Line \"{}\" must contain at least {} numbers", "v", 3) - )); - } - number_end_pos = std::min(position_line.find_first_of(' ', number_begin_pos), position_line.size()); - auto [number_end, conversion_error] = std::from_chars( - position_line.data() + number_begin_pos, - position_line.data() + number_end_pos, - position_coordinates[position_coordinate_index], - std::chars_format::fixed - ); - if (conversion_error != std::errc() || position_line.data() + number_end_pos != number_end) { - throw parse_error(std::format( - "[{}]: {}", - position_line_index, - std::format("Unable to parse \"{}\" floating point value", "v") - )); - } - number_begin_pos = std::min(position_line.find_first_not_of(' ', number_end_pos), position_line.size()); - } - if (number_begin_pos < position_line.size()) { - if (position_line.find_first_not_of("0123456789.-", number_begin_pos)) { - throw parse_error(std::format( - "[{}]: {}", - position_line_index, - std::format("Additional data in \"{}\" line: expected {} only", "v", " [weight]") - )); - } - } - result.position_coordinates[position_line_index] = position_coordinates; - } - if (face_data.index_normal_set.size() > 0 && scan_data.category_map.contains("vn"s)) { - const auto &normal_data = scan_data.category_map.at("vn"s); - for (const auto &normal_index : face_data.index_normal_set) { - std::array normal_coordinates; - const auto &normal_line_index = normal_data.at(normal_index); - const auto &normal_line = scan_data.line_data.at(normal_line_index); - - decltype(normal_line.find_first_of(' ')) number_begin_pos = 3, number_end_pos; - for (std::size_t normal_coordinate_index = 0; normal_coordinate_index < 3; normal_coordinate_index++) { - if (number_begin_pos >= normal_line.size()) { - throw parse_error(std::format( - "[{}]: {}", - normal_line_index, - std::format("Line \"{}\" must contain exactly {} numbers", "vn", 3) - )); - } - number_end_pos = std::min(normal_line.find_first_of(' ', number_begin_pos), normal_line.size()); - auto [number_end, conversion_error] = std::from_chars( - normal_line.data() + number_begin_pos, - normal_line.data() + number_end_pos, - normal_coordinates[normal_coordinate_index], - std::chars_format::fixed - ); - if (conversion_error != std::errc() || normal_line.data() + number_end_pos != number_end) { - throw parse_error(std::format( - "[{}]: {}", - normal_line_index, - std::format("Unable to parse \"{}\" floating point value", "vn") - )); - } - number_begin_pos = std::min(normal_line.find_first_not_of(' ', number_end_pos), normal_line.size()); - } - if (number_end_pos != normal_line.size()) { - throw parse_error(std::format( - "[{}]: {}", - normal_line_index, - std::format("Additional data in \"{}\" line: expected {} only", "vn", " ") - )); - } - result.normal_coordinates[normal_line_index] = normal_coordinates; - } - } - - if (face_data.index_texcoord_set.size() > 0 && scan_data.category_map.contains("vt"s)) { - using insert_texcoord_data_t = std::function; - - const auto &texcoord_data = scan_data.category_map.at("vt"s); - for (const auto &texcoord_index : face_data.index_texcoord_set) { - std::array texcoord_coordinates; - const auto &texcoord_line_index = texcoord_data.at(texcoord_index); - const auto &texcoord_line = scan_data.line_data.at(texcoord_line_index); - - decltype(texcoord_line.find_first_of(' ')) number_begin_pos = 3, number_end_pos; - std::size_t texcoord_coordinate_index = 0; - while (number_begin_pos < texcoord_line.size()) { - if (texcoord_coordinate_index >= 3) { - throw parse_error(std::format( - "[{}]: {}", - texcoord_line_index, - std::format("Line \"{}\" must contain maximum {} numbers", "vt", 3) - )); - } - number_end_pos = std::min(texcoord_line.find_first_of(' ', number_begin_pos), texcoord_line.size()); - auto [number_end, conversion_error] = std::from_chars( - texcoord_line.data() + number_begin_pos, - texcoord_line.data() + number_end_pos, - texcoord_coordinates[texcoord_coordinate_index++], - std::chars_format::fixed - ); - if (conversion_error != std::errc() || texcoord_line.data() + number_end_pos != number_end) { - throw parse_error(std::format( - "[{}]: {}", - texcoord_line_index, - std::format("Unable to parse \"{}\" floating point value", "vt") - )); - } - number_begin_pos = std::min(texcoord_line.find_first_not_of(' ', number_end_pos), texcoord_line.size()); - } - if (texcoord_coordinate_index == 0) [[unlikely]] { - throw parse_error(std::format( - "[{}]: {}", - texcoord_line_index, - std::format("Unable to parse \"{}\" line: expected minimum one number", "vt") - )); - } - if (result.texture_coordinates.valueless_by_exception() || result.texture_coordinates.index() == 0) [[unlikely]] { - if (texcoord_coordinate_index == 1) { - result.texture_coordinates = std::map{}; - } else if (texcoord_coordinate_index == 2) { - result.texture_coordinates = std::map>{}; - } else if (texcoord_coordinate_index == 3) { - result.texture_coordinates = std::map>{}; - } else { - throw parse_error(std::format( - "[{}]: {}", - texcoord_line_index, - std::format("Line \"{}\" must contain maximum {} numbers", "vt", 3) - )); - } - } - if (texcoord_coordinate_index == 0) [[unlikely]] { - throw parse_error(std::format( - "[{}]: {}", - texcoord_line_index, - std::format("Unable to parse \"{}\" line: expected minimum one number", "vt") - )); - } - try { - if (texcoord_coordinate_index == 1) { - std::get<1>(result.texture_coordinates)[texcoord_line_index] = texcoord_coordinates[0]; - } else if (texcoord_coordinate_index == 2) { - std::get<2>(result.texture_coordinates)[texcoord_line_index] = std::array{texcoord_coordinates[0], texcoord_coordinates[1]}; - } else if (texcoord_coordinate_index == 3) { - std::get<3>(result.texture_coordinates)[texcoord_line_index] = texcoord_coordinates; - } - } catch (std::bad_variant_access&) { - throw parse_error(std::format( - "[{}]: {}", - texcoord_line_index, - std::format("Line \"{}\": {}D texture coordinates expected, got {}D texture coordinates", "vt", result.texture_coordinates.index(), texcoord_coordinate_index) - )); - } - } - } - return result; - } + coordinate_data_t parse_coordinate_data(const scan_result &scan_data, const wavefront_face_data_result_t &face_data); template - std::vector create_number_list(const coordinate_data_t &coordinate_data) { - numset_t number_set; - - for (const auto& [line_number, coordinates] : coordinate_data.position_coordinates) { - for (const auto &coordinate : coordinates) { - number_set.emplace(coordinate); - } - } - for (const auto& [line_number, coordinates] : coordinate_data.normal_coordinates) { - for (const auto &coordinate : coordinates) { - number_set.emplace(coordinate); - } - } - - std::visit([&](const auto &texture_coordinate_map) { - if constexpr (std::ranges::range>) { - for (const auto& [line_number, coordinates] : texture_coordinate_map) { - if constexpr (std::ranges::range>) { - for (const auto &coordinate : coordinates) { - number_set.emplace(coordinate); - } - } else { - number_set.emplace(coordinates); - } - } - } - }, coordinate_data.texture_coordinates); - - number_set.emplace(std::numeric_limits::quiet_NaN()); - - std::vector number_list; - number_list.reserve(number_set.size()); - std::copy(number_set.begin(), number_set.end(), std::back_inserter(number_list)); - - return number_list; - } + std::vector create_number_list(const coordinate_data_t &coordinate_data); template - coordinate_data_t create_coordinate_index(const coordinate_data_t &coordinate_data, const std::vector &float_list) { - coordinate_data_t coordinate_index_data; - - static const auto float_compare = float_is_equal{}; - static const auto float_less = less_with_nan_first_and_nearly_equal{}; - - for (const auto& [line_number, coordinates] : coordinate_data.position_coordinates) { - std::array position_coordinate_indices; - for (decltype(coordinates.size()) dim = 0; dim < coordinates.size(); ++dim) { - auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less); - assert(iterator != float_list.end()); - assert(float_compare(*iterator, coordinates[dim])); - auto index = std::distance(float_list.begin(), iterator); - assert(index != 0); - position_coordinate_indices[dim] = index; - } - coordinate_index_data.position_coordinates[line_number] = position_coordinate_indices; - } - for (const auto& [line_number, coordinates] : coordinate_data.normal_coordinates) { - std::array normal_coordinate_indices; - for (decltype(coordinates.size()) dim = 0; dim < coordinates.size(); ++dim) { - auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less); - assert(iterator != float_list.end()); - assert(float_compare(*iterator, coordinates[dim])); - auto index = std::distance(float_list.begin(), iterator); - assert(index != 0); - normal_coordinate_indices[dim] = index; - } - coordinate_index_data.normal_coordinates[line_number] = normal_coordinate_indices; - } - if (!coordinate_data.texture_coordinates.valueless_by_exception() && coordinate_data.texture_coordinates.index() > 0) { - std::visit([&](const auto &texture_coordinate_map) { - if constexpr (std::ranges::range>) { - if constexpr (std::ranges::range::mapped_type>) { - coordinate_index_data.texture_coordinates = std::map< - typename std::decay_t::key_type, - std::array< - IndexType, - std::tuple_size_v::mapped_type> - > - >{}; - } else { - coordinate_index_data.texture_coordinates = std::map< - typename std::decay_t::key_type, - IndexType - >{}; - } - for (const auto& [line_number, coordinates] : texture_coordinate_map) { - if constexpr (std::ranges::range>) { - std::array texcoord_coordinate_indices; - for (std::size_t dim = 0; dim < coordinates.size(); ++dim) { - auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less); - assert(iterator != float_list.end()); - assert(float_compare(*iterator, coordinates[dim])); - auto index = std::distance(float_list.begin(), iterator); - assert(index != 0); - texcoord_coordinate_indices[dim] = index; - } - std::visit([&](auto &target_data) { - if constexpr (std::is_same_v< - std::map< - file_line_t, - std::array< - IndexType, - std::tuple_size_v::mapped_type> - > - >, - typename std::decay_t - >) { - target_data[line_number] = texcoord_coordinate_indices; - } - }, coordinate_index_data.texture_coordinates); - } else { - auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates, float_less); - assert(iterator != float_list.end()); - assert(float_compare(*iterator, coordinates)); - auto coordinate = std::distance(float_list.begin(), iterator); - assert(coordinate != 0); - std::visit([&](auto &target_data) { - if constexpr (std::is_same_v< - std::map, - typename std::decay_t - >) { - target_data[line_number] = coordinate; - } - }, coordinate_index_data.texture_coordinates); - } - } - } - int j = 0; - }, coordinate_data.texture_coordinates); - } - - return coordinate_index_data; - } + coordinate_data_t create_coordinate_index(const coordinate_data_t &coordinate_data, const std::vector &float_list); } +#include "parse.tpp" + #endif // __WAVEFRONT_PARSE_HPP__ \ No newline at end of file diff --git a/src/parse.tpp b/src/parse.tpp new file mode 100644 index 0000000..0fe3b4b --- /dev/null +++ b/src/parse.tpp @@ -0,0 +1,319 @@ +#ifndef __WAVEFRONT_PARSE_TPP__ +#define __WAVEFRONT_PARSE_TPP__ + +#include +#include +#include + +namespace wavefront { + template + coordinate_data_t parse_coordinate_data(const scan_result &scan_data, const wavefront_face_data_result_t &face_data) { + using namespace std::string_literals; + coordinate_data_t result; + + const auto &position_data = scan_data.category_map.at("v"s); + for (const auto &position_index : face_data.index_position_set) { + std::array position_coordinates; + const auto &position_line_index = position_data.at(position_index); + const auto &position_line = scan_data.line_data.at(position_line_index); + + decltype(position_line.find_first_of(' ')) number_begin_pos = 2, number_end_pos; + for (std::size_t position_coordinate_index = 0; position_coordinate_index < 3; position_coordinate_index++) { + if (number_begin_pos >= position_line.size()) { + throw parse_error(std::format( + "[{}]: {}", + position_line_index, + std::format("Line \"{}\" must contain at least {} numbers", "v", 3) + )); + } + number_end_pos = std::min(position_line.find_first_of(' ', number_begin_pos), position_line.size()); + auto [number_end, conversion_error] = std::from_chars( + position_line.data() + number_begin_pos, + position_line.data() + number_end_pos, + position_coordinates[position_coordinate_index], + std::chars_format::fixed + ); + if (conversion_error != std::errc() || position_line.data() + number_end_pos != number_end) { + throw parse_error(std::format( + "[{}]: {}", + position_line_index, + std::format("Unable to parse \"{}\" floating point value", "v") + )); + } + number_begin_pos = std::min(position_line.find_first_not_of(' ', number_end_pos), position_line.size()); + } + if (number_begin_pos < position_line.size()) { + if (position_line.find_first_not_of("0123456789.-", number_begin_pos)) { + throw parse_error(std::format( + "[{}]: {}", + position_line_index, + std::format("Additional data in \"{}\" line: expected {} only", "v", " [weight]") + )); + } + } + result.position_coordinates[position_line_index] = position_coordinates; + } + if (face_data.index_normal_set.size() > 0 && scan_data.category_map.contains("vn"s)) { + const auto &normal_data = scan_data.category_map.at("vn"s); + for (const auto &normal_index : face_data.index_normal_set) { + std::array normal_coordinates; + const auto &normal_line_index = normal_data.at(normal_index); + const auto &normal_line = scan_data.line_data.at(normal_line_index); + + decltype(normal_line.find_first_of(' ')) number_begin_pos = 3, number_end_pos; + for (std::size_t normal_coordinate_index = 0; normal_coordinate_index < 3; normal_coordinate_index++) { + if (number_begin_pos >= normal_line.size()) { + throw parse_error(std::format( + "[{}]: {}", + normal_line_index, + std::format("Line \"{}\" must contain exactly {} numbers", "vn", 3) + )); + } + number_end_pos = std::min(normal_line.find_first_of(' ', number_begin_pos), normal_line.size()); + auto [number_end, conversion_error] = std::from_chars( + normal_line.data() + number_begin_pos, + normal_line.data() + number_end_pos, + normal_coordinates[normal_coordinate_index], + std::chars_format::fixed + ); + if (conversion_error != std::errc() || normal_line.data() + number_end_pos != number_end) { + throw parse_error(std::format( + "[{}]: {}", + normal_line_index, + std::format("Unable to parse \"{}\" floating point value", "vn") + )); + } + number_begin_pos = std::min(normal_line.find_first_not_of(' ', number_end_pos), normal_line.size()); + } + if (number_end_pos != normal_line.size()) { + throw parse_error(std::format( + "[{}]: {}", + normal_line_index, + std::format("Additional data in \"{}\" line: expected {} only", "vn", " ") + )); + } + result.normal_coordinates[normal_line_index] = normal_coordinates; + } + } + + if (face_data.index_texcoord_set.size() > 0 && scan_data.category_map.contains("vt"s)) { + using insert_texcoord_data_t = std::function; + + const auto &texcoord_data = scan_data.category_map.at("vt"s); + for (const auto &texcoord_index : face_data.index_texcoord_set) { + std::array texcoord_coordinates; + const auto &texcoord_line_index = texcoord_data.at(texcoord_index); + const auto &texcoord_line = scan_data.line_data.at(texcoord_line_index); + + decltype(texcoord_line.find_first_of(' ')) number_begin_pos = 3, number_end_pos; + std::size_t texcoord_coordinate_index = 0; + while (number_begin_pos < texcoord_line.size()) { + if (texcoord_coordinate_index >= 3) { + throw parse_error(std::format( + "[{}]: {}", + texcoord_line_index, + std::format("Line \"{}\" must contain maximum {} numbers", "vt", 3) + )); + } + number_end_pos = std::min(texcoord_line.find_first_of(' ', number_begin_pos), texcoord_line.size()); + auto [number_end, conversion_error] = std::from_chars( + texcoord_line.data() + number_begin_pos, + texcoord_line.data() + number_end_pos, + texcoord_coordinates[texcoord_coordinate_index++], + std::chars_format::fixed + ); + if (conversion_error != std::errc() || texcoord_line.data() + number_end_pos != number_end) { + throw parse_error(std::format( + "[{}]: {}", + texcoord_line_index, + std::format("Unable to parse \"{}\" floating point value", "vt") + )); + } + number_begin_pos = std::min(texcoord_line.find_first_not_of(' ', number_end_pos), texcoord_line.size()); + } + if (texcoord_coordinate_index == 0) [[unlikely]] { + throw parse_error(std::format( + "[{}]: {}", + texcoord_line_index, + std::format("Unable to parse \"{}\" line: expected minimum one number", "vt") + )); + } + if (result.texture_coordinates.valueless_by_exception() || result.texture_coordinates.index() == 0) [[unlikely]] { + if (texcoord_coordinate_index == 1) { + result.texture_coordinates = std::map{}; + } else if (texcoord_coordinate_index == 2) { + result.texture_coordinates = std::map>{}; + } else if (texcoord_coordinate_index == 3) { + result.texture_coordinates = std::map>{}; + } else { + throw parse_error(std::format( + "[{}]: {}", + texcoord_line_index, + std::format("Line \"{}\" must contain maximum {} numbers", "vt", 3) + )); + } + } + if (texcoord_coordinate_index == 0) [[unlikely]] { + throw parse_error(std::format( + "[{}]: {}", + texcoord_line_index, + std::format("Unable to parse \"{}\" line: expected minimum one number", "vt") + )); + } + try { + if (texcoord_coordinate_index == 1) { + std::get<1>(result.texture_coordinates)[texcoord_line_index] = texcoord_coordinates[0]; + } else if (texcoord_coordinate_index == 2) { + std::get<2>(result.texture_coordinates)[texcoord_line_index] = std::array{texcoord_coordinates[0], texcoord_coordinates[1]}; + } else if (texcoord_coordinate_index == 3) { + std::get<3>(result.texture_coordinates)[texcoord_line_index] = texcoord_coordinates; + } + } catch (std::bad_variant_access&) { + throw parse_error(std::format( + "[{}]: {}", + texcoord_line_index, + std::format("Line \"{}\": {}D texture coordinates expected, got {}D texture coordinates", "vt", result.texture_coordinates.index(), texcoord_coordinate_index) + )); + } + } + } + return result; + } + + template + std::vector create_number_list(const coordinate_data_t &coordinate_data) { + numset_t number_set; + + for (const auto& [line_number, coordinates] : coordinate_data.position_coordinates) { + for (const auto &coordinate : coordinates) { + number_set.emplace(coordinate); + } + } + for (const auto& [line_number, coordinates] : coordinate_data.normal_coordinates) { + for (const auto &coordinate : coordinates) { + number_set.emplace(coordinate); + } + } + + std::visit([&](const auto &texture_coordinate_map) { + if constexpr (std::ranges::range>) { + for (const auto& [line_number, coordinates] : texture_coordinate_map) { + if constexpr (std::ranges::range>) { + for (const auto &coordinate : coordinates) { + number_set.emplace(coordinate); + } + } else { + number_set.emplace(coordinates); + } + } + } + }, coordinate_data.texture_coordinates); + + number_set.emplace(std::numeric_limits::quiet_NaN()); + + std::vector number_list; + number_list.reserve(number_set.size()); + std::copy(number_set.begin(), number_set.end(), std::back_inserter(number_list)); + + return number_list; + } + + template + coordinate_data_t create_coordinate_index(const coordinate_data_t &coordinate_data, const std::vector &float_list) { + coordinate_data_t coordinate_index_data; + + static const auto float_compare = float_is_equal{}; + static const auto float_less = less_with_nan_first_and_nearly_equal{}; + + for (const auto& [line_number, coordinates] : coordinate_data.position_coordinates) { + std::array position_coordinate_indices; + for (decltype(coordinates.size()) dim = 0; dim < coordinates.size(); ++dim) { + auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less); + assert(iterator != float_list.end()); + assert(float_compare(*iterator, coordinates[dim])); + auto index = std::distance(float_list.begin(), iterator); + assert(index != 0); + position_coordinate_indices[dim] = index; + } + coordinate_index_data.position_coordinates[line_number] = position_coordinate_indices; + } + for (const auto& [line_number, coordinates] : coordinate_data.normal_coordinates) { + std::array normal_coordinate_indices; + for (decltype(coordinates.size()) dim = 0; dim < coordinates.size(); ++dim) { + auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less); + assert(iterator != float_list.end()); + assert(float_compare(*iterator, coordinates[dim])); + auto index = std::distance(float_list.begin(), iterator); + assert(index != 0); + normal_coordinate_indices[dim] = index; + } + coordinate_index_data.normal_coordinates[line_number] = normal_coordinate_indices; + } + if (!coordinate_data.texture_coordinates.valueless_by_exception() && coordinate_data.texture_coordinates.index() > 0) { + std::visit([&](const auto &texture_coordinate_map) { + if constexpr (std::ranges::range>) { + if constexpr (std::ranges::range::mapped_type>) { + coordinate_index_data.texture_coordinates = std::map< + typename std::decay_t::key_type, + std::array< + IndexType, + std::tuple_size_v::mapped_type> + > + >{}; + } else { + coordinate_index_data.texture_coordinates = std::map< + typename std::decay_t::key_type, + IndexType + >{}; + } + for (const auto& [line_number, coordinates] : texture_coordinate_map) { + if constexpr (std::ranges::range>) { + std::array texcoord_coordinate_indices; + for (std::size_t dim = 0; dim < coordinates.size(); ++dim) { + auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less); + assert(iterator != float_list.end()); + assert(float_compare(*iterator, coordinates[dim])); + auto index = std::distance(float_list.begin(), iterator); + assert(index != 0); + texcoord_coordinate_indices[dim] = index; + } + std::visit([&](auto &target_data) { + if constexpr (std::is_same_v< + std::map< + file_line_t, + std::array< + IndexType, + std::tuple_size_v::mapped_type> + > + >, + typename std::decay_t + >) { + target_data[line_number] = texcoord_coordinate_indices; + } + }, coordinate_index_data.texture_coordinates); + } else { + auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates, float_less); + assert(iterator != float_list.end()); + assert(float_compare(*iterator, coordinates)); + auto coordinate = std::distance(float_list.begin(), iterator); + assert(coordinate != 0); + std::visit([&](auto &target_data) { + if constexpr (std::is_same_v< + std::map, + typename std::decay_t + >) { + target_data[line_number] = coordinate; + } + }, coordinate_index_data.texture_coordinates); + } + } + } + int j = 0; + }, coordinate_data.texture_coordinates); + } + + return coordinate_index_data; + } +} + +#endif // __WAVEFRONT_PARSE_TPP__ diff --git a/tests/unit/parse_test.cpp b/tests/unit/parse_test.cpp new file mode 100644 index 0000000..0185a1b --- /dev/null +++ b/tests/unit/parse_test.cpp @@ -0,0 +1,129 @@ +#include + +#include + +#include "parse.hpp" +#include "scan.hpp" + +namespace { + TEST(ParseFaceData, BuildsTrianglesAndIndexSets) { + wavefront::scan_result scan_result; + scan_result.total_lines = 26; + scan_result.line_data = { + {17u, "f 1/1/1 2/2/2 3/3/2"}, + {19u, "f 4/3/2 5/2/1 6/1/2"}, + {21u, "f 7/2/2 8/3/2 9/1/1"}, + {23u, "f 8/1/1 5/2/2 3/3/2"}, + {25u, "f 2/1/1 6/2/2 4/3/2"} + }; + scan_result.category_map = { + {"f", {17u, 19u, 21u, 23u, 25u}} + }; + + const auto face_data = wavefront::parse_face_data(scan_result); + + EXPECT_EQ(face_data.triangle_list.size(), 5u); + + EXPECT_EQ(face_data.index_position_set.size(), 9u); + EXPECT_TRUE(face_data.index_position_set.contains(1)); + EXPECT_TRUE(face_data.index_position_set.contains(9)); + + EXPECT_EQ(face_data.index_normal_set.size(), 2u); + EXPECT_TRUE(face_data.index_normal_set.contains(1)); + EXPECT_TRUE(face_data.index_normal_set.contains(2)); + + EXPECT_EQ(face_data.index_texcoord_set.size(), 3u); + EXPECT_TRUE(face_data.index_texcoord_set.contains(1)); + EXPECT_TRUE(face_data.index_texcoord_set.contains(3)); + + const auto &first_triangle = face_data.triangle_list.at(0); + EXPECT_EQ(first_triangle[0].face_line_number, 17u); + EXPECT_EQ(first_triangle[0].position_index, 1); + EXPECT_EQ(first_triangle[0].texcoord_index, 1); + EXPECT_EQ(first_triangle[0].normal_index, 1); + } + + TEST(ParseCoordinateData, MapsCoordinatesWithoutParsingFaces) { + wavefront::scan_result scan_result; + scan_result.total_lines = 26; + scan_result.line_data = { + {3u, "v 0.1 0.2 0.3"}, + {4u, "v 0.2 0.3 0.4"}, + {5u, "v 0.3 0.4 0.5"}, + {6u, "v 1.1 1.2 1.3"}, + {7u, "v 1.2 1.3 1.4"}, + {8u, "v 1.3 1.4 1.5"}, + {9u, "v 2.1 2.2 2.3"}, + {10u, "v 2.2 2.3 2.4"}, + {11u, "v 2.3 2.4 2.5"}, + {12u, "vn 0.15 0.25 0.35"}, + {13u, "vn 0.25 0.35 0.45"}, + {14u, "vn 0.35 0.45 0.55"}, + {15u, "vt 0.9 0.8"}, + {16u, "vt 0.8 0.7"}, + {17u, "f 1/1/1 2/2/2 3/3/2"}, + {19u, "f 4/3/2 5/2/1 6/1/2"}, + {21u, "f 7/2/2 8/3/2 9/1/1"}, + {23u, "f 8/1/1 5/2/2 3/3/2"}, + {25u, "f 2/1/1 6/2/2 4/3/2"} + }; + scan_result.category_map = { + {"v", {0u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u}}, + {"vn", {0u, 12u, 13u, 14u}}, + {"vt", {0u, 15u, 16u}}, + {"f", {17u, 19u, 21u, 23u, 25u}} + }; + + wavefront::wavefront_face_data_result_t face_data; + face_data.index_position_set = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + face_data.index_normal_set = {1, 2, 3}; + face_data.index_texcoord_set = {1, 2}; + face_data.triangle_list = { + {{{17u, 1, 1, 1}, {17u, 2, 2, 2}, {17u, 3, 3, 2}}}, + {{{19u, 4, 3, 2}, {19u, 5, 2, 1}, {19u, 6, 1, 2}}}, + {{{21u, 7, 2, 2}, {21u, 8, 3, 2}, {21u, 9, 1, 1}}}, + {{{23u, 8, 1, 1}, {23u, 5, 2, 2}, {23u, 3, 3, 2}}}, + {{{25u, 2, 1, 1}, {25u, 6, 2, 2}, {25u, 4, 3, 2}}} + }; + + const auto coordinate_data = wavefront::parse_coordinate_data(scan_result, face_data); + + ASSERT_EQ(coordinate_data.position_coordinates.size(), 9u); + const auto &pos_line_2 = coordinate_data.position_coordinates.at(3u); + EXPECT_FLOAT_EQ(pos_line_2[0], 0.1f); + EXPECT_FLOAT_EQ(pos_line_2[1], 0.2f); + EXPECT_FLOAT_EQ(pos_line_2[2], 0.3f); + + const auto &pos_line_5 = coordinate_data.position_coordinates.at(6u); + EXPECT_FLOAT_EQ(pos_line_5[0], 1.1f); + EXPECT_FLOAT_EQ(pos_line_5[1], 1.2f); + EXPECT_FLOAT_EQ(pos_line_5[2], 1.3f); + + const auto &pos_line_10 = coordinate_data.position_coordinates.at(11u); + EXPECT_FLOAT_EQ(pos_line_10[0], 2.3f); + EXPECT_FLOAT_EQ(pos_line_10[1], 2.4f); + EXPECT_FLOAT_EQ(pos_line_10[2], 2.5f); + + ASSERT_EQ(coordinate_data.normal_coordinates.size(), 3u); + const auto &normal_line_11 = coordinate_data.normal_coordinates.at(12u); + EXPECT_FLOAT_EQ(normal_line_11[0], 0.15f); + EXPECT_FLOAT_EQ(normal_line_11[1], 0.25f); + EXPECT_FLOAT_EQ(normal_line_11[2], 0.35f); + + const auto &normal_line_13 = coordinate_data.normal_coordinates.at(14u); + EXPECT_FLOAT_EQ(normal_line_13[0], 0.35f); + EXPECT_FLOAT_EQ(normal_line_13[1], 0.45f); + EXPECT_FLOAT_EQ(normal_line_13[2], 0.55f); + + ASSERT_EQ(coordinate_data.texture_coordinates.index(), 2u); + const auto &texcoords = std::get<2>(coordinate_data.texture_coordinates); + ASSERT_EQ(texcoords.size(), 2u); + const auto &tex_line_14 = texcoords.at(15u); + EXPECT_FLOAT_EQ(tex_line_14[0], 0.9f); + EXPECT_FLOAT_EQ(tex_line_14[1], 0.8f); + + const auto &tex_line_15 = texcoords.at(16u); + EXPECT_FLOAT_EQ(tex_line_15[0], 0.8f); + EXPECT_FLOAT_EQ(tex_line_15[1], 0.7f); + } +}