227 lines
8.9 KiB
C++
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);
|
|
} |