浏览代码

Merge branch 'master' of https://github.com/heapsio/hide

clandrin 4 年之前
父节点
当前提交
4aee1f8e1c

+ 0 - 1
hide/Ide.hx

@@ -1,5 +1,4 @@
 package hide;
-import hxd.inspect.Group;
 
 @:expose
 class Ide {

+ 23 - 23
hide/comp/FileSelect.hx

@@ -18,7 +18,7 @@ class FileSelect extends Component {
 				ide.chooseFile(extensions, function(path) {
 					this.path = path;
 					onChange();
-				});
+				}, false, path);
 			}
 		});
 		root.contextmenu(function(e) {
@@ -31,42 +31,42 @@ class FileSelect extends Component {
 			]);
 			return false;
 		});
+
 		// allow drag files
 		root.on("dragover", function(e) {
 			root.addClass("dragover");
-			e.preventDefault();
 		});
 		root.on("dragleave", function(e) {
 			root.removeClass("dragover");
 		});
-		root.on("drop", function(e:js.jquery.Event) {
+		root.on("drop", function(e) {
 			root.removeClass("dragover");
-			var file = getTransferFile(e);
-			if( file != null ) {
-				path = file;
-				onChange();
-			}
-			e.preventDefault();
 		});
 	}
 
-	function getTransferFile( e : js.jquery.Event ) {
-		var data : js.html.DataTransfer = untyped e.originalEvent.dataTransfer;
-		var text = data.getData("text/html");
-		var path : String = null;
-
-		if( data.files.length > 0 )
-			path = untyped data.files[0].path;
-		else if( StringTools.startsWith(text, "<a") && text.indexOf("jstree-anchor") > 0 ) {
-			var rpath = ~/id="([^"]+)_anchor"/;
-			if( rpath.match(text) )
-				path = rpath.matched(1);
+	public function onDragDrop( items : Array<String>, isDrop : Bool ) : Bool {
+		if( items.length == 0 )
+			return false;
+		var newPath = ide.makeRelative(items[0]);
+		if( pathIsValid(newPath) ) {
+			if( isDrop ) {
+				path = newPath;
+				onChange();
+			}
+			return true;
 		}
-		if( path != null && sys.FileSystem.exists(ide.getPath(path)) && extensions.indexOf(path.split(".").pop().toLowerCase()) >= 0 )
-			return ide.makeRelative(path);
-		return null;
+		return false;
 	}
 
+	function pathIsValid( path : String ) : Bool {
+		return (
+			path != null
+			&& sys.FileSystem.exists(ide.getPath(path))
+			&& extensions.indexOf(path.split(".").pop().toLowerCase()) >= 0
+		);
+	}
+
+
 	public function getFullPath() {
 		if( path == null )
 			return null;

+ 22 - 2
hide/comp/PropsEditor.hx

@@ -20,6 +20,26 @@ class PropsEditor extends Component {
 		fields = [];
 	}
 
+	public function onDragDrop( items : Array<String>, isDrop : Bool ) : Bool {
+		if( items.length == 0 )
+			return false;
+
+		var pickedEl = js.Browser.document.elementFromPoint(ide.mouseX, ide.mouseY);
+		var rootEl = element[0];
+		while( pickedEl != null ) {
+			if( pickedEl == rootEl )
+				return false;
+			for( field in fields ) {
+				if( field.tselect != null && field.tselect.element[0] == pickedEl )
+					return field.tselect.onDragDrop(items, isDrop);
+				if( field.fselect != null && field.fselect.element[0] == pickedEl )
+					return field.fselect.onDragDrop(items, isDrop);
+			}
+			pickedEl = pickedEl.parentElement;
+		}
+		return false;
+	}
+
 	public function addMaterial( m : h3d.mat.Material, ?parent : Element, ?onChange ) {
 		var def = m.editProps();
 		def = add(def, m.props, function(name) {
@@ -235,10 +255,10 @@ class PropsEditor extends Component {
 }
 
 
+@:allow(hide.comp.PropsEditor)
 class PropsField extends Component {
-
 	public var fname : String;
-	public var isTempChange : Bool;
+	var isTempChange : Bool;
 	var props : PropsEditor;
 	var context : Dynamic;
 	var current : Dynamic;

+ 0 - 1
hide/comp/Scene.hx

@@ -148,7 +148,6 @@ class Scene extends Component implements h3d.IDrawable {
 		engine.onResized = function() {
 			if( s2d == null ) return;
 			visible = engine.width > 32 && engine.height > 32; // 32x32 when hidden !
-			s2d.scaleMode = Stretch(engine.width, engine.height);
 			onResize();
 		};
 		engine.init();

+ 48 - 40
hide/comp/SceneEditor.hx

@@ -98,7 +98,7 @@ class SceneEditorContext extends hide.prefab.EditContext {
 
 	override function rebuildProperties() {
 		editor.scene.setCurrent();
-		editor.selectObjects(elements, NoHistory);
+		editor.selectElements(elements, NoHistory);
 	}
 
 	override function rebuildPrefab( p : hrt.prefab.Prefab ) {
@@ -218,7 +218,7 @@ class SceneEditor {
 		view.keys.register("sceneeditor.selectParent", function() {
 			if(curEdit.rootElements.length > 0) {
 				var p = curEdit.rootElements[0].parent;
-				if( p != null && p != sceneData ) selectObjects([p]);
+				if( p != null && p != sceneData ) selectElements([p]);
 			}
 		});
 		view.keys.register("sceneeditor.reparent", function() {
@@ -398,7 +398,7 @@ class SceneEditor {
 			case K.MOUSE_RIGHT:
 				selectNewObject();
 			case K.MOUSE_LEFT:
-				selectObjects([]);
+				selectElements([]);
 			}
 		};
 		if (!camera2D)
@@ -469,14 +469,14 @@ class SceneEditor {
 			if(evt.ctrlKey) {
 				var sel = tree.getSelection();
 				sel.push(e);
-				selectObjects(sel);
+				selectElements(sel);
 				tree.revealNode(e);
 			}
 			else
-				selectObjects([e]);
+				selectElements([e]);
 		}
 		favTree.onDblClick = function(e) {
-			selectObjects([e]);
+			selectElements([e]);
 			tree.revealNode(e);
 			return true;
 		}
@@ -504,7 +504,7 @@ class SceneEditor {
 			e.preventDefault();
 			var current = tree.getCurrentOver();
 			if(current != null && (curEdit == null || curEdit.elements.indexOf(current) < 0)) {
-				selectObjects([current]);
+				selectElements([current]);
 			}
 
 			var newItems = getNewContextMenu(current);
@@ -531,7 +531,7 @@ class SceneEditor {
 						setLock(curEdit.elements, current.locked);
 					} },
 					{ label : "Select all", click : selectAll },
-					{ label : "Select children", enabled : current != null, click : function() selectObjects(current.flatten()) },
+					{ label : "Select children", enabled : current != null, click : function() selectElements(current.flatten()) },
 				]);
 				if( !isRef )
 					actionItems = actionItems.concat([
@@ -558,7 +558,7 @@ class SceneEditor {
 		tree.allowRename = true;
 		tree.init();
 		tree.onClick = function(e, _) {
-			selectObjects(tree.getSelection(), NoTree);
+			selectElements(tree.getSelection(), NoTree);
 		}
 		tree.onDblClick = function(e) {
 			focusSelection();
@@ -595,7 +595,7 @@ class SceneEditor {
 			}
 		}
 		tree.applyStyle = function(p, el) applyTreeStyle(p, el);
-		selectObjects([]);
+		selectElements([]);
 		refresh();
 		this.camera2D = camera2D;
 	}
@@ -627,7 +627,7 @@ class SceneEditor {
 	}
 
 	function refreshProps() {
-		selectObjects(curEdit.elements, Nothing);
+		selectElements(curEdit.elements, Nothing);
 	}
 
 	public function refreshScene() {
@@ -784,10 +784,10 @@ class SceneEditor {
 						for(e in elts)
 							current.remove(e);
 					}
-					selectObjects(current);
+					selectElements(current);
 				}
 				else
-					selectObjects(elts);
+					selectElements(elts);
 			}
 			// ensure we get onMove even if outside our interactive, allow fast click'n'drag
 			if( e.button == K.MOUSE_LEFT ) {
@@ -1155,7 +1155,7 @@ class SceneEditor {
 						inside.push(elt);
 					}
 				}
-				selectObjects(inside);
+				selectElements(inside);
 				finish = true;
 			}
 
@@ -1355,12 +1355,12 @@ class SceneEditor {
 			lastRenderProps.applyProps(scene.s3d.renderer);
 	}
 
-	public function addObject(elts : Array<PrefabElement>, selectObj : Bool = true, doRefresh : Bool = true, isTemporary = false) {
+	public function addElements(elts : Array<PrefabElement>, selectObj : Bool = true, doRefresh : Bool = true, isTemporary = false) {
 		for (e in elts) {
 			makeInstance(e);
 		}
 		if (doRefresh) {
-			refresh(Partial, if (selectObj) () -> selectObjects(elts, NoHistory) else null);
+			refresh(Partial, if (selectObj) () -> selectElements(elts, NoHistory) else null);
 			refreshParents(elts);
 		}
 		if( isTemporary )
@@ -1369,7 +1369,7 @@ class SceneEditor {
 		undo.change(Custom(function(undo) {
 			var fullRefresh = false;
 			if(undo) {
-				selectObjects([], NoHistory);
+				selectElements([], NoHistory);
 				for (e in elts) {
 					if(!removeInstance(e))
 						fullRefresh = true;
@@ -1382,7 +1382,7 @@ class SceneEditor {
 					e.parent.children.push(e);
 					makeInstance(e);
 				}
-				refresh(Partial, () -> selectObjects(elts,NoHistory));
+				refresh(Partial, () -> selectElements(elts,NoHistory));
 				refreshParents(elts);
 			}
 		}));
@@ -1485,11 +1485,11 @@ class SceneEditor {
 		fillProps(edit, e);
 	}
 
-	function setObjectSelected( p : PrefabElement, ctx : hrt.prefab.Context, b : Bool ) {
+	function setElementSelected( p : PrefabElement, ctx : hrt.prefab.Context, b : Bool ) {
 		return p.setSelected(ctx, b);
 	}
 
-	public function selectObjects( elts : Array<PrefabElement>, ?mode : SelectMode = Default ) {
+	public function selectElements( elts : Array<PrefabElement>, ?mode : SelectMode = Default ) {
 		function impl(elts,mode:SelectMode) {
 			scene.setCurrent();
 			if( curEdit != null )
@@ -1519,7 +1519,7 @@ class SceneEditor {
 				if( map.exists(e) )
 					return;
 				map.set(e, true);
-				if(setObjectSelected(e, getSelContext(e), b))
+				if(setElementSelected(e, getSelContext(e), b))
 					for( e in e.children )
 						selectRec(e,b);
 			}
@@ -1530,7 +1530,7 @@ class SceneEditor {
 			edit.cleanups.push(function() {
 				for( e in map.keys() ) {
 					if( hasBeenRemoved(e) ) continue;
-					setObjectSelected(e, getSelContext(e), false);
+					setElementSelected(e, getSelContext(e), false);
 				}
 			});
 
@@ -1601,6 +1601,14 @@ class SceneEditor {
 	}
 
 	public function onDragDrop( items : Array<String>, isDrop : Bool ) {
+		var pickedEl = js.Browser.document.elementFromPoint(ide.mouseX, ide.mouseY);
+		var propEl = properties.element[0];
+		while( pickedEl != null ) {
+			if( pickedEl == propEl )
+				return properties.onDragDrop(items, isDrop);
+			pickedEl = pickedEl.parentElement;
+		}
+
 		var supported = @:privateAccess hrt.prefab.Library.registeredExtensions;
 		var paths = [];
 		for(path in items) {
@@ -1611,11 +1619,11 @@ class SceneEditor {
 		if( paths.length == 0 )
 			return false;
 		if(isDrop)
-			dropObjects(paths, sceneData);
+			dropElements(paths, sceneData);
 		return true;
 	}
 
-	function dropObjects(paths: Array<String>, parent: PrefabElement) {
+	function dropElements(paths: Array<String>, parent: PrefabElement) {
 		scene.setCurrent();
 		var localMat = getPickTransform(parent);
 		if(localMat == null) return;
@@ -1647,7 +1655,7 @@ class SceneEditor {
 
 		for(e in elts)
 			makeInstance(e);
-		refresh(Partial, () -> selectObjects(elts));
+		refresh(Partial, () -> selectElements(elts));
 
 		undo.change(Custom(function(undo) {
 			if( undo ) {
@@ -1737,11 +1745,11 @@ class SceneEditor {
 				effectFunc(false);
 			}
 			if(undo)
-				refresh(()->selectObjects([],NoHistory));
+				refresh(()->selectElements([],NoHistory));
 			else
-				refresh(()->selectObjects([group],NoHistory));
+				refresh(()->selectElements([group],NoHistory));
 		}));
-		refresh(effectFunc(false) ? Full : Partial, () -> selectObjects([group],NoHistory));
+		refresh(effectFunc(false) ? Full : Partial, () -> selectElements([group],NoHistory));
 	}
 
 	function onCopy() {
@@ -1767,7 +1775,7 @@ class SceneEditor {
 		if(obj != null) {
 			var p = hrt.prefab.Prefab.loadPrefab(obj, parent);
 			autoName(p);
-			addObject([p]);
+			addElements([p]);
 		}
 		else {
 			obj = view.getClipboard("library");
@@ -1777,7 +1785,7 @@ class SceneEditor {
 					autoName(c);
 					c.parent = parent;
 				}
-				addObject(lib.children);
+				addElements(lib.children);
 			}
 		}
 	}
@@ -1807,11 +1815,11 @@ class SceneEditor {
 	}
 
 	public function selectAll() {
-		selectObjects(getAllSelectable3D());
+		selectElements(getAllSelectable3D());
 	}
 
 	public function deselect() {
-		selectObjects([]);
+		selectElements([]);
 	}
 
 	public function isSelected( p : PrefabElement ) {
@@ -1952,7 +1960,7 @@ class SceneEditor {
 			ref.rotationY = obj3d.rotationY;
 			ref.rotationZ = obj3d.rotationZ;
 		}
-		addObject([ref]);
+		addElements([ref]);
 	}
 
 	function duplicate(thenMove: Bool) {
@@ -1979,7 +1987,7 @@ class SceneEditor {
 		}
 
 		refreshTree(function() {
-			selectObjects(newElements);
+			selectElements(newElements);
 			tree.setSelection(newElements);
 			if(thenMove && curEdit.rootObjects.length > 0) {
 				gizmo.startMove(MoveXY, true);
@@ -1990,7 +1998,7 @@ class SceneEditor {
 		});
 
 		undo.change(Custom(function(undo) {
-			selectObjects([], NoHistory);
+			selectElements([], NoHistory);
 
 			var fullRefresh = false;
 			if(undo) {
@@ -2049,7 +2057,7 @@ class SceneEditor {
 		}
 
 		if (doRefresh)
-			refreshFunc(then != null ? then : () -> selectObjects([],NoHistory));
+			refreshFunc(then != null ? then : () -> selectElements([],NoHistory));
 
 		if (enableUndo) {
 			undo.change(Custom(function(undo) {
@@ -2061,7 +2069,7 @@ class SceneEditor {
 				if(undo)
 					for(e in elts) makeInstance(e);
 
-				refreshFunc(then != null ? then : selectObjects.bind(undo ? elts : [],NoHistory));
+				refreshFunc(then != null ? then : selectElements.bind(undo ? elts : [],NoHistory));
 			}));
 		}
 	}
@@ -2317,10 +2325,10 @@ class SceneEditor {
 				if( pmodel.inf.fileSource != null )
 					ide.chooseFile(pmodel.inf.fileSource, function(path) {
 						var p = make(path);
-						addObject([p]);
+						addElements([p]);
 					});
 				else
-					addObject([make()]);
+					addElements([make()]);
 			}
 		};
 	}
@@ -2335,7 +2343,7 @@ class SceneEditor {
 					var s = new hrt.prefab.DynamicShader(parentElt);
 					s.source = path;
 					s.name = name;
-					addObject([s]);
+					addElements([s]);
 				}
 			}
 		}

+ 5 - 5
hide/view/FXEditor.hx

@@ -49,14 +49,14 @@ private class FXSceneEditor extends hide.comp.SceneEditor {
 		parent.onUpdate(dt);
 	}
 
-	override function setObjectSelected( p : PrefabElement, ctx : hrt.prefab.Context, b : Bool ) {
+	override function setElementSelected( p : PrefabElement, ctx : hrt.prefab.Context, b : Bool ) {
 		if( p.getParent(hrt.prefab.fx.Emitter) != null )
 			return false;
-		return super.setObjectSelected(p, ctx, b);
+		return super.setElementSelected(p, ctx, b);
 	}
 
-	override function selectObjects( elts, ?mode ) {
-		super.selectObjects(elts, mode);
+	override function selectElements( elts, ?mode ) {
+		super.selectElements(elts, mode);
 		parent.onSelect(elts);
 	}
 
@@ -1202,7 +1202,7 @@ class FXEditor extends FileView {
 			sceneEditor.refresh();
 		}));
 		sceneEditor.refresh(function() {
-			sceneEditor.selectObjects([element]);
+			sceneEditor.selectElements([element]);
 		});
 		return added;
 	}

+ 2 - 1
hide/view/l3d/Gizmo.hx

@@ -113,7 +113,8 @@ class Gizmo extends h3d.scene.Object {
 	}
 
 	public function startMove(mode: TransformMode, ?duplicating=false) {
-		mouseLock = true;
+		if (mode == Scale || mode == RotateX || mode == RotateY || mode == RotateZ)
+			mouseLock = true;
 		moving = true;
 		if(onStartMove != null) onStartMove(mode);
 		var startMat = getAbsPos().clone();

+ 6 - 4
hide/view/l3d/Level3D.hx

@@ -42,12 +42,14 @@ class CamController extends h3d.scene.CameraController {
 			pushStartX = pushX = e.relX;
 			pushStartY = pushY = e.relY;
 			startPush = new h2d.col.Point(pushX, pushY);
+			@:privateAccess scene.window.mouseLock = true;
 		case ERelease, EReleaseOutside:
 			if( pushing == e.button ) {
 				pushing = -1;
 				startPush = null;
 				if( e.kind == ERelease && haxe.Timer.stamp() - pushTime < 0.2 && hxd.Math.distance(e.relX - pushStartX,e.relY - pushStartY) < 5 )
 					onClick(e);
+				@:privateAccess scene.window.mouseLock = false;
 			}
 		case EMove:
 			switch( pushing ) {
@@ -136,7 +138,7 @@ private class Level3DSceneEditor extends hide.comp.SceneEditor {
 
 		function setup(p : PrefabElement) {
 			autoName(p);
-			haxe.Timer.delay(addObject.bind([p]), 0);
+			haxe.Timer.delay(addElements.bind([p]), 0);
 		}
 
 		function addNewInstances() {
@@ -390,7 +392,7 @@ class Level3D extends FileView {
 
 	function bakeLights() {
 		var curSel = sceneEditor.curEdit.elements;
-		sceneEditor.selectObjects([]);
+		sceneEditor.selectElements([]);
 		var passes = [];
 		for( m in scene.s3d.getMaterials() ) {
 			var s = m.getPass("shadow");
@@ -429,7 +431,7 @@ class Level3D extends FileView {
 				continue;
 			l.saveBaked(sceneEditor.context);
 		}
-		sceneEditor.selectObjects(curSel);
+		sceneEditor.selectElements(curSel);
 	}
 
 	function bakeVolumetricLightmaps(){
@@ -448,7 +450,7 @@ class Level3D extends FileView {
 				return;
 			}
 			v.startBake(sceneEditor.curEdit, bakeNext);
-			sceneEditor.selectObjects([v]);
+			sceneEditor.selectElements([v]);
 		}
 		bakeNext();
 	}

+ 5 - 1
hrt/prefab/Object3D.hx

@@ -186,7 +186,8 @@ class Object3D extends Prefab {
 						}
 					}
 				}
-				var icon = Reflect.field(shared.scene.config.get("sceneeditor.huds"), sheet);
+				var huds : Dynamic = shared.scene.config.get("sceneeditor.huds");
+				var icon = Reflect.field(huds, sheet);
 				if( icon != null ) {
 					var t : Dynamic = ide.resolveCDBValue(sheet,icon, props);
 					if( t != null && (t.file != null || Std.is(t,String)) ) {
@@ -209,6 +210,9 @@ class Object3D extends Prefab {
 								(t.width == null ? 1 : t.width) * t.size,
 								(t.height == null ? 1 : t.height) * t.size
 							);
+							var maxWidth : Dynamic = huds.maxWidth;
+							if( maxWidth != null && bmp.tile.width > maxWidth )
+								bmp.width = maxWidth;
 						} else {
 							var f = Std.downcast(obj.getObjectByName("$huds_f"), h2d.Flow);
 							if( f == null ) {

+ 8 - 8
hrt/prefab/Prefab.hx

@@ -327,13 +327,13 @@ class Prefab {
 	/**
 		Simlar to get() but returns null if not found.
 	**/
-	public function getOpt<T:Prefab>( cl : Class<T>, ?name : String ) : T {
+	public function getOpt<T:Prefab>( cl : Class<T>, ?name : String, ?followRefs : Bool ) : T {
 		if( name == null || this.name == name ) {
 			var cval = to(cl);
 			if( cval != null ) return cval;
 		}
 		for( c in children ) {
-			var p = c.getOpt(cl, name);
+			var p = c.getOpt(cl, name, followRefs);
 			if( p != null )
 				return p;
 		}
@@ -354,19 +354,19 @@ class Prefab {
 	/**
 		Return all prefabs in the tree matching the given prefab class.
 	**/
-	public function getAll<T:Prefab>( cl : Class<T>, ?arr: Array<T> ) : Array<T> {
-		return findAll(function(p) return p.to(cl));
+	public function getAll<T:Prefab>( cl : Class<T>, ?followRefs : Bool, ?arr: Array<T> ) : Array<T> {
+		return findAll(function(p) return p.to(cl), followRefs, arr);
 	}
 
 	/**
 		Find a single prefab in the tree by calling `f` on each and returning the first not-null value returned, or null if not found.
 	**/
-	public function find<T>( f : Prefab -> Null<T> ) : Null<T> {
+	public function find<T>( f : Prefab -> Null<T>, ?followRefs : Bool ) : Null<T> {
 		var v = f(this);
 		if( v != null )
 			return v;
 		for( p in children ) {
-			var v = p.find(f);
+			var v = p.find(f, followRefs);
 			if( v != null ) return v;
 		}
 		return null;
@@ -375,13 +375,13 @@ class Prefab {
 	/**
 		Find several prefabs in the tree by calling `f` on each and returning all the not-null values returned.
 	**/
-	public function findAll<T>( f : Prefab -> Null<T>, ?arr : Array<T> ) : Array<T> {
+	public function findAll<T>( f : Prefab -> Null<T>, ?followRefs : Bool, ?arr : Array<T> ) : Array<T> {
 		if( arr == null ) arr = [];
 		var v = f(this);
 		if( v != null )
 			arr.push(v);
 		for( o in children )
-			o.findAll(f,arr);
+			o.findAll(f,followRefs,arr);
 		return arr;
 	}
 

+ 23 - 0
hrt/prefab/Reference.hx

@@ -80,6 +80,29 @@ class Reference extends Object3D {
 		}
 	}
 
+	override function find<T>( f : Prefab -> Null<T>, ?followRefs : Bool ) : T {
+		if( followRefs && ref != null ) {
+			var v = ref.find(f, followRefs);
+			if( v != null ) return v;
+		}
+		return super.find(f, followRefs);
+	}
+
+	override function findAll<T>( f : Prefab -> Null<T>, ?followRefs : Bool, ?arr : Array<T> ) : Array<T> {
+		if( followRefs && ref != null )
+			arr = ref.findAll(f, followRefs, arr);
+		return super.findAll(f, followRefs, arr);
+	}
+
+	override function getOpt<T:Prefab>( cl : Class<T>, ?name : String, ?followRefs ) : T {
+		if( followRefs && ref != null ) {
+			var v = ref.getOpt(cl, name, true);
+			if( v != null )
+				return v;
+		}
+		return super.getOpt(cl, name, followRefs);
+	}
+
 	override function makeInstance(ctx: Context) : Context {
 		var p = resolveRef(ctx.shared);
 		if(p == null)

+ 4 - 9
hrt/prefab/RenderProps.hx

@@ -67,15 +67,10 @@ class RenderProps extends Prefab {
 		renderer.props = props;
 		for(fx in renderer.effects)
 			fx.dispose();
-		renderer.effects = [];
-		for( s in children ) {
-			var fx = Std.downcast(s, hrt.prefab.rfx.RendererFX);
-			if( fx != null )
-				renderer.effects.push((fx:h3d.impl.RendererFX));
-			var env = Std.downcast(s, hrt.prefab.l3d.Environment);
-			if( env != null )
-				env.applyToRenderer(renderer);
-		}
+		renderer.effects = [for( v in getAll(hrt.prefab.rfx.RendererFX,true) ) v];
+		var env = getOpt(hrt.prefab.l3d.Environment);
+		if( env != null )
+			env.applyToRenderer(renderer);
 		renderer.refreshProps();
 		return true;
 	}

+ 55 - 25
hrt/prefab/l3d/MeshSpray.hx

@@ -203,6 +203,9 @@ class MeshSpray extends Object3D {
 
 	var sceneEditor : hide.comp.SceneEditor;
 
+	var undo(get, null):hide.ui.UndoHistory;
+	function get_undo() { return sceneEditor.view.undo; }
+
 	var lastIndexMesh = -1;
 	var allSetGroups : Array<SetGroup>;
 	var setGroup : SetGroup;
@@ -308,6 +311,7 @@ class MeshSpray extends Object3D {
 
 	var wasEdited = false;
 	var previewModels : Array<hrt.prefab.Prefab> = [];
+	var sprayedModels : Array<hrt.prefab.Prefab> = [];
 	override function edit( ectx : EditContext ) {
 
 		invParent = getAbsPos().clone();
@@ -325,6 +329,7 @@ class MeshSpray extends Object3D {
 
 		var ctx = ectx.getContext(this);
 		var s2d = @:privateAccess ctx.local2d.getScene();
+		reset();
 		interactive = new h2d.Interactive(10000, 10000, s2d);
 		interactive.propagateEvents = true;
 		interactive.cancelEvents = false;
@@ -340,7 +345,7 @@ class MeshSpray extends Object3D {
 					if( !K.isDown( K.SHIFT) ) {
 						if (previewModels.length > 0) {
 							sceneEditor.deleteElements(previewModels, () -> { }, false);
-							sceneEditor.selectObjects([this]);
+							sceneEditor.selectElements([this]);
 							previewModels = [];
 						}
 						var worldPos = ectx.screenToGround(s2d.mouseX, s2d.mouseY);
@@ -365,10 +370,23 @@ class MeshSpray extends Object3D {
 		interactive.onRelease = function(e) {
 			e.propagate = false;
 			sprayEnable = false;
+			var addedModels = sprayedModels.copy();
+			if (sprayedModels.length > 0) {
+				undo.change(Custom(function(undo) {
+					if(undo) {
+						sceneEditor.deleteElements(addedModels, () -> reset(), true, false);
+					}
+					else {
+						sceneEditor.addElements(addedModels, false, true, true);
+					}
+				}));
+				sprayedModels = [];
+			}
+			
 
 			if (previewModels.length > 0) {
 				sceneEditor.deleteElements(previewModels, () -> { }, false);
-				sceneEditor.selectObjects([this], Nothing);
+				sceneEditor.selectElements([this], Nothing);
 				previewModels = [];
 			}
 		};
@@ -595,10 +613,10 @@ class MeshSpray extends Object3D {
 			}
 		});
 		options.find("#add").click(function(_) {
-			hide.Ide.inst.chooseFiles(["fbx", "l3d"], function(path) {
-				for( m in path ) {
-					addMeshPath(m);
-					selectElement.append(new hide.Element('<option value="$m">${extractMeshName(m)}</option>'));
+			hide.Ide.inst.chooseFiles(["fbx", "l3d"], function(paths) {
+				for( path in paths ) {
+					addMeshPath(path);
+					selectElement.append(new hide.Element('<option value="$path">${extractMeshName(path)}</option>'));
 				}
 			});
 		});
@@ -631,7 +649,7 @@ class MeshSpray extends Object3D {
 					}
 				}
 				sceneEditor.deleteElements(meshes);
-				sceneEditor.selectObjects([this], Nothing);
+				sceneEditor.selectElements([this], Nothing);
 			}
 		});
 
@@ -679,31 +697,36 @@ class MeshSpray extends Object3D {
 		sceneEditor.properties.element.find("#repeatMeshBtn").prop("checked", CONFIG.dontRepeatMesh);
 	}
 
+	override function removeInstance(ctx : Context):Bool {
+		reset();
+		return super.removeInstance(ctx);
+	}
 	override function setSelected( ctx : Context, b : Bool ) {
-		if (timerCicle != null) {
-			timerCicle.stop();
-		}
 		if( !b ) {
+			reset();
 			if( gBrushes != null ) {
 				for (g in gBrushes) g.remove();
 				gBrushes = null;
 			}
-			if( interactive != null ) interactive.remove();
-			timerCicle = new haxe.Timer(100);
-			timerCicle.run = function() {
-				timerCicle.stop();
-				if (previewModels != null && previewModels.length > 0) {
-					sceneEditor.deleteElements(previewModels, () -> { }, false, false);
-					previewModels = [];
-				}
-				if (wasEdited)
-					sceneEditor.refresh(Partial, () -> { });
-				wasEdited = false;
-			};
 		}
 		return false;
 	}
 
+	function reset() {
+		if( interactive != null ) interactive.remove();
+		if (previewModels != null && previewModels.length > 0) {
+			sceneEditor.deleteElements(previewModels, () -> { }, false, false);
+			previewModels = [];
+		}
+		if (wasEdited)
+			sceneEditor.refresh(Partial, () -> { });
+		wasEdited = false;
+		if( gBrushes != null ) {
+			for (g in gBrushes) g.remove();
+			gBrushes = null;
+		}
+	}
+
 	function addMeshPath(path : String) {
 		var mesh = { path: path, isRef: path.toLowerCase().indexOf(".fbx") == -1 };
 		if (currentMeshes.filter(m -> m.path == path).length == 0)
@@ -754,7 +777,7 @@ class MeshSpray extends Object3D {
 		if (computedDensity == 1)
 		if (previewModels.length > 0) {
 			sceneEditor.deleteElements(previewModels, () -> { }, false);
-			sceneEditor.selectObjects([this], Nothing);
+			sceneEditor.selectElements([this], Nothing);
 			previewModels = [];
 		}
 		lastPos = point;
@@ -832,7 +855,7 @@ class MeshSpray extends Object3D {
 			}
 
 			if (previewModels.length > 0) {
-				sceneEditor.addObject(previewModels, false, false, true);
+				sceneEditor.addElements(previewModels, false, false, true);
 			}
 		}
 	}
@@ -841,6 +864,7 @@ class MeshSpray extends Object3D {
 		lastMeshId = -1;
 		if (previewModels.length > 0) {
 			wasEdited = true;
+			sprayedModels = sprayedModels.concat(previewModels);
 			previewModels = [];
 		}
 	}
@@ -862,7 +886,7 @@ class MeshSpray extends Object3D {
 		if (childToRemove.length > 0) {
 			wasEdited = true;
 			sceneEditor.deleteElements(childToRemove, () -> { }, false);
-			sceneEditor.selectObjects([this], Nothing);
+			sceneEditor.selectElements([this], Nothing);
 		}
 	}
 
@@ -921,6 +945,12 @@ class MeshSpray extends Object3D {
 		return ctx;
 	}
 
+	override function applyTransform(o : h3d.scene.Object) {
+		super.applyTransform(o);
+		cast(o, MeshSprayObject).redraw();
+	}
+
+
 	function makePrimCircle(segments: Int, inner : Float = 0, rings : Int = 0) {
 		var points = [];
 		var uvs = [];

+ 24 - 11
hrt/prefab/rfx/Configurator.hx

@@ -33,8 +33,10 @@ class ConfiguratorInterp extends hscript.Interp {
 						break;
 					c = Type.getSuperClass(c);
 				}
-				if( c == null )
-					throw o+" has no field "+f;
+				if( c == null ) {
+					var cl = Type.getClass(o);
+					throw (cl == null ? ""+o : Type.getClassName(cl)) + " has no field "+f;
+				}
 			}
 			#end
 			found = { obj : o, field : f, value : null, set : false };
@@ -69,7 +71,7 @@ class Configurator extends RendererFX {
 	@:s var script : String = "";
 	var values : Map<String, Float> = new Map();
 
-	var prefabCache : Map<String, Prefab> = new Map();
+	var prefabCache : Map<String, { r : Prefab }> = new Map();
 
 	#if hscript
 	var interp : ConfiguratorInterp;
@@ -78,6 +80,7 @@ class Configurator extends RendererFX {
 	#if editor
 	var errorTarget : hide.Element;
 	#end
+	var rootPrefab : Prefab;
 
 	public function new(?parent) {
 		super(parent);
@@ -93,16 +96,17 @@ class Configurator extends RendererFX {
 		return bpow / (bpow + Math.pow(1 - v, easing + 1));
 	}
 
-	function getPrefab( id : String ) {
+	function getPrefab( opt : Bool, id : String ) {
 		var p = prefabCache.get(id);
 		if( p != null )
-			return p;
-		var root : Prefab = this;
-		while( root.parent != null ) root = root.parent;
-		var p = root.getOpt(hrt.prefab.Prefab,id);
-		if( p == null ) throw "Missing prefab #"+id;
+			return p.r;
+		var p = rootPrefab.getOpt(hrt.prefab.Prefab,id,true);
+		if( p == null ) {
+			if( opt ) return null;
+			throw "Missing prefab #"+id;
+		}
 		#if !editor
-		prefabCache.set(id, p);
+		prefabCache.set(id, { r : p });
 		#end
 		return p;
 	}
@@ -110,6 +114,14 @@ class Configurator extends RendererFX {
 	override function makeInstance(ctx:Context):Context {
 		for( v in vars )
 			values.set(v.name, v.defValue);
+		rootPrefab = this;
+		var shared = ctx.shared;
+		while( shared.parent != null ) {
+			rootPrefab = shared.parent.prefab;
+			shared = shared.parent.shared;
+		}
+		while( rootPrefab.parent != null )
+			rootPrefab = rootPrefab.parent;
 		#if hscript
 		interp = null;
 		#end
@@ -128,7 +140,8 @@ class Configurator extends RendererFX {
 			}
 			if( interp == null ) {
 				interp = new ConfiguratorInterp();
-				interp.variables.set("get", getPrefab);
+				interp.variables.set("get", getPrefab.bind(false));
+				interp.variables.set("getOpt", getPrefab.bind(true));
 				interp.variables.set("smooth", smoothValue);
 			}
 			for( k => v in values )