aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar gingerBill 2015-09-28 22:42:15 +0100
committerGravatar gingerBill 2015-09-28 22:42:15 +0100
commitbbc94498dc7a346b4cfe2fe180f87015213a0c28 (patch)
tree2f21bae1f41724dd2884267a343a21f1d7fd2706
parentgb.hpp - String (diff)
gb.hpp - Transform Type and Quaternion Functions
-rw-r--r--gb.hpp232
1 files changed, 205 insertions, 27 deletions
diff --git a/gb.hpp b/gb.hpp
index 56d7bc6..232cef3 100644
--- a/gb.hpp
+++ b/gb.hpp
@@ -1,7 +1,8 @@
-// gb.hpp - v0.04 - public domain C++11 helper library - no warranty implied; use at your own risk
+// gb.hpp - v0.05 - public domain C++11 helper library - no warranty implied; use at your own risk
// (Experimental) A C++11 helper library without STL geared towards game development
//
// Version History:
+// 0.05 - Transform Type and Quaternion Functions
// 0.04 - String
// 0.03 - Hash Functions
// 0.02 - Hash Table
@@ -128,7 +129,7 @@
#endif
#ifndef NDEBUG
-#define GB_ASSERT(x, ...) ((void)(gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
+#define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__)))
#else
#define GB_ASSERT(x, ...) ((void)sizeof(x))
#endif
@@ -1206,6 +1207,13 @@ struct Euler_Angles
f32 roll;
};
+struct Transform
+{
+ Vector3 position = Vector3{0, 0, 0};
+ Quaternion orientation = Quaternion{0, 0, 0, 1};
+ Vector3 scale = Vector3{0, 0, 0};
+};
+
////////////////////////////////
/// Math Type Op Overloads ///
////////////////////////////////
@@ -1291,6 +1299,8 @@ Quaternion operator*(f32 s, const Quaternion& a);
Quaternion operator/(const Quaternion& a, f32 s);
+Vector3 operator*(const Quaternion& a, const Vector3& v); // Rotate v by a
+
// Matrix4 Operators
bool operator==(const Matrix4& a, const Matrix4& b);
bool operator!=(const Matrix4& a, const Matrix4& b);
@@ -1309,6 +1319,14 @@ Matrix4& operator+=(Matrix4& a, const Matrix4& b);
Matrix4& operator-=(Matrix4& a, const Matrix4& b);
Matrix4& operator*=(Matrix4& a, const Matrix4& b);
+// Transform Operators
+// World = Parent * Local
+Transform operator*(const Transform& ps, const Transform& ls);
+Transform& operator*=(Transform& ps, const Transform& ls);
+// Local = World / Parent
+Transform operator/(const Transform& ws, const Transform& ps);
+Transform& operator/=(Transform& ws, const Transform& ps);
+
//////////////////////////////////
/// Math Functions & Constants ///
//////////////////////////////////
@@ -1389,6 +1407,8 @@ s32 clamp(s32 x, s32 min, s32 max);
s64 clamp(s64 x, s64 min, s64 max);
f32 clamp(f32 x, f32 min, f32 max);
+f32 lerp(f32 x, f32 y, f32 t);
+
// Vector2 functions
f32 dot(const Vector2& a, const Vector2& b);
f32 cross(const Vector2& a, const Vector2& b);
@@ -1425,8 +1445,6 @@ Quaternion normalize(const Quaternion& a);
Quaternion conjugate(const Quaternion& a);
Quaternion inverse(const Quaternion& a);
-Vector3 operator*(const Quaternion& a, const Vector3& v); // Rotate v by a
-
f32 quaternion_angle(const Quaternion& a);
Vector3 quaternion_axis(const Quaternion& a);
Quaternion axis_angle(const Vector3& axis, f32 radians);
@@ -1441,6 +1459,17 @@ Quaternion euler_angles_to_quaternion(const Euler_Angles& e,
const Vector3& y_axis = {0, 1, 0},
const Vector3& z_axis = {0, 0, 1});
+// Spherical Linear Interpolation
+Quaternion slerp(const Quaternion& x, const Quaternion& y, f32 t);
+
+// Shoemake's Quaternion Curves
+// Sqherical Cubic Interpolation
+inline Quaternion squad(const Quaternion& p,
+ const Quaternion& a,
+ const Quaternion& b,
+ const Quaternion& q,
+ f32 t);
+
// Matrix4 functions
Matrix4 transpose(const Matrix4& m);
f32 determinant(const Matrix4& m);
@@ -1466,6 +1495,10 @@ look_at_matrix4(const Vector3& eye, const Vector3& center, const Vector3& up = {
Quaternion
look_at_quaternion(const Vector3& eye, const Vector3& center, const Vector3& up = {0, 1, 0});
+// Transform Functions
+Vector3 transform_point(const Transform& transform, const Vector3& point);
+Transform inverse(const Transform& t);
+Matrix4 transform_to_matrix4(const Transform& t);
} // namespace math
} // namespace gb
@@ -1820,7 +1853,7 @@ void append_string(String& str, const void* other, String_Size other_len)
namespace impl
{
// NOTE(bill): ptr _must_ be allocated with Allocator& a
-static inline void*
+internal inline void*
string_realloc(Allocator& a, void* ptr, usize old_size, usize new_size)
{
if (!ptr)
@@ -1936,7 +1969,7 @@ u32 adler32(const void* key, usize num_bytes)
return (b << 16) | a;
}
-static const u32 GB_CRC32_TABLE[256] = {
+global const u32 GB_CRC32_TABLE[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -2003,7 +2036,7 @@ static const u32 GB_CRC32_TABLE[256] = {
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
-static const u64 GB_CRC64_TABLE[256] = {
+global const u64 GB_CRC64_TABLE[256] = {
0x0000000000000000ull, 0x42F0E1EBA9EA3693ull, 0x85E1C3D753D46D26ull, 0xC711223CFA3E5BB5ull,
0x493366450E42ECDFull, 0x0BC387AEA7A8DA4Cull, 0xCCD2A5925D9681F9ull, 0x8E224479F47CB76Aull,
0x9266CC8A1C85D9BEull, 0xD0962D61B56FEF2Dull, 0x17870F5D4F51B498ull, 0x5577EEB6E6BB820Bull,
@@ -2113,12 +2146,12 @@ u64 crc64(const void* key, usize num_bytes)
u32 murmur32(const void* key, u32 num_bytes, u32 seed)
{
- static const u32 c1 = 0xcc9e2d51;
- static const u32 c2 = 0x1b873593;
- static const u32 r1 = 15;
- static const u32 r2 = 13;
- static const u32 m = 5;
- static const u32 n = 0xe6546b64;
+ local_persist const u32 c1 = 0xcc9e2d51;
+ local_persist const u32 c2 = 0x1b873593;
+ local_persist const u32 r1 = 15;
+ local_persist const u32 r2 = 13;
+ local_persist const u32 m = 5;
+ local_persist const u32 n = 0xe6546b64;
u32 hash = seed;
@@ -2164,8 +2197,8 @@ u32 murmur32(const void* key, u32 num_bytes, u32 seed)
#ifdef GB_ARCH_64_BIT
u64 murmur64(const void* key, usize num_bytes, u64 seed)
{
- static const u64 m = 0xc6a4a7935bd1e995ULL;
- static const s32 r = 47;
+ local_persist const u64 m = 0xc6a4a7935bd1e995ULL;
+ local_persist const s32 r = 47;
u64 h = seed ^ (num_bytes * m);
@@ -2207,8 +2240,8 @@ u64 murmur64(const void* key, usize num_bytes, u64 seed)
#elif GB_ARCH_32_BIT
u64 murmur64(const void* key, usize num_bytes, u64 seed)
{
- static const u32 m = 0x5bd1e995;
- static const s32 r = 24;
+ local_persist const u32 m = 0x5bd1e995;
+ local_persist const s32 r = 24;
u32 h1 = u32(seed) ^ num_bytes;
u32 h2 = u32(seed >> 32);
@@ -2281,7 +2314,7 @@ u64 murmur64(const void* key, usize num_bytes, u64 seed)
////////////////////////////////
#ifdef GB_SYSTEM_WINDOWS
-static LARGE_INTEGER
+internal LARGE_INTEGER
win32_get_frequency()
{
LARGE_INTEGER f;
@@ -2302,7 +2335,7 @@ Time time_now()
// Get the frequency of the performance counter
// It is constant across the program's lifetime
- static LARGE_INTEGER s_frequency = win32_get_frequency();
+ internal LARGE_INTEGER s_frequency = win32_get_frequency();
// Get the current time
LARGE_INTEGER t;
@@ -2818,6 +2851,13 @@ Quaternion operator/(const Quaternion& a, f32 s)
return {a.x / s, a.y / s, a.z / s, a.w / s};
}
+Vector3 operator*(const Quaternion& a, const Vector3& v) // Rotate v by q
+{
+ // return (q * Quaternion{v.x, v.y, v.z, 0} * math::conjugate(q)).xyz; // More Expensive
+ const Vector3 t = 2.0f * math::cross(a.xyz, v);
+ return (v + a.w * t + math::cross(a.xyz, t));
+}
+
// Matrix4 Operators
bool operator==(const Matrix4& a, const Matrix4& b)
{
@@ -2912,6 +2952,46 @@ Matrix4& operator*=(Matrix4& a, const Matrix4& b)
return (a = a * b);
}
+// Transform Operators
+// World = Parent * Local
+Transform operator*(const Transform& ps, const Transform& ls)
+{
+ Transform ws;
+
+ ws.position = ps.position + ps.orientation * (ps.scale * ls.position);
+ ws.orientation = ps.orientation * ls.orientation;
+ ws.scale = ps.scale * (ps.orientation * ls.scale);
+
+ return ws;
+}
+
+Transform& operator*=(Transform& ps, const Transform& ls)
+{
+ return (ps = ps * ls);
+}
+
+// Local = World / Parent
+Transform operator/(const Transform& ws, const Transform& ps)
+{
+ Transform ls;
+
+ const Quaternion ps_conjugate = math::conjugate(ps.orientation);
+
+ ls.position = (ps_conjugate * (ws.position - ps.position)) / ps.scale;
+ ls.orientation = ps_conjugate * ws.orientation;
+ ls.scale = ps_conjugate * (ws.scale / ps.scale);
+
+ return ls;
+}
+
+Transform& operator/=(Transform& ws, const Transform& ps)
+{
+ return (ws = ws / ps);
+}
+
+
+
+
////////////////////////////////
/// Math Functions ///
////////////////////////////////
@@ -3021,6 +3101,45 @@ inline s64 abs(s64 x)
}
+inline s32 min(s32 a, s32 b) { return a < b ? a : b; }
+inline s64 min(s64 a, s64 b) { return a < b ? a : b; }
+inline f32 min(f32 a, f32 b) { return a < b ? a : b; }
+
+inline s32 max(s32 a, s32 b) { return a > b ? a : b; }
+inline s64 max(s64 a, s64 b) { return a > b ? a : b; }
+inline f32 max(f32 a, f32 b) { return a > b ? a : b; }
+
+inline s32 clamp(s32 x, s32 min, s32 max)
+{
+ if (x < min)
+ return min;
+ if (x > max)
+ return max;
+ return x;
+}
+inline s64 clamp(s64 x, s64 min, s64 max)
+{
+ if (x < min)
+ return min;
+ if (x > max)
+ return max;
+ return x;
+}
+inline f32 clamp(f32 x, f32 min, f32 max)
+{
+ if (x < min)
+ return min;
+ if (x > max)
+ return max;
+ return x;
+}
+
+inline f32 lerp(f32 x, f32 y, f32 t)
+{
+ return x + (y-x)*t;
+}
+
+
// Vector2 functions
@@ -3139,13 +3258,6 @@ Quaternion inverse(const Quaternion& a)
return math::conjugate(a) * m;
}
-Vector3 operator*(const Quaternion& a, const Vector3& v) // Rotate v by q
-{
- // return (q * Quaternion(v, 0) * conjugate(q)).xyz; // More Expensive
- const Vector3 t = 2.0f * cross(a.xyz, v);
- return (v + a.w * t + cross(a.xyz, t));
-}
-
f32 quaternion_angle(const Quaternion& a)
{
return 2.0f * math::acos(a.w);
@@ -3211,6 +3323,45 @@ Quaternion euler_angles_to_quaternion(const Euler_Angles& e,
}
+// Spherical Linear Interpolation
+Quaternion slerp(const Quaternion& x, const Quaternion& y, f32 t)
+{
+ Quaternion z = y;
+
+ f32 cos_theta = dot(x, y);
+
+ if (cos_theta < 0.0f)
+ {
+ z = -y;
+ cos_theta = -cos_theta;
+ }
+
+ if (cos_theta > 1.0f)
+ {
+ return Quaternion{lerp(x.x, y.x, t),
+ lerp(x.y, y.y, t),
+ lerp(x.z, y.z, t),
+ lerp(x.w, y.w, t)};
+ }
+
+ f32 angle = math::acos(cos_theta);
+
+ Quaternion result = math::sin(1.0f - (t * angle)) * x + math::sin(t * angle) * z;
+ return result * (1.0f / math::sin(angle));
+}
+
+// Shoemake's Quaternion Curves
+// Sqherical Cubic Interpolation
+inline Quaternion squad(const Quaternion& p,
+ const Quaternion& a,
+ const Quaternion& b,
+ const Quaternion& q,
+ f32 t)
+{
+ return slerp(slerp(p, q, t), slerp(a, b, t), 2.0f * t * (1.0f - t));
+}
+
+
// Matrix4 functions
Matrix4 transpose(const Matrix4& m)
{
@@ -3588,13 +3739,40 @@ look_at_quaternion(const Vector3& eye, const Vector3& center, const Vector3& up)
{
const f32 similar = 0.001f;
- if (magnitude(center - eye) < similar)
+ if (math::magnitude(center - eye) < similar)
return QUATERNION_IDENTITY; // You cannot look at where you are!
// TODO(bill): Implement using just quaternions
return matrix4_to_quaternion(look_at_matrix4(eye, center, up));
}
+// Transform Functions
+Vector3 transform_point(const Transform& transform, const Vector3& point)
+{
+ return (math::conjugate(transform.orientation) * (transform.position - point)) / transform.scale;
+}
+
+Transform inverse(const Transform& t)
+{
+ const Quaternion inv_orientation = math::conjugate(t.orientation);
+
+ Transform inv_transform;
+
+ inv_transform.position = (inv_orientation * -t.position) / t.scale;
+ inv_transform.orientation = inv_orientation;
+ inv_transform.scale = inv_orientation * (Vector3{1, 1, 1} / t.scale);
+
+ return inv_transform;
+}
+
+Matrix4 transform_to_matrix4(const Transform& t)
+{
+ return math::translate(t.position) * //
+ math::quaternion_to_matrix4(t.orientation) * //
+ math::scale(t.scale); //
+}
+
+
} // namespace math
} // namespace gb