aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h')
-rw-r--r--APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h1064
1 files changed, 1064 insertions, 0 deletions
diff --git a/APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h b/APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h
new file mode 100644
index 00000000..ebfb105a
--- /dev/null
+++ b/APEX_1.4/shared/internal/include/authoring/ApexCSGDefs.h
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#ifndef APEX_CSG_DEFS_H
+#define APEX_CSG_DEFS_H
+
+#include "ApexUsingNamespace.h"
+#include "ApexSharedUtils.h"
+#include "ApexRand.h"
+#include "Link.h"
+#include "authoring/ApexCSG.h"
+#include "authoring/ApexCSGMath.h"
+#include "authoring/ApexGSA.h"
+#include "PsUserAllocated.h"
+#include "ApexGSA.h"
+
+#ifndef WITHOUT_APEX_AUTHORING
+
+namespace ApexCSG
+{
+
+// Binary tree node
+class BinaryNode
+{
+public:
+ PX_INLINE BinaryNode();
+
+ PX_INLINE void setChild(uint32_t index, BinaryNode* child);
+
+ PX_INLINE void detach();
+
+ PX_INLINE BinaryNode* getParent() const
+ {
+ return m_parent;
+ }
+
+ PX_INLINE BinaryNode* getChild(uint32_t index) const
+ {
+ PX_ASSERT((index & 1) == index);
+ return m_children[index & 1];
+ }
+
+ PX_INLINE uint32_t getIndex() const
+ {
+ return m_index;
+ }
+
+protected:
+ BinaryNode* m_parent;
+ BinaryNode* m_children[2];
+ uint32_t m_index; // index of this node in parent (0xFFFFFFFF => not attached)
+};
+
+PX_INLINE
+BinaryNode::BinaryNode()
+{
+ m_index = 0xFFFFFFFF;
+ m_children[1] = m_children[0] = m_parent = NULL;
+}
+
+PX_INLINE void
+BinaryNode::setChild(uint32_t index, BinaryNode* child)
+{
+ index &= 1;
+ BinaryNode*& oldChild = m_children[index];
+
+ if (oldChild != NULL)
+ {
+ oldChild->detach();
+ }
+
+ oldChild = child;
+
+ if (child != NULL)
+ {
+ child->detach();
+ child->m_parent = this;
+ child->m_index = index;
+ }
+}
+
+PX_INLINE void
+BinaryNode::detach()
+{
+ if (m_parent != NULL)
+ {
+ PX_ASSERT(m_parent->getChild(m_index) == this);
+ m_parent->m_children[m_index & 1] = NULL;
+ m_parent = NULL;
+ m_index = 0xFFFFFFFF;
+ }
+}
+
+
+// CSG mesh representation
+
+class UV : public Vec<Real, 2>
+{
+public:
+
+ PX_INLINE UV() {}
+ PX_INLINE UV(const float* uv)
+ {
+ set((Real)uv[0], (Real)uv[1]);
+ }
+ PX_INLINE UV(const double* uv)
+ {
+ set((Real)uv[0], (Real)uv[1]);
+ }
+ PX_INLINE UV& operator = (const UV& uv)
+ {
+ el[0] = uv.el[0];
+ el[1] = uv.el[1];
+ return *this;
+ }
+
+ PX_INLINE void set(Real u, Real v)
+ {
+ el[0] = u;
+ el[1] = v;
+ }
+
+ PX_INLINE const Real& u() const
+ {
+ return el[0];
+ }
+ PX_INLINE const Real& v() const
+ {
+ return el[1];
+ }
+};
+
+class Color : public Vec<Real, 4>
+{
+public:
+
+ PX_INLINE Color() {}
+ PX_INLINE Color(const uint32_t c);
+ PX_INLINE Color& operator = (const Color& c)
+ {
+ el[0] = c.el[0];
+ el[1] = c.el[1];
+ el[2] = c.el[2];
+ el[3] = c.el[3];
+ return *this;
+ }
+
+ PX_INLINE void set(Real r, Real g, Real b, Real a)
+ {
+ el[0] = r;
+ el[1] = g;
+ el[2] = b;
+ el[3] = a;
+ }
+
+ PX_INLINE uint32_t toInt() const;
+
+ PX_INLINE const Real& r() const
+ {
+ return el[0];
+ }
+ PX_INLINE const Real& g() const
+ {
+ return el[1];
+ }
+ PX_INLINE const Real& b() const
+ {
+ return el[2];
+ }
+ PX_INLINE const Real& a() const
+ {
+ return el[3];
+ }
+};
+
+PX_INLINE
+Color::Color(const uint32_t c)
+{
+ const Real recip255 = 1 / (Real)255;
+ set((Real)(c & 0xFF)*recip255, (Real)((c >> 8) & 0xFF)*recip255, (Real)((c >> 16) & 0xFF)*recip255, (Real)(c >> 24)*recip255);
+}
+
+PX_INLINE uint32_t
+Color::toInt() const
+{
+ return (uint32_t)((int)(255 * el[3] + (Real)0.5)) << 24 | (uint32_t)((int)(255 * el[2] + (Real)0.5)) << 16 | (uint32_t)((int)(255 * el[1] + (Real)0.5)) << 8 | (uint32_t)((int)(255 * el[0] + (Real)0.5));
+}
+
+struct VertexData
+{
+ Dir normal;
+ Dir tangent;
+ Dir binormal;
+ UV uv[nvidia::VertexFormat::MAX_UV_COUNT];
+ Color color;
+};
+
+struct Triangle
+{
+ Pos vertices[3];
+ Dir normal;
+ Real area;
+ int32_t submeshIndex;
+ uint32_t smoothingMask;
+ uint32_t extraDataIndex;
+
+ void fromExplicitRenderTriangle(VertexData vertexData[3], const nvidia::ExplicitRenderTriangle& tri)
+ {
+ for (unsigned i = 0; i < 3; ++i)
+ {
+ vertices[i] = Pos(tri.vertices[i].position);
+ vertexData[i].normal = Dir(tri.vertices[i].normal);
+ vertexData[i].tangent = Dir(tri.vertices[i].tangent);
+ vertexData[i].binormal = Dir(tri.vertices[i].binormal);
+ for (unsigned j = 0; j < nvidia::VertexFormat::MAX_UV_COUNT; ++j)
+ {
+ vertexData[i].uv[j] = UV(&tri.vertices[i].uv[j][0]);
+ }
+ vertexData[i].color.set((Real)tri.vertices[i].color.r, (Real)tri.vertices[i].color.g, (Real)tri.vertices[i].color.b, (Real)tri.vertices[i].color.a);
+ }
+ submeshIndex = tri.submeshIndex;
+ smoothingMask = tri.smoothingMask;
+ extraDataIndex = tri.extraDataIndex;
+ calculateQuantities();
+ }
+
+ void toExplicitRenderTriangle(nvidia::ExplicitRenderTriangle& tri, const VertexData vertexData[3]) const
+ {
+ for (unsigned i = 0; i < 3; ++i)
+ {
+ tri.vertices[i].position = ApexCSG::GSA::toPxVec3(vertices[i]);
+ tri.vertices[i].normal = ApexCSG::GSA::toPxVec3(vertexData[i].normal);
+ tri.vertices[i].tangent = ApexCSG::GSA::toPxVec3(vertexData[i].tangent);
+ tri.vertices[i].binormal = ApexCSG::GSA::toPxVec3(vertexData[i].binormal);
+ for (unsigned j = 0; j < nvidia::VertexFormat::MAX_UV_COUNT; ++j)
+ {
+ tri.vertices[i].uv[j].set((float)vertexData[i].uv[j][0], (float)vertexData[i].uv[j][1]);
+ }
+ tri.vertices[i].color.set((float)vertexData[i].color.r(), (float)vertexData[i].color.g(), (float)vertexData[i].color.b(), (float)vertexData[i].color.a());
+ }
+ tri.submeshIndex = submeshIndex;
+ tri.smoothingMask = smoothingMask;
+ tri.extraDataIndex = extraDataIndex;
+ }
+
+ void calculateQuantities()
+ {
+ const Dir e0 = Dir(vertices[1] - vertices[0]);
+ const Dir e1 = Dir(vertices[2] - vertices[1]);
+ const Dir e2 = Dir(vertices[0] - vertices[2]);
+ normal = (e0^e1) + (e1^e2) + (e2^e0);
+ area = (Real)0.5 * normal.normalize();
+ }
+
+ void transform(const Mat4Real& tm)
+ {
+ for (int i = 0; i < 3; ++i)
+ {
+ vertices[i] = tm*vertices[i];
+ }
+ calculateQuantities();
+ }
+};
+
+struct LinkedVertex : public nvidia::Link
+{
+ LinkedVertex* getAdj(uint32_t which) const
+ {
+ return (LinkedVertex*)nvidia::Link::getAdj(which);
+ }
+
+ Pos vertex;
+};
+
+struct LinkedEdge2D : public nvidia::Link
+{
+ LinkedEdge2D() : loopID(-1) {}
+ ~LinkedEdge2D()
+ {
+ remove();
+ }
+
+ void setAdj(uint32_t which, LinkedEdge2D* link)
+ {
+ // Ensure neighboring links' adjoining vertices are equal
+ which &= 1;
+ const uint32_t other = which ^ 1;
+ v[which] = link->v[other];
+ ((LinkedEdge2D*)link->adj[other])->v[which] = ((LinkedEdge2D*)adj[which])->v[other];
+ nvidia::Link::setAdj(which, link);
+ }
+
+ LinkedEdge2D* getAdj(uint32_t which) const
+ {
+ return (LinkedEdge2D*)nvidia::Link::getAdj(which);
+ }
+
+ void remove()
+ {
+ // Ensure neighboring links' adjoining vertices are equal
+ ((LinkedEdge2D*)adj[0])->v[1] = ((LinkedEdge2D*)adj[1])->v[0] = (Real)0.5 * (v[0] + v[1]);
+ nvidia::Link::remove();
+ }
+
+ Vec2Real v[2];
+ int32_t loopID;
+};
+
+struct Surface
+{
+ uint32_t planeIndex;
+ uint32_t triangleIndexStart;
+ uint32_t triangleIndexStop;
+ float totalTriangleArea; // Keeping it 32-bit real, since we don't need precision here
+};
+
+struct Region
+{
+ uint32_t side;
+
+ // Not to be serialized, but we have this extra space since Region is used in a union with Surface
+ uint32_t tempIndex1;
+ uint32_t tempIndex2;
+ uint32_t tempIndex3;
+};
+
+
+// Interpolator - calculates interpolation data for triangle quantities
+class Interpolator
+{
+public:
+
+ enum VertexField
+ {
+ Normal_x, Normal_y, Normal_z,
+ Tangent_x, Tangent_y, Tangent_z,
+ Binormal_x, Binormal_y, Binormal_z,
+ UV0_u, UV0_v, UV1_u, UV1_v, UV2_u, UV2_v, UV3_u, UV3_v,
+ Color_r, Color_g, Color_b, Color_a,
+
+ VertexFieldCount
+ };
+
+ Interpolator() {}
+ Interpolator(const Triangle& tri, const VertexData vertexData[3])
+ {
+ setFromTriangle(tri, vertexData);
+ }
+ Interpolator(const Dir tangents[3], const Vec<Real, 2>& uvScale)
+ {
+ setFlat(tangents, uvScale);
+ }
+
+ PX_INLINE void setFromTriangle(const Triangle& tri, const VertexData vertexData[3]);
+ PX_INLINE void setFlat(const Dir tangents[3], const Vec<Real, 2>& uvScale);
+
+ PX_INLINE void interpolateVertexData(VertexData& vertexData, const Pos& point) const;
+
+ PX_INLINE bool equals(const Interpolator& interpolator, Real frameDirTol, Real frameScaleTol, Real dirTol, Real uvTol, Real colorTol) const;
+
+ PX_INLINE void transform(Interpolator& transformedInterpolator, const Mat4Real& tm, const Mat4Real& cofTM) const;
+
+ void serialize(physx::PxFileBuf& stream) const;
+ void deserialize(physx::PxFileBuf& stream, uint32_t version);
+
+private:
+ ApexCSG::Plane m_frames[VertexFieldCount];
+ static size_t s_offsets[VertexFieldCount];
+
+ friend class InterpolatorBuilder;
+};
+
+PX_INLINE void
+Interpolator::setFromTriangle(const Triangle& tri, const VertexData vertexData[3])
+{
+ const Pos& p0 = tri.vertices[0];
+ const Pos& p1 = tri.vertices[1];
+ const Pos& p2 = tri.vertices[2];
+ const Dir p1xp2 = Dir(p1) ^ Dir(p2);
+ const Dir p2xp0 = Dir(p2) ^ Dir(p0);
+ const Dir p0xp1 = Dir(p0) ^ Dir(p1);
+ const Dir n = p1xp2 + p2xp0 + p0xp1;
+ const Real n2 = n | n;
+ if (n2 < EPS_REAL * EPS_REAL)
+ {
+ for (uint32_t i = 0; i < VertexFieldCount; ++i)
+ {
+ m_frames[i].set(Dir((Real)0), 0);
+ }
+ return;
+ }
+
+ // Calculate inverse 4x4 matrix (only need first three columns):
+ const Dir nP = n / n2; // determinant is -n2
+ const Dir Q0(nP[2] * (p1[1] - p2[1]) - nP[1] * (p1[2] - p2[2]), nP[2] * (p2[1] - p0[1]) - nP[1] * (p2[2] - p0[2]), nP[2] * (p0[1] - p1[1]) - nP[1] * (p0[2] - p1[2]));
+ const Dir Q1(nP[0] * (p1[2] - p2[2]) - nP[2] * (p1[0] - p2[0]), nP[0] * (p2[2] - p0[2]) - nP[2] * (p2[0] - p0[0]), nP[0] * (p0[2] - p1[2]) - nP[2] * (p0[0] - p1[0]));
+ const Dir Q2(nP[1] * (p1[0] - p2[0]) - nP[0] * (p1[1] - p2[1]), nP[1] * (p2[0] - p0[0]) - nP[0] * (p2[1] - p0[1]), nP[1] * (p0[0] - p1[0]) - nP[0] * (p0[1] - p1[1]));
+ const Dir r(nP | p1xp2, nP | p2xp0, nP | p0xp1);
+
+ for (uint32_t i = 0; i < VertexFieldCount; ++i)
+ {
+ const size_t offset = s_offsets[i];
+ const Dir vi(*(Real*)(((uint8_t*)&vertexData[0]) + offset), *(Real*)(((uint8_t*)&vertexData[1]) + offset), *(Real*)(((uint8_t*)&vertexData[2]) + offset));
+ Dir n(Q0 | vi, Q1 | vi, Q2 | vi);
+ if ((n | n) < 100 * EPS_REAL * EPS_REAL)
+ {
+ n.set((Real)0, (Real)0, (Real)0);
+ }
+ Real o = r | vi;
+ if (physx::PxAbs(o) < 100 * EPS_REAL)
+ {
+ o = (Real)0;
+ }
+ m_frames[i].set(n, o);
+ }
+}
+
+PX_INLINE void
+Interpolator::setFlat(const Dir tangents[3], const Vec<Real, 2>& uvScale)
+{
+ // Local z ~ normal = tangents[2], x ~ u and tangent = tangents[0], y ~ v and binormal = tangents[1]
+ m_frames[Normal_x].set(Dir((Real)0), tangents[2][0]);
+ m_frames[Normal_y].set(Dir((Real)0), tangents[2][1]);
+ m_frames[Normal_z].set(Dir((Real)0), tangents[2][2]);
+ m_frames[Tangent_x].set(Dir((Real)0), tangents[0][0]);
+ m_frames[Tangent_y].set(Dir((Real)0), tangents[0][1]);
+ m_frames[Tangent_z].set(Dir((Real)0), tangents[0][2]);
+ m_frames[Binormal_x].set(Dir((Real)0), tangents[1][0]);
+ m_frames[Binormal_y].set(Dir((Real)0), tangents[1][1]);
+ m_frames[Binormal_z].set(Dir((Real)0), tangents[1][2]);
+ const Dir su = (uvScale[0] ? 1 / uvScale[0] : (Real)0) * tangents[0];
+ const Dir sv = (uvScale[1] ? 1 / uvScale[1] : (Real)0) * tangents[1];
+ m_frames[UV0_u].set(su, 0);
+ m_frames[UV0_v].set(sv, 0);
+ m_frames[UV1_u].set(su, 0);
+ m_frames[UV1_v].set(sv, 0);
+ m_frames[UV2_u].set(su, 0);
+ m_frames[UV2_v].set(sv, 0);
+ m_frames[UV3_u].set(su, 0);
+ m_frames[UV3_v].set(sv, 0);
+ m_frames[Color_r].set(Dir((Real)0), (Real)1);
+ m_frames[Color_g].set(Dir((Real)0), (Real)1);
+ m_frames[Color_b].set(Dir((Real)0), (Real)1);
+ m_frames[Color_a].set(Dir((Real)0), (Real)1);
+}
+
+PX_INLINE void
+Interpolator::interpolateVertexData(VertexData& vertexData, const Pos& point) const
+{
+ for (uint32_t i = 0; i < VertexFieldCount; ++i)
+ {
+ Real& value = *(Real*)(((uint8_t*)&vertexData) + s_offsets[i]);
+ value = m_frames[i].distance(point);
+ }
+}
+
+PX_INLINE bool
+framesEqual(const Plane& f0, const Plane& f1, Real twoFrameScaleTol2, Real sinFrameTol2, Real tol2)
+{
+ const Dir n0 = f0.normal();
+ const Dir n1 = f1.normal();
+ const Real n02 = n0 | n0;
+ const Real n12 = n1 | n1;
+ const Real n2Diff = n02 - n12;
+
+ if (n2Diff * n2Diff > twoFrameScaleTol2 * (n02 + n12))
+ {
+ return false; // Scales differ by more than frame scale tolerance
+ }
+
+ const Real n2Prod = n02 * n12;
+ const Real unnormalizedSinFrameTheta2 = (n0 ^ n1).lengthSquared();
+ if (unnormalizedSinFrameTheta2 > n2Prod * sinFrameTol2)
+ {
+ return false; // Directions differ by more than frame angle tolerance
+ }
+
+ const Real unnormalizedOriginDiff = f0.d() - f1.d();
+ const Real originScale = 0.5f * (physx::PxAbs(f0.d()) + physx::PxAbs(f1.d()));
+ if (unnormalizedOriginDiff * unnormalizedOriginDiff > tol2 * originScale * originScale)
+ {
+ return false; // Origins differ by more than tolerance
+ }
+
+ return true;
+}
+
+PX_INLINE bool
+Interpolator::equals(const Interpolator& interpolator, Real frameDirTol, Real frameScaleTol, Real dirTol, Real uvTol, Real colorTol) const
+{
+ const Real twoFrameScaleTol2 = (Real)2 * frameScaleTol * frameScaleTol;
+ const Real sinFrameTol2 = frameDirTol * frameDirTol;
+ const Real dirTol2 = dirTol * dirTol;
+ const Real uvTol2 = uvTol * uvTol;
+ const Real colorTol2 = colorTol * colorTol;
+
+ // Directions
+ for (uint32_t i = Normal_x; i <= Binormal_z; ++i)
+ {
+ if (!framesEqual(m_frames[i], interpolator.m_frames[i], twoFrameScaleTol2, sinFrameTol2, dirTol2))
+ {
+ return false;
+ }
+ }
+
+ // UVs
+ for (uint32_t i = UV0_u; i <= UV3_v; ++i)
+ {
+ if (!framesEqual(m_frames[i], interpolator.m_frames[i], twoFrameScaleTol2, sinFrameTol2, uvTol2))
+ {
+ return false;
+ }
+ }
+
+ // Color
+ for (uint32_t i = Color_r; i <= Color_a; ++i)
+ {
+ if (!framesEqual(m_frames[i], interpolator.m_frames[i], twoFrameScaleTol2, sinFrameTol2, colorTol2))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+PX_INLINE void
+Interpolator::transform(Interpolator& transformedInterpolator, const Mat4Real& tm, const Mat4Real& invTransposeTM) const
+{
+ // Apply left-hand transform.
+ for (uint32_t i = 0; i < VertexFieldCount; ++i)
+ {
+ transformedInterpolator.m_frames[i] = invTransposeTM * m_frames[i];
+ }
+ // Apply right-hand transform. This is specific to the quantities being transformed.
+ for (int i = 0; i < 4; ++i)
+ {
+ // Normal, transform by invTransposeTM:
+ Dir normal_frame_i(transformedInterpolator.m_frames[Interpolator::Normal_x][i], transformedInterpolator.m_frames[Interpolator::Normal_y][i], transformedInterpolator.m_frames[Interpolator::Normal_z][i]);
+ normal_frame_i = invTransposeTM * normal_frame_i;
+ transformedInterpolator.m_frames[Interpolator::Normal_x][i] = normal_frame_i[0];
+ transformedInterpolator.m_frames[Interpolator::Normal_y][i] = normal_frame_i[1];
+ transformedInterpolator.m_frames[Interpolator::Normal_z][i] = normal_frame_i[2];
+ // Tangent, transform by tm:
+ Dir tangent_frame_i(transformedInterpolator.m_frames[Interpolator::Tangent_x][i], transformedInterpolator.m_frames[Interpolator::Tangent_y][i], transformedInterpolator.m_frames[Interpolator::Tangent_z][i]);
+ tangent_frame_i = tm * tangent_frame_i;
+ transformedInterpolator.m_frames[Interpolator::Tangent_x][i] = tangent_frame_i[0];
+ transformedInterpolator.m_frames[Interpolator::Tangent_y][i] = tangent_frame_i[1];
+ transformedInterpolator.m_frames[Interpolator::Tangent_z][i] = tangent_frame_i[2];
+ // Binormal, transform by tm:
+ Dir binormal_frame_i(transformedInterpolator.m_frames[Interpolator::Binormal_x][i], transformedInterpolator.m_frames[Interpolator::Binormal_y][i], transformedInterpolator.m_frames[Interpolator::Binormal_z][i]);
+ binormal_frame_i = tm * binormal_frame_i;
+ transformedInterpolator.m_frames[Interpolator::Binormal_x][i] = binormal_frame_i[0];
+ transformedInterpolator.m_frames[Interpolator::Binormal_y][i] = binormal_frame_i[1];
+ transformedInterpolator.m_frames[Interpolator::Binormal_z][i] = binormal_frame_i[2];
+ // Other quantities are scalars
+ }
+}
+
+
+class InterpolatorBuilder
+{
+public:
+ InterpolatorBuilder()
+ {
+#define CREATE_OFFSET( field ) (size_t)((uintptr_t)&vertexData.field-(uintptr_t)&vertexData)
+
+ VertexData vertexData;
+ Interpolator::s_offsets[Interpolator::Normal_x] = CREATE_OFFSET(normal[0]);
+ Interpolator::s_offsets[Interpolator::Normal_y] = CREATE_OFFSET(normal[1]);
+ Interpolator::s_offsets[Interpolator::Normal_z] = CREATE_OFFSET(normal[2]);
+ Interpolator::s_offsets[Interpolator::Tangent_x] = CREATE_OFFSET(tangent[0]);
+ Interpolator::s_offsets[Interpolator::Tangent_y] = CREATE_OFFSET(tangent[1]);
+ Interpolator::s_offsets[Interpolator::Tangent_z] = CREATE_OFFSET(tangent[2]);
+ Interpolator::s_offsets[Interpolator::Binormal_x] = CREATE_OFFSET(binormal[0]);
+ Interpolator::s_offsets[Interpolator::Binormal_y] = CREATE_OFFSET(binormal[1]);
+ Interpolator::s_offsets[Interpolator::Binormal_z] = CREATE_OFFSET(binormal[2]);
+ Interpolator::s_offsets[Interpolator::UV0_u] = CREATE_OFFSET(uv[0].u());
+ Interpolator::s_offsets[Interpolator::UV0_v] = CREATE_OFFSET(uv[0].v());
+ Interpolator::s_offsets[Interpolator::UV1_u] = CREATE_OFFSET(uv[1].u());
+ Interpolator::s_offsets[Interpolator::UV1_v] = CREATE_OFFSET(uv[1].v());
+ Interpolator::s_offsets[Interpolator::UV2_u] = CREATE_OFFSET(uv[2].u());
+ Interpolator::s_offsets[Interpolator::UV2_v] = CREATE_OFFSET(uv[2].v());
+ Interpolator::s_offsets[Interpolator::UV3_u] = CREATE_OFFSET(uv[3].u());
+ Interpolator::s_offsets[Interpolator::UV3_v] = CREATE_OFFSET(uv[3].v());
+ Interpolator::s_offsets[Interpolator::Color_r] = CREATE_OFFSET(color.r());
+ Interpolator::s_offsets[Interpolator::Color_g] = CREATE_OFFSET(color.g());
+ Interpolator::s_offsets[Interpolator::Color_b] = CREATE_OFFSET(color.b());
+ Interpolator::s_offsets[Interpolator::Color_a] = CREATE_OFFSET(color.a());
+ }
+};
+
+
+// ClippedTriangleInfo - used to map bsp output back to the original mesh
+struct ClippedTriangleInfo
+{
+ uint32_t planeIndex;
+ uint32_t originalTriangleIndex;
+ uint32_t clippedTriangleIndex;
+ uint32_t ccw;
+
+ static int cmp(const void* a, const void* b)
+ {
+ const int planeIndexDiff = (int)((ClippedTriangleInfo*)a)->planeIndex - (int)((ClippedTriangleInfo*)b)->planeIndex;
+ if (planeIndexDiff != 0)
+ {
+ return planeIndexDiff;
+ }
+ const int originalTriangleDiff = (int)((ClippedTriangleInfo*)a)->originalTriangleIndex - (int)((ClippedTriangleInfo*)b)->originalTriangleIndex;
+ if (originalTriangleDiff != 0)
+ {
+ return originalTriangleDiff;
+ }
+ return (int)((ClippedTriangleInfo*)a)->clippedTriangleIndex - (int)((ClippedTriangleInfo*)b)->clippedTriangleIndex;
+ }
+};
+
+// BSPLink - a link with an "isBSP" method to act as a stop
+class BSPLink : public nvidia::Link, public nvidia::UserAllocated
+{
+public:
+ virtual bool isBSP()
+ {
+ return false;
+ }
+
+ BSPLink* getAdjBSP(uint32_t which) const
+ {
+ if (isSolitary())
+ {
+ return NULL;
+ }
+ BSPLink* adjLink = static_cast<BSPLink*>(getAdj(which));
+ return adjLink->isBSP() ? adjLink : NULL;
+ }
+
+ void removeBSPLink()
+ {
+ BSPLink* adjLink = static_cast<BSPLink*>(getAdj(1));
+ remove();
+ if (!adjLink->isBSP() && adjLink->isSolitary())
+ {
+ delete adjLink;
+ }
+ }
+};
+
+// Specialized progress listener implementation
+class QuantityProgressListener : public nvidia::IProgressListener
+{
+public:
+ QuantityProgressListener(Real totalAmount, IProgressListener* parent) :
+ m_total((Real)0)
+ , m_parent(parent)
+ {
+ m_scale = totalAmount > (Real)0 ? (Real)100/(Real)totalAmount : (Real)0;
+ }
+
+ // IProgressListener interface
+ virtual void setProgress(int progress, const char* taskName = NULL)
+ {
+ if (m_parent != NULL)
+ {
+ m_parent->setProgress(progress, taskName);
+ }
+ }
+
+ virtual void add(Real amount)
+ {
+ m_total += amount;
+ if (m_parent != NULL)
+ {
+ m_parent->setProgress((int)(m_total*m_scale + (Real)0.5));
+ }
+ }
+
+private:
+ Real m_total;
+ Real m_scale;
+ IProgressListener* m_parent;
+};
+
+
+// IApexBSP implementation
+class BSP : public IApexBSP, public BSPLink
+{
+public:
+ BSP(IApexBSPMemCache* memCache = NULL, const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxIdentity));
+ ~BSP();
+
+ // IApexBSP implementation
+ void setTolerances(const BSPTolerances& tolerances);
+ bool fromMesh(const nvidia::ExplicitRenderTriangle* mesh, uint32_t meshSize, const BSPBuildParameters& params, nvidia::IProgressListener* progressListener = NULL, volatile bool* cancel = NULL);
+ bool fromConvexPolyhedron(const physx::PxPlane* poly, uint32_t polySize, const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxIdentity), const nvidia::ExplicitRenderTriangle* mesh = NULL, uint32_t meshSize = 0);
+ bool combine(const IApexBSP& bsp);
+ bool op(const IApexBSP& combinedBSP, Operation::Enum operation);
+ bool complement();
+ BSPType::Enum getType() const;
+ bool getSurfaceAreaAndVolume(float& area, float& volume, bool inside, Operation::Enum operation = Operation::NOP) const;
+ bool pointInside(const physx::PxVec3& point, Operation::Enum operation = Operation::NOP) const;
+ bool toMesh(physx::Array<nvidia::ExplicitRenderTriangle>& mesh) const;
+ void copy(const IApexBSP& bsp, const physx::PxMat44& tm = physx::PxMat44(physx::PxIdentity), const physx::PxMat44& internalTransform = physx::PxMat44(physx::PxZero));
+ physx::PxMat44 getInternalTransform() const
+ {
+ return m_internalTransform;
+ }
+
+ void replaceInteriorSubmeshes(uint32_t frameCount, uint32_t* frameIndices, uint32_t submeshIndex);
+
+ IApexBSP* decomposeIntoIslands() const;
+ IApexBSP* getNext() const
+ {
+ return static_cast<BSP*>(getAdjBSP(1));
+ }
+ IApexBSP* getPrev() const
+ {
+ return static_cast<BSP*>(getAdjBSP(0));
+ }
+
+ void deleteTriangles();
+
+ void serialize(physx::PxFileBuf& stream) const;
+ void deserialize(physx::PxFileBuf& stream);
+ void visualize(nvidia::RenderDebugInterface& debugRender, uint32_t flags, uint32_t index = 0) const;
+ void release();
+
+ // Debug
+ void performDiagnostics() const;
+
+ // BSPLink
+ bool isBSP()
+ {
+ return true;
+ }
+
+ // Node, a binary node with geometric data
+ class Node : public BinaryNode
+ {
+ Node& operator = (const Node&); // No assignment
+
+ public:
+ enum Type { Leaf, Branch };
+
+ Node() : m_type(Leaf)
+ {
+ m_leafData.side = 1;
+ }
+
+ PX_INLINE void setLeafData(const Region& leafData)
+ {
+ m_type = Leaf;
+ m_leafData = leafData;
+ }
+ PX_INLINE void setBranchData(const Surface& branchData)
+ {
+ m_type = Branch;
+ m_branchData = branchData;
+ }
+
+ PX_INLINE Type getType() const
+ {
+ return (Type)m_type;
+ }
+
+ PX_INLINE Region* getLeafData()
+ {
+ PX_ASSERT(getType() == Leaf);
+ return &m_leafData;
+ }
+ PX_INLINE Surface* getBranchData()
+ {
+ PX_ASSERT(getType() == Branch);
+ return &m_branchData;
+ }
+ PX_INLINE const Region* getLeafData() const
+ {
+ PX_ASSERT(getType() == Leaf);
+ return &m_leafData;
+ }
+ PX_INLINE const Surface* getBranchData() const
+ {
+ PX_ASSERT(getType() == Branch);
+ return &m_branchData;
+ }
+
+ PX_INLINE Node* getParent() const
+ {
+ return (Node*)BinaryNode::getParent();
+ }
+ PX_INLINE Node* getChild(uint32_t index) const
+ {
+ return (Node*)BinaryNode::getChild(index);
+ }
+
+ // Iterator (uses a stack, but no recursion)
+ // Can handle branches with NULL children
+ class It
+ {
+ public:
+ PX_INLINE It(const Node* root) : m_current(const_cast<Node*>(root)), m_valid(true) {}
+ PX_INLINE It(Node* root) : m_current(root), m_valid(true) {}
+
+ PX_INLINE bool valid() const
+ {
+ return m_valid;
+ }
+
+ PX_INLINE Node* node() const
+ {
+ return m_current;
+ }
+
+ PX_INLINE void inc()
+ {
+ if (m_current != NULL && m_current->getType() == Branch)
+ {
+ m_stack.pushBack(m_current->getChild(1));
+ m_current = m_current->getChild(0);
+ }
+ else
+ if (!m_stack.empty())
+ {
+ m_current = m_stack.popBack();
+ }
+ else
+ {
+ m_current = NULL;
+ m_valid = false;
+ }
+ }
+
+ private:
+ Node* m_current;
+ physx::Array<Node*> m_stack;
+ bool m_valid;
+ };
+
+ protected:
+ uint32_t m_type;
+
+ union
+ {
+ Region m_leafData;
+ Surface m_branchData;
+ };
+ };
+
+ class Halfspace : public GSA::VS3D_Halfspace_Set
+ {
+ public:
+ Halfspace(const Plane plane) : m_plane(plane) {}
+
+ virtual GSA::real farthest_halfspace(GSA::real plane[4], const GSA::real point[4])
+ {
+ for (int i = 0; i < 4; ++i) plane[i] = (GSA::real)m_plane[i];
+ return plane[0]*point[0] + plane[1]*point[1] + plane[2]*point[2] + plane[3]*point[3];
+ }
+
+ Halfspace& operator = (const Halfspace& halfspace) { m_plane = halfspace.m_plane; return *this; }
+
+ private:
+ Plane m_plane;
+ };
+
+ class RegionShape : public GSA::VS3D_Halfspace_Set
+ {
+ public:
+ RegionShape(const Plane* planes, Real skinWidth = (Real)0) : m_planes(planes), m_leaf(NULL), m_nonempty(true), m_skinWidth(skinWidth) {}
+
+ virtual GSA::real farthest_halfspace(GSA::real plane[4], const GSA::real point[4]);
+
+ void set_leaf(const BSP::Node* leaf)
+ {
+ m_leaf = leaf;
+ }
+
+ void calculate()
+ {
+ m_nonempty = (1 == GSA::vs3d_test(*this));
+ }
+
+ bool is_nonempty() const
+ {
+ return m_nonempty;
+ }
+
+#if 0
+ bool intersects_halfspace(const Plane* plane)
+ {
+ Halfspace halfspace(plane);
+ set_shapes(this, &halfspace);
+ return intersect();
+ }
+#endif
+
+ private:
+ const Plane* m_planes;
+ const BSP::Node* m_leaf;
+ bool m_nonempty;
+ Real m_skinWidth;
+ };
+
+private:
+ class BoolOp
+ {
+ public:
+ BoolOp(Operation::Enum op) : c_ba(((uint32_t)op >> 3) & 1), c_b(((uint32_t)op >> 2) & 1), c_a(((uint32_t)op >> 1) & 1), c_k((uint32_t)op & 1) {}
+
+ uint32_t operator()(uint32_t a, uint32_t b) const
+ {
+ return (c_ba & a & b) ^(c_b & b) ^(c_a & a) ^ c_k;
+ }
+
+ private:
+ uint32_t c_ba, c_b, c_a, c_k;
+ };
+
+ struct BuildConstants
+ {
+ BSPBuildParameters m_params;
+ float m_recipMaxArea;
+ };
+
+ void clear();
+
+ void transform(const Mat4Real& tm, bool transformFrames = true);
+
+ // Returns the area and volume of the clipped mesh. clippedMesh and triangleInfo may be NULL, in which case nothing is done but
+ // the area and volume calculation.
+ void clipMeshToLeaf(Real& area, Real& volume, physx::Array<Triangle>* clippedMesh, physx::Array<ClippedTriangleInfo>* triangleInfo, const Node* leaf, float clipTolerance) const;
+
+ // Called by buildTree - forcing no inline to ensure a small stack frame
+
+ // Returns a new stackReadStop
+ PX_INLINE uint32_t removeRedundantSurfacesFromStack(physx::Array<Surface>& surfaceStack, uint32_t stackReadStart, uint32_t stackReadStop, Node* leaf);
+ PX_INLINE void assignLeafSide(Node* leaf, QuantityProgressListener* quantityListener);
+ PX_INLINE void createBranchSurfaceAndSplitStack(uint32_t childReadStart[2], uint32_t childReadStop[2], Node* node, physx::Array<Surface>& surfaceStack,
+ uint32_t stackReadStart, uint32_t stackReadStop, const BuildConstants& buildConstants);
+
+ // Recursive functions
+ void complementLeaves(Node* root) const;
+ void mergeLeaves(const BoolOp& op, Node* root);
+ void clipMeshToLeaves(physx::Array<Triangle>& clippedMesh, physx::Array<ClippedTriangleInfo>& triangleInfo, Node* root, float clipTolerance) const;
+ void clone(Node* root, const Node* originalRoot);
+ void combineTrees(Node* root, const Node* combineRoot, uint32_t triangleIndexOffset, uint32_t planeIndexOffset);
+ bool buildTree(Node* root, physx::Array<Surface>& surfaceStack, uint32_t stackReadStart, uint32_t stackReadStop,
+ const BuildConstants& buildConstants, QuantityProgressListener* quantityListener, volatile bool* cancel = NULL);
+ void visualizeNode(nvidia::RenderDebugInterface& debugRender, uint32_t flags, const Node* root) const;
+ bool addLeafAreasAndVolumes(Real& totalArea, Real& totalVolume, const Node* root, bool inside, const BoolOp& op) const;
+ void serializeNode(const Node* root, physx::PxFileBuf& stream) const;
+ Node* deserializeNode(uint32_t version, physx::PxFileBuf& stream);
+ void releaseNode(Node* node);
+ void indexInsideLeaves(uint32_t& index, Node* root) const;
+ void listInsideLeaves(physx::Array<Node*>& insideLeaves, Node* root) const;
+ void findInsideLeafNeighbors(physx::Array<nvidia::IntPair>& neighbors, Node* root) const;
+
+ void clean();
+
+ // Parameters
+ BSPTolerances m_tolerarnces;
+
+ // Tree
+ Node* m_root;
+
+ // Internal mesh representation
+ physx::Array<Triangle> m_mesh;
+ physx::Array<Interpolator> m_frames;
+ Real m_meshSize;
+ physx::PxBounds3 m_meshBounds;
+ physx::PxMat44 m_internalTransform;
+ Mat4Real m_internalTransformInverse;
+ bool m_incidentalMesh;
+
+
+ // Unique splitting planes
+ physx::Array<Plane> m_planes;
+
+ // Combination data
+ bool m_combined;
+ Real m_combiningMeshSize;
+ bool m_combiningIncidentalMesh;
+
+ // Memory cache
+ class BSPMemCache* m_memCache;
+ bool m_ownsMemCache;
+};
+
+
+// Surface iterator; walks from a leaf's parent to the root of a tree, allowing inspection of surfaces along the way
+class SurfaceIt
+{
+public:
+ PX_INLINE SurfaceIt() : m_current(NULL), m_side(0xFFFFFFFF) {}
+ PX_INLINE SurfaceIt(const BSP::Node* leaf) : m_current((BSP::Node*)leaf)
+ {
+ PX_ASSERT(leaf != NULL && leaf->getType() == BSP::Node::Leaf);
+ inc();
+ }
+
+ PX_INLINE bool valid() const
+ {
+ return m_current != NULL;
+ }
+
+ PX_INLINE void inc()
+ {
+ m_side = m_current->getIndex();
+ m_current = m_current->getParent();
+ }
+
+ PX_INLINE const Surface* surface() const
+ {
+ return m_current->getBranchData();
+ }
+
+ PX_INLINE uint32_t side() const
+ {
+ return m_side;
+ }
+
+private:
+ BSP::Node* m_current;
+ uint32_t m_side;
+};
+
+
+// IBSPMemCache implementation, several pools and growable arrays. Not global, so that concurrent calculations can use different pools
+class BSPMemCache : public IApexBSPMemCache, public nvidia::UserAllocated
+{
+public:
+
+ BSPMemCache();
+
+ void clearAll();
+ void clearTemp();
+
+ void release();
+
+ // Persistent data
+ nvidia::Pool<BSP::Node> m_nodePool;
+
+ // Temporary data
+ nvidia::Pool<LinkedVertex> m_linkedVertexPool;
+ physx::Array<uint8_t> m_surfaceFlags;
+ physx::Array<uint8_t> m_surfaceTestFlags;
+};
+
+
+// Mesh cleaning interface
+void
+cleanMesh(physx::Array<nvidia::ExplicitRenderTriangle>& cleanedMesh, const physx::Array<Triangle>& mesh, physx::Array<ClippedTriangleInfo>& triangleInfo, const physx::Array<Plane>& planes, const physx::Array<Triangle>& originalTriangles, const physx::Array<Interpolator>& frames, Real distanceTol, const Mat4Real& BSPToMeshTM);
+
+}; // namespace ApexCSG
+
+#endif
+
+#endif // #define APEX_CSG_DEFS_H