mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2025-04-20 07:00:47 +00:00
Compare commits
54 commits
Author | SHA1 | Date | |
---|---|---|---|
|
79befe4d38 | ||
|
91fa5bcf3b | ||
|
8bb0124fe6 | ||
|
6d9951dd95 | ||
|
b904ee0d4f | ||
|
61faf0a731 | ||
|
a235a57205 | ||
|
325deba431 | ||
|
b2bd1be433 | ||
|
e1cdb7a9c2 | ||
|
493ee6e96d | ||
|
9634ff74cd | ||
|
706481fe00 | ||
|
21fc40dc44 | ||
|
96b1071b50 | ||
|
807a8d2820 | ||
|
c7811f31d1 | ||
|
65dcb19541 | ||
|
b43a9a67c7 | ||
|
b11fc0fb29 | ||
|
023d0f27a8 | ||
|
bd0592dcc7 | ||
|
152e48b3c7 | ||
|
e201285822 | ||
|
1f3a31bbc8 | ||
|
096daff966 | ||
|
f5c507fe8a | ||
|
b45d7cd653 | ||
|
d322b861f2 | ||
|
33e4bc37ad | ||
|
c01c8b3484 | ||
|
d9db6a2076 | ||
|
b659a9e09e | ||
|
8cf8f3ae1b | ||
|
8cf2ffc445 | ||
|
d90f86e035 | ||
|
e903dc373b | ||
|
d4785e8a9e | ||
|
0a3d613787 | ||
|
f2dbc90823 | ||
|
5068ce7199 | ||
|
5ecbbac97e | ||
|
d354212c5d | ||
|
859cecb424 | ||
|
244b8344ff | ||
|
437e3829aa | ||
|
314e8b0288 | ||
|
709c0abdcf | ||
|
9d09e3f9d8 | ||
|
a56b9ad288 | ||
|
7e092d57a4 | ||
|
4181466815 | ||
|
65ff5bbd80 | ||
|
52799aa99d |
41 changed files with 2205 additions and 609 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -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
|
||||
|
|
14
Makefile
14
Makefile
|
@ -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 \
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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"/>-->
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
set sv_master1 "13.36.227.32:27950"
|
||||
set vr_master1 "mp.quakevr.com:27950"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
|
|
|
@ -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"
|
||||
|
|
BIN
android/app/src/main/assets/z_custom_background66.pk3
Normal file
BIN
android/app/src/main/assets/z_custom_background66.pk3
Normal file
Binary file not shown.
|
@ -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})
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -63,6 +63,9 @@ typedef struct {
|
|||
int *menuCursorX;
|
||||
int *menuCursorY;
|
||||
qboolean menuLeftHanded;
|
||||
|
||||
float recenterYaw;
|
||||
float superSampling;
|
||||
} vr_clientinfo_t;
|
||||
|
||||
#endif //vr_clientinfo_h
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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, ¤tDisplayRefreshRate));
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
594
android/app/src/main/cpp/code/vr/vr_types.c
Normal file
594
android/app/src/main/cpp/code/vr/vr_types.c
Normal 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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
Loading…
Reference in a new issue