First big commit - pretty much playable throughout

This commit is contained in:
Simon 2022-01-29 15:45:18 +00:00
parent 3dc2dac2e5
commit 4b4ee4ec6e
35 changed files with 1202 additions and 172 deletions

View file

@ -2,10 +2,10 @@ PLATFORM=android
ANDROID_SDK_VERSION=android26 ANDROID_SDK_VERSION=android26
ANDROID_NDK_VERSION=21.1.6352462 ANDROID_NDK_VERSION=21.1.6352462
## Uncomment for Windows host platform ## Uncomment for Windows host platform
# ANDROID_NDK=C:/Users/<user>/AppData/Local/Android/Sdk/ndk/$(ANDROID_NDK_VERSION) ANDROID_NDK=C:/Users/simon/AppData/Local/Android/Sdk/ndk/$(ANDROID_NDK_VERSION)
# ANDROID_CC=$(ANDROID_NDK)/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe ANDROID_CC=$(ANDROID_NDK)/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe
# ANDROID_CFLAGS=--target=aarch64-linux-$(ANDROID_SDK_VERSION) ANDROID_CFLAGS=--target=aarch64-linux-$(ANDROID_SDK_VERSION)
# ANDROID_RANLIB=$(ANDROID_NDK)/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android-ranlib.exe ANDROID_RANLIB=$(ANDROID_NDK)/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android-ranlib.exe
## Uncomment for Linux host platform ## Uncomment for Linux host platform
# ANDROID_NDK=~/Android/Sdk/ndk/$(ANDROID_NDK_VERSION) # ANDROID_NDK=~/Android/Sdk/ndk/$(ANDROID_NDK_VERSION)
# ANDROID_CC=$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-$(ANDROID_SDK_VERSION)-clang # ANDROID_CC=$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-$(ANDROID_SDK_VERSION)-clang

View file

@ -17,6 +17,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:hasCode="true"> android:hasCode="true">
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/> <meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
<meta-data android:name="com.oculus.supportedDevices" android:value="quest|quest2"/>
<activity android:name="com.sparkie.ioq3quest.MainActivity" <activity android:name="com.sparkie.ioq3quest.MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:screenOrientation="landscape" android:screenOrientation="landscape"

View file

@ -0,0 +1 @@
E:/ioq3quest/code

View file

@ -13,6 +13,7 @@ extern "C" {
#include <qcommon/qcommon.h> #include <qcommon/qcommon.h>
#include <vr/vr_base.h> #include <vr/vr_base.h>
#include <vr/vr_renderer.h> #include <vr/vr_renderer.h>
#include <unistd.h>
#include <SDL.h> #include <SDL.h>
@ -60,68 +61,56 @@ static ovrJava engine_get_ovrJava() {
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
ovrJava java = engine_get_ovrJava();
engine_t* engine = nullptr;
engine = VR_Init(java);
//First set up resolution cached values
int width, height;
VR_GetRsolution( engine, &width, &height );
CON_LogcatFn(&ioq3_logfn); CON_LogcatFn(&ioq3_logfn);
std::string defaultArgs("+set fs_basepath "); std::string defaultArgs("+set fs_basepath ");
defaultArgs += SDL_AndroidGetExternalStoragePath(); defaultArgs += SDL_AndroidGetExternalStoragePath();
defaultArgs += " +set fs_game baseq3 +map q3dm6"; defaultArgs += " +set fs_game baseq3";
char* args = new char[defaultArgs.length() + 1]; char* args = new char[defaultArgs.length() + 1];
args[defaultArgs.length()] = '\0'; args[defaultArgs.length()] = '\0';
memcpy(args, defaultArgs.c_str(), defaultArgs.length()); memcpy(args, defaultArgs.c_str(), defaultArgs.length());
Com_Init(args); Com_Init(args);
ovrJava java = engine_get_ovrJava(); VR_InitRenderer(engine);
constexpr auto vrEnabled = true; VR_EnterVR(engine, java);
engine_t* engine = nullptr;
if (vrEnabled) //sleep(20);
{
engine = VR_Init(java);
VR_InitRenderer(engine);
VR_EnterVR(engine, java);
}
while (1) { while (1) {
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
LOGI("Received SDL Event: %d", event.type); LOGI("Received SDL Event: %d", event.type);
if (vrEnabled) switch (event.type)
{ {
switch (event.type) case SDL_WINDOWEVENT_FOCUS_GAINED:
{ VR_EnterVR(engine, engine_get_ovrJava());
case SDL_WINDOWEVENT_FOCUS_GAINED: break;
VR_EnterVR(engine, engine_get_ovrJava());
break;
case SDL_WINDOWEVENT_FOCUS_LOST: case SDL_WINDOWEVENT_FOCUS_LOST:
VR_LeaveVR(engine); VR_LeaveVR(engine);
break; break;
}
} }
} }
if (vrEnabled)
{ VR_DrawFrame(engine);
VR_DrawFrame(engine);
}
else
{
Com_Frame();
}
}
if (vrEnabled)
{
VR_LeaveVR(engine);
VR_DestroyRenderer(engine);
} }
VR_LeaveVR(engine);
VR_DestroyRenderer(engine);
Com_Shutdown(); Com_Shutdown();
if (vrEnabled) VR_Destroy(engine);
{
VR_Destroy(engine);
}
delete [] args; delete [] args;
return 0; return 0;
} }

View file

@ -5,10 +5,13 @@ setlocal
set ANDROID_SDK_ROOT=%AppData%\..\Local\Android\Sdk set ANDROID_SDK_ROOT=%AppData%\..\Local\Android\Sdk
set adb="%ANDROID_SDK_ROOT%\platform-tools\adb.exe" set adb="%ANDROID_SDK_ROOT%\platform-tools\adb.exe"
set make="%ANDROID_SDK_ROOT%\ndk\21.1.6352462\prebuilt\windows-x86_64\bin\make.exe" set make="%ANDROID_SDK_ROOT%\ndk\21.1.6352462\prebuilt\windows-x86_64\bin\make.exe"
set apksigner="%ANDROID_SDK_ROOT%\build-tools\29.0.2\apksigner.bat"
set JAVA_HOME=C:\Program Files\Android\Android Studio\jre\jre set JAVA_HOME=C:\Program Files\Android\Android Studio\jre\jre
set BUILD_TYPE=release
set GRADLE_BUILD_TYPE=:app:assembleRelease
pushd %~dp0\.. pushd %~dp0\..
%make% -j %NUMBER_OF_PROCESSORS% debug %make% -j %NUMBER_OF_PROCESSORS% %BUILD_TYPE%
if %ERRORLEVEL% NEQ 0 ( if %ERRORLEVEL% NEQ 0 (
popd popd
@ -19,7 +22,7 @@ if %ERRORLEVEL% NEQ 0 (
pushd android pushd android
set GRADLE_EXIT_CONSOLE=1 set GRADLE_EXIT_CONSOLE=1
call gradlew.bat :app:assembleDebug call gradlew.bat %GRADLE_BUILD_TYPE%
if %ERRORLEVEL% NEQ 0 ( if %ERRORLEVEL% NEQ 0 (
popd popd
@ -30,7 +33,9 @@ if %ERRORLEVEL% NEQ 0 (
set PACKAGE_NAME=com.sparkie.ioq3quest set PACKAGE_NAME=com.sparkie.ioq3quest
set ANDROID_STORAGE_LOCATION=/sdcard/Android/data/%PACKAGE_NAME%/files/ set ANDROID_STORAGE_LOCATION=/sdcard/Android/data/%PACKAGE_NAME%/files/
set APK_LOCATION=.\app\build\outputs\apk\debug\app-debug.apk set APK_LOCATION=.\app\build\outputs\apk\%BUILD_TYPE%\app-%BUILD_TYPE%.apk
REM %apksigner% sign --ks ../drbeef-release-key.keystore --out %APK_LOCATION% .\app\build\outputs\apk\%BUILD_TYPE%\app-%BUILD_TYPE%-unsigned.apk
%adb% install -r %APK_LOCATION% %adb% install -r %APK_LOCATION%
if %ERRORLEVEL% NEQ 0 ( if %ERRORLEVEL% NEQ 0 (
@ -45,7 +50,7 @@ if %ERRORLEVEL% NEQ 0 (
) )
%adb% shell mkdir -p %ANDROID_STORAGE_LOCATION% %adb% shell mkdir -p %ANDROID_STORAGE_LOCATION%
%adb% push --sync "C:\Program Files (x86)\Steam\steamapps\common\Quake 3 Arena\baseq3" %ANDROID_STORAGE_LOCATION% %adb% push --sync "D:\Program Files (x86)\Steam\steamapps\common\Quake 3 Arena\baseq3" %ANDROID_STORAGE_LOCATION%
if %ERRORLEVEL% NEQ 0 ( if %ERRORLEVEL% NEQ 0 (
popd popd
popd popd

View file

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// active (after loading) gameplay // active (after loading) gameplay
#include "cg_local.h" #include "cg_local.h"
#include "../vr/vr_clientinfo.h"
#ifdef MISSIONPACK #ifdef MISSIONPACK
#include "../ui/ui_shared.h" #include "../ui/ui_shared.h"
@ -38,6 +39,9 @@ int drawTeamOverlayModificationCount = -1;
int sortedTeamPlayers[TEAM_MAXOVERLAY]; int sortedTeamPlayers[TEAM_MAXOVERLAY];
int numSortedTeamPlayers; int numSortedTeamPlayers;
extern vr_clientinfo_t* cgVR;
extern stereoFrame_t hudStereoView;
char systemChat[256]; char systemChat[256];
char teamChat1[256]; char teamChat1[256];
char teamChat2[256]; char teamChat2[256];
@ -278,6 +282,7 @@ void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandl
memset( &ent, 0, sizeof( ent ) ); memset( &ent, 0, sizeof( ent ) );
AnglesToAxis( angles, ent.axis ); AnglesToAxis( angles, ent.axis );
VectorCopy( origin, ent.origin ); VectorCopy( origin, ent.origin );
ent.hModel = model; ent.hModel = model;
ent.customSkin = skin; ent.customSkin = skin;
@ -1923,6 +1928,7 @@ static void CG_DrawCrosshair(void)
CG_DrawCrosshair3D CG_DrawCrosshair3D
================= =================
*/ */
void CG_CalculateVRWeaponPosition( vec3_t origin, vec3_t angles );
static void CG_DrawCrosshair3D(void) static void CG_DrawCrosshair3D(void)
{ {
float w; float w;
@ -1976,10 +1982,19 @@ static void CG_DrawCrosshair3D(void)
xmax = zProj * tan(cg.refdef.fov_x * M_PI / 360.0f); xmax = zProj * tan(cg.refdef.fov_x * M_PI / 360.0f);
// let the trace run through until a change in stereo separation of the crosshair becomes less than one pixel. // let the trace run through until a change in stereo separation of the crosshair becomes less than one pixel.
vec3_t viewaxis[3];
vec3_t weaponangles;
vec3_t origin;
CG_CalculateVRWeaponPosition(origin, weaponangles);
AnglesToAxis(weaponangles, viewaxis);
maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax); maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax);
VectorMA(origin, maxdist, viewaxis[0], endpos);
CG_Trace(&trace, origin, NULL, NULL, endpos, 0, MASK_SHOT);
/* maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax);
VectorMA(cg.refdef.vieworg, maxdist, cg.refdef.viewaxis[0], endpos); VectorMA(cg.refdef.vieworg, maxdist, cg.refdef.viewaxis[0], endpos);
CG_Trace(&trace, cg.refdef.vieworg, NULL, NULL, endpos, 0, MASK_SHOT); CG_Trace(&trace, cg.refdef.vieworg, NULL, NULL, endpos, 0, MASK_SHOT);
*/
memset(&ent, 0, sizeof(ent)); memset(&ent, 0, sizeof(ent));
ent.reType = RT_SPRITE; ent.reType = RT_SPRITE;
ent.renderfx = RF_DEPTHHACK | RF_CROSSHAIR; ent.renderfx = RF_DEPTHHACK | RF_CROSSHAIR;
@ -2647,11 +2662,28 @@ void CG_DrawActive( stereoFrame_t stereoView ) {
if(stereoView != STEREO_CENTER) if(stereoView != STEREO_CENTER)
CG_DrawCrosshair3D(); CG_DrawCrosshair3D();
// offset vieworg appropriately if we're doing stereo separation
vec3_t baseOrg;
VectorCopy( cg.refdef.vieworg, baseOrg );
float ipd = 0.065f;
float separation = stereoView == STEREO_LEFT ?
WORLD_SCALE * (-ipd / 2) : //left
WORLD_SCALE * (ipd / 2); // right
cg.refdef.vieworg[2] -= PLAYER_HEIGHT;
cg.refdef.vieworg[2] += cgVR->hmdposition[1] * WORLD_SCALE;
VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );
// draw 3D view // draw 3D view
trap_R_RenderScene( &cg.refdef ); trap_R_RenderScene( &cg.refdef );
VectorCopy( baseOrg, cg.refdef.vieworg );
// draw status bar and other floating elements // draw status bar and other floating elements
CG_Draw2D(stereoView); hudStereoView = stereoView;
CG_Draw2D(hudStereoView);
} }

View file

@ -23,6 +23,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc // cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
#include "cg_local.h" #include "cg_local.h"
int hudflags = 0;
stereoFrame_t hudStereoView = STEREO_CENTER;
/* /*
================ ================
CG_AdjustFrom640 CG_AdjustFrom640
@ -31,17 +34,33 @@ Adjusted for resolution and screen aspect ratio
================ ================
*/ */
void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) { void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
#if 0
// adjust for wide screens if (hudflags & HUD_FLAGS_FULLSCREEN)
if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) { {
*x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) ); // scale for screen sizes
*x *= cgs.screenXScale;
*y *= cgs.screenYScale;
*w *= cgs.screenXScale;
*h *= cgs.screenYScale;
}
else // scale to clearly visible portion of VR screen
{
float screenXScale = cgs.screenXScale / 2.75f;
float screenYScale = cgs.screenYScale / 2.75f;
int xoffset = -64;
if (hudStereoView == STEREO_LEFT) {
xoffset *= -1;
}
*x *= screenXScale;
*y *= screenYScale;
*w *= screenXScale;
*h *= screenYScale;
*x += (cg.refdef.width - (640 * screenXScale)) / 2.0f + xoffset;
*y += (cg.refdef.height - (480 * screenYScale)) / 2.0f;
} }
#endif
// scale for screen sizes
*x *= cgs.screenXScale;
*y *= cgs.screenYScale;
*w *= cgs.screenXScale;
*h *= cgs.screenYScale;
} }
/* /*

View file

@ -90,6 +90,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define DEFAULT_REDTEAM_NAME "Stroggs" #define DEFAULT_REDTEAM_NAME "Stroggs"
#define DEFAULT_BLUETEAM_NAME "Pagans" #define DEFAULT_BLUETEAM_NAME "Pagans"
//VR HUD
#define HUD_FLAGS_FULLSCREEN 1
typedef enum { typedef enum {
FOOTSTEP_NORMAL, FOOTSTEP_NORMAL,

View file

@ -23,12 +23,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// cg_main.c -- initialization and primary entry point for cgame // cg_main.c -- initialization and primary entry point for cgame
#include "cg_local.h" #include "cg_local.h"
#include "../vr/vr_clientinfo.h"
#ifdef MISSIONPACK #ifdef MISSIONPACK
#include "../ui/ui_shared.h" #include "../ui/ui_shared.h"
// display context for new ui stuff // display context for new ui stuff
displayContextDef_t cgDC; displayContextDef_t cgDC;
#endif #endif
vr_clientinfo_t *cgVR;
int forceModelModificationCount = -1; int forceModelModificationCount = -1;
void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ); void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum );
@ -74,6 +78,11 @@ Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, i
case CG_EVENT_HANDLING: case CG_EVENT_HANDLING:
CG_EventHandling(arg0); CG_EventHandling(arg0);
return 0; return 0;
case CG_SET_VR_CLIENT_INFO: {
int ptr[2] = {arg0, arg1};
cgVR = (vr_clientinfo_t *) (*(long*)(ptr));
return 0;
}
default: default:
CG_Error( "vmMain: unknown command %i", command ); CG_Error( "vmMain: unknown command %i", command );
break; break;

View file

@ -231,8 +231,11 @@ typedef enum {
CG_MOUSE_EVENT, CG_MOUSE_EVENT,
// void (*CG_MouseEvent)( int dx, int dy ); // void (*CG_MouseEvent)( int dx, int dy );
CG_EVENT_HANDLING CG_EVENT_HANDLING,
// void (*CG_EventHandling)(int type); // void (*CG_EventHandling)(int type);
CG_SET_VR_CLIENT_INFO
} cgameExport_t; } cgameExport_t;
//---------------------------------------------- //----------------------------------------------

View file

@ -333,8 +333,8 @@ static void CG_OffsetFirstPersonView( void ) {
// if dead, fix the angle and don't add any kick // if dead, fix the angle and don't add any kick
if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) { if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
angles[ROLL] = 40; //angles[ROLL] = 40;
angles[PITCH] = -15; //angles[PITCH] = -15;
angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW];
origin[2] += cg.predictedPlayerState.viewheight; origin[2] += cg.predictedPlayerState.viewheight;
return; return;

View file

@ -22,6 +22,232 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// //
// cg_weapons.c -- events and effects dealing with weapons // cg_weapons.c -- events and effects dealing with weapons
#include "cg_local.h" #include "cg_local.h"
#include "../vr/vr_clientinfo.h"
extern vr_clientinfo_t *cgVR;
#define M_PI2 (float)6.28318530717958647692
/*
=================
SinCos
=================
*/
void SinCos( float radians, float *sine, float *cosine )
{
#if _MSC_VER == 1200
_asm
{
fld dword ptr [radians]
fsincos
mov edx, dword ptr [cosine]
mov eax, dword ptr [sine]
fstp dword ptr [edx]
fstp dword ptr [eax]
}
#else
// I think, better use math.h function, instead of ^
#if defined (__linux__) && !defined (__ANDROID__)
sincosf(radians, sine, cosine);
#else
*sine = sinf(radians);
*cosine = cosf(radians);
#endif
#endif
}
void Matrix4x4_Concat (matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2)
{
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0] + in1[0][3] * in2[3][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1] + in1[0][3] * in2[3][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2] + in1[0][3] * in2[3][2];
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3] * in2[3][3];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0] + in1[1][3] * in2[3][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1] + in1[1][3] * in2[3][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2] + in1[1][3] * in2[3][2];
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3] * in2[3][3];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0] + in1[2][3] * in2[3][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1] + in1[2][3] * in2[3][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2] + in1[2][3] * in2[3][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3] * in2[3][3];
out[3][0] = in1[3][0] * in2[0][0] + in1[3][1] * in2[1][0] + in1[3][2] * in2[2][0] + in1[3][3] * in2[3][0];
out[3][1] = in1[3][0] * in2[0][1] + in1[3][1] * in2[1][1] + in1[3][2] * in2[2][1] + in1[3][3] * in2[3][1];
out[3][2] = in1[3][0] * in2[0][2] + in1[3][1] * in2[1][2] + in1[3][2] * in2[2][2] + in1[3][3] * in2[3][2];
out[3][3] = in1[3][0] * in2[0][3] + in1[3][1] * in2[1][3] + in1[3][2] * in2[2][3] + in1[3][3] * in2[3][3];
}
void Matrix4x4_CreateFromEntity( matrix4x4 out, const vec3_t angles, const vec3_t origin, float scale )
{
float angle, sr, sp, sy, cr, cp, cy;
if( angles[ROLL] )
{
#ifdef XASH_VECTORIZE_SINCOS
SinCosFastVector3( DEG2RAD(angles[YAW]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[ROLL]),
&sy, &sp, &sr,
&cy, &cp, &cr);
#else
angle = angles[YAW] * (M_PI2 / 360.0f);
SinCos( angle, &sy, &cy );
angle = angles[PITCH] * (M_PI2 / 360.0f);
SinCos( angle, &sp, &cp );
angle = angles[ROLL] * (M_PI2 / 360.0f);
SinCos( angle, &sr, &cr );
#endif
out[0][0] = (cp*cy) * scale;
out[0][1] = (sr*sp*cy+cr*-sy) * scale;
out[0][2] = (cr*sp*cy+-sr*-sy) * scale;
out[0][3] = origin[0];
out[1][0] = (cp*sy) * scale;
out[1][1] = (sr*sp*sy+cr*cy) * scale;
out[1][2] = (cr*sp*sy+-sr*cy) * scale;
out[1][3] = origin[1];
out[2][0] = (-sp) * scale;
out[2][1] = (sr*cp) * scale;
out[2][2] = (cr*cp) * scale;
out[2][3] = origin[2];
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
else if( angles[PITCH] )
{
#ifdef XASH_VECTORIZE_SINCOS
SinCosFastVector2( DEG2RAD(angles[YAW]), DEG2RAD(angles[PITCH]),
&sy, &sp,
&cy, &cp);
#else
angle = angles[YAW] * (M_PI2 / 360.0f);
SinCos( angle, &sy, &cy );
angle = angles[PITCH] * (M_PI2 / 360.0f);
SinCos( angle, &sp, &cp );
#endif
out[0][0] = (cp*cy) * scale;
out[0][1] = (-sy) * scale;
out[0][2] = (sp*cy) * scale;
out[0][3] = origin[0];
out[1][0] = (cp*sy) * scale;
out[1][1] = (cy) * scale;
out[1][2] = (sp*sy) * scale;
out[1][3] = origin[1];
out[2][0] = (-sp) * scale;
out[2][1] = 0.0f;
out[2][2] = (cp) * scale;
out[2][3] = origin[2];
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
else if( angles[YAW] )
{
angle = angles[YAW] * (M_PI2 / 360.0f);
SinCos( angle, &sy, &cy );
out[0][0] = (cy) * scale;
out[0][1] = (-sy) * scale;
out[0][2] = 0.0f;
out[0][3] = origin[0];
out[1][0] = (sy) * scale;
out[1][1] = (cy) * scale;
out[1][2] = 0.0f;
out[1][3] = origin[1];
out[2][0] = 0.0f;
out[2][1] = 0.0f;
out[2][2] = scale;
out[2][3] = origin[2];
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
else
{
out[0][0] = scale;
out[0][1] = 0.0f;
out[0][2] = 0.0f;
out[0][3] = origin[0];
out[1][0] = 0.0f;
out[1][1] = scale;
out[1][2] = 0.0f;
out[1][3] = origin[1];
out[2][0] = 0.0f;
out[2][1] = 0.0f;
out[2][2] = scale;
out[2][3] = origin[2];
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
}
void Matrix4x4_ConvertToEntity( vec4_t *in, vec3_t angles, vec3_t origin )
{
float xyDist = sqrt( in[0][0] * in[0][0] + in[1][0] * in[1][0] );
// enough here to get angles?
if( xyDist > 0.001f )
{
angles[0] = RAD2DEG( atan2( -in[2][0], xyDist ));
angles[1] = RAD2DEG( atan2( in[1][0], in[0][0] ));
angles[2] = RAD2DEG( atan2( in[2][1], in[2][2] ));
}
else // forward is mostly Z, gimbal lock
{
angles[0] = RAD2DEG( atan2( -in[2][0], xyDist ));
angles[1] = RAD2DEG( atan2( -in[0][1], in[1][1] ));
angles[2] = 0.0f;
}
origin[0] = in[0][3];
origin[1] = in[1][3];
origin[2] = in[2][3];
}
void rotateAboutOrigin(float x, float y, float rotation, vec2_t out)
{
out[0] = cosf(DEG2RAD(-rotation)) * x + sinf(DEG2RAD(-rotation)) * y;
out[1] = cosf(DEG2RAD(-rotation)) * y - sinf(DEG2RAD(-rotation)) * x;
}
void convertFromVR(vec3_t in, vec3_t offset, vec3_t out)
{
vec3_t vrSpace;
VectorSet(vrSpace, in[2], in[0], in[1] );
vec2_t r;
rotateAboutOrigin(vrSpace[0], vrSpace[1], cg.refdefViewAngles[YAW] - cgVR->hmdorientation[YAW], r);
vrSpace[0] = -r[0];
vrSpace[1] = -r[1];
vec3_t temp;
VectorScale(vrSpace, WORLD_SCALE, temp);
if (offset) {
VectorAdd(temp, offset, out);
} else {
VectorCopy(temp, out);
}
}
void CG_CalculateVRWeaponPosition( vec3_t origin, vec3_t angles )
{
convertFromVR(cgVR->calculated_weaponoffset, cg.refdef.vieworg, origin);
origin[2] -= PLAYER_HEIGHT;
origin[2] += cgVR->hmdposition[1] * WORLD_SCALE;
VectorCopy(cgVR->weaponangles, angles);
angles[YAW] += (cg.refdefViewAngles[YAW] - cgVR->hmdorientation[YAW]);
}
/* /*
========================== ==========================
@ -207,6 +433,49 @@ static void CG_NailgunEjectBrass( centity_t *cent ) {
#endif #endif
/*
==========================
CG_RailTrail2
==========================
*/
void CG_RailTrail2( clientInfo_t *ci, vec3_t start, vec3_t end ) {
localEntity_t *le;
refEntity_t *re;
le = CG_AllocLocalEntity();
re = &le->refEntity;
le->leType = LE_FADE_RGB;
le->startTime = cg.time;
le->endTime = cg.time + 25;
le->lifeRate = 1.0 / ( le->endTime - le->startTime );
re->shaderTime = cg.time / 1000.0f;
re->reType = RT_RAIL_CORE;
re->customShader = cgs.media.railCoreShader;
VectorCopy( start, re->origin );
VectorCopy( end, re->oldorigin );
// // still allow different colors so we can tell AI shots from player shots, etc.
le->color[3] = 1.0f;
if ( ci ) {
if (ci->health == 1)
{
le->color[3] = (ci->handicap / 255.0f);
}
le->color[0] = ci->color1[0] * 0.75;
le->color[1] = ci->color1[1] * 0.75;
le->color[2] = ci->color1[2] * 0.75;
} else {
le->color[0] = 1;
le->color[1] = 0;
le->color[2] = 0;
}
AxisClear( re->axis );
}
/* /*
========================== ==========================
CG_RailTrail CG_RailTrail
@ -1398,11 +1667,12 @@ void CG_AddViewWeapon( playerState_t *ps ) {
} }
// drop gun lower at higher fov // drop gun lower at higher fov
if ( cg_fov.integer > 90 ) { /* if ( cg_fov.integer > 90 ) {
fovOffset = -0.2 * ( cg_fov.integer - 90 ); fovOffset = -0.2 * ( cg_fov.integer - 90 );
} else { } else {
fovOffset = 0; fovOffset = 0;
} }
*/
cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum]; cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
CG_RegisterWeapon( ps->weapon ); CG_RegisterWeapon( ps->weapon );
@ -1411,11 +1681,61 @@ void CG_AddViewWeapon( playerState_t *ps ) {
memset (&hand, 0, sizeof(hand)); memset (&hand, 0, sizeof(hand));
// set up gun position // set up gun position
CG_CalculateWeaponPosition( hand.origin, angles ); CG_CalculateVRWeaponPosition( hand.origin, angles );
//Scale / Move gun etc
float scale = 1.0f;
{
char cvar_name[64];
Com_sprintf(cvar_name, sizeof(cvar_name), "vr_weapon_adjustment_%i", ps->weapon);
char weapon_adjustment[256];
trap_Cvar_VariableStringBuffer(cvar_name, weapon_adjustment, 256);
if (strlen(weapon_adjustment) > 0) {
vec3_t offset;
vec3_t adjust;
vec3_t temp_offset;
VectorClear(temp_offset);
VectorClear(adjust);
sscanf(weapon_adjustment, "%f,%f,%f,%f,%f,%f,%f", &scale,
&(temp_offset[0]), &(temp_offset[1]), &(temp_offset[2]),
&(adjust[PITCH]), &(adjust[YAW]), &(adjust[ROLL]));
VectorScale(temp_offset, scale, offset);
if (!cgVR->right_handed)
{
//yaw needs to go in the other direction as left handed model is reversed
adjust[YAW] *= -1.0f;
}
//Adjust angles for weapon models that aren't aligned very well
matrix4x4 m1, m2, m3;
vec3_t zero;
VectorClear(zero);
Matrix4x4_CreateFromEntity(m1, angles, zero, 1.0);
Matrix4x4_CreateFromEntity(m2, adjust, zero, 1.0);
Matrix4x4_Concat(m3, m1, m2);
Matrix4x4_ConvertToEntity(m3, angles, zero);
//Now move weapon closer to proper origin
vec3_t forward, right, up;
AngleVectors( angles, forward, right, up );
VectorMA( hand.origin, offset[2], forward, hand.origin );
VectorMA( hand.origin, offset[1], up, hand.origin );
if (cgVR->right_handed) {
VectorMA(hand.origin, offset[0], right, hand.origin);
} else {
VectorMA(hand.origin, -offset[0], right, hand.origin);
}
}
}
//Move gun a bit
VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin ); VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin ); VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin ); VectorMA( hand.origin, cg_gun_z.value, cg.refdef.viewaxis[2], hand.origin );
AnglesToAxis( angles, hand.axis ); AnglesToAxis( angles, hand.axis );
@ -1435,8 +1755,39 @@ void CG_AddViewWeapon( playerState_t *ps ) {
hand.hModel = weapon->handsModel; hand.hModel = weapon->handsModel;
hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT; hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;
//scale the whole model
for ( int i = 0; i < 3; i++ ) {
VectorScale( hand.axis[i], cgVR->right_handed || i != 1 ? scale : -scale, hand.axis[i] );
}
// add everything onto the hand // add everything onto the hand
CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] ); CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->persistant[PERS_TEAM] );
//Weapon offset debugging
if (qfalse)
{
vec3_t _origin;
vec3_t endForward, endRight, endUp;
vec3_t _angles;
clientInfo_t ci;
CG_CalculateVRWeaponPosition( _origin, _angles );
vec3_t forward, right, up;
AngleVectors(_angles, forward, right, up);
VectorMA(_origin, 60, forward, endForward);
VectorSet(ci.color1, 1, 0, 0); // Forward is red
CG_RailTrail2(&ci, _origin, endForward);
VectorMA(_origin, 30, right, endRight);
VectorSet(ci.color1, 0, 1, 0); // right is green
CG_RailTrail2(&ci, _origin, endRight);
VectorMA(_origin, 30, up, endUp);
VectorSet(ci.color1, 0, 0, 1); // up is blue
CG_RailTrail2(&ci, _origin, endUp);
}
} }
/* /*

View file

@ -24,12 +24,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "client.h" #include "client.h"
#include "../botlib/botlib.h" #include "../botlib/botlib.h"
#include "../vr/vr_clientinfo.h"
#ifdef USE_MUMBLE #ifdef USE_MUMBLE
#include "libmumblelink.h" #include "libmumblelink.h"
#endif #endif
extern botlib_export_t *botlib_export; extern botlib_export_t *botlib_export;
extern vr_clientinfo_t vr;
extern qboolean loadCamera(const char *name); extern qboolean loadCamera(const char *name);
extern void startCamera(int time); extern void startCamera(int time);
@ -53,6 +55,16 @@ void CL_GetGlconfig( glconfig_t *glconfig ) {
*glconfig = cls.glconfig; *glconfig = cls.glconfig;
} }
/*
=====================
CL_CGameRendering
=====================
*/
void CL_CGameSetVRClientInfo() {
long val = (long)(&vr);
int *ptr = (int*)(&val); //HACK!!
VM_Call( cgvm, CG_SET_VR_CLIENT_INFO, ptr[0], ptr[1] );
}
/* /*
==================== ====================

View file

@ -23,9 +23,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "client.h" #include "client.h"
#include "../vr/vr_input.h"
#include "../vr/vr_clientinfo.h"
unsigned frame_msec; unsigned frame_msec;
int old_com_frameTime; int old_com_frameTime;
extern vr_clientinfo_t vr;
/* /*
=============================================================================== ===============================================================================
@ -290,7 +295,7 @@ Moves the local angle positions
================ ================
*/ */
void CL_AdjustAngles( void ) { void CL_AdjustAngles( void ) {
float speed; /* float speed;
if ( in_speed.active ) { if ( in_speed.active ) {
speed = 0.001 * cls.frametime * cl_anglespeedkey->value; speed = 0.001 * cls.frametime * cl_anglespeedkey->value;
@ -305,6 +310,17 @@ void CL_AdjustAngles( void ) {
cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup); cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown); cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
*/
cl.viewangles[YAW] -= vr.hmdorientation_delta[YAW];
//Make angles good
while (cl.viewangles[YAW] > 180.0f)
cl.viewangles[YAW] -= 360.0f;
while (cl.viewangles[YAW] < -180.0f)
cl.viewangles[YAW] += 360.0f;
cl.viewangles[PITCH] = vr.hmdorientation[PITCH];
cl.viewangles[ROLL] = vr.hmdorientation[ROLL];
} }
/* /*
@ -354,6 +370,17 @@ void CL_KeyMove( usercmd_t *cmd ) {
cmd->upmove = ClampChar( up ); cmd->upmove = ClampChar( up );
} }
void CL_SnapTurn( int dxYaw )
{
cl.viewangles[YAW] -= dxYaw;
//Make angles good
while (cl.viewangles[YAW] > 180.0f)
cl.viewangles[YAW] -= 360.0f;
while (cl.viewangles[YAW] < -180.0f)
cl.viewangles[YAW] += 360.0f;
}
/* /*
================= =================
CL_MouseEvent CL_MouseEvent
@ -554,6 +581,7 @@ void CL_CmdButtons( usercmd_t *cmd ) {
CL_FinishMove CL_FinishMove
============== ==============
*/ */
void rotateAboutOrigin(float x, float y, float rotation, vec2_t out);
void CL_FinishMove( usercmd_t *cmd ) { void CL_FinishMove( usercmd_t *cmd ) {
int i; int i;
@ -564,8 +592,26 @@ void CL_FinishMove( usercmd_t *cmd ) {
// can be determined without allowing cheating // can be determined without allowing cheating
cmd->serverTime = cl.serverTime; cmd->serverTime = cl.serverTime;
for (i=0 ; i<3 ; i++) { //If we are running with a remote non-vr server, then the best we can do is pass the angles from the weapon
cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]); //and adjust the move values accordingly, to "fake" a 3DoF weapon but keeping the movement correct
if ( !com_sv_running || !com_sv_running->integer )
{
vec3_t angles;
VectorCopy(vr.weaponangles, angles);
angles[YAW] += cl.viewangles[YAW];
for (i = 0; i < 3; i++) {
cmd->angles[i] = ANGLE2SHORT(angles[i]);
}
vec3_t out;
rotateAboutOrigin(cmd->rightmove, cmd->forwardmove, cl.viewangles[YAW], out);
cmd->rightmove = out[0];
cmd->forwardmove = out[1];
}
else {
for (i = 0; i < 3; i++) {
cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
}
} }
} }
@ -602,9 +648,9 @@ usercmd_t CL_CreateCmd( void ) {
cl.viewangles[PITCH] = oldAngles[PITCH] + 90; cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
} else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) { } else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {
cl.viewangles[PITCH] = oldAngles[PITCH] - 90; cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
} }
// store out the final values // store out the final values
CL_FinishMove( &cmd ); CL_FinishMove( &cmd );
// draw debug graphs of turning for mouse testing // draw debug graphs of turning for mouse testing
@ -1000,6 +1046,8 @@ void CL_InitInput( void ) {
cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0); cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0); cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
IN_VRInit();
} }
/* /*

View file

@ -3544,7 +3544,7 @@ void CL_Init( void ) {
cl_packetdup = Cvar_Get ("cl_packetdup", "1", CVAR_ARCHIVE ); cl_packetdup = Cvar_Get ("cl_packetdup", "1", CVAR_ARCHIVE );
cl_run = Cvar_Get ("cl_run", "1", CVAR_ARCHIVE); cl_run = Cvar_Get ("cl_run", "1", CVAR_ARCHIVE);
cl_sensitivity = Cvar_Get ("sensitivity", "5", CVAR_ARCHIVE); cl_sensitivity = Cvar_Get ("sensitivity", "8", CVAR_ARCHIVE);
cl_mouseAccel = Cvar_Get ("cl_mouseAccel", "0", CVAR_ARCHIVE); cl_mouseAccel = Cvar_Get ("cl_mouseAccel", "0", CVAR_ARCHIVE);
cl_freelook = Cvar_Get( "cl_freelook", "1", CVAR_ARCHIVE ); cl_freelook = Cvar_Get( "cl_freelook", "1", CVAR_ARCHIVE );
@ -3590,8 +3590,8 @@ void CL_Init( void ) {
j_pitch = Cvar_Get ("j_pitch", "0.022", CVAR_ARCHIVE); j_pitch = Cvar_Get ("j_pitch", "0.022", CVAR_ARCHIVE);
j_yaw = Cvar_Get ("j_yaw", "-0.022", CVAR_ARCHIVE); j_yaw = Cvar_Get ("j_yaw", "-0.022", CVAR_ARCHIVE);
j_forward = Cvar_Get ("j_forward", "-0.25", CVAR_ARCHIVE); j_forward = Cvar_Get ("j_forward", "1.0", CVAR_ARCHIVE);
j_side = Cvar_Get ("j_side", "0.25", CVAR_ARCHIVE); j_side = Cvar_Get ("j_side", "1.0", CVAR_ARCHIVE);
j_up = Cvar_Get ("j_up", "0", CVAR_ARCHIVE); j_up = Cvar_Get ("j_up", "0", CVAR_ARCHIVE);
j_pitch_axis = Cvar_Get ("j_pitch_axis", "3", CVAR_ARCHIVE); j_pitch_axis = Cvar_Get ("j_pitch_axis", "3", CVAR_ARCHIVE);
@ -3618,7 +3618,7 @@ void CL_Init( void ) {
cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE); cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE);
// userinfo // userinfo
Cvar_Get ("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("name", "VR_Player", CVAR_USERINFO | CVAR_ARCHIVE );
cl_rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE ); cl_rate = Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE );
Cvar_Get ("model", "sarge", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("model", "sarge", CVAR_USERINFO | CVAR_ARCHIVE );

View file

@ -514,6 +514,7 @@ void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
break; break;
case CA_LOADING: case CA_LOADING:
case CA_PRIMED: case CA_PRIMED:
CL_CGameSetVRClientInfo();
// draw the game information screen and loading progress // draw the game information screen and loading progress
CL_CGameRendering(stereoFrame); CL_CGameRendering(stereoFrame);
@ -524,6 +525,7 @@ void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qtrue ); VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qtrue );
break; break;
case CA_ACTIVE: case CA_ACTIVE:
CL_CGameSetVRClientInfo();
// always supply STEREO_CENTER as vieworg offset is now done by the engine. // always supply STEREO_CENTER as vieworg offset is now done by the engine.
CL_CGameRendering(stereoFrame); CL_CGameRendering(stereoFrame);
SCR_DrawDemoRecording(); SCR_DrawDemoRecording();

View file

@ -507,6 +507,8 @@ void CL_ReadPackets (void);
void CL_WritePacket( void ); void CL_WritePacket( void );
void IN_CenterView (void); void IN_CenterView (void);
void CL_CGameSetVRClientInfo();
void CL_VerifyCode( void ); void CL_VerifyCode( void );
float CL_KeyState (kbutton_t *key); float CL_KeyState (kbutton_t *key);

View file

@ -35,12 +35,12 @@ float pm_stopspeed = 100.0f;
float pm_duckScale = 0.25f; float pm_duckScale = 0.25f;
float pm_swimScale = 0.50f; float pm_swimScale = 0.50f;
float pm_accelerate = 10.0f; float pm_accelerate = 1000.0f;
float pm_airaccelerate = 1.0f; float pm_airaccelerate = 1.0f;
float pm_wateraccelerate = 4.0f; float pm_wateraccelerate = 4.0f;
float pm_flyaccelerate = 8.0f; float pm_flyaccelerate = 8.0f;
float pm_friction = 6.0f; float pm_friction = 10.0f;
float pm_waterfriction = 1.0f; float pm_waterfriction = 1.0f;
float pm_flightfriction = 3.0f; float pm_flightfriction = 3.0f;
float pm_spectatorfriction = 5.0f; float pm_spectatorfriction = 5.0f;
@ -1807,7 +1807,8 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
// circularly clamp the angles with deltas // circularly clamp the angles with deltas
for (i=0 ; i<3 ; i++) { for (i=0 ; i<3 ; i++) {
temp = cmd->angles[i] + ps->delta_angles[i]; //temp = cmd->angles[i] + ps->delta_angles[i];
temp = cmd->angles[i] + (i == YAW ? ps->delta_angles[i] : 0);
if ( i == PITCH ) { if ( i == PITCH ) {
// don't let the player look up or down more than 90 degrees // don't let the player look up or down more than 90 degrees
if ( temp > 16000 ) { if ( temp > 16000 ) {

View file

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// //
#include "g_local.h" #include "g_local.h"
#include "../vr/vr_clientinfo.h"
level_locals_t level; level_locals_t level;
@ -38,6 +39,8 @@ typedef struct {
gentity_t g_entities[MAX_GENTITIES]; gentity_t g_entities[MAX_GENTITIES];
gclient_t g_clients[MAX_CLIENTS]; gclient_t g_clients[MAX_CLIENTS];
vr_clientinfo_t* gVR;
vmCvar_t g_gametype; vmCvar_t g_gametype;
vmCvar_t g_dmflags; vmCvar_t g_dmflags;
vmCvar_t g_fraglimit; vmCvar_t g_fraglimit;
@ -231,6 +234,11 @@ Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, i
return ConsoleCommand(); return ConsoleCommand();
case BOTAI_START_FRAME: case BOTAI_START_FRAME:
return BotAIStartFrame( arg0 ); return BotAIStartFrame( arg0 );
case GAME_SET_VR_CLIENT_INFO: {
int ptr[2] = {arg0, arg1};
gVR = (vr_clientinfo_t *) (*(long*)(ptr));
return 0;
}
} }
return -1; return -1;

View file

@ -425,6 +425,8 @@ typedef enum {
// The game can issue trap_argc() / trap_argv() commands to get the command // The game can issue trap_argc() / trap_argv() commands to get the command
// and parameters. Return qfalse if the game doesn't recognize it as a command. // and parameters. Return qfalse if the game doesn't recognize it as a command.
BOTAI_START_FRAME // ( int time ); BOTAI_START_FRAME, // ( int time );
GAME_SET_VR_CLIENT_INFO
} gameExport_t; } gameExport_t;

View file

@ -25,12 +25,43 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "g_local.h" #include "g_local.h"
#include "../vr/vr_clientinfo.h"
static float s_quadFactor; static float s_quadFactor;
static vec3_t forward, right, up; static vec3_t forward, right, up;
static vec3_t muzzle; static vec3_t muzzle;
extern vr_clientinfo_t* gVR;
#define NUM_NAILSHOTS 15 #define NUM_NAILSHOTS 15
void rotateAboutOrigin(float x, float y, float rotation, vec2_t out)
{
out[0] = cosf(DEG2RAD(-rotation)) * x + sinf(DEG2RAD(-rotation)) * y;
out[1] = cosf(DEG2RAD(-rotation)) * y - sinf(DEG2RAD(-rotation)) * x;
}
void convertFromVR(gentity_t *ent, vec3_t in, vec3_t offset, vec3_t out)
{
vec3_t vrSpace;
VectorSet(vrSpace, in[2], in[0], in[1] );
vec2_t r;
rotateAboutOrigin(vrSpace[0], vrSpace[1], ent->client->ps.viewangles[YAW] - gVR->hmdorientation[YAW], r);
vrSpace[0] = -r[0];
vrSpace[1] = -r[1];
vec3_t temp;
VectorScale(vrSpace, WORLD_SCALE, temp);
if (offset) {
VectorAdd(temp, offset, out);
} else {
VectorCopy(temp, out);
}
}
/* /*
================ ================
G_BounceProjectile G_BounceProjectile
@ -770,9 +801,19 @@ set muzzle location relative to pivoting eye
=============== ===============
*/ */
void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) { void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
VectorCopy( ent->s.pos.trBase, muzzlePoint ); if ( ( ent->r.svFlags & SVF_BOT ) )
muzzlePoint[2] += ent->client->ps.viewheight; {
VectorMA( muzzlePoint, 14, forward, muzzlePoint ); VectorCopy( ent->s.pos.trBase, muzzlePoint );
muzzlePoint[2] += ent->client->ps.viewheight;
VectorMA( muzzlePoint, 14, forward, muzzlePoint );
}
else if (gVR != NULL)
{
convertFromVR(ent, gVR->calculated_weaponoffset, ent->r.currentOrigin, muzzlePoint);
muzzlePoint[2] -= ent->client->ps.viewheight;
muzzlePoint[2] += gVR->hmdposition[1] * WORLD_SCALE;
}
// snap to integer coordinates for more efficient network bandwidth usage // snap to integer coordinates for more efficient network bandwidth usage
SnapVector( muzzlePoint ); SnapVector( muzzlePoint );
} }
@ -785,11 +826,7 @@ set muzzle location relative to pivoting eye
=============== ===============
*/ */
void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) { void CalcMuzzlePointOrigin ( gentity_t *ent, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) {
VectorCopy( ent->s.pos.trBase, muzzlePoint ); CalcMuzzlePoint(ent, forward, right, up, muzzlePoint);
muzzlePoint[2] += ent->client->ps.viewheight;
VectorMA( muzzlePoint, 14, forward, muzzlePoint );
// snap to integer coordinates for more efficient network bandwidth usage
SnapVector( muzzlePoint );
} }
@ -824,8 +861,19 @@ void FireWeapon( gentity_t *ent ) {
#endif #endif
} }
vec3_t viewang;
if ( !( ent->r.svFlags & SVF_BOT ) && gVR != NULL)
{
VectorCopy(gVR->weaponangles, viewang);
viewang[YAW] += ent->client->ps.viewangles[YAW] - gVR->hmdorientation[YAW];
}
else
{
VectorCopy( ent->client->ps.viewangles, viewang );
}
// set aiming directions // set aiming directions
AngleVectors (ent->client->ps.viewangles, forward, right, up); AngleVectors (viewang, forward, right, up);
CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle ); CalcMuzzlePointOrigin ( ent, ent->client->oldOrigin, forward, right, up, muzzle );

View file

@ -368,6 +368,8 @@ typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4]; typedef vec_t vec4_t[4];
typedef vec_t vec5_t[5]; typedef vec_t vec5_t[5];
typedef vec_t matrix4x4[4][4];
typedef vec_t quat_t[4]; typedef vec_t quat_t[4];
typedef int fixed4_t; typedef int fixed4_t;

View file

@ -991,6 +991,8 @@ void CL_KeyEvent (int key, qboolean down, unsigned time);
void CL_CharEvent( int key ); void CL_CharEvent( int key );
// char events are for field typing, not game control // char events are for field typing, not game control
void CL_SnapTurn(int dx);
void CL_MouseEvent( int dx, int dy, int time ); void CL_MouseEvent( int dx, int dy, int time );
void CL_JoystickEvent( int axis, int value, int time ); void CL_JoystickEvent( int axis, int value, int time );

View file

@ -276,7 +276,7 @@ void GL_SetProjectionMatrix(mat4_t matrix)
void GL_SetModelviewMatrix(mat4_t matrix, qboolean applyStereoView) void GL_SetModelviewMatrix(mat4_t matrix, qboolean applyStereoView)
{ {
if (applyStereoView) if (qfalse) //applyStereoView)
{ {
if (tr.refdef.stereoFrame == STEREO_LEFT) { if (tr.refdef.stereoFrame == STEREO_LEFT) {
Mat4Multiply(tr.vrParms.viewL, matrix, glState.modelview); Mat4Multiply(tr.vrParms.viewL, matrix, glState.modelview);

View file

@ -573,7 +573,7 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
backEnd.pc.msec = 0; backEnd.pc.msec = 0;
} }
#if __ANDROID__ //#if __ANDROID__
void R_Mat4Transpose( const float in[4][4], float* out ) { void R_Mat4Transpose( const float in[4][4], float* out ) {
int i, j; int i, j;
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
@ -583,14 +583,17 @@ void R_Mat4Transpose( const float in[4][4], float* out ) {
} }
} }
void RE_SetVRHeadsetParms( const ovrTracking2* tracking, int renderBufferL, int renderBufferR ) { void RE_SetVRHeadsetParms( const ovrTracking2* tracking, int renderBufferL, int renderBufferR ) {
if (tracking) { if (tracking) {
R_Mat4Transpose(tracking->Eye[0].ProjectionMatrix.M, tr.vrParms.projectionL); R_Mat4Transpose(tracking->Eye[0].ProjectionMatrix.M, tr.vrParms.projectionL);
R_Mat4Transpose(tracking->Eye[1].ProjectionMatrix.M, tr.vrParms.projectionR); R_Mat4Transpose(tracking->Eye[1].ProjectionMatrix.M, tr.vrParms.projectionR);
/*
R_Mat4Transpose(tracking->Eye[0].ViewMatrix.M, tr.vrParms.viewL); R_Mat4Transpose(tracking->Eye[0].ViewMatrix.M, tr.vrParms.viewL);
R_Mat4Transpose(tracking->Eye[1].ViewMatrix.M, tr.vrParms.viewR); R_Mat4Transpose(tracking->Eye[1].ViewMatrix.M, tr.vrParms.viewR);
const float worldToMeter = 25.0f; // https://quakewiki.org/wiki/unit, assume 25 units is 1 meter. const float worldToMeter = 37.0f; // https://quakewiki.org/wiki/unit, assume 25 units is 1 meter.
tr.vrParms.viewL[12] *= worldToMeter; tr.vrParms.viewL[12] *= worldToMeter;
tr.vrParms.viewL[13] *= worldToMeter; tr.vrParms.viewL[13] *= worldToMeter;
tr.vrParms.viewL[14] *= worldToMeter; tr.vrParms.viewL[14] *= worldToMeter;
@ -598,6 +601,8 @@ void RE_SetVRHeadsetParms( const ovrTracking2* tracking, int renderBufferL, int
tr.vrParms.viewR[13] *= worldToMeter; tr.vrParms.viewR[13] *= worldToMeter;
tr.vrParms.viewR[14] *= worldToMeter; tr.vrParms.viewR[14] *= worldToMeter;
*/
tr.vrParms.renderBufferL = renderBufferL; tr.vrParms.renderBufferL = renderBufferL;
tr.vrParms.renderBufferR = renderBufferR; tr.vrParms.renderBufferR = renderBufferR;
@ -606,7 +611,7 @@ void RE_SetVRHeadsetParms( const ovrTracking2* tracking, int renderBufferL, int
tr.vrParms.valid = qfalse; tr.vrParms.valid = qfalse;
} }
} }
#endif //#endif
/* /*
============= =============

View file

@ -34,6 +34,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../renderercommon/tr_common.h" #include "../renderercommon/tr_common.h"
#include "../sys/sys_local.h" #include "../sys/sys_local.h"
#include "sdl_icon.h" #include "sdl_icon.h"
#include "../vr/vr_renderer.h"
typedef enum typedef enum
{ {
@ -429,8 +430,11 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool
ri.Printf (PRINT_ALL, "...setting mode %d:", mode ); ri.Printf (PRINT_ALL, "...setting mode %d:", mode );
VR_GetRsolution(0, &glConfig.vidWidth, &glConfig.vidHeight);
/*
if (mode == -2) if (mode == -2)
{ {
// use desktop video resolution // use desktop video resolution
if( desktopMode.h > 0 ) if( desktopMode.h > 0 )
{ {
@ -444,6 +448,7 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool
ri.Printf( PRINT_ALL, ri.Printf( PRINT_ALL,
"Cannot determine display resolution, assuming 640x480\n" ); "Cannot determine display resolution, assuming 640x480\n" );
} }
glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight; glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight;
} }
@ -452,6 +457,7 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qbool
ri.Printf( PRINT_ALL, " invalid mode\n" ); ri.Printf( PRINT_ALL, " invalid mode\n" );
return RSERR_INVALID_MODE; return RSERR_INVALID_MODE;
} }
*/
ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight); ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
// Center window // Center window

View file

@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "server.h" #include "server.h"
#include "../vr/vr_clientinfo.h"
#ifdef USE_VOIP #ifdef USE_VOIP
cvar_t *sv_voip; cvar_t *sv_voip;
@ -30,6 +31,7 @@ cvar_t *sv_voipProtocol;
serverStatic_t svs; // persistant server info serverStatic_t svs; // persistant server info
server_t sv; // local server server_t sv; // local server
vm_t *gvm = NULL; // game virtual machine vm_t *gvm = NULL; // game virtual machine
extern vr_clientinfo_t vr;
cvar_t *sv_fps = NULL; // time rate for running non-clients cvar_t *sv_fps = NULL; // time rate for running non-clients
cvar_t *sv_timeout; // seconds without any message cvar_t *sv_timeout; // seconds without any message
@ -1128,6 +1130,11 @@ void SV_Frame( int msec ) {
startTime = 0; // quite a compiler warning startTime = 0; // quite a compiler warning
} }
//Ensure the game library has our VR client info
long val = (long)(&vr);
int *ptr = (int*)(&val); //HACK!!
VM_Call( gvm, GAME_SET_VR_CLIENT_INFO, ptr[0], ptr[1] );
// update ping based on the all received frames // update ping based on the all received frames
SV_CalcPings(); SV_CalcPings();

View file

@ -1,11 +1,14 @@
#include "vr_base.h" #include "vr_base.h"
#include "VrApi_Types.h" #include "../VrApi/Include/VrApi_Types.h"
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "../client/client.h"
#if __ANDROID__ //#if __ANDROID__
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes" #pragma clang diagnostic ignored "-Wstrict-prototypes"
#include <VrApi_Helpers.h> #include "../VrApi/Include/VrApi_Helpers.h"
#pragma clang diagnostic pop #pragma clang diagnostic pop
#include <EGL/egl.h> #include <EGL/egl.h>
@ -24,6 +27,8 @@ engine_t* VR_Init( ovrJava java )
initParams = vrapi_DefaultInitParms(&java); initParams = vrapi_DefaultInitParms(&java);
initResult = vrapi_Initialize(&initParams); initResult = vrapi_Initialize(&initParams);
assert(initResult == VRAPI_INITIALIZE_SUCCESS); assert(initResult == VRAPI_INITIALIZE_SUCCESS);
vr_engine.java = java;
return &vr_engine; return &vr_engine;
} }
@ -45,7 +50,7 @@ void VR_EnterVR( engine_t* engine, ovrJava java ) {
engine->ovr = vrapi_EnterVrMode(&modeParams); engine->ovr = vrapi_EnterVrMode(&modeParams);
engine->frameIndex = 0; engine->frameIndex = 0;
vrapi_SetTrackingSpace(engine->ovr, VRAPI_TRACKING_SPACE_LOCAL); vrapi_SetTrackingSpace(engine->ovr, VRAPI_TRACKING_SPACE_LOCAL_FLOOR);
} }
} }
@ -59,4 +64,11 @@ void VR_LeaveVR( engine_t* engine ) {
engine_t* VR_GetEngine( void ) { engine_t* VR_GetEngine( void ) {
return &vr_engine; return &vr_engine;
} }
#endif
bool VR_useScreenLayer( void )
{
return (bool)(clc.state != CA_ACTIVE ||
( Key_GetCatcher( ) & KEYCATCH_UI ) ||
( Key_GetCatcher( ) & KEYCATCH_CONSOLE ));
}
//#endif

View file

@ -5,12 +5,16 @@
#include "vr_types.h" #include "vr_types.h"
#define WORLD_SCALE 37.5f
#define PLAYER_HEIGHT 48
engine_t* VR_Init( ovrJava java ); engine_t* VR_Init( ovrJava java );
void VR_Destroy( engine_t* engine ); void VR_Destroy( engine_t* engine );
void VR_EnterVR( engine_t* engine, ovrJava java ); void VR_EnterVR( engine_t* engine, ovrJava java );
void VR_LeaveVR( engine_t* engine ); void VR_LeaveVR( engine_t* engine );
engine_t* VR_GetEngine( void ); engine_t* VR_GetEngine( void );
bool VR_useScreenLayer( void );
#endif #endif

50
code/vr/vr_clientinfo.h Normal file
View file

@ -0,0 +1,50 @@
#if !defined(vr_clientinfo_h)
#define vr_clientinfo_h
#include "vr_base.h"
#define NUM_WEAPON_SAMPLES 10
#define WEAPON_RECOIL 15.0f;
typedef struct {
qboolean weapon_stabilised;
qboolean right_handed;
qboolean player_moving;
qboolean visible_hud;
qboolean dualwield;
int weaponid;
int lastweaponid;
vec3_t hmdposition;
vec3_t hmdposition_last; // Don't use this, it is just for calculating delta!
vec3_t hmdposition_delta;
vec3_t hmdorientation;
vec3_t hmdorientation_last; // Don't use this, it is just for calculating delta!
vec3_t hmdorientation_delta;
vec3_t weaponangles;
vec3_t weaponangles_last; // Don't use this, it is just for calculating delta!
vec3_t weaponangles_delta;
vec3_t current_weaponoffset;
vec3_t calculated_weaponoffset;
float current_weaponoffset_timestamp;
vec3_t weaponoffset_history[NUM_WEAPON_SAMPLES];
float weaponoffset_history_timestamp[NUM_WEAPON_SAMPLES];
vec3_t offhandangles;
vec3_t offhandoffset;
//////////////////////////////////////
// Test stuff for weapon alignment
//////////////////////////////////////
char test_name[256];
float test_scale;
vec3_t test_angles;
vec3_t test_offset;
} vr_clientinfo_t;
#endif //vr_clientinfo_h

View file

@ -1,12 +1,15 @@
#include "vr_input.h" #include "vr_input.h"
#if __ANDROID__ //#if __ANDROID__
#include "../qcommon/q_shared.h" #include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h" #include "../qcommon/qcommon.h"
#include "../client/keycodes.h" #include "../client/keycodes.h"
#include "vr_base.h" #include "vr_base.h"
#include "VrApi_Input.h" #include "../VrApi/Include/VrApi_Input.h"
#include "../VrApi/Include/VrApi_Helpers.h"
#include "vr_clientinfo.h"
#ifdef USE_LOCAL_HEADERS #ifdef USE_LOCAL_HEADERS
# include "SDL.h" # include "SDL.h"
@ -27,6 +30,8 @@ typedef struct {
uint32_t axisButtons; uint32_t axisButtons;
} vrController_t; } vrController_t;
vr_clientinfo_t vr;
static qboolean controllerInit = qfalse; static qboolean controllerInit = qfalse;
static vrController_t leftController; static vrController_t leftController;
@ -40,49 +45,261 @@ extern cvar_t *cl_sensitivity;
extern cvar_t *m_pitch; extern cvar_t *m_pitch;
extern cvar_t *m_yaw; extern cvar_t *m_yaw;
cvar_t *vr_righthanded;
cvar_t *vr_snapturn;
float radians(float deg) {
return (deg * M_PI) / 180.0;
}
float degrees(float rad) {
return (rad * 180.0) / M_PI;
}
#ifndef EPSILON
#define EPSILON 0.001f
#endif
void rotateAboutOrigin(float x, float y, float rotation, vec2_t out)
{
out[0] = cosf(DEG2RAD(-rotation)) * x + sinf(DEG2RAD(-rotation)) * y;
out[1] = cosf(DEG2RAD(-rotation)) * y - sinf(DEG2RAD(-rotation)) * x;
}
static ovrVector3f normalizeVec(ovrVector3f 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;
//@@if(xxyyzz < EPSILON)
//@@ return *this; // do nothing if it is zero vector
//float invLength = invSqrt(xxyyzz);
ovrVector3f result;
float invLength = 1.0f / sqrtf(xxyyzz);
result.x = vec.x * invLength;
result.y = vec.y * invLength;
result.z = vec.z * invLength;
return result;
}
void NormalizeAngles(vec3_t angles)
{
while (angles[0] >= 90) angles[0] -= 180;
while (angles[1] >= 180) angles[1] -= 360;
while (angles[2] >= 180) angles[2] -= 360;
while (angles[0] < -90) angles[0] += 180;
while (angles[1] < -180) angles[1] += 360;
while (angles[2] < -180) angles[2] += 360;
}
void GetAnglesFromVectors(const ovrVector3f forward, const ovrVector3f right, const ovrVector3f up, vec3_t angles)
{
float sr, sp, sy, cr, cp, cy;
sp = -forward.z;
float cp_x_cy = forward.x;
float cp_x_sy = forward.y;
float cp_x_sr = -right.z;
float cp_x_cr = up.z;
float yaw = atan2(cp_x_sy, cp_x_cy);
float roll = atan2(cp_x_sr, cp_x_cr);
cy = cos(yaw);
sy = sin(yaw);
cr = cos(roll);
sr = sin(roll);
if (fabs(cy) > EPSILON)
{
cp = cp_x_cy / cy;
}
else if (fabs(sy) > EPSILON)
{
cp = cp_x_sy / sy;
}
else if (fabs(sr) > EPSILON)
{
cp = cp_x_sr / sr;
}
else if (fabs(cr) > EPSILON)
{
cp = cp_x_cr / cr;
}
else
{
cp = cos(asin(sp));
}
float pitch = atan2(sp, cp);
angles[0] = pitch / (M_PI*2.f / 360.f);
angles[1] = yaw / (M_PI*2.f / 360.f);
angles[2] = roll / (M_PI*2.f / 360.f);
NormalizeAngles(angles);
}
void QuatToYawPitchRoll(ovrQuatf q, vec3_t rotation, vec3_t out) {
ovrMatrix4f mat = ovrMatrix4f_CreateFromQuaternion( &q );
if (rotation[0] != 0.0f || rotation[1] != 0.0f || rotation[2] != 0.0f)
{
ovrMatrix4f rot = ovrMatrix4f_CreateRotation(radians(rotation[0]), radians(rotation[1]), radians(rotation[2]));
mat = ovrMatrix4f_Multiply(&mat, &rot);
}
ovrVector4f v1 = {0, 0, -1, 0};
ovrVector4f v2 = {1, 0, 0, 0};
ovrVector4f v3 = {0, 1, 0, 0};
ovrVector4f forwardInVRSpace = ovrVector4f_MultiplyMatrix4f(&mat, &v1);
ovrVector4f rightInVRSpace = ovrVector4f_MultiplyMatrix4f(&mat, &v2);
ovrVector4f upInVRSpace = ovrVector4f_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};
ovrVector3f forwardNormal = normalizeVec(forward);
ovrVector3f rightNormal = normalizeVec(right);
ovrVector3f upNormal = normalizeVec(up);
GetAnglesFromVectors(forwardNormal, rightNormal, upNormal, out);
}
void sendButtonActionSimple(const char* action)
{
char command[256];
snprintf( command, sizeof( command ), "%s\n", action );
Cbuf_AddText( command );
}
void IN_VRInit( void )
{
vr_righthanded = Cvar_Get ("vr_righthanded", "1", CVAR_ARCHIVE);
vr_snapturn = Cvar_Get ("vr_snapturn", "1", CVAR_ARCHIVE);
Cvar_Get ("vr_weapon_adjustment_1", "0.8,0,0,0,0,0,0", CVAR_ARCHIVE);
Cvar_Get ("vr_weapon_adjustment_2", "0.8,0,0,0,0,0,0", CVAR_ARCHIVE);
Cvar_Get ("vr_weapon_adjustment_3", "0.8,0,0,0,0,0,0", CVAR_ARCHIVE);
}
static void IN_VRController( qboolean isRightController, ovrTracking remoteTracking )
{
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] =-20.0f;
QuatToYawPitchRoll(remoteTracking.HeadPose.Pose.Orientation, rotation, vr.weaponangles);
VectorSubtract(vr.weaponangles_last, vr.weaponangles, vr.weaponangles_delta);
VectorCopy(vr.weaponangles, vr.weaponangles_last);
//Record recent weapon position for trajectory based stuff
for (int i = (NUM_WEAPON_SAMPLES-1); i != 0; --i)
{
VectorCopy(vr.weaponoffset_history[i-1], vr.weaponoffset_history[i]);
vr.weaponoffset_history_timestamp[i] = vr.weaponoffset_history_timestamp[i-1];
}
VectorCopy(vr.current_weaponoffset, vr.weaponoffset_history[0]);
vr.weaponoffset_history_timestamp[0] = vr.current_weaponoffset_timestamp;
///Weapon location relative to view
vr.current_weaponoffset[0] = remoteTracking.HeadPose.Pose.Position.x - vr.hmdposition[0];
vr.current_weaponoffset[1] = remoteTracking.HeadPose.Pose.Position.y - vr.hmdposition[1];
vr.current_weaponoffset[2] = remoteTracking.HeadPose.Pose.Position.z - vr.hmdposition[2];
vr.current_weaponoffset_timestamp = Sys_Milliseconds( );
//Just copy to calculated offset, used to use this in case we wanted to apply any modifiers, but don't any more
VectorCopy(vr.current_weaponoffset, vr.calculated_weaponoffset);
}
}
static void IN_VRJoystick( qboolean isRightController, float joystickX, float joystickY ) static void IN_VRJoystick( qboolean isRightController, float joystickX, float joystickY )
{ {
vrController_t* controller = isRightController == qtrue ? &rightController : &leftController; vrController_t* controller = isRightController == qtrue ? &rightController : &leftController;
// Menu controls mapped to keyboard codes... //Positional movement speed correction for when we are not hitting target framerate
if (isRightController == qfalse) { static double lastframetime = 0;
if (!(controller->axisButtons & VR_TOUCH_AXIS_UP) && joystickY > pressedThreshold) { int refresh = vrapi_GetSystemPropertyInt(&(VR_GetEngine()->java), VRAPI_SYS_PROP_DISPLAY_REFRESH_RATE);
controller->axisButtons |= VR_TOUCH_AXIS_UP; double newframetime = Sys_Milliseconds();
Com_QueueEvent(in_vrEventTime, SE_KEY, K_UPARROW, qtrue, 0, NULL); float multiplier = (float)((1000.0 / refresh) / (newframetime - lastframetime));
} else if ((controller->axisButtons & VR_TOUCH_AXIS_UP) && joystickY < releasedThreshold) { lastframetime = newframetime;
controller->axisButtons &= ~VR_TOUCH_AXIS_UP;
Com_QueueEvent(in_vrEventTime, SE_KEY, K_UPARROW, qfalse, 0, NULL);
}
if (!(controller->axisButtons & VR_TOUCH_AXIS_DOWN) && joystickY < -pressedThreshold) { vec2_t positional;
controller->axisButtons |= VR_TOUCH_AXIS_DOWN; float factor = (refresh / 72.0F) * 12.0f; // adjust positional factor based on refresh rate
Com_QueueEvent(in_vrEventTime, SE_KEY, K_DOWNARROW, qtrue, 0, NULL); rotateAboutOrigin(-vr.hmdposition_delta[0] * factor * multiplier,
} else if ((controller->axisButtons & VR_TOUCH_AXIS_DOWN) && joystickY > -releasedThreshold) { vr.hmdposition_delta[2] * factor * multiplier, - vr.hmdorientation[YAW], positional);
controller->axisButtons &= ~VR_TOUCH_AXIS_DOWN;
Com_QueueEvent(in_vrEventTime, SE_KEY, K_DOWNARROW, qfalse, 0, NULL);
}
if (!(controller->axisButtons & VR_TOUCH_AXIS_LEFT) && joystickX < -pressedThreshold) { if (VR_useScreenLayer())
controller->axisButtons |= VR_TOUCH_AXIS_LEFT; {
Com_QueueEvent(in_vrEventTime, SE_KEY, K_LEFTARROW, qtrue, 0, NULL); const float x = joystickX * 4.0;
} else if ((controller->axisButtons & VR_TOUCH_AXIS_LEFT) && joystickX > -releasedThreshold) { const float y = joystickY * -4.0;
controller->axisButtons &= ~VR_TOUCH_AXIS_LEFT;
Com_QueueEvent(in_vrEventTime, SE_KEY, K_LEFTARROW, qfalse, 0, NULL);
}
if (!(controller->axisButtons & VR_TOUCH_AXIS_RIGHT) && joystickX > pressedThreshold) {
controller->axisButtons |= VR_TOUCH_AXIS_RIGHT;
Com_QueueEvent(in_vrEventTime, SE_KEY, K_RIGHTARROW, qtrue, 0, NULL);
} else if ((controller->axisButtons & VR_TOUCH_AXIS_RIGHT) && joystickX < releasedThreshold) {
controller->axisButtons &= ~VR_TOUCH_AXIS_RIGHT;
Com_QueueEvent(in_vrEventTime, SE_KEY, K_RIGHTARROW, qfalse, 0, NULL);
}
} else {
const float sensitivity = cl_sensitivity->value;
const float x = joystickX * sensitivity * m_yaw->value;
const float y = joystickY * sensitivity * -m_pitch->value;
Com_QueueEvent(in_vrEventTime, SE_MOUSE, x, y, 0, NULL); Com_QueueEvent(in_vrEventTime, SE_MOUSE, x, y, 0, NULL);
} } else
{
if (isRightController == qfalse) {
//sideways
Com_QueueEvent(in_vrEventTime, SE_JOYSTICK_AXIS, 0, joystickX * 127.0f + positional[0] * 127.0f, 0, NULL);
//forward/back
Com_QueueEvent(in_vrEventTime, SE_JOYSTICK_AXIS, 1, joystickY * 127.0f + positional[1] * 127.0f, 0, NULL);
}
else //right controller
{
//yaw
if (vr_snapturn->integer)
{
if (!(controller->axisButtons & VR_TOUCH_AXIS_RIGHT) && joystickX > pressedThreshold) {
controller->axisButtons |= VR_TOUCH_AXIS_RIGHT;
CL_SnapTurn(45);
} else if ((controller->axisButtons & VR_TOUCH_AXIS_RIGHT) &&
joystickX < releasedThreshold) {
controller->axisButtons &= ~VR_TOUCH_AXIS_RIGHT;
}
if (!(controller->axisButtons & VR_TOUCH_AXIS_LEFT) && joystickX < -pressedThreshold) {
controller->axisButtons |= VR_TOUCH_AXIS_LEFT;
CL_SnapTurn(-45);
} else if ((controller->axisButtons & VR_TOUCH_AXIS_LEFT) &&
joystickX > -releasedThreshold) {
controller->axisButtons &= ~VR_TOUCH_AXIS_LEFT;
}
}
else
{
//smooth turn
const float x = joystickX * cl_sensitivity->value * m_yaw->value;
Com_QueueEvent(in_vrEventTime, SE_MOUSE, x, 0, 0, NULL);
}
if (!(controller->axisButtons & VR_TOUCH_AXIS_UP) && joystickY > pressedThreshold) {
controller->axisButtons |= VR_TOUCH_AXIS_UP;
sendButtonActionSimple("weapnext");
} else if ((controller->axisButtons & VR_TOUCH_AXIS_UP) &&
joystickY < releasedThreshold) {
controller->axisButtons &= ~VR_TOUCH_AXIS_UP;
}
if (!(controller->axisButtons & VR_TOUCH_AXIS_DOWN) && joystickY < -pressedThreshold) {
controller->axisButtons |= VR_TOUCH_AXIS_DOWN;
sendButtonActionSimple("weapprev");
} else if ((controller->axisButtons & VR_TOUCH_AXIS_DOWN) &&
joystickY > -releasedThreshold) {
controller->axisButtons &= ~VR_TOUCH_AXIS_DOWN;
}
}
}
} }
static void IN_VRTriggers( qboolean isRightController, float index ) { static void IN_VRTriggers( qboolean isRightController, float index ) {
@ -103,16 +320,25 @@ static void IN_VRButtonsChanged( qboolean isRightController, uint32_t buttons )
{ {
vrController_t* controller = isRightController == qtrue ? &rightController : &leftController; vrController_t* controller = isRightController == qtrue ? &rightController : &leftController;
if (isRightController == qfalse)
{
if ((buttons & ovrButton_Enter) && !(controller->buttons & ovrButton_Enter)) {
Com_QueueEvent(in_vrEventTime, SE_KEY, K_ESCAPE, qtrue, 0, NULL);
} else if (!(buttons & ovrButton_Enter) && (controller->buttons & ovrButton_Enter)) {
Com_QueueEvent(in_vrEventTime, SE_KEY, K_ESCAPE, qfalse, 0, NULL);
}
}
if ((buttons & ovrButton_A) && !(controller->buttons & ovrButton_A)) { if ((buttons & ovrButton_A) && !(controller->buttons & ovrButton_A)) {
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_A, qtrue, 0, NULL); Com_QueueEvent(in_vrEventTime, SE_KEY, K_SPACE, qtrue, 0, NULL);
} else if (!(buttons & ovrButton_A) && (controller->buttons & ovrButton_A)) { } else if (!(buttons & ovrButton_A) && (controller->buttons & ovrButton_A)) {
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_A, qfalse, 0, NULL); Com_QueueEvent(in_vrEventTime, SE_KEY, K_SPACE, qfalse, 0, NULL);
} }
if ((buttons & ovrButton_B) && !(controller->buttons & ovrButton_B)) { if ((buttons & ovrButton_B) && !(controller->buttons & ovrButton_B)) {
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_B, qtrue, 0, NULL); Com_QueueEvent(in_vrEventTime, SE_KEY, K_ENTER, qtrue, 0, NULL);
} else if (!(buttons & ovrButton_B) && (controller->buttons & ovrButton_B)) { } else if (!(buttons & ovrButton_B) && (controller->buttons & ovrButton_B)) {
Com_QueueEvent(in_vrEventTime, SE_KEY, K_PAD0_B, qfalse, 0, NULL); Com_QueueEvent(in_vrEventTime, SE_KEY, K_ENTER, qfalse, 0, NULL);
} }
if ((buttons & ovrButton_X) && !(controller->buttons & ovrButton_B)) { if ((buttons & ovrButton_X) && !(controller->buttons & ovrButton_B)) {
@ -143,6 +369,32 @@ void IN_VRInputFrame( void )
return; return;
} }
double predictedDisplayTime = vrapi_GetPredictedDisplayTime(ovr, VR_GetEngine()->frameIndex);
{
// We extract Yaw, Pitch, Roll instead of directly using the orientation
// to allow "additional" yaw manipulation with mouse/controller.
ovrTracking2 tracking = vrapi_GetPredictedTracking2(VR_GetEngine()->ovr, predictedDisplayTime);
const ovrQuatf quatHmd = tracking.HeadPose.Pose.Orientation;
const ovrVector3f positionHmd = tracking.HeadPose.Pose.Position;
vec3_t rotation = {0, 0, 0};
QuatToYawPitchRoll(quatHmd, rotation, vr.hmdorientation);
VectorSet(vr.hmdposition, positionHmd.x, positionHmd.y, 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);
}
ovrInputCapabilityHeader capsHeader; ovrInputCapabilityHeader capsHeader;
uint32_t index = 0; uint32_t index = 0;
for (;;) { for (;;) {
@ -170,6 +422,14 @@ void IN_VRInputFrame( void )
continue; continue;
} }
ovrTracking remoteTracking;
stateResult = vrapi_GetInputTrackingState(ovr, capsHeader.DeviceID, predictedDisplayTime,
&remoteTracking);
if (stateResult < 0) {
continue;
}
qboolean isRight; qboolean isRight;
vrController_t* controller; vrController_t* controller;
if (caps.ControllerCapabilities & ovrControllerCaps_LeftHand) { if (caps.ControllerCapabilities & ovrControllerCaps_LeftHand) {
@ -183,7 +443,8 @@ void IN_VRInputFrame( void )
continue; continue;
} }
IN_VRJoystick(isRight, state.JoystickNoDeadZone.x, state.JoystickNoDeadZone.y); IN_VRController(isRight, remoteTracking);
IN_VRJoystick(isRight, state.Joystick.x, state.Joystick.y);
IN_VRTriggers(isRight, state.IndexTrigger); IN_VRTriggers(isRight, state.IndexTrigger);
if (controller->buttons ^ state.Buttons) { if (controller->buttons ^ state.Buttons) {
@ -194,4 +455,4 @@ void IN_VRInputFrame( void )
in_vrEventTime = Sys_Milliseconds( ); in_vrEventTime = Sys_Milliseconds( );
} }
#endif //#endif

View file

@ -4,6 +4,7 @@
#if __ANDROID__ #if __ANDROID__
void IN_VRInputFrame( void ); void IN_VRInputFrame( void );
void IN_VRInit( void );
#endif #endif

View file

@ -1,3 +1,4 @@
#include "vr_base.h"
#include "vr_renderer.h" #include "vr_renderer.h"
#include "../qcommon/q_shared.h" #include "../qcommon/q_shared.h"
@ -6,6 +7,7 @@
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes" #pragma clang diagnostic ignored "-Wstrict-prototypes"
#include <VrApi.h>
#include <VrApi_Helpers.h> #include <VrApi_Helpers.h>
#pragma clang diagnostic pop #pragma clang diagnostic pop
@ -29,6 +31,24 @@ void APIENTRY VR_GLDebugLog(GLenum source, GLenum type, GLuint id,
} }
} }
void VR_GetRsolution(engine_t* engine, int *pWidth, int *pHeight)
{
static int width = 0;
static int height = 0;
if (engine)
{
*pWidth = width = vrapi_GetSystemPropertyInt(&engine->java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH);
*pHeight = height = vrapi_GetSystemPropertyInt(&engine->java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT);
}
else
{
//use cached values
*pWidth = width;
*pHeight = height;
}
}
void VR_InitRenderer( engine_t* engine ) { void VR_InitRenderer( engine_t* engine ) {
#if ENABLE_GL_DEBUG #if ENABLE_GL_DEBUG
glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT);
@ -36,9 +56,8 @@ void VR_InitRenderer( engine_t* engine ) {
#endif #endif
int eyeW, eyeH; int eyeW, eyeH;
VR_GetRsolution(engine, &eyeW, &eyeH);
eyeW = 1440; // vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH);
eyeH = 1600; // vrapi_GetSystemPropertyInt(&java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT);
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) { for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
framebuffer_t* framebuffer = &engine->framebuffers[eye]; framebuffer_t* framebuffer = &engine->framebuffers[eye];
framebuffer->colorTexture = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_2D, GL_RGBA8, framebuffer->colorTexture = vrapi_CreateTextureSwapChain3(VRAPI_TEXTURE_TYPE_2D, GL_RGBA8,
@ -91,10 +110,91 @@ void VR_DestroyRenderer( engine_t* engine ) {
} }
// Assumes landscape cylinder shape.
static ovrMatrix4f CylinderModelMatrix( const int texWidth, const int texHeight,
const ovrVector3f translation,
const float rotateYaw,
const float rotatePitch,
const float radius,
const float density )
{
const ovrMatrix4f scaleMatrix = ovrMatrix4f_CreateScale( radius, radius * (float)texHeight * VRAPI_PI / density, radius );
const ovrMatrix4f transMatrix = ovrMatrix4f_CreateTranslation( translation.x, translation.y, translation.z );
const ovrMatrix4f rotXMatrix = ovrMatrix4f_CreateRotation( rotateYaw, 0.0f, 0.0f );
const ovrMatrix4f rotYMatrix = ovrMatrix4f_CreateRotation( 0.0f, rotatePitch, 0.0f );
const ovrMatrix4f m0 = ovrMatrix4f_Multiply( &transMatrix, &scaleMatrix );
const ovrMatrix4f m1 = ovrMatrix4f_Multiply( &rotXMatrix, &m0 );
const ovrMatrix4f m2 = ovrMatrix4f_Multiply( &rotYMatrix, &m1 );
return m2;
}
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 = 4.0f;
const float distance = -6.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[eye].colorTexture;
layer.Textures[eye].SwapChainIndex = engine->framebuffers[eye].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_DrawFrame( engine_t* engine ) { void VR_DrawFrame( engine_t* engine ) {
double predictedDisplayTime; double predictedDisplayTime;
ovrTracking2 tracking; ovrTracking2 tracking;
ovrLayerProjection2 layer;
if (!engine->ovr) if (!engine->ovr)
{ {
@ -105,37 +205,80 @@ void VR_DrawFrame( engine_t* engine ) {
predictedDisplayTime = vrapi_GetPredictedDisplayTime(engine->ovr, engine->frameIndex); predictedDisplayTime = vrapi_GetPredictedDisplayTime(engine->ovr, engine->frameIndex);
tracking = vrapi_GetPredictedTracking2(engine->ovr, predictedDisplayTime); tracking = vrapi_GetPredictedTracking2(engine->ovr, predictedDisplayTime);
layer = vrapi_DefaultLayerProjection2(); if (VR_useScreenLayer())
layer.HeadPose = tracking.HeadPose; {
static ovrLayer_Union2 cylinderLayer;
memset( &cylinderLayer, 0, sizeof( ovrLayer_Union2 ) );
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) { int eyeW, eyeH;
layer.Textures[eye].ColorSwapChain = engine->framebuffers[eye].colorTexture; VR_GetRsolution(engine, &eyeW, &eyeH);
layer.Textures[eye].SwapChainIndex = engine->framebuffers[eye].swapchainIndex;
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&tracking.Eye[eye].ProjectionMatrix); // Add a simple cylindrical layer
cylinderLayer.Cylinder =
BuildCylinderLayer(engine, eyeW, eyeW, &tracking, 0 );
const ovrLayerHeader2* layers[] = {
&cylinderLayer.Header
};
// Set up the description for this frame.
ovrSubmitFrameDescription2 frameDesc = { 0 };
frameDesc.Flags = 0;
frameDesc.SwapInterval = 1;
frameDesc.FrameIndex = engine->frameIndex;
frameDesc.DisplayTime = predictedDisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;
const framebuffer_t* framebuffers = engine->framebuffers;
re.SetVRHeadsetParms(&tracking,
framebuffers[0].framebuffers[framebuffers[0].swapchainIndex],
framebuffers[1].framebuffers[framebuffers[1].swapchainIndex]);
Com_Frame();
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
engine->framebuffers[eye].swapchainIndex = (engine->framebuffers[eye].swapchainIndex + 1) %
engine->framebuffers[eye].swapchainLength;
}
// Hand over the eye images to the time warp.
vrapi_SubmitFrame2(engine->ovr, &frameDesc);
}
else
{
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
layer.HeadPose = tracking.HeadPose;
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
layer.Textures[eye].ColorSwapChain = engine->framebuffers[eye].colorTexture;
layer.Textures[eye].SwapChainIndex = engine->framebuffers[eye].swapchainIndex;
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&tracking.Eye[eye].ProjectionMatrix);
}
const framebuffer_t* framebuffers = engine->framebuffers;
re.SetVRHeadsetParms(&tracking,
framebuffers[0].framebuffers[framebuffers[0].swapchainIndex],
framebuffers[1].framebuffers[framebuffers[1].swapchainIndex]);
Com_Frame();
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
engine->framebuffers[eye].swapchainIndex = (engine->framebuffers[eye].swapchainIndex + 1) %
engine->framebuffers[eye].swapchainLength;
}
const ovrLayerHeader2* layers[] = {
&layer.Header
};
ovrSubmitFrameDescription2 frameDesc = { 0 };
frameDesc.Flags = 0;
frameDesc.SwapInterval = 1;
frameDesc.FrameIndex = engine->frameIndex;
frameDesc.DisplayTime = predictedDisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;
vrapi_SubmitFrame2(engine->ovr, &frameDesc);
} }
const framebuffer_t* framebuffers = engine->framebuffers;
re.SetVRHeadsetParms(&tracking,
framebuffers[0].framebuffers[framebuffers[0].swapchainIndex],
framebuffers[1].framebuffers[framebuffers[1].swapchainIndex]);
Com_Frame();
for (int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; ++eye) {
engine->framebuffers[eye].swapchainIndex = (engine->framebuffers[eye].swapchainIndex + 1) %
engine->framebuffers[eye].swapchainLength;
}
const ovrLayerHeader2* layers[] = {
&layer.Header
};
ovrSubmitFrameDescription2 frameDesc = { 0 };
frameDesc.Flags = 0;
frameDesc.SwapInterval = 1;
frameDesc.FrameIndex = engine->frameIndex;
frameDesc.DisplayTime = predictedDisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;
vrapi_SubmitFrame2(engine->ovr, &frameDesc);
} }

View file

@ -5,6 +5,7 @@
#include "vr_types.h" #include "vr_types.h"
void VR_GetRsolution( engine_t* engine, int *pWidth, int *pHeight );
void VR_InitRenderer( engine_t* engine ); void VR_InitRenderer( engine_t* engine );
void VR_DestroyRenderer( engine_t* engine ); void VR_DestroyRenderer( engine_t* engine );
void VR_DrawFrame( engine_t* engine ); void VR_DrawFrame( engine_t* engine );

View file

@ -25,6 +25,7 @@ typedef struct {
typedef struct { typedef struct {
uint64_t frameIndex; uint64_t frameIndex;
ovrMobile* ovr; ovrMobile* ovr;
ovrJava java;
framebuffer_t framebuffers[VRAPI_FRAME_LAYER_EYE_MAX]; framebuffer_t framebuffers[VRAPI_FRAME_LAYER_EYE_MAX];
} engine_t; } engine_t;