mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-01 18:13:48 +00:00
Core/Misc: update g3dlite lib (#2904)
* Core/Misc: update g3dlite lib * update Co-authored-by: Francesco Borzì <borzifrancesco@gmail.com>
This commit is contained in:
276
deps/g3dlite/source/Welder.cpp
vendored
276
deps/g3dlite/source/Welder.cpp
vendored
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
@file Welder.cpp
|
||||
\file Welder.cpp
|
||||
|
||||
@author Morgan McGuire, Kyle Whitson, Corey Taylor
|
||||
\author Morgan McGuire, Kyle Whitson, Corey Taylor
|
||||
|
||||
@created 2008-07-30
|
||||
@edited 2009-11-29
|
||||
\created 2008-07-30
|
||||
\edited 2011-07-04
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
@@ -17,9 +17,14 @@
|
||||
#include "G3D/AreaMemoryManager.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
namespace G3D { namespace _internal{
|
||||
|
||||
// Uncomment to print information that can help with performance
|
||||
// profiling.
|
||||
//#define VERBOSE
|
||||
|
||||
/** Used by WeldHelper2::smoothNormals. */
|
||||
class VN {
|
||||
@@ -98,11 +103,11 @@ private:
|
||||
*/
|
||||
int getIndex(const Vector3& v, const Vector3& n, const Vector2& t) {
|
||||
PointHashGrid<VNTi>::SphereIterator it =
|
||||
weldGrid.beginSphereIntersection(Sphere(v, vertexWeldRadius));
|
||||
weldGrid.begin(Sphere(v, vertexWeldRadius));
|
||||
|
||||
if (n.isZero()) {
|
||||
// Don't bother trying to match the surface normal, since this vertex has no surface normal.
|
||||
while (it.hasMore()) {
|
||||
while (it.isValid()) {
|
||||
if ((t - it->texCoord).squaredLength() <= texCoordWeldRadius2) {
|
||||
// This is the vertex
|
||||
return it->index;
|
||||
@@ -110,7 +115,7 @@ private:
|
||||
++it;
|
||||
}
|
||||
} else {
|
||||
while (it.hasMore()) {
|
||||
while (it.isValid()) {
|
||||
if (((n - it->normal).squaredLength() <= normalWeldRadius2) &&
|
||||
((t - it->texCoord).squaredLength() <= texCoordWeldRadius2)) {
|
||||
// This is the vertex
|
||||
@@ -142,12 +147,16 @@ private:
|
||||
|
||||
Called from process()
|
||||
*/
|
||||
void updateTriLists(
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
const Array<Vector2>& texCoordArray) {
|
||||
|
||||
void updateTriLists
|
||||
(Array<Array<int>*>& indexArrayArray,
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
const Array<Vector2>& texCoordArray) {
|
||||
|
||||
# ifdef VERBOSE
|
||||
debugPrintf("WeldHelper::updateTriLists\n");
|
||||
# endif
|
||||
|
||||
// Compute a hash grid so that we can find neighbors quickly.
|
||||
// It begins empty and is extended as the tri lists are iterated
|
||||
// through.
|
||||
@@ -183,13 +192,17 @@ private:
|
||||
/** Expands the indexed triangle lists into a triangle list.
|
||||
|
||||
Called from process() */
|
||||
void unroll(
|
||||
const Array<Array<int>*>& indexArrayArray,
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& unrolledVertexArray,
|
||||
Array<Vector2>& unrolledTexCoordArray) {
|
||||
void unroll
|
||||
(const Array<Array<int>*>& indexArrayArray,
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& unrolledVertexArray,
|
||||
Array<Vector2>& unrolledTexCoordArray) {
|
||||
|
||||
# ifdef VERBOSE
|
||||
debugPrintf("WeldHelper::unroll\n");
|
||||
# endif
|
||||
|
||||
int numTriLists = indexArrayArray.size();
|
||||
for (int t = 0; t < numTriLists; ++t) {
|
||||
if (indexArrayArray[t] != NULL) {
|
||||
@@ -206,9 +219,12 @@ private:
|
||||
/** For every three vertices, compute the face normal and store it three times.
|
||||
Sliver triangles have a zero surface normal, which we will later take to
|
||||
match *any* surface normal. */
|
||||
void computeFaceNormals(
|
||||
const Array<Vector3>& vertexArray,
|
||||
Array<Vector3>& faceNormalArray) {
|
||||
void computeFaceNormals
|
||||
(const Array<Vector3>& vertexArray,
|
||||
Array<Vector3>& faceNormalArray) {
|
||||
# ifdef VERBOSE
|
||||
debugPrintf("WeldHelper::computeFaceNormals\n");
|
||||
# endif
|
||||
|
||||
debugAssertM(vertexArray.size() % 3 == 0, "Input is not a triangle soup");
|
||||
debugAssertM(faceNormalArray.size() == 0, "Output must start empty.");
|
||||
@@ -231,17 +247,19 @@ private:
|
||||
Computes @a smoothNormalArray, whose elements are those of normalArray averaged
|
||||
with neighbors within the angular cutoff.
|
||||
*/
|
||||
void smoothNormals(
|
||||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
Array<Vector3>& smoothNormalArray) {
|
||||
|
||||
void smoothNormals
|
||||
(const Array<Point3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
Array<Vector3>& smoothNormalArray) {
|
||||
if (normalSmoothingAngle <= 0) {
|
||||
smoothNormalArray = normalArray;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
# ifdef VERBOSE
|
||||
debugPrintf("WeldHelper::smoothNormals\n");
|
||||
# endif
|
||||
|
||||
// Create an area memory manager for fast deallocation
|
||||
MemoryManager::Ref mm = AreaMemoryManager::create(iRound(sizeof(VN) * normalArray.size() * 1.5));
|
||||
|
||||
@@ -250,53 +268,110 @@ private:
|
||||
debugAssert(vertexArray.size() == normalArray.size());
|
||||
smoothNormalArray.resize(normalArray.size());
|
||||
|
||||
// Compute a hash grid so that we can find neighbors quickly.
|
||||
PointHashGrid<VN> grid(vertexWeldRadius, mm);
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
grid.insert(VN(vertexArray[v], normalArray[v]));
|
||||
}
|
||||
if (vertexWeldRadius == 0) {
|
||||
// Look for vertices with the exactly identical normal only
|
||||
# ifdef VERBOSE
|
||||
debugPrintf("Taking fast path\n");
|
||||
# endif
|
||||
|
||||
// TODO: this step could be done on multiple threads
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
// Compute the sum of all nearby normals within the cutoff angle.
|
||||
// Search within the vertexWeldRadius, since those are the vertices
|
||||
// that will collapse to the same point.
|
||||
PointHashGrid<VN>::SphereIterator it =
|
||||
grid.beginSphereIntersection(Sphere(vertexArray[v], vertexWeldRadius));
|
||||
// Maximum expected faces that meet at a vertex
|
||||
static const int k = 8;
|
||||
|
||||
Vector3 sum;
|
||||
|
||||
const Vector3& original = normalArray[v];
|
||||
while (it.hasMore()) {
|
||||
const Vector3& N = it->normal;
|
||||
const float cosAngle = N.dot(original);
|
||||
|
||||
if (cosAngle > cosThresholdAngle) {
|
||||
// This normal is close enough to consider. Avoid underflow by scaling up
|
||||
sum += (N * 256.0f);
|
||||
}
|
||||
++it;
|
||||
// Maps vertices to the indices of normals at that vertex
|
||||
Table<Point3, SmallArray<Vector3, k> > normalTable;
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
bool ignore = false;
|
||||
SmallArray<Vector3, k>& list = normalTable.getCreate(vertexArray[v], ignore);
|
||||
list.append(normalArray[v]);
|
||||
}
|
||||
|
||||
const Vector3& average = sum.directionOrZero();
|
||||
for (int v = 0; v < vertexArray.size(); ++v) {
|
||||
Vector3 sum;
|
||||
|
||||
const bool indeterminate = average.isZero();
|
||||
// Never "smooth" a normal so far that it points backwards
|
||||
const bool backFacing = original.dot(average) < 0;
|
||||
const Vector3& original = normalArray[v];
|
||||
|
||||
if (indeterminate || backFacing) {
|
||||
// Revert to the face normal
|
||||
smoothNormalArray[v] = original;
|
||||
} else {
|
||||
// Average available normals
|
||||
smoothNormalArray[v] = average;
|
||||
const SmallArray<Vector3, k>& list = normalTable[vertexArray[v]];
|
||||
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
const Vector3& N = list[i];
|
||||
const float cosAngle = N.dot(original);
|
||||
|
||||
if (cosAngle > cosThresholdAngle) {
|
||||
// This normal is close enough to consider. Avoid underflow by scaling up
|
||||
sum += (N * 256.0f);
|
||||
}
|
||||
}
|
||||
|
||||
const Vector3& average = sum.directionOrZero();
|
||||
|
||||
const bool indeterminate = average.isZero();
|
||||
// Never "smooth" a normal so far that it points backwards
|
||||
const bool backFacing = original.dot(average) < 0;
|
||||
|
||||
if (indeterminate || backFacing) {
|
||||
// Revert to the face normal
|
||||
smoothNormalArray[v] = original;
|
||||
} else {
|
||||
// Average available normals
|
||||
smoothNormalArray[v] = average;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Non-zero vertex normal welding
|
||||
# ifdef VERBOSE
|
||||
debugPrintf("Taking slower weld path because vertexWeldRadius = %f\n",
|
||||
vertexWeldRadius);
|
||||
# endif
|
||||
|
||||
// Compute a hash grid so that we can find neighbors quickly.
|
||||
alwaysAssertM(vertexWeldRadius > 0, "Cannot smooth with zero vertex weld radius");
|
||||
PointHashGrid<VN> grid(vertexWeldRadius, mm);
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
grid.insert(VN(vertexArray[v], normalArray[v]));
|
||||
}
|
||||
|
||||
// OPT: this step could be done on multiple threads
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
// Compute the sum of all nearby normals within the cutoff angle.
|
||||
// Search within the vertexWeldRadius, since those are the vertices
|
||||
// that will collapse to the same point.
|
||||
PointHashGrid<VN>::SphereIterator it =
|
||||
grid.begin(Sphere(vertexArray[v], vertexWeldRadius));
|
||||
|
||||
Vector3 sum;
|
||||
|
||||
const Vector3& original = normalArray[v];
|
||||
while (it.isValid()) {
|
||||
const Vector3& N = it->normal;
|
||||
const float cosAngle = N.dot(original);
|
||||
|
||||
if (cosAngle > cosThresholdAngle) {
|
||||
// This normal is close enough to consider. Avoid underflow by scaling up
|
||||
sum += (N * 256.0f);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
const Vector3& average = sum.directionOrZero();
|
||||
|
||||
const bool indeterminate = average.isZero();
|
||||
// Never "smooth" a normal so far that it points backwards
|
||||
const bool backFacing = original.dot(average) < 0;
|
||||
|
||||
if (indeterminate || backFacing) {
|
||||
// Revert to the face normal
|
||||
smoothNormalArray[v] = original;
|
||||
} else {
|
||||
// Average available normals
|
||||
smoothNormalArray[v] = average;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
Algorithm:
|
||||
|
||||
@@ -311,14 +386,17 @@ public:
|
||||
4. Generate output indexArrayArray. While doing so, merge all vertices where
|
||||
the distance between position, texCoord, and normal is within the thresholds.
|
||||
*/
|
||||
void process(
|
||||
Array<Vector3>& vertexArray,
|
||||
Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& normalArray,
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
float normAngle,
|
||||
float texRadius,
|
||||
float normRadius) {
|
||||
void process
|
||||
( Array<Vector3>& vertexArray,
|
||||
Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& normalArray,
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
float normAngle,
|
||||
float texRadius,
|
||||
float normRadius) {
|
||||
# ifdef VERBOSE
|
||||
debugPrintf("WeldHelper::process\n");
|
||||
# endif
|
||||
|
||||
normalSmoothingAngle = normAngle;
|
||||
normalWeldRadius2 = square(normRadius);
|
||||
@@ -331,11 +409,17 @@ public:
|
||||
"Input arrays are not parallel.");
|
||||
}
|
||||
|
||||
// Create an area memory manager for fast deallocation
|
||||
Array<Vector3> unrolledVertexArray;
|
||||
Array<Vector3> unrolledFaceNormalArray;
|
||||
Array<Vector3> unrolledSmoothNormalArray;
|
||||
Array<Vector2> unrolledTexCoordArray;
|
||||
|
||||
unrolledVertexArray.reserve(vertexArray.size());
|
||||
unrolledFaceNormalArray.reserve(vertexArray.size());
|
||||
unrolledSmoothNormalArray.reserve(vertexArray.size());
|
||||
unrolledTexCoordArray.reserve(vertexArray.size());
|
||||
|
||||
if (! hasTexCoords) {
|
||||
// Generate all zero texture coordinates
|
||||
texCoordArray.resize(vertexArray.size());
|
||||
@@ -373,23 +457,40 @@ public:
|
||||
}
|
||||
|
||||
WeldHelper(float vertRadius) :
|
||||
weldGrid(vertRadius, AreaMemoryManager::create()),
|
||||
weldGrid(max(vertRadius, 0.1f), AreaMemoryManager::create()),
|
||||
vertexWeldRadius(vertRadius) {
|
||||
}
|
||||
|
||||
};
|
||||
} // Internal
|
||||
|
||||
void Welder::weld(
|
||||
Array<Vector3>& vertexArray,
|
||||
Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& normalArray,
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
const Welder::Settings& settings) {
|
||||
|
||||
_internal::WeldHelper(settings.vertexWeldRadius).process(
|
||||
vertexArray, texCoordArray, normalArray, indexArrayArray,
|
||||
settings.normalSmoothingAngle, settings.textureWeldRadius, settings.normalWeldRadius);
|
||||
void Welder::Settings::serialize(class BinaryOutput& b) const {
|
||||
b.writeFloat32(normalSmoothingAngle);
|
||||
b.writeFloat32(vertexWeldRadius);
|
||||
b.writeFloat32(textureWeldRadius);
|
||||
b.writeFloat32(normalWeldRadius);
|
||||
}
|
||||
|
||||
|
||||
void Welder::Settings::deserialize(class BinaryInput& b) {
|
||||
normalSmoothingAngle = b.readFloat32();
|
||||
vertexWeldRadius = b.readFloat32();
|
||||
textureWeldRadius = b.readFloat32();
|
||||
normalWeldRadius = b.readFloat32();
|
||||
}
|
||||
|
||||
|
||||
void Welder::weld
|
||||
(Array<Vector3>& vertexArray,
|
||||
Array<Vector2>& texCoordArray,
|
||||
Array<Vector3>& normalArray,
|
||||
Array<Array<int>*>& indexArrayArray,
|
||||
const Welder::Settings& settings) {
|
||||
|
||||
_internal::WeldHelper(settings.vertexWeldRadius).process
|
||||
(vertexArray, texCoordArray, normalArray, indexArrayArray,
|
||||
settings.normalSmoothingAngle, settings.textureWeldRadius, settings.normalWeldRadius);
|
||||
|
||||
}
|
||||
|
||||
@@ -397,7 +498,7 @@ void Welder::weld(
|
||||
Welder::Settings::Settings(const Any& any) {
|
||||
*this = Settings();
|
||||
any.verifyName("Welder::Settings");
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.isValid(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "normalsmoothingangle") {
|
||||
normalSmoothingAngle = it->value;
|
||||
@@ -413,12 +514,13 @@ Welder::Settings::Settings(const Any& any) {
|
||||
}
|
||||
}
|
||||
|
||||
Welder::Settings::operator Any() const {
|
||||
|
||||
Any Welder::Settings::toAny() const {
|
||||
Any a(Any::TABLE, "Welder::Settings");
|
||||
a.set("normalSmoothingAngle", normalSmoothingAngle);
|
||||
a.set("vertexWeldRadius", vertexWeldRadius);
|
||||
a.set("textureWeldRadius", textureWeldRadius);
|
||||
a.set("normalWeldRadius", normalWeldRadius);
|
||||
a["normalSmoothingAngle"] = normalSmoothingAngle;
|
||||
a["vertexWeldRadius"] = vertexWeldRadius;
|
||||
a["textureWeldRadius"] = textureWeldRadius;
|
||||
a["normalWeldRadius"] = normalWeldRadius;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user