| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  | package iron.object; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import iron.Trait; | 
					
						
							|  |  |  | import iron.data.SceneFormat; | 
					
						
							|  |  |  | import iron.math.Vec4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Object { | 
					
						
							|  |  |  | 	static var uidCounter = 0; | 
					
						
							|  |  |  | 	public var uid: Int; | 
					
						
							|  |  |  | 	public var urandom: Float; | 
					
						
							|  |  |  | 	public var raw: TObj = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public var name: String = ""; | 
					
						
							|  |  |  | 	public var transform: Transform; | 
					
						
							|  |  |  | 	public var constraints: Array<Constraint> = null; | 
					
						
							|  |  |  | 	public var traits: Array<Trait> = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public var parent: Object = null; | 
					
						
							|  |  |  | 	public var children: Array<Object> = []; | 
					
						
							|  |  |  | 	public var lods: Array<Object> = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public var animation: Animation = null; | 
					
						
							|  |  |  | 	public var visible = true; // Skip render, keep updating | 
					
						
							|  |  |  | 	public var visibleMesh = true; | 
					
						
							|  |  |  | 	public var visibleShadow = true; | 
					
						
							|  |  |  | 	public var culled = false; // Object was culled last frame | 
					
						
							|  |  |  | 	public var culledMesh = false; | 
					
						
							|  |  |  | 	public var culledShadow = false; | 
					
						
							|  |  |  | 	public var vertex_groups: Map<String, Array<Vec4>> = null; | 
					
						
							|  |  |  | 	public var properties: Map<String, Dynamic> = null; | 
					
						
							|  |  |  | 	var isEmpty = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function new() { | 
					
						
							|  |  |  | 		uid = uidCounter++; | 
					
						
							|  |  |  | 		urandom = seededRandom(); // Math.random(); | 
					
						
							|  |  |  | 		transform = new Transform(this); | 
					
						
							|  |  |  | 		isEmpty = Type.getClass(this) == Object; | 
					
						
							|  |  |  | 		if (isEmpty && Scene.active != null) Scene.active.empties.push(this); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 		Set the given `parentObject` as the parent of this object. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		If `parentObject` is `null`, the object is parented to the scene's
 | 
					
						
							|  |  |  | 		`sceneParent`, which is the topmost object of the scene tree. | 
					
						
							|  |  |  | 		If you want to remove it from the scene, use `Object.remove()` instead. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		If `parentObject` is the object on which this function is called, | 
					
						
							|  |  |  | 		nothing happens. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		@param parentObject The new parent object. | 
					
						
							|  |  |  | 		@param parentInverse (Optional) Change the scale of the child object to be relative to the new parents 3D space or use the original scale. | 
					
						
							|  |  |  | 		@param keepTransform (Optional) When unparenting from the old parent, keep the transform given by the old parent or revert to the object's default.
 | 
					
						
							|  |  |  | 	**/ | 
					
						
							|  |  |  | 	public function setParent(parentObject: Object, parentInverse = false, keepTransform = false) { | 
					
						
							|  |  |  | 		if (parentObject == this || parentObject == parent) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (parent != null) { | 
					
						
							|  |  |  | 			parent.children.remove(this); | 
					
						
							|  |  |  | 			if (keepTransform) this.transform.applyParent(); | 
					
						
							|  |  |  | 			this.parent = null; // rebuild matrix without a parent | 
					
						
							|  |  |  | 			this.transform.buildMatrix(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (parentObject == null) { | 
					
						
							|  |  |  | 			parentObject = Scene.active.sceneParent; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		parent = parentObject; | 
					
						
							|  |  |  | 		parent.children.push(this); | 
					
						
							|  |  |  | 		if (parentInverse) this.transform.applyParentInverse(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 		Add a game Object as a child of this game Object. | 
					
						
							|  |  |  | 		@param	o The game Object instance to be added as a child. | 
					
						
							|  |  |  | 		@param	parentInverse Optional (default false) change the scale of the child object to be relative to the parents 3D space or use the original scale. | 
					
						
							|  |  |  | 	**/ | 
					
						
							|  |  |  | 	@:deprecated("addChild() is deprecated, please use setParent() instead") | 
					
						
							|  |  |  | 	public inline function addChild(o: Object, parentInverse = false) { | 
					
						
							|  |  |  | 		o.setParent(this, parentInverse, false); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 		Remove a child game Object from it's parentage. Does not remove the object from the scene.
 | 
					
						
							|  |  |  | 		@param	o The game Object instance to be removed. | 
					
						
							|  |  |  | 		@param	keepTransform Optional (defaut false) keep the transform given by the parent or revert to the objects default. | 
					
						
							|  |  |  | 	**/ | 
					
						
							|  |  |  | 	@:deprecated("removeChild() is deprecated, please use setParent(null) instead") | 
					
						
							|  |  |  | 	public inline function removeChild(o: Object, keepTransform = false) { | 
					
						
							|  |  |  | 		o.setParent(null, false, keepTransform); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 		Removes the game object from the scene. | 
					
						
							|  |  |  | 	**/ | 
					
						
							|  |  |  | 	public function remove() { | 
					
						
							|  |  |  | 		if (isEmpty && Scene.active != null) Scene.active.empties.remove(this); | 
					
						
							|  |  |  | 		if (animation != null) animation.remove(); | 
					
						
							|  |  |  | 		while (children.length > 0) children[0].remove(); | 
					
						
							|  |  |  | 		while (traits.length > 0) traits[0].remove(); | 
					
						
							|  |  |  | 		if (parent != null) { | 
					
						
							|  |  |  | 			parent.children.remove(this); | 
					
						
							|  |  |  | 			parent = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 		Get a child game Object of this game Object. Using the childs name property as a lookup. | 
					
						
							|  |  |  | 		@param	name A string matching the name property of the game Object to fetch. | 
					
						
							|  |  |  | 		@return	Object or null | 
					
						
							|  |  |  | 	**/ | 
					
						
							|  |  |  | 	public function getChild(name: String): Object { | 
					
						
							|  |  |  | 		if (this.name == name) return this; | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			for (c in children) { | 
					
						
							|  |  |  | 				var r = c.getChild(name); | 
					
						
							|  |  |  | 				if (r != null) return r; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 		Returns the children of the object. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		If 'recursive' is set to `false`, only direct children will be included | 
					
						
							|  |  |  | 		in the returned array. If `recursive` is `true`, children of children and | 
					
						
							|  |  |  | 		so on will be included too. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		@param recursive = false Include children of children | 
					
						
							|  |  |  | 		@return `Array<Object>` | 
					
						
							|  |  |  | 	**/ | 
					
						
							|  |  |  | 	public function getChildren(?recursive = false): Array<Object> { | 
					
						
							|  |  |  | 		if (!recursive) return children; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var retChildren = children.copy(); | 
					
						
							|  |  |  | 		for (child in children) { | 
					
						
							|  |  |  | 			retChildren = retChildren.concat(child.getChildren(recursive)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return retChildren; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function getChildOfType<T: Object>(type: Class<T>): T { | 
					
						
							|  |  |  | 		if (Std.isOfType(this, type)) return cast this; | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			for (c in children) { | 
					
						
							|  |  |  | 				var r = c.getChildOfType(type); | 
					
						
							|  |  |  | 				if (r != null) return r; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	@:access(iron.Trait) | 
					
						
							|  |  |  | 	public function addTrait(t: Trait) { | 
					
						
							|  |  |  | 		traits.push(t); | 
					
						
							|  |  |  | 		t.object = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (t._add != null) { | 
					
						
							|  |  |  | 			for (f in t._add) f(); | 
					
						
							|  |  |  | 			t._add = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 		Remove the Trait from the Object. | 
					
						
							|  |  |  | 		@param	t The Trait to be removed from the game Object. | 
					
						
							|  |  |  | 	**/ | 
					
						
							|  |  |  | 	@:access(iron.Trait) | 
					
						
							|  |  |  | 	public function removeTrait(t: Trait) { | 
					
						
							|  |  |  | 		if (t._init != null) { | 
					
						
							|  |  |  | 			for (f in t._init) App.removeInit(f); | 
					
						
							|  |  |  | 			t._init = null; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-06-02 04:12:58 +00:00
										 |  |  | 		if (t._fixedUpdate != null) { | 
					
						
							|  |  |  | 			for (f in t._fixedUpdate) App.removeFixedUpdate(f); | 
					
						
							|  |  |  | 			t._fixedUpdate = null; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  | 		if (t._update != null) { | 
					
						
							|  |  |  | 			for (f in t._update) App.removeUpdate(f); | 
					
						
							|  |  |  | 			t._update = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (t._lateUpdate != null) { | 
					
						
							|  |  |  | 			for (f in t._lateUpdate) App.removeLateUpdate(f); | 
					
						
							|  |  |  | 			t._lateUpdate = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (t._render != null) { | 
					
						
							|  |  |  | 			for (f in t._render) App.removeRender(f); | 
					
						
							|  |  |  | 			t._render = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (t._render2D != null) { | 
					
						
							|  |  |  | 			for (f in t._render2D) App.removeRender2D(f); | 
					
						
							|  |  |  | 			t._render2D = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (t._remove != null) { | 
					
						
							|  |  |  | 			for (f in t._remove) f(); | 
					
						
							|  |  |  | 			t._remove = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		traits.remove(t); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 		Get the Trait instance that is attached to this game Object. | 
					
						
							|  |  |  | 		@param	c The class of type Trait to attempt to retrieve. | 
					
						
							|  |  |  | 		@return	Trait or null | 
					
						
							|  |  |  | 	**/ | 
					
						
							|  |  |  | 	public function getTrait<T: Trait>(c: Class<T>): T { | 
					
						
							|  |  |  | 		for (t in traits) if (Type.getClass(t) == cast c) return cast t; | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#if lnx_skin | 
					
						
							|  |  |  | 	public function getBoneAnimation(armatureUid): BoneAnimation { | 
					
						
							|  |  |  | 		for (a in Scene.active.animations) if (a.armature != null && a.armature.uid == armatureUid) return cast a; | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	#else | 
					
						
							|  |  |  | 	public function getBoneAnimation(armatureUid): Animation { | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function getObjectAnimation(): ObjectAnimation { | 
					
						
							|  |  |  | 		if(animation != null) return cast animation; | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function setupAnimation(oactions: Array<TSceneFormat> = null) { | 
					
						
							|  |  |  | 		// Parented to bone | 
					
						
							|  |  |  | 		#if lnx_skin | 
					
						
							|  |  |  | 		if (raw.parent_bone != null) { | 
					
						
							|  |  |  | 			Scene.active.notifyOnInit(function() { | 
					
						
							|  |  |  | 				var banim = getBoneAnimation(parent.uid); | 
					
						
							|  |  |  | 				if (banim != null) banim.addBoneChild(raw.parent_bone, this); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 		// Object actions | 
					
						
							|  |  |  | 		if (oactions == null) return; | 
					
						
							|  |  |  | 		animation = new ObjectAnimation(this, oactions); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#if lnx_morph_target | 
					
						
							|  |  |  | 	public function setupMorphTargets() {} | 
					
						
							|  |  |  | 	#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static var seed = 1; // cpp / js not consistent | 
					
						
							|  |  |  | 	static function seededRandom(): Float { | 
					
						
							|  |  |  | 		seed = (seed * 9301 + 49297) % 233280; | 
					
						
							|  |  |  | 		return seed / 233280.0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |