1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Scene/BsTransform.h"
4#include "Private/RTTI/BsTransformRTTI.h"
5
6namespace bs
7{
8 Transform Transform::IDENTITY;
9
10 Transform::Transform(const Vector3& position, const Quaternion& rotation, const Vector3& scale)
11 : mPosition(position), mRotation(rotation), mScale(scale)
12 { }
13
14 Matrix4 Transform::getMatrix() const
15 {
16 return Matrix4::TRS(mPosition, mRotation, mScale);
17 }
18
19 Matrix4 Transform::getInvMatrix() const
20 {
21 return Matrix4::inverseTRS(mPosition, mRotation, mScale);
22 }
23
24 void Transform::makeLocal(const Transform& parent)
25 {
26 setWorldPosition(mPosition, parent);
27 setWorldRotation(mRotation, parent);
28 setWorldScale(mScale, parent);
29 }
30
31 void Transform::makeWorld(const Transform& parent)
32 {
33 // Update orientation
34 const Quaternion& parentOrientation = parent.getRotation();
35 mRotation = parentOrientation * mRotation;
36
37 // Update scale
38 const Vector3& parentScale = parent.getScale();
39
40 // Scale own position by parent scale, just combine as equivalent axes, no shearing
41 mScale = parentScale * mScale;
42
43 // Change position vector based on parent's orientation & scale
44 mPosition = parentOrientation.rotate(parentScale * mPosition);
45
46 // Add altered position vector to parents
47 mPosition += parent.getPosition();
48 }
49
50 void Transform::setWorldPosition(const Vector3& position, const Transform& parent)
51 {
52 Vector3 invScale = parent.getScale();
53 if (invScale.x != 0) invScale.x = 1.0f / invScale.x;
54 if (invScale.y != 0) invScale.y = 1.0f / invScale.y;
55 if (invScale.z != 0) invScale.z = 1.0f / invScale.z;
56
57 Quaternion invRotation = parent.getRotation().inverse();
58
59 mPosition = invRotation.rotate(position - parent.getPosition()) * invScale;
60 }
61
62 void Transform::setWorldRotation(const Quaternion& rotation, const Transform& parent)
63 {
64 Quaternion invRotation = parent.getRotation().inverse();
65 mRotation = invRotation * rotation;
66 }
67
68 void Transform::setWorldScale(const Vector3& scale, const Transform& parent)
69 {
70 Matrix4 parentMatrix = parent.getMatrix();
71 Matrix3 rotScale = parentMatrix.get3x3();
72 rotScale = rotScale.inverse();
73
74 Matrix3 scaleMat = Matrix3(Quaternion::IDENTITY, scale);
75 scaleMat = rotScale * scaleMat;
76
77 Quaternion rotation;
78 Vector3 localScale;
79 scaleMat.decomposition(rotation, localScale);
80
81 mScale = localScale;
82 }
83
84 void Transform::lookAt(const Vector3& location, const Vector3& up)
85 {
86 Vector3 forward = location - getPosition();
87
88 Quaternion rotation = getRotation();
89 rotation.lookRotation(forward, up);
90 setRotation(rotation);
91 }
92
93 void Transform::move(const Vector3& vec)
94 {
95 setPosition(mPosition + vec);
96 }
97
98 void Transform::moveRelative(const Vector3& vec)
99 {
100 // Transform the axes of the relative vector by camera's local axes
101 Vector3 trans = mRotation.rotate(vec);
102
103 setPosition(mPosition + trans);
104 }
105
106 void Transform::rotate(const Vector3& axis, const Radian& angle)
107 {
108 Quaternion q;
109 q.fromAxisAngle(axis, angle);
110 rotate(q);
111 }
112
113 void Transform::rotate(const Quaternion& q)
114 {
115 // Note the order of the mult, i.e. q comes after
116
117 // Normalize the quat to avoid cumulative problems with precision
118 Quaternion qnorm = q;
119 qnorm.normalize();
120 setRotation(qnorm * mRotation);
121 }
122
123 void Transform::roll(const Radian& angle)
124 {
125 // Rotate around local Z axis
126 Vector3 zAxis = mRotation.rotate(Vector3::UNIT_Z);
127 rotate(zAxis, angle);
128 }
129
130 void Transform::yaw(const Radian& angle)
131 {
132 Vector3 yAxis = mRotation.rotate(Vector3::UNIT_Y);
133 rotate(yAxis, angle);
134 }
135
136 void Transform::pitch(const Radian& angle)
137 {
138 // Rotate around local X axis
139 Vector3 xAxis = mRotation.rotate(Vector3::UNIT_X);
140 rotate(xAxis, angle);
141 }
142
143 void Transform::setForward(const Vector3& forwardDir)
144 {
145 Quaternion currentRotation = getRotation();
146 currentRotation.lookRotation(forwardDir);
147 setRotation(currentRotation);
148 }
149
150 RTTITypeBase* Transform::getRTTIStatic()
151 {
152 return TransformRTTI::instance();
153 }
154
155 RTTITypeBase* Transform::getRTTI() const
156 {
157 return Transform::getRTTIStatic();
158 }
159}
160