summaryrefslogtreecommitdiffstats
path: root/src/Runtime/ogl-runtime/src/runtimerender/Qt3DSRenderPathMath.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/ogl-runtime/src/runtimerender/Qt3DSRenderPathMath.h')
m---------src/Runtime/ogl-runtime0
-rw-r--r--src/Runtime/ogl-runtime/src/runtimerender/Qt3DSRenderPathMath.h713
2 files changed, 0 insertions, 713 deletions
diff --git a/src/Runtime/ogl-runtime b/src/Runtime/ogl-runtime
new file mode 160000
+Subproject 427fddb50d43aa21a90fc7356ee3cdd8a908df5
diff --git a/src/Runtime/ogl-runtime/src/runtimerender/Qt3DSRenderPathMath.h b/src/Runtime/ogl-runtime/src/runtimerender/Qt3DSRenderPathMath.h
deleted file mode 100644
index e9eb2220..00000000
--- a/src/Runtime/ogl-runtime/src/runtimerender/Qt3DSRenderPathMath.h
+++ /dev/null
@@ -1,713 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2008-2012 NVIDIA Corporation.
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt 3D Studio.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) any later version
-** approved by the KDE Free Qt Foundation. The licenses are as published by
-** the Free Software Foundation and appearing in the file LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QT3DS_RENDER_PATH_MATH_H
-#define QT3DS_RENDER_PATH_MATH_H
-#include "Qt3DSRender.h"
-#include "foundation/Qt3DSVec2.h"
-#include "foundation/Qt3DSVec3.h"
-namespace qt3ds {
-namespace render {
-namespace path {
-// Solve quadratic equation in with a templated real number system.
-template <typename REAL>
-
-int quadratic(REAL b, REAL c, REAL rts[2])
-{
- int nquad;
- REAL dis;
- REAL rtdis;
-
- dis = b * b - 4 * c;
- rts[0] = 0;
- rts[1] = 0;
- if (b == 0) {
- if (c == 0) {
- nquad = 2;
- } else {
- if (c < 0) {
- nquad = 2;
- rts[0] = sqrt(-c);
- rts[1] = -rts[0];
- } else {
- nquad = 0;
- }
- }
- } else if (c == 0) {
- nquad = 2;
- rts[0] = -b;
- } else if (dis >= 0) {
- nquad = 2;
- rtdis = sqrt(dis);
- if (b > 0)
- rts[0] = (-b - rtdis) * (1 / REAL(2));
- else
- rts[0] = (-b + rtdis) * (1 / REAL(2));
- if (rts[0] == 0)
- rts[1] = -b;
- else
- rts[1] = c / rts[0];
- } else {
- nquad = 0;
- }
-
- return (nquad);
-} /* quadratic */
-
-float interest_range[2] = {0, 1};
-
-void cubicInflectionPoint(const QT3DSVec2 cp[4], nvvector<QT3DSF32> &key_point)
-{
- // Convert control points to cubic monomial polynomial coefficients
- const QT3DSVec2 A = cp[3] - cp[0] + (cp[1] - cp[2]) * 3.0;
- const QT3DSVec2 B = (cp[0] - cp[1] * 2.0 + cp[2]) * 3.0, C = (cp[1] - cp[0]) * 3.0;
- const QT3DSVec2 D = cp[0];
-
- double a = 3 * (B.x * A.y - A.x * B.y);
- double b = 3 * (C.x * A.y - C.y * A.x);
- double c = C.x * B.y - C.y * B.x;
-
- double roots[2];
- int solutions;
- // Is the quadratic really a degenerate line?
- if (a == 0) {
- // Is the line really a degenerate point?
- if (b == 0) {
- solutions = 0;
- } else {
- solutions = 1;
- roots[0] = c / b;
- }
- } else {
- solutions = quadratic(b / a, c / a, roots);
- }
- for (int i = 0; i < solutions; i++) {
- QT3DSF32 t = static_cast<QT3DSF32>(roots[i]);
-
- QT3DSVec2 p = ((A * t + B) * t + C) * t + D;
- if (t >= interest_range[0] && t <= interest_range[1])
- key_point.push_back(t);
- // else; Outside range of interest, ignore.
- }
-}
-
-typedef enum {
- CT_POINT,
- CT_LINE,
- CT_QUADRATIC,
- CT_CUSP,
- CT_LOOP,
- CT_SERPENTINE
-} CurveType;
-
-static inline bool isZero(double v)
-{
-#if 0
- const double eps = 6e-008;
-
- if (fabs(v) < eps)
- return true;
- else
- return false;
-#else
- return v == 0.0;
-#endif
-}
-
-inline QT3DSVec3 crossv1(const QT3DSVec2 &a, const QT3DSVec2 &b)
-{
- return QT3DSVec3(a[1] - b[1], b[0] - a[0], a[0] * b[1] - a[1] * b[0]);
-}
-
-inline bool sameVertex(const QT3DSVec2 &a, const QT3DSVec2 &b)
-{
- return (a.x == b.x && a.y == b.y);
-}
-
-inline bool sameVertex(const QT3DSVec3 &a, const QT3DSVec3 &b)
-{
- return (a.x == b.x && a.y == b.y && a.z == b.z);
-}
-
-// This function "normalizes" the input vector so the larger of its components
-// is in the range [512,1024]. Exploit integer math on the exponent bits to
-// do this without expensive DP exponentiation.
-inline void scaleTo512To1024(QT3DSVec2 &d, int e)
-{
- union {
- QT3DSU64 u64;
- double f64;
- } x;
- int ie = 10 - (int)e + 1023;
- QT3DS_ASSERT(ie > 0);
- x.u64 = ((QT3DSU64)ie) << 52;
- d *= static_cast<QT3DSF32>(x.f64);
-}
-
-inline double fastfrexp(double d, int *exponent)
-{
- union {
- QT3DSU64 u64;
- double f64;
- } x;
- x.f64 = d;
- *exponent = (((int)(x.u64 >> 52)) & 0x7ff) - 0x3ff;
- x.u64 &= (1ULL << 63) - (1ULL << 52);
- x.u64 |= (0x3ffULL << 52);
- return x.f64;
-}
-
-QT3DSVec3 CreateVec3(QT3DSVec2 xy, float z)
-{
- return QT3DSVec3(xy.x, xy.y, z);
-}
-
-QT3DSVec2 GetXY(const QT3DSVec3 &data)
-{
- return QT3DSVec2(data.x, data.y);
-}
-
-CurveType cubicDoublePoint(const QT3DSVec2 points[4], nvvector<QT3DSF32> &key_point)
-{
-#if 0
- const QT3DSVec2 AA = points[3] - points[0] + (points[1] - points[2]) * 3.0;
- const QT3DSVec3 BB = (points[0] - points[1] * 2.0 + points[2]) * 3.0;
- const QT3DSVec3 CC = (points[1] - points[0]) * 3.0, DD = points[0];
-#endif
-
- // Assume control points of the cubic curve are A, B, C, and D.
- const QT3DSVec3 A = CreateVec3(points[0], 1);
- const QT3DSVec3 B = CreateVec3(points[1], 1);
- const QT3DSVec3 C = CreateVec3(points[2], 1);
- const QT3DSVec3 D = CreateVec3(points[3], 1);
-
- // Compute the discriminant of the roots of
- // H(s,t) = -36*(d1^2*s^2 - d1*d2*s*t + (d2^2 - d1*d3)*t^2)
- // where H is the Hessian (the square matrix of second-order
- // partial derivatives of a function) of I(s,t)
- // where I(s,t) determine the inflection points of the cubic
- // Bezier curve C(s,t).
- //
- // d1, d2, and d3 functions of the determinants constructed
- // from the cubic control points.
- //
- // Recall dot(a,cross(b,c)) is determinant of a 3x3 matrix
- // with a, b, c the rows of the matrix.
- const QT3DSVec3 DC = crossv1(GetXY(D), GetXY(C));
- const QT3DSVec3 AD = crossv1(GetXY(A), GetXY(D));
- const QT3DSVec3 BA = crossv1(GetXY(B), GetXY(A));
-
- const double a1 = A.dot(DC);
- const double a2 = B.dot(AD);
- const double a3 = C.dot(BA);
- const double d1 = a1 - 2 * a2 + 3 * a3;
- const double d2 = -a2 + 3 * a3;
- const double d3 = 3 * a3;
- const double discriminant = (3 * d2 * d2 - 4 * d1 * d3);
-
- // The sign of the discriminant of I classifies the curbic curve
- // C into one of 6 classifications:
- // 1) discriminant>0 ==> serpentine
- // 2) discriminant=0 ==> cusp
- // 3) discriminant<0 ==> loop
-
- // If the discriminant or d1 are almost but not exactly zero, the
- // result is really noisy unacceptable (k,l,m) interpolation.
- // If it looks almost like a quadratic or linear case, treat it that way.
- if (isZero(discriminant) && isZero(d1)) {
- // Cusp case
-
- if (isZero(d2)) {
- // degenerate cases (points, lines, quadratics)...
- if (isZero(d3)) {
- if (sameVertex(A, B) && sameVertex(A, C) && sameVertex(A, D))
- return CT_POINT;
- else
- return CT_LINE;
- } else {
- return CT_QUADRATIC;
- }
- } else {
- return CT_CUSP;
- }
- } else if (discriminant < 0) {
- // Loop case
-
- const QT3DSF32 t = static_cast<QT3DSF32>(d2 + sqrt(-discriminant));
- QT3DSVec2 d = QT3DSVec2(t, static_cast<QT3DSF32>(2 * d1));
- QT3DSVec2 e = QT3DSVec2(static_cast<QT3DSF32>(2 * (d2 * d2 - d1 * d3)),
- static_cast<QT3DSF32>(d1 * t));
-
- // There is the situation where r2=c/t results in division by zero, but
- // in this case, the two roots represent a double root at zero so
- // subsitute l for (the otherwise NaN) m in this case.
- //
- // This situation can occur when the 1st and 2nd (or 3rd and 4th?)
- // control point of a cubic Bezier path SubPath are identical.
- if (e.x == 0 && e.y == 0)
- e = d;
-
- // d, e, or both could be very large values. To mitigate the risk of
- // floating-point overflow in subsequent calculations
- // scale both vectors to be in the range [768,1024] since their relative
- // scale of their x & y components is irrelevant.
-
- // Be careful to divide by a power-of-two to disturb mantissa bits.
-
- double d_max_mag = NVMax(fabs(d.x), fabs(d.y));
- int exponent;
- fastfrexp(d_max_mag, &exponent);
- scaleTo512To1024(d, exponent);
-
- double e_max_mag = NVMax(fabs(e.x), fabs(e.y));
- fastfrexp(e_max_mag, &exponent);
- scaleTo512To1024(e, exponent);
-
- const QT3DSVec2 roots = QT3DSVec2(d.x / d.y, e.x / e.y);
-
- double tt;
-#if 0
- tt = roots[0];
- if (tt >= interest_range[0] && tt <= interest_range[1])
- // key_point.push_back(tt);
- tt = roots[1];
- if (tt >= interest_range[0] && tt <= interest_range[1])
- // key_point.push_back(tt);
-#endif
- tt = (roots[0] + roots[1]) / 2;
- if (tt >= interest_range[0] && tt <= interest_range[1])
- key_point.push_back(static_cast<QT3DSF32>(tt));
-
- return CT_LOOP;
- } else {
- QT3DS_ASSERT(discriminant >= 0);
- cubicInflectionPoint(points, key_point);
- if (discriminant > 0) {
- // Serpentine case
- return CT_SERPENTINE;
- } else {
- // Cusp with inflection at infinity (treat like serpentine)
- return CT_CUSP;
- }
- }
-}
-
-QT3DSVec4 CreateVec4(QT3DSVec2 p1, QT3DSVec2 p2)
-{
- return QT3DSVec4(p1.x, p1.y, p2.x, p2.y);
-}
-
-QT3DSVec2 lerp(QT3DSVec2 p1, QT3DSVec2 p2, QT3DSF32 distance)
-{
- return p1 + (p2 - p1) * distance;
-}
-
-QT3DSF32 lerp(QT3DSF32 p1, QT3DSF32 p2, QT3DSF32 distance)
-{
- return p1 + (p2 - p1) * distance;
-}
-
-// Using first derivative to get tangent.
-// If this equation does not make immediate sense consider that it is the first derivative
-// of the de Casteljau bezier expansion, not the polynomial expansion.
-float TangentAt(float inT, float p1, float c1, float c2, float p2)
-{
- float a = c1 - p1;
- float b = c2 - c1 - a;
- float c = p2 - c2 - a - (2.0f * b);
- float retval = 3.0f * (a + (2.0f * b * inT) + (c * inT * inT));
- return retval;
-}
-
-QT3DSVec2 midpoint(QT3DSVec2 p1, QT3DSVec2 p2)
-{
- return lerp(p1, p2, .5f);
-}
-
-QT3DSF32 LineLength(QT3DSVec2 inStart, QT3DSVec2 inStop)
-{
- return (inStop - inStart).magnitude();
-}
-
-struct SCubicBezierCurve
-{
- QT3DSVec2 m_Points[4];
- SCubicBezierCurve(QT3DSVec2 a1, QT3DSVec2 c1, QT3DSVec2 c2, QT3DSVec2 a2)
- {
- m_Points[0] = a1;
- m_Points[1] = c1;
- m_Points[2] = c2;
- m_Points[3] = a2;
- }
-
- // Normal is of course orthogonal to the tangent.
- QT3DSVec2 NormalAt(float inT) const
- {
- QT3DSVec2 tangent = QT3DSVec2(
- TangentAt(inT, m_Points[0].x, m_Points[1].x, m_Points[2].x, m_Points[3].x),
- TangentAt(inT, m_Points[0].y, m_Points[1].y, m_Points[2].y, m_Points[3].y));
-
- QT3DSVec2 result(tangent.y, -tangent.x);
- result.normalize();
- return result;
- }
-
- eastl::pair<SCubicBezierCurve, SCubicBezierCurve> SplitCubicBezierCurve(float inT)
- {
- // compute point on curve based on inT
- // using de Casteljau algorithm
- QT3DSVec2 p12 = lerp(m_Points[0], m_Points[1], inT);
- QT3DSVec2 p23 = lerp(m_Points[1], m_Points[2], inT);
- QT3DSVec2 p34 = lerp(m_Points[2], m_Points[3], inT);
- QT3DSVec2 p123 = lerp(p12, p23, inT);
- QT3DSVec2 p234 = lerp(p23, p34, inT);
- QT3DSVec2 p1234 = lerp(p123, p234, inT);
-
- return eastl::make_pair(SCubicBezierCurve(m_Points[0], p12, p123, p1234),
- SCubicBezierCurve(p1234, p234, p34, m_Points[3]));
- }
-};
-
-#if 0
- static QT3DSVec2 NormalToLine( QT3DSVec2 startPoint, QT3DSVec2 endPoint )
- {
- QT3DSVec2 lineDxDy = endPoint - startPoint;
- QT3DSVec2 result( lineDxDy.y, -lineDxDy.x );
- result.normalize();
- return result;
- }
-#endif
-
-struct SResultCubic
-{
- enum Mode {
- Normal = 0,
- BeginTaper = 1,
- EndTaper = 2,
- };
- QT3DSVec2 m_P1;
- QT3DSVec2 m_C1;
- QT3DSVec2 m_C2;
- QT3DSVec2 m_P2;
- // Location in the original data where this cubic is taken from
- QT3DSU32 m_EquationIndex;
- QT3DSF32 m_TStart;
- QT3DSF32 m_TStop;
- QT3DSF32 m_Length;
- QT3DSVec2 m_TaperMultiplier; // normally 1, goes to zero at very end of taper if any taper.
- Mode m_Mode;
-
- SResultCubic(QT3DSVec2 inP1, QT3DSVec2 inC1, QT3DSVec2 inC2, QT3DSVec2 inP2,
- QT3DSU32 equationIndex, QT3DSF32 tStart, QT3DSF32 tStop, QT3DSF32 length)
- : m_P1(inP1)
- , m_C1(inC1)
- , m_C2(inC2)
- , m_P2(inP2)
- , m_EquationIndex(equationIndex)
- , m_TStart(tStart)
- , m_TStop(tStop)
- , m_Length(length)
- , m_TaperMultiplier(1.0f, 1.0f)
- , m_Mode(Normal)
- {
- }
- // Note the vec2 items are *not* initialized in any way here.
- SResultCubic() {}
- QT3DSF32 GetP1Width(QT3DSF32 inPathWidth, QT3DSF32 beginTaperWidth, QT3DSF32 endTaperWidth)
- {
- return GetPathWidth(inPathWidth, beginTaperWidth, endTaperWidth, 0);
- }
-
- QT3DSF32 GetP2Width(QT3DSF32 inPathWidth, QT3DSF32 beginTaperWidth, QT3DSF32 endTaperWidth)
- {
- return GetPathWidth(inPathWidth, beginTaperWidth, endTaperWidth, 1);
- }
-
- QT3DSF32 GetPathWidth(QT3DSF32 inPathWidth, QT3DSF32 beginTaperWidth, QT3DSF32 endTaperWidth,
- QT3DSU32 inTaperIndex)
- {
- QT3DSF32 retval = inPathWidth;
- switch (m_Mode) {
- case BeginTaper:
- retval = beginTaperWidth * m_TaperMultiplier[inTaperIndex];
- break;
- case EndTaper:
- retval = endTaperWidth * m_TaperMultiplier[inTaperIndex];
- break;
- default:
- break;
- }
- return retval;
- }
-};
-
-void PushLine(nvvector<SResultCubic> &ioResultVec, QT3DSVec2 inStart, QT3DSVec2 inStop,
- QT3DSU32 inEquationIndex)
-{
- QT3DSVec2 range = inStop - inStart;
- ioResultVec.push_back(SResultCubic(inStart, inStart + range * .333f,
- inStart + range * .666f, inStop, inEquationIndex,
- 0.0f, 1.0f, LineLength(inStart, inStop)));
-}
-
-struct PathDirtyFlagValues
-{
- enum Enum {
- SourceData = 1,
- PathType = 1 << 1,
- Width = 1 << 2,
- BeginTaper = 1 << 3,
- EndTaper = 1 << 4,
- CPUError = 1 << 5,
- };
-};
-
-struct SPathDirtyFlags : public NVFlags<PathDirtyFlagValues::Enum>
-{
- typedef NVFlags<PathDirtyFlagValues::Enum> TBase;
- SPathDirtyFlags() {}
- SPathDirtyFlags(int inFlags)
- : TBase(static_cast<PathDirtyFlagValues::Enum>(inFlags))
- {
- }
- void Clear()
- {
- *this = SPathDirtyFlags();
- }
-};
-
-struct STaperInformation
-{
- QT3DSF32 m_CapOffset;
- QT3DSF32 m_CapOpacity;
- QT3DSF32 m_CapWidth;
-
- STaperInformation()
- : m_CapOffset(0)
- , m_CapOpacity(0)
- , m_CapWidth(0)
- {
- }
- STaperInformation(QT3DSF32 capOffset, QT3DSF32 capOpacity, QT3DSF32 capWidth)
- : m_CapOffset(capOffset)
- , m_CapOpacity(capOpacity)
- , m_CapWidth(capWidth)
- {
- }
-
- bool operator==(const STaperInformation &inOther) const
- {
- return m_CapOffset == inOther.m_CapOffset && m_CapOpacity == inOther.m_CapOpacity
- && m_CapWidth == inOther.m_CapWidth;
- }
-};
-
-template <typename TOptData>
-bool OptionEquals(const Option<TOptData> &lhs, const Option<TOptData> &rhs)
-{
- if (lhs.hasValue() != rhs.hasValue())
- return false;
- if (lhs.hasValue())
- return lhs.getValue() == rhs.getValue();
- return true;
-}
-void OuterAdaptiveSubdivideBezierCurve(nvvector<SResultCubic> &ioResultVec,
- nvvector<QT3DSF32> &keyPointVec,
- SCubicBezierCurve inCurve, QT3DSF32 inLinearError,
- QT3DSU32 inEquationIndex);
-
-void AdaptiveSubdivideBezierCurve(nvvector<SResultCubic> &ioResultVec,
- SCubicBezierCurve &inCurve, QT3DSF32 inLinearError,
- QT3DSU32 inEquationIndex, QT3DSF32 inTStart, QT3DSF32 inTStop);
-
-// Adaptively subdivide source data to produce m_PatchData.
-void AdaptiveSubdivideSourceData(NVConstDataRef<SPathAnchorPoint> inSourceData,
- nvvector<SResultCubic> &ioResultVec,
- nvvector<QT3DSF32> &keyPointVec, QT3DSF32 inLinearError)
-{
- ioResultVec.clear();
- if (inSourceData.size() < 2)
- return;
- // Assuming no attributes in the source data.
- QT3DSU32 numEquations = (inSourceData.size() - 1);
- for (QT3DSU32 idx = 0, end = numEquations; idx < end; ++idx) {
- const SPathAnchorPoint &beginAnchor = inSourceData[idx];
- const SPathAnchorPoint &endAnchor = inSourceData[idx + 1];
-
- QT3DSVec2 anchor1(beginAnchor.m_Position);
- QT3DSVec2 control1(IPathManagerCore::GetControlPointFromAngleDistance(
- beginAnchor.m_Position, beginAnchor.m_OutgoingAngle,
- beginAnchor.m_OutgoingDistance));
-
- QT3DSVec2 control2(IPathManagerCore::GetControlPointFromAngleDistance(
- endAnchor.m_Position, endAnchor.m_IncomingAngle,
- endAnchor.m_IncomingDistance));
- QT3DSVec2 anchor2(endAnchor.m_Position);
-
- OuterAdaptiveSubdivideBezierCurve(
- ioResultVec, keyPointVec,
- SCubicBezierCurve(anchor1, control1, control2, anchor2), inLinearError, idx);
- }
-}
-
-// The outer subdivide function topologically analyzes the curve to ensure that
-// the sign of the second derivative does not change, no inflection points.
-// Once that condition is held, then we proceed with a simple adaptive subdivision algorithm
-// until the curve is accurately approximated by a straight line.
-void OuterAdaptiveSubdivideBezierCurve(nvvector<SResultCubic> &ioResultVec,
- nvvector<QT3DSF32> &keyPointVec,
- SCubicBezierCurve inCurve, QT3DSF32 inLinearError,
- QT3DSU32 inEquationIndex)
-{
- // Step 1, find what type of curve we are dealing with and the inflection points.
- keyPointVec.clear();
- CurveType theCurveType = cubicDoublePoint(inCurve.m_Points, keyPointVec);
-
- QT3DSF32 tStart = 0;
- switch (theCurveType) {
- case CT_POINT:
- ioResultVec.push_back(SResultCubic(inCurve.m_Points[0], inCurve.m_Points[0],
- inCurve.m_Points[0], inCurve.m_Points[0],
- inEquationIndex, 0.0f, 1.0f, 0.0f));
- return; // don't allow further recursion
- case CT_LINE:
- PushLine(ioResultVec, inCurve.m_Points[0], inCurve.m_Points[3], inEquationIndex);
- return; // don't allow further recursion
- case CT_CUSP:
- case CT_LOOP:
- case CT_SERPENTINE: {
- // Break the curve at the inflection points if there is one. If there aren't
- // inflection points
- // the treat as linear (degenerate case that should not happen except in limiting
- // ranges of floating point accuracy)
- if (!keyPointVec.empty()) {
- // It is not clear that the code results in a sorted vector,
- // or a vector where all values are within the range of 0-1
- if (keyPointVec.size() > 1)
- eastl::sort(keyPointVec.begin(), keyPointVec.end());
- for (QT3DSU32 idx = 0, end = (QT3DSU32)keyPointVec.size();
- idx < end && keyPointVec[idx] < 1.0f; ++idx) {
- // We have a list of T values I believe sorted from beginning to end, we
- // will create a set of bezier curves
- // Since we split the curves, tValue is relative to tSTart, not 0.
- QT3DSF32 range = 1.0f - tStart;
- QT3DSF32 splitPoint = keyPointVec[idx] - tStart;
- QT3DSF32 tValue = splitPoint / range;
- if (tValue > 0.0f) {
- eastl::pair<SCubicBezierCurve, SCubicBezierCurve> newCurves
- = inCurve.SplitCubicBezierCurve(tValue);
- AdaptiveSubdivideBezierCurve(ioResultVec, newCurves.first,
- inLinearError, inEquationIndex, tStart,
- splitPoint);
- inCurve = newCurves.second;
- tStart = splitPoint;
- }
- }
- }
- }
- // fallthrough intentional
- break;
- // fallthrough intentional
- case CT_QUADRATIC:
- break;
- }
- AdaptiveSubdivideBezierCurve(ioResultVec, inCurve, inLinearError, inEquationIndex,
- tStart, 1.0f);
-}
-
-static QT3DSF32 DistanceFromPointToLine(QT3DSVec2 inLineDxDy, QT3DSVec2 lineStart, QT3DSVec2 point)
-{
- QT3DSVec2 pointToLineStart = lineStart - point;
- return fabs((inLineDxDy.x * pointToLineStart.y) - (inLineDxDy.y * pointToLineStart.x));
-}
-
-// There are two options here. The first is to just subdivide below a given error
-// tolerance.
-// The second is to fit a quadratic to the curve and then precisely find the length of the
-// quadratic.
-// Obviously we are choosing the subdivide method at this moment but I think the fitting
-// method is probably more robust.
-QT3DSF32 LengthOfBezierCurve(SCubicBezierCurve &inCurve)
-{
- // Find distance of control points from line. Note that both control points should be
- // on same side of line else we have a serpentine which should have been removed by topological
- // analysis.
- QT3DSVec2 lineDxDy = inCurve.m_Points[3] - inCurve.m_Points[0];
- QT3DSF32 c1Distance = DistanceFromPointToLine(
- lineDxDy, inCurve.m_Points[0], inCurve.m_Points[1]);
- QT3DSF32 c2Distance = DistanceFromPointToLine(
- lineDxDy, inCurve.m_Points[0], inCurve.m_Points[2]);
- const float lineTolerance = 100.0f; // error in world coordinates, squared.
- if (c1Distance > lineTolerance || c2Distance > lineTolerance) {
- eastl::pair<SCubicBezierCurve, SCubicBezierCurve> subdivCurve
- = inCurve.SplitCubicBezierCurve(.5f);
- return LengthOfBezierCurve(subdivCurve.first)
- + LengthOfBezierCurve(subdivCurve.second);
- } else {
- return LineLength(inCurve.m_Points[0], inCurve.m_Points[3]);
- }
-}
-
-// The assumption here is the the curve type is not cusp, loop, or serpentine.
-// It is either linear or it is a constant curve meaning we can use very simple means to
-// figure out the curvature. There is a possibility to use some math to figure out the point of
-// maximum curvature, where the second derivative will have a max value. This is probably not
-// necessary.
-void AdaptiveSubdivideBezierCurve(nvvector<SResultCubic> &ioResultVec,
- SCubicBezierCurve &inCurve, QT3DSF32 inLinearError,
- QT3DSU32 inEquationIndex, QT3DSF32 inTStart, QT3DSF32 inTStop)
-{
- // Find distance of control points from line. Note that both control points should be
- // on same side of line else we have a serpentine which should have been removed by topological
- // analysis.
- QT3DSVec2 lineDxDy = inCurve.m_Points[3] - inCurve.m_Points[0];
- QT3DSF32 c1Distance = DistanceFromPointToLine(lineDxDy, inCurve.m_Points[0],
- inCurve.m_Points[1]);
- QT3DSF32 c2Distance = DistanceFromPointToLine(lineDxDy, inCurve.m_Points[0],
- inCurve.m_Points[2]);
- const float lineTolerance = inLinearError * inLinearError; // error in world coordinates
- if (c1Distance > lineTolerance || c2Distance > lineTolerance) {
- eastl::pair<SCubicBezierCurve, SCubicBezierCurve> subdivCurve
- = inCurve.SplitCubicBezierCurve(.5f);
- QT3DSF32 halfway = lerp(inTStart, inTStop, .5f);
- AdaptiveSubdivideBezierCurve(ioResultVec, subdivCurve.first, inLinearError,
- inEquationIndex, inTStart, halfway);
- AdaptiveSubdivideBezierCurve(ioResultVec, subdivCurve.second, inLinearError,
- inEquationIndex, halfway, inTStop);
- } else {
- ioResultVec.push_back(SResultCubic(inCurve.m_Points[0], inCurve.m_Points[1],
- inCurve.m_Points[2], inCurve.m_Points[3],
- inEquationIndex, inTStart, inTStop,
- LengthOfBezierCurve(inCurve)));
- }
-}
-}
-}
-}
-#endif