Replace invalid use of memcpy in curveplot

- Vertex is not trivially copyable, therefore memcpy is not allowed.
- Put local classes and functions into unnamed namespace.
- Remove using namespace std, using namespace Eigen.
- Prefer C++-style casts.
- Use C++17 std::clamp where appropriate.
- Use logger for debugging
pull/1277/head
Andrew Tribick 2021-12-28 21:34:38 +01:00 committed by ajtribick
parent 2069f1ce68
commit 657604c69a
2 changed files with 140 additions and 139 deletions

View File

@ -34,22 +34,24 @@
#define USE_VERTEX_BUFFER 1 #define USE_VERTEX_BUFFER 1
#endif #endif
#include "glsupport.h" #include <algorithm>
#include "curveplot.h" #include <cmath>
#include "shadermanager.h"
#include <vector> #include <vector>
#include <iostream>
using namespace std;
using namespace Eigen;
static const unsigned int SubdivisionFactor = 8;
static const double InvSubdivisionFactor = 1.0 / (double) SubdivisionFactor;
#if DEBUG_ADAPTIVE_SPLINE #if DEBUG_ADAPTIVE_SPLINE
static float SplineColors[10][3] = { #include <celutil/logger.h>
#endif
#include "curveplot.h"
#include "glsupport.h"
#include "shadermanager.h"
namespace {
constexpr unsigned int SubdivisionFactor = 8;
constexpr double InvSubdivisionFactor = 1.0 / static_cast<double>(SubdivisionFactor);
#if DEBUG_ADAPTIVE_SPLINE
constexpr float SplineColors[10][3] = {
{ 0, 0, 1 }, { 0, 0, 1 },
{ 0, 1, 1 }, { 0, 1, 1 },
{ 0, 1, 0 }, { 0, 1, 0 },
@ -62,24 +64,21 @@ static float SplineColors[10][3] = {
{ 1.0f, 1.0f, 0.5f }, { 1.0f, 1.0f, 0.5f },
}; };
static unsigned int SegmentCounts[32]; unsigned int SegmentCounts[32];
#endif
#ifndef EIGEN_VECTORIZE
// Vectorization should be enabled for improved performance.
#endif #endif
// Convert a 3-vector to a 4-vector by adding a zero // Convert a 3-vector to a 4-vector by adding a zero
static inline Vector4d zeroExtend(const Vector3d& v) inline Eigen::Vector4d
zeroExtend(const Eigen::Vector3d& v)
{ {
return Vector4d(v.x(), v.y(), v.z(), 0.0); return Eigen::Vector4d(v.x(), v.y(), v.z(), 0.0);
} }
class HighPrec_Frustum class HighPrec_Frustum
{ {
public: public:
HighPrec_Frustum(double nearZ, double farZ, const Vector3d planeNormals[]) : HighPrec_Frustum(double nearZ, double farZ, const Eigen::Vector3d planeNormals[]) :
m_nearZ(nearZ), m_nearZ(nearZ),
m_farZ(farZ) m_farZ(farZ)
{ {
@ -89,7 +88,7 @@ public:
} }
} }
inline bool cullSphere(const Vector3d& center, inline bool cullSphere(const Eigen::Vector3d& center,
double radius) const double radius) const
{ {
return (center.z() - radius > m_nearZ || return (center.z() - radius > m_nearZ ||
@ -100,7 +99,7 @@ public:
center.dot(m_planeNormals[3].head(3)) < -radius); center.dot(m_planeNormals[3].head(3)) < -radius);
} }
inline bool cullSphere(const Vector4d& center, inline bool cullSphere(const Eigen::Vector4d& center,
double radius) const double radius) const
{ {
return (center.z() - radius > m_nearZ || return (center.z() - radius > m_nearZ ||
@ -117,16 +116,17 @@ public:
private: private:
double m_nearZ; double m_nearZ;
double m_farZ; double m_farZ;
Vector4d m_planeNormals[4]; Eigen::Vector4d m_planeNormals[4];
}; };
static inline Matrix4d cubicHermiteCoefficients(const Vector4d& p0, inline Eigen::Matrix4d
const Vector4d& p1, cubicHermiteCoefficients(const Eigen::Vector4d& p0,
const Vector4d& v0, const Eigen::Vector4d& p1,
const Vector4d& v1) const Eigen::Vector4d& v0,
const Eigen::Vector4d& v1)
{ {
Matrix4d coeff; Eigen::Matrix4d coeff;
coeff.col(0) = p0; coeff.col(0) = p0;
coeff.col(1) = v0; coeff.col(1) = v0;
coeff.col(2) = 3.0 * (p1 - p0) - (2.0 * v0 + v1); coeff.col(2) = 3.0 * (p1 - p0) - (2.0 * v0 + v1);
@ -136,25 +136,6 @@ static inline Matrix4d cubicHermiteCoefficients(const Vector4d& p0,
} }
// Test a point to see if it lies within the frustum defined by
// planes z=nearZ, z=farZ, and the four side planes with specified
// normals.
#if 0
static inline bool frustumCull(const Vector4d& curvePoint,
double curveBoundingRadius,
double nearZ, double farZ,
const Vector4d viewFrustumPlaneNormals[])
{
return (curvePoint.z() - curveBoundingRadius > nearZ ||
curvePoint.z() + curveBoundingRadius < farZ ||
curvePoint.dot(viewFrustumPlaneNormals[0]) < -curveBoundingRadius ||
curvePoint.dot(viewFrustumPlaneNormals[1]) < -curveBoundingRadius ||
curvePoint.dot(viewFrustumPlaneNormals[2]) < -curveBoundingRadius ||
curvePoint.dot(viewFrustumPlaneNormals[3]) < -curveBoundingRadius);
}
#endif
class HighPrec_VertexBuffer class HighPrec_VertexBuffer
{ {
public: public:
@ -189,26 +170,33 @@ public:
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glEnableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex); glEnableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex);
int stride = lineAsTriangles ? sizeof(Vertex) : sizeof(Vertex) * 2; int stride = lineAsTriangles ? sizeof(Vertex) : sizeof(Vertex) * 2;
Vector4f* vertexBase = vbobj ? (Vector4f*) offsetof(Vertex, position) : &data[0].position; const Eigen::Vector4f* vertexBase = vbobj
? reinterpret_cast<const Eigen::Vector4f*>(offsetof(Vertex, position))
: &data[0].position;
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
3, GL_FLOAT, GL_FALSE, stride, vertexBase); 3, GL_FLOAT, GL_FALSE, stride, vertexBase);
Vector4f* colorBase = vbobj ? (Vector4f*) offsetof(Vertex, color) : &data[0].color; const Eigen::Vector4f* colorBase = vbobj
? reinterpret_cast<const Eigen::Vector4f*>(offsetof(Vertex, color))
: &data[0].color;
glVertexAttribPointer(CelestiaGLProgram::ColorAttributeIndex, glVertexAttribPointer(CelestiaGLProgram::ColorAttributeIndex,
4, GL_FLOAT, GL_FALSE, stride, colorBase); 4, GL_FLOAT, GL_FALSE, stride, colorBase);
if (lineAsTriangles) if (lineAsTriangles)
{ {
glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex);
glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex);
float* scaleBase = vbobj ? (float*) offsetof(Vertex, scale) : &data[0].scale; const float* scaleBase = vbobj
? reinterpret_cast<const float*>(offsetof(Vertex, scale))
: &data[0].scale;
glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex, glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex,
1, GL_FLOAT, GL_FALSE, stride, scaleBase); 1, GL_FLOAT, GL_FALSE, stride, scaleBase);
Vector4f* nextVertexBase = vbobj ? (Vector4f*) (offsetof(Vertex, position) + (2 * sizeof(Vertex))) : &data[2].position; const Eigen::Vector4f* nextVertexBase = vbobj
? reinterpret_cast<const Eigen::Vector4f*>(offsetof(Vertex, position) + (2 * sizeof(Vertex)))
: &data[2].position;
glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex, glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex,
4, GL_FLOAT, GL_FALSE, stride, nextVertexBase); 4, GL_FLOAT, GL_FALSE, stride, nextVertexBase);
} }
@ -230,10 +218,10 @@ public:
#endif #endif
} }
inline void vertex(const Vector3d& v) inline void vertex(const Eigen::Vector3d& v)
{ {
#if USE_VERTEX_BUFFER #if USE_VERTEX_BUFFER
Vector3f pos = v.cast<float>(); Eigen::Vector3f pos = v.cast<float>();
int index = currentPosition * 2; int index = currentPosition * 2;
data[index].position.segment<3>(0) = pos; data[index].position.segment<3>(0) = pos;
data[index].color = color; data[index].color = color;
@ -261,15 +249,15 @@ public:
#endif #endif
} }
inline void vertex(const Vector4d& v) inline void vertex(const Eigen::Vector4d& v)
{ {
vertex(v, color); vertex(v, color);
} }
inline void vertex(const Vector4d& v, const Vector4f& color) inline void vertex(const Eigen::Vector4d& v, const Eigen::Vector4f& color)
{ {
#if USE_VERTEX_BUFFER #if USE_VERTEX_BUFFER
Vector4f pos = v.cast<float>(); Eigen::Vector4f pos = v.cast<float>();
int index = currentPosition * 2; int index = currentPosition * 2;
data[index].position = pos; data[index].position = pos;
data[index].color = color; data[index].color = color;
@ -311,7 +299,8 @@ public:
if (currentStripLength > 1) if (currentStripLength > 1)
{ {
int index = currentPosition * 2; int index = currentPosition * 2;
memcpy(&data[index], &data[index - 4], 2 * sizeof(Vertex)); data[index] = data[index - 4];
data[index + 1] = data[index - 3];
currentPosition += 1; currentPosition += 1;
stripLengths.push_back(currentStripLength); stripLengths.push_back(currentStripLength);
} }
@ -340,9 +329,8 @@ public:
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * currentPosition * 2, data); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * currentPosition * 2, data);
unsigned int startIndex = 0; unsigned int startIndex = 0;
for (vector<unsigned int>::const_iterator iter = stripLengths.begin(); iter != stripLengths.end(); ++iter) for (unsigned int lineCount : stripLengths)
{ {
int lineCount = *iter;
if (lineAsTriangles) if (lineAsTriangles)
glDrawArrays(GL_TRIANGLE_STRIP, startIndex * 2, lineCount * 2); glDrawArrays(GL_TRIANGLE_STRIP, startIndex * 2, lineCount * 2);
else else
@ -373,7 +361,7 @@ public:
#endif #endif
} }
void setColor(const Vector4f &aColor) void setColor(const Eigen::Vector4f &aColor)
{ {
#if USE_VERTEX_BUFFER #if USE_VERTEX_BUFFER
color = aColor; color = aColor;
@ -387,15 +375,16 @@ private:
unsigned int capacity; unsigned int capacity;
struct Vertex struct Vertex
{ {
Vector4f position; Eigen::Vector4f position;
Vector4f color; Eigen::Vector4f color;
float scale; float scale;
}; };
Vertex* data; Vertex* data;
GLuint vbobj; GLuint vbobj;
unsigned int currentStripLength; unsigned int currentStripLength;
vector<unsigned int> stripLengths; std::vector<unsigned int> stripLengths;
Vector4f color; Eigen::Vector4f color;
bool lineAsTriangles; bool lineAsTriangles;
}; };
@ -424,7 +413,7 @@ public:
// curve was culled and we need to start a new primitive sequence // curve was culled and we need to start a new primitive sequence
// with glBegin(). // with glBegin().
bool renderCubic(bool restartCurve, bool renderCubic(bool restartCurve,
const Matrix4d& coeff, const Eigen::Matrix4d& coeff,
double t0, double t1, double t0, double t1,
double curveBoundingRadius, double curveBoundingRadius,
int depth) const int depth) const
@ -440,14 +429,14 @@ public:
} }
#endif #endif
Vector4d lastP = coeff * Vector4d(1.0, t0, t0 * t0, t0 * t0 * t0); Eigen::Vector4d lastP = coeff * Eigen::Vector4d(1.0, t0, t0 * t0, t0 * t0 * t0);
for (unsigned int i = 1; i <= SubdivisionFactor; i++) for (unsigned int i = 1; i <= SubdivisionFactor; i++)
{ {
double t = t0 + dt * i; double t = t0 + dt * i;
Vector4d p = coeff * Vector4d(1.0, t, t * t, t * t * t); Eigen::Vector4d p = coeff * Eigen::Vector4d(1.0, t, t * t, t * t * t);
double minDistance = max(-m_viewFrustum.nearZ(), abs(p.z()) - segmentBoundingRadius); double minDistance = std::max(-m_viewFrustum.nearZ(), std::abs(p.z()) - segmentBoundingRadius);
if (segmentBoundingRadius >= m_subdivisionThreshold * minDistance) if (segmentBoundingRadius >= m_subdivisionThreshold * minDistance)
{ {
@ -494,9 +483,9 @@ public:
// curve was culled and we need to start a new primitive sequence // curve was culled and we need to start a new primitive sequence
// with glBegin(). // with glBegin().
bool renderCubicFaded(bool restartCurve, bool renderCubicFaded(bool restartCurve,
const Matrix4d& coeff, const Eigen::Matrix4d& coeff,
double t0, double t1, double t0, double t1,
const Vector4f& color, const Eigen::Vector4f& color,
double fadeStart, double fadeRate, double fadeStart, double fadeRate,
double curveBoundingRadius, double curveBoundingRadius,
int depth) const int depth) const
@ -512,18 +501,18 @@ public:
} }
#endif #endif
Vector4d lastP = coeff * Vector4d(1.0, t0, t0 * t0, t0 * t0 * t0); Eigen::Vector4d lastP = coeff * Eigen::Vector4d(1.0, t0, t0 * t0, t0 * t0 * t0);
double lastOpacity = (t0 - fadeStart) * fadeRate; double lastOpacity = (t0 - fadeStart) * fadeRate;
lastOpacity = max(0.0, min(1.0, lastOpacity)); // clamp lastOpacity = std::clamp(lastOpacity, 0.0, 1.0);
for (unsigned int i = 1; i <= SubdivisionFactor; i++) for (unsigned int i = 1; i <= SubdivisionFactor; i++)
{ {
double t = t0 + dt * i; double t = t0 + dt * i;
Vector4d p = coeff * Vector4d(1.0, t, t * t, t * t * t); Eigen::Vector4d p = coeff * Eigen::Vector4d(1.0, t, t * t, t * t * t);
double opacity = (t - fadeStart) * fadeRate; double opacity = (t - fadeStart) * fadeRate;
opacity = max(0.0, min(1.0, opacity)); // clamp opacity = std::clamp(opacity, 0.0, 1.0);
double minDistance = max(-m_viewFrustum.nearZ(), abs(p.z()) - segmentBoundingRadius); double minDistance = std::max(-m_viewFrustum.nearZ(), std::abs(p.z()) - segmentBoundingRadius);
if (segmentBoundingRadius >= m_subdivisionThreshold * minDistance) if (segmentBoundingRadius >= m_subdivisionThreshold * minDistance)
{ {
@ -557,11 +546,11 @@ public:
if (restartCurve) if (restartCurve)
{ {
m_vbuf.begin(); m_vbuf.begin();
m_vbuf.vertex(lastP, Vector4f(color.x(), color.y(), color.z(), color.w() * float(lastOpacity))); m_vbuf.vertex(lastP, Eigen::Vector4f(color.x(), color.y(), color.z(), color.w() * float(lastOpacity)));
restartCurve = false; restartCurve = false;
} }
m_vbuf.vertex(p, Vector4f(color.x(), color.y(), color.z(), color.w() * float(opacity))); m_vbuf.vertex(p, Eigen::Vector4f(color.x(), color.y(), color.z(), color.w() * float(opacity)));
} }
lastP = p; lastP = p;
lastOpacity = opacity; lastOpacity = opacity;
@ -577,8 +566,12 @@ private:
}; };
HighPrec_VertexBuffer vbuf;
static HighPrec_VertexBuffer vbuf;
} // end unnamed namespace
CurvePlot::CurvePlot() CurvePlot::CurvePlot()
@ -623,22 +616,24 @@ CurvePlot::addSample(const CurvePlotSample& sample)
{ {
const CurvePlotSample& lastSample = m_samples[m_samples.size() - 2]; const CurvePlotSample& lastSample = m_samples[m_samples.size() - 2];
double dt = sample.t - lastSample.t; double dt = sample.t - lastSample.t;
Matrix4d coeff = cubicHermiteCoefficients(zeroExtend(lastSample.position), Eigen::Matrix4d coeff = cubicHermiteCoefficients(
zeroExtend(sample.position), zeroExtend(lastSample.position),
zeroExtend(lastSample.velocity * dt), zeroExtend(sample.position),
zeroExtend(sample.velocity * dt)); zeroExtend(lastSample.velocity * dt),
Vector4d extents = coeff.cwiseAbs() * Vector4d(0.0, 1.0, 1.0, 1.0); zeroExtend(sample.velocity * dt));
Eigen::Vector4d extents = coeff.cwiseAbs() * Eigen::Vector4d(0.0, 1.0, 1.0, 1.0);
m_samples[m_samples.size() - 1].boundingRadius = extents.norm(); m_samples[m_samples.size() - 1].boundingRadius = extents.norm();
} }
else else
{ {
const CurvePlotSample& nextSample = m_samples[1]; const CurvePlotSample& nextSample = m_samples[1];
double dt = nextSample.t - sample.t; double dt = nextSample.t - sample.t;
Matrix4d coeff = cubicHermiteCoefficients(zeroExtend(sample.position), Eigen::Matrix4d coeff = cubicHermiteCoefficients(
zeroExtend(nextSample.position), zeroExtend(sample.position),
zeroExtend(sample.velocity * dt), zeroExtend(nextSample.position),
zeroExtend(nextSample.velocity * dt)); zeroExtend(sample.velocity * dt),
Vector4d extents = coeff.cwiseAbs() * Vector4d(0.0, 1.0, 1.0, 1.0); zeroExtend(nextSample.velocity * dt));
Eigen::Vector4d extents = coeff.cwiseAbs() * Eigen::Vector4d(0.0, 1.0, 1.0, 1.0);
m_samples[1].boundingRadius = extents.norm(); m_samples[1].boundingRadius = extents.norm();
} }
} }
@ -688,21 +683,21 @@ CurvePlot::setDuration(double duration)
* @param subdivisionThreshold the threashhold for subdivision * @param subdivisionThreshold the threashhold for subdivision
*/ */
void void
CurvePlot::render(const Affine3d& modelview, CurvePlot::render(const Eigen::Affine3d& modelview,
double nearZ, double nearZ,
double farZ, double farZ,
const Vector3d viewFrustumPlaneNormals[], const Eigen::Vector3d viewFrustumPlaneNormals[],
double subdivisionThreshold, double subdivisionThreshold,
const Vector4f& color, const Eigen::Vector4f& color,
bool lineAsTriangles) const bool lineAsTriangles) const
{ {
// Flag to indicate whether we need to issue a glBegin() // Flag to indicate whether we need to issue a glBegin()
bool restartCurve = true; bool restartCurve = true;
const Vector3d& p0_ = m_samples[0].position; const Eigen::Vector3d& p0_ = m_samples[0].position;
const Vector3d& v0_ = m_samples[0].velocity; const Eigen::Vector3d& v0_ = m_samples[0].velocity;
Vector4d p0 = modelview * Vector4d(p0_.x(), p0_.y(), p0_.z(), 1.0); Eigen::Vector4d p0 = modelview * Eigen::Vector4d(p0_.x(), p0_.y(), p0_.z(), 1.0);
Vector4d v0 = modelview * Vector4d(v0_.x(), v0_.y(), v0_.z(), 0.0); Eigen::Vector4d v0 = modelview * Eigen::Vector4d(v0_.x(), v0_.y(), v0_.z(), 0.0);
HighPrec_Frustum viewFrustum(nearZ, farZ, viewFrustumPlaneNormals); HighPrec_Frustum viewFrustum(nearZ, farZ, viewFrustumPlaneNormals);
HighPrec_RenderContext rc(vbuf, viewFrustum, subdivisionThreshold); HighPrec_RenderContext rc(vbuf, viewFrustum, subdivisionThreshold);
@ -719,10 +714,10 @@ CurvePlot::render(const Affine3d& modelview,
for (unsigned int i = 1; i < m_samples.size(); i++) for (unsigned int i = 1; i < m_samples.size(); i++)
{ {
// Transform the points into camera space. // Transform the points into camera space.
const Vector3d& p1_ = m_samples[i].position; const Eigen::Vector3d& p1_ = m_samples[i].position;
const Vector3d& v1_ = m_samples[i].velocity; const Eigen::Vector3d& v1_ = m_samples[i].velocity;
Vector4d p1 = modelview * Vector4d(p1_.x(), p1_.y(), p1_.z(), 1.0); Eigen::Vector4d p1 = modelview * Eigen::Vector4d(p1_.x(), p1_.y(), p1_.z(), 1.0);
Vector4d v1 = modelview * Vector4d(v1_.x(), v1_.y(), v1_.z(), 0.0); Eigen::Vector4d v1 = modelview * Eigen::Vector4d(v1_.x(), v1_.y(), v1_.z(), 0.0);
// O(t) is an approximating function for this segment of // O(t) is an approximating function for this segment of
// the orbit, with 0 <= t <= 1 // the orbit, with 0 <= t <= 1
@ -738,7 +733,7 @@ CurvePlot::render(const Affine3d& modelview,
// render it. Otherwise, it should be a performance win // render it. Otherwise, it should be a performance win
// to do a sphere-frustum cull test before subdividing and // to do a sphere-frustum cull test before subdividing and
// rendering segment. // rendering segment.
double minDistance = abs(p0.z()) - curveBoundingRadius; double minDistance = std::abs(p0.z()) - curveBoundingRadius;
// Render close segments as splines with adaptive subdivision. The // Render close segments as splines with adaptive subdivision. The
// subdivisions eliminates kinks between line segments and also // subdivisions eliminates kinks between line segments and also
@ -763,7 +758,7 @@ CurvePlot::render(const Affine3d& modelview,
else else
{ {
double dt = m_samples[i].t - m_samples[i - 1].t; double dt = m_samples[i].t - m_samples[i - 1].t;
Matrix4d coeff = cubicHermiteCoefficients(p0, p1, v0 * dt, v1 * dt); Eigen::Matrix4d coeff = cubicHermiteCoefficients(p0, p1, v0 * dt, v1 * dt);
restartCurve = rc.renderCubic(restartCurve, coeff, 0.0, 1.0, curveBoundingRadius, 1); restartCurve = rc.renderCubic(restartCurve, coeff, 0.0, 1.0, curveBoundingRadius, 1);
} }
@ -810,12 +805,12 @@ CurvePlot::render(const Affine3d& modelview,
vbuf.flush(); vbuf.flush();
vbuf.finish(); vbuf.finish();
#if DEBUG_ADAPTIVE_SPLINE3 #if DEBUG_ADAPTIVE_SPLINE
for (unsigned int i = 0; SegmentCounts[i] != 0 || i < 3; i++) for (unsigned int i = 0; SegmentCounts[i] != 0 || i < 3; i++)
{ {
clog << i << ":" << SegmentCounts[i] << ", "; celestia::util::GetLogger()->debug("{}: {}, ", i, SegmentCounts[i]);
} }
clog << endl; celestia::util::GetLogger()->debug("\n");
#endif #endif
} }
@ -831,14 +826,14 @@ CurvePlot::render(const Affine3d& modelview,
* @param endTime the end of the time interval * @param endTime the end of the time interval
*/ */
void void
CurvePlot::render(const Affine3d& modelview, CurvePlot::render(const Eigen::Affine3d& modelview,
double nearZ, double nearZ,
double farZ, double farZ,
const Vector3d viewFrustumPlaneNormals[], const Eigen::Vector3d viewFrustumPlaneNormals[],
double subdivisionThreshold, double subdivisionThreshold,
double startTime, double startTime,
double endTime, double endTime,
const Vector4f& color, const Eigen::Vector4f& color,
bool lineAsTriangles) const bool lineAsTriangles) const
{ {
// Flag to indicate whether we need to issue a glBegin() // Flag to indicate whether we need to issue a glBegin()
@ -856,10 +851,10 @@ CurvePlot::render(const Affine3d& modelview,
if (startSample > 0) if (startSample > 0)
startSample--; startSample--;
const Vector3d& p0_ = m_samples[startSample].position; const Eigen::Vector3d& p0_ = m_samples[startSample].position;
const Vector3d& v0_ = m_samples[startSample].velocity; const Eigen::Vector3d& v0_ = m_samples[startSample].velocity;
Vector4d p0 = modelview * Vector4d(p0_.x(), p0_.y(), p0_.z(), 1.0); Eigen::Vector4d p0 = modelview * Eigen::Vector4d(p0_.x(), p0_.y(), p0_.z(), 1.0);
Vector4d v0 = modelview * Vector4d(v0_.x(), v0_.y(), v0_.z(), 0.0); Eigen::Vector4d v0 = modelview * Eigen::Vector4d(v0_.x(), v0_.y(), v0_.z(), 0.0);
HighPrec_Frustum viewFrustum(nearZ, farZ, viewFrustumPlaneNormals); HighPrec_Frustum viewFrustum(nearZ, farZ, viewFrustumPlaneNormals);
HighPrec_RenderContext rc(vbuf, viewFrustum, subdivisionThreshold); HighPrec_RenderContext rc(vbuf, viewFrustum, subdivisionThreshold);
@ -874,10 +869,10 @@ CurvePlot::render(const Affine3d& modelview,
for (unsigned int i = startSample + 1; i < m_samples.size() && !lastSegment; i++) for (unsigned int i = startSample + 1; i < m_samples.size() && !lastSegment; i++)
{ {
// Transform the points into camera space. // Transform the points into camera space.
const Vector3d& p1_ = m_samples[i].position; const Eigen::Vector3d& p1_ = m_samples[i].position;
const Vector3d& v1_ = m_samples[i].velocity; const Eigen::Vector3d& v1_ = m_samples[i].velocity;
Vector4d p1 = modelview * Vector4d(p1_.x(), p1_.y(), p1_.z(), 1.0); Eigen::Vector4d p1 = modelview * Eigen::Vector4d(p1_.x(), p1_.y(), p1_.z(), 1.0);
Vector4d v1 = modelview * Vector4d(v1_.x(), v1_.y(), v1_.z(), 0.0); Eigen::Vector4d v1 = modelview * Eigen::Vector4d(v1_.x(), v1_.y(), v1_.z(), 0.0);
if (endTime <= m_samples[i].t) if (endTime <= m_samples[i].t)
{ {
@ -926,7 +921,7 @@ CurvePlot::render(const Affine3d& modelview,
if (firstSegment) if (firstSegment)
{ {
t0 = (startTime - m_samples[i - 1].t) / dt; t0 = (startTime - m_samples[i - 1].t) / dt;
t0 = std::max(0.0, std::min(1.0, t0)); t0 = std::clamp(t0, 0.0, 1.0);
firstSegment = false; firstSegment = false;
} }
@ -935,7 +930,7 @@ CurvePlot::render(const Affine3d& modelview,
t1 = (endTime - m_samples[i - 1].t) / dt; t1 = (endTime - m_samples[i - 1].t) / dt;
} }
Matrix4d coeff = cubicHermiteCoefficients(p0, p1, v0 * dt, v1 * dt); Eigen::Matrix4d coeff = cubicHermiteCoefficients(p0, p1, v0 * dt, v1 * dt);
restartCurve = rc.renderCubic(restartCurve, coeff, t0, t1, curveBoundingRadius, 1); restartCurve = rc.renderCubic(restartCurve, coeff, t0, t1, curveBoundingRadius, 1);
} }
} }
@ -1005,7 +1000,7 @@ CurvePlot::renderFaded(const Eigen::Affine3d& modelview,
double subdivisionThreshold, double subdivisionThreshold,
double startTime, double startTime,
double endTime, double endTime,
const Vector4f& color, const Eigen::Vector4f& color,
double fadeStartTime, double fadeStartTime,
double fadeEndTime, double fadeEndTime,
bool lineAsTriangles) const bool lineAsTriangles) const
@ -1028,12 +1023,12 @@ CurvePlot::renderFaded(const Eigen::Affine3d& modelview,
double fadeDuration = fadeEndTime - fadeStartTime; double fadeDuration = fadeEndTime - fadeStartTime;
double fadeRate = 1.0 / fadeDuration; double fadeRate = 1.0 / fadeDuration;
const Vector3d& p0_ = m_samples[startSample].position; const Eigen::Vector3d& p0_ = m_samples[startSample].position;
const Vector3d& v0_ = m_samples[startSample].velocity; const Eigen::Vector3d& v0_ = m_samples[startSample].velocity;
Vector4d p0 = modelview * Vector4d(p0_.x(), p0_.y(), p0_.z(), 1.0); Eigen::Vector4d p0 = modelview * Eigen::Vector4d(p0_.x(), p0_.y(), p0_.z(), 1.0);
Vector4d v0 = modelview * Vector4d(v0_.x(), v0_.y(), v0_.z(), 0.0); Eigen::Vector4d v0 = modelview * Eigen::Vector4d(v0_.x(), v0_.y(), v0_.z(), 0.0);
double opacity0 = (m_samples[startSample].t - fadeStartTime) * fadeRate; double opacity0 = (m_samples[startSample].t - fadeStartTime) * fadeRate;
opacity0 = max(0.0, min(1.0, opacity0)); opacity0 = std::clamp(opacity0, 0.0, 1.0);
HighPrec_Frustum viewFrustum(nearZ, farZ, viewFrustumPlaneNormals); HighPrec_Frustum viewFrustum(nearZ, farZ, viewFrustumPlaneNormals);
HighPrec_RenderContext rc(vbuf, viewFrustum, subdivisionThreshold); HighPrec_RenderContext rc(vbuf, viewFrustum, subdivisionThreshold);
@ -1047,12 +1042,12 @@ CurvePlot::renderFaded(const Eigen::Affine3d& modelview,
for (unsigned int i = startSample + 1; i < m_samples.size() && !lastSegment; i++) for (unsigned int i = startSample + 1; i < m_samples.size() && !lastSegment; i++)
{ {
// Transform the points into camera space. // Transform the points into camera space.
const Vector3d& p1_ = m_samples[i].position; const Eigen::Vector3d& p1_ = m_samples[i].position;
const Vector3d& v1_ = m_samples[i].velocity; const Eigen::Vector3d& v1_ = m_samples[i].velocity;
Vector4d p1 = modelview * Vector4d(p1_.x(), p1_.y(), p1_.z(), 1.0); Eigen::Vector4d p1 = modelview * Eigen::Vector4d(p1_.x(), p1_.y(), p1_.z(), 1.0);
Vector4d v1 = modelview * Vector4d(v1_.x(), v1_.y(), v1_.z(), 0.0); Eigen::Vector4d v1 = modelview * Eigen::Vector4d(v1_.x(), v1_.y(), v1_.z(), 0.0);
double opacity1 = (m_samples[i].t - fadeStartTime) * fadeRate; double opacity1 = (m_samples[i].t - fadeStartTime) * fadeRate;
opacity1 = max(0.0, min(1.0, opacity1)); opacity1 = std::clamp(opacity1, 0.0, 1.0);
if (endTime <= m_samples[i].t) if (endTime <= m_samples[i].t)
{ {
@ -1073,7 +1068,7 @@ CurvePlot::renderFaded(const Eigen::Affine3d& modelview,
// render it. Otherwise, it should be a performance win // render it. Otherwise, it should be a performance win
// to do a sphere-frustum cull test before subdividing and // to do a sphere-frustum cull test before subdividing and
// rendering segment. // rendering segment.
double minDistance = abs(p0.z()) - curveBoundingRadius; double minDistance = std::abs(p0.z()) - curveBoundingRadius;
// Render close segments as splines with adaptive subdivision. The // Render close segments as splines with adaptive subdivision. The
// subdivisions eliminates kinks between line segments and also // subdivisions eliminates kinks between line segments and also
@ -1101,7 +1096,7 @@ CurvePlot::renderFaded(const Eigen::Affine3d& modelview,
if (firstSegment) if (firstSegment)
{ {
t0 = (startTime - m_samples[i - 1].t) / dt; t0 = (startTime - m_samples[i - 1].t) / dt;
t0 = std::max(0.0, std::min(1.0, t0)); t0 = std::clamp(t0, 0.0, 1.0);
firstSegment = false; firstSegment = false;
} }
@ -1110,7 +1105,7 @@ CurvePlot::renderFaded(const Eigen::Affine3d& modelview,
t1 = (endTime - m_samples[i - 1].t) / dt; t1 = (endTime - m_samples[i - 1].t) / dt;
} }
Matrix4d coeff = cubicHermiteCoefficients(p0, p1, v0 * dt, v1 * dt); Eigen::Matrix4d coeff = cubicHermiteCoefficients(p0, p1, v0 * dt, v1 * dt);
restartCurve = rc.renderCubicFaded(restartCurve, coeff, restartCurve = rc.renderCubicFaded(restartCurve, coeff,
t0, t1, t0, t1,
color, color,
@ -1139,10 +1134,16 @@ CurvePlot::renderFaded(const Eigen::Affine3d& modelview,
if (restartCurve) if (restartCurve)
{ {
vbuf.begin(); vbuf.begin();
vbuf.vertex(p0, Vector4f(color.x(), color.y(), color.z(), color.w() * float(opacity0))); vbuf.vertex(p0, Eigen::Vector4f(color.x(),
color.y(),
color.z(),
color.w() * static_cast<float>(opacity0)));
restartCurve = false; restartCurve = false;
} }
vbuf.vertex(p1, Vector4f(color.x(), color.y(), color.z(), color.w() * float(opacity1))); vbuf.vertex(p1, Eigen::Vector4f(color.x(),
color.y(),
color.z(),
color.w() * static_cast<float>(opacity1)));
} }
} }

View File

@ -30,11 +30,11 @@
#pragma once #pragma once
#include <deque> #include <deque>
#include <Eigen/Core>
#include <Eigen/Geometry> #include <Eigen/Geometry>
class HighPrec_Frustum;
class CurvePlotSample class CurvePlotSample
{ {
public: public:
@ -110,7 +110,7 @@ class CurvePlot
private: private:
std::deque<CurvePlotSample> m_samples; std::deque<CurvePlotSample> m_samples;
double m_duration{ 0.0 }; double m_duration{ 0.0 };
unsigned int m_lastUsed{ 0 }; unsigned int m_lastUsed{ 0 };