This commit is contained in:
Emanuele Disco 2024-03-15 22:17:50 +09:00 committed by GitHub
commit a1aa322d44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 14204 additions and 3494 deletions

216
.github/workflows/build.yaml vendored Normal file
View file

@ -0,0 +1,216 @@
name: Continuous Integration
on:
pull_request:
push:
tags:
- '*'
paths-ignore:
- '**/README.md'
- '**/LICENSE'
# branches:
# - master
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
build:
name: ${{ matrix.name }} | ${{ matrix.build_type }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, windows-latest]
build_type: [Release, Debug]
include:
- progdir: Projects/Android
- ndk: 21.4.7075529
- build_type: Release
build_folder: release
- build_type: Debug
build_folder: debug
- os: windows-latest
name: Visual Studio 64-bit
extra_options: -A x64
- os: ubuntu-20.04
name: Linux GCC 11
deps_cmdline: "sudo apt update && sudo apt install g++-11 libsdl2-dev libgtk-3-dev"
extra_options: "-DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11"
steps:
# - name: Checkout SDK Mobile
# uses: actions/checkout@v3
# with:
# repository: emawind84/ovr_sdk_mobile
# token: ${{ secrets.GH_PAT }}
# path: ''
- name: Checkout QuestZDoom
uses: actions/checkout@v3
with:
fetch-depth: 1
submodules: true
path: ''
- run: git fetch --deepen=100
working-directory: ${{ matrix.progdir }}/jni/gzdoom-g3.3mgw_mobile
- name: Checkout SDK Mobile
uses: actions/checkout@v3
with:
fetch-depth: 1
repository: emawind84/ovr_sdk_mobile_dist
path: 'sdk'
- name: Checkout META SDK Native Libraries
run: 7z x ovr_openxr_mobile_sdk_47.0.zip -ometasdk
working-directory: sdk
- name: Prepare META SDK Native Libraries
shell: bash
run: >
mv sdk/metasdk/OpenXR/Libs/Android/arm64-v8a/Release/libopenxr_loader.so
Projects/Android/libs/arm64-v8a/libopenxr_loader_meta.so
- name: Checkout PICO SDK Native Libraries
run: 7z x Pico_OpenXR_SDK_v210.zip -opicosdk
working-directory: sdk
- name: Prepare PICO SDK Libraries
shell: bash
run: >
mv sdk/picosdk/libs/android.arm64-v8a/libopenxr_loader.so
Projects/Android/libs/arm64-v8a/libopenxr_loader_pico.so
# - uses: actions/cache@v3
# with:
# path: |
# ~/.gradle/caches
# ~/.gradle/wrapper
# key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
# restore-keys: |
# ${{ runner.os }}-gradle-
- name: Install Dependencies
shell: bash
run: |
if [[ ! -z "${{ matrix.deps_cmdline }}" ]]; then
eval ${{ matrix.deps_cmdline }}
fi
- name: Configure CMAKE
shell: bash
run: >
cmake -B build
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-DPK3_QUIET_ZIPDIR=ON ${{ matrix.extra_options }}
.
working-directory: ${{ matrix.progdir }}/jni/gzdoom-g3.3mgw_mobile
- name: Prepare PK3 packages
shell: bash
run: |
cmake --build build \
--config ${{ matrix.build_type }} \
--target lzdoom_pk3 lights_pk3 lz_game_support_pk3 \
--parallel 3
cp build/*.pk3 ../../../../assets/res
working-directory: ${{ matrix.progdir }}/jni/gzdoom-g3.3mgw_mobile
- name: Revision update
shell: bash
run: cmake --build build --config ${{ matrix.build_type }} --target revision_check
working-directory: ${{ matrix.progdir }}/jni/gzdoom-g3.3mgw_mobile
- name: Setup NDK for Ubuntu
if: matrix.os == 'ubuntu-20.04'
shell: bash
run: echo "y" | ${{ env.SDKMANAGER }} "ndk;${{ matrix.ndk }}"
env:
SDKMANAGER: ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager
- name: Setup NDK for Windows
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
$sdkRoot = "C:\Android\android-sdk"
$sdkManager = "$sdkRoot\cmdline-tools\latest\bin\sdkmanager.bat"
& $sdkManager --sdk_root=$sdkRoot "ndk;${{ matrix.ndk }}"
- name: Set up JDK 11 for x64
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
architecture: x64
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
- name: Setup gradle
uses: gradle/gradle-build-action@v2
with:
build-root-directory: ${{ matrix.progdir }}
cache-read-only: true
cache-disabled: false
- name: Set execution flag for gradlew
shell: bash
run: chmod +x gradlew
working-directory: ${{ matrix.progdir }}
- name: Build with gradle
id: gradle_build
shell: bash
run: ./gradlew :Projects:Android:assemble${{ matrix.build_type }}
working-directory: ${{ matrix.progdir }}
- name: Sign app APK
if: matrix.build_type == 'Release'
uses: ilharp/sign-android-release@v1
id: sign_app_apk
with:
releaseDir: ${{ matrix.progdir }}/build/outputs/apk/release
signingKey: ${{ secrets.SIGNING_KEY }}
keyAlias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
buildToolsVersion: 33.0.0
- name: Prepare signed APK
shell: bash
run: mv --force '${{steps.sign_app_apk.outputs.signedFile}}' questzdoom-${{ matrix.build_folder }}.apk
if: ${{ steps.sign_app_apk.outcome == 'success' }}
working-directory: ${{ matrix.progdir }}/build/outputs/apk/${{ matrix.build_folder }}
- name: Upload package
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.name }} ${{ matrix.build_type }}
path: ${{ matrix.progdir }}/build/outputs/apk/${{ matrix.build_folder }}/*-${{ matrix.build_folder }}.apk
if-no-files-found: error
retention-days: 30
- name: Prepare package for release
if: runner.os == 'Linux'
uses: actions/download-artifact@v3
with:
name: ${{ matrix.name }} ${{ matrix.build_type }}
path: release
- name: Display structure of release files
if: runner.os == 'Linux'
shell: bash
run: ls -R
working-directory: release
- name: Prepare release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true
draft: true
files: |
release/*.apk
LICENSE.txt

7
.gitignore vendored
View file

@ -15,9 +15,6 @@ $RECYCLE.BIN/
*.o
*.d
#binaries
*.so
#libs
*.a
@ -36,5 +33,9 @@ Projects/Android/.externalNativeBuild/*
*.bin
*.ser
Projects/Android/.idea/*
.gradle/*
**/local.properties
Projects/Android/.gradle/*
Projects/Android/Android.iml
Projects/Android/libs/arm64-v8a/libopenxr_loader_meta.so
Projects/Android/libs/arm64-v8a/libopenxr_loader_pico.so

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.drbeef.questzdoom"
android:versionCode="31"
android:versionName="1.4.0" android:installLocation="auto" >
android:versionCode="35"
android:versionName="1.6.1" android:installLocation="auto" >
<!-- Tell the system this app requires OpenGL ES 3.1. -->
<uses-feature android:glEsVersion="0x00030001" android:required="true"/>
@ -17,9 +17,17 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application android:allowBackup="false" android:icon="@drawable/ic_qquest" android:label="@string/qzdoom">
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
<!-- META QUEST -->
<meta-data android:name="com.oculus.supportedDevices" android:value="quest|quest2"/>
<meta-data android:name="com.oculus.ossplash" android:value="true"/>
<!-- PICO XR -->
<meta-data android:name="pvr.app.type" android:value="vr" />
<!-- The activity is the built-in NativeActivity framework class. -->
<!-- launchMode is set to singleTask because there should never be multiple copies of the app running. -->
<!-- Theme.Black.NoTitleBar.Fullscreen gives solid black instead of a (bad stereoscopic) gradient on app transition. -->
@ -39,6 +47,7 @@
<!-- This filter lets the apk show up as a launchable icon. -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

View file

@ -1,29 +0,0 @@
@rem Only edit the master copy of this file in SDK_ROOT/bin/scripts/build/perproject
@setlocal enableextensions enabledelayedexpansion
@if not exist "build.gradle" @echo Build script must be executed from project directory. & goto :Abort
@set P=..
:TryAgain
@rem @echo P = %P%
@if exist "%P%\bin\scripts\build\build.py.bat" goto :Found
@if exist "%P%\bin\scripts\build" @echo "Could not find build.py.bat" & goto :Abort
@set P=%P%\..
@goto :TryAgain
:Found
@set P=%P%\bin\scripts\build
@call %P%\build.py.bat %1 %2 %3 %4 %5
@goto :End
:Abort
:End

View file

@ -1,52 +1,60 @@
apply plugin: 'com.android.application'
apply from: "${rootProject.projectDir}/VrApp.gradle"
apply from: "${rootProject.projectDir}/XrApp.gradle"
android {
// This is the name of the generated apk file, which will have
// -debug.apk or -release.apk appended to it.
// The filename doesn't effect the Android installation process.
// Use only letters to remain compatible with the package name.
project.archivesBaseName = "questzdoom"
// This is the name of the generated apk file, which will have
// -debug.apk or -release.apk appended to it.
// The filename doesn't effect the Android installation process.
// Use only letters to remain compatible with the package name.
project.archivesBaseName = "questzdoom"
defaultConfig {
// Gradle replaces the manifest package with this value, which must
// be unique on a system. If you don't change it, a new app
// will replace an older one.
applicationId "com.drbeef." + project.archivesBaseName
compileSdkVersion 26
// override app plugin abiFilters for both 32 and 64-bit support
externalNativeBuild {
ndk {
defaultConfig {
minSdkVersion 24
targetSdkVersion 26
// Gradle replaces the manifest package with this value, which must
// be unique on a system. If you don't change it, a new app
// will replace an older one.
applicationId "com.drbeef." + project.archivesBaseName
// override app plugin abiFilters for both 32 and 64-bit support
externalNativeBuild {
ndk {
abiFilters 'arm64-v8a'
}
ndkBuild {
abiFilters 'arm64-v8a'
if (project.hasProperty("openxr_hmd"))
arguments 'OPENXR_HMD=' + project.getProperty("openxr_hmd")
}
}
ndkBuild {
abiFilters 'arm64-v8a'
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['../../java']
jniLibs.srcDir 'libs'
res.srcDirs = ['../../res']
assets.srcDirs = ['../../assets', 'jni/gzdoom-g3.3mgw_mobile/fm_banks', 'jni/gzdoom-g3.3mgw_mobile/soundfont']
}
}
minSdkVersion 24
targetSdkVersion 26
// packagingOptions {
// specify the path to your object binaries, or generally:
// doNotStrip '**.so'
// }
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['../../java']
jniLibs.srcDir 'libs'
res.srcDirs = ['../../res']
assets.srcDirs = ['../../assets', 'jni/gzdoom-g3.3mgw_mobile/fm_banks', 'jni/gzdoom-g3.3mgw_mobile/soundfont']
}
}
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
packagingOptions {
exclude 'lib/arm64-v8a/libopenxr_loader.so'
}
ndkVersion = "21.4.7075529"
compileSdkVersion = 24
buildToolsVersion = '29.0.1'
/* buildTypes {
release {
debuggable true
@ -55,8 +63,8 @@ android {
}
dependencies {
implementation "com.android.support:support-compat:24.2.0"
implementation "com.android.support:support-core-utils:24.2.0"
implementation "com.android.support:support-compat:26.1.0"
implementation "com.android.support:support-core-utils:26.1.0"
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}
@ -67,4 +75,6 @@ buildscript {
repositories {
google()
}
}
}
//tasks.register("prepareKotlinBuildScriptModel"){}

View file

@ -1,29 +0,0 @@
#!/usr/bin/python
# This first bit of code is common bootstrapping code
# to determine the SDK root, and to set up the import
# path for additional python code.
#begin bootstrap
import os
import sys
def init():
root = os.path.realpath( os.path.dirname(os.path.realpath(__file__) ) )
os.chdir(root) # make sure we are always executing from the project directory
while( os.path.isdir( os.path.join(root, 'bin/scripts/build') ) == False ):
root = os.path.realpath( os.path.join(root, '..') )
if( len(root) <= 5 ): # Should catch both Posix and Windows root directories (e.g. '/' and 'C:\')
print('Unable to find SDK root. Exiting.')
sys.exit(1)
root = os.path.abspath(root)
os.environ['OCULUS_SDK_PATH'] = root
sys.path.append( root + "/bin/scripts/build" )
init()
import ovrbuild
ovrbuild.init()
#end bootstrap
ovrbuild.build()

View file

@ -1,6 +1,6 @@
#Sat Feb 20 22:20:15 GMT 2021
#Fri Dec 23 16:20:08 KST 2022
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View file

@ -1,14 +1,9 @@
# MAKEFILE_LIST specifies the current used Makefiles, of which this is the last
# one. I use that to obtain the Application.mk dir then import the root
# Application.mk.
ROOT_DIR := $(dir $(lastword $(MAKEFILE_LIST)))../../../../..
NDK_MODULE_PATH := $(ROOT_DIR)
APP_PLATFORM := android-19
APP_CFLAGS += -Wl,--no-undefined, -march=armv8+crc
APPLICATIONMK_PATH = $(call my-dir)
NDK_MODULE_PATH := $(APPLICATIONMK_PATH)/../..
TOP_DIR := $(APPLICATIONMK_PATH)
SUPPORT_LIBS := $(APPLICATIONMK_PATH)/SupportLibs

View file

@ -0,0 +1,20 @@
# Copyright (c) 2017 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author:
#
add_subdirectory(openxr)

View file

@ -0,0 +1,101 @@
# Copyright (c) 2017-2022, The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author:
#
# Copy the openxr_platform_defines.h file and place it in the binary (build) directory.
configure_file(openxr_platform_defines.h ${CMAKE_CURRENT_BINARY_DIR}/openxr_platform_defines.h COPYONLY)
# Generate OpenXR header files.
set(HEADERS
openxr.h
openxr_platform.h
openxr_reflection.h)
set(HAVE_PREGENERATED TRUE)
set(SOURCE_HEADERS)
foreach(output ${HEADERS})
list(APPEND SOURCE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/${output})
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${output})
set(HAVE_PREGENERATED FALSE)
endif()
endforeach()
set(XR_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..)
if(HAVE_PREGENERATED AND NOT BUILD_FORCE_GENERATION)
add_custom_target(generate_openxr_header
COMMENT "Using found pre-generated OpenXR headers.")
set(INSTALL_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/openxr_platform_defines.h
${SOURCE_HEADERS})
else()
set(GENERATED_HEADERS)
set(OUTPUT_STAMPS)
# Copy the openxr_platform_defines.h file and place it in the binary (build) directory.
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/openxr_platform_defines.h
${CMAKE_CURRENT_BINARY_DIR}/openxr_platform_defines.h
COPYONLY)
# Generate the header files and place it in the binary (build) directory.
foreach(output ${HEADERS})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${output}
COMMAND ${PYTHON_EXECUTABLE} ${XR_ROOT}/specification/scripts/genxr.py
-registry ${XR_ROOT}/specification/registry/xr.xml
-o ${CMAKE_CURRENT_BINARY_DIR} ${output}
DEPENDS
${XR_ROOT}/specification/scripts/genxr.py
${XR_ROOT}/specification/scripts/cgenerator.py
${XR_ROOT}/specification/scripts/creflectiongenerator.py
${XR_ROOT}/specification/scripts/generator.py
${XR_ROOT}/specification/scripts/reg.py
${XR_ROOT}/specification/registry/xr.xml
COMMENT "Generating ${CMAKE_CURRENT_BINARY_DIR}/${output}"
)
list(APPEND GENERATED_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/${output}")
endforeach()
set_source_files_properties(
${GENERATED_HEADERS}
PROPERTIES GENERATED TRUE
)
set(INSTALL_HEADERS
${CMAKE_CURRENT_BINARY_DIR}/openxr_platform_defines.h
${GENERATED_HEADERS})
# Define generate_openxr_header target to generate the OpenXR header files.
# Other targets that need the OpenXR headers should use generate_openxr_header as a dependency.
add_custom_target(generate_openxr_header
SOURCES ${XR_ROOT}/specification/registry/xr.xml
DEPENDS
${GENERATED_HEADERS}
${OUTPUT_STAMPS}
)
endif()
set_target_properties(generate_openxr_header PROPERTIES FOLDER ${CODEGEN_FOLDER})
if(NOT CMAKE_INSTALL_INCDIR)
set(CMAKE_INSTALL_INCDIR include)
endif()
INSTALL(FILES ${INSTALL_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCDIR}/openxr
COMPONENT Headers
)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,690 @@
#ifndef OPENXR_PLATFORM_H_
#define OPENXR_PLATFORM_H_ 1
/*
** Copyright 2017-2022 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
** This header is generated from the Khronos OpenXR XML API Registry.
**
*/
#include "openxr.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_thread_settings 1
#define XR_KHR_android_thread_settings_SPEC_VERSION 5
#define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "XR_KHR_android_thread_settings"
typedef enum XrAndroidThreadTypeKHR {
XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR = 1,
XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR = 2,
XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR = 3,
XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR = 4,
XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF
} XrAndroidThreadTypeKHR;
typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR(
XrSession session,
XrAndroidThreadTypeKHR threadType,
uint32_t threadId);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_surface_swapchain 1
#define XR_KHR_android_surface_swapchain_SPEC_VERSION 4
#define XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME "XR_KHR_android_surface_swapchain"
typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR(
XrSession session,
const XrSwapchainCreateInfo* info,
XrSwapchain* swapchain,
jobject* surface);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_create_instance 1
#define XR_KHR_android_create_instance_SPEC_VERSION 3
#define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance"
// XrInstanceCreateInfoAndroidKHR extends XrInstanceCreateInfo
typedef struct XrInstanceCreateInfoAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
void* XR_MAY_ALIAS applicationVM;
void* XR_MAY_ALIAS applicationActivity;
} XrInstanceCreateInfoAndroidKHR;
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_swapchain_format_list 1
#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 4
#define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list"
typedef struct XrVulkanSwapchainFormatListCreateInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
uint32_t viewFormatCount;
const VkFormat* viewFormats;
} XrVulkanSwapchainFormatListCreateInfoKHR;
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_OPENGL
#define XR_KHR_opengl_enable 1
#define XR_KHR_opengl_enable_SPEC_VERSION 10
#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable"
#ifdef XR_USE_PLATFORM_WIN32
// XrGraphicsBindingOpenGLWin32KHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLWin32KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
HDC hDC;
HGLRC hGLRC;
} XrGraphicsBindingOpenGLWin32KHR;
#endif // XR_USE_PLATFORM_WIN32
#ifdef XR_USE_PLATFORM_XLIB
// XrGraphicsBindingOpenGLXlibKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLXlibKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
Display* xDisplay;
uint32_t visualid;
GLXFBConfig glxFBConfig;
GLXDrawable glxDrawable;
GLXContext glxContext;
} XrGraphicsBindingOpenGLXlibKHR;
#endif // XR_USE_PLATFORM_XLIB
#ifdef XR_USE_PLATFORM_XCB
// XrGraphicsBindingOpenGLXcbKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLXcbKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
xcb_connection_t* connection;
uint32_t screenNumber;
xcb_glx_fbconfig_t fbconfigid;
xcb_visualid_t visualid;
xcb_glx_drawable_t glxDrawable;
xcb_glx_context_t glxContext;
} XrGraphicsBindingOpenGLXcbKHR;
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_PLATFORM_WAYLAND
// XrGraphicsBindingOpenGLWaylandKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLWaylandKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
struct wl_display* display;
} XrGraphicsBindingOpenGLWaylandKHR;
#endif // XR_USE_PLATFORM_WAYLAND
typedef struct XrSwapchainImageOpenGLKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t image;
} XrSwapchainImageOpenGLKHR;
typedef struct XrGraphicsRequirementsOpenGLKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsOpenGLKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_OPENGL */
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#define XR_KHR_opengl_es_enable 1
#define XR_KHR_opengl_es_enable_SPEC_VERSION 8
#define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable"
#ifdef XR_USE_PLATFORM_ANDROID
// XrGraphicsBindingOpenGLESAndroidKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLESAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
EGLDisplay display;
EGLConfig config;
EGLContext context;
} XrGraphicsBindingOpenGLESAndroidKHR;
#endif // XR_USE_PLATFORM_ANDROID
typedef struct XrSwapchainImageOpenGLESKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t image;
} XrSwapchainImageOpenGLESKHR;
typedef struct XrGraphicsRequirementsOpenGLESKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsOpenGLESKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_enable 1
#define XR_KHR_vulkan_enable_SPEC_VERSION 8
#define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable"
// XrGraphicsBindingVulkanKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingVulkanKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkDevice device;
uint32_t queueFamilyIndex;
uint32_t queueIndex;
} XrGraphicsBindingVulkanKHR;
typedef struct XrSwapchainImageVulkanKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
VkImage image;
} XrSwapchainImageVulkanKHR;
typedef struct XrGraphicsRequirementsVulkanKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsVulkanKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanInstanceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanDeviceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instance, XrSystemId systemId, VkInstance vkInstance, VkPhysicalDevice* vkPhysicalDevice);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDeviceKHR(
XrInstance instance,
XrSystemId systemId,
VkInstance vkInstance,
VkPhysicalDevice* vkPhysicalDevice);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_D3D11
#define XR_KHR_D3D11_enable 1
#define XR_KHR_D3D11_enable_SPEC_VERSION 9
#define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable"
// XrGraphicsBindingD3D11KHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingD3D11KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
ID3D11Device* device;
} XrGraphicsBindingD3D11KHR;
typedef struct XrSwapchainImageD3D11KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
ID3D11Texture2D* texture;
} XrSwapchainImageD3D11KHR;
typedef struct XrGraphicsRequirementsD3D11KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
LUID adapterLuid;
D3D_FEATURE_LEVEL minFeatureLevel;
} XrGraphicsRequirementsD3D11KHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_D3D11 */
#ifdef XR_USE_GRAPHICS_API_D3D12
#define XR_KHR_D3D12_enable 1
#define XR_KHR_D3D12_enable_SPEC_VERSION 9
#define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable"
// XrGraphicsBindingD3D12KHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingD3D12KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
ID3D12Device* device;
ID3D12CommandQueue* queue;
} XrGraphicsBindingD3D12KHR;
typedef struct XrSwapchainImageD3D12KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
ID3D12Resource* texture;
} XrSwapchainImageD3D12KHR;
typedef struct XrGraphicsRequirementsD3D12KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
LUID adapterLuid;
D3D_FEATURE_LEVEL minFeatureLevel;
} XrGraphicsRequirementsD3D12KHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_D3D12 */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_KHR_win32_convert_performance_counter_time 1
#define XR_KHR_win32_convert_performance_counter_time_SPEC_VERSION 1
#define XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME "XR_KHR_win32_convert_performance_counter_time"
typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrInstance instance, const LARGE_INTEGER* performanceCounter, XrTime* time);
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR(
XrInstance instance,
const LARGE_INTEGER* performanceCounter,
XrTime* time);
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR(
XrInstance instance,
XrTime time,
LARGE_INTEGER* performanceCounter);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_TIMESPEC
#define XR_KHR_convert_timespec_time 1
#define XR_KHR_convert_timespec_time_SPEC_VERSION 1
#define XR_KHR_CONVERT_TIMESPEC_TIME_EXTENSION_NAME "XR_KHR_convert_timespec_time"
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance instance, const struct timespec* timespecTime, XrTime* time);
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR(
XrInstance instance,
const struct timespec* timespecTime,
XrTime* time);
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR(
XrInstance instance,
XrTime time,
struct timespec* timespecTime);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_TIMESPEC */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_loader_init_android 1
#define XR_KHR_loader_init_android_SPEC_VERSION 1
#define XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME "XR_KHR_loader_init_android"
typedef struct XrLoaderInitInfoAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
void* XR_MAY_ALIAS applicationVM;
void* XR_MAY_ALIAS applicationContext;
} XrLoaderInitInfoAndroidKHR;
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_enable2 1
#define XR_KHR_vulkan_enable2_SPEC_VERSION 2
#define XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME "XR_KHR_vulkan_enable2"
typedef XrFlags64 XrVulkanInstanceCreateFlagsKHR;
// Flag bits for XrVulkanInstanceCreateFlagsKHR
typedef XrFlags64 XrVulkanDeviceCreateFlagsKHR;
// Flag bits for XrVulkanDeviceCreateFlagsKHR
typedef struct XrVulkanInstanceCreateInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrSystemId systemId;
XrVulkanInstanceCreateFlagsKHR createFlags;
PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
const VkInstanceCreateInfo* vulkanCreateInfo;
const VkAllocationCallbacks* vulkanAllocator;
} XrVulkanInstanceCreateInfoKHR;
typedef struct XrVulkanDeviceCreateInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrSystemId systemId;
XrVulkanDeviceCreateFlagsKHR createFlags;
PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
VkPhysicalDevice vulkanPhysicalDevice;
const VkDeviceCreateInfo* vulkanCreateInfo;
const VkAllocationCallbacks* vulkanAllocator;
} XrVulkanDeviceCreateInfoKHR;
typedef XrGraphicsBindingVulkanKHR XrGraphicsBindingVulkan2KHR;
typedef struct XrVulkanGraphicsDeviceGetInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrSystemId systemId;
VkInstance vulkanInstance;
} XrVulkanGraphicsDeviceGetInfoKHR;
typedef XrSwapchainImageVulkanKHR XrSwapchainImageVulkan2KHR;
typedef XrGraphicsRequirementsVulkanKHR XrGraphicsRequirementsVulkan2KHR;
typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult);
typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirements2KHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanInstanceKHR(
XrInstance instance,
const XrVulkanInstanceCreateInfoKHR* createInfo,
VkInstance* vulkanInstance,
VkResult* vulkanResult);
XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanDeviceKHR(
XrInstance instance,
const XrVulkanDeviceCreateInfoKHR* createInfo,
VkDevice* vulkanDevice,
VkResult* vulkanResult);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDevice2KHR(
XrInstance instance,
const XrVulkanGraphicsDeviceGetInfoKHR* getInfo,
VkPhysicalDevice* vulkanPhysicalDevice);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_PLATFORM_EGL
#define XR_MNDX_egl_enable 1
#define XR_MNDX_egl_enable_SPEC_VERSION 1
#define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable"
// XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo
typedef struct XrGraphicsBindingEGLMNDX {
XrStructureType type;
const void* XR_MAY_ALIAS next;
PFNEGLGETPROCADDRESSPROC getProcAddress;
EGLDisplay display;
EGLConfig config;
EGLContext context;
} XrGraphicsBindingEGLMNDX;
#endif /* XR_USE_PLATFORM_EGL */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_MSFT_perception_anchor_interop 1
#define XR_MSFT_perception_anchor_interop_SPEC_VERSION 1
#define XR_MSFT_PERCEPTION_ANCHOR_INTEROP_EXTENSION_NAME "XR_MSFT_perception_anchor_interop"
typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT)(XrSession session, IUnknown* perceptionAnchor, XrSpatialAnchorMSFT* anchor);
typedef XrResult (XRAPI_PTR *PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT)(XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPerceptionAnchorMSFT(
XrSession session,
IUnknown* perceptionAnchor,
XrSpatialAnchorMSFT* anchor);
XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT(
XrSession session,
XrSpatialAnchorMSFT anchor,
IUnknown** perceptionAnchor);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_MSFT_holographic_window_attachment 1
#define XR_MSFT_holographic_window_attachment_SPEC_VERSION 1
#define XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME "XR_MSFT_holographic_window_attachment"
#ifdef XR_USE_PLATFORM_WIN32
// XrHolographicWindowAttachmentMSFT extends XrSessionCreateInfo
typedef struct XrHolographicWindowAttachmentMSFT {
XrStructureType type;
const void* XR_MAY_ALIAS next;
IUnknown* holographicSpace;
IUnknown* coreWindow;
} XrHolographicWindowAttachmentMSFT;
#endif // XR_USE_PLATFORM_WIN32
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_FB_android_surface_swapchain_create 1
#define XR_FB_android_surface_swapchain_create_SPEC_VERSION 1
#define XR_FB_ANDROID_SURFACE_SWAPCHAIN_CREATE_EXTENSION_NAME "XR_FB_android_surface_swapchain_create"
typedef XrFlags64 XrAndroidSurfaceSwapchainFlagsFB;
// Flag bits for XrAndroidSurfaceSwapchainFlagsFB
static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB = 0x00000001;
static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB = 0x00000002;
#ifdef XR_USE_PLATFORM_ANDROID
// XrAndroidSurfaceSwapchainCreateInfoFB extends XrSwapchainCreateInfo
typedef struct XrAndroidSurfaceSwapchainCreateInfoFB {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrAndroidSurfaceSwapchainFlagsFB createFlags;
} XrAndroidSurfaceSwapchainCreateInfoFB;
#endif // XR_USE_PLATFORM_ANDROID
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_OCULUS_audio_device_guid 1
#define XR_OCULUS_audio_device_guid_SPEC_VERSION 1
#define XR_OCULUS_AUDIO_DEVICE_GUID_EXTENSION_NAME "XR_OCULUS_audio_device_guid"
#define XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS 128
typedef XrResult (XRAPI_PTR *PFN_xrGetAudioOutputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]);
typedef XrResult (XRAPI_PTR *PFN_xrGetAudioInputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioOutputDeviceGuidOculus(
XrInstance instance,
wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]);
XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioInputDeviceGuidOculus(
XrInstance instance,
wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_FB_foveation_vulkan 1
#define XR_FB_foveation_vulkan_SPEC_VERSION 1
#define XR_FB_FOVEATION_VULKAN_EXTENSION_NAME "XR_FB_foveation_vulkan"
// XrSwapchainImageFoveationVulkanFB extends XrSwapchainImageVulkanKHR
typedef struct XrSwapchainImageFoveationVulkanFB {
XrStructureType type;
void* XR_MAY_ALIAS next;
VkImage image;
uint32_t width;
uint32_t height;
} XrSwapchainImageFoveationVulkanFB;
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_FB_swapchain_update_state_android_surface 1
#define XR_FB_swapchain_update_state_android_surface_SPEC_VERSION 1
#define XR_FB_SWAPCHAIN_UPDATE_STATE_ANDROID_SURFACE_EXTENSION_NAME "XR_FB_swapchain_update_state_android_surface"
#ifdef XR_USE_PLATFORM_ANDROID
typedef struct XrSwapchainStateAndroidSurfaceDimensionsFB {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t width;
uint32_t height;
} XrSwapchainStateAndroidSurfaceDimensionsFB;
#endif // XR_USE_PLATFORM_ANDROID
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#define XR_FB_swapchain_update_state_opengl_es 1
#define XR_FB_swapchain_update_state_opengl_es_SPEC_VERSION 1
#define XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME "XR_FB_swapchain_update_state_opengl_es"
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
typedef struct XrSwapchainStateSamplerOpenGLESFB {
XrStructureType type;
void* XR_MAY_ALIAS next;
EGLenum minFilter;
EGLenum magFilter;
EGLenum wrapModeS;
EGLenum wrapModeT;
EGLenum swizzleRed;
EGLenum swizzleGreen;
EGLenum swizzleBlue;
EGLenum swizzleAlpha;
float maxAnisotropy;
XrColor4f borderColor;
} XrSwapchainStateSamplerOpenGLESFB;
#endif // XR_USE_GRAPHICS_API_OPENGL_ES
#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_FB_swapchain_update_state_vulkan 1
#define XR_FB_swapchain_update_state_vulkan_SPEC_VERSION 1
#define XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME "XR_FB_swapchain_update_state_vulkan"
#ifdef XR_USE_GRAPHICS_API_VULKAN
typedef struct XrSwapchainStateSamplerVulkanFB {
XrStructureType type;
void* XR_MAY_ALIAS next;
VkFilter minFilter;
VkFilter magFilter;
VkSamplerMipmapMode mipmapMode;
VkSamplerAddressMode wrapModeS;
VkSamplerAddressMode wrapModeT;
VkComponentSwizzle swizzleRed;
VkComponentSwizzle swizzleGreen;
VkComponentSwizzle swizzleBlue;
VkComponentSwizzle swizzleAlpha;
float maxAnisotropy;
XrColor4f borderColor;
} XrSwapchainStateSamplerVulkanFB;
#endif // XR_USE_GRAPHICS_API_VULKAN
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_META_vulkan_swapchain_create_info 1
#define XR_META_vulkan_swapchain_create_info_SPEC_VERSION 1
#define XR_META_VULKAN_SWAPCHAIN_CREATE_INFO_EXTENSION_NAME "XR_META_vulkan_swapchain_create_info"
// XrVulkanSwapchainCreateInfoMETA extends XrSwapchainCreateInfo
typedef struct XrVulkanSwapchainCreateInfoMETA {
XrStructureType type;
const void* XR_MAY_ALIAS next;
VkImageCreateFlags additionalCreateFlags;
VkImageUsageFlags additionalUsageFlags;
} XrVulkanSwapchainCreateInfoMETA;
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,110 @@
/*
** Copyright (c) 2017-2022, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#ifndef OPENXR_PLATFORM_DEFINES_H_
#define OPENXR_PLATFORM_DEFINES_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/* Platform-specific calling convention macros.
*
* Platforms should define these so that OpenXR clients call OpenXR functions
* with the same calling conventions that the OpenXR implementation expects.
*
* XRAPI_ATTR - Placed before the return type in function declarations.
* Useful for C++11 and GCC/Clang-style function attribute syntax.
* XRAPI_CALL - Placed after the return type in function declarations.
* Useful for MSVC-style calling convention syntax.
* XRAPI_PTR - Placed between the '(' and '*' in function pointer types.
*
* Function declaration: XRAPI_ATTR void XRAPI_CALL xrFunction(void);
* Function pointer type: typedef void (XRAPI_PTR *PFN_xrFunction)(void);
*/
#if defined(_WIN32)
#define XRAPI_ATTR
// On Windows, functions use the stdcall convention
#define XRAPI_CALL __stdcall
#define XRAPI_PTR XRAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
#error "API not supported for the 'armeabi' NDK ABI"
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
// On Android 32-bit ARM targets, functions use the "hardfloat"
// calling convention, i.e. float parameters are passed in registers. This
// is true even if the rest of the application passes floats on the stack,
// as it does by default when compiling for the armeabi-v7a NDK ABI.
#define XRAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define XRAPI_CALL
#define XRAPI_PTR XRAPI_ATTR
#else
// On other platforms, use the default calling convention
#define XRAPI_ATTR
#define XRAPI_CALL
#define XRAPI_PTR
#endif
#include <stddef.h>
#if !defined(XR_NO_STDINT_H)
#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif // !defined( XR_NO_STDINT_H )
// XR_PTR_SIZE (in bytes)
#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__))
#define XR_PTR_SIZE 8
#else
#define XR_PTR_SIZE 4
#endif
// Needed so we can use clang __has_feature portably.
#if !defined(XR_COMPILER_HAS_FEATURE)
#if defined(__clang__)
#define XR_COMPILER_HAS_FEATURE(x) __has_feature(x)
#else
#define XR_COMPILER_HAS_FEATURE(x) 0
#endif
#endif
// Identifies if the current compiler has C++11 support enabled.
// Does not by itself identify if any given C++11 feature is present.
#if !defined(XR_CPP11_ENABLED) && defined(__cplusplus)
#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#define XR_CPP11_ENABLED 1
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
#define XR_CPP11_ENABLED 1
#elif (__cplusplus >= 201103L) // 201103 is the first C++11 version.
#define XR_CPP11_ENABLED 1
#endif
#endif
// Identifies if the current compiler supports C++11 nullptr.
#if !defined(XR_CPP_NULLPTR_SUPPORTED)
#if defined(XR_CPP11_ENABLED) && \
((defined(__clang__) && XR_COMPILER_HAS_FEATURE(cxx_nullptr)) || \
(defined(__GNUC__) && (((__GNUC__ * 1000) + __GNUC_MINOR__) >= 4006)) || \
(defined(_MSC_VER) && (_MSC_VER >= 1600)) || \
(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403)))
#define XR_CPP_NULLPTR_SUPPORTED 1
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,113 @@
#ifndef OPENXR_HELPERS_H_
#define OPENXR_HELPERS_H_
#include <xr_linear.h>
static inline XrTime ToXrTime(const double timeInSeconds) {
return (timeInSeconds * 1e9);
}
static inline double FromXrTime(const XrTime time) {
return (time * 1e-9);
}
static inline XrQuaternionf XrQuaternionf_Identity() {
XrQuaternionf r;
r.x = r.y = r.z = 0.0;
r.w = 1.0f;
return r;
}
static inline XrVector3f XrVector3f_Zero() {
XrVector3f r;
r.x = r.y = r.z = 0.0f;
return r;
}
static inline float XrVector3f_LengthSquared(const XrVector3f v) {
return XrVector3f_Dot(&v, &v);
}
static inline XrVector3f XrVector3f_ScalarMultiply(const XrVector3f v, float scale) {
XrVector3f u;
u.x = v.x * scale;
u.y = v.y * scale;
u.z = v.z * scale;
return u;
}
static inline XrVector3f XrVector3f_Normalized(const XrVector3f v) {
float rcpLen = 1.0f / XrVector3f_Length(&v);
return XrVector3f_ScalarMultiply(v, rcpLen);
}
static inline XrQuaternionf XrQuaternionf_Inverse(const XrQuaternionf q) {
XrQuaternionf r;
r.x = -q.x;
r.y = -q.y;
r.z = -q.z;
r.w = q.w;
return r;
}
static inline XrVector3f XrQuaternionf_Rotate(const XrQuaternionf a, const XrVector3f v) {
XrVector3f r;
XrQuaternionf q = {v.x, v.y, v.z, 0.0f};
XrQuaternionf aq;
XrQuaternionf_Multiply(&aq, &q, &a);
XrQuaternionf aInv = XrQuaternionf_Inverse(a);
XrQuaternionf aqaInv;
XrQuaternionf_Multiply(&aqaInv, &aInv, &aq);
r.x = aqaInv.x;
r.y = aqaInv.y;
r.z = aqaInv.z;
return r;
}
static inline XrQuaternionf XrQuaternionf_CreateFromVectorAngle(
const XrVector3f axis,
const float angle) {
XrQuaternionf r;
if (XrVector3f_LengthSquared(axis) == 0.0f) {
return XrQuaternionf_Identity();
}
XrVector3f unitAxis = XrVector3f_Normalized(axis);
float sinHalfAngle = sinf(angle * 0.5f);
r.w = cosf(angle * 0.5f);
r.x = unitAxis.x * sinHalfAngle;
r.y = unitAxis.y * sinHalfAngle;
r.z = unitAxis.z * sinHalfAngle;
return r;
}
static inline XrPosef XrPosef_Identity() {
XrPosef r;
r.orientation = XrQuaternionf_Identity();
r.position = XrVector3f_Zero();
return r;
}
static inline XrPosef XrPosef_Inverse(const XrPosef a) {
XrPosef b;
b.orientation = XrQuaternionf_Inverse(a.orientation);
b.position = XrQuaternionf_Rotate(b.orientation, XrVector3f_ScalarMultiply(a.position, -1.0f));
return b;
}
static inline XrVector3f XrPosef_Transform(const XrPosef a, const XrVector3f v) {
XrVector3f r0 = XrQuaternionf_Rotate(a.orientation, v);
XrVector3f result;
XrVector3f_Add(&result, &r0, &a.position);
return result;
}
static inline XrPosef XrPosef_Multiply(const XrPosef a, const XrPosef b) {
XrPosef c;
XrQuaternionf_Multiply(&c.orientation, &b.orientation, &a.orientation);
c.position = XrPosef_Transform(a, b.position);
return c;
}
#endif //OPENXR_HELPERS_H_

View file

@ -0,0 +1,787 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2016 Oculus VR, LLC.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: J.M.P. van Waveren
//
#ifndef XR_LINEAR_H_
#define XR_LINEAR_H_
#if defined(OS_LINUX_XCB) || defined(OS_LINUX_XCB_GLX) || defined(OS_LINUX_WAYLAND)
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#include <openxr/openxr.h>
/*
================================================================================================
Description : Vector, matrix and quaternion math.
Author : J.M.P. van Waveren
Date : 12/10/2016
Language : C99
Format : Indent 4 spaces - no tabs.
Copyright : Copyright (c) 2016 Oculus VR, LLC. All Rights reserved.
DESCRIPTION
===========
All matrices are column-major.
INTERFACE
=========
XrVector2f
XrVector3f
XrVector4f
XrQuaternionf
XrMatrix4x4f
inline static void XrVector3f_Set(XrVector3f* v, const float value);
inline static void XrVector3f_Add(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Sub(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Min(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Max(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Decay(XrVector3f* result, const XrVector3f* a, const float value);
inline static void XrVector3f_Lerp(XrVector3f* result, const XrVector3f* a, const XrVector3f* b, const float fraction);
inline static void XrVector3f_Scale(XrVector3f* result, const XrVector3f* a, const float scaleFactor);
inline static void XrVector3f_Normalize(XrVector3f* v);
inline static float XrVector3f_Length(const XrVector3f* v);
inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction);
inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b;
inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result);
inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z);
inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY,
const float degreesZ);
inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z);
inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation,
const XrQuaternionf* rotation, const XrVector3f* scale);
inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, const float tanAngleLeft, const float tanAngleRight,
const float tanAngleUp, float const tanAngleDown, const float nearZ,
const float farZ);
inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, const float fovDegreesLeft, const float fovDegreesRight,
const float fovDegreeUp, const float fovDegreesDown, const float nearZ,
const float farZ);
inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* src);
inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins,
const XrVector3f* maxs);
inline static bool XrMatrix4x4f_IsAffine(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsOrthogonal(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsOrthonormal(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsRigidBody(const XrMatrix4x4f* matrix, const float epsilon);
inline static void XrMatrix4x4f_GetTranslation(XrVector3f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_GetRotation(XrQuaternionf* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_GetScale(XrVector3f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b);
inline static void XrMatrix4x4f_Transpose(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_Invert(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_InvertRigidBody(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_TransformVector3f(XrVector3f* result, const XrMatrix4x4f* m, const XrVector3f* v);
inline static void XrMatrix4x4f_TransformVector4f(XrVector4f* result, const XrMatrix4x4f* m, const XrVector4f* v);
inline static void XrMatrix4x4f_TransformBounds(XrVector3f* resultMins, XrVector3f* resultMaxs, const XrMatrix4x4f* matrix,
const XrVector3f* mins, const XrVector3f* maxs);
inline static bool XrMatrix4x4f_CullBounds(const XrMatrix4x4f* mvp, const XrVector3f* mins, const XrVector3f* maxs);
================================================================================================
*/
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#define MATH_PI 3.14159265358979323846f
#define DEFAULT_NEAR_Z 0.015625f // exact floating point representation
#define INFINITE_FAR_Z 0.0f
static const XrColor4f XrColorRed = {1.0f, 0.0f, 0.0f, 1.0f};
static const XrColor4f XrColorGreen = {0.0f, 1.0f, 0.0f, 1.0f};
static const XrColor4f XrColorBlue = {0.0f, 0.0f, 1.0f, 1.0f};
static const XrColor4f XrColorYellow = {1.0f, 1.0f, 0.0f, 1.0f};
static const XrColor4f XrColorPurple = {1.0f, 0.0f, 1.0f, 1.0f};
static const XrColor4f XrColorCyan = {0.0f, 1.0f, 1.0f, 1.0f};
static const XrColor4f XrColorLightGrey = {0.7f, 0.7f, 0.7f, 1.0f};
static const XrColor4f XrColorDarkGrey = {0.3f, 0.3f, 0.3f, 1.0f};
typedef enum GraphicsAPI { GRAPHICS_VULKAN, GRAPHICS_OPENGL, GRAPHICS_OPENGL_ES, GRAPHICS_D3D } GraphicsAPI;
// Column-major, pre-multiplied. This type does not exist in the OpenXR API and is provided for convenience.
typedef struct XrMatrix4x4f {
float m[16];
} XrMatrix4x4f;
inline static float XrRcpSqrt(const float x) {
const float SMALLEST_NON_DENORMAL = 1.1754943508222875e-038f; // ( 1U << 23 )
const float rcp = (x >= SMALLEST_NON_DENORMAL) ? 1.0f / sqrtf(x) : 1.0f;
return rcp;
}
inline static void XrVector3f_Set(XrVector3f* v, const float value) {
v->x = value;
v->y = value;
v->z = value;
}
inline static void XrVector3f_Add(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->x + b->x;
result->y = a->y + b->y;
result->z = a->z + b->z;
}
inline static void XrVector3f_Sub(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->x - b->x;
result->y = a->y - b->y;
result->z = a->z - b->z;
}
inline static void XrVector3f_Min(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = (a->x < b->x) ? a->x : b->x;
result->y = (a->y < b->y) ? a->y : b->y;
result->z = (a->z < b->z) ? a->z : b->z;
}
inline static void XrVector3f_Max(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = (a->x > b->x) ? a->x : b->x;
result->y = (a->y > b->y) ? a->y : b->y;
result->z = (a->z > b->z) ? a->z : b->z;
}
inline static void XrVector3f_Decay(XrVector3f* result, const XrVector3f* a, const float value) {
result->x = (fabsf(a->x) > value) ? ((a->x > 0.0f) ? (a->x - value) : (a->x + value)) : 0.0f;
result->y = (fabsf(a->y) > value) ? ((a->y > 0.0f) ? (a->y - value) : (a->y + value)) : 0.0f;
result->z = (fabsf(a->z) > value) ? ((a->z > 0.0f) ? (a->z - value) : (a->z + value)) : 0.0f;
}
inline static void XrVector3f_Lerp(XrVector3f* result, const XrVector3f* a, const XrVector3f* b, const float fraction) {
result->x = a->x + fraction * (b->x - a->x);
result->y = a->y + fraction * (b->y - a->y);
result->z = a->z + fraction * (b->z - a->z);
}
inline static void XrVector3f_Scale(XrVector3f* result, const XrVector3f* a, const float scaleFactor) {
result->x = a->x * scaleFactor;
result->y = a->y * scaleFactor;
result->z = a->z * scaleFactor;
}
inline static float XrVector3f_Dot(const XrVector3f* a, const XrVector3f* b) { return a->x * b->x + a->y * b->y + a->z * b->z; }
// Compute cross product, which generates a normal vector.
// Direction vector can be determined by right-hand rule: Pointing index finder in
// direction a and middle finger in direction b, thumb will point in Cross(a, b).
inline static void XrVector3f_Cross(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->y * b->z - a->z * b->y;
result->y = a->z * b->x - a->x * b->z;
result->z = a->x * b->y - a->y * b->x;
}
inline static void XrVector3f_Normalize(XrVector3f* v) {
const float lengthRcp = XrRcpSqrt(v->x * v->x + v->y * v->y + v->z * v->z);
v->x *= lengthRcp;
v->y *= lengthRcp;
v->z *= lengthRcp;
}
inline static float XrVector3f_Length(const XrVector3f* v) { return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); }
inline static void XrQuaternionf_CreateFromAxisAngle(XrQuaternionf* result, const XrVector3f* axis, const float angleInRadians) {
float s = sinf(angleInRadians / 2.0f);
float lengthRcp = XrRcpSqrt(axis->x * axis->x + axis->y * axis->y + axis->z * axis->z);
result->x = s * axis->x * lengthRcp;
result->y = s * axis->y * lengthRcp;
result->z = s * axis->z * lengthRcp;
result->w = cosf(angleInRadians / 2.0f);
}
inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction) {
const float s = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
const float fa = 1.0f - fraction;
const float fb = (s < 0.0f) ? -fraction : fraction;
const float x = a->x * fa + b->x * fb;
const float y = a->y * fa + b->y * fb;
const float z = a->z * fa + b->z * fb;
const float w = a->w * fa + b->w * fb;
const float lengthRcp = XrRcpSqrt(x * x + y * y + z * z + w * w);
result->x = x * lengthRcp;
result->y = y * lengthRcp;
result->z = z * lengthRcp;
result->w = w * lengthRcp;
}
inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b) {
result->x = (b->w * a->x) + (b->x * a->w) + (b->y * a->z) - (b->z * a->y);
result->y = (b->w * a->y) - (b->x * a->z) + (b->y * a->w) + (b->z * a->x);
result->z = (b->w * a->z) + (b->x * a->y) - (b->y * a->x) + (b->z * a->w);
result->w = (b->w * a->w) - (b->x * a->x) - (b->y * a->y) - (b->z * a->z);
}
// Use left-multiplication to accumulate transformations.
inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b) {
result->m[0] = a->m[0] * b->m[0] + a->m[4] * b->m[1] + a->m[8] * b->m[2] + a->m[12] * b->m[3];
result->m[1] = a->m[1] * b->m[0] + a->m[5] * b->m[1] + a->m[9] * b->m[2] + a->m[13] * b->m[3];
result->m[2] = a->m[2] * b->m[0] + a->m[6] * b->m[1] + a->m[10] * b->m[2] + a->m[14] * b->m[3];
result->m[3] = a->m[3] * b->m[0] + a->m[7] * b->m[1] + a->m[11] * b->m[2] + a->m[15] * b->m[3];
result->m[4] = a->m[0] * b->m[4] + a->m[4] * b->m[5] + a->m[8] * b->m[6] + a->m[12] * b->m[7];
result->m[5] = a->m[1] * b->m[4] + a->m[5] * b->m[5] + a->m[9] * b->m[6] + a->m[13] * b->m[7];
result->m[6] = a->m[2] * b->m[4] + a->m[6] * b->m[5] + a->m[10] * b->m[6] + a->m[14] * b->m[7];
result->m[7] = a->m[3] * b->m[4] + a->m[7] * b->m[5] + a->m[11] * b->m[6] + a->m[15] * b->m[7];
result->m[8] = a->m[0] * b->m[8] + a->m[4] * b->m[9] + a->m[8] * b->m[10] + a->m[12] * b->m[11];
result->m[9] = a->m[1] * b->m[8] + a->m[5] * b->m[9] + a->m[9] * b->m[10] + a->m[13] * b->m[11];
result->m[10] = a->m[2] * b->m[8] + a->m[6] * b->m[9] + a->m[10] * b->m[10] + a->m[14] * b->m[11];
result->m[11] = a->m[3] * b->m[8] + a->m[7] * b->m[9] + a->m[11] * b->m[10] + a->m[15] * b->m[11];
result->m[12] = a->m[0] * b->m[12] + a->m[4] * b->m[13] + a->m[8] * b->m[14] + a->m[12] * b->m[15];
result->m[13] = a->m[1] * b->m[12] + a->m[5] * b->m[13] + a->m[9] * b->m[14] + a->m[13] * b->m[15];
result->m[14] = a->m[2] * b->m[12] + a->m[6] * b->m[13] + a->m[10] * b->m[14] + a->m[14] * b->m[15];
result->m[15] = a->m[3] * b->m[12] + a->m[7] * b->m[13] + a->m[11] * b->m[14] + a->m[15] * b->m[15];
}
// Creates the transpose of the given matrix.
inline static void XrMatrix4x4f_Transpose(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
result->m[0] = src->m[0];
result->m[1] = src->m[4];
result->m[2] = src->m[8];
result->m[3] = src->m[12];
result->m[4] = src->m[1];
result->m[5] = src->m[5];
result->m[6] = src->m[9];
result->m[7] = src->m[13];
result->m[8] = src->m[2];
result->m[9] = src->m[6];
result->m[10] = src->m[10];
result->m[11] = src->m[14];
result->m[12] = src->m[3];
result->m[13] = src->m[7];
result->m[14] = src->m[11];
result->m[15] = src->m[15];
}
// Returns a 3x3 minor of a 4x4 matrix.
inline static float XrMatrix4x4f_Minor(const XrMatrix4x4f* matrix, int r0, int r1, int r2, int c0, int c1, int c2) {
return matrix->m[4 * r0 + c0] *
(matrix->m[4 * r1 + c1] * matrix->m[4 * r2 + c2] - matrix->m[4 * r2 + c1] * matrix->m[4 * r1 + c2]) -
matrix->m[4 * r0 + c1] *
(matrix->m[4 * r1 + c0] * matrix->m[4 * r2 + c2] - matrix->m[4 * r2 + c0] * matrix->m[4 * r1 + c2]) +
matrix->m[4 * r0 + c2] *
(matrix->m[4 * r1 + c0] * matrix->m[4 * r2 + c1] - matrix->m[4 * r2 + c0] * matrix->m[4 * r1 + c1]);
}
// Calculates the inverse of a 4x4 matrix.
inline static void XrMatrix4x4f_Invert(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
const float rcpDet =
1.0f / (src->m[0] * XrMatrix4x4f_Minor(src, 1, 2, 3, 1, 2, 3) - src->m[1] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 2, 3) +
src->m[2] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 3) - src->m[3] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 2));
result->m[0] = XrMatrix4x4f_Minor(src, 1, 2, 3, 1, 2, 3) * rcpDet;
result->m[1] = -XrMatrix4x4f_Minor(src, 0, 2, 3, 1, 2, 3) * rcpDet;
result->m[2] = XrMatrix4x4f_Minor(src, 0, 1, 3, 1, 2, 3) * rcpDet;
result->m[3] = -XrMatrix4x4f_Minor(src, 0, 1, 2, 1, 2, 3) * rcpDet;
result->m[4] = -XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 2, 3) * rcpDet;
result->m[5] = XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 2, 3) * rcpDet;
result->m[6] = -XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 2, 3) * rcpDet;
result->m[7] = XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 2, 3) * rcpDet;
result->m[8] = XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 3) * rcpDet;
result->m[9] = -XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 1, 3) * rcpDet;
result->m[10] = XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 1, 3) * rcpDet;
result->m[11] = -XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 1, 3) * rcpDet;
result->m[12] = -XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 2) * rcpDet;
result->m[13] = XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 1, 2) * rcpDet;
result->m[14] = -XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 1, 2) * rcpDet;
result->m[15] = XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 1, 2) * rcpDet;
}
// Calculates the inverse of a rigid body transform.
inline static void XrMatrix4x4f_InvertRigidBody(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
result->m[0] = src->m[0];
result->m[1] = src->m[4];
result->m[2] = src->m[8];
result->m[3] = 0.0f;
result->m[4] = src->m[1];
result->m[5] = src->m[5];
result->m[6] = src->m[9];
result->m[7] = 0.0f;
result->m[8] = src->m[2];
result->m[9] = src->m[6];
result->m[10] = src->m[10];
result->m[11] = 0.0f;
result->m[12] = -(src->m[0] * src->m[12] + src->m[1] * src->m[13] + src->m[2] * src->m[14]);
result->m[13] = -(src->m[4] * src->m[12] + src->m[5] * src->m[13] + src->m[6] * src->m[14]);
result->m[14] = -(src->m[8] * src->m[12] + src->m[9] * src->m[13] + src->m[10] * src->m[14]);
result->m[15] = 1.0f;
}
// Creates an identity matrix.
inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result) {
result->m[0] = 1.0f;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = 1.0f;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = 1.0f;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a translation matrix.
inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z) {
result->m[0] = 1.0f;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = 1.0f;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = 1.0f;
result->m[11] = 0.0f;
result->m[12] = x;
result->m[13] = y;
result->m[14] = z;
result->m[15] = 1.0f;
}
// Creates a rotation matrix.
// If -Z=forward, +Y=up, +X=right, then degreesX=pitch, degreesY=yaw, degreesZ=roll.
inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY,
const float degreesZ) {
const float sinX = sinf(degreesX * (MATH_PI / 180.0f));
const float cosX = cosf(degreesX * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationX = {{1, 0, 0, 0, 0, cosX, sinX, 0, 0, -sinX, cosX, 0, 0, 0, 0, 1}};
const float sinY = sinf(degreesY * (MATH_PI / 180.0f));
const float cosY = cosf(degreesY * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationY = {{cosY, 0, -sinY, 0, 0, 1, 0, 0, sinY, 0, cosY, 0, 0, 0, 0, 1}};
const float sinZ = sinf(degreesZ * (MATH_PI / 180.0f));
const float cosZ = cosf(degreesZ * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationZ = {{cosZ, sinZ, 0, 0, -sinZ, cosZ, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}};
XrMatrix4x4f rotationXY;
XrMatrix4x4f_Multiply(&rotationXY, &rotationY, &rotationX);
XrMatrix4x4f_Multiply(result, &rotationZ, &rotationXY);
}
// Creates a scale matrix.
inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z) {
result->m[0] = x;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = y;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = z;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a matrix from a quaternion.
inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* quat) {
const float x2 = quat->x + quat->x;
const float y2 = quat->y + quat->y;
const float z2 = quat->z + quat->z;
const float xx2 = quat->x * x2;
const float yy2 = quat->y * y2;
const float zz2 = quat->z * z2;
const float yz2 = quat->y * z2;
const float wx2 = quat->w * x2;
const float xy2 = quat->x * y2;
const float wz2 = quat->w * z2;
const float xz2 = quat->x * z2;
const float wy2 = quat->w * y2;
result->m[0] = 1.0f - yy2 - zz2;
result->m[1] = xy2 + wz2;
result->m[2] = xz2 - wy2;
result->m[3] = 0.0f;
result->m[4] = xy2 - wz2;
result->m[5] = 1.0f - xx2 - zz2;
result->m[6] = yz2 + wx2;
result->m[7] = 0.0f;
result->m[8] = xz2 + wy2;
result->m[9] = yz2 - wx2;
result->m[10] = 1.0f - xx2 - yy2;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation,
const XrQuaternionf* rotation, const XrVector3f* scale) {
XrMatrix4x4f scaleMatrix;
XrMatrix4x4f_CreateScale(&scaleMatrix, scale->x, scale->y, scale->z);
XrMatrix4x4f rotationMatrix;
XrMatrix4x4f_CreateFromQuaternion(&rotationMatrix, rotation);
XrMatrix4x4f translationMatrix;
XrMatrix4x4f_CreateTranslation(&translationMatrix, translation->x, translation->y, translation->z);
XrMatrix4x4f combinedMatrix;
XrMatrix4x4f_Multiply(&combinedMatrix, &rotationMatrix, &scaleMatrix);
XrMatrix4x4f_Multiply(result, &translationMatrix, &combinedMatrix);
}
// Creates a projection matrix based on the specified dimensions.
// The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API.
// The far plane is placed at infinity if farZ <= nearZ.
// An infinite projection matrix is preferred for rasterization because, except for
// things *right* up against the near plane, it always provides better precision:
// "Tightening the Precision of Perspective Rendering"
// Paul Upchurch, Mathieu Desbrun
// Journal of Graphics Tools, Volume 16, Issue 1, 2012
inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const float tanAngleLeft,
const float tanAngleRight, const float tanAngleUp, float const tanAngleDown,
const float nearZ, const float farZ) {
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 = graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (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 = (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0;
if (farZ <= nearZ) {
// place the far plane at infinity
result->m[0] = 2.0f / tanAngleWidth;
result->m[4] = 0.0f;
result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
result->m[12] = 0.0f;
result->m[1] = 0.0f;
result->m[5] = 2.0f / tanAngleHeight;
result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
result->m[13] = 0.0f;
result->m[2] = 0.0f;
result->m[6] = 0.0f;
result->m[10] = -1.0f;
result->m[14] = -(nearZ + offsetZ);
result->m[3] = 0.0f;
result->m[7] = 0.0f;
result->m[11] = -1.0f;
result->m[15] = 0.0f;
} else {
// normal projection
result->m[0] = 2.0f / tanAngleWidth;
result->m[4] = 0.0f;
result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
result->m[12] = 0.0f;
result->m[1] = 0.0f;
result->m[5] = 2.0f / tanAngleHeight;
result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
result->m[13] = 0.0f;
result->m[2] = 0.0f;
result->m[6] = 0.0f;
result->m[10] = -(farZ + offsetZ) / (farZ - nearZ);
result->m[14] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ);
result->m[3] = 0.0f;
result->m[7] = 0.0f;
result->m[11] = -1.0f;
result->m[15] = 0.0f;
}
}
// Creates a projection matrix based on the specified FOV.
inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const XrFovf fov,
const float nearZ, const float farZ) {
const float tanLeft = tanf(fov.angleLeft);
const float tanRight = tanf(fov.angleRight);
const float tanDown = tanf(fov.angleDown);
const float tanUp = tanf(fov.angleUp);
XrMatrix4x4f_CreateProjection(result, graphicsApi, tanLeft, tanRight, tanUp, tanDown, nearZ, farZ);
}
// Creates a matrix that transforms the -1 to 1 cube to cover the given 'mins' and 'maxs' transformed with the given 'matrix'.
inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins,
const XrVector3f* maxs) {
const XrVector3f offset = {(maxs->x + mins->x) * 0.5f, (maxs->y + mins->y) * 0.5f, (maxs->z + mins->z) * 0.5f};
const XrVector3f scale = {(maxs->x - mins->x) * 0.5f, (maxs->y - mins->y) * 0.5f, (maxs->z - mins->z) * 0.5f};
result->m[0] = matrix->m[0] * scale.x;
result->m[1] = matrix->m[1] * scale.x;
result->m[2] = matrix->m[2] * scale.x;
result->m[3] = matrix->m[3] * scale.x;
result->m[4] = matrix->m[4] * scale.y;
result->m[5] = matrix->m[5] * scale.y;
result->m[6] = matrix->m[6] * scale.y;
result->m[7] = matrix->m[7] * scale.y;
result->m[8] = matrix->m[8] * scale.z;
result->m[9] = matrix->m[9] * scale.z;
result->m[10] = matrix->m[10] * scale.z;
result->m[11] = matrix->m[11] * scale.z;
result->m[12] = matrix->m[12] + matrix->m[0] * offset.x + matrix->m[4] * offset.y + matrix->m[8] * offset.z;
result->m[13] = matrix->m[13] + matrix->m[1] * offset.x + matrix->m[5] * offset.y + matrix->m[9] * offset.z;
result->m[14] = matrix->m[14] + matrix->m[2] * offset.x + matrix->m[6] * offset.y + matrix->m[10] * offset.z;
result->m[15] = matrix->m[15] + matrix->m[3] * offset.x + matrix->m[7] * offset.y + matrix->m[11] * offset.z;
}
// Returns true if the given matrix is affine.
inline static bool XrMatrix4x4f_IsAffine(const XrMatrix4x4f* matrix, const float epsilon) {
return fabsf(matrix->m[3]) <= epsilon && fabsf(matrix->m[7]) <= epsilon && fabsf(matrix->m[11]) <= epsilon &&
fabsf(matrix->m[15] - 1.0f) <= epsilon;
}
// Returns true if the given matrix is orthogonal.
inline static bool XrMatrix4x4f_IsOrthogonal(const XrMatrix4x4f* matrix, const float epsilon) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i != j) {
if (fabsf(matrix->m[4 * i + 0] * matrix->m[4 * j + 0] + matrix->m[4 * i + 1] * matrix->m[4 * j + 1] +
matrix->m[4 * i + 2] * matrix->m[4 * j + 2]) > epsilon) {
return false;
}
if (fabsf(matrix->m[4 * 0 + i] * matrix->m[4 * 0 + j] + matrix->m[4 * 1 + i] * matrix->m[4 * 1 + j] +
matrix->m[4 * 2 + i] * matrix->m[4 * 2 + j]) > epsilon) {
return false;
}
}
}
}
return true;
}
// Returns true if the given matrix is orthonormal.
inline static bool XrMatrix4x4f_IsOrthonormal(const XrMatrix4x4f* matrix, const float epsilon) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
const float kd = (i == j) ? 1.0f : 0.0f; // Kronecker delta
if (fabsf(kd - (matrix->m[4 * i + 0] * matrix->m[4 * j + 0] + matrix->m[4 * i + 1] * matrix->m[4 * j + 1] +
matrix->m[4 * i + 2] * matrix->m[4 * j + 2])) > epsilon) {
return false;
}
if (fabsf(kd - (matrix->m[4 * 0 + i] * matrix->m[4 * 0 + j] + matrix->m[4 * 1 + i] * matrix->m[4 * 1 + j] +
matrix->m[4 * 2 + i] * matrix->m[4 * 2 + j])) > epsilon) {
return false;
}
}
}
return true;
}
// Returns true if the given matrix is a rigid body transform.
inline static bool XrMatrix4x4f_IsRigidBody(const XrMatrix4x4f* matrix, const float epsilon) {
return XrMatrix4x4f_IsAffine(matrix, epsilon) && XrMatrix4x4f_IsOrthonormal(matrix, epsilon);
}
// Get the translation from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetTranslation(XrVector3f* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
result->x = src->m[12];
result->y = src->m[13];
result->z = src->m[14];
}
// Get the rotation from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetRotation(XrQuaternionf* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
const float rcpScaleX = XrRcpSqrt(src->m[0] * src->m[0] + src->m[1] * src->m[1] + src->m[2] * src->m[2]);
const float rcpScaleY = XrRcpSqrt(src->m[4] * src->m[4] + src->m[5] * src->m[5] + src->m[6] * src->m[6]);
const float rcpScaleZ = XrRcpSqrt(src->m[8] * src->m[8] + src->m[9] * src->m[9] + src->m[10] * src->m[10]);
const float m[9] = {src->m[0] * rcpScaleX, src->m[1] * rcpScaleX, src->m[2] * rcpScaleX,
src->m[4] * rcpScaleY, src->m[5] * rcpScaleY, src->m[6] * rcpScaleY,
src->m[8] * rcpScaleZ, src->m[9] * rcpScaleZ, src->m[10] * rcpScaleZ};
if (m[0 * 3 + 0] + m[1 * 3 + 1] + m[2 * 3 + 2] > 0.0f) {
float t = +m[0 * 3 + 0] + m[1 * 3 + 1] + m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->w = s * t;
result->z = (m[0 * 3 + 1] - m[1 * 3 + 0]) * s;
result->y = (m[2 * 3 + 0] - m[0 * 3 + 2]) * s;
result->x = (m[1 * 3 + 2] - m[2 * 3 + 1]) * s;
} else if (m[0 * 3 + 0] > m[1 * 3 + 1] && m[0 * 3 + 0] > m[2 * 3 + 2]) {
float t = +m[0 * 3 + 0] - m[1 * 3 + 1] - m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->x = s * t;
result->y = (m[0 * 3 + 1] + m[1 * 3 + 0]) * s;
result->z = (m[2 * 3 + 0] + m[0 * 3 + 2]) * s;
result->w = (m[1 * 3 + 2] - m[2 * 3 + 1]) * s;
} else if (m[1 * 3 + 1] > m[2 * 3 + 2]) {
float t = -m[0 * 3 + 0] + m[1 * 3 + 1] - m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->y = s * t;
result->x = (m[0 * 3 + 1] + m[1 * 3 + 0]) * s;
result->w = (m[2 * 3 + 0] - m[0 * 3 + 2]) * s;
result->z = (m[1 * 3 + 2] + m[2 * 3 + 1]) * s;
} else {
float t = -m[0 * 3 + 0] - m[1 * 3 + 1] + m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->z = s * t;
result->w = (m[0 * 3 + 1] - m[1 * 3 + 0]) * s;
result->x = (m[2 * 3 + 0] + m[0 * 3 + 2]) * s;
result->y = (m[1 * 3 + 2] + m[2 * 3 + 1]) * s;
}
}
// Get the scale from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetScale(XrVector3f* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
result->x = sqrtf(src->m[0] * src->m[0] + src->m[1] * src->m[1] + src->m[2] * src->m[2]);
result->y = sqrtf(src->m[4] * src->m[4] + src->m[5] * src->m[5] + src->m[6] * src->m[6]);
result->z = sqrtf(src->m[8] * src->m[8] + src->m[9] * src->m[9] + src->m[10] * src->m[10]);
}
// Transforms a 3D vector.
inline static void XrMatrix4x4f_TransformVector3f(XrVector3f* result, const XrMatrix4x4f* m, const XrVector3f* v) {
const float w = m->m[3] * v->x + m->m[7] * v->y + m->m[11] * v->z + m->m[15];
const float rcpW = 1.0f / w;
result->x = (m->m[0] * v->x + m->m[4] * v->y + m->m[8] * v->z + m->m[12]) * rcpW;
result->y = (m->m[1] * v->x + m->m[5] * v->y + m->m[9] * v->z + m->m[13]) * rcpW;
result->z = (m->m[2] * v->x + m->m[6] * v->y + m->m[10] * v->z + m->m[14]) * rcpW;
}
// Transforms a 4D vector.
inline static void XrMatrix4x4f_TransformVector4f(XrVector4f* result, const XrMatrix4x4f* m, const XrVector4f* v) {
result->x = m->m[0] * v->x + m->m[4] * v->y + m->m[8] * v->z + m->m[12] * v->w;
result->y = m->m[1] * v->x + m->m[5] * v->y + m->m[9] * v->z + m->m[13] * v->w;
result->z = m->m[2] * v->x + m->m[6] * v->y + m->m[10] * v->z + m->m[14] * v->w;
result->w = m->m[3] * v->x + m->m[7] * v->y + m->m[11] * v->z + m->m[15] * v->w;
}
// Transforms the 'mins' and 'maxs' bounds with the given 'matrix'.
inline static void XrMatrix4x4f_TransformBounds(XrVector3f* resultMins, XrVector3f* resultMaxs, const XrMatrix4x4f* matrix,
const XrVector3f* mins, const XrVector3f* maxs) {
assert(XrMatrix4x4f_IsAffine(matrix, 1e-4f));
const XrVector3f center = {(mins->x + maxs->x) * 0.5f, (mins->y + maxs->y) * 0.5f, (mins->z + maxs->z) * 0.5f};
const XrVector3f extents = {maxs->x - center.x, maxs->y - center.y, maxs->z - center.z};
const XrVector3f newCenter = {matrix->m[0] * center.x + matrix->m[4] * center.y + matrix->m[8] * center.z + matrix->m[12],
matrix->m[1] * center.x + matrix->m[5] * center.y + matrix->m[9] * center.z + matrix->m[13],
matrix->m[2] * center.x + matrix->m[6] * center.y + matrix->m[10] * center.z + matrix->m[14]};
const XrVector3f newExtents = {
fabsf(extents.x * matrix->m[0]) + fabsf(extents.y * matrix->m[4]) + fabsf(extents.z * matrix->m[8]),
fabsf(extents.x * matrix->m[1]) + fabsf(extents.y * matrix->m[5]) + fabsf(extents.z * matrix->m[9]),
fabsf(extents.x * matrix->m[2]) + fabsf(extents.y * matrix->m[6]) + fabsf(extents.z * matrix->m[10])};
XrVector3f_Sub(resultMins, &newCenter, &newExtents);
XrVector3f_Add(resultMaxs, &newCenter, &newExtents);
}
// Returns true if the 'mins' and 'maxs' bounds is completely off to one side of the projection matrix.
inline static bool XrMatrix4x4f_CullBounds(const XrMatrix4x4f* mvp, const XrVector3f* mins, const XrVector3f* maxs) {
if (maxs->x <= mins->x && maxs->y <= mins->y && maxs->z <= mins->z) {
return false;
}
XrVector4f c[8];
for (int i = 0; i < 8; i++) {
const XrVector4f corner = {(i & 1) != 0 ? maxs->x : mins->x, (i & 2) != 0 ? maxs->y : mins->y,
(i & 4) != 0 ? maxs->z : mins->z, 1.0f};
XrMatrix4x4f_TransformVector4f(&c[i], mvp, &corner);
}
int i;
for (i = 0; i < 8; i++) {
if (c[i].x > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].x < c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].y > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].y < c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].z > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].z < c[i].w) {
break;
}
}
return i == 8;
}
#endif // XR_LINEAR_H_

View file

@ -0,0 +1,569 @@
#include "VrInput.h"
extern ovrApp gAppState;
XrResult CheckXrResult(XrResult res, const char* originator) {
if (XR_FAILED(res)) {
ALOGE("error: %s", originator);
}
return res;
}
#define CHECK_XRCMD(cmd) CheckXrResult(cmd, #cmd);
#define SIDE_LEFT 0
#define SIDE_RIGHT 1
#define SIDE_COUNT 2
XrActionSet actionSet = nullptr;
XrAction grabAction;
XrAction poseAction;
XrAction vibrateAction;
XrAction quitAction;
XrAction touchpadAction;
XrAction AXAction;
XrAction homeAction;
XrAction BYAction;
XrAction backAction;
XrAction sideAction;
XrAction triggerAction;
XrAction joystickAction;
XrAction batteryAction;
XrAction AXTouchAction;
XrAction BYTouchAction;
XrAction thumbstickTouchAction;
XrAction TriggerTouchAction;
XrAction ThumbrestTouchAction;
XrAction GripAction;
XrAction AAction;
XrAction BAction;
XrAction XAction;
XrAction YAction;
XrAction ATouchAction;
XrAction BTouchAction;
XrAction XTouchAction;
XrAction YTouchAction;
XrAction aimAction;
XrSpace aimSpace[SIDE_COUNT];
XrPath handSubactionPath[SIDE_COUNT];
XrSpace handSpace[SIDE_COUNT];
XrActionSuggestedBinding ActionSuggestedBinding(XrAction action, XrPath path) {
XrActionSuggestedBinding asb;
asb.action = action;
asb.binding = path;
return asb;
}
XrActionStateBoolean GetActionStateBoolean(XrAction action, int hand) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.next = NULL;
if (hand >= 0)
getInfo.subactionPath = handSubactionPath[hand];
XrActionStateBoolean state = {};
state.type = XR_TYPE_ACTION_STATE_BOOLEAN;
state.next = NULL;
CHECK_XRCMD(xrGetActionStateBoolean(gAppState.Session, &getInfo, &state));
return state;
}
XrActionStateFloat GetActionStateFloat(XrAction action, int hand) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.next = NULL;
if (hand >= 0)
getInfo.subactionPath = handSubactionPath[hand];
XrActionStateFloat state = {};
state.type = XR_TYPE_ACTION_STATE_FLOAT;
state.next = NULL;
CHECK_XRCMD(xrGetActionStateFloat(gAppState.Session, &getInfo, &state));
return state;
}
XrActionStateVector2f GetActionStateVector2(XrAction action, int hand) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.next = NULL;
if (hand >= 0)
getInfo.subactionPath = handSubactionPath[hand];
XrActionStateVector2f state = {};
state.type = XR_TYPE_ACTION_STATE_VECTOR2F;
state.next = NULL;
CHECK_XRCMD(xrGetActionStateVector2f(gAppState.Session, &getInfo, &state));
return state;
}
void CreateAction(
XrActionSet actionSet,
XrActionType type,
const char* actionName,
const char* localizedName,
int countSubactionPaths,
XrPath* subactionPaths,
XrAction* action) {
ALOGV("CreateAction %s, %", actionName, countSubactionPaths);
XrActionCreateInfo aci = {};
aci.type = XR_TYPE_ACTION_CREATE_INFO;
aci.next = NULL;
aci.actionType = type;
if (countSubactionPaths > 0) {
aci.countSubactionPaths = countSubactionPaths;
aci.subactionPaths = subactionPaths;
}
strcpy(aci.actionName, actionName);
strcpy(aci.localizedActionName, localizedName ? localizedName : actionName);
*action = XR_NULL_HANDLE;
OXR(xrCreateAction(actionSet, &aci, action));
}
void TBXR_InitActions( void )
{
// Create an action set.
{
XrActionSetCreateInfo actionSetInfo = {};
actionSetInfo.type = XR_TYPE_ACTION_SET_CREATE_INFO;
strcpy(actionSetInfo.actionSetName, "gameplay");
strcpy(actionSetInfo.localizedActionSetName, "Gameplay");
actionSetInfo.priority = 0;
actionSetInfo.next = NULL;
CHECK_XRCMD(xrCreateActionSet(gAppState.Instance, &actionSetInfo, &actionSet));
}
// Get the XrPath for the left and right hands - we will use them as subaction paths.
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left", &handSubactionPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right", &handSubactionPath[SIDE_RIGHT]));
// Create actions.
{
// Create an input action for grabbing objects with the left and right hands.
CreateAction(actionSet, XR_ACTION_TYPE_POSE_INPUT, "grab_object", "Grab Object", SIDE_COUNT, handSubactionPath, &grabAction);
// Create an input action getting the left and right hand poses.
CreateAction(actionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose", "Hand Pose", SIDE_COUNT, handSubactionPath, &poseAction);
CreateAction(actionSet, XR_ACTION_TYPE_POSE_INPUT, "aim_pose", "Aim Pose", SIDE_COUNT, handSubactionPath, &aimAction);
// Create output actions for vibrating the left and right controller.
CreateAction(actionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_hand", "Vibrate Hand", SIDE_COUNT, handSubactionPath, &vibrateAction);
//All remaining actions (not necessarily supported by all controllers)
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "quit_session", "Quit Session", SIDE_COUNT, handSubactionPath, &quitAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "touchpad", "Touchpad", SIDE_COUNT, handSubactionPath, &touchpadAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "axkey", "AXkey", SIDE_COUNT, handSubactionPath, &AXAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "homekey", "Homekey", SIDE_COUNT, handSubactionPath, &homeAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "bykey", "BYkey", SIDE_COUNT, handSubactionPath, &BYAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "backkey", "Backkey", SIDE_COUNT, handSubactionPath, &backAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "sidekey", "Sidekey", SIDE_COUNT, handSubactionPath, &sideAction);
CreateAction(actionSet, XR_ACTION_TYPE_FLOAT_INPUT, "trigger", "Trigger", SIDE_COUNT, handSubactionPath, &triggerAction);
CreateAction(actionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "joystick", "Joystick", SIDE_COUNT, handSubactionPath, &joystickAction);
CreateAction(actionSet, XR_ACTION_TYPE_FLOAT_INPUT, "battery", "battery", SIDE_COUNT, handSubactionPath, &batteryAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "axtouch", "AXtouch", SIDE_COUNT, handSubactionPath, &AXTouchAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "bytouch", "BYtouch", SIDE_COUNT, handSubactionPath, &BYTouchAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "rockertouch", "Rockertouch", SIDE_COUNT, handSubactionPath, &thumbstickTouchAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "triggertouch", "Triggertouch", SIDE_COUNT, handSubactionPath, &TriggerTouchAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbresttouch", "Thumbresttouch", SIDE_COUNT, handSubactionPath, &ThumbrestTouchAction);
CreateAction(actionSet, XR_ACTION_TYPE_FLOAT_INPUT, "gripvalue", "GripValue", SIDE_COUNT, handSubactionPath, &GripAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "akey", "Akey", SIDE_COUNT, handSubactionPath, &AAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "bkey", "Bkey", SIDE_COUNT, handSubactionPath, &BAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "xkey", "Xkey", SIDE_COUNT, handSubactionPath, &XAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "ykey", "Ykey", SIDE_COUNT, handSubactionPath, &YAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "atouch", "Atouch", SIDE_COUNT, handSubactionPath, &ATouchAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "btouch", "Btouch", SIDE_COUNT, handSubactionPath, &BTouchAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "xtouch", "Xtouch", SIDE_COUNT, handSubactionPath, &XTouchAction);
CreateAction(actionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "ytouch", "Ytouch", SIDE_COUNT, handSubactionPath, &YTouchAction);
}
XrPath selectPath[SIDE_COUNT];
XrPath squeezeValuePath[SIDE_COUNT];
XrPath squeezeClickPath[SIDE_COUNT];
XrPath posePath[SIDE_COUNT];
XrPath hapticPath[SIDE_COUNT];
XrPath menuClickPath[SIDE_COUNT];
XrPath systemPath[SIDE_COUNT];
XrPath thumbrestPath[SIDE_COUNT];
XrPath triggerTouchPath[SIDE_COUNT];
XrPath triggerValuePath[SIDE_COUNT];
XrPath thumbstickClickPath[SIDE_COUNT];
XrPath thumbstickTouchPath[SIDE_COUNT];
XrPath thumbstickPosPath[SIDE_COUNT];
XrPath aimPath[SIDE_COUNT];
XrPath touchpadPath[SIDE_COUNT];
XrPath AXValuePath[SIDE_COUNT];
XrPath homeClickPath[SIDE_COUNT];
XrPath BYValuePath[SIDE_COUNT];
XrPath backPath[SIDE_COUNT];
XrPath sideClickPath[SIDE_COUNT];
XrPath triggerPath[SIDE_COUNT];
XrPath joystickPath[SIDE_COUNT];
XrPath batteryPath[SIDE_COUNT];
XrPath GripPath[SIDE_COUNT];
XrPath AXTouchPath[SIDE_COUNT];
XrPath BYTouchPath[SIDE_COUNT];
XrPath RockerTouchPath[SIDE_COUNT];
XrPath TriggerTouchPath[SIDE_COUNT];
XrPath ThumbresetTouchPath[SIDE_COUNT];
XrPath AValuePath[SIDE_COUNT];
XrPath BValuePath[SIDE_COUNT];
XrPath XValuePath[SIDE_COUNT];
XrPath YValuePath[SIDE_COUNT];
XrPath ATouchPath[SIDE_COUNT];
XrPath BTouchPath[SIDE_COUNT];
XrPath XTouchPath[SIDE_COUNT];
XrPath YTouchPath[SIDE_COUNT];
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/select/click", &selectPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/select/click", &selectPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/menu/click", &menuClickPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/menu/click", &menuClickPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/squeeze/value", &squeezeValuePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/squeeze/value", &squeezeValuePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/squeeze/click", &squeezeClickPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/squeeze/click", &squeezeClickPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/grip/pose", &posePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/grip/pose", &posePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/aim/pose", &aimPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/aim/pose", &aimPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/output/haptic", &hapticPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/output/haptic", &hapticPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/trigger/touch", &triggerTouchPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/trigger/touch", &triggerTouchPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/trigger/value", &triggerValuePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/trigger/value", &triggerValuePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick/click", &thumbstickClickPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick/click", &thumbstickClickPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick/touch", &thumbstickTouchPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick/touch", &thumbstickTouchPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbstick", &thumbstickPosPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbstick", &thumbstickPosPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/system/click", &systemPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/system/click", &systemPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/thumbrest/touch", &thumbrestPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/thumbrest/touch", &thumbrestPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/back/click", &backPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/back/click", &backPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/battery/value", &batteryPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/battery/value", &batteryPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/x/click", &XValuePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/y/click", &YValuePath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/a/click", &AValuePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/b/click", &BValuePath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/x/touch", &XTouchPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/left/input/y/touch", &YTouchPath[SIDE_LEFT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/a/touch", &ATouchPath[SIDE_RIGHT]));
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/user/hand/right/input/b/touch", &BTouchPath[SIDE_RIGHT]));
XrResult result;
//First try Pico Devices
{
XrPath picoMixedRealityInteractionProfilePath;
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/interaction_profiles/pico/neo3_controller",
&picoMixedRealityInteractionProfilePath));
XrActionSuggestedBinding bindings[128];
int currBinding = 0;
bindings[currBinding++] = ActionSuggestedBinding(touchpadAction, thumbstickClickPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(touchpadAction, thumbstickClickPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(joystickAction, thumbstickPosPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(joystickAction, thumbstickPosPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(thumbstickTouchAction, thumbstickTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(thumbstickTouchAction, thumbstickTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(triggerAction, triggerValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(triggerAction, triggerValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(TriggerTouchAction, triggerTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(TriggerTouchAction, triggerTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(sideAction, squeezeClickPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(sideAction, squeezeClickPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(GripAction, squeezeValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(GripAction, squeezeValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(poseAction, posePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(poseAction, posePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(homeAction, systemPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(homeAction, systemPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(backAction, backPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(backAction, backPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(batteryAction, batteryPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(batteryAction, batteryPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(ThumbrestTouchAction, thumbrestPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(ThumbrestTouchAction, thumbrestPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(vibrateAction, hapticPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(vibrateAction, hapticPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(XTouchAction, XTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(YTouchAction, YTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(ATouchAction, ATouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(BTouchAction, BTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(XAction, XValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(YAction, YValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(AAction, AValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(BAction, BValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(aimAction, aimPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(aimAction, aimPath[SIDE_RIGHT]);
XrInteractionProfileSuggestedBinding suggestedBindings = {};
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
suggestedBindings.interactionProfile = picoMixedRealityInteractionProfilePath;
suggestedBindings.suggestedBindings = bindings;
suggestedBindings.countSuggestedBindings = currBinding;
suggestedBindings.next = NULL;
result = xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings);
}
if (result != XR_SUCCESS)
{
XrPath touchControllerInteractionProfilePath;
CHECK_XRCMD(xrStringToPath(gAppState.Instance, "/interaction_profiles/oculus/touch_controller",
&touchControllerInteractionProfilePath));
XrActionSuggestedBinding bindings[128];
int currBinding = 0;
bindings[currBinding++] = ActionSuggestedBinding(touchpadAction, thumbstickClickPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(touchpadAction, thumbstickClickPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(joystickAction, thumbstickPosPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(joystickAction, thumbstickPosPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(thumbstickTouchAction, thumbstickTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(thumbstickTouchAction, thumbstickTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(triggerAction, triggerValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(triggerAction, triggerValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(TriggerTouchAction, triggerTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(TriggerTouchAction, triggerTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(GripAction, squeezeValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(GripAction, squeezeValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(poseAction, posePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(poseAction, posePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(backAction, menuClickPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(ThumbrestTouchAction, thumbrestPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(ThumbrestTouchAction, thumbrestPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(vibrateAction, hapticPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(vibrateAction, hapticPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(XTouchAction, XTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(YTouchAction, YTouchPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(ATouchAction, ATouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(BTouchAction, BTouchPath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(XAction, XValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(YAction, YValuePath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(AAction, AValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(BAction, BValuePath[SIDE_RIGHT]);
bindings[currBinding++] = ActionSuggestedBinding(aimAction, aimPath[SIDE_LEFT]);
bindings[currBinding++] = ActionSuggestedBinding(aimAction, aimPath[SIDE_RIGHT]);
XrInteractionProfileSuggestedBinding suggestedBindings = {};
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
suggestedBindings.interactionProfile = touchControllerInteractionProfilePath;
suggestedBindings.suggestedBindings = bindings;
suggestedBindings.countSuggestedBindings = currBinding;
suggestedBindings.next = NULL;
result = xrSuggestInteractionProfileBindings(gAppState.Instance, &suggestedBindings);
}
XrActionSpaceCreateInfo actionSpaceInfo = {};
actionSpaceInfo.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
actionSpaceInfo.action = poseAction;
actionSpaceInfo.poseInActionSpace.orientation.w = 1.f;
actionSpaceInfo.subactionPath = handSubactionPath[SIDE_LEFT];
CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &handSpace[SIDE_LEFT]));
actionSpaceInfo.subactionPath = handSubactionPath[SIDE_RIGHT];
CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &handSpace[SIDE_RIGHT]));
actionSpaceInfo.action = aimAction;
actionSpaceInfo.poseInActionSpace.orientation.w = 1.f;
actionSpaceInfo.subactionPath = handSubactionPath[SIDE_LEFT];
CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &aimSpace[SIDE_LEFT]));
actionSpaceInfo.subactionPath = handSubactionPath[SIDE_RIGHT];
actionSpaceInfo.next = NULL;
CHECK_XRCMD(xrCreateActionSpace(gAppState.Session, &actionSpaceInfo, &aimSpace[SIDE_RIGHT]));
XrSessionActionSetsAttachInfo attachInfo = {};
attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
attachInfo.countActionSets = 1;
attachInfo.actionSets = &actionSet;
attachInfo.next = NULL;
CHECK_XRCMD(xrAttachSessionActionSets(gAppState.Session, &attachInfo));
}
void TBXR_SyncActions( void )
{
if (actionSet)
{
XrActiveActionSet activeActionSet = {};
activeActionSet.actionSet = actionSet;
activeActionSet.subactionPath = XR_NULL_PATH;
XrActionsSyncInfo syncInfo;
syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
syncInfo.countActiveActionSets = 1;
syncInfo.activeActionSets = &activeActionSet;
syncInfo.next = NULL;
CHECK_XRCMD(xrSyncActions(gAppState.Session, &syncInfo));
}
}
void TBXR_UpdateControllers( )
{
TBXR_SyncActions();
//get controller poses
for (int i = 0; i < 2; i++) {
XrSpaceVelocity vel = {};
vel.type = XR_TYPE_SPACE_VELOCITY;
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
loc.next = &vel;
XrResult res = xrLocateSpace(aimSpace[i], gAppState.CurrentSpace, gAppState.FrameState.predictedDisplayTime, &loc);
if (res != XR_SUCCESS) {
ALOGE("xrLocateSpace error: %d", (int)res);
}
gAppState.TrackedController[i].Active = (loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0;
gAppState.TrackedController[i].Pose = loc.pose;
gAppState.TrackedController[i].Velocity = vel;
}
leftRemoteTracking_new = gAppState.TrackedController[0];
rightRemoteTracking_new = gAppState.TrackedController[1];
//button mapping
leftTrackedRemoteState_new.Buttons = 0;
leftTrackedRemoteState_new.Touches = 0;
if (GetActionStateBoolean(backAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Enter;
if (GetActionStateBoolean(XAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_X;
if (GetActionStateBoolean(XTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_X;
if (GetActionStateBoolean(YAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Y;
if (GetActionStateBoolean(YTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_Y;
leftTrackedRemoteState_new.GripTrigger = GetActionStateFloat(GripAction, SIDE_LEFT).currentState;
if (leftTrackedRemoteState_new.GripTrigger > 0.5f) leftTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
if (GetActionStateBoolean(touchpadAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_LThumb;
if (GetActionStateBoolean(touchpadAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Buttons |= xrButton_Joystick;
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_LThumb;
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_Joystick;
leftTrackedRemoteState_new.IndexTrigger = GetActionStateFloat(triggerAction, SIDE_LEFT).currentState;
if (leftTrackedRemoteState_new.IndexTrigger > 0.5f) leftTrackedRemoteState_new.Buttons |= xrButton_Trigger;
if (GetActionStateBoolean(TriggerTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_Trigger;
if (GetActionStateBoolean(ThumbrestTouchAction, SIDE_LEFT).currentState) leftTrackedRemoteState_new.Touches |= xrButton_ThumbRest;
rightTrackedRemoteState_new.Buttons = 0;
rightTrackedRemoteState_new.Touches = 0;
if (GetActionStateBoolean(backAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Enter;
if (GetActionStateBoolean(AAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_A;
if (GetActionStateBoolean(ATouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_A;
if (GetActionStateBoolean(BAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_B;
if (GetActionStateBoolean(BTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_B;
rightTrackedRemoteState_new.GripTrigger = GetActionStateFloat(GripAction, SIDE_RIGHT).currentState;
if (rightTrackedRemoteState_new.GripTrigger > 0.5f) rightTrackedRemoteState_new.Buttons |= xrButton_GripTrigger;
if (GetActionStateBoolean(touchpadAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_RThumb;
if (GetActionStateBoolean(touchpadAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Buttons |= xrButton_Joystick;
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_RThumb;
if (GetActionStateBoolean(thumbstickTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_Joystick;
rightTrackedRemoteState_new.IndexTrigger = GetActionStateFloat(triggerAction, SIDE_RIGHT).currentState;
if (rightTrackedRemoteState_new.IndexTrigger > 0.5f) rightTrackedRemoteState_new.Buttons |= xrButton_Trigger;
if (GetActionStateBoolean(TriggerTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_Trigger;
if (GetActionStateBoolean(ThumbrestTouchAction, SIDE_RIGHT).currentState) rightTrackedRemoteState_new.Touches |= xrButton_ThumbRest;
//thumbstick
XrActionStateVector2f moveJoystickState;
moveJoystickState = GetActionStateVector2(joystickAction, SIDE_LEFT);
leftTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x;
leftTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y;
moveJoystickState = GetActionStateVector2(joystickAction, SIDE_RIGHT);
rightTrackedRemoteState_new.Joystick.x = moveJoystickState.currentState.x;
rightTrackedRemoteState_new.Joystick.y = moveJoystickState.currentState.y;
}
//0 = left, 1 = right
float vibration_channel_duration[2] = {0.0f, 0.0f};
float vibration_channel_intensity[2] = {0.0f, 0.0f};
void TBXR_Vibrate( int duration, int chan, float intensity )
{
for (int i = 0; i < 2; ++i)
{
int channel = i;
if ((i + 1) & chan)
{
if (vibration_channel_duration[channel] > 0.0f)
return;
if (vibration_channel_duration[channel] == -1.0f && duration != 0.0f)
return;
vibration_channel_duration[channel] = duration;
vibration_channel_intensity[channel] = intensity;
}
}
}
void TBXR_ProcessHaptics() {
static float lastFrameTime = 0.0f;
float timestamp = (float)(TBXR_GetTimeInMilliSeconds( ));
float frametime = timestamp - lastFrameTime;
lastFrameTime = timestamp;
for (int i = 0; i < 2; ++i) {
if (vibration_channel_duration[i] > 0.0f ||
vibration_channel_duration[i] == -1.0f) {
// fire haptics using output action
XrHapticVibration vibration = {};
vibration.type = XR_TYPE_HAPTIC_VIBRATION;
vibration.next = NULL;
vibration.amplitude = vibration_channel_intensity[i];
vibration.duration = ToXrTime(vibration_channel_duration[i]);
vibration.frequency = 3000;
XrHapticActionInfo hapticActionInfo = {};
hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO;
hapticActionInfo.next = NULL;
hapticActionInfo.action = vibrateAction;
hapticActionInfo.subactionPath = handSubactionPath[i];
OXR(xrApplyHapticFeedback(gAppState.Session, &hapticActionInfo, (const XrHapticBaseHeader*)&vibration));
if (vibration_channel_duration[i] != -1.0f) {
vibration_channel_duration[i] -= frametime;
if (vibration_channel_duration[i] < 0.0f) {
vibration_channel_duration[i] = 0.0f;
vibration_channel_intensity[i] = 0.0f;
}
}
} else {
// Stop haptics
XrHapticActionInfo hapticActionInfo = {};
hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO;
hapticActionInfo.next = NULL;
hapticActionInfo.action = vibrateAction;
hapticActionInfo.subactionPath = handSubactionPath[i];
OXR(xrStopHapticFeedback(gAppState.Session, &hapticActionInfo));
}
}
}

View file

@ -0,0 +1,759 @@
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <sys/prctl.h> // for prctl( PR_SET_NAME )
#include <android/log.h>
#include <android/native_window_jni.h> // for native window JNI
#include <android/input.h>
#include "cmdlib.h"
#include "argtable3.h"
#include "VrInput.h"
//#define ENABLE_GL_DEBUG
#define ENABLE_GL_DEBUG_VERBOSE 1
//Let's go to the maximum!
extern int NUM_MULTI_SAMPLES;
extern int REFRESH ;
extern float SS_MULTIPLIER ;
/* global arg_xxx structs */
struct arg_dbl *ss;
struct arg_int *cpu;
struct arg_int *gpu;
struct arg_int *msaa;
struct arg_int *refresh;
struct arg_end *end;
char **argv;
int argc=0;
//Define all variables here that were externs in the VrCommon.h
bool qzdoom_initialised;
long long global_time;
float playerYaw;
bool resetDoomYaw;
bool resetPreviousPitch;
float doomYaw;
float previousPitch;
float vrFOV;
vec3_t worldPosition;
vec3_t hmdPosition;
vec3_t hmdorientation;
vec3_t positionDeltaThisFrame;
vec3_t weaponangles;
vec3_t weaponoffset;
bool weaponStabilised;
vec3_t offhandangles;
vec3_t offhandoffset;
bool player_moving;
bool shutdown;
bool ready_teleport;
bool trigger_teleport;
bool cinemamode;
//This is now controlled by the engine
static bool useVirtualScreen = false;
static bool hasIWADs = false;
static bool hasLauncher = false;
extern const char* M_GetActiveProfile();
/*
================================================================================
QuestZDoom Stuff
================================================================================
*/
void QzDoom_setUseScreenLayer(bool use)
{
useVirtualScreen = use;
}
int QzDoom_SetRefreshRate(int refreshRate)
{
XrResult result = XR_SUCCESS;
if (strstr(gAppState.OpenXRHMD, "meta") != NULL)
{
OXR(result = gAppState.pfnRequestDisplayRefreshRate(gAppState.Session, (float) refreshRate));
}
return XR_SUCCEEDED(result) ? 0 : -1;
}
void QzDoom_GetScreenRes(uint32_t *width, uint32_t *height)
{
int iWidth, iHeight;
TBXR_GetScreenRes(&iWidth, &iHeight);
*width = iWidth;
*height = iHeight;
}
bool VR_UseScreenLayer()
{
return useVirtualScreen || cinemamode;
}
float VR_GetScreenLayerDistance()
{
return 4.0f;
}
static void UnEscapeQuotes( char *arg )
{
char *last = NULL;
while( *arg ) {
if( *arg == '"' && *last == '\\' ) {
char *c_curr = arg;
char *c_last = last;
while( *c_curr ) {
*c_last = *c_curr;
c_last = c_curr;
c_curr++;
}
*c_last = '\0';
}
last = arg;
arg++;
}
}
static int ParseCommandLine(char *cmdline, char **argv)
{
char *bufp;
char *lastp = NULL;
int argc, last_argc;
argc = last_argc = 0;
for ( bufp = cmdline; *bufp; ) {
while ( isspace(*bufp) ) {
++bufp;
}
if ( *bufp == '"' ) {
++bufp;
if ( *bufp ) {
if ( argv ) {
argv[argc] = bufp;
}
++argc;
}
while ( *bufp && ( *bufp != '"' || *lastp == '\\' ) ) {
lastp = bufp;
++bufp;
}
} else {
if ( *bufp ) {
if ( argv ) {
argv[argc] = bufp;
}
++argc;
}
while ( *bufp && ! isspace(*bufp) ) {
++bufp;
}
}
if ( *bufp ) {
if ( argv ) {
*bufp = '\0';
}
++bufp;
}
if( argv && last_argc != argc ) {
UnEscapeQuotes( argv[last_argc] );
}
last_argc = argc;
}
if ( argv ) {
argv[argc] = NULL;
}
return(argc);
}
void VR_SetHMDOrientation(float pitch, float yaw, float roll)
{
VectorSet(hmdorientation, pitch, yaw, roll);
if (!VR_UseScreenLayer())
{
playerYaw = yaw;
}
}
void VR_SetHMDPosition(float x, float y, float z )
{
VectorSet(hmdPosition, x, y, z);
positionDeltaThisFrame[0] = (worldPosition[0] - x);
positionDeltaThisFrame[1] = (worldPosition[1] - y);
positionDeltaThisFrame[2] = (worldPosition[2] - z);
worldPosition[0] = x;
worldPosition[1] = y;
worldPosition[2] = z;
}
void VR_GetMove(float *joy_forward, float *joy_side, float *hmd_forward, float *hmd_side, float *up,
float *yaw, float *pitch, float *roll)
{
*joy_forward = remote_movementForward;
*hmd_forward = positional_movementForward;
*up = remote_movementUp;
*joy_side = remote_movementSideways;
*hmd_side = positional_movementSideways;
*yaw = cinemamode ? cinemamodeYaw : hmdorientation[YAW] + snapTurn;
*pitch = cinemamode ? cinemamodePitch : hmdorientation[PITCH];
*roll = cinemamode ? 0.0f : hmdorientation[ROLL];
}
void VR_DoomMain(int argc, char** argv);
void VR_Init()
{
//Initialise all our variables
playerYaw = 0.0f;
resetDoomYaw = true;
resetPreviousPitch = true;
remote_movementSideways = 0.0f;
remote_movementForward = 0.0f;
remote_movementUp = 0.0f;
positional_movementSideways = 0.0f;
positional_movementForward = 0.0f;
snapTurn = 0.0f;
cinemamodeYaw = 0.0f;
cinemamodePitch = 0.0f;
//init randomiser
srand(time(NULL));
shutdown = false;
ready_teleport = false;
trigger_teleport = false;
cinemamode = false;
chdir("/sdcard/QuestZDoom");
}
void * AppThreadFunction(void * parm ) {
gAppThread = (ovrAppThread *) parm;
java.Vm = gAppThread->JavaVm;
java.Vm->AttachCurrentThread(&java.Env, NULL);
java.ActivityObject = gAppThread->ActivityObject;
jclass cls = java.Env->GetObjectClass(java.ActivityObject);
// Note that AttachCurrentThread will reset the thread name.
prctl(PR_SET_NAME, (long) "AppThreadFunction", 0, 0, 0);
//Set device defaults
if (SS_MULTIPLIER == 0.0f)
{
//GB Override as refresh is now 72 by default as we decided a higher res is better as 90hz has stutters
SS_MULTIPLIER = 1.25f;
}
else if (SS_MULTIPLIER > 1.5f)
{
SS_MULTIPLIER = 1.5f;
}
gAppState.MainThreadTid = gettid();
VR_Init();
TBXR_InitialiseOpenXR();
TBXR_EnterVR();
TBXR_InitRenderer();
TBXR_InitActions();
TBXR_WaitForSessionActive();
if (REFRESH != 0)
{
QzDoom_SetRefreshRate(REFRESH);
}
if (hasIWADs && hasLauncher)
{
//Should now be all set up and ready - start the Doom main loop
VR_DoomMain(argc, argv);
}
TBXR_LeaveVR();
//Ask Java to shut down
VR_Shutdown();
return NULL;
}
//All the stuff we want to do each frame specifically for this game
void VR_FrameSetup()
{
}
bool VR_GetVRProjection(int eye, float zNear, float zFar, float* projection)
{
if (strstr(gAppState.OpenXRHMD, "pico") != NULL)
{
XrMatrix4x4f_CreateProjectionFov(
&(gAppState.ProjectionMatrices[eye]), GRAPHICS_OPENGL_ES,
gAppState.Projections[eye].fov, zNear, zFar);
}
if (strstr(gAppState.OpenXRHMD, "meta") != NULL)
{
XrFovf fov = {};
for (int eye = 0; eye < ovrMaxNumEyes; eye++)
{
fov.angleLeft += gAppState.Projections[eye].fov.angleLeft / 2.0f;
fov.angleRight += gAppState.Projections[eye].fov.angleRight / 2.0f;
fov.angleUp += gAppState.Projections[eye].fov.angleUp / 2.0f;
fov.angleDown += gAppState.Projections[eye].fov.angleDown / 2.0f;
}
XrMatrix4x4f_CreateProjectionFov(
&(gAppState.ProjectionMatrices[eye]), GRAPHICS_OPENGL_ES,
fov, zNear, zFar);
}
memcpy(projection, gAppState.ProjectionMatrices[eye].m, 16 * sizeof(float));
return true;
}
extern "C" {
void jni_haptic_event(const char *event, int position, int intensity, float angle, float yHeight);
void jni_haptic_updateevent(const char *event, int intensity, float angle);
void jni_haptic_stopevent(const char *event);
void jni_haptic_endframe();
void jni_haptic_enable();
void jni_haptic_disable();
};
void VR_ExternalHapticEvent(const char* event, int position, int flags, int intensity, float angle, float yHeight )
{
jni_haptic_event(event, position, intensity, angle, yHeight);
}
void VR_HapticStopEvent(const char* event)
{
jni_haptic_stopevent(event);
}
void VR_HapticEnable()
{
static bool firstTime = true;
if (firstTime) {
jni_haptic_enable();
firstTime = false;
jni_haptic_event("fire_pistol", 0, 100, 0, 0);
}
}
void VR_HapticDisable()
{
jni_haptic_disable();
}
void VR_HapticEvent(const char* event, int position, int intensity, float angle, float yHeight )
{
static char buffer[256];
memset(buffer, 0, 256);
for(int i = 0; event[i]; i++)
{
buffer[i] = tolower(event[i]);
}
jni_haptic_event(buffer, position, intensity, angle, yHeight);
}
void QzDoom_Vibrate(float duration, int channel, float intensity )
{
TBXR_Vibrate(duration, channel+1, intensity);
}
void VR_HandleControllerInput() {
TBXR_UpdateControllers();
//Call additional control schemes here
switch (vr_control_scheme)
{
case RIGHT_HANDED_DEFAULT:
HandleInput_Default(vr_control_scheme,
&rightTrackedRemoteState_new, &rightTrackedRemoteState_old, &rightRemoteTracking_new,
&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, &leftRemoteTracking_new,
xrButton_A, xrButton_B, xrButton_X, xrButton_Y);
break;
case LEFT_HANDED_DEFAULT:
case LEFT_HANDED_ALT:
HandleInput_Default(vr_control_scheme,
&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, &leftRemoteTracking_new,
&rightTrackedRemoteState_new, &rightTrackedRemoteState_old, &rightRemoteTracking_new,
xrButton_X, xrButton_Y, xrButton_A, xrButton_B);
break;
}
}
/*
================================================================================
Activity lifecycle
================================================================================
*/
jmethodID android_shutdown;
jmethodID android_reload;
static JavaVM *jVM;
static jobject jniCallbackObj=0;
void jni_shutdown()
{
ALOGV("Calling: jni_shutdown");
JNIEnv *env;
jobject tmp;
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
{
jVM->AttachCurrentThread(&env, NULL);
}
return env->CallVoidMethod(jniCallbackObj, android_shutdown);
}
void VR_Shutdown()
{
jni_shutdown();
}
void jni_reload(const char* profile)
{
ALOGV("Calling: jni_reload");
JNIEnv *env;
jobject tmp;
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
{
jVM->AttachCurrentThread(&env, NULL);
}
jstring jprofile = env->NewStringUTF(profile);
return env->CallVoidMethod(jniCallbackObj, android_reload, jprofile);
}
void QzDoom_Restart()
{
const char* profile = M_GetActiveProfile();
//Ask Java to restart the app
jni_reload(profile);
}
jmethodID android_haptic_event;
jmethodID android_haptic_stopevent;
jmethodID android_haptic_enable;
jmethodID android_haptic_disable;
void jni_haptic_event(const char* event, int position, int intensity, float angle, float yHeight)
{
JNIEnv *env;
jobject tmp;
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
{
jVM->AttachCurrentThread(&env, NULL);
}
jstring StringArg1 = env->NewStringUTF(event);
return env->CallVoidMethod(jniCallbackObj, android_haptic_event, StringArg1, position, intensity, angle, yHeight);
}
void jni_haptic_stopevent(const char* event)
{
ALOGV("Calling: jni_haptic_stopevent");
JNIEnv *env;
jobject tmp;
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
{
jVM->AttachCurrentThread(&env, NULL);
}
jstring StringArg1 = env->NewStringUTF(event);
return env->CallVoidMethod(jniCallbackObj, android_haptic_stopevent, StringArg1);
}
void jni_haptic_enable()
{
ALOGV("Calling: jni_haptic_enable");
JNIEnv *env;
jobject tmp;
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
{
jVM->AttachCurrentThread(&env, NULL);
}
return env->CallVoidMethod(jniCallbackObj, android_haptic_enable);
}
void jni_haptic_disable()
{
ALOGV("Calling: jni_haptic_disable");
JNIEnv *env;
jobject tmp;
if ((jVM->GetEnv((void**) &env, JNI_VERSION_1_4))<0)
{
jVM->AttachCurrentThread(&env, NULL);
}
return env->CallVoidMethod(jniCallbackObj, android_haptic_disable);
}
extern "C" {
int JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv *env;
jVM = vm;
if(vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
{
ALOGE("Failed JNI_OnLoad");
return -1;
}
return JNI_VERSION_1_4;
}
JNIEXPORT jlong JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onCreate( JNIEnv * env, jclass activityClass, jobject activity,
jstring commandLineParams, jboolean jHasIWADs, jboolean jHasLauncher)
{
ALOGV( " GLES3JNILib::onCreate()" );
/* the global arg_xxx structs are initialised within the argtable */
void *argtable[] = {
ss = arg_dbl0("s", "supersampling", "<double>", "super sampling value (default: Q1: 1.2, Q2: 1.35)"),
cpu = arg_int0("c", "cpu", "<int>", "CPU perf index 1-4 (default: 2)"),
gpu = arg_int0("g", "gpu", "<int>", "GPU perf index 1-4 (default: 3)"),
msaa = arg_int0("m", "msaa", "<int>", "MSAA (default: 1)"),
refresh = arg_int0("r", "refresh", "<int>", "Refresh Rate (default: Q1: 72, Q2: 72)"),
end = arg_end(20)
};
hasIWADs = jHasIWADs != 0;
hasLauncher = jHasLauncher != 0;
jboolean iscopy;
const char *arg = env->GetStringUTFChars(commandLineParams, &iscopy);
char *cmdLine = NULL;
if (arg && strlen(arg))
{
cmdLine = strdup(arg);
}
env->ReleaseStringUTFChars(commandLineParams, arg);
ALOGV("Command line %s", cmdLine);
argv = (char**)malloc(sizeof(char*) * 255);
argc = ParseCommandLine(strdup(cmdLine), argv);
/* verify the argtable[] entries were allocated sucessfully */
if (arg_nullcheck(argtable) == 0) {
/* Parse the command line as defined by argtable[] */
arg_parse(argc, argv, argtable);
if (ss->count > 0 && ss->dval[0] > 0.0)
{
SS_MULTIPLIER = ss->dval[0];
}
if (msaa->count > 0 && msaa->ival[0] > 0 && msaa->ival[0] < 10)
{
NUM_MULTI_SAMPLES = msaa->ival[0];
}
if (refresh->count > 0 && refresh->ival[0] > 0 && refresh->ival[0] <= 120)
{
REFRESH = refresh->ival[0];
}
}
ovrAppThread * appThread = (ovrAppThread *) malloc( sizeof( ovrAppThread ) );
ovrAppThread_Create( appThread, env, activity, activityClass );
surfaceMessageQueue_Enable(&appThread->MessageQueue, true);
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_CREATE, MQ_WAIT_PROCESSED);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
return (jlong)((size_t)appThread);
}
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onStart( JNIEnv * env, jobject obj, jlong handle, jobject obj1)
{
ALOGV( " GLES3JNILib::onStart()" );
jniCallbackObj = (jobject)env->NewGlobalRef( obj1);
jclass callbackClass = env->GetObjectClass( jniCallbackObj);
android_shutdown = env->GetMethodID(callbackClass,"shutdown","()V");
android_reload = env->GetMethodID(callbackClass,"reload","(Ljava/lang/String;)V");
android_haptic_event = env->GetMethodID(callbackClass, "haptic_event", "(Ljava/lang/String;IIFF)V");
android_haptic_stopevent = env->GetMethodID(callbackClass, "haptic_stopevent", "(Ljava/lang/String;)V");
android_haptic_enable = env->GetMethodID(callbackClass, "haptic_enable", "()V");
android_haptic_disable = env->GetMethodID(callbackClass, "haptic_disable", "()V");
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_START, MQ_WAIT_PROCESSED);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
}
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onResume( JNIEnv * env, jobject obj, jlong handle )
{
ALOGV( " GLES3JNILib::onResume()" );
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_RESUME, MQ_WAIT_PROCESSED);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
}
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onPause( JNIEnv * env, jobject obj, jlong handle )
{
ALOGV( " GLES3JNILib::onPause()" );
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_PAUSE, MQ_WAIT_PROCESSED);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
}
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onStop( JNIEnv * env, jobject obj, jlong handle )
{
ALOGV( " GLES3JNILib::onStop()" );
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_STOP, MQ_WAIT_PROCESSED);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
}
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onDestroy( JNIEnv * env, jobject obj, jlong handle )
{
ALOGV( " GLES3JNILib::onDestroy()" );
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_DESTROY, MQ_WAIT_PROCESSED);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
surfaceMessageQueue_Enable(&appThread->MessageQueue, false);
ovrAppThread_Destroy( appThread, env );
free( appThread );
}
/*
================================================================================
Surface lifecycle
================================================================================
*/
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onSurfaceCreated( JNIEnv * env, jobject obj, jlong handle, jobject surface )
{
ALOGV( " GLES3JNILib::onSurfaceCreated()" );
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
ANativeWindow * newNativeWindow = ANativeWindow_fromSurface( env, surface );
if ( ANativeWindow_getWidth( newNativeWindow ) < ANativeWindow_getHeight( newNativeWindow ) )
{
// An app that is relaunched after pressing the home button gets an initial surface with
// the wrong orientation even though android:screenOrientation="landscape" is set in the
// manifest. The choreographer callback will also never be called for this surface because
// the surface is immediately replaced with a new surface with the correct orientation.
ALOGE( " Surface not in landscape mode!" );
}
ALOGV( " NativeWindow = ANativeWindow_fromSurface( env, surface )" );
appThread->NativeWindow = newNativeWindow;
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_SURFACE_CREATED, MQ_WAIT_PROCESSED);
surfaceMessage_SetPointerParm(&message, 0, appThread->NativeWindow);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
}
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onSurfaceChanged( JNIEnv * env, jobject obj, jlong handle, jobject surface )
{
ALOGV( " GLES3JNILib::onSurfaceChanged()" );
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
ANativeWindow * newNativeWindow = ANativeWindow_fromSurface( env, surface );
if ( ANativeWindow_getWidth( newNativeWindow ) < ANativeWindow_getHeight( newNativeWindow ) )
{
// An app that is relaunched after pressing the home button gets an initial surface with
// the wrong orientation even though android:screenOrientation="landscape" is set in the
// manifest. The choreographer callback will also never be called for this surface because
// the surface is immediately replaced with a new surface with the correct orientation.
ALOGE( " Surface not in landscape mode!" );
}
if ( newNativeWindow != appThread->NativeWindow )
{
if ( appThread->NativeWindow != NULL )
{
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_SURFACE_DESTROYED, MQ_WAIT_PROCESSED);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
ALOGV( " ANativeWindow_release( NativeWindow )" );
ANativeWindow_release( appThread->NativeWindow );
appThread->NativeWindow = NULL;
}
if ( newNativeWindow != NULL )
{
ALOGV( " NativeWindow = ANativeWindow_fromSurface( env, surface )" );
appThread->NativeWindow = newNativeWindow;
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_SURFACE_CREATED, MQ_WAIT_PROCESSED);
surfaceMessage_SetPointerParm(&message, 0, appThread->NativeWindow);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
}
}
else if ( newNativeWindow != NULL )
{
ANativeWindow_release( newNativeWindow );
}
}
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onSurfaceDestroyed( JNIEnv * env, jobject obj, jlong handle )
{
ALOGV( " GLES3JNILib::onSurfaceDestroyed()" );
ovrAppThread * appThread = (ovrAppThread *)((size_t)handle);
srufaceMessage message;
surfaceMessage_Init(&message, MESSAGE_ON_SURFACE_DESTROYED, MQ_WAIT_PROCESSED);
surfaceMessageQueue_PostMessage(&appThread->MessageQueue, &message);
ALOGV( " ANativeWindow_release( NativeWindow )" );
ANativeWindow_release( appThread->NativeWindow );
appThread->NativeWindow = NULL;
}
JNIEXPORT void JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_prepareEnvironment(JNIEnv * env, jclass obj, jstring path) {
auto p = env->GetStringUTFChars(path, NULL);
progdir = p;
chdir(p);
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,338 @@
#if !defined(tbxr_common_h)
#define tbxr_common_h
//OpenXR
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
#define XR_USE_PLATFORM_ANDROID 1
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <jni.h>
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <openxr_helpers.h>
#include <android/native_window_jni.h>
#include <android/log.h>
#ifndef NDEBUG
#define DEBUG 1
#endif
#define LOG_TAG "TBXR"
#define ALOGE(...) __android_log_print( ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__ )
#if DEBUG
#define ALOGV(...) __android_log_print( ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__ )
#else
#define ALOGV(...)
#endif
enum { ovrMaxLayerCount = 1 };
enum { ovrMaxNumEyes = 2 };
typedef enum xrButton_ {
xrButton_A = 0x00000001,
xrButton_B = 0x00000002,
xrButton_RThumb = 0x00000004,
xrButton_RShoulder = 0x00000008,
xrButton_X = 0x00000100,
xrButton_Y = 0x00000200,
xrButton_LThumb = 0x00000400,
xrButton_LShoulder = 0x00000800,
xrButton_Up = 0x00010000,
xrButton_Down = 0x00020000,
xrButton_Left = 0x00040000,
xrButton_Right = 0x00080000,
xrButton_Enter = 0x00100000,
xrButton_Back = 0x00200000,
xrButton_GripTrigger = 0x04000000,
xrButton_Trigger = 0x20000000,
xrButton_Joystick = 0x80000000,
//Define additional controller touch points (not button presses)
xrButton_ThumbRest = 0x00000010,
xrButton_EnumSize = 0x7fffffff
} xrButton;
typedef struct {
uint32_t Buttons;
uint32_t Touches;
float IndexTrigger;
float GripTrigger;
XrVector2f Joystick;
} ovrInputStateTrackedRemote;
typedef struct {
GLboolean Active;
XrPosef Pose;
XrSpaceVelocity Velocity;
} ovrTrackedController;
typedef enum control_scheme {
RIGHT_HANDED_DEFAULT = 0,
LEFT_HANDED_DEFAULT = 10,
LEFT_HANDED_ALT = 11
} control_scheme_t;
typedef struct {
float M[4][4];
} ovrMatrix4f;
typedef struct {
XrSwapchain Handle;
uint32_t Width;
uint32_t Height;
} ovrSwapChain;
typedef struct {
int Width;
int Height;
int Multisamples;
uint32_t TextureSwapChainLength;
uint32_t TextureSwapChainIndex;
ovrSwapChain ColorSwapChain;
XrSwapchainImageOpenGLESKHR* ColorSwapChainImage;
GLuint* DepthBuffers;
GLuint* FrameBuffers;
} ovrFramebuffer;
/*
================================================================================
ovrRenderer
================================================================================
*/
typedef struct
{
ovrFramebuffer FrameBuffer[ovrMaxNumEyes];
} ovrRenderer;
/*
================================================================================
ovrApp
================================================================================
*/
typedef enum
{
MQ_WAIT_NONE, // don't wait
MQ_WAIT_RECEIVED, // wait until the consumer thread has received the message
MQ_WAIT_PROCESSED // wait until the consumer thread has processed the message
} ovrMQWait;
#define MAX_MESSAGE_PARMS 8
#define MAX_MESSAGES 1024
typedef struct
{
int Id;
ovrMQWait Wait;
long long Parms[MAX_MESSAGE_PARMS];
} srufaceMessage;
typedef struct
{
srufaceMessage Messages[MAX_MESSAGES];
volatile int Head; // dequeue at the head
volatile int Tail; // enqueue at the tail
ovrMQWait Wait;
volatile bool EnabledFlag;
volatile bool PostedFlag;
volatile bool ReceivedFlag;
volatile bool ProcessedFlag;
pthread_mutex_t Mutex;
pthread_cond_t PostedCondition;
pthread_cond_t ReceivedCondition;
pthread_cond_t ProcessedCondition;
} surfaceMessageQueue;
typedef struct
{
JavaVM * JavaVm;
jobject ActivityObject;
jclass ActivityClass;
pthread_t Thread;
surfaceMessageQueue MessageQueue;
ANativeWindow * NativeWindow;
} ovrAppThread;
typedef union {
XrCompositionLayerProjection Projection;
XrCompositionLayerQuad Quad;
} xrCompositorLayer_Union;
#define GL(func) func;
// Forward declarations
XrInstance TBXR_GetXrInstance();
#if defined(DEBUG)
static void
OXR_CheckErrors(XrInstance instance, XrResult result, const char* function, bool failOnError) {
if (XR_FAILED(result)) {
char errorBuffer[XR_MAX_RESULT_STRING_SIZE];
xrResultToString(instance, result, errorBuffer);
if (failOnError) {
ALOGE("OpenXR error: %s: %s\n", function, errorBuffer);
} else {
ALOGV("OpenXR error: %s: %s\n", function, errorBuffer);
}
}
}
#endif
#if defined(DEBUG)
#define OXR(func) OXR_CheckErrors(TBXR_GetXrInstance(), func, #func, true);
#else
#define OXR(func) func;
#endif
typedef struct {
EGLint MajorVersion;
EGLint MinorVersion;
EGLDisplay Display;
EGLConfig Config;
EGLSurface TinySurface;
EGLSurface MainSurface;
EGLContext Context;
} ovrEgl;
/// Java details about an activity
typedef struct ovrJava_ {
JavaVM* Vm; //< Java Virtual Machine
JNIEnv* Env; //< Thread specific environment
jobject ActivityObject; //< Java activity object
} ovrJava;
typedef struct
{
ovrJava Java;
ovrEgl Egl;
ANativeWindow* NativeWindow;
bool Resumed;
bool Focused;
int FrameSetupRefCount;
char* OpenXRHMD;
float Width;
float Height;
XrInstance Instance;
XrSession Session;
XrViewConfigurationProperties ViewportConfig;
XrViewConfigurationView ViewConfigurationView[ovrMaxNumEyes];
XrSystemId SystemId;
XrSpace HeadSpace;
XrSpace StageSpace;
XrSpace FakeStageSpace;
XrSpace CurrentSpace;
GLboolean SessionActive;
XrPosef xfStageFromHead;
XrView* Projections;
XrMatrix4x4f ProjectionMatrices[2];
float currentDisplayRefreshRate;
float* SupportedDisplayRefreshRates;
uint32_t RequestedDisplayRefreshRateIndex;
uint32_t NumSupportedDisplayRefreshRates;
PFN_xrGetDisplayRefreshRateFB pfnGetDisplayRefreshRate;
PFN_xrRequestDisplayRefreshRateFB pfnRequestDisplayRefreshRate;
XrFrameState FrameState;
int SwapInterval;
int MainThreadTid;
int RenderThreadTid;
xrCompositorLayer_Union Layers[ovrMaxLayerCount];
int LayerCount;
ovrRenderer Renderer;
ovrTrackedController TrackedController[2];
} ovrApp;
enum
{
MESSAGE_ON_CREATE,
MESSAGE_ON_START,
MESSAGE_ON_RESUME,
MESSAGE_ON_PAUSE,
MESSAGE_ON_STOP,
MESSAGE_ON_DESTROY,
MESSAGE_ON_SURFACE_CREATED,
MESSAGE_ON_SURFACE_DESTROYED
};
extern ovrAppThread * gAppThread;
extern ovrApp gAppState;
extern ovrJava java;
void ovrTrackedController_Clear(ovrTrackedController* controller);
void * AppThreadFunction(void * parm );
void ovrAppThread_Create( ovrAppThread * appThread, JNIEnv * env, jobject activityObject, jclass activityClass );
void ovrAppThread_Destroy( ovrAppThread * appThread, JNIEnv * env );
/*
* Surface Lifecycle Message Queue
*/
void surfaceMessage_Init(srufaceMessage * message, const int id, const int wait );
void * surfaceMessage_GetPointerParm(srufaceMessage * message, int index );
void surfaceMessage_SetPointerParm(srufaceMessage * message, int index, void * ptr );
void surfaceMessageQueue_Create(surfaceMessageQueue * messageQueue );
void surfaceMessageQueue_Destroy(surfaceMessageQueue * messageQueue );
void surfaceMessageQueue_Enable(surfaceMessageQueue * messageQueue, const bool set );
void surfaceMessageQueue_PostMessage(surfaceMessageQueue * messageQueue, const srufaceMessage * message );
//Functions that need to be implemented by the game specific code
void VR_FrameSetup();
bool VR_UseScreenLayer();
float VR_GetScreenLayerDistance();
bool VR_GetVRProjection(int eye, float zNear, float zFar, float* projection);
void VR_HandleControllerInput();
void VR_SetHMDOrientation(float pitch, float yaw, float roll );
void VR_SetHMDPosition(float x, float y, float z );
void VR_HapticEvent(const char* event, int position, int intensity, float angle, float yHeight );
void VR_HapticUpdateEvent(const char* event, int intensity, float angle );
void VR_HapticEndFrame();
void VR_HapticStopEvent(const char* event);
void VR_HapticEnable();
void VR_HapticDisable();
void VR_Shutdown();
//Reusable Team Beef OpenXR stuff (in TBXR_Common.cpp)
double TBXR_GetTimeInMilliSeconds();
int TBXR_GetRefresh();
void TBXR_Recenter();
void TBXR_InitialiseOpenXR();
void TBXR_WaitForSessionActive();
void TBXR_InitRenderer();
void TBXR_EnterVR();
void TBXR_LeaveVR( );
void TBXR_GetScreenRes(int *width, int *height);
void TBXR_InitActions( void );
void TBXR_Vibrate(int duration, int channel, float intensity );
void TBXR_ProcessHaptics();
bool TBXR_FrameSetup();
void TBXR_updateProjections();
void TBXR_UpdateControllers( );
void TBXR_prepareEyeBuffer(int eye );
void TBXR_finishEyeBuffer(int eye );
void TBXR_submitFrame();
#endif //vrcommon_h

View file

@ -1,13 +1,22 @@
#if !defined(vrcommon_h)
#define vrcommon_h
#ifdef __cplusplus
extern "C"
{
#endif
#include "TBXR_Common.h"
#include "c_cvars.h"
EXTERN_CVAR(Int, vr_control_scheme)
EXTERN_CVAR(Bool, vr_move_use_offhand)
EXTERN_CVAR(Float, vr_weaponRotate);
EXTERN_CVAR(Float, vr_snapTurn);
EXTERN_CVAR(Float, vr_ipd);
EXTERN_CVAR(Float, vr_weaponScale);
EXTERN_CVAR(Bool, vr_teleport);
EXTERN_CVAR(Bool, vr_switch_sticks);
EXTERN_CVAR(Bool, vr_secondary_button_mappings);
EXTERN_CVAR(Bool, vr_two_handed_weapons);
EXTERN_CVAR(Bool, vr_crouch_use_button);
//#include <VrApi_Ext.h>
#include <VrApi_Input.h>
#include <android/log.h>
@ -50,16 +59,6 @@ extern vec3_t positionDeltaThisFrame;
extern vec3_t weaponangles;
extern vec3_t weaponoffset;
extern bool weaponStabilised;
extern float vr_weapon_pitchadjust;
extern bool vr_moveuseoffhand;
extern bool vr_switchsticks;
extern bool vr_secondarybuttonmappings;
extern bool vr_twohandedweapons;
extern float vr_snapturn_angle;
extern float vr_use_teleport;
extern vec3_t offhandangles;
extern vec3_t offhandoffset;
@ -69,43 +68,18 @@ extern bool ready_teleport;
extern bool trigger_teleport;
extern bool shutdown;
void shutdownVR();
float radians(float deg);
float degrees(float rad);
bool isMultiplayer();
double GetTimeInMilliSeconds();
float length(float x, float y);
float nonLinearFilter(float in);
bool between(float min, float val, float max);
void rotateAboutOrigin(float v1, float v2, float rotation, vec2_t out);
void QuatToYawPitchRoll(ovrQuatf q, vec3_t rotation, vec3_t out);
void handleTrackedControllerButton(ovrInputStateTrackedRemote * trackedRemoteState, ovrInputStateTrackedRemote * prevTrackedRemoteState, uint32_t button, int key);
void QuatToYawPitchRoll(XrQuaternionf q, vec3_t rotation, vec3_t out);
//Called from engine code
bool QzDoom_useScreenLayer();
void QzDoom_GetScreenRes(uint32_t *width, uint32_t *height);
void QzDoom_Vibrate(float duration, int channel, float intensity );
bool QzDoom_processMessageQueue();
void QzDoom_FrameSetup();
void QzDoom_setUseScreenLayer(bool use);
void QzDoom_processHaptics();
void QzDoom_getHMDOrientation(ovrTracking2 *tracking);
void QzDoom_getTrackedRemotesOrientation(int vr_control_scheme);
int QzDoom_SetRefreshRate(int refreshRate);
void QzDoom_Restart();
void QzDoom_HapticEvent(const char* event, int position, int intensity, float angle, float yHeight );
void QzDoom_HapticEnable();
void QzDoom_HapticDisable();
void incrementFrameIndex();
void QzDoom_prepareEyeBuffer(int eye );
void QzDoom_finishEyeBuffer(int eye );
void QzDoom_submitFrame(ovrTracking2 *tracking);
#ifdef __cplusplus
} // extern "C"
#endif
#endif //vrcommon_h

View file

@ -1,595 +0,0 @@
/************************************************************************************
Filename : VrCompositor.c
*************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/prctl.h> // for prctl( PR_SET_NAME )
#include <android/log.h>
#include <android/window.h> // for AWINDOW_FLAG_KEEP_SCREEN_ON
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <VrApi.h>
#include <VrApi_Helpers.h>
#include "VrCompositor.h"
/*
================================================================================
renderState
================================================================================
*/
void getCurrentRenderState( renderState * state)
{
state->VertexBuffer = 0;
state->IndexBuffer = 0;
state->VertexArrayObject = 0;
state->Program = 0;
glGetIntegerv(GL_ARRAY_BUFFER, &state->VertexBuffer );
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER, &state->IndexBuffer );
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &state->VertexArrayObject );
glGetIntegerv(GL_CURRENT_PROGRAM, &state->Program );
}
void restoreRenderState( renderState * state )
{
GL( glUseProgram( state->Program ) );
GL( glBindVertexArray( state->VertexArrayObject ) );
GL( glBindBuffer( GL_ARRAY_BUFFER, state->VertexBuffer ) );
GL( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, state->IndexBuffer ) );
}
/*
================================================================================
ovrGeometry
================================================================================
*/
enum VertexAttributeLocation
{
VERTEX_ATTRIBUTE_LOCATION_POSITION,
VERTEX_ATTRIBUTE_LOCATION_COLOR,
VERTEX_ATTRIBUTE_LOCATION_UV,
};
typedef struct
{
enum VertexAttributeLocation location;
const char * name;
} ovrVertexAttribute;
static ovrVertexAttribute ProgramVertexAttributes[] =
{
{ VERTEX_ATTRIBUTE_LOCATION_POSITION, "vertexPosition" },
{ VERTEX_ATTRIBUTE_LOCATION_COLOR, "vertexColor" },
{ VERTEX_ATTRIBUTE_LOCATION_UV, "vertexUv" },
};
static void ovrGeometry_Clear( ovrGeometry * geometry )
{
geometry->VertexBuffer = 0;
geometry->IndexBuffer = 0;
geometry->VertexArrayObject = 0;
geometry->VertexCount = 0;
geometry->IndexCount = 0;
for ( int i = 0; i < MAX_VERTEX_ATTRIB_POINTERS; i++ )
{
memset( &geometry->VertexAttribs[i], 0, sizeof( geometry->VertexAttribs[i] ) );
geometry->VertexAttribs[i].Index = -1;
}
}
static void ovrGeometry_CreateGroundPlane( ovrGeometry * geometry )
{
typedef struct
{
float positions[4][4];
unsigned char colors[4][4];
} ovrCubeVertices;
static const ovrCubeVertices cubeVertices =
{
// positions
{
{ 4.5f, -1.2f, 4.5f, 1.0f },
{ 4.5f, -1.2f, -4.5f, 1.0f },
{ -4.5f, -1.2f, -4.5f, 1.0f },
{ -4.5f, -1.2f, 4.5f, 1.0f }
},
// colors
{
{ 255, 0, 0, 255 },
{ 0, 255, 0, 255 },
{ 0, 0, 255, 255 },
{ 255, 255, 0, 255 },
},
};
static const unsigned short cubeIndices[6] =
{
0, 1, 2,
0, 2, 3,
};
geometry->VertexCount = 4;
geometry->IndexCount = 6;
geometry->VertexAttribs[0].Index = VERTEX_ATTRIBUTE_LOCATION_POSITION;
geometry->VertexAttribs[0].Size = 4;
geometry->VertexAttribs[0].Type = GL_FLOAT;
geometry->VertexAttribs[0].Normalized = false;
geometry->VertexAttribs[0].Stride = sizeof( cubeVertices.positions[0] );
geometry->VertexAttribs[0].Pointer = (const GLvoid *)offsetof( ovrCubeVertices, positions );
geometry->VertexAttribs[1].Index = VERTEX_ATTRIBUTE_LOCATION_COLOR;
geometry->VertexAttribs[1].Size = 4;
geometry->VertexAttribs[1].Type = GL_UNSIGNED_BYTE;
geometry->VertexAttribs[1].Normalized = true;
geometry->VertexAttribs[1].Stride = sizeof( cubeVertices.colors[0] );
geometry->VertexAttribs[1].Pointer = (const GLvoid *)offsetof( ovrCubeVertices, colors );
renderState state;
getCurrentRenderState(&state);
GL( glGenBuffers( 1, &geometry->VertexBuffer ) );
GL( glBindBuffer( GL_ARRAY_BUFFER, geometry->VertexBuffer ) );
GL( glBufferData( GL_ARRAY_BUFFER, sizeof( cubeVertices ), &cubeVertices, GL_STATIC_DRAW ) );
GL( glGenBuffers( 1, &geometry->IndexBuffer ) );
GL( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, geometry->IndexBuffer ) );
GL( glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( cubeIndices ), cubeIndices, GL_STATIC_DRAW ) );
restoreRenderState(&state);
}
static void ovrGeometry_Destroy( ovrGeometry * geometry )
{
GL( glDeleteBuffers( 1, &geometry->IndexBuffer ) );
GL( glDeleteBuffers( 1, &geometry->VertexBuffer ) );
ovrGeometry_Clear( geometry );
}
static void ovrGeometry_CreateVAO( ovrGeometry * geometry )
{
renderState state;
getCurrentRenderState(&state);
GL( glGenVertexArrays( 1, &geometry->VertexArrayObject ) );
GL( glBindVertexArray( geometry->VertexArrayObject ) );
GL( glBindBuffer( GL_ARRAY_BUFFER, geometry->VertexBuffer ) );
for ( int i = 0; i < MAX_VERTEX_ATTRIB_POINTERS; i++ )
{
if ( geometry->VertexAttribs[i].Index != -1 )
{
GL( glEnableVertexAttribArray( geometry->VertexAttribs[i].Index ) );
GL( glVertexAttribPointer( geometry->VertexAttribs[i].Index, geometry->VertexAttribs[i].Size,
geometry->VertexAttribs[i].Type, geometry->VertexAttribs[i].Normalized,
geometry->VertexAttribs[i].Stride, geometry->VertexAttribs[i].Pointer ) );
}
}
GL( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, geometry->IndexBuffer ) );
restoreRenderState(&state);
}
static void ovrGeometry_DestroyVAO( ovrGeometry * geometry )
{
GL( glDeleteVertexArrays( 1, &geometry->VertexArrayObject ) );
}
/*
================================================================================
ovrProgram
================================================================================
*/
typedef struct
{
enum
{
UNIFORM_VIEW_PROJ_MATRIX,
} index;
enum
{
UNIFORM_TYPE_VECTOR4,
UNIFORM_TYPE_MATRIX4X4,
UNIFORM_TYPE_INT,
UNIFORM_TYPE_BUFFER,
} type;
const char * name;
} ovrUniform;
static ovrUniform ProgramUniforms[] =
{
{ UNIFORM_VIEW_PROJ_MATRIX, UNIFORM_TYPE_MATRIX4X4, "viewProjectionMatrix" },
};
static void ovrProgram_Clear( ovrProgram * program )
{
program->Program = 0;
program->VertexShader = 0;
program->FragmentShader = 0;
memset( program->UniformLocation, 0, sizeof( program->UniformLocation ) );
memset( program->UniformBinding, 0, sizeof( program->UniformBinding ) );
memset( program->Textures, 0, sizeof( program->Textures ) );
}
static bool ovrProgram_Create( ovrProgram * program, const char * vertexSource, const char * fragmentSource )
{
GLint r;
GL( program->VertexShader = glCreateShader( GL_VERTEX_SHADER ) );
GL( glShaderSource( program->VertexShader, 1, &vertexSource, 0 ) );
GL( glCompileShader( program->VertexShader ) );
GL( glGetShaderiv( program->VertexShader, GL_COMPILE_STATUS, &r ) );
if ( r == GL_FALSE )
{
GLchar msg[4096];
GL( glGetShaderInfoLog( program->VertexShader, sizeof( msg ), 0, msg ) );
ALOGE( "%s\n%s\n", vertexSource, msg );
return false;
}
GL( program->FragmentShader = glCreateShader( GL_FRAGMENT_SHADER ) );
GL( glShaderSource( program->FragmentShader, 1, &fragmentSource, 0 ) );
GL( glCompileShader( program->FragmentShader ) );
GL( glGetShaderiv( program->FragmentShader, GL_COMPILE_STATUS, &r ) );
if ( r == GL_FALSE )
{
GLchar msg[4096];
GL( glGetShaderInfoLog( program->FragmentShader, sizeof( msg ), 0, msg ) );
ALOGE( "%s\n%s\n", fragmentSource, msg );
return false;
}
GL( program->Program = glCreateProgram() );
GL( glAttachShader( program->Program, program->VertexShader ) );
GL( glAttachShader( program->Program, program->FragmentShader ) );
// Bind the vertex attribute locations.
for ( int i = 0; i < sizeof( ProgramVertexAttributes ) / sizeof( ProgramVertexAttributes[0] ); i++ )
{
GL( glBindAttribLocation( program->Program, ProgramVertexAttributes[i].location, ProgramVertexAttributes[i].name ) );
}
GL( glLinkProgram( program->Program ) );
GL( glGetProgramiv( program->Program, GL_LINK_STATUS, &r ) );
if ( r == GL_FALSE )
{
GLchar msg[4096];
GL( glGetProgramInfoLog( program->Program, sizeof( msg ), 0, msg ) );
ALOGE( "Linking program failed: %s\n", msg );
return false;
}
int numBufferBindings = 0;
// Get the uniform locations.
memset( program->UniformLocation, -1, sizeof( program->UniformLocation ) );
for ( int i = 0; i < sizeof( ProgramUniforms ) / sizeof( ProgramUniforms[0] ); i++ )
{
const int uniformIndex = ProgramUniforms[i].index;
if ( ProgramUniforms[i].type == UNIFORM_TYPE_BUFFER )
{
GL( program->UniformLocation[uniformIndex] = glGetUniformBlockIndex( program->Program, ProgramUniforms[i].name ) );
program->UniformBinding[uniformIndex] = numBufferBindings++;
GL( glUniformBlockBinding( program->Program, program->UniformLocation[uniformIndex], program->UniformBinding[uniformIndex] ) );
}
else
{
GL( program->UniformLocation[uniformIndex] = glGetUniformLocation( program->Program, ProgramUniforms[i].name ) );
program->UniformBinding[uniformIndex] = program->UniformLocation[uniformIndex];
}
}
renderState state;
getCurrentRenderState(&state);
GL( glUseProgram( program->Program ) );
// Get the texture locations.
for ( int i = 0; i < MAX_PROGRAM_TEXTURES; i++ )
{
char name[32];
sprintf( name, "Texture%i", i );
program->Textures[i] = glGetUniformLocation( program->Program, name );
if ( program->Textures[i] != -1 )
{
GL( glUniform1i( program->Textures[i], i ) );
}
}
restoreRenderState(&state);
return true;
}
static void ovrProgram_Destroy( ovrProgram * program )
{
if ( program->Program != 0 )
{
GL( glDeleteProgram( program->Program ) );
program->Program = 0;
}
if ( program->VertexShader != 0 )
{
GL( glDeleteShader( program->VertexShader ) );
program->VertexShader = 0;
}
if ( program->FragmentShader != 0 )
{
GL( glDeleteShader( program->FragmentShader ) );
program->FragmentShader = 0;
}
}
static const char VERTEX_SHADER[] =
"#version 300 es\n"
"in vec3 vertexPosition;\n"
"in vec4 vertexColor;\n"
"uniform mat4 viewProjectionMatrix;\n"
"out vec4 fragmentColor;\n"
"void main()\n"
"{\n"
" gl_Position = viewProjectionMatrix * vec4( vertexPosition, 1.0 );\n"
" fragmentColor = vertexColor;\n"
"}\n";
static const char FRAGMENT_SHADER[] =
"#version 300 es\n"
"in lowp vec4 fragmentColor;\n"
"out lowp vec4 outColor;\n"
"void main()\n"
"{\n"
" outColor = fragmentColor;\n"
"}\n";
/*
================================================================================
ovrScene
================================================================================
*/
void ovrScene_Clear( ovrScene * scene )
{
scene->CreatedScene = false;
scene->CreatedVAOs = false;
ovrProgram_Clear( &scene->Program );
ovrGeometry_Clear( &scene->GroundPlane );
ovrRenderer_Clear( &scene->CylinderRenderer );
scene->CylinderWidth = 0;
scene->CylinderHeight = 0;
}
bool ovrScene_IsCreated( ovrScene * scene )
{
return scene->CreatedScene;
}
void ovrScene_CreateVAOs( ovrScene * scene )
{
if ( !scene->CreatedVAOs )
{
ovrGeometry_CreateVAO( &scene->GroundPlane );
scene->CreatedVAOs = true;
}
}
void ovrScene_DestroyVAOs( ovrScene * scene )
{
if ( scene->CreatedVAOs )
{
ovrGeometry_DestroyVAO( &scene->GroundPlane );
scene->CreatedVAOs = false;
}
}
void ovrScene_Create( int width, int height, ovrScene * scene, const ovrJava * java )
{
// Simple ground plane geometry.
{
ovrProgram_Create( &scene->Program, VERTEX_SHADER, FRAGMENT_SHADER );
ovrGeometry_CreateGroundPlane( &scene->GroundPlane );
ovrScene_CreateVAOs( scene );
}
// Create Cylinder renderer
{
scene->CylinderWidth = width;
scene->CylinderHeight = height;
//Create cylinder renderer
ovrRenderer_Create( width, height, &scene->CylinderRenderer, java );
}
scene->CreatedScene = true;
}
void ovrScene_Destroy( ovrScene * scene )
{
ovrScene_DestroyVAOs( scene );
ovrProgram_Destroy( &scene->Program );
ovrGeometry_Destroy( &scene->GroundPlane );
ovrRenderer_Destroy( &scene->CylinderRenderer );
scene->CreatedScene = false;
}
/*
================================================================================
ovrRenderer
================================================================================
*/
ovrLayerProjection2 ovrRenderer_RenderGroundPlaneToEyeBuffer( ovrRenderer * renderer, const ovrJava * java,
const ovrScene * scene, const ovrTracking2 * tracking )
{
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
layer.HeadPose = tracking->HeadPose;
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
{
ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[eye];
layer.Textures[eye].ColorSwapChain = frameBuffer->ColorTextureSwapChain;
layer.Textures[eye].SwapChainIndex = frameBuffer->ProcessingTextureSwapChainIndex;
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &tracking->Eye[eye].ProjectionMatrix );
}
layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
{
ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[eye];
ovrFramebuffer_SetCurrent( frameBuffer );
renderState state;
getCurrentRenderState(&state);
GL( glUseProgram( scene->Program.Program ) );
ovrMatrix4f viewProjMatrix = ovrMatrix4f_Multiply( &tracking->Eye[eye].ProjectionMatrix, &tracking->Eye[eye].ViewMatrix );
glUniformMatrix4fv( scene->Program.UniformLocation[UNIFORM_VIEW_PROJ_MATRIX], 1, GL_TRUE, &viewProjMatrix.M[0][0] );
GL( glEnable( GL_SCISSOR_TEST ) );
GL( glDepthMask( GL_TRUE ) );
GL( glEnable( GL_DEPTH_TEST ) );
GL( glDepthFunc( GL_LEQUAL ) );
GL( glEnable( GL_CULL_FACE ) );
GL( glCullFace( GL_BACK ) );
GL( glViewport( 0, 0, frameBuffer->Width, frameBuffer->Height ) );
GL( glScissor( 0, 0, frameBuffer->Width, frameBuffer->Height ) );
GL( glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ) );
GL( glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) );
//bind buffers
GL( glBindBuffer( GL_ARRAY_BUFFER, scene->GroundPlane.VertexBuffer ) );
GL( glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, scene->GroundPlane.IndexBuffer ) );
GL( glBindVertexArray( scene->GroundPlane.VertexArrayObject ) );
GL( glDrawElements( GL_TRIANGLES, scene->GroundPlane.IndexCount, GL_UNSIGNED_SHORT, NULL ) );
restoreRenderState(&state);
// Explicitly clear the border texels to black when GL_CLAMP_TO_BORDER is not available.
ovrFramebuffer_ClearEdgeTexels( frameBuffer );
ovrFramebuffer_Resolve( frameBuffer );
ovrFramebuffer_Advance( frameBuffer );
}
ovrFramebuffer_SetNone();
return layer;
}
// Assumes landscape cylinder shape.
static ovrMatrix4f CylinderModelMatrix( const int texWidth, const int texHeight,
const ovrVector3f translation,
const float rotateYaw,
const float rotatePitch,
const float radius,
const float density )
{
const ovrMatrix4f scaleMatrix = ovrMatrix4f_CreateScale( radius, radius * (float)texHeight * VRAPI_PI / density, radius );
const ovrMatrix4f transMatrix = ovrMatrix4f_CreateTranslation( translation.x, translation.y, translation.z );
const ovrMatrix4f rotXMatrix = ovrMatrix4f_CreateRotation( rotateYaw, 0.0f, 0.0f );
const ovrMatrix4f rotYMatrix = ovrMatrix4f_CreateRotation( 0.0f, rotatePitch, 0.0f );
const ovrMatrix4f m0 = ovrMatrix4f_Multiply( &transMatrix, &scaleMatrix );
const ovrMatrix4f m1 = ovrMatrix4f_Multiply( &rotXMatrix, &m0 );
const ovrMatrix4f m2 = ovrMatrix4f_Multiply( &rotYMatrix, &m1 );
return m2;
}
ovrLayerCylinder2 BuildCylinderLayer( ovrRenderer * cylinderRenderer,
const int textureWidth, const int textureHeight,
const ovrTracking2 * tracking, float rotatePitch )
{
ovrLayerCylinder2 layer = vrapi_DefaultLayerCylinder2();
const float fadeLevel = 1.0f;
layer.Header.ColorScale.x =
layer.Header.ColorScale.y =
layer.Header.ColorScale.z =
layer.Header.ColorScale.w = fadeLevel;
layer.Header.SrcBlend = VRAPI_FRAME_LAYER_BLEND_SRC_ALPHA;
layer.Header.DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA;
//layer.Header.Flags = VRAPI_FRAME_LAYER_FLAG_CLIP_TO_TEXTURE_RECT;
layer.HeadPose = tracking->HeadPose;
const float density = 4500.0f;
const float rotateYaw = 0.0f;
const float radius = 4.0f;
const ovrVector3f translation = { 0.0f, 0.0f, -2.5f };
ovrMatrix4f cylinderTransform =
CylinderModelMatrix( textureWidth, textureHeight, translation,
rotateYaw, rotatePitch, radius, density );
const float circScale = density * 0.5f / textureWidth;
const float circBias = -circScale * ( 0.5f * ( 1.0f - 1.0f / circScale ) );
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
{
ovrFramebuffer * cylinderFrameBuffer = &cylinderRenderer->FrameBuffer[eye];
ovrMatrix4f modelViewMatrix = ovrMatrix4f_Multiply( &tracking->Eye[eye].ViewMatrix, &cylinderTransform );
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_Inverse( &modelViewMatrix );
layer.Textures[eye].ColorSwapChain = cylinderFrameBuffer->ColorTextureSwapChain;
layer.Textures[eye].SwapChainIndex = cylinderFrameBuffer->ReadyTextureSwapChainIndex;
// Texcoord scale and bias is just a representation of the aspect ratio. The positioning
// of the cylinder is handled entirely by the TexCoordsFromTanAngles matrix.
const float texScaleX = circScale;
const float texBiasX = circBias;
const float texScaleY = -0.5f;
const float texBiasY = texScaleY * ( 0.5f * ( 1.0f - ( 1.0f / texScaleY ) ) );
layer.Textures[eye].TextureMatrix.M[0][0] = texScaleX;
layer.Textures[eye].TextureMatrix.M[0][2] = texBiasX;
layer.Textures[eye].TextureMatrix.M[1][1] = texScaleY;
layer.Textures[eye].TextureMatrix.M[1][2] = -texBiasY;
layer.Textures[eye].TextureRect.width = 1.0f;
layer.Textures[eye].TextureRect.height = 1.0f;
}
return layer;
}

View file

@ -1,217 +0,0 @@
/************************************************************************************
Filename : VrCompositor.h
*************************************************************************************/
#include "VrInput.h"
#define CHECK_GL_ERRORS
#ifdef CHECK_GL_ERRORS
static const char * GlErrorString( GLenum error )
{
switch ( error )
{
case GL_NO_ERROR: return "GL_NO_ERROR";
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION";
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
default: return "unknown";
}
}
static void GLCheckErrors( int line )
{
for ( int i = 0; i < 10; i++ )
{
const GLenum error = glGetError();
if ( error == GL_NO_ERROR )
{
break;
}
ALOGE( "GL error on line %d: %s", line, GlErrorString( error ) );
}
}
#define GL( func ) func; GLCheckErrors( __LINE__ );
#else // CHECK_GL_ERRORS
#define GL( func ) func;
#endif // CHECK_GL_ERRORS
/*
================================================================================
ovrFramebuffer
================================================================================
*/
typedef struct
{
int Width;
int Height;
int Multisamples;
int TextureSwapChainLength;
int ProcessingTextureSwapChainIndex;
int ReadyTextureSwapChainIndex;
ovrTextureSwapChain * ColorTextureSwapChain;
GLuint * DepthBuffers;
GLuint * FrameBuffers;
} ovrFramebuffer;
void ovrFramebuffer_SetCurrent( ovrFramebuffer * frameBuffer );
void ovrFramebuffer_Destroy( ovrFramebuffer * frameBuffer );
void ovrFramebuffer_SetNone();
void ovrFramebuffer_Resolve( ovrFramebuffer * frameBuffer );
void ovrFramebuffer_Advance( ovrFramebuffer * frameBuffer );
void ovrFramebuffer_ClearEdgeTexels( ovrFramebuffer * frameBuffer );
/*
================================================================================
ovrRenderer
================================================================================
*/
typedef struct
{
ovrFramebuffer FrameBuffer[VRAPI_FRAME_LAYER_EYE_MAX];
int NumBuffers;
} ovrRenderer;
void ovrRenderer_Clear( ovrRenderer * renderer );
void ovrRenderer_Create( int width, int height, ovrRenderer * renderer, const ovrJava * java );
void ovrRenderer_Destroy( ovrRenderer * renderer );
/*
================================================================================
renderState
================================================================================
*/
typedef struct
{
GLint VertexBuffer;
GLint IndexBuffer;
GLint VertexArrayObject;
GLint Program;
GLint VertexShader;
GLint FragmentShader;
} renderState;
void getCurrentRenderState( renderState * state);
void restoreRenderState( renderState * state );
/*
================================================================================
ovrGeometry
================================================================================
*/
typedef struct
{
GLint Index;
GLint Size;
GLenum Type;
GLboolean Normalized;
GLsizei Stride;
const GLvoid * Pointer;
} ovrVertexAttribPointer;
#define MAX_VERTEX_ATTRIB_POINTERS 3
typedef struct
{
GLuint VertexBuffer;
GLuint IndexBuffer;
GLuint VertexArrayObject;
int VertexCount;
int IndexCount;
ovrVertexAttribPointer VertexAttribs[MAX_VERTEX_ATTRIB_POINTERS];
} ovrGeometry;
/*
================================================================================
ovrProgram
================================================================================
*/
#define MAX_PROGRAM_UNIFORMS 8
#define MAX_PROGRAM_TEXTURES 8
typedef struct
{
GLuint Program;
GLuint VertexShader;
GLuint FragmentShader;
// These will be -1 if not used by the program.
GLint UniformLocation[MAX_PROGRAM_UNIFORMS]; // ProgramUniforms[].name
GLint UniformBinding[MAX_PROGRAM_UNIFORMS]; // ProgramUniforms[].name
GLint Textures[MAX_PROGRAM_TEXTURES]; // Texture%i
} ovrProgram;
/*
================================================================================
ovrScene
================================================================================
*/
typedef struct
{
bool CreatedScene;
bool CreatedVAOs;
ovrProgram Program;
ovrGeometry GroundPlane;
//Proper renderer for stereo rendering to the cylinder layer
ovrRenderer CylinderRenderer;
int CylinderWidth;
int CylinderHeight;
} ovrScene;
bool ovrScene_IsCreated( ovrScene * scene );
void ovrScene_Clear( ovrScene * scene );
void ovrScene_Create( int width, int height, ovrScene * scene, const ovrJava * java );
void ovrScene_CreateVAOs( ovrScene * scene );
void ovrScene_DestroyVAOs( ovrScene * scene );
void ovrScene_Destroy( ovrScene * scene );
/*
================================================================================
ovrRenderer
================================================================================
*/
ovrLayerProjection2 ovrRenderer_RenderGroundPlaneToEyeBuffer( ovrRenderer * renderer, const ovrJava * java,
const ovrScene * scene, const ovrTracking2 * tracking );
ovrLayerProjection2 ovrRenderer_RenderToEyeBuffer( ovrRenderer * renderer, const ovrJava * java,
const ovrTracking2 * tracking );
ovrLayerCylinder2 BuildCylinderLayer( ovrRenderer * cylinderRenderer,
const int textureWidth, const int textureHeight,
const ovrTracking2 * tracking, float rotateYaw );
;

View file

@ -5,12 +5,25 @@
#include "VrCommon.h"
extern ovrInputStateTrackedRemote leftTrackedRemoteState_old;
extern ovrInputStateTrackedRemote leftTrackedRemoteState_new;
extern ovrTrackedController leftRemoteTracking_new;
void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime);
extern ovrInputStateTrackedRemote rightTrackedRemoteState_old;
extern ovrInputStateTrackedRemote rightTrackedRemoteState_new;
extern ovrTrackedController rightRemoteTracking_new;
void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackingNew, ovrInputStateGamepad *pFootTrackingOld, ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking,
ovrInputStateTrackedRemote *pOffTrackedRemoteNew, ovrInputStateTrackedRemote *pOffTrackedRemoteOld, ovrTracking* pOffTracking,
extern float remote_movementSideways;
extern float remote_movementForward;
extern float remote_movementUp;
extern float positional_movementSideways;
extern float positional_movementForward;
extern float snapTurn;
void HandleInput_Default( int control_scheme, ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTrackedController* pDominantTracking,
ovrInputStateTrackedRemote *pOffTrackedRemoteNew, ovrInputStateTrackedRemote *pOffTrackedRemoteOld, ovrTrackedController* pOffTracking,
int domButton1, int domButton2, int offButton1, int offButton2 );

View file

@ -1,160 +0,0 @@
/************************************************************************************
Filename : VrInputRight.c
Content : Handles common controller input functionality
Created : September 2019
Authors : Simon Brown
*************************************************************************************/
#include <VrApi.h>
#include <VrApi_Helpers.h>
#include <VrApi_SystemUtils.h>
#include <VrApi_Input.h>
#include <VrApi_Types.h>
#include "VrInput.h"
ovrInputStateTrackedRemote leftTrackedRemoteState_old;
ovrInputStateTrackedRemote leftTrackedRemoteState_new;
ovrTracking leftRemoteTracking_new;
ovrInputStateTrackedRemote rightTrackedRemoteState_old;
ovrInputStateTrackedRemote rightTrackedRemoteState_new;
ovrTracking rightRemoteTracking_new;
ovrInputStateGamepad footTrackedRemoteState_old;
ovrInputStateGamepad footTrackedRemoteState_new;
ovrDeviceID controllerIDs[2];
float remote_movementSideways;
float remote_movementForward;
float remote_movementUp;
float positional_movementSideways;
float positional_movementForward;
float snapTurn;
float cinemamodeYaw;
float cinemamodePitch;
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, int base);
void handleTrackedControllerButton(ovrInputStateTrackedRemote * trackedRemoteState, ovrInputStateTrackedRemote * prevTrackedRemoteState, uint32_t button, int key)
{
Joy_GenerateButtonEvents(prevTrackedRemoteState->Buttons & button ? 1 : 0, trackedRemoteState->Buttons & button ? 1 : 0, 1, key);
}
static void Matrix4x4_Transform (const matrix4x4 *in, const float v[3], float out[3])
{
out[0] = v[0] * (*in)[0][0] + v[1] * (*in)[0][1] + v[2] * (*in)[0][2] + (*in)[0][3];
out[1] = v[0] * (*in)[1][0] + v[1] * (*in)[1][1] + v[2] * (*in)[1][2] + (*in)[1][3];
out[2] = v[0] * (*in)[2][0] + v[1] * (*in)[2][1] + v[2] * (*in)[2][2] + (*in)[2][3];
}
void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale );
void rotateAboutOrigin(float v1, float v2, float rotation, vec2_t out)
{
vec3_t temp = {0.0f, 0.0f, 0.0f};
temp[0] = v1;
temp[1] = v2;
vec3_t v = {0.0f, 0.0f, 0.0f};
matrix4x4 matrix;
vec3_t angles = {0.0f, rotation, 0.0f};
vec3_t origin = {0.0f, 0.0f, 0.0f};
Matrix4x4_CreateFromEntity(matrix, angles, origin, 1.0f);
Matrix4x4_Transform(&matrix, temp, v);
out[0] = v[0];
out[1] = v[1];
}
float length(float x, float y)
{
return sqrtf(powf(x, 2.0f) + powf(y, 2.0f));
}
#define NLF_DEADZONE 0.1
#define NLF_POWER 2.2
float nonLinearFilter(float in)
{
float val = 0.0f;
if (in > NLF_DEADZONE)
{
val = in;
val -= NLF_DEADZONE;
val /= (1.0f - NLF_DEADZONE);
val = powf(val, NLF_POWER);
}
else if (in < -NLF_DEADZONE)
{
val = in;
val += NLF_DEADZONE;
val /= (1.0f - NLF_DEADZONE);
val = -powf(fabsf(val), NLF_POWER);
}
return val;
}
bool between(float min, float val, float max)
{
return (min < val) && (val < max);
}
void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime) {//The amount of yaw changed by controller
for ( int i = 0; ; i++ ) {
ovrInputCapabilityHeader capsHeader;
ovrResult result = vrapi_EnumerateInputDevices(Ovr, i, &capsHeader);
if (result < 0) {
break;
}
if (capsHeader.Type == ovrControllerType_Gamepad) {
ovrInputGamepadCapabilities remoteCaps;
remoteCaps.Header = capsHeader;
if (vrapi_GetInputDeviceCapabilities(Ovr, &remoteCaps.Header) >= 0) {
// remote is connected
ovrInputStateGamepad remoteState;
remoteState.Header.ControllerType = ovrControllerType_Gamepad;
if ( vrapi_GetCurrentInputState( Ovr, capsHeader.DeviceID, &remoteState.Header ) >= 0 )
{
// act on device state returned in remoteState
footTrackedRemoteState_new = remoteState;
}
}
}
else if (capsHeader.Type == ovrControllerType_TrackedRemote) {
ovrTracking remoteTracking;
ovrInputTrackedRemoteCapabilities remoteCaps;
remoteCaps.Header = capsHeader;
if ( vrapi_GetInputDeviceCapabilities( Ovr, &remoteCaps.Header ) >= 0 )
{
// remote is connected
ovrInputStateTrackedRemote remoteState;
remoteState.Header.ControllerType = ovrControllerType_TrackedRemote;
if(vrapi_GetCurrentInputState(Ovr, capsHeader.DeviceID, &remoteState.Header) >= 0) {
if (vrapi_GetInputTrackingState(Ovr, capsHeader.DeviceID, displayTime,
&remoteTracking) >= 0) {
// act on device state returned in remoteState
if (remoteCaps.ControllerCapabilities & ovrControllerCaps_RightHand) {
rightTrackedRemoteState_new = remoteState;
rightRemoteTracking_new = remoteTracking;
controllerIDs[1] = capsHeader.DeviceID;
} else {
leftTrackedRemoteState_new = remoteState;
leftRemoteTracking_new = remoteTracking;
controllerIDs[0] = capsHeader.DeviceID;
}
}
}
}
}
}
}

View file

@ -0,0 +1,98 @@
/************************************************************************************
Filename : VrInputRight.c
Content : Handles common controller input functionality
Created : September 2019
Authors : Simon Brown
*************************************************************************************/
#include "VrInput.h"
ovrInputStateTrackedRemote leftTrackedRemoteState_old;
ovrInputStateTrackedRemote leftTrackedRemoteState_new;
ovrTrackedController leftRemoteTracking_new;
ovrInputStateTrackedRemote rightTrackedRemoteState_old;
ovrInputStateTrackedRemote rightTrackedRemoteState_new;
ovrTrackedController rightRemoteTracking_new;
float remote_movementSideways;
float remote_movementForward;
float remote_movementUp;
float positional_movementSideways;
float positional_movementForward;
float snapTurn;
float cinemamodeYaw;
float cinemamodePitch;
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, int base);
void handleTrackedControllerButton(ovrInputStateTrackedRemote * trackedRemoteState, ovrInputStateTrackedRemote * prevTrackedRemoteState, uint32_t button, int key)
{
Joy_GenerateButtonEvents(prevTrackedRemoteState->Buttons & button ? 1 : 0, trackedRemoteState->Buttons & button ? 1 : 0, 1, key);
}
static void Matrix4x4_Transform (const matrix4x4 *in, const float v[3], float out[3])
{
out[0] = v[0] * (*in)[0][0] + v[1] * (*in)[0][1] + v[2] * (*in)[0][2] + (*in)[0][3];
out[1] = v[0] * (*in)[1][0] + v[1] * (*in)[1][1] + v[2] * (*in)[1][2] + (*in)[1][3];
out[2] = v[0] * (*in)[2][0] + v[1] * (*in)[2][1] + v[2] * (*in)[2][2] + (*in)[2][3];
}
void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale );
void rotateAboutOrigin(float v1, float v2, float rotation, vec2_t out)
{
vec3_t temp = {0.0f, 0.0f, 0.0f};
temp[0] = v1;
temp[1] = v2;
vec3_t v = {0.0f, 0.0f, 0.0f};
matrix4x4 matrix;
vec3_t angles = {0.0f, rotation, 0.0f};
vec3_t origin = {0.0f, 0.0f, 0.0f};
Matrix4x4_CreateFromEntity(matrix, angles, origin, 1.0f);
Matrix4x4_Transform(&matrix, temp, v);
out[0] = v[0];
out[1] = v[1];
}
float length(float x, float y)
{
return sqrtf(powf(x, 2.0f) + powf(y, 2.0f));
}
#define NLF_DEADZONE 0.1
#define NLF_POWER 2.2
float nonLinearFilter(float in)
{
float val = 0.0f;
if (in > NLF_DEADZONE)
{
val = in > 1.0f ? 1.0f : in;
val -= NLF_DEADZONE;
val /= (1.0f - NLF_DEADZONE);
val = powf(val, NLF_POWER);
}
else if (in < -NLF_DEADZONE)
{
val = in < -1.0f ? -1.0f : in;
val += NLF_DEADZONE;
val /= (1.0f - NLF_DEADZONE);
val = -powf(fabsf(val), NLF_POWER);
}
return val;
}
bool between(float min, float val, float max)
{
return (min < val) && (val < max);
}

View file

@ -7,11 +7,7 @@ Authors : Simon Brown
*************************************************************************************/
#include <VrApi.h>
#include <VrApi_Helpers.h>
#include <VrApi_SystemUtils.h>
#include <VrApi_Input.h>
#include <VrApi_Types.h>
#include <android/keycodes.h>
#include "VrInput.h"
@ -20,17 +16,11 @@ Authors : Simon Brown
extern ovrInputStateTrackedRemote leftTrackedRemoteState_old;
extern ovrInputStateTrackedRemote leftTrackedRemoteState_new;
extern ovrTracking leftRemoteTracking_new;
extern ovrTrackedController leftRemoteTracking_new;
extern ovrInputStateTrackedRemote rightTrackedRemoteState_old;
extern ovrInputStateTrackedRemote rightTrackedRemoteState_new;
extern ovrTracking rightRemoteTracking_new;
extern ovrInputStateGamepad footTrackedRemoteState_old;
extern ovrInputStateGamepad footTrackedRemoteState_new;
extern ovrDeviceID controllerIDs[2];
extern ovrTrackedController rightRemoteTracking_new;
extern float remote_movementSideways;
extern float remote_movementForward;
@ -42,29 +32,30 @@ extern float snapTurn;
extern float cinemamodeYaw;
extern float cinemamodePitch;
extern bool weaponStabilised;
int getGameState();
int getMenuState();
void Joy_GenerateButtonEvents(int oldbuttons, int newbuttons, int numbuttons, int base);
float getViewpointYaw();
void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackingNew, ovrInputStateGamepad *pFootTrackingOld,
ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking,
ovrInputStateTrackedRemote *pOffTrackedRemoteNew, ovrInputStateTrackedRemote *pOffTrackedRemoteOld, ovrTracking* pOffTracking,
void HandleInput_Default( int control_scheme, ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTrackedController* pDominantTracking,
ovrInputStateTrackedRemote *pOffTrackedRemoteNew, ovrInputStateTrackedRemote *pOffTrackedRemoteOld, ovrTrackedController* pOffTracking,
int domButton1, int domButton2, int offButton1, int offButton2 )
{
//Menu button - invoke menu
handleTrackedControllerButton(&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, ovrButton_Enter, KEY_ESCAPE);
handleTrackedControllerButton(&rightTrackedRemoteState_new, &rightTrackedRemoteState_old, ovrButton_Enter, KEY_ESCAPE); // For users who have switched the buttons
handleTrackedControllerButton(&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, xrButton_Enter, KEY_ESCAPE);
handleTrackedControllerButton(&rightTrackedRemoteState_new, &rightTrackedRemoteState_old, xrButton_Enter, KEY_ESCAPE); // For users who have switched the buttons
//Dominant Grip works like a shift key
bool dominantGripPushedOld = vr_secondarybuttonmappings ?
(pDominantTrackedRemoteOld->Buttons & ovrButton_GripTrigger) != 0 : false;
bool dominantGripPushedNew = vr_secondarybuttonmappings ?
(pDominantTrackedRemoteNew->Buttons & ovrButton_GripTrigger) != 0 : false;
bool dominantGripPushedOld = vr_secondary_button_mappings ?
(pDominantTrackedRemoteOld->Buttons & xrButton_GripTrigger) : false;
bool dominantGripPushedNew = vr_secondary_button_mappings ?
(pDominantTrackedRemoteNew->Buttons & xrButton_GripTrigger) : false;
ovrInputStateTrackedRemote *pPrimaryTrackedRemoteNew, *pPrimaryTrackedRemoteOld, *pSecondaryTrackedRemoteNew, *pSecondaryTrackedRemoteOld;
if (vr_switchsticks)
if (vr_switch_sticks)
{
pPrimaryTrackedRemoteNew = pOffTrackedRemoteNew;
pPrimaryTrackedRemoteOld = pOffTrackedRemoteOld;
@ -129,19 +120,19 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
// Only do the following if we are definitely not in the menu
if (getMenuState() == 0)
{
float distance = sqrtf(powf(pOffTracking->HeadPose.Pose.Position.x -
pDominantTracking->HeadPose.Pose.Position.x, 2) +
powf(pOffTracking->HeadPose.Pose.Position.y -
pDominantTracking->HeadPose.Pose.Position.y, 2) +
powf(pOffTracking->HeadPose.Pose.Position.z -
pDominantTracking->HeadPose.Pose.Position.z, 2));
float distance = sqrtf(powf(pOffTracking->Pose.position.x -
pDominantTracking->Pose.position.x, 2) +
powf(pOffTracking->Pose.position.y -
pDominantTracking->Pose.position.y, 2) +
powf(pOffTracking->Pose.position.z -
pDominantTracking->Pose.position.z, 2));
//Turn on weapon stabilisation?
if (vr_twohandedweapons &&
(pOffTrackedRemoteNew->Buttons & ovrButton_GripTrigger) !=
(pOffTrackedRemoteOld->Buttons & ovrButton_GripTrigger)) {
if (vr_two_handed_weapons &&
(pOffTrackedRemoteNew->Buttons & xrButton_GripTrigger) !=
(pOffTrackedRemoteOld->Buttons & xrButton_GripTrigger)) {
if (pOffTrackedRemoteNew->Buttons & ovrButton_GripTrigger) {
if (pOffTrackedRemoteNew->Buttons & xrButton_GripTrigger) {
if (distance < 0.50f) {
weaponStabilised = true;
}
@ -153,9 +144,9 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
//dominant hand stuff first
{
///Weapon location relative to view
weaponoffset[0] = pDominantTracking->HeadPose.Pose.Position.x - hmdPosition[0];
weaponoffset[1] = pDominantTracking->HeadPose.Pose.Position.y - hmdPosition[1];
weaponoffset[2] = pDominantTracking->HeadPose.Pose.Position.z - hmdPosition[2];
weaponoffset[0] = pDominantTracking->Pose.position.x - hmdPosition[0];
weaponoffset[1] = pDominantTracking->Pose.position.y - hmdPosition[1];
weaponoffset[2] = pDominantTracking->Pose.position.z - hmdPosition[2];
vec2_t v;
float yawRotation = getViewpointYaw() - hmdorientation[YAW];
@ -164,23 +155,22 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
weaponoffset[2] = v[0];
//Set gun angles
const ovrQuatf quatRemote = pDominantTracking->HeadPose.Pose.Orientation;
vec3_t rotation = {0};
rotation[PITCH] = vr_weapon_pitchadjust;
QuatToYawPitchRoll(quatRemote, rotation, weaponangles);
rotation[PITCH] = vr_weaponRotate;
QuatToYawPitchRoll(pDominantTracking->Pose.orientation, rotation, weaponangles);
if (weaponStabilised) {
float z = pOffTracking->HeadPose.Pose.Position.z -
pDominantTracking->HeadPose.Pose.Position.z;
float x = pOffTracking->HeadPose.Pose.Position.x -
pDominantTracking->HeadPose.Pose.Position.x;
float y = pOffTracking->HeadPose.Pose.Position.y -
pDominantTracking->HeadPose.Pose.Position.y;
float z = pOffTracking->Pose.position.z -
pDominantTracking->Pose.position.z;
float x = pOffTracking->Pose.position.x -
pDominantTracking->Pose.position.x;
float y = pOffTracking->Pose.position.y -
pDominantTracking->Pose.position.y;
float zxDist = length(x, z);
if (zxDist != 0.0f && z != 0.0f) {
VectorSet(weaponangles, -degrees(atanf(y / zxDist)), -degrees(atan2f(x, -z)),
VectorSet(weaponangles, -RAD2DEG(atanf(y / zxDist)), -RAD2DEG(atan2f(x, -z)),
weaponangles[ROLL]);
}
}
@ -190,9 +180,9 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
//off-hand stuff
{
offhandoffset[0] = pOffTracking->HeadPose.Pose.Position.x - hmdPosition[0];
offhandoffset[1] = pOffTracking->HeadPose.Pose.Position.y - hmdPosition[1];
offhandoffset[2] = pOffTracking->HeadPose.Pose.Position.z - hmdPosition[2];
offhandoffset[0] = pOffTracking->Pose.position.x - hmdPosition[0];
offhandoffset[1] = pOffTracking->Pose.position.y - hmdPosition[1];
offhandoffset[2] = pOffTracking->Pose.position.z - hmdPosition[2];
vec2_t v;
float yawRotation = getViewpointYaw() - hmdorientation[YAW];
@ -201,10 +191,10 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
offhandoffset[2] = v[0];
vec3_t rotation = {0};
rotation[PITCH] = vr_weapon_pitchadjust;
QuatToYawPitchRoll(pOffTracking->HeadPose.Pose.Orientation, rotation, offhandangles);
rotation[PITCH] = vr_weaponRotate;
QuatToYawPitchRoll(pOffTracking->Pose.orientation, rotation, offhandangles);
if (vr_moveuseoffhand) {
if (vr_move_use_offhand) {
controllerYawHeading = offhandangles[YAW] - hmdorientation[YAW];
} else {
controllerYawHeading = 0.0f;
@ -214,9 +204,9 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
//Positional movement
{
ALOGV(" Right-Controller-Position: %f, %f, %f",
pDominantTracking->HeadPose.Pose.Position.x,
pDominantTracking->HeadPose.Pose.Position.y,
pDominantTracking->HeadPose.Pose.Position.z);
pDominantTracking->Pose.position.x,
pDominantTracking->Pose.position.y,
pDominantTracking->Pose.position.z);
vec2_t v;
rotateAboutOrigin(positionDeltaThisFrame[0], positionDeltaThisFrame[2],
@ -232,12 +222,12 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
//Off-hand specific stuff
{
ALOGV(" Left-Controller-Position: %f, %f, %f",
pOffTracking->HeadPose.Pose.Position.x,
pOffTracking->HeadPose.Pose.Position.y,
pOffTracking->HeadPose.Pose.Position.z);
pOffTracking->Pose.position.x,
pOffTracking->Pose.position.y,
pOffTracking->Pose.position.z);
//Teleport - only does anything if vr_teleport cvar is true
if (vr_use_teleport) {
if (vr_teleport) {
if ((pSecondaryTrackedRemoteOld->Joystick.y > 0.7f) && !ready_teleport) {
ready_teleport = true;
} else if ((pSecondaryTrackedRemoteOld->Joystick.y < 0.7f) && ready_teleport) {
@ -250,8 +240,9 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
//and we don't get movement jitter when the joystick doesn't quite center properly
float dist = length(pSecondaryTrackedRemoteNew->Joystick.x, pSecondaryTrackedRemoteNew->Joystick.y);
float nlf = nonLinearFilter(dist);
float x = nlf * pSecondaryTrackedRemoteNew->Joystick.x + pFootTrackingNew->LeftJoystick.x;
float y = nlf * pSecondaryTrackedRemoteNew->Joystick.y - pFootTrackingNew->LeftJoystick.y;
dist = (dist > 1.0f) ? dist : 1.0f;
float x = nlf * (pSecondaryTrackedRemoteNew->Joystick.x / dist);
float y = nlf * (pSecondaryTrackedRemoteNew->Joystick.y / dist);
//Apply a simple deadzone
player_moving = (fabs(x) + fabs(y)) > 0.05f;
@ -271,42 +262,44 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
if (!cinemamode && !dominantGripPushedNew)
{
// Turning logic
static int increaseSnap = true;
if (pPrimaryTrackedRemoteNew->Joystick.x > 0.6f) {
if (increaseSnap) {
resetDoomYaw = true;
snapTurn -= vr_snapturn_angle;
if (vr_snapturn_angle > 10.0f) {
increaseSnap = false;
}
static int decreaseSnap = true;
if (snapTurn < -180.0f) {
snapTurn += 360.f;
}
float joy = pPrimaryTrackedRemoteNew->Joystick.x;
if (vr_snapTurn <= 10.0f && abs(joy) > 0.05f)
{
increaseSnap = false;
decreaseSnap = false;
snapTurn -= vr_snapTurn * nonLinearFilter(joy);
}
// Turning logic
if (joy > 0.6f && increaseSnap) {
resetDoomYaw = true;
snapTurn -= vr_snapTurn;
if (vr_snapTurn > 10.0f) {
increaseSnap = false;
}
} else if (pPrimaryTrackedRemoteNew->Joystick.x < 0.4f) {
} else if (joy < 0.4f) {
increaseSnap = true;
}
static int decreaseSnap = true;
if (pPrimaryTrackedRemoteNew->Joystick.x < -0.6f) {
if (decreaseSnap) {
resetDoomYaw = true;
snapTurn += vr_snapturn_angle;
//If snap turn configured for less than 10 degrees
if (vr_snapturn_angle > 10.0f) {
decreaseSnap = false;
}
if (snapTurn > 180.0f) {
snapTurn -= 360.f;
}
if (joy < -0.6f && decreaseSnap) {
resetDoomYaw = true;
snapTurn += vr_snapTurn;
if (vr_snapTurn > 10.0f) {
decreaseSnap = false;
}
} else if (pPrimaryTrackedRemoteNew->Joystick.x > -0.4f) {
} else if (joy > -0.4f) {
decreaseSnap = true;
}
if (snapTurn < -180.0f) {
snapTurn += 360.f;
}
else if (snapTurn > 180.0f) {
snapTurn -= 360.f;
}
}
}
}
@ -328,13 +321,13 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
//If snap turn set to 0, then we can use left/right on the stick as mappable functions
Joy_GenerateButtonEvents(
(pPrimaryTrackedRemoteOld->Joystick.x > 0.7f && !dominantGripPushedOld && !vr_snapturn_angle ? 1 : 0),
(pPrimaryTrackedRemoteNew->Joystick.x > 0.7f && !dominantGripPushedNew && !vr_snapturn_angle ? 1 : 0),
(pPrimaryTrackedRemoteOld->Joystick.x > 0.7f && !dominantGripPushedOld && !vr_snapTurn ? 1 : 0),
(pPrimaryTrackedRemoteNew->Joystick.x > 0.7f && !dominantGripPushedNew && !vr_snapTurn ? 1 : 0),
1, KEY_MWHEELLEFT);
Joy_GenerateButtonEvents(
(pPrimaryTrackedRemoteOld->Joystick.x < -0.7f && !dominantGripPushedOld && !vr_snapturn_angle ? 1 : 0),
(pPrimaryTrackedRemoteNew->Joystick.x < -0.7f && !dominantGripPushedNew && !vr_snapturn_angle ? 1 : 0),
(pPrimaryTrackedRemoteOld->Joystick.x < -0.7f && !dominantGripPushedOld && !vr_snapTurn ? 1 : 0),
(pPrimaryTrackedRemoteNew->Joystick.x < -0.7f && !dominantGripPushedNew && !vr_snapTurn ? 1 : 0),
1, KEY_MWHEELRIGHT);
}
@ -343,8 +336,8 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
{
//Fire
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Buttons & ovrButton_Trigger) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger) != 0) && !dominantGripPushedNew ? 1 : 0,
((pDominantTrackedRemoteOld->Buttons & xrButton_Trigger) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & xrButton_Trigger) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_PAD_RTRIGGER);
//"Use" (open door, toggle switch etc)
@ -361,24 +354,30 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
// Inv Use
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Buttons & ovrButton_Joystick) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) && !dominantGripPushedNew ? 1 : 0,
((pDominantTrackedRemoteOld->Buttons & xrButton_Joystick) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & xrButton_Joystick) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_ENTER);
//No Default Binding
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedNew ? 1 : 0,
((pDominantTrackedRemoteOld->Touches & xrButton_ThumbRest) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Touches & xrButton_ThumbRest) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_JOY5);
//Use grip as an extra button
//Alt-Fire
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Buttons & xrButton_GripTrigger) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & xrButton_GripTrigger) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_PAD_LTRIGGER);
}
//Dominant Hand - Secondary keys (grip pushed)
{
//Alt-Fire
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Buttons & ovrButton_Trigger) != 0) && dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & ovrButton_Trigger) != 0) && dominantGripPushedNew ? 1 : 0,
((pDominantTrackedRemoteOld->Buttons & xrButton_Trigger) != 0) && dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & xrButton_Trigger) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_PAD_LTRIGGER);
//Crouch
@ -391,26 +390,20 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
Joy_GenerateButtonEvents(
((primaryButtonsOld & primaryButton2) != 0) && dominantGripPushedOld ? 1 : 0,
((primaryButtonsNew & primaryButton2) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_RSHIFT);
1, KEY_BACKSPACE);
//No Binding
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Buttons & ovrButton_Joystick) != 0) && dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) && dominantGripPushedNew ? 1 : 0,
((pDominantTrackedRemoteOld->Buttons & xrButton_Joystick) != 0) && dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & xrButton_Joystick) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_TAB);
//No Default Binding
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedNew ? 1 : 0,
((pDominantTrackedRemoteOld->Touches & xrButton_ThumbRest) != 0) && dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Touches & xrButton_ThumbRest) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_JOY6);
//Use grip as an extra button
//Alt-Fire
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Buttons & ovrButton_GripTrigger) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Buttons & ovrButton_GripTrigger) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_PAD_LTRIGGER);
}
@ -418,8 +411,8 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
{
//No Default Binding
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Buttons & ovrButton_Trigger) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & ovrButton_Trigger) != 0) && !dominantGripPushedNew ? 1 : 0,
((pOffTrackedRemoteOld->Buttons & xrButton_Trigger) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & xrButton_Trigger) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_LSHIFT);
//No Default Binding
@ -436,19 +429,19 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
//"Use" (open door, toggle switch etc) - Can be rebound for other uses
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Buttons & ovrButton_Joystick) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) && !dominantGripPushedNew ? 1 : 0,
((pOffTrackedRemoteOld->Buttons & xrButton_Joystick) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & xrButton_Joystick) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_SPACE);
//No Default Binding
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedNew ? 1 : 0,
((pOffTrackedRemoteOld->Touches & xrButton_ThumbRest) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Touches & xrButton_ThumbRest) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_JOY7);
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Buttons & ovrButton_GripTrigger) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & ovrButton_GripTrigger) != 0) && !dominantGripPushedNew ? 1 : 0,
((pOffTrackedRemoteOld->Buttons & xrButton_GripTrigger) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & xrButton_GripTrigger) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_PAD_RTHUMB);
}
@ -456,8 +449,8 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
{
//No Default Binding
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Buttons & ovrButton_Trigger) != 0) && dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & ovrButton_Trigger) != 0) && dominantGripPushedNew ? 1 : 0,
((pOffTrackedRemoteOld->Buttons & xrButton_Trigger) != 0) && dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & xrButton_Trigger) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_LALT);
//Move Down
@ -474,19 +467,19 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
//Land
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Buttons & ovrButton_Joystick) != 0) && dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) && dominantGripPushedNew ? 1 : 0,
((pOffTrackedRemoteOld->Buttons & xrButton_Joystick) != 0) && dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & xrButton_Joystick) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_HOME);
//No Default Binding
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedNew ? 1 : 0,
((pOffTrackedRemoteOld->Touches & xrButton_ThumbRest) != 0) && dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Touches & xrButton_ThumbRest) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_JOY8);
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Buttons & ovrButton_GripTrigger) != 0) && dominantGripPushedOld && !vr_twohandedweapons ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & ovrButton_GripTrigger) != 0) && dominantGripPushedNew && !vr_twohandedweapons ? 1 : 0,
((pOffTrackedRemoteOld->Buttons & xrButton_GripTrigger) != 0) && dominantGripPushedOld && !vr_two_handed_weapons ? 1 : 0,
((pOffTrackedRemoteNew->Buttons & xrButton_GripTrigger) != 0) && dominantGripPushedNew && !vr_two_handed_weapons ? 1 : 0,
1, KEY_PAD_DPAD_UP);
}

@ -1 +1 @@
Subproject commit 88800f0fc2f5a8cb41b0714ebfd234b9f0ba624e
Subproject commit cd597da0c6cf0ecfcb0789d3fc5d5d02aad04b37

View file

@ -0,0 +1,4 @@
Into this folder copy the libopenxr_loader.so for each HMD required to support, suffixed with the headset type:
libopenxr_loader_meta.so
libopenxr_loader_pico.so

View file

@ -1,9 +0,0 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Wed Feb 02 12:33:02 GMT 2022
ndk.dir=C\:\\Users\\simon\\AppData\\Local\\Android\\Sdk\\ndk\\20.0.5594570
sdk.dir=C\:\\Users\\Simon\\AppData\\Local\\Android\\Sdk

View file

@ -1,4 +1,4 @@
rootProject.projectDir = new File(settingsDir, '../../../..')
rootProject.name = "QuestzDoom"
rootProject.projectDir = new File(settingsDir, '../..')
rootProject.name = "QuestZDoom"
include ':', 'VrSamples:QuestzDoom:Projects:Android'
include ':', 'Projects:Android'

View file

@ -0,0 +1,13 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := openxr_loader
LOCAL_SRC_FILES := lib$(LOCAL_MODULE).so
# NOTE: This check is added to prevent the following error when running a "make clean" where
# the prebuilt lib may have been deleted: "LOCAL_SRC_FILES points to a missing file"
ifneq (,$(wildcard $(LOCAL_PATH)/$(LOCAL_SRC_FILES)))
include $(PREBUILT_SHARED_LIBRARY)
endif

Binary file not shown.

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":VrSamples:QuestzDoom:Projects" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/Android" external.system.id="GRADLE" external.system.module.group="QuestzDoom.VrSamples.QuestzDoom" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":VrSamples:QuestzDoom:Projects" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" />
<option name="LAST_KNOWN_AGP_VERSION" />
</configuration>
</facet>
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -1,6 +1,8 @@
![QuestZDoom Banner](https://www.questzdoom.com/img/banner2.jpg)
===
[![Build Status](https://github.com/emawind84/QuestZDoom/actions/workflows/build.yaml/badge.svg)](https://github.com/emawind84/QuestZDoom/actions/workflows/build.yaml)
Welcome to the VR port of the popular LZDoom/GZDoom engine for the Oculus Quest.
This is built solely for the Oculus Quest VR HMD and will *not* run on any other device.

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":VrSamples:QuestzDoom" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/Projects/Android" external.system.id="GRADLE" external.system.module.group="QuestzDoom.VrSamples" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":VrSamples:QuestzDoom" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" />
<option name="LAST_KNOWN_AGP_VERSION" />
</configuration>
</facet>
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

238
XrApp.gradle Normal file
View file

@ -0,0 +1,238 @@
import org.gradle.internal.os.OperatingSystem;
import com.android.ddmlib.AndroidDebugBridge
import com.android.ddmlib.IDevice
import com.android.ddmlib.CollectingOutputReceiver
import org.apache.tools.ant.taskdefs.condition.Os
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
}
tasks.register("wrapper")
}
class XrAppPlugin implements Plugin<Project> {
Project project = null
void installApk( IDevice device, File apkFile, String applicationId ) {
project.logger.quiet "Installing ${applicationId} on device ${device.serialNumber}"
String toinstall = "/data/local/tmp/toinstall.apk"
try {
device.pushFile( apkFile.path, toinstall )
} catch ( Exception e ) {
throw new RuntimeException( "Failed to push ${apkFile.path} to ${toinstall}. ${e}", e )
}
while ( true ) {
try {
device.installRemotePackage( toinstall, true )
break
} catch ( Exception e ) {
project.logger.quiet "Failed to install ${applicationId} on device ${device.serialNumber} (${e}). Trying to uninstall first."
}
try {
device.uninstallPackage( applicationId )
} catch ( Exception e ) {
throw new RuntimeException( "Failed to uninstall ${applicationId}. ${e}", e )
}
}
}
void stopApk( IDevice device, String packageName ) {
CollectingOutputReceiver receiver = new CollectingOutputReceiver()
device.executeShellCommand( "am force-stop ${packageName}", receiver )
}
void runApk( IDevice device, manifestFile ) {
CollectingOutputReceiver receiver = new CollectingOutputReceiver()
def activityClass = new XmlSlurper().parse( manifestFile ).application.activity.find{ it.'intent-filter'.find{ filter ->
return filter.action .find{it.'@android:name'.text() == 'android.intent.action.MAIN' } \
&& ( filter.category.find{it.'@android:name'.text() == 'android.intent.category.LAUNCHER'} \
|| filter.category.find{it.'@android:name'.text() == 'android.intent.category.INFO'} )
}}.'@android:name'
def startActivity = "${project.android.defaultConfig.applicationId}/${activityClass}"
project.logger.quiet "Starting \'$startActivity\' on ${project.deviceMap.size()} devices:"
project.logger.quiet "- ${device.serialNumber}"
device.executeShellCommand( "am start $startActivity", receiver )
}
void apply( Project project ) {
this.project = project
// FIXME: The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead.
project.task( "cleanWorkAround" ) {
description "Workaround for .externalNativeBuild not being deleted on clean"
}.doLast {
project.delete project.file( ".externalNativeBuild" )
}
project.android {
compileSdkVersion 26
defaultConfig {
minSdkVersion 24
targetSdkVersion 25
externalNativeBuild {
ndk {
}
ndkBuild {
def numProcs = Runtime.runtime.availableProcessors()
arguments "V=0", "-j$numProcs", "-C$project.buildDir.parent", "APP_PLATFORM=android-24", "NDK_TOOLCHAIN_VERSION=clang", "APP_STL=c++_static"
}
}
}
externalNativeBuild {
ndkBuild {
path 'jni/Android.mk'
}
}
signingConfigs {
def keystorePath = (project.hasProperty('key.store')) ?
new File(project.getProperty('key.store')) :
project.file('android.debug.keystore')
def keystorePassword = (project.hasProperty('key.store.password')) ?
project.getProperty('key.store.password') : 'android'
def keystoreKeyAlias = (project.hasProperty('key.alias')) ?
project.getProperty('key.alias') : 'androiddebugkey'
def keystoreKeyPassword = (project.hasProperty('key.alias.password')) ?
project.getProperty('key.alias.password') : 'android'
debug {
storeFile keystorePath
storePassword keystorePassword
keyAlias keystoreKeyAlias
keyPassword keystoreKeyPassword
v2SigningEnabled true
}
release {
storeFile keystorePath
storePassword keystorePassword
keyAlias keystoreKeyAlias
keyPassword keystoreKeyPassword
v2SigningEnabled true
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
debuggable true
jniDebuggable true
externalNativeBuild {
ndkBuild {
arguments "NDK_DEBUG=1","USE_ASAN=1"
}
}
}
release {
signingConfig signingConfigs.release
debuggable false
jniDebuggable false
externalNativeBuild {
ndkBuild {
arguments "NDK_DEBUG=0","USE_ASAN=0"
}
}
}
}
}
// WORKAROUND: On Mac OS X, running ndk-build clean with a high num of parallel executions
// set may result in the following build error: rm: fts_read: No such file or directory.
// Currently, there isn't a good way to specify numProcs=1 only on clean. So, in order
// to work around the issue, delete the auto-generated .externalNativeBuild artifacts
// (where $numProcs specified) before executing the clean task.
project.clean.dependsOn project.cleanWorkAround
project.clean {
// remove the auto-generated debug keystore (currently generated by python build script)
// delete "android.debug.keystore"
}
project.afterEvaluate {
Task initDeviceList = project.task( "initDeviceList()" ).doLast {
project.ext.deviceMap = [ : ]
if (project.hasProperty( "should_install" ) == true) {
AndroidDebugBridge.initIfNeeded( false )
AndroidDebugBridge bridge = AndroidDebugBridge.createBridge( project.android.getAdbExe().absolutePath, false )
long timeOut = 30000 // 30 sec
int sleepTime = 1000
while ( !bridge.hasInitialDeviceList() && timeOut > 0 ) {
sleep( sleepTime )
timeOut -= sleepTime
}
if ( timeOut <= 0 && !bridge.hasInitialDeviceList() ) {
throw new RuntimeException( "Timeout getting device list.", null )
}
// if a device is connected both physically and over the network, only include the physical ID
if ( project.hasProperty( "should_install" ) == true ) {
bridge.devices.split { it.getProperty( "ro.serialno" ) != it.serialNumber }.each {
it.collectEntries( project.deviceMap, { [ ( it.getProperty( "ro.serialno" )) : it ] } )
}
}
}
}
project.task( "stopApk", dependsOn: initDeviceList ) {
description "Stops app if currently running on device"
}.doLast {
project.deviceMap.each { deviceSerial, device ->
stopApk( device, android.defaultConfig.applicationId )
}
}
project.android.applicationVariants.all { variant ->
Task installAndRun = project.task( "installAndRun${variant.name.capitalize()}" ) {
dependsOn variant.assembleProvider.get()
dependsOn initDeviceList
onlyIf { project.hasProperty( "should_install" ) }
description "Installs and runs the APK file"
}.doLast { variant.outputs.each { output ->
if ( output.outputFile.exists() ) {
if ( project.deviceMap.size() == 0 ) {
project.logger.quiet "Install requested, but no devices found."
} else {
project.deviceMap.each { deviceSerial, device ->
installApk( device, output.outputFile, project.android.defaultConfig.applicationId )
runApk( device, new File(output.processManifest.manifestOutputDirectory.get().asFile, "AndroidManifest.xml"))
}
}
}
}
}
variant.assembleProvider.get().finalizedBy installAndRun
}
}
}
}
// Workaround to fix issue in Android Studio Chipmunk 2021.2.1 and later
// where opening a project would result in a 'prepareKotlinBuildScriptModel'
// not found error
if (!tasks.findByName("prepareKotlinBuildScriptModel")) {
tasks.register("prepareKotlinBuildScriptModel") {}
}
apply plugin: XrAppPlugin

Binary file not shown.

Binary file not shown.

22
build.gradle Normal file
View file

@ -0,0 +1,22 @@
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

3
gradle.properties Normal file
View file

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
org.gradle.caching=true
org.gradle.configureondemand=true

View file

@ -2,36 +2,60 @@
package com.drbeef.questzdoom;
import static android.system.Os.setenv;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.os.RemoteException;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import com.drbeef.externalhapticsservice.HapticServiceClient;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale;
@SuppressLint("SdCardPath") public class GLES3JNIActivity extends Activity implements SurfaceHolder.Callback
{
private static String manufacturer = "";
// Load the gles3jni library right away to make sure JNI_OnLoad() gets called as the very first thing.
static
{
manufacturer = Build.MANUFACTURER.toLowerCase(Locale.ROOT);
if (manufacturer.contains("oculus")) // rename oculus to meta as this will probably happen in the future anyway
{
manufacturer = "meta";
}
try
{
//Load manufacturer specific loader
System.loadLibrary("openxr_loader_" + manufacturer);
setenv("OPENXR_HMD", manufacturer, true);
} catch (Exception e)
{}
System.loadLibrary( "qzdoom" );
}
@ -44,13 +68,30 @@ import java.io.OutputStream;
private static final int WRITE_EXTERNAL_STORAGE_PERMISSION_ID = 2;
private String commandLineParams;
private String progdir = "/sdcard/QuestZDoom";
private SurfaceView mView;
private SurfaceHolder mSurfaceHolder;
private long mNativeHandle;
public void shutdown() {
System.exit(0);
if (Build.VERSION.SDK_INT >= 21) {
// If yes, run the fancy new function to end the app and
// remove it from the task list.
finishAndRemoveTask();
} else {
// If not, then just end the app without removing it from
// the task list.
finish();
}
}
public void reload(String profile) {
if (profile != null && !profile.isEmpty()) {
copy_file(progdir + "/commandline_" + profile + ".txt", progdir + "/commandline.txt");
copy_file(progdir + "/profiles/commandline_" + profile + ".txt", progdir + "/commandline.txt");
}
restartApplication(this);
}
public void haptic_event(String event, int position, int intensity, float angle, float yHeight) {
@ -63,7 +104,7 @@ import java.io.OutputStream;
}
catch (RemoteException r)
{
Log.v(APPLICATION, r.toString());
Log.e(APPLICATION, r.toString());
}
}
}
@ -76,7 +117,7 @@ import java.io.OutputStream;
}
catch (RemoteException r)
{
Log.v(APPLICATION, r.toString());
Log.e(APPLICATION, r.toString());
}
}
}
@ -89,7 +130,7 @@ import java.io.OutputStream;
}
catch (RemoteException r)
{
Log.v(APPLICATION, r.toString());
Log.e(APPLICATION, r.toString());
}
}
}
@ -102,7 +143,7 @@ import java.io.OutputStream;
}
catch (RemoteException r)
{
Log.v(APPLICATION, r.toString());
Log.e(APPLICATION, r.toString());
}
}
}
@ -151,8 +192,13 @@ import java.io.OutputStream;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) {
if (requestCode == WRITE_EXTERNAL_STORAGE_PERMISSION_ID) {
finish();
System.exit(0);
if (results.length > 0 && results[0] == PackageManager.PERMISSION_GRANTED) {
create();
}
else {
finish();
System.exit(0);
}
}
}
@ -166,50 +212,50 @@ import java.io.OutputStream;
}
public void create() {
copy_asset("/sdcard/QuestZDoom", "commandline.txt", false);
copy_asset(progdir, "commandline.txt", false);
//Create all required folders
new File("/sdcard/QuestZDoom/res").mkdirs();
new File("/sdcard/QuestZDoom/mods").mkdirs();
new File("/sdcard/QuestZDoom/wads").mkdirs();
new File("/sdcard/QuestZDoom/soundfonts").mkdirs();
new File(progdir, "res").mkdirs();
new File(progdir, "mods").mkdirs();
new File(progdir, "wads").mkdirs();
new File(progdir, "soundfonts").mkdirs();
copy_asset("/sdcard/QuestZDoom", "res/lzdoom.pk3", true);
copy_asset("/sdcard/QuestZDoom", "res/lz_game_support.pk3", true);
copy_asset("/sdcard/QuestZDoom", "res/lights.pk3", true);
copy_asset("/sdcard/QuestZDoom", "res/brightmaps.pk3", true);
copy_asset(progdir, "res/lzdoom.pk3", true);
copy_asset(progdir, "res/lz_game_support.pk3", true);
copy_asset(progdir, "res/lights.pk3", true);
copy_asset(progdir, "res/brightmaps.pk3", true);
copy_asset("/sdcard/QuestZDoom", "mods/Ultimate-Cheat-Menu.zip", false);
copy_asset("/sdcard/QuestZDoom", "mods/laser-sight-0.5.5-vr.pk3", false);
copy_asset(progdir, "mods/Ultimate-Cheat-Menu.zip", true);
copy_asset(progdir, "mods/laser-sight-0.5.5-vr.pk3", true);
copy_asset("/sdcard/QuestZDoom/soundfonts", "qzdoom.sf2", false);
copy_asset("/sdcard/QuestZDoom/fm_banks", "GENMIDI.GS.wopl", false);
copy_asset("/sdcard/QuestZDoom/fm_banks", "gs-by-papiezak-and-sneakernets.wopn", false);
//copy_asset("/sdcard/QuestZDoom/audiopack", "snd_fluidsynth/fluidsynth.sf2", false);
copy_asset(progdir + "/soundfonts", "qzdoom.sf2", false);
copy_asset(progdir + "/fm_banks", "GENMIDI.GS.wopl", false);
copy_asset(progdir + "/fm_banks", "gs-by-papiezak-and-sneakernets.wopn", false);
//Read these from a file and pass through
commandLineParams = new String("qzdoom");
//See if user is trying to use command line params
if(new File("/sdcard/QuestZDoom/commandline.txt").exists()) // should exist!
String commandLineFilePath = progdir + "/commandline.txt";
GLES3JNILib.prepareEnvironment(progdir);
if(new File(commandLineFilePath).exists()) // should exist!
{
BufferedReader br;
try {
br = new BufferedReader(new FileReader("/sdcard/QuestZDoom/commandline.txt"));
br = new BufferedReader(new FileReader(commandLineFilePath));
String s;
StringBuilder sb=new StringBuilder(0);
while ((s=br.readLine())!=null)
while ((s=br.readLine())!=null) {
if (s.indexOf("#", 0) == 0) continue;
sb.append(s + " ");
}
br.close();
commandLineParams = new String(sb.toString());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(APPLICATION, e.toString());
finish();
return;
}
}
@ -222,12 +268,12 @@ import java.io.OutputStream;
//If there are no IWADS, then should exit after creating the folders
//to allow the launcher app to do its thing, otherwise it would crash anyway
//Check that launcher is installed too
boolean hasIWADs = ((new File("/sdcard/QuestZDoom/wads").listFiles().length) > 0);
boolean hasLauncher = //(new File("/sdcard/QuestZDoom/no_launcher").exists()) || //Allow users to run without launcher if they _really_ want to
boolean hasIWADs = ((new File(progdir, "wads").listFiles().length) > 0);
boolean hasLauncher = new File(progdir, "no_launcher").exists() || //Allow users to run without launcher if they _really_ want to
isPackageInstalled("com.Baggyg.QuestZDoom_Launcher", this.getPackageManager());
mNativeHandle = GLES3JNILib.onCreate( this, commandLineParams, hasIWADs, hasLauncher );
}
public void copy_asset(String path, String name, boolean force) {
File f = new File(path + "/" + name);
if (!f.exists() || force) {
@ -259,6 +305,22 @@ import java.io.OutputStream;
}
public void copy_file(String path_in, String path_out)
{
File file_in = new File(path_in);
if (file_in.exists()) {
File file_out = new File(path_out);
try (
InputStream in = new BufferedInputStream(new FileInputStream(file_in));
OutputStream out = new BufferedOutputStream(new FileOutputStream(file_out)))
{
copy_stream(in, out);
} catch (IOException e) {
Log.e(APPLICATION, e.toString());
}
}
}
public static void copy_stream(InputStream in, OutputStream out)
throws IOException {
byte[] buf = new byte[1024];
@ -362,4 +424,30 @@ import java.io.OutputStream;
}
}
/**
* Working method for restarting the activity
* @param activity
*/
private void restartApplication(final @NonNull Activity activity) {
// Systems at 29/Q and later don't allow relaunch, but System.exit(0) on
// all supported systems will relaunch ... but by killing the process, then
// restarting the process with the back stack intact. We must make sure that
// the launch activity is the only thing in the back stack before exiting.
final PackageManager pm = activity.getPackageManager();
final Intent intent = pm.getLaunchIntentForPackage(activity.getPackageName());
activity.finishAffinity(); // Finishes all activities.
activity.startActivity(intent); // Start the launch activity
System.exit(0); // System finishes and automatically relaunches us.
}
/**
* Working method for restarting the activity
*/
private void restartApplicationSecondMethod() {
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
Runtime.getRuntime().exit(0);
}
}

View file

@ -20,4 +20,6 @@ public class GLES3JNILib
public static native void onSurfaceCreated( long handle, Surface s );
public static native void onSurfaceChanged( long handle, Surface s );
public static native void onSurfaceDestroyed( long handle );
public static native void prepareEnvironment(String path);
}