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:
Viste
2020-07-30 13:35:45 +03:00
committed by GitHub
parent 91bbbf08eb
commit fcaf91b8b2
183 changed files with 13258 additions and 8022 deletions

View File

@@ -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;
}