Browse Source

Merge branch 'partialrefresh2'

trethaller 6 years ago
parent
commit
eef2b75414

+ 4 - 3
hide/comp/Scene.hx

@@ -175,9 +175,10 @@ class Scene extends Component implements h3d.IDrawable {
 			return;
 		setCurrent();
 		sevents.checkEvents();
-		s2d.setElapsedTime(hxd.Timer.tmod * speed / 60);
-		s3d.setElapsedTime(hxd.Timer.tmod * speed / 60);
-		onUpdate(hxd.Timer.tmod * speed);
+		var dt = hxd.Timer.tmod * speed / 60;
+		s2d.setElapsedTime(dt);
+		s3d.setElapsedTime(dt);
+		onUpdate(dt);
 		engine.render(this);
 	}
 

+ 142 - 149
hide/comp/SceneEditor.hx

@@ -74,6 +74,11 @@ class SceneEditorContext extends hide.prefab.EditContext {
 	}
 }
 
+enum RefreshMode {
+	Partial;
+	Full;
+}
+
 class SceneEditor {
 
 	public var tree : hide.comp.IconTree<PrefabElement>;
@@ -83,7 +88,6 @@ class SceneEditor {
 	public var curEdit(default, null) : SceneEditorContext;
 	public var snapToGround = false;
 	public var localTransform = true;
-	public var enableLightRefresh = false;
 	public var cameraController : h3d.scene.CameraController;
 	public var editorDisplay(default,set) : Bool;
 
@@ -93,7 +97,7 @@ class SceneEditor {
 	var gizmo : hide.view.l3d.Gizmo;
 	var interactives : Map<PrefabElement, h3d.scene.Interactive>;
 	var ide : hide.Ide;
-	var event : hxd.WaitEvent;
+	public var event(default, null) : hxd.WaitEvent;
 	var hideList : Map<PrefabElement, Bool> = new Map();
 
 	var undo(get, null):hide.ui.UndoHistory;
@@ -341,12 +345,12 @@ class SceneEditor {
 		refresh();
 	}
 
-	public function refresh( ?callb ) {
-		refreshScene();
+	public function refresh( ?mode: RefreshMode, ?callb: Void->Void) {
+		if(mode == null || mode == Full) refreshScene();
 		refreshTree(callb);
 	}
 
-	public function refreshTree( ?callb ) {
+	function refreshTree( ?callb ) {
 		tree.refresh(function() {
 			var all = sceneData.flatten(hxd.prefab.Prefab);
 			for(elt in all) {
@@ -755,6 +759,7 @@ class SceneEditor {
 
 	public function getContext(elt : PrefabElement) {
 		if(elt == null) return null;
+		if(elt == sceneData) return context;
 		return context.shared.contexts.get(elt);
 	}
 
@@ -780,46 +785,53 @@ class SceneEditor {
 		return null;
 	}
 
-	public function addObject( e : PrefabElement ) {
-		var roots = e.parent.children;
-		var parentCtx = getContext(e.parent);
-		if(parentCtx == null)
-			parentCtx = context;
-		e.makeInstance(parentCtx);
-		var local3d = getSelfObject(e);
-		var lightRefresh = local3d != null && enableLightRefresh;
-		var parentObj = local3d != null ? local3d.parent : null;
-		var int = interactives.get(e);
+	function removeInstance(elt : PrefabElement) {
+		var result = true;
+		var contexts = context.shared.contexts;
+		function recRemove(e: PrefabElement) {
+			for(c in e.children)
+				recRemove(c);
+			
+			var int = interactives.get(e);
+			if(int != null) {
+				int.remove();
+				interactives.remove(e);
+			}
+			for(ctx in getContexts(e)) {
+				if(!e.removeInstance(ctx))
+					result = false;
+				contexts.remove(e);
+			}
+		}
+		recRemove(elt);	
+		return result;
+	}
+
+	function makeInstance(elt: PrefabElement) {
+		var parentCtx = getContext(elt.parent);
+		elt.makeInstanceRec(parentCtx);
+		makeInteractive(elt);
+		elt.visitChildren(function(e) { makeInteractive(e); return true; });
+	}
+
+	public function addObject(e : PrefabElement) {
+		makeInstance(e);
+		refresh(Partial, () -> selectObjects([e]));
 		undo.change(Custom(function(undo) {
-			deselect();
-			if( undo ) {
-				roots.remove(e);
-				if(parentObj != null)
-					parentObj.removeChild(local3d);
-				if(int != null)
-					interactives.remove(e);
+			var fullRefresh = false;
+			if(undo) {
+				deselect();
+				if(!removeInstance(e))
+					fullRefresh = true;
+				e.parent.children.remove(e);
+				refresh(fullRefresh ? Full : Partial);
 			}
 			else {
-				roots.push(e);
-				if(parentObj != null)
-					parentObj.addChild(local3d);
-				if(int != null)
-					interactives.set(e, int);
+				e.parent.children.push(e);
+				makeInstance(e);
+				refresh(Partial, () -> selectObjects([e]));
 			}
-			if(local3d != null)
-				refreshTree();
-			else 
-				refresh();
 		}));
-		if(lightRefresh) {
-			makeInteractive(e);
-			refreshTree(function() {
-				selectObjects([e]);
-			});
-		}
-		else refresh(function() {
-			selectObjects([e]);
-		});
 	}
 
 	function fillProps( edit, e : PrefabElement ) {
@@ -923,8 +935,31 @@ class SceneEditor {
 			obj3d.setTransform(localMat);
 			autoName(obj3d);
 			elts.push(obj3d);
+
 		}
-		refresh(() -> selectObjects(elts));
+
+		for(e in elts)
+			makeInstance(e);
+		refresh(Partial, () -> selectObjects(elts));
+
+		undo.change(Custom(function(undo) {
+			if( undo ) {
+				var fullRefresh = false;
+				for(e in elts) {
+					if(!removeInstance(e))
+						fullRefresh = true;
+					parent.children.remove(e);
+				}
+				refresh(fullRefresh ? Full : Partial);
+			}
+			else {
+				for(e in elts) {
+					parent.children.push(e);
+					makeInstance(e);
+				}
+				refresh(Partial);
+			}
+		}));
 	}
 
 	function canGroupSelection() {
@@ -1160,69 +1195,58 @@ class SceneEditor {
 		if(elements == null || elements.length == 0)
 			return;
 		var contexts = context.shared.contexts;
-		var oldContexts = contexts.copy();
-		var lightRefresh = enableLightRefresh;
-		var newElements = [for(elt in elements) {
-			var obj3d = Std.instance(elt, Object3D);
-			if(obj3d == null)
-				lightRefresh = false;
+
+		var undoes = [];
+		var newElements = [];
+		for(elt in elements) {
 			var clone = elt.clone();
-			var index = elt.parent.children.indexOf(elt);
+			var index = elt.parent.children.indexOf(elt) + 1;
 			clone.parent = elt.parent;
 			elt.parent.children.remove(clone);
-			elt.parent.children.insert(index+1, clone);
+			elt.parent.children.insert(index, clone);
 			autoName(clone);
-			clone.makeInstanceRec(getContext(elt.parent));
-			makeInteractive(clone);
-			{ elt: clone, idx: index };
-		}];
-		var newContexts = contexts.copy();
-
-		function addUndo() {
-			undo.change(Custom(function(undo) {
-				for(e in newElements) {
-					if(undo) {
-						e.elt.parent.children.remove(e.elt);
-					}
-					else {
-						e.elt.parent.children.insert(e.idx, e.elt);
-					}
-				}
-				if(undo)
-					context.shared.contexts = oldContexts;
-				else
-					context.shared.contexts = newContexts;
-				refresh();
-				deselect();
-			}));
+			makeInstance(clone);
+			newElements.push(clone);
+
+			undoes.push(function(undo) {
+				if(undo) elt.parent.children.remove(clone);
+				else elt.parent.children.insert(index, clone);
+			});
 		}
 
-		function afterRefresh() {
-			var all = [for(e in newElements) e.elt];
-			selectObjects(all);
-			tree.setSelection(all);
+		refreshTree(function() {
+			selectObjects(newElements);
+			tree.setSelection(newElements);
 			if(thenMove && curEdit.rootObjects.length > 0) {
-				/* Disabled for now as getPickTransform() will necessarily project on ground, which we don't always want
-				if(all.length == 1) {
-					var pickMat = getPickTransform(all[0].parent);
-					if(pickMat != null) {
-						setTransform(all[0], pickMat.getPosition());
-						moveGizmoToSelection();
-					}
-				} */
 				gizmo.startMove(MoveXY, true);
 				gizmo.onFinishMove = function() {
 					refreshProps();
-					addUndo();
 				}
 			}
-			else {
-				addUndo();
+		});
+
+		undo.change(Custom(function(undo) {
+			deselect();
+
+			var fullRefresh = false;
+			if(undo) {
+				for(elt in newElements) {
+					if(!removeInstance(elt)) {
+						fullRefresh = true;
+						break;
+					}
+				}
 			}
-		}
-		if(lightRefresh)
-			refreshTree(afterRefresh);
-		else refresh(afterRefresh);
+
+			for(u in undoes) u(undo);
+
+			if(!undo) {
+				for(elt in newElements)
+					makeInstance(elt);
+			}
+
+			refresh(fullRefresh ? Full : Partial);
+		}));
 	}
 
 	function setTransform(elt: PrefabElement, ?mat: h3d.Matrix, ?position: h3d.Vector) {
@@ -1242,67 +1266,36 @@ class SceneEditor {
 	}
 
 	function deleteElements(elts : Array<PrefabElement>) {
-		var contexts = context.shared.contexts;
-		var list = [];
-		var lightRefresh = enableLightRefresh;
-		for(e in elts) {
-			var ctx = getContext(e);
-			if(ctx == null)
-				continue;
-			var local2d = ctx.local2d;
-			var local2dParent = local2d != null ? local2d.parent : null;
-			var obj = getSelfObject(e);
-			var parentObj = obj != null ? obj.parent : null;
-			if(obj == null)
-				lightRefresh = false;
-			list.push({
-				elt: e,
-				parent: e.parent,
-				index: e.parent.children.indexOf(e),
-				obj: obj,
-				parentObj: parentObj,
-				objIndex: parentObj != null ? parentObj.getChildIndex(obj) : -1,
-				local2d: local2d,
-				local2dParent: local2dParent
+		var fullRefresh = false;
+		var undoes = [];
+		for(elt in elts) {
+			if(!removeInstance(elt))
+				fullRefresh = true;
+			var index = elt.parent.children.indexOf(elt);
+			elt.parent.children.remove(elt);
+			undoes.push(function(undo) {
+				if(undo) elt.parent.children.insert(index, elt);
+				else elt.parent.children.remove(elt);
 			});
 		}
-		deselect();
-		var oldContexts = contexts.copy();
-		for(e in elts) {
-			hideList.remove(e);
-			for(c in e.flatten())
-				contexts.remove(c);
-		}
-		saveHideState();
-		var newContexts = contexts.copy();
-		function action(undo) {
-			if( undo ) {
-				for(o in list) {
-					o.parent.children.insert(o.index, o.elt);
-					if(o.obj != null)
-						o.parentObj.addChildAt(o.obj, o.objIndex);
-					if(o.local2dParent != null)
-						o.local2dParent.addChild(o.local2d);
-				}
-				context.shared.contexts = oldContexts;
-			}
-			else {
-				for(o in list) {
-					o.parent.children.remove(o.elt);
-					if(o.parentObj != null)
-						o.parentObj.removeChild(o.obj);
-					if(o.local2dParent != null)
-						o.local2dParent.removeChild(o.local2d);
-				}
-				context.shared.contexts = newContexts;
-			}
-			if(lightRefresh)
-				refreshTree();
-			else
-				refresh();
+
+		function refreshFunc(then) {
+			refresh(fullRefresh ? Full : Partial, then);
 		}
-		action(false);
-		undo.change(Custom(action));
+
+		refreshFunc(selectObjects.bind(elts));
+
+		undo.change(Custom(function(undo) {
+			if(!undo && !fullRefresh)
+				for(e in elts) removeInstance(e);
+
+			for(u in undoes) u(undo);
+
+			if(undo)
+				for(e in elts) makeInstance(e);
+
+			refreshFunc(selectObjects.bind(undo ? elts : []));
+		}));
 	}
 
 	function reparentElement(e : Array<PrefabElement>, to : PrefabElement, index : Int) {

+ 1 - 0
hide/prefab/HideProps.hx

@@ -7,5 +7,6 @@ typedef HideProps = {
 	@:optional dynamic function allowChildren( type : String ) : Bool;
 	@:optional dynamic function allowParent( p : Prefab ) : Bool;
 	@:optional dynamic function onChildUpdate( p : Prefab ) : Void;
+	@:optional dynamic function onChildRemoved( p : Prefab ) : Void;
 	@:optional dynamic function onResourceRenamed( map : (oldPath : String) -> String ) : Void;
 }

+ 6 - 0
hide/prefab/Object3D.hx

@@ -102,6 +102,12 @@ class Object3D extends Prefab {
 			o.visible = visible;
 	}
 
+	override function removeInstance(ctx: Context):Bool {
+		if(ctx.local3d != null)
+			ctx.local3d.remove();
+		return true;
+	}
+
 	#if editor
 	override function edit( ctx : EditContext ) {
 		var props = new hide.Element('

+ 8 - 0
hide/prefab/l3d/Instance.hx

@@ -50,6 +50,14 @@ class Instance extends Object3D {
 		return ctx;
 	}
 
+	override function removeInstance(ctx:Context):Bool {
+		if(!super.removeInstance(ctx))
+			return false;
+		if(ctx.local2d != null)
+			ctx.local2d.remove();
+		return true;
+	}
+
 	public static function getCdbKind(p: Prefab) {
 		if(p.props == null)
 			return null;

+ 7 - 1
hide/view/FXEditor.hx

@@ -52,6 +52,12 @@ private class FXSceneEditor extends hide.comp.SceneEditor {
 		parent.onSelect(elts);
 	}
 
+	override function refresh(?mode, ?callb:Void->Void) {
+		// Always refresh scene
+		refreshScene();
+		refreshTree(callb);
+	}
+
 	override function getNewContextMenu(current: PrefabElement, ?onMake: PrefabElement->Void=null) {
 		if(current != null && current.to(hide.prefab.Shader) != null) {
 			return parent.getNewTrackMenu(current);
@@ -957,7 +963,7 @@ class FXEditor extends FileView {
 			anim = cast ctx.local3d;
 		}
 		if(!pauseButton.isDown()) {
-			currentTime += scene.speed * dt / hxd.Timer.wantedFPS;
+			currentTime += scene.speed * dt;
 			if(timeLineEl != null)
 				timeLineEl.css({left: xt(currentTime)});
 			if(currentTime >= previewMax) {

+ 4 - 0
hide/view/Prefab.hx

@@ -17,6 +17,10 @@ private class PrefabSceneEditor extends hide.comp.SceneEditor {
 		super.update(dt);
 		parent.onUpdate(dt);
 	}
+	override function refresh(?mode, ?callb:Void->Void) {
+		refreshScene();
+		refreshTree(callb);
+	}
 }
 
 class Prefab extends FileView {

+ 21 - 3
hide/view/l3d/Level3D.hx

@@ -80,7 +80,6 @@ private class Level3DSceneEditor extends hide.comp.SceneEditor {
 		super(view, data);
 		parent = cast view;
 		this.localTransform = false; // TODO: Expose option
-		this.enableLightRefresh = true;
 	}
 
 	override function makeCamController() {
@@ -92,9 +91,9 @@ private class Level3DSceneEditor extends hide.comp.SceneEditor {
 		return c;
 	}
 
-	override function refresh(?callback) {
+	override function refresh(?mode, ?callback) {
 		parent.onRefresh();
-		super.refresh(callback);
+		super.refresh(mode, callback);
 	}
 
 	override function refreshScene() {
@@ -299,6 +298,7 @@ class Level3D extends FileView {
 	var lastSyncChange : Float = 0.;
 	var currentSign : String;
 	var sceneFilters : Map<String, Bool>;
+	var statusText : h2d.Text;
 
 	var scene(get, null):  hide.comp.Scene;
 	function get_scene() return sceneEditor.scene;
@@ -382,9 +382,27 @@ class Level3D extends FileView {
 			autoSync = b;
 		});
 
+		statusText = new h2d.Text(hxd.res.DefaultFont.get(), scene.s2d);
+		statusText.setPosition(5, 5);
+		updateStats();
 		updateGrid();
 	}
 
+	function updateStats() {
+		var memStats = scene.engine.mem.stats();
+		@:privateAccess
+		var lines : Array<String> = [
+			'Scene objects: ${scene.s3d.getObjectsCount()}',
+			'Interactives: ' + sceneEditor.interactives.count(),
+			'Contexts: ' + sceneEditor.context.shared.contexts.count(),
+			'Triangles: ${scene.engine.drawTriangles}',
+			'Buffers: ${memStats.bufferCount}',
+			'Textures: ${memStats.textureCount}',
+		];
+		statusText.text = lines.join("\n");
+		sceneEditor.event.wait(0.5, updateStats);
+	}
+
 	function bakeLights() {
 		var curSel = sceneEditor.curEdit.elements;
 		sceneEditor.selectObjects([]);