3rdparty: Import osgXR 0.3.7+
Import osgXR from https://github.com/amalon/osgXR master branch into 3rdparty, specifically commit b7e222775553b529018ac4b847353327c24ae5d4, which is 0.3.7 with tweaks for building as a subproject in a subdirectory. This will allow VR support to be more conveniently built if not already installed, without having to fetch yet another dependency.
This commit is contained in:
parent
31956f1f33
commit
0431e7cb3c
83 changed files with 12256 additions and 0 deletions
184
3rdparty/osgXR/CHANGELOG.md
vendored
Normal file
184
3rdparty/osgXR/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,184 @@
|
|||
Version 0.3.7
|
||||
-------------
|
||||
|
||||
New features:
|
||||
* Implement basic Windows OpenGL graphics binding.
|
||||
|
||||
Windows (MSVC) build fixes:
|
||||
* Session: #ifdef X11 specific workaround.
|
||||
* CMake: Require osgUtil.
|
||||
* Manager: Avoid undefined Mirror.
|
||||
* Fix Win32 DLL imports/exports.
|
||||
* Subaction: Use C++11 smart pointers for \_private to avoid undefined Private
|
||||
implementation class.
|
||||
* Fix build against old OpenGL headers.
|
||||
|
||||
ABI changes (ABI version 5):
|
||||
* Subaction: Use C++11 smart pointers for \_private.
|
||||
* Switch Action, ActionSet & InteractionProfile pimpls to std::unique\_ptr<>.
|
||||
|
||||
Version 0.3.6
|
||||
-------------
|
||||
|
||||
Bug fixes:
|
||||
* Work around Monado GL context assumptions for xrCreateSession &
|
||||
xrCreateSwapchain calls.
|
||||
* Permit new swapchain formats: GL\_RGB10\_A2 (for Monado on AMD) & GL\_RGBA8.
|
||||
|
||||
Behaviour changes:
|
||||
* Report list of swapchain formats on failure to choose one.
|
||||
|
||||
Behind the scenes:
|
||||
* Minor whitespace cleanups in src/XRState.cpp.
|
||||
|
||||
Version 0.3.5
|
||||
-------------
|
||||
|
||||
Bug fixes:
|
||||
* Ensure OpenXR::Action is valid before creating an action state object.
|
||||
* Don't suggest empty InteractionProfile bindings to OpenXR.
|
||||
|
||||
Behaviour changes:
|
||||
* Manager (XRState) no longer keeps counted references to ActionSets or
|
||||
InteractionProfiles. The app should manage the lifetime of these objects
|
||||
itself, and can now safely discard and recreate them.
|
||||
* All created Actions are now provided to OpenXR even if unreferenced by any
|
||||
InteractionProfile suggested bindings.
|
||||
* Action setup is now treated as a separate initialisation stage. As such if
|
||||
no action sets or no interaction profiles have been created, action setup
|
||||
will now take place on the next update() after they are created.
|
||||
|
||||
New/expanded APIs:
|
||||
* Manager::syncActionSet() - To inform osgXR that actions, action sets, or
|
||||
interaction profiles have been altered, so it can take action to apply them
|
||||
as soon as possible.
|
||||
* ActionPose::Location::operator !=, ActionPose::Location::operator == - For
|
||||
comparing pose location objects for equality.
|
||||
|
||||
Behind the scenes:
|
||||
* Some minor refactoring in src/Action.cpp.
|
||||
|
||||
Version 0.3.4
|
||||
-------------
|
||||
|
||||
Bug fixes:
|
||||
* Fix draw pass accounting and slave cam VR mode.
|
||||
|
||||
Behaviour changes:
|
||||
* Automatically fall back from SceneView mode if the view configuration isn't
|
||||
stereo.
|
||||
|
||||
New/expanded APIs:
|
||||
* New action APIs for exposing OpenXR actions (both input and haptics), action
|
||||
sets, interaction profiles, and subactions:
|
||||
* osgXR/Action: New Action, ActionBoolean, ActionFloat, ActionVector2f,
|
||||
ActionPose and ActionVibration classes to represent different kinds of
|
||||
XrAction.
|
||||
* osgXR/ActionSet: New ActionSet class to group actions that can be activated
|
||||
and deactivated together.
|
||||
* osgXR/InteractionProfile: New InteractionProfile class to allows default
|
||||
action bindings for interaction profiles to be suggested.
|
||||
* osgXR/Subaction: New Subaction class to represent a subaction path (or top
|
||||
level user path) which groups physical interactions, allowing single
|
||||
actions that apply to both hands to be handled separately.
|
||||
|
||||
Behind the scenes:
|
||||
* Add internal action management classes in OpenXR namespace.
|
||||
* Wrap XrSpace in an OpenXR::Space class.
|
||||
* Wrap XrPath in an OpenXR::Path class.
|
||||
* Extend inline code documentation.
|
||||
* Code cleanups.
|
||||
|
||||
Version 0.3.3 (formerly 0.4.0)
|
||||
------------------------------
|
||||
|
||||
New/expanded APIs:
|
||||
* Settings::getVisibilityMask(), Settings::getVisibilityMask() - for setting
|
||||
whether osgXR should create visibility masks (when supported by the OpenXR
|
||||
runtime).
|
||||
* Manager::hasVisibilityMaskExtension() - for finding whether the visibility
|
||||
mask extension is supported by the OpenXR runtime.
|
||||
* Manager::setVisibilityMaskNodeMasks() - for setting the left and right eye
|
||||
NodeMasks to use for visibility masks.
|
||||
|
||||
Behind the scenes:
|
||||
* Implement creation, caching, and updating of visibility mask geometry for each
|
||||
OpenXR view.
|
||||
* Implement rendering of visibility masks to the depth buffer to reduce fragment
|
||||
overhead when GPU bound.
|
||||
|
||||
Version 0.3.2
|
||||
-------------
|
||||
|
||||
Bug fixes:
|
||||
* Fix a couple of bugs around session recreation (used when VR or swapchain mode
|
||||
changes).
|
||||
|
||||
Behaviour changes:
|
||||
* Pick depth buffer format based on GraphicsContext traits depth bits.
|
||||
* Enable depth info submission at session state to allow it to be dynamically
|
||||
switched without hitting a SteamVR hang during instance destruction.
|
||||
|
||||
Behind the scenes:
|
||||
* Fix a few inconsequential compiler warnings with -Wall.
|
||||
* Minor cosmetic cleanups (whitespace, explicit include).
|
||||
|
||||
Version 0.3.1
|
||||
-------------
|
||||
|
||||
Behind the scenes:
|
||||
* Fix possible crash in XRState::isRunning() if session is delayed coming up.
|
||||
|
||||
Version 0.3.0
|
||||
-------------
|
||||
|
||||
API changes:
|
||||
* Manager::checkAndResetStateChanged() - to detect when VR state may have
|
||||
changed, requiring app caches to be invalidated or synchronised with the new
|
||||
state.
|
||||
|
||||
Version 0.2.1
|
||||
-------------
|
||||
|
||||
Behind the scenes:
|
||||
* Make frame view location accessors thread safe so multiple cull threads can be
|
||||
used.
|
||||
|
||||
Version 0.2.0
|
||||
-------------
|
||||
|
||||
API changes:
|
||||
* Cleanups (moving dynamic bits out of Settings).
|
||||
* Manager::update() - should be called regularly to allow for incremental
|
||||
bringup and OpenXR event handling.
|
||||
* Manager::setEnabled() - for triggering bringing up/down of VR.
|
||||
|
||||
New/expanded APIs:
|
||||
* Manager::destroyAndWait() and Manager::isDestroying() - for clean shutdown
|
||||
before program exit.
|
||||
* Manager::syncSettings() - to trigger appropriate reinitialisation to handle
|
||||
any changed settings.
|
||||
* Manager::getStateString() - to get a user readable description of the current
|
||||
VR state.
|
||||
* Manager::onRunning() - virtual callback when VR has started (consider setting
|
||||
up desktop mirrors).
|
||||
* Manager::onStopped() - virtual callback when VR has stopped (consider
|
||||
removing desktop mirrors).
|
||||
* Manager::onFocus() - virtual callback when VR app is running in focus
|
||||
(consider resuming if paused).
|
||||
* Manager::onUnfocus() - virtual callback when VR app has lost focus (consider
|
||||
pausing the experience).
|
||||
|
||||
Behind the scenes highlights:
|
||||
* Make OpenXR bringup incremental, reversible and restartable.
|
||||
* Improved handling of SteamVR's messing with GL context and threading.
|
||||
* Separated event handling.
|
||||
|
||||
Version 0.1.0
|
||||
-------------
|
||||
|
||||
This represents early development with the API still in heavy flux.
|
||||
|
||||
It supported:
|
||||
* A Manager class with virtual callbacks for configuring views.
|
||||
* Desktop mirrors of the VR views.
|
79
3rdparty/osgXR/CMakeLists.txt
vendored
Normal file
79
3rdparty/osgXR/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Top level CMakeLists.txt
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
|
||||
set(osgXR_MAJOR_VERSION 0)
|
||||
set(osgXR_MINOR_VERSION 3)
|
||||
set(osgXR_PATCH_VERSION 7)
|
||||
set(osgXR_SOVERSION 5)
|
||||
|
||||
set(osgXR_VERSION "${osgXR_MAJOR_VERSION}.${osgXR_MINOR_VERSION}.${osgXR_PATCH_VERSION}")
|
||||
|
||||
project(osgXR
|
||||
VERSION ${osgXR_VERSION}
|
||||
DESCRIPTION "OpenXR integration for OpenSceneGraph applications"
|
||||
)
|
||||
|
||||
if(CMAKE_PROJECT_NAME STREQUAL osgXR)
|
||||
# Normal top level project build, install package components
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Build options
|
||||
option(BUILD_SHARED_LIBS "Whether to build as a shared library" ON)
|
||||
option(BUILD_OSGXR_EXAMPLES "Enable to build osgXR examples" OFF)
|
||||
|
||||
# Source files in src/
|
||||
add_subdirectory(src)
|
||||
|
||||
if(BUILD_OSGXR_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
set(INSTALL_INCDIR "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
# Preprocess pkgconfig file
|
||||
configure_file(osgXR.pc.in osgXR.pc @ONLY)
|
||||
|
||||
# Preprocess package config
|
||||
configure_package_config_file(Config.cmake.in osgXRConfig.cmake
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/osgXR"
|
||||
PATH_VARS INSTALL_INCDIR
|
||||
)
|
||||
# Build package version file
|
||||
write_basic_package_version_file(osgXRConfigVersion.cmake
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
COMPATIBILITY SameMinorVersion
|
||||
)
|
||||
|
||||
# Install library and headers
|
||||
install(TARGETS osgXR
|
||||
EXPORT osgXRTargets
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
PUBLIC_HEADER DESTINATION "${INSTALL_INCDIR}/osgXR"
|
||||
INCLUDES DESTINATION "${INSTALL_INCDIR}"
|
||||
)
|
||||
# Install pkgconfig file
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/osgXR.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
|
||||
)
|
||||
# Install export targets
|
||||
install(EXPORT osgXRTargets
|
||||
FILE osgXRTargets.cmake
|
||||
NAMESPACE osgXR::
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/osgXR"
|
||||
)
|
||||
# Install package config and version files
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/osgXRConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/osgXRConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/osgXR"
|
||||
)
|
||||
|
||||
else()
|
||||
# Subproject build
|
||||
|
||||
# Just build src/ as a static library
|
||||
set(osgXR_LIBRARY_TYPE STATIC)
|
||||
add_subdirectory(src)
|
||||
|
||||
endif()
|
14
3rdparty/osgXR/Config.cmake.in
vendored
Normal file
14
3rdparty/osgXR/Config.cmake.in
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(OpenGL)
|
||||
find_dependency(OpenSceneGraph COMPONENTS osgViewer)
|
||||
find_dependency(OpenXR)
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set_and_check(osgXR_INCLUDE_DIR @PACKAGE_INSTALL_INCDIR@)
|
||||
set(osgXR_LIBRARY osgXR::osgXR)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/osgXRTargets.cmake")
|
||||
|
||||
check_required_components(osgXR)
|
502
3rdparty/osgXR/LICENSE.txt
vendored
Normal file
502
3rdparty/osgXR/LICENSE.txt
vendored
Normal file
|
@ -0,0 +1,502 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
73
3rdparty/osgXR/README.md
vendored
Normal file
73
3rdparty/osgXR/README.md
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
osgXR: Virtual Reality with OpenXR and OpenSceneGraph
|
||||
=====================================================
|
||||
|
||||
This library is to allow Virtual Reality support to be added to
|
||||
[OpenSceneGraph](http://www.openscenegraph.org/) applications, using the
|
||||
[OpenXR](https://www.khronos.org/OpenXR/) standard.
|
||||
|
||||
Status:
|
||||
* Still in development, contributions welcome. Plenty of work to do.
|
||||
* APIs to support OpenXR VR display output in OpenSceneGraph apps.
|
||||
* APIs to support OpenXR's action based input and haptic output for controller
|
||||
interaction.
|
||||
* OpenGL graphics bindings for Linux (X11/Xlib) and Windows (note that WMR
|
||||
only supports DirectX bindings).
|
||||
|
||||
License: LGPL 2.1
|
||||
|
||||
Dependencies: OpenSceneGraph, OpenXR
|
||||
|
||||
Links:
|
||||
* Matrix room: [#osgxr:hoganfam.uk](https://matrix.to/#/#osgxr:hoganfam.uk?via=hoganfam.uk)
|
||||
* [OpenXR specifications](https://www.khronos.org/registry/OpenXR/#apispecs)
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Something like this:
|
||||
```shell
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
To import osgXR into a CMake based project, you can use the included CMake
|
||||
module, adding something like this to your CMakeLists.txt:
|
||||
```cmake
|
||||
find_package(osgXR 0.3.5 REQUIRED)
|
||||
|
||||
target_link_libraries(target
|
||||
..
|
||||
osgXR::osgXR
|
||||
)
|
||||
```
|
||||
|
||||
osgXR can also optionally be built as a subproject. Consider using ``git
|
||||
subtree`` to import osgXR, then use something like this:
|
||||
```cmake
|
||||
add_subdirectory(osgXR)
|
||||
|
||||
target_link_libraries(target
|
||||
..
|
||||
osgXR
|
||||
)
|
||||
```
|
||||
|
||||
If you have installed osgXR outside of the system prefix (CMake's default prefix
|
||||
on UNIX systems is ``/usr/local``), you may need to tell CMake where to find it
|
||||
when you configure the project. You can do this by defining ``osgXR_DIR`` when
|
||||
invoking cmake, e.g. with the argument ``-DosgXR_DIR=$PREFIX/lib/cmake/osgXR``
|
||||
where ``$PREFIX`` is osgXR's install prefix (``CMAKE_INSTALL_PREFIX``).
|
||||
|
||||
|
||||
The Public API
|
||||
--------------
|
||||
|
||||
See the [API documentation](docs/API.md) for details of the API.
|
102
3rdparty/osgXR/docs/API.md
vendored
Normal file
102
3rdparty/osgXR/docs/API.md
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
osgXR API Documentation
|
||||
=======================
|
||||
|
||||
The osgXR API is currently considered unstable, however it is versioned. Only
|
||||
matching minor version numbers should be expected to be source and binary
|
||||
compatible with one another.
|
||||
|
||||
The osgXR headers can be found in [include/osgXR/](../include/osgXR/).
|
||||
|
||||
The initial version of this library exposed ``<osgXR/OpenXRDisplay>`` for
|
||||
configuring a view for VR, and ``<osgXR/osgXR>`` with a convenience wrapper
|
||||
``osgXR::setupViewerDefaults`` to set up VR automatically based on environment
|
||||
variables. This worked for most simple OpenSceneGraph examples, however for real
|
||||
projects something more capable is needed, so it is likely these will be removed
|
||||
in a future version (they are not currently working due to the new
|
||||
``XRState::update()`` based state machine).
|
||||
|
||||
It is instead recommended to extend the ``osgXR::Manager`` class from
|
||||
``<osgXR/Manager>`` and implement the callbacks.
|
||||
|
||||
## <[osgXR/Action](../include/osgXR/Action)>
|
||||
|
||||
This header provides the ``osgXR::Action`` base class, and the
|
||||
``osgXR::ActionBoolean``, ``osgXR::ActionFloat``, ``osgXR::ActionVector2f``,
|
||||
``osgXR::ActionPose`` and ``osgXR::ActionVibration`` classes which an
|
||||
application can use to define OpenXR actions, read input state, and send haptic
|
||||
output.
|
||||
|
||||
## <[osgXR/ActionSet](../include/osgXR/ActionSet)>
|
||||
|
||||
This header provides the ``osgXR::ActionSet`` class which an application uses
|
||||
to group actions into groups which can be separately activated and deactivated.
|
||||
|
||||
## <[osgXR/InteractionProfile](../include/osgXR/InteractionProfile)>
|
||||
|
||||
This header provides the ``osgXR::InteractionProfile`` class which an
|
||||
application uses to suggest bindings between OpenXR actions and the physical
|
||||
interactions of a given OpenXR controller profile.
|
||||
|
||||
## <[osgXR/Manager](../include/osgXR/Manager)>
|
||||
|
||||
This header provides the ``osgXR::Manager`` class which an application can
|
||||
extend to implement a VR manager class. Virtual callbacks tell the application
|
||||
which camera views are required to implement VR, and an ``update()`` function
|
||||
gives osgXR a chance to incrementally bring up or tear down VR.
|
||||
|
||||
## <[osgXR/Mirror](../include/osgXR/Mirror)>
|
||||
|
||||
This header provides the ``osgXR::Mirror`` class which an application can use to
|
||||
register a desktop mirror of the VR view.
|
||||
|
||||
## <[osgXR/MirrorSettings](../include/osgXR/MirrorSettings)>
|
||||
|
||||
This header provides the ``osgXR::MirrorSettings`` class which encapsulates
|
||||
configuration data for desktop mirrors of VR views.
|
||||
|
||||
## <[osgXR/OpenXRDisplay](../include/osgXR/OpenXRDisplay)>
|
||||
|
||||
This header provides the ``osgXR::OpenXRDisplay`` ViewConfig class. It is
|
||||
largely replaced by ``osgXR::Manager``.
|
||||
|
||||
## <[osgXR/Settings](../include/osgXR/Settings)>
|
||||
|
||||
This header provides the ``osgXR::Settings`` class which encapsulates all the VR
|
||||
configuration data.
|
||||
|
||||
## <[osgXR/Subaction](../include/osgXR/Subaction)>
|
||||
|
||||
This header provides the ``osgXR::Subaction`` class which an application can
|
||||
use to represent OpenXR subaction paths (top level user paths), which allow a
|
||||
single OpenXR action to represent the same action on both hands. It can be
|
||||
passed to other action related classes to filter actions by hand, and it can be
|
||||
extended by the application to implement a callback for InteractionProfile
|
||||
changes.
|
||||
|
||||
## <[osgXR/View](../include/osgXR/View)>
|
||||
|
||||
This header provides the ``osgXR::View`` class which represents a view of the
|
||||
world which ``osgXR::Manager`` will request to be configured by the application.
|
||||
|
||||
## <[osgXR/osgXR](../include/osgXR/osgXR)>
|
||||
|
||||
This header provides convenience functions for quick and easy integration of VR
|
||||
capabilities into a simple OpenSceneGraph application or example. It is
|
||||
recommended ``osgXR::Manager`` be used instead for most projects.
|
||||
|
||||
### osgXR::setupViewerDefaults()
|
||||
|
||||
This sets up VR on the provided viewer based on the content of the following
|
||||
environment variables:
|
||||
* ``OSGXR=1`` enables VR.
|
||||
* ``OSGXR_MODE=SLAVE_CAMERAS`` forces the use of separate slave cameras per view.
|
||||
* ``OSGXR_MODE=SCENE_VIEW`` forces the use of OpenSceneGraph's SceneView stereo (default).
|
||||
* ``OSGXR_SWAPCHAIN=MULTIPLE`` forces the use of separate swapchains per view.
|
||||
* ``OSGXR_SWAPCHAIN=SINGLE`` forces the use of a single swapchain containing all views.
|
||||
* ``OSGXR_UNITS_PER_METER=10`` allows the scale of the environment to be controlled.
|
||||
* ``OSGXR_VALIDATION_LAYER=1`` enables the OpenXR validation layer (off by default).
|
||||
* ``OSGXR_DEPTH_INFO=1`` enables passing of depth information to OpenXR (off by default).
|
||||
* ``OSGXR_MIRROR=NONE`` use a blank screen as the default mirror.
|
||||
* ``OSGXR_MIRROR=LEFT`` use OpenXR view 0 (left) as the default mirror.
|
||||
* ``OSGXR_MIRROR=RIGHT`` use OpenXR view 1 (right) as the default mirror.
|
||||
* ``OSGXR_MIRROR=LEFT_RIGHT`` use both left and right views side by side as the default mirror.
|
29
3rdparty/osgXR/examples/CMakeLists.txt
vendored
Normal file
29
3rdparty/osgXR/examples/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
cmake_minimum_required(VERSION 3.11)
|
||||
project(osgXR::examples)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(OpenSceneGraph REQUIRED COMPONENTS osgDB osgViewer)
|
||||
|
||||
if(CMAKE_PROJECT_NAME STREQUAL osgXR)
|
||||
# If we're building from osgXR source tree, take a shortcut
|
||||
set(osgXR_INCLUDE_DIR "../include")
|
||||
set(osgXR_LIBRARY osgXR)
|
||||
else()
|
||||
# Otherwise, we'd normally use osgXR::osgXR, but osgXR_LIBRARY will do here
|
||||
find_package(osgXR REQUIRED)
|
||||
endif()
|
||||
|
||||
add_executable(osgteapot osgteapot.cpp)
|
||||
|
||||
target_include_directories(osgteapot
|
||||
PRIVATE
|
||||
${OPENGL_INCLUDE_DIR}
|
||||
${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(osgteapot
|
||||
PUBLIC
|
||||
${OPENGL_LIBRARIES}
|
||||
${OPENSCENEGRAPH_LIBRARIES}
|
||||
${osgXR_LIBRARY}
|
||||
)
|
365
3rdparty/osgXR/examples/osgteapot.cpp
vendored
Normal file
365
3rdparty/osgXR/examples/osgteapot.cpp
vendored
Normal file
|
@ -0,0 +1,365 @@
|
|||
/* OpenSceneGraph example, osgteapot.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/TexGen>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
#include <osgXR/osgXR>
|
||||
|
||||
|
||||
// The classic OpenGL teapot... taken form glut-3.7/lib/glut/glut_teapot.c
|
||||
|
||||
/* Copyright (c) Mark J. Kilgard, 1994. */
|
||||
|
||||
/**
|
||||
(c) Copyright 1993, Silicon Graphics, Inc.
|
||||
|
||||
ALL RIGHTS RESERVED
|
||||
|
||||
Permission to use, copy, modify, and distribute this software
|
||||
for any purpose and without fee is hereby granted, provided
|
||||
that the above copyright notice appear in all copies and that
|
||||
both the copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of Silicon
|
||||
Graphics, Inc. not be used in advertising or publicity
|
||||
pertaining to distribution of the software without specific,
|
||||
written prior permission.
|
||||
|
||||
THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
|
||||
"AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
|
||||
OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO
|
||||
EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE
|
||||
ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
|
||||
CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
|
||||
INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
|
||||
SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
|
||||
NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY
|
||||
OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
US Government Users Restricted Rights
|
||||
|
||||
Use, duplication, or disclosure by the Government is subject to
|
||||
restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
|
||||
(c)(1)(ii) of the Rights in Technical Data and Computer
|
||||
Software clause at DFARS 252.227-7013 and/or in similar or
|
||||
successor clauses in the FAR or the DOD or NASA FAR
|
||||
Supplement. Unpublished-- rights reserved under the copyright
|
||||
laws of the United States. Contractor/manufacturer is Silicon
|
||||
Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA
|
||||
94039-7311.
|
||||
|
||||
OpenGL(TM) is a trademark of Silicon Graphics, Inc.
|
||||
*/
|
||||
|
||||
|
||||
/* Rim, body, lid, and bottom data must be reflected in x and
|
||||
y; handle and spout data across the y axis only. */
|
||||
|
||||
static int patchdata[][16] =
|
||||
{
|
||||
/* rim */
|
||||
{102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15},
|
||||
/* body */
|
||||
{12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27},
|
||||
{24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 39, 40},
|
||||
/* lid */
|
||||
{96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101,
|
||||
101, 0, 1, 2, 3,},
|
||||
{0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112,
|
||||
113, 114, 115, 116, 117},
|
||||
/* bottom */
|
||||
{118, 118, 118, 118, 124, 122, 119, 121, 123, 126,
|
||||
125, 120, 40, 39, 38, 37},
|
||||
/* handle */
|
||||
{41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
||||
53, 54, 55, 56},
|
||||
{53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
|
||||
28, 65, 66, 67},
|
||||
/* spout */
|
||||
{68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83},
|
||||
{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
|
||||
92, 93, 94, 95}
|
||||
};
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
static float cpdata[][3] =
|
||||
{
|
||||
{0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0,
|
||||
-0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125},
|
||||
{0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375,
|
||||
0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375,
|
||||
2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84,
|
||||
2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875},
|
||||
{1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75,
|
||||
1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35},
|
||||
{0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2,
|
||||
0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12,
|
||||
0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225},
|
||||
{1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225},
|
||||
{1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0,
|
||||
-1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5,
|
||||
-0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3,
|
||||
2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0,
|
||||
2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0,
|
||||
2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8},
|
||||
{-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3,
|
||||
-0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3,
|
||||
1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2,
|
||||
-0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0,
|
||||
1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0,
|
||||
0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66,
|
||||
0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1},
|
||||
{2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7,
|
||||
-0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0,
|
||||
2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375},
|
||||
{3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475},
|
||||
{3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4},
|
||||
{2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0,
|
||||
3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8,
|
||||
3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4,
|
||||
-0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0,
|
||||
2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4,
|
||||
2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3,
|
||||
2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4},
|
||||
{0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425,
|
||||
-0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425,
|
||||
0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075},
|
||||
{0.84, -1.5, 0.075}
|
||||
};
|
||||
|
||||
static float tex[2][2][2] =
|
||||
{
|
||||
{ {0, 0},
|
||||
{1, 0}},
|
||||
{ {0, 1},
|
||||
{1, 1}}
|
||||
};
|
||||
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static void
|
||||
teapot(GLint grid, GLenum type)
|
||||
{
|
||||
float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3];
|
||||
long i, j, k, l;
|
||||
|
||||
glPushAttrib(GL_ENABLE_BIT | GL_EVAL_BIT);
|
||||
glEnable(GL_AUTO_NORMAL);
|
||||
glEnable(GL_NORMALIZE);
|
||||
glEnable(GL_MAP2_VERTEX_3);
|
||||
glEnable(GL_MAP2_TEXTURE_COORD_2);
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
for (l = 0; l < 3; l++) {
|
||||
p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
|
||||
q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];
|
||||
if (l == 1)
|
||||
q[j][k][l] *= -1.0;
|
||||
if (i < 6) {
|
||||
r[j][k][l] =
|
||||
cpdata[patchdata[i][j * 4 + (3 - k)]][l];
|
||||
if (l == 0)
|
||||
r[j][k][l] *= -1.0;
|
||||
s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
|
||||
if (l == 0)
|
||||
s[j][k][l] *= -1.0;
|
||||
if (l == 1)
|
||||
s[j][k][l] *= -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2,
|
||||
&tex[0][0][0]);
|
||||
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
|
||||
&p[0][0][0]);
|
||||
glMapGrid2f(grid, 0.0, 1.0, grid, 0.0, 1.0);
|
||||
glEvalMesh2(type, 0, grid, 0, grid);
|
||||
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
|
||||
&q[0][0][0]);
|
||||
glEvalMesh2(type, 0, grid, 0, grid);
|
||||
if (i < 6) {
|
||||
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
|
||||
&r[0][0][0]);
|
||||
glEvalMesh2(type, 0, grid, 0, grid);
|
||||
glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
|
||||
&s[0][0][0]);
|
||||
glEvalMesh2(type, 0, grid, 0, grid);
|
||||
}
|
||||
}
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
|
||||
// Now the OSG wrapper for the above OpenGL code, the most complicated bit is computing
|
||||
// the bounding box for the above example, normally you'll find this the easy bit.
|
||||
class Teapot : public osg::Drawable
|
||||
{
|
||||
public:
|
||||
Teapot() {}
|
||||
|
||||
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
|
||||
Teapot(const Teapot& teapot,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
|
||||
osg::Drawable(teapot,copyop) {}
|
||||
|
||||
META_Object(myTeapotApp,Teapot)
|
||||
|
||||
|
||||
// the draw immediate mode method is where the OSG wraps up the drawing of
|
||||
// of OpenGL primitives.
|
||||
virtual void drawImplementation(osg::RenderInfo&) const
|
||||
{
|
||||
// teapot(..) doesn't use vertex arrays at all so we don't need to toggle their state
|
||||
// if we did we'd need to something like following call
|
||||
// state.disableAllVertexArrays(), see src/osg/Geometry.cpp for the low down.
|
||||
|
||||
// just call the OpenGL code.
|
||||
teapot(14,GL_FILL);
|
||||
}
|
||||
|
||||
|
||||
// we need to set up the bounding box of the data too, so that the scene graph knows where this
|
||||
// objects is, for both positioning the camera at start up, and most importantly for culling.
|
||||
virtual osg::BoundingBox computeBoundingBox() const
|
||||
{
|
||||
osg::BoundingBox bbox;
|
||||
|
||||
// follow is some truly horrible code required to calculate the
|
||||
// bounding box of the teapot. Have used the original code above to do
|
||||
// help compute it.
|
||||
float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3];
|
||||
long i, j, k, l;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
|
||||
for (l = 0; l < 3; l++) {
|
||||
p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
|
||||
q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];
|
||||
if (l == 1)
|
||||
q[j][k][l] *= -1.0;
|
||||
|
||||
if (i < 6) {
|
||||
r[j][k][l] =
|
||||
cpdata[patchdata[i][j * 4 + (3 - k)]][l];
|
||||
if (l == 0)
|
||||
r[j][k][l] *= -1.0;
|
||||
s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
|
||||
if (l == 0)
|
||||
s[j][k][l] *= -1.0;
|
||||
if (l == 1)
|
||||
s[j][k][l] *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
bbox.expandBy(osg::Vec3(p[j][k][0],p[j][k][1],p[j][k][2]));
|
||||
bbox.expandBy(osg::Vec3(q[j][k][0],q[j][k][1],q[j][k][2]));
|
||||
|
||||
if (i < 6)
|
||||
{
|
||||
bbox.expandBy(osg::Vec3(r[j][k][0],r[j][k][1],r[j][k][2]));
|
||||
bbox.expandBy(osg::Vec3(s[j][k][0],s[j][k][1],s[j][k][2]));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bbox;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~Teapot() {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
osg::Geode* createTeapot()
|
||||
{
|
||||
osg::Geode* geode = new osg::Geode();
|
||||
|
||||
// add the teapot to the geode.
|
||||
geode->addDrawable( new Teapot );
|
||||
|
||||
// add a reflection map to the teapot.
|
||||
osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile("Images/reflect.rgb");
|
||||
if (image)
|
||||
{
|
||||
osg::Texture2D* texture = new osg::Texture2D;
|
||||
texture->setImage(image);
|
||||
|
||||
osg::TexGen* texgen = new osg::TexGen;
|
||||
texgen->setMode(osg::TexGen::SPHERE_MAP);
|
||||
|
||||
osg::StateSet* stateset = new osg::StateSet;
|
||||
stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
|
||||
stateset->setTextureAttributeAndModes(0,texgen,osg::StateAttribute::ON);
|
||||
|
||||
geode->setStateSet(stateset);
|
||||
}
|
||||
|
||||
return geode;
|
||||
}
|
||||
|
||||
int main(int , char **)
|
||||
{
|
||||
#if 1
|
||||
|
||||
// create viewer on heap as a test, this looks to be causing problems
|
||||
// on init on some platforms, and seg fault on exit when multi-threading on linux.
|
||||
// Normal stack based version below works fine though...
|
||||
|
||||
// construct the viewer.
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
|
||||
|
||||
// add model to viewer.
|
||||
viewer->setSceneData( createTeapot() );
|
||||
|
||||
osgXR::setupViewerDefaults(viewer, "osgteaport", 1);
|
||||
|
||||
return viewer->run();
|
||||
|
||||
#else
|
||||
|
||||
// construct the viewer.
|
||||
osgViewer::Viewer viewer;
|
||||
|
||||
// add model to viewer.
|
||||
viewer.setSceneData( createTeapot() );
|
||||
|
||||
// create the windows and run the threads.
|
||||
return viewer.run();
|
||||
#endif
|
||||
|
||||
}
|
471
3rdparty/osgXR/include/osgXR/Action
vendored
Normal file
471
3rdparty/osgXR/include/osgXR/Action
vendored
Normal file
|
@ -0,0 +1,471 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_Action
|
||||
#define OSGXR_Action 1
|
||||
|
||||
#include <osgXR/Export>
|
||||
|
||||
#include <osg/Quat>
|
||||
#include <osg/Referenced>
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class ActionSet;
|
||||
class Subaction;
|
||||
|
||||
/**
|
||||
* Represents an OpenXR action.
|
||||
* OpenXR actions are inputs & outputs which are abstracted from the physical
|
||||
* input sources. The OpenXR runtime is responsible for binding them to sources,
|
||||
* using suggested bindings in interaction profiles.
|
||||
*
|
||||
* These Action objects can persist across multiple VR sessions, and changes can
|
||||
* be made at any time, however some changes won't take effect while a session
|
||||
* is running.
|
||||
*/
|
||||
class OSGXR_EXPORT Action : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
class Private;
|
||||
|
||||
protected:
|
||||
|
||||
/// Constructor (internal).
|
||||
Action(Private *priv);
|
||||
|
||||
public:
|
||||
|
||||
/// Destructor.
|
||||
~Action();
|
||||
|
||||
/**
|
||||
* Add a subaction that may be later queried.
|
||||
* Any subaction that is intended to be queried must be added to the
|
||||
* action first.
|
||||
* @param subaction Subaction that may be later queried.
|
||||
*/
|
||||
void addSubaction(Subaction *subaction);
|
||||
|
||||
// Accessors
|
||||
|
||||
/**
|
||||
* Set the action's name and localized name.
|
||||
* @param name New name for OpenXR action.
|
||||
* @param localizedName A localized version of @p name.
|
||||
*/
|
||||
void setName(const std::string &name,
|
||||
const std::string &localizedName);
|
||||
|
||||
/**
|
||||
* Set the action's name.
|
||||
* @param name New name for OpenXR action.
|
||||
*/
|
||||
void setName(const std::string &name);
|
||||
/// Get the action's name.
|
||||
const std::string &getName() const;
|
||||
|
||||
/**
|
||||
* Set the action's localized name.
|
||||
* @param localizedName The localized name for the action.
|
||||
*/
|
||||
void setLocalizedName(const std::string &localizedName);
|
||||
/// Get the action's localized name.
|
||||
const std::string &getLocalizedName() const;
|
||||
|
||||
/**
|
||||
* Get a list of currently bound source paths for this action.
|
||||
* @param sourcePaths[out] Vector of source paths to write into.
|
||||
*/
|
||||
void getBoundSources(std::vector<std::string> &sourcePaths) const;
|
||||
|
||||
typedef enum {
|
||||
// Must match XR_INPUT_SOURCE_LOCALIZED_NAME_*
|
||||
/// Include user path (e.g. "Left Hand").
|
||||
USER_PATH_BIT = 1,
|
||||
/// Include interaction profile (e.g. "Vive Controller").
|
||||
INTERACTION_PROFILE_BIT = 2,
|
||||
/// Include input component (e.g. "Trigger").
|
||||
COMPONENT_BIT = 4,
|
||||
} LocalizedNameFlags;
|
||||
|
||||
/**
|
||||
* Get a list of currently bound source localized names for this action.
|
||||
* @param whichComponents Which components to include.
|
||||
* @param names[out] Vector of names to write into.
|
||||
*/
|
||||
void getBoundSourcesLocalizedNames(uint32_t whichComponents,
|
||||
std::vector<std::string> &names) const;
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<Private> _private;
|
||||
|
||||
// Copying not permitted
|
||||
Action(const Action ©);
|
||||
};
|
||||
|
||||
/// An action that can only have boolean values.
|
||||
class OSGXR_EXPORT ActionBoolean : public Action
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a boolean action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
*/
|
||||
ActionBoolean(ActionSet *actionSet);
|
||||
|
||||
/**
|
||||
* Construct a boolean action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action, also used as the
|
||||
* localized name.
|
||||
*/
|
||||
ActionBoolean(ActionSet *actionSet,
|
||||
const std::string &name);
|
||||
|
||||
/**
|
||||
* Construct a boolean action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action.
|
||||
* @param localizedName The localized name for the action.
|
||||
*/
|
||||
ActionBoolean(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName);
|
||||
|
||||
/**
|
||||
* Get the current value of the action as a bool.
|
||||
* @param subaction The subaction to filter sources from, which must
|
||||
* have been specified to Action::addSubaction().
|
||||
* @return The current value of the action.
|
||||
*/
|
||||
bool getValue(Subaction *subaction = nullptr);
|
||||
};
|
||||
|
||||
/// An action that can have floating point values.
|
||||
class OSGXR_EXPORT ActionFloat : public Action
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a floating-point action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
*/
|
||||
ActionFloat(ActionSet *actionSet);
|
||||
|
||||
/**
|
||||
* Construct a floating-point action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action, also used as the
|
||||
* localized name.
|
||||
*/
|
||||
ActionFloat(ActionSet *actionSet,
|
||||
const std::string &name);
|
||||
|
||||
/**
|
||||
* Construct a floating-point action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action.
|
||||
* @param localizedName The localized name for the action.
|
||||
*/
|
||||
ActionFloat(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName);
|
||||
|
||||
/**
|
||||
* Get the current value of the action as a float.
|
||||
* @param subaction The subaction to filter sources from, which must
|
||||
* have been specified to Action::addSubaction().
|
||||
* @return The current value of the action.
|
||||
*/
|
||||
float getValue(Subaction *subaction = nullptr);
|
||||
};
|
||||
|
||||
/// An action that can have 2 dimentional floating point vector values.
|
||||
class OSGXR_EXPORT ActionVector2f : public Action
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a 2d floating-point vector action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
*/
|
||||
ActionVector2f(ActionSet *actionSet);
|
||||
|
||||
/**
|
||||
* Construct a 2d floating-point vector action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action, also used as the
|
||||
* localized name.
|
||||
*/
|
||||
ActionVector2f(ActionSet *actionSet,
|
||||
const std::string &name);
|
||||
|
||||
/**
|
||||
* Construct a 2d floating-point vector action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action.
|
||||
* @param localizedName The localized name for the action.
|
||||
*/
|
||||
ActionVector2f(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName);
|
||||
|
||||
/**
|
||||
* Get the current value of the action as an OSG vector.
|
||||
* @param subaction The subaction to filter sources from, which must
|
||||
* have been specified to Action::addSubaction().
|
||||
* @return The current value of the action.
|
||||
*/
|
||||
osg::Vec2f getValue(Subaction *subaction = nullptr);
|
||||
};
|
||||
|
||||
/// An action that can have pose (position and orientation) values.
|
||||
class OSGXR_EXPORT ActionPose : public Action
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a pose action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
*/
|
||||
ActionPose(ActionSet *actionSet);
|
||||
|
||||
/**
|
||||
* Construct a pose action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action, also used as the
|
||||
* localized name.
|
||||
*/
|
||||
ActionPose(ActionSet *actionSet,
|
||||
const std::string &name);
|
||||
|
||||
/**
|
||||
* Construct a pose action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action.
|
||||
* @param localizedName The localized name for the action.
|
||||
*/
|
||||
ActionPose(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName);
|
||||
|
||||
/**
|
||||
* Represents a pose action's position and orientation.
|
||||
* This represents a pose action's position and orientation, along with
|
||||
* flags to indicate whether each of these are valid and whether they're
|
||||
* currently tracked (as opposed to estimated based on recent tracking).
|
||||
*/
|
||||
class OSGXR_EXPORT Location
|
||||
{
|
||||
public:
|
||||
|
||||
typedef enum {
|
||||
// Must match XR_SPACE_LOCATION_* */
|
||||
ORIENTATION_VALID_BIT = 0x1,
|
||||
POSITION_VALID_BIT = 0x2,
|
||||
ORIENTATION_TRACKED_BIT = 0x4,
|
||||
POSITION_TRACKED_BIT = 0x8,
|
||||
} Flags;
|
||||
|
||||
// Constructors
|
||||
|
||||
/// Construct a pose action location.
|
||||
Location();
|
||||
/// Construct a pose action location.
|
||||
Location(Flags flags,
|
||||
const osg::Quat &orientation,
|
||||
const osg::Vec3f &position);
|
||||
|
||||
// Accessors
|
||||
|
||||
/**
|
||||
* Find whether the orientation is valid.
|
||||
* If not, the orientation is undefined.
|
||||
* @return Whether the orientation is valid.
|
||||
*/
|
||||
bool isOrientationValid() const
|
||||
{
|
||||
return _flags & ORIENTATION_VALID_BIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find whether the position is valid.
|
||||
* If not, the position is undefined.
|
||||
* @return Whether the position is valid.
|
||||
*/
|
||||
bool isPositionValid() const
|
||||
{
|
||||
return _flags & POSITION_VALID_BIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find whether the orientation is being tracked.
|
||||
* If not, the orientation may only be an estimate.
|
||||
* @return Whether the orientation is being tracked.
|
||||
*/
|
||||
bool isOrientationTracked() const
|
||||
{
|
||||
return _flags & ORIENTATION_TRACKED_BIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find whether the position is being tracked.
|
||||
* If not, the position may only be an estimate.
|
||||
* @return Whether the position is being tracked.
|
||||
*/
|
||||
bool isPositionTracked() const
|
||||
{
|
||||
return _flags & POSITION_TRACKED_BIT;
|
||||
}
|
||||
|
||||
/// Get the flags which indicate validity and tracking.
|
||||
Flags getFlags() const
|
||||
{
|
||||
return _flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pose action's orientation as a quaternion.
|
||||
* Get the pose action's orientation relative to the default
|
||||
* reference space as an OSG quaternion.
|
||||
*
|
||||
* The orientation is undefined if isOrientationValid() returns
|
||||
* false.
|
||||
*
|
||||
* The orientation may only be an estimate if
|
||||
* isOrientationTracked() returns false.
|
||||
*/
|
||||
const osg::Quat &getOrientation() const
|
||||
{
|
||||
return _orientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pose action's position as a 3D vector.
|
||||
* Get the pose action's position relative to the default
|
||||
* reference space as an OSG 3D vector.
|
||||
*
|
||||
* The position is undefined if isPositionValid() returns false.
|
||||
*
|
||||
* The position may only be an estimate if isPositionTracked()
|
||||
* returns false.
|
||||
*/
|
||||
const osg::Vec3f &getPosition() const
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
|
||||
// Comparison operators
|
||||
|
||||
bool operator != (const Location &other) const
|
||||
{
|
||||
return _flags != other._flags ||
|
||||
(isOrientationValid() && _orientation != other._orientation) ||
|
||||
(isPositionValid() && _position != other._position);
|
||||
}
|
||||
|
||||
bool operator == (const Location &other) const
|
||||
{
|
||||
return !operator != (other);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
Flags _flags;
|
||||
osg::Quat _orientation;
|
||||
osg::Vec3f _position;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current pose of the action as a Location object.
|
||||
* @param subaction The subaction to filter sources from, which must
|
||||
* have been specified to Action::addSubaction().
|
||||
* @return The current pose of the action.
|
||||
*/
|
||||
Location getValue(Subaction *subaction = nullptr);
|
||||
};
|
||||
|
||||
/// An output action for vibration.
|
||||
class OSGXR_EXPORT ActionVibration : public Action
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a vibration output action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
*/
|
||||
ActionVibration(ActionSet *actionSet);
|
||||
|
||||
/**
|
||||
* Construct a vibration output action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action, also used as the
|
||||
* localized name.
|
||||
*/
|
||||
ActionVibration(ActionSet *actionSet,
|
||||
const std::string &name);
|
||||
|
||||
/**
|
||||
* Construct a vibration output action.
|
||||
* @param actionSet The action set the action should belong to.
|
||||
* @param name The name of the OpenXR action.
|
||||
* @param localizedName The localized name for the action.
|
||||
*/
|
||||
ActionVibration(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName);
|
||||
|
||||
enum {
|
||||
/// Indicates a minimum supported durection for a haptic device.
|
||||
DURATION_MIN = -1,
|
||||
/// Indicates an optimal frequency for a haptic pulse.
|
||||
FREQUENCY_UNSPECIFIED = 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply haptic feedback.
|
||||
* @param duration_ns Duration of vibration in nanoseconds.
|
||||
* @param frequency Frequency of vibration in Hz.
|
||||
* @param amplitude Amplitude of vibration between 0.0 and 1.0.
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
bool applyHapticFeedback(int64_t duration_ns, float frequency,
|
||||
float amplitude);
|
||||
|
||||
/**
|
||||
* Apply haptic feedback.
|
||||
* @param subaction The subaction to apply haptics to, which must
|
||||
* have been specified to Action::addSubaction().
|
||||
* @param duration_ns Duration of vibration in nanoseconds.
|
||||
* @param frequency Frequency of vibration in Hz.
|
||||
* @param amplitude Amplitude of vibration between 0.0 and 1.0.
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
bool applyHapticFeedback(Subaction *subaction,
|
||||
int64_t duration_ns, float frequency,
|
||||
float amplitude);
|
||||
|
||||
/**
|
||||
* Stop any in-progress haptic feedback.
|
||||
* @param subaction The subaction to apply haptics to, which must
|
||||
* have been specified to Action::addSubaction().
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
bool stopHapticFeedback(Subaction *subaction = nullptr);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
138
3rdparty/osgXR/include/osgXR/ActionSet
vendored
Normal file
138
3rdparty/osgXR/include/osgXR/ActionSet
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_ActionSet
|
||||
#define OSGXR_ActionSet 1
|
||||
|
||||
#include <osgXR/Export>
|
||||
|
||||
#include <osg/Referenced>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class Manager;
|
||||
class Subaction;
|
||||
|
||||
/**
|
||||
* Represents a group of OpenXR actions.
|
||||
* Action sets are attached to the OpenXR session, and can be dynamically
|
||||
* activated and deactivated.
|
||||
*/
|
||||
class OSGXR_EXPORT ActionSet : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct an action set.
|
||||
* @param manager The VR manager object to add the action set to.
|
||||
*/
|
||||
ActionSet(Manager *manager);
|
||||
|
||||
/**
|
||||
* Construct an action set.
|
||||
* @param manager The VR manager object to add the action set to.
|
||||
* @param name The name of the OpenXR action set, also used as the
|
||||
* localized name.
|
||||
*/
|
||||
ActionSet(Manager *manager,
|
||||
const std::string &name);
|
||||
|
||||
/**
|
||||
* Construct an action set.
|
||||
* @param manager The VR manager object to add the action set to.
|
||||
* @param name The name of the OpenXR action set.
|
||||
* @param localizedName The localized name for the action set.
|
||||
*/
|
||||
ActionSet(Manager *manager,
|
||||
const std::string &name,
|
||||
const std::string &localizedName);
|
||||
|
||||
/// Destructor.
|
||||
~ActionSet();
|
||||
|
||||
// Accessors
|
||||
|
||||
/**
|
||||
* Set the action set's name and localized name.
|
||||
* @param name New name for OpenXR action set.
|
||||
* @param localizedName A localized version of @p name.
|
||||
*/
|
||||
void setName(const std::string &name,
|
||||
const std::string &localizedName);
|
||||
|
||||
/**
|
||||
* Set the action set's name.
|
||||
* @param name New name for OpenXR action set.
|
||||
*/
|
||||
void setName(const std::string &name);
|
||||
/// Get the action's name.
|
||||
const std::string &getName() const;
|
||||
|
||||
/**
|
||||
* Set the action set's localized name.
|
||||
* @param localizedName The localized name for the action set.
|
||||
*/
|
||||
void setLocalizedName(const std::string &localizedName);
|
||||
/// Get the action set's localized name.
|
||||
const std::string &getLocalizedName() const;
|
||||
|
||||
/**
|
||||
* Set the priority of the action set.
|
||||
* @param priority New priority of the action set. Larger priority
|
||||
* action sets take precedence over smaller priority
|
||||
* action sets.
|
||||
*/
|
||||
void setPriority(uint32_t priority);
|
||||
/// Get the priority of the action set.
|
||||
uint32_t getPriority() const;
|
||||
|
||||
// Activation of the action set
|
||||
|
||||
/**
|
||||
* Activate the action set within a subaction.
|
||||
* Set the action set as active so that its actions (filtered by
|
||||
* subaction) are synchronised each frame. If @p subaction is nullptr,
|
||||
* all subactions in the set will be synchronised, otherwise multiple
|
||||
* subactions can be activated by multiple calls.
|
||||
* @param subaction The subaction to activate this action set within.
|
||||
* May be nullptr (default) in which case all
|
||||
* subactions are activated.
|
||||
*/
|
||||
void activate(Subaction *subaction = nullptr);
|
||||
|
||||
/**
|
||||
* Deactivate the action set within a subaction.
|
||||
* Set the action set as inactive so that its actions (filtered by
|
||||
* subaction) are no longer synchronised each frame. If @p subaction is
|
||||
* nullptr, any full activation is removed, otherwise multiple
|
||||
* subactions can be deactivated by multiple calls.
|
||||
* @param subaction The subaction to deactivate this action set within.
|
||||
* May be nullptr (default) in which case all
|
||||
* subactions activations are removed.
|
||||
*/
|
||||
void deactivate(Subaction *subaction = nullptr);
|
||||
|
||||
/**
|
||||
* Find whether the action set is activated for any subactions.
|
||||
* @return Whether any subactions are activated for this action set.
|
||||
*/
|
||||
bool isActive();
|
||||
|
||||
class Private;
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<Private> _private;
|
||||
|
||||
// Copying not permitted
|
||||
ActionSet(const ActionSet ©);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
22
3rdparty/osgXR/include/osgXR/Export
vendored
Normal file
22
3rdparty/osgXR/include/osgXR/Export
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_Export
|
||||
#define OSGXR_Export 1
|
||||
|
||||
#include <osgXR/Config>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)
|
||||
#if defined(OSGXR_STATIC_LIBRARY)
|
||||
#define OSGXR_EXPORT
|
||||
#elif defined(OSGXR_LIBRARY)
|
||||
#define OSGXR_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define OSGXR_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define OSGXR_EXPORT
|
||||
#endif
|
||||
|
||||
#endif
|
74
3rdparty/osgXR/include/osgXR/InteractionProfile
vendored
Normal file
74
3rdparty/osgXR/include/osgXR/InteractionProfile
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_InteractionProfile
|
||||
#define OSGXR_InteractionProfile 1
|
||||
|
||||
#include <osgXR/Export>
|
||||
|
||||
#include <osg/Referenced>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class Action;
|
||||
class Manager;
|
||||
|
||||
/**
|
||||
* Represents a group of suggested bindings for a specific interaction profile.
|
||||
* This class allow the application to suggest bindings for actions to specific
|
||||
* input paths for a given interaction profile. If the OpenXR runtime recognises
|
||||
* the profile it may use the suggested bindings to bind actions to whichever
|
||||
* input devices the user may have, even without a specific binding to that
|
||||
* device.
|
||||
*/
|
||||
class OSGXR_EXPORT InteractionProfile : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct an interaction profile.
|
||||
* The OpenXR interaction profile path is constructed as
|
||||
* "/interaction_profiles/@p vendor /@p type ".
|
||||
* @param manager The VR manager object to add the action set to.
|
||||
* @param vendor Vendor segment of OpenXR interaction profile path.
|
||||
* @param type Type segment of OpenXR interaction profile path.
|
||||
*/
|
||||
InteractionProfile(Manager *manager,
|
||||
const std::string &vendor,
|
||||
const std::string &type);
|
||||
|
||||
/// Destructor
|
||||
~InteractionProfile();
|
||||
|
||||
// Accessors
|
||||
|
||||
/// Get the vendor segment of the OpenXR interaction profile path.
|
||||
const std::string &getVendor() const;
|
||||
|
||||
/// Get the type segment of the OpenXR interaction profile path.
|
||||
const std::string &getType() const;
|
||||
|
||||
/**
|
||||
* Suggest a binding for an action.
|
||||
* @param action The action to bind.
|
||||
* @param binding The OpenXR path to bind the action to.
|
||||
*/
|
||||
void suggestBinding(Action *action, const std::string &binding);
|
||||
|
||||
class Private;
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<Private> _private;
|
||||
|
||||
// Copying not permitted
|
||||
InteractionProfile(const InteractionProfile ©);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
237
3rdparty/osgXR/include/osgXR/Manager
vendored
Normal file
237
3rdparty/osgXR/include/osgXR/Manager
vendored
Normal file
|
@ -0,0 +1,237 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_Manager
|
||||
#define OSGXR_Manager 1
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Node>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <osgViewer/View>
|
||||
#include <osgViewer/ViewerBase>
|
||||
|
||||
#include <osgXR/Export>
|
||||
#include <osgXR/Mirror>
|
||||
#include <osgXR/Settings>
|
||||
#include <osgXR/View>
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
// Internal state class
|
||||
class XRState;
|
||||
|
||||
/**
|
||||
* Public VR state manager class.
|
||||
* Applications can extend this class to allow tighter integration with osgXR.
|
||||
*/
|
||||
class OSGXR_EXPORT Manager : public osgViewer::ViewConfig
|
||||
{
|
||||
public:
|
||||
|
||||
Manager();
|
||||
virtual ~Manager();
|
||||
|
||||
/// Use if viewer is a CompositeViewer.
|
||||
void setViewer(osgViewer::ViewerBase *viewer)
|
||||
{
|
||||
_viewer = viewer;
|
||||
}
|
||||
|
||||
/// Set the NodeMasks to use for visibility masks.
|
||||
void setVisibilityMaskNodeMasks(osg::Node::NodeMask left,
|
||||
osg::Node::NodeMask right) const;
|
||||
|
||||
void configure(osgViewer::View& view) const override;
|
||||
|
||||
/**
|
||||
* Perform a regular update.
|
||||
* This will poll for OpenXR events, and handle any pending VR start /
|
||||
* stop operations (possibly invoking the Manager's view callbacks).
|
||||
* Some of these operations require threading on the viewer to be
|
||||
* temporarily stopped, but in all cases it is started again.
|
||||
*/
|
||||
virtual void update();
|
||||
|
||||
/// Find whether state has changed since last call, and reset.
|
||||
bool checkAndResetStateChanged();
|
||||
|
||||
/// Find whether VR seems to be present.
|
||||
bool getPresent() const;
|
||||
|
||||
/**
|
||||
* Get whether VR is currently set to be enabled.
|
||||
* When enabled, osgXR will try to keep VR running.
|
||||
* @return Whether VR is enabled
|
||||
*/
|
||||
bool getEnabled() const;
|
||||
/**
|
||||
* Set whether VR is currently set to be enabled.
|
||||
* When enabled, osgXR will try to keep VR running.
|
||||
* @param enabled Whether VR is enabled.
|
||||
*/
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* Start destroying the VR state and wait for safe shutdown.
|
||||
*/
|
||||
void destroyAndWait();
|
||||
|
||||
/**
|
||||
* Find whether this manager is in the process of being destroyed.
|
||||
*/
|
||||
bool isDestroying() const;
|
||||
|
||||
/**
|
||||
* Get whether a VR session is currently running.
|
||||
* @return Whether a VR session is currently running.
|
||||
*/
|
||||
bool isRunning() const;
|
||||
|
||||
/// Arrange reinit as needed for new settings.
|
||||
void syncSettings();
|
||||
|
||||
/// Arrange reinit as needed of action setup.
|
||||
void syncActionSetup();
|
||||
|
||||
/*
|
||||
* OpenXR information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find whether OpenXR's validation layer is supported.
|
||||
* This looks to see whether the OpenXR validation API layer (i.e.
|
||||
* XR_APILAYER_LUNARG_core_validation) is available.
|
||||
*/
|
||||
bool hasValidationLayer() const;
|
||||
|
||||
/**
|
||||
* Find whether OpenXR supports the submission of depth information.
|
||||
* This looks to see whether the OpenXR instance extension for
|
||||
* submitting depth information to help the runtime perform better
|
||||
* reprojection (i.e. XR_KHR_composition_layer_depth) is available.
|
||||
*/
|
||||
bool hasDepthInfoExtension() const;
|
||||
|
||||
/**
|
||||
* Find whether OpenXR supports the visibility mask extension.
|
||||
* This looks to see whether the OpenXR instance extension for getting
|
||||
* visibility masks is available, which can be used to reduce fragment
|
||||
* load.
|
||||
*/
|
||||
bool hasVisibilityMaskExtension() const;
|
||||
|
||||
/// Find the name of the OpenXR runtime.
|
||||
const char *getRuntimeName() const;
|
||||
|
||||
/// Find the name of the OpenXR system in use.
|
||||
const char *getSystemName() const;
|
||||
|
||||
/// Get a string describing the state (for user consumption).
|
||||
const char *getStateString() const;
|
||||
|
||||
/*
|
||||
* For implementation by derived classes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback telling the app to configure a new view.
|
||||
* This callback allows osgXR to tell the app to configure a new view of
|
||||
* the world. The application should notify osgXR of the addition and
|
||||
* removal of slave cameras which osgXR should hook into using the
|
||||
* osgXR::View parameter.
|
||||
* The implementation may stop threading, and it will be started again
|
||||
* before update() returns.
|
||||
* @param xrView The new osgXR::View with a public API to allow the
|
||||
* application to retrieve what it needs in relation to
|
||||
* the view and to inform osgXR of changes.
|
||||
*/
|
||||
virtual void doCreateView(View *xrView) = 0;
|
||||
|
||||
/**
|
||||
* Callback telling the app to destroy an existing view.
|
||||
* This callback allows osgXR to tell the app to remove an existing view
|
||||
* of the world that it had requested via doCreateView(). The
|
||||
* application should notify osgXR of the removal of any slave cameras
|
||||
* which it has already informed osgXR about.
|
||||
* The implementation may stop threading, and it will be started again
|
||||
* before update() returns.
|
||||
*/
|
||||
virtual void doDestroyView(View *xrView) = 0;
|
||||
|
||||
/**
|
||||
* Callback telling the app that the VR session is now running.
|
||||
* This happens after the OpenXR session has started running, and views
|
||||
* have been configured (see doCreateView()). The app should start
|
||||
* rendering the VR views, and may choose to reconfigure the desktop
|
||||
* window to make a VR mirror visible.
|
||||
*/
|
||||
virtual void onRunning();
|
||||
|
||||
/**
|
||||
* Callback telling the app that the VR session has now stopped.
|
||||
* This happens after the OpenXR session has stopped, and views have
|
||||
* been removed (see doDestroyView()). The app should stop rendering the
|
||||
* VR views, and may choose to reconfigure the desktop window so as to
|
||||
* no longer show a VR mirror.
|
||||
*/
|
||||
virtual void onStopped();
|
||||
|
||||
/**
|
||||
* Callback telling the app that the VR session is in focus.
|
||||
* This happens when the VR session enters focus and can get VR input
|
||||
* from the user. The app may choose to resume the experience if it was
|
||||
* previously paused due to onUnfocus().
|
||||
*/
|
||||
virtual void onFocus();
|
||||
|
||||
/**
|
||||
* Callback telling the app that the VR session is no longer in focus.
|
||||
* This happens when the VR session leaves focus and can no longer get
|
||||
* VR input from the user. The VR runtime may be presenting a modal
|
||||
* pop-up on top of the application's rendered frames. The app may
|
||||
* choose to pause the experience.
|
||||
*/
|
||||
virtual void onUnfocus();
|
||||
|
||||
|
||||
/// Add a custom mirror to the queue of mirrors to configure.
|
||||
void addMirror(Mirror *mirror);
|
||||
|
||||
/// Set up a camera to render a VR mirror.
|
||||
void setupMirrorCamera(osg::Camera *camera);
|
||||
|
||||
/*
|
||||
* Internal
|
||||
*/
|
||||
|
||||
inline Settings *_getSettings()
|
||||
{
|
||||
return _settings.get();
|
||||
}
|
||||
|
||||
inline XRState *_getXrState()
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
||||
void _setupMirrors();
|
||||
|
||||
protected:
|
||||
|
||||
osg::ref_ptr<osgViewer::ViewerBase> _viewer;
|
||||
osg::ref_ptr<Settings> _settings;
|
||||
bool _destroying;
|
||||
|
||||
private:
|
||||
|
||||
std::list<osg::ref_ptr<Mirror> > _mirrorQueue;
|
||||
osg::ref_ptr<XRState> _state;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
50
3rdparty/osgXR/include/osgXR/Mirror
vendored
Normal file
50
3rdparty/osgXR/include/osgXR/Mirror
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_Mirror
|
||||
#define OSGXR_Mirror 1
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Referenced>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <osgXR/Export>
|
||||
#include <osgXR/MirrorSettings>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class Manager;
|
||||
|
||||
/**
|
||||
* Public VR mirror class.
|
||||
*/
|
||||
class OSGXR_EXPORT Mirror : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
Mirror(Manager *manager, osg::Camera *camera);
|
||||
virtual ~Mirror();
|
||||
|
||||
/*
|
||||
* internal
|
||||
*/
|
||||
|
||||
// Called when enough is known about OpenXR system
|
||||
void _init();
|
||||
|
||||
private:
|
||||
|
||||
void setupQuad(unsigned int viewIndex,
|
||||
float x, float w);
|
||||
|
||||
osg::observer_ptr<Manager> _manager;
|
||||
osg::observer_ptr<osg::Camera> _camera;
|
||||
|
||||
MirrorSettings _mirrorSettings;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
72
3rdparty/osgXR/include/osgXR/MirrorSettings
vendored
Normal file
72
3rdparty/osgXR/include/osgXR/MirrorSettings
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_MirrorSettings
|
||||
#define OSGXR_MirrorSettings 1
|
||||
|
||||
#include <osgXR/Export>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class OSGXR_EXPORT MirrorSettings
|
||||
{
|
||||
public:
|
||||
|
||||
MirrorSettings();
|
||||
|
||||
/// Equality operator.
|
||||
bool operator == (const MirrorSettings &other) const
|
||||
{
|
||||
return _mirrorMode == other._mirrorMode &&
|
||||
(_mirrorMode != MIRROR_SINGLE ||
|
||||
_mirrorViewIndex == other._mirrorViewIndex);
|
||||
}
|
||||
|
||||
/// Inequality operator.
|
||||
bool operator != (const MirrorSettings &other) const
|
||||
{
|
||||
return _mirrorMode != other._mirrorMode ||
|
||||
(_mirrorMode == MIRROR_SINGLE &&
|
||||
_mirrorViewIndex != other._mirrorViewIndex);
|
||||
}
|
||||
|
||||
/// Type of VR mirror to show.
|
||||
typedef enum MirrorMode
|
||||
{
|
||||
/// Choose automatically.
|
||||
MIRROR_AUTOMATIC,
|
||||
/// Render nothing to the mirror.
|
||||
MIRROR_NONE,
|
||||
/// Render a single view fullscreen to the mirror.
|
||||
MIRROR_SINGLE,
|
||||
/// Render left & right views side by side.
|
||||
MIRROR_LEFT_RIGHT,
|
||||
} MirrorMode;
|
||||
/// Set the mirror mode to use.
|
||||
void setMirror(MirrorMode mode, int viewIndex = -1)
|
||||
{
|
||||
_mirrorMode = mode;
|
||||
_mirrorViewIndex = viewIndex;
|
||||
}
|
||||
/// Get the mirror mode to use.
|
||||
MirrorMode getMirrorMode() const
|
||||
{
|
||||
return _mirrorMode;
|
||||
}
|
||||
/// Get the mirror view index.
|
||||
int getMirrorViewIndex() const
|
||||
{
|
||||
return _mirrorViewIndex;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Mirror mode
|
||||
MirrorMode _mirrorMode;
|
||||
int _mirrorViewIndex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
49
3rdparty/osgXR/include/osgXR/OpenXRDisplay
vendored
Normal file
49
3rdparty/osgXR/include/osgXR/OpenXRDisplay
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OpenXRDisplay
|
||||
#define OSGXR_OpenXRDisplay 1
|
||||
|
||||
#include <osgXR/Export>
|
||||
#include <osgXR/Settings>
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgViewer/View>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class XRState;
|
||||
|
||||
/** a camera for each OpenXR view.*/
|
||||
class OSGXR_EXPORT OpenXRDisplay : public osgViewer::ViewConfig
|
||||
{
|
||||
public:
|
||||
|
||||
OpenXRDisplay();
|
||||
OpenXRDisplay(Settings *settings);
|
||||
|
||||
OpenXRDisplay(const OpenXRDisplay& rhs,
|
||||
const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
|
||||
virtual ~OpenXRDisplay();
|
||||
|
||||
META_Object(osgXR, OpenXRDisplay);
|
||||
|
||||
void configure(osgViewer::View& view) const override;
|
||||
|
||||
protected:
|
||||
|
||||
osg::ref_ptr<Settings> _settings;
|
||||
|
||||
// Internal OpenXR state object
|
||||
// FIXME this should probably belong elsewhere
|
||||
mutable osg::ref_ptr<XRState> _state;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
345
3rdparty/osgXR/include/osgXR/Settings
vendored
Normal file
345
3rdparty/osgXR/include/osgXR/Settings
vendored
Normal file
|
@ -0,0 +1,345 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_Settings
|
||||
#define OSGXR_Settings 1
|
||||
|
||||
#include <osg/Referenced>
|
||||
|
||||
#include <osgXR/Export>
|
||||
#include <osgXR/MirrorSettings>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
/// Encapsulates osgXR / OpenXR settings data.
|
||||
class OSGXR_EXPORT Settings : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* Instance management.
|
||||
*/
|
||||
|
||||
Settings();
|
||||
virtual ~Settings();
|
||||
|
||||
/// Get the default/global instance of Settings.
|
||||
static Settings *instance();
|
||||
|
||||
/*
|
||||
* OpenXR application information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set the application's name and version to expose to OpenXR.
|
||||
* These will be used to create an OpenXR instance.
|
||||
* @param appName Name of the application.
|
||||
* @param appVersion 32-bit version number of the application.
|
||||
*/
|
||||
void setApp(const std::string &appName, uint32_t appVersion)
|
||||
{
|
||||
_appName = appName;
|
||||
_appVersion = appVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the application's name to expose to OpenXR.
|
||||
* This will be used to create an OpenXR instance.
|
||||
* @param appName Name of the application.
|
||||
*/
|
||||
void setAppName(const std::string &appName)
|
||||
{
|
||||
_appName = appName;
|
||||
}
|
||||
/// Get the application's name to expose to OpenXR.
|
||||
const std::string &getAppName() const
|
||||
{
|
||||
return _appName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the application's version to expose to OpenXR.
|
||||
* This will be used to create an OpenXR instance.
|
||||
* @param appVersion 32-bit version number of the application.
|
||||
*/
|
||||
void setAppVersion(uint32_t appVersion)
|
||||
{
|
||||
_appVersion = appVersion;
|
||||
}
|
||||
/// Get the application's 32-bit version number to expose to OpenXR.
|
||||
uint32_t getAppVersion() const
|
||||
{
|
||||
return _appVersion;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* osgXR configuration settings.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set whether to try enabling OpenXR's validation layer.
|
||||
* This controls whether the OpenXR validation API layer (i.e.
|
||||
* XR_APILAYER_LUNARG_core_validation) will be enabled when creating an
|
||||
* OpenXR instance.
|
||||
* By default this is disabled.
|
||||
* @param validationLayer Whether to try enabling the validation layer.
|
||||
*/
|
||||
void setValidationLayer(bool validationLayer)
|
||||
{
|
||||
_validationLayer = validationLayer;
|
||||
}
|
||||
/// Get whether to try enabling OpenXR's validation layer.
|
||||
bool getValidationLayer() const
|
||||
{
|
||||
return _validationLayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to enable submission of depth information to OpenXR.
|
||||
* This controls whether the OpenXR instance depth information extension
|
||||
* (i.e XR_KHR_composition_layer_depth) will be used to submit depth
|
||||
* information to OpenXR to allow improved reprojection.
|
||||
* This is currently disabled by default.
|
||||
* @param depthInfo Whether to enable submission of depth information.
|
||||
*/
|
||||
void setDepthInfo(bool depthInfo)
|
||||
{
|
||||
_depthInfo = depthInfo;
|
||||
}
|
||||
/// Get whether to enable submission of depth information to OpenXR.
|
||||
bool getDepthInfo() const
|
||||
{
|
||||
return _depthInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to create visibility masks.
|
||||
* This controls whether the OpenXR instance visibility mask extension
|
||||
* (i.e. XR_KHR_visibility_mask) will be used to create and update
|
||||
* visibility masks for each VR view in order to mask hidden fragments.
|
||||
* This is enabled by default.
|
||||
* @param visibilityMask Whether to create visibility masks.
|
||||
*/
|
||||
void setVisibilityMask(bool visibilityMask)
|
||||
{
|
||||
_visibilityMask = visibilityMask;
|
||||
}
|
||||
/// Get whether to create visibility masks.
|
||||
bool getVisibilityMask() const
|
||||
{
|
||||
return _visibilityMask;
|
||||
}
|
||||
|
||||
/// OpenXR system orm factors.
|
||||
typedef enum FormFactor
|
||||
{
|
||||
/// A display mounted to the user's head.
|
||||
HEAD_MOUNTED_DISPLAY,
|
||||
/// A display held in the user's hands.
|
||||
HANDHELD_DISPLAY,
|
||||
} FormFactor;
|
||||
/**
|
||||
* Set which OpenXR form factor to use.
|
||||
* This controls which OpenXR form factor to try to use. The default is
|
||||
* HEAD_MOUNTED_DISPLAY.
|
||||
* @param formFactor Form factor to use.
|
||||
*/
|
||||
void setFormFactor(FormFactor formFactor)
|
||||
{
|
||||
_formFactor = formFactor;
|
||||
}
|
||||
/// Get which OpenXR form factor to use.
|
||||
FormFactor getFormFactor() const
|
||||
{
|
||||
return _formFactor;
|
||||
}
|
||||
|
||||
/// Modes for blending layers onto the user's view of the real world.
|
||||
typedef enum BlendMode
|
||||
{
|
||||
// Matches XrEnvironmentBlendMode
|
||||
/// Display layers with no view of physical world behind.
|
||||
OPAQUE = 1,
|
||||
/// Additively blend layers with view of physical world behind.
|
||||
ADDITIVE = 2,
|
||||
/// Alpha blend layers with view of physical world behind.
|
||||
ALPHA_BLEND = 3,
|
||||
} BlendMode;
|
||||
/**
|
||||
* Specify a preferred environment blend mode.
|
||||
* The chosen environment blend mode is permitted for use, and will be
|
||||
* chosen in preference to any other supported environment blend modes
|
||||
* specified by allowEnvBlendMode() if supported by OpenXR.
|
||||
* @param mode Environment blend mode to prefer.
|
||||
*/
|
||||
void preferEnvBlendMode(BlendMode mode)
|
||||
{
|
||||
uint32_t mask = (1u << (unsigned int)mode);
|
||||
_preferredEnvBlendModeMask |= mask;
|
||||
_allowedEnvBlendModeMask |= mask;
|
||||
}
|
||||
/**
|
||||
* Specify a permitted environment blend mode.
|
||||
* The chosen environment blend mode is permitted for use, and may be
|
||||
* chosen if supported by OpenXR when none of the preferred environment
|
||||
* blend modes specified by preferEnvBlenMode() are supported by OpenXR.
|
||||
* @param mode Environment blend mode to prefer.
|
||||
*/
|
||||
void allowEnvBlendMode(BlendMode mode)
|
||||
{
|
||||
uint32_t mask = (1u << (unsigned int)mode);
|
||||
_allowedEnvBlendModeMask |= mask;
|
||||
}
|
||||
/// Get the bitmask of preferred environment blend modes.
|
||||
uint32_t getPreferredEnvBlendModeMask() const
|
||||
{
|
||||
return _preferredEnvBlendModeMask;
|
||||
}
|
||||
/// Set the bitmask of preferred environment blend modes.
|
||||
void setPreferredEnvBlendModeMask(uint32_t preferredEnvBlendModeMask)
|
||||
{
|
||||
_preferredEnvBlendModeMask = preferredEnvBlendModeMask;
|
||||
}
|
||||
/// Get the bitmask of permitted environment blend modes.
|
||||
uint32_t getAllowedEnvBlendModeMask() const
|
||||
{
|
||||
return _allowedEnvBlendModeMask;
|
||||
}
|
||||
/// Set the bitmask of allowed environment blend modes.
|
||||
void setAllowedEnvBlendModeMask(uint32_t allowedEnvBlendModeMask)
|
||||
{
|
||||
_allowedEnvBlendModeMask = allowedEnvBlendModeMask;
|
||||
}
|
||||
|
||||
/// Techniques for rendering multiple views.
|
||||
typedef enum VRMode
|
||||
{
|
||||
/// Choose automatically.
|
||||
VRMODE_AUTOMATIC,
|
||||
/** Create a slave camera for each view.
|
||||
* Either separate swapchains, or single with multiple viewports.
|
||||
*/
|
||||
VRMODE_SLAVE_CAMERAS,
|
||||
/** Use the OSG SceneView stereo functionality.
|
||||
* No extra slave cameras.
|
||||
* Only supports SWAPCHAIN_SINGLE with stereo.
|
||||
*/
|
||||
VRMODE_SCENE_VIEW,
|
||||
} VRMode;
|
||||
/// Set the rendering technique to use.
|
||||
void setVRMode(VRMode mode)
|
||||
{
|
||||
_vrMode = mode;
|
||||
}
|
||||
/// Get the rendering technique to use.
|
||||
VRMode getVRMode() const
|
||||
{
|
||||
return _vrMode;
|
||||
}
|
||||
|
||||
/// Techniques for managing swapchains.
|
||||
typedef enum SwapchainMode
|
||||
{
|
||||
/// Choose automatically.
|
||||
SWAPCHAIN_AUTOMATIC,
|
||||
/// Create a 2D swapchain per view.
|
||||
SWAPCHAIN_MULTIPLE,
|
||||
/** Create a single 2D swapchain with a viewport per view.
|
||||
* Stack them horizontally.
|
||||
*/
|
||||
SWAPCHAIN_SINGLE,
|
||||
} SwapchainMode;
|
||||
/// Set the swapchain management technique to use.
|
||||
void setSwapchainMode(SwapchainMode mode)
|
||||
{
|
||||
_swapchainMode = mode;
|
||||
}
|
||||
/// Get the swapchain management technique to use.
|
||||
SwapchainMode getSwapchainMode() const
|
||||
{
|
||||
return _swapchainMode;
|
||||
}
|
||||
|
||||
/// Get mirror settings.
|
||||
MirrorSettings &getMirrorSettings()
|
||||
{
|
||||
return _mirrorSettings;
|
||||
}
|
||||
/// Get mirror settings.
|
||||
const MirrorSettings &getMirrorSettings() const
|
||||
{
|
||||
return _mirrorSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of virtual world units to fit per real world meter.
|
||||
* This controls the size of the user relative to the virtual world, by
|
||||
* scaling down the size of the world.
|
||||
* @param unitsPerMeter The number of units per real world meter.
|
||||
*/
|
||||
void setUnitsPerMeter(float unitsPerMeter)
|
||||
{
|
||||
_unitsPerMeter = unitsPerMeter;
|
||||
}
|
||||
/// Get the number of virtual world units to fit per real world meter.
|
||||
float getUnitsPerMeter() const
|
||||
{
|
||||
return _unitsPerMeter;
|
||||
}
|
||||
|
||||
// Internal APIs
|
||||
|
||||
typedef enum {
|
||||
DIFF_NONE = 0,
|
||||
DIFF_APP_INFO = (1u << 0),
|
||||
DIFF_VALIDATION_LAYER = (1u << 1),
|
||||
DIFF_DEPTH_INFO = (1u << 2),
|
||||
DIFF_VISIBILITY_MASK = (1u << 3),
|
||||
DIFF_FORM_FACTOR = (1u << 4),
|
||||
DIFF_BLEND_MODE = (1u << 5),
|
||||
DIFF_VR_MODE = (1u << 6),
|
||||
DIFF_SWAPCHAIN_MODE = (1u << 7),
|
||||
DIFF_MIRROR = (1u << 8),
|
||||
DIFF_SCALE = (1u << 9),
|
||||
} _ChangeMask;
|
||||
|
||||
unsigned int _diff(const Settings &other) const;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Internal data.
|
||||
*/
|
||||
|
||||
// For XrInstance creation
|
||||
std::string _appName;
|
||||
uint32_t _appVersion;
|
||||
bool _validationLayer;
|
||||
bool _depthInfo;
|
||||
bool _visibilityMask;
|
||||
|
||||
// To get XrSystem
|
||||
FormFactor _formFactor;
|
||||
|
||||
// For choosing environment blend mode
|
||||
uint32_t _preferredEnvBlendModeMask;
|
||||
uint32_t _allowedEnvBlendModeMask;
|
||||
|
||||
// VR/swapchain modes to use
|
||||
VRMode _vrMode;
|
||||
SwapchainMode _swapchainMode;
|
||||
|
||||
// Mirror settings
|
||||
MirrorSettings _mirrorSettings;
|
||||
|
||||
// How big the world
|
||||
float _unitsPerMeter;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
75
3rdparty/osgXR/include/osgXR/Subaction
vendored
Normal file
75
3rdparty/osgXR/include/osgXR/Subaction
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_Subaction
|
||||
#define OSGXR_Subaction 1
|
||||
|
||||
#include <osgXR/Export>
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class InteractionProfile;
|
||||
class Manager;
|
||||
|
||||
/**
|
||||
* Represents an OpenXR subaction path (a.k.a top level user path).
|
||||
* This represents an OpenXR subaction path, also referred to in the OpenXR spec
|
||||
* as a top level user path. These are the physical groupings of inputs, for
|
||||
* example "/user/head" or "/user/hand/left". Actions and action sets can be
|
||||
* filtered by subactions, so that the same action (e.g. "shoot") can be read
|
||||
* separately for different hands.
|
||||
*/
|
||||
class OSGXR_EXPORT Subaction : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a subaction for a path.
|
||||
* @param manager The VR manager object to add the action set to.
|
||||
* @param path The subaction path, e.g. "/user/hand/left".
|
||||
*/
|
||||
Subaction(Manager *manager,
|
||||
const std::string &path);
|
||||
|
||||
/// Destructor
|
||||
virtual ~Subaction();
|
||||
|
||||
// Accessors
|
||||
|
||||
/// Get the subaction's path.
|
||||
const std::string &getPath() const;
|
||||
|
||||
/// Find the interaction profile bound to the subaction.
|
||||
InteractionProfile *getCurrentProfile();
|
||||
|
||||
class Private;
|
||||
|
||||
protected:
|
||||
|
||||
// Change handlers
|
||||
|
||||
/**
|
||||
* Notification of change of interaction profile for subaction.
|
||||
* This is called when the subaction's current interaction profile is
|
||||
* changed. Derived classes can implement this to their own ends.
|
||||
* @param newProfile The interaction profile object that is now
|
||||
* current for the subaction indicated by @p
|
||||
* subaction. May be nullptr.
|
||||
*/
|
||||
virtual void onProfileChanged(InteractionProfile *newProfile);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<Private> _private;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
79
3rdparty/osgXR/include/osgXR/View
vendored
Normal file
79
3rdparty/osgXR/include/osgXR/View
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_View
|
||||
#define OSGXR_View 1
|
||||
|
||||
#include <osgXR/Export>
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <osgViewer/GraphicsWindow>
|
||||
#include <osgViewer/View>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
/**
|
||||
* Representation of a view from an osgXR app point of view.
|
||||
* This represents a render view that osgXR expects the application to set up.
|
||||
* This may not directly correspond to OpenXR views, for example if using stereo
|
||||
* SceneView mode there will be a single view set up for stereo rendering.
|
||||
*/
|
||||
class OSGXR_EXPORT View : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* Application -> osgXR notifications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Notify osgXR that a new slave camera has been added to the view.
|
||||
* This tells osgXR that a new slave camera has been added to the view
|
||||
* which it should hook into so that it renders to the appropriate
|
||||
* texture and submits for XR display.
|
||||
*/
|
||||
virtual void addSlave(osg::Camera *slaveCamera) = 0;
|
||||
|
||||
/**
|
||||
* Notify osgXR that a slave camera is being removed from the view.
|
||||
* This tells osgXR when a slave camera previously notified with
|
||||
* addSlave() is being removed.
|
||||
*/
|
||||
virtual void removeSlave(osg::Camera *slaveCamera) = 0;
|
||||
|
||||
/*
|
||||
* Accessors.
|
||||
*/
|
||||
|
||||
/// Get the OSG GraphicsWindow associated with this osgXR view.
|
||||
inline const osgViewer::GraphicsWindow *getWindow() const
|
||||
{
|
||||
return _window;
|
||||
}
|
||||
|
||||
/// Get the OSG View associated with this osgXR view.
|
||||
inline const osgViewer::View *getView() const
|
||||
{
|
||||
return _osgView;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
* Internal
|
||||
*/
|
||||
|
||||
View(osgViewer::GraphicsWindow *window, osgViewer::View *osgView);
|
||||
virtual ~View();
|
||||
|
||||
osg::ref_ptr<osgViewer::GraphicsWindow> _window;
|
||||
osg::ref_ptr<osgViewer::View> _osgView;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
22
3rdparty/osgXR/include/osgXR/osgXR
vendored
Normal file
22
3rdparty/osgXR/include/osgXR/osgXR
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_osgXR
|
||||
#define OSGXR_osgXR 1
|
||||
|
||||
#include <osgXR/Export>
|
||||
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
void OSGXR_EXPORT setupViewerDefaults(osgViewer::Viewer *viewer,
|
||||
const std::string &appName,
|
||||
uint32_t appVersion);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
12
3rdparty/osgXR/osgXR.pc.in
vendored
Normal file
12
3rdparty/osgXR/osgXR.pc.in
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
|
||||
Name: @PROJECT_NAME@
|
||||
Description: @PROJECT_DESCRIPTION@
|
||||
Version: @PROJECT_VERSION@
|
||||
|
||||
Requires: openscenegraph OpenXR
|
||||
Libs: -L${libdir} -lmylib
|
||||
Cflags: -I${includedir}
|
507
3rdparty/osgXR/src/Action.cpp
vendored
Normal file
507
3rdparty/osgXR/src/Action.cpp
vendored
Normal file
|
@ -0,0 +1,507 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "Action.h"
|
||||
#include "ActionSet.h"
|
||||
|
||||
#include "OpenXR/Action.h"
|
||||
#include "OpenXR/Session.h"
|
||||
#include "OpenXR/Space.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
// Internal API
|
||||
|
||||
Action::Private::Private(ActionSet *actionSet) :
|
||||
_actionSet(actionSet),
|
||||
_updated(true)
|
||||
{
|
||||
ActionSet::Private::get(_actionSet)->registerAction(this);
|
||||
}
|
||||
|
||||
Action::Private::~Private()
|
||||
{
|
||||
ActionSet::Private::get(_actionSet)->unregisterAction(this);
|
||||
}
|
||||
|
||||
void Action::Private::setName(const std::string &name)
|
||||
{
|
||||
_updated = true;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
const std::string &Action::Private::getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
void Action::Private::setLocalizedName(const std::string &localizedName)
|
||||
{
|
||||
_updated = true;
|
||||
_localizedName = localizedName;
|
||||
}
|
||||
|
||||
const std::string &Action::Private::getLocalizedName() const
|
||||
{
|
||||
return _localizedName;
|
||||
}
|
||||
|
||||
void Action::Private::addSubaction(std::shared_ptr<Subaction::Private> subaction)
|
||||
{
|
||||
_updated = true;
|
||||
_subactions.insert(subaction);
|
||||
}
|
||||
|
||||
void Action::Private::cleanupInstance()
|
||||
{
|
||||
_updated = true;
|
||||
_action = nullptr;
|
||||
}
|
||||
|
||||
void Action::Private::getBoundSources(std::vector<std::string> &sourcePaths) const
|
||||
{
|
||||
OpenXR::Session *session = ActionSet::Private::get(_actionSet)->getSession();
|
||||
if (_action.valid() && session)
|
||||
{
|
||||
std::vector<XrPath> paths;
|
||||
if (session->getActionBoundSources(_action, paths))
|
||||
{
|
||||
// Convert XrPath's into std::string's
|
||||
OpenXR::Instance *instance = session->getInstance();
|
||||
sourcePaths.resize(paths.size());
|
||||
for (unsigned int i = 0; i < paths.size(); ++i)
|
||||
sourcePaths[i] = OpenXR::Path(instance, paths[i]).toString();
|
||||
|
||||
// Success!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Failure, clear output
|
||||
sourcePaths.resize(0);
|
||||
}
|
||||
|
||||
void Action::Private::getBoundSourcesLocalizedNames(XrInputSourceLocalizedNameFlags whichComponents,
|
||||
std::vector<std::string> &names) const
|
||||
{
|
||||
OpenXR::Session *session = ActionSet::Private::get(_actionSet)->getSession();
|
||||
if (_action.valid() && session)
|
||||
{
|
||||
std::vector<XrPath> paths;
|
||||
if (session->getActionBoundSources(_action, paths))
|
||||
{
|
||||
// Convert XrPath's into localized names
|
||||
names.resize(paths.size());
|
||||
for (unsigned int i = 0; i < paths.size(); ++i)
|
||||
names[i] = session->getInputSourceLocalizedName(paths[i],
|
||||
whichComponents);
|
||||
|
||||
// Success!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Failure, clear output
|
||||
names.resize(0);
|
||||
}
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
template <typename T>
|
||||
class ActionPrivateCommon : public Action::Private
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename T::State State;
|
||||
|
||||
ActionPrivateCommon(ActionSet *actionSet) :
|
||||
Private(actionSet)
|
||||
{
|
||||
}
|
||||
|
||||
void cleanupSession() override
|
||||
{
|
||||
_states.clear();
|
||||
}
|
||||
|
||||
OpenXR::Action *setup(OpenXR::Instance *instance) override
|
||||
{
|
||||
OpenXR::ActionSet *actionSet = ActionSet::Private::get(_actionSet)->setup(instance);
|
||||
if (!actionSet)
|
||||
{
|
||||
// Can't continue without an action set
|
||||
_action = nullptr;
|
||||
_updated = true;
|
||||
}
|
||||
else if (_updated || actionSet != _action->getActionSet())
|
||||
{
|
||||
_action = new T(actionSet, _name, _localizedName);
|
||||
for (auto &subaction: _subactions)
|
||||
_action->addSubaction(subaction->setup(instance));
|
||||
_updated = false;
|
||||
}
|
||||
return _action;
|
||||
}
|
||||
|
||||
State *getState(Subaction::Private *subaction = nullptr)
|
||||
{
|
||||
auto it = _states.find(subaction);
|
||||
if (it != _states.end())
|
||||
return (*it).second.get();
|
||||
|
||||
OpenXR::Session *session = ActionSet::Private::get(_actionSet)->getSession();
|
||||
if (session)
|
||||
{
|
||||
OpenXR::Path subactionPath;
|
||||
if (subaction)
|
||||
subactionPath = subaction->setup(session->getInstance());
|
||||
OpenXR::Action *action = setup(session->getInstance());
|
||||
if (action)
|
||||
{
|
||||
osg::ref_ptr<State> ret = static_cast<T*>(_action.get())->createState(session,
|
||||
subactionPath);
|
||||
_states[subaction] = ret;
|
||||
return ret.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
std::map<Subaction::Private *, osg::ref_ptr<State>> _states;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ActionPrivateSimple : public ActionPrivateCommon<T>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename T::State State;
|
||||
|
||||
ActionPrivateSimple(ActionSet *actionSet) :
|
||||
ActionPrivateCommon<T>(actionSet)
|
||||
{
|
||||
}
|
||||
|
||||
auto getValue(Subaction::Private *subaction)
|
||||
{
|
||||
State *state = this->getState(subaction);
|
||||
if (state && state->update() && state->isActive())
|
||||
return state->getCurrentState();
|
||||
else
|
||||
return T::State::Info::defaultValue();
|
||||
}
|
||||
};
|
||||
|
||||
typedef ActionPrivateSimple<OpenXR::ActionBoolean> ActionPrivateBoolean;
|
||||
typedef ActionPrivateSimple<OpenXR::ActionFloat> ActionPrivateFloat;
|
||||
typedef ActionPrivateSimple<OpenXR::ActionVector2f> ActionPrivateVector2f;
|
||||
|
||||
class ActionPrivatePose : public ActionPrivateCommon<OpenXR::ActionPose>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef OpenXR::ActionPose::State State;
|
||||
|
||||
ActionPrivatePose(ActionSet *actionSet) :
|
||||
ActionPrivateCommon(actionSet)
|
||||
{
|
||||
}
|
||||
|
||||
OpenXR::Space *getSpace(Subaction::Private *subaction)
|
||||
{
|
||||
State *state = getState(subaction);
|
||||
if (state && state->update() && state->isActive())
|
||||
return state->getSpace();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool locate(Subaction::Private *subaction,
|
||||
ActionPose::Location &location)
|
||||
{
|
||||
OpenXR::Space *space = getSpace(subaction);
|
||||
OpenXR::Session *session = ActionSet::Private::get(_actionSet)->getSession();
|
||||
if (session && space)
|
||||
{
|
||||
OpenXR::Space::Location loc;
|
||||
bool ret = space->locate(session->getLocalSpace(), session->getLastDisplayTime(),
|
||||
loc);
|
||||
location = ActionPose::Location((ActionPose::Location::Flags)loc.getFlags(),
|
||||
loc.getOrientation(),
|
||||
loc.getPosition());
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
location = ActionPose::Location();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ActionPrivateVibration : public ActionPrivateCommon<OpenXR::ActionVibration>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef OpenXR::ActionVibration::State State;
|
||||
|
||||
ActionPrivateVibration(ActionSet *actionSet) :
|
||||
ActionPrivateCommon(actionSet)
|
||||
{
|
||||
}
|
||||
|
||||
bool applyHapticFeedback(Subaction::Private *subaction,
|
||||
int64_t duration_ns, float frequency,
|
||||
float amplitude)
|
||||
{
|
||||
State *state = getState(subaction);
|
||||
if (!state)
|
||||
return false;
|
||||
return state->applyHapticFeedback(duration_ns, frequency,
|
||||
amplitude);
|
||||
}
|
||||
|
||||
bool stopHapticFeedback(Subaction::Private *subaction)
|
||||
{
|
||||
State *state = getState(subaction);
|
||||
if (!state)
|
||||
return false;
|
||||
return state->stopHapticFeedback();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Public API
|
||||
|
||||
Action::Action(Private *priv) :
|
||||
_private(priv)
|
||||
{
|
||||
}
|
||||
|
||||
Action::~Action()
|
||||
{
|
||||
}
|
||||
|
||||
void Action::addSubaction(Subaction *subaction)
|
||||
{
|
||||
_private->addSubaction(Subaction::Private::get(subaction));
|
||||
}
|
||||
|
||||
void Action::setName(const std::string &name,
|
||||
const std::string &localizedName)
|
||||
{
|
||||
_private->setName(name);
|
||||
_private->setLocalizedName(localizedName);
|
||||
}
|
||||
|
||||
void Action::setName(const std::string &name)
|
||||
{
|
||||
_private->setName(name);
|
||||
}
|
||||
|
||||
const std::string &Action::getName() const
|
||||
{
|
||||
return _private->getName();
|
||||
}
|
||||
|
||||
void Action::setLocalizedName(const std::string &localizedName)
|
||||
{
|
||||
_private->setLocalizedName(localizedName);
|
||||
}
|
||||
|
||||
const std::string &Action::getLocalizedName() const
|
||||
{
|
||||
return _private->getLocalizedName();
|
||||
}
|
||||
|
||||
void Action::getBoundSources(std::vector<std::string> &sourcePaths) const
|
||||
{
|
||||
_private->getBoundSources(sourcePaths);
|
||||
}
|
||||
|
||||
void Action::getBoundSourcesLocalizedNames(uint32_t whichComponents,
|
||||
std::vector<std::string> &names) const
|
||||
{
|
||||
_private->getBoundSourcesLocalizedNames(whichComponents, names);
|
||||
}
|
||||
|
||||
// ActionBoolean
|
||||
|
||||
ActionBoolean::ActionBoolean(ActionSet *actionSet) :
|
||||
Action(new ActionPrivateBoolean(actionSet))
|
||||
{
|
||||
}
|
||||
|
||||
ActionBoolean::ActionBoolean(ActionSet *actionSet,
|
||||
const std::string &name) :
|
||||
Action(new ActionPrivateBoolean(actionSet))
|
||||
{
|
||||
setName(name, name);
|
||||
}
|
||||
|
||||
ActionBoolean::ActionBoolean(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName) :
|
||||
Action(new ActionPrivateBoolean(actionSet))
|
||||
{
|
||||
setName(name, localizedName);
|
||||
}
|
||||
|
||||
bool ActionBoolean::getValue(Subaction *subaction)
|
||||
{
|
||||
auto privSubaction = Subaction::Private::get(subaction);
|
||||
return static_cast<ActionPrivateBoolean *>(Private::get(this))->getValue(privSubaction.get());
|
||||
}
|
||||
|
||||
// ActionFloat
|
||||
|
||||
ActionFloat::ActionFloat(ActionSet *actionSet) :
|
||||
Action(new ActionPrivateFloat(actionSet))
|
||||
{
|
||||
}
|
||||
|
||||
ActionFloat::ActionFloat(ActionSet *actionSet,
|
||||
const std::string &name) :
|
||||
Action(new ActionPrivateFloat(actionSet))
|
||||
{
|
||||
setName(name, name);
|
||||
}
|
||||
|
||||
ActionFloat::ActionFloat(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName) :
|
||||
Action(new ActionPrivateFloat(actionSet))
|
||||
{
|
||||
setName(name, localizedName);
|
||||
}
|
||||
|
||||
float ActionFloat::getValue(Subaction *subaction)
|
||||
{
|
||||
auto privSubaction = Subaction::Private::get(subaction);
|
||||
return static_cast<ActionPrivateFloat *>(Private::get(this))->getValue(privSubaction.get());
|
||||
}
|
||||
|
||||
// ActionVector2f
|
||||
|
||||
ActionVector2f::ActionVector2f(ActionSet *actionSet) :
|
||||
Action(new ActionPrivateVector2f(actionSet))
|
||||
{
|
||||
}
|
||||
|
||||
ActionVector2f::ActionVector2f(ActionSet *actionSet,
|
||||
const std::string &name) :
|
||||
Action(new ActionPrivateVector2f(actionSet))
|
||||
{
|
||||
setName(name, name);
|
||||
}
|
||||
|
||||
ActionVector2f::ActionVector2f(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName) :
|
||||
Action(new ActionPrivateVector2f(actionSet))
|
||||
{
|
||||
setName(name, localizedName);
|
||||
}
|
||||
|
||||
osg::Vec2f ActionVector2f::getValue(Subaction *subaction)
|
||||
{
|
||||
auto privSubaction = Subaction::Private::get(subaction);
|
||||
return static_cast<ActionPrivateVector2f *>(Private::get(this))->getValue(privSubaction.get());
|
||||
}
|
||||
|
||||
// ActionPose
|
||||
|
||||
ActionPose::ActionPose(ActionSet *actionSet) :
|
||||
Action(new ActionPrivatePose(actionSet))
|
||||
{
|
||||
}
|
||||
|
||||
ActionPose::ActionPose(ActionSet *actionSet,
|
||||
const std::string &name) :
|
||||
Action(new ActionPrivatePose(actionSet))
|
||||
{
|
||||
setName(name, name);
|
||||
}
|
||||
|
||||
ActionPose::ActionPose(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName) :
|
||||
Action(new ActionPrivatePose(actionSet))
|
||||
{
|
||||
setName(name, localizedName);
|
||||
}
|
||||
|
||||
ActionPose::Location ActionPose::getValue(Subaction *subaction)
|
||||
{
|
||||
Location location;
|
||||
auto privSubaction = Subaction::Private::get(subaction);
|
||||
static_cast<ActionPrivatePose *>(Private::get(this))->locate(privSubaction.get(),
|
||||
location);
|
||||
return location;
|
||||
}
|
||||
|
||||
ActionPose::Location::Location() :
|
||||
_flags((Flags)0)
|
||||
{
|
||||
}
|
||||
|
||||
ActionPose::Location::Location(Flags flags,
|
||||
const osg::Quat &orientation,
|
||||
const osg::Vec3f &position) :
|
||||
_flags(flags),
|
||||
_orientation(orientation),
|
||||
_position(position)
|
||||
{
|
||||
}
|
||||
|
||||
// ActionVibration
|
||||
|
||||
ActionVibration::ActionVibration(ActionSet *actionSet) :
|
||||
Action(new ActionPrivateVibration(actionSet))
|
||||
{
|
||||
}
|
||||
|
||||
ActionVibration::ActionVibration(ActionSet *actionSet,
|
||||
const std::string &name) :
|
||||
Action(new ActionPrivateVibration(actionSet))
|
||||
{
|
||||
setName(name, name);
|
||||
}
|
||||
|
||||
ActionVibration::ActionVibration(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName) :
|
||||
Action(new ActionPrivateVibration(actionSet))
|
||||
{
|
||||
setName(name, localizedName);
|
||||
}
|
||||
|
||||
bool ActionVibration::applyHapticFeedback(int64_t duration_ns, float frequency,
|
||||
float amplitude)
|
||||
{
|
||||
auto priv = static_cast<ActionPrivateVibration *>(Private::get(this));
|
||||
return priv->applyHapticFeedback(nullptr, duration_ns, frequency,
|
||||
amplitude);
|
||||
}
|
||||
|
||||
bool ActionVibration::applyHapticFeedback(Subaction *subaction,
|
||||
int64_t duration_ns, float frequency,
|
||||
float amplitude)
|
||||
{
|
||||
auto privSubaction = Subaction::Private::get(subaction);
|
||||
auto priv = static_cast<ActionPrivateVibration *>(Private::get(this));
|
||||
return priv->applyHapticFeedback(privSubaction.get(), duration_ns, frequency,
|
||||
amplitude);
|
||||
}
|
||||
|
||||
bool ActionVibration::stopHapticFeedback(Subaction *subaction)
|
||||
{
|
||||
auto privSubaction = Subaction::Private::get(subaction);
|
||||
auto priv = static_cast<ActionPrivateVibration *>(Private::get(this));
|
||||
return priv->stopHapticFeedback(privSubaction.get());
|
||||
}
|
84
3rdparty/osgXR/src/Action.h
vendored
Normal file
84
3rdparty/osgXR/src/Action.h
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_ACTION
|
||||
#define OSGXR_ACTION 1
|
||||
|
||||
#include <osgXR/Action>
|
||||
|
||||
#include "Subaction.h"
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
class Action;
|
||||
class Instance;
|
||||
};
|
||||
|
||||
class Action::Private
|
||||
{
|
||||
public:
|
||||
|
||||
static Private *get(Action *pub)
|
||||
{
|
||||
return pub->_private.get();
|
||||
}
|
||||
|
||||
Private(ActionSet *actionSet);
|
||||
virtual ~Private();
|
||||
|
||||
void setName(const std::string &name);
|
||||
const std::string &getName() const;
|
||||
|
||||
void setLocalizedName(const std::string &localizedName);
|
||||
const std::string &getLocalizedName() const;
|
||||
|
||||
void addSubaction(std::shared_ptr<Subaction::Private> subaction);
|
||||
|
||||
bool getUpdated() const
|
||||
{
|
||||
return _updated;
|
||||
}
|
||||
|
||||
/// Setup action with an OpenXR instance
|
||||
virtual OpenXR::Action *setup(OpenXR::Instance *instance) = 0;
|
||||
/// Clean up action before an OpenXR session is destroyed
|
||||
virtual void cleanupSession() = 0;
|
||||
/// Clean up action before an OpenXR instance is destroyed
|
||||
void cleanupInstance();
|
||||
|
||||
/**
|
||||
* Get a list of currently bound source paths for this action.
|
||||
* @param sourcePaths[out] Vector of source paths to write into.
|
||||
*/
|
||||
void getBoundSources(std::vector<std::string> &sourcePaths) const;
|
||||
|
||||
/**
|
||||
* Get a list of currently bound source localized names for this action.
|
||||
* @param whichComponents Which components to include.
|
||||
* @param names[out] Vector of names to write into.
|
||||
*/
|
||||
void getBoundSourcesLocalizedNames(XrInputSourceLocalizedNameFlags whichComponents,
|
||||
std::vector<std::string> &names) const;
|
||||
|
||||
protected:
|
||||
|
||||
std::string _name;
|
||||
std::string _localizedName;
|
||||
|
||||
osg::ref_ptr<ActionSet> _actionSet;
|
||||
std::set<std::shared_ptr<Subaction::Private>> _subactions;
|
||||
|
||||
bool _updated;
|
||||
osg::ref_ptr<OpenXR::Action> _action;
|
||||
};
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
242
3rdparty/osgXR/src/ActionSet.cpp
vendored
Normal file
242
3rdparty/osgXR/src/ActionSet.cpp
vendored
Normal file
|
@ -0,0 +1,242 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "ActionSet.h"
|
||||
#include "Action.h"
|
||||
|
||||
#include "OpenXR/ActionSet.h"
|
||||
|
||||
#include <osgXR/Manager>
|
||||
|
||||
#include "XRState.h"
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
// Internal API
|
||||
|
||||
ActionSet::Private::Private(XRState *state) :
|
||||
_state(state),
|
||||
_priority(0),
|
||||
_updated(true)
|
||||
{
|
||||
state->addActionSet(this);
|
||||
}
|
||||
|
||||
ActionSet::Private::~Private()
|
||||
{
|
||||
XRState *state = _state.get();
|
||||
if (state)
|
||||
state->removeActionSet(this);
|
||||
}
|
||||
|
||||
void ActionSet::Private::setName(const std::string &name)
|
||||
{
|
||||
_updated = true;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
const std::string &ActionSet::Private::getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
void ActionSet::Private::setLocalizedName(const std::string &localizedName)
|
||||
{
|
||||
_updated = true;
|
||||
_localizedName = localizedName;
|
||||
}
|
||||
|
||||
const std::string &ActionSet::Private::getLocalizedName() const
|
||||
{
|
||||
return _localizedName;
|
||||
}
|
||||
|
||||
void ActionSet::Private::setPriority(uint32_t priority)
|
||||
{
|
||||
_updated = true;
|
||||
_priority = priority;
|
||||
}
|
||||
|
||||
uint32_t ActionSet::Private::getPriority() const
|
||||
{
|
||||
return _priority;
|
||||
}
|
||||
|
||||
bool ActionSet::Private::getUpdated() const
|
||||
{
|
||||
if (_updated)
|
||||
return true;
|
||||
for (Action::Private *action: _actions)
|
||||
if (action->getUpdated())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ActionSet::Private::activate(std::shared_ptr<Subaction::Private> subaction)
|
||||
{
|
||||
_activeSubactions.insert(subaction);
|
||||
|
||||
if (_actionSet.valid() && _session.valid())
|
||||
{
|
||||
OpenXR::Path path;
|
||||
if (subaction)
|
||||
path = subaction->setup(_session->getInstance());
|
||||
_session->activateActionSet(_actionSet, path);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionSet::Private::deactivate(std::shared_ptr<Subaction::Private> subaction)
|
||||
{
|
||||
_activeSubactions.erase(subaction);
|
||||
|
||||
if (_actionSet.valid() && _session.valid())
|
||||
{
|
||||
OpenXR::Path path;
|
||||
if (subaction)
|
||||
path = subaction->setup(_session->getInstance());
|
||||
_session->deactivateActionSet(_actionSet, path);
|
||||
}
|
||||
}
|
||||
|
||||
bool ActionSet::Private::isActive()
|
||||
{
|
||||
return !_activeSubactions.empty();
|
||||
}
|
||||
|
||||
void ActionSet::Private::registerAction(Action::Private *action)
|
||||
{
|
||||
_actions.insert(action);
|
||||
}
|
||||
|
||||
void ActionSet::Private::unregisterAction(Action::Private *action)
|
||||
{
|
||||
_actions.erase(action);
|
||||
}
|
||||
|
||||
OpenXR::ActionSet *ActionSet::Private::setup(OpenXR::Instance *instance)
|
||||
{
|
||||
if (_updated)
|
||||
{
|
||||
_actionSet = new OpenXR::ActionSet(instance, _name, _localizedName,
|
||||
_priority);
|
||||
_updated = false;
|
||||
}
|
||||
return _actionSet;
|
||||
}
|
||||
|
||||
bool ActionSet::Private::setup(OpenXR::Session *session)
|
||||
{
|
||||
_session = session;
|
||||
if (_actionSet.valid())
|
||||
{
|
||||
session->addActionSet(_actionSet);
|
||||
// Init all the actions
|
||||
for (Action::Private *action: _actions)
|
||||
{
|
||||
OpenXR::Action *xrAction = action->setup(session->getInstance());
|
||||
if (xrAction)
|
||||
xrAction->init();
|
||||
}
|
||||
for (auto &subaction: _activeSubactions)
|
||||
{
|
||||
OpenXR::Path path;
|
||||
if (subaction)
|
||||
path = subaction->setup(session->getInstance());
|
||||
session->activateActionSet(_actionSet, path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ActionSet::Private::cleanupSession()
|
||||
{
|
||||
for (auto *action: _actions)
|
||||
action->cleanupSession();
|
||||
}
|
||||
|
||||
void ActionSet::Private::cleanupInstance()
|
||||
{
|
||||
_updated = true;
|
||||
_actionSet = nullptr;
|
||||
for (auto *action: _actions)
|
||||
action->cleanupInstance();
|
||||
}
|
||||
|
||||
// Public API
|
||||
|
||||
ActionSet::ActionSet(Manager *manager) :
|
||||
_private(new Private(manager->_getXrState()))
|
||||
{
|
||||
}
|
||||
|
||||
ActionSet::ActionSet(Manager *manager,
|
||||
const std::string &name) :
|
||||
_private(new Private(manager->_getXrState()))
|
||||
{
|
||||
setName(name, name);
|
||||
}
|
||||
|
||||
ActionSet::ActionSet(Manager *manager,
|
||||
const std::string &name,
|
||||
const std::string &localizedName) :
|
||||
_private(new Private(manager->_getXrState()))
|
||||
{
|
||||
setName(name, localizedName);
|
||||
}
|
||||
|
||||
ActionSet::~ActionSet()
|
||||
{
|
||||
}
|
||||
|
||||
void ActionSet::setName(const std::string &name,
|
||||
const std::string &localizedName)
|
||||
{
|
||||
_private->setName(name);
|
||||
_private->setLocalizedName(localizedName);
|
||||
}
|
||||
|
||||
void ActionSet::setName(const std::string &name)
|
||||
{
|
||||
_private->setName(name);
|
||||
}
|
||||
|
||||
const std::string &ActionSet::getName() const
|
||||
{
|
||||
return _private->getName();
|
||||
}
|
||||
|
||||
void ActionSet::setLocalizedName(const std::string &localizedName)
|
||||
{
|
||||
_private->setLocalizedName(localizedName);
|
||||
}
|
||||
|
||||
const std::string &ActionSet::getLocalizedName() const
|
||||
{
|
||||
return _private->getLocalizedName();
|
||||
}
|
||||
|
||||
void ActionSet::setPriority(uint32_t priority)
|
||||
{
|
||||
_private->setPriority(priority);
|
||||
}
|
||||
|
||||
uint32_t ActionSet::getPriority() const
|
||||
{
|
||||
return _private->getPriority();
|
||||
}
|
||||
|
||||
void ActionSet::activate(Subaction *subaction)
|
||||
{
|
||||
_private->activate(Subaction::Private::get(subaction));
|
||||
}
|
||||
|
||||
void ActionSet::deactivate(Subaction *subaction)
|
||||
{
|
||||
_private->deactivate(Subaction::Private::get(subaction));
|
||||
}
|
||||
|
||||
bool ActionSet::isActive()
|
||||
{
|
||||
return _private->isActive();
|
||||
}
|
93
3rdparty/osgXR/src/ActionSet.h
vendored
Normal file
93
3rdparty/osgXR/src/ActionSet.h
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_ACTION_SET
|
||||
#define OSGXR_ACTION_SET 1
|
||||
|
||||
#include <osgXR/ActionSet>
|
||||
#include <osgXR/Action>
|
||||
|
||||
#include "OpenXR/Path.h"
|
||||
|
||||
#include "Subaction.h"
|
||||
|
||||
#include <osg/observer_ptr>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class Action;
|
||||
class XRState;
|
||||
|
||||
namespace OpenXR {
|
||||
class ActionSet;
|
||||
class Instance;
|
||||
class Session;
|
||||
};
|
||||
|
||||
class ActionSet::Private
|
||||
{
|
||||
public:
|
||||
|
||||
static Private *get(ActionSet *pub)
|
||||
{
|
||||
return pub->_private.get();
|
||||
}
|
||||
|
||||
Private(XRState *state);
|
||||
~Private();
|
||||
|
||||
void setName(const std::string &name);
|
||||
const std::string &getName() const;
|
||||
|
||||
void setLocalizedName(const std::string &localizedName);
|
||||
const std::string &getLocalizedName() const;
|
||||
|
||||
void setPriority(uint32_t priority);
|
||||
uint32_t getPriority() const;
|
||||
|
||||
bool getUpdated() const;
|
||||
|
||||
void activate(std::shared_ptr<Subaction::Private> subaction = nullptr);
|
||||
void deactivate(std::shared_ptr<Subaction::Private> subaction = nullptr);
|
||||
bool isActive();
|
||||
|
||||
void registerAction(Action::Private *action);
|
||||
void unregisterAction(Action::Private *action);
|
||||
|
||||
/// Setup action set with an OpenXR instance
|
||||
OpenXR::ActionSet *setup(OpenXR::Instance *instance);
|
||||
/// Setup action set with an OpenXR session
|
||||
bool setup(OpenXR::Session *session);
|
||||
/// Clean up action before an OpenXR session is destroyed
|
||||
void cleanupSession();
|
||||
/// Clean up action before an OpenXR instance is destroyed
|
||||
void cleanupInstance();
|
||||
|
||||
OpenXR::Session *getSession()
|
||||
{
|
||||
return _session.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<XRState> _state;
|
||||
std::string _name;
|
||||
std::string _localizedName;
|
||||
uint32_t _priority;
|
||||
std::set<std::shared_ptr<Subaction::Private>> _activeSubactions;
|
||||
|
||||
std::set<Action::Private *> _actions;
|
||||
|
||||
bool _updated;
|
||||
osg::ref_ptr<OpenXR::ActionSet> _actionSet;
|
||||
osg::observer_ptr<OpenXR::Session> _session;
|
||||
};
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
132
3rdparty/osgXR/src/CMakeLists.txt
vendored
Normal file
132
3rdparty/osgXR/src/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,132 @@
|
|||
# Dependencies
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(OpenSceneGraph REQUIRED COMPONENTS osgViewer osgUtil)
|
||||
find_package(OpenXR REQUIRED)
|
||||
|
||||
# Public header files
|
||||
set(osgXR_HEADERS
|
||||
include/osgXR/Action
|
||||
include/osgXR/ActionSet
|
||||
include/osgXR/Export
|
||||
include/osgXR/InteractionProfile
|
||||
include/osgXR/Manager
|
||||
include/osgXR/Mirror
|
||||
include/osgXR/MirrorSettings
|
||||
include/osgXR/OpenXRDisplay
|
||||
include/osgXR/Settings
|
||||
include/osgXR/Subaction
|
||||
include/osgXR/View
|
||||
include/osgXR/osgXR
|
||||
)
|
||||
|
||||
# Source files
|
||||
set(osgXR_SRCS
|
||||
OpenXR/Action.cpp
|
||||
OpenXR/ActionSet.cpp
|
||||
OpenXR/Compositor.cpp
|
||||
OpenXR/EventHandler.cpp
|
||||
OpenXR/GraphicsBinding.cpp
|
||||
OpenXR/Instance.cpp
|
||||
OpenXR/InteractionProfile.cpp
|
||||
OpenXR/Path.cpp
|
||||
OpenXR/Session.cpp
|
||||
OpenXR/Space.cpp
|
||||
OpenXR/Swapchain.cpp
|
||||
OpenXR/SwapchainGroup.cpp
|
||||
OpenXR/System.cpp
|
||||
XRFramebuffer.cpp
|
||||
XRState.cpp
|
||||
XRRealizeOperation.cpp
|
||||
Action.cpp
|
||||
ActionSet.cpp
|
||||
FrameStore.cpp
|
||||
InteractionProfile.cpp
|
||||
Manager.cpp
|
||||
Mirror.cpp
|
||||
MirrorSettings.cpp
|
||||
OpenXRDisplay.cpp
|
||||
Settings.cpp
|
||||
Subaction.cpp
|
||||
View.cpp
|
||||
osgXR.cpp
|
||||
projection.cpp
|
||||
)
|
||||
|
||||
# Win32 graphics binding
|
||||
if(WIN32)
|
||||
list(APPEND osgXR_SRCS
|
||||
OpenXR/GraphicsBindingWin32.cpp
|
||||
)
|
||||
add_compile_definitions(OSGXR_USE_WIN32)
|
||||
endif()
|
||||
|
||||
# X11 graphics binding
|
||||
find_package(X11)
|
||||
if(X11_FOUND)
|
||||
list(APPEND osgXR_SRCS
|
||||
OpenXR/GraphicsBindingX11.cpp
|
||||
)
|
||||
add_compile_definitions(OSGXR_USE_X11)
|
||||
endif()
|
||||
|
||||
|
||||
# Build osgXR as a library
|
||||
add_library(osgXR ${osgXR_LIBRARY_TYPE} ${osgXR_SRCS})
|
||||
|
||||
get_target_property(osgXR_TYPE osgXR TYPE)
|
||||
if(osgXR_TYPE STREQUAL STATIC_LIBRARY)
|
||||
# Needed to switch OSGXR_EXPORT off on Windows
|
||||
set(OSGXR_STATIC_LIBRARY 1)
|
||||
endif()
|
||||
# Needed to switch OSGXR_EXPORT to dllexport on Windows
|
||||
add_compile_definitions(OSGXR_LIBRARY)
|
||||
|
||||
# Generate a "generated/Version.h" header
|
||||
set(osgXR_VERSION_HEADER "${PROJECT_BINARY_DIR}/include/generated/Version.h")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Version.h.in"
|
||||
"${osgXR_VERSION_HEADER}")
|
||||
|
||||
# Generate "osgXR/Config" header
|
||||
set(osgXR_CONFIG_HEADER "${PROJECT_BINARY_DIR}/include/osgXR/Config")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Config.in"
|
||||
"${osgXR_CONFIG_HEADER}")
|
||||
list(APPEND osgXR_HEADERS "${osgXR_CONFIG_HEADER}")
|
||||
|
||||
# Ensure required C++ standards are available
|
||||
target_compile_features(osgXR
|
||||
# smart pointers
|
||||
PUBLIC cxx_std_11
|
||||
# std::optional
|
||||
PRIVATE cxx_std_17)
|
||||
|
||||
target_include_directories(osgXR
|
||||
PRIVATE
|
||||
${PROJECT_BINARY_DIR}/include
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${OPENGL_INCLUDE_DIR}
|
||||
${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${OpenXR_INCLUDE_DIR}
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>"
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
|
||||
)
|
||||
|
||||
target_link_libraries(osgXR
|
||||
PRIVATE
|
||||
${OPENGL_LIBRARIES}
|
||||
PUBLIC
|
||||
${OPENSCENEGRAPH_LIBRARIES}
|
||||
OpenXR::openxr_loader
|
||||
)
|
||||
|
||||
set_target_properties(osgXR
|
||||
PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${osgXR_SOVERSION}
|
||||
PUBLIC_HEADER "${osgXR_HEADERS}"
|
||||
INTERFACE_osgXR_MAJOR_VERSION ${osgXR_MAJOR_VERSION}
|
||||
INTERFACE_osgXR_MINOR_VERSION ${osgXR_MINOR_VERSION}
|
||||
)
|
||||
set_property(TARGET osgXR APPEND PROPERTY
|
||||
COMPATIBLE_INTERFACE_STRING osgXR_MAJOR_VERSION osgXR_MINOR_VERSION
|
||||
)
|
10
3rdparty/osgXR/src/Config.in
vendored
Normal file
10
3rdparty/osgXR/src/Config.in
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
// -*-c++-*-
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_Config
|
||||
#define OSGXR_Config 1
|
||||
|
||||
#cmakedefine OSGXR_STATIC_LIBRARY
|
||||
|
||||
#endif
|
86
3rdparty/osgXR/src/FrameStampedVector.h
vendored
Normal file
86
3rdparty/osgXR/src/FrameStampedVector.h
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_FRAME_STAMPED_VECTOR
|
||||
#define OSGXR_FRAME_STAMPED_VECTOR 1
|
||||
|
||||
#include <osg/FrameStamp>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
/**
|
||||
* Manages frame stamping of vector items.
|
||||
* Contains a vector of the chosen type, with each item stamped with a
|
||||
* FrameStamp. Items can be retrieved by index or FrameStamp.
|
||||
*/
|
||||
template <typename T>
|
||||
class FrameStampedVector
|
||||
{
|
||||
public:
|
||||
|
||||
typedef T Item;
|
||||
typedef unsigned int FrameNumber;
|
||||
typedef const osg::FrameStamp *Stamp;
|
||||
typedef std::pair<Item, FrameNumber> StampedItem;
|
||||
|
||||
void reserve(unsigned int len)
|
||||
{
|
||||
_vec.reserve(len);
|
||||
}
|
||||
|
||||
void resize(unsigned int len, Item item = Item())
|
||||
{
|
||||
_vec.resize(len, StampedItem(item, ~0));
|
||||
}
|
||||
|
||||
unsigned int size() const
|
||||
{
|
||||
return _vec.size();
|
||||
}
|
||||
|
||||
void push_back(const Item &item)
|
||||
{
|
||||
_vec.push_back(StampedItem(item, ~0));
|
||||
}
|
||||
|
||||
// operator [] provides an Item if indexed directly
|
||||
const Item &operator [] (unsigned int index) const
|
||||
{
|
||||
return _vec[index].first;
|
||||
}
|
||||
|
||||
// operator [] provides an optional Item if indexed by stamp
|
||||
std::optional<const Item> operator [] (Stamp stamp) const
|
||||
{
|
||||
int index = findStamp(stamp);
|
||||
if (index < 0)
|
||||
return std::nullopt;
|
||||
return _vec[index].first;
|
||||
}
|
||||
|
||||
int findStamp(Stamp stamp) const
|
||||
{
|
||||
unsigned int frameNumber = stamp->getFrameNumber();
|
||||
for (unsigned int i = 0; i < _vec.size(); ++i)
|
||||
if (_vec[i].second == frameNumber)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void setStamp(unsigned int index, Stamp stamp)
|
||||
{
|
||||
_vec[index].second = stamp->getFrameNumber();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<StampedItem> _vec;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
87
3rdparty/osgXR/src/FrameStore.cpp
vendored
Normal file
87
3rdparty/osgXR/src/FrameStore.cpp
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "FrameStore.h"
|
||||
|
||||
#include <osg/FrameStamp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
FrameStore::FrameStore()
|
||||
{
|
||||
}
|
||||
|
||||
osg::ref_ptr<FrameStore::Frame> FrameStore::getFrame(FrameStore::Stamp stamp)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
|
||||
int index = lookupFrame(stamp);
|
||||
if (index < 0)
|
||||
return nullptr;
|
||||
|
||||
return _store[index];
|
||||
}
|
||||
|
||||
osg::ref_ptr<FrameStore::Frame> FrameStore::getFrame(FrameStore::Stamp stamp,
|
||||
OpenXR::Session *session)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
|
||||
int index = lookupFrame(stamp);
|
||||
if (index < 0)
|
||||
{
|
||||
index = blankFrame();
|
||||
// there surely shouldn't be more than 2 frames in parallel
|
||||
assert(index >= 0);
|
||||
if (index < 0)
|
||||
return nullptr;
|
||||
|
||||
osg::ref_ptr<OpenXR::Session::Frame> frame = session->waitFrame();
|
||||
if (frame.valid())
|
||||
{
|
||||
frame->setOsgFrameNumber(stamp->getFrameNumber());
|
||||
_store[index] = frame;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
return _store[index];
|
||||
}
|
||||
|
||||
bool FrameStore::endFrame(FrameStore::Stamp stamp)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
|
||||
int index = lookupFrame(stamp);
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
_store[index]->end();
|
||||
_store[index] = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FrameStore::lookupFrame(FrameStore::Stamp stamp) const
|
||||
{
|
||||
unsigned int frameNumber = stamp->getFrameNumber();
|
||||
for (unsigned int i = 0; i < maxFrames; ++i)
|
||||
{
|
||||
if (_store[i].valid() &&
|
||||
_store[i]->getOsgFrameNumber() == frameNumber)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FrameStore::blankFrame() const
|
||||
{
|
||||
for (unsigned int i = 0; i < maxFrames; ++i)
|
||||
if (!_store[i].valid())
|
||||
return i;
|
||||
return -1;
|
||||
}
|
63
3rdparty/osgXR/src/FrameStore.h
vendored
Normal file
63
3rdparty/osgXR/src/FrameStore.h
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_FRAME_STORE
|
||||
#define OSGXR_FRAME_STORE 1
|
||||
|
||||
#include "OpenXR/Session.h"
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <OpenThreads/Mutex>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace osg {
|
||||
class FrameStamp;
|
||||
}
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
/**
|
||||
* Manages concurrent frames.
|
||||
* A FrameStore stores any concurrent OpenXR frames and allows them to be
|
||||
* created and retrieved in a thread-safe way based on an osg::FrameStamp.
|
||||
*/
|
||||
class FrameStore
|
||||
{
|
||||
public:
|
||||
|
||||
typedef OpenXR::Session::Frame Frame;
|
||||
typedef const osg::FrameStamp *Stamp;
|
||||
|
||||
FrameStore();
|
||||
|
||||
/// Get a frame by FrameStamp.
|
||||
osg::ref_ptr<Frame> getFrame(Stamp stamp);
|
||||
|
||||
/// Get or wait for a frame by FrameStamp.
|
||||
osg::ref_ptr<Frame> getFrame(Stamp stamp, OpenXR::Session *session);
|
||||
|
||||
/**
|
||||
* End a frame by FrameStamp.
|
||||
* @return true on success, false otherwise.
|
||||
*/
|
||||
bool endFrame(Stamp stamp);
|
||||
|
||||
protected:
|
||||
|
||||
// These return cache index or -1
|
||||
int lookupFrame(Stamp stamp) const;
|
||||
int blankFrame() const;
|
||||
|
||||
// 2 allows work to start on next frame before the prior one has ended
|
||||
static constexpr unsigned int maxFrames = 2;
|
||||
// Protected by _mutex
|
||||
osg::ref_ptr<Frame> _store[maxFrames];
|
||||
|
||||
// For access to _store
|
||||
OpenThreads::Mutex _mutex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
106
3rdparty/osgXR/src/InteractionProfile.cpp
vendored
Normal file
106
3rdparty/osgXR/src/InteractionProfile.cpp
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "Action.h"
|
||||
#include "InteractionProfile.h"
|
||||
|
||||
#include "OpenXR/InteractionProfile.h"
|
||||
#include "OpenXR/Path.h"
|
||||
#include "OpenXR/Session.h"
|
||||
|
||||
#include <osgXR/Manager>
|
||||
|
||||
#include "XRState.h"
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
// Internal API
|
||||
|
||||
InteractionProfile::Private::Private(InteractionProfile *pub,
|
||||
XRState *state,
|
||||
const std::string &vendor,
|
||||
const std::string &type) :
|
||||
_pub(pub),
|
||||
_state(state),
|
||||
_vendor(vendor),
|
||||
_type(type),
|
||||
_updated(true)
|
||||
{
|
||||
state->addInteractionProfile(this);
|
||||
}
|
||||
|
||||
InteractionProfile::Private::~Private()
|
||||
{
|
||||
XRState *state = _state.get();
|
||||
if (state)
|
||||
state->removeInteractionProfile(this);
|
||||
}
|
||||
|
||||
void InteractionProfile::Private::suggestBinding(Action *action,
|
||||
const std::string &binding)
|
||||
{
|
||||
_bindings.push_back({action, binding});
|
||||
_updated = true;
|
||||
}
|
||||
|
||||
bool InteractionProfile::Private::setup(OpenXR::Instance *instance)
|
||||
{
|
||||
// Recreate every time, as actions may have been altered and recreated
|
||||
_profile = new OpenXR::InteractionProfile(instance, _vendor.c_str(),
|
||||
_type.c_str());
|
||||
|
||||
for (Binding &binding: _bindings)
|
||||
{
|
||||
// ensure action is set up
|
||||
OpenXR::Action *action = Action::Private::get(binding.action)->setup(instance);
|
||||
if (action)
|
||||
_profile->addBinding(action, binding.binding);
|
||||
}
|
||||
|
||||
bool ret = _profile->suggestBindings();
|
||||
if (ret)
|
||||
_updated = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void InteractionProfile::Private::cleanupInstance()
|
||||
{
|
||||
_profile = nullptr;
|
||||
}
|
||||
|
||||
OpenXR::Path InteractionProfile::Private::getPath() const
|
||||
{
|
||||
if (_profile.valid())
|
||||
return _profile->getPath();
|
||||
else
|
||||
return OpenXR::Path();
|
||||
}
|
||||
|
||||
// Public API
|
||||
|
||||
InteractionProfile::InteractionProfile(Manager *manager,
|
||||
const std::string &vendor,
|
||||
const std::string &type) :
|
||||
_private(new Private(this, manager->_getXrState(), vendor, type))
|
||||
{
|
||||
}
|
||||
|
||||
InteractionProfile::~InteractionProfile()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string &InteractionProfile::getVendor() const
|
||||
{
|
||||
return _private->getVendor();
|
||||
}
|
||||
|
||||
const std::string &InteractionProfile::getType() const
|
||||
{
|
||||
return _private->getType();
|
||||
}
|
||||
|
||||
void InteractionProfile::suggestBinding(Action *action,
|
||||
const std::string &binding)
|
||||
{
|
||||
_private->suggestBinding(action, binding);
|
||||
}
|
93
3rdparty/osgXR/src/InteractionProfile.h
vendored
Normal file
93
3rdparty/osgXR/src/InteractionProfile.h
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_INTERACTION_PROFILE
|
||||
#define OSGXR_INTERACTION_PROFILE 1
|
||||
|
||||
#include <osgXR/InteractionProfile>
|
||||
|
||||
#include <osg/observer_ptr>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class XRState;
|
||||
|
||||
namespace OpenXR {
|
||||
class InteractionProfile;
|
||||
class Path;
|
||||
class Session;
|
||||
};
|
||||
|
||||
class InteractionProfile::Private
|
||||
{
|
||||
public:
|
||||
|
||||
static Private *get(InteractionProfile *pub)
|
||||
{
|
||||
return pub->_private.get();
|
||||
}
|
||||
|
||||
Private(InteractionProfile *pub,
|
||||
XRState *newState,
|
||||
const std::string &newVendor,
|
||||
const std::string &newType);
|
||||
~Private();
|
||||
|
||||
void suggestBinding(Action *action, const std::string &binding);
|
||||
|
||||
bool getUpdated() const
|
||||
{
|
||||
return _updated;
|
||||
}
|
||||
|
||||
/// Setup bindings with an OpenXR instance
|
||||
bool setup(OpenXR::Instance *instance);
|
||||
/// Clean up bindings before an OpenXR instance is destroyed
|
||||
void cleanupInstance();
|
||||
|
||||
// Accessors
|
||||
|
||||
/// Get the public object.
|
||||
InteractionProfile *getPublic()
|
||||
{
|
||||
return _pub;
|
||||
}
|
||||
|
||||
/// Get the vendor segment of the OpenXR interaction profile path.
|
||||
const std::string &getVendor() const
|
||||
{
|
||||
return _vendor;
|
||||
}
|
||||
|
||||
/// Get the type segment of the OpenXR interaction profile path.
|
||||
const std::string &getType() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
OpenXR::Path getPath() const;
|
||||
|
||||
private:
|
||||
|
||||
InteractionProfile *_pub;
|
||||
osg::observer_ptr<XRState> _state;
|
||||
std::string _vendor;
|
||||
std::string _type;
|
||||
|
||||
struct Binding {
|
||||
osg::ref_ptr<Action> action;
|
||||
std::string binding;
|
||||
};
|
||||
std::list<Binding> _bindings;
|
||||
|
||||
bool _updated;
|
||||
osg::ref_ptr<OpenXR::InteractionProfile> _profile;
|
||||
};
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
191
3rdparty/osgXR/src/Manager.cpp
vendored
Normal file
191
3rdparty/osgXR/src/Manager.cpp
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include <osgXR/Manager>
|
||||
#include <osgXR/Mirror>
|
||||
|
||||
#include "XRState.h"
|
||||
#include "XRRealizeOperation.h"
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
Manager::Manager() :
|
||||
_settings(Settings::instance()),
|
||||
_destroying(false),
|
||||
_state(new XRState(_settings, const_cast<Manager *>(this)))
|
||||
{
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
}
|
||||
|
||||
void Manager::setVisibilityMaskNodeMasks(osg::Node::NodeMask left,
|
||||
osg::Node::NodeMask right) const
|
||||
{
|
||||
_state->setVisibilityMaskNodeMasks(left, right);
|
||||
}
|
||||
|
||||
void Manager::configure(osgViewer::View &view) const
|
||||
{
|
||||
osgViewer::ViewerBase *viewer = _viewer;
|
||||
if (!viewer)
|
||||
viewer = dynamic_cast<osgViewer::ViewerBase *>(&view);
|
||||
if (!viewer)
|
||||
return;
|
||||
|
||||
_state->setViewer(viewer);
|
||||
|
||||
// Its rather inconvenient that ViewConfig expects a const configure()
|
||||
// Just cheat and cast away the constness here
|
||||
osg::ref_ptr<XRRealizeOperation> realizeOp = new XRRealizeOperation(_state, &view);
|
||||
viewer->setRealizeOperation(realizeOp);
|
||||
if (viewer->isRealized())
|
||||
{
|
||||
osgViewer::ViewerBase::Contexts contexts;
|
||||
viewer->getContexts(contexts, true);
|
||||
if (contexts.size() > 0)
|
||||
(*realizeOp)(contexts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::update()
|
||||
{
|
||||
_state->update();
|
||||
}
|
||||
|
||||
bool Manager::checkAndResetStateChanged()
|
||||
{
|
||||
return _state->checkAndResetStateChanged();
|
||||
}
|
||||
|
||||
bool Manager::getPresent() const
|
||||
{
|
||||
return _state->getUpState() >= XRState::VRSTATE_SYSTEM;
|
||||
}
|
||||
|
||||
bool Manager::getEnabled() const
|
||||
{
|
||||
return _state->getUpState() == XRState::VRSTATE_ACTIONS;
|
||||
}
|
||||
|
||||
void Manager::setEnabled(bool enabled)
|
||||
{
|
||||
// Avoid needlessly discarding of the instance
|
||||
// SteamVR 1.15 and 1.16 have issues with xrDestroySession() hanging
|
||||
if (enabled)
|
||||
{
|
||||
_destroying = false;
|
||||
_state->setProbing(true);
|
||||
}
|
||||
else if (_destroying)
|
||||
{
|
||||
_state->setProbing(false);
|
||||
}
|
||||
|
||||
_state->setDestState(enabled ? XRState::VRSTATE_ACTIONS
|
||||
: _state->getProbingState());
|
||||
}
|
||||
|
||||
void Manager::destroyAndWait()
|
||||
{
|
||||
_destroying = true;
|
||||
setEnabled(false);
|
||||
while (_state->isStateUpdateNeeded())
|
||||
_state->update();
|
||||
}
|
||||
|
||||
bool Manager::isDestroying() const
|
||||
{
|
||||
return _destroying;
|
||||
}
|
||||
|
||||
bool Manager::isRunning() const
|
||||
{
|
||||
return _state->isRunning();
|
||||
}
|
||||
|
||||
void Manager::syncSettings()
|
||||
{
|
||||
_state->syncSettings();
|
||||
}
|
||||
|
||||
void Manager::syncActionSetup()
|
||||
{
|
||||
_state->syncActionSetup();
|
||||
}
|
||||
|
||||
bool Manager::hasValidationLayer() const
|
||||
{
|
||||
return _state->hasValidationLayer();
|
||||
}
|
||||
|
||||
bool Manager::hasDepthInfoExtension() const
|
||||
{
|
||||
return _state->hasDepthInfoExtension();
|
||||
}
|
||||
|
||||
bool Manager::hasVisibilityMaskExtension() const
|
||||
{
|
||||
return _state->hasVisibilityMaskExtension();
|
||||
}
|
||||
|
||||
const char *Manager::getRuntimeName() const
|
||||
{
|
||||
return _state->getRuntimeName();
|
||||
}
|
||||
|
||||
const char *Manager::getSystemName() const
|
||||
{
|
||||
return _state->getSystemName();
|
||||
}
|
||||
|
||||
const char *Manager::getStateString() const
|
||||
{
|
||||
return _state->getStateString();
|
||||
}
|
||||
|
||||
void Manager::onRunning()
|
||||
{
|
||||
}
|
||||
|
||||
void Manager::onStopped()
|
||||
{
|
||||
}
|
||||
|
||||
void Manager::onFocus()
|
||||
{
|
||||
}
|
||||
|
||||
void Manager::onUnfocus()
|
||||
{
|
||||
}
|
||||
|
||||
void Manager::addMirror(Mirror *mirror)
|
||||
{
|
||||
if (!_state->valid())
|
||||
{
|
||||
// handle this later, _state may not be created yet
|
||||
_mirrorQueue.push_back(mirror);
|
||||
}
|
||||
else
|
||||
{
|
||||
// init the mirror right away
|
||||
mirror->_init();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::setupMirrorCamera(osg::Camera *camera)
|
||||
{
|
||||
addMirror(new Mirror(this, camera));
|
||||
}
|
||||
|
||||
void Manager::_setupMirrors()
|
||||
{
|
||||
// init each mirror in the queue
|
||||
while (!_mirrorQueue.empty())
|
||||
{
|
||||
_mirrorQueue.front()->_init();
|
||||
_mirrorQueue.pop_front();
|
||||
}
|
||||
}
|
139
3rdparty/osgXR/src/Mirror.cpp
vendored
Normal file
139
3rdparty/osgXR/src/Mirror.cpp
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include <osgXR/Manager>
|
||||
#include <osgXR/Mirror>
|
||||
|
||||
#include "XRState.h"
|
||||
|
||||
#include <osg/PolygonMode>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
Mirror::Mirror(Manager *manager, osg::Camera *camera) :
|
||||
_manager(manager),
|
||||
_camera(camera),
|
||||
_mirrorSettings(manager->_getSettings()->getMirrorSettings())
|
||||
{
|
||||
}
|
||||
|
||||
Mirror::~Mirror()
|
||||
{
|
||||
}
|
||||
|
||||
void Mirror::_init()
|
||||
{
|
||||
_camera->setAllowEventFocus(false);
|
||||
_camera->setViewMatrix(osg::Matrix::identity());
|
||||
_camera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
|
||||
|
||||
// Find the mirror settings
|
||||
MirrorSettings *mirrorSettings = &_mirrorSettings;
|
||||
// but fall back to the manager's mirror settings
|
||||
if (mirrorSettings->getMirrorMode() == MirrorSettings::MIRROR_AUTOMATIC)
|
||||
mirrorSettings = &_manager->_getSettings()->getMirrorSettings();
|
||||
switch (mirrorSettings->getMirrorMode())
|
||||
{
|
||||
case MirrorSettings::MIRROR_NONE:
|
||||
// Draw nothing, but still clear the viewport
|
||||
_camera->setClearMask(GL_COLOR_BUFFER_BIT);
|
||||
break;
|
||||
case MirrorSettings::MIRROR_AUTOMATIC:
|
||||
// Fall-through: Default to MIRROR_SINGLE
|
||||
case MirrorSettings::MIRROR_SINGLE:
|
||||
{
|
||||
int viewIndex = mirrorSettings->getMirrorViewIndex();
|
||||
if (viewIndex < 0)
|
||||
viewIndex = 0;
|
||||
setupQuad(viewIndex, 0.0f, 1.0f);
|
||||
}
|
||||
break;
|
||||
case MirrorSettings::MIRROR_LEFT_RIGHT:
|
||||
for (unsigned int viewIndex = 0; viewIndex < 2; ++viewIndex)
|
||||
setupQuad(viewIndex, 0.5f * viewIndex, 0.5f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class MirrorPreDrawCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
|
||||
MirrorPreDrawCallback(osg::ref_ptr<XRState> xrState,
|
||||
osg::ref_ptr<osg::StateSet> stateSet,
|
||||
unsigned int viewIndex) :
|
||||
_xrState(xrState),
|
||||
_stateSet(stateSet),
|
||||
_viewIndex(viewIndex)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(osg::RenderInfo& renderInfo) const override
|
||||
{
|
||||
const osg::FrameStamp *stamp = renderInfo.getState()->getFrameStamp();
|
||||
_stateSet->setTextureAttributeAndModes(0,
|
||||
_xrState->getViewTexture(_viewIndex, stamp));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<XRState> _xrState;
|
||||
osg::ref_ptr<osg::StateSet> _stateSet;
|
||||
unsigned int _viewIndex;
|
||||
};
|
||||
|
||||
class MirrorPostDrawCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
|
||||
MirrorPostDrawCallback(osg::ref_ptr<osg::StateSet> stateSet) :
|
||||
_stateSet(stateSet)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(osg::RenderInfo& renderInfo) const override
|
||||
{
|
||||
_stateSet->removeTextureAttribute(0, osg::StateAttribute::Type::TEXTURE);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::ref_ptr<osg::StateSet> _stateSet;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void Mirror::setupQuad(unsigned int viewIndex,
|
||||
float x, float w)
|
||||
{
|
||||
XRState *xrState = _manager->_getXrState();
|
||||
|
||||
if (viewIndex >= xrState->getViewCount())
|
||||
return;
|
||||
|
||||
// Build an always-visible quad to draw the view texture on
|
||||
osg::ref_ptr<osg::Geode> quad = new osg::Geode;
|
||||
quad->setCullingActive(false);
|
||||
|
||||
XRState::TextureRect rect = xrState->getViewTextureRect(viewIndex);
|
||||
quad->addDrawable(osg::createTexturedQuadGeometry(
|
||||
osg::Vec3(x, 0.0f, 0.0f),
|
||||
osg::Vec3(w, 0.0f, 0.0f),
|
||||
osg::Vec3(0.0f, 1.0f, 0.0f),
|
||||
rect.x, rect.y,
|
||||
rect.x + rect.width, rect.y + rect.height));
|
||||
|
||||
osg::ref_ptr<osg::StateSet> state = quad->getOrCreateStateSet();
|
||||
int forceOff = osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED;
|
||||
state->setMode(GL_LIGHTING, forceOff);
|
||||
state->setMode(GL_DEPTH_TEST, forceOff);
|
||||
|
||||
_camera->addChild(quad);
|
||||
|
||||
// Set a callback so we can switch the texture to the active swapchain image
|
||||
_camera->addPreDrawCallback(new MirrorPreDrawCallback(_manager->_getXrState(),
|
||||
state, viewIndex));
|
||||
_camera->addPostDrawCallback(new MirrorPostDrawCallback(state));
|
||||
}
|
12
3rdparty/osgXR/src/MirrorSettings.cpp
vendored
Normal file
12
3rdparty/osgXR/src/MirrorSettings.cpp
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include <osgXR/MirrorSettings>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
MirrorSettings::MirrorSettings() :
|
||||
_mirrorMode(MIRROR_AUTOMATIC),
|
||||
_mirrorViewIndex(-1)
|
||||
{
|
||||
}
|
188
3rdparty/osgXR/src/OpenXR/Action.cpp
vendored
Normal file
188
3rdparty/osgXR/src/OpenXR/Action.cpp
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "Action.h"
|
||||
#include "Path.h"
|
||||
#include "Session.h"
|
||||
#include "Space.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
Action::Action(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName,
|
||||
XrActionType type) :
|
||||
_actionSet(actionSet),
|
||||
_createInfo{ XR_TYPE_ACTION_CREATE_INFO },
|
||||
_action(XR_NULL_HANDLE)
|
||||
{
|
||||
strncpy(_createInfo.actionName, name.c_str(),
|
||||
XR_MAX_ACTION_NAME_SIZE - 1);
|
||||
strncpy(_createInfo.localizedActionName, localizedName.c_str(),
|
||||
XR_MAX_LOCALIZED_ACTION_NAME_SIZE - 1);
|
||||
_createInfo.actionType = type;
|
||||
}
|
||||
|
||||
Action::~Action()
|
||||
{
|
||||
if (_action != XR_NULL_HANDLE)
|
||||
{
|
||||
check(xrDestroyAction(_action),
|
||||
"Failed to destroy OpenXR action");
|
||||
}
|
||||
}
|
||||
|
||||
void Action::addSubaction(const Path &path)
|
||||
{
|
||||
assert(path.getInstance() == getInstance());
|
||||
_subactionPaths.push_back(path.getXrPath());
|
||||
}
|
||||
|
||||
bool Action::init()
|
||||
{
|
||||
if (valid())
|
||||
return true;
|
||||
|
||||
if (!_subactionPaths.empty())
|
||||
{
|
||||
_createInfo.countSubactionPaths = _subactionPaths.size();
|
||||
_createInfo.subactionPaths = _subactionPaths.data();
|
||||
}
|
||||
return check(xrCreateAction(getXrActionSet(), &_createInfo, &_action),
|
||||
"Failed to create OpenXR action");
|
||||
}
|
||||
|
||||
ActionStateBase::ActionStateBase(Action *action, Session *session,
|
||||
Path subactionPath) :
|
||||
_action(action),
|
||||
_session(session),
|
||||
_subactionPath(subactionPath),
|
||||
_valid(false),
|
||||
_syncCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
ActionStateBase::~ActionStateBase()
|
||||
{
|
||||
}
|
||||
|
||||
bool ActionStateBase::checkUpdate()
|
||||
{
|
||||
unsigned int sessionSyncCount = _session->getActionSyncCount();
|
||||
// If an xrSyncActions has taken place, the state is out of date
|
||||
bool needsUpdate = (_syncCount < sessionSyncCount);
|
||||
// Update the counter as caller is expected to update the state
|
||||
_syncCount = sessionSyncCount;
|
||||
return needsUpdate;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ActionStateCommonBoolean::updateState()
|
||||
{
|
||||
XrActionStateGetInfo getInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
|
||||
getInfo.action = _action->getXrAction();
|
||||
getInfo.subactionPath = _subactionPath.getXrPath();
|
||||
|
||||
_state = { XR_TYPE_ACTION_STATE_BOOLEAN };
|
||||
|
||||
_valid = check(xrGetActionStateBoolean(_session->getXrSession(), &getInfo,
|
||||
&_state),
|
||||
"Failed to get boolean OpenXR action state");
|
||||
return _valid;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ActionStateCommonFloat::updateState()
|
||||
{
|
||||
XrActionStateGetInfo getInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
|
||||
getInfo.action = _action->getXrAction();
|
||||
getInfo.subactionPath = _subactionPath.getXrPath();
|
||||
|
||||
_state = { XR_TYPE_ACTION_STATE_FLOAT };
|
||||
|
||||
_valid = check(xrGetActionStateFloat(_session->getXrSession(), &getInfo,
|
||||
&_state),
|
||||
"Failed to get float OpenXR action state");
|
||||
return _valid;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ActionStateCommonVector2f::updateState()
|
||||
{
|
||||
XrActionStateGetInfo getInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
|
||||
getInfo.action = _action->getXrAction();
|
||||
getInfo.subactionPath = _subactionPath.getXrPath();
|
||||
|
||||
_state = { XR_TYPE_ACTION_STATE_VECTOR2F };
|
||||
|
||||
_valid = check(xrGetActionStateVector2f(_session->getXrSession(), &getInfo,
|
||||
&_state),
|
||||
"Failed to get vector2f OpenXR action state");
|
||||
return _valid;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool ActionStateCommonPose::updateState()
|
||||
{
|
||||
XrActionStateGetInfo getInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
|
||||
getInfo.action = _action->getXrAction();
|
||||
getInfo.subactionPath = _subactionPath.getXrPath();
|
||||
|
||||
_state = { XR_TYPE_ACTION_STATE_POSE };
|
||||
|
||||
_valid = check(xrGetActionStatePose(_session->getXrSession(), &getInfo,
|
||||
&_state),
|
||||
"Failed to get pose OpenXR action state");
|
||||
return _valid;
|
||||
}
|
||||
|
||||
ActionStatePose::ActionStatePose(ActionPose *action, Session *session,
|
||||
Path subactionPath) :
|
||||
Base(action, session, subactionPath),
|
||||
_space(new Space(session, action, subactionPath))
|
||||
{
|
||||
}
|
||||
|
||||
ActionStatePose::~ActionStatePose()
|
||||
{
|
||||
}
|
||||
|
||||
ActionStateVibration::ActionStateVibration(ActionVibration *action,
|
||||
Session *session,
|
||||
Path subactionPath) :
|
||||
_action(action),
|
||||
_session(session),
|
||||
_subactionPath(subactionPath)
|
||||
{
|
||||
}
|
||||
|
||||
bool ActionStateVibration::applyHapticFeedback(int64_t duration_ns,
|
||||
float frequency,
|
||||
float amplitude) const
|
||||
{
|
||||
XrHapticActionInfo actionInfo{ XR_TYPE_HAPTIC_ACTION_INFO };
|
||||
actionInfo.action = _action->getXrAction();
|
||||
actionInfo.subactionPath = _subactionPath.getXrPath();
|
||||
|
||||
XrHapticVibration vibration{ XR_TYPE_HAPTIC_VIBRATION };
|
||||
vibration.duration = duration_ns;
|
||||
vibration.frequency = frequency;
|
||||
vibration.amplitude = amplitude;
|
||||
|
||||
return check(xrApplyHapticFeedback(_session->getXrSession(), &actionInfo,
|
||||
reinterpret_cast<XrHapticBaseHeader*>(&vibration)),
|
||||
"Failed to apply haptic feedback");
|
||||
}
|
||||
|
||||
bool ActionStateVibration::stopHapticFeedback() const
|
||||
{
|
||||
XrHapticActionInfo actionInfo{ XR_TYPE_HAPTIC_ACTION_INFO };
|
||||
actionInfo.action = _action->getXrAction();
|
||||
actionInfo.subactionPath = _subactionPath.getXrPath();
|
||||
|
||||
return check(xrStopHapticFeedback(_session->getXrSession(), &actionInfo),
|
||||
"Failed to stop haptic feedback");
|
||||
}
|
371
3rdparty/osgXR/src/OpenXR/Action.h
vendored
Normal file
371
3rdparty/osgXR/src/OpenXR/Action.h
vendored
Normal file
|
@ -0,0 +1,371 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_ACTION
|
||||
#define OSGXR_OPENXR_ACTION 1
|
||||
|
||||
#include "ActionSet.h"
|
||||
#include "Path.h"
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class Path;
|
||||
class Space;
|
||||
|
||||
class Action : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
Action(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName,
|
||||
XrActionType type);
|
||||
virtual ~Action();
|
||||
|
||||
// Action initialisation
|
||||
|
||||
void addSubaction(const Path &path);
|
||||
|
||||
// Returns true on success
|
||||
bool init();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _action != XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _actionSet->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Conversions
|
||||
|
||||
inline const osg::ref_ptr<ActionSet> getActionSet() const
|
||||
{
|
||||
return _actionSet;
|
||||
}
|
||||
|
||||
inline const osg::ref_ptr<Instance> getInstance() const
|
||||
{
|
||||
return _actionSet->getInstance();
|
||||
}
|
||||
|
||||
inline XrInstance getXrInstance() const
|
||||
{
|
||||
return _actionSet->getXrInstance();
|
||||
}
|
||||
|
||||
inline XrActionSet getXrActionSet() const
|
||||
{
|
||||
return _actionSet->getXrActionSet();
|
||||
}
|
||||
|
||||
inline XrAction getXrAction() const
|
||||
{
|
||||
return _action;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Action data
|
||||
osg::ref_ptr<ActionSet> _actionSet;
|
||||
std::vector<XrPath> _subactionPaths;
|
||||
XrActionCreateInfo _createInfo;
|
||||
XrAction _action;
|
||||
};
|
||||
|
||||
/// Base action state for inputs.
|
||||
class ActionStateBase : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
ActionStateBase(Action *action, Session *session,
|
||||
Path subactionPath = Path());
|
||||
virtual ~ActionStateBase();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _valid;
|
||||
}
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _action->check(result, warnMsg);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Utilities for synchronisation
|
||||
|
||||
// Find whether the state needs update and update sync counter
|
||||
bool checkUpdate();
|
||||
|
||||
// Member data
|
||||
|
||||
osg::ref_ptr<Action> _action;
|
||||
osg::ref_ptr<Session> _session;
|
||||
Path _subactionPath;
|
||||
bool _valid;
|
||||
unsigned int _syncCount;
|
||||
};
|
||||
|
||||
/// All action states have an isActive field.
|
||||
template <typename T>
|
||||
class ActionStateCommon : public ActionStateBase
|
||||
{
|
||||
private:
|
||||
|
||||
typedef ActionStateBase Base;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
ActionStateCommon(Action *action, Session *session,
|
||||
Path subactionPath = Path()) :
|
||||
Base(action, session, subactionPath)
|
||||
{
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
assert(valid());
|
||||
return _state.isActive;
|
||||
}
|
||||
|
||||
// Operations
|
||||
|
||||
/// Update state if a sync has taken place
|
||||
bool update()
|
||||
{
|
||||
if (Base::checkUpdate())
|
||||
return updateState();
|
||||
return valid();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Protected operations
|
||||
|
||||
bool updateState();
|
||||
|
||||
// Data members
|
||||
|
||||
T _state;
|
||||
};
|
||||
|
||||
// These are the base action state classes
|
||||
typedef ActionStateCommon<XrActionStateBoolean> ActionStateCommonBoolean;
|
||||
typedef ActionStateCommon<XrActionStateFloat> ActionStateCommonFloat;
|
||||
typedef ActionStateCommon<XrActionStateVector2f> ActionStateCommonVector2f;
|
||||
typedef ActionStateCommon<XrActionStatePose> ActionStateCommonPose;
|
||||
|
||||
// Convert action values to app / OSG friendly formats
|
||||
template <typename T>
|
||||
struct ActionTypeInfo;
|
||||
|
||||
// XrBool32 -> bool
|
||||
template <>
|
||||
struct ActionTypeInfo<XrActionStateBoolean>
|
||||
{
|
||||
static bool convert(XrBool32 value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool defaultValue()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// float -> float
|
||||
template <>
|
||||
struct ActionTypeInfo<XrActionStateFloat>
|
||||
{
|
||||
static float convert(float value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
static float defaultValue()
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
// XrVector2f -> osg::Vec2f
|
||||
template <>
|
||||
struct ActionTypeInfo<XrActionStateVector2f>
|
||||
{
|
||||
static osg::Vec2f convert(const XrVector2f &value)
|
||||
{
|
||||
return osg::Vec2f(value.x, value.y);
|
||||
}
|
||||
|
||||
static osg::Vec2f defaultValue()
|
||||
{
|
||||
return osg::Vec2f(0.0f, 0.0f);
|
||||
}
|
||||
};
|
||||
|
||||
/// Some action states have currentValue and related fields.
|
||||
template <typename T>
|
||||
class ActionStateSimple : public ActionStateCommon<T>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef ActionStateCommon<T> Base;
|
||||
|
||||
public:
|
||||
|
||||
typedef ActionTypeInfo<T> Info;
|
||||
|
||||
// Constructors
|
||||
|
||||
ActionStateSimple(Action *action, Session *session,
|
||||
Path subactionPath = Path()) :
|
||||
Base(action, session, subactionPath)
|
||||
{
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
auto getCurrentState() const
|
||||
{
|
||||
assert(this->valid());
|
||||
return Info::convert(Base::_state.currentState);
|
||||
}
|
||||
|
||||
bool hasChangedSinceLastSync() const
|
||||
{
|
||||
assert(this->valid());
|
||||
return Base::_state.changedSinceLastSync;
|
||||
}
|
||||
|
||||
XrTime getLastChangedTime() const
|
||||
{
|
||||
assert(this->valid());
|
||||
return Base::_state.lastChangedTime;
|
||||
}
|
||||
};
|
||||
|
||||
// These are the simple action state classes
|
||||
typedef ActionStateSimple<XrActionStateBoolean> ActionStateBoolean;
|
||||
typedef ActionStateSimple<XrActionStateFloat> ActionStateFloat;
|
||||
typedef ActionStateSimple<XrActionStateVector2f> ActionStateVector2f;
|
||||
|
||||
/// Specialise Action for a specific input type
|
||||
template <XrActionType type, typename T>
|
||||
class ActionTyped : public Action
|
||||
{
|
||||
public:
|
||||
|
||||
typedef T State;
|
||||
|
||||
ActionTyped(ActionSet *actionSet,
|
||||
const std::string &name,
|
||||
const std::string &localizedName) :
|
||||
Action(actionSet, name, localizedName, type)
|
||||
{
|
||||
}
|
||||
|
||||
osg::ref_ptr<State> createState(Session *session,
|
||||
Path subactionPath = Path())
|
||||
{
|
||||
return new State(this, session, subactionPath);
|
||||
}
|
||||
};
|
||||
|
||||
// So ActionStatePose etc can take ActionPose etc in constructor
|
||||
class ActionStatePose;
|
||||
class ActionStateVibration;
|
||||
|
||||
// These are the final typed action classes
|
||||
typedef ActionTyped<XR_ACTION_TYPE_BOOLEAN_INPUT, ActionStateBoolean> ActionBoolean;
|
||||
typedef ActionTyped<XR_ACTION_TYPE_FLOAT_INPUT, ActionStateFloat> ActionFloat;
|
||||
typedef ActionTyped<XR_ACTION_TYPE_VECTOR2F_INPUT, ActionStateVector2f> ActionVector2f;
|
||||
typedef ActionTyped<XR_ACTION_TYPE_POSE_INPUT, ActionStatePose> ActionPose;
|
||||
typedef ActionTyped<XR_ACTION_TYPE_VIBRATION_OUTPUT, ActionStateVibration> ActionVibration;
|
||||
|
||||
/// Pose actions have their own way to get the pose
|
||||
class ActionStatePose : public ActionStateCommon<XrActionStatePose>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef ActionStateCommon<XrActionStatePose> Base;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
ActionStatePose(ActionPose *action, Session *session,
|
||||
Path subactionPath = Path());
|
||||
~ActionStatePose();
|
||||
|
||||
// Accessors
|
||||
|
||||
Space *getSpace()
|
||||
{
|
||||
return _space.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::ref_ptr<Space> _space;
|
||||
};
|
||||
|
||||
class ActionStateVibration : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
ActionStateVibration(ActionVibration *action, Session *session,
|
||||
Path subactionPath = Path());
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _action->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Haptic vibrations
|
||||
|
||||
bool applyHapticFeedback(int64_t duration_ns, float frequency,
|
||||
float amplitude) const;
|
||||
bool stopHapticFeedback() const;
|
||||
|
||||
protected:
|
||||
|
||||
// Member data
|
||||
|
||||
osg::ref_ptr<Action> _action;
|
||||
osg::ref_ptr<Session> _session;
|
||||
Path _subactionPath;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
35
3rdparty/osgXR/src/OpenXR/ActionSet.cpp
vendored
Normal file
35
3rdparty/osgXR/src/OpenXR/ActionSet.cpp
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "ActionSet.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
ActionSet::ActionSet(Instance *instance,
|
||||
const std::string &name,
|
||||
const std::string &localizedName,
|
||||
uint32_t priority) :
|
||||
_instance(instance),
|
||||
_actionSet(XR_NULL_HANDLE)
|
||||
{
|
||||
XrActionSetCreateInfo createInfo{ XR_TYPE_ACTION_SET_CREATE_INFO };
|
||||
strncpy(createInfo.actionSetName, name.c_str(),
|
||||
XR_MAX_ACTION_SET_NAME_SIZE - 1);
|
||||
strncpy(createInfo.localizedActionSetName, localizedName.c_str(),
|
||||
XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE - 1);
|
||||
createInfo.priority = priority;
|
||||
|
||||
check(xrCreateActionSet(getXrInstance(), &createInfo, &_actionSet),
|
||||
"Failed to create OpenXR action set");
|
||||
}
|
||||
|
||||
ActionSet::~ActionSet()
|
||||
{
|
||||
if (_actionSet != XR_NULL_HANDLE)
|
||||
{
|
||||
check(xrDestroyActionSet(_actionSet),
|
||||
"Failed to destroy OpenXR action set");
|
||||
}
|
||||
}
|
69
3rdparty/osgXR/src/OpenXR/ActionSet.h
vendored
Normal file
69
3rdparty/osgXR/src/OpenXR/ActionSet.h
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_ACTION_SET
|
||||
#define OSGXR_OPENXR_ACTION_SET 1
|
||||
|
||||
#include "Instance.h"
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class ActionSet : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
ActionSet(Instance *instance,
|
||||
const std::string &name,
|
||||
const std::string &localizedName,
|
||||
uint32_t priority);
|
||||
virtual ~ActionSet();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _actionSet != XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _instance->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Conversions
|
||||
|
||||
inline const osg::ref_ptr<Instance> getInstance() const
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
inline XrInstance getXrInstance() const
|
||||
{
|
||||
return _instance->getXrInstance();
|
||||
}
|
||||
|
||||
inline XrActionSet getXrActionSet() const
|
||||
{
|
||||
return _actionSet;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Action set data
|
||||
osg::ref_ptr<Instance> _instance;
|
||||
XrActionSet _actionSet;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
71
3rdparty/osgXR/src/OpenXR/Compositor.cpp
vendored
Normal file
71
3rdparty/osgXR/src/OpenXR/Compositor.cpp
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "Compositor.h"
|
||||
#include "DepthInfo.h"
|
||||
#include "Space.h"
|
||||
#include "SwapchainGroupSubImage.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
void CompositionLayerProjection::addView(osg::ref_ptr<Session::Frame> frame, uint32_t viewIndex,
|
||||
const SwapchainGroup::SubImage &subImage,
|
||||
const DepthInfo *depthInfo)
|
||||
{
|
||||
assert(viewIndex < _projViews.size());
|
||||
|
||||
XrCompositionLayerProjectionView &projView = _projViews[viewIndex];
|
||||
projView = { XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW };
|
||||
projView.pose = frame->getViewPose(viewIndex);
|
||||
projView.fov = frame->getViewFov(viewIndex);
|
||||
subImage.getXrSubImage(&projView.subImage);
|
||||
|
||||
if (depthInfo && subImage.depthValid())
|
||||
{
|
||||
// depth info
|
||||
XrCompositionLayerDepthInfoKHR &xrDepthInfo = _depthInfos[viewIndex];
|
||||
xrDepthInfo = { XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR };
|
||||
subImage.getDepthXrSubImage(&xrDepthInfo.subImage);
|
||||
xrDepthInfo.minDepth = depthInfo->getMinDepth();
|
||||
xrDepthInfo.maxDepth = depthInfo->getMaxDepth();
|
||||
xrDepthInfo.nearZ = depthInfo->getNearZ();
|
||||
xrDepthInfo.farZ = depthInfo->getFarZ();
|
||||
|
||||
// add depth info to projection view chain
|
||||
projView.next = &xrDepthInfo;
|
||||
}
|
||||
}
|
||||
|
||||
const XrCompositionLayerBaseHeader *CompositionLayerProjection::getXr()
|
||||
{
|
||||
unsigned int validDepthInfos = 0;
|
||||
for (unsigned int i = 0; i < _projViews.size(); ++i)
|
||||
{
|
||||
auto &view = _projViews[i];
|
||||
auto &depthInfo = _depthInfos[i];
|
||||
if (view.type != XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW)
|
||||
{
|
||||
// Eek, some views have been omitted!
|
||||
OSG_WARN << "Partial projection views!" << std::endl;
|
||||
}
|
||||
|
||||
if (depthInfo.type == XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR)
|
||||
++validDepthInfos;
|
||||
}
|
||||
|
||||
// Sanity check that depth info is entirely missing or complete
|
||||
if (validDepthInfos > 0 && validDepthInfos < _projViews.size())
|
||||
{
|
||||
OSG_WARN << "Partial projection depth info, disabling depth information" << std::endl;
|
||||
for (auto &view: _projViews)
|
||||
view.next = nullptr;
|
||||
}
|
||||
|
||||
_layer.layerFlags = _layerFlags;
|
||||
_layer.space = _space->getXrSpace();
|
||||
_layer.viewCount = _projViews.size();
|
||||
_layer.views = _projViews.data();
|
||||
return reinterpret_cast<const XrCompositionLayerBaseHeader*>(&_layer);
|
||||
}
|
92
3rdparty/osgXR/src/OpenXR/Compositor.h
vendored
Normal file
92
3rdparty/osgXR/src/OpenXR/Compositor.h
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_COMPOSITOR
|
||||
#define OSGXR_OPENXR_COMPOSITOR 1
|
||||
|
||||
#include "Session.h"
|
||||
#include "Space.h"
|
||||
#include "SwapchainGroup.h"
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class DepthInfo;
|
||||
|
||||
class CompositionLayer : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
CompositionLayer() :
|
||||
_layerFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CompositionLayer()
|
||||
{
|
||||
}
|
||||
|
||||
inline XrCompositionLayerFlags getLayerFlags() const
|
||||
{
|
||||
return _layerFlags;
|
||||
}
|
||||
inline void setLayerFlags(XrCompositionLayerFlags layerFlags)
|
||||
{
|
||||
_layerFlags = layerFlags;
|
||||
}
|
||||
|
||||
inline Space *getSpace() const
|
||||
{
|
||||
return _space;
|
||||
}
|
||||
inline void setSpace(Space *space)
|
||||
{
|
||||
_space = space;
|
||||
}
|
||||
|
||||
virtual const XrCompositionLayerBaseHeader *getXr() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
XrCompositionLayerFlags _layerFlags;
|
||||
osg::ref_ptr<Space> _space;
|
||||
};
|
||||
|
||||
class CompositionLayerProjection : public CompositionLayer
|
||||
{
|
||||
public:
|
||||
|
||||
CompositionLayerProjection(unsigned int viewCount)
|
||||
{
|
||||
_layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
|
||||
_layer.next = nullptr;
|
||||
_projViews.resize(viewCount);
|
||||
_depthInfos.resize(viewCount);
|
||||
}
|
||||
|
||||
virtual ~CompositionLayerProjection()
|
||||
{
|
||||
}
|
||||
|
||||
void addView(osg::ref_ptr<Session::Frame> frame, uint32_t viewIndex,
|
||||
const SwapchainGroup::SubImage &subImage,
|
||||
const DepthInfo *depthInfo = nullptr);
|
||||
|
||||
const XrCompositionLayerBaseHeader *getXr() override;
|
||||
|
||||
protected:
|
||||
|
||||
mutable XrCompositionLayerProjection _layer;
|
||||
std::vector<XrCompositionLayerProjectionView> _projViews;
|
||||
std::vector<XrCompositionLayerDepthInfoKHR> _depthInfos;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
80
3rdparty/osgXR/src/OpenXR/DepthInfo.h
vendored
Normal file
80
3rdparty/osgXR/src/OpenXR/DepthInfo.h
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_DEPTH_INFO
|
||||
#define OSGXR_OPENXR_DEPTH_INFO 1
|
||||
|
||||
#include <osg/Matrixd>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
// Represents depth information for a view
|
||||
class DepthInfo
|
||||
{
|
||||
public:
|
||||
|
||||
DepthInfo() :
|
||||
_minDepth(0),
|
||||
_maxDepth(1),
|
||||
_nearZ(1),
|
||||
_farZ(10)
|
||||
{
|
||||
}
|
||||
|
||||
// Mutators
|
||||
|
||||
void setDepthRange(float minDepth, float maxDepth)
|
||||
{
|
||||
_minDepth = minDepth;
|
||||
_maxDepth = maxDepth;
|
||||
}
|
||||
|
||||
void setZRange(float nearZ, float farZ)
|
||||
{
|
||||
_nearZ = nearZ;
|
||||
_farZ = farZ;
|
||||
}
|
||||
|
||||
void setZRangeFromProjection(const osg::Matrixd &proj)
|
||||
{
|
||||
float left, right, bottom, top;
|
||||
proj.getFrustum(left, right, bottom, top, _nearZ, _farZ);
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
float getMinDepth() const
|
||||
{
|
||||
return _minDepth;
|
||||
}
|
||||
|
||||
float getMaxDepth() const
|
||||
{
|
||||
return _maxDepth;
|
||||
}
|
||||
|
||||
float getNearZ() const
|
||||
{
|
||||
return _nearZ;
|
||||
}
|
||||
|
||||
float getFarZ() const
|
||||
{
|
||||
return _farZ;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
float _minDepth;
|
||||
float _maxDepth;
|
||||
float _nearZ;
|
||||
float _farZ;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
182
3rdparty/osgXR/src/OpenXR/EventHandler.cpp
vendored
Normal file
182
3rdparty/osgXR/src/OpenXR/EventHandler.cpp
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "EventHandler.h"
|
||||
#include "Instance.h"
|
||||
#include "Session.h"
|
||||
|
||||
#include <osg/Notify>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
void EventHandler::onEvent(Instance *instance,
|
||||
const XrEventDataBuffer *event)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
case XR_TYPE_EVENT_DATA_EVENTS_LOST:
|
||||
onEventsLost(instance,
|
||||
reinterpret_cast<const XrEventDataEventsLost *>(event));
|
||||
break;
|
||||
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
|
||||
onInstanceLossPending(instance,
|
||||
reinterpret_cast<const XrEventDataInstanceLossPending *>(event));
|
||||
break;
|
||||
case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
|
||||
{
|
||||
auto *profileEvent = reinterpret_cast<const XrEventDataInteractionProfileChanged *>(event);
|
||||
Session *session = instance->getSession(profileEvent->session);
|
||||
if (session)
|
||||
onInteractionProfileChanged(session, profileEvent);
|
||||
else
|
||||
OSG_WARN << "Unhandled OpenXR interaction profile changed event: Session not registered" << std::endl;
|
||||
break;
|
||||
}
|
||||
case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING:
|
||||
{
|
||||
auto *spaceEvent = reinterpret_cast<const XrEventDataReferenceSpaceChangePending *>(event);
|
||||
Session *session = instance->getSession(spaceEvent->session);
|
||||
if (session)
|
||||
onReferenceSpaceChangePending(session, spaceEvent);
|
||||
else
|
||||
OSG_WARN << "Unhandled OpenXR reference space change pending event: Session not registered" << std::endl;
|
||||
break;
|
||||
}
|
||||
case XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR:
|
||||
{
|
||||
auto *maskEvent = reinterpret_cast<const XrEventDataVisibilityMaskChangedKHR *>(event);
|
||||
Session *session = instance->getSession(maskEvent->session);
|
||||
if (session)
|
||||
onVisibilityMaskChanged(session, maskEvent);
|
||||
else
|
||||
OSG_WARN << "Unhandled OpenXR visibility mask change event: Session not registered" << std::endl;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
|
||||
{
|
||||
auto *stateEvent = reinterpret_cast<const XrEventDataSessionStateChanged *>(event);
|
||||
Session *session = instance->getSession(stateEvent->session);
|
||||
if (session)
|
||||
onSessionStateChanged(session, stateEvent);
|
||||
else
|
||||
OSG_WARN << "Unhandled OpenXR session state change event: Session not registered" << std::endl;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
onUnhandledEvent(instance, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EventHandler::onUnhandledEvent(Instance *instance,
|
||||
const XrEventDataBuffer *event)
|
||||
{
|
||||
OSG_WARN << "Unhandled OpenXR Event: " << event->type << std::endl;
|
||||
}
|
||||
|
||||
void EventHandler::onEventsLost(Instance *instance,
|
||||
const XrEventDataEventsLost *event)
|
||||
{
|
||||
OSG_WARN << event->lostEventCount << " OpenXR events lost" << std::endl;
|
||||
}
|
||||
|
||||
void EventHandler::onInstanceLossPending(Instance *instance,
|
||||
const XrEventDataInstanceLossPending *event)
|
||||
{
|
||||
OSG_WARN << "OpenXR instance loss pending" << std::endl;
|
||||
}
|
||||
|
||||
void EventHandler::onInteractionProfileChanged(Session *session,
|
||||
const XrEventDataInteractionProfileChanged *event)
|
||||
{
|
||||
OSG_WARN << "OpenXR interaction profile changed" << std::endl;
|
||||
}
|
||||
|
||||
void EventHandler::onReferenceSpaceChangePending(Session *session,
|
||||
const XrEventDataReferenceSpaceChangePending *event)
|
||||
{
|
||||
OSG_WARN << "OpenXR reference space change penging" << std::endl;
|
||||
}
|
||||
|
||||
void EventHandler::onVisibilityMaskChanged(Session *session,
|
||||
const XrEventDataVisibilityMaskChangedKHR *event)
|
||||
{
|
||||
session->updateVisibilityMasks(event->viewConfigurationType,
|
||||
event->viewIndex);
|
||||
}
|
||||
|
||||
void EventHandler::onSessionStateChanged(Session *session,
|
||||
const XrEventDataSessionStateChanged *event)
|
||||
{
|
||||
XrSessionState oldState = session->getState();
|
||||
session->setState(event->state);
|
||||
switch (event->state)
|
||||
{
|
||||
case XR_SESSION_STATE_IDLE:
|
||||
// Either starting or soon to be stopping
|
||||
if (oldState == XR_SESSION_STATE_UNKNOWN)
|
||||
onSessionStateStart(session);
|
||||
break;
|
||||
case XR_SESSION_STATE_READY:
|
||||
// Session ready to begin
|
||||
onSessionStateReady(session);
|
||||
break;
|
||||
case XR_SESSION_STATE_SYNCHRONIZED:
|
||||
// Either session synchronised or no longer visible
|
||||
break;
|
||||
case XR_SESSION_STATE_VISIBLE:
|
||||
// Either session now visible or lost focus
|
||||
if (oldState == XR_SESSION_STATE_FOCUSED)
|
||||
onSessionStateUnfocus(session);
|
||||
break;
|
||||
case XR_SESSION_STATE_FOCUSED:
|
||||
// Session visible and in focus
|
||||
onSessionStateFocus(session);
|
||||
break;
|
||||
case XR_SESSION_STATE_STOPPING:
|
||||
// Session now stopping
|
||||
onSessionStateStopping(session, false);
|
||||
break;
|
||||
case XR_SESSION_STATE_LOSS_PENDING:
|
||||
// Session loss is pending, which can happen at any time
|
||||
if (oldState == XR_SESSION_STATE_FOCUSED)
|
||||
onSessionStateUnfocus(session);
|
||||
if (session->isRunning())
|
||||
onSessionStateStopping(session, true);
|
||||
// Attempt restart
|
||||
onSessionStateEnd(session, true);
|
||||
break;
|
||||
case XR_SESSION_STATE_EXITING:
|
||||
// Session is exiting and should be cleaned up
|
||||
onSessionStateEnd(session, false);
|
||||
break;
|
||||
default:
|
||||
OSG_WARN << "Unknown OpenXR session state: " << event->state << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EventHandler::onSessionStateStart(Session *session)
|
||||
{
|
||||
}
|
||||
|
||||
void EventHandler::onSessionStateEnd(Session *session, bool retry)
|
||||
{
|
||||
}
|
||||
|
||||
void EventHandler::onSessionStateReady(Session *session)
|
||||
{
|
||||
}
|
||||
|
||||
void EventHandler::onSessionStateStopping(Session *session, bool loss)
|
||||
{
|
||||
}
|
||||
|
||||
void EventHandler::onSessionStateFocus(Session *session)
|
||||
{
|
||||
}
|
||||
|
||||
void EventHandler::onSessionStateUnfocus(Session *session)
|
||||
{
|
||||
}
|
75
3rdparty/osgXR/src/OpenXR/EventHandler.h
vendored
Normal file
75
3rdparty/osgXR/src/OpenXR/EventHandler.h
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_EVENT_HANDLER
|
||||
#define OSGXR_OPENXR_EVENT_HANDLER 1
|
||||
|
||||
#include <osg/Referenced>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class Instance;
|
||||
class Session;
|
||||
|
||||
/// This class handles OpenXR events.
|
||||
class EventHandler : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
// Instance events
|
||||
|
||||
/// Top level OpenXR event handler.
|
||||
void onEvent(Instance *instance, const XrEventDataBuffer *event);
|
||||
/// Handle an otherwise unhandled event.
|
||||
virtual void onUnhandledEvent(Instance *instance,
|
||||
const XrEventDataBuffer *event);
|
||||
|
||||
/// Handle an events lost event.
|
||||
virtual void onEventsLost(Instance *instance,
|
||||
const XrEventDataEventsLost *event);
|
||||
/// Handle an instance loss pending event.
|
||||
virtual void onInstanceLossPending(Instance *instance,
|
||||
const XrEventDataInstanceLossPending *event);
|
||||
|
||||
// Session events
|
||||
|
||||
/// Handle an interaction profile changed event.
|
||||
virtual void onInteractionProfileChanged(Session *session,
|
||||
const XrEventDataInteractionProfileChanged *event);
|
||||
/// Handle a reference space change pending event.
|
||||
virtual void onReferenceSpaceChangePending(Session *session,
|
||||
const XrEventDataReferenceSpaceChangePending *event);
|
||||
/// Handle a visibility mask change event.
|
||||
virtual void onVisibilityMaskChanged(Session *session,
|
||||
const XrEventDataVisibilityMaskChangedKHR *event);
|
||||
/// Handle a session state change event.
|
||||
virtual void onSessionStateChanged(Session *session,
|
||||
const XrEventDataSessionStateChanged *event);
|
||||
|
||||
// Session state events
|
||||
|
||||
/// Transition into initial idle state (idle, after init).
|
||||
virtual void onSessionStateStart(Session *session);
|
||||
/// Transition into ending state (exiting / loss pending, before cleanup).
|
||||
virtual void onSessionStateEnd(Session *session, bool retry);
|
||||
|
||||
/// Transition into a ready state.
|
||||
virtual void onSessionStateReady(Session *session);
|
||||
/// Transition out of running state (stopping, before end).
|
||||
virtual void onSessionStateStopping(Session *session, bool loss);
|
||||
|
||||
/// Transition into focused session state.
|
||||
virtual void onSessionStateFocus(Session *session);
|
||||
/// Transition out of focused session state.
|
||||
virtual void onSessionStateUnfocus(Session *session);
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
69
3rdparty/osgXR/src/OpenXR/GraphicsBinding.cpp
vendored
Normal file
69
3rdparty/osgXR/src/OpenXR/GraphicsBinding.cpp
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "GraphicsBinding.h"
|
||||
#include "GraphicsBindingWin32.h"
|
||||
#include "GraphicsBindingX11.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class GraphicsBindingProxy : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
virtual ~GraphicsBindingProxy() {}
|
||||
|
||||
virtual GraphicsBinding *create(osgViewer::GraphicsWindow *window) = 0;
|
||||
};
|
||||
|
||||
template <typename GRAPHICS_BINDING>
|
||||
class GraphicsBindingProxyImpl : public GraphicsBindingProxy
|
||||
{
|
||||
protected:
|
||||
typedef GRAPHICS_BINDING Binding;
|
||||
typedef typename Binding::GraphicsWindow Window;
|
||||
|
||||
virtual ~GraphicsBindingProxyImpl() {}
|
||||
|
||||
public:
|
||||
GraphicsBinding *create(osgViewer::GraphicsWindow *window) override
|
||||
{
|
||||
Window *win = dynamic_cast<Window *>(window);
|
||||
if (!win)
|
||||
return nullptr;
|
||||
|
||||
return new Binding(win);
|
||||
}
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
typedef std::vector<osg::ref_ptr<GraphicsBindingProxy> > ProxyList;
|
||||
|
||||
static ProxyList proxies = {
|
||||
#ifdef OSGXR_USE_WIN32
|
||||
new GraphicsBindingProxyImpl<GraphicsBindingWin32>(),
|
||||
#endif
|
||||
#ifdef OSGXR_USE_X11
|
||||
new GraphicsBindingProxyImpl<GraphicsBindingX11>(),
|
||||
#endif
|
||||
};
|
||||
|
||||
osg::ref_ptr<GraphicsBinding> osgXR::OpenXR::createGraphicsBinding(osgViewer::GraphicsWindow *window)
|
||||
{
|
||||
GraphicsBinding *ret = nullptr;
|
||||
for (GraphicsBindingProxy *proxy: proxies)
|
||||
{
|
||||
ret = proxy->create(window);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
48
3rdparty/osgXR/src/OpenXR/GraphicsBinding.h
vendored
Normal file
48
3rdparty/osgXR/src/OpenXR/GraphicsBinding.h
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_GRAPHICS_BINDING
|
||||
#define OSGXR_OPENXR_GRAPHICS_BINDING 1
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgViewer/GraphicsWindow>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class GraphicsBinding : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
virtual ~GraphicsBinding() { }
|
||||
|
||||
virtual void *getXrGraphicsBinding() = 0;
|
||||
};
|
||||
|
||||
template <typename GRAPHICS_WINDOW, typename XR_BINDING>
|
||||
class GraphicsBindingImpl : public GraphicsBinding
|
||||
{
|
||||
public:
|
||||
typedef GRAPHICS_WINDOW GraphicsWindow;
|
||||
|
||||
GraphicsBindingImpl(GraphicsWindow *window);
|
||||
virtual ~GraphicsBindingImpl() {}
|
||||
|
||||
void *getXrGraphicsBinding() override
|
||||
{
|
||||
return &_binding;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
XR_BINDING _binding;
|
||||
};
|
||||
|
||||
osg::ref_ptr<GraphicsBinding> createGraphicsBinding(osgViewer::GraphicsWindow *window);
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
14
3rdparty/osgXR/src/OpenXR/GraphicsBindingWin32.cpp
vendored
Normal file
14
3rdparty/osgXR/src/OpenXR/GraphicsBindingWin32.cpp
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "GraphicsBindingWin32.h"
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
template <>
|
||||
GraphicsBindingWin32::GraphicsBindingImpl(osgViewer::GraphicsWindowWin32 *window) :
|
||||
_binding{ XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR }
|
||||
{
|
||||
_binding.hDC = window->getHDC();
|
||||
_binding.hGLRC = window->getWGLContext();
|
||||
}
|
29
3rdparty/osgXR/src/OpenXR/GraphicsBindingWin32.h
vendored
Normal file
29
3rdparty/osgXR/src/OpenXR/GraphicsBindingWin32.h
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_GRAPHICS_BINDING_WIN32
|
||||
#define OSGXR_OPENXR_GRAPHICS_BINDING_WIN32 1
|
||||
|
||||
#ifdef OSGXR_USE_WIN32
|
||||
|
||||
#include "GraphicsBinding.h"
|
||||
|
||||
#include <osgViewer/api/Win32/GraphicsWindowWin32>
|
||||
|
||||
#define XR_USE_GRAPHICS_API_OPENGL
|
||||
#define XR_USE_PLATFORM_WIN32
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
typedef GraphicsBindingImpl<osgViewer::GraphicsWindowWin32, XrGraphicsBindingOpenGLWin32KHR> GraphicsBindingWin32;
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif // OSGXR_USE_WIN32
|
||||
|
||||
#endif
|
40
3rdparty/osgXR/src/OpenXR/GraphicsBindingX11.cpp
vendored
Normal file
40
3rdparty/osgXR/src/OpenXR/GraphicsBindingX11.cpp
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "GraphicsBindingX11.h"
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Class to spy on protected members of GraphicsWindowX11.
|
||||
class GraphicsWindowX11Spy : public osgViewer::GraphicsWindowX11
|
||||
{
|
||||
public:
|
||||
const XVisualInfo *getVisualInfo() const
|
||||
{
|
||||
return _visualInfo;
|
||||
}
|
||||
|
||||
const GLXFBConfig &getFBConfig() const
|
||||
{
|
||||
return _fbConfig;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <>
|
||||
GraphicsBindingX11::GraphicsBindingImpl(osgViewer::GraphicsWindowX11 *window) :
|
||||
_binding{ XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR }
|
||||
{
|
||||
// window isn't actually of type GraphicsWindowX11Spy, but this allows us to
|
||||
// spy on protected members that don't have public accessors.
|
||||
auto spyWindow = static_cast<GraphicsWindowX11Spy *>(window);
|
||||
|
||||
_binding.xDisplay = window->getDisplay();
|
||||
_binding.visualid = spyWindow->getVisualInfo()->visualid;
|
||||
_binding.glxFBConfig = spyWindow->getFBConfig();
|
||||
_binding.glxDrawable = window->getWindow();
|
||||
_binding.glxContext = window->getContext();
|
||||
}
|
29
3rdparty/osgXR/src/OpenXR/GraphicsBindingX11.h
vendored
Normal file
29
3rdparty/osgXR/src/OpenXR/GraphicsBindingX11.h
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_GRAPHICS_BINDING_X11
|
||||
#define OSGXR_OPENXR_GRAPHICS_BINDING_X11 1
|
||||
|
||||
#ifdef OSGXR_USE_X11
|
||||
|
||||
#include "GraphicsBinding.h"
|
||||
|
||||
#include <osgViewer/api/X11/GraphicsWindowX11>
|
||||
|
||||
#define XR_USE_GRAPHICS_API_OPENGL
|
||||
#define XR_USE_PLATFORM_XLIB
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
typedef GraphicsBindingImpl<osgViewer::GraphicsWindowX11, XrGraphicsBindingOpenGLXlibKHR> GraphicsBindingX11;
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif // OSGXR_USE_X11
|
||||
|
||||
#endif
|
398
3rdparty/osgXR/src/OpenXR/Instance.cpp
vendored
Normal file
398
3rdparty/osgXR/src/OpenXR/Instance.cpp
vendored
Normal file
|
@ -0,0 +1,398 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "EventHandler.h"
|
||||
#include "Instance.h"
|
||||
#include "Session.h"
|
||||
#include "System.h"
|
||||
#include "generated/Version.h"
|
||||
|
||||
#include <osg/Notify>
|
||||
#include <osg/Version>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#define ENGINE_NAME "osgXR"
|
||||
#define ENGINE_VERSION (OSGXR_MAJOR_VERSION << 16 | \
|
||||
OSGXR_MINOR_VERSION << 8 | \
|
||||
OSGXR_PATCH_VERSION)
|
||||
#define API_VERSION XR_MAKE_VERSION(1, 0, 0)
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
static std::vector<XrApiLayerProperties> layers;
|
||||
static std::vector<XrExtensionProperties> extensions;
|
||||
|
||||
static bool enumerateLayers(bool invalidate = false)
|
||||
{
|
||||
static bool layersEnumerated = false;
|
||||
if (invalidate)
|
||||
{
|
||||
layers.resize(0);
|
||||
layersEnumerated = false;
|
||||
return false;
|
||||
}
|
||||
if (layersEnumerated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Count layers
|
||||
uint32_t layerCount = 0;
|
||||
XrResult res = xrEnumerateApiLayerProperties(0, &layerCount, nullptr);
|
||||
if (XR_FAILED(res))
|
||||
{
|
||||
OSG_WARN << "Failed to count OpenXR API layers: " << res << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (layerCount)
|
||||
{
|
||||
// Allocate memory
|
||||
layers.resize(layerCount);
|
||||
for (auto &layer: layers)
|
||||
{
|
||||
layer.type = XR_TYPE_API_LAYER_PROPERTIES;
|
||||
layer.next = nullptr;
|
||||
}
|
||||
|
||||
// Enumerate layers
|
||||
res = xrEnumerateApiLayerProperties(layers.size(), &layerCount, layers.data());
|
||||
if (XR_FAILED(res))
|
||||
{
|
||||
OSG_WARN << "Failed to enumerate " << layerCount
|
||||
<< " OpenXR API layers: " << res << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Layers may change at any time
|
||||
layers.resize(layerCount);
|
||||
}
|
||||
|
||||
layersEnumerated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool enumerateExtensions(bool invalidate = false)
|
||||
{
|
||||
static bool extensionsEnumerated = false;
|
||||
if (invalidate)
|
||||
{
|
||||
extensions.resize(0);
|
||||
extensionsEnumerated = false;
|
||||
return false;
|
||||
}
|
||||
if (extensionsEnumerated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Count extensions
|
||||
uint32_t extensionCount;
|
||||
XrResult res = xrEnumerateInstanceExtensionProperties(nullptr, 0, &extensionCount, nullptr);
|
||||
if (XR_FAILED(res))
|
||||
{
|
||||
OSG_WARN << "Failed to count OpenXR instance extensions: " << res << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extensionCount)
|
||||
{
|
||||
// Allocate memory
|
||||
extensions.resize(extensionCount);
|
||||
for (auto &extension: extensions)
|
||||
{
|
||||
extension.type = XR_TYPE_EXTENSION_PROPERTIES;
|
||||
extension.next = nullptr;
|
||||
}
|
||||
|
||||
// Enumerate extensions
|
||||
res = xrEnumerateInstanceExtensionProperties(nullptr, extensions.size(),
|
||||
&extensionCount, extensions.data());
|
||||
if (XR_FAILED(res))
|
||||
{
|
||||
OSG_WARN << "Failed to enumerate " << extensionCount
|
||||
<< " OpenXR instance extensions: " << res << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extensions may change (?)
|
||||
extensions.resize(extensionCount);
|
||||
}
|
||||
|
||||
extensionsEnumerated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Instance::invalidateLayers()
|
||||
{
|
||||
enumerateLayers(true);
|
||||
}
|
||||
|
||||
void Instance::invalidateExtensions()
|
||||
{
|
||||
enumerateExtensions(true);
|
||||
}
|
||||
|
||||
bool Instance::hasLayer(const char *name)
|
||||
{
|
||||
enumerateLayers();
|
||||
|
||||
for (auto &layer: layers)
|
||||
{
|
||||
if (!strncmp(name, layer.layerName, XR_MAX_API_LAYER_NAME_SIZE))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Instance::hasExtension(const char *name)
|
||||
{
|
||||
enumerateExtensions();
|
||||
|
||||
for (auto &extension: extensions)
|
||||
{
|
||||
if (!strncmp(name, extension.extensionName, XR_MAX_EXTENSION_NAME_SIZE))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Instance *Instance::instance()
|
||||
{
|
||||
static osg::ref_ptr<Instance> s_instance = new Instance();
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
Instance::Instance():
|
||||
_layerValidation(false),
|
||||
_depthInfo(false),
|
||||
_visibilityMask(true),
|
||||
_instance(XR_NULL_HANDLE),
|
||||
_lost(false)
|
||||
{
|
||||
}
|
||||
|
||||
Instance::~Instance()
|
||||
{
|
||||
if (_instance != XR_NULL_HANDLE)
|
||||
{
|
||||
// Delete the systems
|
||||
for (System *system: _systems)
|
||||
{
|
||||
delete system;
|
||||
}
|
||||
|
||||
// Destroy the OpenXR instance
|
||||
XrResult res = xrDestroyInstance(_instance);
|
||||
if (XR_FAILED(res))
|
||||
{
|
||||
OSG_WARN << "Failed to destroy OpenXR instance" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Instance::InitResult Instance::init(const char *appName, uint32_t appVersion)
|
||||
{
|
||||
if (_instance != XR_NULL_HANDLE)
|
||||
{
|
||||
return INIT_SUCCESS;
|
||||
}
|
||||
|
||||
std::vector<const char *> layerNames;
|
||||
std::vector<const char *> extensionNames;
|
||||
|
||||
// Enable validation layer if selected
|
||||
if (_layerValidation && hasLayer(XR_APILAYER_LUNARG_core_validation))
|
||||
{
|
||||
layerNames.push_back(XR_APILAYER_LUNARG_core_validation);
|
||||
}
|
||||
|
||||
// We need OpenGL support
|
||||
if (!hasExtension(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME))
|
||||
{
|
||||
OSG_WARN << "OpenXR runtime doesn't support XR_KHR_opengl_enable extension" << std::endl;
|
||||
return INIT_FAIL;
|
||||
}
|
||||
extensionNames.push_back(XR_KHR_OPENGL_ENABLE_EXTENSION_NAME);
|
||||
|
||||
// Enable depth composition layer support if supported
|
||||
_supportsCompositionLayerDepth = hasExtension(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME);
|
||||
if (_depthInfo)
|
||||
{
|
||||
if (_supportsCompositionLayerDepth)
|
||||
extensionNames.push_back(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME);
|
||||
else
|
||||
_depthInfo = false;
|
||||
}
|
||||
|
||||
// Enable visibility mask support if supported
|
||||
_supportsVisibilityMask = hasExtension(XR_KHR_VISIBILITY_MASK_EXTENSION_NAME);
|
||||
if (_visibilityMask)
|
||||
{
|
||||
if (_supportsVisibilityMask)
|
||||
extensionNames.push_back(XR_KHR_VISIBILITY_MASK_EXTENSION_NAME);
|
||||
else
|
||||
_visibilityMask = false;
|
||||
}
|
||||
|
||||
// Create the instance
|
||||
XrInstanceCreateInfo info{ XR_TYPE_INSTANCE_CREATE_INFO };
|
||||
strncpy(info.applicationInfo.applicationName, appName,
|
||||
XR_MAX_APPLICATION_NAME_SIZE - 1);
|
||||
info.applicationInfo.applicationVersion = appVersion;
|
||||
strncpy(info.applicationInfo.engineName, ENGINE_NAME,
|
||||
XR_MAX_ENGINE_NAME_SIZE - 1);
|
||||
info.applicationInfo.engineVersion = ENGINE_VERSION;
|
||||
info.applicationInfo.apiVersion = API_VERSION;
|
||||
info.enabledApiLayerCount = layerNames.size();
|
||||
info.enabledApiLayerNames = layerNames.data();
|
||||
info.enabledExtensionCount = extensionNames.size();
|
||||
info.enabledExtensionNames = extensionNames.data();
|
||||
|
||||
XrResult res = xrCreateInstance(&info, &_instance);
|
||||
if (XR_FAILED(res))
|
||||
{
|
||||
OSG_WARN << "Failed to create OpenXR instance: " << res << std::endl;
|
||||
if (res == XR_ERROR_INSTANCE_LOST)
|
||||
return INIT_LATER;
|
||||
return INIT_FAIL;
|
||||
}
|
||||
|
||||
// Log the runtime properties
|
||||
_properties.type = XR_TYPE_INSTANCE_PROPERTIES;
|
||||
_properties.next = nullptr;
|
||||
|
||||
if (XR_SUCCEEDED(xrGetInstanceProperties(_instance, &_properties)))
|
||||
{
|
||||
OSG_INFO << "OpenXR Runtime: \"" << _properties.runtimeName
|
||||
<< "\" version " << XR_VERSION_MAJOR(_properties.runtimeVersion)
|
||||
<< "." << XR_VERSION_MINOR(_properties.runtimeVersion)
|
||||
<< "." << XR_VERSION_PATCH(_properties.runtimeVersion) << std::endl;
|
||||
}
|
||||
|
||||
// Get extension functions
|
||||
_xrGetOpenGLGraphicsRequirementsKHR = (PFN_xrGetOpenGLGraphicsRequirementsKHR)getProcAddr("xrGetOpenGLGraphicsRequirementsKHR");
|
||||
if (_visibilityMask)
|
||||
_xrGetVisibilityMaskKHR = (PFN_xrGetVisibilityMaskKHR)getProcAddr("xrGetVisibilityMaskKHR");
|
||||
|
||||
return INIT_SUCCESS;
|
||||
}
|
||||
|
||||
bool Instance::check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
if (XR_FAILED(result))
|
||||
{
|
||||
if (result == XR_ERROR_INSTANCE_LOST)
|
||||
_lost = true;
|
||||
|
||||
char resultName[XR_MAX_RESULT_STRING_SIZE];
|
||||
if (XR_FAILED(xrResultToString(_instance, result, resultName)))
|
||||
{
|
||||
OSG_WARN << warnMsg << ": " << result << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
OSG_WARN << warnMsg << ": " << resultName << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PFN_xrVoidFunction Instance::getProcAddr(const char *name) const
|
||||
{
|
||||
PFN_xrVoidFunction ret = nullptr;
|
||||
check(xrGetInstanceProcAddr(_instance, name, &ret),
|
||||
"Failed to get OpenXR procedure address");
|
||||
return ret;
|
||||
}
|
||||
|
||||
System *Instance::getSystem(XrFormFactor formFactor, bool *supported)
|
||||
{
|
||||
unsigned long ffId = formFactor - 1;
|
||||
if (ffId < _systems.size() && _systems[ffId])
|
||||
{
|
||||
if (supported)
|
||||
*supported = true;
|
||||
return _systems[ffId];
|
||||
}
|
||||
|
||||
XrSystemGetInfo getInfo{ XR_TYPE_SYSTEM_GET_INFO };
|
||||
getInfo.formFactor = formFactor;
|
||||
|
||||
XrSystemId systemId;
|
||||
XrResult res = xrGetSystem(_instance, &getInfo, &systemId);
|
||||
if (res == XR_ERROR_FORM_FACTOR_UNAVAILABLE)
|
||||
{
|
||||
// The system is only *TEMPORARILY* unavailable
|
||||
if (supported)
|
||||
*supported = true;
|
||||
return nullptr;
|
||||
}
|
||||
else if (check(res, "Failed to get OpenXR system"))
|
||||
{
|
||||
if (ffId >= _systems.size())
|
||||
_systems.resize(ffId+1, nullptr);
|
||||
|
||||
if (supported)
|
||||
*supported = true;
|
||||
return _systems[ffId] = new System(this, systemId);
|
||||
}
|
||||
|
||||
if (supported)
|
||||
*supported = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Instance::invalidateSystem(XrFormFactor formFactor)
|
||||
{
|
||||
unsigned long ffId = formFactor - 1;
|
||||
if (ffId < _systems.size())
|
||||
{
|
||||
delete _systems[ffId];
|
||||
_systems[ffId] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::registerSession(Session *session)
|
||||
{
|
||||
_sessions[session->getXrSession()] = session;
|
||||
}
|
||||
|
||||
void Instance::unregisterSession(Session *session)
|
||||
{
|
||||
_sessions.erase(session->getXrSession());
|
||||
}
|
||||
|
||||
Session *Instance::getSession(XrSession xrSession)
|
||||
{
|
||||
auto it = _sessions.find(xrSession);
|
||||
if (it == _sessions.end())
|
||||
return nullptr;
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
void Instance::pollEvents(EventHandler *handler)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
XrEventDataBuffer event;
|
||||
event.type = XR_TYPE_EVENT_DATA_BUFFER;
|
||||
event.next = nullptr;
|
||||
|
||||
XrResult res = xrPollEvent(_instance, &event);
|
||||
if (XR_FAILED(res))
|
||||
break;
|
||||
if (res == XR_EVENT_UNAVAILABLE)
|
||||
break;
|
||||
|
||||
handler->onEvent(this, &event);
|
||||
}
|
||||
}
|
179
3rdparty/osgXR/src/OpenXR/Instance.h
vendored
Normal file
179
3rdparty/osgXR/src/OpenXR/Instance.h
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_INSTANCE
|
||||
#define OSGXR_OPENXR_INSTANCE 1
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/observer_ptr>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#define XR_USE_GRAPHICS_API_OPENGL
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
#define XR_APILAYER_LUNARG_core_validation "XR_APILAYER_LUNARG_core_validation"
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class EventHandler;
|
||||
class System;
|
||||
class Session;
|
||||
|
||||
class Instance : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
static Instance *instance();
|
||||
|
||||
Instance();
|
||||
virtual ~Instance();
|
||||
|
||||
// Layers and extensions
|
||||
|
||||
static void invalidateLayers();
|
||||
static void invalidateExtensions();
|
||||
static bool hasLayer(const char *name);
|
||||
static bool hasExtension(const char *name);
|
||||
|
||||
// Instance initialisation
|
||||
|
||||
void setValidationLayer(bool layerValidation)
|
||||
{
|
||||
_layerValidation = layerValidation;
|
||||
}
|
||||
|
||||
void setDepthInfo(bool depthInfo)
|
||||
{
|
||||
_depthInfo = depthInfo;
|
||||
}
|
||||
|
||||
void setVisibilityMask(bool visibilityMask)
|
||||
{
|
||||
_visibilityMask = visibilityMask;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
/// Instance creation successful.
|
||||
INIT_SUCCESS,
|
||||
/// Instance creation not possible at the moment, try again later.
|
||||
INIT_LATER,
|
||||
/// Instance creation failed.
|
||||
INIT_FAIL,
|
||||
} InitResult;
|
||||
InitResult init(const char *appName, uint32_t appVersion);
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _instance != XR_NULL_SYSTEM_ID;
|
||||
}
|
||||
|
||||
inline bool lost() const
|
||||
{
|
||||
return _lost;
|
||||
}
|
||||
|
||||
bool check(XrResult result, const char *warnMsg) const;
|
||||
|
||||
// Conversions
|
||||
|
||||
inline XrInstance getXrInstance() const
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
// Instance properties
|
||||
inline const char *getRuntimeName() const
|
||||
{
|
||||
return _properties.runtimeName;
|
||||
}
|
||||
|
||||
// Extensions
|
||||
|
||||
bool supportsCompositionLayerDepth() const
|
||||
{
|
||||
return _supportsCompositionLayerDepth;
|
||||
}
|
||||
|
||||
bool supportsVisibilityMask() const
|
||||
{
|
||||
return _supportsVisibilityMask;
|
||||
}
|
||||
|
||||
PFN_xrVoidFunction getProcAddr(const char *name) const;
|
||||
|
||||
XrResult getOpenGLGraphicsRequirements(XrSystemId systemId,
|
||||
XrGraphicsRequirementsOpenGLKHR* graphicsRequirements) const
|
||||
{
|
||||
if (!_xrGetOpenGLGraphicsRequirementsKHR)
|
||||
return XR_ERROR_FUNCTION_UNSUPPORTED;
|
||||
return _xrGetOpenGLGraphicsRequirementsKHR(_instance, systemId,
|
||||
graphicsRequirements);
|
||||
}
|
||||
|
||||
XrResult xrGetVisibilityMask(XrSession session,
|
||||
XrViewConfigurationType viewConfigurationType,
|
||||
uint32_t viewIndex,
|
||||
XrVisibilityMaskTypeKHR visibilityMaskType,
|
||||
XrVisibilityMaskKHR *visibilityMask)
|
||||
{
|
||||
if (!_xrGetVisibilityMaskKHR)
|
||||
return XR_ERROR_FUNCTION_UNSUPPORTED;
|
||||
return _xrGetVisibilityMaskKHR(session, viewConfigurationType,
|
||||
viewIndex, visibilityMaskType,
|
||||
visibilityMask);
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
System *getSystem(XrFormFactor formFactor, bool *supported = nullptr);
|
||||
|
||||
// Up to caller to ensure no session
|
||||
void invalidateSystem(XrFormFactor formFactor);
|
||||
void registerSession(Session *session);
|
||||
void unregisterSession(Session *session);
|
||||
Session *getSession(XrSession xrSession);
|
||||
|
||||
// Events
|
||||
|
||||
void pollEvents(EventHandler *handler);
|
||||
|
||||
protected:
|
||||
|
||||
// Setup data
|
||||
bool _layerValidation;
|
||||
bool _depthInfo;
|
||||
bool _visibilityMask;
|
||||
|
||||
// Instance data
|
||||
XrInstance _instance;
|
||||
mutable bool _lost;
|
||||
|
||||
// Extension presence
|
||||
bool _supportsCompositionLayerDepth;
|
||||
bool _supportsVisibilityMask;
|
||||
// Extension functions
|
||||
mutable PFN_xrGetOpenGLGraphicsRequirementsKHR _xrGetOpenGLGraphicsRequirementsKHR;
|
||||
mutable PFN_xrGetVisibilityMaskKHR _xrGetVisibilityMaskKHR;
|
||||
|
||||
// Instance properties
|
||||
XrInstanceProperties _properties;
|
||||
|
||||
// Systems
|
||||
mutable std::vector<System *> _systems;
|
||||
|
||||
// Sessions
|
||||
std::map<XrSession, Session *> _sessions;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
59
3rdparty/osgXR/src/OpenXR/InteractionProfile.cpp
vendored
Normal file
59
3rdparty/osgXR/src/OpenXR/InteractionProfile.cpp
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "InteractionProfile.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
InteractionProfile::InteractionProfile(const Path &path) :
|
||||
_path(path)
|
||||
{
|
||||
}
|
||||
|
||||
InteractionProfile::InteractionProfile(Instance *instance,
|
||||
const char *vendor, const char *type) :
|
||||
_path(instance, (std::string)"/interaction_profiles/" + vendor + "/" + type)
|
||||
{
|
||||
}
|
||||
|
||||
InteractionProfile::~InteractionProfile()
|
||||
{
|
||||
}
|
||||
|
||||
void InteractionProfile::addBinding(Action *action, const Path &binding)
|
||||
{
|
||||
assert(binding.getInstance() == getInstance());
|
||||
_bindings.insert(ActionBindingPair(action, binding.getXrPath()));
|
||||
}
|
||||
|
||||
bool InteractionProfile::suggestBindings()
|
||||
{
|
||||
// No bindings: nothing to do!
|
||||
if (_bindings.empty())
|
||||
return true;
|
||||
|
||||
// Construct binding vector from _bindings map
|
||||
std::vector<XrActionSuggestedBinding> bindings;
|
||||
bindings.reserve(_bindings.size());
|
||||
for (auto pair: _bindings)
|
||||
{
|
||||
if (pair.first->init())
|
||||
bindings.push_back({ pair.first->getXrAction(),
|
||||
pair.second });
|
||||
}
|
||||
|
||||
// Suggest the bindings
|
||||
XrInteractionProfileSuggestedBinding suggestedBinding{
|
||||
XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING
|
||||
};
|
||||
suggestedBinding.interactionProfile = _path.getXrPath();
|
||||
suggestedBinding.countSuggestedBindings = bindings.size();
|
||||
suggestedBinding.suggestedBindings = bindings.data();
|
||||
|
||||
return check(xrSuggestInteractionProfileBindings(getXrInstance(),
|
||||
&suggestedBinding),
|
||||
"Failed to suggest interaction profile bindings");
|
||||
}
|
77
3rdparty/osgXR/src/OpenXR/InteractionProfile.h
vendored
Normal file
77
3rdparty/osgXR/src/OpenXR/InteractionProfile.h
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_INTERACTION_PROFILE
|
||||
#define OSGXR_OPENXR_INTERACTION_PROFILE 1
|
||||
|
||||
#include "Action.h"
|
||||
#include "Path.h"
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class InteractionProfile : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
InteractionProfile(const Path &path);
|
||||
InteractionProfile(Instance *instance,
|
||||
const char *vendor, const char *type);
|
||||
virtual ~InteractionProfile();
|
||||
|
||||
// Accessors
|
||||
|
||||
void addBinding(Action *action, const std::string &binding)
|
||||
{
|
||||
Path path(_path.getInstance(), binding);
|
||||
addBinding(action, path);
|
||||
}
|
||||
|
||||
void addBinding(Action *action, const Path &binding);
|
||||
|
||||
// returns true on success
|
||||
bool suggestBindings();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _path.check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Conversions
|
||||
|
||||
inline const osg::ref_ptr<Instance> getInstance() const
|
||||
{
|
||||
return _path.getInstance();
|
||||
}
|
||||
|
||||
inline XrInstance getXrInstance() const
|
||||
{
|
||||
return _path.getXrInstance();
|
||||
}
|
||||
|
||||
inline const Path &getPath() const
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Interaction profile data
|
||||
Path _path;
|
||||
typedef std::pair<osg::ref_ptr<Action>, XrPath> ActionBindingPair;
|
||||
std::set<ActionBindingPair> _bindings;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
41
3rdparty/osgXR/src/OpenXR/Path.cpp
vendored
Normal file
41
3rdparty/osgXR/src/OpenXR/Path.cpp
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "Path.h"
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
Path::Path(Instance *instance,
|
||||
XrPath path) :
|
||||
_instance(instance),
|
||||
_path(path)
|
||||
{
|
||||
}
|
||||
|
||||
Path::Path(Instance *instance,
|
||||
const std::string &path) :
|
||||
_instance(instance),
|
||||
_path(XR_NULL_PATH)
|
||||
{
|
||||
check(xrStringToPath(getXrInstance(), path.c_str(), &_path),
|
||||
"Failed to create OpenXR path from string");
|
||||
}
|
||||
|
||||
std::string Path::toString() const
|
||||
{
|
||||
if (!valid())
|
||||
return "";
|
||||
|
||||
uint32_t count;
|
||||
if (!check(xrPathToString(getXrInstance(), _path,
|
||||
0, &count, nullptr),
|
||||
"Failed to size OpenXR path string"))
|
||||
return "";
|
||||
std::vector<char> buffer(count);
|
||||
if (!check(xrPathToString(getXrInstance(), _path,
|
||||
buffer.size(), &count, buffer.data()),
|
||||
"Failed to get OpenXR path string"))
|
||||
return "";
|
||||
|
||||
return buffer.data();
|
||||
}
|
80
3rdparty/osgXR/src/OpenXR/Path.h
vendored
Normal file
80
3rdparty/osgXR/src/OpenXR/Path.h
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_PATH
|
||||
#define OSGXR_OPENXR_PATH 1
|
||||
|
||||
#include "Instance.h"
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class Path
|
||||
{
|
||||
public:
|
||||
|
||||
Path(Instance *instance = nullptr, XrPath path = XR_NULL_PATH);
|
||||
Path(Instance *instance, const std::string &path);
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _path != XR_NULL_PATH;
|
||||
}
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _instance->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Conversions
|
||||
|
||||
inline const osg::ref_ptr<Instance> getInstance() const
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
inline XrInstance getXrInstance() const
|
||||
{
|
||||
return _instance->getXrInstance();
|
||||
}
|
||||
|
||||
inline XrPath getXrPath() const
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
// Comparisons
|
||||
|
||||
bool operator == (const Path &other) const
|
||||
{
|
||||
return _path == other._path &&
|
||||
_instance == other._instance;
|
||||
}
|
||||
|
||||
bool operator != (const Path &other) const
|
||||
{
|
||||
return _path != other._path ||
|
||||
_instance != other._instance;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Path data
|
||||
osg::ref_ptr<Instance> _instance;
|
||||
XrPath _path;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
519
3rdparty/osgXR/src/OpenXR/Session.cpp
vendored
Normal file
519
3rdparty/osgXR/src/OpenXR/Session.cpp
vendored
Normal file
|
@ -0,0 +1,519 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#define XR_USE_GRAPHICS_API_OPENGL
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
#include "ActionSet.h"
|
||||
#include "Compositor.h"
|
||||
#include "Session.h"
|
||||
#include "GraphicsBinding.h"
|
||||
|
||||
#include <osg/Notify>
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#ifdef OSGXR_USE_X11
|
||||
#include <osgViewer/api/X11/GraphicsWindowX11>
|
||||
#include <GL/glx.h>
|
||||
#endif // OSGXR_USE_X11
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
Session::Session(System *system,
|
||||
osgViewer::GraphicsWindow *window) :
|
||||
_window(window),
|
||||
_instance(system->getInstance()),
|
||||
_system(system),
|
||||
_session(XR_NULL_HANDLE),
|
||||
_viewConfiguration(nullptr),
|
||||
_actionSyncCount(0),
|
||||
_state(XR_SESSION_STATE_UNKNOWN),
|
||||
_running(false),
|
||||
_exiting(false),
|
||||
_readSwapchainFormats(false),
|
||||
_lastDisplayTime(0)
|
||||
{
|
||||
XrSessionCreateInfo createInfo = { XR_TYPE_SESSION_CREATE_INFO };
|
||||
createInfo.systemId = getXrSystemId();
|
||||
|
||||
// Get OpenGL graphics requirements
|
||||
XrGraphicsRequirementsOpenGLKHR req;
|
||||
req.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR;
|
||||
req.next = nullptr;
|
||||
check(_instance->getOpenGLGraphicsRequirements(getXrSystemId(), &req),
|
||||
"Failed to get OpenXR's OpenGL graphics requirements");
|
||||
// ... and pretty much ignore what it says
|
||||
|
||||
osg::ref_ptr<GraphicsBinding> graphicsBinding = createGraphicsBinding(window);
|
||||
if (graphicsBinding == nullptr)
|
||||
{
|
||||
OSG_WARN << "Failed to get OpenXR graphics binding" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
createInfo.next = graphicsBinding->getXrGraphicsBinding();
|
||||
|
||||
// GL context must not be bound in another thread
|
||||
bool currentSet = checkCurrent();
|
||||
// As of 2021-12-16 Monado expects the GL context to be current
|
||||
// See https://gitlab.freedesktop.org/monado/monado/-/issues/145
|
||||
if (!currentSet)
|
||||
makeCurrent();
|
||||
if (check(xrCreateSession(getXrInstance(), &createInfo, &_session),
|
||||
"Failed to create OpenXR session"))
|
||||
{
|
||||
_instance->registerSession(this);
|
||||
}
|
||||
if (!currentSet)
|
||||
releaseContext();
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
{
|
||||
if (_session != XR_NULL_HANDLE)
|
||||
{
|
||||
_instance->unregisterSession(this);
|
||||
_localSpace = nullptr;
|
||||
// GL context must not be bound in another thread
|
||||
check(xrDestroySession(_session),
|
||||
"Failed to destroy OpenXR session");
|
||||
}
|
||||
}
|
||||
|
||||
void Session::addActionSet(ActionSet *actionSet)
|
||||
{
|
||||
assert(actionSet->getInstance() == getInstance());
|
||||
_actionSets.insert(actionSet);
|
||||
}
|
||||
|
||||
bool Session::attachActionSets()
|
||||
{
|
||||
assert(valid());
|
||||
if (_actionSets.empty())
|
||||
return false;
|
||||
|
||||
// Construct vector of XrActionSets
|
||||
std::vector<XrActionSet> actionSets;
|
||||
actionSets.reserve(_actionSets.size());
|
||||
for (auto actionSet: _actionSets)
|
||||
actionSets.push_back(actionSet->getXrActionSet());
|
||||
|
||||
XrSessionActionSetsAttachInfo attachInfo{ XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO };
|
||||
attachInfo.countActionSets = actionSets.size();
|
||||
attachInfo.actionSets = actionSets.data();
|
||||
|
||||
return check(xrAttachSessionActionSets(_session, &attachInfo),
|
||||
"Failed to attach action sets to OpenXR session");
|
||||
}
|
||||
|
||||
Path Session::getCurrentInteractionProfile(const Path &subactionPath) const
|
||||
{
|
||||
XrInteractionProfileState interactionProfile{ XR_TYPE_INTERACTION_PROFILE_STATE };
|
||||
|
||||
if (check(xrGetCurrentInteractionProfile(_session, subactionPath.getXrPath(),
|
||||
&interactionProfile),
|
||||
"Failed to get OpenXR current interaction profile"))
|
||||
{
|
||||
return Path(getInstance(), interactionProfile.interactionProfile);
|
||||
}
|
||||
return Path();
|
||||
}
|
||||
|
||||
bool Session::getActionBoundSources(Action *action,
|
||||
std::vector<XrPath> &sourcePaths) const
|
||||
{
|
||||
if (!valid())
|
||||
return false;
|
||||
|
||||
// Count bound sources
|
||||
XrBoundSourcesForActionEnumerateInfo enumerateInfo{ XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO };
|
||||
enumerateInfo.action = action->getXrAction();
|
||||
uint32_t count;
|
||||
if (check(xrEnumerateBoundSourcesForAction(_session, &enumerateInfo,
|
||||
0, &count, nullptr),
|
||||
"Failed to count OpenXR action bound sources"))
|
||||
{
|
||||
// Resize output buffer
|
||||
sourcePaths.resize(count);
|
||||
if (!count)
|
||||
return true;
|
||||
|
||||
// Fill buffer
|
||||
if (check(xrEnumerateBoundSourcesForAction(_session, &enumerateInfo,
|
||||
sourcePaths.size(),
|
||||
&count,
|
||||
sourcePaths.data()),
|
||||
"Failed to enumerate OpenXR action bound sources"))
|
||||
{
|
||||
// Success!
|
||||
if (count < sourcePaths.size())
|
||||
sourcePaths.resize(count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Failure!
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Session::getInputSourceLocalizedName(XrPath sourcePath,
|
||||
XrInputSourceLocalizedNameFlags whichComponents) const
|
||||
{
|
||||
if (!valid())
|
||||
return "";
|
||||
|
||||
XrInputSourceLocalizedNameGetInfo getInfo{ XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO };
|
||||
getInfo.sourcePath = sourcePath;
|
||||
getInfo.whichComponents = whichComponents;
|
||||
|
||||
uint32_t count;
|
||||
if (!check(xrGetInputSourceLocalizedName(_session, &getInfo,
|
||||
0, &count, nullptr),
|
||||
"Failed to size OpenXR input source localized name string"))
|
||||
return "";
|
||||
std::vector<char> buffer(count);
|
||||
if (!check(xrGetInputSourceLocalizedName(_session, &getInfo,
|
||||
buffer.size(), &count, buffer.data()),
|
||||
"Failed to get OpenXR input source localized name string"))
|
||||
return "";
|
||||
|
||||
return buffer.data();
|
||||
}
|
||||
|
||||
void Session::activateActionSet(ActionSet *actionSet, Path subactionPath)
|
||||
{
|
||||
assert(_actionSets.count(actionSet));
|
||||
_activeActionSets.insert(ActionSetSubactionPair(actionSet, subactionPath.getXrPath()));
|
||||
}
|
||||
|
||||
void Session::deactivateActionSet(ActionSet *actionSet, Path subactionPath)
|
||||
{
|
||||
_activeActionSets.erase(ActionSetSubactionPair(actionSet, subactionPath.getXrPath()));
|
||||
}
|
||||
|
||||
bool Session::syncActions()
|
||||
{
|
||||
assert(valid());
|
||||
|
||||
XrActionsSyncInfo syncInfo{ XR_TYPE_ACTIONS_SYNC_INFO };
|
||||
std::vector<XrActiveActionSet> actionSets;
|
||||
if (!_activeActionSets.empty())
|
||||
{
|
||||
// Construct vector of XrActionSets
|
||||
actionSets.reserve(_activeActionSets.size());
|
||||
for (auto actionSet: _activeActionSets)
|
||||
{
|
||||
XrActiveActionSet activeActionSet;
|
||||
activeActionSet.actionSet = actionSet.first->getXrActionSet();
|
||||
activeActionSet.subactionPath = actionSet.second;
|
||||
actionSets.push_back(activeActionSet);
|
||||
}
|
||||
|
||||
syncInfo.countActiveActionSets = actionSets.size();
|
||||
syncInfo.activeActionSets = actionSets.data();
|
||||
|
||||
bool ret = check(xrSyncActions(_session, &syncInfo),
|
||||
"Failed to sync action sets to OpenXR session");
|
||||
if (ret)
|
||||
++_actionSyncCount;
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const Session::SwapchainFormats &Session::getSwapchainFormats() const
|
||||
{
|
||||
if (!_readSwapchainFormats && valid())
|
||||
{
|
||||
uint32_t formatCount;
|
||||
if (check(xrEnumerateSwapchainFormats(_session, 0, &formatCount, nullptr),
|
||||
"Failed to count OpenXR swapchain formats"))
|
||||
{
|
||||
if (formatCount)
|
||||
{
|
||||
_swapchainFormats.resize(formatCount);
|
||||
if (!check(xrEnumerateSwapchainFormats(_session, formatCount,
|
||||
&formatCount, _swapchainFormats.data()),
|
||||
"Failed to enumerate OpenXR swapchain formats"))
|
||||
{
|
||||
_swapchainFormats.resize(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_readSwapchainFormats = true;
|
||||
}
|
||||
|
||||
return _swapchainFormats;
|
||||
}
|
||||
|
||||
Space *Session::getLocalSpace()
|
||||
{
|
||||
if (!_localSpace.valid())
|
||||
_localSpace = new Space(this, XR_REFERENCE_SPACE_TYPE_LOCAL);
|
||||
|
||||
return _localSpace;
|
||||
}
|
||||
|
||||
void Session::updateVisibilityMasks(XrViewConfigurationType viewConfigurationType,
|
||||
uint32_t viewIndex)
|
||||
{
|
||||
// Session must be started ...
|
||||
if (!_viewConfiguration)
|
||||
return;
|
||||
// ... and with a matching view configuration
|
||||
if (viewConfigurationType != _viewConfiguration->getType())
|
||||
return;
|
||||
|
||||
if (viewIndex >= _viewConfiguration->getViews().size())
|
||||
return;
|
||||
VisMaskGeometryView &visMaskView = _visMaskCache[viewIndex];
|
||||
|
||||
// Regenerate cached visibility mask geometries for this viewIndex
|
||||
for (uint32_t visMaskType = 0; visMaskType < visMaskView.size(); ++visMaskType)
|
||||
if (visMaskView[visMaskType].valid())
|
||||
getVisibilityMask(viewIndex, static_cast<XrVisibilityMaskTypeKHR>(1 + visMaskType), true);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Geometry> Session::getVisibilityMask(uint32_t viewIndex,
|
||||
XrVisibilityMaskTypeKHR visibilityMaskType,
|
||||
bool force)
|
||||
{
|
||||
if (!_viewConfiguration)
|
||||
return nullptr;
|
||||
if (viewIndex >= _viewConfiguration->getViews().size())
|
||||
return nullptr;
|
||||
if (visibilityMaskType == 0 || visibilityMaskType > XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR)
|
||||
return nullptr;
|
||||
|
||||
// Size cache to match number of views...
|
||||
if (_visMaskCache.size() == 0)
|
||||
_visMaskCache.resize(_viewConfiguration->getViews().size());
|
||||
// ... and number of vis mask types
|
||||
VisMaskGeometryView &visMaskView = _visMaskCache[viewIndex];
|
||||
if (visMaskView.size() == 0)
|
||||
visMaskView.resize(XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR);
|
||||
// Cache hit?
|
||||
VisMaskGeometry &visMaskGeometry = visMaskView[visibilityMaskType - 1];
|
||||
if (!force && visMaskGeometry.valid())
|
||||
return visMaskGeometry;
|
||||
|
||||
// Get counts of visibility mask
|
||||
XrVisibilityMaskKHR visibilityMask{ XR_TYPE_VISIBILITY_MASK_KHR };
|
||||
XrResult res = xrGetVisibilityMask(*_viewConfiguration, viewIndex,
|
||||
visibilityMaskType, &visibilityMask);
|
||||
if (res != XR_ERROR_FUNCTION_UNSUPPORTED &&
|
||||
check(res, "Failed to size OpenXR visibility mask"))
|
||||
{
|
||||
osg::PrimitiveSet::Mode mode;
|
||||
switch (visibilityMaskType)
|
||||
{
|
||||
case XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR:
|
||||
// fall through
|
||||
case XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR:
|
||||
mode = osg::PrimitiveSet::TRIANGLES;
|
||||
break;
|
||||
case XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR:
|
||||
mode = osg::PrimitiveSet::LINE_LOOP;
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate space for data
|
||||
osg::ref_ptr<osg::Vec2Array> vertices = new osg::Vec2Array(visibilityMask.vertexCountOutput);
|
||||
osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(mode, visibilityMask.indexCountOutput);
|
||||
|
||||
// Get the actual data
|
||||
static_assert(sizeof((*vertices)[0]) == sizeof(XrVector2f));
|
||||
static_assert(sizeof((*indices)[0]) == sizeof(uint32_t));
|
||||
visibilityMask.vertexCapacityInput = vertices->size();
|
||||
visibilityMask.vertices = reinterpret_cast<XrVector2f *>(&vertices->front());
|
||||
visibilityMask.indexCapacityInput = indices->size();
|
||||
visibilityMask.indices = reinterpret_cast<uint32_t *>(&indices->front());
|
||||
XrResult res = xrGetVisibilityMask(*_viewConfiguration, viewIndex,
|
||||
visibilityMaskType, &visibilityMask);
|
||||
if (check(res, "Failed to get OpenXR visibility mask"))
|
||||
{
|
||||
if (!visMaskGeometry.valid())
|
||||
{
|
||||
// Create a new geometry object
|
||||
osg::Geometry *geometry = new osg::Geometry();
|
||||
geometry->setVertexArray(vertices);
|
||||
geometry->addPrimitiveSet(indices);
|
||||
visMaskGeometry = geometry;
|
||||
return geometry;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update the existing geometry object
|
||||
osg::Geometry *geometry = visMaskGeometry.get();
|
||||
geometry->setVertexArray(vertices);
|
||||
geometry->setPrimitiveSet(0, indices);
|
||||
return geometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Session::checkCurrent() const
|
||||
{
|
||||
#ifdef OSGXR_USE_X11
|
||||
// Ugly X11 specific hack
|
||||
const auto *window = dynamic_cast<const osgViewer::GraphicsWindowX11*>(_window.get());
|
||||
return glXGetCurrentContext() == window->getContext();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Session::makeCurrent() const
|
||||
{
|
||||
#ifdef OSGXR_USE_X11
|
||||
_window->makeCurrentImplementation();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Session::releaseContext() const
|
||||
{
|
||||
#ifdef OSGXR_USE_X11
|
||||
_window->releaseContextImplementation();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Session::begin(const System::ViewConfiguration &viewConfiguration)
|
||||
{
|
||||
_viewConfiguration = &viewConfiguration;
|
||||
|
||||
XrSessionBeginInfo beginInfo{ XR_TYPE_SESSION_BEGIN_INFO };
|
||||
beginInfo.primaryViewConfigurationType = viewConfiguration.getType();
|
||||
if (check(xrBeginSession(_session, &beginInfo),
|
||||
"Failed to begin OpenXR session"))
|
||||
{
|
||||
_running = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Session::end()
|
||||
{
|
||||
check(xrEndSession(_session),
|
||||
"Failed to end OpenXR session");
|
||||
_running = false;
|
||||
_viewConfiguration = nullptr;
|
||||
_visMaskCache.resize(0);
|
||||
}
|
||||
|
||||
void Session::requestExit()
|
||||
{
|
||||
_exiting = true;
|
||||
if (isRunning())
|
||||
check(xrRequestExitSession(_session),
|
||||
"Failed to request OpenXR exit");
|
||||
}
|
||||
|
||||
osg::ref_ptr<Session::Frame> Session::waitFrame()
|
||||
{
|
||||
osg::ref_ptr<Frame> frame;
|
||||
|
||||
XrFrameWaitInfo frameWaitInfo{ XR_TYPE_FRAME_WAIT_INFO };
|
||||
XrFrameState frameState;
|
||||
frameState.type = XR_TYPE_FRAME_STATE;
|
||||
frameState.next = nullptr;
|
||||
if (check(xrWaitFrame(_session, &frameWaitInfo, &frameState),
|
||||
"Failed to wait for OpenXR frame"))
|
||||
{
|
||||
frame = new Frame(this, &frameState);
|
||||
_lastDisplayTime = frameState.predictedDisplayTime;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
Session::Frame::Frame(osg::ref_ptr<Session> session, XrFrameState *frameState) :
|
||||
_session(session),
|
||||
_time(frameState->predictedDisplayTime),
|
||||
_period(frameState->predictedDisplayPeriod),
|
||||
_shouldRender(frameState->shouldRender),
|
||||
_osgFrameNumber(0),
|
||||
_locatedViews(false),
|
||||
_begun(false),
|
||||
_envBlendMode(XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM)
|
||||
{
|
||||
}
|
||||
|
||||
Session::Frame::~Frame()
|
||||
{
|
||||
}
|
||||
|
||||
void Session::Frame::locateViews()
|
||||
{
|
||||
// Get view locations
|
||||
XrViewLocateInfo locateInfo = { XR_TYPE_VIEW_LOCATE_INFO };
|
||||
locateInfo.viewConfigurationType = _session->getViewConfiguration()->getType();
|
||||
locateInfo.displayTime = _time;
|
||||
locateInfo.space = _session->getLocalSpace()->getXrSpace();
|
||||
|
||||
_viewState = { XR_TYPE_VIEW_STATE };
|
||||
|
||||
uint32_t viewCount;
|
||||
if (!check(xrLocateViews(_session->getXrSession(), &locateInfo, &_viewState, 0, &viewCount, nullptr),
|
||||
"Failed to count OpenXR views"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_views.resize(viewCount);
|
||||
for (auto &view: _views)
|
||||
view = { XR_TYPE_VIEW };
|
||||
if (!check(xrLocateViews(_session->getXrSession(), &locateInfo, &_viewState, _views.size(), &viewCount, _views.data()),
|
||||
"Failed to locate OpenXR views"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_locatedViews = true;
|
||||
}
|
||||
|
||||
void Session::Frame::addLayer(osg::ref_ptr<CompositionLayer> layer)
|
||||
{
|
||||
_layers.push_back(layer);
|
||||
}
|
||||
|
||||
bool Session::Frame::begin()
|
||||
{
|
||||
XrFrameBeginInfo frameBeginInfo{ XR_TYPE_FRAME_BEGIN_INFO };
|
||||
return _begun = check(xrBeginFrame(_session->getXrSession(), &frameBeginInfo),
|
||||
"Failed to begin OpenXR frame");
|
||||
}
|
||||
|
||||
bool Session::Frame::end()
|
||||
{
|
||||
std::vector<const XrCompositionLayerBaseHeader *> layers;
|
||||
layers.reserve(_layers.size());
|
||||
for (auto &layer: _layers)
|
||||
layers.push_back(layer->getXr());
|
||||
|
||||
XrFrameEndInfo frameEndInfo{ XR_TYPE_FRAME_END_INFO };
|
||||
frameEndInfo.displayTime = _time;
|
||||
frameEndInfo.environmentBlendMode = _envBlendMode;
|
||||
frameEndInfo.layerCount = layers.size();
|
||||
frameEndInfo.layers = layers.data();
|
||||
|
||||
bool currentSet = _session->checkCurrent();
|
||||
bool ret = check(xrEndFrame(_session->getXrSession(), &frameEndInfo),
|
||||
"Failed to end OpenXR frame");
|
||||
|
||||
// TODO: should not be necessary, but is for SteamVR 1.16.4 (but not 1.15.x)
|
||||
if (currentSet)
|
||||
_session->makeCurrent();
|
||||
|
||||
return ret;
|
||||
}
|
376
3rdparty/osgXR/src/OpenXR/Session.h
vendored
Normal file
376
3rdparty/osgXR/src/OpenXR/Session.h
vendored
Normal file
|
@ -0,0 +1,376 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_SESSION
|
||||
#define OSGXR_OPENXR_SESSION 1
|
||||
|
||||
#include "Path.h"
|
||||
#include "System.h"
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Referenced>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgViewer/GraphicsWindow>
|
||||
#include <OpenThreads/Mutex>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class Action;
|
||||
class ActionSet;
|
||||
class CompositionLayer;
|
||||
class Space;
|
||||
|
||||
class Session : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
// GL context must not be bound in another thread
|
||||
Session(System *system, osgViewer::GraphicsWindow *window);
|
||||
// GL context must not be bound in another thread
|
||||
virtual ~Session();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _session != XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _system->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Action set attachment
|
||||
|
||||
/// Add an action set to the list.
|
||||
void addActionSet(ActionSet *actionSet);
|
||||
/**
|
||||
* Attach the added action sets to the OpenXR session.
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
bool attachActionSets();
|
||||
|
||||
/// Get the current interaction profile for the given subaction path.
|
||||
Path getCurrentInteractionProfile(const Path &subactionPath) const;
|
||||
|
||||
/// Get a list of bound source paths for an action.
|
||||
bool getActionBoundSources(Action *action,
|
||||
std::vector<XrPath> &sourcePaths) const;
|
||||
|
||||
/**
|
||||
* Get a localized name for an input source.
|
||||
* @param sourcePath Input source path.
|
||||
* @param whichComponents Which components to include.
|
||||
* @return Localized name string
|
||||
*/
|
||||
std::string getInputSourceLocalizedName(XrPath sourcePath,
|
||||
XrInputSourceLocalizedNameFlags whichComponents) const;
|
||||
|
||||
// Action syncing
|
||||
|
||||
/// Activate a certain action set.
|
||||
void activateActionSet(ActionSet *actionSet,
|
||||
Path subactionPath = Path());
|
||||
/// Deactivate a certain action set.
|
||||
void deactivateActionSet(ActionSet *actionSet,
|
||||
Path subactionPath = Path());
|
||||
/// Sync active action sets.
|
||||
bool syncActions();
|
||||
|
||||
/// Get the number of action sync counts that have taken place.
|
||||
unsigned int getActionSyncCount() const
|
||||
{
|
||||
return _actionSyncCount;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
// Find whether the session is ready to begin
|
||||
inline bool isReady() const
|
||||
{
|
||||
return _state == XR_SESSION_STATE_READY;
|
||||
}
|
||||
|
||||
// Find whether the session is running
|
||||
inline bool isRunning() const
|
||||
{
|
||||
return _running;
|
||||
}
|
||||
|
||||
// Find whether the session is already in the process of exiting
|
||||
inline bool isExiting() const
|
||||
{
|
||||
return _exiting;
|
||||
}
|
||||
|
||||
inline osgViewer::GraphicsWindow *getWindow() const
|
||||
{
|
||||
return _window.get();
|
||||
}
|
||||
|
||||
// State management
|
||||
|
||||
inline XrSessionState getState() const
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
||||
inline void setState(XrSessionState state)
|
||||
{
|
||||
_state = state;
|
||||
}
|
||||
|
||||
|
||||
// Conversions
|
||||
|
||||
inline const osg::ref_ptr<Instance> getInstance() const
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
inline const System *getSystem() const
|
||||
{
|
||||
return _system;
|
||||
}
|
||||
|
||||
inline XrInstance getXrInstance() const
|
||||
{
|
||||
return _system->getXrInstance();
|
||||
}
|
||||
|
||||
inline XrSystemId getXrSystemId() const
|
||||
{
|
||||
return _system->getXrSystemId();
|
||||
}
|
||||
|
||||
inline XrSession getXrSession()
|
||||
{
|
||||
return _session;
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
typedef std::vector<int64_t> SwapchainFormats;
|
||||
const SwapchainFormats &getSwapchainFormats() const;
|
||||
|
||||
Space *getLocalSpace();
|
||||
XrTime getLastDisplayTime() const
|
||||
{
|
||||
return _lastDisplayTime;
|
||||
}
|
||||
|
||||
void updateVisibilityMasks(XrViewConfigurationType viewConfigurationType,
|
||||
uint32_t viewIndex);
|
||||
osg::ref_ptr<osg::Geometry> getVisibilityMask(uint32_t viewIndex,
|
||||
XrVisibilityMaskTypeKHR visibilityMaskType,
|
||||
bool force = false);
|
||||
|
||||
// Operations
|
||||
|
||||
bool checkCurrent() const;
|
||||
void makeCurrent() const;
|
||||
void releaseContext() const;
|
||||
|
||||
bool begin(const System::ViewConfiguration &viewConfiguration);
|
||||
void end();
|
||||
void requestExit();
|
||||
|
||||
const System::ViewConfiguration *getViewConfiguration() const
|
||||
{
|
||||
return _viewConfiguration;
|
||||
}
|
||||
|
||||
class Frame : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
Frame(osg::ref_ptr<Session> session, XrFrameState *frameState);
|
||||
|
||||
virtual ~Frame();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _session->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
inline bool shouldRender() const
|
||||
{
|
||||
return _shouldRender;
|
||||
}
|
||||
|
||||
inline bool hasBegun() const
|
||||
{
|
||||
return _begun;
|
||||
}
|
||||
|
||||
inline XrTime getTime() const
|
||||
{
|
||||
return _time;
|
||||
}
|
||||
|
||||
void locateViews();
|
||||
|
||||
void checkLocateViews()
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_locateViewsMutex);
|
||||
if (!_locatedViews)
|
||||
locateViews();
|
||||
}
|
||||
|
||||
bool isOrientationValid()
|
||||
{
|
||||
checkLocateViews();
|
||||
return _viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT;
|
||||
}
|
||||
bool isPositionValid()
|
||||
{
|
||||
checkLocateViews();
|
||||
return _viewState.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT;
|
||||
}
|
||||
bool isOrientationTracked()
|
||||
{
|
||||
checkLocateViews();
|
||||
return _viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_TRACKED_BIT;
|
||||
}
|
||||
bool isPositionTracked()
|
||||
{
|
||||
checkLocateViews();
|
||||
return _viewState.viewStateFlags & XR_VIEW_STATE_POSITION_TRACKED_BIT;
|
||||
}
|
||||
uint32_t getNumViews()
|
||||
{
|
||||
checkLocateViews();
|
||||
return _views.size();
|
||||
}
|
||||
const XrFovf &getViewFov(uint32_t index)
|
||||
{
|
||||
checkLocateViews();
|
||||
return _views[index].fov;
|
||||
}
|
||||
const XrPosef &getViewPose(uint32_t index)
|
||||
{
|
||||
checkLocateViews();
|
||||
return _views[index].pose;
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
|
||||
inline void setEnvBlendMode(XrEnvironmentBlendMode envBlendMode)
|
||||
{
|
||||
_envBlendMode = envBlendMode;
|
||||
}
|
||||
inline XrEnvironmentBlendMode getEnvBlendMode() const
|
||||
{
|
||||
return _envBlendMode;
|
||||
}
|
||||
|
||||
inline void setOsgFrameNumber(unsigned int osgFrameNumber)
|
||||
{
|
||||
_osgFrameNumber = osgFrameNumber;
|
||||
}
|
||||
inline unsigned int getOsgFrameNumber() const
|
||||
{
|
||||
return _osgFrameNumber;
|
||||
}
|
||||
|
||||
void addLayer(osg::ref_ptr<CompositionLayer> layer);
|
||||
|
||||
// Operations
|
||||
|
||||
bool begin();
|
||||
bool end();
|
||||
|
||||
protected:
|
||||
|
||||
// Frame info
|
||||
osg::ref_ptr<Session> _session;
|
||||
XrTime _time;
|
||||
XrDuration _period;
|
||||
bool _shouldRender;
|
||||
|
||||
// OpenSceneGraph frame
|
||||
unsigned int _osgFrameNumber;
|
||||
|
||||
// For access to _locatedViews etc
|
||||
OpenThreads::Mutex _locateViewsMutex;
|
||||
|
||||
// View locations (protected by _locateViewsMutex)
|
||||
bool _locatedViews;
|
||||
XrViewState _viewState;
|
||||
std::vector<XrView> _views;
|
||||
|
||||
// Frame end info
|
||||
bool _begun;
|
||||
XrEnvironmentBlendMode _envBlendMode;
|
||||
std::vector<osg::ref_ptr<CompositionLayer> > _layers;
|
||||
};
|
||||
|
||||
osg::ref_ptr<Frame> waitFrame();
|
||||
|
||||
// OpenXR extension wrappers
|
||||
XrResult xrGetVisibilityMask(const System::ViewConfiguration &viewConfiguration,
|
||||
uint32_t viewIndex,
|
||||
XrVisibilityMaskTypeKHR visibilityMaskType,
|
||||
XrVisibilityMaskKHR *visibilityMask)
|
||||
{
|
||||
return _instance->xrGetVisibilityMask(_session,
|
||||
viewConfiguration.getType(),
|
||||
viewIndex, visibilityMaskType,
|
||||
visibilityMask);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Init data
|
||||
osg::observer_ptr<osgViewer::GraphicsWindow> _window;
|
||||
|
||||
// Session data
|
||||
osg::ref_ptr<Instance> _instance;
|
||||
const System *_system;
|
||||
XrSession _session;
|
||||
const System::ViewConfiguration *_viewConfiguration;
|
||||
|
||||
// Action sets
|
||||
std::set<osg::ref_ptr<ActionSet>> _actionSets;
|
||||
typedef std::pair<ActionSet *, XrPath> ActionSetSubactionPair;
|
||||
std::set<ActionSetSubactionPair> _activeActionSets;
|
||||
unsigned int _actionSyncCount;
|
||||
|
||||
// Session state
|
||||
XrSessionState _state;
|
||||
bool _running;
|
||||
bool _exiting;
|
||||
|
||||
// Swapchain formats
|
||||
mutable bool _readSwapchainFormats;
|
||||
mutable SwapchainFormats _swapchainFormats;
|
||||
|
||||
// Reference spaces
|
||||
osg::ref_ptr<Space> _localSpace;
|
||||
XrTime _lastDisplayTime;
|
||||
|
||||
/*
|
||||
* Visibility mask geometry cache.
|
||||
* We keep visibility mask geometries cached to avoid duplication and so
|
||||
* we can update them after a VisibilityMaskChangedKHR event.
|
||||
*/
|
||||
typedef osg::ref_ptr<osg::Geometry> VisMaskGeometry;
|
||||
typedef std::vector<VisMaskGeometry> VisMaskGeometryView;
|
||||
typedef std::vector<VisMaskGeometryView> VisMaskGeometries;
|
||||
VisMaskGeometries _visMaskCache;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
94
3rdparty/osgXR/src/OpenXR/Space.cpp
vendored
Normal file
94
3rdparty/osgXR/src/OpenXR/Space.cpp
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "Space.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
static XrPosef poseIdentity = { { 0.0f, 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.0f } };
|
||||
|
||||
Space::Space(Session *session, XrReferenceSpaceType type) :
|
||||
_session(session),
|
||||
_space(XR_NULL_HANDLE)
|
||||
{
|
||||
// Attempt to create a reference space
|
||||
XrReferenceSpaceCreateInfo createInfo{ XR_TYPE_REFERENCE_SPACE_CREATE_INFO };
|
||||
createInfo.referenceSpaceType = type;
|
||||
createInfo.poseInReferenceSpace = poseIdentity;
|
||||
|
||||
check(xrCreateReferenceSpace(session->getXrSession(), &createInfo, &_space),
|
||||
"Failed to create OpenXR reference space");
|
||||
}
|
||||
|
||||
Space::Space(Session *session, ActionPose *action,
|
||||
Path subactionPath) :
|
||||
_session(session),
|
||||
_space(XR_NULL_HANDLE)
|
||||
{
|
||||
// Attempt to create an action space for this pose action
|
||||
XrActionSpaceCreateInfo createInfo{ XR_TYPE_ACTION_SPACE_CREATE_INFO };
|
||||
createInfo.action = action->getXrAction();
|
||||
createInfo.subactionPath = subactionPath.getXrPath();
|
||||
createInfo.poseInActionSpace = poseIdentity;
|
||||
|
||||
check(xrCreateActionSpace(session->getXrSession(), &createInfo, &_space),
|
||||
"Failed to create OpenXR action space");
|
||||
}
|
||||
|
||||
Space::~Space()
|
||||
{
|
||||
if (_session.valid() && valid())
|
||||
{
|
||||
check(xrDestroySpace(_space),
|
||||
"Failed to destroy OpenXR space");
|
||||
}
|
||||
}
|
||||
|
||||
Space::Location::Location() :
|
||||
_flags(0)
|
||||
{
|
||||
}
|
||||
|
||||
Space::Location::Location(XrSpaceLocationFlags flags,
|
||||
const osg::Quat &orientation,
|
||||
const osg::Vec3f &position) :
|
||||
_flags(flags),
|
||||
_orientation(orientation),
|
||||
_position(position)
|
||||
{
|
||||
}
|
||||
|
||||
bool Space::locate(const Space *baseSpace, XrTime time,
|
||||
Space::Location &location)
|
||||
{
|
||||
if (!_session.valid() || !valid())
|
||||
return false;
|
||||
assert(_session == baseSpace->_session);
|
||||
|
||||
XrSpaceLocation spaceLocation{ XR_TYPE_SPACE_LOCATION };
|
||||
bool ret = check(xrLocateSpace(getXrSpace(),
|
||||
baseSpace->getXrSpace(),
|
||||
time,
|
||||
&spaceLocation),
|
||||
"Failed to locate OpenXR space");
|
||||
if (ret)
|
||||
{
|
||||
osg::Quat orientation(spaceLocation.pose.orientation.x,
|
||||
spaceLocation.pose.orientation.y,
|
||||
spaceLocation.pose.orientation.z,
|
||||
spaceLocation.pose.orientation.w);
|
||||
osg::Vec3f position(spaceLocation.pose.position.x,
|
||||
spaceLocation.pose.position.y,
|
||||
spaceLocation.pose.position.z);
|
||||
location = Location(spaceLocation.locationFlags,
|
||||
orientation,
|
||||
position);
|
||||
}
|
||||
else
|
||||
{
|
||||
location = Location();
|
||||
}
|
||||
return ret;
|
||||
}
|
126
3rdparty/osgXR/src/OpenXR/Space.h
vendored
Normal file
126
3rdparty/osgXR/src/OpenXR/Space.h
vendored
Normal file
|
@ -0,0 +1,126 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_SPACE
|
||||
#define OSGXR_OPENXR_SPACE 1
|
||||
|
||||
#include "Action.h"
|
||||
#include "Path.h"
|
||||
#include "Session.h"
|
||||
|
||||
#include <osg/Quat>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/observer_ptr>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class Space : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
/// Create a reference space
|
||||
Space(Session *session, XrReferenceSpaceType type);
|
||||
/// Create an action space
|
||||
Space(Session *session, ActionPose *action,
|
||||
Path subactionPath = Path());
|
||||
virtual ~Space();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _space != XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _session->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Conversions
|
||||
|
||||
inline XrSpace getXrSpace() const
|
||||
{
|
||||
return _space;
|
||||
}
|
||||
|
||||
// Locating a space
|
||||
|
||||
class Location
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
Location();
|
||||
Location(XrSpaceLocationFlags flags,
|
||||
const osg::Quat &orientation,
|
||||
const osg::Vec3f &position);
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _flags != 0;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
bool isOrientationValid() const
|
||||
{
|
||||
return _flags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT;
|
||||
}
|
||||
|
||||
bool isPositionValid() const
|
||||
{
|
||||
return _flags & XR_SPACE_LOCATION_POSITION_VALID_BIT;
|
||||
}
|
||||
|
||||
bool isOrientationTracked() const
|
||||
{
|
||||
return _flags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT;
|
||||
}
|
||||
|
||||
bool isPositionTracked() const
|
||||
{
|
||||
return _flags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT;
|
||||
}
|
||||
|
||||
XrSpaceLocationFlags getFlags() const
|
||||
{
|
||||
return _flags;
|
||||
}
|
||||
|
||||
const osg::Quat &getOrientation() const
|
||||
{
|
||||
return _orientation;
|
||||
}
|
||||
|
||||
const osg::Vec3f &getPosition() const
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
XrSpaceLocationFlags _flags;
|
||||
osg::Quat _orientation;
|
||||
osg::Vec3f _position;
|
||||
};
|
||||
|
||||
bool locate(const Space *baseSpace, XrTime time,
|
||||
Location &location);
|
||||
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<Session> _session;
|
||||
XrSpace _space;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
170
3rdparty/osgXR/src/OpenXR/Swapchain.cpp
vendored
Normal file
170
3rdparty/osgXR/src/OpenXR/Swapchain.cpp
vendored
Normal file
|
@ -0,0 +1,170 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "Swapchain.h"
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
Swapchain::Swapchain(osg::ref_ptr<Session> session,
|
||||
const System::ViewConfiguration::View &view,
|
||||
XrSwapchainUsageFlags usageFlags,
|
||||
int64_t format) :
|
||||
_session(session),
|
||||
_swapchain(XR_NULL_HANDLE),
|
||||
_width(view.getRecommendedWidth()),
|
||||
_height(view.getRecommendedHeight()),
|
||||
_samples(view.getRecommendedSamples()),
|
||||
_format(format),
|
||||
_readImageTextures(false)
|
||||
{
|
||||
XrSwapchainCreateInfo createInfo{ XR_TYPE_SWAPCHAIN_CREATE_INFO };
|
||||
createInfo.usageFlags = usageFlags;
|
||||
createInfo.format = format;
|
||||
createInfo.sampleCount = _samples;
|
||||
createInfo.width = _width;
|
||||
createInfo.height = _height;
|
||||
createInfo.faceCount = 1;
|
||||
createInfo.arraySize = 1;
|
||||
createInfo.mipCount = 1;
|
||||
|
||||
bool currentSet = _session->checkCurrent();
|
||||
// As of 2021-12-16 Monado expects the GL context to be current
|
||||
// See https://gitlab.freedesktop.org/monado/monado/-/issues/145
|
||||
if (!currentSet)
|
||||
_session->makeCurrent();
|
||||
|
||||
// GL context must not be bound in another thread
|
||||
check(xrCreateSwapchain(getXrSession(), &createInfo, &_swapchain),
|
||||
"Failed to create OpenXR swapchain");
|
||||
|
||||
if (currentSet)
|
||||
// SteamVR 1.16.4 (but not 1.15.x) change context then clear it
|
||||
_session->makeCurrent();
|
||||
else
|
||||
// SteamVR linux_v1.14 changes context without changing back
|
||||
// Monado doesn't change it at all (see above)
|
||||
_session->releaseContext();
|
||||
}
|
||||
|
||||
Swapchain::~Swapchain()
|
||||
{
|
||||
if (valid())
|
||||
{
|
||||
// GL context must not be bound in another thread
|
||||
check(xrDestroySwapchain(_swapchain),
|
||||
"Failed to destroy OpenXR swapchain");
|
||||
}
|
||||
}
|
||||
|
||||
const Swapchain::ImageTextures &Swapchain::getImageTextures() const
|
||||
{
|
||||
if (!_readImageTextures)
|
||||
{
|
||||
// Enumerate the images
|
||||
uint32_t imageCount;
|
||||
// GL context must not be bound in another thread
|
||||
if (check(xrEnumerateSwapchainImages(_swapchain, 0, &imageCount, nullptr),
|
||||
"Failed to count OpenXR swapchain images"))
|
||||
{
|
||||
if (imageCount)
|
||||
{
|
||||
std::vector<XrSwapchainImageOpenGLKHR> images(imageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
|
||||
if (check(xrEnumerateSwapchainImages(_swapchain, images.size(), &imageCount,
|
||||
(XrSwapchainImageBaseHeader *)images.data()),
|
||||
"Failed to enumerate OpenXR swapchain images"))
|
||||
{
|
||||
for (auto image: images)
|
||||
_imageTextures.push_back(image.image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_readImageTextures = true;
|
||||
}
|
||||
|
||||
return _imageTextures;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> Swapchain::getImageOsgTexture(unsigned int index) const
|
||||
{
|
||||
if (_imageOsgTextures.empty())
|
||||
{
|
||||
getImageTextures();
|
||||
_imageOsgTextures.resize(_imageTextures.size());
|
||||
}
|
||||
|
||||
assert(index < _imageOsgTextures.size());
|
||||
if (!_imageOsgTextures[index].valid())
|
||||
{
|
||||
// Create an OSG texture out of it
|
||||
osg::Texture2D *texture = new osg::Texture2D;
|
||||
texture->setTextureSize(getWidth(),
|
||||
getHeight());
|
||||
texture->setInternalFormat(getFormat());
|
||||
unsigned int contextID = _session->getWindow()->getState()->getContextID();
|
||||
texture->setTextureObject(contextID, new osg::Texture::TextureObject(texture, _imageTextures[index], GL_TEXTURE_2D));
|
||||
|
||||
_imageOsgTextures[index] = texture;
|
||||
}
|
||||
|
||||
return _imageOsgTextures[index];
|
||||
}
|
||||
|
||||
int Swapchain::acquireImage() const
|
||||
{
|
||||
// Acquire a swapchain image
|
||||
uint32_t imageIndex;
|
||||
|
||||
bool currentSet = _session->checkCurrent();
|
||||
// GL context must not be bound in another thread
|
||||
if (check(xrAcquireSwapchainImage(_swapchain, nullptr, &imageIndex),
|
||||
"Failed to acquire swapchain image"))
|
||||
{
|
||||
// TODO: should not be necessary, but is for SteamVR 1.16.4 (but not 1.15.x)
|
||||
if (currentSet)
|
||||
_session->makeCurrent();
|
||||
|
||||
return imageIndex;
|
||||
}
|
||||
|
||||
// TODO: should not be necessary, but is for SteamVR 1.16.4 (but not 1.15.x)
|
||||
if (currentSet)
|
||||
_session->makeCurrent();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Swapchain::waitImage(XrDuration timeoutNs) const
|
||||
{
|
||||
// Wait on the swapchain image
|
||||
XrSwapchainImageWaitInfo waitInfo = { XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO };
|
||||
waitInfo.timeout = timeoutNs; // 100ms
|
||||
|
||||
bool currentSet = _session->checkCurrent();
|
||||
// GL context must not be bound in another thread
|
||||
bool ret = check(xrWaitSwapchainImage(_swapchain, &waitInfo),
|
||||
"Failed to wait for swapchain image");
|
||||
|
||||
// TODO: should not be necessary, but is for SteamVR 1.16.4 (but not 1.15.x)
|
||||
if (currentSet)
|
||||
_session->makeCurrent();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Swapchain::releaseImage() const
|
||||
{
|
||||
// Release the swapchain image
|
||||
bool currentSet = _session->checkCurrent();
|
||||
// GL context must not be bound in another thread
|
||||
check(xrReleaseSwapchainImage(_swapchain, nullptr),
|
||||
"Failed to release OpenXR swapchain image");
|
||||
|
||||
// TODO: should not be necessary, but is for SteamVR 1.16.4 (but not 1.15.x)
|
||||
if (currentSet)
|
||||
_session->makeCurrent();
|
||||
}
|
119
3rdparty/osgXR/src/OpenXR/Swapchain.h
vendored
Normal file
119
3rdparty/osgXR/src/OpenXR/Swapchain.h
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_SWAPCHAIN
|
||||
#define OSGXR_OPENXR_SWAPCHAIN 1
|
||||
|
||||
#include "Session.h"
|
||||
#include "System.h"
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class Swapchain : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
// GL context must not be bound in another thread
|
||||
Swapchain(osg::ref_ptr<Session> session,
|
||||
const System::ViewConfiguration::View &view,
|
||||
XrSwapchainUsageFlags usageFlags,
|
||||
int64_t format);
|
||||
// GL context must not be bound in another thread
|
||||
virtual ~Swapchain();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _swapchain != XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _session->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Conversions
|
||||
|
||||
inline XrSession getXrSession() const
|
||||
{
|
||||
return _session->getXrSession();
|
||||
}
|
||||
|
||||
inline XrSwapchain getXrSwapchain() const
|
||||
{
|
||||
return _swapchain;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
inline uint32_t getWidth() const
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
inline uint32_t getHeight() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
inline uint32_t getSamples() const
|
||||
{
|
||||
return _samples;
|
||||
}
|
||||
|
||||
inline int64_t getFormat() const
|
||||
{
|
||||
return _format;
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
typedef std::vector<GLuint> ImageTextures;
|
||||
// GL context must not be bound in another thread
|
||||
const ImageTextures &getImageTextures() const;
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> getImageOsgTexture(unsigned int index) const;
|
||||
|
||||
// Operations
|
||||
|
||||
// GL context must not be bound in another thread
|
||||
int acquireImage() const;
|
||||
// GL context must not be bound in another thread
|
||||
bool waitImage(XrDuration timeoutNs) const;
|
||||
// GL context must not be bound in another thread
|
||||
void releaseImage() const;
|
||||
|
||||
protected:
|
||||
|
||||
// Session data
|
||||
osg::ref_ptr<Session> _session;
|
||||
XrSwapchain _swapchain;
|
||||
uint32_t _width;
|
||||
uint32_t _height;
|
||||
uint32_t _samples;
|
||||
int64_t _format;
|
||||
|
||||
// Image OpenGL textures
|
||||
mutable bool _readImageTextures;
|
||||
mutable ImageTextures _imageTextures;
|
||||
mutable std::vector<osg::ref_ptr<osg::Texture2D>> _imageOsgTextures;
|
||||
|
||||
// Current image
|
||||
mutable int _currentImage;
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
55
3rdparty/osgXR/src/OpenXR/SwapchainGroup.cpp
vendored
Normal file
55
3rdparty/osgXR/src/OpenXR/SwapchainGroup.cpp
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "SwapchainGroup.h"
|
||||
|
||||
#include <osg/Notify>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
SwapchainGroup::SwapchainGroup(osg::ref_ptr<Session> session,
|
||||
const System::ViewConfiguration::View &view,
|
||||
XrSwapchainUsageFlags usageFlags,
|
||||
int64_t format,
|
||||
XrSwapchainUsageFlags depthUsageFlags,
|
||||
int64_t depthFormat) :
|
||||
_swapchain(new Swapchain(session, view, usageFlags, format))
|
||||
{
|
||||
if (depthFormat)
|
||||
_depthSwapchain = new Swapchain(session, view, depthUsageFlags, depthFormat);
|
||||
}
|
||||
|
||||
SwapchainGroup::~SwapchainGroup()
|
||||
{
|
||||
}
|
||||
|
||||
int SwapchainGroup::acquireImages() const
|
||||
{
|
||||
int imageIndex = _swapchain->acquireImage();
|
||||
if (depthValid())
|
||||
{
|
||||
int depthImageIndex = _depthSwapchain->acquireImage();
|
||||
if (imageIndex != depthImageIndex)
|
||||
OSG_WARN << "Depth swapchain image mismatch, expected " << imageIndex
|
||||
<< ", got " << depthImageIndex << std::endl;
|
||||
}
|
||||
return imageIndex;
|
||||
}
|
||||
|
||||
bool SwapchainGroup::waitImages(XrDuration timeoutNs) const
|
||||
{
|
||||
bool ret = _swapchain->waitImage(timeoutNs);
|
||||
if (depthValid())
|
||||
{
|
||||
bool depthRet = _depthSwapchain->waitImage(timeoutNs);
|
||||
ret = ret && depthRet;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SwapchainGroup::releaseImages() const
|
||||
{
|
||||
_swapchain->releaseImage();
|
||||
if (depthValid())
|
||||
_depthSwapchain->releaseImage();
|
||||
}
|
115
3rdparty/osgXR/src/OpenXR/SwapchainGroup.h
vendored
Normal file
115
3rdparty/osgXR/src/OpenXR/SwapchainGroup.h
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_SWAPCHAIN_GROUP
|
||||
#define OSGXR_OPENXR_SWAPCHAIN_GROUP 1
|
||||
|
||||
#include "Swapchain.h"
|
||||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class SwapchainGroupSubImage;
|
||||
|
||||
/// Groups colour and depth swapchains together
|
||||
class SwapchainGroup : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
typedef SwapchainGroupSubImage SubImage;
|
||||
|
||||
// GL context must not be bound in another thread
|
||||
SwapchainGroup(osg::ref_ptr<Session> session,
|
||||
const System::ViewConfiguration::View &view,
|
||||
XrSwapchainUsageFlags usageFlags,
|
||||
int64_t format,
|
||||
XrSwapchainUsageFlags depthUsageFlags = 0,
|
||||
int64_t depthFormat = 0);
|
||||
// GL context must not be bound in another thread
|
||||
virtual ~SwapchainGroup();
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _swapchain->valid();
|
||||
}
|
||||
|
||||
inline bool depthValid() const
|
||||
{
|
||||
return _depthSwapchain.valid() && _depthSwapchain->valid();
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
inline osg::ref_ptr<Swapchain> getSwapchain() const
|
||||
{
|
||||
return _swapchain;
|
||||
}
|
||||
|
||||
inline osg::ref_ptr<Swapchain> getDepthSwapchain() const
|
||||
{
|
||||
return _depthSwapchain;
|
||||
}
|
||||
|
||||
inline XrSwapchain getXrSwapchain() const
|
||||
{
|
||||
return _swapchain->getXrSwapchain();
|
||||
}
|
||||
|
||||
inline XrSwapchain getDepthXrSwapchain() const
|
||||
{
|
||||
if (_depthSwapchain.valid())
|
||||
return _depthSwapchain->getXrSwapchain();
|
||||
else
|
||||
return XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
inline uint32_t getWidth() const
|
||||
{
|
||||
return _swapchain->getWidth();
|
||||
}
|
||||
|
||||
inline uint32_t getHeight() const
|
||||
{
|
||||
return _swapchain->getHeight();
|
||||
}
|
||||
|
||||
inline uint32_t getSamples() const
|
||||
{
|
||||
return _swapchain->getSamples();
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
typedef Swapchain::ImageTextures ImageTextures;
|
||||
const ImageTextures &getImageTextures() const
|
||||
{
|
||||
return _swapchain->getImageTextures();
|
||||
}
|
||||
const ImageTextures &getDepthImageTextures() const
|
||||
{
|
||||
return _depthSwapchain->getImageTextures();
|
||||
}
|
||||
|
||||
// Operations
|
||||
|
||||
int acquireImages() const;
|
||||
bool waitImages(XrDuration timeoutNs) const;
|
||||
void releaseImages() const;
|
||||
|
||||
protected:
|
||||
|
||||
osg::ref_ptr<Swapchain> _swapchain;
|
||||
osg::ref_ptr<Swapchain> _depthSwapchain;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
114
3rdparty/osgXR/src/OpenXR/SwapchainGroupSubImage.h
vendored
Normal file
114
3rdparty/osgXR/src/OpenXR/SwapchainGroupSubImage.h
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_SWAPCHAIN_GROUP_SUB_IMAGE
|
||||
#define OSGXR_OPENXR_SWAPCHAIN_GROUP_SUB_IMAGE 1
|
||||
|
||||
#include "SwapchainGroup.h"
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class SwapchainGroupSubImage
|
||||
{
|
||||
public:
|
||||
SwapchainGroupSubImage(SwapchainGroup *group) :
|
||||
_group(group),
|
||||
_x(0),
|
||||
_y(0),
|
||||
_width(group->getWidth()),
|
||||
_height(group->getHeight()),
|
||||
_arrayIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
SwapchainGroupSubImage(SwapchainGroup *group,
|
||||
const System::ViewConfiguration::View::Viewport &vp) :
|
||||
_group(group),
|
||||
_x(vp.x),
|
||||
_y(vp.y),
|
||||
_width(vp.width),
|
||||
_height(vp.height),
|
||||
_arrayIndex(vp.arrayIndex)
|
||||
{
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return _group->valid();
|
||||
}
|
||||
|
||||
bool depthValid() const
|
||||
{
|
||||
return _group->depthValid();
|
||||
}
|
||||
|
||||
osg::ref_ptr<SwapchainGroup> getSwapchainGroup() const
|
||||
{
|
||||
return _group;
|
||||
}
|
||||
|
||||
uint32_t getX() const
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
|
||||
uint32_t getY() const
|
||||
{
|
||||
return _y;
|
||||
}
|
||||
|
||||
uint32_t getWidth() const
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
uint32_t getHeight() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
uint32_t getArrayIndex() const
|
||||
{
|
||||
return _arrayIndex;
|
||||
}
|
||||
|
||||
void getXrSubImage(XrSwapchainSubImage *out) const
|
||||
{
|
||||
out->swapchain = _group->getXrSwapchain();
|
||||
out->imageRect.offset = { (int32_t)_x,
|
||||
(int32_t)_y };
|
||||
out->imageRect.extent = { (int32_t)_width,
|
||||
(int32_t)_height };
|
||||
out->imageArrayIndex = _arrayIndex;
|
||||
}
|
||||
|
||||
void getDepthXrSubImage(XrSwapchainSubImage *out) const
|
||||
{
|
||||
out->swapchain = _group->getDepthXrSwapchain();
|
||||
out->imageRect.offset = { (int32_t)_x,
|
||||
(int32_t)_y };
|
||||
out->imageRect.extent = { (int32_t)_width,
|
||||
(int32_t)_height };
|
||||
out->imageArrayIndex = _arrayIndex;
|
||||
}
|
||||
|
||||
protected:
|
||||
osg::ref_ptr<SwapchainGroup> _group;
|
||||
uint32_t _x;
|
||||
uint32_t _y;
|
||||
uint32_t _width;
|
||||
uint32_t _height;
|
||||
uint32_t _arrayIndex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
122
3rdparty/osgXR/src/OpenXR/System.cpp
vendored
Normal file
122
3rdparty/osgXR/src/OpenXR/System.cpp
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "System.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace osgXR::OpenXR;
|
||||
|
||||
void System::getProperties() const
|
||||
{
|
||||
XrSystemProperties properties;
|
||||
properties.type = XR_TYPE_SYSTEM_PROPERTIES;
|
||||
properties.next = nullptr;
|
||||
|
||||
if (check(xrGetSystemProperties(getXrInstance(), _systemId, &properties),
|
||||
"Failed to get OpenXR system properties"))
|
||||
{
|
||||
memcpy(_systemName, properties.systemName, sizeof(_systemName));
|
||||
_orientationTracking = properties.trackingProperties.orientationTracking;
|
||||
_positionTracking = properties.trackingProperties.positionTracking;
|
||||
}
|
||||
|
||||
_readProperties = true;
|
||||
}
|
||||
|
||||
const System::ViewConfiguration::Views &System::ViewConfiguration::getViews() const
|
||||
{
|
||||
if (!_readViews)
|
||||
{
|
||||
uint32_t viewCount = 0;
|
||||
if (check(xrEnumerateViewConfigurationViews(_system->getXrInstance(),
|
||||
_system->getXrSystemId(),
|
||||
_type,
|
||||
0, &viewCount, nullptr),
|
||||
"Failed to count OpenXR view configuration views"))
|
||||
{
|
||||
if (viewCount)
|
||||
{
|
||||
std::vector<XrViewConfigurationView> views(viewCount,
|
||||
{ XR_TYPE_VIEW_CONFIGURATION_VIEW });
|
||||
if (check(xrEnumerateViewConfigurationViews(_system->getXrInstance(),
|
||||
_system->getXrSystemId(),
|
||||
_type,
|
||||
views.size(), &viewCount,
|
||||
views.data()),
|
||||
"Failed to enumerate OpenXR view configuration views"))
|
||||
{
|
||||
for (auto &view: views)
|
||||
_views.push_back(View(view));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_readViews = true;
|
||||
}
|
||||
|
||||
return _views;
|
||||
}
|
||||
|
||||
const System::ViewConfiguration::EnvBlendModes &System::ViewConfiguration::getEnvBlendModes() const
|
||||
{
|
||||
if (!_readEnvBlendModes)
|
||||
{
|
||||
uint32_t blendModeCount = 0;
|
||||
if (check(xrEnumerateEnvironmentBlendModes(_system->getXrInstance(),
|
||||
_system->getXrSystemId(),
|
||||
_type,
|
||||
0, &blendModeCount, nullptr),
|
||||
"Failed to count OpenXR environment blend modes"))
|
||||
{
|
||||
if (blendModeCount)
|
||||
{
|
||||
_envBlendModes.resize(blendModeCount);
|
||||
if (!check(xrEnumerateEnvironmentBlendModes(_system->getXrInstance(),
|
||||
_system->getXrSystemId(),
|
||||
_type,
|
||||
_envBlendModes.size(),
|
||||
&blendModeCount,
|
||||
_envBlendModes.data()),
|
||||
"Failed to enumerate OpenXR environment blend modes"))
|
||||
{
|
||||
_envBlendModes.resize(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_readEnvBlendModes = true;
|
||||
}
|
||||
|
||||
return _envBlendModes;
|
||||
}
|
||||
|
||||
const System::ViewConfigurations &System::getViewConfigurations() const
|
||||
{
|
||||
if (!_readViewConfigurations)
|
||||
{
|
||||
uint32_t viewConfigCount = 0;
|
||||
if (check(xrEnumerateViewConfigurations(getXrInstance(), getXrSystemId(),
|
||||
0, &viewConfigCount, nullptr),
|
||||
"Failed to count OpenXR view configuration types"))
|
||||
{
|
||||
if (viewConfigCount)
|
||||
{
|
||||
std::vector<XrViewConfigurationType> types(viewConfigCount);
|
||||
if (check(xrEnumerateViewConfigurations(getXrInstance(), getXrSystemId(),
|
||||
types.size(), &viewConfigCount,
|
||||
types.data()),
|
||||
"Failed to enumerate OpenXR view configuration types"))
|
||||
{
|
||||
_viewConfigurations.reserve(viewConfigCount);
|
||||
for (auto type: types)
|
||||
_viewConfigurations.push_back(ViewConfiguration(this, type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_readViewConfigurations = true;
|
||||
}
|
||||
|
||||
return _viewConfigurations;
|
||||
}
|
221
3rdparty/osgXR/src/OpenXR/System.h
vendored
Normal file
221
3rdparty/osgXR/src/OpenXR/System.h
vendored
Normal file
|
@ -0,0 +1,221 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_OPENXR_SYSTEM
|
||||
#define OSGXR_OPENXR_SYSTEM 1
|
||||
|
||||
#include "Instance.h"
|
||||
|
||||
#include <osg/DisplaySettings>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
namespace OpenXR {
|
||||
|
||||
class System
|
||||
{
|
||||
public:
|
||||
|
||||
System(Instance *instance, XrSystemId systemId) :
|
||||
_instance(instance),
|
||||
_systemId(systemId),
|
||||
_readProperties(false),
|
||||
_orientationTracking(false),
|
||||
_positionTracking(false),
|
||||
_readViewConfigurations(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Error checking
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _instance->check(result, warnMsg);
|
||||
}
|
||||
|
||||
// Conversions
|
||||
|
||||
inline Instance *getInstance()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
inline const Instance *getInstance() const
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
inline XrInstance getXrInstance() const
|
||||
{
|
||||
return _instance->getXrInstance();
|
||||
}
|
||||
|
||||
inline XrSystemId getXrSystemId() const
|
||||
{
|
||||
return _systemId;
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
void getProperties() const;
|
||||
|
||||
inline const char *getSystemName() const
|
||||
{
|
||||
if (!_readProperties)
|
||||
getProperties();
|
||||
return _systemName;
|
||||
}
|
||||
|
||||
inline bool getOrientationTracking() const
|
||||
{
|
||||
if (!_readProperties)
|
||||
getProperties();
|
||||
return _orientationTracking;
|
||||
}
|
||||
|
||||
inline bool getPositionTracking() const
|
||||
{
|
||||
if (!_readProperties)
|
||||
getProperties();
|
||||
return _positionTracking;
|
||||
}
|
||||
|
||||
class ViewConfiguration
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
ViewConfiguration(const System *system, XrViewConfigurationType type) :
|
||||
_system(system),
|
||||
_type(type),
|
||||
_readViews(false),
|
||||
_readEnvBlendModes(false)
|
||||
{
|
||||
}
|
||||
|
||||
XrViewConfigurationType getType() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
class View
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
struct Viewport
|
||||
{
|
||||
uint32_t x, y, width, height, arrayIndex;
|
||||
};
|
||||
|
||||
View(uint32_t recommendedWidth,
|
||||
uint32_t recommendedHeight,
|
||||
uint32_t recommendedSamples = 1) :
|
||||
_recommendedWidth(recommendedWidth),
|
||||
_recommendedHeight(recommendedHeight),
|
||||
_recommendedSamples(recommendedSamples)
|
||||
{
|
||||
}
|
||||
|
||||
View(const XrViewConfigurationView &view) :
|
||||
_recommendedWidth(view.recommendedImageRectWidth),
|
||||
_recommendedHeight(view.recommendedImageRectHeight),
|
||||
_recommendedSamples(view.recommendedSwapchainSampleCount)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t getRecommendedWidth() const
|
||||
{
|
||||
return _recommendedWidth;
|
||||
}
|
||||
|
||||
uint32_t getRecommendedHeight() const
|
||||
{
|
||||
return _recommendedHeight;
|
||||
}
|
||||
|
||||
|
||||
uint32_t getRecommendedSamples() const
|
||||
{
|
||||
return _recommendedSamples;
|
||||
}
|
||||
|
||||
/// Tile another view horizontally after this one
|
||||
struct Viewport tileHorizontally(const View &other)
|
||||
{
|
||||
struct Viewport vp;
|
||||
vp.x = _recommendedWidth;
|
||||
vp.y = 0;
|
||||
vp.width = other._recommendedWidth;
|
||||
vp.height = other._recommendedHeight;
|
||||
vp.arrayIndex = 0;
|
||||
|
||||
_recommendedWidth += other._recommendedWidth;
|
||||
_recommendedHeight = std::max(_recommendedHeight,
|
||||
other._recommendedHeight);
|
||||
return vp;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
uint32_t _recommendedWidth;
|
||||
uint32_t _recommendedHeight;
|
||||
uint32_t _recommendedSamples;
|
||||
};
|
||||
|
||||
typedef std::vector<View> Views;
|
||||
const Views &getViews() const;
|
||||
|
||||
typedef std::vector<XrEnvironmentBlendMode> EnvBlendModes;
|
||||
const EnvBlendModes &getEnvBlendModes() const;
|
||||
|
||||
protected:
|
||||
|
||||
inline bool check(XrResult result, const char *warnMsg) const
|
||||
{
|
||||
return _system->getInstance()->check(result, warnMsg);
|
||||
}
|
||||
|
||||
const System *_system;
|
||||
XrViewConfigurationType _type;
|
||||
|
||||
// Views
|
||||
mutable bool _readViews;
|
||||
mutable Views _views;
|
||||
|
||||
// Environment blend modes
|
||||
mutable bool _readEnvBlendModes;
|
||||
mutable EnvBlendModes _envBlendModes;
|
||||
};
|
||||
|
||||
typedef std::vector<ViewConfiguration> ViewConfigurations;
|
||||
const ViewConfigurations &getViewConfigurations() const;
|
||||
|
||||
protected:
|
||||
|
||||
// System data
|
||||
Instance *_instance;
|
||||
XrSystemId _systemId;
|
||||
|
||||
// Properties
|
||||
mutable char _systemName[XR_MAX_SYSTEM_NAME_SIZE];
|
||||
mutable bool _readProperties;
|
||||
mutable bool _orientationTracking;
|
||||
mutable bool _positionTracking;
|
||||
|
||||
// View configurations
|
||||
mutable bool _readViewConfigurations;
|
||||
mutable ViewConfigurations _viewConfigurations;
|
||||
|
||||
};
|
||||
|
||||
} // osgXR::OpenXR
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
42
3rdparty/osgXR/src/OpenXRDisplay.cpp
vendored
Normal file
42
3rdparty/osgXR/src/OpenXRDisplay.cpp
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include <osgXR/OpenXRDisplay>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgViewer/ViewerBase>
|
||||
|
||||
#include "XRState.h"
|
||||
#include "XRRealizeOperation.h"
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
OpenXRDisplay::OpenXRDisplay()
|
||||
{
|
||||
}
|
||||
|
||||
OpenXRDisplay::OpenXRDisplay(Settings *settings):
|
||||
_settings(settings)
|
||||
{
|
||||
}
|
||||
|
||||
OpenXRDisplay::OpenXRDisplay(const OpenXRDisplay& rhs,
|
||||
const osg::CopyOp& copyop):
|
||||
ViewConfig(rhs,copyop),
|
||||
_settings(rhs._settings)
|
||||
{
|
||||
}
|
||||
|
||||
OpenXRDisplay::~OpenXRDisplay()
|
||||
{
|
||||
}
|
||||
|
||||
void OpenXRDisplay::configure(osgViewer::View &view) const
|
||||
{
|
||||
osgViewer::ViewerBase *viewer = dynamic_cast<osgViewer::ViewerBase *>(&view);
|
||||
if (!viewer)
|
||||
return;
|
||||
|
||||
_state = new XRState(_settings);
|
||||
viewer->setRealizeOperation(new XRRealizeOperation(_state, &view));
|
||||
}
|
63
3rdparty/osgXR/src/Settings.cpp
vendored
Normal file
63
3rdparty/osgXR/src/Settings.cpp
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include <osgXR/Settings>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include "OpenXR/Instance.h"
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
Settings::Settings() :
|
||||
_appName("osgXR"),
|
||||
_appVersion(1),
|
||||
_validationLayer(false),
|
||||
_depthInfo(false),
|
||||
_visibilityMask(true),
|
||||
_formFactor(HEAD_MOUNTED_DISPLAY),
|
||||
_preferredEnvBlendModeMask(0),
|
||||
_allowedEnvBlendModeMask(0),
|
||||
_vrMode(VRMODE_AUTOMATIC),
|
||||
_swapchainMode(SWAPCHAIN_AUTOMATIC),
|
||||
_unitsPerMeter(1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
}
|
||||
|
||||
Settings *Settings::instance()
|
||||
{
|
||||
static osg::ref_ptr<Settings> settings = new Settings();
|
||||
return settings;
|
||||
}
|
||||
|
||||
unsigned int Settings::_diff(const Settings &other) const
|
||||
{
|
||||
unsigned int ret = DIFF_NONE;
|
||||
if (_appName != other._appName ||
|
||||
_appVersion != other._appVersion)
|
||||
ret |= DIFF_APP_INFO;
|
||||
if (_validationLayer != other._validationLayer)
|
||||
ret |= DIFF_VALIDATION_LAYER;
|
||||
if (_depthInfo != other._depthInfo)
|
||||
ret |= DIFF_DEPTH_INFO;
|
||||
if (_visibilityMask != other._visibilityMask)
|
||||
ret |= DIFF_VISIBILITY_MASK;
|
||||
if (_formFactor != other._formFactor)
|
||||
ret |= DIFF_FORM_FACTOR;
|
||||
if (_preferredEnvBlendModeMask != other._preferredEnvBlendModeMask ||
|
||||
_allowedEnvBlendModeMask != other._allowedEnvBlendModeMask)
|
||||
ret |= DIFF_BLEND_MODE;
|
||||
if (_vrMode != other._vrMode)
|
||||
ret |= DIFF_VR_MODE;
|
||||
if (_swapchainMode != other._swapchainMode)
|
||||
ret |= DIFF_SWAPCHAIN_MODE;
|
||||
if (_mirrorSettings != other._mirrorSettings)
|
||||
ret |= DIFF_MIRROR;
|
||||
if (_unitsPerMeter != other._unitsPerMeter)
|
||||
ret |= DIFF_SCALE;
|
||||
return ret;
|
||||
}
|
109
3rdparty/osgXR/src/Subaction.cpp
vendored
Normal file
109
3rdparty/osgXR/src/Subaction.cpp
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "Subaction.h"
|
||||
#include "XRState.h"
|
||||
|
||||
#include <osgXR/Manager>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
// Internal API
|
||||
|
||||
Subaction::Private::Private(XRState *state,
|
||||
const std::string &path) :
|
||||
_state(state),
|
||||
_pathString(path)
|
||||
{
|
||||
}
|
||||
|
||||
void Subaction::Private::registerPublic(Subaction *subaction)
|
||||
{
|
||||
_publics.insert(subaction);
|
||||
}
|
||||
|
||||
void Subaction::Private::unregisterPublic(Subaction *subaction)
|
||||
{
|
||||
_publics.erase(subaction);
|
||||
}
|
||||
|
||||
InteractionProfile *Subaction::Private::getCurrentProfile()
|
||||
{
|
||||
if (!_currentProfile.valid())
|
||||
{
|
||||
if (_path.valid())
|
||||
_currentProfile = _state->getCurrentInteractionProfile(_path);
|
||||
}
|
||||
|
||||
return _currentProfile.get();
|
||||
}
|
||||
|
||||
void Subaction::Private::onInteractionProfileChanged(OpenXR::Session *session)
|
||||
{
|
||||
// Ensure path is set up
|
||||
setup(session->getInstance());
|
||||
|
||||
// Find whether this subaction's current interaction profile has changed
|
||||
InteractionProfile *prevProfile = _currentProfile.get();
|
||||
_currentProfile = nullptr;
|
||||
InteractionProfile *newProfile = getCurrentProfile();
|
||||
if (newProfile != prevProfile)
|
||||
{
|
||||
// Notify any derived Subaction classes from the app
|
||||
for (auto *pub: _publics)
|
||||
pub->onProfileChanged(newProfile);
|
||||
}
|
||||
}
|
||||
|
||||
const OpenXR::Path &Subaction::Private::setup(OpenXR::Instance *instance)
|
||||
{
|
||||
if (!_path.valid())
|
||||
_path = OpenXR::Path(instance, _pathString);
|
||||
return _path;
|
||||
}
|
||||
|
||||
void Subaction::Private::cleanupSession()
|
||||
{
|
||||
bool hadProfile = _currentProfile.valid();
|
||||
_currentProfile = nullptr;
|
||||
if (hadProfile)
|
||||
{
|
||||
// Notify any derived Subaction classes from the app
|
||||
for (auto *pub: _publics)
|
||||
pub->onProfileChanged(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Subaction::Private::cleanupInstance()
|
||||
{
|
||||
_path = OpenXR::Path();
|
||||
}
|
||||
|
||||
// Public API
|
||||
|
||||
Subaction::Subaction(Manager *manager,
|
||||
const std::string &path) :
|
||||
_private(manager->_getXrState()->getSubaction(path))
|
||||
{
|
||||
_private->registerPublic(this);
|
||||
}
|
||||
|
||||
Subaction::~Subaction()
|
||||
{
|
||||
_private->unregisterPublic(this);
|
||||
}
|
||||
|
||||
const std::string &Subaction::getPath() const
|
||||
{
|
||||
return _private->getPathString();
|
||||
}
|
||||
|
||||
InteractionProfile *Subaction::getCurrentProfile()
|
||||
{
|
||||
return _private->getCurrentProfile();
|
||||
}
|
||||
|
||||
void Subaction::onProfileChanged(InteractionProfile *newProfile)
|
||||
{
|
||||
// This is for derived classes to implement to their own ends
|
||||
}
|
75
3rdparty/osgXR/src/Subaction.h
vendored
Normal file
75
3rdparty/osgXR/src/Subaction.h
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_SUBACTION
|
||||
#define OSGXR_SUBACTION 1
|
||||
|
||||
#include <osgXR/Subaction>
|
||||
|
||||
#include "OpenXR/Path.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class XRState;
|
||||
|
||||
namespace OpenXR {
|
||||
class Instance;
|
||||
};
|
||||
|
||||
class Subaction::Private
|
||||
{
|
||||
public:
|
||||
|
||||
static std::shared_ptr<Private> get(Subaction *pub)
|
||||
{
|
||||
if (pub)
|
||||
return pub->_private;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Private(XRState *state, const std::string &path);
|
||||
|
||||
// Public object registration
|
||||
void registerPublic(Subaction *subaction);
|
||||
void unregisterPublic(Subaction *subaction);
|
||||
|
||||
// Accessors
|
||||
|
||||
/// Get the subaction's path as a string.
|
||||
const std::string &getPathString() const
|
||||
{
|
||||
return _pathString;
|
||||
}
|
||||
|
||||
/// Find the current interaction profile.
|
||||
InteractionProfile *getCurrentProfile();
|
||||
|
||||
// Events
|
||||
|
||||
/// Notify that an interaction profile has changed.
|
||||
void onInteractionProfileChanged(OpenXR::Session *session);
|
||||
|
||||
/// Setup path with an OpenXR instance.
|
||||
const OpenXR::Path &setup(OpenXR::Instance *instance);
|
||||
/// Clean up current profile before an OpenXR session is destroyed.
|
||||
void cleanupSession();
|
||||
/// Clean up path before an OpenXR instance is destroyed.
|
||||
void cleanupInstance();
|
||||
|
||||
private:
|
||||
|
||||
XRState *_state;
|
||||
std::string _pathString;
|
||||
std::set<Subaction *> _publics;
|
||||
|
||||
OpenXR::Path _path;
|
||||
osg::ref_ptr<InteractionProfile> _currentProfile;
|
||||
};
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
12
3rdparty/osgXR/src/Version.h.in
vendored
Normal file
12
3rdparty/osgXR/src/Version.h.in
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_Version
|
||||
#define OSGXR_Version 1
|
||||
|
||||
#define OSGXR_MAJOR_VERSION @osgXR_MAJOR_VERSION@
|
||||
#define OSGXR_MINOR_VERSION @osgXR_MINOR_VERSION@
|
||||
#define OSGXR_PATCH_VERSION @osgXR_PATCH_VERSION@
|
||||
#define OSGXR_SOVERSION @osgXR_SOVERSION@
|
||||
|
||||
#endif
|
16
3rdparty/osgXR/src/View.cpp
vendored
Normal file
16
3rdparty/osgXR/src/View.cpp
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include <osgXR/View>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
View::View(osgViewer::GraphicsWindow *window, osgViewer::View *osgView) :
|
||||
_window(window),
|
||||
_osgView(osgView)
|
||||
{
|
||||
}
|
||||
|
||||
View::~View()
|
||||
{
|
||||
}
|
151
3rdparty/osgXR/src/XRFramebuffer.cpp
vendored
Normal file
151
3rdparty/osgXR/src/XRFramebuffer.cpp
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "XRFramebuffer.h"
|
||||
|
||||
#include <osg/FrameBufferObject>
|
||||
#include <osg/Image>
|
||||
#include <osg/State>
|
||||
#include <osg/Version>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
#if(OSG_VERSION_GREATER_OR_EQUAL(3, 4, 0))
|
||||
typedef osg::GLExtensions OSG_GLExtensions;
|
||||
#else
|
||||
typedef osg::FBOExtensions OSG_GLExtensions;
|
||||
#endif
|
||||
|
||||
static const OSG_GLExtensions* getGLExtensions(const osg::State& state)
|
||||
{
|
||||
#if(OSG_VERSION_GREATER_OR_EQUAL(3, 4, 0))
|
||||
return state.get<osg::GLExtensions>();
|
||||
#else
|
||||
return osg::FBOExtensions::instance(state.getContextID(), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
XRFramebuffer::XRFramebuffer(uint32_t width, uint32_t height,
|
||||
GLuint texture, GLuint depthTexture) :
|
||||
_width(width),
|
||||
_height(height),
|
||||
_depthFormat(GL_DEPTH_COMPONENT16),
|
||||
_fbo(0),
|
||||
_texture(texture),
|
||||
_depthTexture(depthTexture),
|
||||
_generated(false),
|
||||
_boundTexture(false),
|
||||
_boundDepthTexture(false),
|
||||
_deleteDepthTexture(false)
|
||||
{
|
||||
}
|
||||
|
||||
XRFramebuffer::~XRFramebuffer()
|
||||
{
|
||||
}
|
||||
|
||||
bool XRFramebuffer::valid(osg::State &state) const
|
||||
{
|
||||
if (!_fbo)
|
||||
return false;
|
||||
|
||||
const OSG_GLExtensions *fbo_ext = getGLExtensions(state);
|
||||
GLenum complete = fbo_ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
|
||||
switch (complete)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||
return true;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
||||
OSG_WARN << "FBO Incomplete attachment" << std::endl;
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
|
||||
OSG_WARN << "FBO Incomplete missing attachment" << std::endl;
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
|
||||
OSG_WARN << "FBO Incomplete draw buffer" << std::endl;
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
||||
OSG_WARN << "FBO Incomplete read buffer" << std::endl;
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
||||
OSG_WARN << "FBO Incomplete unsupported" << std::endl;
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
|
||||
OSG_WARN << "FBO Incomplete multisample" << std::endl;
|
||||
break;
|
||||
default:
|
||||
OSG_WARN << "FBO Incomplete ??? (0x" << std::hex << complete << std::dec << ")" << std::endl;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void XRFramebuffer::bind(osg::State &state)
|
||||
{
|
||||
const OSG_GLExtensions *fbo_ext = getGLExtensions(state);
|
||||
|
||||
if (!_fbo && !_generated)
|
||||
{
|
||||
fbo_ext->glGenFramebuffers(1, &_fbo);
|
||||
_generated = true;
|
||||
}
|
||||
|
||||
if (_fbo)
|
||||
{
|
||||
fbo_ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, _fbo);
|
||||
if (!_boundTexture && _texture)
|
||||
{
|
||||
fbo_ext->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, _texture, 0);
|
||||
_boundTexture = true;
|
||||
}
|
||||
if (!_boundDepthTexture)
|
||||
{
|
||||
if (!_depthTexture)
|
||||
{
|
||||
glGenTextures(1, &_depthTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, _depthTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, _depthFormat, _width, _height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, nullptr);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
_deleteDepthTexture = true;
|
||||
}
|
||||
|
||||
fbo_ext->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, _depthTexture, 0);
|
||||
_boundDepthTexture = true;
|
||||
|
||||
valid(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XRFramebuffer::unbind(osg::State &state)
|
||||
{
|
||||
const OSG_GLExtensions *fbo_ext = getGLExtensions(state);
|
||||
|
||||
if (_fbo && _generated)
|
||||
fbo_ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||
}
|
||||
|
||||
void XRFramebuffer::releaseGLObjects(osg::State &state)
|
||||
{
|
||||
// FIXME can we do it like RenderBuffer::releaseGLObjects?
|
||||
// FIXME better yet, switch to use FrameBufferObject, dynamically bound
|
||||
|
||||
// GL context must be current
|
||||
if (_fbo)
|
||||
{
|
||||
/*
|
||||
unsigned int contextID = state->getContextID();
|
||||
osg::get<GLFrameBufferObjectManager>(contextID)->scheduleGLObjectForDeletion(_fbo);
|
||||
*/
|
||||
const OSG_GLExtensions *fbo_ext = getGLExtensions(state);
|
||||
fbo_ext->glDeleteFramebuffers(1, &_fbo);
|
||||
_fbo = 0;
|
||||
}
|
||||
if (_deleteDepthTexture)
|
||||
{
|
||||
glDeleteTextures(1, &_depthTexture);
|
||||
_depthTexture = 0;
|
||||
_deleteDepthTexture = false;
|
||||
}
|
||||
}
|
52
3rdparty/osgXR/src/XRFramebuffer.h
vendored
Normal file
52
3rdparty/osgXR/src/XRFramebuffer.h
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_XRFRAMEBUFFER
|
||||
#define OSGXR_XRFRAMEBUFFER 1
|
||||
|
||||
#include <osg/GL>
|
||||
#include <osg/Referenced>
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class XRFramebuffer : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
explicit XRFramebuffer(uint32_t width, uint32_t height,
|
||||
GLuint texture, GLuint depthTexture = 0);
|
||||
// releaseGLObjects() first
|
||||
virtual ~XRFramebuffer();
|
||||
|
||||
void setDepthFormat(GLenum depthFormat)
|
||||
{
|
||||
_depthFormat = depthFormat;
|
||||
}
|
||||
|
||||
bool valid(osg::State &state) const;
|
||||
void bind(osg::State &state);
|
||||
void unbind(osg::State &state);
|
||||
// GL context must be current
|
||||
void releaseGLObjects(osg::State &state);
|
||||
|
||||
protected:
|
||||
|
||||
uint32_t _width;
|
||||
uint32_t _height;
|
||||
GLenum _depthFormat;
|
||||
|
||||
GLuint _fbo;
|
||||
GLuint _texture;
|
||||
GLuint _depthTexture;
|
||||
|
||||
bool _generated;
|
||||
bool _boundTexture;
|
||||
bool _boundDepthTexture;
|
||||
bool _deleteDepthTexture;
|
||||
};
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
35
3rdparty/osgXR/src/XRRealizeOperation.cpp
vendored
Normal file
35
3rdparty/osgXR/src/XRRealizeOperation.cpp
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include "XRRealizeOperation.h"
|
||||
|
||||
#include "XRState.h"
|
||||
|
||||
#include <osgViewer/GraphicsWindow>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
XRRealizeOperation::XRRealizeOperation(osg::ref_ptr<XRState> state,
|
||||
osgViewer::View *view) :
|
||||
osg::GraphicsOperation("XRRealizeOperation", false),
|
||||
_state(state),
|
||||
_view(view),
|
||||
_realized(false)
|
||||
{
|
||||
}
|
||||
|
||||
void XRRealizeOperation::operator () (osg::GraphicsContext *gc)
|
||||
{
|
||||
if (!_realized)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
gc->makeCurrent();
|
||||
|
||||
auto *window = dynamic_cast<osgViewer::GraphicsWindow *>(gc);
|
||||
if (window)
|
||||
{
|
||||
_state->init(window, _view);
|
||||
_realized = true;
|
||||
}
|
||||
}
|
||||
}
|
38
3rdparty/osgXR/src/XRRealizeOperation.h
vendored
Normal file
38
3rdparty/osgXR/src/XRRealizeOperation.h
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_XRREALIZEOPERATION
|
||||
#define OSGXR_XRREALIZEOPERATION 1
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgViewer/View>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class XRState;
|
||||
|
||||
class XRRealizeOperation : public osg::GraphicsOperation
|
||||
{
|
||||
public:
|
||||
|
||||
explicit XRRealizeOperation(osg::ref_ptr<XRState> state,
|
||||
osgViewer::View *view);
|
||||
|
||||
void operator () (osg::GraphicsContext *gc) override;
|
||||
|
||||
bool realized() const
|
||||
{
|
||||
return _realized;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
OpenThreads::Mutex _mutex;
|
||||
osg::ref_ptr<XRState> _state;
|
||||
osgViewer::View *_view;
|
||||
bool _realized;
|
||||
};
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
1589
3rdparty/osgXR/src/XRState.cpp
vendored
Normal file
1589
3rdparty/osgXR/src/XRState.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
590
3rdparty/osgXR/src/XRState.h
vendored
Normal file
590
3rdparty/osgXR/src/XRState.h
vendored
Normal file
|
@ -0,0 +1,590 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_XRSTATE
|
||||
#define OSGXR_XRSTATE 1
|
||||
|
||||
#include "OpenXR/ActionSet.h"
|
||||
#include "OpenXR/EventHandler.h"
|
||||
#include "OpenXR/Instance.h"
|
||||
#include "OpenXR/InteractionProfile.h"
|
||||
#include "OpenXR/System.h"
|
||||
#include "OpenXR/Session.h"
|
||||
#include "OpenXR/SwapchainGroup.h"
|
||||
#include "OpenXR/SwapchainGroupSubImage.h"
|
||||
#include "OpenXR/Compositor.h"
|
||||
#include "OpenXR/DepthInfo.h"
|
||||
|
||||
#include "XRFramebuffer.h"
|
||||
#include "FrameStampedVector.h"
|
||||
#include "FrameStore.h"
|
||||
|
||||
#include <osg/DisplaySettings>
|
||||
#include <osg/Referenced>
|
||||
#include <osg/observer_ptr>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <osgXR/ActionSet>
|
||||
#include <osgXR/InteractionProfile>
|
||||
#include <osgXR/Settings>
|
||||
#include <osgXR/Subaction>
|
||||
#include <osgXR/View>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace osg {
|
||||
class FrameStamp;
|
||||
}
|
||||
|
||||
namespace osgViewer {
|
||||
class ViewerBase;
|
||||
}
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class Manager;
|
||||
|
||||
class XRState : public OpenXR::EventHandler
|
||||
{
|
||||
public:
|
||||
typedef Settings::VRMode VRMode;
|
||||
typedef Settings::SwapchainMode SwapchainMode;
|
||||
|
||||
XRState(Settings *settings, Manager *manager = nullptr);
|
||||
|
||||
/// Represents a swapchain group
|
||||
class XRSwapchain : public OpenXR::SwapchainGroup
|
||||
{
|
||||
public:
|
||||
|
||||
XRSwapchain(XRState *state,
|
||||
osg::ref_ptr<OpenXR::Session> session,
|
||||
const OpenXR::System::ViewConfiguration::View &view,
|
||||
int64_t chosenSwapchainFormat,
|
||||
int64_t chosenDepthSwapchainFormat);
|
||||
|
||||
// GL context must be current (for XRFramebuffer)
|
||||
virtual ~XRSwapchain();
|
||||
|
||||
void incNumDrawPasses(unsigned int num = 1)
|
||||
{
|
||||
_numDrawPasses += num;
|
||||
}
|
||||
|
||||
void decNumDrawPasses(unsigned int num = 1)
|
||||
{
|
||||
_numDrawPasses -= num;
|
||||
}
|
||||
|
||||
unsigned int getNumDrawPasses()
|
||||
{
|
||||
return _numDrawPasses;
|
||||
}
|
||||
|
||||
void setupImage(const osg::FrameStamp *stamp);
|
||||
|
||||
void preDrawCallback(osg::RenderInfo &renderInfo);
|
||||
void postDrawCallback(osg::RenderInfo &renderInfo);
|
||||
void endFrame();
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> getOsgTexture(const osg::FrameStamp *stamp);
|
||||
|
||||
protected:
|
||||
|
||||
XRState *_state;
|
||||
FrameStampedVector<osg::ref_ptr<XRFramebuffer> > _imageFramebuffers;
|
||||
|
||||
/// Number of expected draw passes.
|
||||
unsigned int _numDrawPasses;
|
||||
unsigned int _drawPassesDone;
|
||||
bool _imagesReady;
|
||||
};
|
||||
|
||||
/// Represents an OpenXR view
|
||||
class XRView : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
|
||||
XRView(XRState *state,
|
||||
uint32_t viewIndex,
|
||||
osg::ref_ptr<XRSwapchain> swapchain);
|
||||
XRView(XRState *state,
|
||||
uint32_t viewIndex,
|
||||
osg::ref_ptr<XRSwapchain> swapchain,
|
||||
const OpenXR::System::ViewConfiguration::View::Viewport &viewport);
|
||||
|
||||
// GL context must be current (for XRFramebuffer)
|
||||
virtual ~XRView();
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return _swapchainSubImage.valid();
|
||||
}
|
||||
|
||||
osg::ref_ptr<XRSwapchain> getSwapchain()
|
||||
{
|
||||
return static_cast<XRSwapchain *>(_swapchainSubImage.getSwapchainGroup().get());
|
||||
}
|
||||
|
||||
const XRSwapchain::SubImage &getSubImage() const
|
||||
{
|
||||
return _swapchainSubImage;
|
||||
}
|
||||
|
||||
void setupCamera(osg::ref_ptr<osg::Camera> camera);
|
||||
|
||||
void endFrame(OpenXR::Session::Frame *frame);
|
||||
|
||||
protected:
|
||||
|
||||
XRState *_state;
|
||||
XRSwapchain::SubImage _swapchainSubImage;
|
||||
|
||||
uint32_t _viewIndex;
|
||||
};
|
||||
|
||||
/** Represents a generic app level view.
|
||||
* This may handle multiple OpenXR views.
|
||||
*/
|
||||
class AppView : public View
|
||||
{
|
||||
public:
|
||||
|
||||
AppView(XRState *state,
|
||||
osgViewer::GraphicsWindow *window,
|
||||
osgViewer::View *osgView);
|
||||
virtual ~AppView();
|
||||
|
||||
void destroy();
|
||||
|
||||
void init();
|
||||
|
||||
protected:
|
||||
|
||||
bool _valid;
|
||||
|
||||
XRState *_state;
|
||||
};
|
||||
|
||||
/// Represents an app level view in slave cams mode
|
||||
class SlaveCamsAppView : public AppView
|
||||
{
|
||||
public:
|
||||
|
||||
SlaveCamsAppView(XRState *state,
|
||||
uint32_t viewIndex,
|
||||
osgViewer::GraphicsWindow *window,
|
||||
osgViewer::View *osgView);
|
||||
|
||||
void addSlave(osg::Camera *slaveCamera) override;
|
||||
void removeSlave(osg::Camera *slaveCamera) override;
|
||||
|
||||
protected:
|
||||
|
||||
uint32_t _viewIndex;
|
||||
};
|
||||
|
||||
/// Represents an app level view in scene view mode
|
||||
class SceneViewAppView : public AppView
|
||||
{
|
||||
public:
|
||||
|
||||
SceneViewAppView(XRState *state,
|
||||
osgViewer::GraphicsWindow *window,
|
||||
osgViewer::View *osgView);
|
||||
|
||||
void addSlave(osg::Camera *slaveCamera) override;
|
||||
void removeSlave(osg::Camera *slaveCamera) override;
|
||||
};
|
||||
|
||||
bool hasValidationLayer() const;
|
||||
bool hasDepthInfoExtension() const;
|
||||
bool hasVisibilityMaskExtension() const;
|
||||
|
||||
inline const char *getRuntimeName() const
|
||||
{
|
||||
if (_currentState < VRSTATE_INSTANCE)
|
||||
return "";
|
||||
return _instance->getRuntimeName();
|
||||
}
|
||||
|
||||
inline const char *getSystemName() const
|
||||
{
|
||||
if (_currentState < VRSTATE_SYSTEM)
|
||||
return "";
|
||||
return _system->getSystemName();
|
||||
}
|
||||
|
||||
inline bool getPresent() const
|
||||
{
|
||||
return _instance.valid() && _instance->valid();
|
||||
}
|
||||
|
||||
inline bool valid() const
|
||||
{
|
||||
return _currentState >= VRSTATE_SESSION;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
/// No OpenXR instance.
|
||||
VRSTATE_DISABLED = 0,
|
||||
/// OpenXR instance created.
|
||||
VRSTATE_INSTANCE,
|
||||
/// Valid OpenXR system found.
|
||||
VRSTATE_SYSTEM,
|
||||
/// Session created
|
||||
VRSTATE_SESSION,
|
||||
/// Actions configured
|
||||
VRSTATE_ACTIONS,
|
||||
|
||||
VRSTATE_MAX,
|
||||
} VRState;
|
||||
|
||||
/// Set the init state to drop down to before returning to prior level.
|
||||
void setDownState(VRState downState)
|
||||
{
|
||||
if (downState < _downState && downState < _currentState)
|
||||
{
|
||||
_downState = downState;
|
||||
_stateChanged = true;
|
||||
}
|
||||
}
|
||||
/// Get the current init state to rise up to.
|
||||
VRState getUpState() const
|
||||
{
|
||||
return _upState;
|
||||
}
|
||||
/// Get the current init state to rise up to.
|
||||
VRState getCurrentState() const
|
||||
{
|
||||
return _currentState;
|
||||
}
|
||||
/// Set the init state to rise up to.
|
||||
void setUpState(VRState upState)
|
||||
{
|
||||
if (upState != _upState)
|
||||
{
|
||||
_upState = upState;
|
||||
_stateChanged = true;
|
||||
}
|
||||
}
|
||||
/// Set the minimum init state to rise up to.
|
||||
void setMinUpState(VRState minUpState)
|
||||
{
|
||||
if (minUpState > _upState)
|
||||
{
|
||||
_upState = minUpState;
|
||||
_stateChanged = true;
|
||||
}
|
||||
}
|
||||
/// Set destination state, both up and down.
|
||||
void setDestState(VRState destState)
|
||||
{
|
||||
setDownState(destState);
|
||||
setUpState(destState);
|
||||
}
|
||||
/// Find if updates are needed for state changes.
|
||||
bool isStateUpdateNeeded() const
|
||||
{
|
||||
return _currentState > _downState || _currentState < _upState;
|
||||
}
|
||||
|
||||
/// Find if a VR session is running.
|
||||
bool isRunning() const
|
||||
{
|
||||
if (_currentState < VRSTATE_SESSION)
|
||||
return false;
|
||||
return _session->isRunning();
|
||||
}
|
||||
|
||||
/// Set whether probing should be active.
|
||||
void setProbing(bool probing)
|
||||
{
|
||||
if (_probing == probing)
|
||||
return;
|
||||
_probing = probing;
|
||||
if (probing)
|
||||
{
|
||||
// Init at least up to system
|
||||
setMinUpState(VRSTATE_SYSTEM);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If only initing to system, shutdown
|
||||
if (_upState <= VRSTATE_SYSTEM)
|
||||
setDestState(VRSTATE_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
VRState getProbingState() const
|
||||
{
|
||||
return _probing ? VRSTATE_SYSTEM : VRSTATE_DISABLED;
|
||||
}
|
||||
|
||||
void setViewer(osgViewer::ViewerBase *viewer)
|
||||
{
|
||||
_viewer = viewer;
|
||||
}
|
||||
|
||||
/// Set the NodeMasks to use for visibility masks.
|
||||
void setVisibilityMaskNodeMasks(osg::Node::NodeMask left,
|
||||
osg::Node::NodeMask right)
|
||||
{
|
||||
_visibilityMaskLeft = left;
|
||||
_visibilityMaskRight = right;
|
||||
}
|
||||
|
||||
/// Get the subaction object for a subaction path string.
|
||||
std::shared_ptr<Subaction::Private> getSubaction(const std::string &path);
|
||||
|
||||
/// Add an action set
|
||||
void addActionSet(ActionSet::Private *actionSet)
|
||||
{
|
||||
_actionSets.insert(actionSet);
|
||||
_actionsUpdated = true;
|
||||
}
|
||||
|
||||
/// Remove an action set
|
||||
void removeActionSet(ActionSet::Private *actionSet)
|
||||
{
|
||||
_actionSets.erase(actionSet);
|
||||
_actionsUpdated = true;
|
||||
}
|
||||
|
||||
/// Add an interaction profile
|
||||
void addInteractionProfile(InteractionProfile::Private *interactionProfile)
|
||||
{
|
||||
_interactionProfiles.insert(interactionProfile);
|
||||
_actionsUpdated = true;
|
||||
}
|
||||
|
||||
/// Remove an interaction profile
|
||||
void removeInteractionProfile(InteractionProfile::Private *interactionProfile)
|
||||
{
|
||||
_interactionProfiles.erase(interactionProfile);
|
||||
_actionsUpdated = true;
|
||||
}
|
||||
|
||||
/// Get the current interaction profile for the given subaction path.
|
||||
InteractionProfile *getCurrentInteractionProfile(const OpenXR::Path &subactionPath) const;
|
||||
|
||||
/// Get a string describing the state (for user consumption).
|
||||
const char *getStateString() const;
|
||||
|
||||
// Initialize information required for setting up VR
|
||||
void init(osgViewer::GraphicsWindow *window,
|
||||
osgViewer::View *view = nullptr)
|
||||
{
|
||||
_window = window;
|
||||
_view = view;
|
||||
}
|
||||
|
||||
/// Update down state depending on any changed settings.
|
||||
void syncSettings();
|
||||
|
||||
/// Find whether actions have been updated.
|
||||
bool getActionsUpdated() const;
|
||||
|
||||
/// Arrange reinit as needed of action setup.
|
||||
void syncActionSetup();
|
||||
|
||||
/// Find whether state has changed since last call, and reset.
|
||||
bool checkAndResetStateChanged();
|
||||
|
||||
/// Perform a regular update.
|
||||
void update();
|
||||
|
||||
// Extending OpenXR::EventManager
|
||||
void onInstanceLossPending(OpenXR::Instance *instance,
|
||||
const XrEventDataInstanceLossPending *event) override;
|
||||
void onInteractionProfileChanged(OpenXR::Session *session,
|
||||
const XrEventDataInteractionProfileChanged *event) override;
|
||||
void onSessionStateChanged(OpenXR::Session *session,
|
||||
const XrEventDataSessionStateChanged *event) override;
|
||||
void onSessionStateStart(OpenXR::Session *session) override;
|
||||
void onSessionStateEnd(OpenXR::Session *session, bool retry) override;
|
||||
void onSessionStateReady(OpenXR::Session *session) override;
|
||||
void onSessionStateStopping(OpenXR::Session *session, bool loss) override;
|
||||
void onSessionStateFocus(OpenXR::Session *session) override;
|
||||
void onSessionStateUnfocus(OpenXR::Session *session) override;
|
||||
|
||||
osg::ref_ptr<OpenXR::Session::Frame> getFrame(osg::FrameStamp *stamp);
|
||||
void startRendering(osg::FrameStamp *stamp);
|
||||
void endFrame(osg::FrameStamp *stamp);
|
||||
|
||||
void updateSlave(uint32_t viewIndex, osg::View& view,
|
||||
osg::View::Slave& slave);
|
||||
void updateVisibilityMaskTransform(osg::Camera *camera,
|
||||
osg::MatrixTransform *transform);
|
||||
|
||||
osg::Matrixd getEyeProjection(osg::FrameStamp *stamp,
|
||||
uint32_t viewIndex,
|
||||
const osg::Matrixd& projection);
|
||||
osg::Matrixd getEyeView(osg::FrameStamp *stamp, uint32_t viewIndex,
|
||||
const osg::Matrixd& view);
|
||||
|
||||
void initialDrawCallback(osg::RenderInfo &renderInfo);
|
||||
void swapBuffersImplementation(osg::GraphicsContext* gc);
|
||||
|
||||
inline osg::ref_ptr<OpenXR::CompositionLayerProjection> getProjectionLayer()
|
||||
{
|
||||
return _projectionLayer;
|
||||
}
|
||||
|
||||
class TextureRect
|
||||
{
|
||||
public:
|
||||
|
||||
float x, y;
|
||||
float width, height;
|
||||
|
||||
TextureRect(const OpenXR::SwapchainGroup::SubImage &subImage)
|
||||
{
|
||||
float w = subImage.getSwapchainGroup()->getWidth();
|
||||
float h = subImage.getSwapchainGroup()->getHeight();
|
||||
x = (float)subImage.getX() / w;
|
||||
y = (float)subImage.getY() / h;
|
||||
width = (float)subImage.getWidth() / w;
|
||||
height = (float)subImage.getHeight() / h;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int getViewCount() const
|
||||
{
|
||||
return _xrViews.size();
|
||||
}
|
||||
|
||||
TextureRect getViewTextureRect(unsigned int viewIndex) const
|
||||
{
|
||||
return TextureRect(_xrViews[viewIndex]->getSubImage());
|
||||
}
|
||||
|
||||
// Caller must validate viewIndex using getViewCount()
|
||||
osg::ref_ptr<osg::Texture2D> getViewTexture(unsigned int viewIndex,
|
||||
const osg::FrameStamp *stamp) const
|
||||
{
|
||||
return _xrViews[viewIndex]->getSwapchain()->getOsgTexture(stamp);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
typedef enum {
|
||||
/// Successfully completed operation.
|
||||
UP_SUCCESS,
|
||||
/// Operation not possible at the moment, try again soon.
|
||||
UP_SOON,
|
||||
/// Operation not possible at the moment, try again later.
|
||||
UP_LATER,
|
||||
/// Operation permanently failed, disable VR.
|
||||
UP_ABORT,
|
||||
} UpResult;
|
||||
|
||||
typedef enum {
|
||||
/// Successfully completed operation.
|
||||
DOWN_SUCCESS,
|
||||
/// Operation not possible at the moment, try again soon.
|
||||
DOWN_SOON,
|
||||
} DownResult;
|
||||
|
||||
// Pre-instance probing
|
||||
void probe() const;
|
||||
void unprobe() const;
|
||||
|
||||
// These are called during update to raise or lower VR state level
|
||||
UpResult upInstance();
|
||||
DownResult downInstance();
|
||||
UpResult upSystem();
|
||||
DownResult downSystem();
|
||||
UpResult upSession();
|
||||
DownResult downSession();
|
||||
UpResult upActions();
|
||||
DownResult downActions();
|
||||
|
||||
// Set up a single swapchain containing multiple viewports
|
||||
bool setupSingleSwapchain(int64_t format, int64_t depthFormat = 0);
|
||||
// Set up a swapchain for each view
|
||||
bool setupMultipleSwapchains(int64_t format, int64_t depthFormat = 0);
|
||||
// Set up slave cameras
|
||||
void setupSlaveCameras();
|
||||
// Set up SceneView VR mode cameras
|
||||
void setupSceneViewCameras();
|
||||
void setupSceneViewCamera(osg::Camera *camera);
|
||||
// Visibility mask setup
|
||||
inline bool needsVisibilityMask(osg::Camera *camera)
|
||||
{
|
||||
return _useVisibilityMask &&
|
||||
(camera->getClearMask() & GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
void setupSceneViewVisibilityMasks(osg::Camera *camera,
|
||||
osg::ref_ptr<osg::MatrixTransform> &transform);
|
||||
osg::ref_ptr<osg::Geode> setupVisibilityMask(osg::Camera *camera,
|
||||
uint32_t viewIndex,
|
||||
osg::ref_ptr<osg::MatrixTransform> &transform);
|
||||
|
||||
osg::ref_ptr<Settings> _settings;
|
||||
Settings _settingsCopy;
|
||||
osg::observer_ptr<Manager> _manager;
|
||||
|
||||
// app configuration
|
||||
osg::Node::NodeMask _visibilityMaskLeft;
|
||||
osg::Node::NodeMask _visibilityMaskRight;
|
||||
|
||||
// Actions
|
||||
bool _actionsUpdated;
|
||||
std::set<ActionSet::Private *> _actionSets;
|
||||
std::set<InteractionProfile::Private *> _interactionProfiles;
|
||||
std::map<std::string, std::weak_ptr<Subaction::Private>> _subactions;
|
||||
|
||||
/// Current state of OpenXR initialization.
|
||||
VRState _currentState;
|
||||
/// State of OpenXR initialisation to drop down to.
|
||||
VRState _downState;
|
||||
/// State of OpenXR initialisation to rise up to.
|
||||
VRState _upState;
|
||||
/// Number of attempts made to rise VR state.
|
||||
unsigned int _upDelay;
|
||||
/// Whether probing should be kept active.
|
||||
bool _probing;
|
||||
/// Last read state as a user readable string.
|
||||
mutable std::string _stateString;
|
||||
/// Whether state has changed since the last update.
|
||||
bool _stateChanged;
|
||||
|
||||
// Session setup
|
||||
osg::observer_ptr<osgViewer::ViewerBase> _viewer;
|
||||
osg::observer_ptr<osgViewer::GraphicsWindow> _window;
|
||||
osg::observer_ptr<osgViewer::View> _view;
|
||||
|
||||
// Pre-Instance related
|
||||
mutable bool _probed;
|
||||
mutable bool _hasValidationLayer;
|
||||
mutable bool _hasDepthInfoExtension;
|
||||
mutable bool _hasVisibilityMaskExtension;
|
||||
|
||||
// Instance related
|
||||
osg::ref_ptr<OpenXR::Instance> _instance;
|
||||
bool _useDepthInfo;
|
||||
bool _useVisibilityMask;
|
||||
|
||||
// System related
|
||||
XrFormFactor _formFactor;
|
||||
OpenXR::System *_system;
|
||||
const OpenXR::System::ViewConfiguration *_chosenViewConfig;
|
||||
XrEnvironmentBlendMode _chosenEnvBlendMode;
|
||||
|
||||
// Session related
|
||||
VRMode _vrMode;
|
||||
SwapchainMode _swapchainMode;
|
||||
osg::ref_ptr<OpenXR::Session> _session;
|
||||
std::vector<osg::ref_ptr<XRView> > _xrViews;
|
||||
std::vector<osg::ref_ptr<AppView> > _appViews;
|
||||
FrameStore _frames;
|
||||
osg::ref_ptr<OpenXR::CompositionLayerProjection> _projectionLayer;
|
||||
OpenXR::DepthInfo _depthInfo;
|
||||
osg::ref_ptr<osg::DisplaySettings> _stereoDisplaySettings;
|
||||
};
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
195
3rdparty/osgXR/src/XRStateCallbacks.h
vendored
Normal file
195
3rdparty/osgXR/src/XRStateCallbacks.h
vendored
Normal file
|
@ -0,0 +1,195 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_XRSTATE_CALLBACKS
|
||||
#define OSGXR_XRSTATE_CALLBACKS 1
|
||||
|
||||
#include "XRState.h"
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/GraphicsContext>
|
||||
#include <osg/View>
|
||||
|
||||
#include <osgUtil/SceneView>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
class SlaveCamsUpdateSlaveCallback : public osg::View::Slave::UpdateSlaveCallback
|
||||
{
|
||||
public:
|
||||
|
||||
SlaveCamsUpdateSlaveCallback(uint32_t viewIndex,
|
||||
XRState *xrState,
|
||||
osg::MatrixTransform *visMaskTransform) :
|
||||
_viewIndex(viewIndex),
|
||||
_xrState(xrState),
|
||||
_visMaskTransform(visMaskTransform)
|
||||
{
|
||||
}
|
||||
|
||||
void updateSlave(osg::View& view, osg::View::Slave& slave) override
|
||||
{
|
||||
_xrState->updateSlave(_viewIndex, view, slave);
|
||||
if (_visMaskTransform.valid())
|
||||
_xrState->updateVisibilityMaskTransform(slave._camera,
|
||||
_visMaskTransform.get());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
uint32_t _viewIndex;
|
||||
osg::observer_ptr<XRState> _xrState;
|
||||
osg::observer_ptr<osg::MatrixTransform> _visMaskTransform;
|
||||
};
|
||||
|
||||
class SceneViewUpdateSlaveCallback : public osg::View::Slave::UpdateSlaveCallback
|
||||
{
|
||||
public:
|
||||
|
||||
SceneViewUpdateSlaveCallback(osg::ref_ptr<XRState> xrState,
|
||||
osg::ref_ptr<osg::MatrixTransform> visMaskTransform) :
|
||||
_xrState(xrState),
|
||||
_visMaskTransform(visMaskTransform)
|
||||
{
|
||||
}
|
||||
|
||||
void updateSlave(osg::View& view, osg::View::Slave& slave) override
|
||||
{
|
||||
if (_visMaskTransform.valid())
|
||||
_xrState->updateVisibilityMaskTransform(slave._camera,
|
||||
_visMaskTransform.get());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<XRState> _xrState;
|
||||
osg::observer_ptr<osg::MatrixTransform> _visMaskTransform;
|
||||
};
|
||||
|
||||
class ComputeStereoMatricesCallback : public osgUtil::SceneView::ComputeStereoMatricesCallback
|
||||
{
|
||||
public:
|
||||
|
||||
ComputeStereoMatricesCallback(XRState *xrState,
|
||||
osgUtil::SceneView *sceneView) :
|
||||
_xrState(xrState),
|
||||
_sceneView(sceneView)
|
||||
{
|
||||
}
|
||||
|
||||
osg::Matrixd computeLeftEyeProjection(const osg::Matrixd& projection) const override
|
||||
{
|
||||
return _xrState->getEyeProjection(_sceneView->getFrameStamp(),
|
||||
0, projection);
|
||||
}
|
||||
|
||||
osg::Matrixd computeLeftEyeView(const osg::Matrixd& view) const override
|
||||
{
|
||||
return _xrState->getEyeView(_sceneView->getFrameStamp(),
|
||||
0, view);
|
||||
}
|
||||
|
||||
osg::Matrixd computeRightEyeProjection(const osg::Matrixd& projection) const override
|
||||
{
|
||||
return _xrState->getEyeProjection(_sceneView->getFrameStamp(),
|
||||
1, projection);
|
||||
}
|
||||
|
||||
osg::Matrixd computeRightEyeView(const osg::Matrixd& view) const override
|
||||
{
|
||||
return _xrState->getEyeView(_sceneView->getFrameStamp(),
|
||||
1, view);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<XRState> _xrState;
|
||||
osg::observer_ptr<osgUtil::SceneView> _sceneView;
|
||||
};
|
||||
|
||||
class InitialDrawCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
|
||||
InitialDrawCallback(osg::ref_ptr<XRState> xrState) :
|
||||
_xrState(xrState)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(osg::RenderInfo& renderInfo) const override
|
||||
{
|
||||
_xrState->initialDrawCallback(renderInfo);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<XRState> _xrState;
|
||||
};
|
||||
|
||||
class PreDrawCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
|
||||
PreDrawCallback(osg::ref_ptr<XRState::XRSwapchain> xrSwapchain) :
|
||||
_xrSwapchain(xrSwapchain)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(osg::RenderInfo& renderInfo) const override
|
||||
{
|
||||
_xrSwapchain->preDrawCallback(renderInfo);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<XRState::XRSwapchain> _xrSwapchain;
|
||||
};
|
||||
|
||||
class PostDrawCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
|
||||
PostDrawCallback(osg::ref_ptr<XRState::XRSwapchain> xrSwapchain) :
|
||||
_xrSwapchain(xrSwapchain)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(osg::RenderInfo& renderInfo) const override
|
||||
{
|
||||
_xrSwapchain->postDrawCallback(renderInfo);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::observer_ptr<XRState::XRSwapchain> _xrSwapchain;
|
||||
};
|
||||
|
||||
class SwapCallback : public osg::GraphicsContext::SwapCallback
|
||||
{
|
||||
public:
|
||||
|
||||
explicit SwapCallback(osg::ref_ptr<XRState> xrState) :
|
||||
_xrState(xrState),
|
||||
_frameIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
void swapBuffersImplementation(osg::GraphicsContext* gc)
|
||||
{
|
||||
_xrState->swapBuffersImplementation(gc);
|
||||
}
|
||||
|
||||
int frameIndex() const
|
||||
{
|
||||
return _frameIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
osg::observer_ptr<XRState> _xrState;
|
||||
int _frameIndex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
94
3rdparty/osgXR/src/osgXR.cpp
vendored
Normal file
94
3rdparty/osgXR/src/osgXR.cpp
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#include <osgXR/MirrorSettings>
|
||||
#include <osgXR/OpenXRDisplay>
|
||||
#include <osgXR/Settings>
|
||||
#include <osgXR/osgXR>
|
||||
|
||||
#include <osg/Notify>
|
||||
#include <osg/os_utils>
|
||||
|
||||
using namespace osgXR;
|
||||
|
||||
void osgXR::setupViewerDefaults(osgViewer::Viewer *viewer,
|
||||
const std::string &appName,
|
||||
uint32_t appVersion)
|
||||
{
|
||||
unsigned int vr = 0;
|
||||
osg::getEnvVar("OSGXR", vr);
|
||||
|
||||
if (vr)
|
||||
{
|
||||
Settings *settings = Settings::instance();
|
||||
MirrorSettings *mirrorSettings = &settings->getMirrorSettings();
|
||||
std::string value;
|
||||
|
||||
Settings::VRMode vrMode = Settings::VRMODE_AUTOMATIC;
|
||||
if (osg::getEnvVar("OSGXR_MODE", value))
|
||||
{
|
||||
if (value == "SLAVE_CAMERAS")
|
||||
vrMode = Settings::VRMODE_SLAVE_CAMERAS;
|
||||
else if (value == "SCENE_VIEW")
|
||||
vrMode = Settings::VRMODE_SCENE_VIEW;
|
||||
}
|
||||
|
||||
Settings::SwapchainMode swapchainMode = Settings::SWAPCHAIN_AUTOMATIC;
|
||||
if (osg::getEnvVar("OSGXR_SWAPCHAIN", value))
|
||||
{
|
||||
if (value == "MULTIPLE")
|
||||
swapchainMode = Settings::SWAPCHAIN_MULTIPLE;
|
||||
else if (value == "SINGLE")
|
||||
swapchainMode = Settings::SWAPCHAIN_SINGLE;
|
||||
}
|
||||
|
||||
float unitsPerMeter = 0.0f;
|
||||
osg::getEnvVar("OSGXR_UNITS_PER_METER", unitsPerMeter);
|
||||
|
||||
int validationLayer = 0;
|
||||
osg::getEnvVar("OSGXR_VALIDATION_LAYER", validationLayer);
|
||||
|
||||
int depthInfo = 0;
|
||||
osg::getEnvVar("OSGXR_DEPTH_INFO", depthInfo);
|
||||
|
||||
MirrorSettings::MirrorMode mirrorMode = MirrorSettings::MIRROR_AUTOMATIC;
|
||||
int mirrorViewIndex = -1;
|
||||
if (osg::getEnvVar("OSGXR_MIRROR", value))
|
||||
{
|
||||
if (value == "NONE")
|
||||
{
|
||||
mirrorMode = MirrorSettings::MIRROR_NONE;
|
||||
}
|
||||
else if (value == "LEFT")
|
||||
{
|
||||
mirrorMode = MirrorSettings::MIRROR_SINGLE;
|
||||
mirrorViewIndex = 0;
|
||||
}
|
||||
else if (value == "RIGHT")
|
||||
{
|
||||
mirrorMode = MirrorSettings::MIRROR_SINGLE;
|
||||
mirrorViewIndex = 1;
|
||||
}
|
||||
else if (value == "LEFT_RIGHT")
|
||||
{
|
||||
mirrorMode = MirrorSettings::MIRROR_LEFT_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
settings->setApp(appName, appVersion);
|
||||
settings->setFormFactor(Settings::HEAD_MOUNTED_DISPLAY);
|
||||
settings->preferEnvBlendMode(Settings::OPAQUE);
|
||||
if (unitsPerMeter > 0.0f)
|
||||
settings->setUnitsPerMeter(unitsPerMeter);
|
||||
settings->setVRMode(vrMode);
|
||||
settings->setSwapchainMode(swapchainMode);
|
||||
settings->setValidationLayer(!!validationLayer);
|
||||
settings->setDepthInfo(!!depthInfo);
|
||||
mirrorSettings->setMirror(mirrorMode, mirrorViewIndex);
|
||||
|
||||
osg::ref_ptr<OpenXRDisplay> xr = new OpenXRDisplay(settings);
|
||||
viewer->apply(xr);
|
||||
|
||||
OSG_WARN << "Setting up VR" << std::endl;
|
||||
}
|
||||
}
|
79
3rdparty/osgXR/src/projection.cpp
vendored
Normal file
79
3rdparty/osgXR/src/projection.cpp
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
// =============================================================================
|
||||
// Derived from openxr-simple-example
|
||||
// Copyright 2019-2021, Collabora, Ltd.
|
||||
// Which was adapted from
|
||||
// https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/common/xr_linear.h
|
||||
// Copyright (c) 2017 The Khronos Group Inc.
|
||||
// Copyright (c) 2016 Oculus VR, LLC.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================================
|
||||
|
||||
#include "projection.h"
|
||||
|
||||
void osgXR::createProjectionFov(osg::Matrix& result,
|
||||
const XrFovf& fov,
|
||||
const float nearZ,
|
||||
const float farZ)
|
||||
{
|
||||
const float tanAngleLeft = tanf(fov.angleLeft);
|
||||
const float tanAngleRight = tanf(fov.angleRight);
|
||||
|
||||
const float tanAngleDown = tanf(fov.angleDown);
|
||||
const float tanAngleUp = tanf(fov.angleUp);
|
||||
|
||||
const float tanAngleWidth = tanAngleRight - tanAngleLeft;
|
||||
|
||||
// Set to tanAngleDown - tanAngleUp for a clip space with positive Y
|
||||
// down (Vulkan). Set to tanAngleUp - tanAngleDown for a clip space with
|
||||
// positive Y up (OpenGL / D3D / Metal).
|
||||
const float tanAngleHeight = tanAngleUp - tanAngleDown;
|
||||
|
||||
// Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES).
|
||||
// Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal).
|
||||
const float offsetZ = nearZ;
|
||||
|
||||
if (farZ <= nearZ)
|
||||
{
|
||||
// place the far plane at infinity
|
||||
result(0, 0) = 2 / tanAngleWidth;
|
||||
result(1, 0) = 0;
|
||||
result(2, 0) = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
|
||||
result(3, 0) = 0;
|
||||
|
||||
result(0, 1) = 0;
|
||||
result(1, 1) = 2 / tanAngleHeight;
|
||||
result(2, 1) = (tanAngleUp + tanAngleDown) / tanAngleHeight;
|
||||
result(3, 1) = 0;
|
||||
|
||||
result(0, 2) = 0;
|
||||
result(1, 2) = 0;
|
||||
result(2, 2) = -1;
|
||||
result(3, 2) = -(nearZ + offsetZ);
|
||||
|
||||
result(0, 3) = 0;
|
||||
result(1, 3) = 0;
|
||||
result(2, 3) = -1;
|
||||
result(3, 3) = 0;
|
||||
} else {
|
||||
// normal projection
|
||||
result(0, 0) = 2 / tanAngleWidth;
|
||||
result(1, 0) = 0;
|
||||
result(2, 0) = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
|
||||
result(3, 0) = 0;
|
||||
|
||||
result(0, 1) = 0;
|
||||
result(1, 1) = 2 / tanAngleHeight;
|
||||
result(2, 1) = (tanAngleUp + tanAngleDown) / tanAngleHeight;
|
||||
result(3, 1) = 0;
|
||||
|
||||
result(0, 2) = 0;
|
||||
result(1, 2) = 0;
|
||||
result(2, 2) = -(farZ + offsetZ) / (farZ - nearZ);
|
||||
result(3, 2) = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ);
|
||||
|
||||
result(0, 3) = 0;
|
||||
result(1, 3) = 0;
|
||||
result(2, 3) = -1;
|
||||
result(3, 3) = 0;
|
||||
}
|
||||
}
|
20
3rdparty/osgXR/src/projection.h
vendored
Normal file
20
3rdparty/osgXR/src/projection.h
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2021 James Hogan <james@albanarts.com>
|
||||
|
||||
#ifndef OSGXR_PROJECTION
|
||||
#define OSGXR_PROJECTION 1
|
||||
|
||||
#include <osg/Matrix>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
namespace osgXR {
|
||||
|
||||
void createProjectionFov(osg::Matrix& result,
|
||||
const XrFovf& fov,
|
||||
const float nearZ,
|
||||
const float farZ);
|
||||
|
||||
} // osgXR
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue