Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
469 changes: 338 additions & 131 deletions src/engine/utils/meshloader.cpp

Large diffs are not rendered by default.

90 changes: 76 additions & 14 deletions src/engine/utils/meshloader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,30 @@
#include <array>
#include <optional>
#include <vector>
#include <unordered_map>
#include <string>
#include <concepts>

namespace utils
{

/**
namespace utils {
/**
* @brief Collection of raw mesh data.
* triangle data can be found in: faces
*/
struct MeshData
struct MeshData
{
using Handle = const MeshData*;
using group_t = uint32_t;

/**
* @brief Collection of vertices describing one face.
* @brief Collection of vertices describing one face.
* contains 3 ordered vertices
*/
struct FaceData
struct FaceData
{
/**
* @brief Collection of ids describing one vertex.
* @brief Collection of ids describing one vertex.
*/
struct VertexIndices
struct VertexIndices
{
int positionIdx;
///< id to fetch the position from MeshData::positions
Expand All @@ -38,25 +43,82 @@ namespace utils
///< may be not set for a vertex
};
std::array<VertexIndices, 3> indices;
group_t groups;
};

using Handle = const MeshData*;


/**
* @brief load mesh data from an file
* @param _fileName path to file
* @brief load mesh data from an file
* @param _fileName path to file
*/
static Handle load( const char* _fileName );
static Handle load( const char* _fileName ) ;

static void unload( Handle _meshData );

/// list of all positions contains values used by FaceData
std::vector<glm::vec3> positions;
std::vector<glm::vec2> textureCoordinates;
std::vector<glm::vec3> normals;
/// list of all faces described in .obj in order
std::vector<FaceData> faces;

struct MaterialData {
struct {
glm::vec3 ambient;
glm::vec3 diffuse;
glm::vec3 spectral;
} color;
struct TextureData {
glm::vec3 offset;
glm::vec3 scale;
bool clamp;
std::string name;
};
struct {
TextureData ambient;
TextureData diffuse;
TextureData spectral;
TextureData spectralExponent;
TextureData reflection;
} textures;
float spectralExponent;
enum USED_LIGHT {
DIFFUSE_ONLY,
DIFFUSE_AND_AMBIENT,
FULL,
END
} illumination;
};
struct ObjectData {
std::string name;
size_t begin;
size_t end;
size_t maitalIdx;
};
std::vector<MaterialData> material;
std::vector<ObjectData> objects;

std::unordered_map<std::string,group_t> group_names;
std::unordered_map<std::string,size_t> material_names;

using VertexPosition = glm::vec3;
struct VertexTexture {
glm::vec3 position;
glm::vec2 texture;
};
struct VertexNormal {
glm::vec3 position;
glm::vec3 normal;
};
struct VertexTextureNormal {
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texture;
};

};


using MeshLoader = utils::ResourceManager<MeshData>;

} // end utils
202 changes: 202 additions & 0 deletions src/engine/utils/triangulation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
#pragma once

#include <tuple>
#include <optional>
#include <vector>
#include <array>
#include <glm/mat3x3.hpp>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/geometric.hpp>


#include <iostream>
#include <cassert>

namespace utils {
namespace triangulation {
inline float orientationF(
const glm::vec2& a,
const glm::vec2& b,
const glm::vec2& c)
{
return ((b.x*c.y + a.x*b.y + a.y*c.x) - (a.y*b.x + b.y*c.x + a.x*c.y));
}
inline char orientation(
const glm::vec2& a,
const glm::vec2& b,
const glm::vec2& c)
{
float v = orientationF(a, b, c);
return 0b10 * (v <= 0)
| 0b01 * (v >= 0);
}
inline bool isIn(
const glm::vec2& p,
const glm::vec2& a,
const glm::vec2& b,
const glm::vec2& c)
{
char orient[] = {
orientation(a,b,p),
orientation(b,c,p),
orientation(c,a,p)
};
return ((orient[0] & 0b10) == (orient[1] & 0b10) && orient[1] == (orient[2] & 0b10))
|| ((orient[0] & 0b01) == (orient[1] & 0b01) && orient[1] == (orient[2] & 0b01));
}
inline int getId (
std::vector<std::optional<glm::vec2>>& data,
int id,
int i = 0) {
if(i == 0) { return id; }
else if(i < 0) {
const auto& res = id == 0
? data[id = data.size() - 1]
: data[--id];
if(res) { return id; }
return getId(data, id, i);

} else {
const auto& res = (++id == static_cast<int>(data.size()))
? data[id = 0]
: data[id];
if(res) { return id; }
return getId(data, id, i);
}
};
inline const glm::vec2& get(
std::vector<std::optional<glm::vec2>>& data,
int id,
int i = 0) {
return *data[getId(data, id, i)];
}
}


inline std::vector<int> triangulateEarCut(const std::vector<glm::vec3>& polygone) {
glm::vec3 x,y;
{
int i = 0;
do {
x = glm::normalize(polygone[i+1] - polygone[i]),
y = glm::normalize(polygone[i+2] - polygone[i+1]);
++i;
} while(glm::dot(x-y,x-y) < 0.0001f);
}
{
glm::vec3 up = glm::normalize(glm::cross(x,y));
y = glm::normalize(glm::cross(up, x));
}
std::vector<std::optional<glm::vec2>> projected{};
projected.reserve(polygone.size());
for(const glm::vec3& v : polygone) {
projected.push_back({{glm::dot(x,v), glm::dot(y,v)}});
}

std::vector<int> types;
int reflexEnd = 0;
auto insertReflex = [&](int i) {
types.insert(types.begin(), i);
++reflexEnd;
};
auto insertConvex = [&](int i) {
types.insert(types.begin() + reflexEnd, i);
};
auto promoteReflex = [&](int i) {
--reflexEnd;
auto buff = types[reflexEnd];
types[reflexEnd] = types[i];
types[i] = buff;
};
auto findEar = [&]() -> int {
for(auto itr = types.begin() + reflexEnd;
itr != types.end(); ++itr) {
bool isEar = true;
if (projected[*itr])
for(auto refl = types.begin();
refl != types.begin() + reflexEnd; ++refl) {
int ids[] = {
triangulation::getId(projected, *refl),
triangulation::getId(projected, *itr, -1),
triangulation::getId(projected, *itr),
triangulation::getId(projected, *itr, 1)
};
if( ids[1] != ids[0] && ids[2] != ids[0] && ids[3] != ids[0]
&& triangulation::isIn(
*projected[ids[0]],
*projected[ids[1]],
*projected[ids[2]],
*projected[ids[3]]))
{
isEar = false; break;
}
}
if(isEar) {
int ear = *itr;
types.erase(itr);
return ear;
}
}
throw "no ear found!";
};
// assumption: alls set
auto slide = [](auto data, auto fun) {
auto itr = data.begin();
fun(itr - data.begin(), *data.back(), *itr[0], *itr[1]);
++itr;
for(;itr != data.end() - 1; ++itr) {
fun(itr - data.begin(), *itr[-1], *itr[0], *itr[1]);
}
fun(itr - data.begin(), *data.end()[-2], *data.back(), *data.front());
};
char mainOrientation;
{
float sum = 0;
slide(projected, [&sum](auto itr, auto a, auto b, auto c) {
sum += triangulation::orientationF(a, b, c);
});
assert(sum != 0);
mainOrientation = sum < 0 ? 0b10 : 0b01;
slide(projected, [&](auto i, auto a, auto b, auto c) {
if(triangulation::orientation(a, b, c) & mainOrientation) {
insertConvex(i);
} else {
insertReflex(i);
}
});
}
std::vector<int> res{};
size_t finalSize = (projected.size() - 2) * 3;
res.reserve(finalSize);
while(res.size() != finalSize) {
int ear = 0;
try {
ear = findEar();
} catch (const char*) {
res.clear();
return res;
}
int p = triangulation::getId(projected, ear, -1),
pp = triangulation::getId(projected, p, -1);
int n = triangulation::getId(projected, ear, 1),
nn = triangulation::getId(projected, n, 1);
res.push_back(p);
res.push_back(ear);
res.push_back(n);

auto match = std::find(types.begin(), types.end(), p) - types.begin();
if( match < reflexEnd
&& triangulation::orientation(*projected[pp], *projected[p], *projected[n]) & mainOrientation) {
promoteReflex(match);
}
match = std::find(types.begin(), types.end(), n) - types.begin();
if( match < reflexEnd
&& triangulation::orientation(*projected[p], *projected[n], *projected[nn]) & mainOrientation) {
promoteReflex(match);
}
projected[ear] = std::nullopt;
}
return res;
}
}
Binary file added tests/resources/Berreta M9_Material_BaseColor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/resources/Berreta M9_Material_Metallic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/resources/Berreta M9_Material_Normal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/resources/Berreta M9_Material_Roughness.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions tests/resources/Handgun_Packed.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Blender MTL File: 'Handgun_Packed.blend'
# Material Count: 4

newmtl Fire.001
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2

newmtl Material.001
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 1

newmtl Material.004
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2

newmtl handgun
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
Loading