Source: ext/transform.js

"use strict";

/**
 * Object transformations API.
 * With some exceptions specified below, make sure that the objects are dynamic.
 * @module transform
 */
b4w.module["transform"] = function(exports, require) {

var m_obj_util = require("__obj_util");
var m_phy      = require("__physics");
var m_print    = require("__print");
var m_quat     = require("__quat");
var m_trans    = require("__transform");
var m_tsr      = require("__tsr");
var m_util     = require("__util");

var _tsr_tmp = m_tsr.create();
var _vec3_tmp = new Float32Array(3);
var _quat4_tmp = new Float32Array(4);

/**
 * Transform in the local space
 * @const {Space} module:transform.SPACE_LOCAL
 * @deprecated Not needed anymore.
 */
exports.SPACE_LOCAL = m_trans.SPACE_LOCAL;
/**
 * Transform in the world space
 * @const {Space} module:transform.SPACE_WORLD
 * @deprecated Not needed anymore.
 */
exports.SPACE_WORLD = m_trans.SPACE_WORLD;

/**
 * Set the object translation.
 * @method module:transform.set_translation
 * @param {Object3D} obj Object 3D
 * @param {Number} x X coord
 * @param {Number} y Y coord
 * @param {Number} z Z coord
 */
exports.set_translation = function(obj, x, y, z) {
    if (m_obj_util.is_dynamic(obj)) {
        _vec3_tmp[0] = x;
        _vec3_tmp[1] = y;
        _vec3_tmp[2] = z;

        m_trans.set_translation(obj, _vec3_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}
/**
 * Set the object translation (in the coordinate space of its parent).
 * @method module:transform.set_translation_rel
 * @param {Object3D} obj Object 3D
 * @param {Number} x X coord
 * @param {Number} y Y coord
 * @param {Number} z Z coord
 */
exports.set_translation_rel = function(obj, x, y, z) {
    if (m_obj_util.is_dynamic(obj)) {
        _vec3_tmp[0] = x;
        _vec3_tmp[1] = y;
        _vec3_tmp[2] = z;

        m_trans.set_translation_rel(obj, _vec3_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object translation (vector form).
 * @method module:transform.set_translation_v
 * @param {Object3D} obj Object 3D
 * @param {Vec3} trans Translation vector
 */
exports.set_translation_v = function(obj, trans) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_translation(obj, trans);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object translation in vector form
 * (in the coordinate space of its parent).
 * @method module:transform.set_translation_rel_v
 * @param {Object3D} obj Object 3D
 * @param {Vec3} trans Translation vector
 */
exports.set_translation_rel_v = function(obj, trans) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_translation_rel(obj, trans);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object translation relatively to another object.
 * @method module:transform.set_translation_obj_rel
 * @param {Object3D} obj Transformed object
 * @param {Number} x X coord
 * @param {Number} y Y coord
 * @param {Number} z Z coord
 * @param {Object3D} obj_ref Reference object
 */
exports.set_translation_obj_rel = function(obj, x, y, z, obj_ref) {
    if (m_obj_util.is_dynamic(obj)) {
        _vec3_tmp[0] = x;
        _vec3_tmp[1] = y;
        _vec3_tmp[2] = z;

        var trans = m_tsr.get_trans_view(obj_ref.render.world_tsr);
        var quat = m_tsr.get_quat_view(obj_ref.render.world_tsr);

        m_util.transform_vec3(_vec3_tmp, 1, quat, trans, _vec3_tmp);

        m_trans.set_translation(obj, _vec3_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Get the object's translation vector.
 * @method module:transform.get_translation
 * @param {Object3D} obj Object 3D
 * @param {Vec3} [dest] Destination vector
 * @returns {Vec3} Destination vector
 * @example 
 * var m_scenes = require("scenes");
 * var m_trans = require("transform");
 * var m_vec3 = require("vec3");
 * // precache 3D vector
 * var _vec3_tmp = m_vec3.create();
 * // ...
 * var cube = m_scenes.get_object_by_name("Cube");
 * var translation = m_trans.get_translation(cube, _vec3_tmp);
 */
exports.get_translation = function(obj, dest) {
    if (!dest)
        var dest = new Float32Array(3);

    m_trans.get_translation(obj, dest);
    return dest;
}

/**
 * Get the object's translation vector (in the coordinate space of its parent).
 * @method module:transform.get_translation_rel
 * @param {Object3D} obj Object 3D
 * @param {Vec3} [dest] Destination vector
 * @returns {Vec3} Destination vector
 */
exports.get_translation_rel = function(obj, dest) {
    if (!dest)
        var dest = new Float32Array(3);

    m_trans.get_translation_rel(obj, dest);
    return dest;
}

/**
 * Set the object's rotation quaternion.
 * @method module:transform.set_rotation
 * @param {Object3D} obj Object 3D
 * @param {Number} x X part of quaternion
 * @param {Number} y Y part of quaternion
 * @param {Number} z Z part of quaternion
 * @param {Number} w W part of quaternion
 */
exports.set_rotation = function(obj, x, y, z, w) {
    if (m_obj_util.is_dynamic(obj)) {
        _quat4_tmp[0] = x;
        _quat4_tmp[1] = y;
        _quat4_tmp[2] = z;
        _quat4_tmp[3] = w;

        m_trans.set_rotation(obj, _quat4_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object's rotation quaternion (in the coordinate space of its parent).
 * @method module:transform.set_rotation_rel
 * @param {Object3D} obj Object 3D
 * @param {Number} x X part of quaternion
 * @param {Number} y Y part of quaternion
 * @param {Number} z Z part of quaternion
 * @param {Number} w W part of quaternion
 */
exports.set_rotation_rel = function(obj, x, y, z, w) {
    if (m_obj_util.is_dynamic(obj)) {
        _quat4_tmp[0] = x;
        _quat4_tmp[1] = y;
        _quat4_tmp[2] = z;
        _quat4_tmp[3] = w;

        m_trans.set_rotation_rel(obj, _quat4_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object's rotation in vector form.
 * @method module:transform.set_rotation_v
 * @param {Object3D} obj Object 3D
 * @param {Quat} quat Quaternion vector
 */
exports.set_rotation_v = function(obj, quat) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_rotation(obj, quat);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}
/**
 * Set the object's rotation in vector form
 * (in the coordinate space of its parent).
 * @method module:transform.set_rotation_rel_v
 * @param {Object3D} obj Object 3D
 * @param {Quat} quat Quaternion vector
 */
exports.set_rotation_rel_v = function(obj, quat) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_rotation_rel(obj, quat);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Get the object's rotation quaternion.
 * @method module:transform.get_rotation
 * @param {Object3D} obj Object 3D
 * @param {Quat} [opt_dest] Destination vector
 * @returns {Quat} Destination vector
 * @example 
 * var m_scenes = require("scenes");
 * var m_trans = require("transform");
 * var m_quat  = require("quat");
 * // precache quaternion
 * var _quat_tmp = m_quat.create();
 * // ...
 * var cube = m_scenes.get_object_by_name("Cube");
 * var rot_quat = m_trans.get_rotation(cube, _quat_tmp);
 */
exports.get_rotation = function(obj, opt_dest) {
    if (!opt_dest)
        var opt_dest = new Float32Array(4);

    m_trans.get_rotation(obj, opt_dest);
    return opt_dest;
}

/**
 * Get the object's rotation quaternion
 * (in the coordinate space of its parent).
 * @method module:transform.get_rotation_rel
 * @param {Object3D} obj Object 3D
 * @param {Quat} [opt_dest] Destination vector
 * @returns {Quat} Destination vector
 */
exports.get_rotation_rel = function(obj, opt_dest) {
    if (!opt_dest)
        var opt_dest = new Float32Array(4);

    m_trans.get_rotation_rel(obj, opt_dest);
    return opt_dest;
}

/**
 * Set euler rotation in the ZYX intrinsic system.
 * Using euler angles is discouraged, use quaternion instead.
 * @method module:transform.set_rotation_euler
 * @param {Object3D} obj Object 3D
 * @param {Number} x Angle X
 * @param {Number} y Angle Y
 * @param {Number} z Angle Z
 */
exports.set_rotation_euler = function(obj, x, y, z) {
    if (m_obj_util.is_dynamic(obj)) {
        _vec3_tmp[0] = x;
        _vec3_tmp[1] = y;
        _vec3_tmp[2] = z;

        m_trans.set_rotation_euler(obj, _vec3_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Get Euler rotation of object in the ZYX intrinsic system.
 * Using euler angles is discouraged, use quaternion instead.
 * @method module:transform.get_rotation_euler
 * @param {Object3D} obj Object 3D
 * @param {Euler} [dest = new Float32Array(3)] Destination vector
 * @returns {Quat} Vector with Euler angles
 */
exports.get_rotation_euler = function(obj, dest) {
    if (!dest)
        var dest = new Float32Array(3);

    m_trans.get_rotation_euler(obj, dest);
    return dest;
}

/**
 * Get Euler rotation of object in the ZYX intrinsic system
 * (in the coordinate space of its parent).
 * Using euler angles is discouraged, use quaternion instead.
 * @method module:transform.get_rotation_euler
 * @param {Object3D} obj Object 3D
 * @param {Euler} [dest = new Float32Array(3)] Destination vector
 * @returns {Quat} Vector with Euler angles
 */
exports.get_rotation_euler_rel = function(obj, dest) {
    if (!dest)
        var dest = new Float32Array(3);

    m_trans.get_rotation_euler_rel(obj, dest);
    return dest;
}

/**
 * Set euler rotation in the ZYX intrinsic system
 * (in the coordinate space of its parent).
 * Using euler angles is discouraged, use quaternion instead.
 * @method module:transform.set_rotation_euler_rel
 * @param {Object3D} obj Object 3D
 * @param {Number} x Angle X
 * @param {Number} y Angle Y
 * @param {Number} z Angle Z
 */
exports.set_rotation_euler_rel = function(obj, x, y, z) {
    if (m_obj_util.is_dynamic(obj)) {
        _vec3_tmp[0] = x;
        _vec3_tmp[1] = y;
        _vec3_tmp[2] = z;

        m_trans.set_rotation_euler_rel(obj, _vec3_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set euler rotation in vector form.
 * Using euler angles is discouraged, use quaternion instead.
 * @method module:transform.set_rotation_euler_v
 * @param {Object3D} obj Object 3D
 * @param {Euler} euler Vector with euler angles
 */
exports.set_rotation_euler_v = function(obj, euler) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_rotation_euler(obj, euler);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set euler rotation in vector form relatively to its parent
 * (in the coordinate space of its parent).
 * Using euler angles is discouraged, use quaternion instead.
 * @method module:transform.set_rotation_euler_rel_v
 * @param {Object3D} obj Object 3D
 * @param {Euler} euler Vector with euler angles
 */
exports.set_rotation_euler_rel_v = function(obj, euler) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_rotation_euler_rel(obj, euler);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object scale.
 * @method module:transform.set_scale
 * @param {Object3D} obj Object 3D
 * @param {Number} scale Object scale
 */
exports.set_scale = function(obj, scale) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_scale(obj, scale);
        m_trans.update_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object's scale
 * (in the coordinate space of its parent).
 * @method module:transform.set_scale_rel
 * @param {Object3D} obj Object 3D
 * @param {Number} scale Object scale
 */
exports.set_scale_rel = function(obj, scale) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_scale_rel(obj, scale);
        m_trans.update_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Get the object scale.
 * @method module:transform.get_scale
 * @param {Object3D} obj Object 3D
 * @returns {Number} scale
 */
exports.get_scale = function(obj) {
    return m_trans.get_scale(obj);
}

/**
 * Get the object scale
 * (in the coordinate space of its parent).
 * @method module:transform.get_scale_rel
 * @param {Object3D} obj Object 3D
 * @returns {Number} scale
 */
exports.get_scale_rel = function(obj) {
    return m_trans.get_scale_rel(obj);
}

/**
 * Reset EMPTY's transform to allow child objects behave in the absolute (world) space.
 * @method module:transform.empty_reset_transform
 * @param {Object3D} obj Object 3D
 */
exports.empty_reset_transform = function(obj) {
    if (obj.type != "EMPTY") {
        m_print.error("Wrong object: " + obj.name);
        return;
    }

    for (var i = 0; i < obj.cons_descends.length; i++)
        if (!m_obj_util.is_dynamic(obj.cons_descends[i])) {
            m_print.error("Wrong object: \"" + obj.cons_descends[i].name 
                    + "\" is not dynamic.");
            return;
        }

    m_trans.set_translation(obj, [0, 0, 0]);
    m_trans.set_rotation(obj, [0, 0, 0, 1]);
    m_trans.set_scale(obj, 1);
    m_trans.update_transform(obj);
    m_phy.sync_transform(obj);
}

/**
 * Get object size (maximum radius, calculated from bounding box).
 * @method module:transform.get_object_size
 * @param {Object3D} obj Object 3D
 * @returns {Number} Object size
 */
exports.get_object_size = function(obj) {

    if (!m_obj_util.is_mesh(obj)) {
        m_print.error("Wrong object: " + obj.name);
        return 0;
    }

    return m_trans.get_object_size(obj);
}
/**
 * Get the object center in the world space.
 * Works for dynamic and static objects.
 * @method module:transform.get_object_center
 * @param {Object3D} obj Object 3D
 * @param {Boolean} calc_bs_center Use the object's bounding sphere to
 * calculate center, otherwise use the bounding box.
 * @param {Vec3} [dest] Destination vector
 * @returns {Vec3} Destination vector
 */
exports.get_object_center = function(obj, calc_bs_center, dest) {

    if (!m_obj_util.is_mesh(obj)) {
        m_print.error("Wrong object: " + obj.name);
        return null;
    }

    if (!dest)
        var dest = new Float32Array(3);

    return m_trans.get_object_center(obj, calc_bs_center, dest);
}

/**
 * Perform incremental object translation in the local space.
 * @method module:transform.move_local
 * @param {Object3D} obj Object 3D
 * @param {Number} dx Translation offset along X axis
 * @param {Number} dy Translation offset along Y axis
 * @param {Number} dz Translation offset along Z axis
 */
exports.move_local = function(obj, dx, dy, dz) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.move_local(obj, dx, dy, dz);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Perform incremental rotation around X axis in the local space.
 * @method module:transform.rotate_x_local
 * @param {Object3D} obj Object 3D
 * @param {Number} angle Angle
 */
exports.rotate_x_local = function(obj, angle) {
    if (m_obj_util.is_dynamic(obj)) {
        var quat = m_quat.setAxisAngle(m_util.AXIS_X, angle, _quat4_tmp);
        m_trans.rotate_local(obj, quat);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Perform incremental rotation around Y axis in the local space.
 * @method module:transform.rotate_y_local
 * @param {Object3D} obj Object 3D
 * @param {Number} angle Angle
 */
exports.rotate_y_local = function(obj, angle) {
    if (m_obj_util.is_dynamic(obj)) {
        var quat = m_quat.setAxisAngle(m_util.AXIS_MY, angle, _quat4_tmp);
        m_trans.rotate_local(obj, quat);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Perform incremental rotation around Z axis in the local space.
 * @method module:transform.rotate_z_local
 * @param {Object3D} obj Object 3D
 * @param {Number} angle Angle
 */
exports.rotate_z_local = function(obj, angle) {
    if (m_obj_util.is_dynamic(obj)) {
        var quat = m_quat.setAxisAngle(m_util.AXIS_Z, angle, _quat4_tmp);
        m_trans.rotate_local(obj, quat);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Get object bounding box.
 * @method module:transform.get_object_bounding_box
 * @param {Object3D} obj Object 3D
 * @returns {BoundingBox} Bounding box
 * @cc_externs max_x min_x max_y min_y max_z min_z
 */
exports.get_object_bounding_box = function(obj) {
    return m_trans.get_object_bounding_box(obj);
}

/**
 * Set the object's TSR vector.
 * @method module:transform.set_tsr
 * @param {Object3D} obj Object 3D
 * @param {TSR} tsr vector
 */
exports.set_tsr = function(obj, tsr) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_tsr(obj, tsr);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object's TSR vector
 * (in the coordinate space of its parent).
 * @method module:transform.set_tsr_rel
 * @param {Object3D} obj Object 3D
 * @param {TSR} tsr vector
 */
exports.set_tsr_rel = function(obj, tsr) {
    if (m_obj_util.is_dynamic(obj)) {
        m_trans.set_tsr_rel(obj, tsr);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Return an object's transformation in TSR form.
 * @method module:transform.get_tsr
 * @param {Object3D} obj Object 3D
 * @param {TSR} [dest] Destination vector.
 * @returns {TSR} Destination vector.
 */
exports.get_tsr = function(obj, dest) {
    if (!dest)
        var dest = new Float32Array(8);

    m_trans.get_tsr(obj, dest);

    return dest;
}

/**
 * Return the object transformation in TSR form.
 * (in the coordinate space of its parent).
 * @method module:transform.get_tsr_rel
 * @param {Object3D} obj Object 3D
 * @param {TSR} [dest] Destination vector.
 * @returns {TSR} Destination vector.
 */
exports.get_tsr_rel = function(obj, dest) {
    if (!dest)
        var dest = new Float32Array(8);

    m_trans.get_tsr_rel(obj, dest);

    return dest;
}

/**
 * Get distance between the two objects.
 * @param {Object3D} obj1 Object 3D 1
 * @param {Object3D} obj2 Object 3D 2
 * @returns {Number} Distance
 */
exports.distance = function(obj1, obj2) {
    return m_trans.distance(obj1, obj2);
}

/**
 * Set the object's transformation matrix.
 * It's better to use TSR form.
 * @method module:transform.set_matrix
 * @param {Object3D} obj Object 3D
 * @param {Mat4} mat Matrix
 */
exports.set_matrix = function(obj, mat) {
    if (m_obj_util.is_dynamic(obj)) {
        m_tsr.from_mat4(mat, _tsr_tmp);
        m_trans.set_tsr(obj, _tsr_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Set the object's transformation matrix
 * (in the coordinate space of its parent).
 * It's better to use TSR form.
 * @method module:transform.set_matrix_rel
 * @param {Object3D} obj Object 3D
 * @param {Mat4} mat Matrix
 */
exports.set_matrix_rel = function(obj, mat) {
    if (m_obj_util.is_dynamic(obj)) {
        m_tsr.from_mat4(mat, _tsr_tmp);
        m_trans.set_tsr_rel(obj, _tsr_tmp);
        m_trans.update_transform(obj);
        m_phy.sync_transform(obj);
    } else
        m_print.error("Wrong object: \"" + obj.name + "\" is not dynamic.");
}

/**
 * Return the object's transformation matrix.
 * It's better to use TSR form.
 * @method module:transform.get_matrix
 * @param {Object3D} obj Object 3D
 * @param {Mat4} [dest] Destination matrix.
 * @returns {Mat4} Destination matrix.
 */
exports.get_matrix = function(obj, dest) {
    if (!dest)
        var dest = new Float32Array(16);

    m_trans.get_tsr(obj, _tsr_tmp);
    m_tsr.to_mat4(_tsr_tmp, dest);

    return dest;
}

/**
 * Return the object's transformation matrix
 * (in the coordinate space of its parent).
 * It's better to use TSR form.
 * @method module:transform.get_matrix_rel
 * @param {Object3D} obj Object 3D
 * @param {Mat4} [dest] Destination matrix.
 * @returns {Mat4} Destination matrix.
 */
exports.get_matrix_rel = function(obj, dest) {
    if (!dest)
        var dest = new Float32Array(16);

    m_trans.get_tsr_rel(obj, _tsr_tmp);
    m_tsr.to_mat4(_tsr_tmp, dest);

    return dest;
}

}