engine/engine/inc/uf/utils/math/transform/transform.inl

227 lines
8.9 KiB
C++

template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::initialize( pod::Transform<T>& transform ) {
transform.position = {0, 0, 0};
transform.scale = {1, 1, 1};
transform.orientation = {0, 0, 0, 1};
transform.reference = nullptr;
return transform;
}
template<typename T>
pod::Transform<T> /*UF_API*/ uf::transform::initialize() {
pod::Transform<T> transform;
return uf::transform::initialize(transform);
}
template<typename T>
pod::Axes /*UF_API*/ uf::transform::axes( const pod::Transform<T>& transform, const pod::Vector3t<T>& at ) {
pod::Axes axes;
auto& q = transform.orientation;
axes.forward = { 2 * (q.x * q.z + q.w * q.y), 2 * (q.y * q.z - q.w * q.x), 1 - 2 * (q.x * q.x + q.y * q.y) };
axes.up = { 2 * (q.x * q.y - q.w * q.z), 1 - 2 * (q.x * q.x + q.z * q.z), 2 * (q.y * q.z + q.w * q.x)};
axes.right = { 1 - 2 * (q.y * q.y + q.z * q.z), 2 * (q.x * q.y + q.w * q.z), 2 * (q.x * q.z - q.w * q.y)};
if ( at != pod::Vector3f{} ) {
axes.forward = uf::vector::normalize( at - transform.position );
axes.right = uf::vector::normalize(uf::vector::cross( axes.up, axes.forward ));
axes.up = uf::vector::normalize(uf::vector::cross( axes.forward, axes.right ));
}
return axes;
}
template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::lookAt( pod::Transform<T>& transform, const pod::Vector3t<T>& at ) {
auto axes = uf::transform::axes( transform, at );
transform.orientation = uf::quaternion::lookAt( axes.forward, axes.up );
return transform;
}
template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::move( pod::Transform<T>& transform, const pod::Vector3t<T>& axis, pod::Math::num_t delta ) {
transform.position += (axis * delta);
return transform;
}
template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::move( pod::Transform<T>& transform, const pod::Vector3t<T>& delta ) {
transform.position += delta;
return transform;
}
template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::rotate( pod::Transform<T>& transform, const pod::Vector3t<T>& axis, pod::Math::num_t delta ) {
pod::Quaternion<> quat = uf::quaternion::axisAngle( axis, delta );
transform.orientation = uf::vector::normalize(uf::quaternion::multiply(quat, transform.orientation));
return transform;
}
template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::rotate( pod::Transform<T>& transform, const pod::Quaternion<T>& quat ) {
transform.orientation = uf::vector::normalize(uf::quaternion::multiply(quat, transform.orientation));
return transform;
}
template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::scale( pod::Transform<T>& transform, const pod::Vector3t<T>& factor ) {
transform.scale = factor;
return transform;
}
template<typename T>
inline pod::Transform<T> /*UF_API*/ uf::transform::condense( const pod::Transform<T>& transform ) {
return uf::transform::fromMatrix( uf::transform::model( transform, false ) );
}
template<typename T>
pod::Transform<T> /*UF_API*/ uf::transform::flatten( const pod::Transform<T>& transform, size_t depth ) {
if ( !transform.reference ) return transform;
pod::Transform<T> combined = transform;
combined.reference = nullptr;
const pod::Transform<T>* pointer = transform.reference;
while ( pointer && depth-- > 0 ) {
combined.position = pointer->position + uf::quaternion::rotate(pointer->orientation, combined.position * pointer->scale);
combined.orientation = uf::quaternion::multiply( pointer->orientation, combined.orientation );
combined.scale = combined.scale * pointer->scale;
if ( pointer == pointer->reference ) break;
pointer = pointer->reference;
}
return combined;
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::transform::model( const pod::Transform<T>& transform, bool flatten, size_t depth ) {
if ( flatten ) {
pod::Transform<T> flat = uf::transform::flatten(transform, depth);
return uf::matrix::translate( uf::matrix::identity(), flat.position ) *
uf::quaternion::matrix( flat.orientation ) *
uf::matrix::scale( uf::matrix::identity(), flat.scale );
}
pod::Matrix4t<T> matrix = uf::matrix::identity();
const pod::Transform<T>* pointer = &transform;
do {
pod::Matrix4t<T> modelMat = uf::matrix::translate( uf::matrix::identity(), pointer->position ) *
uf::quaternion::matrix( pointer->orientation ) *
uf::matrix::scale( uf::matrix::identity(), pointer->scale );
matrix = modelMat * matrix;
if ( pointer == pointer->reference ) break;
pointer = pointer->reference;
} while ( pointer && --depth > 0 );
return matrix;
}
template<typename T>
pod::Transform<T> uf::transform::fromMatrix( const pod::Matrix4t<T>& matrix ) {
pod::Transform<T> transform;
transform.position = uf::matrix::extractTranslation( matrix );
transform.orientation = uf::quaternion::fromMatrix( matrix );
transform.scale = uf::matrix::extractScale( matrix );
return transform;
}
template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::reference( pod::Transform<T>& transform, const pod::Transform<T>& parent, bool reorient ) {
transform.reference = const_cast<pod::Transform<T>*>(&parent);
if ( reorient ) transform.position = parent.position - transform.position;
return transform;
}
template<typename T>
pod::Transform<T> /*UF_API*/ uf::transform::interpolate( const pod::Transform<T>& from, const pod::Transform<T>& to, float factor ) {
pod::Transform transform = to;
transform.position = uf::vector::lerp( from.position, to.position, factor );
transform.orientation = uf::quaternion::slerp( from.orientation, to.orientation, factor );
return transform;
}
template<typename T>
pod::Transform<T> uf::transform::inverse(const pod::Transform<T>& t) {
pod::Transform<T> inv;
pod::Quaternion<T> qInv = uf::quaternion::conjugate(uf::vector::normalize(t.orientation));
pod::Vector3t<T> sInv {
(fabs(t.scale.x) > 1e-8) ? (1.0f / t.scale.x) : 0.0f,
(fabs(t.scale.y) > 1e-8) ? (1.0f / t.scale.y) : 0.0f,
(fabs(t.scale.z) > 1e-8) ? (1.0f / t.scale.z) : 0.0f
};
inv.scale = sInv;
inv.orientation = qInv;
pod::Vector3t<T> negPos = -t.position;
inv.position = uf::quaternion::rotate(qInv, pod::Vector3f{
negPos.x * sInv.x,
negPos.y * sInv.y,
negPos.z * sInv.z
});
return inv;
}
template<typename T>
pod::Vector3t<T> uf::transform::apply( const pod::Transform<T>& t, const pod::Vector3t<T>& p ) {
return uf::quaternion::rotate( t.orientation, p * t.scale ) + t.position;
}
template<typename T>
pod::Vector3t<T> uf::transform::applyInverse( const pod::Transform<T>& t, const pod::Vector3t<T>& worldPoint ) {
pod::Vector3t<T> translated = worldPoint - t.position;
return uf::quaternion::rotate(uf::quaternion::inverse(t.orientation), translated) / t.scale;
}
template<typename T>
pod::Transform<T> uf::transform::relative( const pod::Transform<T>& a, const pod::Transform<T>& b ) {
pod::Transform<T> rel;
auto invOriA = uf::quaternion::inverse(a.orientation);
rel.position = uf::quaternion::rotate(invOriA, b.position - a.position);
rel.orientation = invOriA * b.orientation;
return rel;
}
template<typename T>
uf::stl::string /*UF_API*/ uf::transform::toString( const pod::Transform<T>& t, bool flatten ) {
pod::Transform<T> transform = flatten ? uf::transform::flatten(t) : t;
uf::stl::stringstream ss;
ss << "Transform(" << uf::string::toString(transform.position) << "; " << uf::string::toString(transform.orientation) << ")";
return ss.str();
}
template<typename T>
ext::json::Value /*UF_API*/ uf::transform::encode( const pod::Transform<T>& t, bool flatten, const ext::json::EncodingSettings& settings ) {
pod::Transform<T> transform = flatten ? uf::transform::flatten(t) : t;
ext::json::Value json;
json["position"] = uf::vector::encode(transform.position, settings);
json["orientation"] = uf::vector::encode(transform.orientation, settings);
json["scale"] = uf::vector::encode(transform.scale, settings);
return json;
}
template<typename T>
pod::Transform<T>& /*UF_API*/ uf::transform::decode( const ext::json::Value& _json, pod::Transform<T>& transform ) {
ext::json::Value json = _json; // cringe null behavior
transform.position = uf::vector::decode<T, 3>(json["position"], transform.position);
transform.scale = uf::vector::decode<T, 3>(json["scale"], transform.scale);
transform.orientation = uf::vector::decode<T, 4>(json["orientation"], transform.orientation);
if ( ext::json::isObject(json["rotation"]) && !ext::json::isNull(json["rotation"]["axis"]) && !ext::json::isNull(json["rotation"]["angle"]) ) {
pod::Vector3t<T> axis = uf::vector::decode<T, 3>(json["rotation"]["axis"]);
T angle = json["rotation"]["angle"].as<T>();
transform.orientation = uf::quaternion::axisAngle( axis, angle );
}
return transform;
}
template<typename T>
pod::Transform<T> /*UF_API*/ uf::transform::decode( const ext::json::Value& json, const pod::Transform<T>& t ) {
pod::Transform<T> transform = t;
return uf::transform::decode(json, transform);
}