Ver código fonte

curve sampling

trethaller 7 anos atrás
pai
commit
850b42dfb8
3 arquivos alterados com 92 adições e 4 exclusões
  1. 15 4
      hide/comp/CurveEditor.hx
  2. 8 0
      hide/comp/SVG.hx
  3. 69 0
      hide/prefab/Curve.hx

+ 15 - 4
hide/comp/CurveEditor.hx

@@ -106,10 +106,21 @@ class CurveEditor extends Component {
 		var handlesGroup = svg.group(root, "handles");
 		var size = 7;
 
-		for(ik in 0...curve.keys.length-1) {
-			var pt = curve.keys[ik];
-			var nextPt = curve.keys[ik+1];
-			svg.line(curveGroup, xt(pt.time), yt(pt.value), xt(nextPt.time), yt(nextPt.value));
+		// Draw curve
+		{
+			// for(ik in 0...curve.keys.length-1) {
+			// 	var pt = curve.keys[ik];
+			// 	var nextPt = curve.keys[ik+1];
+			// 	svg.line(curveGroup, xt(pt.time), yt(pt.value), xt(nextPt.time), yt(nextPt.value));
+			// }
+			var pts = curve.sample(200);
+			var poly = [];
+			for(i in 0...pts.length) {
+				var x = xt(curve.duration * i / (pts.length - 1));
+				var y = yt(pts[i]);
+				poly.push(new h2d.col.Point(x, y));
+			}
+			svg.polyLine(curveGroup, poly);
 		}
 
 

+ 8 - 0
hide/comp/SVG.hx

@@ -49,6 +49,14 @@ class SVG extends Component {
 		return make(parent, "line", {x1:x1, y1:y1, x2:x2, y2:y2}, style);
 	}
 
+	public function polyLine(?parent: Element, points: Array<h2d.col.Point>, ?style:Dynamic) {
+		var lines = ['M${points[0].x},${points[0].y} '];
+		for(i in 1...points.length) {
+			lines.push('L${points[i].x},${points[i].y} ');
+		}
+		return make(parent, "path", {d: lines.join("")}, style);
+	}
+
 	public function group(?parent: Element, ?className: String, ?attr: Dynamic) {
 		var g = make(parent, "g", attr);
 		if(className != null)

+ 69 - 0
hide/prefab/Curve.hx

@@ -43,4 +43,73 @@ class Curve extends Prefab {
 			keys: keys
 		};
 	}
+	
+	static inline function bezier(c0: Float, c1:Float, c2:Float, c3: Float, t:Float) {
+		var u = 1 - t;
+		return u * u * u * c0 + c1 * 3 * t * u * u + c2 * 3 * t * t * u + t * t * t * c3;
+	}
+
+	public function getVal(time: Float) : Float {
+		switch(keys.length) {
+			case 0: return 0;
+			case 1: return keys[0].value;
+			default:
+		}
+
+		var idx = -1;
+		for(ik in 0...keys.length) {
+			var key = keys[ik];
+			if(time > key.time)
+				idx = ik;
+		}
+
+		if(idx < 0)
+			return keys[0].value;
+
+		var cur = keys[idx];
+		var next = keys[idx + 1];
+		if(next == null)
+			return cur.value;
+		
+		var minT = 0.;
+		var maxT = 1.;
+		var maxDelta = 1./ 25.;
+
+
+		inline function sampleTime(t) {
+			return bezier(cur.time, cur.time + cur.nextHandle.dt, next.time + next.prevHandle.dt, next.time, t);
+		}
+
+		inline function sampleVal(t) {
+			return bezier(cur.value, cur.value + cur.nextHandle.dv, next.value + next.prevHandle.dv, next.value, t);
+		}
+
+		while( maxT - minT > maxDelta ) {
+			var t = (maxT + minT) * 0.5;
+			var t = sampleTime(t);
+			if( t > time )
+				maxT = t;
+			else
+				minT = t;
+		}
+
+		var x0 = sampleTime(minT);
+		var x1 = sampleTime(maxT);
+		var dx = x1 - x0;
+		var xfactor = dx == 0 ? 0.5 : (time - x0) / dx;
+
+		var y0 = sampleVal(minT);
+		var y1 = sampleVal(maxT);
+		var y = y0 + (y1 - y0) * xfactor;
+		return y;
+	}
+
+	public function sample(numPts: Int) {
+		var vals = [];
+		for(i in 0...numPts) {
+			var v = getVal(duration * i/(numPts-1));
+			vals.push(v);
+		}
+		return vals;
+	}
 }