feat: parse wavefront as string lines
This commit is contained in:
53
build.sh
Executable file
53
build.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Determine absolute project root (script’s parent directory)
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Helper to configure & build
|
||||
# $1 = build directory name under PROJECT_ROOT/build
|
||||
# $2 = CMake build type (arbitrary string; flags are driven by -DCMAKE_CXX_FLAGS)
|
||||
# $3 = CXX flags
|
||||
cmake_build() {
|
||||
local name=$1
|
||||
local type=$2
|
||||
local flags=$3
|
||||
local build_dir="${PROJECT_ROOT}/build/${name}"
|
||||
|
||||
echo "=== Configuring ${name} (${flags}) ==="
|
||||
rm -rf "${build_dir}"
|
||||
mkdir -p "${build_dir}"
|
||||
pushd "${build_dir}" >/dev/null
|
||||
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE="${type}" \
|
||||
-DCMAKE_CXX_FLAGS="${flags}" \
|
||||
"${PROJECT_ROOT}"
|
||||
make -j$(nproc)
|
||||
|
||||
popd >/dev/null
|
||||
}
|
||||
|
||||
# 1) Debug: -g
|
||||
cmake_build "Debug" "Debug" "-g"
|
||||
|
||||
# 2) Release: -O3
|
||||
cmake_build "Release" "Release" "-O3"
|
||||
|
||||
# 3) RelWithDebugInfo: -g -O3
|
||||
cmake_build "RelWithDebugInfo" "RelWithDebInfo" "-g -O3"
|
||||
|
||||
# 4) Generate verbose assembly (.S) for all translation units in RelWithDebugInfo
|
||||
echo "=== Generating .S assembly in build/RelWithDebugInfo ==="
|
||||
ASM_OUT_DIR="${PROJECT_ROOT}/build/RelWithDebugInfo/asm"
|
||||
mkdir -p "${ASM_OUT_DIR}"
|
||||
|
||||
# adjust the source‐file patterns as needed (e.g. .cc, .cxx)
|
||||
find "${PROJECT_ROOT}" -type f \( -name '*.cpp' -o -name '*.cc' \) | while read -r src; do
|
||||
fname="$(basename "${src}")"
|
||||
base="${fname%.*}"
|
||||
g++ -g -O3 -masm=intel -fno-verbose-asm -std=c++20 -S "${src}" \
|
||||
-o "${ASM_OUT_DIR}/${base}.S"
|
||||
done
|
||||
|
||||
echo "All builds complete."
|
||||
@@ -12,4 +12,14 @@ constexpr std::array<T, N> array_fill(const T& value) {
|
||||
return array;
|
||||
}
|
||||
|
||||
template<typename F, std::size_t... I>
|
||||
constexpr void _static_for_impl(F &&f, std::index_sequence<I...>) {
|
||||
(f(std::integral_constant<std::size_t, I>{}), ...);
|
||||
}
|
||||
|
||||
template<std::size_t N, typename F>
|
||||
constexpr void static_for(F &&f) {
|
||||
_static_for_impl(std::forward<F>(f), std::make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
#endif // APP_HELPER_H
|
||||
36
src/main.cpp
36
src/main.cpp
@@ -13,7 +13,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "wavefront.hpp"
|
||||
#include "output.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@@ -109,31 +108,22 @@ int main(int argc, char *argv[]) {
|
||||
// printUsage();
|
||||
// return 1;
|
||||
// }
|
||||
WaveFront::Settings wavefront_settings(
|
||||
selected_objects.empty() ? std::nullopt : std::make_optional(selected_objects),
|
||||
selected_groups.empty() ? std::nullopt : std::make_optional(selected_groups)
|
||||
);
|
||||
WaveFront wavefront_parser(wavefront_settings);
|
||||
// WaveFrontFilter wavefront_filter(
|
||||
// selected_objects.empty() ? std::nullopt : std::make_optional(selected_objects),
|
||||
// selected_groups.empty() ? std::nullopt : std::make_optional(selected_groups)
|
||||
// );
|
||||
|
||||
try {
|
||||
if (input_file_path == "-") {
|
||||
wavefront_parser.parse(std::cin);
|
||||
} else {
|
||||
std::ifstream input_file(input_file_path);
|
||||
if (!input_file) {
|
||||
std::cerr << "Failed to open input file: " << input_file_path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
wavefront_parser.parse(input_file);
|
||||
}
|
||||
} catch (const WaveFront::parse_error& e) {
|
||||
std::cerr << input_file_path << ":" << e.line_number() << ": " << e.what() << std::endl;
|
||||
return 1;
|
||||
std::ifstream input_file;
|
||||
std::istream &input_stream = (input_file_path == "")
|
||||
? std::cin
|
||||
: (input_file.open(input_file_path), input_file);
|
||||
|
||||
if (!input_stream) {
|
||||
std::cerr << "Failed to open file: " << input_file_path << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
Output output;
|
||||
|
||||
output.compile(wavefront_parser);
|
||||
auto wavefront_lines = parse_wavefront(input_stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include "output.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "numset.hpp"
|
||||
|
||||
Output::Output() {
|
||||
float_data_.push_back(std::numeric_limits<float>::quiet_NaN());
|
||||
vector_2d_data_.push_back(array_fill<2, std::uint32_t>(0));
|
||||
vector_3d_data_.push_back(array_fill<3, std::uint32_t>(0));
|
||||
triangle_data_.push_back(array_fill<3, uint32_t>(0));
|
||||
}
|
||||
|
||||
void Output::compile(const WaveFront &input) {
|
||||
compile_float_data(input);
|
||||
}
|
||||
|
||||
static const std::array<std::string, 3> attribute_name = {
|
||||
"position",
|
||||
"texture",
|
||||
"normal"
|
||||
};
|
||||
|
||||
template<std::size_t N>
|
||||
void ensure_dims(std::size_t num_dimensions, std::uint32_t attribute_index) {
|
||||
if (num_dimensions != 3) {
|
||||
std::stringstream message;
|
||||
message << "Unexpected unaligned " << attribute_name[attribute_index] << " size: expected exactly " << N << " dimensions, got " << num_dimensions;
|
||||
throw std::runtime_error(message.str());
|
||||
}
|
||||
}
|
||||
|
||||
void Output::compile_float_data(const WaveFront &input) {
|
||||
using get_data_reference_func_t = std::function<const std::vector<std::array<float, 3>> &()>;
|
||||
static const std::array<get_data_reference_func_t, 3> get_data_reference{{
|
||||
[&]() -> const std::vector<std::array<float, 3>> & {
|
||||
return input.obj_v();
|
||||
},
|
||||
[&]() -> const std::vector<std::array<float, 3>> & {
|
||||
return input.obj_vt();
|
||||
},
|
||||
[&]() -> const std::vector<std::array<float, 3>> & {
|
||||
return input.obj_vn();
|
||||
},
|
||||
}};
|
||||
std::set<float, less_with_nan_first_and_nearly_equal<float>> float_set;
|
||||
std::size_t texture_size = 0;
|
||||
|
||||
using check_attribute_dimensions_func_t = std::function<void(std::uint32_t, std::uint32_t)>;
|
||||
std::array<check_attribute_dimensions_func_t, 3> check_attribute_dimensions{{
|
||||
ensure_dims<3>,
|
||||
[&](std::uint32_t num_dimensions, std::uint32_t attribute_index) {
|
||||
texture_size = num_dimensions;
|
||||
check_attribute_dimensions[1] = [&](std::uint32_t num_dimensions, std::uint32_t attribute_index) {
|
||||
if (texture_size != num_dimensions) {
|
||||
std::stringstream message;
|
||||
message << "Unexpected unaligned texture size: expected exactly " << texture_size << " dimensions, got " << num_dimensions;
|
||||
throw std::runtime_error(message.str());
|
||||
}
|
||||
};
|
||||
},
|
||||
ensure_dims<3>,
|
||||
}};
|
||||
for (const auto &triangle : input.obj_f()) {
|
||||
for (const auto &vertex : triangle) {
|
||||
for (std::uint32_t attribute_index = 0; attribute_index < 3; ++attribute_index) {
|
||||
const auto &attribute_reference = vertex[attribute_index];
|
||||
if (attribute_reference == 0) {
|
||||
continue;
|
||||
}
|
||||
const auto &container = get_data_reference[attribute_index]();
|
||||
assert(attribute_reference < container.size());
|
||||
std::uint32_t dim_count = 0;
|
||||
for (const auto &value : container.at(attribute_reference)) {
|
||||
if (std::isnan(value)) {
|
||||
break;
|
||||
}
|
||||
++dim_count;
|
||||
float_set.insert(value);
|
||||
}
|
||||
assert(dim_count > 0);
|
||||
check_attribute_dimensions[attribute_index](dim_count, attribute_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float_data_.insert(float_data_.end(), float_set.begin(), float_set.end());
|
||||
|
||||
int j = 0;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef APP_MODEL_HPP
|
||||
#define APP_MODEL_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "wavefront.hpp"
|
||||
|
||||
class Output {
|
||||
std::vector<float> float_data_;
|
||||
std::vector<std::array<std::uint32_t, 2>> vector_2d_data_;
|
||||
std::vector<std::array<std::uint32_t, 3>> vector_3d_data_;
|
||||
std::variant<
|
||||
uint32_t,
|
||||
std::array<uint32_t, 2>,
|
||||
std::array<uint32_t, 3>
|
||||
> vertex_data_;
|
||||
std::vector<std::array<uint32_t, 3>> triangle_data_;
|
||||
|
||||
public:
|
||||
Output();
|
||||
~Output() = default;
|
||||
|
||||
private:
|
||||
void compile_float_data(const WaveFront &input);
|
||||
|
||||
public:
|
||||
void compile(const WaveFront &input);
|
||||
};
|
||||
|
||||
#endif // APP_MODEL_HPP
|
||||
@@ -1,278 +1,120 @@
|
||||
#include "wavefront.hpp"
|
||||
#include "helper.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
WaveFront::Settings::Settings(
|
||||
std::optional<std::vector<std::string>> selected_objects,
|
||||
std::optional<std::vector<std::string>> selected_groups
|
||||
) :
|
||||
selected_objects_(selected_objects),
|
||||
selected_groups_(selected_groups)
|
||||
{
|
||||
#include "wavefront.hpp"
|
||||
|
||||
WaveFrontLine::WaveFrontLine(const std::size_t &line_number, const std::string &type, const std::string &content)
|
||||
: line_number_(line_number), type_(type), content_(content) {
|
||||
}
|
||||
|
||||
WaveFront::parse_error::parse_error(std::size_t line_number, const std::string& message) :
|
||||
std::runtime_error(message),
|
||||
line_number_(line_number)
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t WaveFront::parse_error::line_number() const noexcept {
|
||||
const std::size_t &WaveFrontLine::line_number() {
|
||||
return line_number_;
|
||||
}
|
||||
|
||||
const std::map<std::string, WaveFront::_parse_line_t> WaveFront::_parse_line_{
|
||||
{ "v", &WaveFront::parse_v },
|
||||
{ "vt", &WaveFront::parse_vt },
|
||||
{ "vn", &WaveFront::parse_vn },
|
||||
{ "f", &WaveFront::parse_f },
|
||||
{ "o", &WaveFront::parse_o },
|
||||
{ "g", &WaveFront::parse_g },
|
||||
};
|
||||
|
||||
WaveFront::WaveFront(
|
||||
const Settings& settings
|
||||
) :
|
||||
settings_(settings),
|
||||
num_attributes_(0),
|
||||
num_texture_coordinates_(0),
|
||||
current_line_(0)
|
||||
{
|
||||
obj_v_.push_back(array_fill<3>(std::numeric_limits<float>::quiet_NaN()));
|
||||
obj_vt_.push_back(array_fill<3>(std::numeric_limits<float>::quiet_NaN()));
|
||||
obj_vn_.push_back(array_fill<3>(std::numeric_limits<float>::quiet_NaN()));
|
||||
obj_f_.push_back(array_fill<3>(array_fill<3>(uint32_t(0))));
|
||||
const std::string &WaveFrontLine::type() {
|
||||
return type_;
|
||||
}
|
||||
const std::string &WaveFrontLine::content() {
|
||||
return content_;
|
||||
}
|
||||
|
||||
void WaveFront::parse(std::istream &input_stream) {
|
||||
std::string line;
|
||||
const WaveFrontFilter WaveFrontFilter::no_filter{std::nullopt, std::nullopt};
|
||||
|
||||
while(std::getline(input_stream, line)) {
|
||||
++current_line_;
|
||||
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue; // Skip empty lines and comments
|
||||
}
|
||||
|
||||
std::istringstream line_parser(line);
|
||||
std::string token;
|
||||
|
||||
std::getline(line_parser, token, ' ');
|
||||
if (token.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto token_parser_iterator = _parse_line_.find(token);
|
||||
if (token_parser_iterator != _parse_line_.end()) {
|
||||
(this->*(token_parser_iterator->second))(line_parser);
|
||||
}
|
||||
}
|
||||
inline std::string trim(const std::string &source) {
|
||||
static const auto if_space = [](auto source_char){
|
||||
return std::isspace(source_char);
|
||||
};
|
||||
auto left = std::find_if_not(source.begin(), source.end(), if_space);
|
||||
auto right = std::find_if_not(source.rbegin(), source.rend(), if_space).base();
|
||||
return std::string(left, right);
|
||||
}
|
||||
|
||||
void WaveFront::parse_o(std::istringstream &line_parser) {
|
||||
std::string object_name;
|
||||
std::getline(line_parser, object_name);
|
||||
if (object_name.empty()) {
|
||||
current_object_.reset();
|
||||
inline void assign_if_not_empty(std::optional<std::string> &context, const std::string &name) {
|
||||
auto trimmed_name = trim(name);
|
||||
if (trimmed_name.empty()) {
|
||||
context.reset();
|
||||
} else {
|
||||
current_object_ = object_name;
|
||||
context = name;
|
||||
}
|
||||
}
|
||||
|
||||
void WaveFront::parse_g(std::istringstream &line_parser) {
|
||||
std::string group_name;
|
||||
std::getline(line_parser, group_name);
|
||||
if (group_name.empty()) {
|
||||
current_group_.reset();
|
||||
} else {
|
||||
current_group_ = group_name;
|
||||
}
|
||||
}
|
||||
|
||||
void WaveFront::parse_v(std::istringstream &line_parser) {
|
||||
std::array<float, 3> data = array_fill<3>(std::numeric_limits<float>::quiet_NaN());
|
||||
std::string element;
|
||||
std::size_t element_count = 0;
|
||||
|
||||
while (std::getline(line_parser, element, ' ')) {
|
||||
if (element_count >= 3) {
|
||||
throw parse_error(current_line_, "Type \"v\" with more than 3 components is not supported.");
|
||||
}
|
||||
if (element.empty()) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
data[element_count++] = std::stof(element);
|
||||
} catch (const std::invalid_argument&) {
|
||||
throw parse_error(current_line_, "Invalid float value in vertex definition.");
|
||||
} catch (const std::out_of_range&) {
|
||||
throw parse_error(current_line_, "Float value out of range in vertex definition.");
|
||||
}
|
||||
}
|
||||
if (element_count < 3) {
|
||||
throw parse_error(current_line_, "Type \"v\" must have exactly 3 components.");
|
||||
}
|
||||
obj_v_.push_back(data);
|
||||
}
|
||||
|
||||
void WaveFront::parse_vn(std::istringstream &line_parser) {
|
||||
std::array<float, 3> data = array_fill<3>(std::numeric_limits<float>::quiet_NaN());
|
||||
std::string element;
|
||||
std::size_t element_count = 0;
|
||||
|
||||
while (std::getline(line_parser, element, ' ')) {
|
||||
if (element_count >= 3) {
|
||||
throw parse_error(current_line_, "Type \"vn\" with more than 3 components is not supported.");
|
||||
}
|
||||
if (element.empty()) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
data[element_count++] = std::stof(element);
|
||||
} catch (const std::invalid_argument&) {
|
||||
throw parse_error(current_line_, "Invalid float value in vertex normal definition.");
|
||||
} catch (const std::out_of_range&) {
|
||||
throw parse_error(current_line_, "Float value out of range in vertex normal definition.");
|
||||
}
|
||||
}
|
||||
if (element_count < 3) {
|
||||
throw parse_error(current_line_, "Type \"vn\" with have exactly 3 components.");
|
||||
}
|
||||
obj_vn_.push_back(data);
|
||||
}
|
||||
|
||||
void WaveFront::parse_vt(std::istringstream &line_parser) {
|
||||
std::array<float, 3> data = array_fill<3>(std::numeric_limits<float>::quiet_NaN());
|
||||
std::string element;
|
||||
std::size_t element_count = 0;
|
||||
|
||||
while (std::getline(line_parser, element, ' ')) {
|
||||
if (element_count >= 3) {
|
||||
throw parse_error(current_line_, "Type \"vt\" with more than 3 components is not supported.");
|
||||
std::map<std::string, std::vector<WaveFrontLine>> parse_wavefront(
|
||||
std::istream &input_stream,
|
||||
const WaveFrontFilter &filter
|
||||
) {
|
||||
std::map<std::string, std::vector<WaveFrontLine>> line_data;
|
||||
std::optional<std::string> current_object, current_group;
|
||||
std::size_t current_line_number = 0;
|
||||
bool select_face = true;
|
||||
using check_filter_func_t = std::function<bool()>;
|
||||
static const auto return_true = []()->bool { return true; };
|
||||
check_filter_func_t check_object = return_true;
|
||||
check_filter_func_t check_group = return_true;
|
||||
if (filter.selected_objects.has_value()) {
|
||||
check_object = [&]()->bool {
|
||||
auto selected = filter.selected_objects.value();
|
||||
auto begin = selected.begin();
|
||||
auto end = selected.end();
|
||||
return std::find(begin, end, current_object.value_or("")) == end;
|
||||
};
|
||||
if (element.empty()) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
data[element_count++] = std::stof(element);
|
||||
} catch (const std::invalid_argument&) {
|
||||
throw parse_error(current_line_, "Invalid float value in texture coordinate definition.");
|
||||
} catch (const std::out_of_range&) {
|
||||
throw parse_error(current_line_, "Float value out of range in texture coordinate definition.");
|
||||
}
|
||||
}
|
||||
|
||||
if (element_count < 1) {
|
||||
throw parse_error(current_line_, "Type \"vt\" must have at least 1 component.");
|
||||
if (filter.selected_groups.has_value()) {
|
||||
check_group = [&]()->bool {
|
||||
auto selected = filter.selected_objects.value();
|
||||
auto begin = selected.begin();
|
||||
auto end = selected.end();
|
||||
return std::find(begin, end, current_object.value_or("")) == end;
|
||||
};
|
||||
}
|
||||
using line_processor_func_t = std::function<void(const std::string &type, const std::string &content)>;
|
||||
line_processor_func_t insert_line = [&](const std::string &type, const std::string &content) {
|
||||
line_data[type].push_back(WaveFrontLine(
|
||||
current_line_number,
|
||||
type,
|
||||
content
|
||||
));
|
||||
};
|
||||
static const std::map<std::string, line_processor_func_t> line_post_processor_map{
|
||||
{ "o", [&](const std::string &type, const std::string &content) {
|
||||
assign_if_not_empty(current_object, content);
|
||||
}},
|
||||
{ "g", [&](const std::string &type, const std::string &content) {
|
||||
assign_if_not_empty(current_group, content);
|
||||
}},
|
||||
{ "f", [&](const std::string &type, const std::string &content) {
|
||||
if (!check_object() || !check_group()) {
|
||||
return;
|
||||
}
|
||||
insert_line(type, content);
|
||||
}},
|
||||
{ "v", insert_line },
|
||||
{ "vt", insert_line },
|
||||
{ "vn", insert_line },
|
||||
};
|
||||
|
||||
obj_vt_.push_back(data);
|
||||
}
|
||||
{
|
||||
std::string line;
|
||||
while(std::getline(input_stream, line)) {
|
||||
++current_line_number;
|
||||
|
||||
void WaveFront::parse_f(std::istringstream &line_parser) {
|
||||
if (settings_.selected_objects_.has_value()) {
|
||||
if (!current_object_.has_value()) {
|
||||
return;
|
||||
}
|
||||
auto &selected_objects = settings_.selected_objects_.value();
|
||||
if (std::find(selected_objects.begin(), selected_objects.end(), current_object_.value()) == selected_objects.end()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (settings_.selected_groups_) {
|
||||
if (!current_group_.has_value()) {
|
||||
return;
|
||||
}
|
||||
auto selected_begin = settings_.selected_groups_->begin();
|
||||
auto selected_end = settings_.selected_groups_->end();
|
||||
auto current_value = current_group_.value();
|
||||
if (std::find(selected_begin, selected_end, current_value) == selected_end) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue; // Skip empty lines and comments
|
||||
}
|
||||
|
||||
std::size_t vertex_count = 0;
|
||||
std::array<std::array<uint32_t, 3>, 3> triangle;
|
||||
std::string token;
|
||||
std::istringstream line_parser(line);
|
||||
std::string line_type;
|
||||
|
||||
while (std::getline(line_parser, token, ' ')) {
|
||||
if (token.empty()) {
|
||||
break;
|
||||
}
|
||||
auto vertex_indices = parse_vertex(token);
|
||||
if (vertex_count < 3) {
|
||||
triangle[vertex_count] = vertex_indices;
|
||||
} else {
|
||||
obj_f_.push_back(triangle);
|
||||
triangle[0] = triangle[1];
|
||||
triangle[1] = triangle[2];
|
||||
triangle[2] = vertex_indices;
|
||||
}
|
||||
++vertex_count;
|
||||
}
|
||||
}
|
||||
std::getline(line_parser, line_type, ' ');
|
||||
if (line_type.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::array<uint32_t, 3> WaveFront::parse_vertex(std::string &token) {
|
||||
std::istringstream token_parser(token);
|
||||
std::array<uint32_t, 3> vertex_result{0, 0, 0};
|
||||
std::string vertex_token;
|
||||
std::size_t attribute_count = 0;
|
||||
|
||||
static const std::array<std::vector<std::array<float, 3>>, 3> data_reference = {obj_v_, obj_vt_, obj_vn_};
|
||||
|
||||
while (std::getline(token_parser, vertex_token, '/')) {
|
||||
if (attribute_count >= 3) {
|
||||
throw parse_error(current_line_, "Face vertex with more than 3 components is not supported.");
|
||||
}
|
||||
int64_t attribute_value;
|
||||
if (vertex_token.empty()) {
|
||||
attribute_value = 0;
|
||||
} else {
|
||||
try {
|
||||
attribute_value = std::stoll(vertex_token);
|
||||
} catch (const std::invalid_argument&) {
|
||||
std::stringstream message;
|
||||
message << "Invalid face vertex index: " << vertex_token;
|
||||
throw parse_error(current_line_, message.str());
|
||||
} catch (const std::out_of_range&) {
|
||||
std::stringstream message;
|
||||
message << "Face vertex index out of range: " << vertex_token;
|
||||
throw parse_error(current_line_, message.str());
|
||||
auto preprocessor_iterator = line_post_processor_map.find(line_type);
|
||||
if (preprocessor_iterator != line_post_processor_map.end()) {
|
||||
std::ostringstream line_content;
|
||||
line_content << line_parser.rdbuf();
|
||||
(preprocessor_iterator->second)(line_type, line_content.str());
|
||||
}
|
||||
}
|
||||
|
||||
if (attribute_value < 0) {
|
||||
attribute_value = data_reference[attribute_count].size() + attribute_value;
|
||||
if (attribute_value < 1 || attribute_value > data_reference[attribute_count].size()) {
|
||||
std::stringstream message;
|
||||
message << "Face vertex index out of range: " << vertex_token;
|
||||
throw parse_error(current_line_, message.str());
|
||||
}
|
||||
} else if (attribute_value >= static_cast<int64_t>(std::numeric_limits<uint32_t>::max())) {
|
||||
std::stringstream message;
|
||||
message << "Face vertex index out of range: " << vertex_token;
|
||||
throw parse_error(current_line_, message.str());
|
||||
}
|
||||
vertex_result[attribute_count] = attribute_value;
|
||||
++attribute_count;
|
||||
}
|
||||
return vertex_result;
|
||||
}
|
||||
|
||||
const std::vector<std::array<float, 3>> &WaveFront::obj_v() const noexcept {
|
||||
return obj_v_;
|
||||
}
|
||||
|
||||
const std::vector<std::array<float, 3>> &WaveFront::obj_vt() const noexcept {
|
||||
return obj_vt_;
|
||||
}
|
||||
|
||||
const std::vector<std::array<float, 3>> &WaveFront::obj_vn() const noexcept {
|
||||
return obj_vn_;
|
||||
}
|
||||
|
||||
const std::vector<std::array<std::array<std::uint32_t, 3>, 3>> &WaveFront::obj_f() const noexcept {
|
||||
return obj_f_;
|
||||
return line_data;
|
||||
}
|
||||
@@ -1,80 +1,41 @@
|
||||
#ifndef APP_WAVEFRONT_HPP
|
||||
#define APP_WAVEFRONT_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class WaveFront;
|
||||
|
||||
class WaveFront {
|
||||
public:
|
||||
enum class AttributeIndex : uint32_t {
|
||||
POSITION = 0,
|
||||
TEXTURE = 1,
|
||||
NORMAL = 2
|
||||
};
|
||||
public:
|
||||
class Settings {
|
||||
friend class WaveFront;
|
||||
private:
|
||||
std::optional<std::vector<std::string>> selected_objects_;
|
||||
std::optional<std::vector<std::string>> selected_groups_;
|
||||
|
||||
public:
|
||||
Settings() = default;
|
||||
Settings(
|
||||
std::optional<std::vector<std::string>> selected_objects,
|
||||
std::optional<std::vector<std::string>> selected_groups
|
||||
);
|
||||
Settings(const Settings&) = default;
|
||||
Settings(Settings&&) = default;
|
||||
~Settings() = default;
|
||||
};
|
||||
|
||||
class parse_error : public std::runtime_error {
|
||||
public:
|
||||
parse_error(std::size_t line_number, const std::string& message);
|
||||
std::size_t line_number() const noexcept;
|
||||
|
||||
private:
|
||||
std::size_t line_number_;
|
||||
};
|
||||
private:
|
||||
using _parse_line_t = void (WaveFront::*)(std::istringstream&);
|
||||
Settings settings_;
|
||||
std::vector<std::array<float, 3>> obj_v_, obj_vt_, obj_vn_;
|
||||
std::vector<std::array<std::array<std::uint32_t, 3>, 3>> obj_f_;
|
||||
std::size_t num_attributes_, num_texture_coordinates_, current_line_;
|
||||
std::optional<std::string> current_object_, current_group_;
|
||||
|
||||
static const std::map<std::string, _parse_line_t> _parse_line_;
|
||||
|
||||
private:
|
||||
void parse_o(std::istringstream &line_parser);
|
||||
void parse_g(std::istringstream &line_parser);
|
||||
void parse_v(std::istringstream &line_parser);
|
||||
void parse_vn(std::istringstream &line_parser);
|
||||
void parse_vt(std::istringstream &line_parser);
|
||||
void parse_f(std::istringstream &line_parser);
|
||||
std::array<uint32_t, 3> parse_vertex(std::string &line_parser);
|
||||
class WaveFrontLine {
|
||||
std::size_t line_number_;
|
||||
std::string type_;
|
||||
std::string content_;
|
||||
|
||||
public:
|
||||
const std::vector<std::array<float, 3>> &obj_v() const noexcept;
|
||||
const std::vector<std::array<float, 3>> &obj_vt() const noexcept;
|
||||
const std::vector<std::array<float, 3>> &obj_vn() const noexcept;
|
||||
const std::vector<std::array<std::array<std::uint32_t, 3>, 3>> &obj_f() const noexcept;
|
||||
WaveFrontLine(const std::size_t &line_number, const std::string &type, const std::string &content);
|
||||
~WaveFrontLine() = default;
|
||||
WaveFrontLine(const WaveFrontLine &) = default;
|
||||
WaveFrontLine(WaveFrontLine &&) = default;
|
||||
|
||||
public:
|
||||
explicit WaveFront(const Settings &settings = Settings(std::nullopt, std::nullopt));
|
||||
~WaveFront() = default;
|
||||
|
||||
void parse(std::istream &input_string);
|
||||
const std::size_t &line_number();
|
||||
const std::string &type();
|
||||
const std::string &content();
|
||||
};
|
||||
|
||||
class WaveFrontFilter {
|
||||
public:
|
||||
std::optional<std::vector<std::string>> selected_objects;
|
||||
std::optional<std::vector<std::string>> selected_groups;
|
||||
public:
|
||||
static const WaveFrontFilter no_filter;
|
||||
};
|
||||
|
||||
std::map<std::string, std::vector<WaveFrontLine>> parse_wavefront(
|
||||
std::istream &input_stream,
|
||||
const WaveFrontFilter &filter = WaveFrontFilter::no_filter
|
||||
);
|
||||
|
||||
#endif // APP_WAVEFRONT_HPP
|
||||
|
||||
Reference in New Issue
Block a user