Several Changes

- world scale cvar - defaulted to 32.0
- extra latency mode enabled by default
- used sound implementation (OpenSLES) from RTCW which should eliminate the slight delay that SDL/OpenAL seems to have
- multiple cvar changes courtesy of vr_bummser
This commit is contained in:
Simon 2022-01-30 23:36:14 +00:00
parent 4b4ee4ec6e
commit 1b8dbcb6dc
21 changed files with 643 additions and 494 deletions

View file

@ -254,6 +254,7 @@ RGL1DIR=$(MOUNT_DIR)/renderergl1
RGL2DIR=$(MOUNT_DIR)/renderergl2
CMDIR=$(MOUNT_DIR)/qcommon
SDLDIR=$(MOUNT_DIR)/sdl
ANDROIDDIR=$(MOUNT_DIR)/android
VRDIR=$(MOUNT_DIR)/vr
ASMDIR=$(MOUNT_DIR)/asm
SYSDIR=$(MOUNT_DIR)/sys
@ -456,7 +457,7 @@ ifeq ($(PLATFORM),android)
THREAD_LIBS =
LIBS = -ldl -lm -Wl,--no-undefined -shared
CLIENT_LIBS = -lGLESv3
CLIENT_LIBS = -lGLESv3 -lOpenSLES
RENDERER_LIBS = -lGLESv3 -lEGL
# SDL
@ -1478,6 +1479,7 @@ makedirs:
@$(MKDIR) $(B)/renderergl2
@$(MKDIR) $(B)/renderergl2/glsl
@$(MKDIR) $(B)/ded
@$(MKDIR) $(B)/$(BASEGAME)/android
@$(MKDIR) $(B)/$(BASEGAME)/cgame
@$(MKDIR) $(B)/$(BASEGAME)/game
@$(MKDIR) $(B)/$(BASEGAME)/ui
@ -1808,7 +1810,7 @@ Q3OBJ = \
$(B)/client/l_struct.o \
\
$(B)/client/sdl_input.o \
$(B)/client/sdl_snd.o \
$(B)/client/android_snd.o \
\
$(B)/client/vr_base.o \
$(B)/client/vr_input.o \
@ -2752,6 +2754,9 @@ $(B)/client/%.o: $(ZDIR)/%.c
$(B)/client/%.o: $(SDLDIR)/%.c
$(DO_CC)
$(B)/client/%.o: $(ANDROIDDIR)/%.c
$(DO_CC)
$(B)/client/%.o: $(VRDIR)/%.c
$(DO_CC)

516
code/android/android_snd.c Normal file
View file

@ -0,0 +1,516 @@
/*
===========================================================================
Return to Castle Wolfenstein single player GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”).
RTCW SP Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
RTCW SP Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with RTCW SP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
//#include <sys/shm.h>
#include <sys/wait.h>
#ifdef __linux__ // rb0101023 - guard this
#include <linux/soundcard.h>
#endif
#ifdef __FreeBSD__ // rb0101023 - added
#include <sys/soundcard.h>
#endif
#include <stdio.h>
#include "../qcommon/q_shared.h"
#include "../client/snd_local.h"
//Updated by Emile Belanger for OpenSL
// for native audio
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <pthread.h>
pthread_mutex_t dma_mutex;
// engine interfaces
static SLObjectItf engineObject = NULL;
static SLEngineItf engineEngine;
// output mix interfaces
static SLObjectItf outputMixObject = NULL;
// buffer queue player interfaces
static SLObjectItf bqPlayerObject = NULL;
static SLPlayItf bqPlayerPlay;
#ifdef ANDROID_NDK
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
#else
static SLBufferQueueItf bqPlayerBufferQueue;
#endif
static SLEffectSendItf bqPlayerEffectSend;
static SLMuteSoloItf bqPlayerMuteSolo;
static SLVolumeItf bqPlayerVolume;
void myassert(int v,const char * message)
{
if (!v)
Com_Printf("myassert: %s",message);
}
int audio_fd;
int snd_inited = 0;
cvar_t *sndbits;
cvar_t *sndspeed;
cvar_t *sndchannels;
cvar_t *snddevice;
/* Some devices may work only with 48000 */
static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 };
static int dmapos = 0;
static int dmasize = 0;
#define OPENSL_BUFF_LEN 1024
static unsigned char play_buffer[OPENSL_BUFF_LEN];
void bqPause(int p)
{
int result;
if (p)
{
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
myassert(SL_RESULT_SUCCESS == result,"SetPlayState");
}
else
{
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
myassert(SL_RESULT_SUCCESS == result,"SetPlayState");
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, "\0", 1);
myassert(SL_RESULT_SUCCESS == result,"Enqueue first buffer");
}
}
//NOTE!! There are definetly threading issues with this, but it appears to work for now...
// TEST is me testing black screen issue!
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
//LOGI("bqPlayerCallback");
// TEST pthread_mutex_lock(&dma_mutex);
int pos = (dmapos * (dma.samplebits/8));
if (pos >= dmasize)
dmapos = pos = 0;
int len = OPENSL_BUFF_LEN;
int factor = 2*2;
int FrameCount = (unsigned int)OPENSL_BUFF_LEN / factor;
if (!snd_inited) /* shouldn't happen, but just in case... */
{
memset(play_buffer, '\0', len);
return;
}
else
{
int tobufend = dmasize - pos; /* bytes to buffer's end. */
int len1 = len;
int len2 = 0;
if (len1 > tobufend)
{
len1 = tobufend;
len2 = len - len1;
}
memcpy(play_buffer, dma.buffer + pos, len1);
if (len2 <= 0)
dmapos += (len1 / (dma.samplebits/8));
else /* wraparound? */
{
memcpy(play_buffer+len1, dma.buffer, len2);
dmapos = (len2 / (dma.samplebits/8));
}
}
if (dmapos >= dmasize)
dmapos = 0;
SLresult result;
//LOGI("Frame count = %d",FrameCount);
if (FrameCount == 0)
FrameCount = 1;
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, play_buffer,FrameCount * factor);
myassert(SL_RESULT_SUCCESS == result,"Enqueue failed");
// TEST pthread_mutex_unlock(&dma_mutex);
}
qboolean SNDDMA_Init( void ) {
int rc;
int fmt;
int tmp;
int i;
// char *s; // bk001204 - unused
struct audio_buf_info info;
int caps;
extern uid_t saved_euid;
if ( snd_inited ) {
return 1;
}
dmapos = 0;
dma.samplebits = 16;
dma.channels = 2;
dma.samples = 1024*16;
dma.submission_chunk = 1024*2;
//dma.submission_chunk = 1;
dma.speed = 44100;
dma.speed = 22050;
dmasize = (dma.samples * (dma.samplebits/8));
dma.buffer = calloc(1, dmasize);
SLresult result;
// create engine
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
myassert(SL_RESULT_SUCCESS == result,"slCreateEngine");
// realize the engine
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
myassert(SL_RESULT_SUCCESS == result,"Realize");
// get the engine interface, which is needed in order to create other objects
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
myassert(SL_RESULT_SUCCESS == result,"GetInterface");
// create output mix
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
myassert(SL_RESULT_SUCCESS == result,"CreateOutputMix");
// realize the output mix
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
myassert(SL_RESULT_SUCCESS == result,"Realize output mix");
//CREATE THE PLAYER
// configure audio source
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_22_05,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN};
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
// configure audio sink
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL};
// create audio player
Com_Printf("create audio player");
const SLInterfaceID ids[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
1, ids, req);
myassert(SL_RESULT_SUCCESS == result,"CreateAudioPlayer");
// realize the player
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
myassert(SL_RESULT_SUCCESS == result,"Realize AudioPlayer");
// get the play interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
myassert(SL_RESULT_SUCCESS == result,"GetInterface AudioPlayer");
// get the buffer queue interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
&bqPlayerBufferQueue);
myassert(SL_RESULT_SUCCESS == result,"GetInterface buffer queue");
// register callback on the buffer queue
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
myassert(SL_RESULT_SUCCESS == result,"RegisterCallback");
snd_inited = 1;
// set the player's state to playing
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
myassert(SL_RESULT_SUCCESS == result,"SetPlayState");
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, "\0", 1);
myassert(SL_RESULT_SUCCESS == result,"Enqueue first buffer");
return 1;
}
int SNDDMA_GetDMAPos( void ) {
struct count_info count;
if ( !snd_inited ) {
return 0;
}
// TEST pthread_mutex_lock(&dma_mutex);
//LOGI("SNDDMA_GetDMAPos");
return dmapos;
}
void SNDDMA_Shutdown( void ) {
//LOGI("shutdown Sound");
bqPause(1);
(*bqPlayerObject)->Destroy(bqPlayerObject);
(*outputMixObject)->Destroy(outputMixObject);
(*engineObject)->Destroy(engineObject);
bqPlayerObject = NULL;
outputMixObject = NULL;
engineObject = NULL;
}
/*
==============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
===============
*/
void SNDDMA_Submit( void ) {
//LOGI("SNDDMA_Submit");
// TEST pthread_mutex_unlock(&dma_mutex);
}
void SNDDMA_BeginPainting( void ) {
//LOGI("SNDDMA_BeginPainting");
//pthread_mutex_lock(&dma_mutex);
}
/*
========================================================================
BACKGROUND FILE STREAMING
========================================================================
*/
#if 1
void Sys_InitStreamThread( void ) {
}
void Sys_ShutdownStreamThread( void ) {
}
void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
}
void Sys_EndStreamedFile( fileHandle_t f ) {
}
int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
return FS_Read( buffer, size * count, f );
}
void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
FS_Seek( f, offset, origin );
}
#else
typedef struct
{
fileHandle_t file;
byte *buffer;
qboolean eof;
int bufferSize;
int streamPosition; // next byte to be returned by Sys_StreamRead
int threadPosition; // next byte to be read from file
} streamState_t;
streamState_t stream;
/*
===============
Sys_StreamThread
A thread will be sitting in this loop forever
================
*/
void Sys_StreamThread( void ) {
int buffer;
int count;
int readCount;
int bufferPoint;
int r;
// if there is any space left in the buffer, fill it up
if ( !stream.eof ) {
count = stream.bufferSize - ( stream.threadPosition - stream.streamPosition );
if ( count ) {
bufferPoint = stream.threadPosition % stream.bufferSize;
buffer = stream.bufferSize - bufferPoint;
readCount = buffer < count ? buffer : count;
r = FS_Read( stream.buffer + bufferPoint, readCount, stream.file );
stream.threadPosition += r;
if ( r != readCount ) {
stream.eof = qtrue;
}
}
}
}
/*
===============
Sys_InitStreamThread
================
*/
void Sys_InitStreamThread( void ) {
}
/*
===============
Sys_ShutdownStreamThread
================
*/
void Sys_ShutdownStreamThread( void ) {
}
/*
===============
Sys_BeginStreamedFile
================
*/
void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
if ( stream.file ) {
Com_Error( ERR_FATAL, "Sys_BeginStreamedFile: unclosed stream" );
}
stream.file = f;
stream.buffer = Z_Malloc( readAhead );
stream.bufferSize = readAhead;
stream.streamPosition = 0;
stream.threadPosition = 0;
stream.eof = qfalse;
}
/*
===============
Sys_EndStreamedFile
================
*/
void Sys_EndStreamedFile( fileHandle_t f ) {
if ( f != stream.file ) {
Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file" );
}
stream.file = 0;
Z_Free( stream.buffer );
}
/*
===============
Sys_StreamedRead
================
*/
int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
int available;
int remaining;
int sleepCount;
int copy;
int bufferCount;
int bufferPoint;
byte *dest;
dest = (byte *)buffer;
remaining = size * count;
if ( remaining <= 0 ) {
Com_Error( ERR_FATAL, "Streamed read with non-positive size" );
}
sleepCount = 0;
while ( remaining > 0 )
{
available = stream.threadPosition - stream.streamPosition;
if ( !available ) {
if ( stream.eof ) {
break;
}
Sys_StreamThread();
continue;
}
bufferPoint = stream.streamPosition % stream.bufferSize;
bufferCount = stream.bufferSize - bufferPoint;
copy = available < bufferCount ? available : bufferCount;
if ( copy > remaining ) {
copy = remaining;
}
memcpy( dest, stream.buffer + bufferPoint, copy );
stream.streamPosition += copy;
dest += copy;
remaining -= copy;
}
return ( count * size - remaining ) / size;
}
/*
===============
Sys_StreamSeek
================
*/
void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
// clear to that point
FS_Seek( f, offset, origin );
stream.streamPosition = 0;
stream.threadPosition = 0;
stream.eof = qfalse;
}
#endif

View file

@ -199,6 +199,8 @@ void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text
#endif
float trap_Cvar_VariableValue( const char *var_name );
/*
==============
CG_DrawField
@ -2666,13 +2668,15 @@ void CG_DrawActive( stereoFrame_t stereoView ) {
vec3_t baseOrg;
VectorCopy( cg.refdef.vieworg, baseOrg );
float worldscale = trap_Cvar_VariableValue("vr_worldscale");
float ipd = 0.065f;
float separation = stereoView == STEREO_LEFT ?
WORLD_SCALE * (-ipd / 2) : //left
WORLD_SCALE * (ipd / 2); // right
worldscale * (-ipd / 2) : //left
worldscale * (ipd / 2); // right
cg.refdef.vieworg[2] -= PLAYER_HEIGHT;
cg.refdef.vieworg[2] += cgVR->hmdposition[1] * WORLD_SCALE;
cg.refdef.vieworg[2] += cgVR->hmdposition[1] * worldscale;
VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );

View file

@ -253,9 +253,9 @@ static cvarTable_t cvarTable[] = {
{ &cg_centertime, "cg_centertime", "3", CVAR_CHEAT },
{ &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
{ &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
{ &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT },
{ &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
{ &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
{ &cg_bobup , "cg_bobup", "0.0", CVAR_CHEAT },
{ &cg_bobpitch, "cg_bobpitch", "0.0", CVAR_ARCHIVE },
{ &cg_bobroll, "cg_bobroll", "0.0", CVAR_ARCHIVE },
{ &cg_weaponbob, "cg_weaponbob", "1", CVAR_ARCHIVE },
{ &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
{ &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },

View file

@ -217,6 +217,13 @@ void rotateAboutOrigin(float x, float y, float rotation, vec2_t out)
out[1] = cosf(DEG2RAD(-rotation)) * y - sinf(DEG2RAD(-rotation)) * x;
}
float trap_Cvar_VariableValue( const char *var_name ) {
char buf[128];
trap_Cvar_VariableStringBuffer(var_name, buf, sizeof(buf));
return atof(buf);
}
void convertFromVR(vec3_t in, vec3_t offset, vec3_t out)
{
vec3_t vrSpace;
@ -227,8 +234,9 @@ void convertFromVR(vec3_t in, vec3_t offset, vec3_t out)
vrSpace[0] = -r[0];
vrSpace[1] = -r[1];
float worldscale = trap_Cvar_VariableValue("vr_worldscale");
vec3_t temp;
VectorScale(vrSpace, WORLD_SCALE, temp);
VectorScale(vrSpace, worldscale, temp);
if (offset) {
VectorAdd(temp, offset, out);
@ -241,8 +249,9 @@ void CG_CalculateVRWeaponPosition( vec3_t origin, vec3_t angles )
{
convertFromVR(cgVR->calculated_weaponoffset, cg.refdef.vieworg, origin);
float worldscale = trap_Cvar_VariableValue("vr_worldscale");
origin[2] -= PLAYER_HEIGHT;
origin[2] += cgVR->hmdposition[1] * WORLD_SCALE;
origin[2] += cgVR->hmdposition[1] * worldscale;
VectorCopy(cgVR->weaponangles, angles);
@ -1252,7 +1261,11 @@ static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
// CPMA "true" lightning
if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {
vec3_t angle;
int i;
vec3_t dummy;
CG_CalculateVRWeaponPosition(dummy, angle);
/* int i;
for (i = 0; i < 3; i++) {
float a = cent->lerpAngles[i] - cg.refdefViewAngles[i];
@ -1271,7 +1284,7 @@ static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
angle[i] -= 360;
}
}
*/
AngleVectors(angle, forward, NULL, NULL );
VectorCopy(cent->lerpOrigin, muzzlePoint );
// VectorCopy(cg.refdef.vieworg, muzzlePoint );

View file

@ -27,6 +27,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../sys/sys_local.h"
#include "../sys/sys_loadlib.h"
#include "../vr/vr_base.h"
#ifdef USE_MUMBLE
#include "libmumblelink.h"
#endif
@ -1433,7 +1435,7 @@ void CL_Disconnect( qboolean showMainMenu ) {
}
SCR_StopCinematic ();
S_ClearSoundBuffer();
S_ClearSoundBuffer( );
// send a disconnect message to the server
// send it a few times in case one is dropped
@ -3509,6 +3511,8 @@ void CL_Init( void ) {
CL_InitInput ();
VR_InitCvars();
//
// register our variables
//

View file

@ -507,7 +507,7 @@ void CL_ReadPackets (void);
void CL_WritePacket( void );
void IN_CenterView (void);
void CL_CGameSetVRClientInfo();
void CL_CGameSetVRClientInfo( void );
void CL_VerifyCode( void );

View file

@ -1255,6 +1255,8 @@ void S_GetSoundtime(void)
return;
}
dma.fullsamples = dma.samples / dma.channels;
// it is possible to miscount buffers if it has wrapped twice between
// calls to S_Update. Oh well.
samplepos = SNDDMA_GetDMAPos();
@ -1338,8 +1340,6 @@ void S_Update_(void) {
if (endtime - s_soundtime > dma.fullsamples)
endtime = s_soundtime + dma.fullsamples;
SNDDMA_BeginPainting ();
S_PaintChannels (endtime);

View file

@ -52,8 +52,9 @@ void convertFromVR(gentity_t *ent, vec3_t in, vec3_t offset, vec3_t out)
vrSpace[0] = -r[0];
vrSpace[1] = -r[1];
float worldscale = trap_Cvar_VariableValue("vr_worldscale");
vec3_t temp;
VectorScale(vrSpace, WORLD_SCALE, temp);
VectorScale(vrSpace, worldscale, temp);
if (offset) {
VectorAdd(temp, offset, out);
@ -809,9 +810,10 @@ void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up,
}
else if (gVR != NULL)
{
float worldscale = trap_Cvar_VariableValue("vr_worldscale");
convertFromVR(ent, gVR->calculated_weaponoffset, ent->r.currentOrigin, muzzlePoint);
muzzlePoint[2] -= ent->client->ps.viewheight;
muzzlePoint[2] += gVR->hmdposition[1] * WORLD_SCALE;
muzzlePoint[2] += gVR->hmdposition[1] * worldscale;
}
// snap to integer coordinates for more efficient network bandwidth usage

View file

@ -193,7 +193,7 @@ static cvarTable_t cvarTable[] = {
{ &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
{ &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
{ &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
{ &ui_drawCrosshairNames, "cg_drawCrosshairNames", "0", CVAR_ARCHIVE },
{ &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
{ &ui_server1, "server1", "", CVAR_ARCHIVE },

View file

@ -909,6 +909,27 @@ char *Q_strupr( char *s1 ) {
}
char* Q_strrchr( const char* string, int c ) {
char cc = c;
char *s;
char *sp = (char *)0;
s = (char*)string;
while ( *s )
{
if ( *s == cc ) {
sp = s;
}
s++;
}
if ( cc == 0 ) {
sp = s;
}
return sp;
}
// never goes past bounds or leaves without a terminating 0
void Q_strcat( char *dest, int size, const char *src ) {
int l1;

View file

@ -256,6 +256,14 @@ typedef int clipHandle_t;
#define BIG_INFO_VALUE 8192
//#define SND_NORMAL 0x000 // (default) Allow sound to be cut off only by the same sound on this channel
#define SND_OKTOCUT 0x001 // Allow sound to be cut off by any following sounds on this channel
#define SND_REQUESTCUT 0x002 // Allow sound to be cut off by following sounds on this channel only for sounds who request cutoff
#define SND_CUTOFF 0x004 // Cut off sounds on this channel that are marked 'SND_REQUESTCUT'
#define SND_CUTOFF_ALL 0x008 // Cut off all sounds on this channel
#define SND_NOCUT 0x010 // Don't cut off. Always let finish (overridden by SND_CUTOFF_ALL)
#define MAX_QPATH 64 // max length of a quake game pathname
#ifdef PATH_MAX
#define MAX_OSPATH PATH_MAX
@ -825,6 +833,7 @@ int Q_stricmpn (const char *s1, const char *s2, int n);
char *Q_strlwr( char *s1 );
char *Q_strupr( char *s1 );
const char *Q_stristr( const char *s, const char *find);
char *Q_strrchr( const char* string, int c );
// buffer size safe library replacements
void Q_strncpyz( char *dest, const char *src, int destsize );

View file

@ -1078,8 +1078,8 @@ void R_Register( void )
r_fastsky = ri.Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE );
r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
r_drawSun = ri.Cvar_Get( "r_drawSun", "0", CVAR_ARCHIVE );
r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE );
r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "0", CVAR_ARCHIVE );
r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "0", CVAR_ARCHIVE );
r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE);
r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE );
r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0",

View file

@ -1193,11 +1193,11 @@ void R_Register( void )
r_ext_direct_state_access = ri.Cvar_Get("r_ext_direct_state_access", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic",
"0", CVAR_ARCHIVE | CVAR_LATCH );
r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH );
"1", CVAR_ARCHIVE | CVAR_LATCH );
r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "4", CVAR_ARCHIVE | CVAR_LATCH );
r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_picmip = ri.Cvar_Get ("r_picmip", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH );
ri.Cvar_CheckRange( r_picmip, 0, 16, qtrue );
r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH );
@ -1310,7 +1310,7 @@ void R_Register( void )
r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
r_dlightBacks = ri.Cvar_Get( "r_dlightBacks", "1", CVAR_ARCHIVE );
r_finish = ri.Cvar_Get ("r_finish", "0", CVAR_ARCHIVE);
r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE );
r_textureMode = ri.Cvar_Get( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
r_swapInterval = ri.Cvar_Get( "r_swapInterval", "0",
CVAR_ARCHIVE | CVAR_LATCH );
r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE );

View file

@ -1,445 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <stdlib.h>
#include <stdio.h>
#ifdef USE_LOCAL_HEADERS
# include "SDL.h"
#else
# include <SDL.h>
#endif
#include "../qcommon/q_shared.h"
#include "../client/snd_local.h"
#include "../client/client.h"
qboolean snd_inited = qfalse;
cvar_t *s_sdlBits;
cvar_t *s_sdlSpeed;
cvar_t *s_sdlChannels;
cvar_t *s_sdlDevSamps;
cvar_t *s_sdlMixSamps;
/* The audio callback. All the magic happens here. */
static int dmapos = 0;
static int dmasize = 0;
static SDL_AudioDeviceID sdlPlaybackDevice;
#if defined USE_VOIP && SDL_VERSION_ATLEAST( 2, 0, 5 )
#define USE_SDL_AUDIO_CAPTURE
static SDL_AudioDeviceID sdlCaptureDevice;
static cvar_t *s_sdlCapture;
static float sdlMasterGain = 1.0f;
#endif
/*
===============
SNDDMA_AudioCallback
===============
*/
static void SNDDMA_AudioCallback(void *userdata, Uint8 *stream, int len)
{
int pos = (dmapos * (dma.samplebits/8));
if (pos >= dmasize)
dmapos = pos = 0;
if (!snd_inited) /* shouldn't happen, but just in case... */
{
memset(stream, '\0', len);
return;
}
else
{
int tobufend = dmasize - pos; /* bytes to buffer's end. */
int len1 = len;
int len2 = 0;
if (len1 > tobufend)
{
len1 = tobufend;
len2 = len - len1;
}
memcpy(stream, dma.buffer + pos, len1);
if (len2 <= 0)
dmapos += (len1 / (dma.samplebits/8));
else /* wraparound? */
{
memcpy(stream+len1, dma.buffer, len2);
dmapos = (len2 / (dma.samplebits/8));
}
}
if (dmapos >= dmasize)
dmapos = 0;
#ifdef USE_SDL_AUDIO_CAPTURE
if (sdlMasterGain != 1.0f)
{
int i;
if (dma.isfloat && (dma.samplebits == 32))
{
float *ptr = (float *) stream;
len /= sizeof (*ptr);
for (i = 0; i < len; i++, ptr++)
{
*ptr *= sdlMasterGain;
}
}
else if (dma.samplebits == 16)
{
Sint16 *ptr = (Sint16 *) stream;
len /= sizeof (*ptr);
for (i = 0; i < len; i++, ptr++)
{
*ptr = (Sint16) (((float) *ptr) * sdlMasterGain);
}
}
else if (dma.samplebits == 8)
{
Uint8 *ptr = (Uint8 *) stream;
len /= sizeof (*ptr);
for (i = 0; i < len; i++, ptr++)
{
*ptr = (Uint8) (((float) *ptr) * sdlMasterGain);
}
}
}
#endif
}
static struct
{
Uint16 enumFormat;
char *stringFormat;
} formatToStringTable[ ] =
{
{ AUDIO_U8, "AUDIO_U8" },
{ AUDIO_S8, "AUDIO_S8" },
{ AUDIO_U16LSB, "AUDIO_U16LSB" },
{ AUDIO_S16LSB, "AUDIO_S16LSB" },
{ AUDIO_U16MSB, "AUDIO_U16MSB" },
{ AUDIO_S16MSB, "AUDIO_S16MSB" },
{ AUDIO_F32LSB, "AUDIO_F32LSB" },
{ AUDIO_F32MSB, "AUDIO_F32MSB" }
};
static int formatToStringTableSize = ARRAY_LEN( formatToStringTable );
/*
===============
SNDDMA_PrintAudiospec
===============
*/
static void SNDDMA_PrintAudiospec(const char *str, const SDL_AudioSpec *spec)
{
int i;
char *fmt = NULL;
Com_Printf("%s:\n", str);
for( i = 0; i < formatToStringTableSize; i++ ) {
if( spec->format == formatToStringTable[ i ].enumFormat ) {
fmt = formatToStringTable[ i ].stringFormat;
}
}
if( fmt ) {
Com_Printf( " Format: %s\n", fmt );
} else {
Com_Printf( " Format: " S_COLOR_RED "UNKNOWN\n");
}
Com_Printf( " Freq: %d\n", (int) spec->freq );
Com_Printf( " Samples: %d\n", (int) spec->samples );
Com_Printf( " Channels: %d\n", (int) spec->channels );
}
/*
===============
SNDDMA_Init
===============
*/
qboolean SNDDMA_Init(void)
{
SDL_AudioSpec desired;
SDL_AudioSpec obtained;
int tmp;
if (snd_inited)
return qtrue;
if (!s_sdlBits) {
s_sdlBits = Cvar_Get("s_sdlBits", "16", CVAR_ARCHIVE);
s_sdlSpeed = Cvar_Get("s_sdlSpeed", "0", CVAR_ARCHIVE);
s_sdlChannels = Cvar_Get("s_sdlChannels", "2", CVAR_ARCHIVE);
s_sdlDevSamps = Cvar_Get("s_sdlDevSamps", "0", CVAR_ARCHIVE);
s_sdlMixSamps = Cvar_Get("s_sdlMixSamps", "0", CVAR_ARCHIVE);
}
Com_Printf( "SDL_Init( SDL_INIT_AUDIO )... " );
if (SDL_Init(SDL_INIT_AUDIO) != 0)
{
Com_Printf( "FAILED (%s)\n", SDL_GetError( ) );
return qfalse;
}
Com_Printf( "OK\n" );
Com_Printf( "SDL audio driver is \"%s\".\n", SDL_GetCurrentAudioDriver( ) );
memset(&desired, '\0', sizeof (desired));
memset(&obtained, '\0', sizeof (obtained));
tmp = ((int) s_sdlBits->value);
if ((tmp != 16) && (tmp != 8))
tmp = 16;
desired.freq = (int) s_sdlSpeed->value;
if(!desired.freq) desired.freq = 22050;
desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8);
// I dunno if this is the best idea, but I'll give it a try...
// should probably check a cvar for this...
if (s_sdlDevSamps->value)
desired.samples = s_sdlDevSamps->value;
else
{
// just pick a sane default.
if (desired.freq <= 11025)
desired.samples = 256;
else if (desired.freq <= 22050)
desired.samples = 512;
else if (desired.freq <= 44100)
desired.samples = 1024;
else
desired.samples = 2048; // (*shrug*)
}
desired.channels = (int) s_sdlChannels->value;
desired.callback = SNDDMA_AudioCallback;
sdlPlaybackDevice = SDL_OpenAudioDevice(NULL, SDL_FALSE, &desired, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE);
if (sdlPlaybackDevice == 0)
{
Com_Printf("SDL_OpenAudioDevice() failed: %s\n", SDL_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return qfalse;
}
SNDDMA_PrintAudiospec("SDL_AudioSpec", &obtained);
// dma.samples needs to be big, or id's mixer will just refuse to
// work at all; we need to keep it significantly bigger than the
// amount of SDL callback samples, and just copy a little each time
// the callback runs.
// 32768 is what the OSS driver filled in here on my system. I don't
// know if it's a good value overall, but at least we know it's
// reasonable...this is why I let the user override.
tmp = s_sdlMixSamps->value;
if (!tmp)
tmp = (obtained.samples * obtained.channels) * 10;
// samples must be divisible by number of channels
tmp -= tmp % obtained.channels;
dmapos = 0;
dma.samplebits = SDL_AUDIO_BITSIZE(obtained.format);
dma.isfloat = SDL_AUDIO_ISFLOAT(obtained.format);
dma.channels = obtained.channels;
dma.samples = tmp;
dma.fullsamples = dma.samples / dma.channels;
dma.submission_chunk = 1;
dma.speed = obtained.freq;
dmasize = (dma.samples * (dma.samplebits/8));
dma.buffer = calloc(1, dmasize);
#ifdef USE_SDL_AUDIO_CAPTURE
// !!! FIXME: some of these SDL_OpenAudioDevice() values should be cvars.
s_sdlCapture = Cvar_Get( "s_sdlCapture", "1", CVAR_ARCHIVE | CVAR_LATCH );
// !!! FIXME: pulseaudio capture records audio the entire time the program is running. https://bugzilla.libsdl.org/show_bug.cgi?id=4087
if (Q_stricmp(SDL_GetCurrentAudioDriver(), "pulseaudio") == 0)
{
Com_Printf("SDL audio capture support disabled for pulseaudio (https://bugzilla.libsdl.org/show_bug.cgi?id=4087)\n");
}
else if (!s_sdlCapture->integer)
{
Com_Printf("SDL audio capture support disabled by user ('+set s_sdlCapture 1' to enable)\n");
}
#if USE_MUMBLE
else if (cl_useMumble->integer)
{
Com_Printf("SDL audio capture support disabled for Mumble support\n");
}
#endif
else
{
/* !!! FIXME: list available devices and let cvar specify one, like OpenAL does */
SDL_AudioSpec spec;
SDL_zero(spec);
spec.freq = 48000;
spec.format = AUDIO_S16SYS;
spec.channels = 1;
spec.samples = VOIP_MAX_PACKET_SAMPLES * 4;
sdlCaptureDevice = SDL_OpenAudioDevice(NULL, SDL_TRUE, &spec, NULL, 0);
Com_Printf( "SDL capture device %s.\n",
(sdlCaptureDevice == 0) ? "failed to open" : "opened");
}
sdlMasterGain = 1.0f;
#endif
Com_Printf("Starting SDL audio callback...\n");
SDL_PauseAudioDevice(sdlPlaybackDevice, 0); // start callback.
// don't unpause the capture device; we'll do that in StartCapture.
Com_Printf("SDL audio initialized.\n");
snd_inited = qtrue;
return qtrue;
}
/*
===============
SNDDMA_GetDMAPos
===============
*/
int SNDDMA_GetDMAPos(void)
{
return dmapos;
}
/*
===============
SNDDMA_Shutdown
===============
*/
void SNDDMA_Shutdown(void)
{
if (sdlPlaybackDevice != 0)
{
Com_Printf("Closing SDL audio playback device...\n");
SDL_CloseAudioDevice(sdlPlaybackDevice);
Com_Printf("SDL audio playback device closed.\n");
sdlPlaybackDevice = 0;
}
#ifdef USE_SDL_AUDIO_CAPTURE
if (sdlCaptureDevice)
{
Com_Printf("Closing SDL audio capture device...\n");
SDL_CloseAudioDevice(sdlCaptureDevice);
Com_Printf("SDL audio capture device closed.\n");
sdlCaptureDevice = 0;
}
#endif
SDL_QuitSubSystem(SDL_INIT_AUDIO);
free(dma.buffer);
dma.buffer = NULL;
dmapos = dmasize = 0;
snd_inited = qfalse;
Com_Printf("SDL audio shut down.\n");
}
/*
===============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
===============
*/
void SNDDMA_Submit(void)
{
SDL_UnlockAudioDevice(sdlPlaybackDevice);
}
/*
===============
SNDDMA_BeginPainting
===============
*/
void SNDDMA_BeginPainting (void)
{
SDL_LockAudioDevice(sdlPlaybackDevice);
}
#ifdef USE_VOIP
void SNDDMA_StartCapture(void)
{
#ifdef USE_SDL_AUDIO_CAPTURE
if (sdlCaptureDevice)
{
SDL_ClearQueuedAudio(sdlCaptureDevice);
SDL_PauseAudioDevice(sdlCaptureDevice, 0);
}
#endif
}
int SNDDMA_AvailableCaptureSamples(void)
{
#ifdef USE_SDL_AUDIO_CAPTURE
// divided by 2 to convert from bytes to (mono16) samples.
return sdlCaptureDevice ? (SDL_GetQueuedAudioSize(sdlCaptureDevice) / 2) : 0;
#else
return 0;
#endif
}
void SNDDMA_Capture(int samples, byte *data)
{
#ifdef USE_SDL_AUDIO_CAPTURE
// multiplied by 2 to convert from (mono16) samples to bytes.
if (sdlCaptureDevice)
{
SDL_DequeueAudio(sdlCaptureDevice, data, samples * 2);
}
else
#endif
{
SDL_memset(data, '\0', samples * 2);
}
}
void SNDDMA_StopCapture(void)
{
#ifdef USE_SDL_AUDIO_CAPTURE
if (sdlCaptureDevice)
{
SDL_PauseAudioDevice(sdlCaptureDevice, 1);
}
#endif
}
void SNDDMA_MasterGain( float val )
{
#ifdef USE_SDL_AUDIO_CAPTURE
sdlMasterGain = val;
#endif
}
#endif

View file

@ -17,6 +17,8 @@
static engine_t vr_engine;
cvar_t *vr_worldscale = NULL;
engine_t* VR_Init( ovrJava java )
{
ovrInitParms initParams;
@ -33,6 +35,11 @@ engine_t* VR_Init( ovrJava java )
return &vr_engine;
}
void VR_InitCvars( void )
{
vr_worldscale = Cvar_Get ("vr_worldscale", "32.0", CVAR_ARCHIVE);
}
void VR_Destroy( engine_t* engine )
{
if (engine == &vr_engine) {

View file

@ -5,10 +5,10 @@
#include "vr_types.h"
#define WORLD_SCALE 37.5f
#define PLAYER_HEIGHT 48
engine_t* VR_Init( ovrJava java );
void VR_InitCvars( void );
void VR_Destroy( engine_t* engine );
void VR_EnterVR( engine_t* engine, ovrJava java );
void VR_LeaveVR( engine_t* engine );

View file

@ -10,6 +10,7 @@
#include "../VrApi/Include/VrApi_Helpers.h"
#include "vr_clientinfo.h"
#include <unistd.h>
#ifdef USE_LOCAL_HEADERS
# include "SDL.h"
@ -62,6 +63,8 @@ float degrees(float rad) {
#define EPSILON 0.001f
#endif
cvar_t *vr_extralatencymode = NULL;
void rotateAboutOrigin(float x, float y, float rotation, vec2_t out)
{
out[0] = cosf(DEG2RAD(-rotation)) * x + sinf(DEG2RAD(-rotation)) * y;
@ -184,10 +187,11 @@ void IN_VRInit( void )
{
vr_righthanded = Cvar_Get ("vr_righthanded", "1", CVAR_ARCHIVE);
vr_snapturn = Cvar_Get ("vr_snapturn", "1", CVAR_ARCHIVE);
vr_extralatencymode = Cvar_Get ("vr_extralatencymode", "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);
Cvar_Get ("vr_weapon_adjustment_1", "1.0,0,0,0,0,0,0", CVAR_ARCHIVE);
Cvar_Get ("vr_weapon_adjustment_2", "1.0,0,0,0,0,0,0", CVAR_ARCHIVE);
Cvar_Get ("vr_weapon_adjustment_3", "1.0,0,0,0,0,0,0", CVAR_ARCHIVE);
}
static void IN_VRController( qboolean isRightController, ovrTracking remoteTracking )
@ -369,14 +373,21 @@ void IN_VRInputFrame( void )
return;
}
double predictedDisplayTime = vrapi_GetPredictedDisplayTime(ovr, VR_GetEngine()->frameIndex);
ovrResult result;
if (vr_extralatencymode != NULL &&
vr_extralatencymode->integer) {
result = vrapi_SetExtraLatencyMode(VR_GetEngine()->ovr, VRAPI_EXTRA_LATENCY_MODE_ON);
assert(result == VRAPI_INITIALIZE_SUCCESS);
}
result = vrapi_SetClockLevels(VR_GetEngine()->ovr, 4, 4);
assert(result == VRAPI_INITIALIZE_SUCCESS);
{
// 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;
const ovrQuatf quatHmd = VR_GetEngine()->tracking.HeadPose.Pose.Orientation;
const ovrVector3f positionHmd = VR_GetEngine()->tracking.HeadPose.Pose.Position;
vec3_t rotation = {0, 0, 0};
QuatToYawPitchRoll(quatHmd, rotation, vr.hmdorientation);
VectorSet(vr.hmdposition, positionHmd.x, positionHmd.y, positionHmd.z);
@ -423,7 +434,7 @@ void IN_VRInputFrame( void )
}
ovrTracking remoteTracking;
stateResult = vrapi_GetInputTrackingState(ovr, capsHeader.DeviceID, predictedDisplayTime,
stateResult = vrapi_GetInputTrackingState(ovr, capsHeader.DeviceID, VR_GetEngine()->predictedDisplayTime,
&remoteTracking);
if (stateResult < 0) {
continue;

View file

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

View file

@ -21,6 +21,8 @@
#include <GLES3/gl32.h>
#endif
#define SUPER_SAMPLE 1.2f
void APIENTRY VR_GLDebugLog(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
@ -38,8 +40,8 @@ void VR_GetRsolution(engine_t* engine, int *pWidth, int *pHeight)
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);
*pWidth = width = vrapi_GetSystemPropertyInt(&engine->java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH) * SUPER_SAMPLE;
*pHeight = height = vrapi_GetSystemPropertyInt(&engine->java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT) * SUPER_SAMPLE;
}
else
{
@ -193,8 +195,6 @@ ovrLayerCylinder2 BuildCylinderLayer(engine_t* engine, const int textureWidth, c
}
void VR_DrawFrame( engine_t* engine ) {
double predictedDisplayTime;
ovrTracking2 tracking;
if (!engine->ovr)
{
@ -202,8 +202,8 @@ void VR_DrawFrame( engine_t* engine ) {
}
++engine->frameIndex;
predictedDisplayTime = vrapi_GetPredictedDisplayTime(engine->ovr, engine->frameIndex);
tracking = vrapi_GetPredictedTracking2(engine->ovr, predictedDisplayTime);
engine->predictedDisplayTime = vrapi_GetPredictedDisplayTime(engine->ovr, engine->frameIndex);
engine->tracking = vrapi_GetPredictedTracking2(engine->ovr, engine->predictedDisplayTime);
if (VR_useScreenLayer())
{
@ -215,7 +215,7 @@ void VR_DrawFrame( engine_t* engine ) {
// Add a simple cylindrical layer
cylinderLayer.Cylinder =
BuildCylinderLayer(engine, eyeW, eyeW, &tracking, 0 );
BuildCylinderLayer(engine, eyeW, eyeW, &engine->tracking, 0 );
const ovrLayerHeader2* layers[] = {
&cylinderLayer.Header
@ -226,12 +226,12 @@ void VR_DrawFrame( engine_t* engine ) {
frameDesc.Flags = 0;
frameDesc.SwapInterval = 1;
frameDesc.FrameIndex = engine->frameIndex;
frameDesc.DisplayTime = predictedDisplayTime;
frameDesc.DisplayTime = engine->predictedDisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;
const framebuffer_t* framebuffers = engine->framebuffers;
re.SetVRHeadsetParms(&tracking,
re.SetVRHeadsetParms(&engine->tracking,
framebuffers[0].framebuffers[framebuffers[0].swapchainIndex],
framebuffers[1].framebuffers[framebuffers[1].swapchainIndex]);
Com_Frame();
@ -247,16 +247,16 @@ void VR_DrawFrame( engine_t* engine ) {
else
{
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
layer.HeadPose = tracking.HeadPose;
layer.HeadPose = engine->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);
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&engine->tracking.Eye[eye].ProjectionMatrix);
}
const framebuffer_t* framebuffers = engine->framebuffers;
re.SetVRHeadsetParms(&tracking,
re.SetVRHeadsetParms(&engine->tracking,
framebuffers[0].framebuffers[framebuffers[0].swapchainIndex],
framebuffers[1].framebuffers[framebuffers[1].swapchainIndex]);
Com_Frame();
@ -274,7 +274,7 @@ void VR_DrawFrame( engine_t* engine ) {
frameDesc.Flags = 0;
frameDesc.SwapInterval = 1;
frameDesc.FrameIndex = engine->frameIndex;
frameDesc.DisplayTime = predictedDisplayTime;
frameDesc.DisplayTime = engine->predictedDisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;

View file

@ -26,6 +26,8 @@ typedef struct {
uint64_t frameIndex;
ovrMobile* ovr;
ovrJava java;
double predictedDisplayTime;
ovrTracking2 tracking;
framebuffer_t framebuffers[VRAPI_FRAME_LAYER_EYE_MAX];
} engine_t;