mirror of
https://github.com/amwatson/CitraVR.git
synced 2024-09-20 03:11:40 +02:00
clang-formatted code from my clang-format to citra's (I like mine better, but it's easier that way)
This commit is contained in:
parent
51147c49be
commit
b3b21894ae
19 changed files with 1150 additions and 1697 deletions
|
@ -14,23 +14,19 @@ License : Licensed under GPLv2 or any later version.
|
|||
#include "utils/LogUtils.h"
|
||||
#include "utils/XrMath.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t CURSOR_WIDTH = 16;
|
||||
constexpr uint32_t CURSOR_HEIGHT = CURSOR_WIDTH;
|
||||
constexpr uint32_t CURSOR_WIDTH = 16;
|
||||
constexpr uint32_t CURSOR_HEIGHT = CURSOR_WIDTH;
|
||||
constexpr uint32_t SUPER_SAMPLE_FACTOR = 2;
|
||||
|
||||
constexpr uint8_t CURSOR_ALPHA = 255;
|
||||
|
||||
constexpr uint8_t COLOR_WHITE_RGB[3] = {255, 255,
|
||||
255}; // White color for the cursor.
|
||||
constexpr uint8_t COLOR_CYAN_RGB[3] = {10, 185,
|
||||
180}; // Cyan color for the cursor.
|
||||
constexpr uint8_t COLOR_WHITE_RGB[3] = {255, 255, 255}; // White color for the cursor.
|
||||
constexpr uint8_t COLOR_CYAN_RGB[3] = {10, 185, 180}; // Cyan color for the cursor.
|
||||
|
||||
constexpr uint8_t OUTLINE_COLOR_RGB[3] = {0, 0,
|
||||
0}; // Black color for the outline.
|
||||
constexpr uint32_t OUTLINE_THICKNESS = 2;
|
||||
constexpr uint8_t OUTLINE_COLOR_RGB[3] = {0, 0, 0}; // Black color for the outline.
|
||||
constexpr uint32_t OUTLINE_THICKNESS = 2;
|
||||
|
||||
typedef std::array<uint8_t, CURSOR_WIDTH * CURSOR_HEIGHT * 4> CursorBuffer;
|
||||
|
||||
|
@ -41,24 +37,23 @@ typedef std::array<uint8_t, CURSOR_WIDTH * CURSOR_HEIGHT * 4> CursorBuffer;
|
|||
#warning "CursorLayer.cpp is designed to be compiled with C++17 or later."
|
||||
#endif
|
||||
|
||||
Swapchain CreateSwapchain(const XrSession& session)
|
||||
{
|
||||
Swapchain swapchain;
|
||||
Swapchain CreateSwapchain(const XrSession& session) {
|
||||
Swapchain swapchain;
|
||||
XrSwapchainCreateInfo swapChainCreateInfo;
|
||||
memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo));
|
||||
swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
|
||||
swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
|
||||
swapChainCreateInfo.createFlags = XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT;
|
||||
swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT |
|
||||
XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
swapChainCreateInfo.format = GL_SRGB8_ALPHA8;
|
||||
swapChainCreateInfo.usageFlags =
|
||||
XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
swapChainCreateInfo.format = GL_SRGB8_ALPHA8;
|
||||
swapChainCreateInfo.sampleCount = 1;
|
||||
swapChainCreateInfo.width = CURSOR_WIDTH;
|
||||
swapChainCreateInfo.height = CURSOR_HEIGHT;
|
||||
swapChainCreateInfo.faceCount = 1;
|
||||
swapChainCreateInfo.arraySize = 1;
|
||||
swapChainCreateInfo.mipCount = 1;
|
||||
swapChainCreateInfo.width = CURSOR_WIDTH;
|
||||
swapChainCreateInfo.height = CURSOR_HEIGHT;
|
||||
swapChainCreateInfo.faceCount = 1;
|
||||
swapChainCreateInfo.arraySize = 1;
|
||||
swapChainCreateInfo.mipCount = 1;
|
||||
|
||||
swapchain.Width = swapChainCreateInfo.width;
|
||||
swapchain.Width = swapChainCreateInfo.width;
|
||||
swapchain.Height = swapChainCreateInfo.height;
|
||||
|
||||
// Create the swapchain.
|
||||
|
@ -66,16 +61,14 @@ Swapchain CreateSwapchain(const XrSession& session)
|
|||
return swapchain;
|
||||
}
|
||||
|
||||
std::vector<XrSwapchainImageOpenGLESKHR>
|
||||
CreateSwapchainImages(const XrSession& session, const XrSwapchain& xrSwapchain)
|
||||
{
|
||||
std::vector<XrSwapchainImageOpenGLESKHR> CreateSwapchainImages(const XrSession& session,
|
||||
const XrSwapchain& xrSwapchain) {
|
||||
uint32_t length;
|
||||
OXR(xrEnumerateSwapchainImages(xrSwapchain, 0, &length, NULL));
|
||||
|
||||
std::vector<XrSwapchainImageOpenGLESKHR> images =
|
||||
std::vector<XrSwapchainImageOpenGLESKHR>(length);
|
||||
for (size_t i = 0; i < images.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < images.size(); i++) {
|
||||
images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
|
||||
images[i].next = NULL;
|
||||
}
|
||||
|
@ -85,48 +78,37 @@ CreateSwapchainImages(const XrSession& session, const XrSwapchain& xrSwapchain)
|
|||
return images;
|
||||
}
|
||||
|
||||
CursorBuffer CreateSuperSampledCursorBuffer(const uint8_t colorRGB[3])
|
||||
{
|
||||
constexpr uint32_t SUPER_WIDTH = CURSOR_WIDTH * SUPER_SAMPLE_FACTOR;
|
||||
CursorBuffer CreateSuperSampledCursorBuffer(const uint8_t colorRGB[3]) {
|
||||
constexpr uint32_t SUPER_WIDTH = CURSOR_WIDTH * SUPER_SAMPLE_FACTOR;
|
||||
constexpr uint32_t SUPER_HEIGHT = CURSOR_HEIGHT * SUPER_SAMPLE_FACTOR;
|
||||
uint8_t superCursorData[SUPER_WIDTH * SUPER_HEIGHT * 4];
|
||||
uint8_t superCursorData[SUPER_WIDTH * SUPER_HEIGHT * 4];
|
||||
|
||||
// Create the high-res cursor.
|
||||
{
|
||||
constexpr uint32_t superCenterX = SUPER_WIDTH / 2;
|
||||
constexpr uint32_t superCenterY = SUPER_HEIGHT / 2;
|
||||
constexpr uint32_t superRadius =
|
||||
SUPER_WIDTH / 2; // Adjust the radius as needed.
|
||||
constexpr uint32_t superOutlineThickness =
|
||||
OUTLINE_THICKNESS * SUPER_SAMPLE_FACTOR;
|
||||
constexpr uint32_t superRadius = SUPER_WIDTH / 2; // Adjust the radius as needed.
|
||||
constexpr uint32_t superOutlineThickness = OUTLINE_THICKNESS * SUPER_SAMPLE_FACTOR;
|
||||
|
||||
for (uint32_t y = 0; y < SUPER_HEIGHT; y++)
|
||||
{
|
||||
for (uint32_t x = 0; x < SUPER_WIDTH; x++)
|
||||
{
|
||||
const uint32_t index = (y * SUPER_WIDTH + x) * 4;
|
||||
const int32_t dx = x - superCenterX;
|
||||
const int32_t dy = y - superCenterY;
|
||||
for (uint32_t y = 0; y < SUPER_HEIGHT; y++) {
|
||||
for (uint32_t x = 0; x < SUPER_WIDTH; x++) {
|
||||
const uint32_t index = (y * SUPER_WIDTH + x) * 4;
|
||||
const int32_t dx = x - superCenterX;
|
||||
const int32_t dy = y - superCenterY;
|
||||
const uint32_t distanceSquared = dx * dx + dy * dy;
|
||||
|
||||
if (distanceSquared < (superRadius * superRadius) &&
|
||||
distanceSquared >= ((superRadius - superOutlineThickness) *
|
||||
(superRadius - superOutlineThickness)))
|
||||
{
|
||||
(superRadius - superOutlineThickness))) {
|
||||
// Pixel is part of the outline.
|
||||
memcpy(&superCursorData[index], OUTLINE_COLOR_RGB, 3);
|
||||
superCursorData[index + 3] = CURSOR_ALPHA;
|
||||
}
|
||||
else if (distanceSquared <
|
||||
((superRadius - superOutlineThickness) *
|
||||
(superRadius - superOutlineThickness)))
|
||||
{
|
||||
} else if (distanceSquared < ((superRadius - superOutlineThickness) *
|
||||
(superRadius - superOutlineThickness))) {
|
||||
// Pixel is inside the circle.
|
||||
memcpy(&superCursorData[index], colorRGB, 3);
|
||||
superCursorData[index + 3] = CURSOR_ALPHA;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Pixel is outside the circle (transparent).
|
||||
memset(&superCursorData[index], 0, 4);
|
||||
}
|
||||
|
@ -136,21 +118,16 @@ CursorBuffer CreateSuperSampledCursorBuffer(const uint8_t colorRGB[3])
|
|||
|
||||
CursorBuffer cursorData;
|
||||
// Downsample to the final image.
|
||||
for (uint32_t y = 0; y < CURSOR_HEIGHT; y++)
|
||||
{
|
||||
for (uint32_t x = 0; x < CURSOR_WIDTH; x++)
|
||||
{
|
||||
for (uint32_t y = 0; y < CURSOR_HEIGHT; y++) {
|
||||
for (uint32_t x = 0; x < CURSOR_WIDTH; x++) {
|
||||
uint32_t index = (y * CURSOR_WIDTH + x) * 4;
|
||||
uint32_t r = 0, g = 0, b = 0, a = 0;
|
||||
|
||||
for (uint32_t dy = 0; dy < SUPER_SAMPLE_FACTOR; dy++)
|
||||
{
|
||||
for (uint32_t dx = 0; dx < SUPER_SAMPLE_FACTOR; dx++)
|
||||
{
|
||||
const uint32_t superIndex =
|
||||
((y * SUPER_SAMPLE_FACTOR + dy) * SUPER_WIDTH +
|
||||
(x * SUPER_SAMPLE_FACTOR + dx)) *
|
||||
4;
|
||||
for (uint32_t dy = 0; dy < SUPER_SAMPLE_FACTOR; dy++) {
|
||||
for (uint32_t dx = 0; dx < SUPER_SAMPLE_FACTOR; dx++) {
|
||||
const uint32_t superIndex = ((y * SUPER_SAMPLE_FACTOR + dy) * SUPER_WIDTH +
|
||||
(x * SUPER_SAMPLE_FACTOR + dx)) *
|
||||
4;
|
||||
r += superCursorData[superIndex];
|
||||
g += superCursorData[superIndex + 1];
|
||||
b += superCursorData[superIndex + 2];
|
||||
|
@ -159,81 +136,65 @@ CursorBuffer CreateSuperSampledCursorBuffer(const uint8_t colorRGB[3])
|
|||
}
|
||||
|
||||
cursorData[index] = r / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
|
||||
cursorData[index + 1] =
|
||||
g / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
|
||||
cursorData[index + 2] =
|
||||
b / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
|
||||
cursorData[index + 3] =
|
||||
a / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
|
||||
cursorData[index + 1] = g / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
|
||||
cursorData[index + 2] = b / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
|
||||
cursorData[index + 3] = a / (SUPER_SAMPLE_FACTOR * SUPER_SAMPLE_FACTOR);
|
||||
}
|
||||
}
|
||||
return cursorData;
|
||||
}
|
||||
|
||||
void GenerateCursorImage(
|
||||
const XrSwapchain& xrSwapchain,
|
||||
const std::vector<XrSwapchainImageOpenGLESKHR>& xrImages,
|
||||
const uint8_t colorRGB[3])
|
||||
{
|
||||
void GenerateCursorImage(const XrSwapchain& xrSwapchain,
|
||||
const std::vector<XrSwapchainImageOpenGLESKHR>& xrImages,
|
||||
const uint8_t colorRGB[3]) {
|
||||
const CursorBuffer cursorData = CreateSuperSampledCursorBuffer(colorRGB);
|
||||
|
||||
uint32_t index = 0;
|
||||
XrSwapchainImageAcquireInfo acquireInfo = {
|
||||
XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, NULL};
|
||||
uint32_t index = 0;
|
||||
XrSwapchainImageAcquireInfo acquireInfo = {XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, NULL};
|
||||
OXR(xrAcquireSwapchainImage(xrSwapchain, &acquireInfo, &index));
|
||||
|
||||
XrSwapchainImageWaitInfo waitInfo = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO,
|
||||
NULL, 0};
|
||||
XrSwapchainImageWaitInfo waitInfo = {XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, NULL, 0};
|
||||
OXR(xrWaitSwapchainImage(xrSwapchain, &waitInfo));
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, xrImages[0].image);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, CURSOR_WIDTH, CURSOR_HEIGHT,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, cursorData.data());
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, CURSOR_WIDTH, CURSOR_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
cursorData.data());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
XrSwapchainImageReleaseInfo releaseInfo = {
|
||||
XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
|
||||
XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
|
||||
OXR(xrReleaseSwapchainImage(xrSwapchain, &releaseInfo));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
CursorLayer::CursorImage::CursorImage(const XrSession& session,
|
||||
const uint8_t colorRGB[3])
|
||||
{
|
||||
mSwapchain = CreateSwapchain(session);
|
||||
CursorLayer::CursorImage::CursorImage(const XrSession& session, const uint8_t colorRGB[3]) {
|
||||
mSwapchain = CreateSwapchain(session);
|
||||
mSwapchainImages = CreateSwapchainImages(session, mSwapchain.Handle);
|
||||
|
||||
GenerateCursorImage(mSwapchain.Handle, mSwapchainImages, colorRGB);
|
||||
}
|
||||
|
||||
CursorLayer::CursorImage::~CursorImage()
|
||||
{
|
||||
if (mSwapchain.Handle != XR_NULL_HANDLE)
|
||||
{
|
||||
CursorLayer::CursorImage::~CursorImage() {
|
||||
if (mSwapchain.Handle != XR_NULL_HANDLE) {
|
||||
xrDestroySwapchain(mSwapchain.Handle);
|
||||
}
|
||||
// destroy images.
|
||||
for (size_t i = 0; i < mSwapchainImages.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < mSwapchainImages.size(); i++) {
|
||||
glDeleteTextures(1, &mSwapchainImages[i].image);
|
||||
}
|
||||
}
|
||||
|
||||
CursorLayer::CursorLayer(const XrSession& session)
|
||||
: mCursorImages({CursorImage(session, COLOR_WHITE_RGB),
|
||||
CursorImage(session, COLOR_CYAN_RGB)})
|
||||
{
|
||||
: mCursorImages({CursorImage(session, COLOR_WHITE_RGB), CursorImage(session, COLOR_CYAN_RGB)}) {
|
||||
}
|
||||
|
||||
void CursorLayer::Frame(const XrSpace& space, XrCompositionLayerQuad& layer,
|
||||
const XrPosef& cursorPose, const float scaleFactor,
|
||||
const CursorType& cursorType) const
|
||||
{
|
||||
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
|
||||
const CursorType& cursorType) const {
|
||||
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
|
||||
layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
|
||||
layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
|
@ -242,15 +203,14 @@ void CursorLayer::Frame(const XrSpace& space, XrCompositionLayerQuad& layer,
|
|||
layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
|
||||
memset(&layer.subImage, 0, sizeof(XrSwapchainSubImage));
|
||||
|
||||
const auto& swapchain =
|
||||
mCursorImages.at(static_cast<size_t>(cursorType)).GetSwapchain();
|
||||
layer.subImage.swapchain = swapchain.Handle;
|
||||
layer.subImage.imageRect.offset.x = 0;
|
||||
layer.subImage.imageRect.offset.y = 0;
|
||||
layer.subImage.imageRect.extent.width = swapchain.Width;
|
||||
const auto& swapchain = mCursorImages.at(static_cast<size_t>(cursorType)).GetSwapchain();
|
||||
layer.subImage.swapchain = swapchain.Handle;
|
||||
layer.subImage.imageRect.offset.x = 0;
|
||||
layer.subImage.imageRect.offset.y = 0;
|
||||
layer.subImage.imageRect.extent.width = swapchain.Width;
|
||||
layer.subImage.imageRect.extent.height = swapchain.Height;
|
||||
layer.size.width = scaleFactor;
|
||||
layer.size.width = scaleFactor;
|
||||
layer.size.height = layer.size.width * swapchain.Height / swapchain.Width;
|
||||
layer.subImage.imageArrayIndex = 0;
|
||||
layer.pose = cursorPose;
|
||||
layer.pose = cursorPose;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ License : Licensed under GPLv2 or any later version.
|
|||
#include <EGL/egl.h>
|
||||
|
||||
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
|
||||
#define XR_USE_PLATFORM_ANDROID 1
|
||||
#define XR_USE_PLATFORM_ANDROID 1
|
||||
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
|
@ -32,18 +32,12 @@ CursorLayer
|
|||
================================================================================
|
||||
*/
|
||||
|
||||
class CursorLayer
|
||||
{
|
||||
class CursorLayer {
|
||||
public:
|
||||
/** The type of cursor to render.
|
||||
* Determines the color of the cursor.
|
||||
**/
|
||||
enum class CursorType
|
||||
{
|
||||
CURSOR_TYPE_NORMAL,
|
||||
CURSOR_TYPE_TOP_PANEL,
|
||||
NUM_CURSOR_TYPES
|
||||
};
|
||||
enum class CursorType { CURSOR_TYPE_NORMAL, CURSOR_TYPE_TOP_PANEL, NUM_CURSOR_TYPES };
|
||||
/**
|
||||
* @param session a valid XR Session
|
||||
*/
|
||||
|
@ -58,14 +52,12 @@ public:
|
|||
* @param scaleFactor the scale factor to apply to the cursor
|
||||
* @param cursorType the type of cursor to render
|
||||
*/
|
||||
void Frame(const XrSpace& space, XrCompositionLayerQuad& layer,
|
||||
const XrPosef& cursorPose, const float scaleFactor,
|
||||
const CursorType& cursorType) const;
|
||||
void Frame(const XrSpace& space, XrCompositionLayerQuad& layer, const XrPosef& cursorPose,
|
||||
const float scaleFactor, const CursorType& cursorType) const;
|
||||
|
||||
private:
|
||||
/** Helper class to manage the cursor image. */
|
||||
class CursorImage
|
||||
{
|
||||
class CursorImage {
|
||||
public:
|
||||
/** Create a new cursor image.
|
||||
*
|
||||
|
@ -76,13 +68,14 @@ private:
|
|||
~CursorImage();
|
||||
|
||||
/** Get the swapchain used to render the cursor. */
|
||||
const Swapchain& GetSwapchain() const { return mSwapchain; }
|
||||
const Swapchain& GetSwapchain() const {
|
||||
return mSwapchain;
|
||||
}
|
||||
|
||||
private:
|
||||
Swapchain mSwapchain;
|
||||
Swapchain mSwapchain;
|
||||
std::vector<XrSwapchainImageOpenGLESKHR> mSwapchainImages;
|
||||
};
|
||||
|
||||
std::array<CursorImage, static_cast<size_t>(CursorType::NUM_CURSOR_TYPES)>
|
||||
mCursorImages;
|
||||
std::array<CursorImage, static_cast<size_t>(CursorType::NUM_CURSOR_TYPES)> mCursorImages;
|
||||
};
|
||||
|
|
|
@ -26,8 +26,7 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
|
||||
constexpr float kLowerPanelScaleFactor = 0.75f;
|
||||
/** Used to translate texture coordinates into the corresponding coordinates
|
||||
|
@ -38,27 +37,26 @@ constexpr float kLowerPanelScaleFactor = 0.75f;
|
|||
* corresponding coordinates on the window, it will be as if the user touched
|
||||
* the game surface.
|
||||
*/
|
||||
class AndroidWindowSpace
|
||||
{
|
||||
class AndroidWindowSpace {
|
||||
public:
|
||||
AndroidWindowSpace(const float widthInDp, const float heightInDp)
|
||||
: widthInDp_(widthInDp)
|
||||
, heightInDp_(heightInDp)
|
||||
{
|
||||
: widthInDp_(widthInDp), heightInDp_(heightInDp) {}
|
||||
float Width() const {
|
||||
return widthInDp_;
|
||||
}
|
||||
float Height() const {
|
||||
return heightInDp_;
|
||||
}
|
||||
float Width() const { return widthInDp_; }
|
||||
float Height() const { return heightInDp_; }
|
||||
|
||||
// "DP" refers to display pixels, which are the same as Android's
|
||||
// "density-independent pixels" (dp).
|
||||
const float widthInDp_ = 0;
|
||||
const float widthInDp_ = 0;
|
||||
const float heightInDp_ = 0;
|
||||
|
||||
// given a 2D point in worldspace 'point2d', returns the transformed
|
||||
// coordinate in DP, written to 'result'
|
||||
void Transform(const XrVector2f& point2d, XrVector2f& result) const
|
||||
{
|
||||
const float width = static_cast<float>(Width());
|
||||
void Transform(const XrVector2f& point2d, XrVector2f& result) const {
|
||||
const float width = static_cast<float>(Width());
|
||||
const float height = static_cast<float>(Height());
|
||||
|
||||
result.x = (point2d.x * width) + (width / 2.0f);
|
||||
|
@ -73,65 +71,52 @@ public:
|
|||
static constexpr std::chrono::milliseconds kMinTimeBetweenChecks(500);
|
||||
|
||||
// Get density on an interval
|
||||
float GetDensitySysprop()
|
||||
{
|
||||
static constexpr float kDefaultDensity =
|
||||
GameSurfaceLayer::DEFAULT_QUAD_DENSITY;
|
||||
float GetDensitySysprop() {
|
||||
static constexpr float kDefaultDensity = GameSurfaceLayer::DEFAULT_QUAD_DENSITY;
|
||||
static float lastDensity = kDefaultDensity;
|
||||
static std::chrono::time_point<std::chrono::steady_clock> lastTime = {};
|
||||
// Only check the sysprop every 500ms
|
||||
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks)
|
||||
{
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
lastDensity = SyspropUtils::GetSysPropAsFloat("debug.citra.density",
|
||||
kDefaultDensity);
|
||||
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks) {
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
lastDensity = SyspropUtils::GetSysPropAsFloat("debug.citra.density", kDefaultDensity);
|
||||
}
|
||||
return lastDensity;
|
||||
}
|
||||
|
||||
int32_t GetCylinderSysprop()
|
||||
{
|
||||
int32_t GetCylinderSysprop() {
|
||||
static constexpr int32_t kDefaultCylinder = 0;
|
||||
static int32_t lastCylinder = kDefaultCylinder;
|
||||
static int32_t lastCylinder = kDefaultCylinder;
|
||||
static std::chrono::time_point<std::chrono::steady_clock> lastTime = {};
|
||||
// Only check the sysprop every 500ms
|
||||
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks)
|
||||
{
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
lastCylinder = SyspropUtils::GetSysPropAsInt("debug.citra.cylinder",
|
||||
kDefaultCylinder);
|
||||
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks) {
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
lastCylinder = SyspropUtils::GetSysPropAsInt("debug.citra.cylinder", kDefaultCylinder);
|
||||
}
|
||||
return lastCylinder;
|
||||
}
|
||||
|
||||
float GetRadiusSysprop()
|
||||
{
|
||||
static constexpr float kDefaultRadius =
|
||||
GameSurfaceLayer::DEFAULT_CYLINDER_RADIUS;
|
||||
float GetRadiusSysprop() {
|
||||
static constexpr float kDefaultRadius = GameSurfaceLayer::DEFAULT_CYLINDER_RADIUS;
|
||||
static float lastRadius = kDefaultRadius;
|
||||
static std::chrono::time_point<std::chrono::steady_clock> lastTime = {};
|
||||
// Only check the sysprop every 500ms
|
||||
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks)
|
||||
{
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
lastRadius = SyspropUtils::GetSysPropAsFloat("debug.citra.radius",
|
||||
kDefaultRadius);
|
||||
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks) {
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
lastRadius = SyspropUtils::GetSysPropAsFloat("debug.citra.radius", kDefaultRadius);
|
||||
}
|
||||
return lastRadius;
|
||||
}
|
||||
|
||||
float GetCentralAngleSysprop()
|
||||
{
|
||||
float GetCentralAngleSysprop() {
|
||||
static constexpr float kDefaultCentralAngle =
|
||||
GameSurfaceLayer::DEFAULT_CYLINDER_CENTRAL_ANGLE_DEGREES;
|
||||
static float lastCentralAngle = kDefaultCentralAngle;
|
||||
static std::chrono::time_point<std::chrono::steady_clock> lastTime = {};
|
||||
// Only check the sysprop every 500ms
|
||||
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks)
|
||||
{
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
lastCentralAngle = SyspropUtils::GetSysPropAsFloat(
|
||||
"debug.citra.cylinder_degrees", kDefaultCentralAngle);
|
||||
if ((std::chrono::steady_clock::now() - lastTime) >= kMinTimeBetweenChecks) {
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
lastCentralAngle =
|
||||
SyspropUtils::GetSysPropAsFloat("debug.citra.cylinder_degrees", kDefaultCentralAngle);
|
||||
}
|
||||
return lastCentralAngle;
|
||||
}
|
||||
|
@ -144,23 +129,19 @@ float GetCentralAngleSysprop()
|
|||
* - Rotated 45 degrees away from viewer
|
||||
* - Half the distance away from viewer as top panel
|
||||
*/
|
||||
XrPosef CreateLowerPanelFromWorld(const XrPosef& topPanelFromWorld)
|
||||
{
|
||||
XrPosef CreateLowerPanelFromWorld(const XrPosef& topPanelFromWorld) {
|
||||
|
||||
constexpr float kLowerPanelYOffset = -0.75f;
|
||||
constexpr float kLowerPanelYOffset = -0.75f;
|
||||
XrPosef lowerPanelFromWorld = topPanelFromWorld;
|
||||
// Pitch the lower panel away from the viewer 45 degrees
|
||||
lowerPanelFromWorld.orientation =
|
||||
XrMath::Quatf::FromEuler(0.0f, -MATH_FLOAT_PI / 4.0f, 0.0f);
|
||||
lowerPanelFromWorld.orientation = XrMath::Quatf::FromEuler(0.0f, -MATH_FLOAT_PI / 4.0f, 0.0f);
|
||||
lowerPanelFromWorld.position.y += kLowerPanelYOffset;
|
||||
lowerPanelFromWorld.position.z = -1.5f;
|
||||
return lowerPanelFromWorld;
|
||||
}
|
||||
|
||||
XrVector3f CalculatePanelPosition(const XrVector3f& viewerPosition,
|
||||
const XrVector3f& controllerPosition,
|
||||
float sphereRadius)
|
||||
{
|
||||
const XrVector3f& controllerPosition, float sphereRadius) {
|
||||
// Vector from viewer to controller
|
||||
XrVector3f viewerToController = controllerPosition - viewerPosition;
|
||||
XrMath::Vector3f::Normalize(viewerToController);
|
||||
|
@ -171,8 +152,7 @@ XrVector3f CalculatePanelPosition(const XrVector3f& viewerPosition,
|
|||
|
||||
XrQuaternionf CalculatePanelRotation(const XrVector3f& windowPosition,
|
||||
const XrVector3f& viewerPosition,
|
||||
const XrVector3f& upDirection)
|
||||
{
|
||||
const XrVector3f& upDirection) {
|
||||
// Compute forward direction (normalized)
|
||||
XrVector3f forward = viewerPosition - windowPosition;
|
||||
XrMath::Vector3f::Normalize(forward);
|
||||
|
@ -187,28 +167,24 @@ XrQuaternionf CalculatePanelRotation(const XrVector3f& windowPosition,
|
|||
return XrMath::Quatf::FromThreeVectors(forward, up, right);
|
||||
}
|
||||
|
||||
bool GetRayIntersectionWithPanel(const XrPosef& panelFromWorld,
|
||||
const uint32_t panelWidth,
|
||||
const uint32_t panelHeight,
|
||||
const XrVector2f& scaleFactor,
|
||||
bool GetRayIntersectionWithPanel(const XrPosef& panelFromWorld, const uint32_t panelWidth,
|
||||
const uint32_t panelHeight, const XrVector2f& scaleFactor,
|
||||
const XrVector3f& start, const XrVector3f& end,
|
||||
XrVector2f& result2d, XrPosef& result3d)
|
||||
|
||||
{
|
||||
const XrPosef worldFromPanel = XrMath::Posef::Inverted(panelFromWorld);
|
||||
const XrVector3f localStart =
|
||||
XrMath::Posef::Transform(worldFromPanel, start);
|
||||
const XrPosef worldFromPanel = XrMath::Posef::Inverted(panelFromWorld);
|
||||
const XrVector3f localStart = XrMath::Posef::Transform(worldFromPanel, start);
|
||||
const XrVector3f localEnd = XrMath::Posef::Transform(worldFromPanel, end);
|
||||
// Note: assumes layer lies in the XZ plane
|
||||
const float tan = localStart.z / (localStart.z - localEnd.z);
|
||||
|
||||
// Check for backwards controller
|
||||
if (tan < 0)
|
||||
{
|
||||
if (tan < 0) {
|
||||
ALOGD("Backwards controller");
|
||||
return false;
|
||||
}
|
||||
result3d.position = start + (end - start) * tan;
|
||||
result3d.position = start + (end - start) * tan;
|
||||
result3d.orientation = panelFromWorld.orientation;
|
||||
|
||||
const XrVector2f result2dNDC = {
|
||||
|
@ -218,103 +194,88 @@ bool GetRayIntersectionWithPanel(const XrPosef& panelFromWorld,
|
|||
const AndroidWindowSpace androidSpace(panelWidth, panelHeight);
|
||||
androidSpace.Transform(result2dNDC, result2d);
|
||||
const bool isInBounds = result2d.x >= 0 && result2d.y >= 0 &&
|
||||
result2d.x < androidSpace.Width() &&
|
||||
result2d.y < androidSpace.Height();
|
||||
result2d.x < androidSpace.Width() && result2d.y < androidSpace.Height();
|
||||
result2d.y += androidSpace.Height();
|
||||
|
||||
if (!isInBounds) { return false; }
|
||||
if (!isInBounds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Uses a density for scaling and sets aspect ratio
|
||||
XrVector2f GetDensityScaleForSize(const int32_t texWidth,
|
||||
const int32_t texHeight,
|
||||
const float scaleFactor)
|
||||
{
|
||||
XrVector2f GetDensityScaleForSize(const int32_t texWidth, const int32_t texHeight,
|
||||
const float scaleFactor) {
|
||||
const float density = GetDensitySysprop();
|
||||
return XrVector2f{2.0f * static_cast<float>(texWidth) / density,
|
||||
(static_cast<float>(texHeight) / density)} *
|
||||
scaleFactor;
|
||||
}
|
||||
|
||||
XrPosef CreateTopPanelFromWorld(const XrVector3f& position)
|
||||
{
|
||||
XrPosef CreateTopPanelFromWorld(const XrVector3f& position) {
|
||||
return XrPosef{XrMath::Quatf::Identity(), position};
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
GameSurfaceLayer::GameSurfaceLayer(const XrVector3f&& position, JNIEnv* env,
|
||||
jobject activityObject,
|
||||
GameSurfaceLayer::GameSurfaceLayer(const XrVector3f&& position, JNIEnv* env, jobject activityObject,
|
||||
const XrSession& session)
|
||||
: session_(session)
|
||||
, topPanelFromWorld_(CreateTopPanelFromWorld(position))
|
||||
, lowerPanelFromWorld_(CreateLowerPanelFromWorld(topPanelFromWorld_))
|
||||
, env_(env)
|
||||
, activityObject_(activityObject)
|
||||
: session_(session), topPanelFromWorld_(CreateTopPanelFromWorld(position)),
|
||||
lowerPanelFromWorld_(CreateLowerPanelFromWorld(topPanelFromWorld_)), env_(env),
|
||||
activityObject_(activityObject)
|
||||
|
||||
{
|
||||
const int32_t initializationStatus =
|
||||
Init(activityObject, position, session);
|
||||
if (initializationStatus < 0)
|
||||
{
|
||||
FAIL("Could not initialize GameSurfaceLayer -- error '%d'",
|
||||
initializationStatus);
|
||||
const int32_t initializationStatus = Init(activityObject, position, session);
|
||||
if (initializationStatus < 0) {
|
||||
FAIL("Could not initialize GameSurfaceLayer -- error '%d'", initializationStatus);
|
||||
}
|
||||
}
|
||||
|
||||
GameSurfaceLayer::~GameSurfaceLayer() { Shutdown(); }
|
||||
|
||||
void GameSurfaceLayer::SetSurface() const
|
||||
{
|
||||
assert(vrGameSurfaceClass_ != nullptr);
|
||||
assert(setSurfaceMethodID_ != nullptr);
|
||||
env_->CallStaticVoidMethod(vrGameSurfaceClass_, setSurfaceMethodID_,
|
||||
activityObject_, surface_);
|
||||
GameSurfaceLayer::~GameSurfaceLayer() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void GameSurfaceLayer::Frame(const XrSpace& space,
|
||||
std::vector<XrCompositionLayer>& layers,
|
||||
uint32_t& layerCount) const
|
||||
void GameSurfaceLayer::SetSurface() const {
|
||||
assert(vrGameSurfaceClass_ != nullptr);
|
||||
assert(setSurfaceMethodID_ != nullptr);
|
||||
env_->CallStaticVoidMethod(vrGameSurfaceClass_, setSurfaceMethodID_, activityObject_, surface_);
|
||||
}
|
||||
|
||||
void GameSurfaceLayer::Frame(const XrSpace& space, std::vector<XrCompositionLayer>& layers,
|
||||
uint32_t& layerCount) const
|
||||
|
||||
{
|
||||
const uint32_t panelWidth = swapchain_.Width / 2;
|
||||
const uint32_t panelWidth = swapchain_.Width / 2;
|
||||
const uint32_t panelHeight = swapchain_.Height / 2;
|
||||
const double aspectRatio =
|
||||
const double aspectRatio =
|
||||
static_cast<double>(2 * panelWidth) / static_cast<double>(panelHeight);
|
||||
// Prevent a seam between the top and bottom view
|
||||
constexpr uint32_t verticalBorderTex = 1;
|
||||
const int32_t useCylinder = GetCylinderSysprop();
|
||||
if (useCylinder == 1)
|
||||
{
|
||||
const int32_t useCylinder = GetCylinderSysprop();
|
||||
if (useCylinder == 1) {
|
||||
|
||||
// Create the Top Display Panel (Curved display)
|
||||
for (uint32_t eye = 0; eye < NUM_EYES; eye++)
|
||||
{
|
||||
for (uint32_t eye = 0; eye < NUM_EYES; eye++) {
|
||||
XrCompositionLayerCylinderKHR layer = {};
|
||||
|
||||
layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR;
|
||||
layer.layerFlags =
|
||||
XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
layer.layerFlags |=
|
||||
XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
|
||||
layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
|
||||
layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
// NOTE: may not want unpremultiplied alpha
|
||||
|
||||
layer.space = space;
|
||||
|
||||
layer.eyeVisibility =
|
||||
eye == 0 ? XR_EYE_VISIBILITY_LEFT : XR_EYE_VISIBILITY_RIGHT;
|
||||
layer.eyeVisibility = eye == 0 ? XR_EYE_VISIBILITY_LEFT : XR_EYE_VISIBILITY_RIGHT;
|
||||
memset(&layer.subImage, 0, sizeof(XrSwapchainSubImage));
|
||||
layer.subImage.swapchain = swapchain_.Handle;
|
||||
layer.subImage.imageRect.offset.x = eye == 0 ? 0 : panelWidth;
|
||||
layer.subImage.imageRect.offset.y = 0;
|
||||
layer.subImage.swapchain = swapchain_.Handle;
|
||||
layer.subImage.imageRect.offset.x = eye == 0 ? 0 : panelWidth;
|
||||
layer.subImage.imageRect.offset.y = 0;
|
||||
layer.subImage.imageRect.extent.width = panelWidth;
|
||||
layer.subImage.imageRect.extent.height =
|
||||
panelHeight - verticalBorderTex;
|
||||
layer.subImage.imageRect.extent.height = panelHeight - verticalBorderTex;
|
||||
layer.subImage.imageArrayIndex = 0;
|
||||
layer.pose = topPanelFromWorld_;
|
||||
layer.pose = topPanelFromWorld_;
|
||||
layer.pose.position.z += GetRadiusSysprop();
|
||||
|
||||
// Radius effectively controls the width of the cylinder shape.
|
||||
|
@ -322,46 +283,37 @@ void GameSurfaceLayer::Frame(const XrSpace& space,
|
|||
// covered by the texture. Together, they control the
|
||||
// scale of the texture.
|
||||
const float radius = GetRadiusSysprop();
|
||||
layer.radius = radius;
|
||||
layer.centralAngle =
|
||||
GetCentralAngleSysprop() * MATH_FLOAT_PI / 180.0f;
|
||||
layer.aspectRatio = -aspectRatio;
|
||||
layer.radius = radius;
|
||||
layer.centralAngle = GetCentralAngleSysprop() * MATH_FLOAT_PI / 180.0f;
|
||||
layer.aspectRatio = -aspectRatio;
|
||||
layers[layerCount++].mCylinder = layer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Create the Top Display Panel (Flat display)
|
||||
for (uint32_t eye = 0; eye < 2; eye++)
|
||||
{
|
||||
for (uint32_t eye = 0; eye < 2; eye++) {
|
||||
XrCompositionLayerQuad layer = {};
|
||||
|
||||
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
|
||||
layer.layerFlags =
|
||||
XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
layer.layerFlags |=
|
||||
XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
|
||||
layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
|
||||
layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
// NOTE: may not want unpremultiplied alpha
|
||||
|
||||
layer.space = space;
|
||||
|
||||
layer.eyeVisibility =
|
||||
eye == 0 ? XR_EYE_VISIBILITY_LEFT : XR_EYE_VISIBILITY_RIGHT;
|
||||
layer.eyeVisibility = eye == 0 ? XR_EYE_VISIBILITY_LEFT : XR_EYE_VISIBILITY_RIGHT;
|
||||
memset(&layer.subImage, 0, sizeof(XrSwapchainSubImage));
|
||||
layer.subImage.swapchain = swapchain_.Handle;
|
||||
layer.subImage.imageRect.offset.x = (eye == 0 ? 0 : panelWidth) + 125;
|
||||
layer.subImage.imageRect.offset.y = 0;
|
||||
layer.subImage.swapchain = swapchain_.Handle;
|
||||
layer.subImage.imageRect.offset.x = (eye == 0 ? 0 : panelWidth) + 125;
|
||||
layer.subImage.imageRect.offset.y = 0;
|
||||
layer.subImage.imageRect.extent.width = panelWidth - 250;
|
||||
layer.subImage.imageRect.extent.height =
|
||||
panelHeight - verticalBorderTex;
|
||||
layer.subImage.imageRect.extent.height = panelHeight - verticalBorderTex;
|
||||
layer.subImage.imageArrayIndex = 0;
|
||||
layer.pose = topPanelFromWorld_;
|
||||
layer.pose = topPanelFromWorld_;
|
||||
// Scale to get the desired density within the visible area (if we
|
||||
// want).
|
||||
const auto scale =
|
||||
GetDensityScaleForSize(panelWidth - 250, -panelHeight, 1.0f);
|
||||
layer.size.width = scale.x;
|
||||
const auto scale = GetDensityScaleForSize(panelWidth - 250, -panelHeight, 1.0f);
|
||||
layer.size.width = scale.x;
|
||||
layer.size.height = scale.y;
|
||||
|
||||
layers[layerCount++].mQuad = layer;
|
||||
|
@ -377,10 +329,9 @@ void GameSurfaceLayer::Frame(const XrSpace& space,
|
|||
{
|
||||
XrCompositionLayerQuad layer = {};
|
||||
|
||||
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
|
||||
layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
|
||||
layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
||||
layer.layerFlags |=
|
||||
XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
|
||||
layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
|
||||
layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
|
||||
// NOTE: may not want unpremultiplied alpha
|
||||
|
||||
|
@ -388,69 +339,61 @@ void GameSurfaceLayer::Frame(const XrSpace& space,
|
|||
|
||||
layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
|
||||
memset(&layer.subImage, 0, sizeof(XrSwapchainSubImage));
|
||||
layer.subImage.swapchain = swapchain_.Handle;
|
||||
layer.subImage.imageRect.offset.x = 225;
|
||||
layer.subImage.imageRect.offset.y = panelHeight + verticalBorderTex;
|
||||
layer.subImage.swapchain = swapchain_.Handle;
|
||||
layer.subImage.imageRect.offset.x = 225;
|
||||
layer.subImage.imageRect.offset.y = panelHeight + verticalBorderTex;
|
||||
layer.subImage.imageRect.extent.width = panelWidth - 450;
|
||||
layer.subImage.imageRect.extent.height = panelHeight;
|
||||
layer.subImage.imageArrayIndex = 0;
|
||||
layer.pose = lowerPanelFromWorld_;
|
||||
const auto scale = GetDensityScaleForSize(panelWidth - 450, -panelHeight,
|
||||
kLowerPanelScaleFactor);
|
||||
layer.size.width = scale.x;
|
||||
layer.subImage.imageArrayIndex = 0;
|
||||
layer.pose = lowerPanelFromWorld_;
|
||||
const auto scale =
|
||||
GetDensityScaleForSize(panelWidth - 450, -panelHeight, kLowerPanelScaleFactor);
|
||||
layer.size.width = scale.x;
|
||||
layer.size.height = scale.y;
|
||||
layers[layerCount++].mQuad = layer;
|
||||
}
|
||||
}
|
||||
|
||||
bool GameSurfaceLayer::GetRayIntersectionWithPanelTopPanel(
|
||||
const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const
|
||||
bool GameSurfaceLayer::GetRayIntersectionWithPanelTopPanel(const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const
|
||||
|
||||
{
|
||||
const uint32_t panelWidth = swapchain_.Width / 2;
|
||||
const uint32_t panelWidth = swapchain_.Width / 2;
|
||||
const uint32_t panelHeight = swapchain_.Height / 2;
|
||||
const auto scale = GetDensityScaleForSize(panelWidth, panelHeight, 1.0f);
|
||||
return ::GetRayIntersectionWithPanel(topPanelFromWorld_, panelWidth,
|
||||
panelHeight, scale, start, end,
|
||||
result2d, result3d);
|
||||
return ::GetRayIntersectionWithPanel(topPanelFromWorld_, panelWidth, panelHeight, scale, start,
|
||||
end, result2d, result3d);
|
||||
}
|
||||
|
||||
bool GameSurfaceLayer::GetRayIntersectionWithPanel(const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const
|
||||
{
|
||||
const uint32_t panelWidth = swapchain_.Width / 2;
|
||||
const uint32_t panelHeight = swapchain_.Height / 2;
|
||||
bool GameSurfaceLayer::GetRayIntersectionWithPanel(const XrVector3f& start, const XrVector3f& end,
|
||||
XrVector2f& result2d, XrPosef& result3d) const {
|
||||
const uint32_t panelWidth = swapchain_.Width / 2;
|
||||
const uint32_t panelHeight = swapchain_.Height / 2;
|
||||
const XrVector2f scale =
|
||||
GetDensityScaleForSize(panelWidth, panelHeight, kLowerPanelScaleFactor);
|
||||
return ::GetRayIntersectionWithPanel(lowerPanelFromWorld_, panelWidth,
|
||||
panelHeight, scale, start, end,
|
||||
result2d, result3d);
|
||||
return ::GetRayIntersectionWithPanel(lowerPanelFromWorld_, panelWidth, panelHeight, scale,
|
||||
start, end, result2d, result3d);
|
||||
}
|
||||
|
||||
void GameSurfaceLayer::SetTopPanelFromController(
|
||||
const XrVector3f& controllerPosition)
|
||||
{
|
||||
void GameSurfaceLayer::SetTopPanelFromController(const XrVector3f& controllerPosition) {
|
||||
|
||||
static const XrVector3f viewerPosition{0, 0, 0}; // Set viewer position
|
||||
const float sphereRadius = XrMath::Vector3f::Length(
|
||||
topPanelFromWorld_.position -
|
||||
viewerPosition); // Set the initial distance of the
|
||||
const float sphereRadius = XrMath::Vector3f::Length(
|
||||
topPanelFromWorld_.position - viewerPosition); // Set the initial distance of the
|
||||
|
||||
// window from the viewer
|
||||
const XrVector3f windowUpDirection{0, 1, 0}; // Y is up
|
||||
|
||||
const XrVector3f windowPosition = CalculatePanelPosition(
|
||||
viewerPosition, controllerPosition, sphereRadius);
|
||||
const XrQuaternionf windowRotation = CalculatePanelRotation(
|
||||
windowPosition, viewerPosition, windowUpDirection);
|
||||
if (windowPosition.y < 0) { return; }
|
||||
if (XrMath::Quatf::GetYawInRadians(windowRotation) > MATH_FLOAT_PI / 3.0f)
|
||||
{
|
||||
const XrVector3f windowPosition =
|
||||
CalculatePanelPosition(viewerPosition, controllerPosition, sphereRadius);
|
||||
const XrQuaternionf windowRotation =
|
||||
CalculatePanelRotation(windowPosition, viewerPosition, windowUpDirection);
|
||||
if (windowPosition.y < 0) {
|
||||
return;
|
||||
}
|
||||
if (XrMath::Quatf::GetYawInRadians(windowRotation) > MATH_FLOAT_PI / 3.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -458,30 +401,24 @@ void GameSurfaceLayer::SetTopPanelFromController(
|
|||
}
|
||||
|
||||
// based on thumbstick, modify the depth of the top panel
|
||||
void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY)
|
||||
{
|
||||
void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) {
|
||||
static constexpr float kDepthSpeed = 0.05f;
|
||||
static constexpr float kMaxDepth = -10.0f;
|
||||
static constexpr float kMaxDepth = -10.0f;
|
||||
|
||||
topPanelFromWorld_.position.z -= (thumbstickY * kDepthSpeed);
|
||||
topPanelFromWorld_.position.z = std::min(topPanelFromWorld_.position.z,
|
||||
lowerPanelFromWorld_.position.z);
|
||||
topPanelFromWorld_.position.z =
|
||||
std::max(topPanelFromWorld_.position.z, kMaxDepth);
|
||||
std::min(topPanelFromWorld_.position.z, lowerPanelFromWorld_.position.z);
|
||||
topPanelFromWorld_.position.z = std::max(topPanelFromWorld_.position.z, kMaxDepth);
|
||||
}
|
||||
|
||||
// Next error code: -2
|
||||
int32_t GameSurfaceLayer::Init(const jobject activityObject,
|
||||
const XrVector3f& position,
|
||||
const XrSession& session)
|
||||
{
|
||||
int32_t GameSurfaceLayer::Init(const jobject activityObject, const XrVector3f& position,
|
||||
const XrSession& session) {
|
||||
|
||||
static const std::string gameSurfaceClassName =
|
||||
"org/citra/citra_emu/vr/GameSurfaceLayer";
|
||||
vrGameSurfaceClass_ = JniUtils::GetGlobalClassReference(
|
||||
env_, activityObject, gameSurfaceClassName);
|
||||
BAIL_ON_COND(vrGameSurfaceClass_ == nullptr,
|
||||
"No java Game Surface Layer class", -1);
|
||||
static const std::string gameSurfaceClassName = "org/citra/citra_emu/vr/GameSurfaceLayer";
|
||||
vrGameSurfaceClass_ =
|
||||
JniUtils::GetGlobalClassReference(env_, activityObject, gameSurfaceClassName);
|
||||
BAIL_ON_COND(vrGameSurfaceClass_ == nullptr, "No java Game Surface Layer class", -1);
|
||||
|
||||
CreateSwapchain();
|
||||
SetSurface();
|
||||
|
@ -489,27 +426,24 @@ int32_t GameSurfaceLayer::Init(const jobject activityObject,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void GameSurfaceLayer::Shutdown()
|
||||
{
|
||||
void GameSurfaceLayer::Shutdown() {
|
||||
xrDestroySwapchain(swapchain_.Handle);
|
||||
// This currently causes a memory exception
|
||||
// env_->DeleteGlobalRef(vrGameSurfaceClass_);
|
||||
}
|
||||
|
||||
void GameSurfaceLayer::CreateSwapchain()
|
||||
{
|
||||
void GameSurfaceLayer::CreateSwapchain() {
|
||||
// Initialize swapchain
|
||||
{
|
||||
XrSwapchainCreateInfo xsci;
|
||||
memset(&xsci, 0, sizeof(xsci));
|
||||
xsci.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
|
||||
xsci.next = nullptr;
|
||||
xsci.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT |
|
||||
XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
xsci.format = 0;
|
||||
xsci.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
|
||||
xsci.next = nullptr;
|
||||
xsci.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
xsci.format = 0;
|
||||
xsci.sampleCount = 0;
|
||||
xsci.width = SURFACE_WIDTH;
|
||||
xsci.height = SURFACE_HEIGHT;
|
||||
xsci.width = SURFACE_WIDTH;
|
||||
xsci.height = SURFACE_HEIGHT;
|
||||
|
||||
xsci.faceCount = 0;
|
||||
xsci.arraySize = 0;
|
||||
|
@ -518,27 +452,25 @@ void GameSurfaceLayer::CreateSwapchain()
|
|||
// so that you do not need them.
|
||||
xsci.mipCount = 0;
|
||||
|
||||
PFN_xrCreateSwapchainAndroidSurfaceKHR
|
||||
pfnCreateSwapchainAndroidSurfaceKHR = nullptr;
|
||||
PFN_xrCreateSwapchainAndroidSurfaceKHR pfnCreateSwapchainAndroidSurfaceKHR = nullptr;
|
||||
assert(OpenXr::GetInstance() != XR_NULL_HANDLE);
|
||||
XrResult xrResult = xrGetInstanceProcAddr(
|
||||
OpenXr::GetInstance(), "xrCreateSwapchainAndroidSurfaceKHR",
|
||||
(PFN_xrVoidFunction*)(&pfnCreateSwapchainAndroidSurfaceKHR));
|
||||
if (xrResult != XR_SUCCESS ||
|
||||
pfnCreateSwapchainAndroidSurfaceKHR == nullptr)
|
||||
{
|
||||
XrResult xrResult =
|
||||
xrGetInstanceProcAddr(OpenXr::GetInstance(), "xrCreateSwapchainAndroidSurfaceKHR",
|
||||
(PFN_xrVoidFunction*)(&pfnCreateSwapchainAndroidSurfaceKHR));
|
||||
if (xrResult != XR_SUCCESS || pfnCreateSwapchainAndroidSurfaceKHR == nullptr) {
|
||||
FAIL("xrGetInstanceProcAddr failed for "
|
||||
"xrCreateSwapchainAndroidSurfaceKHR");
|
||||
}
|
||||
|
||||
OXR(pfnCreateSwapchainAndroidSurfaceKHR(session_, &xsci,
|
||||
&swapchain_.Handle, &surface_));
|
||||
swapchain_.Width = xsci.width;
|
||||
OXR(pfnCreateSwapchainAndroidSurfaceKHR(session_, &xsci, &swapchain_.Handle, &surface_));
|
||||
swapchain_.Width = xsci.width;
|
||||
swapchain_.Height = xsci.height;
|
||||
}
|
||||
|
||||
setSurfaceMethodID_ = env_->GetStaticMethodID(
|
||||
vrGameSurfaceClass_, "setSurface",
|
||||
"(Lorg/citra/citra_emu/vr/VrActivity;Landroid/view/Surface;)V");
|
||||
if (setSurfaceMethodID_ == nullptr) { FAIL("Couldn't find setSurface()"); }
|
||||
setSurfaceMethodID_ =
|
||||
env_->GetStaticMethodID(vrGameSurfaceClass_, "setSurface",
|
||||
"(Lorg/citra/citra_emu/vr/VrActivity;Landroid/view/Surface;)V");
|
||||
if (setSurfaceMethodID_ == nullptr) {
|
||||
FAIL("Couldn't find setSurface()");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,10 +52,10 @@ License : Licensed under GPLv2 or any later version.
|
|||
*******************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "../../../../../../core/3ds.h" // for 3ds screen sizes.
|
||||
#include "OpenXR.h"
|
||||
#include "Swapchain.h"
|
||||
#include "utils/Common.h"
|
||||
#include "../../../../../../core/3ds.h" // for 3ds screen sizes.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
|
@ -69,16 +69,14 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
================================================================================
|
||||
*/
|
||||
class GameSurfaceLayer
|
||||
{
|
||||
class GameSurfaceLayer {
|
||||
|
||||
public:
|
||||
// Density scale for surface. Citra's auto-scale sets this as the internal
|
||||
// resolution.
|
||||
static constexpr uint32_t SCALE_FACTOR = 5;
|
||||
static constexpr float DEFAULT_QUAD_DENSITY =
|
||||
240 * static_cast<float>(SCALE_FACTOR);
|
||||
static constexpr float DEFAULT_CYLINDER_RADIUS = 2.0f;
|
||||
static constexpr float DEFAULT_QUAD_DENSITY = 240 * static_cast<float>(SCALE_FACTOR);
|
||||
static constexpr float DEFAULT_CYLINDER_RADIUS = 2.0f;
|
||||
static constexpr float DEFAULT_CYLINDER_CENTRAL_ANGLE_DEGREES = 55.0f;
|
||||
|
||||
/** Constructor.
|
||||
|
@ -87,8 +85,8 @@ public:
|
|||
* the class information for gameSurfaceClass
|
||||
* @param session a valid XrSession
|
||||
*/
|
||||
GameSurfaceLayer(const XrVector3f&& position, JNIEnv* jni,
|
||||
jobject activityObject, const XrSession& session);
|
||||
GameSurfaceLayer(const XrVector3f&& position, JNIEnv* jni, jobject activityObject,
|
||||
const XrSession& session);
|
||||
~GameSurfaceLayer();
|
||||
|
||||
/** Called on resume. Sets the surface in the native rendering library.
|
||||
|
@ -126,21 +124,16 @@ public:
|
|||
*
|
||||
* Note: assumes viewer is looking down the -Z axis.
|
||||
*/
|
||||
bool GetRayIntersectionWithPanel(const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const;
|
||||
bool GetRayIntersectionWithPanelTopPanel(const XrVector3f& start,
|
||||
const XrVector3f& end,
|
||||
XrVector2f& result2d,
|
||||
XrPosef& result3d) const;
|
||||
bool GetRayIntersectionWithPanel(const XrVector3f& start, const XrVector3f& end,
|
||||
XrVector2f& result2d, XrPosef& result3d) const;
|
||||
bool GetRayIntersectionWithPanelTopPanel(const XrVector3f& start, const XrVector3f& end,
|
||||
XrVector2f& result2d, XrPosef& result3d) const;
|
||||
void SetTopPanelFromController(const XrVector3f& controllerPosition);
|
||||
|
||||
void SetTopPanelFromThumbstick(const float thumbstickY);
|
||||
|
||||
private:
|
||||
int Init(const jobject activityObject, const XrVector3f& position,
|
||||
const XrSession& session);
|
||||
int Init(const jobject activityObject, const XrVector3f& position, const XrSession& session);
|
||||
void Shutdown();
|
||||
|
||||
/** Creates the swapchain.
|
||||
|
@ -148,31 +141,29 @@ private:
|
|||
void CreateSwapchain();
|
||||
|
||||
static constexpr uint32_t SURFACE_WIDTH =
|
||||
(NUM_EYES * std::max(Core::kScreenTopWidth, Core::kScreenBottomWidth) *
|
||||
SCALE_FACTOR) - 1500;
|
||||
(NUM_EYES * std::max(Core::kScreenTopWidth, Core::kScreenBottomWidth) * SCALE_FACTOR) -
|
||||
1500;
|
||||
static constexpr uint32_t SURFACE_HEIGHT =
|
||||
(Core::kScreenTopHeight + Core::kScreenBottomHeight) * SCALE_FACTOR;
|
||||
|
||||
// Width and height should both be even numbers, as the swapchain will
|
||||
// be split twice: once (horizontally) for stereo views, and once
|
||||
// (vertically) for the upper/lower screen.
|
||||
static_assert((SURFACE_WIDTH % 2) == 0,
|
||||
"Swapchain width must be a multiple of 2");
|
||||
static_assert((SURFACE_HEIGHT % 2) == 0,
|
||||
"Swapchain height must be a multiple of 2");
|
||||
static_assert((SURFACE_WIDTH % 2) == 0, "Swapchain width must be a multiple of 2");
|
||||
static_assert((SURFACE_HEIGHT % 2) == 0, "Swapchain height must be a multiple of 2");
|
||||
|
||||
const XrSession session_;
|
||||
Swapchain swapchain_;
|
||||
Swapchain swapchain_;
|
||||
|
||||
XrPosef topPanelFromWorld_;
|
||||
XrPosef lowerPanelFromWorld_;
|
||||
|
||||
//============================
|
||||
// JNI objects
|
||||
JNIEnv* env_ = nullptr;
|
||||
jobject activityObject_ = nullptr;
|
||||
jclass vrGameSurfaceClass_ = nullptr;
|
||||
jobject surface_ = nullptr;
|
||||
JNIEnv* env_ = nullptr;
|
||||
jobject activityObject_ = nullptr;
|
||||
jclass vrGameSurfaceClass_ = nullptr;
|
||||
jobject surface_ = nullptr;
|
||||
|
||||
//============================
|
||||
// JNI methods
|
||||
|
|
|
@ -20,28 +20,25 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#define BAIL_ON_ERR(fn, returnCode) \
|
||||
do { \
|
||||
const int32_t ret = fn; \
|
||||
if (ret < 0) \
|
||||
{ \
|
||||
ALOGE("ERROR (%s): %s() returned %d", __FUNCTION__, #fn, ret); \
|
||||
return (returnCode); \
|
||||
} \
|
||||
#define BAIL_ON_ERR(fn, returnCode) \
|
||||
do { \
|
||||
const int32_t ret = fn; \
|
||||
if (ret < 0) { \
|
||||
ALOGE("ERROR (%s): %s() returned %d", __FUNCTION__, #fn, ret); \
|
||||
return (returnCode); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
XrInstance instance;
|
||||
void OXR_CheckErrors(XrResult result, const char* function, bool failOnError)
|
||||
{
|
||||
if (XR_FAILED(result))
|
||||
{
|
||||
void OXR_CheckErrors(XrResult result, const char* function, bool failOnError) {
|
||||
if (XR_FAILED(result)) {
|
||||
char errorBuffer[XR_MAX_RESULT_STRING_SIZE];
|
||||
xrResultToString(instance, result, errorBuffer);
|
||||
if (failOnError)
|
||||
{
|
||||
if (failOnError) {
|
||||
FAIL("OpenXR error: %s: %s\n", function, errorBuffer);
|
||||
} else {
|
||||
ALOGV("OpenXR error: %s: %s\n", function, errorBuffer);
|
||||
}
|
||||
else { ALOGV("OpenXR error: %s: %s\n", function, errorBuffer); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,35 +49,29 @@ void OXR_CheckErrors(XrResult result, const char* function, bool failOnError)
|
|||
|
||||
================================================================================
|
||||
*/
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
#define DECL_PFN(pfn) PFN_##pfn pfn = nullptr
|
||||
#define INIT_PFN(pfn) \
|
||||
OXR(xrGetInstanceProcAddr(instance, #pfn, (PFN_xrVoidFunction*)(&pfn)))
|
||||
#define INIT_PFN(pfn) OXR(xrGetInstanceProcAddr(instance, #pfn, (PFN_xrVoidFunction*)(&pfn)))
|
||||
|
||||
DECL_PFN(xrEnumerateDisplayRefreshRatesFB);
|
||||
DECL_PFN(xrRequestDisplayRefreshRateFB);
|
||||
|
||||
void InitOXRFunctions(const XrInstance xrInstance)
|
||||
{
|
||||
void InitOXRFunctions(const XrInstance xrInstance) {
|
||||
assert(xrInstance != XR_NULL_HANDLE);
|
||||
INIT_PFN(xrEnumerateDisplayRefreshRatesFB);
|
||||
INIT_PFN(xrRequestDisplayRefreshRateFB);
|
||||
}
|
||||
|
||||
[[maybe_unused]] void XrEnumerateLayerProperties()
|
||||
{
|
||||
XrResult result;
|
||||
[[maybe_unused]] void XrEnumerateLayerProperties() {
|
||||
XrResult result;
|
||||
PFN_xrEnumerateApiLayerProperties xrEnumerateApiLayerProperties;
|
||||
OXR(result = xrGetInstanceProcAddr(
|
||||
XR_NULL_HANDLE, "xrEnumerateApiLayerProperties",
|
||||
(PFN_xrVoidFunction*)&xrEnumerateApiLayerProperties));
|
||||
if (result != XR_SUCCESS)
|
||||
{
|
||||
OXR(result = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrEnumerateApiLayerProperties",
|
||||
(PFN_xrVoidFunction*)&xrEnumerateApiLayerProperties));
|
||||
if (result != XR_SUCCESS) {
|
||||
FAIL("Failed to get xrEnumerateApiLayerProperties function pointer.");
|
||||
}
|
||||
|
||||
uint32_t numInputLayers = 0;
|
||||
uint32_t numInputLayers = 0;
|
||||
uint32_t numOutputLayers = 0;
|
||||
OXR(xrEnumerateApiLayerProperties(numInputLayers, &numOutputLayers, NULL));
|
||||
|
||||
|
@ -88,25 +79,21 @@ void InitOXRFunctions(const XrInstance xrInstance)
|
|||
|
||||
auto layerProperties = std::vector<XrApiLayerProperties>(numOutputLayers);
|
||||
|
||||
for (auto& lp : layerProperties)
|
||||
{
|
||||
for (auto& lp : layerProperties) {
|
||||
lp.type = XR_TYPE_API_LAYER_PROPERTIES;
|
||||
lp.next = NULL;
|
||||
}
|
||||
|
||||
OXR(xrEnumerateApiLayerProperties(numInputLayers, &numOutputLayers,
|
||||
layerProperties.data()));
|
||||
OXR(xrEnumerateApiLayerProperties(numInputLayers, &numOutputLayers, layerProperties.data()));
|
||||
|
||||
for (uint32_t i = 0; i < numOutputLayers; i++)
|
||||
{
|
||||
for (uint32_t i = 0; i < numOutputLayers; i++) {
|
||||
ALOGI("Found layer %s", layerProperties[i].layerName);
|
||||
}
|
||||
}
|
||||
|
||||
// Next return code: -3
|
||||
int XrCheckRequiredExtensions(const char* const* requiredExtensionNames,
|
||||
const size_t numRequiredExtensions)
|
||||
{
|
||||
const size_t numRequiredExtensions) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
XrEnumerateLayerProperties();
|
||||
|
@ -116,65 +103,50 @@ int XrCheckRequiredExtensions(const char* const* requiredExtensionNames,
|
|||
// runtime.
|
||||
{
|
||||
XrResult result;
|
||||
PFN_xrEnumerateInstanceExtensionProperties
|
||||
xrEnumerateInstanceExtensionProperties;
|
||||
PFN_xrEnumerateInstanceExtensionProperties xrEnumerateInstanceExtensionProperties;
|
||||
OXR(result = xrGetInstanceProcAddr(
|
||||
XR_NULL_HANDLE, "xrEnumerateInstanceExtensionProperties",
|
||||
(PFN_xrVoidFunction*)&xrEnumerateInstanceExtensionProperties));
|
||||
if (result != XR_SUCCESS)
|
||||
{
|
||||
if (result != XR_SUCCESS) {
|
||||
ALOGE("Failed to get xrEnumerateInstanceExtensionProperties "
|
||||
"function pointer.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t numInputExtensions = 0;
|
||||
uint32_t numInputExtensions = 0;
|
||||
uint32_t numOutputExtensions = 0;
|
||||
OXR(xrEnumerateInstanceExtensionProperties(NULL, numInputExtensions,
|
||||
&numOutputExtensions, NULL));
|
||||
ALOGV("xrEnumerateInstanceExtensionProperties found %u extension(s).",
|
||||
numOutputExtensions);
|
||||
OXR(xrEnumerateInstanceExtensionProperties(NULL, numInputExtensions, &numOutputExtensions,
|
||||
NULL));
|
||||
ALOGV("xrEnumerateInstanceExtensionProperties found %u extension(s).", numOutputExtensions);
|
||||
|
||||
numInputExtensions = numOutputExtensions;
|
||||
|
||||
auto extensionProperties =
|
||||
std::vector<XrExtensionProperties>(numOutputExtensions);
|
||||
auto extensionProperties = std::vector<XrExtensionProperties>(numOutputExtensions);
|
||||
|
||||
for (auto& ext : extensionProperties)
|
||||
{
|
||||
for (auto& ext : extensionProperties) {
|
||||
ext.type = XR_TYPE_EXTENSION_PROPERTIES;
|
||||
ext.next = NULL;
|
||||
}
|
||||
|
||||
OXR(xrEnumerateInstanceExtensionProperties(NULL, numInputExtensions,
|
||||
&numOutputExtensions,
|
||||
OXR(xrEnumerateInstanceExtensionProperties(NULL, numInputExtensions, &numOutputExtensions,
|
||||
extensionProperties.data()));
|
||||
#ifndef NDEBUG
|
||||
for (uint32_t i = 0; i < numOutputExtensions; i++)
|
||||
{
|
||||
ALOGV("Extension #%d = '%s'.", i,
|
||||
extensionProperties[i].extensionName);
|
||||
for (uint32_t i = 0; i < numOutputExtensions; i++) {
|
||||
ALOGV("Extension #%d = '%s'.", i, extensionProperties[i].extensionName);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (uint32_t i = 0; i < numRequiredExtensions; i++)
|
||||
{
|
||||
for (uint32_t i = 0; i < numRequiredExtensions; i++) {
|
||||
bool found = false;
|
||||
for (uint32_t j = 0; j < numOutputExtensions; j++)
|
||||
{
|
||||
if (!strcmp(requiredExtensionNames[i],
|
||||
extensionProperties[j].extensionName))
|
||||
{
|
||||
ALOGD("Found required extension %s",
|
||||
requiredExtensionNames[i]);
|
||||
for (uint32_t j = 0; j < numOutputExtensions; j++) {
|
||||
if (!strcmp(requiredExtensionNames[i], extensionProperties[j].extensionName)) {
|
||||
ALOGD("Found required extension %s", requiredExtensionNames[i]);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
ALOGE("Failed to find required extension %s",
|
||||
requiredExtensionNames[i]);
|
||||
if (!found) {
|
||||
ALOGE("Failed to find required extension %s", requiredExtensionNames[i]);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
@ -182,8 +154,7 @@ int XrCheckRequiredExtensions(const char* const* requiredExtensionNames,
|
|||
return 0;
|
||||
}
|
||||
|
||||
XrInstance XrInstanceCreate()
|
||||
{
|
||||
XrInstance XrInstanceCreate() {
|
||||
// Check that the extensions required are present.
|
||||
static const char* const requiredExtensionNames[] = {
|
||||
XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME,
|
||||
|
@ -199,8 +170,7 @@ XrInstance XrInstanceCreate()
|
|||
static constexpr size_t numRequiredExtensions =
|
||||
sizeof(requiredExtensionNames) / sizeof(requiredExtensionNames[0]);
|
||||
|
||||
BAIL_ON_ERR(XrCheckRequiredExtensions(&requiredExtensionNames[0],
|
||||
numRequiredExtensions),
|
||||
BAIL_ON_ERR(XrCheckRequiredExtensions(&requiredExtensionNames[0], numRequiredExtensions),
|
||||
XR_NULL_HANDLE);
|
||||
|
||||
XrApplicationInfo appInfo = {};
|
||||
|
@ -208,25 +178,23 @@ XrInstance XrInstanceCreate()
|
|||
appInfo.applicationVersion = 0;
|
||||
strcpy(appInfo.engineName, "custom");
|
||||
appInfo.engineVersion = 0;
|
||||
appInfo.apiVersion = XR_CURRENT_API_VERSION;
|
||||
appInfo.apiVersion = XR_CURRENT_API_VERSION;
|
||||
|
||||
XrInstanceCreateInfo ici = {};
|
||||
ici.type = XR_TYPE_INSTANCE_CREATE_INFO;
|
||||
ici.next = nullptr;
|
||||
ici.createFlags = 0;
|
||||
ici.applicationInfo = appInfo;
|
||||
ici.enabledApiLayerCount = 0;
|
||||
ici.enabledApiLayerNames = NULL;
|
||||
XrInstanceCreateInfo ici = {};
|
||||
ici.type = XR_TYPE_INSTANCE_CREATE_INFO;
|
||||
ici.next = nullptr;
|
||||
ici.createFlags = 0;
|
||||
ici.applicationInfo = appInfo;
|
||||
ici.enabledApiLayerCount = 0;
|
||||
ici.enabledApiLayerNames = NULL;
|
||||
ici.enabledExtensionCount = numRequiredExtensions;
|
||||
ici.enabledExtensionNames = requiredExtensionNames;
|
||||
|
||||
XrResult initResult;
|
||||
XrResult initResult;
|
||||
XrInstance instanceLocal;
|
||||
OXR(initResult = xrCreateInstance(&ici, &instanceLocal));
|
||||
if (initResult != XR_SUCCESS)
|
||||
{
|
||||
ALOGE("ERROR(%s()): Failed to create XR instance_: %d.", __FUNCTION__,
|
||||
initResult);
|
||||
if (initResult != XR_SUCCESS) {
|
||||
ALOGE("ERROR(%s()): Failed to create XR instance_: %d.", __FUNCTION__, initResult);
|
||||
return XR_NULL_HANDLE;
|
||||
}
|
||||
// Log runtime instance info
|
||||
|
@ -244,73 +212,61 @@ XrInstance XrInstanceCreate()
|
|||
}
|
||||
|
||||
// Next return code: -2
|
||||
int32_t XrInitializeLoaderTrampoline(JavaVM* jvm, jobject activityObject)
|
||||
{
|
||||
int32_t XrInitializeLoaderTrampoline(JavaVM* jvm, jobject activityObject) {
|
||||
PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
|
||||
xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR",
|
||||
(PFN_xrVoidFunction*)&xrInitializeLoaderKHR);
|
||||
if (xrInitializeLoaderKHR != nullptr)
|
||||
{
|
||||
if (xrInitializeLoaderKHR != nullptr) {
|
||||
XrLoaderInitInfoAndroidKHR loaderInitializeInfoAndroid;
|
||||
memset(&loaderInitializeInfoAndroid, 0,
|
||||
sizeof(loaderInitializeInfoAndroid));
|
||||
memset(&loaderInitializeInfoAndroid, 0, sizeof(loaderInitializeInfoAndroid));
|
||||
loaderInitializeInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR;
|
||||
loaderInitializeInfoAndroid.next = NULL;
|
||||
loaderInitializeInfoAndroid.applicationVM = jvm;
|
||||
loaderInitializeInfoAndroid.applicationVM = jvm;
|
||||
loaderInitializeInfoAndroid.applicationContext = activityObject;
|
||||
xrInitializeLoaderKHR(
|
||||
(XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid);
|
||||
}
|
||||
else
|
||||
{
|
||||
xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid);
|
||||
} else {
|
||||
ALOGE("%s(): xrInitializeLoaderKHR is NULL", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
XrSession XrSessionCreate(const XrInstance& localInstance,
|
||||
const XrSystemId& systemId,
|
||||
const std::unique_ptr<EglContext>& egl)
|
||||
{
|
||||
XrSession XrSessionCreate(const XrInstance& localInstance, const XrSystemId& systemId,
|
||||
const std::unique_ptr<EglContext>& egl) {
|
||||
XrGraphicsBindingOpenGLESAndroidKHR graphicsBinding = {};
|
||||
graphicsBinding.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
|
||||
graphicsBinding.next = NULL;
|
||||
graphicsBinding.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
|
||||
graphicsBinding.next = NULL;
|
||||
graphicsBinding.display = egl->mDisplay;
|
||||
graphicsBinding.config = egl->mConfig;
|
||||
graphicsBinding.config = egl->mConfig;
|
||||
graphicsBinding.context = egl->mContext;
|
||||
|
||||
XrSessionCreateInfo sessionCreateInfo = {};
|
||||
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
|
||||
sessionCreateInfo.next = &graphicsBinding;
|
||||
sessionCreateInfo.createFlags = 0;
|
||||
sessionCreateInfo.systemId = systemId;
|
||||
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
|
||||
sessionCreateInfo.next = &graphicsBinding;
|
||||
sessionCreateInfo.createFlags = 0;
|
||||
sessionCreateInfo.systemId = systemId;
|
||||
|
||||
XrSession session;
|
||||
XrResult initResult;
|
||||
OXR(initResult =
|
||||
xrCreateSession(localInstance, &sessionCreateInfo, &session));
|
||||
if (initResult != XR_SUCCESS)
|
||||
{
|
||||
XrResult initResult;
|
||||
OXR(initResult = xrCreateSession(localInstance, &sessionCreateInfo, &session));
|
||||
if (initResult != XR_SUCCESS) {
|
||||
ALOGE("Failed to create XR session: %d.", initResult);
|
||||
return XR_NULL_HANDLE;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
XrSystemId XrGetSystemId(const XrInstance& instanceLocal)
|
||||
{
|
||||
XrSystemId XrGetSystemId(const XrInstance& instanceLocal) {
|
||||
XrSystemId systemId = XR_NULL_SYSTEM_ID;
|
||||
|
||||
XrSystemGetInfo sgi = {};
|
||||
sgi.type = XR_TYPE_SYSTEM_GET_INFO;
|
||||
sgi.next = NULL;
|
||||
sgi.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||
sgi.type = XR_TYPE_SYSTEM_GET_INFO;
|
||||
sgi.next = NULL;
|
||||
sgi.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||
|
||||
XrResult initResult;
|
||||
OXR(initResult = xrGetSystem(instanceLocal, &sgi, &systemId));
|
||||
if (initResult != XR_SUCCESS)
|
||||
{
|
||||
if (initResult != XR_SUCCESS) {
|
||||
ALOGE("ERROR (%s()): Failed to get system.", __FUNCTION__);
|
||||
return XR_NULL_SYSTEM_ID;
|
||||
}
|
||||
|
@ -319,38 +275,35 @@ XrSystemId XrGetSystemId(const XrInstance& instanceLocal)
|
|||
|
||||
// TODO give users a choice, since the highest refresh rate also drains battery
|
||||
// life.
|
||||
void SetHighestRefreshRate(const XrSession& session)
|
||||
{
|
||||
void SetHighestRefreshRate(const XrSession& session) {
|
||||
// attempts to set desired refresh rate. If not available, sets highest
|
||||
// refresh rate.
|
||||
static constexpr float desiredRefreshRate = 90.0f;
|
||||
// Enumerate refresh rates
|
||||
uint32_t numRefreshRates = 0;
|
||||
OXR(xrEnumerateDisplayRefreshRatesFB(session, 0, &numRefreshRates,
|
||||
nullptr));
|
||||
OXR(xrEnumerateDisplayRefreshRatesFB(session, 0, &numRefreshRates, nullptr));
|
||||
std::vector<float> availableRefreshRates(numRefreshRates);
|
||||
OXR(xrEnumerateDisplayRefreshRatesFB(session, availableRefreshRates.size(),
|
||||
&numRefreshRates,
|
||||
OXR(xrEnumerateDisplayRefreshRatesFB(session, availableRefreshRates.size(), &numRefreshRates,
|
||||
availableRefreshRates.data()));
|
||||
assert((size_t)numRefreshRates == availableRefreshRates.size());
|
||||
bool hasDesiredRefreshRate = false;
|
||||
float maxRefreshRate = 0;
|
||||
for (auto r : availableRefreshRates)
|
||||
{
|
||||
if (r == desiredRefreshRate) { hasDesiredRefreshRate = true; }
|
||||
if (r > maxRefreshRate) { maxRefreshRate = r; }
|
||||
bool hasDesiredRefreshRate = false;
|
||||
float maxRefreshRate = 0;
|
||||
for (auto r : availableRefreshRates) {
|
||||
if (r == desiredRefreshRate) {
|
||||
hasDesiredRefreshRate = true;
|
||||
}
|
||||
if (r > maxRefreshRate) {
|
||||
maxRefreshRate = r;
|
||||
}
|
||||
}
|
||||
const float refreshRate =
|
||||
hasDesiredRefreshRate ? desiredRefreshRate : maxRefreshRate;
|
||||
const float refreshRate = hasDesiredRefreshRate ? desiredRefreshRate : maxRefreshRate;
|
||||
ALOGI("Setting max refresh rate %.1fHz", refreshRate);
|
||||
OXR(xrRequestDisplayRefreshRateFB(session, refreshRate));
|
||||
}
|
||||
|
||||
size_t GetMaxLayerCount(const XrInstance& instanceLocal,
|
||||
const XrSystemId& systemId)
|
||||
{
|
||||
size_t GetMaxLayerCount(const XrInstance& instanceLocal, const XrSystemId& systemId) {
|
||||
XrSystemProperties systemProperties = {};
|
||||
systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
|
||||
systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
|
||||
OXR(xrGetSystemProperties(instanceLocal, systemId, &systemProperties));
|
||||
|
||||
ALOGV("System Properties: Name=%s VendorId=%x", systemProperties.systemName,
|
||||
|
@ -361,21 +314,22 @@ size_t GetMaxLayerCount(const XrInstance& instanceLocal,
|
|||
systemProperties.graphicsProperties.maxLayerCount);
|
||||
ALOGV("System Tracking Properties: OrientationTracking=%s "
|
||||
"PositionTracking=%s",
|
||||
systemProperties.trackingProperties.orientationTracking ? "True"
|
||||
: "False",
|
||||
systemProperties.trackingProperties.positionTracking ? "True"
|
||||
: "False");
|
||||
systemProperties.trackingProperties.orientationTracking ? "True" : "False",
|
||||
systemProperties.trackingProperties.positionTracking ? "True" : "False");
|
||||
|
||||
return systemProperties.graphicsProperties.maxLayerCount;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
XrInstance& OpenXr::GetInstance() { return instance; }
|
||||
XrInstance& OpenXr::GetInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
int32_t OpenXr::Init(JavaVM* const jvm, const jobject activityObject)
|
||||
{
|
||||
for (int eye = 0; eye < 2; eye++) { viewConfigurationViews_[eye] = {}; }
|
||||
int32_t OpenXr::Init(JavaVM* const jvm, const jobject activityObject) {
|
||||
for (int eye = 0; eye < 2; eye++) {
|
||||
viewConfigurationViews_[eye] = {};
|
||||
}
|
||||
BAIL_ON_ERR(OpenXRInit(jvm, activityObject), -1);
|
||||
BAIL_ON_ERR(XrViewConfigInit(), -2);
|
||||
BAIL_ON_ERR(XrSpaceInit(), -3);
|
||||
|
@ -384,69 +338,56 @@ int32_t OpenXr::Init(JavaVM* const jvm, const jobject activityObject)
|
|||
}
|
||||
|
||||
// Next return code: -2
|
||||
int32_t OpenXr::XrViewConfigInit()
|
||||
{
|
||||
int32_t OpenXr::XrViewConfigInit() {
|
||||
// Enumerate the viewport configurations.
|
||||
uint32_t viewportConfigTypeCount = 0;
|
||||
OXR(xrEnumerateViewConfigurations(instance_, systemId_, 0,
|
||||
&viewportConfigTypeCount, NULL));
|
||||
OXR(xrEnumerateViewConfigurations(instance_, systemId_, 0, &viewportConfigTypeCount, NULL));
|
||||
|
||||
auto viewportConfigurationTypes =
|
||||
std::vector<XrViewConfigurationType>(viewportConfigTypeCount);
|
||||
auto viewportConfigurationTypes = std::vector<XrViewConfigurationType>(viewportConfigTypeCount);
|
||||
|
||||
OXR(xrEnumerateViewConfigurations(
|
||||
instance_, systemId_, viewportConfigTypeCount, &viewportConfigTypeCount,
|
||||
viewportConfigurationTypes.data()));
|
||||
OXR(xrEnumerateViewConfigurations(instance_, systemId_, viewportConfigTypeCount,
|
||||
&viewportConfigTypeCount, viewportConfigurationTypes.data()));
|
||||
|
||||
ALOGV("Available Viewport Configuration Types: %d",
|
||||
viewportConfigTypeCount);
|
||||
ALOGV("Available Viewport Configuration Types: %d", viewportConfigTypeCount);
|
||||
|
||||
bool foundSupportedViewport;
|
||||
for (uint32_t i = 0; i < viewportConfigTypeCount; i++)
|
||||
{
|
||||
const XrViewConfigurationType viewportConfigType =
|
||||
viewportConfigurationTypes[i];
|
||||
for (uint32_t i = 0; i < viewportConfigTypeCount; i++) {
|
||||
const XrViewConfigurationType viewportConfigType = viewportConfigurationTypes[i];
|
||||
|
||||
ALOGV("Viewport configuration type %d : %s", viewportConfigType,
|
||||
viewportConfigType == VIEW_CONFIG_TYPE ? "Selected" : "");
|
||||
|
||||
XrViewConfigurationProperties viewportConfig;
|
||||
viewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
|
||||
OXR(xrGetViewConfigurationProperties(
|
||||
instance_, systemId_, viewportConfigType, &viewportConfig));
|
||||
ALOGV("FovMutable=%s ConfigurationType %d",
|
||||
viewportConfig.fovMutable ? "true" : "false",
|
||||
OXR(xrGetViewConfigurationProperties(instance_, systemId_, viewportConfigType,
|
||||
&viewportConfig));
|
||||
ALOGV("FovMutable=%s ConfigurationType %d", viewportConfig.fovMutable ? "true" : "false",
|
||||
viewportConfig.viewConfigurationType);
|
||||
|
||||
uint32_t viewCount;
|
||||
OXR(xrEnumerateViewConfigurationViews(
|
||||
instance_, systemId_, viewportConfigType, 0, &viewCount, NULL));
|
||||
OXR(xrEnumerateViewConfigurationViews(instance_, systemId_, viewportConfigType, 0,
|
||||
&viewCount, NULL));
|
||||
|
||||
if (viewCount > 0)
|
||||
{
|
||||
if (viewCount > 0) {
|
||||
auto elements = std::vector<XrViewConfigurationView>(viewCount);
|
||||
|
||||
for (uint32_t e = 0; e < viewCount; e++)
|
||||
{
|
||||
for (uint32_t e = 0; e < viewCount; e++) {
|
||||
elements[e].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
|
||||
elements[e].next = NULL;
|
||||
}
|
||||
|
||||
OXR(xrEnumerateViewConfigurationViews(instance_, systemId_,
|
||||
viewportConfigType, viewCount,
|
||||
&viewCount, elements.data()));
|
||||
OXR(xrEnumerateViewConfigurationViews(instance_, systemId_, viewportConfigType,
|
||||
viewCount, &viewCount, elements.data()));
|
||||
|
||||
// Log the view config info for each view type for debugging
|
||||
// purposes.
|
||||
for (uint32_t e = 0; e < viewCount; e++)
|
||||
{
|
||||
for (uint32_t e = 0; e < viewCount; e++) {
|
||||
const XrViewConfigurationView* element = &elements[e];
|
||||
(void)element;
|
||||
|
||||
ALOGV("Viewport [%d]: Recommended Width=%d Height=%d "
|
||||
"SampleCount=%d",
|
||||
e, element->recommendedImageRectWidth,
|
||||
element->recommendedImageRectHeight,
|
||||
e, element->recommendedImageRectWidth, element->recommendedImageRectHeight,
|
||||
element->recommendedSwapchainSampleCount);
|
||||
|
||||
ALOGV("Viewport [%d]: Max Width=%d Height=%d SampleCount=%d", e,
|
||||
|
@ -455,20 +396,18 @@ int32_t OpenXr::XrViewConfigInit()
|
|||
}
|
||||
|
||||
// Cache the view config properties for the selected config type.
|
||||
if (viewportConfigType == VIEW_CONFIG_TYPE)
|
||||
{
|
||||
if (viewportConfigType == VIEW_CONFIG_TYPE) {
|
||||
foundSupportedViewport = true;
|
||||
assert(viewCount == NUM_EYES);
|
||||
for (uint32_t e = 0; e < viewCount; e++)
|
||||
{
|
||||
for (uint32_t e = 0; e < viewCount; e++) {
|
||||
viewConfigurationViews_[e] = elements[e];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ALOGD("Empty viewport configuration type: %d", viewCount);
|
||||
}
|
||||
else { ALOGD("Empty viewport configuration type: %d", viewCount); }
|
||||
}
|
||||
if (!foundSupportedViewport)
|
||||
{
|
||||
if (!foundSupportedViewport) {
|
||||
ALOGE("No supported viewport found");
|
||||
return -1;
|
||||
}
|
||||
|
@ -477,13 +416,11 @@ int32_t OpenXr::XrViewConfigInit()
|
|||
// type.
|
||||
viewportConfig_.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
|
||||
|
||||
OXR(xrGetViewConfigurationProperties(instance_, systemId_, VIEW_CONFIG_TYPE,
|
||||
&viewportConfig_));
|
||||
OXR(xrGetViewConfigurationProperties(instance_, systemId_, VIEW_CONFIG_TYPE, &viewportConfig_));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t OpenXr::XrSpaceInit()
|
||||
{
|
||||
int32_t OpenXr::XrSpaceInit() {
|
||||
bool stageSupported = false;
|
||||
|
||||
uint32_t numOutputSpaces = 0;
|
||||
|
@ -494,10 +431,8 @@ int32_t OpenXr::XrSpaceInit()
|
|||
OXR(xrEnumerateReferenceSpaces(session_, numOutputSpaces, &numOutputSpaces,
|
||||
referenceSpaces.data()));
|
||||
|
||||
for (uint32_t i = 0; i < numOutputSpaces; i++)
|
||||
{
|
||||
if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE)
|
||||
{
|
||||
for (uint32_t i = 0; i < numOutputSpaces; i++) {
|
||||
if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) {
|
||||
stageSupported = true;
|
||||
break;
|
||||
}
|
||||
|
@ -515,10 +450,8 @@ int32_t OpenXr::XrSpaceInit()
|
|||
OXR(xrCreateReferenceSpace(session_, &spaceCreateInfo, &localSpace_));
|
||||
}
|
||||
|
||||
if (stageSupported)
|
||||
{
|
||||
XrReferenceSpaceCreateInfo spaceCreateInfo = {
|
||||
XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
|
||||
if (stageSupported) {
|
||||
XrReferenceSpaceCreateInfo spaceCreateInfo = {XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
|
||||
|
||||
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
|
||||
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
|
||||
|
@ -528,28 +461,23 @@ int32_t OpenXr::XrSpaceInit()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void OpenXr::XrSpaceDestroy()
|
||||
{
|
||||
if (headSpace_ != XR_NULL_HANDLE)
|
||||
{
|
||||
void OpenXr::XrSpaceDestroy() {
|
||||
if (headSpace_ != XR_NULL_HANDLE) {
|
||||
OXR(xrDestroySpace(headSpace_));
|
||||
headSpace_ = XR_NULL_HANDLE;
|
||||
}
|
||||
if (localSpace_ != XR_NULL_HANDLE)
|
||||
{
|
||||
if (localSpace_ != XR_NULL_HANDLE) {
|
||||
OXR(xrDestroySpace(localSpace_));
|
||||
localSpace_ = XR_NULL_HANDLE;
|
||||
}
|
||||
if (stageSpace_ != XR_NULL_HANDLE)
|
||||
{
|
||||
if (stageSpace_ != XR_NULL_HANDLE) {
|
||||
OXR(xrDestroySpace(stageSpace_));
|
||||
stageSpace_ = XR_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
// Next return code: -7
|
||||
int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
|
||||
{
|
||||
int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject) {
|
||||
|
||||
/////////////////////////////////////
|
||||
// Initialize OpenXR loader
|
||||
|
@ -560,8 +488,7 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
|
|||
// Create the OpenXR instance.
|
||||
/////////////////////////////////////
|
||||
instance_ = XrInstanceCreate();
|
||||
if (instance_ == XR_NULL_HANDLE)
|
||||
{
|
||||
if (instance_ == XR_NULL_HANDLE) {
|
||||
ALOGE("Failed to create XR instance");
|
||||
return -2;
|
||||
}
|
||||
|
@ -569,8 +496,7 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
|
|||
instance = instance_;
|
||||
|
||||
systemId_ = XrGetSystemId(instance_);
|
||||
if (systemId_ == XR_NULL_SYSTEM_ID)
|
||||
{
|
||||
if (systemId_ == XR_NULL_SYSTEM_ID) {
|
||||
ALOGE("Failed to retrieve XR system ID");
|
||||
return -3;
|
||||
}
|
||||
|
@ -582,16 +508,13 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
|
|||
////////////////////////////////
|
||||
{
|
||||
// Get the graphics requirements.
|
||||
PFN_xrGetOpenGLESGraphicsRequirementsKHR
|
||||
pfnGetOpenGLESGraphicsRequirementsKHR = NULL;
|
||||
OXR(xrGetInstanceProcAddr(
|
||||
instance_, "xrGetOpenGLESGraphicsRequirementsKHR",
|
||||
(PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR)));
|
||||
PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL;
|
||||
OXR(xrGetInstanceProcAddr(instance_, "xrGetOpenGLESGraphicsRequirementsKHR",
|
||||
(PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR)));
|
||||
|
||||
XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {};
|
||||
graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR;
|
||||
OXR(pfnGetOpenGLESGraphicsRequirementsKHR(instance_, systemId_,
|
||||
&graphicsRequirements));
|
||||
OXR(pfnGetOpenGLESGraphicsRequirementsKHR(instance_, systemId_, &graphicsRequirements));
|
||||
|
||||
{
|
||||
// Create the EGL Context
|
||||
|
@ -604,8 +527,7 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
|
|||
glGetIntegerv(GL_MINOR_VERSION, &eglMinor);
|
||||
const XrVersion eglVersion = XR_MAKE_VERSION(eglMajor, eglMinor, 0);
|
||||
if (eglVersion < graphicsRequirements.minApiVersionSupported ||
|
||||
eglVersion > graphicsRequirements.maxApiVersionSupported)
|
||||
{
|
||||
eglVersion > graphicsRequirements.maxApiVersionSupported) {
|
||||
ALOGE("GLES version %d.%d not supported", eglMajor, eglMinor);
|
||||
return -5;
|
||||
}
|
||||
|
@ -621,8 +543,7 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
|
|||
// Create the OpenXR Session.
|
||||
//////////////////////////////
|
||||
session_ = XrSessionCreate(instance, systemId_, eglContext_);
|
||||
if (session_ == XR_NULL_HANDLE)
|
||||
{
|
||||
if (session_ == XR_NULL_HANDLE) {
|
||||
ALOGE("Failed to create XR session");
|
||||
return -6;
|
||||
}
|
||||
|
@ -632,18 +553,15 @@ int OpenXr::OpenXRInit(JavaVM* const jvm, const jobject activityObject)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void OpenXr::Shutdown()
|
||||
{
|
||||
void OpenXr::Shutdown() {
|
||||
XrSpaceDestroy();
|
||||
|
||||
if (session_ != XR_NULL_HANDLE)
|
||||
{
|
||||
if (session_ != XR_NULL_HANDLE) {
|
||||
OXR(xrDestroySession(session_));
|
||||
session_ = XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (instance_ != XR_NULL_HANDLE)
|
||||
{
|
||||
if (instance_ != XR_NULL_HANDLE) {
|
||||
OXR(xrDestroyInstance(instance_));
|
||||
instance_ = XR_NULL_HANDLE;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ License : Licensed under GPLv2 or any later version.
|
|||
#include <jni.h>
|
||||
|
||||
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
|
||||
#define XR_USE_PLATFORM_ANDROID 1
|
||||
#define XR_USE_PLATFORM_ANDROID 1
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
@ -26,30 +26,29 @@ License : Licensed under GPLv2 or any later version.
|
|||
#define OXR(func) OXR_CheckErrors(func, #func, true);
|
||||
void OXR_CheckErrors(XrResult result, const char* function, bool failOnError);
|
||||
|
||||
class OpenXr
|
||||
{
|
||||
class OpenXr {
|
||||
|
||||
public:
|
||||
static XrInstance& GetInstance();
|
||||
int32_t Init(JavaVM* const jvm, const jobject activityObject);
|
||||
void Shutdown();
|
||||
int32_t Init(JavaVM* const jvm, const jobject activityObject);
|
||||
void Shutdown();
|
||||
|
||||
XrInstance instance_ = XR_NULL_HANDLE;
|
||||
XrSystemId systemId_ = XR_NULL_SYSTEM_ID;
|
||||
XrSession session_ = XR_NULL_HANDLE;
|
||||
XrSession session_ = XR_NULL_HANDLE;
|
||||
// this structure contains the HMD's recommended eye textures sizes. In
|
||||
// OpenXR, this is meant to be extensible to allow spectator views as well.
|
||||
// One for each eye.
|
||||
XrViewConfigurationView viewConfigurationViews_[2] = {};
|
||||
XrViewConfigurationProperties viewportConfig_ = {};
|
||||
XrViewConfigurationView viewConfigurationViews_[2] = {};
|
||||
XrViewConfigurationProperties viewportConfig_ = {};
|
||||
static constexpr XrViewConfigurationType VIEW_CONFIG_TYPE =
|
||||
XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
|
||||
XrSpace headSpace_ = XR_NULL_HANDLE;
|
||||
XrSpace headSpace_ = XR_NULL_HANDLE;
|
||||
XrSpace forwardDirectionSpace_ = XR_NULL_HANDLE;
|
||||
|
||||
XrSpace localSpace_ = XR_NULL_HANDLE;
|
||||
XrSpace stageSpace_ = XR_NULL_HANDLE;
|
||||
size_t maxLayerCount_ = 0;
|
||||
XrSpace localSpace_ = XR_NULL_HANDLE;
|
||||
XrSpace stageSpace_ = XR_NULL_HANDLE;
|
||||
size_t maxLayerCount_ = 0;
|
||||
|
||||
// EGL context
|
||||
std::unique_ptr<EglContext> eglContext_;
|
||||
|
@ -58,5 +57,5 @@ private:
|
|||
int32_t OpenXRInit(JavaVM* const jvm, const jobject activityObject);
|
||||
int32_t XrViewConfigInit();
|
||||
int32_t XrSpaceInit();
|
||||
void XrSpaceDestroy();
|
||||
void XrSpaceDestroy();
|
||||
};
|
||||
|
|
|
@ -13,9 +13,8 @@ License : Licensed under GPLv2 or any later version.
|
|||
#pragma once
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
struct Swapchain
|
||||
{
|
||||
struct Swapchain {
|
||||
XrSwapchain Handle;
|
||||
uint32_t Width;
|
||||
uint32_t Height;
|
||||
uint32_t Width;
|
||||
uint32_t Height;
|
||||
};
|
||||
|
|
|
@ -9,8 +9,8 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include "XrController.h"
|
||||
#include "OpenXR.h"
|
||||
#include "XrController.h"
|
||||
#include "utils/LogUtils.h"
|
||||
|
||||
#include <vector>
|
||||
|
@ -23,24 +23,20 @@ License : Licensed under GPLv2 or any later version.
|
|||
#define ALOG_INPUT_VERBOSE(...)
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
|
||||
XrAction CreateAction(XrActionSet actionSet, XrActionType type,
|
||||
const char* actionName, const char* localizedName,
|
||||
int countSubactionPaths = 0,
|
||||
XrPath* subactionPaths = nullptr)
|
||||
{
|
||||
XrAction CreateAction(XrActionSet actionSet, XrActionType type, const char* actionName,
|
||||
const char* localizedName, int countSubactionPaths = 0,
|
||||
XrPath* subactionPaths = nullptr) {
|
||||
ALOG_INPUT_VERBOSE("CreateAction %s, %d" actionName, countSubactionPaths);
|
||||
|
||||
XrActionCreateInfo aci = {};
|
||||
aci.type = XR_TYPE_ACTION_CREATE_INFO;
|
||||
aci.next = nullptr;
|
||||
aci.actionType = type;
|
||||
if (countSubactionPaths > 0)
|
||||
{
|
||||
aci.type = XR_TYPE_ACTION_CREATE_INFO;
|
||||
aci.next = nullptr;
|
||||
aci.actionType = type;
|
||||
if (countSubactionPaths > 0) {
|
||||
aci.countSubactionPaths = countSubactionPaths;
|
||||
aci.subactionPaths = subactionPaths;
|
||||
aci.subactionPaths = subactionPaths;
|
||||
}
|
||||
strcpy(aci.actionName, actionName);
|
||||
strcpy(aci.localizedActionName, localizedName ? localizedName : actionName);
|
||||
|
@ -49,10 +45,8 @@ XrAction CreateAction(XrActionSet actionSet, XrActionType type,
|
|||
return action;
|
||||
}
|
||||
|
||||
XrActionSuggestedBinding ActionSuggestedBinding(const XrInstance& instance,
|
||||
XrAction action,
|
||||
const char* bindingString)
|
||||
{
|
||||
XrActionSuggestedBinding ActionSuggestedBinding(const XrInstance& instance, XrAction action,
|
||||
const char* bindingString) {
|
||||
XrActionSuggestedBinding asb;
|
||||
asb.action = action;
|
||||
XrPath bindingPath;
|
||||
|
@ -61,24 +55,20 @@ XrActionSuggestedBinding ActionSuggestedBinding(const XrInstance& instance,
|
|||
return asb;
|
||||
}
|
||||
|
||||
XrSpace CreateActionSpace(const XrSession& session, XrAction poseAction,
|
||||
XrPath subactionPath)
|
||||
{
|
||||
XrActionSpaceCreateInfo asci = {};
|
||||
asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
|
||||
asci.action = poseAction;
|
||||
XrSpace CreateActionSpace(const XrSession& session, XrAction poseAction, XrPath subactionPath) {
|
||||
XrActionSpaceCreateInfo asci = {};
|
||||
asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
|
||||
asci.action = poseAction;
|
||||
asci.poseInActionSpace.orientation.w = 1.0f;
|
||||
asci.subactionPath = subactionPath;
|
||||
XrSpace actionSpace = XR_NULL_HANDLE;
|
||||
asci.subactionPath = subactionPath;
|
||||
XrSpace actionSpace = XR_NULL_HANDLE;
|
||||
OXR(xrCreateActionSpace(session, &asci, &actionSpace));
|
||||
return actionSpace;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
InputStateStatic::InputStateStatic(const XrInstance& instance,
|
||||
const XrSession& session)
|
||||
{
|
||||
InputStateStatic::InputStateStatic(const XrInstance& instance, const XrSession& session) {
|
||||
// Create action set.
|
||||
{
|
||||
XrActionSetCreateInfo actionSetInfo{XR_TYPE_ACTION_SET_CREATE_INFO};
|
||||
|
@ -87,46 +77,34 @@ InputStateStatic::InputStateStatic(const XrInstance& instance,
|
|||
actionSetInfo.priority = 2;
|
||||
OXR(xrCreateActionSet(instance, &actionSetInfo, &mActionSet));
|
||||
}
|
||||
mRightHandIndexTriggerAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
|
||||
"right_index_trigger", "Right Index Trigger");
|
||||
mLeftHandIndexTriggerAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
|
||||
"left_index_trigger", "Left Index Trigger");
|
||||
mLeftMenuButtonAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu", "Menu");
|
||||
mAButtonAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "a", "A button");
|
||||
mBButtonAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "b", "B button");
|
||||
mXButtonAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "x", "X button");
|
||||
mYButtonAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "y", "Y button");
|
||||
mRightHandIndexTriggerAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
|
||||
"right_index_trigger", "Right Index Trigger");
|
||||
mLeftHandIndexTriggerAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
|
||||
"left_index_trigger", "Left Index Trigger");
|
||||
mLeftMenuButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu", "Menu");
|
||||
mAButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "a", "A button");
|
||||
mBButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "b", "B button");
|
||||
mXButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "x", "X button");
|
||||
mYButtonAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "y", "Y button");
|
||||
|
||||
OXR(xrStringToPath(instance, "/user/hand/left", &mLeftHandSubactionPath));
|
||||
OXR(xrStringToPath(instance, "/user/hand/right", &mRightHandSubactionPath));
|
||||
XrPath handSubactionPaths[2] = {mLeftHandSubactionPath,
|
||||
mRightHandSubactionPath};
|
||||
XrPath handSubactionPaths[2] = {mLeftHandSubactionPath, mRightHandSubactionPath};
|
||||
|
||||
mHandPoseAction = CreateAction(mActionSet, XR_ACTION_TYPE_POSE_INPUT,
|
||||
"aim_pose", nullptr, 2, handSubactionPaths);
|
||||
mHandPoseAction = CreateAction(mActionSet, XR_ACTION_TYPE_POSE_INPUT, "aim_pose", nullptr, 2,
|
||||
handSubactionPaths);
|
||||
|
||||
mThumbStickAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "thumb_stick",
|
||||
nullptr, 2, handSubactionPaths);
|
||||
mThumbStickAction = CreateAction(mActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "thumb_stick",
|
||||
nullptr, 2, handSubactionPaths);
|
||||
|
||||
mThumbClickAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumb_click",
|
||||
nullptr, 2, handSubactionPaths);
|
||||
mThumbClickAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumb_click",
|
||||
nullptr, 2, handSubactionPaths);
|
||||
|
||||
mSqueezeTriggerAction =
|
||||
CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
|
||||
"squeeze_trigger", nullptr, 2, handSubactionPaths);
|
||||
mSqueezeTriggerAction = CreateAction(mActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT,
|
||||
"squeeze_trigger", nullptr, 2, handSubactionPaths);
|
||||
|
||||
XrPath interactionProfilePath = XR_NULL_PATH;
|
||||
OXR(xrStringToPath(instance,
|
||||
"/interaction_profiles/oculus/touch_controller",
|
||||
OXR(xrStringToPath(instance, "/interaction_profiles/oculus/touch_controller",
|
||||
&interactionProfilePath));
|
||||
|
||||
// Create bindings for Quest controllers.
|
||||
|
@ -134,66 +112,60 @@ InputStateStatic::InputStateStatic(const XrInstance& instance,
|
|||
// Map bindings
|
||||
|
||||
std::vector<XrActionSuggestedBinding> bindings;
|
||||
bindings.push_back(ActionSuggestedBinding(
|
||||
instance, mAButtonAction, "/user/hand/right/input/a/click"));
|
||||
bindings.push_back(ActionSuggestedBinding(
|
||||
instance, mBButtonAction, "/user/hand/right/input/b/click"));
|
||||
bindings.push_back(ActionSuggestedBinding(
|
||||
instance, mXButtonAction, "/user/hand/left/input/x/click"));
|
||||
bindings.push_back(ActionSuggestedBinding(
|
||||
instance, mYButtonAction, "/user/hand/left/input/y/click"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mAButtonAction, "/user/hand/right/input/a/click"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mBButtonAction, "/user/hand/right/input/b/click"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mXButtonAction, "/user/hand/left/input/x/click"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mYButtonAction, "/user/hand/left/input/y/click"));
|
||||
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mLeftHandIndexTriggerAction,
|
||||
"/user/hand/left/input/trigger"));
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mRightHandIndexTriggerAction,
|
||||
"/user/hand/right/input/trigger"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mLeftHandIndexTriggerAction,
|
||||
"/user/hand/left/input/trigger"));
|
||||
ActionSuggestedBinding(instance, mHandPoseAction, "/user/hand/left/input/aim/pose"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mRightHandIndexTriggerAction,
|
||||
"/user/hand/right/input/trigger"));
|
||||
bindings.push_back(ActionSuggestedBinding(
|
||||
instance, mHandPoseAction, "/user/hand/left/input/aim/pose"));
|
||||
bindings.push_back(ActionSuggestedBinding(
|
||||
instance, mHandPoseAction, "/user/hand/right/input/aim/pose"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mLeftMenuButtonAction,
|
||||
"/user/hand/left/input/menu/click"));
|
||||
bindings.push_back(ActionSuggestedBinding(
|
||||
instance, mThumbStickAction, "/user/hand/left/input/thumbstick"));
|
||||
bindings.push_back(ActionSuggestedBinding(
|
||||
instance, mThumbStickAction, "/user/hand/right/input/thumbstick"));
|
||||
ActionSuggestedBinding(instance, mHandPoseAction, "/user/hand/right/input/aim/pose"));
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mLeftMenuButtonAction,
|
||||
"/user/hand/left/input/menu/click"));
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mThumbStickAction,
|
||||
"/user/hand/left/input/thumbstick"));
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mThumbStickAction,
|
||||
"/user/hand/right/input/thumbstick"));
|
||||
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mThumbClickAction,
|
||||
"/user/hand/right/input/thumbstick/click"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mThumbClickAction,
|
||||
"/user/hand/left/input/thumbstick/click"));
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mThumbClickAction,
|
||||
"/user/hand/right/input/thumbstick/click"));
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mThumbClickAction,
|
||||
"/user/hand/left/input/thumbstick/click"));
|
||||
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mSqueezeTriggerAction,
|
||||
"/user/hand/right/input/squeeze/value"));
|
||||
bindings.push_back(
|
||||
ActionSuggestedBinding(instance, mSqueezeTriggerAction,
|
||||
"/user/hand/left/input/squeeze/value"));
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mSqueezeTriggerAction,
|
||||
"/user/hand/right/input/squeeze/value"));
|
||||
bindings.push_back(ActionSuggestedBinding(instance, mSqueezeTriggerAction,
|
||||
"/user/hand/left/input/squeeze/value"));
|
||||
|
||||
XrInteractionProfileSuggestedBinding suggestedBindings = {};
|
||||
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
|
||||
suggestedBindings.interactionProfile = interactionProfilePath;
|
||||
suggestedBindings.suggestedBindings = &bindings[0];
|
||||
suggestedBindings.interactionProfile = interactionProfilePath;
|
||||
suggestedBindings.suggestedBindings = &bindings[0];
|
||||
suggestedBindings.countSuggestedBindings = bindings.size();
|
||||
OXR(xrSuggestInteractionProfileBindings(instance, &suggestedBindings));
|
||||
|
||||
// Attach to session
|
||||
XrSessionActionSetsAttachInfo attachInfo = {};
|
||||
attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
|
||||
attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
|
||||
attachInfo.countActionSets = 1;
|
||||
attachInfo.actionSets = &mActionSet;
|
||||
attachInfo.actionSets = &mActionSet;
|
||||
OXR(xrAttachSessionActionSets(session, &attachInfo));
|
||||
}
|
||||
}
|
||||
|
||||
InputStateStatic::~InputStateStatic()
|
||||
{
|
||||
if (mActionSet != XR_NULL_HANDLE) { OXR(xrDestroyActionSet(mActionSet)); }
|
||||
InputStateStatic::~InputStateStatic() {
|
||||
if (mActionSet != XR_NULL_HANDLE) {
|
||||
OXR(xrDestroyActionSet(mActionSet));
|
||||
}
|
||||
OXR(xrDestroyAction(mLeftHandIndexTriggerAction));
|
||||
OXR(xrDestroyAction(mRightHandIndexTriggerAction));
|
||||
OXR(xrDestroyAction(mLeftMenuButtonAction));
|
||||
|
@ -206,62 +178,54 @@ InputStateStatic::~InputStateStatic()
|
|||
OXR(xrDestroyAction(mThumbClickAction));
|
||||
OXR(xrDestroyAction(mSqueezeTriggerAction));
|
||||
|
||||
if (mLeftHandSpace != XR_NULL_HANDLE)
|
||||
{
|
||||
if (mLeftHandSpace != XR_NULL_HANDLE) {
|
||||
OXR(xrDestroySpace(mLeftHandSpace));
|
||||
}
|
||||
if (mRightHandSpace != XR_NULL_HANDLE)
|
||||
{
|
||||
if (mRightHandSpace != XR_NULL_HANDLE) {
|
||||
OXR(xrDestroySpace(mRightHandSpace));
|
||||
}
|
||||
}
|
||||
|
||||
XrActionStateBoolean SyncButtonState(const XrSession& session,
|
||||
const XrAction& action,
|
||||
const XrPath& subactionPath = XR_NULL_PATH)
|
||||
{
|
||||
XrActionStateBoolean SyncButtonState(const XrSession& session, const XrAction& action,
|
||||
const XrPath& subactionPath = XR_NULL_PATH) {
|
||||
XrActionStateGetInfo getInfo = {};
|
||||
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
|
||||
getInfo.action = action;
|
||||
getInfo.subactionPath = subactionPath;
|
||||
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
|
||||
getInfo.action = action;
|
||||
getInfo.subactionPath = subactionPath;
|
||||
|
||||
XrActionStateBoolean state = {};
|
||||
state.type = XR_TYPE_ACTION_STATE_BOOLEAN;
|
||||
state.type = XR_TYPE_ACTION_STATE_BOOLEAN;
|
||||
|
||||
OXR(xrGetActionStateBoolean(session, &getInfo, &state));
|
||||
return state;
|
||||
}
|
||||
|
||||
XrActionStateVector2f
|
||||
SyncVector2fState(const XrSession& session, const XrAction& action,
|
||||
const XrPath& subactionPath = XR_NULL_PATH)
|
||||
{
|
||||
XrActionStateVector2f SyncVector2fState(const XrSession& session, const XrAction& action,
|
||||
const XrPath& subactionPath = XR_NULL_PATH) {
|
||||
XrActionStateGetInfo getInfo = {};
|
||||
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
|
||||
getInfo.action = action;
|
||||
getInfo.subactionPath = subactionPath;
|
||||
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
|
||||
getInfo.action = action;
|
||||
getInfo.subactionPath = subactionPath;
|
||||
|
||||
XrActionStateVector2f state = {};
|
||||
state.type = XR_TYPE_ACTION_STATE_VECTOR2F;
|
||||
state.type = XR_TYPE_ACTION_STATE_VECTOR2F;
|
||||
|
||||
OXR(xrGetActionStateVector2f(session, &getInfo, &state));
|
||||
return state;
|
||||
}
|
||||
|
||||
void InputStateFrame::SyncButtonsAndThumbSticks(
|
||||
const XrSession& session,
|
||||
const std::unique_ptr<InputStateStatic>& staticState)
|
||||
{
|
||||
const XrSession& session, const std::unique_ptr<InputStateStatic>& staticState) {
|
||||
assert(staticState != nullptr);
|
||||
XrActiveActionSet activeActionSet = {};
|
||||
activeActionSet.actionSet = staticState->mActionSet;
|
||||
activeActionSet.subactionPath = XR_NULL_PATH;
|
||||
activeActionSet.actionSet = staticState->mActionSet;
|
||||
activeActionSet.subactionPath = XR_NULL_PATH;
|
||||
|
||||
XrActionsSyncInfo syncInfo = {};
|
||||
syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
|
||||
syncInfo.next = nullptr;
|
||||
XrActionsSyncInfo syncInfo = {};
|
||||
syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
|
||||
syncInfo.next = nullptr;
|
||||
syncInfo.countActiveActionSets = 1;
|
||||
syncInfo.activeActionSets = &activeActionSet;
|
||||
syncInfo.activeActionSets = &activeActionSet;
|
||||
OXR(xrSyncActions(session, &syncInfo));
|
||||
|
||||
// Sync button states
|
||||
|
@ -270,92 +234,71 @@ void InputStateFrame::SyncButtonsAndThumbSticks(
|
|||
mXButtonState = SyncButtonState(session, staticState->mXButtonAction);
|
||||
mYButtonState = SyncButtonState(session, staticState->mYButtonAction);
|
||||
|
||||
mLeftMenuButtonState =
|
||||
SyncButtonState(session, staticState->mLeftMenuButtonAction);
|
||||
mLeftMenuButtonState = SyncButtonState(session, staticState->mLeftMenuButtonAction);
|
||||
|
||||
// Sync thumbstick states
|
||||
mThumbStickState[LEFT_CONTROLLER] =
|
||||
SyncVector2fState(session, staticState->mThumbStickAction,
|
||||
staticState->mLeftHandSubactionPath);
|
||||
mThumbStickState[RIGHT_CONTROLLER] =
|
||||
SyncVector2fState(session, staticState->mThumbStickAction,
|
||||
staticState->mRightHandSubactionPath);
|
||||
mThumbStickState[LEFT_CONTROLLER] = SyncVector2fState(session, staticState->mThumbStickAction,
|
||||
staticState->mLeftHandSubactionPath);
|
||||
mThumbStickState[RIGHT_CONTROLLER] = SyncVector2fState(session, staticState->mThumbStickAction,
|
||||
staticState->mRightHandSubactionPath);
|
||||
|
||||
// Sync thumbstick click states
|
||||
mThumbStickClickState[LEFT_CONTROLLER] =
|
||||
SyncButtonState(session, staticState->mThumbClickAction,
|
||||
staticState->mLeftHandSubactionPath);
|
||||
mThumbStickClickState[RIGHT_CONTROLLER] =
|
||||
SyncButtonState(session, staticState->mThumbClickAction,
|
||||
staticState->mRightHandSubactionPath);
|
||||
mThumbStickClickState[LEFT_CONTROLLER] = SyncButtonState(
|
||||
session, staticState->mThumbClickAction, staticState->mLeftHandSubactionPath);
|
||||
mThumbStickClickState[RIGHT_CONTROLLER] = SyncButtonState(
|
||||
session, staticState->mThumbClickAction, staticState->mRightHandSubactionPath);
|
||||
|
||||
// Sync index trigger states
|
||||
mIndexTriggerState[LEFT_CONTROLLER] =
|
||||
SyncButtonState(session, staticState->mLeftHandIndexTriggerAction,
|
||||
staticState->mLeftHandSubactionPath);
|
||||
mIndexTriggerState[RIGHT_CONTROLLER] =
|
||||
SyncButtonState(session, staticState->mRightHandIndexTriggerAction,
|
||||
staticState->mRightHandSubactionPath);
|
||||
mIndexTriggerState[LEFT_CONTROLLER] = SyncButtonState(
|
||||
session, staticState->mLeftHandIndexTriggerAction, staticState->mLeftHandSubactionPath);
|
||||
mIndexTriggerState[RIGHT_CONTROLLER] = SyncButtonState(
|
||||
session, staticState->mRightHandIndexTriggerAction, staticState->mRightHandSubactionPath);
|
||||
|
||||
// Sync squeeze trigger states
|
||||
mSqueezeTriggerState[LEFT_CONTROLLER] =
|
||||
SyncButtonState(session, staticState->mSqueezeTriggerAction,
|
||||
staticState->mLeftHandSubactionPath);
|
||||
mSqueezeTriggerState[RIGHT_CONTROLLER] =
|
||||
SyncButtonState(session, staticState->mSqueezeTriggerAction,
|
||||
staticState->mRightHandSubactionPath);
|
||||
mSqueezeTriggerState[LEFT_CONTROLLER] = SyncButtonState(
|
||||
session, staticState->mSqueezeTriggerAction, staticState->mLeftHandSubactionPath);
|
||||
mSqueezeTriggerState[RIGHT_CONTROLLER] = SyncButtonState(
|
||||
session, staticState->mSqueezeTriggerAction, staticState->mRightHandSubactionPath);
|
||||
|
||||
if (staticState->mLeftHandSpace == XR_NULL_HANDLE)
|
||||
{
|
||||
staticState->mLeftHandSpace =
|
||||
CreateActionSpace(session, staticState->mHandPoseAction,
|
||||
staticState->mLeftHandSubactionPath);
|
||||
if (staticState->mLeftHandSpace == XR_NULL_HANDLE) {
|
||||
staticState->mLeftHandSpace = CreateActionSpace(session, staticState->mHandPoseAction,
|
||||
staticState->mLeftHandSubactionPath);
|
||||
}
|
||||
if (staticState->mRightHandSpace == XR_NULL_HANDLE)
|
||||
{
|
||||
staticState->mRightHandSpace =
|
||||
CreateActionSpace(session, staticState->mHandPoseAction,
|
||||
staticState->mRightHandSubactionPath);
|
||||
if (staticState->mRightHandSpace == XR_NULL_HANDLE) {
|
||||
staticState->mRightHandSpace = CreateActionSpace(session, staticState->mHandPoseAction,
|
||||
staticState->mRightHandSubactionPath);
|
||||
}
|
||||
|
||||
// get the active state and pose for the two comtrollers
|
||||
if (staticState->mLeftHandSpace != XR_NULL_HANDLE)
|
||||
{
|
||||
XrActionStateGetInfo getInfo = {
|
||||
.type = XR_TYPE_ACTION_STATE_GET_INFO,
|
||||
.action = staticState->mHandPoseAction,
|
||||
.subactionPath = staticState->mLeftHandSubactionPath};
|
||||
if (staticState->mLeftHandSpace != XR_NULL_HANDLE) {
|
||||
XrActionStateGetInfo getInfo = {.type = XR_TYPE_ACTION_STATE_GET_INFO,
|
||||
.action = staticState->mHandPoseAction,
|
||||
.subactionPath = staticState->mLeftHandSubactionPath};
|
||||
XrActionStatePose handPose = {.type = XR_TYPE_ACTION_STATE_POSE};
|
||||
OXR(xrGetActionStatePose(session, &getInfo, &handPose));
|
||||
mIsHandActive[LEFT_CONTROLLER] = handPose.isActive;
|
||||
}
|
||||
if (staticState->mRightHandSpace != XR_NULL_HANDLE)
|
||||
{
|
||||
XrActionStateGetInfo getInfo = {
|
||||
.type = XR_TYPE_ACTION_STATE_GET_INFO,
|
||||
.action = staticState->mHandPoseAction,
|
||||
.subactionPath = staticState->mRightHandSubactionPath};
|
||||
if (staticState->mRightHandSpace != XR_NULL_HANDLE) {
|
||||
XrActionStateGetInfo getInfo = {.type = XR_TYPE_ACTION_STATE_GET_INFO,
|
||||
.action = staticState->mHandPoseAction,
|
||||
.subactionPath = staticState->mRightHandSubactionPath};
|
||||
XrActionStatePose handPose = {.type = XR_TYPE_ACTION_STATE_POSE};
|
||||
OXR(xrGetActionStatePose(session, &getInfo, &handPose));
|
||||
mIsHandActive[RIGHT_CONTROLLER] = handPose.isActive;
|
||||
}
|
||||
}
|
||||
|
||||
void InputStateFrame::SyncHandPoses(
|
||||
const XrSession& session,
|
||||
const std::unique_ptr<InputStateStatic>& staticState,
|
||||
const XrSpace& referenceSpace,
|
||||
const XrTime predictedDisplayTime)
|
||||
{
|
||||
OXR(xrLocateSpace(staticState->mRightHandSpace, referenceSpace,
|
||||
predictedDisplayTime,
|
||||
void InputStateFrame::SyncHandPoses(const XrSession& session,
|
||||
const std::unique_ptr<InputStateStatic>& staticState,
|
||||
const XrSpace& referenceSpace,
|
||||
const XrTime predictedDisplayTime) {
|
||||
OXR(xrLocateSpace(staticState->mRightHandSpace, referenceSpace, predictedDisplayTime,
|
||||
&mHandPositions[InputStateFrame::RIGHT_CONTROLLER]));
|
||||
mIsHandActive[RIGHT_CONTROLLER] =
|
||||
(mHandPositions[InputStateFrame::RIGHT_CONTROLLER].locationFlags &
|
||||
XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0;
|
||||
|
||||
OXR(xrLocateSpace(staticState->mLeftHandSpace, referenceSpace,
|
||||
predictedDisplayTime,
|
||||
OXR(xrLocateSpace(staticState->mLeftHandSpace, referenceSpace, predictedDisplayTime,
|
||||
&mHandPositions[InputStateFrame::LEFT_CONTROLLER]));
|
||||
mIsHandActive[LEFT_CONTROLLER] =
|
||||
(mHandPositions[InputStateFrame::LEFT_CONTROLLER].locationFlags &
|
||||
|
@ -364,40 +307,29 @@ void InputStateFrame::SyncHandPoses(
|
|||
// Determine preferred hand.
|
||||
{
|
||||
// First, determine which controllers are active
|
||||
const bool isLeftHandActive = mIsHandActive[LEFT_CONTROLLER];
|
||||
const bool isLeftHandActive = mIsHandActive[LEFT_CONTROLLER];
|
||||
const bool isRightHandActive = mIsHandActive[RIGHT_CONTROLLER];
|
||||
|
||||
// if only one controller is active, use that one
|
||||
if (isLeftHandActive && !isRightHandActive)
|
||||
{
|
||||
if (isLeftHandActive && !isRightHandActive) {
|
||||
mPreferredHand = LEFT_CONTROLLER;
|
||||
}
|
||||
else if (!isLeftHandActive && isRightHandActive)
|
||||
{
|
||||
} else if (!isLeftHandActive && isRightHandActive) {
|
||||
mPreferredHand = RIGHT_CONTROLLER;
|
||||
}
|
||||
else if (isLeftHandActive && isRightHandActive)
|
||||
{
|
||||
} else if (isLeftHandActive && isRightHandActive) {
|
||||
// if both controllers are active, use whichever one last pressed
|
||||
// the index trigger
|
||||
if (mIndexTriggerState[LEFT_CONTROLLER].changedSinceLastSync &&
|
||||
mIndexTriggerState[LEFT_CONTROLLER].currentState == 1)
|
||||
{
|
||||
mIndexTriggerState[LEFT_CONTROLLER].currentState == 1) {
|
||||
mPreferredHand = LEFT_CONTROLLER;
|
||||
}
|
||||
if (mIndexTriggerState[RIGHT_CONTROLLER].changedSinceLastSync &&
|
||||
mIndexTriggerState[RIGHT_CONTROLLER].currentState == 1)
|
||||
{
|
||||
mIndexTriggerState[RIGHT_CONTROLLER].currentState == 1) {
|
||||
mPreferredHand = RIGHT_CONTROLLER;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// if neither controller has pressed the index trigger, use the
|
||||
// last active controller
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// if no controllers are active, use the last active controller
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,63 +18,54 @@ License : Licensed under GPLv2 or any later version.
|
|||
#include <jni.h> // needed for openxr_platform.h when XR_USE_PLATFORM_ANDROID is defined
|
||||
|
||||
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
|
||||
#define XR_USE_PLATFORM_ANDROID 1
|
||||
#define XR_USE_PLATFORM_ANDROID 1
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
#include <memory> // for unique_ptr
|
||||
|
||||
class InputStateStatic
|
||||
{
|
||||
class InputStateStatic {
|
||||
public:
|
||||
InputStateStatic(const XrInstance& instance, const XrSession& session);
|
||||
~InputStateStatic();
|
||||
XrActionSet mActionSet = XR_NULL_HANDLE;
|
||||
|
||||
XrSpace mLeftHandSpace = XR_NULL_HANDLE;
|
||||
XrPath mLeftHandSubactionPath;
|
||||
XrPath mLeftHandSubactionPath;
|
||||
|
||||
XrAction mLeftHandIndexTriggerAction = XR_NULL_HANDLE;
|
||||
XrAction mXButtonAction = XR_NULL_HANDLE;
|
||||
XrAction mYButtonAction = XR_NULL_HANDLE;
|
||||
XrAction mLeftMenuButtonAction = XR_NULL_HANDLE;
|
||||
XrAction mXButtonAction = XR_NULL_HANDLE;
|
||||
XrAction mYButtonAction = XR_NULL_HANDLE;
|
||||
XrAction mLeftMenuButtonAction = XR_NULL_HANDLE;
|
||||
|
||||
XrSpace mRightHandSpace = XR_NULL_HANDLE;
|
||||
XrPath mRightHandSubactionPath;
|
||||
XrPath mRightHandSubactionPath;
|
||||
|
||||
XrAction mRightHandIndexTriggerAction = XR_NULL_HANDLE;
|
||||
XrAction mAButtonAction = XR_NULL_HANDLE;
|
||||
XrAction mBButtonAction = XR_NULL_HANDLE;
|
||||
XrAction mAButtonAction = XR_NULL_HANDLE;
|
||||
XrAction mBButtonAction = XR_NULL_HANDLE;
|
||||
|
||||
XrAction mThumbStickAction = XR_NULL_HANDLE;
|
||||
XrAction mHandPoseAction = XR_NULL_HANDLE;
|
||||
XrAction mThumbClickAction = XR_NULL_HANDLE;
|
||||
XrAction mThumbStickAction = XR_NULL_HANDLE;
|
||||
XrAction mHandPoseAction = XR_NULL_HANDLE;
|
||||
XrAction mThumbClickAction = XR_NULL_HANDLE;
|
||||
XrAction mSqueezeTriggerAction = XR_NULL_HANDLE;
|
||||
};
|
||||
|
||||
struct InputStateFrame
|
||||
{
|
||||
struct InputStateFrame {
|
||||
|
||||
void SyncButtonsAndThumbSticks(
|
||||
const XrSession& session,
|
||||
const std::unique_ptr<InputStateStatic>& staticState);
|
||||
void SyncButtonsAndThumbSticks(const XrSession& session,
|
||||
const std::unique_ptr<InputStateStatic>& staticState);
|
||||
// Called after SyncButtonsAndThumbSticks
|
||||
void SyncHandPoses(const XrSession& session,
|
||||
void SyncHandPoses(const XrSession& session,
|
||||
const std::unique_ptr<InputStateStatic>& staticState,
|
||||
const XrSpace& referenceSpace,
|
||||
const XrTime predictedDisplayTime);
|
||||
enum
|
||||
{
|
||||
LEFT_CONTROLLER,
|
||||
RIGHT_CONTROLLER,
|
||||
NUM_CONTROLLERS
|
||||
} mPreferredHand = RIGHT_CONTROLLER;
|
||||
const XrSpace& referenceSpace, const XrTime predictedDisplayTime);
|
||||
enum { LEFT_CONTROLLER, RIGHT_CONTROLLER, NUM_CONTROLLERS } mPreferredHand = RIGHT_CONTROLLER;
|
||||
|
||||
XrActionStateVector2f mThumbStickState[NUM_CONTROLLERS];
|
||||
XrActionStateBoolean mThumbStickClickState[NUM_CONTROLLERS];
|
||||
XrActionStateBoolean mIndexTriggerState[NUM_CONTROLLERS];
|
||||
XrActionStateBoolean mSqueezeTriggerState[NUM_CONTROLLERS];
|
||||
XrActionStateBoolean mThumbStickClickState[NUM_CONTROLLERS];
|
||||
XrActionStateBoolean mIndexTriggerState[NUM_CONTROLLERS];
|
||||
XrActionStateBoolean mSqueezeTriggerState[NUM_CONTROLLERS];
|
||||
|
||||
// Left hand buttons.
|
||||
XrActionStateBoolean mXButtonState;
|
||||
|
@ -85,7 +76,7 @@ struct InputStateFrame
|
|||
XrActionStateBoolean mAButtonState;
|
||||
XrActionStateBoolean mBButtonState;
|
||||
|
||||
XrSpaceLocation mHandPositions[NUM_CONTROLLERS] = {
|
||||
{XR_TYPE_SPACE_LOCATION}, {XR_TYPE_SPACE_LOCATION}};
|
||||
XrSpaceLocation mHandPositions[NUM_CONTROLLERS] = {{XR_TYPE_SPACE_LOCATION},
|
||||
{XR_TYPE_SPACE_LOCATION}};
|
||||
bool mIsHandActive[NUM_CONTROLLERS] = {false, false};
|
||||
};
|
||||
|
|
|
@ -9,105 +9,96 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include "Egl.h"
|
||||
#include "../utils/LogUtils.h"
|
||||
#include "Egl.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
|
||||
const char* EglErrorToStr(const EGLint error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case EGL_SUCCESS:
|
||||
return "EGL_SUCCESS";
|
||||
case EGL_NOT_INITIALIZED:
|
||||
return "EGL_NOT_INITIALIZED";
|
||||
case EGL_BAD_ACCESS:
|
||||
return "EGL_BAD_ACCESS";
|
||||
case EGL_BAD_ALLOC:
|
||||
return "EGL_BAD_ALLOC";
|
||||
case EGL_BAD_ATTRIBUTE:
|
||||
return "EGL_BAD_ATTRIBUTE";
|
||||
case EGL_BAD_CONTEXT:
|
||||
return "EGL_BAD_CONTEXT";
|
||||
case EGL_BAD_CONFIG:
|
||||
return "EGL_BAD_CONFIG";
|
||||
case EGL_BAD_CURRENT_SURFACE:
|
||||
return "EGL_BAD_CURRENT_SURFACE";
|
||||
case EGL_BAD_DISPLAY:
|
||||
return "EGL_BAD_DISPLAY";
|
||||
case EGL_BAD_SURFACE:
|
||||
return "EGL_BAD_SURFACE";
|
||||
case EGL_BAD_MATCH:
|
||||
return "EGL_BAD_MATCH";
|
||||
case EGL_BAD_PARAMETER:
|
||||
return "EGL_BAD_PARAMETER";
|
||||
case EGL_BAD_NATIVE_PIXMAP:
|
||||
return "EGL_BAD_NATIVE_PIXMAP";
|
||||
case EGL_BAD_NATIVE_WINDOW:
|
||||
return "EGL_BAD_NATIVE_WINDOW";
|
||||
case EGL_CONTEXT_LOST:
|
||||
return "EGL_CONTEXT_LOST";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
const char* EglErrorToStr(const EGLint error) {
|
||||
switch (error) {
|
||||
case EGL_SUCCESS:
|
||||
return "EGL_SUCCESS";
|
||||
case EGL_NOT_INITIALIZED:
|
||||
return "EGL_NOT_INITIALIZED";
|
||||
case EGL_BAD_ACCESS:
|
||||
return "EGL_BAD_ACCESS";
|
||||
case EGL_BAD_ALLOC:
|
||||
return "EGL_BAD_ALLOC";
|
||||
case EGL_BAD_ATTRIBUTE:
|
||||
return "EGL_BAD_ATTRIBUTE";
|
||||
case EGL_BAD_CONTEXT:
|
||||
return "EGL_BAD_CONTEXT";
|
||||
case EGL_BAD_CONFIG:
|
||||
return "EGL_BAD_CONFIG";
|
||||
case EGL_BAD_CURRENT_SURFACE:
|
||||
return "EGL_BAD_CURRENT_SURFACE";
|
||||
case EGL_BAD_DISPLAY:
|
||||
return "EGL_BAD_DISPLAY";
|
||||
case EGL_BAD_SURFACE:
|
||||
return "EGL_BAD_SURFACE";
|
||||
case EGL_BAD_MATCH:
|
||||
return "EGL_BAD_MATCH";
|
||||
case EGL_BAD_PARAMETER:
|
||||
return "EGL_BAD_PARAMETER";
|
||||
case EGL_BAD_NATIVE_PIXMAP:
|
||||
return "EGL_BAD_NATIVE_PIXMAP";
|
||||
case EGL_BAD_NATIVE_WINDOW:
|
||||
return "EGL_BAD_NATIVE_WINDOW";
|
||||
case EGL_CONTEXT_LOST:
|
||||
return "EGL_CONTEXT_LOST";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
EglContext::EglContext()
|
||||
{
|
||||
EglContext::EglContext() {
|
||||
|
||||
const int32_t ret = Init();
|
||||
if (ret < 0) { FAIL("EglContext::EglContext() failed: ret=%i", ret); }
|
||||
if (ret < 0) {
|
||||
FAIL("EglContext::EglContext() failed: ret=%i", ret);
|
||||
}
|
||||
}
|
||||
|
||||
EglContext::~EglContext() { Shutdown(); }
|
||||
EglContext::~EglContext() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
// next return code: -7
|
||||
int32_t EglContext::Init()
|
||||
{
|
||||
int32_t EglContext::Init() {
|
||||
mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (mDisplay == EGL_NO_DISPLAY)
|
||||
{
|
||||
ALOGE(" eglGetDisplay() failed: %s",
|
||||
EglErrorToStr(eglGetError()));
|
||||
if (mDisplay == EGL_NO_DISPLAY) {
|
||||
ALOGE(" eglGetDisplay() failed: %s", EglErrorToStr(eglGetError()));
|
||||
return -1;
|
||||
}
|
||||
{
|
||||
ALOGV(" eglInitialize(mDisplay, &MajorVersion, &MinorVersion)");
|
||||
EGLint majorVersion = 0;
|
||||
EGLint minorVersion = 0;
|
||||
if (eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_FALSE)
|
||||
{
|
||||
ALOGE(" eglInitialize() failed: %s",
|
||||
EglErrorToStr(eglGetError()));
|
||||
if (eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_FALSE) {
|
||||
ALOGE(" eglInitialize() failed: %s", EglErrorToStr(eglGetError()));
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
EGLint numConfigs = 0;
|
||||
const EGLint configAttribs[] = {
|
||||
EGL_RED_SIZE,
|
||||
8,
|
||||
EGL_GREEN_SIZE,
|
||||
8,
|
||||
EGL_BLUE_SIZE,
|
||||
8,
|
||||
EGL_ALPHA_SIZE,
|
||||
8,
|
||||
EGL_DEPTH_SIZE, // probably don't need
|
||||
0,
|
||||
EGL_STENCIL_SIZE, // probably don't need, but we'll see.
|
||||
0,
|
||||
EGL_SAMPLES,
|
||||
0,
|
||||
EGL_NONE};
|
||||
EGLint numConfigs = 0;
|
||||
const EGLint configAttribs[] = {EGL_RED_SIZE,
|
||||
8,
|
||||
EGL_GREEN_SIZE,
|
||||
8,
|
||||
EGL_BLUE_SIZE,
|
||||
8,
|
||||
EGL_ALPHA_SIZE,
|
||||
8,
|
||||
EGL_DEPTH_SIZE, // probably don't need
|
||||
0,
|
||||
EGL_STENCIL_SIZE, // probably don't need, but we'll see.
|
||||
0,
|
||||
EGL_SAMPLES,
|
||||
0,
|
||||
EGL_NONE};
|
||||
|
||||
if (eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs) ==
|
||||
EGL_FALSE)
|
||||
{
|
||||
ALOGE(" eglChooseConfig() failed: %s",
|
||||
EglErrorToStr(eglGetError()));
|
||||
if (eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs) == EGL_FALSE) {
|
||||
ALOGE(" eglChooseConfig() failed: %s", EglErrorToStr(eglGetError()));
|
||||
return -3;
|
||||
}
|
||||
// print out chosen config attributes
|
||||
|
@ -152,33 +143,25 @@ int32_t EglContext::Init()
|
|||
ALOGV(" mContext = eglCreateContext(mDisplay, mConfig, "
|
||||
"EGL_NO_CONTEXT, "
|
||||
"contextAttribs)");
|
||||
mContext =
|
||||
eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs);
|
||||
if (mContext == EGL_NO_CONTEXT)
|
||||
{
|
||||
ALOGE(" eglCreateContext() failed: %s",
|
||||
EglErrorToStr(eglGetError()));
|
||||
mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs);
|
||||
if (mContext == EGL_NO_CONTEXT) {
|
||||
ALOGE(" eglCreateContext() failed: %s", EglErrorToStr(eglGetError()));
|
||||
return -4;
|
||||
}
|
||||
const EGLint surfaceAttribs[] = {EGL_WIDTH, 16, EGL_HEIGHT, 16, EGL_NONE};
|
||||
ALOGV(" mDummySurface = eglCreatePbufferSurface(mDisplay, mConfig, "
|
||||
"surfaceAttribs)");
|
||||
mDummySurface = eglCreatePbufferSurface(mDisplay, mConfig, surfaceAttribs);
|
||||
if (mDummySurface == EGL_NO_SURFACE)
|
||||
{
|
||||
ALOGE(" eglCreatePbufferSurface() failed: %s",
|
||||
EglErrorToStr(eglGetError()));
|
||||
if (mDummySurface == EGL_NO_SURFACE) {
|
||||
ALOGE(" eglCreatePbufferSurface() failed: %s", EglErrorToStr(eglGetError()));
|
||||
eglDestroyContext(mDisplay, mContext);
|
||||
mContext = EGL_NO_CONTEXT;
|
||||
return -5;
|
||||
}
|
||||
ALOGV(" eglMakeCurrent(mDisplay, mDummySurface, mDummySurface, "
|
||||
"mContext)");
|
||||
if (eglMakeCurrent(mDisplay, mDummySurface, mDummySurface, mContext) ==
|
||||
EGL_FALSE)
|
||||
{
|
||||
ALOGE(" eglMakeCurrent() failed: %s",
|
||||
EglErrorToStr(eglGetError()));
|
||||
if (eglMakeCurrent(mDisplay, mDummySurface, mDummySurface, mContext) == EGL_FALSE) {
|
||||
ALOGE(" eglMakeCurrent() failed: %s", EglErrorToStr(eglGetError()));
|
||||
eglDestroySurface(mDisplay, mDummySurface);
|
||||
eglDestroyContext(mDisplay, mContext);
|
||||
mContext = EGL_NO_CONTEXT;
|
||||
|
@ -188,23 +171,18 @@ int32_t EglContext::Init()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void EglContext::Shutdown()
|
||||
{
|
||||
if (mContext != EGL_NO_CONTEXT)
|
||||
{
|
||||
ALOGV(
|
||||
" eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, "
|
||||
"EGL_NO_CONTEXT)");
|
||||
eglMakeCurrent(
|
||||
mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
void EglContext::Shutdown() {
|
||||
if (mContext != EGL_NO_CONTEXT) {
|
||||
ALOGV(" eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, "
|
||||
"EGL_NO_CONTEXT)");
|
||||
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
ALOGV(" eglDestroySurface(mDisplay, mDummySurface)");
|
||||
eglDestroySurface(mDisplay, mDummySurface);
|
||||
ALOGV(" eglDestroyContext(mDisplay, mContext)");
|
||||
eglDestroyContext(mDisplay, mContext);
|
||||
mContext = EGL_NO_CONTEXT;
|
||||
}
|
||||
if (mDisplay != EGL_NO_DISPLAY)
|
||||
{
|
||||
if (mDisplay != EGL_NO_DISPLAY) {
|
||||
ALOGV(" eglTerminate(mDisplay)");
|
||||
eglTerminate(mDisplay);
|
||||
mDisplay = EGL_NO_DISPLAY;
|
||||
|
|
|
@ -16,20 +16,19 @@ License : Licensed under GPLv2 or any later version.
|
|||
#include <GLES3/gl3.h>
|
||||
#include <GLES3/gl3ext.h>
|
||||
|
||||
class EglContext
|
||||
{
|
||||
class EglContext {
|
||||
|
||||
public:
|
||||
EglContext();
|
||||
~EglContext();
|
||||
|
||||
EGLDisplay mDisplay = 0;
|
||||
EGLConfig mConfig = 0;
|
||||
EGLConfig mConfig = 0;
|
||||
EGLContext mContext = EGL_NO_CONTEXT;
|
||||
|
||||
private:
|
||||
int32_t Init();
|
||||
void Shutdown();
|
||||
void Shutdown();
|
||||
// Create an unused surface because our device doesn't support creating a
|
||||
// surfaceless context (KHR_surfaceless_context) (It's available in AOSP as
|
||||
// a module, though, so that might be cool).
|
||||
|
|
|
@ -12,9 +12,8 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
#pragma once
|
||||
#include "OpenXR.h"
|
||||
namespace vr
|
||||
{
|
||||
namespace vr {
|
||||
|
||||
XrSession& GetSession();
|
||||
void PrioritizeTid(const int tid);
|
||||
void PrioritizeTid(const int tid);
|
||||
} // namespace vr
|
||||
|
|
|
@ -15,32 +15,28 @@ License : Licensed under GPLv2 or any later version.
|
|||
#include <openxr/openxr.h>
|
||||
|
||||
#ifndef NUM_EYES
|
||||
#define NUM_EYES \
|
||||
2 // this will never change, it just helps people know what we mean.
|
||||
#define NUM_EYES 2 // this will never change, it just helps people know what we mean.
|
||||
#endif
|
||||
|
||||
#define BAIL_ON_COND(cond, errorStr, returnCode) \
|
||||
do { \
|
||||
if (cond) \
|
||||
{ \
|
||||
ALOGE("ERROR (%s): %s", __FUNCTION__, errorStr); \
|
||||
return (returnCode); \
|
||||
} \
|
||||
#define BAIL_ON_COND(cond, errorStr, returnCode) \
|
||||
do { \
|
||||
if (cond) { \
|
||||
ALOGE("ERROR (%s): %s", __FUNCTION__, errorStr); \
|
||||
return (returnCode); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BAIL_ON_ERR(fn, returnCode) \
|
||||
do { \
|
||||
const int32_t ret = fn; \
|
||||
if (ret < 0) \
|
||||
{ \
|
||||
ALOGE("ERROR (%s): %s() returned %d", __FUNCTION__, #fn, ret); \
|
||||
return (returnCode); \
|
||||
} \
|
||||
#define BAIL_ON_ERR(fn, returnCode) \
|
||||
do { \
|
||||
const int32_t ret = fn; \
|
||||
if (ret < 0) { \
|
||||
ALOGE("ERROR (%s): %s() returned %d", __FUNCTION__, #fn, ret); \
|
||||
return (returnCode); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
union XrCompositionLayer
|
||||
{
|
||||
XrCompositionLayerQuad mQuad;
|
||||
union XrCompositionLayer {
|
||||
XrCompositionLayerQuad mQuad;
|
||||
XrCompositionLayerCylinderKHR mCylinder;
|
||||
XrCompositionLayerPassthroughFB Passthrough;
|
||||
};
|
||||
|
|
|
@ -15,62 +15,54 @@ License : Licensed under GPLv2 or any later version.
|
|||
#include "LogUtils.h"
|
||||
|
||||
jclass JniUtils::GetGlobalClassReference(JNIEnv* jni, jobject activityObject,
|
||||
const std::string& className)
|
||||
{
|
||||
const std::string& className) {
|
||||
// First, get the class object of the activity to get its class loader
|
||||
const jclass activityClass = jni->GetObjectClass(activityObject);
|
||||
if (activityClass == nullptr)
|
||||
{
|
||||
if (activityClass == nullptr) {
|
||||
ALOGE("Failed to get activity class");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get the getClassLoader method ID
|
||||
const jmethodID getClassLoaderMethod = jni->GetMethodID(
|
||||
activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
if (getClassLoaderMethod == nullptr)
|
||||
{
|
||||
const jmethodID getClassLoaderMethod =
|
||||
jni->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
if (getClassLoaderMethod == nullptr) {
|
||||
ALOGE("Failed to get getClassLoader method ID");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Call getClassLoader of the activity object to obtain the class loader
|
||||
const jobject classLoaderObject =
|
||||
jni->CallObjectMethod(activityObject, getClassLoaderMethod);
|
||||
if (classLoaderObject == nullptr)
|
||||
{
|
||||
const jobject classLoaderObject = jni->CallObjectMethod(activityObject, getClassLoaderMethod);
|
||||
if (classLoaderObject == nullptr) {
|
||||
ALOGE("Failed to get class loader object");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get the class loader class
|
||||
const jclass classLoaderClass = jni->FindClass("java/lang/ClassLoader");
|
||||
if (classLoaderClass == nullptr)
|
||||
{
|
||||
if (classLoaderClass == nullptr) {
|
||||
ALOGE("Failed to get class loader class");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get the findClass method ID from the class loader class
|
||||
const jmethodID findClassMethod = jni->GetMethodID(
|
||||
classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
if (findClassMethod == nullptr)
|
||||
{
|
||||
const jmethodID findClassMethod =
|
||||
jni->GetMethodID(classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
if (findClassMethod == nullptr) {
|
||||
ALOGE("Failed to get findClass method ID");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Convert the class name string to a jstring
|
||||
const jstring javaClassName = jni->NewStringUTF(className.c_str());
|
||||
if (javaClassName == nullptr)
|
||||
{
|
||||
if (javaClassName == nullptr) {
|
||||
ALOGE("Failed to convert class name to jstring");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Call findClass on the class loader object with the class name
|
||||
const jclass classToFind = static_cast<jclass>(jni->CallObjectMethod(
|
||||
classLoaderObject, findClassMethod, javaClassName));
|
||||
const jclass classToFind = static_cast<jclass>(
|
||||
jni->CallObjectMethod(classLoaderObject, findClassMethod, javaClassName));
|
||||
|
||||
// Clean up local references
|
||||
jni->DeleteLocalRef(activityClass);
|
||||
|
@ -78,15 +70,13 @@ jclass JniUtils::GetGlobalClassReference(JNIEnv* jni, jobject activityObject,
|
|||
jni->DeleteLocalRef(classLoaderClass);
|
||||
jni->DeleteLocalRef(javaClassName);
|
||||
|
||||
if (classToFind == nullptr)
|
||||
{
|
||||
if (classToFind == nullptr) {
|
||||
// Handle error (Class not found)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a global reference to the class
|
||||
const jclass globalClassRef =
|
||||
reinterpret_cast<jclass>(jni->NewGlobalRef(classToFind));
|
||||
const jclass globalClassRef = reinterpret_cast<jclass>(jni->NewGlobalRef(classToFind));
|
||||
|
||||
// Clean up the local reference of the class
|
||||
jni->DeleteLocalRef(classToFind);
|
||||
|
|
|
@ -22,8 +22,6 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
#include <string>
|
||||
|
||||
namespace JniUtils
|
||||
{
|
||||
jclass GetGlobalClassReference(JNIEnv* jni, jobject activityObject,
|
||||
const std::string& className);
|
||||
namespace JniUtils {
|
||||
jclass GetGlobalClassReference(JNIEnv* jni, jobject activityObject, const std::string& className);
|
||||
} // namespace JniUtils
|
||||
|
|
|
@ -20,15 +20,14 @@ License : Licensed under GPLv2 or any later version.
|
|||
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define ALOGV(...) \
|
||||
__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
#ifndef NDEBUG
|
||||
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define ALOGD(...)
|
||||
#endif
|
||||
#define FAIL(...) \
|
||||
do { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__); \
|
||||
abort(); \
|
||||
#define FAIL(...) \
|
||||
do { \
|
||||
__android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
|
|
@ -14,44 +14,41 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
namespace SyspropUtils
|
||||
{
|
||||
static inline float GetSysPropAsFloat(const char* propertyName,
|
||||
const float defaultValue)
|
||||
{
|
||||
char value[PROP_VALUE_MAX];
|
||||
namespace SyspropUtils {
|
||||
static inline float GetSysPropAsFloat(const char* propertyName, const float defaultValue) {
|
||||
char value[PROP_VALUE_MAX];
|
||||
int32_t length = __system_property_get(propertyName, value);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if (length > 0) {
|
||||
// Attempt to convert the string to a float
|
||||
char* end;
|
||||
float float_value = std::strtof(value, &end);
|
||||
|
||||
// Check if the conversion was successful (end points to the end of the
|
||||
// number)
|
||||
if (end != value) { return float_value; }
|
||||
if (end != value) {
|
||||
return float_value;
|
||||
}
|
||||
}
|
||||
|
||||
// Return default value if property is not set or conversion failed
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static inline int32_t GetSysPropAsInt(const char* propertyName,
|
||||
const int32_t defaultValue)
|
||||
{
|
||||
char value[PROP_VALUE_MAX];
|
||||
static inline int32_t GetSysPropAsInt(const char* propertyName, const int32_t defaultValue) {
|
||||
char value[PROP_VALUE_MAX];
|
||||
int32_t length = __system_property_get(propertyName, value);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if (length > 0) {
|
||||
// Attempt to convert the string to an int
|
||||
char* end;
|
||||
char* end;
|
||||
int32_t int_value = std::strtol(value, &end, 10);
|
||||
|
||||
// Check if the conversion was successful (end points to the end of the
|
||||
// number)
|
||||
if (end != value) { return int_value; }
|
||||
if (end != value) {
|
||||
return int_value;
|
||||
}
|
||||
}
|
||||
|
||||
// Return default value if property is not set or conversion failed
|
||||
|
|
|
@ -12,8 +12,8 @@ License : Licensed under GPLv2 or any later version.
|
|||
|
||||
#include "LogUtils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef MATH_FLOAT_PI
|
||||
#define MATH_FLOAT_PI 3.14159265358979323846f
|
||||
|
@ -23,34 +23,27 @@ License : Licensed under GPLv2 or any later version.
|
|||
#define MATH_FLOAT_TWOPI MATH_FLOAT_PI * 2.0f
|
||||
#endif
|
||||
|
||||
static inline XrVector2f operator*(const XrVector2f& lhs, const float rhs)
|
||||
{
|
||||
static inline XrVector2f operator*(const XrVector2f& lhs, const float rhs) {
|
||||
return XrVector2f{lhs.x * rhs, lhs.y * rhs};
|
||||
}
|
||||
|
||||
static inline XrVector3f operator+(const XrVector3f& lhs, const XrVector3f& rhs)
|
||||
{
|
||||
static inline XrVector3f operator+(const XrVector3f& lhs, const XrVector3f& rhs) {
|
||||
return XrVector3f{lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z};
|
||||
}
|
||||
|
||||
static inline XrVector3f operator-(const XrVector3f& lhs, const XrVector3f& rhs)
|
||||
{
|
||||
static inline XrVector3f operator-(const XrVector3f& lhs, const XrVector3f& rhs) {
|
||||
return XrVector3f{lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z};
|
||||
}
|
||||
|
||||
static inline XrVector3f operator*(const XrVector3f& lhs, const float rhs)
|
||||
{
|
||||
static inline XrVector3f operator*(const XrVector3f& lhs, const float rhs) {
|
||||
return XrVector3f{lhs.x * rhs, lhs.y * rhs, lhs.z * rhs};
|
||||
}
|
||||
|
||||
static inline XrVector3f operator*(const float lhs, const XrVector3f& rhs)
|
||||
{
|
||||
static inline XrVector3f operator*(const float lhs, const XrVector3f& rhs) {
|
||||
return XrVector3f{lhs * rhs.x, lhs * rhs.y, lhs * rhs.z};
|
||||
}
|
||||
|
||||
static inline XrQuaternionf operator*(const XrQuaternionf& lhs,
|
||||
const XrQuaternionf& rhs)
|
||||
{
|
||||
static inline XrQuaternionf operator*(const XrQuaternionf& lhs, const XrQuaternionf& rhs) {
|
||||
XrQuaternionf result;
|
||||
result.x = lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y;
|
||||
result.y = lhs.w * rhs.y - lhs.x * rhs.z + lhs.y * rhs.w + lhs.z * rhs.x;
|
||||
|
@ -59,75 +52,64 @@ static inline XrQuaternionf operator*(const XrQuaternionf& lhs,
|
|||
return result;
|
||||
}
|
||||
|
||||
namespace XrMath
|
||||
{
|
||||
namespace XrMath {
|
||||
|
||||
static constexpr float kEpsilon = 0.00001f;
|
||||
|
||||
static inline float SafeRcpSqrt(const float x)
|
||||
{
|
||||
return (x >= std::numeric_limits<float>::min())
|
||||
? 1.0f / sqrtf(x)
|
||||
: std::numeric_limits<float>::max();
|
||||
static inline float SafeRcpSqrt(const float x) {
|
||||
return (x >= std::numeric_limits<float>::min()) ? 1.0f / sqrtf(x)
|
||||
: std::numeric_limits<float>::max();
|
||||
}
|
||||
|
||||
class Vector3f
|
||||
{
|
||||
class Vector3f {
|
||||
public:
|
||||
static float LengthSq(const XrVector3f& v)
|
||||
{
|
||||
static float LengthSq(const XrVector3f& v) {
|
||||
return v.x * v.x + v.y * v.y + v.z * v.z;
|
||||
}
|
||||
static float Length(const XrVector3f& v) { return sqrtf(LengthSq(v)); }
|
||||
static float Length(const XrVector3f& v) {
|
||||
return sqrtf(LengthSq(v));
|
||||
}
|
||||
|
||||
static void Normalize(XrVector3f& v)
|
||||
{
|
||||
static void Normalize(XrVector3f& v) {
|
||||
const float lengthRcp = SafeRcpSqrt(LengthSq(v));
|
||||
v.x *= lengthRcp;
|
||||
v.y *= lengthRcp;
|
||||
v.z *= lengthRcp;
|
||||
}
|
||||
|
||||
static XrVector3f Normalized(const XrVector3f& v)
|
||||
{
|
||||
static XrVector3f Normalized(const XrVector3f& v) {
|
||||
XrVector3f res = v;
|
||||
Normalize(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static XrVector3f Cross(const XrVector3f& a, const XrVector3f& b)
|
||||
{
|
||||
return XrVector3f{a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z,
|
||||
a.x * b.y - a.y * b.x};
|
||||
static XrVector3f Cross(const XrVector3f& a, const XrVector3f& b) {
|
||||
return XrVector3f{a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
|
||||
}
|
||||
};
|
||||
|
||||
class Quatf
|
||||
{
|
||||
class Quatf {
|
||||
public:
|
||||
static XrQuaternionf Identity()
|
||||
{
|
||||
static XrQuaternionf Identity() {
|
||||
return XrQuaternionf{0.0f, 0.0f, 0.0f, 1.0f};
|
||||
}
|
||||
|
||||
// Given a yaw (Y-axis), pitch (X-axis) and roll (Z-axis) in radians, create
|
||||
// a quaternion representing the same rotation
|
||||
static XrQuaternionf FromEuler(const float yawInRadians,
|
||||
const float pitchInRadians,
|
||||
const float rollInRadians)
|
||||
{
|
||||
static XrQuaternionf FromEuler(const float yawInRadians, const float pitchInRadians,
|
||||
const float rollInRadians) {
|
||||
// Calculate half angles
|
||||
const float halfPitch = pitchInRadians * 0.5f;
|
||||
const float halfYaw = yawInRadians * 0.5f;
|
||||
const float halfRoll = rollInRadians * 0.5f;
|
||||
const float halfYaw = yawInRadians * 0.5f;
|
||||
const float halfRoll = rollInRadians * 0.5f;
|
||||
|
||||
// Calculate sin and cos for each half angle
|
||||
const float sinPitch = std::sin(halfPitch);
|
||||
const float cosPitch = std::cos(halfPitch);
|
||||
const float sinYaw = std::sin(halfYaw);
|
||||
const float cosYaw = std::cos(halfYaw);
|
||||
const float sinRoll = std::sin(halfRoll);
|
||||
const float cosRoll = std::cos(halfRoll);
|
||||
const float sinYaw = std::sin(halfYaw);
|
||||
const float cosYaw = std::cos(halfYaw);
|
||||
const float sinRoll = std::sin(halfRoll);
|
||||
const float cosRoll = std::cos(halfRoll);
|
||||
|
||||
// Create quaternions for each rotation
|
||||
const XrQuaternionf qx = {sinPitch, 0.0f, 0.0f, cosPitch};
|
||||
|
@ -139,43 +121,36 @@ public:
|
|||
}
|
||||
|
||||
// Yaw (around Y-axis)
|
||||
static float GetYawInRadians(const XrQuaternionf& q)
|
||||
{
|
||||
static float GetYawInRadians(const XrQuaternionf& q) {
|
||||
assert(IsNormalized(q));
|
||||
return atan2f(2.0f * (q.x * q.y + q.w * q.z),
|
||||
q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z);
|
||||
}
|
||||
|
||||
// Pitch (around X-axis)
|
||||
static float GetPitchInRadians(const XrQuaternionf& q)
|
||||
{
|
||||
static float GetPitchInRadians(const XrQuaternionf& q) {
|
||||
assert(IsNormalized(q));
|
||||
return asinf(-2.0f * (q.x * q.z - q.w * q.y));
|
||||
}
|
||||
|
||||
// Roll (around Z-axis)
|
||||
static float GetRollInRadians(const XrQuaternionf& q)
|
||||
{
|
||||
static float GetRollInRadians(const XrQuaternionf& q) {
|
||||
assert(IsNormalized(q));
|
||||
return atan2f(2.0f * (q.y * q.z + q.w * q.x),
|
||||
q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool IsNormalized(const XrQuaternionf& q)
|
||||
{
|
||||
return fabs(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w - 1.0f) <
|
||||
kEpsilon;
|
||||
[[maybe_unused]] static bool IsNormalized(const XrQuaternionf& q) {
|
||||
return fabs(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w - 1.0f) < kEpsilon;
|
||||
}
|
||||
|
||||
static XrQuaternionf Inverted(const XrQuaternionf& q)
|
||||
{
|
||||
static XrQuaternionf Inverted(const XrQuaternionf& q) {
|
||||
assert(IsNormalized(q));
|
||||
return XrQuaternionf{-q.x, -q.y, -q.z, q.w};
|
||||
}
|
||||
// Formula: v' = q * v * q*
|
||||
// Where q* is the conjugate of q
|
||||
static XrVector3f Rotate(const XrQuaternionf& q, const XrVector3f& _v)
|
||||
{
|
||||
static XrVector3f Rotate(const XrQuaternionf& q, const XrVector3f& _v) {
|
||||
assert(IsNormalized(q));
|
||||
|
||||
const float vx = 2 * (q.y * _v.z - q.z * _v.y);
|
||||
|
@ -190,63 +165,47 @@ public:
|
|||
// Compute a quaternion representing a rotation between three orthogonal
|
||||
// basis vectors. These vectors correspond to the forward, up, and right
|
||||
// directions of a rotation matrix.
|
||||
static XrQuaternionf FromThreeVectors(const XrVector3f& forward,
|
||||
const XrVector3f& up,
|
||||
const XrVector3f& right)
|
||||
{
|
||||
static XrQuaternionf FromThreeVectors(const XrVector3f& forward, const XrVector3f& up,
|
||||
const XrVector3f& right) {
|
||||
const float trace = right.x + up.y + forward.z;
|
||||
if (trace > 0.0f)
|
||||
{
|
||||
if (trace > 0.0f) {
|
||||
const float s = 0.5f / sqrtf(trace + 1.0f);
|
||||
return XrQuaternionf{(up.z - forward.y) * s,
|
||||
(forward.x - right.z) * s,
|
||||
return XrQuaternionf{(up.z - forward.y) * s, (forward.x - right.z) * s,
|
||||
(right.y - up.x) * s, 0.25f / s};
|
||||
}
|
||||
if (right.x > up.y && right.x > forward.z)
|
||||
{
|
||||
if (right.x > up.y && right.x > forward.z) {
|
||||
const float s = 2.0f * sqrtf(1.0f + right.x - up.y - forward.z);
|
||||
return XrQuaternionf{0.25f * s, (up.x + right.y) / s,
|
||||
(forward.x + right.z) / s,
|
||||
return XrQuaternionf{0.25f * s, (up.x + right.y) / s, (forward.x + right.z) / s,
|
||||
(up.z - forward.y) / s};
|
||||
}
|
||||
else if (up.y > forward.z)
|
||||
{
|
||||
} else if (up.y > forward.z) {
|
||||
const float s = 2.0f * sqrtf(1.0f + up.y - right.x - forward.z);
|
||||
return XrQuaternionf{(up.x + right.y) / s, 0.25f * s,
|
||||
(forward.y + up.z) / s,
|
||||
return XrQuaternionf{(up.x + right.y) / s, 0.25f * s, (forward.y + up.z) / s,
|
||||
(forward.x - right.z) / s};
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
const float s = 2.0f * sqrtf(1.0f + forward.z - right.x - up.y);
|
||||
return XrQuaternionf{(forward.x + right.z) / s,
|
||||
(forward.y + up.z) / s, 0.25f * s,
|
||||
return XrQuaternionf{(forward.x + right.z) / s, (forward.y + up.z) / s, 0.25f * s,
|
||||
(up.z - forward.y) / s};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Posef
|
||||
{
|
||||
class Posef {
|
||||
public:
|
||||
static XrPosef Identity()
|
||||
{
|
||||
static XrPosef Identity() {
|
||||
return XrPosef{Quatf::Identity(), {0.0f, 0.0f, 0.0f}};
|
||||
}
|
||||
|
||||
static XrVector3f Transform(const XrPosef& pose, const XrVector3f& vector)
|
||||
{
|
||||
static XrVector3f Transform(const XrPosef& pose, const XrVector3f& vector) {
|
||||
return Quatf::Rotate(pose.orientation, vector) + pose.position;
|
||||
}
|
||||
|
||||
static XrPosef Inverted(const XrPosef& pose)
|
||||
{
|
||||
static XrPosef Inverted(const XrPosef& pose) {
|
||||
const XrQuaternionf invOrientation = Quatf::Inverted(pose.orientation);
|
||||
|
||||
XrVector3f invPosition = Quatf::Rotate(invOrientation, pose.position);
|
||||
invPosition.x = -invPosition.x;
|
||||
invPosition.y = -invPosition.y;
|
||||
invPosition.z = -invPosition.z;
|
||||
invPosition.x = -invPosition.x;
|
||||
invPosition.y = -invPosition.y;
|
||||
invPosition.z = -invPosition.z;
|
||||
|
||||
return {invOrientation, invPosition};
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue