Procházet zdrojové kódy

review and changed references handling:
- isRef becomes isSceneReference - only for references within same-prefab (by name)
- file references creates new ContextShared with different currentPath / baked cache

Nicolas Cannasse před 4 roky
rodič
revize
2a78a4710b

+ 29 - 11
hide/comp/SceneEditor.hx

@@ -1277,15 +1277,19 @@ class SceneEditor {
 		return interactives.get(elt);
 	}
 
-	public function getContext(elt : PrefabElement) {
+	public function getContext(elt : PrefabElement, ?shared : hrt.prefab.ContextShared) {
 		if(elt == null) return null;
-		var ctx = null;
-		if(elt == sceneData) {
-			ctx = context.shared.contexts.get(sceneData);
-			if(ctx != null) return ctx; // Some libs make their own instances
-			return context;
+		if( shared == null ) shared = context.shared;
+		var ctx = shared.contexts.get(elt);
+		if( ctx == null ) {
+			for( r in @:privateAccess shared.refsContexts ) {
+				ctx = getContext(elt, r);
+				if( ctx != null ) break;
+			}
 		}
-		return context.shared.contexts.get(elt);
+		if( ctx == null && elt == sceneData )
+			ctx = context;
+		return ctx;
 	}
 
 	public function getContexts(elt: PrefabElement) {
@@ -1540,12 +1544,19 @@ class SceneEditor {
 	}
 
 	function hasBeenRemoved( e : hrt.prefab.Prefab ) {
-		while( e != null && e != sceneData ) {
+		var root = sceneData;
+		var eltCtx = context.shared.getContexts(e)[0];
+		if( eltCtx != null && eltCtx.shared.parent != null ) {
+			if( hasBeenRemoved(eltCtx.shared.parent.prefab) )
+				return true;
+			root = null;
+		}
+		while( e != null && e != root ) {
 			if( e.parent != null && e.parent.children.indexOf(e) < 0 )
 				return true;
 			e = e.parent;
 		}
-		return e == null;
+		return e != root;
 	}
 
 	public function resetCamera() {
@@ -2181,8 +2192,15 @@ class SceneEditor {
 
 	// Override
 	function makeEditContext(elts : Array<PrefabElement>) : SceneEditorContext {
-		var edit = new SceneEditorContext(context, elts, this);
-		edit.prefabPath = view.state.path;
+		var p = elts[0];
+		var rootCtx = context;
+		while( p != null ) {
+			var ctx = context.shared.getContexts(p)[0];
+			if( ctx != null ) rootCtx = ctx;
+			p = p.parent;
+		}
+		// rootCtx might not be == context depending on references
+		var edit = new SceneEditorContext(rootCtx, elts, this);
 		edit.properties = properties;
 		edit.scene = scene;
 		return edit;

+ 4 - 0
hide/prefab/ContextShared.hx

@@ -13,6 +13,10 @@ class ContextShared extends hrt.prefab.ContextShared {
 		return scene;
 	}
 
+	override function allocForRef() {
+		return new ContextShared(scene);
+	}
+
 	override function onError( e : Dynamic ) {
 		hide.Ide.inst.error(e);
 	}

+ 15 - 8
hide/prefab/EditContext.hx

@@ -10,12 +10,12 @@ class EditContext {
 
 	var updates : Array<Float->Void> = [];
 
-	public var prefabPath : String;
 	public var ide(get,never) : hide.Ide;
 	public var scene : hide.comp.Scene;
 	public var properties : hide.comp.PropsEditor;
 	public var cleanups : Array<Void->Void>;
 	function get_ide() return hide.Ide.inst;
+
 	public function onChange(p : Prefab, propName : String) {
 		var ctx = getContext(p);
 		scene.setCurrent();
@@ -28,12 +28,9 @@ class EditContext {
 				parent = parent.parent;
 			}
 		}
-
-		var refs = rootContext.shared.references.get(p);
-		if(refs != null) {
-			for(ctx in refs)
-				p.updateInstance(ctx, propName);
-		}
+		for( ctx2 in rootContext.shared.getContexts(p) )
+			if( ctx2 != ctx )
+				p.updateInstance(ctx2, propName);
 	}
 
 	public function getCurrentProps( p : Prefab ) : Element {
@@ -132,7 +129,17 @@ class EditContext {
 			path.pop();
 		}
 
-		for( o in rootContext.shared.root3d )
+		// for references, we have an extra root level
+		var roots;
+		if( rootContext.shared.parent == null )
+			roots = [rootContext.shared.root3d];
+		else {
+			roots = [];
+			for( o in rootContext.shared.root3d )
+				roots.push(o);
+		}
+
+		for( o in roots )
 			getRec([], o);
 
 		return out;

+ 0 - 1
hide/view/FXEditor.hx

@@ -281,7 +281,6 @@ class FXEditor extends FileView {
 		fxprops = new hide.comp.PropsEditor(undo,null,element.find(".fx-props"));
 		{
 			var edit = new FXEditContext(this, sceneEditor.context);
-			edit.prefabPath = state.path;
 			edit.properties = fxprops;
 			edit.scene = sceneEditor.scene;
 			edit.cleanups = [];

+ 0 - 1
hide/view/l3d/Level3D.hx

@@ -319,7 +319,6 @@ class Level3D extends FileView {
 		// Level edit
 		{
 			var edit = new LevelEditContext(this, sceneEditor.context);
-			edit.prefabPath = state.path;
 			edit.properties = levelProps;
 			edit.scene = sceneEditor.scene;
 			edit.cleanups = [];

+ 16 - 8
hrt/prefab/Context.hx

@@ -7,7 +7,13 @@ package hrt.prefab;
 	public var shared : ContextShared;
 	public var cleanup : Void -> Void;
 	public var custom : Dynamic;
-	public var isRef : Bool = false;
+
+	/**
+		isSceneReference is set to true when this
+		context is a local reference to another prefab
+		within the same scene.
+	**/
+	public var isSceneReference : Bool;
 
 	public function new() {
 	}
@@ -25,15 +31,17 @@ package hrt.prefab;
 		c.local2d = local2d;
 		c.local3d = local3d;
 		c.custom = custom;
-		c.isRef = isRef;
+		c.isSceneReference = isSceneReference;
 		if( p != null ) {
-			if(!isRef)
+			if( !isSceneReference )
 				shared.contexts.set(p, c);
-			else {
-				if(!shared.references.exists(p))
-					shared.references.set(p, [c])
-				else
-					shared.references[p].push(c);
+			else @:privateAccess {
+				var arr = shared.sceneReferences.get(p);
+				if( arr == null ) {
+					arr = [];
+					shared.sceneReferences.set(p, arr);
+				}
+				arr.push(c);
 			}
 		}
 		return c;

+ 55 - 6
hrt/prefab/ContextShared.hx

@@ -11,21 +11,35 @@ class ContextShared {
 	public var root2d : h2d.Object;
 	public var root3d : h3d.scene.Object;
 	public var contexts : Map<Prefab,Context>;
-	public var references : Map<Prefab,Array<Context>>;
 	public var currentPath : String;
 	public var editorDisplay : Bool;
 
+	/**
+		If is a reference to another prefab file, this is the parent prefab.
+		See refContexts for children.
+	**/
+	public var parent : { prefab : Prefab, shared : ContextShared };
+
 	var cache : h3d.prim.ModelCache;
 	var shaderCache : ShaderDefCache;
 	var bakedData : Map<String, haxe.io.Bytes>;
+	/**
+		References to prefab within the same scene
+	**/
+	var sceneReferences : Map<Prefab,Array<Context>>;
+	/**
+		Contexts of references to other prefabs
+	**/
+	var refsContexts : Map<Prefab, ContextShared>;
 
 	public function new( ?res : hxd.res.Resource ) {
 		root2d = new h2d.Object();
 		root3d = new h3d.scene.Object();
 		contexts = new Map();
-		references = new Map();
 		cache = new h3d.prim.ModelCache();
 		shaderCache = new ShaderDefCache();
+		sceneReferences = new Map();
+		refsContexts = new Map();
 		if( res != null ) currentPath = res.entry.path;
 	}
 
@@ -37,17 +51,52 @@ class ContextShared {
 		return [for(e in contexts.keys()) e];
 	}
 
-	public function getContexts(p: Prefab) {
+	public function getContexts(p: Prefab) : Array<Context> {
 		var ret : Array<Context> = [];
 		var ctx = contexts.get(p);
 		if(ctx != null)
 			ret.push(ctx);
-		var ctxs = references.get(p);
-		if(ctxs != null)
-			return ret.concat(ctxs);
+		var ctxs = sceneReferences.get(p);
+		if( ctxs != null )
+			for( v in ctxs )
+				ret.push(v);
+		for( ref in refsContexts )
+			for( v in ref.getContexts(p) )
+				ret.push(v);
 		return ret;
 	}
 
+	public function cloneRef( prefab : Prefab, newPath : String ) {
+		var ctx = contexts.get(prefab);
+		if( ctx == null )
+			throw "Prefab reference has no context created";
+		var sh = refsContexts.get(prefab);
+		if( sh != null ) {
+			sh.root2d = ctx.local2d;
+			sh.root3d = ctx.local3d;
+			return sh;
+		}
+		sh = allocForRef();
+		refsContexts.set(prefab, sh);
+
+		sh.root2d = ctx.local2d;
+		sh.root3d = ctx.local3d;
+		// own contexts
+		// own references
+		sh.currentPath = newPath;
+		sh.editorDisplay = editorDisplay;
+		sh.parent = { shared : this, prefab : prefab };
+		sh.cache = cache;
+		sh.shaderCache = shaderCache;
+		// own bakedData
+		// own refsContext
+		return sh;
+	}
+
+	function allocForRef() {
+		return new ContextShared();
+	}
+
 	public function loadDir(p : String, ?dir : String ) : Array<hxd.res.Any> {
 		var datPath = new haxe.io.Path(currentPath);
 		datPath.ext = "dat";

+ 5 - 0
hrt/prefab/Library.hx

@@ -14,6 +14,11 @@ class Library extends Prefab {
 		return {};
 	}
 
+	override function makeInstance(ctx:Context):Context {
+		if( ctx.shared.parent != null ) ctx = ctx.clone(this);
+		return super.makeInstance(ctx);
+	}
+
 	/**
 		Returns the prefab within children that matches the given absolute path
 	**/

+ 1 - 1
hrt/prefab/Light.hx

@@ -189,7 +189,7 @@ class Light extends Object3D {
 		cookieTex = initTexture(cookiePath);
 		updateInstance(ctx);
 
-		if(!ctx.isRef)
+		if( ctx.shared.parent == null )
 			loadBaked(ctx);
 		return ctx;
 	}

+ 4 - 5
hrt/prefab/Reference.hx

@@ -85,11 +85,10 @@ class Reference extends Object3D {
 
 		if(isFile()) {
 			ctx = super.makeInstance(ctx);
-			ctx.isRef = !editMode;
-			var prevPath = ctx.shared.currentPath;
-			ctx.shared.currentPath = refpath.substr(1);
+			var prevShared = ctx.shared;
+			ctx.shared = ctx.shared.cloneRef(this, refpath.substr(1));
 			p.make(ctx);
-			ctx.shared.currentPath = prevPath;
+			ctx.shared = prevShared;
 
 			#if editor
 			if (ctx.local2d == null) {
@@ -106,7 +105,7 @@ class Reference extends Object3D {
 		}
 		else {
 			ctx = ctx.clone(this);
-			ctx.isRef = true;
+			ctx.isSceneReference = true;
 			var refCtx = p.make(ctx);
 			ctx.local3d = refCtx.local3d;
 			updateInstance(ctx);

+ 3 - 5
hrt/prefab/l3d/Instance.hx

@@ -20,13 +20,11 @@ class Instance extends Object3D {
 			try {
 				if(hrt.prefab.Library.getPrefabType(modelPath) != null) {
 					var ref = ctx.shared.loadPrefab(modelPath);
-					var ctx = ctx.clone(this);
-					ctx.isRef = true;
 					if(ref != null) {
-						var prev = ctx.shared.root3d;
-						ctx.shared.root3d = ctx.local3d; // allows Context.locateObject to work (constraints)
+						var prevShared = ctx.shared;
+						ctx.shared = ctx.shared.cloneRef(this, modelPath);
 						ref.make(ctx);
-						ctx.shared.root3d = prev;
+						ctx.shared = prevShared;
 					}
 				}
 				else {