port from perforce
This commit is contained in:
31
meshTools/meshTools.sln
Normal file
31
meshTools/meshTools.sln
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "meshTools", "meshTools\meshTools.vcxproj", "{A07570FA-501F-400E-823E-00B5459C7E8D}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{6E7DF6F1-481D-41A2-84CD-27B2626BC21D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A07570FA-501F-400E-823E-00B5459C7E8D} = {A07570FA-501F-400E-823E-00B5459C7E8D}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A07570FA-501F-400E-823E-00B5459C7E8D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A07570FA-501F-400E-823E-00B5459C7E8D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A07570FA-501F-400E-823E-00B5459C7E8D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A07570FA-501F-400E-823E-00B5459C7E8D}.Release|Win32.Build.0 = Release|Win32
|
||||
{6E7DF6F1-481D-41A2-84CD-27B2626BC21D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{6E7DF6F1-481D-41A2-84CD-27B2626BC21D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{6E7DF6F1-481D-41A2-84CD-27B2626BC21D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{6E7DF6F1-481D-41A2-84CD-27B2626BC21D}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
BIN
meshTools/meshTools.v12.suo
Normal file
BIN
meshTools/meshTools.v12.suo
Normal file
Binary file not shown.
299
meshTools/meshTools/include/common/Linq.h
Normal file
299
meshTools/meshTools/include/common/Linq.h
Normal file
@@ -0,0 +1,299 @@
|
||||
#pragma once
|
||||
#include "List.h"
|
||||
#include "Map.h"
|
||||
#include "Performancer.h"
|
||||
|
||||
template<class TKey, class TValue>
|
||||
struct Pair
|
||||
{
|
||||
Pair()
|
||||
{
|
||||
}
|
||||
|
||||
Pair(TKey key, TValue value)
|
||||
: Key{ key }
|
||||
, Value{ value }
|
||||
{
|
||||
}
|
||||
|
||||
TKey Key;
|
||||
TValue Value;
|
||||
};
|
||||
|
||||
namespace Linq
|
||||
{
|
||||
template<class T>
|
||||
Map<T, T> ToSet(const List<T>& what)
|
||||
{
|
||||
Map<T, T> result;
|
||||
for (const auto& element : what)
|
||||
result.Add(element, element);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
List<T> ToList(const T& what)
|
||||
{
|
||||
List<T> result;
|
||||
result.Add(what);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
List<T> ToList(T array[], size_t size)
|
||||
{
|
||||
List<T> result;
|
||||
for (int i = 0; i < size; ++i)
|
||||
result.Add(array[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
List<T> Concat(const List<T>& a, const List<T>& b)
|
||||
{
|
||||
List<T> result(a.Count() + b.Count());
|
||||
for (auto i = 0; i < a.Count(); ++i)
|
||||
result.Add(a[i]);
|
||||
for (auto i = 0; i < b.Count(); ++i)
|
||||
result.Add(b[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
List<T> Reverse(const List<T>& what)
|
||||
{
|
||||
List<T> result;
|
||||
|
||||
for (auto i = what.Count() - 1; i >= 0; --i)
|
||||
result.Add(what[i]);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
List<T> Distinct(const List<T>& what)
|
||||
{
|
||||
List<T> result(what.Count());
|
||||
|
||||
Map<T, bool> map;
|
||||
for (const auto& element : what)
|
||||
if (!map.ContainsKey(element))
|
||||
{
|
||||
map.Add(element, false);
|
||||
result.Add(element);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void AddRange(List<T>& destination, const List<T>& what)
|
||||
{
|
||||
for (const auto& element : what)
|
||||
destination.Add(element);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
List<T> Except(const List<T>& what, const List<T>& except)
|
||||
{
|
||||
List<T> result;
|
||||
|
||||
for (const auto& element : what)
|
||||
if (except.IndexOf(element) == -1)
|
||||
result.Add(element);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
List<T> Union(const List<T>& what, const List<T>& other)
|
||||
{
|
||||
List<T> result = what;
|
||||
Linq::AddRange(result, other);
|
||||
result = Linq::Distinct(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
List<T> Intersect(const List<T>& what, const List<T>& other)
|
||||
{
|
||||
List<T> result;
|
||||
|
||||
for (const auto& element : what)
|
||||
if (other.IndexOf(element) != -1)
|
||||
result.Add(element);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, class TGroupValue, typename Func>
|
||||
void GroupBy(const List<T>& what, Map<TGroupValue, List<T>>& dest, Func groupByFunc)
|
||||
{
|
||||
for (const auto& element : what)
|
||||
{
|
||||
auto key = groupByFunc(element);
|
||||
List<T>* values;
|
||||
if (dest.TryGetValue(key, values))
|
||||
values->Add(element);
|
||||
else
|
||||
{
|
||||
List<T> value(1);
|
||||
value.Add(element);
|
||||
dest.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Map<T, int> Group(const List<T>& what)
|
||||
{
|
||||
Map<T, int> result;
|
||||
|
||||
for (const auto& element : what)
|
||||
{
|
||||
int cnt;
|
||||
if (result.TryGetValue(element, cnt))
|
||||
result[element] = ++cnt;
|
||||
else
|
||||
result.Add(element, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Map<T, int> GroupValues(const List<T>& what)
|
||||
{
|
||||
Map<T, int> result;
|
||||
|
||||
for (const auto& element : what)
|
||||
{
|
||||
int cnt;
|
||||
if (result.TryGetValue(element, cnt))
|
||||
result[element] = ++cnt;
|
||||
else
|
||||
result.Add(element, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, class Func>
|
||||
T Max(const List<T>& what, Func sortCallback)
|
||||
{
|
||||
List<Pair<T, float>> sortData;
|
||||
|
||||
int maxId = 0;
|
||||
float maxSortValue = -Math::Infinity;
|
||||
for (int i = 0; i < what.Count(); ++i)
|
||||
{
|
||||
auto sortValue = sortCallback(what[i]);
|
||||
if (i == 0 || maxSortValue < sortValue)
|
||||
{
|
||||
maxId = i;
|
||||
maxSortValue = sortValue;
|
||||
}
|
||||
}
|
||||
|
||||
return what[maxId];
|
||||
}
|
||||
|
||||
template<class T, class Func>
|
||||
T Min(const List<T>& what, Func sortCallback)
|
||||
{
|
||||
List<Pair<T, float>> sortData;
|
||||
|
||||
int index = 0;
|
||||
float sortValue = Math::Infinity;
|
||||
for (int i = 0; i < what.Count(); ++i)
|
||||
{
|
||||
auto currentSortValue = sortCallback(what[i]);
|
||||
if (i == 0 || sortValue > currentSortValue)
|
||||
{
|
||||
index = i;
|
||||
sortValue = currentSortValue;
|
||||
}
|
||||
}
|
||||
|
||||
return what[index];
|
||||
}
|
||||
|
||||
template<class T, class Func>
|
||||
List<T> OrderByDescending(const List<T>& what, Func sortCallback)
|
||||
{
|
||||
List<T> result;
|
||||
List<T> tmp = what;
|
||||
while (tmp.Count() > 0)
|
||||
{
|
||||
auto max = Linq::Max(tmp, sortCallback);
|
||||
tmp.Remove(max);
|
||||
result.Add(max);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, class Func>
|
||||
List<T> Where(const List<T>& what, Func whereCallback)
|
||||
{
|
||||
List<T> result;
|
||||
|
||||
for (auto& element : what)
|
||||
if (whereCallback(element))
|
||||
result.Add(element);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T2, class T, class Func>
|
||||
List<T2> Select(const List<T>& what, Func selectCallback)
|
||||
{
|
||||
List<T2> result;
|
||||
for (auto& element : what)
|
||||
result.Add(selectCallback(element));
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class TResult, class T, class Func>
|
||||
List<TResult> SelectMany(const List<T>& what, Func selectCallback)
|
||||
{
|
||||
List<TResult> result;
|
||||
for (auto& element : what)
|
||||
Linq::AddRange<TResult>(result, selectCallback(element));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class TResult, class T, class Func>
|
||||
List<TResult> SelectUniqueMany(const List<T>& what, Func selectCallback)
|
||||
{
|
||||
List<TResult> result(what.Count());
|
||||
Map<TResult, bool> map;
|
||||
|
||||
for (auto& element : what)
|
||||
{
|
||||
auto subResult = selectCallback(element);
|
||||
for (const auto& subElement : subResult)
|
||||
{
|
||||
if (!map.ContainsKey(subElement))
|
||||
{
|
||||
map.Add(subElement, false);
|
||||
result.Add(subElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, class Func>
|
||||
bool Any(const List<T>& what, Func callback)
|
||||
{
|
||||
for (auto& element : what)
|
||||
if (callback(element))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
202
meshTools/meshTools/include/common/List.h
Normal file
202
meshTools/meshTools/include/common/List.h
Normal file
@@ -0,0 +1,202 @@
|
||||
#pragma once
|
||||
#if _DEBUG
|
||||
//#include <assert.h>
|
||||
#define assert(a) if (!(a)) { throw #a; }
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
class List;
|
||||
|
||||
template<typename TSrc, typename TDest>
|
||||
struct convert
|
||||
{
|
||||
static TDest Convert(const TSrc& srx)
|
||||
{
|
||||
static_assert(false, "Conversion is not possible, implement a custom conversion method.");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
class List
|
||||
{
|
||||
public:
|
||||
List(int capacity = 1)
|
||||
: capacity{ capacity }
|
||||
, count{0}
|
||||
, data{ new T[capacity] }
|
||||
{
|
||||
}
|
||||
|
||||
List(List<T>&& other)
|
||||
: count{ other.count }
|
||||
, capacity{ other.capacity }
|
||||
, data{ other.data }
|
||||
{
|
||||
other.count = 0;
|
||||
other.capacity = 0;
|
||||
other.data = nullptr;
|
||||
}
|
||||
|
||||
List(const List<T>& other)
|
||||
: count{other.count}
|
||||
, capacity{ other.count }
|
||||
, data{ new T[other.count] }
|
||||
{
|
||||
for (int index = 0; index < count; ++index)
|
||||
data[index] = other.data[index];
|
||||
}
|
||||
|
||||
~List()
|
||||
{
|
||||
delete[] data;
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
List<T>& operator=(List<T>&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
delete[] data;
|
||||
|
||||
count = other.count;
|
||||
capacity = other.capacity;
|
||||
data = other.data;
|
||||
other.count = 0;
|
||||
other.capacity = 0;
|
||||
other.data = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
List<T>& operator=(const List<T>& other)
|
||||
{
|
||||
count = other.count;
|
||||
capacity = other.count;
|
||||
data = new T[other.count];
|
||||
for (int index = 0; index < count; ++index)
|
||||
data[index] = other.data[index];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Add(const T& value)
|
||||
{
|
||||
if (count == capacity)
|
||||
Grow();
|
||||
data[count] = value;
|
||||
count++;
|
||||
}
|
||||
|
||||
void Remove(const T& value)
|
||||
{
|
||||
auto index = IndexOf(value);
|
||||
if (index == -1)
|
||||
return;
|
||||
RemoveAt(index);
|
||||
}
|
||||
|
||||
void RemoveAt(int index)
|
||||
{
|
||||
#if _DEBUG
|
||||
assert(index >= 0 && index < count);
|
||||
#endif
|
||||
|
||||
//data[index++].~T();
|
||||
index++;
|
||||
for (; index < count; ++index)
|
||||
data[index - 1] = data[index];
|
||||
|
||||
count--;
|
||||
}
|
||||
|
||||
bool Contains(const T& value) const
|
||||
{
|
||||
return IndexOf(value) != -1;
|
||||
}
|
||||
|
||||
int IndexOf(const T& value) const
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < count; ++i)
|
||||
if (data[i] == value)
|
||||
break;
|
||||
|
||||
if (i == count)
|
||||
return -1;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int Count() const
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
/*for (int i = 0; i < count; ++i)
|
||||
data[i].~T();*/
|
||||
|
||||
count = 0;
|
||||
/*capacity = 1;
|
||||
delete[] data;
|
||||
data = new T[capacity];*/
|
||||
}
|
||||
|
||||
T& operator[](int index)
|
||||
{
|
||||
#if _DEBUG
|
||||
assert(index >= 0 && index < count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
|
||||
const T& operator[](int index) const
|
||||
{
|
||||
#if _DEBUG
|
||||
assert(index >= 0 && index < count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
|
||||
T* Get() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
T* begin() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
T* end() const
|
||||
{
|
||||
return data + count;
|
||||
}
|
||||
|
||||
template<typename TDest>
|
||||
operator TDest() const
|
||||
{
|
||||
return convert<List<T>, TDest>::Convert(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
void Grow()
|
||||
{
|
||||
auto newCapacity = capacity ? capacity * 2 : 1;
|
||||
|
||||
T* newData = new T[newCapacity];
|
||||
for (int i = 0; i < count; ++i)
|
||||
newData[i] = data[i]; //newData[i] = (T&&)data[i];
|
||||
|
||||
capacity = newCapacity;
|
||||
delete[] data;
|
||||
data = newData;
|
||||
}
|
||||
|
||||
private:
|
||||
T* data;
|
||||
int count;
|
||||
int capacity;
|
||||
};
|
||||
318
meshTools/meshTools/include/common/Map.h
Normal file
318
meshTools/meshTools/include/common/Map.h
Normal file
@@ -0,0 +1,318 @@
|
||||
#pragma once
|
||||
#include "List.h"
|
||||
#if _DEBUG
|
||||
//#include <assert.h>
|
||||
#define assert(a) if (!(a)) { throw #a; }
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct equality { static bool Equals(T a, T b) { return a == b; } };
|
||||
|
||||
template<typename T>
|
||||
struct hashing
|
||||
{
|
||||
static int Generate(T a)
|
||||
{
|
||||
return (int)a;
|
||||
}
|
||||
};
|
||||
|
||||
// Finetune this value for better performance.
|
||||
#define MAXBUCKETSIZE 10
|
||||
|
||||
template<typename TKey, typename TValue>
|
||||
class Map
|
||||
{
|
||||
public:
|
||||
struct Pair
|
||||
{
|
||||
int Hash;
|
||||
TKey Key;
|
||||
TValue Value;
|
||||
};
|
||||
|
||||
private:
|
||||
class HashBucket
|
||||
{
|
||||
public:
|
||||
HashBucket(const List<Pair*> pairs)
|
||||
: left{ nullptr }
|
||||
, right{ nullptr }
|
||||
, pairs { pairs }
|
||||
{
|
||||
if (pairs.Count() > 0)
|
||||
centerHash = pairs[0]->Hash;
|
||||
|
||||
}
|
||||
|
||||
HashBucket()
|
||||
: left{ nullptr }
|
||||
, right{ nullptr }
|
||||
{
|
||||
}
|
||||
|
||||
~HashBucket()
|
||||
{
|
||||
delete left;
|
||||
delete right;
|
||||
}
|
||||
|
||||
HashBucket* GetValue(const TKey& key, int hash, bool& success, TValue*& result) const
|
||||
{
|
||||
if ((hash == centerHash || left == nullptr) && pairs.Count() != 0)
|
||||
{
|
||||
for (const auto& pair : pairs)
|
||||
if (equality<const TKey&>::Equals(pair->Key, key))
|
||||
{
|
||||
success = true;
|
||||
result = &pair->Value;
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
else if (left != nullptr)
|
||||
return hash < centerHash ? left : right;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HashBucket* Remove(const TKey key, int hash, Pair*& pairResult)
|
||||
{
|
||||
if (left == nullptr || hash == centerHash)
|
||||
{
|
||||
for (int i = 0, iLength = pairs.Count(); i < iLength; ++i)
|
||||
{
|
||||
auto pair = pairs[i];
|
||||
if (equality<const TKey&>::Equals(pair->Key, key))
|
||||
{
|
||||
pairs.RemoveAt(i);
|
||||
pairResult = pair;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
else if (left != nullptr)
|
||||
return hash < centerHash ? left : right;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HashBucket* Add(Pair* pair)
|
||||
{
|
||||
if (pairs.Count() == 0)
|
||||
centerHash = pair->Hash;
|
||||
if (centerHash == pair->Hash || (left == nullptr && pairs.Count() < MAXBUCKETSIZE))
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
for (const auto& oldPair : pairs)
|
||||
if (equality<const TKey&>::Equals(oldPair->Key, pair->Key))
|
||||
assert("Key already exists in map" && false);
|
||||
#endif
|
||||
pairs.Add(pair);
|
||||
}
|
||||
else if (left == nullptr)
|
||||
{
|
||||
centerHash = pairs[pairs.Count() / 2]->Hash;
|
||||
|
||||
List<Pair*> leftPairs;
|
||||
List<Pair*> centerPairs;
|
||||
List<Pair*> rightPairs;
|
||||
|
||||
for (const auto& oldPair : pairs)
|
||||
{
|
||||
if (oldPair->Hash < centerHash)
|
||||
leftPairs.Add(oldPair);
|
||||
if (oldPair->Hash > centerHash)
|
||||
rightPairs.Add(oldPair);
|
||||
else
|
||||
centerPairs.Add(oldPair);
|
||||
}
|
||||
|
||||
left = new HashBucket(leftPairs);
|
||||
right = new HashBucket(rightPairs);
|
||||
pairs = centerPairs;
|
||||
|
||||
return Add(pair);
|
||||
}
|
||||
else
|
||||
return pair->Hash < centerHash ? left : right;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
int centerHash;
|
||||
HashBucket* left;
|
||||
HashBucket* right;
|
||||
List<Pair*> pairs;
|
||||
};
|
||||
|
||||
public:
|
||||
Map()
|
||||
: rootBucket{ new HashBucket() }
|
||||
{
|
||||
}
|
||||
|
||||
Map(Map&& other)
|
||||
: pairs{ other.pairs }
|
||||
, rootBucket{ other.rootBucket }
|
||||
{
|
||||
other.rootBucket = nullptr;
|
||||
other.pairs.Clear();
|
||||
}
|
||||
|
||||
Map(const Map& other)
|
||||
{
|
||||
throw "Implement me bitch!";
|
||||
}
|
||||
|
||||
~Map()
|
||||
{
|
||||
for (int i = 0, iLength = pairs.Count(); i < iLength; ++i)
|
||||
delete pairs[i];
|
||||
|
||||
delete rootBucket;
|
||||
}
|
||||
|
||||
Map& operator=(Map&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
delete rootBucket;
|
||||
pairs = other.pairs;
|
||||
rootBucket = other.rootBucket;
|
||||
other.rootBucket = nullptr;
|
||||
other.pairs.Clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void Add(const TKey& key, const TValue& value)
|
||||
{
|
||||
auto pair = new Pair();
|
||||
pair->Key = key;
|
||||
pair->Value = value;
|
||||
pair->Hash = hashing<const TKey&>::Generate(key);
|
||||
|
||||
auto bucket = rootBucket;
|
||||
do
|
||||
{
|
||||
bucket = bucket->Add(pair);
|
||||
} while (bucket != nullptr);
|
||||
|
||||
pairs.Add(pair);
|
||||
}
|
||||
|
||||
bool TryGetValue(const TKey& key, TValue& value) const
|
||||
{
|
||||
bool success = false;
|
||||
auto hash = hashing<const TKey&>::Generate(key);
|
||||
TValue* result;
|
||||
|
||||
auto bucket = rootBucket;
|
||||
do
|
||||
{
|
||||
bucket = bucket->GetValue(key, hash, success, result);
|
||||
} while (bucket != nullptr);
|
||||
if (success)
|
||||
value = *result;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool TryGetValue(const TKey& key, TValue*& value) const
|
||||
{
|
||||
bool success = false;
|
||||
auto hash = hashing<const TKey&>::Generate(key);
|
||||
TValue* result;
|
||||
|
||||
auto bucket = rootBucket;
|
||||
do
|
||||
{
|
||||
bucket = bucket->GetValue(key, hash, success, result);
|
||||
} while (bucket != nullptr);
|
||||
if (success)
|
||||
value = result;
|
||||
return success;
|
||||
}
|
||||
|
||||
void Remove(const TKey& key)
|
||||
{
|
||||
auto hash = hashing<const TKey&>::Generate(key);
|
||||
|
||||
auto bucket = rootBucket;
|
||||
Pair* pair;
|
||||
do
|
||||
{
|
||||
bucket = bucket->Remove(key, hash, pair);
|
||||
} while (bucket != nullptr);
|
||||
|
||||
if (pair != nullptr)
|
||||
{
|
||||
pairs.Remove(pair);
|
||||
}
|
||||
}
|
||||
|
||||
TValue& GetValue(const TKey& key) const
|
||||
{
|
||||
TValue* result;
|
||||
bool success = false;
|
||||
auto hash = hashing<const TKey&>::Generate(key);
|
||||
|
||||
auto bucket = rootBucket;
|
||||
do
|
||||
{
|
||||
bucket = bucket->GetValue(key, hash, success, result);
|
||||
} while (bucket != nullptr);
|
||||
|
||||
#if _DEBUG
|
||||
assert("No value found!" && success);
|
||||
#endif
|
||||
return *result;
|
||||
}
|
||||
|
||||
Pair** begin() const
|
||||
{
|
||||
return pairs.begin();
|
||||
}
|
||||
|
||||
Pair** end() const
|
||||
{
|
||||
return pairs.end();
|
||||
}
|
||||
|
||||
int Count() const
|
||||
{
|
||||
return pairs.Count();
|
||||
}
|
||||
|
||||
bool ContainsKey(const TKey& key) const
|
||||
{
|
||||
TValue tmp;
|
||||
return TryGetValue(key, tmp);
|
||||
}
|
||||
|
||||
TValue& operator[](const TKey& key)
|
||||
{
|
||||
return GetValue(key);
|
||||
}
|
||||
|
||||
const TValue& operator[](const TKey& key) const
|
||||
{
|
||||
return GetValue(key);
|
||||
}
|
||||
|
||||
List<TValue> GetValues() const
|
||||
{
|
||||
List<TValue> result;
|
||||
for (const auto& pair : pairs)
|
||||
result.Add(pair->Value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
HashBucket* rootBucket;
|
||||
List<Pair*> pairs;
|
||||
};
|
||||
74
meshTools/meshTools/include/common/Performancer.h
Normal file
74
meshTools/meshTools/include/common/Performancer.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
class PerformancerData
|
||||
{
|
||||
public:
|
||||
PerformancerData(const std::string& name, const std::string& fullName);
|
||||
void Add(long long duration);
|
||||
|
||||
std::string Name;
|
||||
std::string FullName;
|
||||
long long Calls;
|
||||
long long Elapsed;
|
||||
long long Max;
|
||||
long long Min;
|
||||
};
|
||||
|
||||
|
||||
#include <chrono>
|
||||
|
||||
struct HighResClock
|
||||
{
|
||||
typedef long long rep;
|
||||
typedef std::nano period;
|
||||
typedef std::chrono::duration<rep, period> duration;
|
||||
typedef std::chrono::time_point<HighResClock> time_point;
|
||||
static const bool is_steady = true;
|
||||
|
||||
static time_point now();
|
||||
};
|
||||
|
||||
|
||||
class Performancer
|
||||
{
|
||||
public:
|
||||
int RegisterMethod(const std::string& name, const std::string& fullName);
|
||||
void AddData(int index, long long duration);
|
||||
void Dump();
|
||||
|
||||
static Performancer Instance;
|
||||
|
||||
private:
|
||||
std::vector<PerformancerData> data;
|
||||
};
|
||||
|
||||
|
||||
class PerformancerEntry
|
||||
{
|
||||
public:
|
||||
PerformancerEntry(int index);
|
||||
~PerformancerEntry();
|
||||
|
||||
private:
|
||||
std::chrono::time_point<HighResClock> start;
|
||||
int index;
|
||||
};
|
||||
|
||||
#define PERFORMANCER \
|
||||
static int __performancerIndex = Performancer::Instance.RegisterMethod( __FUNCTION__, __FUNCSIG__); \
|
||||
PerformancerEntry __performancerEntry(__performancerIndex);
|
||||
|
||||
#define PERFORMANCER_DUMP Performancer::Instance.Dump();
|
||||
|
||||
#else
|
||||
|
||||
#define PERFORMANCER
|
||||
#define PERFORMANCER_DUMP
|
||||
|
||||
#endif
|
||||
6
meshTools/meshTools/include/common/common.h
Normal file
6
meshTools/meshTools/include/common/common.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Linq.h"
|
||||
#include "Map.h"
|
||||
#include "List.h"
|
||||
#include "Performancer.h"
|
||||
30
meshTools/meshTools/include/core/Edge.h
Normal file
30
meshTools/meshTools/include/core/Edge.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../math/math.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
class Edge
|
||||
{
|
||||
friend class Mesh;
|
||||
public:
|
||||
Edge();
|
||||
Edge(Vertex* a, Vertex* b);
|
||||
~Edge();
|
||||
|
||||
Vertex* GetOtherVertex(Vertex* vertex) const;
|
||||
|
||||
const VertexList& GetVertices() const;
|
||||
const FaceList& GetFaces() const;
|
||||
EdgeList GetEdges() const;
|
||||
|
||||
vec3 GetDirection() const;
|
||||
vec3 GetCenter() const;
|
||||
float GetLength() const;
|
||||
|
||||
Edge* GetHalfEdge(Face* face) const;
|
||||
private:
|
||||
VertexList vertices;
|
||||
FaceList faces;
|
||||
Mesh* mesh;
|
||||
};
|
||||
66
meshTools/meshTools/include/core/Face.h
Normal file
66
meshTools/meshTools/include/core/Face.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
#include "../common/common.h"
|
||||
#include "../math/math.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "Triangle.h"
|
||||
|
||||
class Vertex;
|
||||
class UVGeneratorBase;
|
||||
|
||||
class Face
|
||||
{
|
||||
friend class Mesh;
|
||||
public:
|
||||
Face();
|
||||
Face(Vertex* a, Vertex* b, Vertex* c, Vertex* d = nullptr);
|
||||
Face(const VertexList& vertices);
|
||||
~Face();
|
||||
|
||||
vec3 GetNormal() const;
|
||||
Plane GetPlane() const;
|
||||
|
||||
bool IsTriangle() const;
|
||||
void FlipNormal();
|
||||
void FlipNormal(const vec3& dir);
|
||||
FaceList Triangulate();
|
||||
void FlipEdge();
|
||||
|
||||
bool IsDegenerated() const;
|
||||
bool RegainIntegrity();
|
||||
|
||||
const VertexList& GetVertices() const;
|
||||
FaceList GetFaces() const;
|
||||
const EdgeList& GetEdges() const;
|
||||
|
||||
bool HasTag(int tag) const;
|
||||
bool HasTagsAny(const List<int>& tagsToCheck) const;
|
||||
bool HasTagsAll(const List<int>& tagsToCheck) const;
|
||||
void AddTag(int tag);
|
||||
void RemoveTag(int tag);
|
||||
List<int> GetTags() const;
|
||||
|
||||
void SetMaterialId(int materialId);
|
||||
int GetMaterialId() const;
|
||||
void SetUVGenerator(UVGeneratorBase* generator);
|
||||
UVGeneratorBase* GetUVGenerator() const;
|
||||
|
||||
List<int> GetIndices(bool allowQuads) const;
|
||||
|
||||
void CopyProperties(Face* other, bool merge = false);
|
||||
Mesh* GetMesh() const;
|
||||
|
||||
operator FaceList() { FaceList result; result.Add(const_cast<Face*>(this)); return result; }
|
||||
|
||||
private:
|
||||
List<Triangle> GetTriangles() const;
|
||||
List<int> GetMetaIndices() const;
|
||||
|
||||
List<int> tags;
|
||||
|
||||
UVGeneratorBase* uvGenerator;
|
||||
VertexList vertices;
|
||||
EdgeList edges;
|
||||
int materialId;
|
||||
Mesh* mesh;
|
||||
};
|
||||
65
meshTools/meshTools/include/core/Mesh.h
Normal file
65
meshTools/meshTools/include/core/Mesh.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../math/math.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
class Mesh
|
||||
{
|
||||
public:
|
||||
Mesh();
|
||||
~Mesh();
|
||||
|
||||
const VertexList& GetVertices() const;
|
||||
const FaceList& GetFaces() const;
|
||||
EdgeList GetEdges() const;
|
||||
|
||||
void AddFace(Face* face);
|
||||
void RemoveFace(Face* face);
|
||||
|
||||
FaceList SplitEdge(Edge* edgeToSplit, Vertex* splitVertex);
|
||||
|
||||
void ReplaceVertexFromFaces(const FaceList& faces, Vertex* oldVertex, Vertex* newVertex);
|
||||
void ReplaceVertices(const VertexList& verticesToReplace, Vertex* newVertex);
|
||||
|
||||
List<int> GetIndices(bool allowQuads);
|
||||
|
||||
Map<int, FaceList> GetSubMeshs();
|
||||
|
||||
void StartAutoUpdate(FaceList& faceList);
|
||||
void StopAutoUpdate(FaceList& faceList);
|
||||
void TriggerFaceReplaced(Face* oldFace, const FaceList& newFaces);
|
||||
|
||||
private:
|
||||
Edge* FindEdge(Vertex* a, Vertex* b);
|
||||
void UpdateIndices();
|
||||
|
||||
void RemoveFaceFromEdge(Edge* edge, Face* face);
|
||||
void RemoveEdgeFromVertex(Vertex* vertex, Edge* edge);
|
||||
|
||||
private:
|
||||
VertexList vertices;
|
||||
FaceList faces;
|
||||
List<FaceList*> autoUpdateHandles;
|
||||
};
|
||||
|
||||
|
||||
// AutoFaceList will watch for changes (replace & remove) on the content of this list and will reflect these.
|
||||
// This means, when an operation removes a face which is contained in the AutoFaceList it will removed from the
|
||||
// list even when the operation was performed on a different list.
|
||||
// Example:
|
||||
// FaceList a;
|
||||
// .. // fill a
|
||||
// AutoFaceList b(a);
|
||||
// mt::Delete(a); // b.Count() == 0;
|
||||
class AutoFaceList : public FaceList
|
||||
{
|
||||
public:
|
||||
AutoFaceList(FaceList&& other);
|
||||
AutoFaceList(const FaceList& other);
|
||||
~AutoFaceList();
|
||||
|
||||
private:
|
||||
void Init();
|
||||
Mesh* mesh;
|
||||
};
|
||||
44
meshTools/meshTools/include/core/Path.h
Normal file
44
meshTools/meshTools/include/core/Path.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../math/math.h"
|
||||
|
||||
class Path
|
||||
{
|
||||
public:
|
||||
void SetPoints(const List<vec3>& points);
|
||||
void SetScale(const List<float>& scale);
|
||||
void SetRotation(const List<float>& rotation);
|
||||
|
||||
vec3 GetPoint(float t) const;
|
||||
float GetScale(float t) const;
|
||||
float GetRotation(float t) const;
|
||||
vec3 GetDirection(float t) const;
|
||||
|
||||
private:
|
||||
template <typename T> static void GetValues(const List<T>& source, float& t, T& p0, T& p1, T& p2, T& p3)
|
||||
{
|
||||
auto maxT = source.Count();
|
||||
auto p1Index = (int)Math::Min(t * maxT, maxT - 1.0f);
|
||||
auto p0Index = (int)Math::Max(p1Index - 1.0f, 0.0f);
|
||||
auto p2Index = (int)Math::Min(p1Index + 1.0f, maxT - 1.0f);
|
||||
auto p3Index = (int)Math::Min(p2Index + 1.0f, maxT - 1.0f);
|
||||
|
||||
p1 = source[p1Index];
|
||||
p2 = p1Index == p2Index ? p1 + (p1 - source[p0Index]) : source[p2Index];
|
||||
p0 = p0Index == p1Index ? p1 - (p2 - p1) : source[p0Index];
|
||||
p3 = p3Index == p2Index ? p1 + (p2 - p1) : source[p3Index];
|
||||
|
||||
t = (t - (1.0f / maxT * p1Index)) / (1.0f / maxT);
|
||||
}
|
||||
|
||||
static float Spline(float p0, float p1, float p2, float p3, float t);
|
||||
static vec3 Spline(const vec3& p0, const vec3& p1, const vec3& p2, const vec3& p3, float t);
|
||||
|
||||
|
||||
private:
|
||||
List<vec3> points;
|
||||
List<float> rotation;
|
||||
List<float> scale;
|
||||
};
|
||||
|
||||
26
meshTools/meshTools/include/core/Triangle.h
Normal file
26
meshTools/meshTools/include/core/Triangle.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../math/math.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
|
||||
class Vertex;
|
||||
|
||||
class Triangle
|
||||
{
|
||||
public:
|
||||
Triangle();
|
||||
Triangle(Vertex* a, Vertex* b, Vertex* c);
|
||||
~Triangle();
|
||||
|
||||
vec3 GetNormal() const;
|
||||
const VertexList& GetVertices() const;
|
||||
|
||||
bool IsDegenerated() const;
|
||||
float GetArea() const;
|
||||
|
||||
private:
|
||||
VertexList vertices;
|
||||
};
|
||||
|
||||
43
meshTools/meshTools/include/core/Vertex.h
Normal file
43
meshTools/meshTools/include/core/Vertex.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../math/math.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
|
||||
class Vertex
|
||||
{
|
||||
friend class Mesh;
|
||||
friend class Selection;
|
||||
public:
|
||||
Vertex(const vec3& position);
|
||||
Vertex(Vertex* other);
|
||||
//Vertex();
|
||||
~Vertex();
|
||||
|
||||
int GetIndex() const;
|
||||
|
||||
vec3 GetNormal() const;
|
||||
void SetNormal(const vec3& normal);
|
||||
|
||||
bool HasManualNormal() const { return normal != nullptr; }
|
||||
|
||||
VertexList GetVertices() const;
|
||||
FaceList GetFaces() const;
|
||||
const EdgeList& GetEdges() const;
|
||||
|
||||
Mesh* GetMesh() const;
|
||||
|
||||
void Interpolate(Vertex* other, float t);
|
||||
|
||||
public:
|
||||
vec3 Position;
|
||||
float UV[4];
|
||||
float UV2[4];
|
||||
|
||||
private:
|
||||
vec3* normal;
|
||||
int index;
|
||||
EdgeList edges;
|
||||
Mesh* mesh;
|
||||
};
|
||||
12
meshTools/meshTools/include/core/core.h
Normal file
12
meshTools/meshTools/include/core/core.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/common.h"
|
||||
#include "../math/math.h"
|
||||
|
||||
#include "Mesh.h"
|
||||
#include "Face.h"
|
||||
#include "Vertex.h"
|
||||
#include "Triangle.h"
|
||||
#include "Edge.h"
|
||||
#include "Path.h"
|
||||
#include "typedefs.h"
|
||||
10
meshTools/meshTools/include/core/typedefs.h
Normal file
10
meshTools/meshTools/include/core/typedefs.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "../common/common.h"
|
||||
|
||||
class Vertex;
|
||||
class Edge;
|
||||
class Face;
|
||||
|
||||
typedef List<Vertex*> VertexList;
|
||||
typedef List<Edge*> EdgeList;
|
||||
typedef List<Face*> FaceList;
|
||||
28
meshTools/meshTools/include/math/Bounds.h
Normal file
28
meshTools/meshTools/include/math/Bounds.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "vec3.h"
|
||||
|
||||
class Bounds
|
||||
{
|
||||
public:
|
||||
Bounds(vec3 min, vec3 max)
|
||||
: Min{min}
|
||||
, Max{max}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
vec3 Min;
|
||||
vec3 Max;
|
||||
|
||||
float GetRadius() const
|
||||
{
|
||||
auto length = (Max - Min).GetLength();
|
||||
return length / 2;
|
||||
}
|
||||
|
||||
vec3 GetCenter() const
|
||||
{
|
||||
return (Min + Max) * 0.5f;
|
||||
}
|
||||
};
|
||||
23
meshTools/meshTools/include/math/Plane.h
Normal file
23
meshTools/meshTools/include/math/Plane.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "vec3.h"
|
||||
|
||||
class Plane
|
||||
{
|
||||
public:
|
||||
Plane(const vec3& normal, const vec3& point);
|
||||
Plane(const vec3& a, const vec3& b, const vec3& c);
|
||||
~Plane();
|
||||
|
||||
float GetDistanceToPoint(const vec3& point) const;
|
||||
vec3 GetNormal() const;
|
||||
float GetDistance() const;
|
||||
bool GetSide(const vec3& point) const;
|
||||
void Flip();
|
||||
float IntersectLinesegment(vec3 a, vec3 b, vec3& result) const;
|
||||
|
||||
private:
|
||||
vec3 normal;
|
||||
float distance;
|
||||
};
|
||||
|
||||
24
meshTools/meshTools/include/math/Quaternion.h
Normal file
24
meshTools/meshTools/include/math/Quaternion.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
class vec3;
|
||||
class Quaternion
|
||||
{
|
||||
public:
|
||||
static Quaternion identity;
|
||||
static Quaternion LookRotation(const vec3& normal);
|
||||
static Quaternion CreateFromAxisAngle(const vec3& axis, float angle);
|
||||
static Quaternion FromTo(vec3 v0, vec3 v1);
|
||||
|
||||
public:
|
||||
Quaternion();
|
||||
|
||||
void Inverse();
|
||||
void Normalize();
|
||||
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
101
meshTools/meshTools/include/math/math.h
Normal file
101
meshTools/meshTools/include/math/math.h
Normal file
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath> // acos and shit
|
||||
#include "Bounds.h"
|
||||
#include "Plane.h"
|
||||
#include "Quaternion.h"
|
||||
#include "vec3.h"
|
||||
|
||||
|
||||
class Math
|
||||
{
|
||||
public:
|
||||
static const float Rad2Deg;
|
||||
static const float Deg2Rad;
|
||||
static const float FloatEpsilon;
|
||||
static const float Pi;
|
||||
static const float Infinity;
|
||||
|
||||
static float Clamp01(float a)
|
||||
{
|
||||
return a > 1 ? 1 : a < 0 ? 0 : a;
|
||||
}
|
||||
|
||||
static float Pow(float a, float b)
|
||||
{
|
||||
return std::pow(a, b);
|
||||
}
|
||||
|
||||
static float Max(float a, float b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
static float Min(float a, float b)
|
||||
{
|
||||
return a > b ? b : a;
|
||||
}
|
||||
|
||||
static float Abs(float a)
|
||||
{
|
||||
return a > 0 ? a : -a;
|
||||
}
|
||||
|
||||
static float Sin(float x)
|
||||
{
|
||||
/*_asm fld x
|
||||
_asm fsin*/
|
||||
return std::sin(x);
|
||||
}
|
||||
|
||||
static float Cos(float x)
|
||||
{
|
||||
/*_asm fld x
|
||||
_asm fcos*/
|
||||
return std::cos(x);
|
||||
}
|
||||
|
||||
static float Acos(float x)
|
||||
{
|
||||
/*_asm
|
||||
{
|
||||
fld x
|
||||
fld x
|
||||
fmul
|
||||
fld1
|
||||
fsubr
|
||||
fsqrt
|
||||
fxch
|
||||
fpatan
|
||||
}*/
|
||||
return std::acos(x);
|
||||
}
|
||||
|
||||
static float Atan2(float x, float y)
|
||||
{
|
||||
return std::atan2(x, y);
|
||||
}
|
||||
|
||||
static float Lerp(float a, float b, float t)
|
||||
{
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
static float Sqrt(float x)
|
||||
{
|
||||
#if _DEBUG
|
||||
return std::sqrt(x);
|
||||
#else
|
||||
float xhalf = 0.5f*x;
|
||||
int i = *(int*)&x;
|
||||
i = 0x5f375a86 - (i >> 1);
|
||||
x = *(float*)&i;
|
||||
x = x*(1.5f - xhalf*x*x);
|
||||
x = x*(1.5f - xhalf*x*x);
|
||||
x = x*(1.5f - xhalf*x*x);
|
||||
x = 1 / x;
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
53
meshTools/meshTools/include/math/vec3.h
Normal file
53
meshTools/meshTools/include/math/vec3.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include "Quaternion.h"
|
||||
|
||||
class vec3
|
||||
{
|
||||
public:
|
||||
static const vec3 zero;
|
||||
static const vec3 one;
|
||||
static const vec3 up;
|
||||
static const vec3 down;
|
||||
static const vec3 left;
|
||||
static const vec3 right;
|
||||
static const vec3 forward;
|
||||
static const vec3 back;
|
||||
|
||||
vec3();
|
||||
vec3(float x, float y, float z);
|
||||
vec3(const vec3& other);
|
||||
~vec3();
|
||||
|
||||
float GetLength() const;
|
||||
float GetLengthSq() const;
|
||||
void Normalize();
|
||||
|
||||
static vec3 Mul(const vec3& a, const vec3& b);
|
||||
|
||||
static float Dot(const vec3& a, const vec3& b);
|
||||
static vec3 Cross(const vec3& a, const vec3& b);
|
||||
|
||||
static vec3 Min(const vec3& a, const vec3& b);
|
||||
static vec3 Max(const vec3& a, const vec3& b);
|
||||
static float Distance(const vec3& a, const vec3& b);
|
||||
static float DistanceSq(const vec3& a, const vec3& b);
|
||||
|
||||
vec3 operator- () const;
|
||||
bool operator== (const vec3& other) const;
|
||||
bool operator!= (const vec3& other) const;
|
||||
vec3 operator+ (const vec3& other) const;
|
||||
void operator+= (const vec3& other);
|
||||
void operator-= (const vec3& other);
|
||||
void operator/= (float other);
|
||||
void operator*= (float other);
|
||||
vec3 operator- (const vec3& other) const;
|
||||
vec3 operator* (float other) const;
|
||||
vec3 operator/ (float other) const;
|
||||
vec3 operator* (const Quaternion& q) const;
|
||||
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
|
||||
18
meshTools/meshTools/include/tools/CSG.h
Normal file
18
meshTools/meshTools/include/tools/CSG.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Generates the CSG Union of a and b.
|
||||
// All faces will be triangulated.
|
||||
Mesh* CsgUnion(const FaceList& a, const FaceList& b);
|
||||
|
||||
// Generates the CSG subtraction of a and b.
|
||||
// All faces will be triangulated.
|
||||
Mesh* CsgSubtract(const FaceList& a, const FaceList& b);
|
||||
|
||||
// Generates the CSG intersection of a and b.
|
||||
// All faces will be triangulated.
|
||||
Mesh* CsgIntersect(const FaceList& a, const FaceList& b);
|
||||
}
|
||||
45
meshTools/meshTools/include/tools/CSGBase.h
Normal file
45
meshTools/meshTools/include/tools/CSGBase.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
class CSG
|
||||
{
|
||||
public:
|
||||
static CSG* FromPolygons(const FaceList& faces);
|
||||
|
||||
CSG* Clone();
|
||||
CSG* Inverse();
|
||||
const FaceList& GetFaces() const;
|
||||
|
||||
CSG* Union(CSG* other);
|
||||
CSG* Subtract(CSG* other);
|
||||
CSG* Intersect(CSG* other);
|
||||
private:
|
||||
FaceList faces;
|
||||
};
|
||||
|
||||
class CSGNode
|
||||
{
|
||||
public:
|
||||
CSGNode();
|
||||
CSGNode(const FaceList& faces);
|
||||
~CSGNode();
|
||||
|
||||
CSGNode* Clone();
|
||||
void Invert();
|
||||
|
||||
FaceList ClipPolygons(const FaceList& other);
|
||||
void ClipTo(CSGNode* other);
|
||||
FaceList AllPolygons();
|
||||
|
||||
void Build(const FaceList& faces);
|
||||
|
||||
private:
|
||||
FaceList faces;
|
||||
Plane* plane;
|
||||
CSGNode* front;
|
||||
CSGNode* back;
|
||||
};
|
||||
}
|
||||
20
meshTools/meshTools/include/tools/Calculate.h
Normal file
20
meshTools/meshTools/include/tools/Calculate.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "../core/core.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Returns the bounding box of the vertices.
|
||||
Bounds GetBoundingBox(const VertexList& vertices);
|
||||
|
||||
// Returns the average normal of the vertices.
|
||||
vec3 GetNormal(const VertexList& vertices);
|
||||
|
||||
// Returns the center of the bounding box of the vertices.
|
||||
vec3 GetCenter(const VertexList& vertices);
|
||||
|
||||
// Generates half edges from the given edges and faces.
|
||||
EdgeList GetHalfEdges(const EdgeList& edges, const FaceList& faces);
|
||||
|
||||
// Returns the outline edges of the faces. An outline is an edge which has only 1 face (excluding faces not in the provided faces list).
|
||||
EdgeList GetOutlineEdges(const FaceList& faces);
|
||||
}
|
||||
15
meshTools/meshTools/include/tools/Copy.h
Normal file
15
meshTools/meshTools/include/tools/Copy.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Clones the faces which do not belong to the target mesh and transfers the result to the target mesh.
|
||||
FaceList CopyToMesh(const FaceList& faces, Mesh* target);
|
||||
|
||||
// Clones the faces and returns the copy.
|
||||
FaceList Copy(const FaceList& faces);
|
||||
|
||||
// Clones the faces into a new mesh.
|
||||
Mesh* ToMesh(const FaceList& faces);
|
||||
}
|
||||
9
meshTools/meshTools/include/tools/Delete.h
Normal file
9
meshTools/meshTools/include/tools/Delete.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Deletes the faces and removes them from the mesh.
|
||||
void Delete(const FaceList& faces);
|
||||
}
|
||||
12
meshTools/meshTools/include/tools/Detach.h
Normal file
12
meshTools/meshTools/include/tools/Detach.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Removes the faces from attaching faces.
|
||||
Map<Vertex*, Vertex*> Detach(const FaceList& faces, bool preserveVertexNormals = false, EdgeList* outline = nullptr);
|
||||
|
||||
// Removes each face from attaching faces.
|
||||
void DetachAll(const FaceList& faces, bool preserveVertexNormals = false);
|
||||
}
|
||||
24
meshTools/meshTools/include/tools/Extrude.h
Normal file
24
meshTools/meshTools/include/tools/Extrude.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Extrudes the given vertices.
|
||||
FaceList ExtrudeVertices(const VertexList& vertices, float sideEdgeLength, float extrudeHeight);
|
||||
|
||||
// Detaches the faces from the mesh and moves the vertices by the given factor and move mode. Then generates side faces to combine the outlines of the hole of the detached faces to the detached faces.
|
||||
FaceList Extrude(const FaceList& faces, float factor, MoveMode mode = MoveMode::UseVertexNormal);
|
||||
|
||||
// Detaches the faces from the mesh and moves the vertices by the given extrude direction. Then generates side faces to combine the outlines of the hole of the detached faces to the detached faces.
|
||||
FaceList Extrude(const FaceList& faces, const vec3& extrudeDirection);
|
||||
|
||||
// Detaches the faces from the mesh, moves the vertices by the given extrude direction and scales the detached faces. Then generates side faces to combine the outlines of the hole of the detached faces to the detached faces.
|
||||
FaceList Bevel(const FaceList& faces, const vec3& extrudeDirection, float capScale);
|
||||
|
||||
// Detaches the faces from the mesh, moves the vertices by the given factor and move mode and scales the detached faces. Then generates side faces to combine the outlines of the hole of the detached faces to the detached faces.
|
||||
FaceList Bevel(const FaceList& faces, float factor, float capScale, MoveMode mode = MoveMode::UseVertexNormal, const vec3* extrudeDirectionOverride = nullptr);
|
||||
|
||||
// Extrudes the given faces along the given path.
|
||||
List<FaceList> Loft(const FaceList& faces, const Path& path, int segments);
|
||||
}
|
||||
95
meshTools/meshTools/include/tools/FFD.h
Normal file
95
meshTools/meshTools/include/tools/FFD.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Free Form Deformation
|
||||
// Creates an 3D control point array of (L+1) * (M+1) * (N+1) Elements.
|
||||
// Each control point goes from -HalfBounds to +HalfBounds along each axis of control points.
|
||||
// Changing the position of the control points will move the vertices based upon a coeficient to the new position.
|
||||
class FFD
|
||||
{
|
||||
public:
|
||||
enum FFDControlPointMode
|
||||
{
|
||||
All,
|
||||
Edges,
|
||||
Surface
|
||||
};
|
||||
|
||||
private:
|
||||
class Vector3Param
|
||||
{
|
||||
public:
|
||||
///bernstein polynomial packing
|
||||
List<List<float>> bernPolyPack;
|
||||
|
||||
///Point after applying s,t,u to p0, should result in original point
|
||||
vec3 p;
|
||||
|
||||
///Origin
|
||||
vec3 p0;
|
||||
|
||||
///Distances along S/T/U axes
|
||||
float s, t, u;
|
||||
|
||||
Vector3Param()
|
||||
{
|
||||
s = 0.0f;
|
||||
t = 0.0f;
|
||||
u = 0.0f;
|
||||
}
|
||||
|
||||
Vector3Param(const Vector3Param& v)
|
||||
{
|
||||
s = v.s;
|
||||
t = v.t;
|
||||
u = v.u;
|
||||
p = v.p;
|
||||
p0 = v.p0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
vec3 S;
|
||||
vec3 T;
|
||||
vec3 U;
|
||||
|
||||
List<Vector3Param> vertexParams;
|
||||
const FaceList& faces;
|
||||
VertexList originalVertices;
|
||||
FFDControlPointMode ffdControlPointMode;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Number of controls for S, T, & U respectively. (L,M, and N MUST be >= 1)
|
||||
/// </summary>
|
||||
const int L;
|
||||
const int M;
|
||||
const int N;
|
||||
|
||||
// The control points of the FFD Box in unnormalized point space.
|
||||
// ControlPoints[0][0][0] results in a vec3(-0.5f, -0.5f, -0.5f) position when the FFD Box encapsulates a Cube with an edge length of 1.0f.
|
||||
vec3*** ControlPoints;
|
||||
|
||||
FFD(const FaceList& faces, int l, int m, int n, FFDControlPointMode ffdControlPointMode = FFDControlPointMode::All);
|
||||
~FFD();
|
||||
void Apply();
|
||||
|
||||
List<vec3*> SelectPoints(int startX, int endX, int startY, int endY, int startZ, int endZ);
|
||||
|
||||
private:
|
||||
float binomialCoeff(int n, int k);
|
||||
float bernsteinPoly(int n, int v, float x);
|
||||
void calculateSTU(const vec3& max, const vec3& min);
|
||||
|
||||
void calculateTrivariateBernsteinPolynomial(const vec3& p0);
|
||||
void Parameterize();
|
||||
void createControlPoints(const vec3& origin);
|
||||
vec3 createControlPoint(const vec3& p0, int i, int j, int k);
|
||||
vec3 getWorldVector3(const Vector3Param& r);
|
||||
};
|
||||
}
|
||||
9
meshTools/meshTools/include/tools/Flip.h
Normal file
9
meshTools/meshTools/include/tools/Flip.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Flips the facing direction of all faces.
|
||||
void FlipSides(const FaceList& faces);
|
||||
}
|
||||
12
meshTools/meshTools/include/tools/Group.h
Normal file
12
meshTools/meshTools/include/tools/Group.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Groups the faces into adjancing faces. Adjancing faces are faces attached to each other with the same face direction.
|
||||
// This function does not weld the faces to each other before performing and does not detach the groups from each other after performing.
|
||||
// Use a threshold >= 2 to get groups of connected faces
|
||||
// Use any other threshold to get groups of connected faces who are connected to each other by a certain angle
|
||||
List<FaceList> GetGroups(const FaceList& faces, float threshold);
|
||||
}
|
||||
19
meshTools/meshTools/include/tools/Prefab.h
Normal file
19
meshTools/meshTools/include/tools/Prefab.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Creates a quad face with the given size, direction and center position.
|
||||
Face* CreateQuad(const vec3& size, const vec3& position, PlaneDirection direction);
|
||||
|
||||
// Creates a plane mesh with the given size, direction and center position.
|
||||
Mesh* CreatePlane(const vec3& position = vec3::zero, float edgeSize = 1, PlaneDirection direction = PlaneDirection::Up);
|
||||
|
||||
// Creates a cube mesh with the given size, direction and center position, the cube may be optionally smooth or sharp.
|
||||
Mesh* CreateCube(bool weldVertices = true, const vec3& position = vec3::zero, float edgeSize = 1);
|
||||
|
||||
// Creates a sphere mesh with the given size, tesselation and center position.
|
||||
// The tesselationLevel is the number of times a start cube will be subdivided and smoothed, so using a level of 0 will result to a welded cube.
|
||||
Mesh* CreateSphere(int tesselationLevel = 1, const vec3& position = vec3::zero, float baseSize = 1);
|
||||
}
|
||||
18
meshTools/meshTools/include/tools/Project.h
Normal file
18
meshTools/meshTools/include/tools/Project.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Projects all vertices to the plane generated of the center and average normal of all vertices.
|
||||
void Flatten(const VertexList& vertices);
|
||||
|
||||
// Projects all vertices to the plane generated of the center and the given normal.
|
||||
void Flatten(const VertexList& vertices, const vec3& normal);
|
||||
|
||||
// Projects all vertices to the given plane.
|
||||
void Project(const VertexList& vertices, const Plane& plane);
|
||||
|
||||
// Projects all vertices to the given plane when the vertex is at the negative side of the plane.
|
||||
void Clamp(const VertexList& vertices, const Plane& plane);
|
||||
}
|
||||
49
meshTools/meshTools/include/tools/Select.h
Normal file
49
meshTools/meshTools/include/tools/Select.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Returns the vertices associated to the elements.
|
||||
template<class T>
|
||||
VertexList GetVertices(const List<T>& elements)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return Linq::SelectUniqueMany<Vertex*>(elements, [](T element) { return element->GetVertices(); });
|
||||
}
|
||||
|
||||
// Returns the elements associated to the vertices.
|
||||
template<class T>
|
||||
FaceList GetFaces(const List<T>& elements)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return Linq::SelectUniqueMany<Face*>(elements, [](T element) { return element->GetFaces(); });
|
||||
}
|
||||
|
||||
// Returns all faces which face to the given direction. An threshold may be used to allow faces which face the direction nearly.
|
||||
// Mirroring is optionally appplied which also uses the negated direction to check for mathing faces.
|
||||
FaceList GetFacesByDirection(const FaceList& faces, const vec3 direction, float threshold = 0.0f, bool mirror = false);
|
||||
|
||||
// Returns all faces which intersect the given plane or are on the positive side of it.
|
||||
FaceList GetFacesOnPositivePlane(const FaceList& faces, const Plane& plane);
|
||||
|
||||
// Returns all vertices which intersect the given plane or are on the positive side of it.
|
||||
VertexList GetVerticesOnPositivePlane(const VertexList& vertices, const Plane& plane);
|
||||
|
||||
// Returns all faces with the given tag.
|
||||
FaceList GetFacesWithTag(const FaceList& faces, int tag);
|
||||
|
||||
// Returns all faces with one or all (optionally) tags from the given tag list.
|
||||
FaceList GetFacesWithTags(const FaceList& faces, List<int> tags, bool canMatchAnyTag = true);
|
||||
|
||||
// Returns all faces inside or intersecting the sphere at the given postion and radius.
|
||||
FaceList GetFacesAt(const FaceList& faces, const vec3& position, float radius);
|
||||
|
||||
// Returns all vertices inside or intersecting the sphere at the given postion and radius.
|
||||
VertexList GetVerticesAt(const VertexList& vertices, const vec3& position, float radius);
|
||||
|
||||
// Returns the nearest face to the given point in the given range.
|
||||
Face* GetFaceAt(const FaceList& faces, const vec3& position, float range = Math::Infinity);
|
||||
|
||||
// Returns the nearest vertex to the given point in the given range.
|
||||
Vertex* GetVertexAt(const VertexList& vertices, const vec3& position, float range = Math::Infinity);
|
||||
}
|
||||
12
meshTools/meshTools/include/tools/Split.h
Normal file
12
meshTools/meshTools/include/tools/Split.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Splits the provided faces by the given plane.
|
||||
FaceList Split(const FaceList& faces, const Plane& plane);
|
||||
|
||||
// Merges two triangles and returns the new quad face.
|
||||
Face* MergeTriangles(Face* a, Face* b);
|
||||
}
|
||||
10
meshTools/meshTools/include/tools/Subdivide.h
Normal file
10
meshTools/meshTools/include/tools/Subdivide.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Splits the faces into 3 (for triangles) or 4 (for quads) faces and applies the optional smoothing step.
|
||||
// Warning: This method removes the provided faces.
|
||||
FaceList Subdivide(const FaceList& faces, bool smooth);
|
||||
}
|
||||
11
meshTools/meshTools/include/tools/Tags.h
Normal file
11
meshTools/meshTools/include/tools/Tags.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Adds the given tag to all faces.
|
||||
void AddTag(const FaceList& faces, int tag);
|
||||
// Removes the given tag from all faces.
|
||||
void RemoveTag(const FaceList& faces, int tag);
|
||||
}
|
||||
45
meshTools/meshTools/include/tools/Transform.h
Normal file
45
meshTools/meshTools/include/tools/Transform.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include "../core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Sets the position of each vertex relative to their center to the given position.
|
||||
void MoveTo(const VertexList& vertices, const vec3& position);
|
||||
|
||||
// Moves each vertex about the given offset.
|
||||
void MoveBy(const VertexList& vertices, const vec3& offset);
|
||||
|
||||
// Moves each vertex about the given offset.
|
||||
void MoveBy(const VertexList& vertices, float factor, MoveMode mode = MoveMode::UseCollectionNormal);
|
||||
|
||||
// Scales each vertex around the given center.
|
||||
void Scale(const VertexList& vertices, float factor, CenterMode mode = CenterMode::CollectionCenter);
|
||||
|
||||
// Scales each vertex around the given center.
|
||||
void Scale(const VertexList& vertices, const vec3& center, float factor);
|
||||
|
||||
// Scales each vertex around the given center.
|
||||
void Scale(const VertexList& vertices, const vec3& factor, const vec3& center);
|
||||
|
||||
// Scales each vertex around the center of the given centermode.
|
||||
void Scale(const VertexList& vertices, const vec3& factor, CenterMode mode = mt::CenterMode::CollectionCenter);
|
||||
|
||||
// Rotates the vertices to the given direction, based upon the average of the vertices normals.
|
||||
void Rotate(const VertexList& vertices, const vec3& startNormal, const vec3& direction);
|
||||
|
||||
// Rotates the vertices to the given direction, based upon the average of the vertices normals.
|
||||
void Rotate(const VertexList& vertices, const vec3& center, const vec3& startNormal, const vec3& direction);
|
||||
|
||||
// Rotates the vertices through the given axis at the center of the vertices by the given radian angle.
|
||||
void Rotate(const VertexList& vertices, const vec3& axis, float angle);
|
||||
|
||||
// Rotates the vertices through the given axis at the given center by the given radian angle.
|
||||
void Rotate(const VertexList& vertices, const vec3& center, const vec3& axis, float angle);
|
||||
|
||||
// Rotates the vertices through by the given quaternion at the given center.
|
||||
void Rotate(const VertexList& vertices, const vec3& center, const Quaternion& rotation);
|
||||
|
||||
// Mirrors the faces on the given plane
|
||||
void Mirror(const FaceList& faces, const Plane& plane);
|
||||
}
|
||||
9
meshTools/meshTools/include/tools/Triangulate.h
Normal file
9
meshTools/meshTools/include/tools/Triangulate.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "../../include/core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Transforms each quad into two triangles.
|
||||
FaceList Triangulate(const FaceList& faces);
|
||||
}
|
||||
13
meshTools/meshTools/include/tools/Weld.h
Normal file
13
meshTools/meshTools/include/tools/Weld.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "../core/core.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
// Combines vertices which lay near to each other.
|
||||
// Warning: This method may remove the faces of the provided vertices.
|
||||
void Weld(const VertexList& vertices, float range = 0);
|
||||
|
||||
// Moves all vertices of the faces to the center and welds them.
|
||||
void Collapse(const FaceList& faces, CenterMode mode = CenterMode::CollectionCenter);
|
||||
}
|
||||
22
meshTools/meshTools/include/tools/tools.h
Normal file
22
meshTools/meshTools/include/tools/tools.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "../core/core.h"
|
||||
#include "Prefab.h"
|
||||
#include "Select.h"
|
||||
#include "Transform.h"
|
||||
#include "Calculate.h"
|
||||
#include "Extrude.h"
|
||||
#include "Flip.h"
|
||||
#include "Copy.h"
|
||||
#include "Detach.h"
|
||||
#include "Weld.h"
|
||||
#include "Group.h"
|
||||
#include "Triangulate.h"
|
||||
#include "Project.h"
|
||||
#include "Delete.h"
|
||||
#include "Tags.h"
|
||||
#include "Subdivide.h"
|
||||
#include "CSG.h"
|
||||
#include "FFD.h"
|
||||
#include "Split.h"
|
||||
#include "typedefs.h"
|
||||
76
meshTools/meshTools/include/tools/typedefs.h
Normal file
76
meshTools/meshTools/include/tools/typedefs.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
#include "Select.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
enum MoveMode
|
||||
{
|
||||
UseCollectionNormal,
|
||||
UseVertexNormal
|
||||
};
|
||||
|
||||
enum CenterMode
|
||||
{
|
||||
FaceCenter,
|
||||
MeshCenter,
|
||||
CollectionCenter
|
||||
};
|
||||
|
||||
enum PlaneDirection
|
||||
{
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
Forward,
|
||||
Backward
|
||||
};
|
||||
|
||||
enum Tags
|
||||
{
|
||||
ReservedTagsStartId = 1 << 16,
|
||||
DirectionUp,
|
||||
DirectionDown,
|
||||
DirectionLeft,
|
||||
DirectionRight,
|
||||
DirectionBack,
|
||||
DirectionFront
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
struct convert<FaceList, VertexList>
|
||||
{
|
||||
static VertexList Convert(const FaceList& src)
|
||||
{
|
||||
return mt::GetVertices(src);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct convert<EdgeList, VertexList>
|
||||
{
|
||||
static VertexList Convert(const EdgeList& src)
|
||||
{
|
||||
return mt::GetVertices(src);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct convert<VertexList, FaceList>
|
||||
{
|
||||
static FaceList Convert(const VertexList& src)
|
||||
{
|
||||
return mt::GetFaces(src);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct convert<EdgeList, FaceList>
|
||||
{
|
||||
static FaceList Convert(const EdgeList& src)
|
||||
{
|
||||
return mt::GetFaces(src);
|
||||
}
|
||||
};
|
||||
164
meshTools/meshTools/meshTools.vcxproj
Normal file
164
meshTools/meshTools/meshTools.vcxproj
Normal file
@@ -0,0 +1,164 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\common\common.h" />
|
||||
<ClInclude Include="include\core\core.h" />
|
||||
<ClInclude Include="include\tools\Delete.h" />
|
||||
<ClInclude Include="include\tools\Flip.h" />
|
||||
<ClInclude Include="include\common\Linq.h" />
|
||||
<ClInclude Include="include\common\List.h" />
|
||||
<ClInclude Include="include\common\Map.h" />
|
||||
<ClInclude Include="include\common\Performancer.h" />
|
||||
<ClInclude Include="include\core\Edge.h" />
|
||||
<ClInclude Include="include\core\Face.h" />
|
||||
<ClInclude Include="include\core\Mesh.h" />
|
||||
<ClInclude Include="include\core\Path.h" />
|
||||
<ClInclude Include="include\core\Triangle.h" />
|
||||
<ClInclude Include="include\core\typedefs.h" />
|
||||
<ClInclude Include="include\core\Vertex.h" />
|
||||
<ClInclude Include="include\tools\Copy.h" />
|
||||
<ClInclude Include="include\tools\CSG.h" />
|
||||
<ClInclude Include="include\tools\CSGBase.h" />
|
||||
<ClInclude Include="include\tools\Detach.h" />
|
||||
<ClInclude Include="include\tools\Extrude.h" />
|
||||
<ClInclude Include="include\tools\FFD.h" />
|
||||
<ClInclude Include="include\math\Bounds.h" />
|
||||
<ClInclude Include="include\math\Plane.h" />
|
||||
<ClInclude Include="include\math\Quaternion.h" />
|
||||
<ClInclude Include="include\math\vec3.h" />
|
||||
<ClInclude Include="include\tools\Group.h" />
|
||||
<ClInclude Include="include\tools\Project.h" />
|
||||
<ClInclude Include="include\tools\Select.h" />
|
||||
<ClInclude Include="include\tools\Calculate.h" />
|
||||
<ClInclude Include="include\tools\tools.h" />
|
||||
<ClInclude Include="include\tools\Prefab.h" />
|
||||
<ClInclude Include="include\tools\Split.h" />
|
||||
<ClInclude Include="include\tools\Subdivide.h" />
|
||||
<ClInclude Include="include\tools\Tags.h" />
|
||||
<ClInclude Include="include\tools\Transform.h" />
|
||||
<ClInclude Include="include\tools\Triangulate.h" />
|
||||
<ClInclude Include="include\tools\typedefs.h" />
|
||||
<ClInclude Include="include\tools\Weld.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\tools\Delete.cpp" />
|
||||
<ClCompile Include="src\tools\Flip.cpp" />
|
||||
<ClCompile Include="src\common\Performancer.cpp" />
|
||||
<ClCompile Include="src\core\Edge.cpp" />
|
||||
<ClCompile Include="src\core\Face.cpp" />
|
||||
<ClCompile Include="src\core\Mesh.cpp" />
|
||||
<ClCompile Include="src\core\Path.cpp" />
|
||||
<ClCompile Include="src\core\Triangle.cpp" />
|
||||
<ClCompile Include="src\core\Vertex.cpp" />
|
||||
<ClCompile Include="src\tools\Copy.cpp" />
|
||||
<ClCompile Include="src\tools\CSG.cpp" />
|
||||
<ClCompile Include="src\tools\CSGBase.cpp" />
|
||||
<ClCompile Include="src\tools\Detach.cpp" />
|
||||
<ClCompile Include="src\tools\Extrude.cpp" />
|
||||
<ClCompile Include="src\tools\FFD.cpp" />
|
||||
<ClCompile Include="src\math\Math.cpp" />
|
||||
<ClCompile Include="src\math\Plane.cpp" />
|
||||
<ClCompile Include="src\math\Quaternion.cpp" />
|
||||
<ClCompile Include="src\math\vec3.cpp" />
|
||||
<ClCompile Include="src\tools\Group.cpp" />
|
||||
<ClCompile Include="src\tools\Project.cpp" />
|
||||
<ClCompile Include="src\tools\Select.cpp" />
|
||||
<ClCompile Include="src\tools\Calculate.cpp" />
|
||||
<ClCompile Include="src\tools\Prefab.cpp" />
|
||||
<ClCompile Include="src\tools\Split.cpp" />
|
||||
<ClCompile Include="src\tools\Subdivide.cpp" />
|
||||
<ClCompile Include="src\tools\Tags.cpp" />
|
||||
<ClCompile Include="src\tools\Transform.cpp" />
|
||||
<ClCompile Include="src\tools\Triangulate.cpp" />
|
||||
<ClCompile Include="src\tools\Weld.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A07570FA-501F-400E-823E-00B5459C7E8D}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>meshTools</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>$(SolutionDir)Bin\$(Configuration)\lib\</OutDir>
|
||||
<LibraryPath>$(SolutionDir)Bin\$(Configuration)\lib\;C:\Program Files %28x86%29\Visual Leak Detector\lib\Win32;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(SolutionDir)math/include;$(SolutionDir)common/include;$(SolutionDir)meshCore/include;C:\Program Files %28x86%29\Visual Leak Detector\include;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(SolutionDir)Bin\$(Configuration)\lib\</OutDir>
|
||||
<LibraryPath>$(SolutionDir);C:\Program Files %28x86%29\Visual Leak Detector\lib\Win32;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\Program Files %28x86%29\Visual Leak Detector\include;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>
|
||||
</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<Lib>
|
||||
<AdditionalDependencies>msvcrt_old.LIB</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
225
meshTools/meshTools/meshTools.vcxproj.filters
Normal file
225
meshTools/meshTools/meshTools.vcxproj.filters
Normal file
@@ -0,0 +1,225 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\common\common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Calculate.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Copy.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\CSG.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\CSGBase.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Delete.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Detach.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Extrude.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\FFD.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Flip.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Group.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Prefab.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Project.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Select.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Split.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Subdivide.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Tags.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Transform.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Triangulate.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\typedefs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\Weld.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\math\Bounds.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\math\Plane.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\math\Quaternion.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\math\vec3.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\tools\tools.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\core\Edge.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\core\Face.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\core\Mesh.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\core\Path.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\core\Triangle.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\core\Vertex.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\core\typedefs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\core\core.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\common\Performancer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\common\Linq.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\common\List.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\common\Map.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\core\Edge.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\core\Face.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\core\Mesh.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\core\Path.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\core\Triangle.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\core\Vertex.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\math\Math.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\math\Plane.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\math\Quaternion.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\math\vec3.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\common\Performancer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Calculate.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\CSG.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\CSGBase.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Extrude.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\FFD.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Prefab.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Select.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Subdivide.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Tags.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Transform.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Split.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Triangulate.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Weld.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Project.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Group.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Detach.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Copy.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Flip.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tools\Delete.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
6
meshTools/meshTools/meshTools.vcxproj.user
Normal file
6
meshTools/meshTools/meshTools.vcxproj.user
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ShowAllFiles>true</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
161
meshTools/meshTools/src/common/Performancer.cpp
Normal file
161
meshTools/meshTools/src/common/Performancer.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#if _DEBUG
|
||||
|
||||
#include "../../include/common/Performancer.h"
|
||||
#include "Windows.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
const long long g_Frequency = []() -> long long
|
||||
{
|
||||
LARGE_INTEGER frequency;
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
return frequency.QuadPart;
|
||||
}();
|
||||
}
|
||||
|
||||
HighResClock::time_point HighResClock::now()
|
||||
{
|
||||
LARGE_INTEGER count;
|
||||
QueryPerformanceCounter(&count);
|
||||
return time_point(duration(count.QuadPart * static_cast<rep>(period::den) / g_Frequency));
|
||||
}
|
||||
|
||||
Performancer Performancer::Instance;
|
||||
|
||||
int Performancer::RegisterMethod(const std::string& name, const std::string& fullName)
|
||||
{
|
||||
data.push_back({ name, fullName });
|
||||
return data.size() - 1;
|
||||
}
|
||||
|
||||
void Performancer::AddData(int index, long long duration)
|
||||
{
|
||||
data[index].Add(duration);
|
||||
}
|
||||
|
||||
struct my_numpunct : std::numpunct<char> {
|
||||
std::string do_grouping() const { return "\03"; }
|
||||
};
|
||||
|
||||
void Performancer::Dump()
|
||||
{
|
||||
auto sorted = data;
|
||||
std::sort(sorted.begin(), sorted.end(), [](const PerformancerData& lhs, const PerformancerData& rhs)
|
||||
{
|
||||
return lhs.Elapsed > rhs.Elapsed;
|
||||
});
|
||||
|
||||
long long total = 0;
|
||||
long long average = 0;
|
||||
size_t maxNameLength = 0;
|
||||
for (const auto& data : sorted)
|
||||
{
|
||||
maxNameLength = data.Name.size() > maxNameLength ? data.Name.size() : maxNameLength;
|
||||
total += data.Elapsed;
|
||||
average += data.Elapsed / data.Calls;
|
||||
}
|
||||
|
||||
maxNameLength += 2;
|
||||
|
||||
const int usWidth = 20;
|
||||
std::locale loc(std::cout.getloc(), new my_numpunct);
|
||||
std::stringstream ss;
|
||||
ss.imbue(loc);
|
||||
ss << "Performancer summary:\n";
|
||||
ss.width(10);
|
||||
ss << std::left << "Rank";
|
||||
ss.width(maxNameLength);
|
||||
ss << std::left << "Name";
|
||||
ss.width(usWidth);
|
||||
ss << std::left << "Calls";
|
||||
ss.width(usWidth);
|
||||
ss << std::left << "Min (us)";
|
||||
ss.width(usWidth);
|
||||
ss << std::left << "Max (us)";
|
||||
ss.width(usWidth);
|
||||
ss << std::left << "Average (us)";
|
||||
ss.width(usWidth);
|
||||
ss << std::left << "Average (%)";
|
||||
ss.width(usWidth);
|
||||
ss << std::left << "Total (us)";
|
||||
ss.width(usWidth);
|
||||
ss << std::left << "Total (%)";
|
||||
ss.width(usWidth);
|
||||
ss << "Full Name";
|
||||
ss << "\n";
|
||||
|
||||
|
||||
|
||||
int i = 0;
|
||||
for (const auto& data : sorted)
|
||||
{
|
||||
i++;
|
||||
ss.width(10);
|
||||
ss << std::left << i;
|
||||
ss.width(maxNameLength);
|
||||
ss << std::left << data.Name;
|
||||
ss.width(usWidth);
|
||||
ss << std::left << data.Calls;
|
||||
ss.width(usWidth);
|
||||
ss << std::left << data.Min;
|
||||
ss.width(usWidth);
|
||||
ss << std::left << data.Max;
|
||||
ss.width(usWidth);
|
||||
ss << std::left << data.Elapsed / data.Calls;
|
||||
ss.width(usWidth);
|
||||
ss << std::left << (int)(((data.Elapsed / data.Calls) / (double)average) * 100);
|
||||
ss.width(usWidth);
|
||||
ss << std::left << data.Elapsed;
|
||||
ss.width(usWidth);
|
||||
ss << std::left << (int)((data.Elapsed / (double)total) * 100);
|
||||
ss << data.FullName;
|
||||
ss << "\n";
|
||||
}
|
||||
ss << "\n";
|
||||
|
||||
OutputDebugStringA(ss.str().c_str());
|
||||
}
|
||||
|
||||
|
||||
PerformancerEntry::PerformancerEntry(int index)
|
||||
: index{ index }
|
||||
, start{ HighResClock::now() }
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PerformancerEntry::~PerformancerEntry()
|
||||
{
|
||||
auto end = HighResClock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
||||
Performancer::Instance.AddData(index, duration);
|
||||
}
|
||||
|
||||
PerformancerData::PerformancerData(const std::string& name, const std::string& fullName)
|
||||
: Name(name)
|
||||
, FullName(fullName)
|
||||
, Calls{ 0 }
|
||||
, Elapsed{ 0 }
|
||||
, Max{ 0 }
|
||||
, Min{ 0 }
|
||||
{
|
||||
}
|
||||
|
||||
void PerformancerData::Add(long long duration)
|
||||
{
|
||||
if (Calls == 0)
|
||||
{
|
||||
Min = duration;
|
||||
Max = duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
Min = Min > duration ? duration : Min;
|
||||
Max = Max < duration ? duration : Max;
|
||||
}
|
||||
|
||||
Elapsed += duration;
|
||||
Calls++;
|
||||
}
|
||||
#endif
|
||||
99
meshTools/meshTools/src/core/Edge.cpp
Normal file
99
meshTools/meshTools/src/core/Edge.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "../../include/core/Edge.h"
|
||||
#include "../../include/core/Face.h"
|
||||
#include "../../include/core/Vertex.h"
|
||||
|
||||
|
||||
Edge::Edge()
|
||||
: mesh{ nullptr }
|
||||
, vertices{ 2 }
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
Edge::Edge(Vertex* a, Vertex* b)
|
||||
: mesh{ nullptr }
|
||||
, vertices{ 2 }
|
||||
{
|
||||
PERFORMANCER;
|
||||
vertices.Add(a);
|
||||
vertices.Add(b);
|
||||
}
|
||||
|
||||
|
||||
Edge::~Edge()
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
Vertex* Edge::GetOtherVertex(Vertex* vertex) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return vertices[0] == vertex ? vertices[1] : vertices[0];
|
||||
}
|
||||
|
||||
|
||||
const VertexList& Edge::GetVertices() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
|
||||
const FaceList& Edge::GetFaces() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return faces;
|
||||
}
|
||||
|
||||
|
||||
EdgeList Edge::GetEdges() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto result = Linq::SelectUniqueMany<Edge*>(faces, [](Face* face){ return face->GetEdges(); });
|
||||
result.Remove(const_cast<Edge*>(this));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
vec3 Edge::GetDirection() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto direction = vertices[1]->Position - vertices[0]->Position;
|
||||
direction.Normalize();
|
||||
return direction;
|
||||
}
|
||||
|
||||
|
||||
vec3 Edge::GetCenter() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return (vertices[1]->Position + vertices[0]->Position) * 0.5f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float Edge::GetLength() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto length = vertices[0]->Position - vertices[1]->Position;
|
||||
return length.GetLength();
|
||||
}
|
||||
|
||||
|
||||
Edge* Edge::GetHalfEdge(Face* face) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
|
||||
auto edges = face->GetEdges();
|
||||
auto index = edges.IndexOf(const_cast<Edge*>(this));
|
||||
auto faceVertices = face->GetVertices();
|
||||
|
||||
auto next = (index + 1) % faceVertices.Count();
|
||||
|
||||
auto newEdge = new Edge(faceVertices[index], faceVertices[next]);
|
||||
newEdge->faces = faces;
|
||||
|
||||
return newEdge;
|
||||
}
|
||||
303
meshTools/meshTools/src/core/Face.cpp
Normal file
303
meshTools/meshTools/src/core/Face.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
#include "../../include/core/Mesh.h"
|
||||
#include "../../include/core/Face.h"
|
||||
#include "../../include/core/Vertex.h"
|
||||
#include "../../include/core/Edge.h"
|
||||
|
||||
|
||||
Face::Face()
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
Face::Face(Vertex* a, Vertex* b, Vertex* c, Vertex* d)
|
||||
: materialId{ 0 }
|
||||
, uvGenerator{ nullptr }
|
||||
, mesh{ nullptr }
|
||||
{
|
||||
PERFORMANCER;
|
||||
vertices.Add(a);
|
||||
vertices.Add(b);
|
||||
vertices.Add(c);
|
||||
if (d != nullptr)
|
||||
vertices.Add(d);
|
||||
}
|
||||
|
||||
|
||||
Face::Face(const VertexList& otherVertices)
|
||||
: materialId{ 0 }
|
||||
, uvGenerator{ nullptr }
|
||||
, mesh{ nullptr }
|
||||
{
|
||||
PERFORMANCER;
|
||||
vertices = otherVertices;
|
||||
}
|
||||
|
||||
|
||||
Face::~Face()
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
vec3 Face::GetNormal() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
vec3 normal;
|
||||
|
||||
auto cnt = vertices.Count();
|
||||
for (int i = 0; i < cnt; i++)
|
||||
normal += vec3::Cross(vertices[i]->Position, vertices[(i + 1) % cnt]->Position); // cross product
|
||||
|
||||
normal.Normalize();
|
||||
return normal;
|
||||
}
|
||||
|
||||
Plane Face::GetPlane() const
|
||||
{
|
||||
return Plane(vertices[0]->Position, vertices[1]->Position, vertices[2]->Position);
|
||||
}
|
||||
|
||||
|
||||
bool Face::IsTriangle() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return vertices.Count() == 3;
|
||||
}
|
||||
|
||||
|
||||
List<Triangle> Face::GetTriangles() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
|
||||
List<Triangle> result(2);
|
||||
if (vertices.Count() == 3)
|
||||
result.Add({ vertices[0], vertices[1], vertices[2] });
|
||||
else
|
||||
{
|
||||
result.Add({ vertices[0], vertices[1], vertices[2] });
|
||||
result.Add({ vertices[2], vertices[3], vertices[0] });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
List<int> Face::GetIndices(bool allowQuads) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
|
||||
if (allowQuads)
|
||||
return Linq::Select<int>(vertices, [](Vertex* vertex) { return vertex->GetIndex(); });
|
||||
|
||||
const int quadIndices[6] =
|
||||
{
|
||||
0, 1, 2,
|
||||
2, 3, 0
|
||||
};
|
||||
const int triangleIndices[3] =
|
||||
{
|
||||
0, 1, 2
|
||||
};
|
||||
|
||||
const int* metaIndices = vertices.Count() == 3 ? triangleIndices : quadIndices;
|
||||
|
||||
List<int> result;
|
||||
for (int i = 0; i < vertices.Count(); ++i)
|
||||
result.Add(vertices[metaIndices[i]]->GetIndex());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Face::FlipNormal()
|
||||
{
|
||||
PERFORMANCER;
|
||||
vertices = Linq::Reverse(vertices);
|
||||
}
|
||||
|
||||
|
||||
void Face::FlipNormal(const vec3& dir)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (vec3::Dot(GetNormal(), dir) < 0)
|
||||
FlipNormal();
|
||||
}
|
||||
|
||||
|
||||
FaceList Face::Triangulate()
|
||||
{
|
||||
PERFORMANCER;
|
||||
FaceList result;
|
||||
if (IsTriangle() && !IsDegenerated())
|
||||
{
|
||||
result.Add(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
auto triangles = GetTriangles();
|
||||
for (const auto& triangle : triangles)
|
||||
{
|
||||
if (triangle.IsDegenerated())
|
||||
continue;
|
||||
auto newFace = new Face(triangle.GetVertices());
|
||||
newFace->CopyProperties(this);
|
||||
mesh->AddFace(newFace);
|
||||
result.Add(newFace);
|
||||
}
|
||||
mesh->RemoveFace(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Face::FlipEdge()
|
||||
{
|
||||
if (IsTriangle())
|
||||
return;
|
||||
|
||||
auto oldVertices = vertices;
|
||||
vertices.Clear();
|
||||
vertices.Add(oldVertices[1]);
|
||||
vertices.Add(oldVertices[2]);
|
||||
vertices.Add(oldVertices[3]);
|
||||
vertices.Add(oldVertices[0]);
|
||||
}
|
||||
|
||||
|
||||
bool Face::IsDegenerated() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto triangles = GetTriangles();
|
||||
for (const auto& triangle : triangles)
|
||||
if (!triangle.IsDegenerated())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Face::RegainIntegrity()
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto triangles = GetTriangles();
|
||||
for (const auto& triangle : triangles)
|
||||
if (triangle.IsDegenerated())
|
||||
{
|
||||
vertices = Linq::Distinct(vertices);
|
||||
return vertices.Count() > 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Face::CopyProperties(Face* other, bool merge)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (!merge)
|
||||
tags = other->tags;
|
||||
else
|
||||
tags = Linq::Union(tags, other->tags);
|
||||
materialId = other->materialId;
|
||||
}
|
||||
|
||||
|
||||
Mesh* Face::GetMesh() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
const VertexList& Face::GetVertices() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
|
||||
FaceList Face::GetFaces() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto result = Linq::SelectUniqueMany<Face*>(edges, [](Edge* edge){ return edge->GetFaces(); });
|
||||
result.Remove(const_cast<Face*>(this));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const EdgeList& Face::GetEdges() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return edges;
|
||||
}
|
||||
|
||||
|
||||
bool Face::HasTag(int tag) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return tags.IndexOf(tag) != -1;
|
||||
}
|
||||
|
||||
|
||||
bool Face::HasTagsAny(const List<int>& tagsToCheck) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return Linq::Intersect(tags, tagsToCheck).Count() > 0;
|
||||
}
|
||||
|
||||
|
||||
bool Face::HasTagsAll(const List<int>& tagsToCheck) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return Linq::Intersect(tags, tagsToCheck).Count() == tags.Count();
|
||||
}
|
||||
|
||||
|
||||
void Face::AddTag(int tag)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (HasTag(tag))
|
||||
return;
|
||||
tags.Add(tag);
|
||||
}
|
||||
|
||||
|
||||
void Face::RemoveTag(int tag)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (!HasTag(tag))
|
||||
return;
|
||||
tags.Remove(tag);
|
||||
}
|
||||
|
||||
|
||||
List<int> Face::GetTags() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return tags;
|
||||
}
|
||||
|
||||
|
||||
void Face::SetMaterialId(int materialId)
|
||||
{
|
||||
PERFORMANCER;
|
||||
this->materialId = materialId;
|
||||
}
|
||||
|
||||
|
||||
int Face::GetMaterialId() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return materialId;
|
||||
}
|
||||
|
||||
|
||||
void Face::SetUVGenerator(UVGeneratorBase* generator)
|
||||
{
|
||||
PERFORMANCER;
|
||||
uvGenerator = generator;
|
||||
}
|
||||
|
||||
|
||||
UVGeneratorBase* Face::GetUVGenerator() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return uvGenerator;
|
||||
}
|
||||
287
meshTools/meshTools/src/core/Mesh.cpp
Normal file
287
meshTools/meshTools/src/core/Mesh.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
#include "../../include/core/Mesh.h"
|
||||
#include "../../include/core/Face.h"
|
||||
#include "../../include/core/Edge.h"
|
||||
#include "../../include/core/Vertex.h"
|
||||
|
||||
|
||||
Mesh::Mesh()
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
Mesh::~Mesh()
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
const VertexList& Mesh::GetVertices() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
|
||||
const FaceList& Mesh::GetFaces() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return faces;
|
||||
}
|
||||
|
||||
|
||||
EdgeList Mesh::GetEdges() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return Linq::SelectUniqueMany<Edge*>(faces, [](Face* face) { return face->GetEdges(); });
|
||||
}
|
||||
|
||||
|
||||
void Mesh::AddFace(Face* faceToAdd)
|
||||
{
|
||||
PERFORMANCER;
|
||||
faceToAdd->mesh = this;
|
||||
faces.Add(faceToAdd);
|
||||
|
||||
auto& faceVertices = faceToAdd->vertices;
|
||||
auto& faceEdges = faceToAdd->edges;
|
||||
|
||||
faceEdges.Add(FindEdge(faceVertices[0], faceVertices[1]));
|
||||
faceEdges.Add(FindEdge(faceVertices[1], faceVertices[2]));
|
||||
if (faceToAdd->IsTriangle())
|
||||
faceEdges.Add(FindEdge(faceVertices[2], faceVertices[0]));
|
||||
else
|
||||
{
|
||||
faceEdges.Add(FindEdge(faceVertices[2], faceVertices[3]));
|
||||
faceEdges.Add(FindEdge(faceVertices[3], faceVertices[0]));
|
||||
}
|
||||
|
||||
for (const auto& edge : faceEdges)
|
||||
edge->faces.Add(faceToAdd);
|
||||
}
|
||||
|
||||
|
||||
// Removing a face results in an update to all affected elements of the face
|
||||
// We remove the face from the meshs face list and from all neighbourfaces, edges and vertices.
|
||||
void Mesh::RemoveFace(Face* faceToRemove)
|
||||
{
|
||||
PERFORMANCER;
|
||||
faceToRemove->mesh = nullptr;
|
||||
faces.Remove(faceToRemove);
|
||||
|
||||
auto& faceEdges = faceToRemove->edges;
|
||||
for (const auto& edge : faceEdges)
|
||||
RemoveFaceFromEdge(edge, faceToRemove);
|
||||
faceEdges.Clear();
|
||||
}
|
||||
|
||||
|
||||
Edge* Mesh::FindEdge(Vertex* a, Vertex* b)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& existingEdge : a->edges)
|
||||
for (const auto& edgeVertex : existingEdge->vertices)
|
||||
if (edgeVertex == b)
|
||||
return existingEdge;
|
||||
|
||||
Edge* newEdge = new Edge{ a, b };
|
||||
newEdge->mesh = this;
|
||||
|
||||
a->edges.Add(newEdge);
|
||||
b->edges.Add(newEdge);
|
||||
|
||||
if (a->mesh == nullptr)
|
||||
{
|
||||
a->mesh = this;
|
||||
vertices.Add(a);
|
||||
}
|
||||
|
||||
if (b->mesh == nullptr)
|
||||
{
|
||||
b->mesh = this;
|
||||
vertices.Add(b);
|
||||
}
|
||||
|
||||
return newEdge;
|
||||
}
|
||||
|
||||
|
||||
List<int> Mesh::GetIndices(bool allowQuads)
|
||||
{
|
||||
PERFORMANCER;
|
||||
UpdateIndices();
|
||||
return Linq::SelectMany<int>(faces, [allowQuads](Face* face){ return face->GetIndices(allowQuads); });
|
||||
}
|
||||
|
||||
|
||||
void Mesh::UpdateIndices()
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (int i = 0, iLength = vertices.Count(); i < iLength; ++i)
|
||||
vertices[i]->index = i;
|
||||
}
|
||||
|
||||
|
||||
FaceList Mesh::SplitEdge(Edge* edgeToSplit, Vertex* splitVertex)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto attachedFaces = edgeToSplit->faces;
|
||||
FaceList allNewFaces;
|
||||
|
||||
for (const auto& attachedFace : attachedFaces)
|
||||
{
|
||||
auto normal = attachedFace->GetNormal();
|
||||
auto faceEdges = attachedFace->edges;
|
||||
|
||||
FaceList newFaces;
|
||||
for (const auto& faceEdge : faceEdges)
|
||||
{
|
||||
if (faceEdge != edgeToSplit)
|
||||
{
|
||||
auto newFace = new Face(faceEdge->vertices[0], faceEdge->vertices[1], splitVertex);
|
||||
newFace->FlipNormal(normal);
|
||||
newFace->CopyProperties(attachedFace);
|
||||
|
||||
AddFace(newFace);
|
||||
allNewFaces.Add(newFace);
|
||||
newFaces.Add(newFace);
|
||||
}
|
||||
}
|
||||
|
||||
TriggerFaceReplaced(attachedFace, newFaces);
|
||||
RemoveFace(attachedFace);
|
||||
}
|
||||
|
||||
return allNewFaces;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::ReplaceVertexFromFaces(const FaceList& faces, Vertex* oldVertex, Vertex* newVertex)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
bool isRemoved = false;
|
||||
for (int i = 0; i < face->vertices.Count(); ++i)
|
||||
if (face->vertices[i] == oldVertex)
|
||||
{
|
||||
if (!isRemoved)
|
||||
{
|
||||
RemoveFace(face);
|
||||
isRemoved = true;
|
||||
}
|
||||
face->vertices[i] = newVertex;
|
||||
}
|
||||
|
||||
if (isRemoved)
|
||||
AddFace(face);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mesh::ReplaceVertices(const VertexList& verticesToReplace, Vertex* newVertex)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& vertex : verticesToReplace)
|
||||
{
|
||||
auto faces = vertex->GetFaces();
|
||||
ReplaceVertexFromFaces(faces, vertex, newVertex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mesh::RemoveFaceFromEdge(Edge* edge, Face* face)
|
||||
{
|
||||
PERFORMANCER;
|
||||
edge->faces.Remove(face);
|
||||
if (edge->faces.Count() == 0)
|
||||
{
|
||||
edge->mesh = nullptr;
|
||||
|
||||
for (const auto& vertex : edge->vertices)
|
||||
RemoveEdgeFromVertex(vertex, edge);
|
||||
|
||||
delete edge;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mesh::RemoveEdgeFromVertex(Vertex* vertex, Edge* edge)
|
||||
{
|
||||
PERFORMANCER;
|
||||
vertex->edges.Remove(edge);
|
||||
if (vertex->edges.Count() == 0)
|
||||
{
|
||||
vertex->mesh = nullptr;
|
||||
vertices.Remove(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Map<int, FaceList> Mesh::GetSubMeshs()
|
||||
{
|
||||
PERFORMANCER;
|
||||
UpdateIndices();
|
||||
Map<int, FaceList> groups;
|
||||
Linq::GroupBy(this->GetFaces(), groups, [](Face* face)
|
||||
{
|
||||
return face->GetMaterialId();
|
||||
});
|
||||
return groups;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::StartAutoUpdate(FaceList& faceList)
|
||||
{
|
||||
PERFORMANCER;
|
||||
autoUpdateHandles.Add(&faceList);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::StopAutoUpdate(FaceList& handle)
|
||||
{
|
||||
PERFORMANCER;
|
||||
autoUpdateHandles.Remove(&handle);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::TriggerFaceReplaced(Face* oldFace, const FaceList& newFaces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& faces : autoUpdateHandles)
|
||||
{
|
||||
auto index = faces->IndexOf(oldFace);
|
||||
if (index == -1)
|
||||
continue;
|
||||
|
||||
faces->RemoveAt(index);
|
||||
|
||||
for (auto const& newFace : newFaces)
|
||||
if (!faces->Contains(newFace))
|
||||
faces->Add(newFace);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////
|
||||
AutoFaceList::AutoFaceList(FaceList&& other)
|
||||
: FaceList(other)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
AutoFaceList::AutoFaceList(const FaceList& other)
|
||||
: FaceList(other)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
AutoFaceList::~AutoFaceList()
|
||||
{
|
||||
mesh->StopAutoUpdate(*this);
|
||||
}
|
||||
|
||||
void AutoFaceList::Init()
|
||||
{
|
||||
mesh = (*this)[0]->GetMesh();
|
||||
mesh->StartAutoUpdate(*this);
|
||||
}
|
||||
98
meshTools/meshTools/src/core/Path.cpp
Normal file
98
meshTools/meshTools/src/core/Path.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include "../../include/core/Path.h"
|
||||
|
||||
|
||||
void Path::SetPoints(const List<vec3>& points)
|
||||
{
|
||||
PERFORMANCER;
|
||||
this->points = points;
|
||||
}
|
||||
|
||||
|
||||
void Path::SetScale(const List<float>& scale)
|
||||
{
|
||||
PERFORMANCER;
|
||||
this->scale = scale;
|
||||
}
|
||||
|
||||
|
||||
void Path::SetRotation(const List<float>& rotation)
|
||||
{
|
||||
PERFORMANCER;
|
||||
this->rotation = rotation;
|
||||
}
|
||||
|
||||
|
||||
vec3 Path::GetPoint(float t) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
vec3 p1;
|
||||
vec3 p2;
|
||||
vec3 p0;
|
||||
vec3 p3;
|
||||
Path::GetValues(points, t, p0, p1, p2, p3);
|
||||
return Spline(p0, p1, p2, p3, t);
|
||||
}
|
||||
|
||||
|
||||
float Path::GetScale(float t) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (scale.Count() == 0)
|
||||
return 1.0f;
|
||||
|
||||
float p1;
|
||||
float p2;
|
||||
float p0;
|
||||
float p3;
|
||||
Path::GetValues(scale, t, p0, p1, p2, p3);
|
||||
return Math::Max(0, Spline(p0, p1, p2, p3, t));
|
||||
}
|
||||
|
||||
|
||||
float Path::GetRotation(float t) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (rotation.Count() == 0)
|
||||
return 0.0f;
|
||||
|
||||
float p1;
|
||||
float p2;
|
||||
float p0;
|
||||
float p3;
|
||||
Path::GetValues(rotation, t, p0, p1, p2, p3);
|
||||
return Spline(p0, p1, p2, p3, t);
|
||||
}
|
||||
|
||||
|
||||
vec3 Path::GetDirection(float t) const
|
||||
{
|
||||
PERFORMANCER;
|
||||
const float delta = 0.0001f;
|
||||
auto a = GetPoint(t);
|
||||
auto b = GetPoint(t + delta);
|
||||
b -= a;
|
||||
b.Normalize();
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
float Path::Spline(float p0, float p1, float p2, float p3, float t)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return 0.5f *((2 * p1) +
|
||||
(-p0 + p2) * t +
|
||||
(2 * p0 - 5 * p1 + 4 * p2 - p3) * (t*t) +
|
||||
(-p0 + 3 * p1 - 3 * p2 + p3) * (t*t*t));
|
||||
}
|
||||
|
||||
|
||||
vec3 Path::Spline(const vec3& p0, const vec3& p1, const vec3& p2, const vec3& p3, float t)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return
|
||||
{
|
||||
Spline(p0.x, p1.x, p2.x, p3.x, t),
|
||||
Spline(p0.y, p1.y, p2.y, p3.y, t),
|
||||
Spline(p0.z, p1.z, p2.z, p3.z, t)
|
||||
};
|
||||
}
|
||||
78
meshTools/meshTools/src/core/Triangle.cpp
Normal file
78
meshTools/meshTools/src/core/Triangle.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "../../include/core/Triangle.h"
|
||||
#include "../../include/core/Vertex.h"
|
||||
|
||||
Triangle::Triangle()
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
Triangle::Triangle(Vertex* a, Vertex* b, Vertex* c)
|
||||
{
|
||||
PERFORMANCER;
|
||||
vertices.Add(a);
|
||||
vertices.Add(b);
|
||||
vertices.Add(c);
|
||||
}
|
||||
|
||||
|
||||
Triangle::~Triangle()
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
vec3 Triangle::GetNormal() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto v1 = vertices[0]->Position;
|
||||
auto v2 = vertices[1]->Position;
|
||||
auto v3 = vertices[2]->Position;
|
||||
|
||||
auto normal = vec3::Cross(v2 - v1, v3 - v1);
|
||||
normal.Normalize();
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
|
||||
const List<Vertex*>& Triangle::GetVertices() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
|
||||
bool Triangle::IsDegenerated() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (vertices[0] == vertices[1] || vertices[1] == vertices[2] || vertices[2] == vertices[0])
|
||||
return true;
|
||||
|
||||
auto d = (vertices[0]->Position - vertices[1]->Position).GetLengthSq();
|
||||
if (d <= Math::FloatEpsilon)
|
||||
return true;
|
||||
|
||||
d = (vertices[1]->Position - vertices[2]->Position).GetLengthSq();
|
||||
if (d <= Math::FloatEpsilon)
|
||||
return true;
|
||||
|
||||
d = (vertices[2]->Position - vertices[0]->Position).GetLengthSq();
|
||||
if (d <= Math::FloatEpsilon)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float Triangle::GetArea() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
// http://www.iquilezles.org/blog/?p=1579
|
||||
auto a = (vertices[0]->Position - vertices[1]->Position).GetLengthSq();
|
||||
auto b = (vertices[1]->Position - vertices[2]->Position).GetLengthSq();
|
||||
auto c = (vertices[2]->Position - vertices[0]->Position).GetLengthSq();
|
||||
auto area = (2 * a*b + 2 * b*c + 2 * c*a - a*a - b*b - c*c) / 16;
|
||||
return Math::Sqrt(area);
|
||||
}
|
||||
136
meshTools/meshTools/src/core/Vertex.cpp
Normal file
136
meshTools/meshTools/src/core/Vertex.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#include "../../include/core/Vertex.h"
|
||||
#include "../../include/core/Face.h"
|
||||
#include "../../include/core/Edge.h"
|
||||
#include "../../include/core/Mesh.h"
|
||||
|
||||
Vertex::Vertex(const vec3& position)
|
||||
: index{ -1 }
|
||||
, normal{ nullptr }
|
||||
, Position{position}
|
||||
, mesh{ nullptr }
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
UV[i] = 0;
|
||||
UV2[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vertex::Vertex(Vertex* other)
|
||||
: index{ -1 }
|
||||
, normal{ nullptr }
|
||||
, Position{ other->Position }
|
||||
, mesh{ nullptr }
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
UV[i] = other->UV[i];
|
||||
UV2[i] = other->UV2[i];
|
||||
}
|
||||
|
||||
if (other->normal != nullptr)
|
||||
normal = new vec3{*other->normal};
|
||||
}
|
||||
|
||||
|
||||
Vertex::~Vertex()
|
||||
{
|
||||
PERFORMANCER;
|
||||
delete normal;
|
||||
}
|
||||
|
||||
|
||||
int Vertex::GetIndex() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
vec3 Vertex::GetNormal() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (normal == nullptr)
|
||||
{
|
||||
vec3 n;
|
||||
for (const auto& face : GetFaces())
|
||||
n += face->GetNormal();
|
||||
|
||||
n.Normalize();
|
||||
return n;
|
||||
}
|
||||
else
|
||||
return *normal;
|
||||
}
|
||||
|
||||
|
||||
void Vertex::SetNormal(const vec3& newNormal)
|
||||
{
|
||||
PERFORMANCER;
|
||||
delete normal;
|
||||
if (newNormal == vec3::zero)
|
||||
normal = nullptr;
|
||||
else
|
||||
normal = new vec3{ newNormal };
|
||||
}
|
||||
|
||||
|
||||
VertexList Vertex::GetVertices() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto result = Linq::SelectUniqueMany<Vertex*>(edges, [](Edge* edge){ return edge->GetVertices(); });
|
||||
result.Remove(const_cast<Vertex*>(this));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FaceList Vertex::GetFaces() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
FaceList result;
|
||||
for (const auto& edge : edges)
|
||||
for (const auto& face : edge->GetFaces())
|
||||
if (!result.Contains(face))
|
||||
result.Add(face);
|
||||
|
||||
//auto result = Linq::SelectUniqueMany<Face*>(edges, [](Edge* edge){ return edge->GetFaces(); });
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const EdgeList& Vertex::GetEdges() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return edges;
|
||||
}
|
||||
|
||||
|
||||
Mesh* Vertex::GetMesh() const
|
||||
{
|
||||
PERFORMANCER;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
void Vertex::Interpolate(Vertex* other, float t)
|
||||
{
|
||||
Position.x = Math::Lerp(Position.x, other->Position.x, t);
|
||||
Position.y = Math::Lerp(Position.y, other->Position.y, t);
|
||||
Position.z = Math::Lerp(Position.z, other->Position.z, t);
|
||||
|
||||
if (other->HasManualNormal() && HasManualNormal())
|
||||
{
|
||||
normal->x = Math::Lerp(normal->x, other->normal->x, t);
|
||||
normal->y = Math::Lerp(normal->y, other->normal->y, t);
|
||||
normal->z = Math::Lerp(normal->z, other->normal->z, t);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
UV[i] = Math::Lerp(UV[i], other->UV[i], t);
|
||||
UV2[i] = Math::Lerp(UV2[i], other->UV2[i], t);
|
||||
}
|
||||
}
|
||||
7
meshTools/meshTools/src/math/Math.cpp
Normal file
7
meshTools/meshTools/src/math/Math.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "../../include/math/Math.h"
|
||||
|
||||
const float Math::Rad2Deg = 57.2957795f;
|
||||
const float Math::Deg2Rad = 3.14159265359f / 180;
|
||||
const float Math::FloatEpsilon = 1E-5f;
|
||||
const float Math::Pi = 3.14159265359f;
|
||||
const float Math::Infinity = 3.402823466e+38F;
|
||||
63
meshTools/meshTools/src/math/Plane.cpp
Normal file
63
meshTools/meshTools/src/math/Plane.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "../../include/math/Plane.h"
|
||||
|
||||
Plane::Plane(const vec3& normal, const vec3& point)
|
||||
:normal { normal}
|
||||
,distance { vec3::Dot(normal, point) }
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Plane::Plane(const vec3& a, const vec3& b, const vec3& c)
|
||||
{
|
||||
normal = vec3::Cross(b-a, c - a);
|
||||
normal.Normalize();
|
||||
distance = vec3::Dot(normal, a);
|
||||
}
|
||||
|
||||
|
||||
Plane::~Plane()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
float Plane::GetDistanceToPoint(const vec3& point) const
|
||||
{
|
||||
return vec3::Dot(normal, point) - distance;
|
||||
}
|
||||
|
||||
|
||||
vec3 Plane::GetNormal() const
|
||||
{
|
||||
return normal;
|
||||
}
|
||||
|
||||
|
||||
float Plane::GetDistance() const
|
||||
{
|
||||
return distance;
|
||||
}
|
||||
|
||||
|
||||
bool Plane::GetSide(const vec3& point) const
|
||||
{
|
||||
return GetDistanceToPoint(point) > 0.0;
|
||||
}
|
||||
|
||||
|
||||
void Plane::Flip()
|
||||
{
|
||||
normal = -normal;
|
||||
distance = -distance;
|
||||
}
|
||||
|
||||
|
||||
float Plane::IntersectLinesegment(vec3 a, vec3 b, vec3& result) const
|
||||
{
|
||||
auto ba = b - a;
|
||||
float nDotA = vec3::Dot(normal, a);
|
||||
float nDotBA = vec3::Dot(normal, ba);
|
||||
|
||||
auto d = (distance - nDotA) / nDotBA;
|
||||
result = a + (ba * d);
|
||||
return d;
|
||||
}
|
||||
112
meshTools/meshTools/src/math/Quaternion.cpp
Normal file
112
meshTools/meshTools/src/math/Quaternion.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "../../include/math/Quaternion.h"
|
||||
#include "../../include/math/Math.h"
|
||||
#include "../../include/math/vec3.h"
|
||||
|
||||
Quaternion Quaternion::identity;
|
||||
|
||||
|
||||
Quaternion::Quaternion()
|
||||
: x{ 0 }
|
||||
, y{ 0 }
|
||||
, z{ 0 }
|
||||
, w{ 1 }
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Quaternion Quaternion::CreateFromAxisAngle(const vec3& axis, float angle)
|
||||
{
|
||||
float halfAngle = angle * .5f;
|
||||
float s = (float)Math::Sin(halfAngle);
|
||||
Quaternion q;
|
||||
q.x = axis.x * s;
|
||||
q.y = axis.y * s;
|
||||
q.z = axis.z * s;
|
||||
q.w = (float)Math::Cos(halfAngle);
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
Quaternion Quaternion::LookRotation(const vec3& forward)
|
||||
{
|
||||
float dot = vec3::Dot(vec3::up, forward);
|
||||
|
||||
if (Math::Abs(dot - (-1.0f)) < 0.000001f)
|
||||
{
|
||||
return CreateFromAxisAngle(vec3::forward, Math::Pi);
|
||||
}
|
||||
if (Math::Abs(dot - (1.0f)) < 0.000001f)
|
||||
{
|
||||
return Quaternion::identity;
|
||||
}
|
||||
|
||||
float rotAngle = (float)Math::Acos(dot);
|
||||
vec3 rotAxis = vec3::Cross(vec3::up, forward);
|
||||
rotAxis.Normalize();
|
||||
|
||||
return CreateFromAxisAngle(rotAxis, rotAngle);
|
||||
}
|
||||
|
||||
|
||||
Quaternion Quaternion::FromTo(vec3 v0, vec3 v1)
|
||||
{
|
||||
Quaternion q;
|
||||
v0.Normalize();
|
||||
v1.Normalize();
|
||||
|
||||
float d = vec3::Dot(v0, v1);
|
||||
// If dot == 1, vectors are the same
|
||||
if (d >= 1.0f)
|
||||
{
|
||||
return Quaternion::identity;
|
||||
}
|
||||
if (d < (1e-6f - 1.0f))
|
||||
{
|
||||
vec3 axis = vec3::Cross(vec3::right, v0);
|
||||
if (axis.GetLengthSq() < Math::FloatEpsilon) // pick another if colinear
|
||||
axis = vec3::Cross(vec3::up, v0);
|
||||
axis.Normalize();
|
||||
return Quaternion::CreateFromAxisAngle(axis, Math::Pi);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto s = Math::Sqrt((1 + d) * 2);
|
||||
auto invs = 1 / s;
|
||||
|
||||
auto c = vec3::Cross(v0, v1);
|
||||
|
||||
q.x = c.x * invs;
|
||||
q.y = c.y * invs;
|
||||
q.z = c.z * invs;
|
||||
q.w = s * 0.5f;
|
||||
q.Normalize();
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
void Quaternion::Inverse()
|
||||
{
|
||||
auto newX = w;
|
||||
auto newY = -x;
|
||||
auto newZ = -y;
|
||||
auto newW = -z;
|
||||
x = newX;
|
||||
y = newY;
|
||||
z = newZ;
|
||||
w = newW;
|
||||
|
||||
Normalize();
|
||||
}
|
||||
|
||||
|
||||
void Quaternion::Normalize()
|
||||
{
|
||||
auto norm = w*w + x*x + y*y + z*z;
|
||||
auto s = 1 / norm;
|
||||
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
w *= s;
|
||||
}
|
||||
207
meshTools/meshTools/src/math/vec3.cpp
Normal file
207
meshTools/meshTools/src/math/vec3.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include "../../include/math/vec3.h"
|
||||
#include "../../include/math/Math.h"
|
||||
|
||||
vec3 const vec3::zero = {0, 0, 0};
|
||||
vec3 const vec3::one = {1,1,1};
|
||||
vec3 const vec3::up = {0, 1, 0};
|
||||
vec3 const vec3::down = {0, -1, 0};
|
||||
vec3 const vec3::left = {-1, 0, 0};
|
||||
vec3 const vec3::right = {1, 0, 0};
|
||||
vec3 const vec3::forward = {0, 0, 1};
|
||||
vec3 const vec3::back = {0, 0, -1};
|
||||
|
||||
vec3::vec3()
|
||||
: x{0}
|
||||
, y{0}
|
||||
, z{0}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
vec3::vec3(float x, float y, float z)
|
||||
: x{ x }
|
||||
, y{ y }
|
||||
, z{ z }
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
vec3::vec3(const vec3& other)
|
||||
: x{ other.x }
|
||||
, y{ other.y }
|
||||
, z{ other.z }
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
vec3::~vec3()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
float vec3::GetLength() const
|
||||
{
|
||||
return Math::Sqrt(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
|
||||
float vec3::GetLengthSq() const
|
||||
{
|
||||
return x*x + y*y + z*z;
|
||||
}
|
||||
|
||||
|
||||
void vec3::Normalize()
|
||||
{
|
||||
auto length = GetLength();
|
||||
if (length == 0)
|
||||
{
|
||||
x = y = z = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
x /= length;
|
||||
y /= length;
|
||||
z /= length;
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::Mul(const vec3& a, const vec3& b)
|
||||
{
|
||||
return vec3(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||
}
|
||||
|
||||
|
||||
float vec3::Dot(const vec3& a, const vec3& b)
|
||||
{
|
||||
float result = 0;
|
||||
result += a.x * b.x;
|
||||
result += a.y * b.y;
|
||||
result += a.z * b.z;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::Cross(const vec3& a, const vec3& b)
|
||||
{
|
||||
return vec3(
|
||||
a.y * b.z - a.z * b.y,
|
||||
a.z * b.x - a.x * b.z,
|
||||
a.x * b.y - a.y * b.x
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::Min(const vec3& a, const vec3& b)
|
||||
{
|
||||
return {
|
||||
Math::Min(a.x, b.x),
|
||||
Math::Min(a.y, b.y),
|
||||
Math::Min(a.z, b.z),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::Max(const vec3& a, const vec3& b)
|
||||
{
|
||||
return{
|
||||
Math::Max(a.x, b.x),
|
||||
Math::Max(a.y, b.y),
|
||||
Math::Max(a.z, b.z),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
float vec3::Distance(const vec3& a, const vec3& b)
|
||||
{
|
||||
return (a - b).GetLength();
|
||||
}
|
||||
|
||||
|
||||
float vec3::DistanceSq(const vec3& a, const vec3& b)
|
||||
{
|
||||
return (a - b).GetLengthSq();
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::operator- () const
|
||||
{
|
||||
return{ -x, -y, -z };
|
||||
}
|
||||
|
||||
|
||||
bool vec3::operator== (const vec3& other) const
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
|
||||
|
||||
bool vec3::operator!= (const vec3& other) const
|
||||
{
|
||||
return x != other.x || y != other.y || z != other.z;
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::operator+ (const vec3& other) const
|
||||
{
|
||||
return{ x + other.x, y + other.y, z + other.z };
|
||||
}
|
||||
|
||||
|
||||
void vec3::operator+= (const vec3& other)
|
||||
{
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
}
|
||||
|
||||
|
||||
void vec3::operator-= (const vec3& other)
|
||||
{
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
}
|
||||
|
||||
|
||||
void vec3::operator/= (float other)
|
||||
{
|
||||
x /= other;
|
||||
y /= other;
|
||||
z /= other;
|
||||
}
|
||||
|
||||
|
||||
void vec3::operator*= (float other)
|
||||
{
|
||||
x *= other;
|
||||
y *= other;
|
||||
z *= other;
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::operator- (const vec3& other) const
|
||||
{
|
||||
return{ x - other.x, y - other.y, z - other.z };
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::operator* (float other) const
|
||||
{
|
||||
return{ x * other, y * other, z * other };
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::operator/ (float other) const
|
||||
{
|
||||
return{ x / other, y / other, z / other };
|
||||
}
|
||||
|
||||
|
||||
vec3 vec3::operator* (const Quaternion& q) const
|
||||
{
|
||||
vec3 qxyz = { q.x, q.y, q.z };
|
||||
auto t = vec3::Cross(qxyz, *this) * 2;
|
||||
return *this + t * q.w + vec3::Cross(qxyz, t);
|
||||
}
|
||||
51
meshTools/meshTools/src/tools/CSG.cpp
Normal file
51
meshTools/meshTools/src/tools/CSG.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "../../include/tools/CSG.h"
|
||||
#include "../../include/tools/Delete.h"
|
||||
#include "../../include/tools/Triangulate.h"
|
||||
#include "../../include/tools/Copy.h"
|
||||
#include "../../include/tools/CSGBase.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
Mesh* CsgOperation(const FaceList& a, const FaceList& b, mt::CSG* (mt::CSG::*func)(mt::CSG*))
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (a.Count() == 0 || b.Count() == 0)
|
||||
return{};
|
||||
|
||||
auto tmpA = mt::Triangulate(mt::Copy(a));
|
||||
auto tmpB = mt::Triangulate(mt::Copy(b));
|
||||
|
||||
auto csgA = mt::CSG::FromPolygons(tmpA);
|
||||
auto csgB = mt::CSG::FromPolygons(tmpB);
|
||||
|
||||
auto csgResult = (csgA->*func)(csgB);
|
||||
|
||||
auto result = mt::ToMesh(csgResult->GetFaces());
|
||||
delete csgA;
|
||||
delete csgB;
|
||||
delete csgResult;
|
||||
|
||||
mt::Delete(tmpA);
|
||||
mt::Delete(tmpB);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Mesh* CsgUnion(const FaceList& a, const FaceList& b)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return CsgOperation(a, b, &CSG::Union);
|
||||
}
|
||||
|
||||
Mesh* CsgSubtract(const FaceList& a, const FaceList& b)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return CsgOperation(a, b, &CSG::Subtract);
|
||||
}
|
||||
|
||||
Mesh* CsgIntersect(const FaceList& a, const FaceList& b)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return CsgOperation(a, b, &CSG::Intersect);
|
||||
}
|
||||
}
|
||||
296
meshTools/meshTools/src/tools/CSGBase.cpp
Normal file
296
meshTools/meshTools/src/tools/CSGBase.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
#include "../../include/tools/CSGBase.h"
|
||||
#include "../../include/tools/Flip.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
enum FaceSplitState : int
|
||||
{
|
||||
Coplanar,
|
||||
Front,
|
||||
Back,
|
||||
Spanning
|
||||
};
|
||||
|
||||
void SplitFace(Face* face, const Plane& plane, FaceList& coplanarFront, FaceList& coplanarBack, FaceList& front, FaceList& back)
|
||||
{
|
||||
PERFORMANCER;
|
||||
const float EPSILON = 0.00001f;
|
||||
|
||||
const auto& vertices = face->GetVertices();
|
||||
int polygonType = 0;
|
||||
FaceSplitState types[4];
|
||||
for (int i = 0; i < vertices.Count(); ++i)
|
||||
{
|
||||
auto vertex = vertices[i];
|
||||
|
||||
auto t = vec3::Dot(plane.GetNormal(), vertex->Position) - plane.GetDistance();
|
||||
auto type = (t < -EPSILON) ? FaceSplitState::Back : (t > EPSILON) ? FaceSplitState::Front : FaceSplitState::Coplanar;
|
||||
polygonType |= type;
|
||||
types[i] = type;
|
||||
}
|
||||
|
||||
switch (polygonType)
|
||||
{
|
||||
case FaceSplitState::Coplanar:
|
||||
(vec3::Dot(plane.GetNormal(), face->GetPlane().GetNormal()) > 0 ? coplanarFront : coplanarBack).Add(face);
|
||||
break;
|
||||
case FaceSplitState::Front:
|
||||
front.Add(face);
|
||||
break;
|
||||
case FaceSplitState::Back:
|
||||
back.Add(face);
|
||||
break;
|
||||
case FaceSplitState::Spanning:
|
||||
VertexList f;
|
||||
VertexList b;
|
||||
for (int i = 0; i < vertices.Count(); ++i)
|
||||
{
|
||||
auto j = (i + 1) % vertices.Count();
|
||||
auto ti = types[i];
|
||||
auto tj = types[j];
|
||||
auto vi = vertices[i];
|
||||
auto vj = vertices[j];
|
||||
if (ti != FaceSplitState::Back)
|
||||
f.Add(vi);
|
||||
if (ti != FaceSplitState::Front)
|
||||
b.Add(vi);// ti != FaceSplitState::Back ? new Vertex(vi) : vi);
|
||||
if ((ti | tj) == FaceSplitState::Spanning)
|
||||
{
|
||||
auto t = (plane.GetDistance() - vec3::Dot(plane.GetNormal(), vi->Position)) / vec3::Dot(plane.GetNormal(), vj->Position - vi->Position);
|
||||
auto v = new Vertex(vi);
|
||||
v->Interpolate(vj, t);
|
||||
f.Add(v);
|
||||
b.Add(v);// new Vertex(v));
|
||||
}
|
||||
}
|
||||
if (f.Count() == 3)
|
||||
front.Add(new Face(f));
|
||||
else if (f.Count() == 4)
|
||||
{
|
||||
front.Add(new Face(f[0], f[1], f[2]));
|
||||
front.Add(new Face(f[2], f[3], f[0]));
|
||||
}
|
||||
|
||||
if (b.Count() == 3)
|
||||
back.Add(new Face(b));
|
||||
else if (b.Count() == 4)
|
||||
{
|
||||
back.Add(new Face(b[0], b[1], b[2]));
|
||||
back.Add(new Face(b[2], b[3], b[0]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CSG* CSG::FromPolygons(const FaceList& faces)
|
||||
{
|
||||
auto csg = new CSG();
|
||||
csg->faces = faces;
|
||||
return csg;
|
||||
}
|
||||
|
||||
|
||||
CSG* CSG::Clone()
|
||||
{
|
||||
auto csg = new CSG();
|
||||
csg->faces = faces;// mt::Clone(faces);
|
||||
|
||||
return csg;
|
||||
}
|
||||
|
||||
|
||||
CSG* CSG::Inverse()
|
||||
{
|
||||
auto csg = Clone();
|
||||
for (const auto& face : csg->faces)
|
||||
face->FlipNormal();
|
||||
|
||||
return csg;
|
||||
}
|
||||
|
||||
|
||||
const FaceList& CSG::GetFaces() const
|
||||
{
|
||||
return faces;
|
||||
}
|
||||
|
||||
|
||||
CSG* CSG::Union(CSG* other)
|
||||
{
|
||||
auto a = new CSGNode(Clone()->faces);
|
||||
auto b = new CSGNode(other->Clone()->faces);
|
||||
a->ClipTo(b);
|
||||
b->ClipTo(a);
|
||||
b->Invert();
|
||||
b->ClipTo(a);
|
||||
b->Invert();
|
||||
a->Build(b->AllPolygons());
|
||||
return CSG::FromPolygons(a->AllPolygons());
|
||||
}
|
||||
|
||||
|
||||
CSG* CSG::Subtract(CSG* other)
|
||||
{
|
||||
auto a = new CSGNode(Clone()->faces);
|
||||
auto b = new CSGNode(other->Clone()->faces);
|
||||
a->Invert();
|
||||
a->ClipTo(b);
|
||||
b->ClipTo(a);
|
||||
b->Invert();
|
||||
b->ClipTo(a);
|
||||
b->Invert();
|
||||
a->Build(b->AllPolygons());
|
||||
a->Invert();
|
||||
return CSG::FromPolygons(a->AllPolygons());
|
||||
}
|
||||
|
||||
|
||||
CSG* CSG::Intersect(CSG* other)
|
||||
{
|
||||
auto a = new CSGNode(Clone()->faces);
|
||||
auto b = new CSGNode(other->Clone()->faces);
|
||||
a->Invert();
|
||||
b->ClipTo(a);
|
||||
b->Invert();
|
||||
a->ClipTo(b);
|
||||
b->ClipTo(a);
|
||||
a->Build(b->AllPolygons());
|
||||
a->Invert();
|
||||
return CSG::FromPolygons(a->AllPolygons());
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSGNode::CSGNode()
|
||||
: front{ nullptr }
|
||||
, back{ nullptr }
|
||||
, plane{ nullptr }
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
|
||||
CSGNode::CSGNode(const FaceList& faces)
|
||||
: CSGNode()
|
||||
{
|
||||
PERFORMANCER;
|
||||
this->Build(faces);
|
||||
}
|
||||
|
||||
|
||||
CSGNode::~CSGNode()
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (plane)
|
||||
delete plane;
|
||||
if (front)
|
||||
delete front;
|
||||
if (back)
|
||||
delete back;
|
||||
}
|
||||
|
||||
|
||||
CSGNode* CSGNode::Clone()
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto node = new CSGNode();
|
||||
|
||||
node->plane = plane ? new Plane(*plane) : nullptr;
|
||||
node->front = front ? front->Clone() : nullptr;
|
||||
node->back = back ? back->Clone() : nullptr;
|
||||
node->faces = faces;// mt::Clone(faces);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
void CSGNode::Invert()
|
||||
{
|
||||
PERFORMANCER;
|
||||
mt::FlipSides(faces);
|
||||
if (plane)
|
||||
plane->Flip();
|
||||
if (front)
|
||||
front->Invert();
|
||||
if (back)
|
||||
back->Invert();
|
||||
|
||||
auto temp = front;
|
||||
front = back;
|
||||
back = temp;
|
||||
}
|
||||
|
||||
|
||||
FaceList CSGNode::ClipPolygons(const FaceList& other)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (!plane)
|
||||
return other;
|
||||
FaceList front;
|
||||
FaceList back;
|
||||
|
||||
for (const auto& face : other)
|
||||
SplitFace(face, *plane, front, back, front, back);
|
||||
|
||||
if (this->front)
|
||||
front = this->front->ClipPolygons(front);
|
||||
if (this->back)
|
||||
back = this->back->ClipPolygons(back);
|
||||
else
|
||||
back.Clear();
|
||||
return Linq::Concat(front, back);
|
||||
}
|
||||
|
||||
|
||||
void CSGNode::ClipTo(CSGNode* other)
|
||||
{
|
||||
PERFORMANCER;
|
||||
faces = other->ClipPolygons(faces);
|
||||
if (front)
|
||||
front->ClipTo(other);
|
||||
if (back)
|
||||
back->ClipTo(other);
|
||||
}
|
||||
|
||||
FaceList CSGNode::AllPolygons()
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto result = faces;
|
||||
if (front)
|
||||
result = Linq::Concat(result, front->AllPolygons());
|
||||
if (back)
|
||||
result = Linq::Concat(result, back->AllPolygons());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void CSGNode::Build(const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (faces.Count() == 0)
|
||||
return;
|
||||
if (!plane)
|
||||
plane = new Plane(faces[0]->GetPlane());
|
||||
|
||||
FaceList front;
|
||||
FaceList back;
|
||||
|
||||
for (const auto& face : faces)
|
||||
SplitFace(face, *plane, this->faces, this->faces, front, back);
|
||||
|
||||
if (front.Count() != 0)
|
||||
{
|
||||
if (!this->front)
|
||||
this->front = new CSGNode();
|
||||
this->front->Build(front);
|
||||
}
|
||||
if (back.Count() != 0)
|
||||
{
|
||||
if (!this->back)
|
||||
this->back = new CSGNode();
|
||||
this->back->Build(back);
|
||||
}
|
||||
}
|
||||
}
|
||||
110
meshTools/meshTools/src/tools/Calculate.cpp
Normal file
110
meshTools/meshTools/src/tools/Calculate.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "../../include/tools/Calculate.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
Bounds GetBoundingBox(const VertexList& vertices)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (vertices.Count() == 0)
|
||||
return{ vec3::zero, vec3::zero };
|
||||
|
||||
auto min = vertices[0]->Position;
|
||||
auto max = min;
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
min = vec3::Min(vertex->Position, min);
|
||||
max = vec3::Max(vertex->Position, max);
|
||||
}
|
||||
|
||||
return{ min, max };
|
||||
}
|
||||
|
||||
|
||||
vec3 GetNormal(const VertexList& vertices)
|
||||
{
|
||||
PERFORMANCER;
|
||||
vec3 normal;
|
||||
if (vertices.Count() != 0)
|
||||
{
|
||||
for (const auto& vertex : vertices)
|
||||
normal += vertex->GetNormal();
|
||||
normal.Normalize();
|
||||
}
|
||||
return normal;
|
||||
}
|
||||
|
||||
|
||||
vec3 GetNormal(const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
vec3 normal;
|
||||
if (faces.Count() != 0)
|
||||
{
|
||||
for (const auto& face: faces)
|
||||
normal += face->GetNormal();
|
||||
normal.Normalize();
|
||||
}
|
||||
return normal;
|
||||
}
|
||||
|
||||
|
||||
vec3 GetCenter(const VertexList& vertices)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto bounds = GetBoundingBox(vertices);
|
||||
return bounds.GetCenter();
|
||||
}
|
||||
|
||||
|
||||
EdgeList GetHalfEdges(const EdgeList& edges, const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
List<Edge*> result;
|
||||
for (const auto& edge : edges)
|
||||
{
|
||||
auto edgeFaces = edge->GetFaces();
|
||||
Face* relevantFace = nullptr;
|
||||
for (const auto& edgeFace : edgeFaces)
|
||||
{
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
if (face == edgeFace)
|
||||
{
|
||||
relevantFace = edgeFace;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (relevantFace != nullptr)
|
||||
break;
|
||||
}
|
||||
|
||||
result.Add(edge->GetHalfEdge(relevantFace));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
EdgeList GetOutlineEdges(const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto faceSet = Linq::ToSet(faces);
|
||||
|
||||
EdgeList outlineEdges;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
for (const auto& edge : face->GetEdges())
|
||||
{
|
||||
auto edgeFaces = edge->GetFaces();
|
||||
if (edgeFaces.Count() > 1)
|
||||
for (const auto& edgeFace : edgeFaces)
|
||||
if (edgeFace != face && faceSet.ContainsKey(edgeFace))
|
||||
goto fastBreak;
|
||||
outlineEdges.Add(edge);
|
||||
fastBreak:; // soooo ugly
|
||||
}
|
||||
}
|
||||
|
||||
return outlineEdges;
|
||||
}
|
||||
}
|
||||
109
meshTools/meshTools/src/tools/Copy.cpp
Normal file
109
meshTools/meshTools/src/tools/Copy.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "../../include/tools/Copy.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Transform.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
FaceList CreateCopy(const FaceList& faces, Mesh* outMesh)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (faces.Count() == 0)
|
||||
return{};
|
||||
|
||||
auto vertices = mt::GetVertices(faces);
|
||||
|
||||
Map<Vertex*, Vertex*> originalToClone;
|
||||
for (const auto& vertex : vertices)
|
||||
originalToClone.Add(vertex, new Vertex(vertex));
|
||||
|
||||
FaceList newFaces;
|
||||
|
||||
auto mesh = outMesh ? outMesh : faces[0]->GetMesh();
|
||||
//mesh.Materials = Owner.Materials;
|
||||
|
||||
for (const auto& face : (FaceList)faces)
|
||||
{
|
||||
Face* newFace;
|
||||
auto vertices = face->GetVertices();
|
||||
|
||||
if (face->IsTriangle())
|
||||
newFace = new Face(
|
||||
originalToClone[vertices[0]],
|
||||
originalToClone[vertices[1]],
|
||||
originalToClone[vertices[2]]
|
||||
);
|
||||
else
|
||||
newFace = new Face(
|
||||
originalToClone[vertices[0]],
|
||||
originalToClone[vertices[1]],
|
||||
originalToClone[vertices[2]],
|
||||
originalToClone[vertices[3]]
|
||||
);
|
||||
|
||||
newFace->CopyProperties(face);
|
||||
newFaces.Add(newFace);
|
||||
mesh->AddFace(newFace);
|
||||
}
|
||||
|
||||
return newFaces;
|
||||
}
|
||||
|
||||
|
||||
FaceList CopyToMesh(const FaceList& faces, Mesh* target)
|
||||
{
|
||||
PERFORMANCER;
|
||||
const auto& vertices = mt::GetVertices(faces);
|
||||
|
||||
Map<Vertex*, Vertex*> originalToClone;
|
||||
for (const auto& vertex : vertices)
|
||||
originalToClone.Add(vertex, new Vertex(vertex));
|
||||
|
||||
FaceList newFaces;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
if (face->GetMesh() == target)
|
||||
{
|
||||
newFaces.Add(face);
|
||||
continue;
|
||||
}
|
||||
auto faceVertices = face->GetVertices();
|
||||
Face* newFace;
|
||||
if (face->IsTriangle())
|
||||
newFace = new Face(
|
||||
originalToClone[faceVertices[0]],
|
||||
originalToClone[faceVertices[1]],
|
||||
originalToClone[faceVertices[2]]);
|
||||
else
|
||||
newFace = new Face(
|
||||
originalToClone[faceVertices[0]],
|
||||
originalToClone[faceVertices[1]],
|
||||
originalToClone[faceVertices[2]],
|
||||
originalToClone[faceVertices[3]]);
|
||||
|
||||
newFace->CopyProperties(face);
|
||||
newFaces.Add(newFace);
|
||||
|
||||
target->AddFace(newFace);
|
||||
}
|
||||
|
||||
return newFaces;
|
||||
}
|
||||
|
||||
|
||||
FaceList Copy(const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return CreateCopy(faces, nullptr);
|
||||
}
|
||||
|
||||
|
||||
Mesh* ToMesh(const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto mesh = new Mesh();
|
||||
CreateCopy(faces, mesh);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
14
meshTools/meshTools/src/tools/Delete.cpp
Normal file
14
meshTools/meshTools/src/tools/Delete.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "../../include/tools/Delete.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Transform.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
void Delete(const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& face : (FaceList)faces)
|
||||
face->GetMesh()->RemoveFace(face);
|
||||
}
|
||||
}
|
||||
96
meshTools/meshTools/src/tools/Detach.cpp
Normal file
96
meshTools/meshTools/src/tools/Detach.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "../../include/tools/Detach.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Transform.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
Vertex* CloneVertex(Map<Vertex*, Vertex*>& parentToCloneVertices, Vertex* oldVertex, bool& isNewVertex)
|
||||
{
|
||||
PERFORMANCER;
|
||||
Vertex* newVertex;
|
||||
if (parentToCloneVertices.TryGetValue(oldVertex, newVertex))
|
||||
return newVertex;
|
||||
|
||||
newVertex = new Vertex(oldVertex);
|
||||
parentToCloneVertices.Add(oldVertex, newVertex);
|
||||
|
||||
return newVertex;
|
||||
}
|
||||
|
||||
Map<Vertex*, Vertex*> Detach(const FaceList& faces, bool preserveVertexNormals, EdgeList* outline)
|
||||
{
|
||||
PERFORMANCER;
|
||||
bool customOutline = outline != nullptr;
|
||||
if (!customOutline)
|
||||
{
|
||||
outline = new List<Edge*>();
|
||||
*outline = mt::GetOutlineEdges(faces);
|
||||
}
|
||||
|
||||
Map<Vertex*, vec3> parentToNormals;
|
||||
Map<Vertex*, Vertex*> parentToCloneVertices;
|
||||
|
||||
if (preserveVertexNormals)
|
||||
{
|
||||
auto vertices = Linq::SelectUniqueMany<Vertex*>(*outline, [](Edge* edge){ return edge->GetVertices(); });
|
||||
for (const auto& vertex : vertices)
|
||||
parentToNormals.Add(vertex, vertex->GetNormal());
|
||||
}
|
||||
|
||||
for (const auto& edge : *outline)
|
||||
{
|
||||
auto edgeVertices = edge->GetVertices();
|
||||
auto original0 = edgeVertices[0];
|
||||
auto original1 = edgeVertices[1];
|
||||
|
||||
bool isNewVertex0;
|
||||
bool isNewVertex1;
|
||||
|
||||
auto clone0 = CloneVertex(parentToCloneVertices, original0, isNewVertex0);
|
||||
auto clone1 = CloneVertex(parentToCloneVertices, original1, isNewVertex1);
|
||||
if (preserveVertexNormals)
|
||||
{
|
||||
if (isNewVertex0 && parentToNormals.ContainsKey(original0))
|
||||
clone0->SetNormal(parentToNormals[original0]);
|
||||
if (isNewVertex1 && parentToNormals.ContainsKey(original1))
|
||||
clone1->SetNormal(parentToNormals[original1]);
|
||||
}
|
||||
|
||||
original0->GetMesh()->ReplaceVertexFromFaces(faces, original0, clone0);
|
||||
original1->GetMesh()->ReplaceVertexFromFaces(faces, original1, clone1);
|
||||
}
|
||||
|
||||
if (!customOutline)
|
||||
delete outline;
|
||||
|
||||
return parentToCloneVertices;
|
||||
}
|
||||
|
||||
void DetachAll(const FaceList& faces, bool preserveVertexNormals)
|
||||
{
|
||||
PERFORMANCER;
|
||||
Map<Vertex*, vec3> parentToNormals;
|
||||
|
||||
if (preserveVertexNormals)
|
||||
{
|
||||
for (const auto& vertex : mt::GetVertices(faces))
|
||||
parentToNormals.Add(vertex, vertex->GetNormal());
|
||||
}
|
||||
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
auto vertices = face->GetVertices();
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
auto newVertex = new Vertex(vertex);
|
||||
if (preserveVertexNormals && parentToNormals.ContainsKey(vertex))
|
||||
newVertex->SetNormal(parentToNormals[vertex]);
|
||||
|
||||
List<Face*> tmpFaces;
|
||||
tmpFaces.Add(face);
|
||||
vertex->GetMesh()->ReplaceVertexFromFaces(tmpFaces, vertex, newVertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
163
meshTools/meshTools/src/tools/Extrude.cpp
Normal file
163
meshTools/meshTools/src/tools/Extrude.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "../../include/tools/Extrude.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Transform.h"
|
||||
#include "../../include/tools/Detach.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
FaceList ExtrudeVertices(const VertexList& vertices, float sideEdgeLength, float extrudeHeight)
|
||||
{
|
||||
PERFORMANCER;
|
||||
Map<Vertex*, vec3> vertexNormals;
|
||||
for (const auto& vertex : vertices)
|
||||
vertexNormals.Add(vertex, vertex->GetNormal());
|
||||
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
auto vertexEdges = vertex->GetEdges();
|
||||
for (const auto& edge : vertexEdges)
|
||||
{
|
||||
auto otherEdgeVertex = edge->GetOtherVertex(vertex);
|
||||
auto direction = otherEdgeVertex->Position - vertex->Position;
|
||||
auto length = direction.GetLength();
|
||||
if (length == 0)
|
||||
continue;
|
||||
|
||||
direction.Normalize();
|
||||
length = Math::Min(length, sideEdgeLength);
|
||||
|
||||
auto splitVertex = new Vertex(vertex->Position + direction * length);
|
||||
|
||||
vertex->GetMesh()->SplitEdge(edge, splitVertex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<Face*> newFaces;
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
auto normal = vertexNormals[vertex];
|
||||
vertex->Position += normal * extrudeHeight;
|
||||
}
|
||||
|
||||
return newFaces;
|
||||
}
|
||||
|
||||
|
||||
FaceList Extrude(const FaceList& faces, float factor, MoveMode mode)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return Bevel(faces, factor, 1.0f, mode);
|
||||
}
|
||||
|
||||
|
||||
FaceList Extrude(const FaceList& faces, const vec3& extrudeDirection)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return Bevel(faces, extrudeDirection, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
FaceList Bevel(const FaceList& faces, const vec3& extrudeDirection, float capScale)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return Bevel(faces, 0.0f, capScale, MoveMode::UseCollectionNormal, &extrudeDirection);
|
||||
}
|
||||
|
||||
|
||||
FaceList Bevel(const FaceList& faces, float factor, float capScale, MoveMode mode, const vec3* extrudeDirectionOverride)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (mode == MoveMode::UseCollectionNormal && extrudeDirectionOverride == nullptr && mt::GetNormal(mt::GetVertices(faces)) == vec3::zero)
|
||||
return{};
|
||||
|
||||
auto oldOutlineEdges = mt::GetHalfEdges(mt::GetOutlineEdges(faces), faces);
|
||||
|
||||
auto oldToNewVertices = mt::Detach(faces, false, &oldOutlineEdges);
|
||||
|
||||
auto newOutlineEdges = mt::GetHalfEdges(mt::GetOutlineEdges(faces), faces);
|
||||
const auto& vertices = mt::GetVertices(faces);
|
||||
|
||||
if (extrudeDirectionOverride != nullptr)
|
||||
mt::MoveBy(vertices, *extrudeDirectionOverride);
|
||||
else
|
||||
mt::MoveBy(vertices, factor, mode);
|
||||
if (capScale != 1.0f)
|
||||
mt::Scale(vertices, capScale, mt::CenterMode::FaceCenter);
|
||||
|
||||
FaceList sideFaces;
|
||||
Map<Vertex*, Vertex*> parentToCloneVertices;
|
||||
for (int i = 0; i < newOutlineEdges.Count(); ++i)
|
||||
{
|
||||
auto oldEdge = oldOutlineEdges[i];
|
||||
auto newEdge = newOutlineEdges[i];
|
||||
|
||||
Face* relevantFace = nullptr;
|
||||
for (const auto& face : newEdge->GetFaces())
|
||||
if (faces.Contains(face))
|
||||
{
|
||||
relevantFace = face;
|
||||
break;
|
||||
}
|
||||
|
||||
auto oldEdgeVertices = oldEdge->GetVertices();
|
||||
|
||||
auto original0 = oldEdgeVertices[0];
|
||||
auto original1 = oldEdgeVertices[1];
|
||||
|
||||
auto target0 = oldToNewVertices[oldEdgeVertices[0]];
|
||||
auto target1 = oldToNewVertices[oldEdgeVertices[1]];
|
||||
|
||||
Face* sideFace;
|
||||
if (factor < 0)
|
||||
sideFace = new Face(target1, target0, original0, original1);
|
||||
else
|
||||
sideFace = new Face(original0, original1, target1, target0);
|
||||
|
||||
sideFace->CopyProperties(relevantFace);
|
||||
sideFaces.Add(sideFace);
|
||||
|
||||
relevantFace->GetMesh()->AddFace(sideFace);
|
||||
}
|
||||
|
||||
return sideFaces;
|
||||
}
|
||||
|
||||
|
||||
List<FaceList> Loft(const FaceList& faces, const Path& path, int segments)
|
||||
{
|
||||
PERFORMANCER;
|
||||
List<FaceList> result;
|
||||
|
||||
for (int segment = 0; segment < segments; ++segment)
|
||||
{
|
||||
auto progress = (1.0f + segment) / segments;
|
||||
|
||||
auto sides = mt::Extrude(faces, 1);
|
||||
|
||||
if (segment == 0)
|
||||
{
|
||||
FaceList tmp;
|
||||
for (int i = 0; i < sides.Count(); ++i)
|
||||
result.Add(tmp);
|
||||
}
|
||||
for (int i = 0; i < sides.Count(); ++i)
|
||||
result[i].Add(sides[i]);
|
||||
|
||||
|
||||
auto position = path.GetPoint(progress);
|
||||
auto rotation = path.GetRotation(progress);
|
||||
auto scale = path.GetScale(progress);
|
||||
auto direction = path.GetDirection(progress);
|
||||
auto vertices = mt::GetVertices(faces);
|
||||
|
||||
mt::MoveTo(vertices, position);
|
||||
mt::Scale(vertices, scale, mt::CenterMode::CollectionCenter);
|
||||
mt::Rotate(vertices, mt::GetNormal(vertices), direction);
|
||||
mt::Rotate(vertices, mt::GetNormal(vertices), rotation);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
227
meshTools/meshTools/src/tools/FFD.cpp
Normal file
227
meshTools/meshTools/src/tools/FFD.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
#include "../../include/tools/FFD.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
|
||||
FFD::FFD(const FaceList& faces, int l, int m, int n, FFDControlPointMode ffdControlPointMode)
|
||||
: faces{ faces }
|
||||
, L{ l }
|
||||
, M{ m }
|
||||
, N{ n }
|
||||
, ffdControlPointMode{ ffdControlPointMode }
|
||||
{
|
||||
PERFORMANCER;
|
||||
originalVertices = mt::GetVertices(faces);
|
||||
Parameterize();
|
||||
}
|
||||
|
||||
|
||||
FFD::~FFD()
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (int i = 0; i < L + 1; ++i)
|
||||
{
|
||||
for (int j = 0; j < M + 1; ++j)
|
||||
{
|
||||
delete [] ControlPoints[i][j];
|
||||
}
|
||||
delete [] ControlPoints[i];
|
||||
}
|
||||
delete [] ControlPoints;
|
||||
}
|
||||
|
||||
|
||||
void FFD::Apply()
|
||||
{
|
||||
PERFORMANCER;
|
||||
int idx = 0;
|
||||
for (const auto& vp : vertexParams)
|
||||
{
|
||||
auto p = getWorldVector3(vp);
|
||||
originalVertices[idx++]->Position = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<vec3*> FFD::SelectPoints(int startX, int endX, int startY, int endY, int startZ, int endZ)
|
||||
{
|
||||
List<vec3*> result;
|
||||
for (int x = startX; x <= endX; ++x)
|
||||
for (int y = startY; y <= endY; ++y)
|
||||
for (int z = startZ; z <= endZ; ++z)
|
||||
result.Add(&ControlPoints[x][y][z]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
float FFD::binomialCoeff(int n, int k)
|
||||
{
|
||||
PERFORMANCER;
|
||||
float total = 1.0f;
|
||||
for (int i = 1; i <= k; i++)
|
||||
{
|
||||
total *= (n - (k - i)) / (float)i;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
float FFD::bernsteinPoly(int n, int v, float x)
|
||||
{
|
||||
PERFORMANCER;
|
||||
return binomialCoeff(n, v) * Math::Pow(x, (float)v) * Math::Pow((float)(1.0f - x), (float)(n - v));
|
||||
}
|
||||
|
||||
|
||||
void FFD::calculateSTU(const vec3& max, const vec3& min)
|
||||
{
|
||||
PERFORMANCER;
|
||||
S = { max.x - min.x, 0.0f, 0.0f };
|
||||
T = { 0.0f, max.y - min.y, 0.0f };
|
||||
U = { 0.0f, 0.0f, max.z - min.z };
|
||||
}
|
||||
|
||||
|
||||
void FFD::calculateTrivariateBernsteinPolynomial(const vec3& p0)
|
||||
{
|
||||
PERFORMANCER;
|
||||
vec3 TcU = vec3::Cross(T, U);
|
||||
vec3 ScU = vec3::Cross(S, U);
|
||||
vec3 ScT = vec3::Cross(S, T);
|
||||
|
||||
float TcUdS = vec3::Dot(TcU, S);
|
||||
float ScUdT = vec3::Dot(ScU, T);
|
||||
float ScTdU = vec3::Dot(ScT, U);
|
||||
|
||||
for (int v = 0; v < originalVertices.Count(); v++)
|
||||
{
|
||||
vec3 diff = originalVertices[v]->Position - p0;
|
||||
|
||||
Vector3Param tmp;
|
||||
tmp.s = vec3::Dot(TcU, diff / TcUdS);
|
||||
tmp.t = vec3::Dot(ScU, diff / ScUdT);
|
||||
tmp.u = vec3::Dot(ScT, diff / ScTdU);
|
||||
tmp.p = p0 + (S * tmp.s) + (T * tmp.t) + (U * tmp.u);
|
||||
tmp.p0 = p0;
|
||||
|
||||
{ // Reserve room for each bernstein polynomial pack.
|
||||
tmp.bernPolyPack.Add(List<float>(L)); //outer bernstein poly
|
||||
tmp.bernPolyPack.Add(List<float>(M)); //middle bernstein poly
|
||||
tmp.bernPolyPack.Add(List<float>(N)); //inner bernstein poly
|
||||
}
|
||||
|
||||
{ // Pre-calculate bernstein polynomial expansion. It only needs to be done once per parameterization
|
||||
for (int i = 0; i <= L; i++)
|
||||
{
|
||||
for (int j = 0; j <= M; j++)
|
||||
{
|
||||
for (int k = 0; k <= N; k++)
|
||||
{
|
||||
tmp.bernPolyPack[2].Add(bernsteinPoly(N, k, tmp.u));
|
||||
}
|
||||
tmp.bernPolyPack[1].Add(bernsteinPoly(M, j, tmp.t));
|
||||
}
|
||||
tmp.bernPolyPack[0].Add(bernsteinPoly(L, i, tmp.s));
|
||||
}
|
||||
}
|
||||
vertexParams.Add(tmp);
|
||||
if (vec3::Distance(tmp.p, originalVertices[v]->Position) > 0.001f)
|
||||
{
|
||||
//Debug.Log("Warning, mismatched parameterization");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FFD::Parameterize()
|
||||
{
|
||||
PERFORMANCER;
|
||||
vec3 min = { Math::Infinity, Math::Infinity, Math::Infinity };
|
||||
vec3 max = { -Math::Infinity, -Math::Infinity, -Math::Infinity };
|
||||
for (const auto& v : mt::GetVertices(faces))
|
||||
{
|
||||
max = vec3::Max(v->Position, max);
|
||||
min = vec3::Min(v->Position, min);
|
||||
}
|
||||
calculateSTU(max, min);
|
||||
calculateTrivariateBernsteinPolynomial(min);
|
||||
createControlPoints(min);
|
||||
}
|
||||
|
||||
|
||||
void FFD::createControlPoints(const vec3& origin)
|
||||
{
|
||||
PERFORMANCER;
|
||||
ControlPoints = new vec3**[L + 1];
|
||||
for (int i = 0; i < L + 1; ++i)
|
||||
{
|
||||
ControlPoints[i] = new vec3*[M + 1];
|
||||
for (int j = 0; j < M + 1; ++j)
|
||||
ControlPoints[i][j] = new vec3[N + 1];
|
||||
}
|
||||
|
||||
for (int i = 0; i <= L; i++)
|
||||
{
|
||||
for (int j = 0; j <= M; j++)
|
||||
{
|
||||
for (int k = 0; k <= N; k++)
|
||||
{
|
||||
auto matches = (i == 0 || i == L) ? 1 : 0;
|
||||
matches += (j == 0 || j == M) ? 1 : 0;
|
||||
matches += (k == 0 || k == N) ? 1 : 0;
|
||||
|
||||
if (ffdControlPointMode == FFDControlPointMode::Surface && matches < 1)
|
||||
continue;
|
||||
else if (ffdControlPointMode == FFDControlPointMode::Edges && matches < 2)
|
||||
continue;
|
||||
|
||||
ControlPoints[i][j][k] = createControlPoint(origin, i, j, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec3 FFD::createControlPoint(const vec3& p0, int i, int j, int k)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto position = p0 + (S * (i / (float)L)) + (T * (j / (float)M)) + (U * (k / (float)N));
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
vec3 FFD::getWorldVector3(const Vector3Param& r)
|
||||
{
|
||||
PERFORMANCER;
|
||||
int l = L;
|
||||
int m = M;
|
||||
int n = N;
|
||||
|
||||
vec3 tS = vec3::zero;
|
||||
for (int i = 0; i <= l; i++)
|
||||
{
|
||||
vec3 tM = vec3::zero;
|
||||
for (int j = 0; j <= m; j++)
|
||||
{
|
||||
vec3 tK = vec3::zero;
|
||||
for (int k = 0; k <= n; k++)
|
||||
{
|
||||
auto matches = (i == 0 || i == L) ? 1 : 0;
|
||||
matches += (j == 0 || j == M) ? 1 : 0;
|
||||
matches += (k == 0 || k == N) ? 1 : 0;
|
||||
|
||||
if (ffdControlPointMode == FFDControlPointMode::Surface && matches < 1)
|
||||
continue;
|
||||
else if (ffdControlPointMode == FFDControlPointMode::Edges && matches < 2)
|
||||
continue;
|
||||
|
||||
tK += ControlPoints[i][j][k] * r.bernPolyPack[2][k];
|
||||
}
|
||||
tM += tK * r.bernPolyPack[1][j];
|
||||
}
|
||||
tS += tM * r.bernPolyPack[0][i];
|
||||
}
|
||||
return tS;
|
||||
}
|
||||
}
|
||||
14
meshTools/meshTools/src/tools/Flip.cpp
Normal file
14
meshTools/meshTools/src/tools/Flip.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "../../include/tools/Flip.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Transform.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
void FlipSides(const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& face : faces)
|
||||
face->FlipNormal();
|
||||
}
|
||||
}
|
||||
60
meshTools/meshTools/src/tools/Group.cpp
Normal file
60
meshTools/meshTools/src/tools/Group.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "../../include/tools/Group.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Transform.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
void CheckFace(float angleThreshold, Map<Face*, Face*>& checkedFaces, FaceList& nextFaces, FaceList& groupFaces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto currentFace = nextFaces[nextFaces.Count() - 1];
|
||||
nextFaces.RemoveAt(nextFaces.Count() - 1);
|
||||
groupFaces.Add(currentFace);
|
||||
|
||||
for (const auto& edge : currentFace->GetEdges())
|
||||
{
|
||||
auto edgeFaces = edge->GetFaces();
|
||||
if (edgeFaces.Count() != 2)
|
||||
continue;
|
||||
|
||||
auto otherFace = edgeFaces[0] == currentFace ? edgeFaces[1] : edgeFaces[0];
|
||||
|
||||
if (!checkedFaces.ContainsKey(otherFace))
|
||||
{
|
||||
auto dotResult = vec3::Dot(currentFace->GetNormal(), otherFace->GetNormal());
|
||||
if (dotResult >= 1 - angleThreshold)
|
||||
{
|
||||
nextFaces.Add(otherFace);
|
||||
checkedFaces.Add(otherFace, otherFace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<FaceList> GetGroups(const FaceList& faces, float threshold)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto currentFaces = faces;
|
||||
|
||||
List<FaceList> groups;
|
||||
while (currentFaces.Count() > 0)
|
||||
{
|
||||
FaceList pendingFaces;
|
||||
Map<Face*, Face*> checkedFaces;
|
||||
FaceList groupFaces;
|
||||
|
||||
auto currentFace = faces[0];
|
||||
checkedFaces.Add(currentFace, currentFace);
|
||||
pendingFaces.Add(currentFace);
|
||||
while (pendingFaces.Count() != 0)
|
||||
CheckFace(threshold, checkedFaces, pendingFaces, groupFaces);
|
||||
|
||||
groups.Add(groupFaces);
|
||||
currentFaces = Linq::Except(currentFaces, groupFaces);
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
115
meshTools/meshTools/src/tools/Prefab.cpp
Normal file
115
meshTools/meshTools/src/tools/Prefab.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "../../include/tools/Prefab.h"
|
||||
#include "../../include/tools/Weld.h"
|
||||
#include "../../include/tools/Subdivide.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
Face* CreateQuad(const vec3& size, const vec3& position, PlaneDirection direction)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto face = new Face(
|
||||
new Vertex(vec3::zero),
|
||||
new Vertex(vec3::zero),
|
||||
new Vertex(vec3::zero),
|
||||
new Vertex(vec3::zero));
|
||||
|
||||
auto halfSize = size * 0.5f;
|
||||
|
||||
auto& vertices = face->GetVertices();
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case PlaneDirection::Forward:
|
||||
vertices[0]->Position = position + vec3(halfSize.x, halfSize.y, 0);
|
||||
vertices[1]->Position = position + vec3(-halfSize.x, halfSize.y, 0);
|
||||
vertices[2]->Position = position + vec3(-halfSize.x, -halfSize.y, 0);
|
||||
vertices[3]->Position = position + vec3(halfSize.x, -halfSize.y, 0);
|
||||
break;
|
||||
case PlaneDirection::Backward:
|
||||
vertices[0]->Position = position + vec3(-halfSize.x, halfSize.y, 0);
|
||||
vertices[1]->Position = position + vec3(halfSize.x, halfSize.y, 0);
|
||||
vertices[2]->Position = position + vec3(halfSize.x, -halfSize.y, 0);
|
||||
vertices[3]->Position = position + vec3(-halfSize.x, -halfSize.y, 0);
|
||||
break;
|
||||
case PlaneDirection::Left:
|
||||
vertices[0]->Position = position + vec3(0, halfSize.y, halfSize.x);
|
||||
vertices[1]->Position = position + vec3(0, halfSize.y, -halfSize.x);
|
||||
vertices[2]->Position = position + vec3(0, -halfSize.y, -halfSize.x);
|
||||
vertices[3]->Position = position + vec3(0, -halfSize.y, halfSize.x);
|
||||
break;
|
||||
case PlaneDirection::Right:
|
||||
vertices[0]->Position = position + vec3(0, halfSize.y, -halfSize.x);
|
||||
vertices[1]->Position = position + vec3(0, halfSize.y, halfSize.x);
|
||||
vertices[2]->Position = position + vec3(0, -halfSize.y, halfSize.x);
|
||||
vertices[3]->Position = position + vec3(0, -halfSize.y, -halfSize.x);
|
||||
break;
|
||||
case PlaneDirection::Up:
|
||||
vertices[0]->Position = position + vec3(-halfSize.x, 0, halfSize.y);
|
||||
vertices[1]->Position = position + vec3(halfSize.x, 0, halfSize.y);
|
||||
vertices[2]->Position = position + vec3(halfSize.x, 0, -halfSize.y);
|
||||
vertices[3]->Position = position + vec3(-halfSize.x, 0, -halfSize.y);
|
||||
break;
|
||||
case PlaneDirection::Down:
|
||||
vertices[0]->Position = position + vec3(halfSize.x, 0, halfSize.y);
|
||||
vertices[1]->Position = position + vec3(-halfSize.x, 0, halfSize.y);
|
||||
vertices[2]->Position = position + vec3(-halfSize.x, 0, -halfSize.y);
|
||||
vertices[3]->Position = position + vec3(halfSize.x, 0, -halfSize.y);
|
||||
break;
|
||||
}
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
|
||||
Mesh* CreatePlane(const vec3& position, float edgeSize, PlaneDirection direction)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto mesh = new Mesh();
|
||||
|
||||
vec3 size = { edgeSize, edgeSize, edgeSize };
|
||||
|
||||
mesh->AddFace(CreateQuad(size, position, direction));
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
Mesh* CreateCube(bool weldVertices, const vec3& position, float edgeSize)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto mesh = new Mesh();
|
||||
|
||||
auto halfSize = edgeSize / 2;
|
||||
vec3 size = { edgeSize, edgeSize, edgeSize };
|
||||
|
||||
mesh->AddFace(CreateQuad(size, position + vec3{ 0, halfSize, 0 }, PlaneDirection::Up));
|
||||
mesh->AddFace(CreateQuad(size, position + vec3{ 0, -halfSize, 0 }, PlaneDirection::Down));
|
||||
mesh->AddFace(CreateQuad(size, position + vec3{ halfSize, 0, 0 }, PlaneDirection::Right));
|
||||
mesh->AddFace(CreateQuad(size, position + vec3{ -halfSize, 0, 0 }, PlaneDirection::Left));
|
||||
mesh->AddFace(CreateQuad(size, position + vec3{ 0, 0, halfSize }, PlaneDirection::Forward));
|
||||
mesh->AddFace(CreateQuad(size, position + vec3{ 0, 0, -halfSize }, PlaneDirection::Backward));
|
||||
|
||||
const auto& faces = mesh->GetFaces();
|
||||
faces[0]->AddTag(Tags::DirectionUp);
|
||||
faces[1]->AddTag(Tags::DirectionDown);
|
||||
faces[2]->AddTag(Tags::DirectionRight);
|
||||
faces[3]->AddTag(Tags::DirectionLeft);
|
||||
faces[4]->AddTag(Tags::DirectionFront);
|
||||
faces[5]->AddTag(Tags::DirectionBack);
|
||||
|
||||
if (weldVertices)
|
||||
mt::Weld(mesh->GetVertices());
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Mesh* CreateSphere(int tesselationLevel, const vec3& position, float baseSize)
|
||||
{
|
||||
auto mesh = CreateCube(true, position, baseSize);
|
||||
|
||||
for (int i = 0; i < tesselationLevel; ++i)
|
||||
mt::Subdivide(mesh->GetFaces(), true);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
42
meshTools/meshTools/src/tools/Project.cpp
Normal file
42
meshTools/meshTools/src/tools/Project.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "../../include/tools/Project.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Transform.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
void Flatten(const VertexList& vertices)
|
||||
{
|
||||
PERFORMANCER;
|
||||
Flatten(vertices, mt::GetNormal(vertices));
|
||||
}
|
||||
|
||||
|
||||
void Flatten(const VertexList& vertices, const vec3& normal)
|
||||
{
|
||||
PERFORMANCER;
|
||||
Project(vertices, { normal, mt::GetCenter(vertices) });
|
||||
}
|
||||
|
||||
|
||||
void Project(const VertexList& vertices, const Plane& plane)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
auto distance = plane.GetDistanceToPoint(vertex->Position);
|
||||
vertex->Position -= plane.GetNormal() * distance;
|
||||
}
|
||||
}
|
||||
|
||||
void Clamp(const VertexList& vertices, const Plane& plane)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
auto distance = plane.GetDistanceToPoint(vertex->Position);
|
||||
if (distance < 0)
|
||||
vertex->Position -= plane.GetNormal() * distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
meshTools/meshTools/src/tools/Select.cpp
Normal file
155
meshTools/meshTools/src/tools/Select.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#include "../../include/tools/Select.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
FaceList GetFacesByDirection(const FaceList& faces, const vec3 direction, float threshold, bool mirror)
|
||||
{
|
||||
PERFORMANCER;
|
||||
FaceList selected;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
auto dot = vec3::Dot(face->GetNormal(), direction);
|
||||
if (mirror)
|
||||
dot = Math::Abs(dot);
|
||||
if (dot >= 1 - threshold)
|
||||
selected.Add(face);
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
FaceList GetFacesOnPositivePlane(const FaceList& faces, const Plane& plane)
|
||||
{
|
||||
PERFORMANCER;
|
||||
FaceList selected;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
for (const auto& vertex : face->GetVertices())
|
||||
if (plane.GetSide(vertex->Position))
|
||||
{
|
||||
selected.Add(face);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
VertexList GetVerticesOnPositivePlane(const VertexList& vertices, const Plane& plane)
|
||||
{
|
||||
PERFORMANCER;
|
||||
VertexList selected;
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
if (plane.GetSide(vertex->Position))
|
||||
{
|
||||
selected.Add(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
FaceList GetFacesWithTag(const FaceList& faces, int tag)
|
||||
{
|
||||
PERFORMANCER;
|
||||
FaceList selected;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
if (face->HasTag(tag))
|
||||
selected.Add(face);
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
FaceList GetFacesWithTags(const FaceList& faces, List<int> tags, bool canMatchAnyTag)
|
||||
{
|
||||
PERFORMANCER;
|
||||
FaceList selected;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
if (canMatchAnyTag ? face->HasTagsAny(tags) : face->HasTagsAll(tags))
|
||||
selected.Add(face);
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
FaceList GetFacesAt(const FaceList& faces, const vec3& position, float range)
|
||||
{
|
||||
PERFORMANCER;
|
||||
FaceList selected;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
for (const auto& vertex : face->GetVertices())
|
||||
if (vec3::Distance(vertex->Position, position) <= range)
|
||||
{
|
||||
selected.Add(face);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
VertexList GetVerticesAt(const VertexList& vertices, const vec3& position, float range)
|
||||
{
|
||||
PERFORMANCER;
|
||||
VertexList selected;
|
||||
for (const auto& vertex : vertices)
|
||||
if (vec3::Distance(vertex->Position, position) <= range)
|
||||
{
|
||||
selected.Add(vertex);
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
Face* GetFaceAt(const FaceList& faces, const vec3& position, float range)
|
||||
{
|
||||
PERFORMANCER;
|
||||
Face* nearest = nullptr;
|
||||
float nearestDistance = Math::Infinity;
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
for (const auto& vertex : face->GetVertices())
|
||||
{
|
||||
auto distance = vec3::Distance(vertex->Position, position);
|
||||
if (distance <= range && distance < nearestDistance)
|
||||
{
|
||||
nearestDistance = distance;
|
||||
nearest = face;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
|
||||
Vertex* GetVertexAt(const VertexList& vertices, const vec3& position, float range)
|
||||
{
|
||||
PERFORMANCER;
|
||||
Vertex* nearest = nullptr;
|
||||
float nearestDistance = Math::Infinity;
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
auto distance = vec3::Distance(vertex->Position, position);
|
||||
if (distance <= range && distance < nearestDistance)
|
||||
{
|
||||
nearestDistance = distance;
|
||||
nearest = vertex;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
}
|
||||
139
meshTools/meshTools/src/tools/Split.cpp
Normal file
139
meshTools/meshTools/src/tools/Split.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "../../include/tools/Split.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
Face* FindPartnerFace(Face* self, const VertexList& vertices, const FaceList& faces)
|
||||
{
|
||||
const EdgeList& edges = self->GetEdges();
|
||||
for (auto edge : edges)
|
||||
{
|
||||
int cnt = 0;
|
||||
for (auto vertex : edge->GetVertices())
|
||||
{
|
||||
if (vertices.Contains(vertex))
|
||||
cnt++;
|
||||
}
|
||||
if (cnt == 1)
|
||||
{
|
||||
for (auto face : edge->GetFaces())
|
||||
if (face != self && faces.Contains(face))
|
||||
return face;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FaceList Split(const FaceList& faces, const Plane& plane)
|
||||
{
|
||||
if (faces.Count() == 0)
|
||||
return{};
|
||||
auto mesh = faces[0]->GetMesh();
|
||||
|
||||
Map<Edge*, Vertex*> edgesToIntersectionPoints;
|
||||
VertexList splitVertices;
|
||||
auto edges = Linq::SelectUniqueMany<Edge*>(faces, [](Face* face){ return face->GetEdges(); });
|
||||
for (auto edge : edges)
|
||||
{
|
||||
const auto& vertices = edge->GetVertices();
|
||||
|
||||
vec3 intersectionPoint;
|
||||
auto d = plane.IntersectLinesegment(vertices[0]->Position, vertices[1]->Position, intersectionPoint);
|
||||
if (d >= 0 && d <= 1)
|
||||
{
|
||||
auto splitVertex = new Vertex(vertices[0]);
|
||||
splitVertex->Interpolate(vertices[1], d);
|
||||
edgesToIntersectionPoints.Add(edge, splitVertex);
|
||||
splitVertices.Add(splitVertex);
|
||||
}
|
||||
}
|
||||
|
||||
FaceList result = faces;
|
||||
mesh->StartAutoUpdate(result);
|
||||
for (auto pair : edgesToIntersectionPoints)
|
||||
{
|
||||
auto edge = pair->Key;
|
||||
auto vertex = pair->Value;
|
||||
mesh->SplitEdge(edge, vertex);
|
||||
}
|
||||
|
||||
FaceList sides[2];
|
||||
sides[0] = mt::GetFacesOnPositivePlane(result, plane);
|
||||
sides[1] = Linq::Except(result, sides[0]);
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
while (sides[i].Count())
|
||||
{
|
||||
auto face = sides[i][sides[i].Count() - 1];
|
||||
sides[i].RemoveAt(sides[i].Count() - 1);
|
||||
auto partnerFace = FindPartnerFace(face, splitVertices, sides[i]);
|
||||
if (partnerFace != nullptr)
|
||||
{
|
||||
sides[i].Remove(partnerFace);
|
||||
mt::MergeTriangles(face, partnerFace);
|
||||
}
|
||||
}
|
||||
}
|
||||
mesh->StopAutoUpdate(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Face* MergeTriangles(Face* a, Face* b)
|
||||
{
|
||||
auto mesh = a->GetMesh();
|
||||
auto otherEdges = b->GetEdges();
|
||||
Edge* sharedEdge;
|
||||
for (const auto& edge : a->GetEdges())
|
||||
if (otherEdges.IndexOf(edge) != -1)
|
||||
{
|
||||
sharedEdge = edge;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sharedEdge == nullptr)
|
||||
return nullptr;
|
||||
|
||||
List<Vertex*> vertices;
|
||||
|
||||
auto start0 = a->GetVertices().IndexOf(sharedEdge->GetVertices()[0]);
|
||||
auto direction = 1;
|
||||
auto sharedEdgeVertices = sharedEdge->GetVertices();
|
||||
if (sharedEdgeVertices.IndexOf(a->GetVertices()[(start0 + 1) % 3]) >= 0)
|
||||
direction = -1;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
auto realIndex = start0 % 3;
|
||||
if (realIndex < 0)
|
||||
realIndex = realIndex + 3;
|
||||
|
||||
vertices.Add(a->GetVertices()[realIndex]);
|
||||
start0 += direction;
|
||||
}
|
||||
Vertex* lastVertex;
|
||||
for (const auto& vertex : b->GetVertices())
|
||||
if (sharedEdgeVertices.IndexOf(vertex) == -1)
|
||||
{
|
||||
lastVertex = vertex;
|
||||
break;
|
||||
}
|
||||
vertices = Linq::Reverse(vertices);
|
||||
vertices.Add(lastVertex);
|
||||
|
||||
auto c = new Face(vertices);
|
||||
c->CopyProperties(a);
|
||||
c->CopyProperties(b, true);
|
||||
c->FlipNormal(a->GetNormal());
|
||||
|
||||
mesh->AddFace(c);
|
||||
mesh->RemoveFace(a);
|
||||
mesh->RemoveFace(b);
|
||||
|
||||
auto faces = Linq::ToList(c);
|
||||
mesh->TriggerFaceReplaced(a, faces);
|
||||
mesh->TriggerFaceReplaced(b, faces);
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
||||
161
meshTools/meshTools/src/tools/Subdivide.cpp
Normal file
161
meshTools/meshTools/src/tools/Subdivide.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "../../include/tools/Subdivide.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
FaceList Subdivide(const FaceList& inFaces, bool smooth)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto faces = inFaces;
|
||||
if (faces.Count() == 0)
|
||||
return{};
|
||||
|
||||
auto mesh = faces[0]->GetMesh();
|
||||
auto vertices = mt::GetVertices(faces);
|
||||
auto edges = Linq::SelectUniqueMany<Edge*>(faces, [](Face* face) { return face->GetEdges(); });
|
||||
|
||||
// A FacePoint is defined as the average of the points from a face, in our case this is the face center.
|
||||
Map<Face*, Vertex*> facePoints;
|
||||
for (const auto& face : faces)
|
||||
facePoints.Add(face, new Vertex(mt::GetCenter(face->GetVertices())));
|
||||
|
||||
Map<Edge*, Vertex*> borderEdges;
|
||||
Map<Edge*, Vertex*> edgePoints;
|
||||
for (const auto& edge : edges)
|
||||
{
|
||||
auto edgeFaces = edge->GetFaces();
|
||||
edgeFaces = Linq::Intersect(edgeFaces, faces);
|
||||
|
||||
vec3 point = edge->GetCenter();
|
||||
auto isBorderEdge = 1 == edgeFaces.Count();
|
||||
if (smooth)
|
||||
{
|
||||
// An EdgePoint is the average of the edgepoints and the facepoints of the edges faces, if the edge is a border edge the edgepoint is only the average of the edgepoints (the center).
|
||||
auto cnt = 1;
|
||||
if (!isBorderEdge)
|
||||
{
|
||||
for (const auto& face : edgeFaces)
|
||||
{
|
||||
point += mt::GetCenter(face->GetVertices());
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
point /= (float)cnt;
|
||||
}
|
||||
|
||||
auto edgeVertex = new Vertex(point);
|
||||
edgePoints.Add(edge, edgeVertex);
|
||||
|
||||
if (isBorderEdge && edge->GetFaces().Count() > 1)
|
||||
borderEdges.Add(edge, edgeVertex);
|
||||
}
|
||||
|
||||
if (smooth)
|
||||
{
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
auto vertexFaces = Linq::Intersect(vertex->GetFaces(), faces);
|
||||
|
||||
auto touchingFaces = Linq::Where(vertexFaces, [&](Face* face) { return faces.IndexOf(face) != -1; });
|
||||
auto touchingFaceEdges = Linq::SelectUniqueMany<Edge*>(touchingFaces, [&](Face* face) { return face->GetEdges(); });
|
||||
auto touchingEdges = Linq::Where(touchingFaceEdges, [&](Edge* edge) { return edge->GetVertices().IndexOf(vertex) != -1; });
|
||||
touchingEdges = Linq::Distinct(touchingEdges);
|
||||
|
||||
auto isBorderVertex = touchingFaces.Count() != touchingEdges.Count();
|
||||
if (isBorderVertex)
|
||||
{
|
||||
vec3 R;
|
||||
float cnt = 1.0f;
|
||||
for (const auto& touchingEdge : touchingEdges)
|
||||
{
|
||||
auto edgeFaces = Linq::Intersect(touchingEdge->GetFaces(), faces);
|
||||
if (edgeFaces.Count() == 1)
|
||||
{
|
||||
R += edgePoints[touchingEdge]->Position;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
vertex->Position = (R + vertex->Position) / cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec3 F;
|
||||
for (const auto& touchingFace : touchingFaces)
|
||||
F += facePoints[touchingFace]->Position;
|
||||
F /= (float)touchingFaces.Count();
|
||||
|
||||
vec3 R;
|
||||
for (const auto& touchingEdge : touchingEdges)
|
||||
R += edgePoints[touchingEdge]->Position;
|
||||
R /= (float)touchingEdges.Count();
|
||||
|
||||
auto n = (float)vertexFaces.Count();
|
||||
|
||||
auto m1 = (n - 3) / n;
|
||||
auto m2 = 1 / n;
|
||||
auto m3 = 2 / n;
|
||||
auto newPosition = (vertex->Position * m1)
|
||||
+ (F * m2)
|
||||
+ (R * m3);
|
||||
|
||||
//newPosition = (F + R * 2 + vertex->Position * (n - 3)) / n;
|
||||
|
||||
vertex->Position = newPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<Face*, List<Edge*>> faceEdges;
|
||||
for (const auto& face : faces)
|
||||
faceEdges.Add(face, face->GetEdges());
|
||||
|
||||
FaceList newFaces;
|
||||
|
||||
for (const auto& face : faces)
|
||||
{
|
||||
FaceList currentNewFaces;
|
||||
auto faceVertices = face->GetVertices();
|
||||
|
||||
auto facePoint = facePoints[face];
|
||||
auto edgePoint0 = edgePoints[faceEdges[face][0]];
|
||||
auto edgePoint1 = edgePoints[faceEdges[face][1]];
|
||||
auto edgePoint2 = edgePoints[faceEdges[face][2]];
|
||||
|
||||
if (face->IsTriangle())
|
||||
{
|
||||
currentNewFaces.Add(new Face(faceVertices[0], edgePoint0, facePoint, edgePoint2));
|
||||
currentNewFaces.Add(new Face(faceVertices[1], edgePoint1, facePoint, edgePoint0));
|
||||
currentNewFaces.Add(new Face(faceVertices[2], edgePoint2, facePoint, edgePoint1));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto edgePoint3 = edgePoints[faceEdges[face][3]];
|
||||
|
||||
currentNewFaces.Add(new Face(faceVertices[0], edgePoint0, facePoint, edgePoint3));
|
||||
currentNewFaces.Add(new Face(faceVertices[1], edgePoint1, facePoint, edgePoint0));
|
||||
currentNewFaces.Add(new Face(faceVertices[2], edgePoint2, facePoint, edgePoint1));
|
||||
currentNewFaces.Add(new Face(faceVertices[3], edgePoint3, facePoint, edgePoint2));
|
||||
}
|
||||
for (auto& newFace : currentNewFaces)
|
||||
{
|
||||
newFace->CopyProperties(face);
|
||||
newFace->FlipNormal(face->GetNormal());
|
||||
mesh->AddFace(newFace);
|
||||
|
||||
newFaces.Add(newFace);
|
||||
}
|
||||
|
||||
mesh->TriggerFaceReplaced(face, currentNewFaces);
|
||||
}
|
||||
|
||||
for (const auto& face : faces)
|
||||
mesh->RemoveFace(face);
|
||||
|
||||
for (const auto& pair : borderEdges)
|
||||
Linq::AddRange(newFaces, mesh->SplitEdge(pair->Key, pair->Value));
|
||||
|
||||
return newFaces;
|
||||
}
|
||||
}
|
||||
18
meshTools/meshTools/src/tools/Tags.cpp
Normal file
18
meshTools/meshTools/src/tools/Tags.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "../../include/tools/Tags.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
void AddTag(const FaceList& faces, int tag)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& face : faces)
|
||||
face->AddTag(tag);
|
||||
}
|
||||
|
||||
void RemoveTag(const FaceList& faces, int tag)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& face : faces)
|
||||
face->RemoveTag(tag);
|
||||
}
|
||||
}
|
||||
175
meshTools/meshTools/src/tools/Transform.cpp
Normal file
175
meshTools/meshTools/src/tools/Transform.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#include "../../include/tools/Transform.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Group.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
void MoveTo(const VertexList& vertices, const vec3& position)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto center = mt::GetCenter(vertices);
|
||||
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position += position - center;
|
||||
}
|
||||
|
||||
|
||||
void MoveBy(const VertexList& vertices, const vec3& offset)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto center = mt::GetCenter(vertices);
|
||||
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position += offset;
|
||||
}
|
||||
|
||||
|
||||
void MoveBy(const VertexList& vertices, float factor, MoveMode mode)
|
||||
{
|
||||
PERFORMANCER;
|
||||
switch (mode)
|
||||
{
|
||||
case MoveMode::UseVertexNormal:
|
||||
{
|
||||
Map<Vertex*, vec3> normalMap;
|
||||
for (const auto& vertex : vertices)
|
||||
normalMap.Add(vertex, vertex->GetNormal());
|
||||
|
||||
for (auto& pair : normalMap)
|
||||
pair->Key->Position += pair->Value * factor;
|
||||
break;
|
||||
}
|
||||
case MoveMode::UseCollectionNormal:
|
||||
{
|
||||
auto normal = mt::GetNormal(vertices);
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position += normal * factor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Scale(const VertexList& vertices, const vec3& center, float factor)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position = center + (vertex->Position - center) * factor;
|
||||
}
|
||||
|
||||
|
||||
void Scale(const VertexList& vertices, const vec3& factor, const vec3& center)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position = center + vec3::Mul(vertex->Position - center, factor);
|
||||
}
|
||||
|
||||
|
||||
void Scale(const VertexList& vertices, float factor, CenterMode mode)
|
||||
{
|
||||
PERFORMANCER;
|
||||
Scale(vertices, { factor, factor, factor }, mode);
|
||||
}
|
||||
|
||||
|
||||
void Scale(const VertexList& vertices, const vec3& factor, CenterMode mode)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (vertices.Count() == 0)
|
||||
return;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case CenterMode::CollectionCenter:
|
||||
{
|
||||
mt::Scale(vertices, factor, mt::GetCenter(vertices));
|
||||
break;
|
||||
}
|
||||
case CenterMode::MeshCenter:
|
||||
{
|
||||
auto center = mt::GetCenter(vertices[0]->GetMesh()->GetVertices());
|
||||
mt::Scale(vertices, factor, center);
|
||||
break;
|
||||
}
|
||||
case CenterMode::FaceCenter:
|
||||
{
|
||||
Map<Vertex*, vec3> normalMap;
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
vec3 center;
|
||||
auto faces = vertex->GetFaces();
|
||||
for (const auto& face : faces)
|
||||
center += mt::GetCenter(face->GetVertices());
|
||||
center /= (float)faces.Count();
|
||||
normalMap.Add(vertex, center);
|
||||
}
|
||||
|
||||
for (const auto& pair : normalMap)
|
||||
pair->Key->Position = pair->Value + vec3::Mul(pair->Key->Position - pair->Value, factor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Rotate(const VertexList& vertices, const vec3& startNormal, const vec3& direction)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto center = mt::GetCenter(vertices);
|
||||
Rotate(vertices, center, startNormal, direction);
|
||||
}
|
||||
|
||||
|
||||
void Rotate(const VertexList& vertices, const vec3& center, const vec3& startNormal, const vec3& direction)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto rotation = Quaternion::FromTo(startNormal, direction);
|
||||
Rotate(vertices, center, rotation);
|
||||
}
|
||||
|
||||
|
||||
void Rotate(const VertexList& vertices, const vec3& axis, float angle)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto center = mt::GetCenter(vertices);
|
||||
Rotate(vertices, center, axis, angle);
|
||||
}
|
||||
|
||||
|
||||
void Rotate(const VertexList& vertices, const vec3& center, const vec3& axis, float angle)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto rotation = Quaternion::CreateFromAxisAngle(axis, angle);
|
||||
Rotate(vertices, center, rotation);
|
||||
}
|
||||
|
||||
|
||||
void Rotate(const VertexList& vertices, const vec3& center, const Quaternion& rotation)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position = ((vertex->Position - center) * rotation) + center;
|
||||
}
|
||||
|
||||
|
||||
void Mirror(const FaceList& faces, const Plane& plane)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& vertex : mt::GetVertices(faces))
|
||||
{
|
||||
auto distance = plane.GetDistanceToPoint(vertex->Position);
|
||||
vertex->Position -= plane.GetNormal() * distance * 2;
|
||||
if (vertex->HasManualNormal())
|
||||
{
|
||||
auto normal = vertex->GetNormal();
|
||||
auto planeNormalMagnitude = plane.GetNormal().GetLength();
|
||||
vertex->SetNormal(normal - (plane.GetNormal() * 2) * vec3::Dot(normal, plane.GetNormal()) / (planeNormalMagnitude * planeNormalMagnitude));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& face : faces)
|
||||
face->FlipNormal();
|
||||
}
|
||||
}
|
||||
9
meshTools/meshTools/src/tools/Triangulate.cpp
Normal file
9
meshTools/meshTools/src/tools/Triangulate.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "../../include/tools/Triangulate.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
FaceList Triangulate(const FaceList& faces)
|
||||
{
|
||||
return Linq::SelectMany<Face*>((FaceList)faces, [](Face* face) { return face->Triangulate(); });
|
||||
}
|
||||
}
|
||||
88
meshTools/meshTools/src/tools/Weld.cpp
Normal file
88
meshTools/meshTools/src/tools/Weld.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "../../include/tools/Weld.h"
|
||||
#include "../../include/tools/Calculate.h"
|
||||
#include "../../include/tools/Select.h"
|
||||
#include "../../include/tools/Transform.h"
|
||||
|
||||
namespace mt
|
||||
{
|
||||
void Weld(const VertexList& vertices, float range)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (range <= Math::FloatEpsilon)
|
||||
range = Math::FloatEpsilon;
|
||||
else
|
||||
range *= range;
|
||||
|
||||
auto pendingVertices = vertices;
|
||||
|
||||
VertexList toWeld(1);
|
||||
while (pendingVertices.Count() > 0)
|
||||
{
|
||||
toWeld.Clear();
|
||||
|
||||
auto vertex = pendingVertices[pendingVertices.Count() - 1];
|
||||
|
||||
for (int i = pendingVertices.Count() - 1; i >= 0; --i)
|
||||
{
|
||||
auto weldCandidate = pendingVertices[i];
|
||||
|
||||
if (vec3::DistanceSq(weldCandidate->Position, vertex->Position) <= range)
|
||||
{
|
||||
toWeld.Add(weldCandidate);
|
||||
pendingVertices.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (toWeld.Count() == 1)
|
||||
continue;
|
||||
|
||||
auto newVertex = new Vertex(toWeld[0]);
|
||||
newVertex->Position = mt::GetCenter(toWeld);
|
||||
toWeld[0]->GetMesh()->ReplaceVertices(toWeld, newVertex);
|
||||
|
||||
for (const auto& face : newVertex->GetFaces())
|
||||
if (!face->RegainIntegrity())
|
||||
face->GetMesh()->RemoveFace(face);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Collapse(const FaceList& faces, CenterMode mode)
|
||||
{
|
||||
PERFORMANCER;
|
||||
if (faces.Count() == 0)
|
||||
return;
|
||||
|
||||
auto vertices = mt::GetVertices(faces);
|
||||
if (mode == CenterMode::CollectionCenter)
|
||||
{
|
||||
auto center = mt::GetCenter(vertices);
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position = center;
|
||||
}
|
||||
else if (mode == CenterMode::MeshCenter)
|
||||
{
|
||||
auto center = mt::GetCenter(faces[0]->GetMesh()->GetVertices());
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position = center;
|
||||
}
|
||||
else if (mode == CenterMode::FaceCenter)
|
||||
{
|
||||
Map<Vertex*, vec3> normalMap;
|
||||
for (const auto& vertex : vertices)
|
||||
{
|
||||
vec3 center;
|
||||
auto faces = vertex->GetFaces();
|
||||
for (const auto& face : faces)
|
||||
center += mt::GetCenter(face->GetVertices());
|
||||
center /= (float)faces.Count();
|
||||
normalMap.Add(vertex, center);
|
||||
}
|
||||
|
||||
for (const auto& pair : normalMap)
|
||||
pair->Key->Position = pair->Value;
|
||||
}
|
||||
|
||||
mt::Weld(vertices);
|
||||
}
|
||||
}
|
||||
115
meshTools/test/src/ObjExporter.cpp
Normal file
115
meshTools/test/src/ObjExporter.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
|
||||
#if _DEBUG
|
||||
|
||||
#include "ObjExporter.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
void ObjExporter::Export(Mesh* mesh, const std::string& filePath)
|
||||
{
|
||||
PERFORMANCER;
|
||||
ObjExporter exporter(mesh);
|
||||
exporter.Export(filePath);
|
||||
}
|
||||
|
||||
|
||||
ObjExporter::ObjExporter(Mesh* mesh)
|
||||
: mesh{mesh}
|
||||
{
|
||||
PERFORMANCER;
|
||||
}
|
||||
|
||||
void ObjExporter::Export(const std::string& filePath)
|
||||
{
|
||||
PERFORMANCER;
|
||||
std::ostringstream builder;
|
||||
std::ostringstream mtlBuilder;
|
||||
builder << "mtllib " + replace(filePath, ".obj", ".mtl") << std::endl;
|
||||
WritePositions(builder);
|
||||
WriteNormals(builder);
|
||||
WriteUVs(builder);
|
||||
WriteFaceGroups(builder, mtlBuilder);
|
||||
|
||||
std::ofstream objFile(filePath);
|
||||
objFile << builder.str();
|
||||
objFile.close();
|
||||
|
||||
std::ofstream mtlFile(replace(filePath, ".obj", ".mtl"));
|
||||
mtlFile << mtlBuilder.str();
|
||||
mtlFile.close();
|
||||
}
|
||||
|
||||
|
||||
void ObjExporter::WriteFaceGroups(std::ostringstream& builder, std::ostringstream& mtlBuilder)
|
||||
{
|
||||
PERFORMANCER;
|
||||
auto groups = mesh->GetSubMeshs();
|
||||
for(const auto& group : groups)
|
||||
{
|
||||
auto materialId = group->Key;
|
||||
|
||||
builder << "usemtl " << materialId << std::endl;
|
||||
builder << "g " << materialId << std::endl;
|
||||
|
||||
WriteFaces(builder, group->Value);
|
||||
|
||||
mtlBuilder << "newmtl " << materialId << std::endl;
|
||||
mtlBuilder << "Ka 0.0 0.0 0.0" << std::endl;
|
||||
mtlBuilder << "Kd 1.0 1.0 1.0" << std::endl;
|
||||
mtlBuilder << "Ks 1.0 1.0 1.0" << std::endl;
|
||||
mtlBuilder << "Ns 16.0" << std::endl;
|
||||
mtlBuilder << "illum 0" << std::endl;
|
||||
|
||||
mtlBuilder << "map_Kd " << materialId << ".png" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ObjExporter::WriteFaces(std::ostringstream& builder, const FaceList& faces)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (auto face : faces)
|
||||
{
|
||||
auto indices = face->GetIndices(true);
|
||||
|
||||
builder << "f";
|
||||
for (int i = 0; i < indices.Count(); ++i)
|
||||
{
|
||||
builder << " ";
|
||||
auto index = indices[i] + 1;
|
||||
builder << index << "/" << index << "/" << index;
|
||||
}
|
||||
builder << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjExporter::WritePositions(std::ostringstream& builder)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& v : mesh->GetVertices())
|
||||
{
|
||||
builder << "v " << v->Position.x << " " << v->Position.y << " " << v->Position.z << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjExporter::WriteNormals(std::ostringstream& builder)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& v : mesh->GetVertices())
|
||||
{
|
||||
auto normal = v->GetNormal();
|
||||
builder << "vn " << normal.x << " " << normal.y << " " << normal.z << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjExporter::WriteUVs(std::ostringstream& builder)
|
||||
{
|
||||
PERFORMANCER;
|
||||
for (const auto& v : mesh->GetVertices())
|
||||
{
|
||||
builder << "vt " << v->UV[0] << " " << v->UV[1] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
44
meshTools/test/src/ObjExporter.h
Normal file
44
meshTools/test/src/ObjExporter.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#if _DEBUG
|
||||
|
||||
#include <core/core.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
class Mesh;
|
||||
|
||||
class ObjExporter
|
||||
{
|
||||
public:
|
||||
static void Export(Mesh* mesh, const std::string& filePath);
|
||||
|
||||
ObjExporter(Mesh* mesh);
|
||||
void Export(const std::string& filePath);
|
||||
void WriteFaceGroups(std::ostringstream& builder, std::ostringstream& mtlBuilder);
|
||||
void WriteFaces(std::ostringstream& builder, const FaceList& faces);
|
||||
void WritePositions(std::ostringstream& builder);
|
||||
void WriteNormals(std::ostringstream& builder);
|
||||
void WriteUVs(std::ostringstream& builder);
|
||||
|
||||
private:
|
||||
std::string replace(const std::string &input, const std::string &search, const std::string &replace)
|
||||
{
|
||||
auto s = input;
|
||||
for (size_t pos = 0;; pos += replace.length())
|
||||
{
|
||||
// Locate the substring to replace
|
||||
pos = s.find(search, pos);
|
||||
if (pos == std::string::npos) break;
|
||||
// Replace by erasing and inserting
|
||||
s.erase(pos, search.length());
|
||||
s.insert(pos, replace);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
private:
|
||||
Mesh* mesh;
|
||||
};
|
||||
|
||||
#endif
|
||||
247
meshTools/test/src/main.cpp
Normal file
247
meshTools/test/src/main.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#include <TCHAR.h>
|
||||
|
||||
#include <tools/tools.h>
|
||||
#include "ObjExporter.h"
|
||||
|
||||
|
||||
void PlaceCubesOnPoints(const List<vec3*> points, Mesh* target, float size = 0.025f)
|
||||
{
|
||||
auto sphere = mt::CreateSphere(1, vec3::zero, size);
|
||||
|
||||
for (auto point : points)
|
||||
{
|
||||
auto faces = mt::CopyToMesh(sphere->GetFaces(), target);
|
||||
mt::MoveTo(mt::GetVertices(faces), *point);
|
||||
}
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
|
||||
void MakePointer(vec3 pos, vec3 dir, Mesh* mesh)
|
||||
{
|
||||
auto pointer = mt::CreateCube(true, vec3::zero, 0.1f);
|
||||
mt::Collapse(mt::GetFacesWithTag(pointer->GetFaces(), mt::Tags::DirectionUp));
|
||||
mt::Scale(pointer->GetVertices(), vec3{0.5f, 2, 0.5f});
|
||||
mt::MoveBy(pointer->GetVertices(), { 0, 0.1f, 0 });
|
||||
|
||||
mt::Rotate(pointer->GetVertices(), vec3::zero, vec3::up, dir);
|
||||
mt::MoveTo(pointer->GetVertices(), pos);
|
||||
mt::CopyToMesh(pointer->GetFaces(), mesh);
|
||||
|
||||
delete pointer;
|
||||
}
|
||||
|
||||
void DeleteOffsideFaces(const FaceList& faces, bool negate = false)
|
||||
{
|
||||
mt::Delete(mt::GetFacesByDirection(faces, negate ? vec3::right : vec3::left));
|
||||
}
|
||||
|
||||
|
||||
void MarkFaces(const FaceList& faces)
|
||||
{
|
||||
int i = 0;
|
||||
for (auto face : faces)
|
||||
face->SetMaterialId(i++);
|
||||
}
|
||||
|
||||
Mesh* Skull()
|
||||
{
|
||||
const int EYE = 0;
|
||||
const int BROW = 1;
|
||||
const int NOSE = 2;
|
||||
PERFORMANCER;
|
||||
auto mesh = mt::CreateSphere(2);
|
||||
const auto& meshFaces = mesh->GetFaces();
|
||||
mt::Scale(mesh->GetVertices(), vec3{ 1, 0.8f, 0.8f });
|
||||
mt::Delete(mt::GetFacesOnPositivePlane(meshFaces, { vec3::left, vec3::zero }));
|
||||
|
||||
{
|
||||
mt::FFD ffd(meshFaces, 1, 3, 3);
|
||||
|
||||
auto points = ffd.SelectPoints(0, 1, 0, 0, 3, 3);
|
||||
for (auto point : points)
|
||||
*point += vec3::forward * 0.1f;
|
||||
|
||||
points = ffd.SelectPoints(0, 0, 0, 0, 3, 3);
|
||||
for (auto point : points)
|
||||
*point += vec3::up * 0.15f;
|
||||
|
||||
points = ffd.SelectPoints(0, 1, 1, 1, 3, 3);
|
||||
for (auto point : points)
|
||||
*point += vec3::forward * 0.25f + vec3::up * 0.1f;
|
||||
|
||||
points = ffd.SelectPoints(0, 1, 2, 2, 3, 3);
|
||||
for (auto point : points)
|
||||
*point += vec3::forward * -0.1f;
|
||||
|
||||
points = ffd.SelectPoints(0, 1, 0, 0, 2, 2);
|
||||
for (auto point : points)
|
||||
*point += vec3::up * 0.15f + vec3::forward * 0.1f;
|
||||
|
||||
points = ffd.SelectPoints(0, 1, 0, 3, 3, 3);
|
||||
for (auto point : points)
|
||||
*point += vec3::up * 0.2f;
|
||||
|
||||
points = ffd.SelectPoints(1, 1, 0, 3, 3, 3);
|
||||
for (auto point : points)
|
||||
*point += vec3::left * 0.1f;
|
||||
|
||||
points = ffd.SelectPoints(1, 1, 0, 3, 0, 3);
|
||||
for (auto point : points)
|
||||
*point += vec3::left * 0.05f;
|
||||
|
||||
ffd.Apply();
|
||||
}
|
||||
// Chin
|
||||
FaceList selection;
|
||||
selection.Add(meshFaces[8]);
|
||||
selection.Add(meshFaces[9]);
|
||||
selection.Add(meshFaces[20]);
|
||||
selection.Add(meshFaces[23]);
|
||||
|
||||
auto vertices = mt::GetVertices(selection);
|
||||
vertices[0]->Position.x += 0.03f;
|
||||
mt::Flatten(vertices, vec3::down);
|
||||
mt::MoveBy(vertices, vec3{ 0, -0.08f, 0 });
|
||||
mt::Weld(mesh->GetVertices(), 0.05f);
|
||||
mt::Weld(mesh->GetVertices(), 0.05f);
|
||||
|
||||
mt::Rotate(mesh->GetVertices(), vec3::right, 0.2f);
|
||||
|
||||
DeleteOffsideFaces(mt::Extrude(selection, vec3{ 0, -0.05f, 0 }));
|
||||
|
||||
// Eye socket
|
||||
selection.Clear();
|
||||
selection.Add(meshFaces[42]);
|
||||
selection.Add(meshFaces[18]);
|
||||
|
||||
mt::Split(selection, { vec3::up, vec3::zero });
|
||||
|
||||
selection = Linq::ToList(meshFaces[54]);
|
||||
vertices = meshFaces[54]->GetVertices();
|
||||
vertices[0]->Position.x -= 0.09f;
|
||||
vertices[1]->Position.x -= 0.07f;
|
||||
vertices[2]->Position.y += 0.025f;
|
||||
vertices[3]->Position += vec3{ -0.02f, 0.05f, 0 };
|
||||
|
||||
auto brows = mt::Bevel(selection, 0, 0.9f);
|
||||
mt::AddTag(selection, EYE);
|
||||
mt::Scale(selection, 0.8f);
|
||||
|
||||
// Nose
|
||||
selection = Linq::ToList(meshFaces[53]);
|
||||
mt::Split(selection, { vec3::up, vec3{0, 0.08f, 0} });
|
||||
|
||||
vertices = meshFaces[16]->GetVertices();
|
||||
vertices[0]->Position.z -= 0.03f;
|
||||
|
||||
selection = Linq::ToList(meshFaces[55]);
|
||||
mt::Split(selection, { vec3::up, vec3{ 0, -0.08f, 0 } });
|
||||
|
||||
selection = Linq::ToList(meshFaces[53]);
|
||||
mt::Split(selection, { vec3::up, vec3{ 0, -0.08f, 0 } });
|
||||
|
||||
selection.Clear();
|
||||
selection.Add(meshFaces[61]);
|
||||
selection.Add(meshFaces[65]);
|
||||
mt::AddTag(selection, NOSE);
|
||||
|
||||
DeleteOffsideFaces(mt::Extrude(selection, vec3{ 0, 0.05f, -0.1f }), true);
|
||||
mt::Scale(selection, vec3::one * .5f, vec3::zero);
|
||||
|
||||
{
|
||||
mt::FFD ffd(meshFaces, 1, 2, 2);
|
||||
|
||||
// shrink upper head area
|
||||
auto points = ffd.SelectPoints(0, 1, 2, 2, 0, 2);
|
||||
for (auto point : points)
|
||||
{
|
||||
*point = vec3::Mul(*point, vec3(0.7f, 0.8f, 0.7f));
|
||||
point->z -= 0.1f;
|
||||
}
|
||||
|
||||
points = ffd.SelectPoints(0, 0, 2, 2, 0, 2);
|
||||
for (auto point : points)
|
||||
point->y += 0.03f;
|
||||
|
||||
// thinning the upper jaw
|
||||
points = ffd.SelectPoints(0, 1, 0, 0, 2, 2);
|
||||
for (auto point : points)
|
||||
{
|
||||
point->x *= 0.2f;
|
||||
point->z *= 0.9f;
|
||||
}
|
||||
|
||||
points = ffd.SelectPoints(1, 1, 0, 2, 0, 0);
|
||||
for (auto point : points)
|
||||
point->x *= 0.6f;
|
||||
|
||||
points = ffd.SelectPoints(1, 1, 0, 1, 0, 0);
|
||||
for (auto point : points)
|
||||
point->x *= 0.6f;
|
||||
|
||||
points = ffd.SelectPoints(0, 0, 0, 2, 2, 2);
|
||||
for (auto point : points)
|
||||
point->z -= 0.05f;
|
||||
|
||||
ffd.Apply();
|
||||
}
|
||||
|
||||
selection.Clear();
|
||||
selection.Add(meshFaces[26]);
|
||||
selection.Add(meshFaces[9]);
|
||||
selection.Add(meshFaces[31]);
|
||||
|
||||
vertices = mt::GetVertices(selection);
|
||||
vertices = Linq::Where(vertices, [](Vertex* vertex) { return vertex->Position.z > 0; });
|
||||
for (const auto& vertex : vertices)
|
||||
vertex->Position.x *= 0.3f;
|
||||
|
||||
selection = mt::GetFacesWithTag(meshFaces, EYE);
|
||||
mt::Bevel(selection, { 0, 0, -0.1f }, 0.7f);
|
||||
|
||||
selection.Clear();
|
||||
selection.Add(brows[3]);
|
||||
mt::Scale(selection, { 1, 2, 1 });
|
||||
mt::Bevel(selection, 0.02f, 0.5f);
|
||||
|
||||
selection = Linq::ToList(meshFaces[58]);
|
||||
vertices = mt::GetVertices(selection);
|
||||
vertices[0]->Position += vec3{ 0, -0.01f, 0.08f };
|
||||
vertices[1]->Position += vec3{ 0, -0.01f, 0.025f };
|
||||
MarkFaces(meshFaces);
|
||||
|
||||
// Finalize
|
||||
auto clone = mt::Copy(meshFaces);
|
||||
mt::Mirror(clone, { vec3::left, vec3::zero });
|
||||
|
||||
auto edges = mt::GetOutlineEdges(meshFaces);
|
||||
mt::Weld(edges);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
int _tmain()
|
||||
#else
|
||||
int mainCRTStartup()
|
||||
#endif
|
||||
{
|
||||
auto mesh = Skull();
|
||||
/*MakePointer(vec3::up, vec3::up, mesh);
|
||||
MakePointer(vec3::right, vec3::right, mesh);
|
||||
MakePointer(vec3::forward, vec3::forward, mesh);*/
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
ObjExporter exporter(mesh);
|
||||
exporter.Export("../Bin/export.obj");
|
||||
#endif
|
||||
|
||||
PERFORMANCER_DUMP
|
||||
return 0;
|
||||
}
|
||||
|
||||
102
meshTools/test/test.vcxproj
Normal file
102
meshTools/test/test.vcxproj
Normal file
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{6E7DF6F1-481D-41A2-84CD-27B2626BC21D}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>test</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)Bin\$(Configuration)\</OutDir>
|
||||
<IncludePath>$(SolutionDir)common/include;$(SolutionDir)math/include;$(SolutionDir)meshCore/include;$(SolutionDir)meshTools/include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)Bin\$(Configuration)\lib\;C:\Program Files %28x86%29\Visual Leak Detector\lib\Win32;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)Bin\$(Configuration)\</OutDir>
|
||||
<IncludePath>$(SolutionDir)meshTools/include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(SolutionDir);$(SolutionDir)Bin\$(Configuration)\lib\;C:\Program Files %28x86%29\Visual Leak Detector\lib\Win32;$(LibraryPath)</LibraryPath>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>meshTools.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<AdditionalOptions>/QIfist %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>msvcrt_old.LIB;meshTools.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalOptions>/CRINKLER %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\ObjExporter.cpp" />
|
||||
<ClCompile Include="src\main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\ObjExporter.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
30
meshTools/test/test.vcxproj.filters
Normal file
30
meshTools/test/test.vcxproj.filters
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\ObjExporter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\ObjExporter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
6
meshTools/test/test.vcxproj.user
Normal file
6
meshTools/test/test.vcxproj.user
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ShowAllFiles>true</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user