Compare commits

..

54 commits

Author SHA1 Message Date
Simon
79befe4d38
Merge pull request #92 from lvonasek/feature_remote_keyboard
Support for BT/OTG keyboards
2022-12-04 14:39:17 +00:00
Lubos
91fa5bcf3b Handle only suppoted characters 2022-12-03 11:47:22 +01:00
Lubos
8bb0124fe6 Support external keyboards 2022-12-02 09:58:21 +01:00
Simon
6d9951dd95
Merge pull request #91 from petr666/master
Implement virtual gun stock (OpenXR)
2022-10-29 19:28:06 +01:00
Petr Bartos
b904ee0d4f Fix virtual gun stock height adjustment 2022-10-20 08:46:45 +02:00
Petr Bartos
61faf0a731 Implement virtual gun stock 2022-10-19 22:20:39 +02:00
Simon
a235a57205 Update version numbers 2022-09-30 20:10:19 +01:00
Simon
325deba431 Revert "Merge pull request #87 from foxtrotdev/feature/app-improvements-1"
This reverts commit c65bff06ad.
2022-09-30 20:10:19 +01:00
Simon
b2bd1be433
Merge pull request #87 from foxtrotdev/feature/app-improvements-1
[Android] Correct versioning, increase gradle version, new launcher icon, configs clean up
2022-09-30 18:40:27 +01:00
Simon
e1cdb7a9c2
Merge pull request #89 from petr666/master
Configurable supersampling, added 120hz option, small cosmetic change (master/OpenXr)
2022-09-30 18:40:13 +01:00
Simon
493ee6e96d
Merge branch 'master' into master 2022-09-30 18:40:05 +01:00
Simon
9634ff74cd
Merge pull request #86 from lvonasek/feature_openxr_tweaks
Make OpenXR build behave the same like VrAPI build
2022-09-30 18:37:58 +01:00
Petr Bartos
706481fe00 Add 1.3 option for supersampling 2022-09-29 22:06:20 +02:00
Petr Bartos
21fc40dc44 Do not draw weapon model, crosshair and hud in menu screen 2022-09-29 17:41:20 +02:00
Petr Bartos
96b1071b50 Add super sampling configuration and 120hz refresh rate 2022-09-29 17:38:20 +02:00
Lubos
807a8d2820 OpenXR - Make the initializations more universal 2022-09-02 12:28:14 +02:00
Michał Mokrzycki
c7811f31d1 feature: return to compileSdkVersion 29 2022-09-01 09:20:21 +02:00
Michał Mokrzycki
65dcb19541 feat: correct versioning (moved to gradle file)
feat: increased gradle version to 7.2.1
feat: add launcher icons (from Wikipedia - https://de.wikipedia.org/wiki/Datei:Quake_III_Arena_Logo.svg - author: unknown)
2022-08-09 17:47:12 +02:00
Lubos
b43a9a67c7 Make OpenXR build behave the same like VrAPI build 2022-07-05 16:28:08 +02:00
Simon
b11fc0fb29 QoL tweaks
- Make the frag / flag / time limit values modifiable lists of values, rather than text entry
- Couple of changes to the credits screen
2022-06-12 11:42:41 +01:00
Simon
023d0f27a8 Master Server address change
- Change cvar name (vr_master) and value to use mp.quakevr.com:27950
- Added Omarlego's background pak
2022-05-23 21:12:48 +01:00
Simon
bd0592dcc7 Update ui_credits.c 2022-05-22 10:21:33 +01:00
Simon
152e48b3c7 Update ui_credits.c 2022-05-22 10:16:21 +01:00
Simon
e201285822 Fixed incorrect credits 2022-05-21 20:59:06 +01:00
Simon
1f3a31bbc8 Allow a Quest running the demo pak to connect to another quest server 2022-05-21 09:37:52 +01:00
Simon
096daff966 Ensure roll angles are passed to the server if enabled 2022-05-19 22:34:32 +01:00
Simon
f5c507fe8a
Merge pull request #84 from petr666/master
Delete obsolete glsl folder on startup
2022-05-19 19:30:40 +01:00
Simon
b45d7cd653 Grey out non-demo servers if playing with demo pak0
- don't allow players to even start a MP game on a non-demo server
- fixed the website url
- updated the message about the demo in the main menu
2022-05-19 19:11:00 +01:00
Petr Bartos
d322b861f2 Do not create missionpack folder if not installed 2022-05-18 22:48:05 +02:00
Petr Bartos
33e4bc37ad Delete obsolete glsl folder on startup 2022-05-16 21:37:43 +02:00
Simon
c01c8b3484 Change to multiplayer menu message
also disabled the "specify" button as it is useless in this port
2022-05-15 18:06:51 +01:00
Simon
d9db6a2076
Merge pull request #83 from petr666/feature/control-tweaks
Remap face buttons along with switching thumbsticks
2022-05-15 16:09:33 +01:00
Simon
b659a9e09e Support for ForeceTube/ProTube Stock
Also added f2hunter to the credits
2022-05-15 10:34:43 +01:00
Petr Bartos
8cf8f3ae1b Remap face buttons along with switching thumbsticks 2022-05-14 19:30:50 +02:00
Simon
8cf2ffc445
Merge pull request #82 from petr666/master
Generate random suffix for default player name
2022-05-14 12:20:19 +01:00
Simon
d90f86e035
Merge pull request #81 from lvonasek/hotfix_openxr
OpenXR jitter hotfix
2022-05-14 12:19:37 +01:00
Petr Bartos
e903dc373b Update also already stored default player name with random suffix 2022-05-14 12:41:24 +02:00
Petr Bartos
d4785e8a9e Generate random suffix for default player name 2022-05-14 12:06:55 +02:00
Lubos
0a3d613787 Revert "OpenXR recenter after the first frame"
This reverts commit 5068ce7199.
2022-05-13 18:31:16 +02:00
Lubos
f2dbc90823 OpenXR controllers coordinates relative to head space 2022-05-11 16:51:07 +02:00
Lubos
5068ce7199 OpenXR recenter after the first frame 2022-05-11 16:11:54 +02:00
Lubos
5ecbbac97e OpenXR restore haptics calling 2022-05-10 22:30:10 +02:00
Lubos
d354212c5d OpenXR change the way of getting the head position 2022-05-10 22:26:55 +02:00
Lubos
859cecb424 OpenXR getting view matrix simplified 2022-05-10 20:35:53 +02:00
Lubos
244b8344ff OpenXR do not call stop haptics every frame 2022-05-10 19:34:18 +02:00
Lubos
437e3829aa OpenXR ignore controller velocity 2022-05-10 19:23:51 +02:00
Lubos
314e8b0288 OpenXR attach actions to session just once 2022-05-10 19:21:13 +02:00
Simon
709c0abdcf
Merge pull request #80 from lvonasek/hotfix_app_flow
Hotfix app flow
2022-05-08 19:24:50 +01:00
Lubos
9d09e3f9d8 Start the game on clean install fix 2022-05-08 08:50:25 +02:00
Lubos
a56b9ad288 OpenXR set yaw to zero on a fresh start 2022-05-08 08:46:59 +02:00
Simon
7e092d57a4 Set RC1 version number 2022-05-07 19:24:48 +01:00
Simon
4181466815
Merge pull request #79 from lvonasek/hotfix_railgun_zoom
OpenXR calculate FOV as average of both eyes
2022-05-07 19:03:12 +01:00
Lubos
65ff5bbd80 OpenXR calculate FOV as average of both eyes 2022-05-07 19:31:37 +02:00
Simon
52799aa99d Squashed commit of the following:
commit 0adeb4ba3b
Merge: 7feea565 d8653ad7
Author: Simon <simonbrown77@googlemail.com>
Date:   Sat May 7 14:32:21 2022 +0100

    Merge branch 'OpenXR' of https://github.com/DrBeef/ioq3quest into OpenXR

commit 7feea56514
Author: Simon <simonbrown77@googlemail.com>
Date:   Sat May 7 14:32:14 2022 +0100

    Update Version Number

commit d8653ad70e
Merge: 79983b2b 7e6aa6da
Author: Simon <simonbrown77@googlemail.com>
Date:   Sat May 7 14:31:45 2022 +0100

    Merge pull request #76 from lvonasek/OpenXR

    OpenXR delayed controller pose fixed

commit 79983b2bc5
Merge: 325641f9 7f89d6d1
Author: Simon <simonbrown77@googlemail.com>
Date:   Sat May 7 14:31:31 2022 +0100

    Merge pull request #77 from petr666/OpenXR

    Update gamma values to better suit OpenXR build

commit 7f89d6d19b
Author: Petr Bartos <petr.bartos@plus4u.net>
Date:   Sat May 7 13:56:03 2022 +0200

    Update gamma values to better suit OpenXR build

commit 7e6aa6dab8
Author: Lubos <tridosm@gmail.com>
Date:   Sat May 7 11:32:11 2022 +0200

    OpenXR sync actions before updating controllers

commit 027a7e96c3
Author: Lubos <tridosm@gmail.com>
Date:   Fri May 6 10:34:50 2022 +0200

    OpenXR implement controller velocity again

commit af80d5c284
Author: Lubos <tridosm@gmail.com>
Date:   Fri May 6 10:18:51 2022 +0200

    Compile fix

commit ab1e853554
Author: Lubos <tridosm@gmail.com>
Date:   Fri May 6 10:14:08 2022 +0200

    OpenXR input cleanup

commit be158b4ad9
Author: Lubos <tridosm@gmail.com>
Date:   Fri May 6 09:39:49 2022 +0200

    OpenXR sync input actions from renderer

commit ed96160ffc
Author: Lubos <tridosm@gmail.com>
Date:   Fri May 6 09:25:59 2022 +0200

    OpenXR do not use pose velocity to track controllers

commit 42bf984ef8
Author: Lubos <tridosm@gmail.com>
Date:   Thu May 5 22:39:10 2022 +0200

    OpenXR apply controller pose from renderer

commit 92941b3547
Author: Lubos <tridosm@gmail.com>
Date:   Thu May 5 22:26:33 2022 +0200

    OpenXR delayed controller pose fixed

commit 325641f90e
Merge: de198fba 3ee3f590
Author: Simon <simonbrown77@googlemail.com>
Date:   Thu May 5 16:30:07 2022 +0100

    Merge pull request #75 from lvonasek/OpenXR

    OpenXR menuyaw and recenter support added

commit 3ee3f59058
Author: Lubos <tridosm@gmail.com>
Date:   Thu May 5 12:22:36 2022 +0200

    OpenXR do not recenter on renderer reload

commit 7072b0b89e
Author: Lubos <tridosm@gmail.com>
Date:   Wed May 4 21:05:45 2022 +0200

    OpenXR recenter sets yaw always to 0

commit 8e5f6414a6
Author: Lubos <tridosm@gmail.com>
Date:   Wed May 4 16:19:48 2022 +0200

    OpenXR recenter integrated

commit 08a4fc7fbf
Author: Lubos <tridosm@gmail.com>
Date:   Tue May 3 18:37:28 2022 +0200

    OpenXR use the same coordinate system in all layers

commit a1de0e1ffe
Author: Lubos <tridosm@gmail.com>
Date:   Mon May 2 22:17:53 2022 +0200

    OpenXR menuYaw support added

commit de198fba0d
Author: Simon <simonbrown77@googlemail.com>
Date:   Mon May 2 10:01:42 2022 +0100

    Update version numbers and add openxr identifier

commit b83f99fe5b
Merge: c623bf13 9c14728b
Author: Simon <simonbrown77@googlemail.com>
Date:   Mon May 2 09:43:47 2022 +0100

    Merge pull request #74 from lvonasek/OpenXR

    OpenXR left controller mapping fixed

commit 9c14728bc9
Merge: 11a849b1 0695c7ac
Author: Lubos <tridosm@gmail.com>
Date:   Sun May 1 19:41:45 2022 +0200

    Merge branch 'master' into OpenXR

commit 11a849b189
Author: Lubos <tridosm@gmail.com>
Date:   Sun May 1 19:09:12 2022 +0200

    OpenXR controller mapping fixed

commit 712584eae8
Merge: df4bc0c0 c623bf13
Author: Luboš Vonásek <tridosm@gmail.com>
Date:   Sun May 1 19:04:45 2022 +0200

    Merge branch 'DrBeef:OpenXR' into OpenXR

commit c623bf1399
Merge: cb152467 e42a2f4e
Author: Simon <simonbrown77@googlemail.com>
Date:   Sun May 1 14:10:23 2022 +0100

    Merge pull request #72 from lvonasek/OpenXR

    OpenXR jitter fixed

commit e42a2f4e0d
Author: Lubos <tridosm@gmail.com>
Date:   Sun May 1 14:34:38 2022 +0200

    Compile fix

commit acbff1e736
Author: Lubos <tridosm@gmail.com>
Date:   Sun May 1 13:59:41 2022 +0200

    OpenXR camera view moved into renderer

commit cb152467ba
Merge: decc2d02 26071937
Author: Simon <simonbrown77@googlemail.com>
Date:   Sun May 1 10:20:40 2022 +0100

    Merge pull request #69 from lvonasek/feature_openxr

    OpenXR integration

commit 26071937c8
Author: Lubos <tridosm@gmail.com>
Date:   Sun May 1 11:17:50 2022 +0200

    OpenXR frameskip integrated

commit f735535dce
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 30 22:57:48 2022 +0200

    OpenXR attempt to fix flickering

commit 0eb1d43b4a
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 30 21:28:26 2022 +0200

    2D aspect ratio fixed

commit 9d07c27604
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 30 21:23:53 2022 +0200

    Hud model rendering fixed

commit 30c9b4eaa0
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 30 17:03:54 2022 +0200

    Release build fixed

commit 405ca571ad
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 30 14:10:27 2022 +0200

    OpenXR foveation removed

commit 61b3192bce
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 30 14:02:21 2022 +0200

    OpenXR projection matrix calculation from example code

commit ecd50dbcb1
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 29 21:21:10 2022 +0200

    OpenXR low framerate fixed

commit f5a8429fc1
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 29 19:21:29 2022 +0200

    Solution for black rectangles in the scene

commit 9ae93a5fe9
Merge: 10548445 decc2d02
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 29 14:58:35 2022 +0200

    Merge branch 'master' into feature_openxr

commit 1054844524
Merge: 65e2031e 3cdf1858
Author: Lubos <tridosm@gmail.com>
Date:   Wed Apr 27 21:52:55 2022 +0200

    Merge branch 'master' into feature_openxr

commit 65e2031e95
Author: Lubos <tridosm@gmail.com>
Date:   Tue Apr 26 22:02:04 2022 +0200

    OpenXR integration fixes

commit c321b97894
Author: Lubos <tridosm@gmail.com>
Date:   Mon Apr 25 16:48:09 2022 +0200

    OpenXR multiview integrated

commit 5947168966
Author: Lubos <tridosm@gmail.com>
Date:   Sun Apr 24 20:25:19 2022 +0200

    OpenXR minor fixes

commit 249847930b
Author: Lubos <tridosm@gmail.com>
Date:   Sun Apr 24 18:06:02 2022 +0200

    OpenXR use just one framebuffer

commit b11122e368
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 23 21:06:35 2022 +0200

    OpenXR touch controllers completely implemented

commit 0bf485664c
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 23 19:44:18 2022 +0200

    OpenXR haptics and refreshrate fixed

commit 4716387e52
Author: Lubos <tridosm@gmail.com>
Date:   Sat Apr 23 15:54:07 2022 +0200

    OpenXR input except buttons implemented

commit 7bd1fe31c2
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 22 21:18:49 2022 +0200

    OpenXR input in progress

commit 3c26e08f01
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 22 18:41:26 2022 +0200

    Old code removed

commit 4d2644cae2
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 22 18:32:42 2022 +0200

    OpenXR fov fixed

commit 501869a051
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 22 17:56:14 2022 +0200

    OpenXR motion tracking in game mode added

commit b152d21ddc
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 22 16:14:36 2022 +0200

    OpenXR cylinder projection added

commit 3e9c80679e
Merge: 0de4a0d1 39f669dd
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 22 14:13:18 2022 +0200

    Merge branch 'master' into feature_openxr

commit 0de4a0d196
Author: Lubos <tridosm@gmail.com>
Date:   Fri Apr 22 13:45:22 2022 +0200

    OpenXR tracking added init, first working rendering

commit 8431b1aa83
Author: Lubos <tridosm@gmail.com>
Date:   Thu Apr 21 21:15:02 2022 +0200

    OpenXR add missing foveation

commit 4ff90d8ba0
Author: Lubos <tridosm@gmail.com>
Date:   Thu Apr 21 21:00:02 2022 +0200

    OpenXR renderer cleanup

commit d736af15bd
Merge: 7b9d51ec fe180129
Author: Lubos <tridosm@gmail.com>
Date:   Thu Mar 31 17:47:45 2022 +0200

    Merge branch 'master' into feature_openxr

commit 7b9d51ec30
Author: Lubos <tridosm@gmail.com>
Date:   Thu Mar 31 17:47:36 2022 +0200

    OpenXR renderer in progress

commit e7a2229edc
Merge: abeaf046 bcf9287a
Author: Lubos <tridosm@gmail.com>
Date:   Wed Mar 30 09:44:15 2022 +0200

    Merge branch 'master' into feature_openxr

commit abeaf04607
Author: Lubos <tridosm@gmail.com>
Date:   Tue Mar 29 19:57:47 2022 +0200

    OpenXR initialization fixed

commit f2fefbf708
Author: Lubos <tridosm@gmail.com>
Date:   Tue Mar 29 17:13:48 2022 +0200

    OpenXR initialization added

commit 96bf69cb15
Author: Lubos <tridosm@gmail.com>
Date:   Tue Mar 29 12:56:37 2022 +0200

    VR API removed
2022-05-07 14:34:37 +01:00
41 changed files with 2205 additions and 609 deletions

2
.gitignore vendored
View file

@ -1,4 +1,6 @@
build
android/app/src/main/cpp/code/OpenXR-SDK
android/app/src/main/cpp/code/OpenXR
android/app/src/main/cpp/code/VrApi
*.swp
*tags

View file

@ -281,7 +281,8 @@ LOKISETUPDIR=misc/setup
NSISDIR=misc/nsis
SDLHDIR=$(MOUNT_DIR)/SDL2
LIBSDIR=$(MOUNT_DIR)/libs
VRAPIDIR=$(MOUNT_DIR)/VrApi
OPENXRDIR=$(MOUNT_DIR)/OpenXR
OPENXRSDKDIR=$(MOUNT_DIR)/OpenXR-SDK
bin_path=$(shell which $(1) 2> /dev/null)
@ -468,11 +469,11 @@ ifeq ($(PLATFORM),android)
RENDERER_LIBS += $(LIBSDIR)/android/arm64-v8a/libSDL2.so
CLIENT_EXTRA_FILES += $(LIBSDIR)/android/arm64-v8a/libSDL2.so
# VrApi
BASE_CFLAGS += -I$(VRAPIDIR)/Include
CLIENT_LIBS += $(VRAPIDIR)/Libs/Android/arm64-v8a/Release/libvrapi.so
RENDERER_LIBS += $(VRAPIDIR)/Libs/Android/arm64-v8a/Release/libvrapi.so
CLIENT_EXTRA_FILES += $(VRAPIDIR)/Libs/Android/arm64-v8a/Release/libvrapi.so
# OpenXR
BASE_CFLAGS += -I$(OPENXRDIR)/Include -I$(OPENXRSDKDIR)/include
CLIENT_LIBS += $(OPENXRDIR)/Libs/Android/arm64-v8a/Release/libopenxr_loader.so
RENDERER_LIBS += $(OPENXRDIR)/Libs/Android/arm64-v8a/Release/libopenxr_loader.so
CLIENT_EXTRA_FILES += $(OPENXRDIR)/Libs/Android/arm64-v8a/Release/libopenxr_loader.so
else # ifeq Android
#############################################################################
@ -1819,6 +1820,7 @@ Q3OBJ = \
$(B)/client/vr_base.o \
$(B)/client/vr_input.o \
$(B)/client/vr_renderer.o \
$(B)/client/vr_types.o \
\
$(B)/client/con_log.o \
$(B)/client/sys_autoupdater.o \

View file

@ -5,7 +5,9 @@
### Prerequisites
1. Install your copy of Quake III Arena from Steam.
2. Android Studio with NDK version 21.1.6352462.
3. Copy the Oculus VR SDK from https://developer.oculus.com/downloads/package/oculus-mobile-sdk/ and extract the VrApi folder to ./android/app/src/main/cpp/code/VrApi/
3. Download the Oculus OpenXR SDK from https://developer.oculus.com/downloads/package/oculus-openxr-mobile-sdk/
4. Extract the OpenXR folder to ./android/app/src/main/cpp/code/OpenXR/
5. Extract the 3rdParty/khronos/openxr/OpenXR-SDK folder to ./android/app/src/main/cpp/code/OpenXR-SDK/
### Building and running the build
The scripts assume that you installed everything in the default locations. In case you want to deviate from that, the paths are in ./android/run.(sh|bat) and in Makefile.local.

View file

@ -8,8 +8,8 @@ android {
applicationId = 'com.drbeef.ioq3quest'
minSdkVersion 25
targetSdkVersion 26
versionCode 1
versionName "1.0"
versionCode 58
versionName "1.1.3"
externalNativeBuild {
cmake {
arguments '-DANDROID_STL=c++_static'

View file

@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.drbeef.ioq3quest"
android:installLocation="preferExternal"
android:versionCode="55"
android:versionName="1.1.0">
android:versionCode="58"
android:versionName="1.1.3">
<uses-feature android:name="android.hardware.vr.headtracking" android:version="1" android:required="true" />
<uses-feature android:glEsVersion="0x00030001" />
<!-- <uses-feature android:name="oculus.software.overlay_keyboard" android:required="false"/>-->

View file

@ -1,4 +1,4 @@
set sv_master1 "13.36.227.32:27950"
set vr_master1 "mp.quakevr.com:27950"
//////////////////////////////////////////////////////////////////////////////////////////////////
// //

View file

@ -1,4 +1,4 @@
set sv_master1 "13.36.227.32:27950"
set vr_master1 "mp.quakevr.com:27950"
set vr_weapon_adjustment_1 "1.0,0,12,-13,-36,0,100"
set vr_weapon_adjustment_2 "1.0,-6,6,-3,0,0,0"

Binary file not shown.

View file

@ -15,7 +15,7 @@ endif()
add_custom_target(copy_libs
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/libioquake3_opengl2.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libioquake3_opengl2.so
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/libSDL2.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libSDL2.so
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/libvrapi.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libvrapi.so
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/libopenxr_loader.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libopenxr_loader.so
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/baseq3/cgameaarch64.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libcgameaarch64_baseq3.so
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/baseq3/qagameaarch64.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libqagameaarch64_baseq3.so
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../../../../../build/${BUILD_FOLDER}/baseq3/uiaarch64.so ${CMAKE_SOURCE_DIR}/../jniLibs/arm64-v8a/libuiaarch64_baseq3.so
@ -27,7 +27,8 @@ add_custom_target(copy_libs
add_dependencies(main copy_libs)
target_include_directories(main PRIVATE
${CMAKE_SOURCE_DIR}/code/VrApi/Include
${CMAKE_SOURCE_DIR}/code/OpenXR-SDK/include
${CMAKE_SOURCE_DIR}/code/OpenXR/Include
${CMAKE_SOURCE_DIR}/code/SDL2/include
${CMAKE_SOURCE_DIR}/code)
@ -40,5 +41,5 @@ target_link_libraries(main
android
ioquake3_opengl2
SDL2
vrapi
openxr_loader
${log-lib})

View file

@ -2824,7 +2824,7 @@ void CG_DrawActive( void ) {
// clear around the rendered view if sized down
CG_TileClear();
if(!vr->weapon_zoomed)
if(!vr->weapon_zoomed && !vr->virtual_screen)
CG_DrawCrosshair3D();
// offset vieworg appropriately if we're doing stereo separation
@ -2892,7 +2892,7 @@ void CG_DrawActive( void ) {
}
//Now draw the HUD shader in the world
if (trap_Cvar_VariableValue("vr_hudDrawStatus") != 2.0f)
if (trap_Cvar_VariableValue("vr_hudDrawStatus") != 2.0f && !vr->weapon_zoomed && !vr->virtual_screen)
{
refEntity_t ent;
trace_t trace;
@ -2955,7 +2955,7 @@ void CG_DrawActive( void ) {
//Now draw the screen 2D stuff
CG_DrawScreen2D();
if (!vr->weapon_zoomed)
if (!vr->weapon_zoomed && !vr->virtual_screen)
{
cg.drawingHUD = qtrue;

View file

@ -1728,8 +1728,8 @@ void CG_AddViewWeapon( playerState_t *ps ) {
return;
}
if (vr->weapon_zoomed) {
return; // do not draw weapon model with enabled weapon scope
if (vr->weapon_zoomed || vr->virtual_screen) {
return; // do not draw weapon model with enabled weapon scope or when in menu
}
cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];

View file

@ -4198,7 +4198,7 @@ void CL_GlobalServers_f( void ) {
int numAddress = 0;
for ( i = 1; i <= MAX_MASTER_SERVERS; i++ ) {
sprintf(command, "sv_master%d", i);
sprintf(command, "vr_master%d", i);
masteraddress = Cvar_VariableString(command);
if(!*masteraddress)
@ -4216,7 +4216,7 @@ void CL_GlobalServers_f( void ) {
return;
}
sprintf(command, "sv_master%d", masterNum);
sprintf(command, "vr_master%d", masterNum);
masteraddress = Cvar_VariableString(command);
if(!*masteraddress)

View file

@ -65,7 +65,7 @@ typedef struct {
menuradiobutton_s autoswitch;
menuradiobutton_s scope;
menuradiobutton_s twohanded;
menulist_s twohanded;
menulist_s directionmode;
menulist_s snapturn;
menuradiobutton_s uturn;
@ -84,7 +84,7 @@ static controls3_t s_controls3;
static void Controls3_SetMenuItems( void ) {
s_controls3.autoswitch.curvalue = trap_Cvar_VariableValue( "cg_autoswitch" ) != 0;
s_controls3.scope.curvalue = trap_Cvar_VariableValue( "vr_weaponScope" ) != 0;
s_controls3.twohanded.curvalue = trap_Cvar_VariableValue( "vr_twoHandedWeapons" ) != 0;
s_controls3.twohanded.curvalue = trap_Cvar_VariableValue( "vr_twoHandedWeapons" );
s_controls3.directionmode.curvalue = (int)trap_Cvar_VariableValue( "vr_directionMode" ) % NUM_DIRECTIONMODE;
s_controls3.snapturn.curvalue = (int)trap_Cvar_VariableValue( "vr_snapturn" ) / 45;
s_controls3.uturn.curvalue = trap_Cvar_VariableValue( "vr_uturn" ) != 0;
@ -268,6 +268,14 @@ static void Controls3_MenuInit( void ) {
NULL
};
static const char *s_twohandedmode[] =
{
"Disabled",
"Enabled (Basic)",
"Enabled (VR Gun Stock)",
NULL
};
memset( &s_controls3, 0 ,sizeof(controls3_t) );
Controls3_Cache();
@ -317,13 +325,15 @@ static void Controls3_MenuInit( void ) {
s_controls3.scope.generic.y = y;
y += BIGCHAR_HEIGHT+2;
s_controls3.twohanded.generic.type = MTYPE_RADIOBUTTON;
s_controls3.twohanded.generic.type = MTYPE_SPINCONTROL;
s_controls3.twohanded.generic.name = "Two-Handed Weapons:";
s_controls3.twohanded.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_controls3.twohanded.generic.callback = Controls3_MenuEvent;
s_controls3.twohanded.generic.id = ID_TWOHANDED;
s_controls3.twohanded.generic.x = VR_X_POS;
s_controls3.twohanded.generic.y = y;
s_controls3.twohanded.itemnames = s_twohandedmode;
s_controls3.twohanded.numitems = 3;
y += BIGCHAR_HEIGHT+2;
s_controls3.directionmode.generic.type = MTYPE_SPINCONTROL;

View file

@ -140,12 +140,14 @@ Special Thanks to the whole discord!
y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
UI_DrawProportionalString( 320, y, "Additional Contributions", UI_CENTER|UI_SMALLFONT, color_red );
y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
UI_DrawString( 320, y, "Bummser, Skillfur, Ceno, Cukier, Eispfogel, Pizzaluigi", UI_CENTER|UI_SMALLFONT, color_white );
UI_DrawString( 320, y, "Bummser, Skillfur, Ceno, Cukier, Eispfogel", UI_CENTER|UI_SMALLFONT, color_white );
y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
UI_DrawString( 320, y, "Omarlego (custom Q3Q background), Pizzaluigi", UI_CENTER|UI_SMALLFONT, color_white );
y += 1.42 * PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
UI_DrawProportionalString( 320, y, "Dedicated Beta Testers", UI_CENTER|UI_SMALLFONT, color_red );
y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
UI_DrawString( 320, y, "f2hunter, XQuader, Ceno, Cukier, Bummser, Retro1N, Benny91, Ikarus,", UI_CENTER|UI_SMALLFONT, color_white );
UI_DrawString( 320, y, "f2hunter, XQuader, Ceno, Cukier, Bummser, Retro1N, Benny91, Madmac(Ikarus),", UI_CENTER|UI_SMALLFONT, color_white );
y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;
UI_DrawString( 320, y, "GeTall, Lubos, MasakaPete, Config2, Maniac, Ghostdog72, Slydog43,", UI_CENTER|UI_SMALLFONT, color_white );
y += PROP_HEIGHT * PROP_SMALL_SIZE_SCALE;

View file

@ -1126,7 +1126,7 @@ int ArenaServers_SetType( int type )
if(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
{
char masterstr[2], cvarname[sizeof("sv_master1")];
char masterstr[2], cvarname[sizeof("vr_master1")];
int direction;
if (type == g_servertype || type == ((g_servertype+1) % UIAS_NUM_SOURCES)) {
@ -1137,7 +1137,7 @@ int ArenaServers_SetType( int type )
while(type >= UIAS_GLOBAL1 && type <= UIAS_GLOBAL5)
{
Com_sprintf(cvarname, sizeof(cvarname), "sv_master%d", type - UIAS_GLOBAL0);
Com_sprintf(cvarname, sizeof(cvarname), "vr_master%d", type - UIAS_GLOBAL0);
trap_Cvar_VariableStringBuffer(cvarname, masterstr, sizeof(masterstr));
if(*masterstr)
break;

View file

@ -99,6 +99,14 @@ static const char *gametype_items[] = {
static int gametype_remap[] = {GT_FFA, GT_TEAM, GT_TOURNAMENT, GT_CTF};
static int gametype_remap2[] = {0, 2, 0, 1, 3};
static int fraglimit_values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 50, 75, 100, 200, 500, -1};
static const char *fraglimit_items[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "15",
"20", "25", "30", "40", "50", "75", "100", "200", "500", NULL};
static int timelimit_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 50, 60, 120, 240, 480, -1};
static const char *timelimit_items[] = {"No limit", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "15",
"20", "25", "30", "40", "50", "60", "120", "240", "480", NULL};
// use ui_servers2.c definition
extern const char* punkbuster_items[];
@ -631,9 +639,9 @@ typedef struct {
menubitmap_s picframe;
menulist_s dedicated;
menufield_s timelimit;
menufield_s fraglimit;
menufield_s flaglimit;
menulist_s timelimit;
menulist_s fraglimit;
menulist_s flaglimit;
menuradiobutton_s friendlyfire;
menufield_s hostname;
menuradiobutton_s pure;
@ -735,9 +743,9 @@ static void ServerOptions_Start( void ) {
char buf[64];
const char *info;
timelimit = atoi( s_serveroptions.timelimit.field.buffer );
fraglimit = atoi( s_serveroptions.fraglimit.field.buffer );
flaglimit = atoi( s_serveroptions.flaglimit.field.buffer );
timelimit = timelimit_values[s_serveroptions.timelimit.curvalue];
fraglimit = fraglimit_values[s_serveroptions.fraglimit.curvalue];
flaglimit = fraglimit_values[s_serveroptions.flaglimit.curvalue];
dedicated = s_serveroptions.dedicated.curvalue;
friendlyfire = s_serveroptions.friendlyfire.curvalue;
pure = s_serveroptions.pure.curvalue;
@ -1127,6 +1135,21 @@ static void ServerOptions_InitBotNames( void ) {
}
}
static int getValueIndex(int* values, int value, int defaultVal)
{
int index = 0;
while (values[index] != -1)
{
if (values[index] == value)
{
return index;
}
index++;
}
//Just return the default
return defaultVal;
}
/*
=================
@ -1141,24 +1164,24 @@ static void ServerOptions_SetMenuItems( void ) {
switch( s_serveroptions.gametype ) {
case GT_FFA:
default:
Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ) ) );
Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_timelimit" ) ) );
s_serveroptions.fraglimit.curvalue = getValueIndex(fraglimit_values, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ), 11);
s_serveroptions.timelimit.curvalue = getValueIndex(timelimit_values, trap_Cvar_VariableValue( "ui_ffa_timelimit" ), 0);
break;
case GT_TOURNAMENT:
Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ) ) );
Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_timelimit" ) ) );
s_serveroptions.fraglimit.curvalue = getValueIndex(fraglimit_values, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ), 11);
s_serveroptions.timelimit.curvalue = getValueIndex(timelimit_values, trap_Cvar_VariableValue( "ui_tourney_timelimit" ), 0);
break;
case GT_TEAM:
Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_fraglimit" ) ) );
Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_timelimit" ) ) );
s_serveroptions.fraglimit.curvalue = getValueIndex(fraglimit_values, trap_Cvar_VariableValue( "ui_team_fraglimit"), 11);
s_serveroptions.timelimit.curvalue = getValueIndex(timelimit_values, trap_Cvar_VariableValue( "ui_team_timelimit" ), 0);
s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_team_friendly" ) );
break;
case GT_CTF:
Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ) ) );
Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_timelimit" ) ) );
s_serveroptions.flaglimit.curvalue = getValueIndex(fraglimit_values, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ), 11);
s_serveroptions.timelimit.curvalue = getValueIndex(timelimit_values, trap_Cvar_VariableValue( "ui_ctf_timelimit" ), 0);
s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_friendly" ) );
break;
}
@ -1281,35 +1304,35 @@ static void ServerOptions_MenuInit( qboolean multiplayer ) {
y = 272;
if( s_serveroptions.gametype != GT_CTF ) {
s_serveroptions.fraglimit.generic.type = MTYPE_FIELD;
s_serveroptions.fraglimit.generic.type = MTYPE_SPINCONTROL;
s_serveroptions.fraglimit.generic.name = "Frag Limit:";
s_serveroptions.fraglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_serveroptions.fraglimit.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_serveroptions.fraglimit.generic.x = OPTIONS_X;
s_serveroptions.fraglimit.generic.y = y;
s_serveroptions.fraglimit.generic.statusbar = ServerOptions_StatusBar;
s_serveroptions.fraglimit.field.widthInChars = 3;
s_serveroptions.fraglimit.field.maxchars = 3;
s_serveroptions.fraglimit.curvalue = 11;
s_serveroptions.fraglimit.itemnames = fraglimit_items;
}
else {
s_serveroptions.flaglimit.generic.type = MTYPE_FIELD;
s_serveroptions.flaglimit.generic.type = MTYPE_SPINCONTROL;
s_serveroptions.flaglimit.generic.name = "Capture Limit:";
s_serveroptions.flaglimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_serveroptions.flaglimit.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_serveroptions.flaglimit.generic.x = OPTIONS_X;
s_serveroptions.flaglimit.generic.y = y;
s_serveroptions.flaglimit.generic.statusbar = ServerOptions_StatusBar;
s_serveroptions.flaglimit.field.widthInChars = 3;
s_serveroptions.flaglimit.field.maxchars = 3;
s_serveroptions.flaglimit.curvalue = 9;
s_serveroptions.flaglimit.itemnames = fraglimit_items;
}
y += BIGCHAR_HEIGHT+2;
s_serveroptions.timelimit.generic.type = MTYPE_FIELD;
s_serveroptions.timelimit.generic.type = MTYPE_SPINCONTROL;
s_serveroptions.timelimit.generic.name = "Time Limit:";
s_serveroptions.timelimit.generic.flags = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_serveroptions.timelimit.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_serveroptions.timelimit.generic.x = OPTIONS_X;
s_serveroptions.timelimit.generic.y = y;
s_serveroptions.timelimit.generic.statusbar = ServerOptions_StatusBar;
s_serveroptions.timelimit.field.widthInChars = 3;
s_serveroptions.timelimit.field.maxchars = 3;
s_serveroptions.flaglimit.curvalue = 0;
s_serveroptions.timelimit.itemnames = timelimit_items;
if( s_serveroptions.gametype >= GT_TEAM ) {
y += BIGCHAR_HEIGHT+2;

View file

@ -249,10 +249,12 @@ GRAPHICS OPTIONS MENU
#define ID_PLAYERSHADOW 109
#define ID_GAMMA 110
#define ID_HIGHQUALITYSKY 111
#define ID_SUPERSAMPLING 112
#define NUM_REFRESHRATE 4
#define NUM_REFRESHRATE 5
#define NUM_SHADOWS 3
#define NUM_RAILGUN 2
#define NUM_SUPERSAMPLING 6
typedef struct {
menuframework_s menu;
@ -276,6 +278,7 @@ typedef struct {
menulist_s playershadow;
menuslider_s gamma;
menuradiobutton_s highqualitysky;
menulist_s supersampling;
menubitmap_s apply;
menubitmap_s back;
@ -292,6 +295,7 @@ typedef struct
int playershadow;
float gamma;
int highqualitysky;
float supersampling;
} InitialVideoOptions_s;
static InitialVideoOptions_s s_ivo;
@ -313,6 +317,7 @@ static void GraphicsOptions_GetInitialVideo( void )
s_ivo.playershadow = s_graphicsoptions.playershadow.curvalue;
s_ivo.gamma = s_graphicsoptions.gamma.curvalue;
s_ivo.highqualitysky = s_graphicsoptions.highqualitysky.curvalue;
s_ivo.supersampling = s_graphicsoptions.supersampling.curvalue;
}
/*
@ -401,6 +406,9 @@ static void GraphicsOptions_Event( void* ptr, int event ) {
case 3:
refresh = 90;
break;
case 4:
refresh = 120;
break;
}
trap_Cvar_SetValue("vr_refreshrate", refresh);
}
@ -452,6 +460,32 @@ static void GraphicsOptions_Event( void* ptr, int event ) {
trap_Cvar_SetValue( "r_fastsky", !s_graphicsoptions.highqualitysky.curvalue );
break;
case ID_SUPERSAMPLING: {
float supersampling;
switch (s_graphicsoptions.supersampling.curvalue) {
case 0:
supersampling = 0.8;
break;
case 1:
supersampling = 0.9;
break;
case 2:
supersampling = 1.0;
break;
case 3:
supersampling = 1.1;
break;
case 4:
supersampling = 1.2;
break;
case 5:
supersampling = 1.3;
break;
}
trap_Cvar_SetValue("vr_superSampling", supersampling);
}
break;
case ID_DRIVERINFO:
UI_DriverInfo_Menu();
break;
@ -542,6 +576,12 @@ static void GraphicsOptions_SetMenuItems( void )
case 90:
s_graphicsoptions.refreshrate.curvalue = 3;
break;
case 120:
s_graphicsoptions.refreshrate.curvalue = 4;
break;
default:
s_graphicsoptions.refreshrate.curvalue = 1;
break;
}
switch ( (int) trap_Cvar_VariableValue( "cg_shadows" ) )
@ -570,6 +610,23 @@ static void GraphicsOptions_SetMenuItems( void )
break;
}
float superSampling = trap_Cvar_VariableValue( "vr_superSampling" );
if (superSampling == 0.8f) {
s_graphicsoptions.supersampling.curvalue = 0;
} else if (superSampling == 0.9f) {
s_graphicsoptions.supersampling.curvalue = 1;
} else if (superSampling == 1.0f) {
s_graphicsoptions.supersampling.curvalue = 2;
} else if (superSampling == 1.1f) {
s_graphicsoptions.supersampling.curvalue = 3;
} else if (superSampling == 1.2f) {
s_graphicsoptions.supersampling.curvalue = 4;
} else if (superSampling == 1.3f) {
s_graphicsoptions.supersampling.curvalue = 5;
} else {
s_graphicsoptions.supersampling.curvalue = 3;
}
s_graphicsoptions.lighting.curvalue = trap_Cvar_VariableValue( "r_vertexLight" ) != 0;
s_graphicsoptions.railgun.curvalue = trap_Cvar_VariableValue( "cg_oldRail" );
s_graphicsoptions.gamma.curvalue = trap_Cvar_VariableValue( "r_gamma" );
@ -602,9 +659,10 @@ void GraphicsOptions_MenuInit( void )
static const char *s_refreshrate[] =
{
"60",
"72 (Recommended)",
"72",
"80",
"90",
"120",
NULL
};
@ -623,6 +681,17 @@ void GraphicsOptions_MenuInit( void )
NULL
};
static const char *s_supersampling[] =
{
"0.8",
"0.9",
"1.0",
"1.1",
"1.2",
"1.3",
NULL
};
int y;
// zero set all our globals
@ -687,7 +756,7 @@ void GraphicsOptions_MenuInit( void )
s_graphicsoptions.network.style = UI_RIGHT;
s_graphicsoptions.network.color = color_red;
y = 254 - 5 * (BIGCHAR_HEIGHT + 2);
y = 254 - 6 * (BIGCHAR_HEIGHT + 2);
// references "vr_refreshrate"
s_graphicsoptions.refreshrate.generic.type = MTYPE_SPINCONTROL;
@ -701,6 +770,18 @@ void GraphicsOptions_MenuInit( void )
s_graphicsoptions.refreshrate.numitems = NUM_REFRESHRATE;
y += BIGCHAR_HEIGHT+2;
// references "vr_superSampling"
s_graphicsoptions.supersampling.generic.type = MTYPE_SPINCONTROL;
s_graphicsoptions.supersampling.generic.name = "Supersampling:";
s_graphicsoptions.supersampling.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_graphicsoptions.supersampling.generic.x = 400;
s_graphicsoptions.supersampling.generic.y = y;
s_graphicsoptions.supersampling.itemnames = s_supersampling;
s_graphicsoptions.supersampling.generic.callback = GraphicsOptions_Event;
s_graphicsoptions.supersampling.generic.id = ID_SUPERSAMPLING;
s_graphicsoptions.supersampling.numitems = NUM_SUPERSAMPLING;
y += BIGCHAR_HEIGHT+2;
// references "r_gamma"
s_graphicsoptions.gamma.generic.type = MTYPE_SLIDER;
s_graphicsoptions.gamma.generic.name = "Brightness:";
@ -709,8 +790,8 @@ void GraphicsOptions_MenuInit( void )
s_graphicsoptions.gamma.generic.y = y;
s_graphicsoptions.gamma.generic.callback = GraphicsOptions_Event;
s_graphicsoptions.gamma.generic.id = ID_GAMMA;
s_graphicsoptions.gamma.minvalue = 0.8f;
s_graphicsoptions.gamma.maxvalue = 1.2f;
s_graphicsoptions.gamma.minvalue = 0.6f;
s_graphicsoptions.gamma.maxvalue = 1.0f;
y += BIGCHAR_HEIGHT+2;
// references "cg_oldRail"
@ -828,6 +909,7 @@ void GraphicsOptions_MenuInit( void )
Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.network );
Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.refreshrate );
Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.supersampling );
Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.railgun );
Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.gamma );
Menu_AddItem( &s_graphicsoptions.menu, ( void * ) &s_graphicsoptions.lighting );

View file

@ -24,13 +24,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_types.h"
#if __ANDROID__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"
#include <VrApi.h>
#pragma clang diagnostic pop
#endif
#define REF_API_VERSION 8
//
@ -92,8 +85,9 @@ typedef struct {
void (*EndFrame)( int *frontEndMsec, int *backEndMsec );
#if __ANDROID__
void (*SetVRHeadsetParms)( const ovrMatrix4f *projectionMatrix, const ovrMatrix4f *nonVRProjectionMatrix,
int renderBuffer );
void (*SetVRHeadsetParms)( const float projectionMatrix[4][4],
const float nonVRProjectionMatrix[4][4],
int renderBuffer );
#endif
int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,

View file

@ -513,11 +513,10 @@ void R_Mat4Transpose( const float in[4][4], float* out ) {
}
}
void RE_SetVRHeadsetParms( const ovrMatrix4f *projectionMatrix, const ovrMatrix4f *nonVRProjectionMatrix,
void RE_SetVRHeadsetParms( const float projectionMatrix[4][4], const float nonVRProjectionMatrix[4][4],
int renderBuffer ) {
R_Mat4Transpose(projectionMatrix->M, tr.vrParms.projection);
R_Mat4Transpose(nonVRProjectionMatrix->M, tr.vrParms.monoVRProjection);
R_Mat4Transpose(projectionMatrix, tr.vrParms.projection);
R_Mat4Transpose(nonVRProjectionMatrix, tr.vrParms.monoVRProjection);
tr.vrParms.renderBuffer = renderBuffer;
tr.vrParms.valid = qtrue;
}

View file

@ -1322,7 +1322,7 @@ void R_Register( void )
r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0",
CVAR_ARCHIVE | CVAR_LATCH );
r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE );
r_gamma = ri.Cvar_Get( "r_gamma", "0.8", CVAR_ARCHIVE );
r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE );
r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE );

View file

@ -2535,8 +2535,9 @@ void RE_StretchPic ( float x, float y, float w, float h,
void RE_BeginFrame( stereoFrame_t stereoFrame );
void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
#if __ANDROID__
void RE_SetVRHeadsetParms( const ovrMatrix4f *projectionMatrix, const ovrMatrix4f *nonVRProjectionMatrix,
int renderBuffer );
void RE_SetVRHeadsetParms( const float projectionMatrix[4][4],
const float nonVRProjectionMatrix[4][4],
int renderBuffer );
#endif
void RE_HUDBufferStart( qboolean clear );
void RE_HUDBufferEnd( void );

View file

@ -274,7 +274,7 @@ extern cvar_t *sv_maxclients;
extern cvar_t *sv_privateClients;
extern cvar_t *sv_hostname;
extern cvar_t *sv_master[MAX_MASTER_SERVERS];
extern cvar_t *vr_master[MAX_MASTER_SERVERS];
extern cvar_t *sv_reconnectlimit;
extern cvar_t *sv_showloss;
extern cvar_t *sv_padPackets;

View file

@ -672,11 +672,11 @@ void SV_Init (void)
sv_allowDownload = Cvar_Get ("sv_allowDownload", "1", CVAR_SERVERINFO);
Cvar_Get ("sv_dlURL", "", CVAR_SERVERINFO | CVAR_ARCHIVE);
sv_master[0] = Cvar_Get("sv_master1", "", 0); // This is set to our Q3Q master
sv_master[1] = Cvar_Get("sv_master2", MASTER_SERVER_NAME, 0);
sv_master[2] = Cvar_Get("sv_master3", "master.ioquake3.org", 0);
vr_master[0] = Cvar_Get("vr_master1", "mp.quakevr.com:27950", 0); // This is set to our Q3Q master
vr_master[1] = Cvar_Get("vr_master2", MASTER_SERVER_NAME, 0);
vr_master[2] = Cvar_Get("vr_master3", "master.ioquake3.org", 0);
for(index = 3; index < MAX_MASTER_SERVERS; index++)
sv_master[index] = Cvar_Get(va("sv_master%d", index + 1), "", CVAR_ARCHIVE);
vr_master[index] = Cvar_Get(va("vr_master%d", index + 1), "", CVAR_ARCHIVE);
sv_reconnectlimit = Cvar_Get ("sv_reconnectlimit", "3", 0);
sv_showloss = Cvar_Get ("sv_showloss", "0", 0);

View file

@ -41,7 +41,7 @@ cvar_t *sv_maxclients;
cvar_t *sv_privateClients; // number of clients reserved for password
cvar_t *sv_hostname;
cvar_t *sv_master[MAX_MASTER_SERVERS]; // master server ip address
cvar_t *vr_master[MAX_MASTER_SERVERS]; // master server ip address
cvar_t *sv_reconnectlimit; // minimum seconds between connect messages
cvar_t *sv_showloss; // report when usercmds are lost
cvar_t *sv_padPackets; // add nop bytes to messages
@ -262,20 +262,20 @@ void SV_MasterHeartbeat(const char *message)
// send to group masters
for (i = 0; i < MAX_MASTER_SERVERS; i++)
{
if(!sv_master[i]->string[0])
if(!vr_master[i]->string[0])
continue;
// see if we haven't already resolved the name or if it's been over 24 hours
// resolving usually causes hitches on win95, so only do it when needed
if (sv_master[i]->modified || svs.time > svs.masterResolveTime[i])
if (vr_master[i]->modified || svs.time > svs.masterResolveTime[i])
{
sv_master[i]->modified = qfalse;
vr_master[i]->modified = qfalse;
svs.masterResolveTime[i] = svs.time + MASTERDNS_MSEC;
if(netenabled & NET_ENABLEV4)
{
Com_Printf("Resolving %s (IPv4)\n", sv_master[i]->string);
res = NET_StringToAdr(sv_master[i]->string, &adr[i][0], NA_IP);
Com_Printf("Resolving %s (IPv4)\n", vr_master[i]->string);
res = NET_StringToAdr(vr_master[i]->string, &adr[i][0], NA_IP);
if(res == 2)
{
@ -284,15 +284,15 @@ void SV_MasterHeartbeat(const char *message)
}
if(res)
Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][0]));
Com_Printf( "%s resolved to %s\n", vr_master[i]->string, NET_AdrToStringwPort(adr[i][0]));
else
Com_Printf( "%s has no IPv4 address.\n", sv_master[i]->string);
Com_Printf( "%s has no IPv4 address.\n", vr_master[i]->string);
}
if(netenabled & NET_ENABLEV6)
{
Com_Printf("Resolving %s (IPv6)\n", sv_master[i]->string);
res = NET_StringToAdr(sv_master[i]->string, &adr[i][1], NA_IP6);
Com_Printf("Resolving %s (IPv6)\n", vr_master[i]->string);
res = NET_StringToAdr(vr_master[i]->string, &adr[i][1], NA_IP6);
if(res == 2)
{
@ -301,9 +301,9 @@ void SV_MasterHeartbeat(const char *message)
}
if(res)
Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][1]));
Com_Printf( "%s resolved to %s\n", vr_master[i]->string, NET_AdrToStringwPort(adr[i][1]));
else
Com_Printf( "%s has no IPv6 address.\n", sv_master[i]->string);
Com_Printf( "%s has no IPv6 address.\n", vr_master[i]->string);
}
}
@ -313,7 +313,7 @@ void SV_MasterHeartbeat(const char *message)
}
Com_Printf ("Sending heartbeat to %s\n", sv_master[i]->string );
Com_Printf ("Sending heartbeat to %s\n", vr_master[i]->string );
// this command should be changed if the server info / status format
// ever incompatably changes

View file

@ -2488,11 +2488,11 @@ static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
if(ui_netSource.integer >= UIAS_GLOBAL1 && ui_netSource.integer <= UIAS_GLOBAL5)
{
char masterstr[2], cvarname[sizeof("sv_master1")];
char masterstr[2], cvarname[sizeof("vr_master1")];
while(ui_netSource.integer >= UIAS_GLOBAL1 && ui_netSource.integer <= UIAS_GLOBAL5)
{
Com_sprintf(cvarname, sizeof(cvarname), "sv_master%d", ui_netSource.integer - UIAS_GLOBAL0);
Com_sprintf(cvarname, sizeof(cvarname), "vr_master%d", ui_netSource.integer - UIAS_GLOBAL0);
trap_Cvar_VariableStringBuffer(cvarname, masterstr, sizeof(masterstr));
if(*masterstr)
break;

View file

@ -1,22 +1,26 @@
#include "vr_base.h"
#include "../VrApi/Include/VrApi.h"
#include "../VrApi/Include/VrApi_Helpers.h"
#include "../VrApi/Include/VrApi_Types.h"
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "../client/client.h"
#include "vr_base.h"
#include "vr_clientinfo.h"
//#if __ANDROID__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"
#pragma clang diagnostic pop
#include <EGL/egl.h>
#include <assert.h>
#include <unistd.h>
static engine_t vr_engine;
qboolean vr_initialized = qfalse;
extern vr_clientinfo_t vr;
const char* const requiredExtensionNames[] = {
XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME,
XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME,
XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME,
XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME,
XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME};
const uint32_t numRequiredExtensions =
sizeof(requiredExtensionNames) / sizeof(requiredExtensionNames[0]);
cvar_t *vr_worldscale = NULL;
cvar_t *vr_worldscaleScaler = NULL;
@ -31,6 +35,7 @@ cvar_t *vr_weaponPitch = NULL;
cvar_t *vr_twoHandedWeapons = NULL;
cvar_t *vr_showItemInHand = NULL;
cvar_t *vr_refreshrate = NULL;
cvar_t *vr_superSampling = NULL;
cvar_t *vr_weaponScope = NULL;
cvar_t *vr_rollWhenHit = NULL;
cvar_t *vr_hudYOffset = NULL;
@ -46,18 +51,92 @@ cvar_t *vr_showConsoleMessages = NULL;
engine_t* VR_Init( ovrJava java )
{
ovrInitParms initParams;
ovrResult initResult;
if (vr_initialized)
return &vr_engine;
memset(&vr_engine, 0, sizeof(vr_engine));
ovrApp_Clear(&vr_engine.appState);
initParams = vrapi_DefaultInitParms(&java);
initResult = vrapi_Initialize(&initParams);
assert(initResult == VRAPI_INITIALIZE_SUCCESS);
vr_engine.java = java;
PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
xrGetInstanceProcAddr(
XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&xrInitializeLoaderKHR);
if (xrInitializeLoaderKHR != NULL) {
XrLoaderInitInfoAndroidKHR loaderInitializeInfoAndroid;
memset(&loaderInitializeInfoAndroid, 0, sizeof(loaderInitializeInfoAndroid));
loaderInitializeInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR;
loaderInitializeInfoAndroid.next = NULL;
loaderInitializeInfoAndroid.applicationVM = java.Vm;
loaderInitializeInfoAndroid.applicationContext = java.ActivityObject;
xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid);
}
return &vr_engine;
// Create the OpenXR instance.
XrApplicationInfo appInfo;
memset(&appInfo, 0, sizeof(appInfo));
strcpy(appInfo.applicationName, "Quake 3 Arena");
appInfo.applicationVersion = 0;
strcpy(appInfo.engineName, "Quake 3 Arena");
appInfo.engineVersion = 0;
appInfo.apiVersion = XR_CURRENT_API_VERSION;
XrInstanceCreateInfo instanceCreateInfo;
memset(&instanceCreateInfo, 0, sizeof(instanceCreateInfo));
instanceCreateInfo.type = XR_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.next = NULL;
instanceCreateInfo.createFlags = 0;
instanceCreateInfo.applicationInfo = appInfo;
instanceCreateInfo.enabledApiLayerCount = 0;
instanceCreateInfo.enabledApiLayerNames = NULL;
instanceCreateInfo.enabledExtensionCount = numRequiredExtensions;
instanceCreateInfo.enabledExtensionNames = requiredExtensionNames;
XrResult initResult;
OXR(initResult = xrCreateInstance(&instanceCreateInfo, &vr_engine.appState.Instance));
if (initResult != XR_SUCCESS) {
ALOGE("Failed to create XR instance: %d.", initResult);
exit(1);
}
XrInstanceProperties instanceInfo;
instanceInfo.type = XR_TYPE_INSTANCE_PROPERTIES;
instanceInfo.next = NULL;
OXR(xrGetInstanceProperties(vr_engine.appState.Instance, &instanceInfo));
ALOGV(
"Runtime %s: Version : %u.%u.%u",
instanceInfo.runtimeName,
XR_VERSION_MAJOR(instanceInfo.runtimeVersion),
XR_VERSION_MINOR(instanceInfo.runtimeVersion),
XR_VERSION_PATCH(instanceInfo.runtimeVersion));
XrSystemGetInfo systemGetInfo;
memset(&systemGetInfo, 0, sizeof(systemGetInfo));
systemGetInfo.type = XR_TYPE_SYSTEM_GET_INFO;
systemGetInfo.next = NULL;
systemGetInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
XrSystemId systemId;
OXR(initResult = xrGetSystem(vr_engine.appState.Instance, &systemGetInfo, &systemId));
if (initResult != XR_SUCCESS) {
ALOGE("Failed to get system.");
exit(1);
}
// Get the graphics requirements.
PFN_xrGetOpenGLESGraphicsRequirementsKHR pfnGetOpenGLESGraphicsRequirementsKHR = NULL;
OXR(xrGetInstanceProcAddr(
vr_engine.appState.Instance,
"xrGetOpenGLESGraphicsRequirementsKHR",
(PFN_xrVoidFunction*)(&pfnGetOpenGLESGraphicsRequirementsKHR)));
XrGraphicsRequirementsOpenGLESKHR graphicsRequirements = {};
graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR;
OXR(pfnGetOpenGLESGraphicsRequirementsKHR(vr_engine.appState.Instance, systemId, &graphicsRequirements));
vr_engine.appState.MainThreadTid = gettid();
vr_engine.appState.SystemId = systemId;
vr_engine.java = java;
vr_initialized = qtrue;
return &vr_engine;
}
void VR_InitCvars( void )
@ -76,6 +155,7 @@ void VR_InitCvars( void )
vr_twoHandedWeapons = Cvar_Get ("vr_twoHandedWeapons", "1", CVAR_ARCHIVE);
vr_showItemInHand = Cvar_Get ("vr_showItemInHand", "1", CVAR_ARCHIVE);
vr_refreshrate = Cvar_Get ("vr_refreshrate", "72", CVAR_ARCHIVE);
vr_superSampling = Cvar_Get ("vr_superSampling", "1.1", CVAR_ARCHIVE);
vr_weaponScope = Cvar_Get ("vr_weaponScope", "1", CVAR_ARCHIVE);
vr_rollWhenHit = Cvar_Get ("vr_rollWhenHit", "0", CVAR_ARCHIVE);
vr_hudYOffset = Cvar_Get ("vr_hudYOffset", "0", CVAR_ARCHIVE);
@ -191,57 +271,89 @@ void VR_InitCvars( void )
Cvar_Get ("vr_button_map_SECONDARYGRIP", "+weapon_stabilise", CVAR_ARCHIVE); // Weapon stabilisation
Cvar_Get ("vr_button_map_SECONDARYGRIP_ALT", "", CVAR_ARCHIVE); // unmapped
Cvar_Get ("vr_button_map_PRIMARYGRIP_ALT", "", CVAR_ARCHIVE); // unmapped
vr.menuYaw = 0;
vr.recenterYaw = 0;
}
void VR_Destroy( engine_t* engine )
{
if (engine == &vr_engine) {
vrapi_Shutdown();
}
if (engine == &vr_engine) {
xrDestroyInstance(engine->appState.Instance);
ovrApp_Destroy(&engine->appState);
}
}
void VR_EnterVR( engine_t* engine, ovrJava java ) {
if (!engine->ovr) {
ovrModeParms modeParams = vrapi_DefaultModeParms(&java);
modeParams.Display = (size_t)eglGetCurrentDisplay();
modeParams.WindowSurface = (size_t)eglGetCurrentSurface(EGL_DRAW);
modeParams.ShareContext = (size_t)eglGetCurrentContext();
engine->ovr = vrapi_EnterVrMode(&modeParams);
engine->frameIndex = 0;
if (engine->appState.Session) {
Com_Printf("VR_EnterVR called with existing session");
return;
}
vrapi_SetTrackingSpace(engine->ovr, VRAPI_TRACKING_SPACE_LOCAL_FLOOR);
// Create the OpenXR Session.
XrGraphicsBindingOpenGLESAndroidKHR graphicsBindingAndroidGLES = {};
graphicsBindingAndroidGLES.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
graphicsBindingAndroidGLES.next = NULL;
graphicsBindingAndroidGLES.display = eglGetCurrentDisplay();
graphicsBindingAndroidGLES.config = eglGetCurrentSurface(EGL_DRAW);
graphicsBindingAndroidGLES.context = eglGetCurrentContext();
vrapi_SetClockLevels(engine->ovr, 4, 4);
}
XrSessionCreateInfo sessionCreateInfo = {};
memset(&sessionCreateInfo, 0, sizeof(sessionCreateInfo));
sessionCreateInfo.type = XR_TYPE_SESSION_CREATE_INFO;
sessionCreateInfo.next = &graphicsBindingAndroidGLES;
sessionCreateInfo.createFlags = 0;
sessionCreateInfo.systemId = engine->appState.SystemId;
XrResult initResult;
OXR(initResult = xrCreateSession(engine->appState.Instance, &sessionCreateInfo, &engine->appState.Session));
if (initResult != XR_SUCCESS) {
ALOGE("Failed to create XR session: %d.", initResult);
exit(1);
}
// Create a space to the first path
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.HeadSpace));
}
void VR_LeaveVR( engine_t* engine ) {
if (engine->ovr) {
vrapi_LeaveVrMode(engine->ovr);
engine->ovr = NULL;
}
if (engine->appState.Session) {
OXR(xrDestroySpace(engine->appState.HeadSpace));
// StageSpace is optional.
if (engine->appState.StageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->appState.StageSpace));
}
OXR(xrDestroySpace(engine->appState.FakeStageSpace));
engine->appState.CurrentSpace = XR_NULL_HANDLE;
OXR(xrDestroySession(engine->appState.Session));
engine->appState.Session = NULL;
}
}
engine_t* VR_GetEngine( void ) {
return &vr_engine;
}
bool VR_isPauseable( void )
int VR_isPauseable( void )
{
return (bool)( ( clc.state == CA_ACTIVE) && !Cvar_VariableValue ("cl_paused") );
return ( clc.state == CA_ACTIVE) && !Cvar_VariableValue ("cl_paused");
}
bool VR_useScreenLayer( void )
int VR_useScreenLayer( void )
{
//intermission is never full screen
if ( cl.snap.ps.pm_type == PM_INTERMISSION )
{
return qfalse;
return 0;
}
int keyCatcher = Key_GetCatcher( );
return (bool)( clc.state == CA_CINEMATIC ||
return ( clc.state == CA_CINEMATIC ||
( keyCatcher & (KEYCATCH_UI | KEYCATCH_CONSOLE) ));
}
//#endif

View file

@ -12,8 +12,8 @@ void VR_EnterVR( engine_t* engine, ovrJava java );
void VR_LeaveVR( engine_t* engine );
engine_t* VR_GetEngine( void );
bool VR_isPauseable( void );
bool VR_useScreenLayer( void );
int VR_useScreenLayer( void );
int VR_isPauseable( void );
float radians(float deg);

View file

@ -63,6 +63,9 @@ typedef struct {
int *menuCursorX;
int *menuCursorY;
qboolean menuLeftHanded;
float recenterYaw;
float superSampling;
} vr_clientinfo_t;
#endif //vr_clientinfo_h

View file

@ -2,13 +2,10 @@
//#if __ANDROID__
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "../client/keycodes.h"
#include "../client/client.h"
#include "vr_base.h"
#include "../VrApi/Include/VrApi_Input.h"
#include "../VrApi/Include/VrApi_Helpers.h"
#include "vr_clientinfo.h"
#include <unistd.h>
@ -20,6 +17,33 @@
# include <SDL.h>
#endif
//OpenXR
XrPath leftHandPath;
XrPath rightHandPath;
XrAction handPoseLeftAction;
XrAction handPoseRightAction;
XrAction indexLeftAction;
XrAction indexRightAction;
XrAction menuAction;
XrAction buttonAAction;
XrAction buttonBAction;
XrAction buttonXAction;
XrAction buttonYAction;
XrAction gripLeftAction;
XrAction gripRightAction;
XrAction moveOnLeftJoystickAction;
XrAction moveOnRightJoystickAction;
XrAction thumbstickLeftClickAction;
XrAction thumbstickRightClickAction;
XrAction vibrateLeftFeedback;
XrAction vibrateRightFeedback;
XrActionSet runningActionSet;
XrSpace leftControllerAimSpace = XR_NULL_HANDLE;
XrSpace rightControllerAimSpace = XR_NULL_HANDLE;
qboolean actionsAttached = qfalse;
qboolean inputInitialized = qfalse;
qboolean useSimpleProfile = qfalse;
enum {
VR_TOUCH_AXIS_UP = 1 << 0,
VR_TOUCH_AXIS_UPRIGHT = 1 << 1,
@ -92,7 +116,7 @@ void rotateAboutOrigin(float x, float y, float rotation, vec2_t out)
out[1] = cosf(DEG2RAD(-rotation)) * y - sinf(DEG2RAD(-rotation)) * x;
}
static ovrVector3f normalizeVec(ovrVector3f vec) {
XrVector3f normalizeVec(XrVector3f vec) {
//NOTE: leave w-component untouched
//@@const float EPSILON = 0.000001f;
float xxyyzz = vec.x*vec.x + vec.y*vec.y + vec.z*vec.z;
@ -100,7 +124,7 @@ static ovrVector3f normalizeVec(ovrVector3f vec) {
//@@ return *this; // do nothing if it is zero vector
//float invLength = invSqrt(xxyyzz);
ovrVector3f result;
XrVector3f result;
float invLength = 1.0f / sqrtf(xxyyzz);
result.x = vec.x * invLength;
result.y = vec.y * invLength;
@ -123,7 +147,7 @@ void NormalizeAngles(vec3_t angles)
while (angles[2] < -180) angles[2] += 360;
}
void GetAnglesFromVectors(const ovrVector3f forward, const ovrVector3f right, const ovrVector3f up, vec3_t angles)
void GetAnglesFromVectors(const XrVector3f forward, const XrVector3f right, const XrVector3f up, vec3_t angles)
{
float sr, sp, sy, cr, cp, cy;
@ -172,7 +196,7 @@ void GetAnglesFromVectors(const ovrVector3f forward, const ovrVector3f right, co
NormalizeAngles(angles);
}
void QuatToYawPitchRoll(ovrQuatf q, vec3_t rotation, vec3_t out) {
void QuatToYawPitchRoll(XrQuaternionf q, vec3_t rotation, vec3_t out) {
ovrMatrix4f mat = ovrMatrix4f_CreateFromQuaternion( &q );
@ -182,21 +206,21 @@ void QuatToYawPitchRoll(ovrQuatf q, vec3_t rotation, vec3_t out) {
mat = ovrMatrix4f_Multiply(&mat, &rot);
}
ovrVector4f v1 = {0, 0, -1, 0};
ovrVector4f v2 = {1, 0, 0, 0};
ovrVector4f v3 = {0, 1, 0, 0};
XrVector4f v1 = {0, 0, -1, 0};
XrVector4f v2 = {1, 0, 0, 0};
XrVector4f v3 = {0, 1, 0, 0};
ovrVector4f forwardInVRSpace = ovrVector4f_MultiplyMatrix4f(&mat, &v1);
ovrVector4f rightInVRSpace = ovrVector4f_MultiplyMatrix4f(&mat, &v2);
ovrVector4f upInVRSpace = ovrVector4f_MultiplyMatrix4f(&mat, &v3);
XrVector4f forwardInVRSpace = XrVector4f_MultiplyMatrix4f(&mat, &v1);
XrVector4f rightInVRSpace = XrVector4f_MultiplyMatrix4f(&mat, &v2);
XrVector4f upInVRSpace = XrVector4f_MultiplyMatrix4f(&mat, &v3);
ovrVector3f forward = {-forwardInVRSpace.z, -forwardInVRSpace.x, forwardInVRSpace.y};
ovrVector3f right = {-rightInVRSpace.z, -rightInVRSpace.x, rightInVRSpace.y};
ovrVector3f up = {-upInVRSpace.z, -upInVRSpace.x, upInVRSpace.y};
XrVector3f forward = {-forwardInVRSpace.z, -forwardInVRSpace.x, forwardInVRSpace.y};
XrVector3f right = {-rightInVRSpace.z, -rightInVRSpace.x, rightInVRSpace.y};
XrVector3f up = {-upInVRSpace.z, -upInVRSpace.x, upInVRSpace.y};
ovrVector3f forwardNormal = normalizeVec(forward);
ovrVector3f rightNormal = normalizeVec(right);
ovrVector3f upNormal = normalizeVec(up);
XrVector3f forwardNormal = normalizeVec(forward);
XrVector3f rightNormal = normalizeVec(right);
XrVector3f upNormal = normalizeVec(up);
GetAnglesFromVectors(forwardNormal, rightNormal, upNormal, out);
}
@ -204,7 +228,6 @@ void QuatToYawPitchRoll(ovrQuatf q, vec3_t rotation, vec3_t out) {
//0 = left, 1 = right
float vibration_channel_duration[2] = {0.0f, 0.0f};
float vibration_channel_intensity[2] = {0.0f, 0.0f};
ovrDeviceID controllerIDs[2];
void VR_Vibrate( int duration, int chan, float intensity )
{
@ -235,8 +258,19 @@ static void VR_processHaptics() {
for (int i = 0; i < 2; ++i) {
if (vibration_channel_duration[i] > 0.0f ||
vibration_channel_duration[i] == -1.0f) {
vrapi_SetHapticVibrationSimple(VR_GetEngine()->ovr, controllerIDs[i],
vibration_channel_intensity[i]);
// 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 = i == 0 ? vibrateLeftFeedback : vibrateRightFeedback;
OXR(xrApplyHapticFeedback(VR_GetEngine()->appState.Session, &hapticActionInfo, (const XrHapticBaseHeader*)&vibration));
if (vibration_channel_duration[i] != -1.0f) {
vibration_channel_duration[i] -= frametime;
@ -247,7 +281,12 @@ static void VR_processHaptics() {
}
}
} else {
vrapi_SetHapticVibrationSimple(VR_GetEngine()->ovr, controllerIDs[i], 0.0f);
// Stop haptics
XrHapticActionInfo hapticActionInfo = {};
hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO;
hapticActionInfo.next = NULL;
hapticActionInfo.action = i == 0 ? vibrateLeftFeedback : vibrateRightFeedback;
OXR(xrStopHapticFeedback(VR_GetEngine()->appState.Session, &hapticActionInfo));
}
}
}
@ -468,50 +507,355 @@ void VR_HapticEvent(const char* event, int position, int flags, int intensity, f
}
}
XrSpace CreateActionSpace(XrAction poseAction, XrPath subactionPath) {
XrActionSpaceCreateInfo asci = {};
asci.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
asci.action = poseAction;
asci.poseInActionSpace.orientation.w = 1.0f;
asci.subactionPath = subactionPath;
XrSpace actionSpace = XR_NULL_HANDLE;
OXR(xrCreateActionSpace(VR_GetEngine()->appState.Session, &asci, &actionSpace));
return actionSpace;
}
XrActionSuggestedBinding ActionSuggestedBinding(XrAction action, const char* bindingString) {
XrActionSuggestedBinding asb;
asb.action = action;
XrPath bindingPath;
OXR(xrStringToPath(VR_GetEngine()->appState.Instance, bindingString, &bindingPath));
asb.binding = bindingPath;
return asb;
}
XrActionSet CreateActionSet(int priority, const char* name, const char* localizedName) {
XrActionSetCreateInfo asci = {};
asci.type = XR_TYPE_ACTION_SET_CREATE_INFO;
asci.next = NULL;
asci.priority = priority;
strcpy(asci.actionSetName, name);
strcpy(asci.localizedActionSetName, localizedName);
XrActionSet actionSet = XR_NULL_HANDLE;
OXR(xrCreateActionSet(VR_GetEngine()->appState.Instance, &asci, &actionSet));
return actionSet;
}
XrAction CreateAction(
XrActionSet actionSet,
XrActionType type,
const char* actionName,
const char* localizedName,
int countSubactionPaths,
XrPath* subactionPaths) {
ALOGV("CreateAction %s, %" PRIi32, 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);
XrAction action = XR_NULL_HANDLE;
OXR(xrCreateAction(actionSet, &aci, &action));
return action;
}
qboolean ActionPoseIsActive(XrAction action, XrPath subactionPath) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
getInfo.subactionPath = subactionPath;
XrActionStatePose state = {};
state.type = XR_TYPE_ACTION_STATE_POSE;
OXR(xrGetActionStatePose(VR_GetEngine()->appState.Session, &getInfo, &state));
return state.isActive != XR_FALSE;
}
XrActionStateFloat GetActionStateFloat(XrAction action) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
XrActionStateFloat state = {};
state.type = XR_TYPE_ACTION_STATE_FLOAT;
OXR(xrGetActionStateFloat(VR_GetEngine()->appState.Session, &getInfo, &state));
return state;
}
XrActionStateBoolean GetActionStateBoolean(XrAction action) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
XrActionStateBoolean state = {};
state.type = XR_TYPE_ACTION_STATE_BOOLEAN;
OXR(xrGetActionStateBoolean(VR_GetEngine()->appState.Session, &getInfo, &state));
return state;
}
XrActionStateVector2f GetActionStateVector2(XrAction action) {
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.action = action;
XrActionStateVector2f state = {};
state.type = XR_TYPE_ACTION_STATE_VECTOR2F;
OXR(xrGetActionStateVector2f(VR_GetEngine()->appState.Session, &getInfo, &state));
return state;
}
void IN_VRInit( void )
{
if (inputInitialized)
return;
memset(&vr, 0, sizeof(vr));
engine_t *engine = VR_GetEngine();
callbackClass = (*engine->java.Env)->GetObjectClass(engine->java.Env, engine->java.ActivityObject);
android_haptic_event = (*engine->java.Env)->GetMethodID(engine->java.Env, callbackClass, "haptic_event","(Ljava/lang/String;IIIFF)V");
// Actions
runningActionSet = CreateActionSet(1, "running_action_set", "Action Set used on main loop");
indexLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_left", "Index left", 0, NULL);
indexRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "index_right", "Index right", 0, NULL);
menuAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "menu_action", "Menu", 0, NULL);
buttonAAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_a", "Button A", 0, NULL);
buttonBAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_b", "Button B", 0, NULL);
buttonXAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_x", "Button X", 0, NULL);
buttonYAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "button_y", "Button Y", 0, NULL);
gripLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_FLOAT_INPUT, "grip_left", "Grip left", 0, NULL);
gripRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_FLOAT_INPUT, "grip_right", "Grip right", 0, NULL);
moveOnLeftJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_left_joy", "Move on left Joy", 0, NULL);
moveOnRightJoystickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_VECTOR2F_INPUT, "move_on_right_joy", "Move on right Joy", 0, NULL);
thumbstickLeftClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_left", "Thumbstick left", 0, NULL);
thumbstickRightClickAction = CreateAction(runningActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "thumbstick_right", "Thumbstick right", 0, NULL);
vibrateLeftFeedback = CreateAction(runningActionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_left_feedback", "Vibrate Left Controller Feedback", 0, NULL);
vibrateRightFeedback = CreateAction(runningActionSet, XR_ACTION_TYPE_VIBRATION_OUTPUT, "vibrate_right_feedback", "Vibrate Right Controller Feedback", 0, NULL);
OXR(xrStringToPath(engine->appState.Instance, "/user/hand/left", &leftHandPath));
OXR(xrStringToPath(engine->appState.Instance, "/user/hand/right", &rightHandPath));
handPoseLeftAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_left", NULL, 1, &leftHandPath);
handPoseRightAction = CreateAction(runningActionSet, XR_ACTION_TYPE_POSE_INPUT, "hand_pose_right", NULL, 1, &rightHandPath);
XrPath interactionProfilePath = XR_NULL_PATH;
XrPath interactionProfilePathTouch = XR_NULL_PATH;
XrPath interactionProfilePathKHRSimple = XR_NULL_PATH;
OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/oculus/touch_controller", &interactionProfilePathTouch));
OXR(xrStringToPath(engine->appState.Instance, "/interaction_profiles/khr/simple_controller", &interactionProfilePathKHRSimple));
// Toggle this to force simple as a first choice, otherwise use it as a last resort
if (useSimpleProfile) {
ALOGV("xrSuggestInteractionProfileBindings found bindings for Khronos SIMPLE controller");
interactionProfilePath = interactionProfilePathKHRSimple;
} else {
// Query Set
XrActionSet queryActionSet = CreateActionSet(1, "query_action_set", "Action Set used to query device caps");
XrAction dummyAction = CreateAction(queryActionSet, XR_ACTION_TYPE_BOOLEAN_INPUT, "dummy_action", "Dummy Action", 0, NULL);
// Map bindings
XrActionSuggestedBinding bindings[1];
int currBinding = 0;
bindings[currBinding++] = ActionSuggestedBinding(dummyAction, "/user/hand/right/input/system/click");
XrInteractionProfileSuggestedBinding suggestedBindings = {};
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
suggestedBindings.next = NULL;
suggestedBindings.suggestedBindings = bindings;
suggestedBindings.countSuggestedBindings = currBinding;
// Try all
suggestedBindings.interactionProfile = interactionProfilePathTouch;
XrResult suggestTouchResult = xrSuggestInteractionProfileBindings(engine->appState.Instance, &suggestedBindings);
OXR(suggestTouchResult);
if (XR_SUCCESS == suggestTouchResult) {
ALOGV("xrSuggestInteractionProfileBindings found bindings for QUEST controller");
interactionProfilePath = interactionProfilePathTouch;
}
if (interactionProfilePath == XR_NULL_PATH) {
// Simple as a fallback
bindings[0] = ActionSuggestedBinding(dummyAction, "/user/hand/right/input/select/click");
suggestedBindings.interactionProfile = interactionProfilePathKHRSimple;
XrResult suggestKHRSimpleResult = xrSuggestInteractionProfileBindings(engine->appState.Instance, &suggestedBindings);
OXR(suggestKHRSimpleResult);
if (XR_SUCCESS == suggestKHRSimpleResult) {
ALOGV("xrSuggestInteractionProfileBindings found bindings for Khronos SIMPLE controller");
interactionProfilePath = interactionProfilePathKHRSimple;
} else {
ALOGE("xrSuggestInteractionProfileBindings did NOT find any bindings.");
assert(qfalse);
}
}
}
// Action creation
{
// Map bindings
XrActionSuggestedBinding bindings[32]; // large enough for all profiles
int currBinding = 0;
{
if (interactionProfilePath == interactionProfilePathTouch) {
bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/trigger");
bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/trigger");
bindings[currBinding++] = ActionSuggestedBinding(menuAction, "/user/hand/left/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/left/input/x/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonYAction, "/user/hand/left/input/y/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/right/input/a/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonBAction, "/user/hand/right/input/b/click");
bindings[currBinding++] = ActionSuggestedBinding(gripLeftAction, "/user/hand/left/input/squeeze/value");
bindings[currBinding++] = ActionSuggestedBinding(gripRightAction, "/user/hand/right/input/squeeze/value");
bindings[currBinding++] = ActionSuggestedBinding(moveOnLeftJoystickAction, "/user/hand/left/input/thumbstick");
bindings[currBinding++] = ActionSuggestedBinding(moveOnRightJoystickAction, "/user/hand/right/input/thumbstick");
bindings[currBinding++] = ActionSuggestedBinding(thumbstickLeftClickAction, "/user/hand/left/input/thumbstick/click");
bindings[currBinding++] = ActionSuggestedBinding(thumbstickRightClickAction, "/user/hand/right/input/thumbstick/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(handPoseLeftAction, "/user/hand/left/input/aim/pose");
bindings[currBinding++] = ActionSuggestedBinding(handPoseRightAction, "/user/hand/right/input/aim/pose");
}
if (interactionProfilePath == interactionProfilePathKHRSimple) {
bindings[currBinding++] = ActionSuggestedBinding(indexLeftAction, "/user/hand/left/input/select/click");
bindings[currBinding++] = ActionSuggestedBinding(indexRightAction, "/user/hand/right/input/select/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonAAction, "/user/hand/left/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(buttonXAction, "/user/hand/right/input/menu/click");
bindings[currBinding++] = ActionSuggestedBinding(vibrateLeftFeedback, "/user/hand/left/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(vibrateRightFeedback, "/user/hand/right/output/haptic");
bindings[currBinding++] = ActionSuggestedBinding(handPoseLeftAction, "/user/hand/left/input/aim/pose");
bindings[currBinding++] = ActionSuggestedBinding(handPoseRightAction, "/user/hand/right/input/aim/pose");
}
}
XrInteractionProfileSuggestedBinding suggestedBindings = {};
suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
suggestedBindings.next = NULL;
suggestedBindings.interactionProfile = interactionProfilePath;
suggestedBindings.suggestedBindings = bindings;
suggestedBindings.countSuggestedBindings = currBinding;
OXR(xrSuggestInteractionProfileBindings(engine->appState.Instance, &suggestedBindings));
// Enumerate actions
XrPath actionPathsBuffer[32];
char stringBuffer[256];
XrAction actionsToEnumerate[] = {
indexLeftAction,
indexRightAction,
menuAction,
buttonAAction,
buttonBAction,
buttonXAction,
buttonYAction,
gripLeftAction,
gripRightAction,
moveOnLeftJoystickAction,
moveOnRightJoystickAction,
thumbstickLeftClickAction,
thumbstickRightClickAction,
vibrateLeftFeedback,
vibrateRightFeedback,
handPoseLeftAction,
handPoseRightAction
};
for (size_t i = 0; i < sizeof(actionsToEnumerate) / sizeof(actionsToEnumerate[0]); ++i) {
XrBoundSourcesForActionEnumerateInfo enumerateInfo = {};
enumerateInfo.type = XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO;
enumerateInfo.next = NULL;
enumerateInfo.action = actionsToEnumerate[i];
// Get Count
uint32_t countOutput = 0;
OXR(xrEnumerateBoundSourcesForAction(
engine->appState.Session, &enumerateInfo, 0 /* request size */, &countOutput, NULL));
ALOGV(
"xrEnumerateBoundSourcesForAction action=%lld count=%u",
(long long)enumerateInfo.action,
countOutput);
if (countOutput < 32) {
OXR(xrEnumerateBoundSourcesForAction(
engine->appState.Session, &enumerateInfo, 32, &countOutput, actionPathsBuffer));
for (uint32_t a = 0; a < countOutput; ++a) {
XrInputSourceLocalizedNameGetInfo nameGetInfo = {};
nameGetInfo.type = XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO;
nameGetInfo.next = NULL;
nameGetInfo.sourcePath = actionPathsBuffer[a];
nameGetInfo.whichComponents = XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT |
XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT |
XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT;
uint32_t stringCount = 0u;
OXR(xrGetInputSourceLocalizedName(
engine->appState.Session, &nameGetInfo, 0, &stringCount, NULL));
if (stringCount < 256) {
OXR(xrGetInputSourceLocalizedName(
engine->appState.Session, &nameGetInfo, 256, &stringCount, stringBuffer));
char pathStr[256];
uint32_t strLen = 0;
OXR(xrPathToString(
engine->appState.Instance,
actionPathsBuffer[a],
(uint32_t)sizeof(pathStr),
&strLen,
pathStr));
ALOGV(
" -> path = %lld `%s` -> `%s`",
(long long)actionPathsBuffer[a],
pathStr,
stringBuffer);
}
}
}
}
}
inputInitialized = qtrue;
}
static void IN_VRController( qboolean isRightController, ovrTracking remoteTracking )
static void IN_VRController( qboolean isRightController, XrPosef pose )
{
//Set gun angles - We need to calculate all those we might need (including adjustments) for the client to then take its pick
vec3_t rotation = {0};
if (isRightController == (vr_righthanded->integer != 0))
{
//Set gun angles - We need to calculate all those we might need (including adjustments) for the client to then take its pick
vec3_t rotation = {0};
rotation[PITCH] = vr_weaponPitch->value;
QuatToYawPitchRoll(remoteTracking.HeadPose.Pose.Orientation, rotation, vr.weaponangles);
VectorSubtract(vr.weaponangles_last, vr.weaponangles, vr.weaponangles_delta);
VectorCopy(vr.weaponangles, vr.weaponangles_last);
///Weapon location relative to view
vr.weaponposition[0] = remoteTracking.HeadPose.Pose.Position.x;
vr.weaponposition[1] = remoteTracking.HeadPose.Pose.Position.y + vr_heightAdjust->value;
vr.weaponposition[2] = remoteTracking.HeadPose.Pose.Position.z;
VectorCopy(vr.weaponoffset_last[1], vr.weaponoffset_last[0]);
VectorCopy(vr.weaponoffset, vr.weaponoffset_last[1]);
VectorSubtract(vr.weaponposition, vr.hmdposition, vr.weaponoffset);
} else {
vec3_t rotation = {0};
QuatToYawPitchRoll(remoteTracking.HeadPose.Pose.Orientation, rotation, vr.offhandangles2); // used for off-hand direction mode
{
//Set gun angles - We need to calculate all those we might need (including adjustments) for the client to then take its pick
rotation[PITCH] = vr_weaponPitch->value;
QuatToYawPitchRoll(remoteTracking.HeadPose.Pose.Orientation, rotation, vr.offhandangles);
QuatToYawPitchRoll(pose.orientation, rotation, vr.weaponangles);
VectorSubtract(vr.weaponangles_last, vr.weaponangles, vr.weaponangles_delta);
VectorCopy(vr.weaponangles, vr.weaponangles_last);
///Weapon location relative to view
vr.weaponposition[0] = pose.position.x;
vr.weaponposition[1] = pose.position.y + vr_heightAdjust->value;
vr.weaponposition[2] = pose.position.z;
VectorCopy(vr.weaponoffset_last[1], vr.weaponoffset_last[0]);
VectorCopy(vr.weaponoffset, vr.weaponoffset_last[1]);
VectorSubtract(vr.weaponposition, vr.hmdposition, vr.weaponoffset);
} else {
QuatToYawPitchRoll(pose.orientation, rotation, vr.offhandangles2); // used for off-hand direction mode
rotation[PITCH] = vr_weaponPitch->value;
QuatToYawPitchRoll(pose.orientation, rotation, vr.offhandangles);
///location relative to view
vr.offhandposition[0] = remoteTracking.HeadPose.Pose.Position.x;
vr.offhandposition[1] = remoteTracking.HeadPose.Pose.Position.y + vr_heightAdjust->value;
vr.offhandposition[2] = remoteTracking.HeadPose.Pose.Position.z;
vr.offhandposition[0] = pose.position.x;
vr.offhandposition[1] = pose.position.y + vr_heightAdjust->value;
vr.offhandposition[2] = pose.position.z;
VectorCopy(vr.offhandoffset_last[1], vr.offhandoffset_last[0]);
VectorCopy(vr.offhandoffset, vr.offhandoffset_last[1]);
VectorSubtract(vr.offhandposition, vr.hmdposition, vr.offhandoffset);
}
}
if (vr.virtual_screen || cl.snap.ps.pm_type == PM_INTERMISSION)
{
@ -545,20 +889,39 @@ static void IN_VRController( qboolean isRightController, ovrTracking remoteTrack
if (vr_twoHandedWeapons->integer && vr.weapon_stabilised)
{
//Apply smoothing to the weapon hand
vec3_t smooth_weaponoffset;
VectorAdd(vr.weaponoffset, vr.weaponoffset_last[0], smooth_weaponoffset);
VectorAdd(smooth_weaponoffset, vr.weaponoffset_last[1],smooth_weaponoffset);
VectorScale(smooth_weaponoffset, 1.0f/3.0f, smooth_weaponoffset);
if (vr_twoHandedWeapons->integer == 2) // Virtual gun stock
{
// Offset to the appropriate eye a little bit
vec2_t xy;
rotateAboutOrigin(Cvar_VariableValue("cg_stereoSeparation") / 2.0f, 0.0f, -vr.hmdorientation[YAW], xy);
float x = vr.offhandposition[0] - (vr.hmdposition[0] + xy[0]);
float y = vr.offhandposition[1] - (vr.hmdposition[1] - 0.1f); // Use a point lower
float z = vr.offhandposition[2] - (vr.hmdposition[2] + xy[1]);
vec3_t vec;
VectorSubtract(vr.offhandoffset, smooth_weaponoffset, vec);
float zxDist = length(x, z);
float zxDist = length(vec[0], vec[2]);
if (zxDist != 0.0f && z != 0.0f) {
VectorSet(vr.weaponangles, -degrees(atanf(y / zxDist)),
-degrees(atan2f(x, -z)), 0);
}
}
else // Basic two-handed
{
// Apply smoothing to the weapon hand
vec3_t smooth_weaponoffset;
VectorAdd(vr.weaponoffset, vr.weaponoffset_last[0], smooth_weaponoffset);
VectorAdd(smooth_weaponoffset, vr.weaponoffset_last[1],smooth_weaponoffset);
VectorScale(smooth_weaponoffset, 1.0f/3.0f, smooth_weaponoffset);
if (zxDist != 0.0f && vec[2] != 0.0f) {
VectorSet(vr.weaponangles, -degrees(atanf(vec[1] / zxDist)),
-degrees(atan2f(vec[0], -vec[2])), vr.weaponangles[ROLL] / 2.0f); //Dampen roll on stabilised weapon
vec3_t vec;
VectorSubtract(vr.offhandoffset, smooth_weaponoffset, vec);
float zxDist = length(vec[0], vec[2]);
if (zxDist != 0.0f && vec[2] != 0.0f) {
VectorSet(vr.weaponangles, -degrees(atanf(vec[1] / zxDist)),
-degrees(atan2f(vec[0], -vec[2])), vr.weaponangles[ROLL] / 2.0f); // Dampen roll on stabilised weapon
}
}
}
}
@ -731,7 +1094,8 @@ static void IN_VRJoystick( qboolean isRightController, float joystickX, float jo
else
{
//Positional movement speed correction for when we are not hitting target framerate
int refresh = vrapi_GetSystemPropertyInt(&(VR_GetEngine()->java), VRAPI_SYS_PROP_DISPLAY_REFRESH_RATE);
float refresh;
VR_GetEngine()->appState.pfnGetDisplayRefreshRate(VR_GetEngine()->appState.Session, &refresh);
float multiplier = (float)((1000.0 / refresh) / (in_vrEventTime - lastframetime));
float factor = (refresh / 72.0F) * 10.0f; // adjust positional factor based on refresh rate
@ -948,7 +1312,6 @@ static void IN_VRButtons( qboolean isRightController, uint32_t buttons )
} else {
IN_HandleInactiveInput(&controller->buttons, ovrButton_Y, "Y", 0, qfalse);
}
}
void IN_VRInputFrame( void )
@ -958,27 +1321,17 @@ void IN_VRInputFrame( void )
memset(&rightController, 0, sizeof(rightController));
controllerInit = qtrue;
}
engine_t* engine = VR_GetEngine();
ovrMobile* ovr = VR_GetEngine()->ovr;
if (!ovr) {
return;
}
ovrResult result;
if (vr_extralatencymode != NULL &&
vr_extralatencymode->integer) {
result = vrapi_SetExtraLatencyMode(VR_GetEngine()->ovr, VRAPI_EXTRA_LATENCY_MODE_ON);
assert(result == VRAPI_INITIALIZE_SUCCESS);
//TODO:vrapi_SetExtraLatencyMode(VR_GetEngine()->ovr, VRAPI_EXTRA_LATENCY_MODE_ON);
}
if (vr_refreshrate != NULL && vr_refreshrate->integer)
{
vrapi_SetDisplayRefreshRate(VR_GetEngine()->ovr, (float)vr_refreshrate->integer);
if (vr_refreshrate != NULL && vr_refreshrate->integer) {
OXR(engine->appState.pfnRequestDisplayRefreshRate(engine->appState.Session, (float)vr_refreshrate->integer));
}
result = vrapi_SetClockLevels(VR_GetEngine()->ovr, 4, 4);
assert(result == VRAPI_INITIALIZE_SUCCESS);
vr.virtual_screen = VR_useScreenLayer();
VR_processHaptics();
@ -986,90 +1339,134 @@ void IN_VRInputFrame( void )
//trigger frame tick for haptics
VR_HapticEvent("frame_tick", 0, 0, 0, 0, 0);
{
// We extract Yaw, Pitch, Roll instead of directly using the orientation
// to allow "additional" yaw manipulation with mouse/controller.
const ovrQuatf quatHmd = VR_GetEngine()->tracking.HeadPose.Pose.Orientation;
const ovrVector3f positionHmd = VR_GetEngine()->tracking.HeadPose.Pose.Position;
vec3_t rotation = {0, 0, 0};
QuatToYawPitchRoll(quatHmd, rotation, vr.hmdorientation);
VectorSet(vr.hmdposition, positionHmd.x, positionHmd.y + vr_heightAdjust->value, positionHmd.z);
if (leftControllerAimSpace == XR_NULL_HANDLE) {
leftControllerAimSpace = CreateActionSpace(handPoseLeftAction, leftHandPath);
}
if (rightControllerAimSpace == XR_NULL_HANDLE) {
rightControllerAimSpace = CreateActionSpace(handPoseRightAction, rightHandPath);
}
//Position
VectorSubtract(vr.hmdposition_last, vr.hmdposition, vr.hmdposition_delta);
//button mapping
uint32_t lButtons = 0;
if (GetActionStateBoolean(menuAction).currentState) lButtons |= ovrButton_Enter;
if (GetActionStateBoolean(buttonXAction).currentState) lButtons |= ovrButton_X;
if (GetActionStateBoolean(buttonYAction).currentState) lButtons |= ovrButton_Y;
if (GetActionStateFloat(gripLeftAction).currentState > 0.5f) lButtons |= ovrButton_GripTrigger;
if (GetActionStateBoolean(thumbstickLeftClickAction).currentState) lButtons |= ovrButton_LThumb;
IN_VRButtons(qfalse, lButtons);
uint32_t rButtons = 0;
if (GetActionStateBoolean(buttonAAction).currentState) rButtons |= ovrButton_A;
if (GetActionStateBoolean(buttonBAction).currentState) rButtons |= ovrButton_B;
if (GetActionStateFloat(gripRightAction).currentState > 0.5f) rButtons |= ovrButton_GripTrigger;
if (GetActionStateBoolean(thumbstickRightClickAction).currentState) rButtons |= ovrButton_RThumb;
IN_VRButtons(qtrue, rButtons);
//Keep this for our records
VectorCopy(vr.hmdposition, vr.hmdposition_last);
//index finger click
XrActionStateBoolean indexState;
indexState = GetActionStateBoolean(indexLeftAction);
IN_VRTriggers(qfalse, indexState.currentState ? 1 : 0);
indexState = GetActionStateBoolean(indexRightAction);
IN_VRTriggers(qtrue, indexState.currentState ? 1 : 0);
//Orientation
VectorSubtract(vr.hmdorientation_last, vr.hmdorientation, vr.hmdorientation_delta);
//Keep this for our records
VectorCopy(vr.hmdorientation, vr.hmdorientation_last);
// View yaw delta
const float clientview_yaw = vr.clientviewangles[YAW] - vr.hmdorientation[YAW];
vr.clientview_yaw_delta = vr.clientview_yaw_last - clientview_yaw;
vr.clientview_yaw_last = clientview_yaw;
}
ovrInputCapabilityHeader capsHeader;
uint32_t index = 0;
for (;;) {
ovrResult enumResult = vrapi_EnumerateInputDevices(ovr, index, &capsHeader);
if (enumResult < 0) {
break;
}
++index;
if (capsHeader.Type != ovrControllerType_TrackedRemote) {
continue;
}
ovrInputTrackedRemoteCapabilities caps;
caps.Header = capsHeader;
ovrResult capsResult = vrapi_GetInputDeviceCapabilities(ovr, &caps.Header);
if (capsResult < 0) {
continue;
}
ovrInputStateTrackedRemote state;
state.Header.ControllerType = ovrControllerType_TrackedRemote;
ovrResult stateResult = vrapi_GetCurrentInputState(ovr, capsHeader.DeviceID, &state.Header);
if (stateResult < 0) {
continue;
}
ovrTracking remoteTracking;
stateResult = vrapi_GetInputTrackingState(ovr, capsHeader.DeviceID, VR_GetEngine()->predictedDisplayTime,
&remoteTracking);
if (stateResult < 0) {
continue;
}
qboolean isRight;
vrController_t* controller;
if (caps.ControllerCapabilities & ovrControllerCaps_LeftHand) {
isRight = qfalse;
controller = &leftController;
controllerIDs[0] = capsHeader.DeviceID;
} else if (caps.ControllerCapabilities & ovrControllerCaps_RightHand) {
isRight = qtrue;
controller = &rightController;
controllerIDs[1] = capsHeader.DeviceID;
}
else {
continue;
}
IN_VRButtons(isRight, state.Buttons);
IN_VRController(isRight, remoteTracking);
IN_VRJoystick(isRight, state.Joystick.x, state.Joystick.y);
IN_VRTriggers(isRight, state.IndexTrigger);
}
//thumbstick
XrActionStateVector2f moveJoystickState;
moveJoystickState = GetActionStateVector2(moveOnLeftJoystickAction);
IN_VRJoystick(qfalse, moveJoystickState.currentState.x, moveJoystickState.currentState.y);
moveJoystickState = GetActionStateVector2(moveOnRightJoystickAction);
IN_VRJoystick(qtrue, moveJoystickState.currentState.x, moveJoystickState.currentState.y);
lastframetime = in_vrEventTime;
in_vrEventTime = Sys_Milliseconds( );
}
void IN_VRSyncActions( void )
{
engine_t* engine = VR_GetEngine();
// Attach to session
if (!actionsAttached) {
XrSessionActionSetsAttachInfo attachInfo = {};
attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
attachInfo.next = NULL;
attachInfo.countActionSets = 1;
attachInfo.actionSets = &runningActionSet;
OXR(xrAttachSessionActionSets(engine->appState.Session, &attachInfo));
actionsAttached = qtrue;
}
// sync action data
XrActiveActionSet activeActionSet = {};
activeActionSet.actionSet = runningActionSet;
activeActionSet.subactionPath = XR_NULL_PATH;
XrActionsSyncInfo syncInfo = {};
syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
syncInfo.next = NULL;
syncInfo.countActiveActionSets = 1;
syncInfo.activeActionSets = &activeActionSet;
OXR(xrSyncActions(engine->appState.Session, &syncInfo));
// query input action states
XrActionStateGetInfo getInfo = {};
getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
getInfo.next = NULL;
getInfo.subactionPath = XR_NULL_PATH;
}
void IN_VRUpdateControllers( XrPosef xfStageFromHead, float predictedDisplayTime )
{
engine_t* engine = VR_GetEngine();
//get controller poses
XrAction controller[] = {handPoseLeftAction, handPoseRightAction};
XrPath subactionPath[] = {leftHandPath, rightHandPath};
XrSpace controllerSpace[] = {leftControllerAimSpace, rightControllerAimSpace};
for (int i = 0; i < 2; i++) {
if (ActionPoseIsActive(controller[i], subactionPath[i])) {
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
OXR(xrLocateSpace(controllerSpace[i], engine->appState.HeadSpace, predictedDisplayTime, &loc));
engine->appState.TrackedController[i].Active = (loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0;
engine->appState.TrackedController[i].Pose = XrPosef_Multiply(xfStageFromHead, loc.pose);
} else {
ovrTrackedController_Clear(&engine->appState.TrackedController[i]);
}
}
//apply controller poses
if (engine->appState.TrackedController[0].Active)
IN_VRController(qfalse, engine->appState.TrackedController[0].Pose);
if (engine->appState.TrackedController[1].Active)
IN_VRController(qtrue, engine->appState.TrackedController[1].Pose);
}
void IN_VRUpdateHMD( XrPosef xfStageFromHead )
{
// We extract Yaw, Pitch, Roll instead of directly using the orientation
// to allow "additional" yaw manipulation with mouse/controller.
const XrQuaternionf quatHmd = xfStageFromHead.orientation;
const XrVector3f positionHmd = xfStageFromHead.position;
vec3_t rotation = {0, 0, 0};
QuatToYawPitchRoll(quatHmd, rotation, vr.hmdorientation);
VectorSet(vr.hmdposition, positionHmd.x, positionHmd.y + vr_heightAdjust->value, positionHmd.z);
//Position
VectorSubtract(vr.hmdposition_last, vr.hmdposition, vr.hmdposition_delta);
//Keep this for our records
VectorCopy(vr.hmdposition, vr.hmdposition_last);
//Orientation
VectorSubtract(vr.hmdorientation_last, vr.hmdorientation, vr.hmdorientation_delta);
//Keep this for our records
VectorCopy(vr.hmdorientation, vr.hmdorientation_last);
// View yaw delta
const float clientview_yaw = vr.clientviewangles[YAW] - vr.hmdorientation[YAW];
vr.clientview_yaw_delta = vr.clientview_yaw_last - clientview_yaw;
vr.clientview_yaw_last = clientview_yaw;
}
//#endif

View file

@ -1,10 +1,18 @@
#ifndef __VR_INPUT_H
#define __VR_INPUT_H
#include "../qcommon/q_shared.h"
#include "vr_types.h"
#if __ANDROID__
void IN_VRInputFrame( void );
void IN_VRInit( void );
void IN_VRSyncActions( void );
void IN_VRUpdateHMD( XrPosef xfStageFromHead );
void IN_VRUpdateControllers( XrPosef xfStageFromHead, float predictedDisplayTime );
void QuatToYawPitchRoll(XrQuaternionf q, vec3_t rotation, vec3_t out);
#endif

View file

@ -4,22 +4,11 @@
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "../client/client.h"
#include "../VrApi/Include/VrApi_Types.h"
#include "vr_clientinfo.h"
#include "vr_input.h"
#include "vr_types.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"
#include <VrApi.h>
#include <VrApi_Helpers.h>
#pragma clang diagnostic pop
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -30,9 +19,33 @@
#include <GLES3/gl32.h>
#endif
#define SUPER_SAMPLE 1.15f
#define DEFAULT_SUPER_SAMPLING 1.1f
extern vr_clientinfo_t vr;
extern cvar_t *vr_heightAdjust;
XrView* projections;
GLboolean stageSupported = GL_FALSE;
qboolean fullscreenMode = qfalse;
qboolean needRecenter = qtrue;
void VR_UpdateStageBounds(ovrApp* pappState) {
XrExtent2Df stageBounds = {};
XrResult result;
OXR(result = xrGetReferenceSpaceBoundsRect(
pappState->Session, XR_REFERENCE_SPACE_TYPE_STAGE, &stageBounds));
if (result != XR_SUCCESS) {
ALOGV("Stage bounds query failed: using small defaults");
stageBounds.width = 1.0f;
stageBounds.height = 1.0f;
pappState->CurrentSpace = pappState->FakeStageSpace;
}
ALOGV("Stage bounds: width = %f, depth %f", stageBounds.width, stageBounds.height);
}
void APIENTRY VR_GLDebugLog(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
@ -68,14 +81,97 @@ void VR_GetResolution(engine_t* engine, int *pWidth, int *pHeight)
{
static int width = 0;
static int height = 0;
float superSampling = 0.0f;
float configuredSuperSampling = Cvar_VariableValue("vr_superSampling");
if (vr.superSampling == 0.0f || configuredSuperSampling != vr.superSampling) {
vr.superSampling = configuredSuperSampling;
if (vr.superSampling != 0.0f) {
Cbuf_AddText( "vid_restart\n" );
}
}
if (vr.superSampling == 0.0f) {
superSampling = DEFAULT_SUPER_SAMPLING;
} else {
superSampling = vr.superSampling;
}
if (engine)
{
*pWidth = width = vrapi_GetSystemPropertyInt(&engine->java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH) * SUPER_SAMPLE;
*pHeight = height = vrapi_GetSystemPropertyInt(&engine->java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT) * SUPER_SAMPLE;
// Enumerate the viewport configurations.
uint32_t viewportConfigTypeCount = 0;
OXR(xrEnumerateViewConfigurations(
engine->appState.Instance, engine->appState.SystemId, 0, &viewportConfigTypeCount, NULL));
vr.fov_x = vrapi_GetSystemPropertyInt( &engine->java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_X);
vr.fov_y = vrapi_GetSystemPropertyInt( &engine->java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y);
XrViewConfigurationType* viewportConfigurationTypes =
(XrViewConfigurationType*)malloc(viewportConfigTypeCount * sizeof(XrViewConfigurationType));
OXR(xrEnumerateViewConfigurations(
engine->appState.Instance,
engine->appState.SystemId,
viewportConfigTypeCount,
&viewportConfigTypeCount,
viewportConfigurationTypes));
ALOGV("Available Viewport Configuration Types: %d", viewportConfigTypeCount);
for (uint32_t i = 0; i < viewportConfigTypeCount; i++) {
const XrViewConfigurationType viewportConfigType = viewportConfigurationTypes[i];
ALOGV(
"Viewport configuration type %d : %s",
viewportConfigType,
viewportConfigType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO ? "Selected" : "");
XrViewConfigurationProperties viewportConfig;
viewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
OXR(xrGetViewConfigurationProperties(
engine->appState.Instance, engine->appState.SystemId, viewportConfigType, &viewportConfig));
ALOGV(
"FovMutable=%s ConfigurationType %d",
viewportConfig.fovMutable ? "true" : "false",
viewportConfig.viewConfigurationType);
uint32_t viewCount;
OXR(xrEnumerateViewConfigurationViews(
engine->appState.Instance, engine->appState.SystemId, viewportConfigType, 0, &viewCount, NULL));
if (viewCount > 0) {
XrViewConfigurationView* elements =
(XrViewConfigurationView*)malloc(viewCount * sizeof(XrViewConfigurationView));
for (uint32_t e = 0; e < viewCount; e++) {
elements[e].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
elements[e].next = NULL;
}
OXR(xrEnumerateViewConfigurationViews(
engine->appState.Instance,
engine->appState.SystemId,
viewportConfigType,
viewCount,
&viewCount,
elements));
// Cache the view config properties for the selected config type.
if (viewportConfigType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO) {
assert(viewCount == ovrMaxNumEyes);
for (uint32_t e = 0; e < viewCount; e++) {
engine->appState.ViewConfigurationView[e] = elements[e];
}
}
free(elements);
} else {
ALOGE("Empty viewport configuration type: %d", viewCount);
}
}
free(viewportConfigurationTypes);
*pWidth = width = engine->appState.ViewConfigurationView[0].recommendedImageRectWidth * superSampling;
*pHeight = height = engine->appState.ViewConfigurationView[0].recommendedImageRectHeight * superSampling;
}
else
{
@ -85,13 +181,53 @@ void VR_GetResolution(engine_t* engine, int *pWidth, int *pHeight)
}
}
typedef void(GL_APIENTRY* PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(
GLenum target,
GLenum attachment,
GLuint texture,
GLint level,
GLint baseViewIndex,
GLsizei numViews);
void VR_Recenter(engine_t* engine) {
// Calculate recenter reference
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
if (engine->appState.CurrentSpace != XR_NULL_HANDLE) {
vec3_t rotation = {0, 0, 0};
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
OXR(xrLocateSpace(engine->appState.HeadSpace, engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc));
QuatToYawPitchRoll(loc.pose.orientation, rotation, vr.hmdorientation);
vr.recenterYaw += radians(vr.hmdorientation[YAW]);
spaceCreateInfo.poseInReferenceSpace.orientation.x = 0;
spaceCreateInfo.poseInReferenceSpace.orientation.y = sin(vr.recenterYaw / 2);
spaceCreateInfo.poseInReferenceSpace.orientation.z = 0;
spaceCreateInfo.poseInReferenceSpace.orientation.w = cos(vr.recenterYaw / 2);
}
// Delete previous space instances
if (engine->appState.StageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->appState.StageSpace));
}
if (engine->appState.FakeStageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->appState.FakeStageSpace));
}
// Create a default stage space to use if SPACE_TYPE_STAGE is not
// supported, or calls to xrGetReferenceSpaceBoundsRect fail.
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.FakeStageSpace));
ALOGV("Created fake stage space from local space with offset");
engine->appState.CurrentSpace = engine->appState.FakeStageSpace;
if (stageSupported) {
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
spaceCreateInfo.poseInReferenceSpace.position.y = 0.0f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace));
ALOGV("Created stage space");
engine->appState.CurrentSpace = engine->appState.StageSpace;
}
// Update menu orientation
vr.menuYaw = 0;
}
void VR_InitRenderer( engine_t* engine ) {
#if ENABLE_GL_DEBUG
@ -99,305 +235,335 @@ void VR_InitRenderer( engine_t* engine ) {
glDebugMessageCallback(VR_GLDebugLog, 0);
#endif
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR =
(PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress(
"glFramebufferTextureMultiviewOVR");
int eyeW, eyeH;
VR_GetResolution(engine, &eyeW, &eyeH);
//for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye)
{
framebuffer_t* framebuffer = &engine->framebuffers;
framebuffer->colorTexture = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_2D_ARRAY, GL_RGBA8,
eyeW, eyeH, 1, 3);
framebuffer->swapchainLength = vrapi_GetTextureSwapChainLength(framebuffer->colorTexture);
framebuffer->depthBuffers = (GLuint*)malloc(framebuffer->swapchainLength * sizeof(GLuint));
framebuffer->framebuffers = (GLuint*)malloc(framebuffer->swapchainLength * sizeof(GLuint));
for (int index = 0; index < framebuffer->swapchainLength; ++index) {
GLuint colorTexture;
GLenum framebufferStatus;
// Get the viewport configuration info for the chosen viewport configuration type.
engine->appState.ViewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
colorTexture = vrapi_GetTextureSwapChainHandle(framebuffer->colorTexture, index);
glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture);
GLfloat borderColor[] = {0.0f, 0.0f, 0.0f, 0.0f};
glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, borderColor);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
OXR(xrGetViewConfigurationProperties(
engine->appState.Instance, engine->appState.SystemId, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, &engine->appState.ViewportConfig));
glGenTextures(1, &framebuffer->depthBuffers[index]);
glBindTexture(GL_TEXTURE_2D_ARRAY, framebuffer->depthBuffers[index]);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH_COMPONENT24, eyeW, eyeH, 2);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
// Get the supported display refresh rates for the system.
{
PFN_xrEnumerateDisplayRefreshRatesFB pfnxrEnumerateDisplayRefreshRatesFB = NULL;
OXR(xrGetInstanceProcAddr(
engine->appState.Instance,
"xrEnumerateDisplayRefreshRatesFB",
(PFN_xrVoidFunction*)(&pfnxrEnumerateDisplayRefreshRatesFB)));
glGenFramebuffers(1, &framebuffer->framebuffers[index]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer->framebuffers[index]);
OXR(pfnxrEnumerateDisplayRefreshRatesFB(
engine->appState.Session, 0, &engine->appState.NumSupportedDisplayRefreshRates, NULL));
glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
framebuffer->depthBuffers[index], 0, 0, 2);
glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
colorTexture, 0, 0, 2);
engine->appState.SupportedDisplayRefreshRates =
(float*)malloc(engine->appState.NumSupportedDisplayRefreshRates * sizeof(float));
OXR(pfnxrEnumerateDisplayRefreshRatesFB(
engine->appState.Session,
engine->appState.NumSupportedDisplayRefreshRates,
&engine->appState.NumSupportedDisplayRefreshRates,
engine->appState.SupportedDisplayRefreshRates));
ALOGV("Supported Refresh Rates:");
for (uint32_t i = 0; i < engine->appState.NumSupportedDisplayRefreshRates; i++) {
ALOGV("%d:%f", i, engine->appState.SupportedDisplayRefreshRates[i]);
}
framebufferStatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
assert(framebufferStatus == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
}
OXR(xrGetInstanceProcAddr(
engine->appState.Instance,
"xrGetDisplayRefreshRateFB",
(PFN_xrVoidFunction*)(&engine->appState.pfnGetDisplayRefreshRate)));
float currentDisplayRefreshRate = 0.0f;
OXR(engine->appState.pfnGetDisplayRefreshRate(engine->appState.Session, &currentDisplayRefreshRate));
ALOGV("Current System Display Refresh Rate: %f", currentDisplayRefreshRate);
OXR(xrGetInstanceProcAddr(
engine->appState.Instance,
"xrRequestDisplayRefreshRateFB",
(PFN_xrVoidFunction*)(&engine->appState.pfnRequestDisplayRefreshRate)));
// Test requesting the system default.
OXR(engine->appState.pfnRequestDisplayRefreshRate(engine->appState.Session, 0.0f));
ALOGV("Requesting system default display refresh rate");
}
uint32_t numOutputSpaces = 0;
OXR(xrEnumerateReferenceSpaces(engine->appState.Session, 0, &numOutputSpaces, NULL));
XrReferenceSpaceType* referenceSpaces =
(XrReferenceSpaceType*)malloc(numOutputSpaces * sizeof(XrReferenceSpaceType));
OXR(xrEnumerateReferenceSpaces(
engine->appState.Session, numOutputSpaces, &numOutputSpaces, referenceSpaces));
for (uint32_t i = 0; i < numOutputSpaces; i++) {
if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) {
stageSupported = qtrue;
break;
}
}
free(referenceSpaces);
if (engine->appState.CurrentSpace == XR_NULL_HANDLE) {
VR_Recenter(engine);
}
projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView)));
ovrRenderer_Create(
engine->appState.Session,
&engine->appState.Renderer,
eyeW,
eyeH);
}
void VR_DestroyRenderer( engine_t* engine ) {
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye)
{
if (engine->framebuffers.swapchainLength > 0) {
glDeleteFramebuffers(engine->framebuffers.swapchainLength,
engine->framebuffers.depthBuffers);
free(engine->framebuffers.depthBuffers);
free(engine->framebuffers.framebuffers);
vrapi_DestroyTextureSwapChain(engine->framebuffers.colorTexture);
memset(&engine->framebuffers, 0, sizeof(engine->framebuffers));
}
}
void VR_DestroyRenderer( engine_t* engine )
{
ovrRenderer_Destroy(&engine->appState.Renderer);
free(projections);
}
void VR_ReInitRenderer()
{
VR_DestroyRenderer( VR_GetEngine() );
VR_InitRenderer( VR_GetEngine() );
}
// 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 )
void VR_ClearFrameBuffer( int width, int height)
{
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;
}
extern cvar_t *vr_screen_dist;
ovrLayerCylinder2 BuildCylinderLayer(engine_t* engine, 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 = 12.0f;
const float distance = -16.0f;
const ovrVector3f translation = { 0.0f, 1.0f, distance };
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++ )
{
ovrMatrix4f modelViewMatrix = ovrMatrix4f_Multiply( &tracking->Eye[eye].ViewMatrix, &cylinderTransform );
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_Inverse( &modelViewMatrix );
layer.Textures[eye].ColorSwapChain = engine->framebuffers.colorTexture;
layer.Textures[eye].SwapChainIndex = engine->framebuffers.swapchainIndex;
// 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;
}
void VR_ClearFrameBuffer( GLuint frameBuffer, int width, int height)
{
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBuffer );
glEnable( GL_SCISSOR_TEST );
glViewport( 0, 0, width, height );
if (Cvar_VariableIntegerValue("vr_thirdPersonSpectator"))
{
//Blood red.. ish
glClearColor( 0.12f, 0.0f, 0.05f, 1.0f );
}
else
{
//Black
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
}
if (Cvar_VariableIntegerValue("vr_thirdPersonSpectator"))
{
//Blood red.. ish
glClearColor( 0.12f, 0.0f, 0.05f, 1.0f );
}
else
{
//Black
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
}
glScissor( 0, 0, width, height );
glClear( GL_COLOR_BUFFER_BIT );
glScissor( 0, 0, 0, 0 );
glDisable( GL_SCISSOR_TEST );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
}
void VR_DrawFrame( engine_t* engine ) {
if (!engine->ovr)
{
return;
}
++engine->frameIndex;
engine->predictedDisplayTime = vrapi_GetPredictedDisplayTime(engine->ovr, engine->frameIndex);
engine->tracking = vrapi_GetPredictedTracking2(engine->ovr, engine->predictedDisplayTime);
float fov_y = vrapi_GetSystemPropertyInt( engine->ovr, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y);
float fov_x = vrapi_GetSystemPropertyInt( engine->ovr, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_X);
if (vr.weapon_zoomed) {
vr.weapon_zoomLevel += 0.05;
if (vr.weapon_zoomLevel > 2.5f)
vr.weapon_zoomLevel = 2.5f;
vr.weapon_zoomLevel = 2.5f;
}
else {
//Zoom back out quicker
vr.weapon_zoomLevel -= 0.25f;
//Zoom back out quicker
vr.weapon_zoomLevel -= 0.25f;
if (vr.weapon_zoomLevel < 1.0f)
vr.weapon_zoomLevel = 1.0f;
vr.weapon_zoomLevel = 1.0f;
}
const ovrMatrix4f projectionMatrix = ovrMatrix4f_CreateProjectionFov(
fov_x / vr.weapon_zoomLevel, fov_y / vr.weapon_zoomLevel, 0.0f, 0.0f, 1.0f, 0.0f );
GLboolean stageBoundsDirty = GL_TRUE;
if (ovrApp_HandleXrEvents(&engine->appState)) {
VR_Recenter(engine);
}
if (engine->appState.SessionActive == GL_FALSE) {
return;
}
//Projection used for drawing HUD models etc
const ovrMatrix4f monoVRMatrix = ovrMatrix4f_CreateProjectionFov(
30.0f, 30.0f, 0.0f, 0.0f, 1.0f, 0.0f );
if (stageBoundsDirty) {
VR_UpdateStageBounds(&engine->appState);
stageBoundsDirty = GL_FALSE;
}
int eyeW, eyeH;
VR_GetResolution(engine, &eyeW, &eyeH);
// NOTE: OpenXR does not use the concept of frame indices. Instead,
// XrWaitFrame returns the predicted display time.
XrFrameWaitInfo waitFrameInfo = {};
waitFrameInfo.type = XR_TYPE_FRAME_WAIT_INFO;
waitFrameInfo.next = NULL;
if (VR_useScreenLayer() ||
(cl.snap.ps.pm_flags & PMF_FOLLOW && vr.follow_mode == VRFM_FIRSTPERSON))
{
static ovrLayer_Union2 cylinderLayer;
memset( &cylinderLayer, 0, sizeof( ovrLayer_Union2 ) );
XrFrameState frameState = {};
frameState.type = XR_TYPE_FRAME_STATE;
frameState.next = NULL;
// Add a simple cylindrical layer
cylinderLayer.Cylinder =
BuildCylinderLayer(engine, eyeW, eyeW * 0.75f, &engine->tracking, radians(vr.menuYaw) );
OXR(xrWaitFrame(engine->appState.Session, &waitFrameInfo, &frameState));
engine->predictedDisplayTime = frameState.predictedDisplayTime;
if (!frameState.shouldRender) {
return;
}
const ovrLayerHeader2* layers[] = {
&cylinderLayer.Header
};
// Get the HMD pose, predicted for the middle of the time period during which
// the new eye images will be displayed. The number of frames predicted ahead
// depends on the pipeline depth of the engine and the synthesis rate.
// The better the prediction, the less black will be pulled in at the edges.
XrFrameBeginInfo beginFrameDesc = {};
beginFrameDesc.type = XR_TYPE_FRAME_BEGIN_INFO;
beginFrameDesc.next = NULL;
OXR(xrBeginFrame(engine->appState.Session, &beginFrameDesc));
// Set up the description for this frame.
ovrSubmitFrameDescription2 frameDesc = { 0 };
frameDesc.Flags = 0;
frameDesc.SwapInterval = 1;
frameDesc.FrameIndex = engine->frameIndex;
frameDesc.DisplayTime = engine->predictedDisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;
XrViewLocateInfo projectionInfo = {};
projectionInfo.type = XR_TYPE_VIEW_LOCATE_INFO;
projectionInfo.viewConfigurationType = engine->appState.ViewportConfig.viewConfigurationType;
projectionInfo.displayTime = frameState.predictedDisplayTime;
projectionInfo.space = engine->appState.CurrentSpace;
re.SetVRHeadsetParms(&projectionMatrix, &monoVRMatrix,
engine->framebuffers.framebuffers[engine->framebuffers.swapchainIndex]);
XrViewState viewState = {XR_TYPE_VIEW_STATE, NULL};
VR_ClearFrameBuffer(engine->framebuffers.framebuffers[engine->framebuffers.swapchainIndex], eyeW, eyeH);
uint32_t projectionCapacityInput = ovrMaxNumEyes;
uint32_t projectionCountOutput = projectionCapacityInput;
Com_Frame();
OXR(xrLocateViews(
engine->appState.Session,
&projectionInfo,
&viewState,
projectionCapacityInput,
&projectionCountOutput,
projections));
//
// Clear the alpha channel, other way VR API would not transfer the framebuffer fully
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
XrFovf fov = {};
XrPosef invViewTransform[2];
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
invViewTransform[eye] = projections[eye].pose;
engine->framebuffers.swapchainIndex = (engine->framebuffers.swapchainIndex + 1) %
engine->framebuffers.swapchainLength;
fov.angleLeft += projections[eye].fov.angleLeft / 2.0f;
fov.angleRight += projections[eye].fov.angleRight / 2.0f;
fov.angleUp += projections[eye].fov.angleUp / 2.0f;
fov.angleDown += projections[eye].fov.angleDown / 2.0f;
}
vr.fov_x = (fabs(fov.angleLeft) + fabs(fov.angleRight)) * 180.0f / M_PI;
vr.fov_y = (fabs(fov.angleUp) + fabs(fov.angleDown)) * 180.0f / M_PI;
// Hand over the eye images to the time warp.
vrapi_SubmitFrame2(engine->ovr, &frameDesc);
}
else
{
vr.menuYaw = vr.hmdorientation[YAW];
// Update HMD and controllers
IN_VRUpdateHMD( invViewTransform[0] );
IN_VRUpdateControllers( invViewTransform[0], frameState.predictedDisplayTime );
IN_VRSyncActions();
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
layer.HeadPose = engine->tracking.HeadPose;
//Projection used for drawing HUD models etc
float hudScale = M_PI * 15.0f / 180.0f;
const ovrMatrix4f monoVRMatrix = ovrMatrix4f_CreateProjectionFov(
-hudScale, hudScale, hudScale, -hudScale, 1.0f, 0.0f );
const ovrMatrix4f projectionMatrix = ovrMatrix4f_CreateProjectionFov(
fov.angleLeft / vr.weapon_zoomLevel,
fov.angleRight / vr.weapon_zoomLevel,
fov.angleUp / vr.weapon_zoomLevel,
fov.angleDown / vr.weapon_zoomLevel,
1.0f, 0.0f );
const ovrMatrix4f defaultProjection = ovrMatrix4f_CreateProjectionFov(
fov_x, fov_y, 0.0f, 0.0f, 1.0f, 0.0f );
engine->appState.LayerCount = 0;
memset(engine->appState.Layers, 0, sizeof(ovrCompositorLayer_Union) * ovrMaxLayerCount);
ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer;
int swapchainIndex = engine->appState.Renderer.FrameBuffer.TextureSwapChainIndex;
int glFramebuffer = engine->appState.Renderer.FrameBuffer.FrameBuffers[swapchainIndex];
re.SetVRHeadsetParms(projectionMatrix.M, monoVRMatrix.M, glFramebuffer);
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
layer.Textures[eye].ColorSwapChain = engine->framebuffers.colorTexture;
layer.Textures[eye].SwapChainIndex = engine->framebuffers.swapchainIndex;
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&defaultProjection);
}
layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
ovrFramebuffer_Acquire(frameBuffer);
ovrFramebuffer_SetCurrent(frameBuffer);
VR_ClearFrameBuffer(frameBuffer->ColorSwapChain.Width, frameBuffer->ColorSwapChain.Height);
Com_Frame();
VR_ClearFrameBuffer(engine->framebuffers.framebuffers[engine->framebuffers.swapchainIndex], eyeW, eyeH);
// Clear the alpha channel, other way OpenXR would not transfer the framebuffer fully
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
re.SetVRHeadsetParms(&projectionMatrix, &monoVRMatrix,
engine->framebuffers.framebuffers[engine->framebuffers.swapchainIndex]);
ovrFramebuffer_Resolve(frameBuffer);
ovrFramebuffer_Release(frameBuffer);
ovrFramebuffer_SetNone();
Com_Frame();
XrCompositionLayerProjectionView projection_layer_elements[2] = {};
if (!VR_useScreenLayer() && !(cl.snap.ps.pm_flags & PMF_FOLLOW && vr.follow_mode == VRFM_FIRSTPERSON)) {
vr.menuYaw = vr.hmdorientation[YAW];
engine->framebuffers.swapchainIndex = (engine->framebuffers.swapchainIndex + 1) %
engine->framebuffers.swapchainLength;
if (fullscreenMode) {
VR_ReInitRenderer();
fullscreenMode = qfalse;
}
const ovrLayerHeader2* layers[] = {
&layer.Header
};
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer;
ovrSubmitFrameDescription2 frameDesc = { 0 };
frameDesc.Flags = 0;
frameDesc.SwapInterval = 1;
frameDesc.FrameIndex = engine->frameIndex;
frameDesc.DisplayTime = engine->predictedDisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;
memset(&projection_layer_elements[eye], 0, sizeof(XrCompositionLayerProjectionView));
projection_layer_elements[eye].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
projection_layer_elements[eye].pose = invViewTransform[eye];
projection_layer_elements[eye].fov = fov;
vrapi_SubmitFrame2(engine->ovr, &frameDesc);
}
memset(&projection_layer_elements[eye].subImage, 0, sizeof(XrSwapchainSubImage));
projection_layer_elements[eye].subImage.swapchain = frameBuffer->ColorSwapChain.Handle;
projection_layer_elements[eye].subImage.imageRect.offset.x = 0;
projection_layer_elements[eye].subImage.imageRect.offset.y = 0;
projection_layer_elements[eye].subImage.imageRect.extent.width = frameBuffer->ColorSwapChain.Width;
projection_layer_elements[eye].subImage.imageRect.extent.height = frameBuffer->ColorSwapChain.Height;
projection_layer_elements[eye].subImage.imageArrayIndex = eye;
}
XrCompositionLayerProjection projection_layer = {};
projection_layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
projection_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
projection_layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
projection_layer.space = engine->appState.CurrentSpace;
projection_layer.viewCount = ovrMaxNumEyes;
projection_layer.views = projection_layer_elements;
engine->appState.Layers[engine->appState.LayerCount++].Projection = projection_layer;
} else {
fullscreenMode = qtrue;
// Build the cylinder layer
int width = engine->appState.Renderer.FrameBuffer.ColorSwapChain.Width;
int height = engine->appState.Renderer.FrameBuffer.ColorSwapChain.Height;
XrCompositionLayerCylinderKHR cylinder_layer = {};
cylinder_layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR;
cylinder_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
cylinder_layer.space = engine->appState.CurrentSpace;
cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
memset(&cylinder_layer.subImage, 0, sizeof(XrSwapchainSubImage));
cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer.ColorSwapChain.Handle;
cylinder_layer.subImage.imageRect.offset.x = 0;
cylinder_layer.subImage.imageRect.offset.y = 0;
cylinder_layer.subImage.imageRect.extent.width = width;
cylinder_layer.subImage.imageRect.extent.height = height;
cylinder_layer.subImage.imageArrayIndex = 0;
const XrVector3f axis = {0.0f, 1.0f, 0.0f};
XrVector3f pos = {
invViewTransform[0].position.x - sin(radians(vr.menuYaw)) * 6.0f,
invViewTransform[0].position.y,
invViewTransform[0].position.z - cos(radians(vr.menuYaw)) * 6.0f
};
cylinder_layer.pose.orientation = XrQuaternionf_CreateFromVectorAngle(axis, radians(vr.menuYaw));
cylinder_layer.pose.position = pos;
cylinder_layer.radius = 8.0f;
cylinder_layer.centralAngle = MATH_PI * 0.5f;
cylinder_layer.aspectRatio = width / (float)height / 0.75f;
engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer;
}
// Compose the layers for this frame.
const XrCompositionLayerBaseHeader* layers[ovrMaxLayerCount] = {};
for (int i = 0; i < engine->appState.LayerCount; i++) {
layers[i] = (const XrCompositionLayerBaseHeader*)&engine->appState.Layers[i];
}
XrFrameEndInfo endFrameInfo = {};
endFrameInfo.type = XR_TYPE_FRAME_END_INFO;
endFrameInfo.displayTime = frameState.predictedDisplayTime;
endFrameInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
endFrameInfo.layerCount = engine->appState.LayerCount;
endFrameInfo.layers = layers;
OXR(xrEndFrame(engine->appState.Session, &endFrameInfo));
frameBuffer->TextureSwapChainIndex++;
frameBuffer->TextureSwapChainIndex %= frameBuffer->TextureSwapChainLength;
if (needRecenter)
{
VR_Recenter(engine);
needRecenter = qfalse;
}
}

View file

@ -9,6 +9,7 @@ void VR_GetResolution( engine_t* engine, int *pWidth, int *pHeight );
void VR_InitRenderer( engine_t* engine );
void VR_DestroyRenderer( engine_t* engine );
void VR_DrawFrame( engine_t* engine );
void VR_ReInitRenderer();
#endif

View file

@ -0,0 +1,594 @@
#include "vr_types.h"
/************************************************************************************
Original file name : XrCompositor_NativeActivity.c
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
*************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <assert.h>
typedef void(GL_APIENTRY* PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(
GLenum target,
GLenum attachment,
GLuint texture,
GLint level,
GLint baseViewIndex,
GLsizei numViews);
/*
================================================================================
ovrFramebuffer
================================================================================
*/
void ovrFramebuffer_Clear(ovrFramebuffer* frameBuffer) {
frameBuffer->Width = 0;
frameBuffer->Height = 0;
frameBuffer->TextureSwapChainLength = 0;
frameBuffer->TextureSwapChainIndex = 0;
frameBuffer->ColorSwapChain.Handle = XR_NULL_HANDLE;
frameBuffer->ColorSwapChain.Width = 0;
frameBuffer->ColorSwapChain.Height = 0;
frameBuffer->ColorSwapChainImage = NULL;
frameBuffer->DepthSwapChain.Handle = XR_NULL_HANDLE;
frameBuffer->DepthSwapChain.Width = 0;
frameBuffer->DepthSwapChain.Height = 0;
frameBuffer->DepthSwapChainImage = NULL;
frameBuffer->FrameBuffers = NULL;
}
bool ovrFramebuffer_Create(
XrSession session,
ovrFramebuffer* frameBuffer,
const int width,
const int height) {
frameBuffer->Width = width;
frameBuffer->Height = height;
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR =
(PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress(
"glFramebufferTextureMultiviewOVR");
XrSwapchainCreateInfo swapChainCreateInfo;
memset(&swapChainCreateInfo, 0, sizeof(swapChainCreateInfo));
swapChainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
swapChainCreateInfo.sampleCount = 1;
swapChainCreateInfo.width = width;
swapChainCreateInfo.height = height;
swapChainCreateInfo.faceCount = 1;
swapChainCreateInfo.arraySize = 2;
swapChainCreateInfo.mipCount = 1;
frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height;
frameBuffer->DepthSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->DepthSwapChain.Height = swapChainCreateInfo.height;
// Create the color swapchain.
swapChainCreateInfo.format = GL_RGBA8;
swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->ColorSwapChain.Handle));
// Create the depth swapchain.
swapChainCreateInfo.format = GL_DEPTH24_STENCIL8;
swapChainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
OXR(xrCreateSwapchain(session, &swapChainCreateInfo, &frameBuffer->DepthSwapChain.Handle));
// Get the number of swapchain images.
OXR(xrEnumerateSwapchainImages(
frameBuffer->ColorSwapChain.Handle, 0, &frameBuffer->TextureSwapChainLength, NULL));
// Allocate the swapchain images array.
frameBuffer->ColorSwapChainImage = (XrSwapchainImageOpenGLESKHR*)malloc(
frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR));
frameBuffer->DepthSwapChainImage = (XrSwapchainImageOpenGLESKHR*)malloc(
frameBuffer->TextureSwapChainLength * sizeof(XrSwapchainImageOpenGLESKHR));
// Populate the swapchain image array.
for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) {
frameBuffer->ColorSwapChainImage[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
frameBuffer->ColorSwapChainImage[i].next = NULL;
frameBuffer->DepthSwapChainImage[i].type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR;
frameBuffer->DepthSwapChainImage[i].next = NULL;
}
OXR(xrEnumerateSwapchainImages(
frameBuffer->ColorSwapChain.Handle,
frameBuffer->TextureSwapChainLength,
&frameBuffer->TextureSwapChainLength,
(XrSwapchainImageBaseHeader*)frameBuffer->ColorSwapChainImage));
OXR(xrEnumerateSwapchainImages(
frameBuffer->DepthSwapChain.Handle,
frameBuffer->TextureSwapChainLength,
&frameBuffer->TextureSwapChainLength,
(XrSwapchainImageBaseHeader*)frameBuffer->DepthSwapChainImage));
frameBuffer->FrameBuffers = (GLuint*)malloc(frameBuffer->TextureSwapChainLength * sizeof(GLuint));
for (uint32_t i = 0; i < frameBuffer->TextureSwapChainLength; i++) {
// Create the color buffer texture.
const GLuint colorTexture = frameBuffer->ColorSwapChainImage[i].image;
const GLuint depthTexture = frameBuffer->DepthSwapChainImage[i].image;
// Create the frame buffer.
GL(glGenFramebuffers(1, &frameBuffer->FrameBuffers[i]));
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[i]));
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexture, 0, 0, 2));
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, 0, 2));
GL(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, 0, 2));
GL(GLenum renderFramebufferStatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
if (renderFramebufferStatus != GL_FRAMEBUFFER_COMPLETE) {
ALOGE("Incomplete frame buffer object: %d", renderFramebufferStatus);
return false;
}
}
return true;
}
void ovrFramebuffer_Destroy(ovrFramebuffer* frameBuffer) {
GL(glDeleteFramebuffers(frameBuffer->TextureSwapChainLength, frameBuffer->FrameBuffers));
OXR(xrDestroySwapchain(frameBuffer->ColorSwapChain.Handle));
OXR(xrDestroySwapchain(frameBuffer->DepthSwapChain.Handle));
free(frameBuffer->ColorSwapChainImage);
free(frameBuffer->DepthSwapChainImage);
free(frameBuffer->FrameBuffers);
ovrFramebuffer_Clear(frameBuffer);
}
void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer) {
GL(glBindFramebuffer(
GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[frameBuffer->TextureSwapChainIndex]));
}
void ovrFramebuffer_SetNone() {
GL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
}
void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer) {
// Discard the depth buffer, so the tiler won't need to write it back out to memory.
const GLenum depthAttachment[1] = {GL_DEPTH_ATTACHMENT};
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, depthAttachment);
}
void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer) {
// Acquire the swapchain image
XrSwapchainImageAcquireInfo acquireInfo = {XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, NULL};
OXR(xrAcquireSwapchainImage(
frameBuffer->ColorSwapChain.Handle, &acquireInfo, &frameBuffer->TextureSwapChainIndex));
XrSwapchainImageWaitInfo waitInfo;
waitInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
waitInfo.next = NULL;
waitInfo.timeout = 1000; /* timeout in nanoseconds */
XrResult res = xrWaitSwapchainImage(frameBuffer->ColorSwapChain.Handle, &waitInfo);
int i = 0;
while (res != XR_SUCCESS) {
res = xrWaitSwapchainImage(frameBuffer->ColorSwapChain.Handle, &waitInfo);
i++;
ALOGV(
" Retry xrWaitSwapchainImage %d times due to XR_TIMEOUT_EXPIRED (duration %f micro seconds)",
i,
waitInfo.timeout * (1E-9));
}
}
void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer) {
XrSwapchainImageReleaseInfo releaseInfo = {XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, NULL};
OXR(xrReleaseSwapchainImage(frameBuffer->ColorSwapChain.Handle, &releaseInfo));
}
/*
================================================================================
ovrRenderer
================================================================================
*/
void ovrRenderer_Clear(ovrRenderer* renderer) {
ovrFramebuffer_Clear(&renderer->FrameBuffer);
}
void ovrRenderer_Create(
XrSession session,
ovrRenderer* renderer,
int suggestedEyeTextureWidth,
int suggestedEyeTextureHeight) {
// Create the frame buffers.
ovrFramebuffer_Create(
session,
&renderer->FrameBuffer,
suggestedEyeTextureWidth,
suggestedEyeTextureHeight);
}
void ovrRenderer_Destroy(ovrRenderer* renderer) {
ovrFramebuffer_Destroy(&renderer->FrameBuffer);
}
/*
================================================================================
ovrApp
================================================================================
*/
void ovrApp_Clear(ovrApp* app) {
app->Focused = false;
app->Instance = XR_NULL_HANDLE;
app->Session = XR_NULL_HANDLE;
memset(&app->ViewportConfig, 0, sizeof(XrViewConfigurationProperties));
memset(&app->ViewConfigurationView, 0, ovrMaxNumEyes * sizeof(XrViewConfigurationView));
app->SystemId = XR_NULL_SYSTEM_ID;
app->HeadSpace = XR_NULL_HANDLE;
app->StageSpace = XR_NULL_HANDLE;
app->FakeStageSpace = XR_NULL_HANDLE;
app->CurrentSpace = XR_NULL_HANDLE;
app->SessionActive = false;
app->SupportedDisplayRefreshRates = NULL;
app->RequestedDisplayRefreshRateIndex = 0;
app->NumSupportedDisplayRefreshRates = 0;
app->pfnGetDisplayRefreshRate = NULL;
app->pfnRequestDisplayRefreshRate = NULL;
app->SwapInterval = 1;
memset(app->Layers, 0, sizeof(ovrCompositorLayer_Union) * ovrMaxLayerCount);
app->LayerCount = 0;
app->MainThreadTid = 0;
app->RenderThreadTid = 0;
ovrRenderer_Clear(&app->Renderer);
}
void ovrApp_Destroy(ovrApp* app) {
if (app->SupportedDisplayRefreshRates != NULL) {
free(app->SupportedDisplayRefreshRates);
}
ovrApp_Clear(app);
}
void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) {
if (state == XR_SESSION_STATE_READY) {
assert(app->SessionActive == false);
XrSessionBeginInfo sessionBeginInfo;
memset(&sessionBeginInfo, 0, sizeof(sessionBeginInfo));
sessionBeginInfo.type = XR_TYPE_SESSION_BEGIN_INFO;
sessionBeginInfo.next = NULL;
sessionBeginInfo.primaryViewConfigurationType = app->ViewportConfig.viewConfigurationType;
XrResult result;
OXR(result = xrBeginSession(app->Session, &sessionBeginInfo));
app->SessionActive = (result == XR_SUCCESS);
// Set session state once we have entered VR mode and have a valid session object.
if (app->SessionActive) {
XrPerfSettingsLevelEXT cpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT;
XrPerfSettingsLevelEXT gpuPerfLevel = XR_PERF_SETTINGS_LEVEL_BOOST_EXT;
PFN_xrPerfSettingsSetPerformanceLevelEXT pfnPerfSettingsSetPerformanceLevelEXT = NULL;
OXR(xrGetInstanceProcAddr(
app->Instance,
"xrPerfSettingsSetPerformanceLevelEXT",
(PFN_xrVoidFunction*)(&pfnPerfSettingsSetPerformanceLevelEXT)));
OXR(pfnPerfSettingsSetPerformanceLevelEXT(
app->Session, XR_PERF_SETTINGS_DOMAIN_CPU_EXT, cpuPerfLevel));
OXR(pfnPerfSettingsSetPerformanceLevelEXT(
app->Session, XR_PERF_SETTINGS_DOMAIN_GPU_EXT, gpuPerfLevel));
PFN_xrSetAndroidApplicationThreadKHR pfnSetAndroidApplicationThreadKHR = NULL;
OXR(xrGetInstanceProcAddr(
app->Instance,
"xrSetAndroidApplicationThreadKHR",
(PFN_xrVoidFunction*)(&pfnSetAndroidApplicationThreadKHR)));
OXR(pfnSetAndroidApplicationThreadKHR(
app->Session, XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, app->MainThreadTid));
OXR(pfnSetAndroidApplicationThreadKHR(
app->Session, XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR, app->RenderThreadTid));
}
} else if (state == XR_SESSION_STATE_STOPPING) {
assert(app->SessionActive);
OXR(xrEndSession(app->Session));
app->SessionActive = false;
}
}
GLboolean ovrApp_HandleXrEvents(ovrApp* app) {
XrEventDataBuffer eventDataBuffer = {};
GLboolean recenter = GL_FALSE;
// Poll for events
for (;;) {
XrEventDataBaseHeader* baseEventHeader = (XrEventDataBaseHeader*)(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = NULL;
XrResult r;
OXR(r = xrPollEvent(app->Instance, &eventDataBuffer));
if (r != XR_SUCCESS) {
break;
}
switch (baseEventHeader->type) {
case XR_TYPE_EVENT_DATA_EVENTS_LOST:
ALOGV("xrPollEvent: received XR_TYPE_EVENT_DATA_EVENTS_LOST event");
break;
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: {
const XrEventDataInstanceLossPending* instance_loss_pending_event =
(XrEventDataInstanceLossPending*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING event: time %f",
FromXrTime(instance_loss_pending_event->lossTime));
} break;
case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
ALOGV("xrPollEvent: received XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED event");
break;
case XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT: {
const XrEventDataPerfSettingsEXT* perf_settings_event =
(XrEventDataPerfSettingsEXT*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT event: type %d subdomain %d : level %d -> level %d",
perf_settings_event->type,
perf_settings_event->subDomain,
perf_settings_event->fromLevel,
perf_settings_event->toLevel);
} break;
case XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB: {
const XrEventDataDisplayRefreshRateChangedFB* refresh_rate_changed_event =
(XrEventDataDisplayRefreshRateChangedFB*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB event: fromRate %f -> toRate %f",
refresh_rate_changed_event->fromDisplayRefreshRate,
refresh_rate_changed_event->toDisplayRefreshRate);
} break;
case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: {
XrEventDataReferenceSpaceChangePending* ref_space_change_event =
(XrEventDataReferenceSpaceChangePending*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING event: changed space: %d for session %p at time %f",
ref_space_change_event->referenceSpaceType,
(void*)ref_space_change_event->session,
FromXrTime(ref_space_change_event->changeTime));
recenter = GL_TRUE;
} break;
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
const XrEventDataSessionStateChanged* session_state_changed_event =
(XrEventDataSessionStateChanged*)(baseEventHeader);
ALOGV(
"xrPollEvent: received XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: %d for session %p at time %f",
session_state_changed_event->state,
(void*)session_state_changed_event->session,
FromXrTime(session_state_changed_event->time));
switch (session_state_changed_event->state) {
case XR_SESSION_STATE_FOCUSED:
app->Focused = true;
break;
case XR_SESSION_STATE_VISIBLE:
app->Focused = false;
break;
case XR_SESSION_STATE_READY:
case XR_SESSION_STATE_STOPPING:
ovrApp_HandleSessionStateChanges(app, session_state_changed_event->state);
break;
default:
break;
}
} break;
default:
ALOGV("xrPollEvent: Unknown event");
break;
}
}
return recenter;
}
/*
================================================================================
ovrMatrix4f
================================================================================
*/
ovrMatrix4f ovrMatrix4f_CreateProjectionFov(
const float angleLeft,
const float angleRight,
const float angleUp,
const float angleDown,
const float nearZ,
const float farZ) {
const float tanAngleLeft = tanf(angleLeft);
const float tanAngleRight = tanf(angleRight);
const float tanAngleDown = tanf(angleDown);
const float tanAngleUp = tanf(angleUp);
const float tanAngleWidth = tanAngleRight - tanAngleLeft;
// Set to tanAngleDown - tanAngleUp for a clip space with positive Y
// down (Vulkan). Set to tanAngleUp - tanAngleDown for a clip space with
// positive Y up (OpenGL / D3D / Metal).
const float tanAngleHeight = tanAngleUp - tanAngleDown;
// Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES).
// Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal).
const float offsetZ = nearZ;
ovrMatrix4f result;
if (farZ <= nearZ) {
// place the far plane at infinity
result.M[0][0] = 2 / tanAngleWidth;
result.M[0][1] = 0;
result.M[0][2] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
result.M[0][3] = 0;
result.M[1][0] = 0;
result.M[1][1] = 2 / tanAngleHeight;
result.M[1][2] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
result.M[1][3] = 0;
result.M[2][0] = 0;
result.M[2][1] = 0;
result.M[2][2] = -1;
result.M[2][3] = -(nearZ + offsetZ);
result.M[3][0] = 0;
result.M[3][1] = 0;
result.M[3][2] = -1;
result.M[3][3] = 0;
} else {
// normal projection
result.M[0][0] = 2 / tanAngleWidth;
result.M[0][1] = 0;
result.M[0][2] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
result.M[0][3] = 0;
result.M[1][0] = 0;
result.M[1][1] = 2 / tanAngleHeight;
result.M[1][2] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
result.M[1][3] = 0;
result.M[2][0] = 0;
result.M[2][1] = 0;
result.M[2][2] = -(farZ + offsetZ) / (farZ - nearZ);
result.M[2][3] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ);
result.M[3][0] = 0;
result.M[3][1] = 0;
result.M[3][2] = -1;
result.M[3][3] = 0;
}
return result;
}
ovrMatrix4f ovrMatrix4f_CreateFromQuaternion(const XrQuaternionf* q) {
const float ww = q->w * q->w;
const float xx = q->x * q->x;
const float yy = q->y * q->y;
const float zz = q->z * q->z;
ovrMatrix4f out;
out.M[0][0] = ww + xx - yy - zz;
out.M[0][1] = 2 * (q->x * q->y - q->w * q->z);
out.M[0][2] = 2 * (q->x * q->z + q->w * q->y);
out.M[0][3] = 0;
out.M[1][0] = 2 * (q->x * q->y + q->w * q->z);
out.M[1][1] = ww - xx + yy - zz;
out.M[1][2] = 2 * (q->y * q->z - q->w * q->x);
out.M[1][3] = 0;
out.M[2][0] = 2 * (q->x * q->z - q->w * q->y);
out.M[2][1] = 2 * (q->y * q->z + q->w * q->x);
out.M[2][2] = ww - xx - yy + zz;
out.M[2][3] = 0;
out.M[3][0] = 0;
out.M[3][1] = 0;
out.M[3][2] = 0;
out.M[3][3] = 1;
return out;
}
/// Use left-multiplication to accumulate transformations.
ovrMatrix4f ovrMatrix4f_Multiply(const ovrMatrix4f* a, const ovrMatrix4f* b) {
ovrMatrix4f out;
out.M[0][0] = a->M[0][0] * b->M[0][0] + a->M[0][1] * b->M[1][0] + a->M[0][2] * b->M[2][0] +
a->M[0][3] * b->M[3][0];
out.M[1][0] = a->M[1][0] * b->M[0][0] + a->M[1][1] * b->M[1][0] + a->M[1][2] * b->M[2][0] +
a->M[1][3] * b->M[3][0];
out.M[2][0] = a->M[2][0] * b->M[0][0] + a->M[2][1] * b->M[1][0] + a->M[2][2] * b->M[2][0] +
a->M[2][3] * b->M[3][0];
out.M[3][0] = a->M[3][0] * b->M[0][0] + a->M[3][1] * b->M[1][0] + a->M[3][2] * b->M[2][0] +
a->M[3][3] * b->M[3][0];
out.M[0][1] = a->M[0][0] * b->M[0][1] + a->M[0][1] * b->M[1][1] + a->M[0][2] * b->M[2][1] +
a->M[0][3] * b->M[3][1];
out.M[1][1] = a->M[1][0] * b->M[0][1] + a->M[1][1] * b->M[1][1] + a->M[1][2] * b->M[2][1] +
a->M[1][3] * b->M[3][1];
out.M[2][1] = a->M[2][0] * b->M[0][1] + a->M[2][1] * b->M[1][1] + a->M[2][2] * b->M[2][1] +
a->M[2][3] * b->M[3][1];
out.M[3][1] = a->M[3][0] * b->M[0][1] + a->M[3][1] * b->M[1][1] + a->M[3][2] * b->M[2][1] +
a->M[3][3] * b->M[3][1];
out.M[0][2] = a->M[0][0] * b->M[0][2] + a->M[0][1] * b->M[1][2] + a->M[0][2] * b->M[2][2] +
a->M[0][3] * b->M[3][2];
out.M[1][2] = a->M[1][0] * b->M[0][2] + a->M[1][1] * b->M[1][2] + a->M[1][2] * b->M[2][2] +
a->M[1][3] * b->M[3][2];
out.M[2][2] = a->M[2][0] * b->M[0][2] + a->M[2][1] * b->M[1][2] + a->M[2][2] * b->M[2][2] +
a->M[2][3] * b->M[3][2];
out.M[3][2] = a->M[3][0] * b->M[0][2] + a->M[3][1] * b->M[1][2] + a->M[3][2] * b->M[2][2] +
a->M[3][3] * b->M[3][2];
out.M[0][3] = a->M[0][0] * b->M[0][3] + a->M[0][1] * b->M[1][3] + a->M[0][2] * b->M[2][3] +
a->M[0][3] * b->M[3][3];
out.M[1][3] = a->M[1][0] * b->M[0][3] + a->M[1][1] * b->M[1][3] + a->M[1][2] * b->M[2][3] +
a->M[1][3] * b->M[3][3];
out.M[2][3] = a->M[2][0] * b->M[0][3] + a->M[2][1] * b->M[1][3] + a->M[2][2] * b->M[2][3] +
a->M[2][3] * b->M[3][3];
out.M[3][3] = a->M[3][0] * b->M[0][3] + a->M[3][1] * b->M[1][3] + a->M[3][2] * b->M[2][3] +
a->M[3][3] * b->M[3][3];
return out;
}
ovrMatrix4f ovrMatrix4f_CreateRotation(const float radiansX, const float radiansY, const float radiansZ) {
const float sinX = sinf(radiansX);
const float cosX = cosf(radiansX);
const ovrMatrix4f rotationX = {
{{1, 0, 0, 0}, {0, cosX, -sinX, 0}, {0, sinX, cosX, 0}, {0, 0, 0, 1}}};
const float sinY = sinf(radiansY);
const float cosY = cosf(radiansY);
const ovrMatrix4f rotationY = {
{{cosY, 0, sinY, 0}, {0, 1, 0, 0}, {-sinY, 0, cosY, 0}, {0, 0, 0, 1}}};
const float sinZ = sinf(radiansZ);
const float cosZ = cosf(radiansZ);
const ovrMatrix4f rotationZ = {
{{cosZ, -sinZ, 0, 0}, {sinZ, cosZ, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}};
const ovrMatrix4f rotationXY = ovrMatrix4f_Multiply(&rotationY, &rotationX);
return ovrMatrix4f_Multiply(&rotationZ, &rotationXY);
}
XrVector4f XrVector4f_MultiplyMatrix4f(const ovrMatrix4f* a, const XrVector4f* v) {
XrVector4f out;
out.x = a->M[0][0] * v->x + a->M[0][1] * v->y + a->M[0][2] * v->z + a->M[0][3] * v->w;
out.y = a->M[1][0] * v->x + a->M[1][1] * v->y + a->M[1][2] * v->z + a->M[1][3] * v->w;
out.z = a->M[2][0] * v->x + a->M[2][1] * v->y + a->M[2][2] * v->z + a->M[2][3] * v->w;
out.w = a->M[3][0] * v->x + a->M[3][1] * v->y + a->M[3][2] * v->z + a->M[3][3] * v->w;
return out;
}
/*
================================================================================
ovrTrackedController
================================================================================
*/
void ovrTrackedController_Clear(ovrTrackedController* controller) {
controller->Active = false;
controller->Pose = XrPosef_Identity();
}

View file

@ -9,26 +9,135 @@
# include <SDL_opengles2.h>
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"
#include <VrApi.h>
#pragma clang diagnostic pop
//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/openxr_oculus.h>
#include <openxr/openxr_oculus_helpers.h>
#define MATH_PI 3.14159265358979323846f
#define ALOGE(...) printf(__VA_ARGS__)
#define ALOGV(...) printf(__VA_ARGS__)
typedef union {
XrCompositionLayerProjection Projection;
XrCompositionLayerCylinderKHR Cylinder;
} ovrCompositorLayer_Union;
enum { ovrMaxLayerCount = 1 };
enum { ovrMaxNumEyes = 2 };
#define GL(func) func;
#define OXR(func) func;
typedef struct {
int swapchainLength;
int swapchainIndex;
ovrTextureSwapChain* colorTexture;
GLuint* depthBuffers;
GLuint* framebuffers;
} framebuffer_t;
JavaVM* Vm;
jobject ActivityObject;
JNIEnv* Env;
} ovrJava;
typedef struct {
XrSwapchain Handle;
uint32_t Width;
uint32_t Height;
} ovrSwapChain;
typedef struct {
int Width;
int Height;
uint32_t TextureSwapChainLength;
uint32_t TextureSwapChainIndex;
ovrSwapChain ColorSwapChain;
ovrSwapChain DepthSwapChain;
XrSwapchainImageOpenGLESKHR* ColorSwapChainImage;
XrSwapchainImageOpenGLESKHR* DepthSwapChainImage;
GLuint* FrameBuffers;
} ovrFramebuffer;
typedef struct {
ovrFramebuffer FrameBuffer;
} ovrRenderer;
typedef struct {
GLboolean Active;
XrPosef Pose;
} ovrTrackedController;
typedef struct {
GLboolean Focused;
XrInstance Instance;
XrSession Session;
XrViewConfigurationProperties ViewportConfig;
XrViewConfigurationView ViewConfigurationView[ovrMaxNumEyes];
XrSystemId SystemId;
XrSpace HeadSpace;
XrSpace StageSpace;
XrSpace FakeStageSpace;
XrSpace CurrentSpace;
GLboolean SessionActive;
float* SupportedDisplayRefreshRates;
uint32_t RequestedDisplayRefreshRateIndex;
uint32_t NumSupportedDisplayRefreshRates;
PFN_xrGetDisplayRefreshRateFB pfnGetDisplayRefreshRate;
PFN_xrRequestDisplayRefreshRateFB pfnRequestDisplayRefreshRate;
int SwapInterval;
// These threads will be marked as performance threads.
int MainThreadTid;
int RenderThreadTid;
ovrCompositorLayer_Union Layers[ovrMaxLayerCount];
int LayerCount;
ovrRenderer Renderer;
ovrTrackedController TrackedController[2];
} ovrApp;
typedef struct {
float M[4][4];
} ovrMatrix4f;
typedef enum ovrButton_ {
ovrButton_A = 0x00000001, // Set for trigger pulled on the Gear VR and Go Controllers
ovrButton_B = 0x00000002,
ovrButton_RThumb = 0x00000004,
ovrButton_RShoulder = 0x00000008,
ovrButton_X = 0x00000100,
ovrButton_Y = 0x00000200,
ovrButton_LThumb = 0x00000400,
ovrButton_LShoulder = 0x00000800,
ovrButton_Up = 0x00010000,
ovrButton_Down = 0x00020000,
ovrButton_Left = 0x00040000,
ovrButton_Right = 0x00080000,
ovrButton_Enter = 0x00100000, //< Set for touchpad click on the Go Controller, menu
// button on Left Quest Controller
ovrButton_Back = 0x00200000, //< Back button on the Go Controller (only set when
// a short press comes up)
ovrButton_GripTrigger = 0x04000000, //< grip trigger engaged
ovrButton_Trigger = 0x20000000, //< Index Trigger engaged
ovrButton_Joystick = 0x80000000, //< Click of the Joystick
ovrButton_EnumSize = 0x7fffffff
} ovrButton;
typedef struct {
uint64_t frameIndex;
ovrMobile* ovr;
ovrApp appState;
ovrJava java;
double predictedDisplayTime;
ovrTracking2 tracking;
framebuffer_t framebuffers;//[VRAPI_FRAME_LAYER_EYE_MAX];
float predictedDisplayTime;
} engine_t;
typedef enum {
@ -47,4 +156,36 @@ typedef enum {
VRFM_QUERY = 99 //Used to query which mode is active
} vrFollowMode_t;
void ovrApp_Clear(ovrApp* app);
void ovrApp_Destroy(ovrApp* app);
GLboolean ovrApp_HandleXrEvents(ovrApp* app);
void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer);
void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer);
void ovrFramebuffer_Release(ovrFramebuffer* frameBuffer);
void ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer);
void ovrFramebuffer_SetNone();
void ovrRenderer_Create(
XrSession session,
ovrRenderer* renderer,
int suggestedEyeTextureWidth,
int suggestedEyeTextureHeight);
void ovrRenderer_Destroy(ovrRenderer* renderer);
void ovrTrackedController_Clear(ovrTrackedController* controller);
ovrMatrix4f ovrMatrix4f_Multiply(const ovrMatrix4f* a, const ovrMatrix4f* b);
ovrMatrix4f ovrMatrix4f_CreateRotation(const float radiansX, const float radiansY, const float radiansZ);
ovrMatrix4f ovrMatrix4f_CreateFromQuaternion(const XrQuaternionf* q);
ovrMatrix4f ovrMatrix4f_CreateProjectionFov(
const float fovDegreesX,
const float fovDegreesY,
const float offsetX,
const float offsetY,
const float nearZ,
const float farZ);
XrVector4f XrVector4f_MultiplyMatrix4f(const ovrMatrix4f* a, const XrVector4f* v);
#endif

View file

@ -4,9 +4,6 @@
#include <android/log.h>
#include <VrApi.h>
#include <VrApi_Helpers.h>
#include <client/keycodes.h>
#include <qcommon/q_shared.h>
#include <qcommon/qcommon.h>
@ -27,7 +24,7 @@ extern void CON_LogcatFn( void (*LogcatFn)( const char* message ) );
static JNIEnv* g_Env = NULL;
static JavaVM* g_JavaVM = NULL;
static jobject g_ActivityObject = NULL;
static bool g_HasFocus = true;
static qboolean g_HasFocus = qtrue;
JNIEXPORT void JNICALL Java_com_drbeef_ioq3quest_MainActivity_nativeCreate(JNIEnv* env, jclass cls, jobject thisObject)
{
@ -39,6 +36,14 @@ JNIEXPORT void JNICALL Java_com_drbeef_ioq3quest_MainActivity_nativeFocusChanged
g_HasFocus = focus;
}
JNIEXPORT void JNICALL Java_com_drbeef_ioq3quest_MainActivity_nativeKey(JNIEnv *env, jclass clazz, jint keycode, jint action)
{
if (action == 0)
{
Com_QueueEvent( 0, SE_CHAR, keycode, qtrue, 0, NULL );
}
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
g_JavaVM = vm;
@ -80,23 +85,22 @@ int main(int argc, char* argv[]) {
Com_Init(args);
NET_Init( );
VR_EnterVR(engine, java);
VR_InitRenderer(engine);
VR_EnterVR(engine, java);
bool hasFocus = true;
bool paused = false;
qboolean hasFocus = qtrue;
qboolean paused = qfalse;
while (1) {
if (hasFocus != g_HasFocus) {
hasFocus = g_HasFocus;
if (!hasFocus && VR_isPauseable()) {
Com_QueueEvent( Sys_Milliseconds(), SE_KEY, K_ESCAPE, qtrue, 0, NULL );
//Com_QueueEvent( Sys_Milliseconds(), SE_KEY, K_CONSOLE, qtrue, 0, NULL );
paused = true;
paused = qtrue;
} else if (hasFocus && paused) {
//Com_QueueEvent( Sys_Milliseconds(), SE_KEY, K_CONSOLE, qtrue, 0, NULL );
Com_QueueEvent( Sys_Milliseconds(), SE_KEY, K_ESCAPE, qtrue, 0, NULL );
paused = false;
paused = qfalse;
}
}
@ -125,4 +129,4 @@ int main(int argc, char* argv[]) {
VR_Destroy(engine);
return 0;
}
}

View file

@ -8,6 +8,7 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
@ -35,6 +36,7 @@ import static android.system.Os.setenv;
public class MainActivity extends SDLActivity // implements KeyEvent.Callback
{
private static final String SUPPORTED_ASCII = "qwertyuiop[]asdfghjkl;'\\<zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:\"|>ZXCVBNM<>?`1234567890-=~!@#$%^&*()_+";
private int permissionCount = 0;
private static final int READ_EXTERNAL_STORAGE_PERMISSION_ID = 1;
private static final int WRITE_EXTERNAL_STORAGE_PERMISSION_ID = 2;
@ -72,6 +74,17 @@ public class MainActivity extends SDLActivity // implements KeyEvent.Callback
super.onDestroy();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
//ASCII characters directly passed into the engine
if (SUPPORTED_ASCII.indexOf(event.getUnicodeChar()) >= 0) {
nativeKey(event.getUnicodeChar(), event.getAction());
return true;
}
//special keys using SDL
return super.dispatchKeyEvent(event);
}
/**
* Initializes the Activity only if the permission has been granted.
*/
@ -95,8 +108,10 @@ public class MainActivity extends SDLActivity // implements KeyEvent.Callback
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) {
if (requestCode == WRITE_EXTERNAL_STORAGE_PERMISSION_ID) {
finish();
System.exit(0);
try {
create();
} catch (Exception e) {
}
}
}
@ -115,6 +130,8 @@ public class MainActivity extends SDLActivity // implements KeyEvent.Callback
// Copy our special pak file and demo
copy_asset("/sdcard/ioquake3Quest/baseq3", "pakQ3Q.pk3", true);
copy_asset("/sdcard/ioquake3Quest/baseq3", "pak0.pk3", false);
//Copy Omarlego's excellent replacement background
copy_asset("/sdcard/ioquake3Quest/baseq3", "z_custom_background66.pk3", false);
// Cleanup incompatible shaders
delete_asset("/sdcard/ioquake3Quest/baseq3/glsl");
@ -242,6 +259,7 @@ public class MainActivity extends SDLActivity // implements KeyEvent.Callback
public static native void nativeCreate(MainActivity thisObject);
public static native void nativeFocusChanged(boolean focus);
public static native void nativeKey(int keycode, int action);
static {
System.loadLibrary("main");

View file

@ -69,9 +69,10 @@ itemDef {
itemDef {
name controls3
group grpControls3
type ITEM_TYPE_YESNO
type ITEM_TYPE_MULTI
text "Two-Handed Weapons:"
cvar "vr_twoHandedWeapons"
cvarFloatList { "Disabled" 0 "Enabled (Basic)" 1 "Enabled (VR Gun Stock)" 2}
rect 99 125 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128

View file

@ -191,9 +191,10 @@ itemDef {
itemDef {
name controls
group grpControls
type ITEM_TYPE_YESNO
type ITEM_TYPE_MULTI
text "Two-Handed Weapons:"
cvar "vr_twoHandedWeapons"
cvarFloatList { "Disabled" 0 "Enabled (Basic)" 1 "Enabled (VR Gun Stock)" 2}
rect 30 56 200 20
textalign ITEM_ALIGN_RIGHT
textalignx 143

View file

@ -184,7 +184,7 @@ itemDef {
type ITEM_TYPE_MULTI
text "Refresh Rate:"
cvar "vr_refreshrate"
cvarFloatList { "60" 60 "72 (Recommended)" 72 "80" 80 "90" 90 }
cvarFloatList { "60" 60 "72" 72 "80" 80 "90" 90 "120" 120 }
rect 0 50 306 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
@ -194,13 +194,29 @@ itemDef {
visible 0
}
itemDef {
name graphics
group grpSystem
type ITEM_TYPE_MULTI
text "Supersampling:"
cvar "vr_superSampling"
cvarFloatList { "0.8" 0.8 "0.9" 0.9 "1.0" 1.0 "1.1" 1.1 "1.2" 1.2 "1.3" 1.3 }
rect 0 70 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
textscale .25
forecolor 1 1 1 1
visible 0
}
itemDef {
name graphics
group grpSystem
type ITEM_TYPE_SLIDER
text "Brightness:"
cvarfloat "r_gamma" 0.05 0.8 1.2
rect 0 70 256 20
cvarfloat "r_gamma" 0.05 0.6 1.0
rect 0 90 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
@ -216,7 +232,7 @@ itemDef {
text "Railgun Effect:"
cvar "cg_oldRail"
cvarFloatList { "Q2 Style" 0 "Q3 Style" 1 }
rect 0 90 256 20
rect 0 110 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
@ -232,7 +248,7 @@ itemDef {
text "Lighting:"
cvar "r_vertexlight"
cvarFloatList { "Lightmap (High)" 0 "Vertex (Low)" 1 }
rect 0 110 256 20
rect 0 130 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
@ -249,7 +265,7 @@ itemDef {
text "Opponent Shadows:"
cvar "cg_shadows"
cvarFloatList { "None" 0 "Low" 1 "High" 3 }
rect 0 130 306 20
rect 0 150 306 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
@ -265,7 +281,7 @@ itemDef {
text "Player Shadow:"
cvar "cg_playerShadow"
cvarFloatList { "None" 0 "Low" 1 "High" 3 }
rect 0 150 306 20
rect 0 170 306 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
@ -281,7 +297,7 @@ itemDef {
text "Geometric Detail:"
cvar "r_lodbias"
cvarFloatList { "High" -1 "Medium" 1 "Low" 2 }
rect 0 170 256 20
rect 0 190 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
@ -298,7 +314,7 @@ itemDef {
text "Texture Detail:"
cvar "r_picmip"
cvarFloatList { "Low" 2 "Normal" 1 "High" 0 }
rect 0 190 256 20
rect 0 210 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
@ -314,7 +330,7 @@ itemDef {
type ITEM_TYPE_YESNO
text "Compress Textures:"
cvar "r_ext_compressed_textures"
rect 0 210 256 20
rect 0 230 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17
@ -330,7 +346,7 @@ itemDef {
type ITEM_TYPE_YESNO
text "Low Quality Sky:"
cvar "r_fastsky"
rect 0 230 256 20
rect 0 250 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 133
textaligny 17

View file

@ -87,7 +87,7 @@ itemDef {
type ITEM_TYPE_MULTI
text "Refresh Rate:"
cvar "vr_refreshrate"
cvarFloatList { "60" 60 "72 (Recommended)" 72 "80" 80 "90" 90 }
cvarFloatList { "60" 60 "72" 72 "80" 80 "90" 90 "120" 120 }
rect 99 42 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
@ -97,13 +97,29 @@ itemDef {
visible 0
}
itemDef {
name graphics
group grpSystem
type ITEM_TYPE_MULTI
text "Supersampling:"
cvar "vr_superSampling"
cvarFloatList { "0.8" 0.8 "0.9" 0.9 "1.0" 1.0 "1.1" 1.1 "1.2" 1.2 "1.3" 1.3 }
rect 99 67 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
textscale .333
forecolor 1 1 1 1
visible 0
}
itemDef {
name graphics
group grpSystem
type ITEM_TYPE_SLIDER
text "Brightness:"
cvarfloat "r_gamma" 0.05 0.8 1.2
rect 99 67 256 20
cvarfloat "r_gamma" 0.05 0.6 1.0
rect 99 92 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
@ -119,7 +135,7 @@ itemDef {
text "Railgun Effect:"
cvar "cg_oldRail"
cvarFloatList { "Q2 Style" 0 "Q3 Style" 1 }
rect 99 92 256 20
rect 99 117 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
@ -135,7 +151,7 @@ itemDef {
text "Lighting:"
cvar "r_vertexlight"
cvarFloatList { "Lightmap (High)" 0 "Vertex (Low)" 1 }
rect 99 117 256 20
rect 99 142 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
@ -152,7 +168,7 @@ itemDef {
text "Opponent Shadows:"
cvar "cg_shadows"
cvarFloatList { "None" 0 "Low" 1 "High" 3 }
rect 99 142 256 20
rect 99 167 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
@ -168,7 +184,7 @@ itemDef {
text "Player Shadow:"
cvar "cg_playerShadow"
cvarFloatList { "None" 0 "Low" 1 "High" 3 }
rect 99 167 256 20
rect 99 192 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
@ -184,7 +200,7 @@ itemDef {
text "Geometric Detail:"
cvar "r_lodbias"
cvarFloatList { "High" -1 "Medium" 1 "Low" 2 }
rect 99 192 256 20
rect 99 217 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
@ -201,7 +217,7 @@ itemDef {
text "Texture Detail:"
cvar "r_picmip"
cvarFloatList { "Low" 2 "Normal" 1 "High" 0 }
rect 99 217 256 20
rect 99 242 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
@ -217,7 +233,7 @@ itemDef {
type ITEM_TYPE_YESNO
text "Compress Textures:"
cvar "r_ext_compressed_textures"
rect 99 242 256 20
rect 99 267 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20
@ -233,7 +249,7 @@ itemDef {
type ITEM_TYPE_YESNO
text "Low Quality Sky:"
cvar "r_fastsky"
rect 99 267 256 20
rect 99 292 256 20
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 20

View file

@ -3,7 +3,7 @@
setlocal
set BUILD_TYPE=release
set VERSION=1.1.0
set VERSION=1.1.3
@REM Define the following environment variables to sign a release build
@REM set KEYSTORE=