7 #include <glm/gtx/matrix_decompose.hpp>
8 #include <glm/gtx/quaternion.hpp>
13 static constexpr
auto in_place_delete =
true;
16 glm::vec3 position_ = {},
17 glm::quat rotation_ = glm::identity<glm::quat>(),
18 glm::vec3 scale_ = glm::vec3{1})
19 : transform(glm::identity<glm::mat4>())
20 , rotationQuat(rotation_)
21 , rotationEuler(glm::eulerAngles(rotation_))
25 , useEulerAngles(
false)
28 [[nodiscard]] glm::mat4 getMatrix() {
30 return this->parent->getMatrix() * this->getMatrixLocal();
32 return this->getMatrixLocal();
34 [[nodiscard]]
const glm::mat4& getMatrixLocal() {
36 this->transform = TransformComponent::createTransformMatrix(
37 glm::identity<glm::mat4>(),
38 this->getPositionLocal(),
44 return this->transform;
46 void setMatrixLocal(
const glm::mat4& transform_) {
48 glm::vec4 perspective;
49 glm::decompose(transform_, this->scale, this->rotationQuat, this->position, skew, perspective);
51 this->setRotation(this->rotationQuat);
54 [[nodiscard]] glm::vec3 getPosition()
const {
56 return this->parent->getPosition() + this->getPositionLocal();
58 return this->position;
60 void setPosition(glm::vec3 newGlobalPosition) {
62 this->position = newGlobalPosition - this->parent->getPosition();
64 this->position = newGlobalPosition;
69 [[nodiscard]] glm::vec3 getPositionLocal()
const {
70 return this->position;
72 void setPositionLocal(glm::vec3 newLocalPosition) {
73 this->position = newLocalPosition;
77 [[nodiscard]] glm::quat getRotation()
const {
78 return this->useEulerAngles ? glm::quat(this->rotationEuler) : this->rotationQuat;
80 [[nodiscard]] glm::vec3 getRotationEuler()
const {
81 return this->useEulerAngles ? this->rotationEuler : glm::eulerAngles(this->rotationQuat);
85 return this->getRotationEuler().x;
89 return this->getRotationEuler().y;
93 return this->getRotationEuler().z;
95 void setRotation(glm::quat newRotation) {
96 this->rotationQuat = newRotation;
97 this->rotationEuler = glm::eulerAngles(newRotation);
98 this->useEulerAngles =
false;
101 void setRotation(glm::vec3 newRotation) {
102 this->rotationQuat = glm::quat(newRotation);
103 this->rotationEuler = newRotation;
104 this->useEulerAngles =
true;
110 this->useEulerAngles =
true;
116 this->useEulerAngles =
true;
122 this->useEulerAngles =
true;
126 [[nodiscard]] glm::vec3 getScale()
const {
129 void setScale(glm::vec3 newScale) {
130 this->scale = newScale;
134 void translate(glm::vec3 translateByAmount) {
135 this->position += translateByAmount;
138 void translateWithRotation(glm::vec3 translateByAmount) {
139 glm::quat p{glm::length(translateByAmount), translateByAmount.x, translateByAmount.y, translateByAmount.z};
140 p = this->getRotation() * p * glm::conjugate(this->getRotation());
141 this->translate(glm::vec3{p.x, p.y, p.z});
144 void rotate(glm::quat rotateByAmount) {
145 this->rotationQuat += rotateByAmount;
146 this->rotationEuler = glm::eulerAngles(this->rotationQuat);
147 this->useEulerAngles =
false;
150 void rotate(glm::vec3 rotateByAmount) {
151 this->pitch(rotateByAmount.x);
152 this->yaw(rotateByAmount.y);
153 this->roll(rotateByAmount.z);
154 this->rotationQuat = glm::quat(this->rotationEuler);
155 this->useEulerAngles =
true;
158 void pitch(
float pitch) {
159 this->rotationEuler = glm::rotate(glm::angleAxis(pitch, glm::vec3{1,0,0}), this->rotationEuler);
160 this->rotationQuat = glm::quat(this->rotationEuler);
161 this->useEulerAngles =
true;
164 void yaw(
float yaw) {
165 this->rotationEuler = glm::rotate(glm::angleAxis(yaw, glm::vec3{0,1,0}), this->rotationEuler);
166 this->rotationQuat = glm::quat(this->rotationEuler);
167 this->useEulerAngles =
true;
170 void roll(
float roll) {
171 this->rotationEuler = glm::rotate(glm::angleAxis(roll, glm::vec3{0,0,1}), this->rotationEuler);
172 this->rotationQuat = glm::quat(this->rotationEuler);
173 this->useEulerAngles =
true;
177 [[nodiscard]] glm::vec3 getFrontVector()
const {
179 out.x = 2 * (this->rotationQuat.x * this->rotationQuat.z + this->rotationQuat.w * this->rotationQuat.y);
180 out.y = 2 * (this->rotationQuat.y * this->rotationQuat.z - this->rotationQuat.w * this->rotationQuat.x);
181 out.z = 1 - 2 * (this->rotationQuat.x * this->rotationQuat.x + this->rotationQuat.y * this->rotationQuat.y);
184 [[nodiscard]] glm::vec3 getUpVector()
const {
186 out.x = 2 * (this->rotationQuat.x * this->rotationQuat.y - this->rotationQuat.w * this->rotationQuat.z);
187 out.y = 1 - 2 * (this->rotationQuat.x * this->rotationQuat.x + this->rotationQuat.z * this->rotationQuat.z);
188 out.z = 2 * (this->rotationQuat.y * this->rotationQuat.z + this->rotationQuat.w * this->rotationQuat.x);
191 [[nodiscard]] glm::vec3 getRightVector()
const {
193 out.x = 1 - 2 * (this->rotationQuat.y * this->rotationQuat.y + this->rotationQuat.z * this->rotationQuat.z);
194 out.y = 2 * (this->rotationQuat.x * this->rotationQuat.y + this->rotationQuat.w * this->rotationQuat.z);
195 out.z = 2 * (this->rotationQuat.x * this->rotationQuat.z - this->rotationQuat.w * this->rotationQuat.y);
199 [[nodiscard]]
bool operator==(
const TransformComponent& other)
const {
200 return this->parent == other.parent &&
201 this->position == other.position &&
202 this->rotationQuat == other.rotationQuat &&
203 this->scale == other.scale;
206 [[nodiscard]]
static glm::mat4 createTransformMatrix(
const glm::mat4& start, glm::vec3 position, glm::quat rotation, glm::vec3 scale) {
207 return glm::scale(glm::translate(start, position) * glm::mat4_cast(rotation), scale);
212 glm::quat rotationQuat;
213 glm::vec3 rotationEuler;
217 TransformComponent* parent;
223 concept CComponentHasTransform = requires(T t) {
225 {t.transform} -> std::same_as<TransformComponent*&>;