forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			365 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
			
		
		
	
	
			365 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
package iron.object;
 | 
						|
 | 
						|
import iron.math.Mat4;
 | 
						|
import iron.math.Vec4;
 | 
						|
import iron.math.Quat;
 | 
						|
 | 
						|
class Transform {
 | 
						|
	/**
 | 
						|
		The world matrix (read-only).
 | 
						|
	**/
 | 
						|
	public var world: Mat4;
 | 
						|
	/**
 | 
						|
		Prevent applying parent matrix.
 | 
						|
	**/
 | 
						|
	public var localOnly = false;
 | 
						|
	/**
 | 
						|
		The local matrix. If you modify this, call `decompose()` to update the
 | 
						|
		`loc`, `rot` and `scale` fields, or `buildMatrix()` to update
 | 
						|
		everything.
 | 
						|
	**/
 | 
						|
	public var local: Mat4;
 | 
						|
	/**
 | 
						|
		The local translation. Changes to this field should be applied by
 | 
						|
		calling `buildMatrix()`.
 | 
						|
	**/
 | 
						|
	public var loc: Vec4;
 | 
						|
	/**
 | 
						|
		The local rotation. Changes to this field should be applied by
 | 
						|
		calling `buildMatrix()`.
 | 
						|
	**/
 | 
						|
	public var rot: Quat;
 | 
						|
	/**
 | 
						|
		The local scale. Changes to this field should be applied by
 | 
						|
		calling `buildMatrix()`.
 | 
						|
	**/
 | 
						|
	public var scale: Vec4;
 | 
						|
	/**
 | 
						|
		Uniform scale factor for `world` matrix.
 | 
						|
	**/
 | 
						|
	public var scaleWorld: kha.FastFloat = 1.0;
 | 
						|
	/**
 | 
						|
		The world matrix with `scaleWorld` applied (read-only).
 | 
						|
	**/
 | 
						|
	public var worldUnpack: Mat4;
 | 
						|
	/**
 | 
						|
		Flag to rebuild the `world` matrix on next update.
 | 
						|
	**/
 | 
						|
	public var dirty: Bool;
 | 
						|
	/**
 | 
						|
		The object that is effected by this transform.
 | 
						|
	**/
 | 
						|
	public var object: Object;
 | 
						|
	/**
 | 
						|
		The dimensions of the object in local space (without parent, prepended
 | 
						|
		or appended matrices applied).
 | 
						|
	**/
 | 
						|
	public var dim: Vec4;
 | 
						|
	/**
 | 
						|
		The radius of the smallest sphere that encompasses the object in local
 | 
						|
		space.
 | 
						|
	**/
 | 
						|
	public var radius: kha.FastFloat;
 | 
						|
 | 
						|
	static var temp = Mat4.identity();
 | 
						|
	static var q = new Quat();
 | 
						|
 | 
						|
	var boneParent: Mat4 = null;
 | 
						|
	var lastWorld: Mat4 = null;
 | 
						|
 | 
						|
	// Wrong order returned from getEuler(), store last state for animation
 | 
						|
	var _eulerX: kha.FastFloat;
 | 
						|
	var _eulerY: kha.FastFloat;
 | 
						|
	var _eulerZ: kha.FastFloat;
 | 
						|
 | 
						|
	// Animated delta transform
 | 
						|
	var dloc: Vec4 = null;
 | 
						|
	var drot: Quat = null;
 | 
						|
	var dscale: Vec4 = null;
 | 
						|
	var _deulerX: kha.FastFloat;
 | 
						|
	var _deulerY: kha.FastFloat;
 | 
						|
	var _deulerZ: kha.FastFloat;
 | 
						|
 | 
						|
	public function new(object: Object) {
 | 
						|
		this.object = object;
 | 
						|
		reset();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Reset to a null transform: zero location and rotation, and a uniform
 | 
						|
		scale of one. Other fields such as prepended matrices and bone parents
 | 
						|
		will not be changed.
 | 
						|
	**/
 | 
						|
	public function reset() {
 | 
						|
		world = Mat4.identity();
 | 
						|
		worldUnpack = Mat4.identity();
 | 
						|
		local = Mat4.identity();
 | 
						|
		loc = new Vec4();
 | 
						|
		rot = new Quat();
 | 
						|
		scale = new Vec4(1.0, 1.0, 1.0);
 | 
						|
		dim = new Vec4(2.0, 2.0, 2.0);
 | 
						|
		radius = 1.0;
 | 
						|
		dirty = true;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Rebuild the matrices, if needed.
 | 
						|
	**/
 | 
						|
	public function update() {
 | 
						|
		if (dirty) buildMatrix();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Clear delta transforms. `dloc`, `drot` and `dscale` are set to `null`
 | 
						|
	**/
 | 
						|
	public function clearDelta() {
 | 
						|
 | 
						|
		dloc = null;
 | 
						|
		drot = null;
 | 
						|
		dscale = null;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Reset delta transforms. `dloc`, `drot` and `dscale` 
 | 
						|
		are set to `Vec4(0, 0, 0)`, `Quat(0, 0, 0, 0)` and `Vec4(1, 1, 1)` respectively
 | 
						|
	**/
 | 
						|
	public function resetDelta() {
 | 
						|
		dloc = new Vec4();
 | 
						|
		drot = new Quat();
 | 
						|
		_deulerX = _deulerY = _deulerZ = 0.0;
 | 
						|
		dscale = new Vec4().set(1, 1, 1);
 | 
						|
	}
 | 
						|
 | 
						|
	function composeDelta() {
 | 
						|
		// Delta transform
 | 
						|
		var dl = new Vec4().addvecs(loc, dloc);
 | 
						|
		var ds = new Vec4().setFrom(scale);
 | 
						|
		ds.x *= dscale.x;
 | 
						|
		ds.y *= dscale.y;
 | 
						|
		ds.z *= dscale.z;
 | 
						|
		var dr = new Quat().fromEuler(_deulerX, _deulerY, _deulerZ);
 | 
						|
		dr.multquats(dr, rot);
 | 
						|
		dr.multquats(drot, dr);
 | 
						|
		local.compose(dl, dr, ds);
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Update the transform matrix based on `loc`, `rot`, and `scale`. If any
 | 
						|
		change is made to `loc`, `rot`, or `scale` `buildMatrix()` must be
 | 
						|
		called to update the objects transform.
 | 
						|
	**/
 | 
						|
	public function buildMatrix() {
 | 
						|
		dloc == null ? local.compose(loc, rot, scale) : composeDelta();
 | 
						|
 | 
						|
		if (boneParent != null) local.multmats(boneParent, local);
 | 
						|
 | 
						|
		if (object.parent != null && !localOnly) {
 | 
						|
			world.multmats3x4(local, object.parent.transform.world);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			world.setFrom(local);
 | 
						|
		}
 | 
						|
 | 
						|
		worldUnpack.setFrom(world);
 | 
						|
		if (scaleWorld != 1.0) {
 | 
						|
			worldUnpack._00 *= scaleWorld;
 | 
						|
			worldUnpack._01 *= scaleWorld;
 | 
						|
			worldUnpack._02 *= scaleWorld;
 | 
						|
			worldUnpack._03 *= scaleWorld;
 | 
						|
			worldUnpack._10 *= scaleWorld;
 | 
						|
			worldUnpack._11 *= scaleWorld;
 | 
						|
			worldUnpack._12 *= scaleWorld;
 | 
						|
			worldUnpack._13 *= scaleWorld;
 | 
						|
			worldUnpack._20 *= scaleWorld;
 | 
						|
			worldUnpack._21 *= scaleWorld;
 | 
						|
			worldUnpack._22 *= scaleWorld;
 | 
						|
			worldUnpack._23 *= scaleWorld;
 | 
						|
		}
 | 
						|
 | 
						|
		// Constraints
 | 
						|
		if (object.constraints != null) for (c in object.constraints) c.apply(this);
 | 
						|
 | 
						|
		computeDim();
 | 
						|
 | 
						|
		// Update children
 | 
						|
		for (n in object.children) {
 | 
						|
			n.transform.buildMatrix();
 | 
						|
		}
 | 
						|
 | 
						|
		dirty = false;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Move the game Object by the defined amount relative to its current location.
 | 
						|
		@param	x Amount to move on the local x axis.
 | 
						|
		@param	y Amount to move on the local y axis.
 | 
						|
		@param	z Amount to move on the local z axis.
 | 
						|
	**/
 | 
						|
	public function translate(x: kha.FastFloat, y: kha.FastFloat, z: kha.FastFloat) {
 | 
						|
		loc.x += x;
 | 
						|
		loc.y += y;
 | 
						|
		loc.z += z;
 | 
						|
		buildMatrix();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Set the local matrix and update `loc`, `rot`, `scale` and `world`.
 | 
						|
		@param	mat The new local matrix.
 | 
						|
	**/
 | 
						|
	public function setMatrix(mat: Mat4) {
 | 
						|
		local.setFrom(mat);
 | 
						|
		decompose();
 | 
						|
		buildMatrix();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Apply another transform to this one, i.e. multiply this transform's
 | 
						|
		local matrix by another.
 | 
						|
		@param	mat The other transform to apply.
 | 
						|
	**/
 | 
						|
	public function multMatrix(mat: Mat4) {
 | 
						|
		local.multmat(mat);
 | 
						|
		decompose();
 | 
						|
		buildMatrix();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Update the `loc`, `rot` and `scale` fields according to the local
 | 
						|
		matrix. You may need to call this after directly mutating the local
 | 
						|
		matrix.
 | 
						|
	**/
 | 
						|
	public function decompose() {
 | 
						|
		local.decompose(loc, rot, scale);
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Rotate around an axis.
 | 
						|
		@param	axis The axis to rotate around.
 | 
						|
		@param	f The magnitude of the rotation in radians.
 | 
						|
	**/
 | 
						|
	public function rotate(axis: Vec4, f: kha.FastFloat) {
 | 
						|
		q.fromAxisAngle(axis, f);
 | 
						|
		rot.multquats(q, rot);
 | 
						|
		buildMatrix();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Apply a scaled translation in local space.
 | 
						|
		@param	axis The direction to move.
 | 
						|
		@param	f A multiplier for the movement. If `axis` is a unit
 | 
						|
	  			vector, then this is the distance to move.
 | 
						|
	**/
 | 
						|
	public function move(axis: Vec4, f = 1.0) {
 | 
						|
		loc.addf(axis.x * f, axis.y * f, axis.z * f);
 | 
						|
		buildMatrix();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Set the rotation of the object in radians.
 | 
						|
		@param	x Set the x axis rotation in radians.
 | 
						|
		@param	y Set the y axis rotation in radians.
 | 
						|
		@param	z Set the z axis rotation in radians.
 | 
						|
	**/
 | 
						|
	public function setRotation(x: kha.FastFloat, y: kha.FastFloat, z: kha.FastFloat) {
 | 
						|
		rot.fromEuler(x, y, z);
 | 
						|
		_eulerX = x;
 | 
						|
		_eulerY = y;
 | 
						|
		_eulerZ = z;
 | 
						|
		dirty = true;
 | 
						|
	}
 | 
						|
 | 
						|
	function computeRadius() {
 | 
						|
		radius = Math.sqrt(dim.x * dim.x + dim.y * dim.y + dim.z * dim.z);
 | 
						|
	}
 | 
						|
 | 
						|
	function computeDim() {
 | 
						|
		if (object.raw == null) {
 | 
						|
			computeRadius();
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		var d = object.raw.dimensions;
 | 
						|
		if (d == null) dim.set(2 * scale.x, 2 * scale.y, 2 * scale.z);
 | 
						|
		else dim.set(d[0] * scale.x, d[1] * scale.y, d[2] * scale.z);
 | 
						|
		computeRadius();
 | 
						|
	}
 | 
						|
 | 
						|
	public function applyParentInverse() {
 | 
						|
		var pt = object.parent.transform;
 | 
						|
		pt.buildMatrix();
 | 
						|
		temp.getInverse(pt.world);
 | 
						|
		this.local.multmat(temp);
 | 
						|
		this.decompose();
 | 
						|
		this.buildMatrix();
 | 
						|
	}
 | 
						|
 | 
						|
	public function applyParent() {
 | 
						|
		var pt = object.parent.transform;
 | 
						|
		pt.buildMatrix();
 | 
						|
		this.local.multmat(pt.world);
 | 
						|
		this.decompose();
 | 
						|
		this.buildMatrix();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		Check whether the transform has changed at all since the last time
 | 
						|
		this function was called.
 | 
						|
		@return	`true` if the transform has changed.
 | 
						|
	**/
 | 
						|
	public function diff(): Bool {
 | 
						|
		if (lastWorld == null) {
 | 
						|
			lastWorld = Mat4.identity().setFrom(world);
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
		var a = world;
 | 
						|
		var b = lastWorld;
 | 
						|
		var r = a._00 != b._00 || a._01 != b._01 || a._02 != b._02 || a._03 != b._03 ||
 | 
						|
				a._10 != b._10 || a._11 != b._11 || a._12 != b._12 || a._13 != b._13 ||
 | 
						|
				a._20 != b._20 || a._21 != b._21 || a._22 != b._22 || a._23 != b._23 ||
 | 
						|
				a._30 != b._30 || a._31 != b._31 || a._32 != b._32 || a._33 != b._33;
 | 
						|
		if (r) lastWorld.setFrom(world);
 | 
						|
		return r;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		@return	The look vector (positive local y axis) in world space.
 | 
						|
	**/
 | 
						|
	public inline function look(): Vec4 {
 | 
						|
		return world.look();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		@return	The right vector (positive local x axis) in world space.
 | 
						|
	**/
 | 
						|
	public inline function right(): Vec4 {
 | 
						|
		return world.right();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		@return	The up vector (positive local z axis) in world space.
 | 
						|
	**/
 | 
						|
	public inline function up(): Vec4 {
 | 
						|
		return world.up();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		@return The world x location.
 | 
						|
	**/
 | 
						|
	public inline function worldx(): kha.FastFloat {
 | 
						|
		return world._30;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		@return The world y location.
 | 
						|
	**/
 | 
						|
	public inline function worldy(): kha.FastFloat {
 | 
						|
		return world._31;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
		@return The world z location.
 | 
						|
	**/
 | 
						|
	public inline function worldz(): kha.FastFloat {
 | 
						|
		return world._32;
 | 
						|
	}
 | 
						|
}
 |