worked on obj and mtl prefetching nad parsing

This commit is contained in:
ZY4N
2024-12-26 20:20:02 +01:00
parent b385b3b1c8
commit 447146b7f5
16 changed files with 606 additions and 376 deletions

View File

@@ -10,31 +10,35 @@
#include "assets/dynamic_data_loaders/dynamic_texture_loader.hpp"
namespace mtl_loader_error {
struct category : std::error_category {
[[nodiscard]] const char* name() const noexcept override {
return "connector";
namespace mtl_loader_error
{
struct category : std::error_category
{
[[nodiscard]] const char* name() const noexcept override
{
return "mtl_loader";
}
[[nodiscard]] std::string message(int ev) const override {
switch (static_cast<codes>(ev)) {
[[nodiscard]] std::string message(int ev) const override
{
switch (static_cast<codes>(ev))
{
using enum codes;
case mtl_cannot_open_file:
case cannot_open_file:
return "Cannot open mtl file.";
case mtl_cannot_open_texture:
case cannot_open_texture:
return "Cannot open texture file.";
case mtl_malformed_ambient_color:
case malformed_ambient_color:
return "File contains malformed 'Ka' statement.";
case mtl_malformed_diffuse_color:
case malformed_diffuse_color:
return "File contains malformed 'Kd' statement.";
case mtl_malformed_specular_color:
case malformed_specular_color:
return "File contains malformed 'Ks' statement.";
case mtl_malformed_specular_exponent:
case malformed_specular_exponent:
return "File contains malformed 'Ns' statement.";
case mtl_malformed_dissolve:
case malformed_dissolve:
return "File contains malformed 'd' statement.";
case mlt_unknown_line_begin:
case unknown_line_begin:
return "Unknown mtl line begin";
default:
using namespace std::string_literals;
@@ -45,22 +49,24 @@ struct category : std::error_category {
} // namespace mesh_loader_error
inline std::error_category& connector_error_category() {
inline std::error_category& connector_error_category()
{
static mtl_loader_error::category category;
return category;
}
namespace mtl_loader_error {
inline std::error_code make_error_code(codes e) {
namespace mtl_loader_error
{
inline std::error_code make_error_code(codes e)
{
return { static_cast<int>(e), connector_error_category() };
}
} // namespace mtl_loader_error
template<typename T, std::size_t Count>
std::errc parse_numeric_vector(std::string_view param, std::array<T, Count>& values) {
std::errc parse_numeric_vector(std::string_view param, std::array<T, Count>& values)
{
auto it = param.begin(), end = param.end();
for (auto& value : values)
@@ -83,20 +89,202 @@ std::errc parse_numeric_vector(std::string_view param, std::array<T, Count>& val
return {};
};
std::optional<dynamic_material_store::id_type> mtl_loader::find_id(std::string_view name)
{
const auto it = m_id_lookup.find(name);
if (it == m_id_lookup.end())
void mtl_loader::find_textures(
std::span<char> buffer,
std::filesystem::path& path_buffer,
const std::filesystem::path& base_directory,
std::ifstream& in,
ztu::string_list& texture_filenames
) {
using namespace std::string_view_literals;
// TODO 'bump' is missing!!!
static constexpr auto keyword = "\nmap_"sv;
using long_postfix_type = std::array<char, 2>;
static constexpr auto postfix_length = std::tuple_size_v<long_postfix_type>;
static constexpr auto make_postfix = [](const std::string_view str) static constexpr
{
return it->second;
}
auto postfix = long_postfix_type{};
assert(str.length() >= postfix_length);
std::copy_n(str.begin(), postfix.size(), postfix.begin());
return postfix;
};
return std::nullopt;
static constexpr auto postfixes = std::array{
make_postfix("d "),
make_postfix("Ka"),
make_postfix("Kd"),
make_postfix("Ks"),
make_postfix("Ns")
};
const auto buffer_view = std::string_view(buffer);
// Add linebreak to simplify line begin search.
buffer.front() = '\n';
auto leftover = std::size_t{ 1 };
enum class match {
exact,
overflowed,
none
};
const auto check_match = [](std::string_view& potential_match) static -> match
{
std::cout << '\'' << potential_match.substr(0, std::min(40ul, potential_match.size())) << '\'' << std::endl;
if (potential_match.length() < postfix_length)
{
return match::overflowed;
}
const auto postfix = make_postfix(potential_match);
// Optimized for SIMD.
if (not std::ranges::contains(postfixes, postfix))
{
return match::none;
}
const auto long_match = postfix.back() != ' ';
if (long_match and (
potential_match.length() < postfix_length + sizeof(' ') or
potential_match[postfix_length] != ' '
)) {
return match::overflowed;
}
const auto actual_postfix_length = std::size_t{ 1 } + static_cast<std::size_t>(long_match);
const auto filename_begin = actual_postfix_length + sizeof(' ');
const auto filename_end = potential_match.find('\n', filename_begin);
if (filename_end == std::string_view::npos)
{
return match::overflowed;
}
const auto length = filename_end - filename_begin;
potential_match = potential_match.substr(filename_begin, length);
return match::exact;
};
do
{
// Keep some old characters to continue matching interrupted sequence.
std::copy(buffer.end() - leftover, buffer.end(), buffer.begin());
in.read(buffer.data() + leftover, buffer.size() - leftover);
const auto str = buffer_view.substr(0, leftover + in.gcount());
auto pos = std::string_view::size_type{};
while ((pos = str.find(keyword, pos)) != std::string_view::npos)
{
const auto keyword_end = pos + keyword.size();
auto potential_match = str.substr(keyword_end);
const auto match_type = check_match(potential_match);
if (match_type == match::exact)
{
path_buffer.assign(potential_match);
if (path_buffer.is_relative())
{
path_buffer = base_directory;
path_buffer /= potential_match;
}
texture_filenames.push_back(path_buffer.c_str());
pos += potential_match.size();
leftover = 0;
}
else if (match_type == match::overflowed)
{
if (pos == 0) [[unlikely]]
{
ztu::logger::error("Ignoring string match, as it exceeds buffer size of % characters.", buffer.size());
leftover = 0;
}
else
{
leftover = str.size() - pos;
}
break;
}
else
{
leftover = keyword.size();
}
}
} while (not in.eof());
}
void mtl_loader::clear_name_lookup() {
m_id_lookup.clear();
std::error_code mtl_loader::prefetch(
const file_dir_list& paths,
prefetch_queue& queue
) {
namespace fs = std::filesystem;
using mtl_loader_error::codes;
using mtl_loader_error::make_error_code;
auto buffer = std::vector<char>(8 * 1024, '\0');
auto in = std::ifstream{};
auto path_buffer = fs::path{};
auto filename_buffer = fs::path{};
const auto process_file = [&]()
{
in.open(filename_buffer);
if (not in.is_open()) {
ztu::logger::error("Could not open .mtl file '%'", filename_buffer);
return;
}
filename_buffer.remove_filename();
find_textures(buffer, path_buffer, filename_buffer, in, queue.texture.files);
in.close();
};
for (const auto file : paths.files)
{
filename_buffer.assign(file);
process_file();
}
for (const auto directory : paths.directories)
{
for (const auto& file : fs::directory_iterator{ directory }) {
filename_buffer.assign(file.path());
// Avoid heap allocation of .extension()
if (not std::string_view(filename_buffer.c_str()).ends_with(".obj"))
{
continue;
}
process_file();
}
}
return {};
}
std::error_code mtl_loader::load_directory(
@@ -164,7 +352,7 @@ std::error_code mtl_loader::load(
auto in = std::ifstream{ filename };
if (not in.is_open()) {
return make_error_code(codes::mtl_cannot_open_file);
return make_error_code(codes::cannot_open_file);
}
namespace fs = std::filesystem;
@@ -252,7 +440,7 @@ std::error_code mtl_loader::load(
auto& properties = material.initialized_surface_properties();
if (parse_numeric_vector(param, properties.ambient_filter) != std::errc{}) [[unlikely]]
{
return codes::mtl_malformed_ambient_color;
return codes::malformed_ambient_color;
}
material.components() |= flags::surface_properties;
@@ -266,7 +454,7 @@ std::error_code mtl_loader::load(
auto& properties = material.initialized_surface_properties();
if (parse_numeric_vector(param, properties.diffuse_filter) != std::errc{}) [[unlikely]]
{
return codes::mtl_malformed_diffuse_color;
return codes::malformed_diffuse_color;
}
material.components() |= flags::surface_properties;
@@ -280,7 +468,7 @@ std::error_code mtl_loader::load(
auto& properties = material.initialized_surface_properties();
if (parse_numeric_vector(param, properties.specular_filter) != std::errc{}) [[unlikely]]
{
return codes::mtl_malformed_specular_color;
return codes::malformed_specular_color;
}
material.components() |= flags::surface_properties;
@@ -295,7 +483,7 @@ std::error_code mtl_loader::load(
std::array<float, 1> shininess{};
if (parse_numeric_vector(param, shininess) != std::errc{}) [[unlikely]]
{
return codes::mtl_malformed_specular_exponent;
return codes::malformed_specular_exponent;
}
properties.shininess = shininess.front();
@@ -310,7 +498,7 @@ std::error_code mtl_loader::load(
std::array<float, 1> transparency{};
if (parse_numeric_vector(param, transparency) != std::errc{}) [[unlikely]]
{
return codes::mtl_malformed_dissolve;
return codes::malformed_dissolve;
}
material.transparency().emplace(transparency.front());