<commit_before>
#include "model_builder.hpp"
#include "model_basic_primitives.hpp"
#include "model_gltf_save.hpp"
#include "model_msh_save.hpp"
#include "model_scene.hpp"
#include "synced_cout.hpp"

#include <algorithm>
#include <iterator>
#include <string_view>
#include <tuple>

#include <fmt/format.h>
#include <gsl/gsl>
#include <tbb/tbb.h>

using namespace std::literals;

namespace model {

namespace {

template<typename Type>
void merge_containers(std::vector<Type>& into, std::vector<Type>& from) noexcept
{
   into.insert(into.end(), std::make_move_iterator(from.begin()),
               std::make_move_iterator(from.end()));

   from.clear();
}

auto lod_suffix(const Lod lod) -> std::string_view
{
   switch (lod) {
   case Lod::zero:
      return ""sv;
   case Lod::one:
      return "_lod1"sv;
   case Lod::two:
      return "_lod2"sv;
   case Lod::three:
      return "_lod3"sv;
   case Lod::lowres:
      return "_lowres"sv;
   default:
      std::terminate();
   }
}

auto collision_flags_string(const Collision_flags flags) -> std::string
{
   if (flags == Collision_flags::all) return ""s;

   std::string str;

   if (are_flags_set(flags, Collision_flags::soldier)) str += "s"sv;
   if (are_flags_set(flags, Collision_flags::vehicle)) str += "v"sv;
   if (are_flags_set(flags, Collision_flags::building)) str += "b"sv;
   if (are_flags_set(flags, Collision_flags::terrain)) str += "t"sv;
   if (are_flags_set(flags, Collision_flags::ordnance)) str += "o"sv;
   if (are_flags_set(flags, Collision_flags::flyer)) str += "f"sv;

   return str;
}

auto insert_scene_material(scene::Scene& scene, scene::Material material) -> std::size_t
{
   if (auto it = std::find(scene.materials.begin(), scene.materials.end(), material);
       it != scene.materials.end()) {
      return static_cast<std::size_t>(std::distance(scene.materials.begin(), it));
   }

   const auto index = scene.materials.size();

   scene.materials.emplace_back(std::move(material));

   return index;
}

auto make_primitive_visualization_geometry(const Collision_primitive_type type,
                                           const glm::vec3 size) -> scene::Geometry
{
   const auto [indices, positions, normals, texcoords, scale] = [=] {
      using namespace primitives;

      const auto as_spans = [](const auto&... args) {
         return std::make_tuple(gsl::make_span(args)...);
      };

      switch (type) {
      case Collision_primitive_type::sphere:
         return std::tuple_cat(as_spans(sphere_indices, sphere_vertex_positions,
                                        sphere_vertex_normals, sphere_vertex_texcoords),
                               std::make_tuple(glm::vec3{size.x}));
      case Collision_primitive_type::cylinder:
         return std::tuple_cat(as_spans(cylinder_indices, cylinder_vertex_positions,
                                        cylinder_vertex_normals,
                                        cylinder_vertex_texcoords),
                               std::make_tuple(glm::vec3{size.xyx}));
      case Collision_primitive_type::cube:
         return std::tuple_cat(as_spans(cube_indices, cube_vertex_positions,
                                        cube_vertex_normals, cube_vertex_texcoords),
                               std::make_tuple(glm::vec3{size}));
      default:
         std::terminate();
      }
   }();

   scene::Geometry geometry{
      .topology = primitives::primitive_topology,
      .indices = Indices{std::cbegin(indices), std::cend(indices)},
      .vertices = Vertices{static_cast<std::size_t>(positions.size()),
                           {.positions = true, .normals = true, .texcoords = true}}};

   std::transform(std::cbegin(positions), std::cend(positions),
                  geometry.vertices.positions.get(),
                  [scale](const auto pos) { return pos * scale; });
   std::copy(std::cbegin(normals), std::cend(normals), geometry.vertices.normals.get());
   std::copy(std::cbegin(texcoords), std::cend(texcoords),
             geometry.vertices.texcoords.get());

   return geometry;
}

auto positions_to_vertices(const std::vector<glm::vec3>& positions) -> Vertices
{
   Vertices vertices{positions.size(), {.positions = true}};

   std::copy(std::cbegin(positions), std::cend(positions), vertices.positions.get());

   return vertices;
}

auto create_scene(Model model) -> scene::Scene<commit_msg>fix invalid collision primitive shape handling<commit_after>
#include "model_builder.hpp"
#include "model_basic_primitives.hpp"
#include "model_gltf_save.hpp"
#include "model_msh_save.hpp"
#include "model_scene.hpp"
#include "synced_cout.hpp"

#include <algorithm>
#include <iterator>
#include <string_view>
#include <tuple>

#include <fmt/format.h>
#include <gsl/gsl>
#include <tbb/tbb.h>

using namespace std::literals;

namespace model {

namespace {

template<typename Type>
void merge_containers(std::vector<Type>& into, std::vector<Type>& from) noexcept
{
   into.insert(into.end(), std::make_move_iterator(from.begin()),
               std::make_move_iterator(from.end()));

   from.clear();
}

auto lod_suffix(const Lod lod) -> std::string_view
{
   switch (lod) {
   case Lod::zero:
      return ""sv;
   case Lod::one:
      return "_lod1"sv;
   case Lod::two:
      return "_lod2"sv;
   case Lod::three:
      return "_lod3"sv;
   case Lod::lowres:
      return "_lowres"sv;
   default:
      std::terminate();
   }
}

auto collision_flags_string(const Collision_flags flags) -> std::string
{
   if (flags == Collision_flags::all) return ""s;

   std::string str;

   if (are_flags_set(flags, Collision_flags::soldier)) str += "s"sv;
   if (are_flags_set(flags, Collision_flags::vehicle)) str += "v"sv;
   if (are_flags_set(flags, Collision_flags::building)) str += "b"sv;
   if (are_flags_set(flags, Collision_flags::terrain)) str += "t"sv;
   if (are_flags_set(flags, Collision_flags::ordnance)) str += "o"sv;
   if (are_flags_set(flags, Collision_flags::flyer)) str += "f"sv;

   return str;
}

auto insert_scene_material(scene::Scene& scene, scene::Material material) -> std::size_t
{
   if (auto it = std::find(scene.materials.begin(), scene.materials.end(), material);
       it != scene.materials.end()) {
      return static_cast<std::size_t>(std::distance(scene.materials.begin(), it));
   }

   const auto index = scene.materials.size();

   scene.materials.emplace_back(std::move(material));

   return index;
}

auto make_primitive_visualization_geometry(const Collision_primitive_type type,
                                           const glm::vec3 size) -> scene::Geometry
{
   const auto [indices, positions, normals, texcoords, scale] = [=] {
      using namespace primitives;

      const auto as_spans = [](const auto&... args) {
         return std::make_tuple(gsl::make_span(args)...);
      };

      switch (type) {
      case Collision_primitive_type::cylinder:
         return std::tuple_cat(as_spans(cylinder_indices, cylinder_vertex_positions,
                                        cylinder_vertex_normals,
                                        cylinder_vertex_texcoords),
                               std::make_tuple(glm::vec3{size.xyx}));
      case Collision_primitive_type::cube:
         return std::tuple_cat(as_spans(cube_indices, cube_vertex_positions,
                                        cube_vertex_normals, cube_vertex_texcoords),
                               std::make_tuple(glm::vec3{size}));
      default:
         return std::tuple_cat(as_spans(sphere_indices, sphere_vertex_positions,
                                        sphere_vertex_normals, sphere_vertex_texcoords),
                               std::make_tuple(glm::vec3{size.x}));
      }
   }();

   scene::Geometry geometry{
      .topology = primitives::primitive_topology,
      .indices = Indices{std::cbegin(indices), std::cend(indices)},
      .vertices = Vertices{static_cast<std::size_t>(positions.size()),
                           {.positions = true, .normals = true, .texcoords = true}}};

   std::transform(std::cbegin(positions), std::cend(positions),
                  geometry.vertices.positions.get(),
                  [scale](const auto pos) { return pos * scale; });
   std::copy(std::cbegin(normals), std::cend(normals), geometry.vertices.normals.get());
   std::copy(std::cbegin(texcoords), std::cend(texcoords),
             geometry.vertices.texcoords.get());

   return geometry;
}

auto positions_to_vertices(const std::vector<glm::vec3>& positions) -> Vertices
{
   Vertices vertices{positions.size(), {.positions = true}};

   std::copy(std::cbegin(positions), std::cend(positions), vertices.positions.get());

   return vertices;
}

auto create_scene(Model model) -> scene::Scene
{'fraction_non_alphanumeric': 0.13956157465855618, 'fraction_numerical': 0.0018363365086652129, 'mean_word_length': 3.2096618357487925, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2603928', 'n_tokens_mistral': 2827, 'n_tokens_neox': 2713, 'n_words': 493}