feature: vertex and triangle index storage
This commit is contained in:
198
src/compile.hpp
198
src/compile.hpp
@@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "parse.hpp"
|
||||
#include "repeat.hpp"
|
||||
|
||||
namespace wavefront {
|
||||
template<typename IndexType, template<typename, typename...> typename ContainerType, typename ... Args>
|
||||
@@ -26,6 +27,13 @@ namespace wavefront {
|
||||
> &source
|
||||
) {
|
||||
for (const auto &[line_number, coordinates] : source) {
|
||||
if constexpr (std::ranges::range<std::decay_t<decltype(coordinates)>>) {
|
||||
for (const auto &coordinate : coordinates) {
|
||||
assert(coordinate != 0);
|
||||
}
|
||||
} else {
|
||||
assert(coordinates != 0);
|
||||
}
|
||||
std::get<NumDims>(target).emplace(coordinates);
|
||||
}
|
||||
}
|
||||
@@ -73,7 +81,14 @@ namespace wavefront {
|
||||
auto &target,
|
||||
const auto &source
|
||||
) {
|
||||
target.reserve(source.size());
|
||||
target.reserve(source.size() + 1);
|
||||
if (source.size() > 0) {
|
||||
if constexpr (std::ranges::range<typename std::decay_t<decltype(target)>::value_type>) {
|
||||
target.push_back(repeat_value<IndexType, std::tuple_size_v<typename std::decay_t<decltype(target)>::value_type>>(0));
|
||||
} else {
|
||||
target.push_back(0);
|
||||
}
|
||||
}
|
||||
std::copy(
|
||||
source.begin(),
|
||||
source.end(),
|
||||
@@ -106,6 +121,7 @@ namespace wavefront {
|
||||
auto data_vector_iterator = std::lower_bound(data_storage.begin(), data_storage.end(), data_vector);
|
||||
assert(data_vector_iterator != data_storage.end());
|
||||
auto data_vector_index = std::distance(data_storage.begin(), data_vector_iterator);
|
||||
assert(data_vector_index != 0);
|
||||
result.position_coordinate_index[line_number] = data_vector_index;
|
||||
}
|
||||
}
|
||||
@@ -115,6 +131,7 @@ namespace wavefront {
|
||||
auto data_vector_iterator = std::lower_bound(data_storage.begin(), data_storage.end(), data_vector);
|
||||
assert(data_vector_iterator != data_storage.end());
|
||||
auto data_vector_index = std::distance(data_storage.begin(), data_vector_iterator);
|
||||
assert(data_vector_index != 0);
|
||||
result.normal_coordinate_index[line_number] = data_vector_index;
|
||||
}
|
||||
}
|
||||
@@ -126,10 +143,12 @@ namespace wavefront {
|
||||
auto data_vector_iterator = std::lower_bound(data_storage.begin(), data_storage.end(), data_vector);
|
||||
assert(data_vector_iterator != data_storage.end());
|
||||
auto data_vector_index = std::distance(data_storage.begin(), data_vector_iterator);
|
||||
assert(data_vector_index != 0);
|
||||
result.texcoord_coordinate_index[line_number] = data_vector_index;
|
||||
}
|
||||
} else {
|
||||
for (const auto &[line_number, data_index] : texture_coordinates) {
|
||||
assert(data_index != 0);
|
||||
result.texcoord_coordinate_index[line_number] = data_index;
|
||||
}
|
||||
}
|
||||
@@ -138,4 +157,181 @@ namespace wavefront {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
using unwrap_vertex_func_t = std::function<vertex_index_t(const triangle_vertex_indices &)>;
|
||||
|
||||
namespace {
|
||||
static const unwrap_vertex_func_t get_position_vertex_index = [] (const triangle_vertex_indices &vertex_indices) -> vertex_index_t {
|
||||
return vertex_indices.position_index;
|
||||
};
|
||||
|
||||
static const unwrap_vertex_func_t get_normal_vertex_index = [] (const triangle_vertex_indices &vertex_indices) -> vertex_index_t {
|
||||
return vertex_indices.normal_index;
|
||||
};
|
||||
|
||||
static const unwrap_vertex_func_t get_texcoord_vertex_index = [] (const triangle_vertex_indices &vertex_indices) -> vertex_index_t {
|
||||
return vertex_indices.texcoord_index;
|
||||
};
|
||||
|
||||
template<typename IndexType>
|
||||
struct coordinate_mapper_t {
|
||||
const unwrap_vertex_func_t &get_vertex_index;
|
||||
const std::vector<std::size_t> &attribute_line_map;
|
||||
const std::map<file_line_t, IndexType> &line_coordinate_map;
|
||||
};
|
||||
|
||||
template<typename IndexType, std::size_t VertexDimCount>
|
||||
std::vector<std::array<IndexType, VertexDimCount>> compile_vertex_storage_impl(
|
||||
const scan_result &scan_data,
|
||||
const wavefront_face_data_result_t &face_data,
|
||||
const std::array<coordinate_mapper_t<IndexType>, VertexDimCount> &mapper
|
||||
) {
|
||||
std::set<std::array<IndexType, VertexDimCount>> vertex_storage_set;
|
||||
|
||||
for (const auto &triangle : face_data.triangle_list) {
|
||||
for (const auto &vertex : triangle) {
|
||||
std::array<IndexType, VertexDimCount> coordinate_indices;
|
||||
for (std::size_t i = 0; i < VertexDimCount; ++i) {
|
||||
const auto &wavefront_index = mapper[i].get_vertex_index(vertex);
|
||||
const auto &line_index = mapper[i].attribute_line_map.at(wavefront_index);
|
||||
const auto &coordinate_index = mapper[i].line_coordinate_map.at(line_index);
|
||||
assert(coordinate_index != 0);
|
||||
coordinate_indices[i] = coordinate_index;
|
||||
}
|
||||
vertex_storage_set.emplace(coordinate_indices);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::array<IndexType, VertexDimCount>> result;
|
||||
result.reserve(vertex_storage_set.size() + 1);
|
||||
result.push_back(repeat_value<IndexType, VertexDimCount>(0));
|
||||
std::copy(
|
||||
vertex_storage_set.begin(),
|
||||
vertex_storage_set.end(),
|
||||
std::back_inserter(result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename IndexType, std::size_t VertexDimCount>
|
||||
std::vector<std::array<IndexType, 3>> compile_triangle_storage_impl(
|
||||
const scan_result &scan_data,
|
||||
const wavefront_face_data_result_t &face_data,
|
||||
const std::array<coordinate_mapper_t<IndexType>, VertexDimCount> &mapper,
|
||||
const std::vector<std::array<IndexType, VertexDimCount>> &vertex_data
|
||||
) {
|
||||
std::set<std::array<IndexType, 3>> triangle_data_set;
|
||||
|
||||
for (const auto &triangle : face_data.triangle_list) {
|
||||
std::array<IndexType, 3> triangle_data;
|
||||
std::size_t triangle_vertex_index = 0;
|
||||
for (const auto &vertex : triangle) {
|
||||
std::array<IndexType, VertexDimCount> coordinate_indices;
|
||||
for (std::size_t i = 0; i < VertexDimCount; ++i) {
|
||||
const auto &wavefront_index = mapper[i].get_vertex_index(vertex);
|
||||
const auto &line_index = mapper[i].attribute_line_map.at(wavefront_index);
|
||||
const auto &coordinate_index = mapper[i].line_coordinate_map.at(line_index);
|
||||
assert(coordinate_index != 0);
|
||||
coordinate_indices[i] = coordinate_index;
|
||||
}
|
||||
auto iterator = std::lower_bound(vertex_data.begin(), vertex_data.end(), coordinate_indices);
|
||||
assert(iterator != vertex_data.end());
|
||||
auto index = std::distance(vertex_data.begin(), iterator);
|
||||
assert(index != 0);
|
||||
assert(triangle_vertex_index < 3);
|
||||
triangle_data[triangle_vertex_index++] = index;
|
||||
}
|
||||
assert(triangle_vertex_index == 3);
|
||||
triangle_data_set.emplace(triangle_data);
|
||||
}
|
||||
|
||||
std::vector<std::array<IndexType, 3>> result;
|
||||
result.reserve(triangle_data_set.size() + 1);
|
||||
result.push_back(repeat_value<IndexType, 3>(0));
|
||||
std::copy(
|
||||
triangle_data_set.begin(),
|
||||
triangle_data_set.end(),
|
||||
std::back_inserter(result)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename IndexType, template<typename, typename...> typename ContainerType, typename ... Args>
|
||||
using vertex_storage_t = std::variant<
|
||||
ContainerType<std::array<IndexType, 1>>,
|
||||
ContainerType<std::array<IndexType, 2>>,
|
||||
ContainerType<std::array<IndexType, 3>>
|
||||
>;
|
||||
|
||||
template<typename IndexType, template<typename, typename...> typename ContainerType, typename ... Args>
|
||||
struct compile_triangle_data_result_t {
|
||||
vertex_storage_t<IndexType, ContainerType, Args...> vertices;
|
||||
ContainerType<std::array<IndexType, 3>> triangles;
|
||||
};
|
||||
|
||||
template<typename IndexType>
|
||||
compile_triangle_data_result_t<IndexType, std::vector> compile_vertex_storage(
|
||||
const scan_result &scan_data,
|
||||
const wavefront_face_data_result_t &face_data,
|
||||
const coordinate_storage_line_mapping_t<IndexType> &coordinate_storage_index
|
||||
) {
|
||||
std::vector<coordinate_mapper_t<IndexType>> coordinate_mapper;
|
||||
if (coordinate_storage_index.position_coordinate_index.size() > 0) [[likely]] {
|
||||
coordinate_mapper.push_back(coordinate_mapper_t{
|
||||
.get_vertex_index = get_position_vertex_index,
|
||||
.attribute_line_map = scan_data.category_map.at("v"),
|
||||
.line_coordinate_map = coordinate_storage_index.position_coordinate_index
|
||||
});
|
||||
} else [[unlikely]] {
|
||||
throw parse_error("Expected at least one position coordinate index");
|
||||
}
|
||||
if (coordinate_storage_index.normal_coordinate_index.size() > 0) {
|
||||
coordinate_mapper.push_back(coordinate_mapper_t{
|
||||
.get_vertex_index = get_normal_vertex_index,
|
||||
.attribute_line_map = scan_data.category_map.at("vn"),
|
||||
.line_coordinate_map = coordinate_storage_index.normal_coordinate_index
|
||||
});
|
||||
}
|
||||
if (coordinate_storage_index.texcoord_coordinate_index.size() > 0) {
|
||||
coordinate_mapper.push_back(coordinate_mapper_t{
|
||||
.get_vertex_index = get_texcoord_vertex_index,
|
||||
.attribute_line_map = scan_data.category_map.at("vt"),
|
||||
.line_coordinate_map = coordinate_storage_index.texcoord_coordinate_index
|
||||
});
|
||||
}
|
||||
std::variant<
|
||||
std::array<coordinate_mapper_t<IndexType>, 1>,
|
||||
std::array<coordinate_mapper_t<IndexType>, 2>,
|
||||
std::array<coordinate_mapper_t<IndexType>, 3>
|
||||
> coordinate_mapper_data = ([&]() -> std::variant<
|
||||
std::array<coordinate_mapper_t<IndexType>, 1>,
|
||||
std::array<coordinate_mapper_t<IndexType>, 2>,
|
||||
std::array<coordinate_mapper_t<IndexType>, 3>
|
||||
> {
|
||||
auto vertex_size = coordinate_mapper.size();
|
||||
if (vertex_size == 1) {
|
||||
return std::array<coordinate_mapper_t<IndexType>, 1>{coordinate_mapper[0]};
|
||||
} else if (vertex_size == 2) {
|
||||
return std::array<coordinate_mapper_t<IndexType>, 2>{coordinate_mapper[0], coordinate_mapper[1]};
|
||||
} else if (vertex_size == 3) {
|
||||
return std::array<coordinate_mapper_t<IndexType>, 3>{coordinate_mapper[0], coordinate_mapper[1], coordinate_mapper[2]};
|
||||
} else [[unlikely]] {
|
||||
throw std::runtime_error(std::format("Invalid vertex size: {}", vertex_size));
|
||||
}
|
||||
})();
|
||||
|
||||
auto vertex_data = std::visit([&](const auto &coordinate_mapper) -> vertex_storage_t<IndexType, std::vector> {
|
||||
return compile_vertex_storage_impl<IndexType, std::tuple_size_v<std::decay_t<decltype(coordinate_mapper)>>>(scan_data, face_data, coordinate_mapper);
|
||||
}, coordinate_mapper_data);
|
||||
auto triangle_data = std::visit([&](const auto &coordinate_mapper, const auto &vertex_data) -> std::vector<std::array<IndexType, 3>> {
|
||||
if constexpr (std::tuple_size_v<std::decay_t<decltype(coordinate_mapper)>> == std::tuple_size_v<typename std::decay_t<decltype(vertex_data)>::value_type>) {
|
||||
return compile_triangle_storage_impl<IndexType, std::tuple_size_v<std::decay_t<decltype(coordinate_mapper)>>>(scan_data, face_data, coordinate_mapper, vertex_data);
|
||||
}
|
||||
throw std::runtime_error("Invalid state");
|
||||
}, coordinate_mapper_data, vertex_data);
|
||||
return { vertex_data, triangle_data };
|
||||
}
|
||||
}
|
||||
52
src/main.cpp
52
src/main.cpp
@@ -151,10 +151,54 @@ int main(int argc, char** argv) {
|
||||
|
||||
auto coordinate_storage = compile_coordinate_storage(coordinate_index_data);
|
||||
|
||||
auto coordinate_storage_index = compile_coordinate_storage_line_mapping(coordinate_index_data, coordinate_storage);
|
||||
if (std::get<1>(coordinate_storage).size() > 0) {
|
||||
std::cerr << "Indexed " << 1 << "D coordinates: " << std::get<1>(coordinate_storage).size() << std::endl;
|
||||
}
|
||||
|
||||
if (std::get<2>(coordinate_storage).size() > 0) {
|
||||
std::cerr << "Indexed " << 2 << "D coordinates: " << std::get<2>(coordinate_storage).size() << std::endl;
|
||||
}
|
||||
|
||||
if (std::get<3>(coordinate_storage).size() > 0) {
|
||||
std::cerr << "Indexed " << 3 << "D coordinates: " << std::get<3>(coordinate_storage).size() << std::endl;
|
||||
}
|
||||
|
||||
auto coordinate_storage_index = compile_coordinate_storage_line_mapping<IndexType>(coordinate_index_data, coordinate_storage);
|
||||
|
||||
auto index_storage = compile_vertex_storage<IndexType>(scan_data, face_data, coordinate_storage_index);
|
||||
|
||||
std::visit([&](const auto &vertex_storage) {
|
||||
std::cerr << "Compiled " << vertex_storage.size() << " vertices" << std::endl;
|
||||
}, index_storage.vertices);
|
||||
|
||||
std::cerr << "Compiled " << index_storage.triangles.size() << " triangles" << std::endl;
|
||||
|
||||
// TODO: We need to output:
|
||||
// 1. Some kind of singature;
|
||||
// 2. A version number;
|
||||
// 3. Flags describing the data:
|
||||
// 3.1. position: required, always 3 coordinates (no flag needed)
|
||||
// 3.2. normal: optional, always 3 coordinates (single flag needed)
|
||||
// 3.3. texcoord: optional, up to 3 coordinates (two flags needed, 0 = none, 1 = 1D, 2 = 2D, 3 = 3D)
|
||||
// 3.4. type of number data: 0 = float, 1 = double
|
||||
// 3.5. vertices: 0 = never used, 1 = one attribute per vertex, 2 = two attributes per vertex, 3 = three attributes per vertex
|
||||
// Flags: (0 = number type, 1 = normals present, 2-3 = texture_coordinate size, 4-7 = number of vertex attributes (up to 16), only 3 supported for now)
|
||||
// 4. Data order: up to attribute_count attributes, 1-byte each, specifying an index of map in file order. 0 is the number_list and therefore reserved.
|
||||
// 5. Sizes:
|
||||
// 5.1. Size of the number list (in items): 1 item = 1 float/double (depending on number_type)
|
||||
// 5.2. Size of the position list (in items): 1 item = 3 indices into the float_list
|
||||
// 5.3. Size of the normal list (in items, only if normal flag is set): 1 item = 3 indices into the float_list
|
||||
// 5.4. Size of the texcoord list (in items, only if texcoord_size is not 0): 1 item = 1-3 indices into the float_list (depending on texcoord_size)
|
||||
// 5.5. Size of the vertex list (in items): 1 item = 1-attribute_count indices into different maps.
|
||||
// 5.6. Size of the triangle list (in items): 1 item = 3 triangle vertex indices into the vertex list.
|
||||
// Special references: number_list, triangle_list, vertex_list, position_list
|
||||
// All other references are additional attributes.
|
||||
// In order for quick load into GPU buffer we want:
|
||||
// - each map start file pos to be known
|
||||
// - each map size in bytes to be known
|
||||
// - each map type (float32, float64, int8, int16, int32, int64)
|
||||
// - number of elements per item (or stride, i.e. number of bytes per item)
|
||||
// - each map file pos aligned to 16-bytes (assuming file is loaded aligned to 16-bytes). Elements within the map do not need to be aligned.
|
||||
|
||||
// Form coordinate_list_data : std::vector variant of coordinate_index_data. Internally, it creates std::set initially, stores everything in the set and then convert to vector.
|
||||
// Then we can form coordinate_line_mapping : std::map<file_line_t, std::size_t> pointing for each entry to entry in coordinate_list_data.
|
||||
// Then using face_data.triangle_list and scan_data.category_map[v/vn/vt], coordinate_line_mapping, we can form vertex_list_data. The vertex here is 1-3 IndexType numbers pointing to coordinate_list_data.
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -270,21 +270,30 @@ namespace wavefront {
|
||||
coordinate_data_t<IndexType> create_coordinate_index(const coordinate_data_t<FloatType> &coordinate_data, const std::vector<FloatType> &float_list) {
|
||||
coordinate_data_t<IndexType> coordinate_index_data;
|
||||
|
||||
static const auto float_compare = float_is_equal<FloatType>{};
|
||||
static const auto float_less = less_with_nan_first_and_nearly_equal<FloatType>{};
|
||||
|
||||
for (const auto& [line_number, coordinates] : coordinate_data.position_coordinates) {
|
||||
std::array<IndexType, coordinates.size()> 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]);
|
||||
auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less);
|
||||
assert(iterator != float_list.end());
|
||||
position_coordinate_indices[dim] = std::distance(float_list.begin(), iterator);
|
||||
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<IndexType, coordinates.size()> 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]);
|
||||
auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less);
|
||||
assert(iterator != float_list.end());
|
||||
normal_coordinate_indices[dim] = std::distance(float_list.begin(), iterator);
|
||||
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;
|
||||
}
|
||||
@@ -309,9 +318,12 @@ namespace wavefront {
|
||||
if constexpr (std::ranges::range<std::decay_t<decltype(coordinates)>>) {
|
||||
std::array<IndexType, coordinates.size()> 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]);
|
||||
auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates[dim], float_less);
|
||||
assert(iterator != float_list.end());
|
||||
texcoord_coordinate_indices[dim] = std::distance(float_list.begin(), iterator);
|
||||
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<
|
||||
@@ -328,9 +340,11 @@ namespace wavefront {
|
||||
}
|
||||
}, coordinate_index_data.texture_coordinates);
|
||||
} else {
|
||||
auto iterator = std::lower_bound(float_list.begin(), float_list.end(), coordinates);
|
||||
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<file_line_t, IndexType>,
|
||||
|
||||
16
src/repeat.hpp
Normal file
16
src/repeat.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef __WAVEFRONT_REPEAT_HPP__
|
||||
#define __WAVEFRONT_REPEAT_HPP__
|
||||
|
||||
#include<array>
|
||||
#include<cstdint>
|
||||
|
||||
namespace wavefront {
|
||||
template<typename ValueType, std::size_t Length>
|
||||
std::array<ValueType, Length> repeat_value(ValueType value) {
|
||||
std::array<ValueType, Length> result;
|
||||
result.fill(value);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __WAVEFRONT_REPEAT_HPP__
|
||||
Reference in New Issue
Block a user