瀏覽代碼

spline editor: support loop

trethaller 5 年之前
父節點
當前提交
95b54912bc
共有 2 個文件被更改,包括 36 次插入29 次删除
  1. 22 21
      hide/prefab/SplineEditor.hx
  2. 14 8
      hrt/prefab/l3d/Spline.hx

+ 22 - 21
hide/prefab/SplineEditor.hx

@@ -49,7 +49,7 @@ class NewSplinePointViewer extends h3d.scene.Object {
 	public function update( spd : SplinePointData ) {
 
 		pointViewer.setPosition(spd.pos.x, spd.pos.y, spd.pos.z);
-		
+
 		tangentViewer.clear();
 		tangentViewer.visible = spd.tangent != null;
 		if( spd.tangent != null ) {
@@ -102,7 +102,7 @@ class SplinePointViewer extends h3d.scene.Object {
 		indexText = new h2d.ObjectFollower(pointViewer,  @:privateAccess ctx.local2d.getScene());
 		var t = new h2d.Text(hxd.res.DefaultFont.get(), indexText);
 		t.textColor = 0xff00ff;
-		t.textAlign = Center;		
+		t.textAlign = Center;
 		t.dropShadow = { dx : 0.5, dy : 0.5, color : 0x202020, alpha : 1.0 };
 		t.setScale(2.5);
 	}
@@ -183,7 +183,7 @@ class SplineEditor {
 	}
 
 	function getClosestSplinePointFromMouse( mouseX : Float, mouseY : Float, ctx : hrt.prefab.Context ) : SplinePoint {
-		if( ctx == null || ctx.local3d == null || ctx.local3d.getScene() == null ) 
+		if( ctx == null || ctx.local3d == null || ctx.local3d.getScene() == null )
 			return null;
 
 		var mousePos = new h3d.Vector( mouseX / h3d.Engine.getCurrent().width, 1.0 - mouseY / h3d.Engine.getCurrent().height, 0);
@@ -207,7 +207,7 @@ class SplineEditor {
 	function getNewPointPosition( mouseX : Float, mouseY : Float, ctx : hrt.prefab.Context ) : SplinePointData {
 		if( prefab.points.length == 0 ) {
 			return { pos : ctx.local3d.getAbsPos().getPosition().toPoint(), tangent : ctx.local3d.getAbsPos().right().toPoint() , prev : null, next : null };
-		} 
+		}
 
 		var closestPt = getClosestPointFromMouse(mouseX, mouseY, ctx);
 
@@ -221,13 +221,13 @@ class SplineEditor {
 			var pt = ray.intersect(plane);
 			return { pos : pt, tangent : closestPt.tangent, prev : closestPt.prev, next : closestPt.next };
 		}
-		else 
+		else
 			return closestPt;
 	}
 
 	function getClosestPointFromMouse( mouseX : Float, mouseY : Float, ctx : hrt.prefab.Context ) : SplinePointData {
 
-		if( ctx == null || ctx.local3d == null || ctx.local3d.getScene() == null ) 
+		if( ctx == null || ctx.local3d == null || ctx.local3d.getScene() == null )
 			return null;
 
 		var result : SplinePointData = null;
@@ -277,7 +277,7 @@ class SplineEditor {
 				result.pos = firstPt;
 				result.tangent = firstSp.getAbsPos().right().toPoint();
 				result.prev = null;
-				result.next = prefab.points[0]; 
+				result.next = prefab.points[0];
 			}
 		}
 
@@ -297,7 +297,7 @@ class SplineEditor {
 
 		var pos = spd.pos.toVector();
 		pos.project(invMatrix);
-	
+
 		var index = 0;
 		var scale = 1.0;
 		if( spd.prev == null && spd.next == null ) {
@@ -310,7 +310,7 @@ class SplineEditor {
 		}
 		else if( spd.next == null ) {
 			index = prefab.points.length;
-			scale = prefab.points[prefab.points.length - 1].getAbsPos().getScale().x; 
+			scale = prefab.points[prefab.points.length - 1].getAbsPos().getScale().x;
 		}
 		else {
 			index = prefab.points.indexOf(spd.next);
@@ -367,7 +367,7 @@ class SplineEditor {
 			gizmo.visible = false; // Not visible by default, only show the closest in the onMove of interactive
 
 			gizmo.onStartMove = function(mode) {
-				
+
 				var sceneObj = sp;
 				var pivotPt = sceneObj.getAbsPos().getPosition();
 				var localMat : h3d.Matrix = sceneEditor.worldMat(sceneObj).clone();
@@ -402,7 +402,7 @@ class SplineEditor {
 					newMat.translate(pivotPt.x, pivotPt.y, pivotPt.z);
 					newMat.multiply(newMat, parentInvMat);
 					if(scale != null) newMat.prependScale(scale.x, scale.y, scale.z);
-					
+
 					var rot = newMat.getEulerAngles();
 					sceneObj.x = quantize(newMat.tx, posQuant);
 					sceneObj.y = quantize(newMat.ty, posQuant);
@@ -420,9 +420,9 @@ class SplineEditor {
 						sceneObj.scaleX = quantize(scaleSnap(s.x), scaleQuant);
 						sceneObj.scaleY = quantize(scaleSnap(s.y), scaleQuant);
 						sceneObj.scaleZ = quantize(scaleSnap(s.z), scaleQuant);
-					}	
+					}
 
-					prefab.updateInstance(ctx);	
+					prefab.updateInstance(ctx);
 				}
 
 				gizmo.onFinishMove = function() {
@@ -454,7 +454,7 @@ class SplineEditor {
 			editMode = false;
 			return;
 		}
-		
+
 		if( editMode ) {
 			createGizmos(ctx);
 			var s2d = @:privateAccess ctx.local2d.getScene();
@@ -515,7 +515,7 @@ class SplineEditor {
 			interactive.onMove =
 				function(e) {
 
-					if( prefab.points.length == 0 ) 
+					if( prefab.points.length == 0 )
 						return;
 
 					// Only show the gizmo of the closest splinePoint
@@ -526,7 +526,7 @@ class SplineEditor {
 					}
 
 					if( K.isDown( K.CTRL ) ) {
-						if( newSplinePointViewer == null ) 
+						if( newSplinePointViewer == null )
 							newSplinePointViewer = new NewSplinePointViewer(ctx.local3d.getScene());
 						newSplinePointViewer.visible = true;
 
@@ -534,7 +534,7 @@ class SplineEditor {
 						newSplinePointViewer.update(npt);
 					}
 					else {
-						if( newSplinePointViewer != null ) 
+						if( newSplinePointViewer != null )
 							newSplinePointViewer.visible = false;
 					}
 
@@ -547,7 +547,7 @@ class SplineEditor {
 								spv.setColor(0xFFFFFFFF);
 						}
 					}
-						
+
 				};
 		}
 	}
@@ -577,16 +577,17 @@ class SplineEditor {
 		var reverseButton = props.find(".reverse");
 		reverseButton.click(function(_) {
 			prefab.points.reverse();
-			for( p in prefab.points ) 
+			for( p in prefab.points )
 				p.rotate(0, 0, hxd.Math.degToRad(180));
 
 			undo.change(Custom(function(undo) {
 				prefab.points.reverse();
-				for( p in prefab.points ) 
+				for( p in prefab.points )
 					p.rotate(0, 0, hxd.Math.degToRad(180));
 			}));
-			
 			ctx.onChange(prefab, null);
+			removeGizmos();
+			createGizmos(getContext());
 		});
 
 		var editModeButton = props.find(".editModeButton");

+ 14 - 8
hrt/prefab/l3d/Spline.hx

@@ -158,7 +158,7 @@ class Spline extends Object3D {
 		#end
 	}
 
-	// Return an interpolation of two samples at t, 0 <= t <= 0
+	// Return an interpolation of two samples at t, 0 <= t <= 1
 	public function getPointAt( t : Float ) : h3d.col.Point {
 		if( data == null )
 			computeSplineData();
@@ -224,28 +224,33 @@ class Spline extends Object3D {
 		var sumT = 0.0;
 		var maxT = 1.0;
 		var minT = 0.0;
-		while( i < points.length - 1 ) {
-
+		var maxI = loop ? points.length : points.length - 1;
+		var curP = points[0];
+		var nextP = points[1];
+		while( i < maxI ) {
 			var t = (maxT + minT) * 0.5;
-			var p = getPointBetween(t, points[i], points[i+1]);
+
+			var p = getPointBetween(t, curP, nextP);
 			var curSegmentLength = p.distance(samples[samples.length - 1].pos);
 
 			// Point found
 			if( hxd.Math.abs(curSegmentLength - step) <= threshold ) {
-				samples.insert(samples.length, { pos : p, tangent : getTangentBetween(t, points[i], points[i+1]), prev : points[i], next : points[i+1], t : t });
+				samples.insert(samples.length, { pos : p, tangent : getTangentBetween(t, curP, nextP), prev : curP, next : nextP, t : t });
 				sumT = t;
 				maxT = 1.0;
 				minT = sumT;
 				// Last point of the curve too close from the last sample
-				if( points[i+1].getPoint().distance(samples[samples.length - 1].pos) < step ) {
+				if( nextP.getPoint().distance(samples[samples.length - 1].pos) < step ) {
 					// End of the spline
-					if( i == points.length - 2 ) {
-						samples.insert(samples.length, { pos : points[points.length - 1].getPoint(), tangent : points[points.length - 1].getTangent(), prev : points[points.length - 2], next : points[points.length - 1], t : 1.0 });
+					if( i == maxI - 1 ) {
+						samples.insert(samples.length, { pos : nextP.getPoint(), tangent : nextP.getTangent(), prev : curP, next : nextP, t : 1.0 });
 						break;
 					}
 					// End of the current curve
 					else {
 						i++;
+						curP = points[i];
+						nextP = points[(i+1) % points.length];
 						sumT = 0.0;
 						minT = 0.0;
 						maxT = 1.0;
@@ -397,6 +402,7 @@ class Spline extends Object3D {
 					<dt>Thickness</dt><dd><input type="range" min="1" max="10" field="lineThickness"/></dd>
 					<dt>Step</dt><dd><input type="range" min="0.1" max="1" field="step"/></dd>
 					<dt>Threshold</dt><dd><input type="range" min="0.001" max="1" field="threshold"/></dd>
+					<dt>Loop</dt><dd><input type="checkbox" field="loop"/></dd>
 					<dt>Show Spline</dt><dd><input type="checkbox" field="showSpline"/></dd>
 					<dt>Type</dt>
 						<dd>