mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-07 22:07:48 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1,528 @@
|
||||
/************************************************************************************␍
|
||||
␍
|
||||
Filename : VrApi.h␍
|
||||
Content : Minimum necessary API for mobile VR␍
|
||||
Created : June 25, 2014␍
|
||||
Authors : John Carmack, J.M.P. van Waveren␍
|
||||
␍
|
||||
Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved.␍
|
||||
␍
|
||||
*************************************************************************************/␍
|
||||
#ifndef OVR_VrApi_h␍
|
||||
#define OVR_VrApi_h␍
|
||||
␍
|
||||
#include "VrApi_Config.h"␍
|
||||
#include "VrApi_Version.h"␍
|
||||
#include "VrApi_Types.h"␍
|
||||
␍
|
||||
/*␍
|
||||
␍
|
||||
VrApi␍
|
||||
=====␍
|
||||
␍
|
||||
Multiple Android activities that live in the same address space can cooperatively use the VrApi.␍
|
||||
However, only one activity can be in "VR mode" at a time. The following explains when an activity␍
|
||||
is expected to enter/leave VR mode.␍
|
||||
␍
|
||||
␍
|
||||
Android Activity life cycle␍
|
||||
===========================␍
|
||||
␍
|
||||
An Android Activity can only be in VR mode while the activity is in the resumed state.␍
|
||||
The following shows how VR mode fits into the Android Activity life cycle.␍
|
||||
␍
|
||||
1. VrActivity::onCreate() <---------+␍
|
||||
2. VrActivity::onStart() <-------+ |␍
|
||||
3. VrActivity::onResume() <---+ | |␍
|
||||
4. vrapi_EnterVrMode() | | |␍
|
||||
5. vrapi_LeaveVrMode() | | |␍
|
||||
6. VrActivity::onPause() -----+ | |␍
|
||||
7. VrActivity::onStop() ---------+ |␍
|
||||
8. VrActivity::onDestroy() ---------+␍
|
||||
␍
|
||||
␍
|
||||
Android Surface life cycle␍
|
||||
==========================␍
|
||||
␍
|
||||
An Android Activity can only be in VR mode while there is a valid Android Surface.␍
|
||||
The following shows how VR mode fits into the Android Surface life cycle.␍
|
||||
␍
|
||||
1. VrActivity::surfaceCreated() <----+␍
|
||||
2. VrActivity::surfaceChanged() |␍
|
||||
3. vrapi_EnterVrMode() |␍
|
||||
4. vrapi_LeaveVrMode() |␍
|
||||
5. VrActivity::surfaceDestroyed() ---+␍
|
||||
␍
|
||||
Note that the life cycle of a surface is not necessarily tightly coupled with the␍
|
||||
life cycle of an activity. These two life cycles may interleave in complex ways.␍
|
||||
Usually surfaceCreated() is called after onResume() and surfaceDestroyed() is called␍
|
||||
between onPause() and onDestroy(). However, this is not guaranteed and, for instance,␍
|
||||
surfaceDestroyed() may be called after onDestroy() or even before onPause().␍
|
||||
␍
|
||||
An Android Activity is only in the resumed state with a valid Android Surface between␍
|
||||
surfaceChanged() or onResume(), whichever comes last, and surfaceDestroyed() or onPause(),␍
|
||||
whichever comes first. In other words, a VR application will typically enter VR mode␍
|
||||
from surfaceChanged() or onResume(), whichever comes last, and leave VR mode from␍
|
||||
surfaceDestroyed() or onPause(), whichever comes first.␍
|
||||
␍
|
||||
␍
|
||||
Android VR life cycle␍
|
||||
=====================␍
|
||||
␍
|
||||
// Setup the Java references.␍
|
||||
ovrJava java;␍
|
||||
java.Vm = javaVm;␍
|
||||
java.Env = jniEnv;␍
|
||||
java.ActivityObject = activityObject;␍
|
||||
␍
|
||||
// Initialize the API.␍
|
||||
const ovrInitParms initParms = vrapi_DefaultInitParms( &java );␍
|
||||
if ( vrapi_Initialize( &initParms ) != VRAPI_INITIALIZE_SUCCESS )␍
|
||||
{␍
|
||||
FAIL( "Failed to initialize VrApi!" );␍
|
||||
abort();␍
|
||||
}␍
|
||||
␍
|
||||
// Create an EGLContext and get the suggested FOV and suggested␍
|
||||
// resolution to setup a projection matrix and eye texture swap chains.␍
|
||||
const float suggestedEyeFovDegreesX = vrapi_GetSystemPropertyFloat( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_X );␍
|
||||
const float suggestedEyeFovDegreesY = vrapi_GetSystemPropertyFloat( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y );␍
|
||||
␍
|
||||
// Setup a projection matrix based on the 'ovrHmdInfo'.␍
|
||||
const ovrMatrix4f eyeProjectionMatrix = ovrMatrix4f_CreateProjectionFov( suggestedEyeFovDegreesX,␍
|
||||
suggestedEyeFovDegreesY,␍
|
||||
0.0f, 0.0f, VRAPI_ZNEAR, 0.0f );␍
|
||||
␍
|
||||
const int suggestedEyeTextureWidth = vrapi_GetSystemPropertyInt( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH );␍
|
||||
const int suggestedEyeTextureHeight = vrapi_GetSystemPropertyInt( &java, VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT );␍
|
||||
␍
|
||||
// Allocate a texture swap chain for each eye.␍
|
||||
ovrTextureSwapChain * colorTextureSwapChain[VRAPI_FRAME_LAYER_EYE_MAX];␍
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )␍
|
||||
{␍
|
||||
colorTextureSwapChain[eye] = vrapi_CreateTextureSwapChain( VRAPI_TEXTURE_TYPE_2D, VRAPI_TEXTURE_FORMAT_8888,␍
|
||||
suggestedEyeTextureWidth,␍
|
||||
suggestedEyeTextureHeight,␍
|
||||
1, true );␍
|
||||
}␍
|
||||
␍
|
||||
// Android Activity/Surface life cycle loop.␍
|
||||
for ( ; ; )␍
|
||||
{␍
|
||||
// Acquire ANativeWindow from Android Surface and create EGLSurface.␍
|
||||
// Make the EGLContext context current on the surface.␍
|
||||
␍
|
||||
// Enter VR mode once the activity is in the resumed state with a␍
|
||||
// valid EGLSurface and current EGLContext.␍
|
||||
const ovrModeParms modeParms = vrapi_DefaultModeParms( &java );␍
|
||||
ovrMobile * ovr = vrapi_EnterVrMode( &modeParms );␍
|
||||
␍
|
||||
// Frame loop, possibly running on another thread.␍
|
||||
for ( long long frameIndex = 1; ; frameIndex++ )␍
|
||||
{␍
|
||||
// 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.␍
|
||||
const double predictedDisplayTime = vrapi_GetPredictedDisplayTime( ovr, frameIndex );␍
|
||||
const ovrTracking baseTracking = vrapi_GetPredictedTracking( ovr, predictedDisplayTime );␍
|
||||
␍
|
||||
// Apply the head-on-a-stick model if there is no positional tracking.␍
|
||||
const ovrHeadModelParms headModelParms = vrapi_DefaultHeadModelParms();␍
|
||||
const ovrTracking tracking = vrapi_ApplyHeadModel( &headModelParms, &baseTracking );␍
|
||||
␍
|
||||
// Advance the simulation based on the predicted display time.␍
|
||||
␍
|
||||
// Render eye images and setup ovrFrameParms using 'ovrTracking'.␍
|
||||
const double currentTime = vrapi_GetTimeInSeconds();␍
|
||||
ovrFrameParms frameParms = vrapi_DefaultFrameParms( &java, VRAPI_FRAME_INIT_DEFAULT, currentTime, NULL );␍
|
||||
frameParms.FrameIndex = frameIndex;␍
|
||||
␍
|
||||
const ovrMatrix4f centerEyeViewMatrix = vrapi_GetCenterEyeViewMatrix( &headModelParms, &tracking, NULL );␍
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )␍
|
||||
{␍
|
||||
const ovrMatrix4f eyeViewMatrix = vrapi_GetEyeViewMatrix( &headModelParms, ¢erEyeViewMatrix, eye );␍
|
||||
␍
|
||||
const int colorTextureSwapChainIndex = frameIndex % vrapi_GetTextureSwapChainLength( colorTextureSwapChain[eye] );␍
|
||||
const unsigned int textureId = vrapi_GetTextureSwapChainHandle( colorTextureSwapChain[eye], colorTextureSwapChainIndex );␍
|
||||
␍
|
||||
// Render to 'textureId' using the 'eyeViewMatrix' and 'eyeProjectionMatrix'.␍
|
||||
␍
|
||||
frameParms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].ColorTextureSwapChain = colorTextureSwapChain[eye];␍
|
||||
frameParms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].TextureSwapChainIndex = colorTextureSwapChainIndex;␍
|
||||
frameParms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &eyeProjectionMatrix );␍
|
||||
frameParms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].HeadPose = tracking.HeadPose;␍
|
||||
}␍
|
||||
␍
|
||||
// Hand over the eye images to the time warp.␍
|
||||
vrapi_SubmitFrame( ovr, &frameParms );␍
|
||||
}␍
|
||||
␍
|
||||
// Leave VR mode when the activity is paused, the Android Surface is␍
|
||||
// destroyed, or when switching to another activity.␍
|
||||
vrapi_LeaveVrMode( ovr );␍
|
||||
}␍
|
||||
␍
|
||||
// Destroy the texture swap chains.␍
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )␍
|
||||
{␍
|
||||
vrapi_DestroyTextureSwapChain( colorTextureSwapChain[eye] );␍
|
||||
}␍
|
||||
␍
|
||||
// Shut down the API.␍
|
||||
vrapi_Shutdown();␍
|
||||
␍
|
||||
␍
|
||||
Integration␍
|
||||
===========␍
|
||||
␍
|
||||
The API is designed to work with an Android Activity using a plain Android SurfaceView,␍
|
||||
where the Activity life cycle and the Surface life cycle are managed completely in native␍
|
||||
code by sending the life cycle events (onResume, onPause, surfaceChanged etc.) to native code.␍
|
||||
␍
|
||||
The API does not work with an Android Activity using a GLSurfaceView. The GLSurfaceView␍
|
||||
class manages the window surface and EGLSurface and the implementation of GLSurfaceView␍
|
||||
may unbind the EGLSurface before onPause() gets called. As such, there is no way to␍
|
||||
leave VR mode before the EGLSurface disappears. Another problem with GLSurfaceView is␍
|
||||
that it creates the EGLContext using eglChooseConfig(). The Android EGL code pushes in␍
|
||||
multisample flags in eglChooseConfig() if the user has selected the "force 4x MSAA" option␍
|
||||
in settings. Using a multisampled front buffer is completely wasted for time warp␍
|
||||
rendering.␍
|
||||
␍
|
||||
Alternatively an Android NativeActivity can be used to avoid manually handling all␍
|
||||
the life cycle events. However, it is important to select the EGLConfig manually␍
|
||||
without using eglChooseConfig() to make sure the front buffer is not multisampled.␍
|
||||
␍
|
||||
The vrapi_GetSystemProperty* functions can be called at any time from any thread.␍
|
||||
This allows an application to setup its renderer, possibly running on a separate␍
|
||||
thread, before entering VR mode.␍
|
||||
␍
|
||||
On Android, an application cannot just allocate a new window/frontbuffer and render to it.␍
|
||||
Android allocates and manages the window/frontbuffer and (after the fact) notifies the␍
|
||||
application of the state of affairs through life cycle events (surfaceCreated / surfaceChanged␍
|
||||
/ surfaceDestroyed). The application (or 3rd party engine) typically handles these events.␍
|
||||
Since the VrApi cannot just allocate a new window/frontbuffer, and the VrApi does not␍
|
||||
handle the life cycle events, the VrApi somehow has to hijack the Android surface from␍
|
||||
the application. The easiest way to do this is by having the application first setup an␍
|
||||
OpenGL ES context that is current on the Android window surface. vrapi_EnterVrMode() is␍
|
||||
then called from the thread with this OpenGL ESL context, which allows vrapi_EnterVrMode()␍
|
||||
to swap out the Android window surface and take ownership of the actual frontbuffer that␍
|
||||
is used for rendering.␍
|
||||
␍
|
||||
Sensor input only becomes available after entering VR mode. In part this is because the␍
|
||||
VrApi supports hybrid apps. The app starts out in non-stereo mode, and only switches to␍
|
||||
VR mode when the phone is docked into the headset. While not in VR mode, a non-stereo app␍
|
||||
shoud not be burdened with a SCHED_FIFO device manager thread for sensor input and possibly␍
|
||||
expensive sensor/vision processing. In other words, there is no sensor input until the␍
|
||||
phone is docked and the app is in VR mode.␍
|
||||
␍
|
||||
Before getting sensor input, the application also needs to know when the images that are␍
|
||||
going to be synthesized will be displayed, because the sensor input needs to be predicted␍
|
||||
ahead for that time. As it turns out, it is not trivial to get an accurate predicted␍
|
||||
display time. Therefore the calculation of this predicted display time is part of the VrApi.␍
|
||||
An accurate predicted display time can only really be calculated once the rendering loop␍
|
||||
is up and running and submitting frames regularly. In other words, before getting sensor␍
|
||||
input, the application needs an accurate predicted display time, which in return requires␍
|
||||
the renderer to be up and running. As such, it makes sense that sensor input is not␍
|
||||
available until vrapi_EnterVrMode() has been called. However, once the application is␍
|
||||
in VR mode, it can call vrapi_GetPredictedDisplayTime() and vrapi_GetPredictedTracking()␍
|
||||
at any time from any thread.␍
|
||||
␍
|
||||
vrapi_SubmitFrame() must be called from the thread with the OpenGL ES context that was␍
|
||||
used for rendering. The reason for this is that the VrApi allows for one frame of overlap␍
|
||||
which is essential on tiled mobile GPUs. Because there is one frame of overlap, the eye images␍
|
||||
have typically not completed rendering by the time they are submitted to vrapi_SubmitFrame().␍
|
||||
vrapi_SubmitFrame() therefore adds a sync object to the current context which allows the␍
|
||||
background time warp thread to check when the eye images have completed.␍
|
||||
␍
|
||||
Note that vrapi_EnterVrMode() and vrapi_SubmitFrame() can be called from different threads.␍
|
||||
vrapi_EnterVrMode() needs to be called from a thread with an OpenGL ES context that is current␍
|
||||
on the Android window surface. This does not need to be the same context that is also used␍
|
||||
for rendering. vrapi_SubmitFrame() needs to be called from the thread with the OpenGL ES␍
|
||||
context that was used to render the eye images. If this is a different context than the context␍
|
||||
used to enter VR mode, then for stereoscopic rendering this context never needs to be current␍
|
||||
on the Android window surface.␍
|
||||
␍
|
||||
␍
|
||||
Eye Image Synthesis␍
|
||||
===================␍
|
||||
␍
|
||||
vrapi_SubmitFrame() controls the synthesis rate through an application specified␍
|
||||
ovrFrameParms::MinimumVsyncs. vrapi_SubmitFrame() also controls at which point during␍
|
||||
a display refresh cycle the calling thread gets released. vrapi_SubmitFrame() only returns␍
|
||||
when the previous eye images have been consumed by the asynchronous time warp thread,␍
|
||||
and at least the specified minimum number of V-syncs have passed since the last call␍
|
||||
to vrapi_SubmitFrame(). The asynchronous time warp thread consumes new eye images and␍
|
||||
updates the V-sync counter halfway through a display refresh cycle. This is the first␍
|
||||
time the time warp can start updating the first eye, covering the first half of the␍
|
||||
display. As a result, vrapi_SubmitFrame() returns and releases the calling thread halfway␍
|
||||
through a display refresh cycle.␍
|
||||
␍
|
||||
Once vrapi_SubmitFrame() returns, synthesis has a full display refresh cycle to generate␍
|
||||
new eye images up to the next halfway point. At the next halfway point, the time␍
|
||||
warp has half a display refresh cycle (up to V-sync) to update the first eye. The␍
|
||||
time warp then effectively waits for V-sync and then has another half a display␍
|
||||
refresh cycle (up to the next-next halfway point) to update the second eye. The␍
|
||||
asynchronous time warp uses a high priority GPU context and will eat away cycles␍
|
||||
from synthesis, so synthesis does not have a full display refresh cycle worth of␍
|
||||
actual GPU cycles. However, the asynchronous time warp tends to be very fast,␍
|
||||
leaving most of the GPU time for synthesis.␍
|
||||
␍
|
||||
Instead of using the latest sensor sampling, synthesis uses predicted sensor input␍
|
||||
for the middle of the time period during which the new eye images will be displayed.␍
|
||||
This predicted time is calculated using vrapi_GetPredictedDisplayTime(). The number␍
|
||||
of frames predicted ahead depends on the pipeline depth and the minimum number of␍
|
||||
V-syncs in between eye image rendering. Less than half a display refresh cycle␍
|
||||
before each eye image will be displayed, the asynchronous time warp will get new␍
|
||||
predicted sensor input using the very latest sensor sampling. The asynchronous␍
|
||||
time warp then corrects the eye images using this new sensor input. In other words,␍
|
||||
the asynchronous time warp will always correct the eye images even if the predicted␍
|
||||
sensor input for synthesis was not perfect. However, the better the prediction for␍
|
||||
synthesis, the less black will be pulled in at the edges by the asynchronous time warp.␍
|
||||
␍
|
||||
The application can improve the prediction by fetching the latest predicted sensor␍
|
||||
input right before rendering each eye, and passing a, possibly different, sensor state␍
|
||||
for each eye to vrapi_SubmitFrame(). However, it is very important that both eyes use a␍
|
||||
sensor state that is predicted for the exact same display time, so both eyes can be␍
|
||||
displayed at the same time without causing intra frame motion judder. While the predicted␍
|
||||
orientation can be updated for each eye, the position must remain the same for both eyes,␍
|
||||
or the position would seem to judder "backwards in time" if a frame is dropped.␍
|
||||
␍
|
||||
Ideally the eye images are only displayed for the MinimumVsyncs display refresh cycles␍
|
||||
that are centered about the eye image predicted display time. In other words, a set␍
|
||||
of eye images is first displayed at prediction time minus MinimumVsyncs / 2 display␍
|
||||
refresh cycles. The eye images should never be shown before this time because that␍
|
||||
can cause intra frame motion judder. Ideally the eye images are also not shown after␍
|
||||
the prediction time plus MinimumVsyncs / 2 display refresh cycles, but this may␍
|
||||
happen if synthesis fails to produce new eye images in time.␍
|
||||
␍
|
||||
MinimumVsyncs = 1␍
|
||||
|-------|-------|-------| - V-syncs␍
|
||||
| * | * | * | - eye image display periods (* = predicted time in middle of display period)␍
|
||||
\ / \ / \ /␍
|
||||
^ \ / ^ | +---- The asynchronous time warp projects the second eye image onto the display.␍
|
||||
| \ / | +---- The asynchronous time warp projects the first eye image onto the display. ␍
|
||||
| | |␍
|
||||
| | +---- Call vrapi_SubmitFrame before this point.␍
|
||||
| | vrapi_SubmitFrame inserts a GPU fence and hands over eye images to the asynchronous time warp.␍
|
||||
| | The asynchronous time warp checks the fence and uses the new eye images if rendering has completed.␍
|
||||
| |␍
|
||||
| +---- Generate GPU commands and execute commands on GPU.␍
|
||||
|␍
|
||||
+---- vrapi_SubmitFrame releases the renderer thread.␍
|
||||
␍
|
||||
MinimumVsyncs = 2␍
|
||||
|-------|-------|-------|-------|-------| - V-syncs␍
|
||||
* | * | * | - eye image display periods (* = predicted time in middle of display period)␍
|
||||
\ / \ / \ / \ / \ /␍
|
||||
^ \ / ^ | | | +---- The asynchronous time warp re-projects the second eye image onto the display.␍
|
||||
| \ / | | | +---- The asynchronous time warp re-projects the first eye image onto the display. ␍
|
||||
| \ / | | +---- The asynchronous time warp projects the second eye image onto the display.␍
|
||||
| \ / | +---- The asynchronous time warp projects the first eye image onto the display.␍
|
||||
| \ / |␍
|
||||
| \ / +---- Call vrapi_SubmitFrame before this point.␍
|
||||
| | vrapi_SubmitFrame inserts a GPU fence and hands over eye images to the asynchronous time warp.␍
|
||||
| | The asynchronous time warp checks the fence and uses the new eye images if rendering has completed.␍
|
||||
| |␍
|
||||
| +---- Generate GPU commands and execute commands on GPU.␍
|
||||
|␍
|
||||
+---- vrapi_SubmitFrame releases the renderer thread.␍
|
||||
␍
|
||||
MinimumVsyncs = 3␍
|
||||
|-------|-------|-------|-------|-------|-------|-------| - V-syncs␍
|
||||
| * | * | - eye image display periods (* = predicted time in middle of display period)␍
|
||||
\ / \ / \ / \ / \ / \ / \ /␍
|
||||
^ \ / ^ | | | | | +---- The asynchronous time warp re-projects the second eye image onto the display.␍
|
||||
| \ / | | | | | +---- The asynchronous time warp re-projects the first eye image onto the display. ␍
|
||||
| \ / | | | | +---- The asynchronous time warp re-projects the second eye image onto the display.␍
|
||||
| \ / | | | +---- The asynchronous time warp re-projects the first eye image onto the display. ␍
|
||||
| \ / | | +---- The asynchronous time warp projects the second eye image onto the display.␍
|
||||
| \ / | +---- The asynchronous time warp projects the first eye image onto the display.␍
|
||||
| \ / |␍
|
||||
| \ / +---- Call vrapi_SubmitFrame before this point.␍
|
||||
| \ / vrapi_SubmitFrame inserts a GPU fence and hands over eye images to the asynchronous time warp.␍
|
||||
| \ / The asynchronous time warp checks the fence and uses the new eye images if rendering has completed.␍
|
||||
| |␍
|
||||
| +---- Generate GPU commands and execute commands on GPU.␍
|
||||
| ␍
|
||||
+---- vrapi_SubmitFrame releases the renderer thread.␍
|
||||
␍
|
||||
*/␍
|
||||
␍
|
||||
#if defined( __cplusplus )␍
|
||||
extern "C" {␍
|
||||
#endif␍
|
||||
␍
|
||||
// Returns the version + compile time stamp as a string.␍
|
||||
// Can be called any time from any thread.␍
|
||||
OVR_VRAPI_EXPORT const char * vrapi_GetVersionString();␍
|
||||
␍
|
||||
// Returns global, absolute high-resolution time in seconds. This is the same value␍
|
||||
// as used in sensor messages and on Android also the same as Java's system.nanoTime(),␍
|
||||
// which is what the Choreographer V-sync timestamp is based on.␍
|
||||
// WARNING: do not use this time as a seed for simulations, animations or other logic.␍
|
||||
// An animation, for instance, should not be updated based on the "real time" the␍
|
||||
// animation code is executed. Instead, an animation should be updated based on the␍
|
||||
// time it will be displayed. Using the "real time" will introduce intra-frame motion␍
|
||||
// judder when the code is not executed at a consistent point in time every frame.␍
|
||||
// In other words, for simulations, animations and other logic use the time returned␍
|
||||
// by vrapi_GetPredictedDisplayTime().␍
|
||||
// Can be called any time from any thread.␍
|
||||
OVR_VRAPI_EXPORT double vrapi_GetTimeInSeconds();␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Initialization/Shutdown␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Initializes the API for application use.␍
|
||||
// This is lightweight and does not create any threads.␍
|
||||
// This is typically called from onCreate() or shortly thereafter.␍
|
||||
// Can be called from any thread.␍
|
||||
// Returns a non-zero value from ovrInitializeStatus on error.␍
|
||||
OVR_VRAPI_EXPORT ovrInitializeStatus vrapi_Initialize( const ovrInitParms * initParms );␍
|
||||
␍
|
||||
// Shuts down the API on application exit.␍
|
||||
// This is typically called from onDestroy() or shortly thereafter.␍
|
||||
// Can be called from any thread.␍
|
||||
OVR_VRAPI_EXPORT void vrapi_Shutdown();␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// System properties and status␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Returns a system property. These are constants for a particular device.␍
|
||||
// This function can be called any time from any thread once the VrApi is initialized.␍
|
||||
OVR_VRAPI_EXPORT int vrapi_GetSystemPropertyInt( const ovrJava * java, const ovrSystemProperty propType );␍
|
||||
OVR_VRAPI_EXPORT float vrapi_GetSystemPropertyFloat( const ovrJava * java, const ovrSystemProperty propType );␍
|
||||
␍
|
||||
// Returns a system status. These are variables that may change at run-time.␍
|
||||
// This function can be called any time from any thread once the VrApi is initialized.␍
|
||||
OVR_VRAPI_EXPORT int vrapi_GetSystemStatusInt( const ovrJava * java, const ovrSystemStatus statusType );␍
|
||||
OVR_VRAPI_EXPORT float vrapi_GetSystemStatusFloat( const ovrJava * java, const ovrSystemStatus statusType );␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Enter/Leave VR mode␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Starts up the time warp, V-sync tracking, sensor reading, clock locking,␍
|
||||
// thread scheduling, and sets video options. The parms are copied, and are␍
|
||||
// not referenced after the function returns.␍
|
||||
//␍
|
||||
// This should be called after vrapi_Initialize(), when the app is both␍
|
||||
// resumed and has a valid window surface. ␍
|
||||
//␍
|
||||
// Must be called from a thread that has an OpenGL ES context current␍
|
||||
// on the active Android window surface. The context of the calling␍
|
||||
// thread is used to match the version and config for the context used by␍
|
||||
// the background time warp thread. The time warp will also hijack the␍
|
||||
// Android window surface from the context that is current on the calling␍
|
||||
// thread. On return, the context from the calling thread will be current␍
|
||||
// on an invisible pbuffer, because the time warp takes ownership of the␍
|
||||
// Android window surface. Note that this requires the config used by the␍
|
||||
// calling thread to have an EGL_SURFACE_TYPE with EGL_PBUFFER_BIT.␍
|
||||
OVR_VRAPI_EXPORT ovrMobile * vrapi_EnterVrMode( const ovrModeParms * parms );␍
|
||||
␍
|
||||
// Shut everything down for window destruction.␍
|
||||
// The ovrMobile object is freed by this function.␍
|
||||
//␍
|
||||
// Must be called from the same thread that called vrapi_EnterVrMode() with␍
|
||||
// the same OpenGL ES context that was current on the Android window surface␍
|
||||
// before calling vrapi_EnterVrMode(). By calling this function the time warp␍
|
||||
// gives up ownership of the Android window surface, and on return, the␍
|
||||
// context from the calling thread will be current again on the Android␍
|
||||
// window surface.␍
|
||||
OVR_VRAPI_EXPORT void vrapi_LeaveVrMode( ovrMobile * ovr );␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Tracking␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Returns a predicted absolute system time in seconds at which the next set␍
|
||||
// of eye images will be displayed.␍
|
||||
//␍
|
||||
// The predicted time is 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 minumum number of V-syncs in␍
|
||||
// between eye image rendering. The better the prediction, the less black will␍
|
||||
// be pulled in at the edges by the time warp.␍
|
||||
//␍
|
||||
// The frameIndex is an application controlled number that uniquely identifies␍
|
||||
// the new set of eye images for which synthesis is about to start. This same␍
|
||||
// frameIndex must be passed to vrapi_SubmitFrame() when the new eye images are␍
|
||||
// submitted to the time warp. The frameIndex is expected to be incremented␍
|
||||
// once every frame before calling this function.␍
|
||||
//␍
|
||||
// Can be called from any thread while in VR mode.␍
|
||||
OVR_VRAPI_EXPORT double vrapi_GetPredictedDisplayTime( ovrMobile * ovr, long long frameIndex );␍
|
||||
␍
|
||||
// Returns the predicted sensor state based on the specified absolute system time␍
|
||||
// in seconds. Pass absTime value of 0.0 to request the most recent sensor reading.␍
|
||||
//␍
|
||||
// Can be called from any thread while in VR mode.␍
|
||||
OVR_VRAPI_EXPORT ovrTracking vrapi_GetPredictedTracking( ovrMobile * ovr, double absTimeInSeconds );␍
|
||||
␍
|
||||
// Recenters the orientation on the yaw axis and will recenter the position␍
|
||||
// when position tracking is available.␍
|
||||
//␍
|
||||
// Note that this immediately affects vrapi_GetPredictedTracking() which may␍
|
||||
// be called asynchronously from the time warp. It is therefore best to␍
|
||||
// make sure the screen is black before recentering to avoid previous eye␍
|
||||
// images from being abrubtly warped across the screen.␍
|
||||
//␍
|
||||
// Can be called from any thread while in VR mode.␍
|
||||
OVR_VRAPI_EXPORT void vrapi_RecenterPose( ovrMobile * ovr );␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Texture Swap Chains␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Create a texture swap chain that can be passed to vrapi_SubmitFrame.␍
|
||||
// Must be called from a thread with a valid OpenGL ES context current.␍
|
||||
OVR_VRAPI_EXPORT ovrTextureSwapChain * vrapi_CreateTextureSwapChain( ovrTextureType type, ovrTextureFormat format,␍
|
||||
int width, int height, int levels, bool buffered );␍
|
||||
␍
|
||||
// Destroy the given texture swap chain.␍
|
||||
// Must be called from a thread with a valid OpenGL ES context current.␍
|
||||
OVR_VRAPI_EXPORT void vrapi_DestroyTextureSwapChain( ovrTextureSwapChain * chain );␍
|
||||
␍
|
||||
// Returns the number of textures in the swap chain.␍
|
||||
OVR_VRAPI_EXPORT int vrapi_GetTextureSwapChainLength( ovrTextureSwapChain * chain );␍
|
||||
␍
|
||||
// Get the OpenGL name of the texture at the given index.␍
|
||||
OVR_VRAPI_EXPORT unsigned int vrapi_GetTextureSwapChainHandle( ovrTextureSwapChain * chain, int index );␍
|
||||
␍
|
||||
// Set the OpenGL name of the texture at the given index. NOTE: This is not portable to PC.␍
|
||||
OVR_VRAPI_EXPORT void vrapi_SetTextureSwapChainHandle( ovrTextureSwapChain * chain, int index, unsigned int handle );␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Frame Submission␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Accepts new eye images plus poses that will be used for future warps.␍
|
||||
// The parms are copied, and are not referenced after the function returns.␍
|
||||
//␍
|
||||
// This will block until the textures from the previous vrapi_SubmitFrame() have been␍
|
||||
// consumed by the background thread, to allow one frame of overlap for maximum␍
|
||||
// GPU utilization, while preventing multiple frames from piling up variable latency.␍
|
||||
//␍
|
||||
// This will block until at least MinimumVsyncs have passed since the last␍
|
||||
// call to vrapi_SubmitFrame() to prevent applications with simple scenes from␍
|
||||
// generating completely wasted frames.␍
|
||||
//␍
|
||||
// IMPORTANT: any dynamic textures that are passed to vrapi_SubmitFrame() must be␍
|
||||
// triple buffered to avoid flickering and performance problems.␍
|
||||
//␍
|
||||
// Note that the config used by the calling thread must have an EGL_SURFACE_TYPE␍
|
||||
// with EGL_WINDOW_BIT so textures can be shared with the background thread.␍
|
||||
//␍
|
||||
// Must be called from the thread with the OpenGL ES context current that was␍
|
||||
// used to render the eye images, but drawing does not need to be completed.␍
|
||||
// A sync object will be added to the current context so the background␍
|
||||
// thread can know when rendering of the eye images has completed.␍
|
||||
OVR_VRAPI_EXPORT void vrapi_SubmitFrame( ovrMobile * ovr, const ovrFrameParms * parms );␍
|
||||
␍
|
||||
#if defined( __cplusplus )␍
|
||||
} // extern "C"␍
|
||||
#endif␍
|
||||
␍
|
||||
#endif // OVR_VrApi_h␍
|
||||
@@ -0,0 +1,37 @@
|
||||
/************************************************************************************␍
|
||||
␍
|
||||
Filename : VrApi_Config.h␍
|
||||
Content : VrApi preprocessor settings␍
|
||||
Created : April 23, 2015␍
|
||||
Authors : James Dolan␍
|
||||
␍
|
||||
Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved.␍
|
||||
␍
|
||||
*************************************************************************************/␍
|
||||
␍
|
||||
#ifndef OVR_VrApi_Config_h␍
|
||||
#define OVR_VrApi_Config_h␍
|
||||
␍
|
||||
#if defined( _MSC_VER ) || defined( __ICL )␍
|
||||
␍
|
||||
#if defined( OVR_VRAPI_ENABLE_EXPORT )␍
|
||||
#define OVR_VRAPI_EXPORT __declspec(dllexport)␍
|
||||
#else␍
|
||||
#define OVR_VRAPI_EXPORT␍
|
||||
#endif␍
|
||||
␍
|
||||
#define OVR_VRAPI_DEPRECATED __declspec(deprecated)␍
|
||||
␍
|
||||
#else␍
|
||||
␍
|
||||
#if defined( OVR_VRAPI_ENABLE_EXPORT )␍
|
||||
#define OVR_VRAPI_EXPORT __attribute__((__visibility__("default")))␍
|
||||
#else␍
|
||||
#define OVR_VRAPI_EXPORT ␍
|
||||
#endif␍
|
||||
␍
|
||||
#define OVR_VRAPI_DEPRECATED __attribute__ ((deprecated))␍
|
||||
␍
|
||||
#endif␍
|
||||
␍
|
||||
#endif // !OVR_VrApi_Config_h␍
|
||||
@@ -0,0 +1,640 @@
|
||||
/************************************************************************************␍
|
||||
␍
|
||||
Filename : VrApi_Helpers.h␍
|
||||
Content : Pure, stateless, inlined helper functions, used to initialize␍
|
||||
parameters to the VrApi.␍
|
||||
Created : March 2, 2015␍
|
||||
Authors : J.M.P. van Waveren␍
|
||||
␍
|
||||
Copyright : Copyright 2015 Oculus VR, LLC. All Rights reserved.␍
|
||||
␍
|
||||
*************************************************************************************/␍
|
||||
#ifndef OVR_VrApi_Helpers_h␍
|
||||
#define OVR_VrApi_Helpers_h␍
|
||||
␍
|
||||
#include "math.h" // for cosf(), sinf(), tanf()␍
|
||||
#include "string.h" // for memset()␍
|
||||
#include "VrApi_Config.h"␍
|
||||
#include "VrApi_Version.h"␍
|
||||
#include "VrApi_Types.h"␍
|
||||
␍
|
||||
#define VRAPI_PI 3.14159265358979323846f␍
|
||||
#define VRAPI_ZNEAR 0.1f␍
|
||||
␍
|
||||
#if defined( __GNUC__ )␍
|
||||
# define VRAPI_UNUSED(a) do {__typeof__ (&a) __attribute__ ((unused)) __tmp = &a; } while(0)␍
|
||||
#else␍
|
||||
# define VRAPI_UNUSED(a) (a)␍
|
||||
#endif␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Matrix helper functions.␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Use left-multiplication to accumulate transformations.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_Multiply( const ovrMatrix4f * a, const ovrMatrix4f * b )␍
|
||||
{␍
|
||||
ovrMatrix4f out;␍
|
||||
out.M[0][0] = a->M[0][0] * b->M[0][0] + a->M[0][1] * b->M[1][0] + a->M[0][2] * b->M[2][0] + a->M[0][3] * b->M[3][0];␍
|
||||
out.M[1][0] = a->M[1][0] * b->M[0][0] + a->M[1][1] * b->M[1][0] + a->M[1][2] * b->M[2][0] + a->M[1][3] * b->M[3][0];␍
|
||||
out.M[2][0] = a->M[2][0] * b->M[0][0] + a->M[2][1] * b->M[1][0] + a->M[2][2] * b->M[2][0] + a->M[2][3] * b->M[3][0];␍
|
||||
out.M[3][0] = a->M[3][0] * b->M[0][0] + a->M[3][1] * b->M[1][0] + a->M[3][2] * b->M[2][0] + a->M[3][3] * b->M[3][0];␍
|
||||
␍
|
||||
out.M[0][1] = a->M[0][0] * b->M[0][1] + a->M[0][1] * b->M[1][1] + a->M[0][2] * b->M[2][1] + a->M[0][3] * b->M[3][1];␍
|
||||
out.M[1][1] = a->M[1][0] * b->M[0][1] + a->M[1][1] * b->M[1][1] + a->M[1][2] * b->M[2][1] + a->M[1][3] * b->M[3][1];␍
|
||||
out.M[2][1] = a->M[2][0] * b->M[0][1] + a->M[2][1] * b->M[1][1] + a->M[2][2] * b->M[2][1] + a->M[2][3] * b->M[3][1];␍
|
||||
out.M[3][1] = a->M[3][0] * b->M[0][1] + a->M[3][1] * b->M[1][1] + a->M[3][2] * b->M[2][1] + a->M[3][3] * b->M[3][1];␍
|
||||
␍
|
||||
out.M[0][2] = a->M[0][0] * b->M[0][2] + a->M[0][1] * b->M[1][2] + a->M[0][2] * b->M[2][2] + a->M[0][3] * b->M[3][2];␍
|
||||
out.M[1][2] = a->M[1][0] * b->M[0][2] + a->M[1][1] * b->M[1][2] + a->M[1][2] * b->M[2][2] + a->M[1][3] * b->M[3][2];␍
|
||||
out.M[2][2] = a->M[2][0] * b->M[0][2] + a->M[2][1] * b->M[1][2] + a->M[2][2] * b->M[2][2] + a->M[2][3] * b->M[3][2];␍
|
||||
out.M[3][2] = a->M[3][0] * b->M[0][2] + a->M[3][1] * b->M[1][2] + a->M[3][2] * b->M[2][2] + a->M[3][3] * b->M[3][2];␍
|
||||
␍
|
||||
out.M[0][3] = a->M[0][0] * b->M[0][3] + a->M[0][1] * b->M[1][3] + a->M[0][2] * b->M[2][3] + a->M[0][3] * b->M[3][3];␍
|
||||
out.M[1][3] = a->M[1][0] * b->M[0][3] + a->M[1][1] * b->M[1][3] + a->M[1][2] * b->M[2][3] + a->M[1][3] * b->M[3][3];␍
|
||||
out.M[2][3] = a->M[2][0] * b->M[0][3] + a->M[2][1] * b->M[1][3] + a->M[2][2] * b->M[2][3] + a->M[2][3] * b->M[3][3];␍
|
||||
out.M[3][3] = a->M[3][0] * b->M[0][3] + a->M[3][1] * b->M[1][3] + a->M[3][2] * b->M[2][3] + a->M[3][3] * b->M[3][3];␍
|
||||
return out;␍
|
||||
}␍
|
||||
␍
|
||||
// Returns the transpose of a 4x4 matrix.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_Transpose( const ovrMatrix4f * a )␍
|
||||
{␍
|
||||
ovrMatrix4f out;␍
|
||||
out.M[0][0] = a->M[0][0]; out.M[0][1] = a->M[1][0]; out.M[0][2] = a->M[2][0]; out.M[0][3] = a->M[3][0];␍
|
||||
out.M[1][0] = a->M[0][1]; out.M[1][1] = a->M[1][1]; out.M[1][2] = a->M[2][1]; out.M[1][3] = a->M[3][1];␍
|
||||
out.M[2][0] = a->M[0][2]; out.M[2][1] = a->M[1][2]; out.M[2][2] = a->M[2][2]; out.M[2][3] = a->M[3][2];␍
|
||||
out.M[3][0] = a->M[0][3]; out.M[3][1] = a->M[1][3]; out.M[3][2] = a->M[2][3]; out.M[3][3] = a->M[3][3];␍
|
||||
return out;␍
|
||||
}␍
|
||||
␍
|
||||
// Returns a 3x3 minor of a 4x4 matrix.␍
|
||||
static inline float ovrMatrix4f_Minor( const ovrMatrix4f * m, int r0, int r1, int r2, int c0, int c1, int c2 )␍
|
||||
{␍
|
||||
return m->M[r0][c0] * ( m->M[r1][c1] * m->M[r2][c2] - m->M[r2][c1] * m->M[r1][c2] ) -␍
|
||||
m->M[r0][c1] * ( m->M[r1][c0] * m->M[r2][c2] - m->M[r2][c0] * m->M[r1][c2] ) +␍
|
||||
m->M[r0][c2] * ( m->M[r1][c0] * m->M[r2][c1] - m->M[r2][c0] * m->M[r1][c1] );␍
|
||||
}␍
|
||||
␍
|
||||
// Returns the inverse of a 4x4 matrix.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_Inverse( const ovrMatrix4f * m )␍
|
||||
{␍
|
||||
const float rcpDet = 1.0f / ( m->M[0][0] * ovrMatrix4f_Minor( m, 1, 2, 3, 1, 2, 3 ) -␍
|
||||
m->M[0][1] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 2, 3 ) +␍
|
||||
m->M[0][2] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 3 ) -␍
|
||||
m->M[0][3] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 2 ) );␍
|
||||
ovrMatrix4f out;␍
|
||||
out.M[0][0] = ovrMatrix4f_Minor( m, 1, 2, 3, 1, 2, 3 ) * rcpDet;␍
|
||||
out.M[0][1] = -ovrMatrix4f_Minor( m, 0, 2, 3, 1, 2, 3 ) * rcpDet;␍
|
||||
out.M[0][2] = ovrMatrix4f_Minor( m, 0, 1, 3, 1, 2, 3 ) * rcpDet;␍
|
||||
out.M[0][3] = -ovrMatrix4f_Minor( m, 0, 1, 2, 1, 2, 3 ) * rcpDet;␍
|
||||
out.M[1][0] = -ovrMatrix4f_Minor( m, 1, 2, 3, 0, 2, 3 ) * rcpDet;␍
|
||||
out.M[1][1] = ovrMatrix4f_Minor( m, 0, 2, 3, 0, 2, 3 ) * rcpDet;␍
|
||||
out.M[1][2] = -ovrMatrix4f_Minor( m, 0, 1, 3, 0, 2, 3 ) * rcpDet;␍
|
||||
out.M[1][3] = ovrMatrix4f_Minor( m, 0, 1, 2, 0, 2, 3 ) * rcpDet;␍
|
||||
out.M[2][0] = ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 3 ) * rcpDet;␍
|
||||
out.M[2][1] = -ovrMatrix4f_Minor( m, 0, 2, 3, 0, 1, 3 ) * rcpDet;␍
|
||||
out.M[2][2] = ovrMatrix4f_Minor( m, 0, 1, 3, 0, 1, 3 ) * rcpDet;␍
|
||||
out.M[2][3] = -ovrMatrix4f_Minor( m, 0, 1, 2, 0, 1, 3 ) * rcpDet;␍
|
||||
out.M[3][0] = -ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 2 ) * rcpDet;␍
|
||||
out.M[3][1] = ovrMatrix4f_Minor( m, 0, 2, 3, 0, 1, 2 ) * rcpDet;␍
|
||||
out.M[3][2] = -ovrMatrix4f_Minor( m, 0, 1, 3, 0, 1, 2 ) * rcpDet;␍
|
||||
out.M[3][3] = ovrMatrix4f_Minor( m, 0, 1, 2, 0, 1, 2 ) * rcpDet;␍
|
||||
return out;␍
|
||||
}␍
|
||||
␍
|
||||
// Returns a 4x4 identity matrix.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_CreateIdentity()␍
|
||||
{␍
|
||||
ovrMatrix4f out;␍
|
||||
out.M[0][0] = 1.0f; out.M[0][1] = 0.0f; out.M[0][2] = 0.0f; out.M[0][3] = 0.0f;␍
|
||||
out.M[1][0] = 0.0f; out.M[1][1] = 1.0f; out.M[1][2] = 0.0f; out.M[1][3] = 0.0f;␍
|
||||
out.M[2][0] = 0.0f; out.M[2][1] = 0.0f; out.M[2][2] = 1.0f; out.M[2][3] = 0.0f;␍
|
||||
out.M[3][0] = 0.0f; out.M[3][1] = 0.0f; out.M[3][2] = 0.0f; out.M[3][3] = 1.0f;␍
|
||||
return out;␍
|
||||
}␍
|
||||
␍
|
||||
// Returns a 4x4 homogeneous translation matrix.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_CreateTranslation( const float x, const float y, const float z )␍
|
||||
{␍
|
||||
ovrMatrix4f out;␍
|
||||
out.M[0][0] = 1.0f; out.M[0][1] = 0.0f; out.M[0][2] = 0.0f; out.M[0][3] = x;␍
|
||||
out.M[1][0] = 0.0f; out.M[1][1] = 1.0f; out.M[1][2] = 0.0f; out.M[1][3] = y;␍
|
||||
out.M[2][0] = 0.0f; out.M[2][1] = 0.0f; out.M[2][2] = 1.0f; out.M[2][3] = z;␍
|
||||
out.M[3][0] = 0.0f; out.M[3][1] = 0.0f; out.M[3][2] = 0.0f; out.M[3][3] = 1.0f;␍
|
||||
return out;␍
|
||||
}␍
|
||||
␍
|
||||
// Returns a 4x4 homogeneous rotation matrix.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_CreateRotation( const float radiansX, const float radiansY, const float radiansZ )␍
|
||||
{␍
|
||||
const float sinX = sinf( radiansX );␍
|
||||
const float cosX = cosf( radiansX );␍
|
||||
const ovrMatrix4f rotationX =␍
|
||||
{ {␍
|
||||
{ 1, 0, 0, 0 },␍
|
||||
{ 0, cosX, -sinX, 0 },␍
|
||||
{ 0, sinX, cosX, 0 },␍
|
||||
{ 0, 0, 0, 1 }␍
|
||||
} };␍
|
||||
const float sinY = sinf( radiansY );␍
|
||||
const float cosY = cosf( radiansY );␍
|
||||
const ovrMatrix4f rotationY =␍
|
||||
{ {␍
|
||||
{ cosY, 0, sinY, 0 },␍
|
||||
{ 0, 1, 0, 0 },␍
|
||||
{ -sinY, 0, cosY, 0 },␍
|
||||
{ 0, 0, 0, 1 }␍
|
||||
} };␍
|
||||
const float sinZ = sinf( radiansZ );␍
|
||||
const float cosZ = cosf( radiansZ );␍
|
||||
const ovrMatrix4f rotationZ =␍
|
||||
{ {␍
|
||||
{ cosZ, -sinZ, 0, 0 },␍
|
||||
{ sinZ, cosZ, 0, 0 },␍
|
||||
{ 0, 0, 1, 0 },␍
|
||||
{ 0, 0, 0, 1 }␍
|
||||
} };␍
|
||||
const ovrMatrix4f rotationXY = ovrMatrix4f_Multiply( &rotationY, &rotationX );␍
|
||||
return ovrMatrix4f_Multiply( &rotationZ, &rotationXY );␍
|
||||
}␍
|
||||
␍
|
||||
// Returns a projection matrix based on the specified dimensions.␍
|
||||
// The far plane is placed at infinity if farZ <= nearZ.␍
|
||||
// An infinite projection matrix is preferred for rasterization because, except for␍
|
||||
// things *right* up against the near plane, it always provides better precision:␍
|
||||
// "Tightening the Precision of Perspective Rendering"␍
|
||||
// Paul Upchurch, Mathieu Desbrun␍
|
||||
// Journal of Graphics Tools, Volume 16, Issue 1, 2012␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_CreateProjection( const float minX, const float maxX,␍
|
||||
float const minY, const float maxY, const float nearZ, const float farZ )␍
|
||||
{␍
|
||||
const float width = maxX - minX;␍
|
||||
const float height = maxY - minY;␍
|
||||
const float offsetZ = nearZ; // set to zero for a [0,1] clip space␍
|
||||
␍
|
||||
ovrMatrix4f out;␍
|
||||
if ( farZ <= nearZ )␍
|
||||
{␍
|
||||
// place the far plane at infinity␍
|
||||
out.M[0][0] = 2 * nearZ / width;␍
|
||||
out.M[0][1] = 0;␍
|
||||
out.M[0][2] = ( maxX + minX ) / width;␍
|
||||
out.M[0][3] = 0;␍
|
||||
␍
|
||||
out.M[1][0] = 0;␍
|
||||
out.M[1][1] = 2 * nearZ / height;␍
|
||||
out.M[1][2] = ( maxY + minY ) / height;␍
|
||||
out.M[1][3] = 0;␍
|
||||
␍
|
||||
out.M[2][0] = 0;␍
|
||||
out.M[2][1] = 0;␍
|
||||
out.M[2][2] = -1;␍
|
||||
out.M[2][3] = -( nearZ + offsetZ );␍
|
||||
␍
|
||||
out.M[3][0] = 0;␍
|
||||
out.M[3][1] = 0;␍
|
||||
out.M[3][2] = -1;␍
|
||||
out.M[3][3] = 0;␍
|
||||
}␍
|
||||
else␍
|
||||
{␍
|
||||
// normal projection␍
|
||||
out.M[0][0] = 2 * nearZ / width;␍
|
||||
out.M[0][1] = 0;␍
|
||||
out.M[0][2] = ( maxX + minX ) / width;␍
|
||||
out.M[0][3] = 0;␍
|
||||
␍
|
||||
out.M[1][0] = 0;␍
|
||||
out.M[1][1] = 2 * nearZ / height;␍
|
||||
out.M[1][2] = ( maxY + minY ) / height;␍
|
||||
out.M[1][3] = 0;␍
|
||||
␍
|
||||
out.M[2][0] = 0;␍
|
||||
out.M[2][1] = 0;␍
|
||||
out.M[2][2] = -( farZ + offsetZ ) / ( farZ - nearZ );␍
|
||||
out.M[2][3] = -( farZ * ( nearZ + offsetZ ) ) / ( farZ - nearZ );␍
|
||||
␍
|
||||
out.M[3][0] = 0;␍
|
||||
out.M[3][1] = 0;␍
|
||||
out.M[3][2] = -1;␍
|
||||
out.M[3][3] = 0;␍
|
||||
}␍
|
||||
return out;␍
|
||||
}␍
|
||||
␍
|
||||
// Returns a projection matrix based on the given FOV.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_CreateProjectionFov( const float fovDegreesX, const float fovDegreesY,␍
|
||||
const float offsetX, const float offsetY, const float nearZ, const float farZ )␍
|
||||
{␍
|
||||
const float halfWidth = nearZ * tanf( fovDegreesX * ( VRAPI_PI / 180.0f * 0.5f ) );␍
|
||||
const float halfHeight = nearZ * tanf( fovDegreesY * ( VRAPI_PI / 180.0f * 0.5f ) );␍
|
||||
␍
|
||||
const float minX = offsetX - halfWidth;␍
|
||||
const float maxX = offsetX + halfWidth;␍
|
||||
␍
|
||||
const float minY = offsetY - halfHeight;␍
|
||||
const float maxY = offsetY + halfHeight;␍
|
||||
␍
|
||||
return ovrMatrix4f_CreateProjection( minX, maxX, minY, maxY, nearZ, farZ );␍
|
||||
}␍
|
||||
␍
|
||||
// Returns the 4x4 rotation matrix for the given quaternion.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_CreateFromQuaternion( const ovrQuatf * q )␍
|
||||
{␍
|
||||
const float ww = q->w * q->w;␍
|
||||
const float xx = q->x * q->x;␍
|
||||
const float yy = q->y * q->y;␍
|
||||
const float zz = q->z * q->z;␍
|
||||
␍
|
||||
ovrMatrix4f out;␍
|
||||
out.M[0][0] = ww + xx - yy - zz;␍
|
||||
out.M[0][1] = 2 * ( q->x * q->y - q->w * q->z );␍
|
||||
out.M[0][2] = 2 * ( q->x * q->z + q->w * q->y );␍
|
||||
out.M[0][3] = 0;␍
|
||||
␍
|
||||
out.M[1][0] = 2 * ( q->x * q->y + q->w * q->z );␍
|
||||
out.M[1][1] = ww - xx + yy - zz;␍
|
||||
out.M[1][2] = 2 * ( q->y * q->z - q->w * q->x );␍
|
||||
out.M[1][3] = 0;␍
|
||||
␍
|
||||
out.M[2][0] = 2 * ( q->x * q->z - q->w * q->y );␍
|
||||
out.M[2][1] = 2 * ( q->y * q->z + q->w * q->x );␍
|
||||
out.M[2][2] = ww - xx - yy + zz;␍
|
||||
out.M[2][3] = 0;␍
|
||||
␍
|
||||
out.M[3][0] = 0;␍
|
||||
out.M[3][1] = 0;␍
|
||||
out.M[3][2] = 0;␍
|
||||
out.M[3][3] = 1;␍
|
||||
return out;␍
|
||||
}␍
|
||||
␍
|
||||
// Convert a standard projection matrix into a TexCoordsFromTanAngles matrix for␍
|
||||
// the primary time warp surface.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_TanAngleMatrixFromProjection( const ovrMatrix4f * projection )␍
|
||||
{␍
|
||||
/*␍
|
||||
A projection matrix goes from a view point to NDC, or -1 to 1 space.␍
|
||||
Scale and bias to convert that to a 0 to 1 space.␍
|
||||
␍
|
||||
const ovrMatrix3f m =␍
|
||||
{ {␍
|
||||
{ projection->M[0][0], 0.0f, projection->M[0][2] },␍
|
||||
{ 0.0f, projection->M[1][1], projection->M[1][2] },␍
|
||||
{ 0.0f, 0.0f, -1.0f }␍
|
||||
} };␍
|
||||
// Note that there is no Y-flip because eye buffers have 0,0 = left-bottom.␍
|
||||
const ovrMatrix3f s = ovrMatrix3f_CreateScaling( 0.5f, 0.5f );␍
|
||||
const ovrMatrix3f t = ovrMatrix3f_CreateTranslation( 0.5f, 0.5f );␍
|
||||
const ovrMatrix3f r0 = ovrMatrix3f_Multiply( &s, &m );␍
|
||||
const ovrMatrix3f r1 = ovrMatrix3f_Multiply( &t, &r0 );␍
|
||||
return r1;␍
|
||||
␍
|
||||
clipZ = ( z * projection[2][2] + projection[2][3] ) / ( projection[3][2] * z )␍
|
||||
z = projection[2][3] / ( clipZ * projection[3][2] - projection[2][2] )␍
|
||||
z = ( projection[2][3] / projection[3][2] ) / ( clipZ - projection[2][2] / projection[3][2] )␍
|
||||
*/␍
|
||||
const ovrMatrix4f tanAngleMatrix =␍
|
||||
{ {␍
|
||||
{ 0.5f * projection->M[0][0], 0.0f, 0.5f * projection->M[0][2] - 0.5f, 0.0f },␍
|
||||
{ 0.0f, 0.5f * projection->M[1][1], 0.5f * projection->M[1][2] - 0.5f, 0.0f },␍
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f },␍
|
||||
// Store the values to convert a clip-Z to a linear depth in the unused matrix elements.␍
|
||||
{ projection->M[2][2], projection->M[2][3], projection->M[3][2], 1.0f }␍
|
||||
} };␍
|
||||
return tanAngleMatrix;␍
|
||||
}␍
|
||||
␍
|
||||
// If a simple quad defined as a -1 to 1 XY unit square is transformed to␍
|
||||
// the camera view with the given modelView matrix, it can alternately be␍
|
||||
// drawn as a time warp overlay image to take advantage of the full window␍
|
||||
// resolution, which is usually higher than the eye buffer textures, and␍
|
||||
// avoids resampling both into the eye buffer, and again to the screen.␍
|
||||
// This is used for high quality movie screens and user interface planes.␍
|
||||
//␍
|
||||
// Note that this is NOT an MVP matrix -- the "projection" is handled␍
|
||||
// by the distortion process.␍
|
||||
//␍
|
||||
// The exact composition of the overlay image and the base image is␍
|
||||
// determined by the warp program, you may still need to draw the geometry␍
|
||||
// into the eye buffer to punch a hole in the alpha channel to let the␍
|
||||
// overlay/underlay show through.␍
|
||||
//␍
|
||||
// This utility functions converts a model-view matrix that would normally␍
|
||||
// draw a -1 to 1 unit square to the view into a TexCoordsFromTanAngles matrix ␍
|
||||
// for an overlay surface.␍
|
||||
//␍
|
||||
// The resulting z value should be straight ahead distance to the plane.␍
|
||||
// The x and y values will be pre-multiplied by z for projective texturing.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_TanAngleMatrixFromUnitSquare( const ovrMatrix4f * modelView )␍
|
||||
{␍
|
||||
/*␍
|
||||
// Take the inverse of the view matrix because the view matrix transforms the unit square␍
|
||||
// from world space into view space, while the matrix needed here is the one that transforms␍
|
||||
// the unit square from view space to world space.␍
|
||||
const ovrMatrix4f inv = ovrMatrix4f_Inverse( modelView );␍
|
||||
// This matrix calculates the projection onto the (-1, 1) X and Y axes of the unit square,␍
|
||||
// of the intersection of the vector (tanX, tanY, -1) with the plane described by the matrix␍
|
||||
// that transforms the unit square into world space.␍
|
||||
const ovrMatrix3f m =␍
|
||||
{ {␍
|
||||
{ inv.M[0][0] * inv.M[2][3] - inv.M[0][3] * inv.M[2][0],␍
|
||||
inv.M[0][1] * inv.M[2][3] - inv.M[0][3] * inv.M[2][1],␍
|
||||
inv.M[0][2] * inv.M[2][3] - inv.M[0][3] * inv.M[2][2] },␍
|
||||
{ inv.M[1][0] * inv.M[2][3] - inv.M[1][3] * inv.M[2][0],␍
|
||||
inv.M[1][1] * inv.M[2][3] - inv.M[1][3] * inv.M[2][1],␍
|
||||
inv.M[1][2] * inv.M[2][3] - inv.M[1][3] * inv.M[2][2] },␍
|
||||
{ - inv.M[2][0],␍
|
||||
- inv.M[2][1],␍
|
||||
- inv.M[2][2] }␍
|
||||
} };␍
|
||||
// Flip the Y because textures have 0,0 = left-top as opposed to left-bottom.␍
|
||||
const ovrMatrix3f f = ovrMatrix3f_CreateScaling( 1.0f, -1.0f );␍
|
||||
const ovrMatrix3f s = ovrMatrix3f_CreateScaling( 0.5f, 0.5f );␍
|
||||
const ovrMatrix3f t = ovrMatrix3f_CreateTranslation( 0.5f, 0.5f );␍
|
||||
const ovrMatrix3f r0 = ovrMatrix3f_Multiply( &f, &m );␍
|
||||
const ovrMatrix3f r1 = ovrMatrix3f_Multiply( &s, &r0 );␍
|
||||
const ovrMatrix3f r2 = ovrMatrix3f_Multiply( &t, &r1 );␍
|
||||
return r2;␍
|
||||
*/␍
|
||||
␍
|
||||
const ovrMatrix4f inv = ovrMatrix4f_Inverse( modelView );␍
|
||||
␍
|
||||
ovrMatrix4f m;␍
|
||||
m.M[0][0] = + 0.5f * ( inv.M[0][0] * inv.M[2][3] - inv.M[0][3] * inv.M[2][0] ) - 0.5f * inv.M[2][0];␍
|
||||
m.M[0][1] = + 0.5f * ( inv.M[0][1] * inv.M[2][3] - inv.M[0][3] * inv.M[2][1] ) - 0.5f * inv.M[2][1];␍
|
||||
m.M[0][2] = + 0.5f * ( inv.M[0][2] * inv.M[2][3] - inv.M[0][3] * inv.M[2][2] ) - 0.5f * inv.M[2][2];␍
|
||||
m.M[0][3] = 0.0f;␍
|
||||
␍
|
||||
m.M[1][0] = - 0.5f * ( inv.M[1][0] * inv.M[2][3] - inv.M[1][3] * inv.M[2][0] ) - 0.5f * inv.M[2][0];␍
|
||||
m.M[1][1] = - 0.5f * ( inv.M[1][1] * inv.M[2][3] - inv.M[1][3] * inv.M[2][1] ) - 0.5f * inv.M[2][1];␍
|
||||
m.M[1][2] = - 0.5f * ( inv.M[1][2] * inv.M[2][3] - inv.M[1][3] * inv.M[2][2] ) - 0.5f * inv.M[2][2];␍
|
||||
m.M[1][3] = 0.0f;␍
|
||||
␍
|
||||
m.M[2][0] = - inv.M[2][0];␍
|
||||
m.M[2][1] = - inv.M[2][1];␍
|
||||
m.M[2][2] = - inv.M[2][2];␍
|
||||
m.M[2][3] = 0.0f;␍
|
||||
␍
|
||||
m.M[3][0] = 0.0f;␍
|
||||
m.M[3][1] = 0.0f;␍
|
||||
m.M[3][2] = 0.0f;␍
|
||||
m.M[3][3] = 1.0f;␍
|
||||
return m;␍
|
||||
}␍
|
||||
␍
|
||||
// Utility function to calculate external velocity for smooth stick yaw turning.␍
|
||||
// To reduce judder in FPS style experiences when the application framerate is␍
|
||||
// lower than the vsync rate, the rotation from a joypad can be applied to the␍
|
||||
// view space distorted eye vectors before applying the time warp.␍
|
||||
static inline ovrMatrix4f ovrMatrix4f_CalculateExternalVelocity( const ovrMatrix4f * viewMatrix, const float yawRadiansPerSecond )␍
|
||||
{␍
|
||||
const float angle = yawRadiansPerSecond * ( -1.0f / 60.0f );␍
|
||||
const float sinHalfAngle = sinf( angle * 0.5f );␍
|
||||
const float cosHalfAngle = cosf( angle * 0.5f );␍
|
||||
␍
|
||||
// Yaw is always going to be around the world Y axis␍
|
||||
ovrQuatf quat;␍
|
||||
quat.x = viewMatrix->M[0][1] * sinHalfAngle;␍
|
||||
quat.y = viewMatrix->M[1][1] * sinHalfAngle;␍
|
||||
quat.z = viewMatrix->M[2][1] * sinHalfAngle;␍
|
||||
quat.w = cosHalfAngle;␍
|
||||
return ovrMatrix4f_CreateFromQuaternion( &quat );␍
|
||||
}␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Default initialization helper functions.␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Utility function to default initialize the ovrInitParms.␍
|
||||
static inline ovrInitParms vrapi_DefaultInitParms( const ovrJava * java )␍
|
||||
{␍
|
||||
ovrInitParms parms;␍
|
||||
memset( &parms, 0, sizeof( parms ) );␍
|
||||
␍
|
||||
parms.Type = VRAPI_STRUCTURE_TYPE_INIT_PARMS;␍
|
||||
parms.ProductVersion = VRAPI_PRODUCT_VERSION;␍
|
||||
parms.MajorVersion = VRAPI_MAJOR_VERSION;␍
|
||||
parms.MinorVersion = VRAPI_MINOR_VERSION;␍
|
||||
parms.PatchVersion = VRAPI_PATCH_VERSION;␍
|
||||
parms.GraphicsAPI = VRAPI_GRAPHICS_API_OPENGL_ES_2;␍
|
||||
parms.Java = *java;␍
|
||||
␍
|
||||
return parms;␍
|
||||
}␍
|
||||
␍
|
||||
// Utility function to default initialize the ovrModeParms.␍
|
||||
static inline ovrModeParms vrapi_DefaultModeParms( const ovrJava * java )␍
|
||||
{␍
|
||||
ovrModeParms parms;␍
|
||||
memset( &parms, 0, sizeof( parms ) );␍
|
||||
␍
|
||||
parms.Type = VRAPI_STRUCTURE_TYPE_MODE_PARMS;␍
|
||||
parms.AllowPowerSave = true;␍
|
||||
parms.ResetWindowFullscreen = true;␍
|
||||
parms.Java = *java;␍
|
||||
␍
|
||||
return parms;␍
|
||||
}␍
|
||||
␍
|
||||
// Utility function to default initialize the ovrPerformanceParms.␍
|
||||
static inline ovrPerformanceParms vrapi_DefaultPerformanceParms()␍
|
||||
{␍
|
||||
ovrPerformanceParms parms;␍
|
||||
parms.CpuLevel = 2;␍
|
||||
parms.GpuLevel = 2;␍
|
||||
parms.MainThreadTid = 0;␍
|
||||
parms.RenderThreadTid = 0;␍
|
||||
return parms;␍
|
||||
}␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_FRAME_INIT_DEFAULT,␍
|
||||
VRAPI_FRAME_INIT_BLACK,␍
|
||||
VRAPI_FRAME_INIT_BLACK_FLUSH,␍
|
||||
VRAPI_FRAME_INIT_BLACK_FINAL,␍
|
||||
VRAPI_FRAME_INIT_LOADING_ICON,␍
|
||||
VRAPI_FRAME_INIT_LOADING_ICON_FLUSH,␍
|
||||
VRAPI_FRAME_INIT_MESSAGE,␍
|
||||
VRAPI_FRAME_INIT_MESSAGE_FLUSH␍
|
||||
} ovrFrameInit;␍
|
||||
␍
|
||||
// Utility function to default initialize the ovrFrameParms.␍
|
||||
static inline ovrFrameParms vrapi_DefaultFrameParms( const ovrJava * java, const ovrFrameInit init, const double currentTime, ␍
|
||||
ovrTextureSwapChain * textureSwapChain )␍
|
||||
{␍
|
||||
const ovrMatrix4f projectionMatrix = ovrMatrix4f_CreateProjectionFov( 90.0f, 90.0f, 0.0f, 0.0f, 0.1f, 0.0f );␍
|
||||
const ovrMatrix4f texCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &projectionMatrix );␍
|
||||
␍
|
||||
ovrFrameParms parms;␍
|
||||
memset( &parms, 0, sizeof( parms ) );␍
|
||||
␍
|
||||
parms.Type = VRAPI_STRUCTURE_TYPE_FRAME_PARMS;␍
|
||||
for ( int layer = 0; layer < VRAPI_FRAME_LAYER_TYPE_MAX; layer++ )␍
|
||||
{␍
|
||||
parms.Layers[layer].ProgramParms[2] = 1.0f; // color scale␍
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )␍
|
||||
{␍
|
||||
parms.Layers[layer].Textures[eye].TexCoordsFromTanAngles = texCoordsFromTanAngles;␍
|
||||
parms.Layers[layer].Textures[eye].TextureRect.width = 1.0f;␍
|
||||
parms.Layers[layer].Textures[eye].TextureRect.height = 1.0f;␍
|
||||
parms.Layers[layer].Textures[eye].HeadPose.Pose.Orientation.w = 1.0f;␍
|
||||
parms.Layers[layer].Textures[eye].HeadPose.TimeInSeconds = currentTime;␍
|
||||
}␍
|
||||
}␍
|
||||
parms.LayerCount = 1;␍
|
||||
parms.MinimumVsyncs = 1;␍
|
||||
parms.ExtraLatencyMode = VRAPI_EXTRA_LATENCY_MODE_OFF;␍
|
||||
parms.ExternalVelocity.M[0][0] = 1.0f;␍
|
||||
parms.ExternalVelocity.M[1][1] = 1.0f;␍
|
||||
parms.ExternalVelocity.M[2][2] = 1.0f;␍
|
||||
parms.ExternalVelocity.M[3][3] = 1.0f;␍
|
||||
parms.PerformanceParms = vrapi_DefaultPerformanceParms();␍
|
||||
parms.Java = *java;␍
|
||||
␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].SrcBlend = VRAPI_FRAME_LAYER_BLEND_ONE;␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].DstBlend = VRAPI_FRAME_LAYER_BLEND_ZERO;␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Flags = 0;␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].SrcBlend = VRAPI_FRAME_LAYER_BLEND_SRC_ALPHA;␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].DstBlend = VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA;␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].Flags = 0;␍
|
||||
␍
|
||||
switch ( init )␍
|
||||
{␍
|
||||
case VRAPI_FRAME_INIT_DEFAULT:␍
|
||||
{␍
|
||||
break;␍
|
||||
}␍
|
||||
case VRAPI_FRAME_INIT_BLACK:␍
|
||||
case VRAPI_FRAME_INIT_BLACK_FLUSH:␍
|
||||
case VRAPI_FRAME_INIT_BLACK_FINAL:␍
|
||||
{␍
|
||||
parms.Flags = VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER;␍
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )␍
|
||||
{␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].ColorTextureSwapChain = (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_BLACK;␍
|
||||
}␍
|
||||
break;␍
|
||||
}␍
|
||||
case VRAPI_FRAME_INIT_LOADING_ICON:␍
|
||||
case VRAPI_FRAME_INIT_LOADING_ICON_FLUSH:␍
|
||||
{␍
|
||||
parms.LayerCount = 2;␍
|
||||
parms.Flags = VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER;␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].Flags = VRAPI_FRAME_LAYER_FLAG_SPIN;␍
|
||||
parms.Layers[1].ProgramParms[0] = 1.0f; // rotation in radians per second␍
|
||||
parms.Layers[1].ProgramParms[1] = 16.0f; // icon size factor smaller than fullscreen␍
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )␍
|
||||
{␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].ColorTextureSwapChain = (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_BLACK;␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].Textures[eye].ColorTextureSwapChain = ( textureSwapChain != NULL ) ? textureSwapChain : (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_LOADING_ICON;␍
|
||||
}␍
|
||||
break;␍
|
||||
}␍
|
||||
case VRAPI_FRAME_INIT_MESSAGE:␍
|
||||
case VRAPI_FRAME_INIT_MESSAGE_FLUSH:␍
|
||||
{␍
|
||||
parms.LayerCount = 2;␍
|
||||
parms.Flags = VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER;␍
|
||||
parms.Layers[1].ProgramParms[0] = 0.0f; // rotation in radians per second␍
|
||||
parms.Layers[1].ProgramParms[1] = 2.0f; // message size factor smaller than fullscreen␍
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )␍
|
||||
{␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_WORLD].Textures[eye].ColorTextureSwapChain = (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_BLACK;␍
|
||||
parms.Layers[VRAPI_FRAME_LAYER_TYPE_OVERLAY].Textures[eye].ColorTextureSwapChain = ( textureSwapChain != NULL ) ? textureSwapChain : (ovrTextureSwapChain *)VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_LOADING_ICON;␍
|
||||
}␍
|
||||
break;␍
|
||||
}␍
|
||||
}␍
|
||||
␍
|
||||
if ( init == VRAPI_FRAME_INIT_BLACK_FLUSH || init == VRAPI_FRAME_INIT_LOADING_ICON_FLUSH || init == VRAPI_FRAME_INIT_MESSAGE_FLUSH )␍
|
||||
{␍
|
||||
parms.Flags |= VRAPI_FRAME_FLAG_FLUSH;␍
|
||||
}␍
|
||||
if ( init == VRAPI_FRAME_INIT_BLACK_FINAL )␍
|
||||
{␍
|
||||
parms.Flags |= VRAPI_FRAME_FLAG_FLUSH | VRAPI_FRAME_FLAG_FINAL;␍
|
||||
}␍
|
||||
␍
|
||||
return parms;␍
|
||||
}␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Head Model␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Utility function to default initialize the ovrHeadModelParms.␍
|
||||
static inline ovrHeadModelParms vrapi_DefaultHeadModelParms()␍
|
||||
{␍
|
||||
ovrHeadModelParms parms;␍
|
||||
memset( &parms, 0, sizeof( parms ) );␍
|
||||
␍
|
||||
parms.InterpupillaryDistance = 0.0640f; // average interpupillary distance␍
|
||||
parms.EyeHeight = 1.6750f; // average eye height above the ground when standing␍
|
||||
parms.HeadModelDepth = 0.0805f;␍
|
||||
parms.HeadModelHeight = 0.0750f;␍
|
||||
␍
|
||||
return parms;␍
|
||||
}␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Eye view matrix helper functions.␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Apply the head-on-a-stick model if head tracking is not available.␍
|
||||
static inline ovrTracking vrapi_ApplyHeadModel( const ovrHeadModelParms * headModelParms, const ovrTracking * tracking )␍
|
||||
{␍
|
||||
if ( ( tracking->Status & VRAPI_TRACKING_STATUS_POSITION_TRACKED ) == 0 )␍
|
||||
{␍
|
||||
// Calculate the head position based on the head orientation using a head-on-a-stick model.␍
|
||||
const ovrHeadModelParms * p = headModelParms;␍
|
||||
const ovrMatrix4f m = ovrMatrix4f_CreateFromQuaternion( &tracking->HeadPose.Pose.Orientation );␍
|
||||
ovrTracking newTracking = *tracking;␍
|
||||
newTracking.HeadPose.Pose.Position.x = m.M[0][1] * p->HeadModelHeight - m.M[0][2] * p->HeadModelDepth;␍
|
||||
newTracking.HeadPose.Pose.Position.y = m.M[1][1] * p->HeadModelHeight - m.M[1][2] * p->HeadModelDepth - p->HeadModelHeight;␍
|
||||
newTracking.HeadPose.Pose.Position.z = m.M[2][1] * p->HeadModelHeight - m.M[2][2] * p->HeadModelDepth;␍
|
||||
return newTracking;␍
|
||||
}␍
|
||||
return *tracking;␍
|
||||
}␍
|
||||
␍
|
||||
// Utility function to get the center eye transform.␍
|
||||
// Pass in NULL for 'input' if there is no additional controller input.␍
|
||||
static inline ovrMatrix4f vrapi_GetCenterEyeTransform( const ovrHeadModelParms * headModelParms,␍
|
||||
const ovrTracking * tracking,␍
|
||||
const ovrMatrix4f * input )␍
|
||||
{␍
|
||||
VRAPI_UNUSED( headModelParms );␍
|
||||
␍
|
||||
// Controller input is expected to be applied relative to the head in neutral position, which means␍
|
||||
// ovrTracking::HeadPose.Pose.Position should be relative to the center of the head in neutral position.␍
|
||||
const ovrMatrix4f centerEyeRotation = ovrMatrix4f_CreateFromQuaternion( &tracking->HeadPose.Pose.Orientation );␍
|
||||
const ovrVector3f centerEyeOffset = tracking->HeadPose.Pose.Position;␍
|
||||
const ovrMatrix4f centerEyeTranslation = ovrMatrix4f_CreateTranslation( centerEyeOffset.x, centerEyeOffset.y, centerEyeOffset.z );␍
|
||||
const ovrMatrix4f centerEyeTransform = ovrMatrix4f_Multiply( ¢erEyeTranslation, ¢erEyeRotation );␍
|
||||
return ( input == NULL ) ? centerEyeTransform : ovrMatrix4f_Multiply( input, ¢erEyeTransform );␍
|
||||
}␍
|
||||
␍
|
||||
// Utility function to get the center eye view matrix.␍
|
||||
// Pass in NULL for 'input' if there is no additional controller input.␍
|
||||
static inline ovrMatrix4f vrapi_GetCenterEyeViewMatrix( const ovrHeadModelParms * headModelParms,␍
|
||||
const ovrTracking * tracking,␍
|
||||
const ovrMatrix4f * input )␍
|
||||
{␍
|
||||
const ovrMatrix4f centerEyeTransform = vrapi_GetCenterEyeTransform( headModelParms, tracking, input );␍
|
||||
return ovrMatrix4f_Inverse( ¢erEyeTransform );␍
|
||||
}␍
|
||||
␍
|
||||
// Utility function to get the eye view matrix based on the center eye view matrix and the IPD.␍
|
||||
static inline ovrMatrix4f vrapi_GetEyeViewMatrix( const ovrHeadModelParms * headModelParms,␍
|
||||
const ovrMatrix4f * centerEyeViewMatrix,␍
|
||||
const int eye )␍
|
||||
{␍
|
||||
const float eyeOffset = ( eye ? -0.5f : 0.5f ) * headModelParms->InterpupillaryDistance;␍
|
||||
const ovrMatrix4f eyeOffsetMatrix = ovrMatrix4f_CreateTranslation( eyeOffset, 0.0f, 0.0f );␍
|
||||
return ovrMatrix4f_Multiply( &eyeOffsetMatrix, centerEyeViewMatrix );␍
|
||||
}␍
|
||||
␍
|
||||
#endif // OVR_VrApi_Helpers_h␍
|
||||
@@ -0,0 +1,84 @@
|
||||
/************************************************************************************␍
|
||||
␍
|
||||
Filename : VrApi_LocalPrefs.h␍
|
||||
Content : Interface for device-local preferences␍
|
||||
Created : July 8, 2014␍
|
||||
Authors : John Carmack␍
|
||||
␍
|
||||
Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved.␍
|
||||
␍
|
||||
*************************************************************************************/␍
|
||||
#ifndef OVR_VrApi_LocalPrefs_h␍
|
||||
#define OVR_VrApi_LocalPrefs_h␍
|
||||
␍
|
||||
#include "VrApi_Config.h"␍
|
||||
#include "VrApi_Types.h"␍
|
||||
␍
|
||||
#if defined( __cplusplus )␍
|
||||
extern "C" {␍
|
||||
#endif␍
|
||||
␍
|
||||
// Local preferences are for storing platform-wide settings that are tied to␍
|
||||
// a device instead of an application or user.␍
|
||||
␍
|
||||
// Initially this is just a set of strings stored to /sdcard/.oculusprefs, but it␍
|
||||
// may move to some other database.␍
|
||||
//␍
|
||||
// While it is here, you can easily set one or more values with adb like this:␍
|
||||
// adb shell "echo dev_enableCapture 1 > /sdcard/.oculusprefs"␍
|
||||
//␍
|
||||
// The key / value pairs are just alternate tokens, with no newline required, so␍
|
||||
// you can set multiple values at once:␍
|
||||
//␍
|
||||
// adb shell "echo dev_enableCapture 1 dev_powerLevelState 1 > /sdcard/.oculusprefs"␍
|
||||
␍
|
||||
// Enable support for Oculus Remote Monitor to connect to the application.␍
|
||||
#define LOCAL_PREF_VRAPI_ENABLE_CAPTURE "dev_enableCapture" // "0" or "1"␍
|
||||
␍
|
||||
// Use the provided cpu and gpu levels for setting␍
|
||||
// fixed clock levels.␍
|
||||
#define LOCAL_PREF_VRAPI_CPU_LEVEL "dev_cpuLevel" // "0", "1", "2", or "3"␍
|
||||
#define LOCAL_PREF_VRAPI_GPU_LEVEL "dev_gpuLevel" // "0", "1", "2", or "3"␍
|
||||
␍
|
||||
// Shipping applications will always want this on, but if you want to draw␍
|
||||
// directly to the screen for debug tasks, you can run synchronously so the␍
|
||||
// init thread is still current on the window.␍
|
||||
#define LOCAL_PREF_VRAPI_ASYNC_TIMEWARP "dev_asyncTimewarp" // "0" or "1"␍
|
||||
␍
|
||||
// Optionally force a specific MinimumVsyncs.␍
|
||||
#define LOCAL_PREF_VRAPI_MINIMUM_VSYNCS "dev_mimumumVsyncs" // "0", "1", "2", "3"␍
|
||||
␍
|
||||
// Optionally force a specific extra latency mode.␍
|
||||
#define LOCAL_PREF_VRAPI_EXTRA_LATENCY_MODE "dev_extraLatencyMode" // "0" = off, "1" = on, "2" = dynamic␍
|
||||
␍
|
||||
// For video capture or testing on reference platforms without direct frontbuffer␍
|
||||
// rendering, direct frontbuffer can be forced off.␍
|
||||
#define LOCAL_PREF_VRAPI_FRONTBUFFER "dev_frontbuffer" // "0" or "1"␍
|
||||
␍
|
||||
// Optional distortion file to override built-in distortion.␍
|
||||
#define LOCAL_PREF_VRAPI_DISTORTION_FILE_NAME "dev_distortionFileName" // default = ""␍
|
||||
␍
|
||||
// Experimental feature that clips the distortion mesh to reduce GPU fill for timewarp+distortion␍
|
||||
#define LOCAL_PREF_VRAPI_CLIP_DISTORTION_MESH "dev_clipDistortionMesh" // "0" = off, "1" = clip to optics, "2" = clip to framebuffer␍
|
||||
␍
|
||||
// Debug option to draw the axis lines after warp.␍
|
||||
#define LOCAL_PREF_VRAPI_DRAW_CALIBRATION_LINES "dev_drawCalibrationLines" // "0" or "1"␍
|
||||
␍
|
||||
#define LOCAL_PREF_VRAPI_GPU_TIMINGS "dev_gpuTimings" // "0" = off, "1" = glBeginQuery/glEndQuery, "2" = glQueryCounter␍
|
||||
␍
|
||||
#define LOCAL_PREF_APP_DEBUG_OPTIONS "dev_debugOptions" // "0" or "1"␍
|
||||
␍
|
||||
#define LOCAL_PREF_VRAPI_SIMULATE_UNDOCK "dev_simulateUndock" // time to wait before simulating an undock event, < 0 means don't simulate␍
|
||||
␍
|
||||
// Query the in-memory preferences for a (case insensitive) key / value pair.␍
|
||||
// If the returned string is not defaultKeyValue, it will remain valid until the next ovr_UpdateLocalPreferences().␍
|
||||
OVR_VRAPI_EXPORT const char * ovr_GetLocalPreferenceValueForKey( const char * keyName, const char * defaultKeyValue );␍
|
||||
␍
|
||||
// Updates the in-memory data and synchronously writes it to storage.␍
|
||||
OVR_VRAPI_EXPORT void ovr_SetLocalPreferenceValueForKey( const char * keyName, const char * keyValue );␍
|
||||
␍
|
||||
#if defined( __cplusplus )␍
|
||||
} // extern "C"␍
|
||||
#endif␍
|
||||
␍
|
||||
#endif // OVR_VrApi_LocalPrefs_h␍
|
||||
@@ -0,0 +1,530 @@
|
||||
/************************************************************************************␍
|
||||
␍
|
||||
Filename : VrApi_Types.h␍
|
||||
Content : Types for minimum necessary API for mobile VR␍
|
||||
Created : April 30, 2015␍
|
||||
Authors : J.M.P. van Waveren␍
|
||||
␍
|
||||
Copyright : Copyright 2015 Oculus VR, LLC. All Rights reserved.␍
|
||||
␍
|
||||
*************************************************************************************/␍
|
||||
#ifndef OVR_VrApi_Types_h␍
|
||||
#define OVR_VrApi_Types_h␍
|
||||
␍
|
||||
#include <stdbool.h>␍
|
||||
#include "VrApi_Config.h" // needed for VRAPI_EXPORT␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Java␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
#if defined( ANDROID )␍
|
||||
#include <jni.h>␍
|
||||
#elif defined( __cplusplus )␍
|
||||
typedef struct _JNIEnv JNIEnv;␍
|
||||
typedef struct _JavaVM JavaVM;␍
|
||||
typedef class _jobject * jobject;␍
|
||||
#else␍
|
||||
typedef const struct JNINativeInterface * JNIEnv;␍
|
||||
typedef const struct JNIInvokeInterface * JavaVM;␍
|
||||
void * jobject;␍
|
||||
#endif␍
|
||||
␍
|
||||
typedef struct␍
|
||||
{␍
|
||||
JavaVM * Vm; // Java Virtual Machine␍
|
||||
JNIEnv * Env; // Thread specific environment␍
|
||||
jobject ActivityObject; // Java activity object␍
|
||||
} ovrJava;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Basic Types␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
typedef struct ovrVector3f_␍
|
||||
{␍
|
||||
float x, y, z;␍
|
||||
} ovrVector3f;␍
|
||||
␍
|
||||
// Quaternion.␍
|
||||
typedef struct ovrQuatf_␍
|
||||
{␍
|
||||
float x, y, z, w;␍
|
||||
} ovrQuatf;␍
|
||||
␍
|
||||
// Row-major 4x4 matrix.␍
|
||||
typedef struct ovrMatrix4f_␍
|
||||
{␍
|
||||
float M[4][4];␍
|
||||
} ovrMatrix4f;␍
|
||||
␍
|
||||
// Position and orientation together.␍
|
||||
typedef struct ovrPosef_␍
|
||||
{␍
|
||||
ovrQuatf Orientation;␍
|
||||
ovrVector3f Position;␍
|
||||
} ovrPosef;␍
|
||||
␍
|
||||
typedef struct ovrRectf_␍
|
||||
{␍
|
||||
float x;␍
|
||||
float y;␍
|
||||
float width;␍
|
||||
float height;␍
|
||||
} ovrRectf;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_FALSE = 0,␍
|
||||
VRAPI_TRUE␍
|
||||
} ovrBooleanResult;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Structure Types␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_STRUCTURE_TYPE_INIT_PARMS = 1,␍
|
||||
VRAPI_STRUCTURE_TYPE_MODE_PARMS = 2,␍
|
||||
VRAPI_STRUCTURE_TYPE_FRAME_PARMS = 3,␍
|
||||
} ovrStructureType;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// System Properties and Status␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_DEVICE_TYPE_NOTE4,␍
|
||||
VRAPI_DEVICE_TYPE_NOTE5,␍
|
||||
VRAPI_DEVICE_TYPE_S6,␍
|
||||
VRAPI_MAX_DEVICE_TYPES␍
|
||||
} ovrDeviceType;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_SYS_PROP_DEVICE_TYPE,␍
|
||||
VRAPI_SYS_PROP_MAX_FULLSPEED_FRAMEBUFFER_SAMPLES,␍
|
||||
// Physical width and height of the display in pixels.␍
|
||||
VRAPI_SYS_PROP_DISPLAY_PIXELS_WIDE,␍
|
||||
VRAPI_SYS_PROP_DISPLAY_PIXELS_HIGH,␍
|
||||
// Refresh rate of the display in cycles per second.␍
|
||||
// Currently 60Hz.␍
|
||||
VRAPI_SYS_PROP_DISPLAY_REFRESH_RATE,␍
|
||||
// With a display resolution of 2560x1440, the pixels at the center␍
|
||||
// of each eye cover about 0.06 degrees of visual arc. To wrap a␍
|
||||
// full 360 degrees, about 6000 pixels would be needed and about one␍
|
||||
// quarter of that would be needed for ~90 degrees FOV. As such, Eye␍
|
||||
// images with a resolution of 1536x1536 result in a good 1:1 mapping␍
|
||||
// in the center, but they need mip-maps for off center pixels. To␍
|
||||
// avoid the need for mip-maps and for significantly improved rendering␍
|
||||
// performance this currently returns a conservative 1024x1024.␍
|
||||
VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_WIDTH,␍
|
||||
VRAPI_SYS_PROP_SUGGESTED_EYE_TEXTURE_HEIGHT,␍
|
||||
// This is a product of the lens distortion and the screen size,␍
|
||||
// but there is no truly correct answer.␍
|
||||
// There is a tradeoff in resolution and coverage.␍
|
||||
// Too small of an FOV will leave unrendered pixels visible, but too␍
|
||||
// large wastes resolution or fill rate. It is unreasonable to␍
|
||||
// increase it until the corners are completely covered, but we do␍
|
||||
// want most of the outside edges completely covered.␍
|
||||
// Applications might choose to render a larger FOV when angular␍
|
||||
// acceleration is high to reduce black pull in at the edges by␍
|
||||
// the time warp.␍
|
||||
// Currently symmetric 90.0 degrees.␍
|
||||
VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_X, // Horizontal field of view in degrees␍
|
||||
VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y, // Vertical field of view in degrees␍
|
||||
} ovrSystemProperty;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_SYS_STATUS_DOCKED, // Device is docked.␍
|
||||
VRAPI_SYS_STATUS_MOUNTED, // Device is mounted.␍
|
||||
VRAPI_SYS_STATUS_THROTTLED, // Device is in powersave mode.␍
|
||||
VRAPI_SYS_STATUS_THROTTLED2, // Device is in extreme powersave mode.␍
|
||||
VRAPI_SYS_STATUS_THROTTLED_WARNING_LEVEL, // Powersave mode warning required.␍
|
||||
VRAPI_SYS_STATUS_RENDER_LATENCY_MILLISECONDS, // Average time between render tracking sample and scanout.␍
|
||||
VRAPI_SYS_STATUS_TIMEWARP_LATENCY_MILLISECONDS, // Average time between timewarp tracking sample and scanout.␍
|
||||
VRAPI_SYS_STATUS_SCANOUT_LATENCY_MILLISECONDS, // Average time between Vsync and scanout.␍
|
||||
VRAPI_SYS_STATUS_APP_FRAMES_PER_SECOND, // Number of frames per second delivered through vrapi_SubmitFrame.␍
|
||||
VRAPI_SYS_STATUS_SCREEN_TEARS_PER_SECOND, // Number of screen tears per second (per eye).␍
|
||||
VRAPI_SYS_STATUS_EARLY_FRAMES_PER_SECOND, // Number of frames per second delivered a whole display refresh early.␍
|
||||
VRAPI_SYS_STATUS_STALE_FRAMES_PER_SECOND, // Number of frames per second delivered late.␍
|
||||
} ovrSystemStatus;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Initialization␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_INITIALIZE_SUCCESS = 0,␍
|
||||
VRAPI_INITIALIZE_UNKNOWN_ERROR = -1,␍
|
||||
VRAPI_INITIALIZE_PERMISSIONS_ERROR = -2,␍
|
||||
} ovrInitializeStatus;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_GRAPHICS_API_OPENGL_ES_2 = ( 0x10000 | 0x0200 ), // OpenGL ES 2.x context␍
|
||||
VRAPI_GRAPHICS_API_OPENGL_ES_3 = ( 0x10000 | 0x0300 ), // OpenGL ES 3.x context␍
|
||||
VRAPI_GRAPHICS_API_OPENGL_COMPAT = ( 0x20000 | 0x0100 ), // OpenGL Compatibility Profile␍
|
||||
VRAPI_GRAPHICS_API_OPENGL_CORE_3 = ( 0x20000 | 0x0300 ), // OpenGL Core Profile 3.x␍
|
||||
VRAPI_GRAPHICS_API_OPENGL_CORE_4 = ( 0x20000 | 0x0400 ), // OpenGL Core Profile 4.x␍
|
||||
} ovrGraphicsAPI;␍
|
||||
␍
|
||||
typedef struct␍
|
||||
{␍
|
||||
ovrStructureType Type;␍
|
||||
int ProductVersion;␍
|
||||
int MajorVersion;␍
|
||||
int MinorVersion;␍
|
||||
int PatchVersion;␍
|
||||
ovrGraphicsAPI GraphicsAPI;␍
|
||||
ovrJava Java;␍
|
||||
} ovrInitParms;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// VR Mode␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
typedef struct␍
|
||||
{␍
|
||||
ovrStructureType Type;␍
|
||||
␍
|
||||
// If true, warn and allow the app to continue at 30fps when␍
|
||||
// throttling occurs.␍
|
||||
// If false, display the level 2 error message which requires␍
|
||||
// the user to undock.␍
|
||||
bool AllowPowerSave;␍
|
||||
␍
|
||||
// When an application with multiple activities moves backwards on␍
|
||||
// the activity stack, the activity window it returns to is no longer␍
|
||||
// flagged as fullscreen. As a result, Android will also render␍
|
||||
// the decor view, which wastes a significant amount of bandwidth.␍
|
||||
// By setting this flag, the fullscreen flag is reset on the window.␍
|
||||
// Unfortunately, this causes Android life cycle events that mess up␍
|
||||
// several NativeActivity codebases like Stratum and UE4, so this␍
|
||||
// flag should only be set for select applications with multiple␍
|
||||
// activities. Use "adb shell dumpsys SurfaceFlinger" to verify␍
|
||||
// that there is only one HWC next to the FB_TARGET.␍
|
||||
bool ResetWindowFullscreen;␍
|
||||
␍
|
||||
// The Java VM is needed for the time warp thread to create a Java environment.␍
|
||||
// A Java environment is needed to access various system services. The thread␍
|
||||
// that enters VR mode is responsible for attaching and detaching the Java␍
|
||||
// environment. The Java Activity object is needed to get the windowManager,␍
|
||||
// packageName, systemService, etc.␍
|
||||
ovrJava Java;␍
|
||||
␍
|
||||
// If not zero, then use this display for asynchronous time warp rendering.␍
|
||||
// Using EGL this is an EGLDisplay.␍
|
||||
unsigned long long Display;␍
|
||||
␍
|
||||
// If not zero, then use this window surface for asynchronous time warp rendering␍
|
||||
// This is expected to be the front buffer.␍
|
||||
// Using EGL this is an EGLSurface.␍
|
||||
unsigned long long WindowSurface;␍
|
||||
␍
|
||||
// If not zero, then resources from this context will be shared␍
|
||||
// with the asynchronous time warp.␍
|
||||
// Using EGL this is an EGLContext.␍
|
||||
unsigned long long ShareContext;␍
|
||||
} ovrModeParms;␍
|
||||
␍
|
||||
// VR context␍
|
||||
// To allow multiple Android activities that live in the same address space␍
|
||||
// to cooperatively use the VrApi, each activity needs to maintain its own␍
|
||||
// separate contexts for a lot of the video related systems.␍
|
||||
typedef struct ovrMobile ovrMobile;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Tracking␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
// Full rigid body pose with first and second derivatives.␍
|
||||
typedef struct ovrRigidBodyPosef_␍
|
||||
{␍
|
||||
ovrPosef Pose;␍
|
||||
ovrVector3f AngularVelocity;␍
|
||||
ovrVector3f LinearVelocity;␍
|
||||
ovrVector3f AngularAcceleration;␍
|
||||
ovrVector3f LinearAcceleration;␍
|
||||
double TimeInSeconds; // Absolute time of this pose.␍
|
||||
double PredictionInSeconds; // Seconds this pose was predicted ahead.␍
|
||||
} ovrRigidBodyPosef;␍
|
||||
␍
|
||||
// Bit flags describing the current status of sensor tracking.␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_TRACKING_STATUS_ORIENTATION_TRACKED = 0x0001, // Orientation is currently tracked.␍
|
||||
VRAPI_TRACKING_STATUS_POSITION_TRACKED = 0x0002, // Position is currently tracked.␍
|
||||
VRAPI_TRACKING_STATUS_HMD_CONNECTED = 0x0080 // HMD is available & connected.␍
|
||||
} ovrTrackingStatus;␍
|
||||
␍
|
||||
// Tracking state at a given absolute time.␍
|
||||
typedef struct ovrTracking_␍
|
||||
{␍
|
||||
// Sensor status described by ovrTrackingStatus flags.␍
|
||||
unsigned int Status;␍
|
||||
// Predicted head configuration at the requested absolute time.␍
|
||||
// The pose describes the head orientation and center eye position.␍
|
||||
ovrRigidBodyPosef HeadPose;␍
|
||||
} ovrTracking;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Texture Swap Chain␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_TEXTURE_TYPE_2D, // 2D textures.␍
|
||||
VRAPI_TEXTURE_TYPE_2D_EXTERNAL, // External 2D texture.␍
|
||||
VRAPI_TEXTURE_TYPE_2D_ARRAY, // Texture array.␍
|
||||
VRAPI_TEXTURE_TYPE_CUBE, // Cube maps.␍
|
||||
VRAPI_TEXTURE_TYPE_MAX␍
|
||||
} ovrTextureType;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_TEXTURE_FORMAT_NONE,␍
|
||||
VRAPI_TEXTURE_FORMAT_565,␍
|
||||
VRAPI_TEXTURE_FORMAT_5551,␍
|
||||
VRAPI_TEXTURE_FORMAT_4444,␍
|
||||
VRAPI_TEXTURE_FORMAT_8888,␍
|
||||
VRAPI_TEXTURE_FORMAT_8888_sRGB,␍
|
||||
VRAPI_TEXTURE_FORMAT_RGBA16F,␍
|
||||
VRAPI_TEXTURE_FORMAT_DEPTH_16,␍
|
||||
VRAPI_TEXTURE_FORMAT_DEPTH_24,␍
|
||||
VRAPI_TEXTURE_FORMAT_DEPTH_24_STENCIL_8,␍
|
||||
} ovrTextureFormat;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_BLACK = 0x1,␍
|
||||
VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_LOADING_ICON = 0x2␍
|
||||
} ovrDefaultTextureSwapChain;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_TEXTURE_SWAPCHAIN_FULL_MIP_CHAIN = -1␍
|
||||
} ovrTextureSwapChainSettings;␍
|
||||
␍
|
||||
typedef struct ovrTextureSwapChain ovrTextureSwapChain;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Frame Submission␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
// To get gamma correct sRGB filtering of the eye textures, the textures must be␍
|
||||
// allocated with GL_SRGB8_ALPHA8 format and the window surface must be allocated␍
|
||||
// with these attributes:␍
|
||||
// EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR␍
|
||||
//␍
|
||||
// While we can reallocate textures easily enough, we can't change the window␍
|
||||
// colorspace without relaunching the entire application, so if you want to␍
|
||||
// be able to toggle between gamma correct and incorrect, you must allocate␍
|
||||
// the framebuffer as sRGB, then inhibit that processing when using normal␍
|
||||
// textures.␍
|
||||
VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER = 1,␍
|
||||
// Flush the warp swap pipeline so the images show up immediately.␍
|
||||
// This is expensive and should only be used when an immediate transition␍
|
||||
// is needed like displaying black when resetting the HMD orientation.␍
|
||||
VRAPI_FRAME_FLAG_FLUSH = 2,␍
|
||||
// This is the final frame. Do not accept any more frames after this.␍
|
||||
VRAPI_FRAME_FLAG_FINAL = 4,␍
|
||||
// Display continuously changing graph of TimeWarp timing data. By default,␍
|
||||
// this will display the start and end times of the draw.␍
|
||||
VRAPI_FRAME_FLAG_TIMEWARP_DEBUG_GRAPH_SHOW = 8,␍
|
||||
// Continue to display the timing data, but no new data is collected and displayed.␍
|
||||
VRAPI_FRAME_FLAG_TIMEWARP_DEBUG_GRAPH_FREEZE = 16,␍
|
||||
// Change the TimeWarp graph to display the latency (seconds from eye buffer␍
|
||||
// orientation time) instead of the draw times.␍
|
||||
VRAPI_FRAME_FLAG_TIMEWARP_DEBUG_GRAPH_LATENCY_MODE = 32,␍
|
||||
} ovrFrameFlags;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
// Enable writing to the alpha channel␍
|
||||
VRAPI_FRAME_LAYER_FLAG_WRITE_ALPHA = 1,␍
|
||||
// Correct for chromatic aberration. Quality/perf trade-off.␍
|
||||
VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION = 2,␍
|
||||
// Used for some HUDs, but generally considered bad practice.␍
|
||||
VRAPI_FRAME_LAYER_FLAG_FIXED_TO_VIEW = 4,␍
|
||||
// Spin the layer - for loading icons␍
|
||||
VRAPI_FRAME_LAYER_FLAG_SPIN = 8,␍
|
||||
} ovrFrameLayerFlags;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_FRAME_LAYER_EYE_LEFT,␍
|
||||
VRAPI_FRAME_LAYER_EYE_RIGHT,␍
|
||||
VRAPI_FRAME_LAYER_EYE_MAX␍
|
||||
} ovrFrameLayerEye;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_FRAME_LAYER_BLEND_ZERO,␍
|
||||
VRAPI_FRAME_LAYER_BLEND_ONE,␍
|
||||
VRAPI_FRAME_LAYER_BLEND_SRC_ALPHA,␍
|
||||
VRAPI_FRAME_LAYER_BLEND_DST_ALPHA,␍
|
||||
VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_DST_ALPHA,␍
|
||||
VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA␍
|
||||
} ovrFrameLayerBlend;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_FRAME_LAYER_TYPE_WORLD,␍
|
||||
VRAPI_FRAME_LAYER_TYPE_OVERLAY,␍
|
||||
VRAPI_FRAME_LAYER_TYPE_CURSOR,␍
|
||||
VRAPI_FRAME_LAYER_TYPE_USER,␍
|
||||
VRAPI_FRAME_LAYER_TYPE_MAX␍
|
||||
} ovrFrameLayerType;␍
|
||||
␍
|
||||
typedef enum␍
|
||||
{␍
|
||||
VRAPI_EXTRA_LATENCY_MODE_OFF,␍
|
||||
VRAPI_EXTRA_LATENCY_MODE_ON,␍
|
||||
VRAPI_EXTRA_LATENCY_MODE_DYNAMIC␍
|
||||
} ovrExtraLatencyMode;␍
|
||||
␍
|
||||
// Note that any layer textures that are dynamic must be triple buffered.␍
|
||||
typedef struct␍
|
||||
{␍
|
||||
// Because OpenGL ES does not support clampToBorder, it is the␍
|
||||
// application's responsibility to make sure that all mip levels␍
|
||||
// of the primary eye texture have a black border that will show␍
|
||||
// up when time warp pushes the texture partially off screen.␍
|
||||
ovrTextureSwapChain * ColorTextureSwapChain;␍
|
||||
␍
|
||||
// The depth texture is optional for positional time warp.␍
|
||||
ovrTextureSwapChain * DepthTextureSwapChain;␍
|
||||
␍
|
||||
// Index to the texture from the set that should be displayed.␍
|
||||
int TextureSwapChainIndex;␍
|
||||
␍
|
||||
// Points on the screen are mapped by a distortion correction␍
|
||||
// function into ( TanX, TanY, -1, 1 ) vectors that are transformed␍
|
||||
// by this matrix to get ( S, T, Q, _ ) vectors that are looked␍
|
||||
// up with texture2dproj() to get texels.␍
|
||||
ovrMatrix4f TexCoordsFromTanAngles;␍
|
||||
␍
|
||||
// Only texels within this range should be drawn.␍
|
||||
// This is a sub-rectangle of the [(0,0)-(1,1)] texture coordinate range.␍
|
||||
ovrRectf TextureRect;␍
|
||||
␍
|
||||
// The tracking state for which ModelViewMatrix is correct.␍
|
||||
// It is ok to update the orientation for each eye, which␍
|
||||
// can help minimize black edge pull-in, but the position␍
|
||||
// must remain the same for both eyes, or the position would␍
|
||||
// seem to judder "backwards in time" if a frame is dropped.␍
|
||||
ovrRigidBodyPosef HeadPose;␍
|
||||
␍
|
||||
// If not zero, this fence will be used to determine whether or not␍
|
||||
// rendering to the color and depth texture swap chains has completed.␍
|
||||
unsigned long long CompletionFence;␍
|
||||
} ovrFrameLayerTexture;␍
|
||||
␍
|
||||
typedef struct␍
|
||||
{␍
|
||||
// Image used for each eye.␍
|
||||
ovrFrameLayerTexture Textures[VRAPI_FRAME_LAYER_EYE_MAX];␍
|
||||
␍
|
||||
// Program-specific tuning values.␍
|
||||
float ProgramParms[4];␍
|
||||
␍
|
||||
// Layer blend function.␍
|
||||
ovrFrameLayerBlend SrcBlend;␍
|
||||
ovrFrameLayerBlend DstBlend;␍
|
||||
␍
|
||||
// Combination of ovrFrameLayerFlags flags.␍
|
||||
int Flags;␍
|
||||
} ovrFrameLayer;␍
|
||||
␍
|
||||
typedef struct␍
|
||||
{␍
|
||||
// These are fixed clock levels in the range [0, 3].␍
|
||||
int CpuLevel;␍
|
||||
int GpuLevel;␍
|
||||
␍
|
||||
// These threads will get SCHED_FIFO.␍
|
||||
int MainThreadTid;␍
|
||||
int RenderThreadTid;␍
|
||||
} ovrPerformanceParms;␍
|
||||
␍
|
||||
typedef struct␍
|
||||
{␍
|
||||
ovrStructureType Type;␍
|
||||
␍
|
||||
// Layers composited in the time warp.␍
|
||||
ovrFrameLayer Layers[VRAPI_FRAME_LAYER_TYPE_MAX];␍
|
||||
int LayerCount;␍
|
||||
␍
|
||||
// Combination of ovrFrameFlags flags.␍
|
||||
int Flags;␍
|
||||
␍
|
||||
// Application controlled frame index that uniquely identifies this particular frame.␍
|
||||
// This must be the same frame index that was passed to vrapi_GetPredictedDisplayTime()␍
|
||||
// when synthesis of this frame started.␍
|
||||
long long FrameIndex;␍
|
||||
␍
|
||||
// WarpSwap will not return until at least this many V-syncs have␍
|
||||
// passed since the previous WarpSwap returned.␍
|
||||
// Setting to 2 will reduce power consumption and may make animation␍
|
||||
// more regular for applications that can't hold full frame rate.␍
|
||||
int MinimumVsyncs;␍
|
||||
␍
|
||||
// Latency Mode.␍
|
||||
ovrExtraLatencyMode ExtraLatencyMode;␍
|
||||
␍
|
||||
// Rotation from a joypad can be added on generated frames to reduce␍
|
||||
// judder in FPS style experiences when the application framerate is␍
|
||||
// lower than the V-sync rate.␍
|
||||
// This will be applied to the view space distorted␍
|
||||
// eye vectors before applying the rest of the time warp.␍
|
||||
// This will only be added when the same ovrFrameParms is used for␍
|
||||
// more than one V-sync.␍
|
||||
ovrMatrix4f ExternalVelocity;␍
|
||||
␍
|
||||
// jobject that will be updated before each eye for minimal␍
|
||||
// latency.␍
|
||||
// IMPORTANT: This should be a JNI weak reference to the object.␍
|
||||
// The system will try to convert it into a global reference before␍
|
||||
// calling SurfaceTexture->Update, which allows it to be safely␍
|
||||
// freed by the application.␍
|
||||
jobject SurfaceTextureObject;␍
|
||||
␍
|
||||
// CPU/GPU performance parameters.␍
|
||||
ovrPerformanceParms PerformanceParms;␍
|
||||
␍
|
||||
// For handling HMD events and power level state changes.␍
|
||||
ovrJava Java;␍
|
||||
} ovrFrameParms;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// Head Model␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
typedef struct␍
|
||||
{␍
|
||||
float InterpupillaryDistance; // Distance between eyes.␍
|
||||
float EyeHeight; // Eye height relative to the ground.␍
|
||||
float HeadModelDepth; // Eye offset forward from the head center at EyeHeight.␍
|
||||
float HeadModelHeight; // Neck joint offset down from the head center at EyeHeight.␍
|
||||
} ovrHeadModelParms;␍
|
||||
␍
|
||||
//-----------------------------------------------------------------␍
|
||||
// FIXME:VRAPI remove this once all simulation code uses VrFrame::PredictedDisplayTimeInSeconds and perf timing uses LOGCPUTIME␍
|
||||
//-----------------------------------------------------------------␍
|
||||
␍
|
||||
#if defined( __cplusplus )␍
|
||||
extern "C" {␍
|
||||
#endif␍
|
||||
OVR_VRAPI_EXPORT double vrapi_GetTimeInSeconds();␍
|
||||
#if defined( __cplusplus )␍
|
||||
} // extern "C"␍
|
||||
#endif␍
|
||||
␍
|
||||
#endif // OVR_VrApi_Types_h␍
|
||||
@@ -0,0 +1,29 @@
|
||||
/************************************************************************************␍
|
||||
␍
|
||||
Filename : VrApi_Version.h␍
|
||||
Content : API version␍
|
||||
␍
|
||||
Copyright : Copyright 2015 Oculus VR, LLC. All Rights reserved.␍
|
||||
␍
|
||||
*************************************************************************************/␍
|
||||
␍
|
||||
#ifndef OVR_VrApi_Version_h␍
|
||||
#define OVR_VrApi_Version_h␍
|
||||
␍
|
||||
// At some point we will transition to product version 1 ␍
|
||||
// and reset the major version back to 1 (first product release, version 1.0).␍
|
||||
#define VRAPI_PRODUCT_VERSION 1␍
|
||||
#define VRAPI_MAJOR_VERSION 0␍
|
||||
#define VRAPI_MINOR_VERSION 0␍
|
||||
#define VRAPI_PATCH_VERSION 0␍
|
||||
␍
|
||||
// Internal build identifier␍
|
||||
#define VRAPI_BUILD_VERSION 119482␍
|
||||
␍
|
||||
// Internal build description␍
|
||||
#define VRAPI_BUILD_DESCRIPTION ""␍
|
||||
␍
|
||||
// Minimum version of the driver required for this API␍
|
||||
#define VRAPI_DRIVER_VERSION 16693008␍
|
||||
␍
|
||||
#endif // OVR_VrApi_Version_h␍
|
||||
Reference in New Issue
Block a user