-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathglm_utils.cpp
More file actions
168 lines (137 loc) · 4.93 KB
/
glm_utils.cpp
File metadata and controls
168 lines (137 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "glm_utils.hpp"
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <iostream>
#include <ostream>
#include <regex>
namespace glm_utils {
glm::mat4 identity_matrix(1.0f);
glm::mat4 zero_matrix(0.0f);
glm::vec3 zero_R3(0, 0, 0);
glm::vec3 one_R3(1, 1, 1);
glm::vec3 minus_one_R3 = -1.0f * one_R3;
glm::vec2 zero_R2(0, 0);
glm::vec2 one_R2(1, 1);
glm::vec2 minus_one_R2 = -1.0f * one_R2;
glm::vec3 x(1, 0, 0);
glm::vec2 x_R2(1, 0);
glm::vec3 y(0, 1, 0);
glm::vec2 y_R2(0, 1);
glm::vec3 z(0, 0, 1);
glm::vec3 lift(const glm::vec2 &v, float value, Component component) {
switch (component) {
case Component::x:
return glm::vec3(value, v.x, v.y);
case Component::y:
return glm::vec3(v.x, value, v.y);
case Component::z:
return glm::vec3(v.x, v.y, value);
}
return glm::vec3(0.0f); // should never hit
}
glm::vec2 drop(const glm::vec3 &v, Component component) {
switch (component) {
case Component::x:
return glm::vec2(v.y, v.z);
case Component::y:
return glm::vec2(v.x, v.z);
case Component::z:
return glm::vec2(v.x, v.y);
}
return glm::vec2(0.0f); // should never hit
}
glm::vec3 set_component(const glm::vec3 &v, Component component, float value) {
glm::vec3 result = v;
switch (component) {
case Component::x:
result.x = value;
break;
case Component::y:
result.y = value;
break;
case Component::z:
result.z = value;
break;
}
return result;
}
float signed_component_distance(const glm::vec3 &a, const glm::vec3 &b, const Component &component) {
switch (component) {
case Component::x:
return a.x - b.x;
case Component::y:
return a.y - b.y;
case Component::z:
return a.z - b.z;
}
}
float signed_component_distance(const glm::vec2 &a, const glm::vec2 &b, const Component &component) {
switch (component) {
case Component::x:
return a.x - b.x;
case Component::y:
return a.y - b.y;
case Component::z:
throw std::out_of_range("vec2 has only x and y");
}
}
float component_distance(const glm::vec3 &a, const glm::vec3 &b, const Component &component) {
return std::abs(signed_component_distance(a, b, component));
}
float component_distance(const glm::vec2 &a, const glm::vec2 &b, const Component &component) {
return std::abs(signed_component_distance(a, b, component));
}
glm::vec2 parse_vec2(const std::string &s) {
static const std::regex vec3_pattern(regex_utils::captured_float_tuple);
std::smatch match;
if (std::regex_match(s, match, vec3_pattern)) {
float x = std::stof(match[1].str());
float y = std::stof(match[2].str());
return glm::vec2(x, y);
} else {
throw std::invalid_argument("Invalid vec2 format: " + s);
}
}
glm::vec3 parse_vec3(const std::string &s) {
static const std::regex vec3_pattern(regex_utils::captured_float_triplet);
std::smatch match;
if (std::regex_match(s, match, vec3_pattern)) {
float x = std::stof(match[1].str());
float y = std::stof(match[2].str());
float z = std::stof(match[3].str());
return glm::vec3(x, y, z);
} else {
throw std::invalid_argument("Invalid vec3 format: " + s);
}
}
/*
* the direction vector between a and b is b - a, then we want to go halway across this so (b - a) * 0.5
* and then add this to a to obtain (a + b) * 0.5
*/
glm::vec3 get_midpoint(const glm::vec3 &a, const glm::vec3 &b) { return (a + b) * 0.5f; }
glm::vec3 linearly_interpolate(const glm::vec3 &a, const glm::vec3 &b, float t) { return (1 - t) * a + t * b; }
glm::vec3 rotate_vector_to_align_with_forward(const glm::vec3 &forward, const glm::vec3 &to_be_rotated) {
glm::vec3 canonical_forward = glm::vec3(0.0f, 0.0f, -1.0f);
// Normalize to ensure valid rotation
glm::vec3 norm_forward = glm::normalize(forward);
glm::vec3 norm_canonical = glm::normalize(canonical_forward);
// Compute the quaternion that rotates `forward` to `canonical_forward`
glm::quat rotation = glm::rotation(norm_forward, norm_canonical);
// Rotate the target vector by this quaternion
glm::vec3 rotated_target = rotation * to_be_rotated;
return rotated_target;
}
glm::vec2 rotate_vector_to_align_with_forward(const glm::vec2 &forward, const glm::vec2 &to_be_rotated) {
glm::vec2 canonical_forward = glm::vec2(0.0f, -1.0f);
glm::vec2 norm_forward = glm::normalize(forward);
glm::vec2 norm_canonical = glm::normalize(canonical_forward);
// Compute angle between forward and canonical
float angle = glm::orientedAngle(norm_forward, norm_canonical); // signed angle in radians
// Rotate the target vector by this angle
float cos_a = glm::cos(angle);
float sin_a = glm::sin(angle);
glm::mat2 rotation_matrix = glm::mat2(cos_a, -sin_a, sin_a, cos_a);
return rotation_matrix * to_be_rotated;
}
} // namespace glm_utils