2025-01-22 16:18:30 +01:00

249 lines
7.1 KiB
Haxe

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;
}
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;
}
}