2020-06-10 18:20:11 +00:00
/************************************************************************************
2020-06-28 13:41:34 +00:00
Filename : RTCWVR_SurfaceView . c based on VrCubeWorld_SurfaceView . c
2020-06-10 18:20:11 +00:00
Content : This sample uses a plain Android SurfaceView and handles all
Activity and Surface life cycle events in native code . This sample
does not use the application framework and also does not use LibOVR .
This sample only uses the VrApi .
Created : March , 2015
Authors : J . M . P . van Waveren / Simon Brown
Copyright : Copyright 2015 Oculus VR , LLC . All Rights reserved .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdio.h>
# include <ctype.h>
# include <stdlib.h>
# include <time.h>
# include <unistd.h>
# include <pthread.h>
# include <sys/prctl.h> // for prctl( PR_SET_NAME )
# include <android/log.h>
# include <android/native_window_jni.h> // for native window JNI
# include <android/input.h>
# include "argtable3.h"
# include "VrInput.h"
# include "VrCvars.h"
# include <EGL/egl.h>
# include <EGL/eglext.h>
# include <GLES3/gl3.h>
# include <GLES3/gl3ext.h>
2020-08-21 01:29:21 +00:00
# include <GLES/gl2ext.h>
2020-06-10 18:20:11 +00:00
# include "VrApi.h"
# include "VrApi_Helpers.h"
# include "VrApi_SystemUtils.h"
# include "VrApi_Input.h"
# include "VrApi_Types.h"
# include <src/gl/loader.h>
2020-06-28 13:41:34 +00:00
//#include <SDL2/SDL.h>
//#include <SDL2/SDL_main.h>
# include <src/client/client.h>
2020-06-10 18:20:11 +00:00
# include "VrCompositor.h"
# include "VrInput.h"
# if !defined( EGL_OPENGL_ES3_BIT_KHR )
# define EGL_OPENGL_ES3_BIT_KHR 0x0040
# endif
// EXT_texture_border_clamp
# ifndef GL_CLAMP_TO_BORDER
# define GL_CLAMP_TO_BORDER 0x812D
# endif
# ifndef GL_TEXTURE_BORDER_COLOR
# define GL_TEXTURE_BORDER_COLOR 0x1004
# endif
// Must use EGLSyncKHR because the VrApi still supports OpenGL ES 2.0
# define EGL_SYNC
# if defined EGL_SYNC
// EGL_KHR_reusable_sync
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR ;
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR ;
PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR ;
PFNEGLSIGNALSYNCKHRPROC eglSignalSyncKHR ;
PFNEGLGETSYNCATTRIBKHRPROC eglGetSyncAttribKHR ;
# endif
//Let's go to the maximum!
int CPU_LEVEL = 4 ;
int GPU_LEVEL = 4 ;
int NUM_MULTI_SAMPLES = 1 ;
2020-12-28 11:06:37 +00:00
int REFRESH = 0 ;
float SS_MULTIPLIER = 0.0f ;
2020-12-10 20:48:58 +00:00
2020-06-10 18:20:11 +00:00
jclass clazz ;
float radians ( float deg ) {
return ( deg * M_PI ) / 180.0 ;
}
float degrees ( float rad ) {
return ( rad * 180.0 ) / M_PI ;
}
/* global arg_xxx structs */
struct arg_dbl * ss ;
struct arg_int * cpu ;
struct arg_int * gpu ;
2020-08-21 01:29:21 +00:00
struct arg_int * msaa ;
2020-12-28 11:06:37 +00:00
struct arg_int * refresh ;
2020-06-10 18:20:11 +00:00
struct arg_end * end ;
char * * argv ;
int argc = 0 ;
extern cvar_t * r_lefthand ;
extern cvar_t * cl_paused ;
enum control_scheme {
RIGHT_HANDED_DEFAULT = 0 ,
LEFT_HANDED_DEFAULT = 10 ,
2020-07-13 22:58:12 +00:00
WEAPON_ALIGN = 99
2020-06-10 18:20:11 +00:00
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
System Clock Time in millis
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
double GetTimeInMilliSeconds ( )
{
struct timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
return ( now . tv_sec * 1e9 + now . tv_nsec ) * ( double ) ( 1e-6 ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
LAMBDA1VR Stuff
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2020-06-30 23:03:19 +00:00
qboolean RTCWVR_useScreenLayer ( )
2020-06-10 18:20:11 +00:00
{
2020-07-23 18:23:29 +00:00
vr . screen = ( qboolean ) ( showingScreenLayer | |
2020-07-01 22:49:41 +00:00
( cls . state = = CA_CINEMATIC ) | |
( cls . state = = CA_LOADING ) | |
( clc . demoplaying ) | |
2020-07-02 06:39:44 +00:00
( cl . cameraMode ) | |
2020-07-01 22:49:41 +00:00
( Key_GetCatcher ( ) & KEYCATCH_UI ) | |
( Key_GetCatcher ( ) & KEYCATCH_CONSOLE ) ) ;
2020-07-23 18:23:29 +00:00
return vr . screen ;
2020-06-10 18:20:11 +00:00
}
int runStatus = - 1 ;
2020-06-28 13:41:34 +00:00
void RTCWVR_exit ( int exitCode )
2020-06-10 18:20:11 +00:00
{
runStatus = exitCode ;
}
static void UnEscapeQuotes ( char * arg )
{
char * last = NULL ;
while ( * arg ) {
if ( * arg = = ' " ' & & * last = = ' \\ ' ) {
char * c_curr = arg ;
char * c_last = last ;
while ( * c_curr ) {
* c_last = * c_curr ;
c_last = c_curr ;
c_curr + + ;
}
* c_last = ' \0 ' ;
}
last = arg ;
arg + + ;
}
}
static int ParseCommandLine ( char * cmdline , char * * argv )
{
char * bufp ;
char * lastp = NULL ;
int argc , last_argc ;
argc = last_argc = 0 ;
for ( bufp = cmdline ; * bufp ; ) {
while ( isspace ( * bufp ) ) {
+ + bufp ;
}
if ( * bufp = = ' " ' ) {
+ + bufp ;
if ( * bufp ) {
if ( argv ) {
argv [ argc ] = bufp ;
}
+ + argc ;
}
while ( * bufp & & ( * bufp ! = ' " ' | | * lastp = = ' \\ ' ) ) {
lastp = bufp ;
+ + bufp ;
}
} else {
if ( * bufp ) {
if ( argv ) {
argv [ argc ] = bufp ;
}
+ + argc ;
}
while ( * bufp & & ! isspace ( * bufp ) ) {
+ + bufp ;
}
}
if ( * bufp ) {
if ( argv ) {
* bufp = ' \0 ' ;
}
+ + bufp ;
}
if ( argv & & last_argc ! = argc ) {
UnEscapeQuotes ( argv [ last_argc ] ) ;
}
last_argc = argc ;
}
if ( argv ) {
argv [ argc ] = NULL ;
}
return ( argc ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
OpenGL - ES Utility Functions
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
typedef struct
{
bool multi_view ; // GL_OVR_multiview, GL_OVR_multiview2
bool EXT_texture_border_clamp ; // GL_EXT_texture_border_clamp, GL_OES_texture_border_clamp
} OpenGLExtensions_t ;
OpenGLExtensions_t glExtensions ;
static void EglInitExtensions ( )
{
# if defined EGL_SYNC
eglCreateSyncKHR = ( PFNEGLCREATESYNCKHRPROC ) eglGetProcAddress ( " eglCreateSyncKHR " ) ;
eglDestroySyncKHR = ( PFNEGLDESTROYSYNCKHRPROC ) eglGetProcAddress ( " eglDestroySyncKHR " ) ;
eglClientWaitSyncKHR = ( PFNEGLCLIENTWAITSYNCKHRPROC ) eglGetProcAddress ( " eglClientWaitSyncKHR " ) ;
eglSignalSyncKHR = ( PFNEGLSIGNALSYNCKHRPROC ) eglGetProcAddress ( " eglSignalSyncKHR " ) ;
eglGetSyncAttribKHR = ( PFNEGLGETSYNCATTRIBKHRPROC ) eglGetProcAddress ( " eglGetSyncAttribKHR " ) ;
# endif
const char * allExtensions = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
if ( allExtensions ! = NULL )
{
glExtensions . multi_view = strstr ( allExtensions , " GL_OVR_multiview2 " ) & &
strstr ( allExtensions , " GL_OVR_multiview_multisampled_render_to_texture " ) ;
glExtensions . EXT_texture_border_clamp = false ; //strstr( allExtensions, "GL_EXT_texture_border_clamp" ) ||
//strstr( allExtensions, "GL_OES_texture_border_clamp" );
}
}
static const char * EglErrorString ( const EGLint error )
{
switch ( error )
{
case EGL_SUCCESS : return " EGL_SUCCESS " ;
case EGL_NOT_INITIALIZED : return " EGL_NOT_INITIALIZED " ;
case EGL_BAD_ACCESS : return " EGL_BAD_ACCESS " ;
case EGL_BAD_ALLOC : return " EGL_BAD_ALLOC " ;
case EGL_BAD_ATTRIBUTE : return " EGL_BAD_ATTRIBUTE " ;
case EGL_BAD_CONTEXT : return " EGL_BAD_CONTEXT " ;
case EGL_BAD_CONFIG : return " EGL_BAD_CONFIG " ;
case EGL_BAD_CURRENT_SURFACE : return " EGL_BAD_CURRENT_SURFACE " ;
case EGL_BAD_DISPLAY : return " EGL_BAD_DISPLAY " ;
case EGL_BAD_SURFACE : return " EGL_BAD_SURFACE " ;
case EGL_BAD_MATCH : return " EGL_BAD_MATCH " ;
case EGL_BAD_PARAMETER : return " EGL_BAD_PARAMETER " ;
case EGL_BAD_NATIVE_PIXMAP : return " EGL_BAD_NATIVE_PIXMAP " ;
case EGL_BAD_NATIVE_WINDOW : return " EGL_BAD_NATIVE_WINDOW " ;
case EGL_CONTEXT_LOST : return " EGL_CONTEXT_LOST " ;
default : return " unknown " ;
}
}
static const char * GlFrameBufferStatusString ( GLenum status )
{
switch ( status )
{
case GL_FRAMEBUFFER_UNDEFINED : return " GL_FRAMEBUFFER_UNDEFINED " ;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT : return " GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT " ;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : return " GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT " ;
case GL_FRAMEBUFFER_UNSUPPORTED : return " GL_FRAMEBUFFER_UNSUPPORTED " ;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE : return " GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE " ;
default : return " unknown " ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ovrEgl
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
typedef struct
{
EGLint MajorVersion ;
EGLint MinorVersion ;
EGLDisplay Display ;
EGLConfig Config ;
EGLSurface TinySurface ;
EGLSurface MainSurface ;
EGLContext Context ;
} ovrEgl ;
static void ovrEgl_Clear ( ovrEgl * egl )
{
egl - > MajorVersion = 0 ;
egl - > MinorVersion = 0 ;
egl - > Display = 0 ;
egl - > Config = 0 ;
egl - > TinySurface = EGL_NO_SURFACE ;
egl - > MainSurface = EGL_NO_SURFACE ;
egl - > Context = EGL_NO_CONTEXT ;
}
static void ovrEgl_CreateContext ( ovrEgl * egl , const ovrEgl * shareEgl )
{
if ( egl - > Display ! = 0 )
{
return ;
}
egl - > Display = eglGetDisplay ( EGL_DEFAULT_DISPLAY ) ;
ALOGV ( " eglInitialize( Display, &MajorVersion, &MinorVersion ) " ) ;
eglInitialize ( egl - > Display , & egl - > MajorVersion , & egl - > MinorVersion ) ;
// Do NOT use eglChooseConfig, because the Android EGL code pushes in multisample
// flags in eglChooseConfig if the user has selected the "force 4x MSAA" option in
// settings, and that is completely wasted for our warp target.
const int MAX_CONFIGS = 1024 ;
EGLConfig configs [ MAX_CONFIGS ] ;
EGLint numConfigs = 0 ;
if ( eglGetConfigs ( egl - > Display , configs , MAX_CONFIGS , & numConfigs ) = = EGL_FALSE )
{
ALOGE ( " eglGetConfigs() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
return ;
}
const EGLint configAttribs [ ] =
{
EGL_RED_SIZE , 8 ,
EGL_GREEN_SIZE , 8 ,
EGL_BLUE_SIZE , 8 ,
EGL_ALPHA_SIZE , 8 , // need alpha for the multi-pass timewarp compositor
EGL_DEPTH_SIZE , 0 ,
EGL_STENCIL_SIZE , 0 ,
EGL_SAMPLES , 0 ,
EGL_NONE
} ;
egl - > Config = 0 ;
for ( int i = 0 ; i < numConfigs ; i + + )
{
EGLint value = 0 ;
eglGetConfigAttrib ( egl - > Display , configs [ i ] , EGL_RENDERABLE_TYPE , & value ) ;
if ( ( value & EGL_OPENGL_ES3_BIT_KHR ) ! = EGL_OPENGL_ES3_BIT_KHR )
{
continue ;
}
// The pbuffer config also needs to be compatible with normal window rendering
// so it can share textures with the window context.
eglGetConfigAttrib ( egl - > Display , configs [ i ] , EGL_SURFACE_TYPE , & value ) ;
if ( ( value & ( EGL_WINDOW_BIT | EGL_PBUFFER_BIT ) ) ! = ( EGL_WINDOW_BIT | EGL_PBUFFER_BIT ) )
{
continue ;
}
int j = 0 ;
for ( ; configAttribs [ j ] ! = EGL_NONE ; j + = 2 )
{
eglGetConfigAttrib ( egl - > Display , configs [ i ] , configAttribs [ j ] , & value ) ;
if ( value ! = configAttribs [ j + 1 ] )
{
break ;
}
}
if ( configAttribs [ j ] = = EGL_NONE )
{
egl - > Config = configs [ i ] ;
break ;
}
}
if ( egl - > Config = = 0 )
{
ALOGE ( " eglChooseConfig() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
return ;
}
EGLint contextAttribs [ ] =
{
EGL_CONTEXT_CLIENT_VERSION , 3 ,
EGL_NONE
} ;
ALOGV ( " Context = eglCreateContext( Display, Config, EGL_NO_CONTEXT, contextAttribs ) " ) ;
egl - > Context = eglCreateContext ( egl - > Display , egl - > Config , ( shareEgl ! = NULL ) ? shareEgl - > Context : EGL_NO_CONTEXT , contextAttribs ) ;
if ( egl - > Context = = EGL_NO_CONTEXT )
{
ALOGE ( " eglCreateContext() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
return ;
}
const EGLint surfaceAttribs [ ] =
{
EGL_WIDTH , 16 ,
EGL_HEIGHT , 16 ,
EGL_NONE
} ;
ALOGV ( " TinySurface = eglCreatePbufferSurface( Display, Config, surfaceAttribs ) " ) ;
egl - > TinySurface = eglCreatePbufferSurface ( egl - > Display , egl - > Config , surfaceAttribs ) ;
if ( egl - > TinySurface = = EGL_NO_SURFACE )
{
ALOGE ( " eglCreatePbufferSurface() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
eglDestroyContext ( egl - > Display , egl - > Context ) ;
egl - > Context = EGL_NO_CONTEXT ;
return ;
}
ALOGV ( " eglMakeCurrent( Display, TinySurface, TinySurface, Context ) " ) ;
if ( eglMakeCurrent ( egl - > Display , egl - > TinySurface , egl - > TinySurface , egl - > Context ) = = EGL_FALSE )
{
ALOGE ( " eglMakeCurrent() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
eglDestroySurface ( egl - > Display , egl - > TinySurface ) ;
eglDestroyContext ( egl - > Display , egl - > Context ) ;
egl - > Context = EGL_NO_CONTEXT ;
return ;
}
}
static void ovrEgl_DestroyContext ( ovrEgl * egl )
{
if ( egl - > Display ! = 0 )
{
ALOGE ( " eglMakeCurrent( Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ) " ) ;
if ( eglMakeCurrent ( egl - > Display , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) = = EGL_FALSE )
{
ALOGE ( " eglMakeCurrent() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
}
}
if ( egl - > Context ! = EGL_NO_CONTEXT )
{
ALOGE ( " eglDestroyContext( Display, Context ) " ) ;
if ( eglDestroyContext ( egl - > Display , egl - > Context ) = = EGL_FALSE )
{
ALOGE ( " eglDestroyContext() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
}
egl - > Context = EGL_NO_CONTEXT ;
}
if ( egl - > TinySurface ! = EGL_NO_SURFACE )
{
ALOGE ( " eglDestroySurface( Display, TinySurface ) " ) ;
if ( eglDestroySurface ( egl - > Display , egl - > TinySurface ) = = EGL_FALSE )
{
ALOGE ( " eglDestroySurface() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
}
egl - > TinySurface = EGL_NO_SURFACE ;
}
if ( egl - > Display ! = 0 )
{
ALOGE ( " eglTerminate( Display ) " ) ;
if ( eglTerminate ( egl - > Display ) = = EGL_FALSE )
{
ALOGE ( " eglTerminate() failed: %s " , EglErrorString ( eglGetError ( ) ) ) ;
}
egl - > Display = 0 ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ovrFramebuffer
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
static void ovrFramebuffer_Clear ( ovrFramebuffer * frameBuffer )
{
frameBuffer - > Width = 0 ;
frameBuffer - > Height = 0 ;
frameBuffer - > Multisamples = 0 ;
frameBuffer - > TextureSwapChainLength = 0 ;
2020-06-30 23:03:19 +00:00
frameBuffer - > ProcessingTextureSwapChainIndex = 0 ;
frameBuffer - > ReadyTextureSwapChainIndex = 0 ;
2020-06-10 18:20:11 +00:00
frameBuffer - > ColorTextureSwapChain = NULL ;
frameBuffer - > DepthBuffers = NULL ;
frameBuffer - > FrameBuffers = NULL ;
}
static bool ovrFramebuffer_Create ( ovrFramebuffer * frameBuffer , const GLenum colorFormat , const int width , const int height , const int multisamples )
{
LOAD_GLES2 ( glBindTexture ) ;
LOAD_GLES2 ( glTexParameteri ) ;
LOAD_GLES2 ( glGenRenderbuffers ) ;
LOAD_GLES2 ( glBindRenderbuffer ) ;
LOAD_GLES2 ( glRenderbufferStorage ) ;
LOAD_GLES2 ( glGenFramebuffers ) ;
LOAD_GLES2 ( glBindFramebuffer ) ;
LOAD_GLES2 ( glFramebufferRenderbuffer ) ;
LOAD_GLES2 ( glFramebufferTexture2D ) ;
LOAD_GLES2 ( glCheckFramebufferStatus ) ;
frameBuffer - > Width = width ;
frameBuffer - > Height = height ;
frameBuffer - > Multisamples = multisamples ;
frameBuffer - > ColorTextureSwapChain = vrapi_CreateTextureSwapChain3 ( VRAPI_TEXTURE_TYPE_2D , colorFormat , frameBuffer - > Width , frameBuffer - > Height , 1 , 3 ) ;
frameBuffer - > TextureSwapChainLength = vrapi_GetTextureSwapChainLength ( frameBuffer - > ColorTextureSwapChain ) ;
frameBuffer - > DepthBuffers = ( GLuint * ) malloc ( frameBuffer - > TextureSwapChainLength * sizeof ( GLuint ) ) ;
frameBuffer - > FrameBuffers = ( GLuint * ) malloc ( frameBuffer - > TextureSwapChainLength * sizeof ( GLuint ) ) ;
2020-08-21 01:29:21 +00:00
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT =
( PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC ) eglGetProcAddress ( " glRenderbufferStorageMultisampleEXT " ) ;
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT =
( PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC ) eglGetProcAddress ( " glFramebufferTexture2DMultisampleEXT " ) ;
2020-06-10 18:20:11 +00:00
for ( int i = 0 ; i < frameBuffer - > TextureSwapChainLength ; i + + )
{
// Create the color buffer texture.
const GLuint colorTexture = vrapi_GetTextureSwapChainHandle ( frameBuffer - > ColorTextureSwapChain , i ) ;
GLenum colorTextureTarget = GL_TEXTURE_2D ;
GL ( gles_glBindTexture ( colorTextureTarget , colorTexture ) ) ;
// Just clamp to edge. However, this requires manually clearing the border
// around the layer to clear the edge texels.
GL ( gles_glTexParameteri ( colorTextureTarget , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ) ;
GL ( gles_glTexParameteri ( colorTextureTarget , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ) ;
GL ( gles_glTexParameteri ( colorTextureTarget , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
GL ( gles_glTexParameteri ( colorTextureTarget , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
GL ( gles_glBindTexture ( colorTextureTarget , 0 ) ) ;
2020-08-21 01:29:21 +00:00
if ( multisamples > 1 & & glRenderbufferStorageMultisampleEXT ! = NULL & & glFramebufferTexture2DMultisampleEXT ! = NULL )
{
// Create multisampled depth buffer.
GL ( glGenRenderbuffers ( 1 , & frameBuffer - > DepthBuffers [ i ] ) ) ;
GL ( glBindRenderbuffer ( GL_RENDERBUFFER , frameBuffer - > DepthBuffers [ i ] ) ) ;
GL ( glRenderbufferStorageMultisampleEXT ( GL_RENDERBUFFER , multisamples , GL_DEPTH_COMPONENT24 , width , height ) ) ;
GL ( glBindRenderbuffer ( GL_RENDERBUFFER , 0 ) ) ;
// Create the frame buffer.
GL ( glGenFramebuffers ( 1 , & frameBuffer - > FrameBuffers [ i ] ) ) ;
GL ( glBindFramebuffer ( GL_FRAMEBUFFER , frameBuffer - > FrameBuffers [ i ] ) ) ;
GL ( glFramebufferTexture2DMultisampleEXT ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , colorTexture , 0 , multisamples ) ) ;
GL ( glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , frameBuffer - > DepthBuffers [ i ] ) ) ;
GL ( GLenum renderFramebufferStatus = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ) ;
GL ( glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ) ;
if ( renderFramebufferStatus ! = GL_FRAMEBUFFER_COMPLETE )
{
ALOGE ( " OVRHelper::Incomplete frame buffer object: %s " , GlFrameBufferStatusString ( renderFramebufferStatus ) ) ;
return false ;
}
}
else
2020-06-10 18:20:11 +00:00
{
{
// Create depth buffer.
GL ( gles_glGenRenderbuffers ( 1 , & frameBuffer - > DepthBuffers [ i ] ) ) ;
GL ( gles_glBindRenderbuffer ( GL_RENDERBUFFER , frameBuffer - > DepthBuffers [ i ] ) ) ;
GL ( gles_glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT24 , frameBuffer - > Width , frameBuffer - > Height ) ) ;
GL ( gles_glBindRenderbuffer ( GL_RENDERBUFFER , 0 ) ) ;
// Create the frame buffer.
GL ( gles_glGenFramebuffers ( 1 , & frameBuffer - > FrameBuffers [ i ] ) ) ;
GL ( gles_glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , frameBuffer - > FrameBuffers [ i ] ) ) ;
GL ( gles_glFramebufferRenderbuffer ( GL_DRAW_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , frameBuffer - > DepthBuffers [ i ] ) ) ;
GL ( gles_glFramebufferTexture2D ( GL_DRAW_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , colorTexture , 0 ) ) ;
GL ( GLenum renderFramebufferStatus = gles_glCheckFramebufferStatus ( GL_DRAW_FRAMEBUFFER ) ) ;
GL ( gles_glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ) ;
if ( renderFramebufferStatus ! = GL_FRAMEBUFFER_COMPLETE )
{
ALOGE ( " Incomplete frame buffer object: %s " , GlFrameBufferStatusString ( renderFramebufferStatus ) ) ;
return false ;
}
}
}
}
return true ;
}
void ovrFramebuffer_Destroy ( ovrFramebuffer * frameBuffer )
{
LOAD_GLES2 ( glDeleteFramebuffers ) ;
LOAD_GLES2 ( glDeleteRenderbuffers ) ;
GL ( gles_glDeleteFramebuffers ( frameBuffer - > TextureSwapChainLength , frameBuffer - > FrameBuffers ) ) ;
GL ( gles_glDeleteRenderbuffers ( frameBuffer - > TextureSwapChainLength , frameBuffer - > DepthBuffers ) ) ;
vrapi_DestroyTextureSwapChain ( frameBuffer - > ColorTextureSwapChain ) ;
free ( frameBuffer - > DepthBuffers ) ;
free ( frameBuffer - > FrameBuffers ) ;
ovrFramebuffer_Clear ( frameBuffer ) ;
}
2020-07-04 19:20:16 +00:00
void GPUWaitSync ( )
{
GLsync syncBuff = glFenceSync ( GL_SYNC_GPU_COMMANDS_COMPLETE , 0 ) ;
GLenum status = glClientWaitSync ( syncBuff , GL_SYNC_FLUSH_COMMANDS_BIT , 1000 * 1000 * 50 ) ; // Wait for a max of 50ms...
if ( status ! = GL_CONDITION_SATISFIED )
{
LOGE ( " Error on glClientWaitSync: %d \n " , status ) ;
}
glDeleteSync ( syncBuff ) ;
}
2020-06-10 18:20:11 +00:00
void ovrFramebuffer_SetCurrent ( ovrFramebuffer * frameBuffer )
{
LOAD_GLES2 ( glBindFramebuffer ) ;
2020-06-30 23:03:19 +00:00
GL ( gles_glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , frameBuffer - > FrameBuffers [ frameBuffer - > ProcessingTextureSwapChainIndex ] ) ) ;
2020-06-10 18:20:11 +00:00
}
void ovrFramebuffer_SetNone ( )
{
LOAD_GLES2 ( glBindFramebuffer ) ;
GL ( gles_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.
2020-06-30 23:03:19 +00:00
// const GLenum depthAttachment[1] = { GL_DEPTH_ATTACHMENT };
// glInvalidateFramebuffer( GL_DRAW_FRAMEBUFFER, 1, depthAttachment );
2020-06-10 18:20:11 +00:00
// Flush this frame worth of commands.
glFlush ( ) ;
}
void ovrFramebuffer_Advance ( ovrFramebuffer * frameBuffer )
{
// Advance to the next texture from the set.
2020-06-30 23:03:19 +00:00
frameBuffer - > ReadyTextureSwapChainIndex = frameBuffer - > ProcessingTextureSwapChainIndex ;
frameBuffer - > ProcessingTextureSwapChainIndex = ( frameBuffer - > ProcessingTextureSwapChainIndex + 1 ) % frameBuffer - > TextureSwapChainLength ;
2020-06-10 18:20:11 +00:00
}
void ovrFramebuffer_ClearEdgeTexels ( ovrFramebuffer * frameBuffer )
{
LOAD_GLES2 ( glEnable ) ;
LOAD_GLES2 ( glDisable ) ;
LOAD_GLES2 ( glViewport ) ;
LOAD_GLES2 ( glScissor ) ;
LOAD_GLES2 ( glClearColor ) ;
LOAD_GLES2 ( glClear ) ;
GL ( gles_glEnable ( GL_SCISSOR_TEST ) ) ;
GL ( gles_glViewport ( 0 , 0 , frameBuffer - > Width , frameBuffer - > Height ) ) ;
// Explicitly clear the border texels to black because OpenGL-ES does not support GL_CLAMP_TO_BORDER.
// Clear to fully opaque black.
GL ( gles_glClearColor ( 0.0f , 0.0f , 0.0f , 1.0f ) ) ;
// bottom
2020-07-20 18:56:58 +00:00
GL ( gles_glScissor ( 0 , 0 , frameBuffer - > Width , 1 ) ) ;
2020-06-10 18:20:11 +00:00
GL ( gles_glClear ( GL_COLOR_BUFFER_BIT ) ) ;
// top
2020-07-20 18:56:58 +00:00
GL ( gles_glScissor ( 0 , frameBuffer - > Height - 1 , frameBuffer - > Width , 1 ) ) ;
2020-06-10 18:20:11 +00:00
GL ( gles_glClear ( GL_COLOR_BUFFER_BIT ) ) ;
// left
2020-07-20 18:56:58 +00:00
GL ( gles_glScissor ( 0 , 0 , 1 , frameBuffer - > Height ) ) ;
2020-06-10 18:20:11 +00:00
GL ( gles_glClear ( GL_COLOR_BUFFER_BIT ) ) ;
// right
2020-07-20 18:56:58 +00:00
GL ( gles_glScissor ( frameBuffer - > Width - 1 , 0 , 1 , frameBuffer - > Height ) ) ;
2020-06-10 18:20:11 +00:00
GL ( gles_glClear ( GL_COLOR_BUFFER_BIT ) ) ;
GL ( gles_glScissor ( 0 , 0 , 0 , 0 ) ) ;
GL ( gles_glDisable ( GL_SCISSOR_TEST ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ovrRenderer
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void ovrRenderer_Clear ( ovrRenderer * renderer )
{
for ( int eye = 0 ; eye < VRAPI_FRAME_LAYER_EYE_MAX ; eye + + )
{
ovrFramebuffer_Clear ( & renderer - > FrameBuffer [ eye ] ) ;
}
renderer - > ProjectionMatrix = ovrMatrix4f_CreateIdentity ( ) ;
renderer - > NumBuffers = VRAPI_FRAME_LAYER_EYE_MAX ;
}
void ovrRenderer_Create ( int width , int height , ovrRenderer * renderer , const ovrJava * java )
{
renderer - > NumBuffers = VRAPI_FRAME_LAYER_EYE_MAX ;
//Now using a symmetrical render target, based on the horizontal FOV
2020-10-18 21:20:07 +00:00
vr . fov = vrapi_GetSystemPropertyInt ( java , VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y ) ;
2020-06-10 18:20:11 +00:00
// Create the render Textures.
for ( int eye = 0 ; eye < VRAPI_FRAME_LAYER_EYE_MAX ; eye + + )
{
ovrFramebuffer_Create ( & renderer - > FrameBuffer [ eye ] ,
GL_RGBA8 ,
width ,
height ,
NUM_MULTI_SAMPLES ) ;
}
// Setup the projection matrix.
renderer - > ProjectionMatrix = ovrMatrix4f_CreateProjectionFov (
2020-07-03 22:26:33 +00:00
vr . fov , vr . fov , 0.0f , 0.0f , 1.0f , 0.0f ) ;
2020-06-10 18:20:11 +00:00
}
void ovrRenderer_Destroy ( ovrRenderer * renderer )
{
for ( int eye = 0 ; eye < renderer - > NumBuffers ; eye + + )
{
ovrFramebuffer_Destroy ( & renderer - > FrameBuffer [ eye ] ) ;
}
renderer - > ProjectionMatrix = ovrMatrix4f_CreateIdentity ( ) ;
}
# ifndef EPSILON
# define EPSILON 0.001f
# endif
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 ) ;
}
2020-06-30 23:03:19 +00:00
void QuatToYawPitchRoll ( ovrQuatf q , vec3_t rotation , vec3_t out ) {
2020-06-10 18:20:11 +00:00
ovrMatrix4f mat = ovrMatrix4f_CreateFromQuaternion ( & q ) ;
2020-06-30 23:03:19 +00:00
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 ) ;
}
2020-06-10 18:20:11 +00:00
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 ) ;
2020-06-30 23:03:19 +00:00
ovrVector3f forward = { - forwardInVRSpace . z , - forwardInVRSpace . x , forwardInVRSpace . y } ;
ovrVector3f right = { - rightInVRSpace . z , - rightInVRSpace . x , rightInVRSpace . y } ;
ovrVector3f up = { - upInVRSpace . z , - upInVRSpace . x , upInVRSpace . y } ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrVector3f forwardNormal = normalizeVec ( forward ) ;
ovrVector3f rightNormal = normalizeVec ( right ) ;
ovrVector3f upNormal = normalizeVec ( up ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
GetAnglesFromVectors ( forwardNormal , rightNormal , upNormal , out ) ;
return ;
2020-06-10 18:20:11 +00:00
}
2020-07-05 09:49:07 +00:00
void updateHMDOrientation ( )
2020-06-10 18:20:11 +00:00
{
2020-07-05 09:49:07 +00:00
//Position
VectorSubtract ( vr . hmdposition_last , vr . hmdposition , vr . hmdposition_delta ) ;
2020-06-10 18:20:11 +00:00
2020-07-05 09:49:07 +00:00
//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 ) ;
2020-06-10 18:20:11 +00:00
}
2020-07-05 09:49:07 +00:00
void setHMDPosition ( float x , float y , float z )
2020-06-10 18:20:11 +00:00
{
2020-06-30 23:03:19 +00:00
static qboolean s_useScreen = qfalse ;
2020-06-10 18:20:11 +00:00
2020-07-05 09:49:07 +00:00
VectorSet ( vr . hmdposition , x , y , z ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
if ( s_useScreen ! = RTCWVR_useScreenLayer ( ) )
2020-06-10 18:20:11 +00:00
{
2020-06-30 23:03:19 +00:00
s_useScreen = RTCWVR_useScreenLayer ( ) ;
2020-06-10 18:20:11 +00:00
//Record player height on transition
playerHeight = y ;
2020-07-19 14:41:27 +00:00
//Resync yaw on transition
RTCWVR_ResyncClientYawWithGameYaw ( ) ;
2020-06-10 18:20:11 +00:00
}
2020-06-30 23:03:19 +00:00
if ( ! RTCWVR_useScreenLayer ( ) )
2020-06-10 18:20:11 +00:00
{
2020-07-05 09:49:07 +00:00
playerYaw = vr . hmdorientation [ YAW ] ;
2020-06-10 18:20:11 +00:00
}
}
qboolean isMultiplayer ( )
{
return Cvar_VariableValue ( " maxclients " ) > 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
2020-07-01 22:49:41 +00:00
RTCWVR_Vibrate
2020-06-10 18:20:11 +00:00
= = = = = = = = = = = = = = = = = = = = = = = =
*/
//0 = left, 1 = right
float vibration_channel_duration [ 2 ] = { 0.0f , 0.0f } ;
float vibration_channel_intensity [ 2 ] = { 0.0f , 0.0f } ;
2020-07-14 19:27:41 +00:00
void RTCWVR_Vibrate ( int duration , int channel , float intensity )
2020-06-10 18:20:11 +00:00
{
if ( vibration_channel_duration [ channel ] > 0.0f )
return ;
if ( vibration_channel_duration [ channel ] = = - 1.0f & & duration ! = 0.0f )
return ;
vibration_channel_duration [ channel ] = duration ;
vibration_channel_intensity [ channel ] = intensity ;
}
2021-06-02 14:55:46 +00:00
void RTCWVR_Haptic ( int duration , int channel , float intensity , char * description , float yaw , float height )
{
if ( strstr ( description , " camera_shake " ) = = NULL )
Com_Printf ( " Vibrate Description: %s " , description ) ;
if ( strstr ( description , " damage_ " ) ! = NULL ) {
RTCWVR_HapticEvent ( description , 0 , 0 , 100.0f * intensity , yaw , height ) ;
}
else if ( strstr ( description , " fire_ " ) ! = NULL ) {
if ( strcmp ( description , " fire_11 " ) = = 0 | | strcmp ( description , " fire_2 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_pistol " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_3 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_mp40 " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_4 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_mauser " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_5 " ) = = 0 | | strcmp ( description , " fire_17 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_fg42 " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_6 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_grenadelauncher " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_7 " ) = = 0 | | strcmp ( description , " fire_rocket " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_panzerfaust " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_8 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_venom " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_9 " ) = = 0 | | strcmp ( description , " fire_flames " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_flamethrower " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_10 " ) = = 0 | | strcmp ( description , " fire_tesla " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_tesla " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_12 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_thompson " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_13 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_garand " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_14 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_grenade " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_15 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_sniper " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_16 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_snooperscope " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_18 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_sten " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_19 " ) = = 0 ) {
RTCWVR_HapticEvent ( " fire_silencer " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " fire_20 " ) = = 0 ) {
//Plays on 0 position (Vest) (not left or right)
RTCWVR_HapticEvent ( " fire_akimbo " , 0 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
}
else if ( strcmp ( description , " knife_hit " ) = = 0 ) {
RTCWVR_HapticEvent ( " knife_hit " , channel = = 1 ? 2 : 1 , 0 , 100.0f * intensity , 0 , 0 ) ;
}
else if ( strcmp ( description , " camera_shake_left " ) = = 0 ) {
RTCWVR_HapticEvent ( " rumble_front " , 0 , 0 , 100.0f * intensity , yaw , height ) ;
}
else if ( strcmp ( description , " camera_shake_right " ) = = 0 ) {
RTCWVR_HapticEvent ( " rumble_back " , 0 , 0 , 100.0f * intensity , yaw , height ) ;
}
else {
if ( strstr ( description , " ignore " ) = = NULL & &
strstr ( description , " dead " ) = = NULL )
Com_Printf ( " Missing Haptic: %s " , description ) ;
}
}
2021-05-01 05:56:52 +00:00
void jni_haptic_event ( const char * event , int position , int flags , int intensity , float angle , float yHeight ) ;
void jni_haptic_updateevent ( const char * event , int intensity , float angle ) ;
void jni_haptic_stopevent ( const char * event ) ;
void jni_haptic_endframe ( ) ;
void jni_haptic_enable ( ) ;
void jni_haptic_disable ( ) ;
void RTCWVR_HapticEvent ( const char * event , int position , int flags , int intensity , float angle , float yHeight )
{
2021-06-02 14:55:46 +00:00
Com_Printf ( " Vibrate Event Fired: %s " , event ) ;
2021-05-01 05:56:52 +00:00
jni_haptic_event ( event , position , flags , intensity , angle , yHeight ) ;
}
void RTCWVR_HapticUpdateEvent ( const char * event , int intensity , float angle )
{
jni_haptic_updateevent ( event , intensity , angle ) ;
}
void RTCWVR_HapticEndFrame ( )
{
jni_haptic_endframe ( ) ;
}
void RTCWVR_HapticStopEvent ( const char * event )
{
jni_haptic_stopevent ( event ) ;
}
void RTCWVR_HapticEnable ( )
{
2021-06-02 14:55:46 +00:00
static bool firstTime = true ;
if ( firstTime ) {
jni_haptic_enable ( ) ;
firstTime = false ;
}
2021-05-01 05:56:52 +00:00
}
void RTCWVR_HapticDisable ( )
{
jni_haptic_disable ( ) ;
}
2020-07-14 17:56:03 +00:00
void RTCWVR_GetMove ( float * forward , float * side , float * pos_forward , float * pos_side , float * up ,
float * yaw , float * pitch , float * roll )
2020-06-10 18:20:11 +00:00
{
2020-06-30 23:03:19 +00:00
* forward = remote_movementForward ;
* pos_forward = positional_movementForward ;
2020-06-10 18:20:11 +00:00
* up = remote_movementUp ;
2020-06-30 23:03:19 +00:00
* side = remote_movementSideways ;
* pos_side = positional_movementSideways ;
2020-07-02 06:39:44 +00:00
* yaw = vr . hmdorientation [ YAW ] + snapTurn ;
* pitch = vr . hmdorientation [ PITCH ] ;
* roll = vr . hmdorientation [ ROLL ] ;
2020-06-10 18:20:11 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ovrRenderThread
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ovrApp
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
typedef struct
{
ovrJava Java ;
ovrEgl Egl ;
ANativeWindow * NativeWindow ;
bool Resumed ;
ovrMobile * Ovr ;
ovrScene Scene ;
long long FrameIndex ;
double DisplayTime ;
int SwapInterval ;
int CpuLevel ;
int GpuLevel ;
int MainThreadTid ;
int RenderThreadTid ;
ovrLayer_Union2 Layers [ ovrMaxLayerCount ] ;
int LayerCount ;
ovrRenderer Renderer ;
} ovrApp ;
static void ovrApp_Clear ( ovrApp * app )
{
app - > Java . Vm = NULL ;
app - > Java . Env = NULL ;
app - > Java . ActivityObject = NULL ;
app - > Ovr = NULL ;
app - > FrameIndex = 1 ;
app - > DisplayTime = 0 ;
app - > SwapInterval = 1 ;
2020-07-04 10:46:12 +00:00
app - > CpuLevel = 3 ;
app - > GpuLevel = 3 ;
2020-06-10 18:20:11 +00:00
app - > MainThreadTid = 0 ;
app - > RenderThreadTid = 0 ;
ovrEgl_Clear ( & app - > Egl ) ;
ovrScene_Clear ( & app - > Scene ) ;
ovrRenderer_Clear ( & app - > Renderer ) ;
}
static void ovrApp_PushBlackFinal ( ovrApp * app )
{
int frameFlags = 0 ;
frameFlags | = VRAPI_FRAME_FLAG_FLUSH | VRAPI_FRAME_FLAG_FINAL ;
ovrLayerProjection2 layer = vrapi_DefaultLayerBlackProjection2 ( ) ;
layer . Header . Flags | = VRAPI_FRAME_LAYER_FLAG_INHIBIT_SRGB_FRAMEBUFFER ;
const ovrLayerHeader2 * layers [ ] =
{
& layer . Header
} ;
ovrSubmitFrameDescription2 frameDesc = { } ;
frameDesc . Flags = frameFlags ;
frameDesc . SwapInterval = 1 ;
frameDesc . FrameIndex = app - > FrameIndex ;
frameDesc . DisplayTime = app - > DisplayTime ;
frameDesc . LayerCount = 1 ;
frameDesc . Layers = layers ;
vrapi_SubmitFrame2 ( app - > Ovr , & frameDesc ) ;
}
static void ovrApp_HandleVrModeChanges ( ovrApp * app )
{
if ( app - > Resumed ! = false & & app - > NativeWindow ! = NULL )
{
if ( app - > Ovr = = NULL )
{
ovrModeParms parms = vrapi_DefaultModeParms ( & app - > Java ) ;
// Must reset the FLAG_FULLSCREEN window flag when using a SurfaceView
parms . Flags | = VRAPI_MODE_FLAG_RESET_WINDOW_FULLSCREEN ;
parms . Flags | = VRAPI_MODE_FLAG_NATIVE_WINDOW ;
parms . Display = ( size_t ) app - > Egl . Display ;
parms . WindowSurface = ( size_t ) app - > NativeWindow ;
parms . ShareContext = ( size_t ) app - > Egl . Context ;
ALOGV ( " eglGetCurrentSurface( EGL_DRAW ) = %p " , eglGetCurrentSurface ( EGL_DRAW ) ) ;
ALOGV ( " vrapi_EnterVrMode() " ) ;
app - > Ovr = vrapi_EnterVrMode ( & parms ) ;
ALOGV ( " eglGetCurrentSurface( EGL_DRAW ) = %p " , eglGetCurrentSurface ( EGL_DRAW ) ) ;
// If entering VR mode failed then the ANativeWindow was not valid.
if ( app - > Ovr = = NULL )
{
ALOGE ( " Invalid ANativeWindow! " ) ;
app - > NativeWindow = NULL ;
}
// Set performance parameters once we have entered VR mode and have a valid ovrMobile.
if ( app - > Ovr ! = NULL )
{
2020-12-10 20:48:58 +00:00
//AmmarkoV : Set our refresh rate..!
2020-12-28 11:06:37 +00:00
ovrResult result = vrapi_SetDisplayRefreshRate ( app - > Ovr , REFRESH ) ;
if ( result = = ovrSuccess ) { ALOGV ( " Changed refresh rate. %f Hz " , REFRESH ) ; } else
2020-12-10 20:48:58 +00:00
{ ALOGV ( " Failed to change refresh rate to 90Hz Result=%d " , result ) ; }
vrapi_SetClockLevels ( app - > Ovr , app - > CpuLevel , app - > GpuLevel ) ;
2020-06-10 18:20:11 +00:00
ALOGV ( " vrapi_SetClockLevels( %d, %d ) " , app - > CpuLevel , app - > GpuLevel ) ;
vrapi_SetPerfThread ( app - > Ovr , VRAPI_PERF_THREAD_TYPE_MAIN , app - > MainThreadTid ) ;
ALOGV ( " vrapi_SetPerfThread( MAIN, %d ) " , app - > MainThreadTid ) ;
vrapi_SetPerfThread ( app - > Ovr , VRAPI_PERF_THREAD_TYPE_RENDERER , app - > RenderThreadTid ) ;
ALOGV ( " vrapi_SetPerfThread( RENDERER, %d ) " , app - > RenderThreadTid ) ;
}
}
}
else
{
if ( app - > Ovr ! = NULL )
{
ALOGV ( " eglGetCurrentSurface( EGL_DRAW ) = %p " , eglGetCurrentSurface ( EGL_DRAW ) ) ;
ALOGV ( " vrapi_LeaveVrMode() " ) ;
vrapi_LeaveVrMode ( app - > Ovr ) ;
app - > Ovr = NULL ;
ALOGV ( " eglGetCurrentSurface( EGL_DRAW ) = %p " , eglGetCurrentSurface ( EGL_DRAW ) ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ovrMessageQueue
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
typedef enum
{
MQ_WAIT_NONE , // don't wait
MQ_WAIT_RECEIVED , // wait until the consumer thread has received the message
MQ_WAIT_PROCESSED // wait until the consumer thread has processed the message
} ovrMQWait ;
# define MAX_MESSAGE_PARMS 8
# define MAX_MESSAGES 1024
typedef struct
{
int Id ;
ovrMQWait Wait ;
long long Parms [ MAX_MESSAGE_PARMS ] ;
} ovrMessage ;
static void ovrMessage_Init ( ovrMessage * message , const int id , const int wait )
{
message - > Id = id ;
message - > Wait = wait ;
memset ( message - > Parms , 0 , sizeof ( message - > Parms ) ) ;
}
static void ovrMessage_SetPointerParm ( ovrMessage * message , int index , void * ptr ) { * ( void * * ) & message - > Parms [ index ] = ptr ; }
static void * ovrMessage_GetPointerParm ( ovrMessage * message , int index ) { return * ( void * * ) & message - > Parms [ index ] ; }
static void ovrMessage_SetIntegerParm ( ovrMessage * message , int index , int value ) { message - > Parms [ index ] = value ; }
static int ovrMessage_GetIntegerParm ( ovrMessage * message , int index ) { return ( int ) message - > Parms [ index ] ; }
static void ovrMessage_SetFloatParm ( ovrMessage * message , int index , float value ) { * ( float * ) & message - > Parms [ index ] = value ; }
static float ovrMessage_GetFloatParm ( ovrMessage * message , int index ) { return * ( float * ) & message - > Parms [ index ] ; }
// Cyclic queue with messages.
typedef struct
{
ovrMessage Messages [ MAX_MESSAGES ] ;
volatile int Head ; // dequeue at the head
volatile int Tail ; // enqueue at the tail
ovrMQWait Wait ;
volatile bool EnabledFlag ;
volatile bool PostedFlag ;
volatile bool ReceivedFlag ;
volatile bool ProcessedFlag ;
pthread_mutex_t Mutex ;
pthread_cond_t PostedCondition ;
pthread_cond_t ReceivedCondition ;
pthread_cond_t ProcessedCondition ;
} ovrMessageQueue ;
static void ovrMessageQueue_Create ( ovrMessageQueue * messageQueue )
{
messageQueue - > Head = 0 ;
messageQueue - > Tail = 0 ;
messageQueue - > Wait = MQ_WAIT_NONE ;
messageQueue - > EnabledFlag = false ;
messageQueue - > PostedFlag = false ;
messageQueue - > ReceivedFlag = false ;
messageQueue - > ProcessedFlag = false ;
pthread_mutexattr_t attr ;
pthread_mutexattr_init ( & attr ) ;
pthread_mutexattr_settype ( & attr , PTHREAD_MUTEX_ERRORCHECK ) ;
pthread_mutex_init ( & messageQueue - > Mutex , & attr ) ;
pthread_mutexattr_destroy ( & attr ) ;
pthread_cond_init ( & messageQueue - > PostedCondition , NULL ) ;
pthread_cond_init ( & messageQueue - > ReceivedCondition , NULL ) ;
pthread_cond_init ( & messageQueue - > ProcessedCondition , NULL ) ;
}
static void ovrMessageQueue_Destroy ( ovrMessageQueue * messageQueue )
{
pthread_mutex_destroy ( & messageQueue - > Mutex ) ;
pthread_cond_destroy ( & messageQueue - > PostedCondition ) ;
pthread_cond_destroy ( & messageQueue - > ReceivedCondition ) ;
pthread_cond_destroy ( & messageQueue - > ProcessedCondition ) ;
}
static void ovrMessageQueue_Enable ( ovrMessageQueue * messageQueue , const bool set )
{
messageQueue - > EnabledFlag = set ;
}
static void ovrMessageQueue_PostMessage ( ovrMessageQueue * messageQueue , const ovrMessage * message )
{
if ( ! messageQueue - > EnabledFlag )
{
return ;
}
while ( messageQueue - > Tail - messageQueue - > Head > = MAX_MESSAGES )
{
usleep ( 1000 ) ;
}
pthread_mutex_lock ( & messageQueue - > Mutex ) ;
messageQueue - > Messages [ messageQueue - > Tail & ( MAX_MESSAGES - 1 ) ] = * message ;
messageQueue - > Tail + + ;
messageQueue - > PostedFlag = true ;
pthread_cond_broadcast ( & messageQueue - > PostedCondition ) ;
if ( message - > Wait = = MQ_WAIT_RECEIVED )
{
while ( ! messageQueue - > ReceivedFlag )
{
pthread_cond_wait ( & messageQueue - > ReceivedCondition , & messageQueue - > Mutex ) ;
}
messageQueue - > ReceivedFlag = false ;
}
else if ( message - > Wait = = MQ_WAIT_PROCESSED )
{
while ( ! messageQueue - > ProcessedFlag )
{
pthread_cond_wait ( & messageQueue - > ProcessedCondition , & messageQueue - > Mutex ) ;
}
messageQueue - > ProcessedFlag = false ;
}
pthread_mutex_unlock ( & messageQueue - > Mutex ) ;
}
static void ovrMessageQueue_SleepUntilMessage ( ovrMessageQueue * messageQueue )
{
if ( messageQueue - > Wait = = MQ_WAIT_PROCESSED )
{
messageQueue - > ProcessedFlag = true ;
pthread_cond_broadcast ( & messageQueue - > ProcessedCondition ) ;
messageQueue - > Wait = MQ_WAIT_NONE ;
}
pthread_mutex_lock ( & messageQueue - > Mutex ) ;
if ( messageQueue - > Tail > messageQueue - > Head )
{
pthread_mutex_unlock ( & messageQueue - > Mutex ) ;
return ;
}
while ( ! messageQueue - > PostedFlag )
{
pthread_cond_wait ( & messageQueue - > PostedCondition , & messageQueue - > Mutex ) ;
}
messageQueue - > PostedFlag = false ;
pthread_mutex_unlock ( & messageQueue - > Mutex ) ;
}
static bool ovrMessageQueue_GetNextMessage ( ovrMessageQueue * messageQueue , ovrMessage * message , bool waitForMessages )
{
if ( messageQueue - > Wait = = MQ_WAIT_PROCESSED )
{
messageQueue - > ProcessedFlag = true ;
pthread_cond_broadcast ( & messageQueue - > ProcessedCondition ) ;
messageQueue - > Wait = MQ_WAIT_NONE ;
}
if ( waitForMessages )
{
ovrMessageQueue_SleepUntilMessage ( messageQueue ) ;
}
pthread_mutex_lock ( & messageQueue - > Mutex ) ;
if ( messageQueue - > Tail < = messageQueue - > Head )
{
pthread_mutex_unlock ( & messageQueue - > Mutex ) ;
return false ;
}
* message = messageQueue - > Messages [ messageQueue - > Head & ( MAX_MESSAGES - 1 ) ] ;
messageQueue - > Head + + ;
pthread_mutex_unlock ( & messageQueue - > Mutex ) ;
if ( message - > Wait = = MQ_WAIT_RECEIVED )
{
messageQueue - > ReceivedFlag = true ;
pthread_cond_broadcast ( & messageQueue - > ReceivedCondition ) ;
}
else if ( message - > Wait = = MQ_WAIT_PROCESSED )
{
messageQueue - > Wait = MQ_WAIT_PROCESSED ;
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ovrAppThread
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
enum
{
MESSAGE_ON_CREATE ,
MESSAGE_ON_START ,
MESSAGE_ON_RESUME ,
MESSAGE_ON_PAUSE ,
MESSAGE_ON_STOP ,
MESSAGE_ON_DESTROY ,
MESSAGE_ON_SURFACE_CREATED ,
MESSAGE_ON_SURFACE_DESTROYED
} ;
typedef struct
{
JavaVM * JavaVm ;
jobject ActivityObject ;
jclass ActivityClass ;
pthread_t Thread ;
ovrMessageQueue MessageQueue ;
ANativeWindow * NativeWindow ;
} ovrAppThread ;
long shutdownCountdown ;
int m_width ;
int m_height ;
qboolean R_SetMode ( void ) ;
2020-07-01 22:49:41 +00:00
void RTCWVR_GetScreenRes ( int * width , int * height )
2020-06-10 18:20:11 +00:00
{
2020-07-01 22:49:41 +00:00
* width = m_width ;
* height = m_height ;
2020-06-10 18:20:11 +00:00
}
void Android_MessageBox ( const char * title , const char * text )
{
ALOGE ( " %s %s " , title , text ) ;
}
void initialize_gl4es ( ) ;
2020-07-03 22:26:33 +00:00
void RTCWVR_ResyncClientYawWithGameYaw ( )
{
2020-07-06 22:09:20 +00:00
//Allow several frames for the yaw to sync, first is this frame which is the old yaw
2020-07-03 22:26:33 +00:00
//second is the next frame which _should_ be the new yaw, but just in case it isn't
//we resync on the 3rd frame as well
2020-07-06 22:28:15 +00:00
resyncClientYawWithGameYaw = 2 ;
2020-07-03 22:26:33 +00:00
}
void RTCWVR_Init ( )
2020-06-10 18:20:11 +00:00
{
//Initialise all our variables
playerYaw = 0.0f ;
2020-07-01 22:49:41 +00:00
showingScreenLayer = qfalse ;
2020-06-10 18:20:11 +00:00
remote_movementSideways = 0.0f ;
remote_movementForward = 0.0f ;
remote_movementUp = 0.0f ;
positional_movementSideways = 0.0f ;
positional_movementForward = 0.0f ;
snapTurn = 0.0f ;
ducked = DUCK_NOTDUCKED ;
2020-07-03 22:26:33 +00:00
RTCWVR_ResyncClientYawWithGameYaw ( ) ;
2020-06-10 18:20:11 +00:00
//init randomiser
srand ( time ( NULL ) ) ;
//Create Cvars
2020-08-13 14:43:50 +00:00
vr_turn_mode = Cvar_Get ( " vr_turn_mode " , " 0 " , CVAR_ARCHIVE ) ; // 0 = snap, 1 = smooth
vr_turn_angle = Cvar_Get ( " vr_turn_angle " , " 45 " , CVAR_ARCHIVE ) ;
2020-07-01 22:49:41 +00:00
vr_reloadtimeoutms = Cvar_Get ( " vr_reloadtimeoutms " , " 200 " , CVAR_ARCHIVE ) ;
2020-07-04 10:46:12 +00:00
vr_positional_factor = Cvar_Get ( " vr_positional_factor " , " 12 " , CVAR_ARCHIVE ) ;
2020-08-13 14:43:50 +00:00
vr_walkdirection = Cvar_Get ( " vr_walkdirection " , " 0 " , CVAR_ARCHIVE ) ;
2020-08-11 15:42:09 +00:00
vr_movement_multiplier = Cvar_Get ( " vr_movement_multiplier " , " 0.7 " , CVAR_ARCHIVE ) ;
2020-06-10 18:20:11 +00:00
vr_weapon_pitchadjust = Cvar_Get ( " vr_weapon_pitchadjust " , " -20.0 " , CVAR_ARCHIVE ) ;
2020-08-22 11:33:30 +00:00
vr_lasersight = Cvar_Get ( " vr_lasersight " , " 0 " , CVAR_ARCHIVE ) ;
2020-07-20 18:56:58 +00:00
vr_teleport = Cvar_Get ( " vr_teleport " , " 0 " , CVAR_ARCHIVE ) ;
2020-08-24 22:23:04 +00:00
vr_virtual_stock = Cvar_Get ( " vr_virtual_stock " , " 0 " , CVAR_ARCHIVE ) ;
2020-07-13 22:58:12 +00:00
//Defaults
vr_control_scheme = Cvar_Get ( " vr_control_scheme " , " 0 " , CVAR_ARCHIVE ) ;
2020-08-16 17:31:46 +00:00
vr_switch_sticks = Cvar_Get ( " vr_switch_sticks " , " 0 " , CVAR_ARCHIVE ) ;
2020-07-15 22:16:44 +00:00
2020-08-24 22:23:04 +00:00
vr_cinematic_stereo = Cvar_Get ( " vr_cinematic_stereo " , " 0 " , CVAR_ARCHIVE ) ; // Default to 2D
2020-08-23 16:58:43 +00:00
vr_screen_dist = Cvar_Get ( " vr_screen_dist " , " 3.5 " , CVAR_ARCHIVE ) ;
2020-07-15 22:16:44 +00:00
//Set up vr client info
vr . backpackitemactive = 0 ;
vr . visible_hud = qtrue ;
2020-07-16 22:52:04 +00:00
vr . dualwield = qfalse ;
2020-09-03 18:17:44 +00:00
vr . weapon_recoil = 0.0f ;
2020-07-20 18:56:58 +00:00
//Clear teleport stuff
vr . teleportexecute = qfalse ;
vr . teleportseek = qfalse ;
vr . teleportenabled = qfalse ;
vr . teleportready = qfalse ;
2020-06-10 18:20:11 +00:00
}
2020-06-30 23:03:19 +00:00
static ovrAppThread * gAppThread = NULL ;
static ovrApp gAppState ;
static ovrJava java ;
static qboolean destroyed = qfalse ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
void RTCWVR_prepareEyeBuffer ( int eye )
{
ovrRenderer * renderer = RTCWVR_useScreenLayer ( ) ? & gAppState . Scene . CylinderRenderer : & gAppState . Renderer ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrFramebuffer * frameBuffer = & ( renderer - > FrameBuffer [ eye ] ) ;
ovrFramebuffer_SetCurrent ( frameBuffer ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
GL ( glEnable ( GL_SCISSOR_TEST ) ) ;
GL ( glDepthMask ( GL_TRUE ) ) ;
GL ( glEnable ( GL_DEPTH_TEST ) ) ;
GL ( glDepthFunc ( GL_LEQUAL ) ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
//Weusing the size of the render target
GL ( glViewport ( 0 , 0 , frameBuffer - > Width , frameBuffer - > Height ) ) ;
GL ( glScissor ( 0 , 0 , frameBuffer - > Width , frameBuffer - > Height ) ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
GL ( glClearColor ( 0.0f , 0.0f , 0.0f , 1.0f ) ) ;
GL ( glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ) ;
GL ( glDisable ( GL_SCISSOR_TEST ) ) ;
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
void RTCWVR_finishEyeBuffer ( int eye )
{
ovrRenderer * renderer = RTCWVR_useScreenLayer ( ) ? & gAppState . Scene . CylinderRenderer : & gAppState . Renderer ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrFramebuffer * frameBuffer = & ( renderer - > FrameBuffer [ eye ] ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
//Clear edge to prevent smearing
ovrFramebuffer_ClearEdgeTexels ( frameBuffer ) ;
ovrFramebuffer_Resolve ( frameBuffer ) ;
ovrFramebuffer_Advance ( frameBuffer ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrFramebuffer_SetNone ( ) ;
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
qboolean RTCWVR_processMessageQueue ( ) {
for ( ; ; )
2020-06-10 18:20:11 +00:00
{
2020-06-30 23:03:19 +00:00
ovrMessage message ;
const bool waitForMessages = ( gAppState . Ovr = = NULL & & destroyed = = false ) ;
if ( ! ovrMessageQueue_GetNextMessage ( & gAppThread - > MessageQueue , & message , waitForMessages ) )
2020-06-10 18:20:11 +00:00
{
2020-06-30 23:03:19 +00:00
break ;
}
switch ( message . Id )
{
case MESSAGE_ON_CREATE :
2020-06-10 18:20:11 +00:00
{
break ;
}
2020-06-30 23:03:19 +00:00
case MESSAGE_ON_START :
2020-06-10 18:20:11 +00:00
{
2020-06-30 23:03:19 +00:00
if ( ! rtcw_initialised )
2020-06-10 18:20:11 +00:00
{
2020-06-30 23:03:19 +00:00
ALOGV ( " Initialising rtcw Engine " ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
//Set command line arguments here
if ( argc ! = 0 )
{
//TODO
}
else
{
int argc = 1 ; char * argv [ ] = { " rtcw " } ;
2020-06-10 18:20:11 +00:00
}
2020-06-30 23:03:19 +00:00
rtcw_initialised = qtrue ;
2020-06-10 18:20:11 +00:00
}
2020-06-30 23:03:19 +00:00
break ;
2020-06-10 18:20:11 +00:00
}
2020-06-30 23:03:19 +00:00
case MESSAGE_ON_RESUME :
{
//If we get here, then user has opted not to quit
gAppState . Resumed = true ;
break ;
}
case MESSAGE_ON_PAUSE :
{
gAppState . Resumed = false ;
break ;
}
case MESSAGE_ON_STOP :
{
break ;
}
case MESSAGE_ON_DESTROY :
{
gAppState . NativeWindow = NULL ;
destroyed = true ;
//shutdown = true;
break ;
}
case MESSAGE_ON_SURFACE_CREATED : { gAppState . NativeWindow = ( ANativeWindow * ) ovrMessage_GetPointerParm ( & message , 0 ) ; break ; }
case MESSAGE_ON_SURFACE_DESTROYED : { gAppState . NativeWindow = NULL ; break ; }
2020-06-10 18:20:11 +00:00
}
2020-06-30 23:03:19 +00:00
ovrApp_HandleVrModeChanges ( & gAppState ) ;
}
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
void showLoadingIcon ( ) ;
void jni_shutdown ( ) ;
void RTCWVR_incrementFrameIndex ( ) ;
void shutdownVR ( ) ;
int VR_main ( int argc , char * argv [ ] ) ;
2020-06-10 18:20:11 +00:00
2020-10-18 21:20:07 +00:00
int GetRefresh ( )
{
return vrapi_GetSystemPropertyInt ( & java , VRAPI_SYS_PROP_DISPLAY_REFRESH_RATE ) ;
}
2020-06-30 23:03:19 +00:00
void * AppThreadFunction ( void * parm ) {
gAppThread = ( ovrAppThread * ) parm ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
java . Vm = gAppThread - > JavaVm ;
( * java . Vm ) - > AttachCurrentThread ( java . Vm , & java . Env , NULL ) ;
java . ActivityObject = gAppThread - > ActivityObject ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
jclass cls = ( * java . Env ) - > GetObjectClass ( java . Env , java . ActivityObject ) ;
// Note that AttachCurrentThread will reset the thread name.
prctl ( PR_SET_NAME , ( long ) " OVR::Main " , 0 , 0 , 0 ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
rtcw_initialised = false ;
2020-08-23 16:58:43 +00:00
vr_screen_dist = NULL ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
const ovrInitParms initParms = vrapi_DefaultInitParms ( & java ) ;
int32_t initResult = vrapi_Initialize ( & initParms ) ;
if ( initResult ! = VRAPI_INITIALIZE_SUCCESS ) {
// If intialization failed, vrapi_* function calls will not be available.
exit ( 0 ) ;
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrApp_Clear ( & gAppState ) ;
gAppState . Java = java ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
// This app will handle android gamepad events itself.
vrapi_SetPropertyInt ( & gAppState . Java , VRAPI_EAT_NATIVE_GAMEPAD_EVENTS , 0 ) ;
2020-06-10 18:20:11 +00:00
2020-12-28 11:06:37 +00:00
//Set device defaults
if ( vrapi_GetSystemPropertyInt ( & java , VRAPI_SYS_PROP_DEVICE_TYPE ) = = VRAPI_DEVICE_TYPE_OCULUSQUEST )
{
if ( SS_MULTIPLIER = = 0.0f )
{
2021-04-20 20:10:50 +00:00
SS_MULTIPLIER = 1.2f ;
2020-12-28 11:06:37 +00:00
}
}
else if ( vrapi_GetSystemPropertyInt ( & java , VRAPI_SYS_PROP_DEVICE_TYPE ) = = VRAPI_DEVICE_TYPE_OCULUSQUEST2 )
{
if ( SS_MULTIPLIER = = 0.0f )
{
2021-04-20 20:10:50 +00:00
//Lower to allow 90hz to work nicely
SS_MULTIPLIER = 1.0f ;
2020-12-28 11:06:37 +00:00
}
2021-04-20 20:10:50 +00:00
else if ( SS_MULTIPLIER > 1.2F )
{
SS_MULTIPLIER = 1.2f ;
}
2020-12-28 11:06:37 +00:00
} else {
//Don't know what headset this is!? abort
return NULL ;
}
2020-06-30 23:03:19 +00:00
//Using a symmetrical render target
m_height = m_width = ( int ) ( vrapi_GetSystemPropertyInt ( & java , VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH ) * SS_MULTIPLIER ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
gAppState . CpuLevel = CPU_LEVEL ;
gAppState . GpuLevel = GPU_LEVEL ;
gAppState . MainThreadTid = gettid ( ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrEgl_CreateContext ( & gAppState . Egl , NULL ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
EglInitExtensions ( ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
//First handle any messages in the queue
while ( gAppState . Ovr = = NULL ) {
RTCWVR_processMessageQueue ( ) ;
}
ovrRenderer_Create ( m_width , m_height , & gAppState . Renderer , & java ) ;
if ( gAppState . Ovr = = NULL )
{
return NULL ;
}
// Create the scene if not yet created.
ovrScene_Create ( m_width , m_height , & gAppState . Scene , & java ) ;
chdir ( " /sdcard/RTCWQuest " ) ;
//Run loading loop until we are ready to start RTCWVR
while ( ! destroyed & & ! rtcw_initialised ) {
RTCWVR_processMessageQueue ( ) ;
RTCWVR_incrementFrameIndex ( ) ;
showLoadingIcon ( ) ;
}
2020-12-28 11:06:37 +00:00
int maximumSupportRefresh = 0 ;
2020-12-10 20:48:58 +00:00
//AmmarkoV : Query Refresh rates and select maximum..!
//-----------------------------------------------------------------------------------------------------------
2020-12-28 11:06:37 +00:00
int numberOfRefreshRates = vrapi_GetSystemPropertyInt ( & java ,
VRAPI_SYS_PROP_NUM_SUPPORTED_DISPLAY_REFRESH_RATES ) ;
2020-12-10 20:48:58 +00:00
float refreshRatesArray [ 16 ] ; //Refresh rates are currently (12/2020) the following 4 : 60.0 / 72.0 / 80.0 / 90.0
2020-12-28 11:06:37 +00:00
if ( numberOfRefreshRates > 16 ) { numberOfRefreshRates = 16 ; }
vrapi_GetSystemPropertyFloatArray ( & java , VRAPI_SYS_PROP_SUPPORTED_DISPLAY_REFRESH_RATES ,
& refreshRatesArray [ 0 ] , numberOfRefreshRates ) ;
2020-12-10 20:48:58 +00:00
for ( int i = 0 ; i < numberOfRefreshRates ; i + + ) {
2021-06-02 14:55:46 +00:00
ALOGV ( " Supported refresh rate : %d Hz " , refreshRatesArray [ i ] ) ;
2020-12-28 11:06:37 +00:00
if ( maximumSupportRefresh < refreshRatesArray [ i ] ) {
maximumSupportRefresh = refreshRatesArray [ i ] ;
2020-12-10 20:48:58 +00:00
}
}
2020-12-28 11:06:37 +00:00
if ( maximumSupportRefresh > 90.0 ) {
2020-12-10 20:48:58 +00:00
ALOGV ( " Soft limiting to 90.0 Hz as per John carmack's request ( https://www.onlinepeeps.org/oculus-quest-2-according-to-carmack-in-the-future-also-at-120-hz/ );P " ) ;
2020-12-28 11:06:37 +00:00
maximumSupportRefresh = 90.0 ;
}
if ( REFRESH = = 0 | | REFRESH > maximumSupportRefresh )
{
REFRESH = maximumSupportRefresh ;
2020-12-10 20:48:58 +00:00
}
//-----------------------------------------------------------------------------------------------------------
//start
2020-06-30 23:03:19 +00:00
VR_main ( argc , argv ) ;
//We are done, shutdown cleanly
shutdownVR ( ) ;
//Ask Java to shut down
jni_shutdown ( ) ;
return NULL ;
}
//All the stuff we want to do each frame
void RTCWVR_FrameSetup ( )
{
//Use floor based tracking space
vrapi_SetTrackingSpace ( gAppState . Ovr , VRAPI_TRACKING_SPACE_LOCAL_FLOOR ) ;
2020-12-12 11:49:23 +00:00
//Set framerate so VrApi doesn't change it on us..
2020-12-28 11:06:37 +00:00
vrapi_SetDisplayRefreshRate ( gAppState . Ovr , REFRESH ) ;
2020-06-30 23:03:19 +00:00
}
void RTCWVR_processHaptics ( ) {
static float lastFrameTime = 0.0f ;
float timestamp = ( float ) ( GetTimeInMilliSeconds ( ) ) ;
float frametime = timestamp - lastFrameTime ;
lastFrameTime = timestamp ;
for ( int i = 0 ; i < 2 ; + + i ) {
if ( vibration_channel_duration [ i ] > 0.0f | |
vibration_channel_duration [ i ] = = - 1.0f ) {
vrapi_SetHapticVibrationSimple ( gAppState . Ovr , controllerIDs [ i ] ,
vibration_channel_intensity [ i ] ) ;
if ( vibration_channel_duration [ i ] ! = - 1.0f ) {
vibration_channel_duration [ i ] - = frametime ;
if ( vibration_channel_duration [ i ] < 0.0f ) {
vibration_channel_duration [ i ] = 0.0f ;
vibration_channel_intensity [ i ] = 0.0f ;
2020-06-10 18:20:11 +00:00
}
}
2020-06-30 23:03:19 +00:00
} else {
vrapi_SetHapticVibrationSimple ( gAppState . Ovr , controllerIDs [ i ] , 0.0f ) ;
2020-06-10 18:20:11 +00:00
}
2020-06-30 23:03:19 +00:00
}
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
void showLoadingIcon ( )
{
int frameFlags = 0 ;
frameFlags | = VRAPI_FRAME_FLAG_FLUSH ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrLayerProjection2 blackLayer = vrapi_DefaultLayerBlackProjection2 ( ) ;
blackLayer . Header . Flags | = VRAPI_FRAME_LAYER_FLAG_INHIBIT_SRGB_FRAMEBUFFER ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrLayerLoadingIcon2 iconLayer = vrapi_DefaultLayerLoadingIcon2 ( ) ;
iconLayer . Header . Flags | = VRAPI_FRAME_LAYER_FLAG_INHIBIT_SRGB_FRAMEBUFFER ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
const ovrLayerHeader2 * layers [ ] =
{
& blackLayer . Header ,
& iconLayer . Header ,
} ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ovrSubmitFrameDescription2 frameDesc = { } ;
frameDesc . Flags = frameFlags ;
frameDesc . SwapInterval = 1 ;
frameDesc . FrameIndex = gAppState . FrameIndex ;
frameDesc . DisplayTime = gAppState . DisplayTime ;
frameDesc . LayerCount = 2 ;
frameDesc . Layers = layers ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
vrapi_SubmitFrame2 ( gAppState . Ovr , & frameDesc ) ;
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
void RTCWVR_getHMDOrientation ( ) { //Get orientation
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
// 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.
tracking = vrapi_GetPredictedTracking2 ( gAppState . Ovr , gAppState . DisplayTime ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
// We extract Yaw, Pitch, Roll instead of directly using the orientation
// to allow "additional" yaw manipulation with mouse/controller.
const ovrQuatf quatHmd = tracking . HeadPose . Pose . Orientation ;
const ovrVector3f positionHmd = tracking . HeadPose . Pose . Position ;
2020-09-01 18:27:10 +00:00
vec3_t rotation = { 0 , 0 , 0 } ;
2020-07-02 06:39:44 +00:00
QuatToYawPitchRoll ( quatHmd , rotation , vr . hmdorientation ) ;
2020-07-05 09:49:07 +00:00
setHMDPosition ( positionHmd . x , positionHmd . y , positionHmd . z ) ;
2020-06-10 18:20:11 +00:00
2020-07-05 09:49:07 +00:00
updateHMDOrientation ( ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
ALOGV ( " HMD-Position: %f, %f, %f " , positionHmd . x , positionHmd . y , positionHmd . z ) ;
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
void shutdownVR ( ) {
ovrRenderer_Destroy ( & gAppState . Renderer ) ;
ovrEgl_DestroyContext ( & gAppState . Egl ) ;
( * java . Vm ) - > DetachCurrentThread ( java . Vm ) ;
vrapi_Shutdown ( ) ;
}
2020-06-10 18:20:11 +00:00
2020-07-05 09:49:07 +00:00
long long RTCWVR_getFrameIndex ( )
{
return gAppState . FrameIndex ;
}
2020-06-30 23:03:19 +00:00
void RTCWVR_incrementFrameIndex ( )
{
// This is the only place the frame index is incremented, right before
// calling vrapi_GetPredictedDisplayTime().
gAppState . FrameIndex + + ;
gAppState . DisplayTime = vrapi_GetPredictedDisplayTime ( gAppState . Ovr ,
gAppState . FrameIndex ) ;
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
void RTCWVR_getTrackedRemotesOrientation ( ) { //Get info for tracked remotes
acquireTrackedRemotesData ( gAppState . Ovr , gAppState . DisplayTime ) ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
//Call additional control schemes here
switch ( vr_control_scheme - > integer )
{
case RIGHT_HANDED_DEFAULT :
HandleInput_Default ( & rightTrackedRemoteState_new , & rightTrackedRemoteState_old , & rightRemoteTracking_new ,
& leftTrackedRemoteState_new , & leftTrackedRemoteState_old , & leftRemoteTracking_new ,
ovrButton_A , ovrButton_B , ovrButton_X , ovrButton_Y ) ;
break ;
case LEFT_HANDED_DEFAULT :
HandleInput_Default ( & leftTrackedRemoteState_new , & leftTrackedRemoteState_old , & leftRemoteTracking_new ,
& rightTrackedRemoteState_new , & rightTrackedRemoteState_old , & rightRemoteTracking_new ,
ovrButton_X , ovrButton_Y , ovrButton_A , ovrButton_B ) ;
break ;
2020-07-13 22:58:12 +00:00
case WEAPON_ALIGN :
HandleInput_WeaponAlign ( & rightTrackedRemoteState_new , & rightTrackedRemoteState_old , & rightRemoteTracking_new ,
& leftTrackedRemoteState_new , & leftTrackedRemoteState_old , & leftRemoteTracking_new ,
ovrButton_A , ovrButton_B , ovrButton_X , ovrButton_Y ) ;
break ;
2020-06-30 23:03:19 +00:00
}
}
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
void RTCWVR_submitFrame ( )
{
ovrSubmitFrameDescription2 frameDesc = { 0 } ;
2020-06-10 18:20:11 +00:00
2020-06-30 23:03:19 +00:00
if ( ! RTCWVR_useScreenLayer ( ) ) {
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2 ( ) ;
layer . HeadPose = tracking . HeadPose ;
for ( int eye = 0 ; eye < VRAPI_FRAME_LAYER_EYE_MAX ; eye + + )
2020-06-10 18:20:11 +00:00
{
2020-06-30 23:03:19 +00:00
ovrFramebuffer * frameBuffer = & gAppState . Renderer . FrameBuffer [ gAppState . Renderer . NumBuffers = = 1 ? 0 : eye ] ;
layer . Textures [ eye ] . ColorSwapChain = frameBuffer - > ColorTextureSwapChain ;
layer . Textures [ eye ] . SwapChainIndex = frameBuffer - > ReadyTextureSwapChainIndex ;
ovrMatrix4f projectionMatrix ;
2020-07-03 22:26:33 +00:00
projectionMatrix = ovrMatrix4f_CreateProjectionFov ( vr . fov , vr . fov ,
2020-06-30 23:03:19 +00:00
0.0f , 0.0f , 0.1f , 0.0f ) ;
layer . Textures [ eye ] . TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection ( & projectionMatrix ) ;
layer . Textures [ eye ] . TextureRect . x = 0 ;
layer . Textures [ eye ] . TextureRect . y = 0 ;
layer . Textures [ eye ] . TextureRect . width = 1.0f ;
layer . Textures [ eye ] . TextureRect . height = 1.0f ;
2020-06-10 18:20:11 +00:00
}
2020-06-30 23:03:19 +00:00
layer . Header . Flags | = VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION ;
// Set up the description for this frame.
const ovrLayerHeader2 * layers [ ] =
{
& layer . Header
} ;
frameDesc . Flags = 0 ;
frameDesc . SwapInterval = gAppState . SwapInterval ;
frameDesc . FrameIndex = gAppState . FrameIndex ;
frameDesc . DisplayTime = gAppState . DisplayTime ;
frameDesc . LayerCount = 1 ;
frameDesc . Layers = layers ;
// Hand over the eye images to the time warp.
vrapi_SubmitFrame2 ( gAppState . Ovr , & frameDesc ) ;
} else {
// Set-up the compositor layers for this frame.
// NOTE: Multiple independent layers are allowed, but they need to be added
// in a depth consistent order.
memset ( gAppState . Layers , 0 , sizeof ( ovrLayer_Union2 ) * ovrMaxLayerCount ) ;
gAppState . LayerCount = 0 ;
// Add a simple cylindrical layer
gAppState . Layers [ gAppState . LayerCount + + ] . Cylinder =
BuildCylinderLayer ( & gAppState . Scene . CylinderRenderer ,
gAppState . Scene . CylinderWidth , gAppState . Scene . CylinderHeight , & tracking , radians ( playerYaw ) ) ;
// Compose the layers for this frame.
const ovrLayerHeader2 * layerHeaders [ ovrMaxLayerCount ] = { 0 } ;
for ( int i = 0 ; i < gAppState . LayerCount ; i + + )
{
layerHeaders [ i ] = & gAppState . Layers [ i ] . Header ;
}
// Set up the description for this frame.
frameDesc . Flags = 0 ;
frameDesc . SwapInterval = gAppState . SwapInterval ;
frameDesc . FrameIndex = gAppState . FrameIndex ;
frameDesc . DisplayTime = gAppState . DisplayTime ;
frameDesc . LayerCount = gAppState . LayerCount ;
frameDesc . Layers = layerHeaders ;
// Hand over the eye images to the time warp.
vrapi_SubmitFrame2 ( gAppState . Ovr , & frameDesc ) ;
2020-06-10 18:20:11 +00:00
}
2020-07-04 19:20:16 +00:00
2020-06-30 23:03:19 +00:00
RTCWVR_incrementFrameIndex ( ) ;
2021-06-02 14:55:46 +00:00
RTCWVR_HapticEndFrame ( ) ;
2020-06-10 18:20:11 +00:00
}
static void ovrAppThread_Create ( ovrAppThread * appThread , JNIEnv * env , jobject activityObject , jclass activityClass )
{
( * env ) - > GetJavaVM ( env , & appThread - > JavaVm ) ;
appThread - > ActivityObject = ( * env ) - > NewGlobalRef ( env , activityObject ) ;
appThread - > ActivityClass = ( * env ) - > NewGlobalRef ( env , activityClass ) ;
appThread - > Thread = 0 ;
appThread - > NativeWindow = NULL ;
ovrMessageQueue_Create ( & appThread - > MessageQueue ) ;
const int createErr = pthread_create ( & appThread - > Thread , NULL , AppThreadFunction , appThread ) ;
if ( createErr ! = 0 )
{
ALOGE ( " pthread_create returned %i " , createErr ) ;
}
}
static void ovrAppThread_Destroy ( ovrAppThread * appThread , JNIEnv * env )
{
pthread_join ( appThread - > Thread , NULL ) ;
( * env ) - > DeleteGlobalRef ( env , appThread - > ActivityObject ) ;
( * env ) - > DeleteGlobalRef ( env , appThread - > ActivityClass ) ;
ovrMessageQueue_Destroy ( & appThread - > MessageQueue ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Activity lifecycle
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2020-06-30 23:03:19 +00:00
jmethodID android_shutdown ;
2021-05-03 19:58:50 +00:00
jmethodID android_haptic_event ;
jmethodID android_haptic_updateevent ;
jmethodID android_haptic_stopevent ;
jmethodID android_haptic_endframe ;
jmethodID android_haptic_enable ;
jmethodID android_haptic_disable ;
2020-06-30 23:03:19 +00:00
static JavaVM * jVM ;
2021-05-03 19:58:50 +00:00
static jobject jniCallbackObj = 0 ;
2020-06-30 23:03:19 +00:00
void jni_shutdown ( )
{
ALOGV ( " Calling: jni_shutdown " ) ;
JNIEnv * env ;
jobject tmp ;
if ( ( ( * jVM ) - > GetEnv ( jVM , ( void * * ) & env , JNI_VERSION_1_4 ) ) < 0 )
{
( * jVM ) - > AttachCurrentThread ( jVM , & env , NULL ) ;
}
2021-05-03 19:58:50 +00:00
return ( * env ) - > CallVoidMethod ( env , jniCallbackObj , android_shutdown ) ;
}
void jni_haptic_event ( const char * event , int position , int flags , int intensity , float angle , float yHeight )
{
JNIEnv * env ;
jobject tmp ;
if ( ( ( * jVM ) - > GetEnv ( jVM , ( void * * ) & env , JNI_VERSION_1_4 ) ) < 0 )
{
( * jVM ) - > AttachCurrentThread ( jVM , & env , NULL ) ;
}
jstring StringArg1 = ( * env ) - > NewStringUTF ( env , event ) ;
return ( * env ) - > CallVoidMethod ( env , jniCallbackObj , android_haptic_event , StringArg1 , position , flags , intensity , angle , yHeight ) ;
}
void jni_haptic_updateevent ( const char * event , int intensity , float angle )
{
JNIEnv * env ;
jobject tmp ;
if ( ( ( * jVM ) - > GetEnv ( jVM , ( void * * ) & env , JNI_VERSION_1_4 ) ) < 0 )
{
( * jVM ) - > AttachCurrentThread ( jVM , & env , NULL ) ;
}
jstring StringArg1 = ( * env ) - > NewStringUTF ( env , event ) ;
return ( * env ) - > CallVoidMethod ( env , jniCallbackObj , android_haptic_updateevent , StringArg1 , intensity , angle ) ;
}
void jni_haptic_stopevent ( const char * event )
{
ALOGV ( " Calling: jni_haptic_stopevent " ) ;
JNIEnv * env ;
jobject tmp ;
if ( ( ( * jVM ) - > GetEnv ( jVM , ( void * * ) & env , JNI_VERSION_1_4 ) ) < 0 )
{
( * jVM ) - > AttachCurrentThread ( jVM , & env , NULL ) ;
}
jstring StringArg1 = ( * env ) - > NewStringUTF ( env , event ) ;
return ( * env ) - > CallVoidMethod ( env , jniCallbackObj , android_haptic_stopevent , StringArg1 ) ;
}
void jni_haptic_endframe ( )
{
JNIEnv * env ;
jobject tmp ;
if ( ( ( * jVM ) - > GetEnv ( jVM , ( void * * ) & env , JNI_VERSION_1_4 ) ) < 0 )
{
( * jVM ) - > AttachCurrentThread ( jVM , & env , NULL ) ;
}
return ( * env ) - > CallVoidMethod ( env , jniCallbackObj , android_haptic_endframe ) ;
}
void jni_haptic_enable ( )
{
ALOGV ( " Calling: jni_haptic_enable " ) ;
JNIEnv * env ;
jobject tmp ;
if ( ( ( * jVM ) - > GetEnv ( jVM , ( void * * ) & env , JNI_VERSION_1_4 ) ) < 0 )
{
( * jVM ) - > AttachCurrentThread ( jVM , & env , NULL ) ;
}
return ( * env ) - > CallVoidMethod ( env , jniCallbackObj , android_haptic_enable ) ;
}
void jni_haptic_disable ( )
{
ALOGV ( " Calling: jni_haptic_disable " ) ;
JNIEnv * env ;
jobject tmp ;
if ( ( ( * jVM ) - > GetEnv ( jVM , ( void * * ) & env , JNI_VERSION_1_4 ) ) < 0 )
{
( * jVM ) - > AttachCurrentThread ( jVM , & env , NULL ) ;
}
return ( * env ) - > CallVoidMethod ( env , jniCallbackObj , android_haptic_disable ) ;
2020-06-30 23:03:19 +00:00
}
2020-06-10 18:20:11 +00:00
int JNI_OnLoad ( JavaVM * vm , void * reserved )
{
JNIEnv * env ;
2020-07-07 22:22:47 +00:00
jVM = vm ;
2020-06-10 18:20:11 +00:00
if ( ( * vm ) - > GetEnv ( vm , ( void * * ) & env , JNI_VERSION_1_4 ) ! = JNI_OK )
{
ALOGE ( " Failed JNI_OnLoad " ) ;
return - 1 ;
}
2020-06-30 23:03:19 +00:00
return JNI_VERSION_1_4 ;
2020-06-10 18:20:11 +00:00
}
2020-06-28 13:41:34 +00:00
JNIEXPORT jlong JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onCreate ( JNIEnv * env , jclass activityClass , jobject activity ,
2020-06-10 18:20:11 +00:00
jstring commandLineParams )
{
ALOGV ( " GLES3JNILib::onCreate() " ) ;
/* the global arg_xxx structs are initialised within the argtable */
void * argtable [ ] = {
2020-08-21 01:29:21 +00:00
ss = arg_dbl0 ( " s " , " supersampling " , " <double> " , " super sampling value (e.g. 1.0) " ) ,
2020-06-10 18:20:11 +00:00
cpu = arg_int0 ( " c " , " cpu " , " <int> " , " CPU perf index 1-4 (default: 2) " ) ,
gpu = arg_int0 ( " g " , " gpu " , " <int> " , " GPU perf index 1-4 (default: 3) " ) ,
2020-08-21 01:29:21 +00:00
msaa = arg_int0 ( " m " , " msaa " , " <int> " , " MSAA (default: 1) " ) ,
2020-12-28 11:06:37 +00:00
refresh = arg_int0 ( " r " , " refresh " , " <int> " , " Refresh Rate (default: Q1: 72, Q2: 90) " ) ,
2020-08-21 01:29:21 +00:00
end = arg_end ( 20 )
2020-06-10 18:20:11 +00:00
} ;
jboolean iscopy ;
const char * arg = ( * env ) - > GetStringUTFChars ( env , commandLineParams , & iscopy ) ;
char * cmdLine = NULL ;
if ( arg & & strlen ( arg ) )
{
cmdLine = strdup ( arg ) ;
}
( * env ) - > ReleaseStringUTFChars ( env , commandLineParams , arg ) ;
ALOGV ( " Command line %s " , cmdLine ) ;
argv = malloc ( sizeof ( char * ) * 255 ) ;
argc = ParseCommandLine ( strdup ( cmdLine ) , argv ) ;
/* verify the argtable[] entries were allocated sucessfully */
if ( arg_nullcheck ( argtable ) = = 0 ) {
/* Parse the command line as defined by argtable[] */
arg_parse ( argc , argv , argtable ) ;
if ( ss - > count > 0 & & ss - > dval [ 0 ] > 0.0 )
{
SS_MULTIPLIER = ss - > dval [ 0 ] ;
}
if ( cpu - > count > 0 & & cpu - > ival [ 0 ] > 0 & & cpu - > ival [ 0 ] < 10 )
{
CPU_LEVEL = cpu - > ival [ 0 ] ;
}
if ( gpu - > count > 0 & & gpu - > ival [ 0 ] > 0 & & gpu - > ival [ 0 ] < 10 )
{
GPU_LEVEL = gpu - > ival [ 0 ] ;
}
2020-08-21 01:29:21 +00:00
if ( msaa - > count > 0 & & msaa - > ival [ 0 ] > 0 & & msaa - > ival [ 0 ] < 10 )
{
NUM_MULTI_SAMPLES = msaa - > ival [ 0 ] ;
}
2020-12-28 11:06:37 +00:00
if ( refresh - > count > 0 & & refresh - > ival [ 0 ] > 0 & & refresh - > ival [ 0 ] < = 120 )
{
REFRESH = refresh - > ival [ 0 ] ;
}
2020-06-10 18:20:11 +00:00
}
initialize_gl4es ( ) ;
ovrAppThread * appThread = ( ovrAppThread * ) malloc ( sizeof ( ovrAppThread ) ) ;
ovrAppThread_Create ( appThread , env , activity , activityClass ) ;
ovrMessageQueue_Enable ( & appThread - > MessageQueue , true ) ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_CREATE , MQ_WAIT_PROCESSED ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
return ( jlong ) ( ( size_t ) appThread ) ;
}
2020-06-30 23:03:19 +00:00
JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onStart ( JNIEnv * env , jobject obj , jlong handle , jobject obj1 )
2020-06-10 18:20:11 +00:00
{
ALOGV ( " GLES3JNILib::onStart() " ) ;
2020-06-30 23:03:19 +00:00
2021-05-03 19:58:50 +00:00
jniCallbackObj = ( jobject ) ( * env ) - > NewGlobalRef ( env , obj1 ) ;
jclass callbackClass = ( * env ) - > GetObjectClass ( env , jniCallbackObj ) ;
2020-06-30 23:03:19 +00:00
android_shutdown = ( * env ) - > GetMethodID ( env , callbackClass , " shutdown " , " ()V " ) ;
2021-06-02 14:55:46 +00:00
android_haptic_event = ( * env ) - > GetMethodID ( env , callbackClass , " haptic_event " , " (Ljava/lang/String;IIIFF)V " ) ;
android_haptic_updateevent = ( * env ) - > GetMethodID ( env , callbackClass , " haptic_updateevent " , " (Ljava/lang/String;IF)V " ) ;
android_haptic_stopevent = ( * env ) - > GetMethodID ( env , callbackClass , " haptic_stopevent " , " (Ljava/lang/String;)V " ) ;
android_haptic_endframe = ( * env ) - > GetMethodID ( env , callbackClass , " haptic_endframe " , " ()V " ) ;
android_haptic_enable = ( * env ) - > GetMethodID ( env , callbackClass , " haptic_enable " , " ()V " ) ;
android_haptic_disable = ( * env ) - > GetMethodID ( env , callbackClass , " haptic_disable " , " ()V " ) ;
2020-06-30 23:03:19 +00:00
2020-06-10 18:20:11 +00:00
ovrAppThread * appThread = ( ovrAppThread * ) ( ( size_t ) handle ) ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_START , MQ_WAIT_PROCESSED ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
}
2020-06-28 13:41:34 +00:00
JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onResume ( JNIEnv * env , jobject obj , jlong handle )
2020-06-10 18:20:11 +00:00
{
ALOGV ( " GLES3JNILib::onResume() " ) ;
ovrAppThread * appThread = ( ovrAppThread * ) ( ( size_t ) handle ) ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_RESUME , MQ_WAIT_PROCESSED ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
}
2020-06-28 13:41:34 +00:00
JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onPause ( JNIEnv * env , jobject obj , jlong handle )
2020-06-10 18:20:11 +00:00
{
ALOGV ( " GLES3JNILib::onPause() " ) ;
ovrAppThread * appThread = ( ovrAppThread * ) ( ( size_t ) handle ) ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_PAUSE , MQ_WAIT_PROCESSED ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
}
2020-06-28 13:41:34 +00:00
JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onStop ( JNIEnv * env , jobject obj , jlong handle )
2020-06-10 18:20:11 +00:00
{
ALOGV ( " GLES3JNILib::onStop() " ) ;
ovrAppThread * appThread = ( ovrAppThread * ) ( ( size_t ) handle ) ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_STOP , MQ_WAIT_PROCESSED ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
}
2020-06-28 13:41:34 +00:00
JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onDestroy ( JNIEnv * env , jobject obj , jlong handle )
2020-06-10 18:20:11 +00:00
{
ALOGV ( " GLES3JNILib::onDestroy() " ) ;
ovrAppThread * appThread = ( ovrAppThread * ) ( ( size_t ) handle ) ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_DESTROY , MQ_WAIT_PROCESSED ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
ovrMessageQueue_Enable ( & appThread - > MessageQueue , false ) ;
ovrAppThread_Destroy ( appThread , env ) ;
free ( appThread ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Surface lifecycle
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2020-06-28 13:41:34 +00:00
JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onSurfaceCreated ( JNIEnv * env , jobject obj , jlong handle , jobject surface )
2020-06-10 18:20:11 +00:00
{
ALOGV ( " GLES3JNILib::onSurfaceCreated() " ) ;
ovrAppThread * appThread = ( ovrAppThread * ) ( ( size_t ) handle ) ;
ANativeWindow * newNativeWindow = ANativeWindow_fromSurface ( env , surface ) ;
if ( ANativeWindow_getWidth ( newNativeWindow ) < ANativeWindow_getHeight ( newNativeWindow ) )
{
// An app that is relaunched after pressing the home button gets an initial surface with
// the wrong orientation even though android:screenOrientation="landscape" is set in the
// manifest. The choreographer callback will also never be called for this surface because
// the surface is immediately replaced with a new surface with the correct orientation.
ALOGE ( " Surface not in landscape mode! " ) ;
}
ALOGV ( " NativeWindow = ANativeWindow_fromSurface( env, surface ) " ) ;
appThread - > NativeWindow = newNativeWindow ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_SURFACE_CREATED , MQ_WAIT_PROCESSED ) ;
ovrMessage_SetPointerParm ( & message , 0 , appThread - > NativeWindow ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
}
2020-06-28 13:41:34 +00:00
JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onSurfaceChanged ( JNIEnv * env , jobject obj , jlong handle , jobject surface )
2020-06-10 18:20:11 +00:00
{
ALOGV ( " GLES3JNILib::onSurfaceChanged() " ) ;
ovrAppThread * appThread = ( ovrAppThread * ) ( ( size_t ) handle ) ;
ANativeWindow * newNativeWindow = ANativeWindow_fromSurface ( env , surface ) ;
if ( ANativeWindow_getWidth ( newNativeWindow ) < ANativeWindow_getHeight ( newNativeWindow ) )
{
// An app that is relaunched after pressing the home button gets an initial surface with
// the wrong orientation even though android:screenOrientation="landscape" is set in the
// manifest. The choreographer callback will also never be called for this surface because
// the surface is immediately replaced with a new surface with the correct orientation.
ALOGE ( " Surface not in landscape mode! " ) ;
}
if ( newNativeWindow ! = appThread - > NativeWindow )
{
if ( appThread - > NativeWindow ! = NULL )
{
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_SURFACE_DESTROYED , MQ_WAIT_PROCESSED ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
ALOGV ( " ANativeWindow_release( NativeWindow ) " ) ;
ANativeWindow_release ( appThread - > NativeWindow ) ;
appThread - > NativeWindow = NULL ;
}
if ( newNativeWindow ! = NULL )
{
ALOGV ( " NativeWindow = ANativeWindow_fromSurface( env, surface ) " ) ;
appThread - > NativeWindow = newNativeWindow ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_SURFACE_CREATED , MQ_WAIT_PROCESSED ) ;
ovrMessage_SetPointerParm ( & message , 0 , appThread - > NativeWindow ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
}
}
else if ( newNativeWindow ! = NULL )
{
ANativeWindow_release ( newNativeWindow ) ;
}
}
2020-06-28 13:41:34 +00:00
JNIEXPORT void JNICALL Java_com_drbeef_rtcwquest_GLES3JNILib_onSurfaceDestroyed ( JNIEnv * env , jobject obj , jlong handle )
2020-06-10 18:20:11 +00:00
{
ALOGV ( " GLES3JNILib::onSurfaceDestroyed() " ) ;
ovrAppThread * appThread = ( ovrAppThread * ) ( ( size_t ) handle ) ;
ovrMessage message ;
ovrMessage_Init ( & message , MESSAGE_ON_SURFACE_DESTROYED , MQ_WAIT_PROCESSED ) ;
ovrMessageQueue_PostMessage ( & appThread - > MessageQueue , & message ) ;
ALOGV ( " ANativeWindow_release( NativeWindow ) " ) ;
ANativeWindow_release ( appThread - > NativeWindow ) ;
appThread - > NativeWindow = NULL ;
}