Γ-W1-T3: staged contour traces draw the curve their exponent defines
New pure curve_tessellate joins the overlay's node vertices through curveMap, one sample per pixel column; the knot no longer floats off its own trace.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
// curve_tessellate.cpp — see curve_tessellate.h. Pure geometry; no host types.
|
||||
|
||||
#include "core/instrument/ui/curve_tessellate.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "core/util/curve_law.h"
|
||||
|
||||
namespace reasampler::instrument::ui {
|
||||
|
||||
using StrokePoint = reasampler::ui::StrokePoint;
|
||||
|
||||
namespace {
|
||||
|
||||
StrokePoint pt(double x, double y) {
|
||||
return StrokePoint{static_cast<float>(x), static_cast<float>(y)};
|
||||
}
|
||||
|
||||
// The samples strictly BETWEEN two nodes. The endpoints are the caller's, so a shared node is
|
||||
// emitted once and the polyline carries no zero-length joint.
|
||||
void appendInterior(int x0, int y0, int x1, int y1, double exponent,
|
||||
std::vector<StrokePoint>& out) {
|
||||
const int span = std::abs(x1 - x0);
|
||||
if (span < 2 || y1 == y0 || exponent == util::kCurveNeutral) return;
|
||||
const double dx = static_cast<double>(x1 - x0);
|
||||
const double dy = static_cast<double>(y1 - y0);
|
||||
for (int i = 1; i < span; ++i) {
|
||||
// phi is exact at every column, so x lands on the integer column and the last interior
|
||||
// sample is one column short of the end node.
|
||||
const double phi = static_cast<double>(i) / static_cast<double>(span);
|
||||
out.push_back(pt(static_cast<double>(x0) + dx * phi,
|
||||
static_cast<double>(y0) + dy * util::curveMap(phi, exponent)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
double segmentCurve(const StageEnvelope& env, EnvNode endNode) {
|
||||
switch (endNode) {
|
||||
case EnvNode::AttackEnd: return env.attackCurve;
|
||||
case EnvNode::DecayEnd: return env.decayCurve;
|
||||
case EnvNode::ReleaseEnd: return env.releaseCurve;
|
||||
default: return util::kCurveNeutral;
|
||||
}
|
||||
}
|
||||
|
||||
void buildEnvelopeTrace(const std::vector<EnvVertex>& poly, const StageEnvelope& env, int xLo,
|
||||
int xHi, std::vector<StrokePoint>& out) {
|
||||
out.clear();
|
||||
bool started = false;
|
||||
int px = 0;
|
||||
int py = 0;
|
||||
for (const EnvVertex& v : poly) {
|
||||
if (v.knot) continue;
|
||||
const int x = std::max(xLo, std::min(xHi, v.x));
|
||||
if (started) appendInterior(px, py, x, v.y, segmentCurve(env, v.node), out);
|
||||
out.push_back(pt(x, v.y));
|
||||
started = true;
|
||||
px = x;
|
||||
py = v.y;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace reasampler::instrument::ui
|
||||
Reference in New Issue
Block a user