gtkradiant/tools/urt/libs/transformlib.h

250 lines
5.2 KiB
C
Raw Normal View History

#if !defined (INCLUDED_TRANSFORMLIB_H)
#define INCLUDED_TRANSFORMLIB_H
class Matrix4;
/// \brief A transform node.
class Transformable
{
public:
static const char* getTypeName()
{
return "Transformable";
}
/// \brief Returns the transform which maps the node's local-space into the local-space of its parent node.
virtual const Matrix4& localToParent() const = 0;
};
#include "math/matrix.h"
#include "math/quaternion.h"
/// \brief A transform node which has no effect.
class IdentityTransform : public Transformable
{
public:
/// \brief Returns the identity matrix.
const Matrix4& localToParent() const
{
return g_matrix4_identity;
}
};
/// \brief A transform node which stores a generic transformation matrix.
class MatrixTransform : public Transformable
{
Matrix4 m_localToParent;
public:
MatrixTransform() : m_localToParent(g_matrix4_identity)
{
}
Matrix4& localToParent()
{
return m_localToParent;
}
/// \brief Returns the stored local->parent transform.
const Matrix4& localToParent() const
{
return m_localToParent;
}
};
namespace Transform
{
class Translation
{
Vector3 m_value;
public:
Translation()
: m_value(0, 0, 0)
{
}
const Vector3& get() const
{
return m_value;
}
void set(const Vector3& value)
{
m_value = value;
}
void translate(const Vector3& value)
{
m_value[0] += value[0];
m_value[1] += value[1];
m_value[2] += value[2];
}
};
class Rotation
{
Quaternion m_value;
public:
Rotation()
: m_value(c_quaternion_identity)
{
}
const Quaternion& get() const
{
return m_value;
}
void set(const Quaternion& value)
{
m_value = value;
}
void rotate(const Quaternion& value)
{
quaternion_multiply_by_quaternion(m_value, value);
quaternion_normalise(m_value);
}
};
class Scale
{
Vector3 m_value;
public:
Scale()
: m_value(1, 1, 1)
{
}
const Vector3& get() const
{
return m_value;
}
void set(const Vector3& value)
{
m_value = value;
}
void scale(const Vector3& value)
{
m_value[0] *= value[0];
m_value[1] *= value[1];
m_value[2] *= value[2];
}
};
}
/// \brief A transform node composed of separate translation, rotation and scale transforms.
///
/// - Each component transform can be individually modified at any time.
/// - The transforms are applied in the order: Scale, Rotate, Translate.
/// - The transformation matrix produced is guaranteed to be affine and orthogonal.
class ComponentTransform : public Transformable
{
Transform::Translation m_translation;
Transform::Rotation m_rotation;
Transform::Scale m_scale;
mutable Matrix4 m_transform;
mutable bool m_changed;
void changed() const
{
m_changed = true;
}
void evaluate() const
{
if(m_changed)
{
m_changed = false;
Matrix4 rotation(matrix4_rotation_for_quaternion_quantised(m_rotation.get()));
m_transform.xx() = rotation.xx() * m_scale.get().x();
m_transform.xy() = rotation.xy() * m_scale.get().x();
m_transform.xz() = rotation.xz() * m_scale.get().x();
m_transform.xw() = 0;
m_transform.yx() = rotation.yx() * m_scale.get().y();
m_transform.yy() = rotation.yy() * m_scale.get().y();
m_transform.yz() = rotation.yz() * m_scale.get().y();
m_transform.yw() = 0;
m_transform.zx() = rotation.zx() * m_scale.get().z();
m_transform.zy() = rotation.zy() * m_scale.get().z();
m_transform.zz() = rotation.zz() * m_scale.get().z();
m_transform.zw() = 0;
m_transform.tx() = m_translation.get().x();
m_transform.ty() = m_translation.get().y();
m_transform.tz() = m_translation.get().z();
m_transform.tw() = 1;
}
}
public:
ComponentTransform()
: m_changed(true)
{
}
const Matrix4& localToParent() const
{
evaluate();
return m_transform;
}
const Vector3& getTranslation()
{
return m_translation.get();
}
const Quaternion& getRotation()
{
return m_rotation.get();
}
const Vector3& getScale()
{
return m_scale.get();
}
void setTranslation(const Vector3& value)
{
m_translation.set(value);
changed();
}
void setRotation(const Quaternion& value)
{
m_rotation.set(value);
changed();
}
void setScale(const Vector3& value)
{
m_scale.set(value);
changed();
}
void translate(const Vector3& translation)
{
m_translation.translate(translation);
changed();
}
void rotate(const Quaternion& rotation)
{
m_rotation.rotate(rotation);
changed();
}
void scale(const Vector3& scale)
{
m_scale.scale(scale);
changed();
}
void identity_translate()
{
m_translation = Transform::Translation();
changed();
}
void identity_rotate()
{
m_rotation = Transform::Rotation();
changed();
}
void identity_scale()
{
m_scale = Transform::Scale();
changed();
}
};
#endif