6#include <openxr/openxr.h>
7#include <DirectXMath.h>
19 constexpr XrPosef
Translation(
const XrVector3f& translation);
21 XrPosef
LookAt(
const XrVector3f& origin,
const XrVector3f& forward,
const XrVector3f& up);
22 XrPosef
Multiply(
const XrPosef& a,
const XrPosef& b);
23 XrPosef
Slerp(
const XrPosef& a,
const XrPosef& b,
float alpha);
24 XrPosef
Invert(
const XrPosef& pose);
26 constexpr bool IsPoseValid(
const XrSpaceLocation& location);
27 constexpr bool IsPoseTracked(
const XrSpaceLocation& location);
28 constexpr bool IsPoseValid(
const XrHandJointLocationEXT& jointLocation);
29 constexpr bool IsPoseTracked(
const XrHandJointLocationEXT& jointLocation);
30 constexpr bool IsPoseValid(
const XrViewState& viewState);
33 template <
typename Quaternion,
typename Vector3>
42 XrQuaternionf
Slerp(
const XrQuaternionf& a,
const XrQuaternionf& b,
float alpha);
57 template <
typename X,
typename Y>
58 constexpr const X&
cast(
const Y& value) =
delete;
62 DirectX::XMVECTOR XM_CALLCONV
LoadXrVector3(
const XrVector3f& vector);
63 DirectX::XMVECTOR XM_CALLCONV
LoadXrVector4(
const XrVector4f& vector);
64 DirectX::XMVECTOR XM_CALLCONV
LoadXrQuaternion(
const XrQuaternionf& quaternion);
65 DirectX::XMMATRIX XM_CALLCONV
LoadXrPose(
const XrPosef& rigidTransform);
67 DirectX::XMVECTOR XM_CALLCONV
LoadXrExtent(
const XrExtent2Df& extend);
70 void XM_CALLCONV
StoreXrVector2(XrVector2f* outVec, DirectX::FXMVECTOR inVec);
71 void XM_CALLCONV
StoreXrVector3(XrVector3f* outVec, DirectX::FXMVECTOR inVec);
72 void XM_CALLCONV
StoreXrVector4(XrVector4f* outVec, DirectX::FXMVECTOR inVec);
73 void XM_CALLCONV
StoreXrQuaternion(XrQuaternionf* outQuat, DirectX::FXMVECTOR inQuat);
74 bool XM_CALLCONV
StoreXrPose(XrPosef* out, DirectX::FXMMATRIX matrix);
75 void XM_CALLCONV
StoreXrExtent(XrExtent2Df* extend, DirectX::FXMVECTOR inVec);
83#pragma region Implementation
87 template <
typename X,
typename Y>
89 static_assert(std::is_trivially_copyable<X>::value,
"Unsafe to cast between non-POD types.");
90 static_assert(std::is_trivially_copyable<Y>::value,
"Unsafe to cast between non-POD types.");
91 static_assert(!std::is_pointer<X>::value,
"Incorrect cast between pointer types.");
92 static_assert(!std::is_pointer<Y>::value,
"Incorrect cast between pointer types.");
93 static_assert(
sizeof(X) ==
sizeof(Y),
"Incorrect cast between types with different sizes.");
94 return reinterpret_cast<const X&
>(value);
97 template <
typename X,
typename Y>
99 static_assert(std::is_trivially_copyable<X>::value,
"Unsafe to cast between non-POD types.");
100 static_assert(std::is_trivially_copyable<Y>::value,
"Unsafe to cast between non-POD types.");
101 static_assert(!std::is_pointer<X>::value,
"Incorrect cast between pointer types.");
102 static_assert(!std::is_pointer<Y>::value,
"Incorrect cast between pointer types.");
103 static_assert(
sizeof(X) ==
sizeof(Y),
"Incorrect cast between types with different sizes.");
104 return reinterpret_cast<X&
>(value);
109#define DEFINE_CAST(X, Y) \
111 constexpr const X& cast<X, Y>(const Y& value) { \
112 return detail::implement_math_cast<X>(value); \
115 static_assert(offsetof(DirectX::XMFLOAT2, x) == offsetof(XrVector2f, x));
116 static_assert(offsetof(DirectX::XMFLOAT2, y) == offsetof(XrVector2f, y));
120 static_assert(offsetof(DirectX::XMFLOAT3, x) == offsetof(XrVector3f, x));
121 static_assert(offsetof(DirectX::XMFLOAT3, y) == offsetof(XrVector3f, y));
122 static_assert(offsetof(DirectX::XMFLOAT3, z) == offsetof(XrVector3f, z));
126 static_assert(offsetof(DirectX::XMFLOAT4, x) == offsetof(XrVector4f, x));
127 static_assert(offsetof(DirectX::XMFLOAT4, y) == offsetof(XrVector4f, y));
128 static_assert(offsetof(DirectX::XMFLOAT4, z) == offsetof(XrVector4f, z));
129 static_assert(offsetof(DirectX::XMFLOAT4, w) == offsetof(XrVector4f, w));
133 static_assert(offsetof(DirectX::XMFLOAT4, x) == offsetof(XrQuaternionf, x));
134 static_assert(offsetof(DirectX::XMFLOAT4, y) == offsetof(XrQuaternionf, y));
135 static_assert(offsetof(DirectX::XMFLOAT4, z) == offsetof(XrQuaternionf, z));
136 static_assert(offsetof(DirectX::XMFLOAT4, w) == offsetof(XrQuaternionf, w));
140 static_assert(offsetof(DirectX::XMINT2, x) == offsetof(XrExtent2Di, width));
141 static_assert(offsetof(DirectX::XMINT2, y) == offsetof(XrExtent2Di, height));
145 static_assert(offsetof(DirectX::XMFLOAT2, x) == offsetof(XrExtent2Df, width));
146 static_assert(offsetof(DirectX::XMFLOAT2, y) == offsetof(XrExtent2Df, height));
150 static_assert(offsetof(DirectX::XMFLOAT4, x) == offsetof(XrColor4f, r));
151 static_assert(offsetof(DirectX::XMFLOAT4, y) == offsetof(XrColor4f, g));
152 static_assert(offsetof(DirectX::XMFLOAT4, z) == offsetof(XrColor4f, b));
153 static_assert(offsetof(DirectX::XMFLOAT4, w) == offsetof(XrColor4f, a));
160#define DEFINE_CAST(X, Y) \
161 constexpr const X& cast(const Y& value) { \
162 return detail::implement_math_cast<X>(value); \
164 constexpr X& cast(Y& value) { \
165 return detail::implement_math_cast<X>(value); \
175#define VECTOR2F_OPERATOR(op) \
176 constexpr XrVector2f operator op(const XrVector2f& a, const XrVector2f& b) { \
177 return XrVector2f{a.x op b.x, a.y op b.y}; \
183#undef VECTOR2F_OPERATOR
185#define VECTOR2F_OPERATOR(op) \
186 constexpr XrVector2f operator op(const XrVector2f& a, float s) { \
187 return XrVector2f{a.x op s, a.y op s}; \
193#undef VECTOR2F_OPERATOR
195#define VECTOR2F_OPERATOR(op) \
196 constexpr XrVector2f operator op(float s, const XrVector2f& a) { \
197 return XrVector2f{s op a.x, s op a.y}; \
203#undef VECTOR2F_OPERATOR
205#define VECTOR3F_OPERATOR(op) \
206 constexpr XrVector3f operator op(const XrVector3f& a, const XrVector3f& b) { \
207 return XrVector3f{a.x op b.x, a.y op b.y, a.z op b.z}; \
213#undef VECTOR3F_OPERATOR
215#define VECTOR3F_OPERATOR(op) \
216 constexpr XrVector3f operator op(const XrVector3f& a, float s) { \
217 return XrVector3f{a.x op s, a.y op s, a.z op s}; \
223#undef VECTOR3F_OPERATOR
225#define VECTOR3F_OPERATOR(op) \
226 constexpr XrVector3f operator op(float s, const XrVector3f& a) { \
227 return XrVector3f{s op a.x, s op a.y, s op a.z}; \
233#undef VECTOR3F_OPERATOR
235 inline DirectX::XMVECTOR XM_CALLCONV
LoadXrVector2(
const XrVector2f& vector) {
239 inline DirectX::XMVECTOR XM_CALLCONV
LoadXrVector3(
const XrVector3f& vector) {
243 inline DirectX::XMVECTOR XM_CALLCONV
LoadXrVector4(
const XrVector4f& vector) {
251 inline DirectX::XMVECTOR XM_CALLCONV
LoadXrExtent(
const XrExtent2Df& extend) {
255 inline DirectX::XMMATRIX XM_CALLCONV
LoadXrPose(
const XrPosef& pose) {
257 const DirectX::XMVECTOR position =
LoadXrVector3(pose.position);
258 DirectX::XMMATRIX matrix = DirectX::XMMatrixRotationQuaternion(orientation);
259 matrix.r[3] = DirectX::XMVectorAdd(matrix.r[3], position);
267 inline void XM_CALLCONV
StoreXrVector2(XrVector2f* outVec, DirectX::FXMVECTOR inVec) {
271 inline void XM_CALLCONV
StoreXrVector3(XrVector3f* outVec, DirectX::FXMVECTOR inVec) {
275 inline void XM_CALLCONV
StoreXrVector4(XrVector4f* outVec, DirectX::FXMVECTOR inVec) {
283 inline void XM_CALLCONV
StoreXrExtent(XrExtent2Df* outVec, DirectX::FXMVECTOR inVec) {
287 inline bool XM_CALLCONV
StoreXrPose(XrPosef* out, DirectX::FXMMATRIX matrix) {
288 DirectX::XMVECTOR position;
289 DirectX::XMVECTOR orientation;
290 DirectX::XMVECTOR scale;
292 if (!DirectX::XMMatrixDecompose(&scale, &orientation, &position, matrix)) {
303 return {{0, 0, 0, 1}, {0, 0, 0}};
308 pose.position = translation;
312 inline XrPosef
LookAt(
const XrVector3f& origin,
const XrVector3f& forward,
const XrVector3f& up) {
313 DirectX::XMMATRIX virtualToGazeOrientation =
321 inline XrPosef
Slerp(
const XrPosef& a,
const XrPosef& b,
float alpha) {
322 return MakePose(Quaternion::Slerp(a.orientation, b.orientation, alpha), a.position + (b.position - a.position) * alpha);
325 inline XrPosef
Invert(
const XrPosef& pose) {
327 const DirectX::XMVECTOR invertOrientation = DirectX::XMQuaternionConjugate(orientation);
329 const DirectX::XMVECTOR position =
LoadXrVector3(pose.position);
330 const DirectX::XMVECTOR invertPosition = DirectX::XMVector3Rotate(DirectX::XMVectorNegate(position), invertOrientation);
338 inline XrPosef
Multiply(
const XrPosef& a,
const XrPosef& b) {
356 StoreXrVector3(&c.position, DirectX::XMVectorAdd(DirectX::XMVector3Rotate(pa, qb), pb));
361 constexpr XrSpaceLocationFlags PoseValidFlags = XR_SPACE_LOCATION_POSITION_VALID_BIT | XR_SPACE_LOCATION_ORIENTATION_VALID_BIT;
362 return (locationFlags & PoseValidFlags) == PoseValidFlags;
366 constexpr XrSpaceLocationFlags PoseTrackedFlags =
367 XR_SPACE_LOCATION_POSITION_TRACKED_BIT | XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT;
368 return (locationFlags & PoseTrackedFlags) == PoseTrackedFlags;
371 constexpr bool IsPoseValid(
const XrSpaceLocation& spaceLocation) {
379 constexpr bool IsPoseValid(
const XrHandJointLocationEXT& jointLocation) {
388 constexpr XrViewStateFlags PoseValidFlags = XR_VIEW_STATE_POSITION_VALID_BIT | XR_VIEW_STATE_ORIENTATION_VALID_BIT;
389 return (viewState.viewStateFlags & PoseValidFlags) == PoseValidFlags;
393 constexpr XrViewStateFlags PoseTrackedFlags = XR_VIEW_STATE_POSITION_TRACKED_BIT | XR_VIEW_STATE_ORIENTATION_TRACKED_BIT;
394 return (viewState.viewStateFlags & PoseTrackedFlags) == PoseTrackedFlags;
397 template <
typename Quaternion,
typename Vector3>
399 return XrPosef{{orientation.x, orientation.y, orientation.z, orientation.w}, {position.x, position.y, position.z}};
408 inline float Length(
const XrQuaternionf& quaternion) {
410 return DirectX::XMVectorGetX(DirectX::XMVector4Length(vector));
425 StoreXrQuaternion(&q, DirectX::XMQuaternionRotationRollPitchYaw(anglesInRadians.x, anglesInRadians.y, anglesInRadians.z));
429 inline XrQuaternionf
Slerp(
const XrQuaternionf& a,
const XrQuaternionf& b,
float alpha) {
432 DirectX::XMVECTOR qr = DirectX::XMQuaternionSlerp(qa, qb, alpha);
433 XrQuaternionf result;
440 inline XrPosef
operator*(
const XrPosef& a,
const XrPosef& b) {
444 inline float Dot(
const XrVector3f& a,
const XrVector3f& b) {
445 return a.x * b.x + a.y * b.y + a.z * b.z;
448 inline float Length(
const XrVector3f& v) {
449 return std::sqrt(
Dot(v, v));
453 return a / std::sqrt(
Dot(a, a));
461 const auto ValidateFovAngle = [](
float angle) {
462 if (angle >= DirectX::XM_PIDIV2 || angle <= -DirectX::XM_PIDIV2) {
463 throw std::runtime_error(
"Invalid projection specification");
466 ValidateFovAngle(fov.angleLeft);
467 ValidateFovAngle(fov.angleRight);
468 ValidateFovAngle(fov.angleUp);
469 ValidateFovAngle(fov.angleDown);
470 if (fabs(fov.angleLeft - fov.angleRight) < std::numeric_limits<float>::epsilon() ||
471 fabs(fov.angleUp - fov.angleDown) < std::numeric_limits<float>::epsilon()) {
472 throw std::runtime_error(
"Invalid projection specification");
475 const float nearPlane = nearFar.
Near;
476 const float farPlane = nearFar.
Far;
477 const bool infNearPlane = isinf(nearPlane);
478 const bool infFarPlane = isinf(farPlane);
480 float l = tan(fov.angleLeft);
481 float r = tan(fov.angleRight);
482 float b = tan(fov.angleDown);
483 float t = tan(fov.angleUp);
491 if (nearPlane < 0.f || farPlane < 0.f) {
492 throw std::runtime_error(
"Invalid projection specification");
495 if (infNearPlane || infFarPlane) {
496 if (infNearPlane && infFarPlane) {
497 throw std::runtime_error(
"Invalid projection specification");
500 const float reciprocalWidth = 1.0f / (r - l);
501 const float reciprocalHeight = 1.0f / (t - b);
503 DirectX::XMFLOAT4X4 projectionMatrix;
509 projectionMatrix._33 = 0.0f;
510 projectionMatrix._43 = farPlane;
512 twoNearZ = nearPlane + nearPlane;
514 projectionMatrix._33 = -1.0f;
515 projectionMatrix._43 = -nearPlane;
518 projectionMatrix._11 = twoNearZ * reciprocalWidth;
519 projectionMatrix._12 = 0.0f;
520 projectionMatrix._13 = 0.0f;
521 projectionMatrix._14 = 0.0f;
523 projectionMatrix._21 = 0.0f;
524 projectionMatrix._22 = twoNearZ * reciprocalHeight;
525 projectionMatrix._23 = 0.0f;
526 projectionMatrix._24 = 0.0f;
528 projectionMatrix._31 = (l + r) * reciprocalWidth;
529 projectionMatrix._32 = (t + b) * reciprocalHeight;
530 projectionMatrix._34 = -1.0f;
532 projectionMatrix._41 = 0.0f;
533 projectionMatrix._42 = 0.0f;
534 projectionMatrix._44 = 0.0f;
536 return DirectX::XMLoadFloat4x4(&projectionMatrix);
538 return DirectX::XMMatrixPerspectiveOffCenterRH(l, r, b, t, nearPlane, farPlane);
547 return (p._33 == -1);
552 if (p._12 != 0 || p._13 != 0 || p._14 != 0 ||
554 p._23 != 0 || p._24 != 0 ||
556 p._34 != -1 || p._41 != 0 || p._42 != 0 || p._44 != 0) {
557 throw std::runtime_error(
"Invalid projection matrix");
567 d.
Near = std::numeric_limits<float>::infinity();
571 d.
Far = std::numeric_limits<float>::infinity();
574 d.
Near = p._43 / p._33;
575 d.
Far = p._43 / (1 + p._33);
591 fov.angleLeft = atan2(p._31 - 1, p._11);
592 fov.angleRight = atan2(p._31 + 1, p._11);
593 fov.angleDown = atan2(p._32 - 1, p._22);
594 fov.angleUp = atan2(p._32 + 1, p._22);
598 template <u
int32_t alignment>
599 inline constexpr uint32_t
AlignTo(uint32_t n) {
600 static_assert((alignment & (alignment - 1)) == 0);
601 return (n + alignment - 1) & ~(alignment - 1);
605 return (x + y - 1) / y;
#define VECTOR2F_OPERATOR(op)
#define VECTOR3F_OPERATOR(op)
#define DEFINE_CAST(X, Y)
Ogre::Quaternion Quaternion
constexpr bool IsPoseValid(const XrSpaceLocation &location)
XrPosef Slerp(const XrPosef &a, const XrPosef &b, float alpha)
constexpr XrPosef Identity()
XrPosef Invert(const XrPosef &pose)
constexpr bool IsPoseTracked(const XrSpaceLocation &location)
XrPosef LookAt(const XrVector3f &origin, const XrVector3f &forward, const XrVector3f &up)
XrPosef MakePose(const Quaternion &orientation, const Vector3 &position)
constexpr XrPosef Translation(const XrVector3f &translation)
XrPosef Multiply(const XrPosef &a, const XrPosef &b)
bool IsNormalized(const XrQuaternionf &quaternion)
XrQuaternionf RotationAxisAngle(const XrVector3f &axis, float angleInRadians)
XrQuaternionf Slerp(const XrQuaternionf &a, const XrQuaternionf &b, float alpha)
constexpr XrQuaternionf Identity()
XrQuaternionf RotationRollPitchYaw(const XrVector3f &eulerAnglesInRadians)
float Length(const XrQuaternionf &quaternion)
constexpr const X & implement_math_cast(const Y &value)
bool IsInfiniteFarPlaneProjectionMatrix(const DirectX::XMFLOAT4X4 &p)
void XM_CALLCONV StoreXrExtent(XrExtent2Df *extend, DirectX::FXMVECTOR inVec)
DirectX::XMVECTOR XM_CALLCONV LoadXrExtent(const XrExtent2Df &extend)
void XM_CALLCONV StoreXrVector3(XrVector3f *outVec, DirectX::FXMVECTOR inVec)
constexpr uint32_t AlignTo(uint32_t n)
DirectX::XMMATRIX XM_CALLCONV LoadXrPose(const XrPosef &rigidTransform)
XrPosef operator*(const XrPosef &a, const XrPosef &b)
constexpr float QuaternionEpsilon
constexpr float OneOverFloatEpsilon
DirectX::XMVECTOR XM_CALLCONV LoadXrQuaternion(const XrQuaternionf &quaternion)
void XM_CALLCONV StoreXrQuaternion(XrQuaternionf *outQuat, DirectX::FXMVECTOR inQuat)
bool IsInfiniteNearPlaneProjectionMatrix(const DirectX::XMFLOAT4X4 &p)
constexpr const X & cast(const Y &value)=delete
bool XM_CALLCONV StoreXrPose(XrPosef *out, DirectX::FXMMATRIX matrix)
XrVector3f Normalize(const XrVector3f &a)
XrFovf DecomposeProjectionMatrix(const DirectX::XMFLOAT4X4 &projectionMatrix)
void XM_CALLCONV StoreXrVector4(XrVector4f *outVec, DirectX::FXMVECTOR inVec)
float Dot(const XrVector3f &a, const XrVector3f &b)
NearFar GetProjectionNearFar(const DirectX::XMFLOAT4X4 &projectionMatrix)
DirectX::XMVECTOR XM_CALLCONV LoadXrVector4(const XrVector4f &vector)
void XM_CALLCONV StoreXrVector2(XrVector2f *outVec, DirectX::FXMVECTOR inVec)
void ValidateProjectionMatrix(const DirectX::XMFLOAT4X4 &p)
DirectX::XMMATRIX ComposeProjectionMatrix(const XrFovf &fov, const NearFar &nearFar)
DirectX::XMVECTOR XM_CALLCONV LoadXrVector3(const XrVector3f &vector)
float Length(const XrVector3f &v)
DirectX::XMMATRIX XM_CALLCONV LoadInvertedXrPose(const XrPosef &rigidTransform)
constexpr uint32_t DivideRoundingUp(uint32_t x, uint32_t y)
DirectX::XMVECTOR XM_CALLCONV LoadXrVector2(const XrVector2f &vector)