浏览代码

[animgraph] Choose resolver in editor

Clément Espeute 8 月之前
父节点
当前提交
3099ea3f6c
共有 2 个文件被更改,包括 120 次插入37 次删除
  1. 103 37
      hide/view/animgraph/BlendSpace2DEditor.hx
  2. 17 0
      hrt/animgraph/AnimGraph.hx

+ 103 - 37
hide/view/animgraph/BlendSpace2DEditor.hx

@@ -38,6 +38,8 @@ class BlendSpace2DEditor extends hide.view.FileView {
 
 
 	var animPreview : hrt.animgraph.AnimGraphInstance;
 	var animPreview : hrt.animgraph.AnimGraphInstance;
 
 
+	var customProviderIndex = 0;
+
 	inline function getPointPos(clientX : Float, clientY : Float, snap: Bool) : h2d.col.Point {
 	inline function getPointPos(clientX : Float, clientY : Float, snap: Bool) : h2d.col.Point {
 		var x = hxd.Math.clamp(graphXToLocal(clientX), blendSpace2D.minX, blendSpace2D.maxX);
 		var x = hxd.Math.clamp(graphXToLocal(clientX), blendSpace2D.minX, blendSpace2D.maxX);
 		var y = hxd.Math.clamp(graphYToLocal(clientY), blendSpace2D.minY, blendSpace2D.maxY);
 		var y = hxd.Math.clamp(graphYToLocal(clientY), blendSpace2D.minY, blendSpace2D.maxY);
@@ -238,7 +240,6 @@ class BlendSpace2DEditor extends hide.view.FileView {
 								addPoint(pt2);
 								addPoint(pt2);
 							}
 							}
 						});
 						});
-
 					}
 					}
 
 
 					hide.comp.ContextMenu.createFromEvent(e, options);
 					hide.comp.ContextMenu.createFromEvent(e, options);
@@ -347,7 +348,14 @@ class BlendSpace2DEditor extends hide.view.FileView {
 			if (animPreview == null) {
 			if (animPreview == null) {
 				var blendSpaceNode = new hrt.animgraph.nodes.BlendSpace2D.BlendSpace2D();
 				var blendSpaceNode = new hrt.animgraph.nodes.BlendSpace2D.BlendSpace2D();
 				@:privateAccess blendSpaceNode.blendSpace = blendSpace2D;
 				@:privateAccess blendSpaceNode.blendSpace = blendSpace2D;
-				animPreview = new hrt.animgraph.AnimGraphInstance(blendSpaceNode, "", 1000, 1.0/60.0);
+				var resolver = null;
+				if (hrt.animgraph.AnimGraph.customEditorResolverProvider != null) {
+					var resolvers = hrt.animgraph.AnimGraph.customEditorResolverProvider(_);
+					if (resolvers != null) {
+						resolver = resolvers[customProviderIndex]?.resolver;
+					}
+				}
+				animPreview = new hrt.animgraph.AnimGraphInstance(blendSpaceNode, resolver, "", 1000, 1.0/60.0);
 				@:privateAccess animPreview.editorSkipClone = true;
 				@:privateAccess animPreview.editorSkipClone = true;
 				cast previewModel.playAnimation(animPreview);
 				cast previewModel.playAnimation(animPreview);
 			}
 			}
@@ -355,6 +363,15 @@ class BlendSpace2DEditor extends hide.view.FileView {
 				var root : hrt.animgraph.nodes.BlendSpace2D.BlendSpace2D = cast @:privateAccess animPreview.rootNode;
 				var root : hrt.animgraph.nodes.BlendSpace2D.BlendSpace2D = cast @:privateAccess animPreview.rootNode;
 				var old = root.points[0]?.animInfo?.anim.frame;
 				var old = root.points[0]?.animInfo?.anim.frame;
 
 
+				var resolver = null;
+				if (hrt.animgraph.AnimGraph.customEditorResolverProvider != null) {
+					var resolvers = hrt.animgraph.AnimGraph.customEditorResolverProvider(_);
+					if (resolvers != null) {
+						resolver = resolvers[customProviderIndex]?.resolver;
+					}
+				}
+				animPreview.resolver = resolver;
+
 				// if the anim or the mesh changed between the last refreshPreviewAnimation
 				// if the anim or the mesh changed between the last refreshPreviewAnimation
 				if (previewModel.currentAnimation == animPreview) {
 				if (previewModel.currentAnimation == animPreview) {
 					animPreview.bind(previewModel);
 					animPreview.bind(previewModel);
@@ -382,7 +399,6 @@ class BlendSpace2DEditor extends hide.view.FileView {
 	function refreshPropertiesPannel() {
 	function refreshPropertiesPannel() {
 		propsEditor.clear();
 		propsEditor.clear();
 
 
-
 		propsEditor.add(new hide.Element('
 		propsEditor.add(new hide.Element('
 		<div class="group" name="BlendSpace">
 		<div class="group" name="BlendSpace">
 			<dl>
 			<dl>
@@ -416,24 +432,41 @@ class BlendSpace2DEditor extends hide.view.FileView {
 			var dd = new Element("<dd>").appendTo(div);
 			var dd = new Element("<dd>").appendTo(div);
 			var button = new hide.comp.Button(dd, null, "", {hasDropdown: true});
 			var button = new hide.comp.Button(dd, null, "", {hasDropdown: true});
 			button.label = blendSpace2D.points[selectedPoint].animPath;
 			button.label = blendSpace2D.points[selectedPoint].animPath;
+
+			var items : Array<hide.comp.ContextMenu.MenuItem> = [];
+
+			function setPointPath(path: String) {
+				var old = blendSpace2D.points[selectedPoint].animPath;
+				blendSpace2D.points[selectedPoint].animPath = path;
+				undo.change(Field(blendSpace2D.points[selectedPoint], "animPath", old), () -> {
+					button.label = blendSpace2D.points[selectedPoint].animPath;
+					refreshPreviewAnimation();
+				});
+				button.label = blendSpace2D.points[selectedPoint].animPath;
+				refreshPreviewAnimation();
+			}
+
+			items.push({
+				label: "Choose File ...",
+				click: () -> {
+				ide.chooseFile(["fbx"], setPointPath, true);
+				}
+			});
+
+			if (hrt.animgraph.AnimGraph.customAnimNameLister != null) {
+				items.push({isSeparator: true});
+
+				var anims = hrt.animgraph.AnimGraph.customAnimNameLister(null);
+				for (anim in anims) {
+					items.push({
+						label: anim,
+						click: setPointPath.bind(anim),
+					});
+				}
+			}
+
 			button.onClick = () -> {
 			button.onClick = () -> {
-				hide.comp.ContextMenu.createDropdown(button.element.get(0), [
-					{
-						label: "Choose File ...",
-						click: () -> {
-						ide.chooseFile(["fbx"], (path) -> {
-								var old = blendSpace2D.points[selectedPoint].animPath;
-								blendSpace2D.points[selectedPoint].animPath = path;
-								undo.change(Field(blendSpace2D.points[selectedPoint], "animPath", old), () -> {
-									button.label = blendSpace2D.points[selectedPoint].animPath;
-									refreshPreviewAnimation();
-								});
-								button.label = blendSpace2D.points[selectedPoint].animPath;
-								refreshPreviewAnimation();
-							}, true);
-						}
-					}
-				], {search: Visible, autoWidth: true});
+				hide.comp.ContextMenu.createDropdown(button.element.get(0), items, {search: Visible, autoWidth: true});
 			};
 			};
 
 
 			button.element.get(0).ondragover = (e:js.html.DragEvent) -> {
 			button.element.get(0).ondragover = (e:js.html.DragEvent) -> {
@@ -447,28 +480,61 @@ class BlendSpace2DEditor extends hide.view.FileView {
 					return;
 					return;
 				e.preventDefault();
 				e.preventDefault();
 
 
-				var old = blendSpace2D.points[selectedPoint].animPath;
-				blendSpace2D.points[selectedPoint].animPath = data;
-				undo.change(Field(blendSpace2D.points[selectedPoint], "animPath", old), () -> {
-					button.label = blendSpace2D.points[selectedPoint].animPath;
-					refreshPreviewAnimation();
-				});
-
-				button.label = blendSpace2D.points[selectedPoint].animPath;
-				refreshPreviewAnimation();
+				setPointPath(data);
 			};
 			};
 		}
 		}
 
 
-		propsEditor.add(new hide.Element('
-			<div class="group" name="Preview">
-					<dl>
-						<dt>X</dt><dd><input type="range" min="0.0" max="1.0" field="x"/></dd>
-						<dt>Y</dt><dd><input type="range" min="0.0" max="1.0" field="y"/></dd>
-					</dl>
-				</div>
-		'), previewAxis, (_) -> {
+		var preview = new hide.Element('
+		<div class="group" name="Preview">
+				<dl>
+					<dt>X</dt><dd><input type="range" min="0.0" max="1.0" field="x"/></dd>
+					<dt>Y</dt><dd><input type="range" min="0.0" max="1.0" field="y"/></dd>
+				</dl>
+			</div>
+		');
+
+		propsEditor.add(preview, previewAxis, (_) -> {
 			updatePreviewAxis();
 			updatePreviewAxis();
 		});
 		});
+
+		if (hrt.animgraph.AnimGraph.customEditorResolverProvider != null)
+		{
+			var dl = preview.find("dl");
+			var div = new Element("<div></div>").appendTo(dl);
+			div.append(new Element("<dt>Anim Set</dt>"));
+
+			var providers = hrt.animgraph.AnimGraph.customEditorResolverProvider(_);
+
+			var button = new hide.comp.Button(div, null, null, {hasDropdown: true});
+			button.label = providers[customProviderIndex].name;
+
+			var options : Array<hide.comp.ContextMenu.MenuItem> = [];
+			for (i => provider in providers) {
+				options.push({
+					label: provider.name,
+					click: () -> {
+						var old = customProviderIndex;
+						function exec(isUndo: Bool) {
+							if (!isUndo) {
+								customProviderIndex = i;
+							} else {
+								customProviderIndex = old;
+							}
+							button.label = providers[customProviderIndex].name;
+							refreshPreviewAnimation();
+						}
+						exec(false);
+						undo.change(Custom(exec));
+					}
+				});
+			}
+
+			button.onClick = () -> {
+				hide.comp.ContextMenu.createDropdown(button.element.get(0), options, {search: Visible, autoWidth: true});
+			}
+		}
+
+
 	}
 	}
 
 
 	override function save() {
 	override function save() {

+ 17 - 0
hrt/animgraph/AnimGraph.hx

@@ -36,6 +36,9 @@ class AnimGraph extends hrt.prefab.Prefab {
 		This anim should be instanciated using getInstance() after that (or use the h3d.scene.Object.playAnimation() function that does this for you)
 		This anim should be instanciated using getInstance() after that (or use the h3d.scene.Object.playAnimation() function that does this for you)
 	**/
 	**/
 	public function getAnimation(previewNode: hrt.animgraph.nodes.AnimNode = null, resolver: hrt.animgraph.AnimGraphInstance.AnimResolver = null) : AnimGraphInstance {
 	public function getAnimation(previewNode: hrt.animgraph.nodes.AnimNode = null, resolver: hrt.animgraph.AnimGraphInstance.AnimResolver = null) : AnimGraphInstance {
+		if (resolver == null && customResolverProvider != null) {
+			resolver = customResolverProvider(this);
+		}
 		return AnimGraphInstance.fromAnimGraph(this, previewNode, resolver);
 		return AnimGraphInstance.fromAnimGraph(this, previewNode, resolver);
 	}
 	}
 
 
@@ -168,5 +171,19 @@ class AnimGraph extends hrt.prefab.Prefab {
 	}
 	}
 	#end
 	#end
 
 
+	/**
+		Called by getAnimation when the given resolver is null. Allow the game to provide a custom animation resolver on a prefab by prefab basis.
+	**/
+	public static var customResolverProvider : (graph: AnimGraph) -> hrt.animgraph.AnimGraphInstance.AnimResolver;
+
+	#if editor
+	/**
+		Used to display a list of valid animation names to use with the animResolver feature
+	**/
+	public static var customAnimNameLister : (graph: AnimGraph) -> Array<String>;
+
+	public static var customEditorResolverProvider : (graph: AnimGraph) -> Array<{name: String, resolver: hrt.animgraph.AnimGraphInstance.AnimResolver}>;
+	#end
+
 	static var _ = hrt.prefab.Prefab.register("animgraph", AnimGraph, "animgraph");
 	static var _ = hrt.prefab.Prefab.register("animgraph", AnimGraph, "animgraph");
 }
 }