ovr_mobile_sys/
helpers.rs

1use std::mem;
2use super::*;
3use super::ovrFrameInit::*;
4use super::ovrGraphicsAPI::*;
5use super::ovrStructureType::*;
6use super::ovrLayerType2::*;
7use super::ovrFrameLayerEye::*;
8use super::ovrFrameLayerBlend::*;
9
10//-----------------------------------------------------------------
11// Matrix helper functions.
12//-----------------------------------------------------------------
13
14// Use left-multiplication to accumulate transformations.
15pub fn ovrMatrix4f_Multiply(a: &ovrMatrix4f, b: &ovrMatrix4f) -> ovrMatrix4f {
16    let mut out: ovrMatrix4f = unsafe { mem::uninitialized( )};
17
18    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];
19    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];
20    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];
21    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];
22
23    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];
24    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];
25    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];
26    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];
27
28    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];
29    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];
30    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];
31    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];
32
33    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];
34    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];
35    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];
36    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];
37
38    out
39}
40
41// Returns the transpose of a 4x4 matrix.
42pub fn ovrMatrix4f_Transpose(a: &ovrMatrix4f) -> ovrMatrix4f {
43    let mut out: ovrMatrix4f = unsafe { mem::uninitialized( )};
44
45    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];
46    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];
47    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];
48    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];
49
50    out
51}
52
53// Returns a 3x3 minor of a 4x4 matrix.
54pub fn ovrMatrix4f_Minor(m: &ovrMatrix4f, r0:usize, r1:usize, r2:usize, c0:usize, c1:usize, c2:usize) -> f32 {
55    m.M[r0][c0] * ( m.M[r1][c1] * m.M[r2][c2] - m.M[r2][c1] * m.M[r1][c2] ) -
56    m.M[r0][c1] * ( m.M[r1][c0] * m.M[r2][c2] - m.M[r2][c0] * m.M[r1][c2] ) +
57    m.M[r0][c2] * ( m.M[r1][c0] * m.M[r2][c1] - m.M[r2][c0] * m.M[r1][c1] )
58}
59 
60// Returns the inverse of a 4x4 matrix.
61pub fn ovrMatrix4f_Inverse(m: &ovrMatrix4f) -> ovrMatrix4f
62{
63    let rcp_det = 1.0 / (m.M[0][0] * ovrMatrix4f_Minor( m, 1, 2, 3, 1, 2, 3 ) -
64                         m.M[0][1] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 2, 3 ) +
65                         m.M[0][2] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 3 ) -
66                         m.M[0][3] * ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 2 ) );
67    let mut out: ovrMatrix4f = unsafe { mem::uninitialized( )};
68    out.M[0][0] =  ovrMatrix4f_Minor( m, 1, 2, 3, 1, 2, 3 ) * rcp_det;
69    out.M[0][1] = -ovrMatrix4f_Minor( m, 0, 2, 3, 1, 2, 3 ) * rcp_det;
70    out.M[0][2] =  ovrMatrix4f_Minor( m, 0, 1, 3, 1, 2, 3 ) * rcp_det;
71    out.M[0][3] = -ovrMatrix4f_Minor( m, 0, 1, 2, 1, 2, 3 ) * rcp_det;
72    out.M[1][0] = -ovrMatrix4f_Minor( m, 1, 2, 3, 0, 2, 3 ) * rcp_det;
73    out.M[1][1] =  ovrMatrix4f_Minor( m, 0, 2, 3, 0, 2, 3 ) * rcp_det;
74    out.M[1][2] = -ovrMatrix4f_Minor( m, 0, 1, 3, 0, 2, 3 ) * rcp_det;
75    out.M[1][3] =  ovrMatrix4f_Minor( m, 0, 1, 2, 0, 2, 3 ) * rcp_det;
76    out.M[2][0] =  ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 3 ) * rcp_det;
77    out.M[2][1] = -ovrMatrix4f_Minor( m, 0, 2, 3, 0, 1, 3 ) * rcp_det;
78    out.M[2][2] =  ovrMatrix4f_Minor( m, 0, 1, 3, 0, 1, 3 ) * rcp_det;
79    out.M[2][3] = -ovrMatrix4f_Minor( m, 0, 1, 2, 0, 1, 3 ) * rcp_det;
80    out.M[3][0] = -ovrMatrix4f_Minor( m, 1, 2, 3, 0, 1, 2 ) * rcp_det;
81    out.M[3][1] =  ovrMatrix4f_Minor( m, 0, 2, 3, 0, 1, 2 ) * rcp_det;
82    out.M[3][2] = -ovrMatrix4f_Minor( m, 0, 1, 3, 0, 1, 2 ) * rcp_det;
83    out.M[3][3] =  ovrMatrix4f_Minor( m, 0, 1, 2, 0, 1, 2 ) * rcp_det;
84
85    out
86}
87
88// Returns a 4x4 identity matrix.
89pub fn ovrMatrix4f_CreateIdentity() -> ovrMatrix4f {
90    let mut out: ovrMatrix4f = unsafe { mem::uninitialized( )};
91
92    out.M[0][0] = 1.0; out.M[0][1] = 0.0; out.M[0][2] = 0.0; out.M[0][3] = 0.0;
93    out.M[1][0] = 0.0; out.M[1][1] = 1.0; out.M[1][2] = 0.0; out.M[1][3] = 0.0;
94    out.M[2][0] = 0.0; out.M[2][1] = 0.0; out.M[2][2] = 1.0; out.M[2][3] = 0.0;
95    out.M[3][0] = 0.0; out.M[3][1] = 0.0; out.M[3][2] = 0.0; out.M[3][3] = 1.0;
96
97    out
98}
99
100// Returns a 4x4 homogeneous translation matrix.
101pub fn ovrMatrix4f_CreateTranslation(x: f32, y: f32, z: f32) -> ovrMatrix4f {
102    let mut out: ovrMatrix4f = unsafe { mem::uninitialized( )};
103
104    out.M[0][0] = 1.0; out.M[0][1] = 0.0; out.M[0][2] = 0.0; out.M[0][3] = x;
105    out.M[1][0] = 0.0; out.M[1][1] = 1.0; out.M[1][2] = 0.0; out.M[1][3] = y;
106    out.M[2][0] = 0.0; out.M[2][1] = 0.0; out.M[2][2] = 1.0; out.M[2][3] = z;
107    out.M[3][0] = 0.0; out.M[3][1] = 0.0; out.M[3][2] = 0.0; out.M[3][3] = 1.0;
108
109    out
110}
111
112// Returns a 4x4 homogeneous rotation matrix.
113pub fn ovrMatrix4f_CreateRotation(radiansX: f32, radiansY: f32, radiansZ: f32) -> ovrMatrix4f
114{
115    let sinX = radiansX.sin();
116    let cosX = radiansX.cos();
117    let rotationX = ovrMatrix4f {
118        M: [[ 1.0,  0.0,   0.0, 0.0 ],
119            [ 0.0, cosX, -sinX, 0.0 ],
120            [ 0.0, sinX,  cosX, 0.0 ],
121            [ 0.0,  0.0,   0.0, 1.0 ]]
122    };
123
124    let sinY = radiansY.sin();
125    let cosY = radiansY.cos();
126    let rotationY = ovrMatrix4f {
127        M: [[  cosY, 0.0, sinY, 0.0 ],
128            [   0.0, 1.0,  0.0, 0.0 ],
129            [ -sinY, 0.0, cosY, 0.0 ],
130            [   0.0, 0.0,  0.0, 1.0 ]]
131    };
132
133    let sinZ = radiansZ.sin();
134    let cosZ = radiansZ.cos();
135    let rotationZ = ovrMatrix4f {
136        M: [[ cosZ, -sinZ, 0.0, 0.0 ],
137            [ sinZ,  cosZ, 0.0, 0.0 ],
138            [  0.0,   0.0, 1.0, 0.0 ],
139            [  0.0,   0.0, 0.0, 1.0 ]]
140    };
141
142    let rotationXY = ovrMatrix4f_Multiply(&rotationY, &rotationX);
143
144    ovrMatrix4f_Multiply(&rotationZ, &rotationXY)
145}
146
147// Returns a projection matrix based on the specified dimensions.
148// The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API.
149// The far plane is placed at infinity if far_z <= near_z.
150// An infinite projection matrix is preferred for rasterization because, except for
151// things *right* up against the near plane, it always provides better precision:
152//        "Tightening the Precision of Perspective Rendering"
153//        Paul Upchurch, Mathieu Desbrun
154//        Journal of Graphics Tools, Volume 16, Issue 1, 2012
155pub fn ovrMatrix4f_CreateProjection(min_x: f32,
156                                    max_x: f32,
157                                    min_y: f32,
158                                    max_y: f32,
159                                    near_z: f32,
160                                    far_z: f32)
161                                    -> ovrMatrix4f
162{
163    let width = max_x - min_x;
164    let height = max_y - min_y;
165    let offsetZ = near_z;    // set to zero for a [0,1] clip space
166
167    let mut out: ovrMatrix4f = unsafe { mem::uninitialized() };
168    if far_z <= near_z {
169        // place the far plane at infinity
170        out.M[0][0] = 2.0 * near_z / width;
171        out.M[0][1] = 0.0;
172        out.M[0][2] = ( max_x + min_x ) / width;
173        out.M[0][3] = 0.0;
174
175        out.M[1][0] = 0.0;
176        out.M[1][1] = 2.0 * near_z / height;
177        out.M[1][2] = ( max_y + min_y ) / height;
178        out.M[1][3] = 0.0;
179
180        out.M[2][0] = 0.0;
181        out.M[2][1] = 0.0;
182        out.M[2][2] = -1.0;
183        out.M[2][3] = -( near_z + offsetZ );
184
185        out.M[3][0] = 0.0;
186        out.M[3][1] = 0.0;
187        out.M[3][2] = -1.0;
188        out.M[3][3] = 0.0;
189    } else {
190        // normal projection
191        out.M[0][0] = 2.0 * near_z / width;
192        out.M[0][1] = 0.0;
193        out.M[0][2] = ( max_x + min_x ) / width;
194        out.M[0][3] = 0.0;
195
196        out.M[1][0] = 0.0;
197        out.M[1][1] = 2.0 * near_z / height;
198        out.M[1][2] = ( max_y + min_y ) / height;
199        out.M[1][3] = 0.0;
200
201        out.M[2][0] = 0.0;
202        out.M[2][1] = 0.0;
203        out.M[2][2] = -( far_z + offsetZ ) / ( far_z - near_z );
204        out.M[2][3] = -( far_z * ( near_z + offsetZ ) ) / ( far_z - near_z );
205
206        out.M[3][0] = 0.0;
207        out.M[3][1] = 0.0;
208        out.M[3][2] = -1.0;
209        out.M[3][3] = 0.0;
210    }
211    out
212}
213
214// Returns a projection matrix based on the given FOV.
215pub fn ovrMatrix4f_CreateProjectionFov(fov_degrees_x: f32,
216                                       fov_degrees_y: f32,
217                                       offset_x: f32,
218                                       offset_y: f32,
219                                       near_z: f32,
220                                       far_z: f32)
221                                       -> ovrMatrix4f
222{
223    let half_width = near_z * (fov_degrees_x * (VRAPI_PI as f32 / 180.032 * 0.532)).tan();
224    let half_height = near_z * (fov_degrees_y * (VRAPI_PI as f32 / 180.032 * 0.532)).tan();
225
226    let min_x = offset_x - half_width;
227    let max_x = offset_x + half_width;
228
229    let min_y = offset_y - half_height;
230    let max_y = offset_y + half_height;
231
232    ovrMatrix4f_CreateProjection( min_x, max_x, min_y, max_y, near_z, far_z )
233}
234
235
236// Returns the 4x4 rotation matrix for the given quaternion.
237pub fn ovrMatrix4f_CreateFromQuaternion(q: &ovrQuatf) -> ovrMatrix4f {
238    let ww = q.w * q.w;
239    let xx = q.x * q.x;
240    let yy = q.y * q.y;
241    let zz = q.z * q.z;
242
243    let mut out: ovrMatrix4f = unsafe { mem::uninitialized() };
244    out.M[0][0] = ww + xx - yy - zz;
245    out.M[0][1] = 2.0 * ( q.x * q.y - q.w * q.z );
246    out.M[0][2] = 2.0 * ( q.x * q.z + q.w * q.y );
247    out.M[0][3] = 0.0;
248
249    out.M[1][0] = 2.0 * ( q.x * q.y + q.w * q.z );
250    out.M[1][1] = ww - xx + yy - zz;
251    out.M[1][2] = 2.0 * ( q.y * q.z - q.w * q.x );
252    out.M[1][3] = 0.0;
253
254    out.M[2][0] = 2.0 * ( q.x * q.z - q.w * q.y );
255    out.M[2][1] = 2.0 * ( q.y * q.z + q.w * q.x );
256    out.M[2][2] = ww - xx - yy + zz;
257    out.M[2][3] = 0.0;
258
259    out.M[3][0] = 0.0;
260    out.M[3][1] = 0.0;
261    out.M[3][2] = 0.0;
262    out.M[3][3] = 1.0;
263
264    out
265}
266
267// Convert a standard projection matrix into a TexCoordsFromTanAngles matrix for
268// the primary time warp surface.
269pub fn ovrMatrix4f_TanAngleMatrixFromProjection(projection: &ovrMatrix4f) -> ovrMatrix4f {
270    /*
271        A projection matrix goes from a view point to NDC, or -1 to 1 space.
272        Scale and bias to convert that to a 0 to 1 space.
273
274        const ovrMatrix3f m =
275        { {
276            { projection.M[0][0],                0.0, projection.M[0][2] },
277            {                0.0, projection.M[1][1], projection.M[1][2] },
278            {                0.0,                0.0,               -1.0 }
279        } };
280        // Note that there is no Y-flip because eye buffers have 0,0 = left-bottom.
281        const ovrMatrix3f s = ovrMatrix3f_CreateScaling( 0.5, 0.5 );
282        const ovrMatrix3f t = ovrMatrix3f_CreateTranslation( 0.5, 0.5 );
283        const ovrMatrix3f r0 = ovrMatrix3f_Multiply( &s, &m );
284        const ovrMatrix3f r1 = ovrMatrix3f_Multiply( &t, &r0 );
285        return r1;
286
287        clipZ = ( z * projection[2][2] + projection[2][3] ) / ( projection[3][2] * z )
288        z = projection[2][3] / ( clipZ * projection[3][2] - projection[2][2] )
289        z = ( projection[2][3] / projection[3][2] ) / ( clipZ - projection[2][2] / projection[3][2] )
290    */
291
292    let tanAngleMatrix = ovrMatrix4f {
293        M: [[ 0.5 * projection.M[0][0], 0.0, 0.5 * projection.M[0][2] - 0.5, 0.0 ],
294            [ 0.0, 0.5 * projection.M[1][1], 0.5 * projection.M[1][2] - 0.5, 0.0 ],
295            [ 0.0, 0.0, -1.0, 0.0 ],
296            // Store the values to convert a clip-Z to a linear depth in the unused matrix elements.
297            [ projection.M[2][2], projection.M[2][3], projection.M[3][2], 1.0 ]]
298    };
299
300    tanAngleMatrix
301}
302
303// If a simple quad defined as a -1 to 1 XY unit square is transformed to
304// the camera view with the given modelView matrix, it can alternately be
305// drawn as a time warp overlay image to take advantage of the full window
306// resolution, which is usually higher than the eye buffer textures, and
307// avoids resampling both into the eye buffer, and again to the screen.
308// This is used for high quality movie screens and user interface planes.
309//
310// Note that this is NOT an MVP matrix -- the "projection" is handled
311// by the distortion process.
312//
313// This utility functions converts a model-view matrix that would normally
314// draw a -1 to 1 unit square to the view into a TexCoordsFromTanAngles matrix 
315// for an overlay surface.
316//
317// The resulting z value should be straight ahead distance to the plane.
318// The x and y values will be pre-multiplied by z for projective texturing.
319pub fn ovrMatrix4f_TanAngleMatrixFromUnitSquare(modelView: &ovrMatrix4f) -> ovrMatrix4f{
320    /*
321        // Take the inverse of the view matrix because the view matrix transforms the unit square
322        // from world space into view space, while the matrix needed here is the one that transforms
323        // the unit square from view space to world space.
324        const ovrMatrix4f inv = ovrMatrix4f_Inverse( modelView );
325        // This matrix calculates the projection onto the (-1, 1) X and Y axes of the unit square,
326        // of the intersection of the vector (tanX, tanY, -1) with the plane described by the matrix
327        // that transforms the unit square into world space.
328        const ovrMatrix3f m =
329        { {
330            {    inv.M[0][0] * inv.M[2][3] - inv.M[0][3] * inv.M[2][0],
331                inv.M[0][1] * inv.M[2][3] - inv.M[0][3] * inv.M[2][1],
332                inv.M[0][2] * inv.M[2][3] - inv.M[0][3] * inv.M[2][2] },
333            {    inv.M[1][0] * inv.M[2][3] - inv.M[1][3] * inv.M[2][0],
334                inv.M[1][1] * inv.M[2][3] - inv.M[1][3] * inv.M[2][1],
335                inv.M[1][2] * inv.M[2][3] - inv.M[1][3] * inv.M[2][2] },
336            {    - inv.M[2][0],
337                - inv.M[2][1],
338                - inv.M[2][2] }
339        } };
340        // Flip the Y because textures have 0,0 = left-top as opposed to left-bottom.
341        const ovrMatrix3f f = ovrMatrix3f_CreateScaling( 1.0, -1.0 );
342        const ovrMatrix3f s = ovrMatrix3f_CreateScaling( 0.5, 0.5 );
343        const ovrMatrix3f t = ovrMatrix3f_CreateTranslation( 0.5, 0.5 );
344        const ovrMatrix3f r0 = ovrMatrix3f_Multiply( &f, &m );
345        const ovrMatrix3f r1 = ovrMatrix3f_Multiply( &s, &r0 );
346        const ovrMatrix3f r2 = ovrMatrix3f_Multiply( &t, &r1 );
347        return r2;
348    */
349
350    let inv = ovrMatrix4f_Inverse( modelView );
351    let coef = if inv.M[2][3] > 0.0 {
352        1.0
353    } else { 
354        -1.0
355    };
356
357    let mut m: ovrMatrix4f = unsafe { mem::uninitialized() };
358    m.M[0][0] = ( 0.5 * ( inv.M[0][0] * inv.M[2][3] - inv.M[0][3] * inv.M[2][0] ) - 0.5 * inv.M[2][0] ) * coef;
359    m.M[0][1] = ( 0.5 * ( inv.M[0][1] * inv.M[2][3] - inv.M[0][3] * inv.M[2][1] ) - 0.5 * inv.M[2][1] ) * coef;
360    m.M[0][2] = ( 0.5 * ( inv.M[0][2] * inv.M[2][3] - inv.M[0][3] * inv.M[2][2] ) - 0.5 * inv.M[2][2] ) * coef;
361    m.M[0][3] = 0.0;
362
363    m.M[1][0] = ( -0.5 * ( inv.M[1][0] * inv.M[2][3] - inv.M[1][3] * inv.M[2][0] ) - 0.5 * inv.M[2][0] ) * coef;
364    m.M[1][1] = ( -0.5 * ( inv.M[1][1] * inv.M[2][3] - inv.M[1][3] * inv.M[2][1] ) - 0.5 * inv.M[2][1] ) * coef;
365    m.M[1][2] = ( -0.5 * ( inv.M[1][2] * inv.M[2][3] - inv.M[1][3] * inv.M[2][2] ) - 0.5 * inv.M[2][2] ) * coef;
366    m.M[1][3] = 0.0;
367
368    m.M[2][0] = ( -inv.M[2][0] ) * coef;
369    m.M[2][1] = ( -inv.M[2][1] ) * coef;
370    m.M[2][2] = ( -inv.M[2][2] ) * coef;
371    m.M[2][3] = 0.0;
372
373    m.M[3][0] = 0.0;
374    m.M[3][1] = 0.0;
375    m.M[3][2] = 0.0;
376    m.M[3][3] = 1.0;
377
378    m
379}
380
381// Convert a standard view matrix into a TexCoordsFromTanAngles matrix for
382// the looking into a cube map.
383pub fn ovrMatrix4f_TanAngleMatrixForCubeMap(viewMatrix: &ovrMatrix4f) -> ovrMatrix4f {
384    let mut m = *viewMatrix;
385    // clear translation
386    for i in 0..3 {
387        m.M[ i ][ 3 ] = 0.0;
388    }
389
390    ovrMatrix4f_Inverse(&m)
391}
392
393// Utility function to calculate external velocity for smooth stick yaw turning.
394// To reduce judder in FPS style experiences when the application framerate is
395// lower than the vsync rate, the rotation from a joypad can be applied to the
396// view space distorted eye vectors before applying the time warp.
397pub fn ovrMatrix4f_CalculateExternalVelocity(viewMatrix: &ovrMatrix4f, yawRadiansPerSecond: f32) -> ovrMatrix4f {
398    let angle = yawRadiansPerSecond * ( -1.0 / 60.0 );
399    let sinHalfAngle = ( angle * 0.5 ).sin();
400    let cosHalfAngle = ( angle * 0.5 ).cos();
401
402    // Yaw is always going to be around the world Y axis
403    let mut quat: ovrQuatf = unsafe { mem::uninitialized() };
404    quat.x = viewMatrix.M[0][1] * sinHalfAngle;
405    quat.y = viewMatrix.M[1][1] * sinHalfAngle;
406    quat.z = viewMatrix.M[2][1] * sinHalfAngle;
407    quat.w = cosHalfAngle;
408
409    ovrMatrix4f_CreateFromQuaternion( &quat )
410}
411
412//-----------------------------------------------------------------
413// Default initialization helper functions.
414//-----------------------------------------------------------------
415
416
417// Utility function to default initialize the ovrInitParms.
418pub fn vrapi_DefaultInitParms(java: *const ovrJava) -> ovrInitParms {
419    let mut parms: ovrInitParms = unsafe { mem::zeroed() };
420
421    parms.Type = VRAPI_STRUCTURE_TYPE_INIT_PARMS;
422    parms.ProductVersion = VRAPI_PRODUCT_VERSION as i32;
423    parms.MajorVersion = VRAPI_MAJOR_VERSION as i32;
424    parms.MinorVersion = VRAPI_MINOR_VERSION as i32;
425    parms.PatchVersion = VRAPI_PATCH_VERSION as i32;
426    parms.GraphicsAPI = VRAPI_GRAPHICS_API_OPENGL_ES_2;
427    parms.Java = unsafe { *java };
428
429    return parms;
430}
431
432// Utility function to default initialize the ovrModeParms.
433pub fn vrapi_DefaultModeParms(java: *const ovrJava) -> ovrModeParms {
434    let mut parms: ovrModeParms = unsafe { mem::zeroed() };
435
436    parms.Type = VRAPI_STRUCTURE_TYPE_MODE_PARMS;
437    parms.Flags |= ovrModeFlags::VRAPI_MODE_FLAG_ALLOW_POWER_SAVE as u32;
438    parms.Flags |= ovrModeFlags::VRAPI_MODE_FLAG_RESET_WINDOW_FULLSCREEN as u32;
439    parms.Java = unsafe { *java };
440
441    parms
442}
443
444// Utility function to default initialize the ovrPerformanceParms.
445pub fn vrapi_DefaultPerformanceParms() -> ovrPerformanceParms {
446    let mut parms: ovrPerformanceParms = unsafe { mem::zeroed() };
447    parms.CpuLevel = 2;
448    parms.GpuLevel = 2;
449    parms.MainThreadTid = 0;
450    parms.RenderThreadTid = 0;
451
452    parms
453}
454
455// Utility function to default initialize the ovrFrameParms.
456pub fn vrapi_DefaultFrameParms(java: *const ovrJava,
457                               init: ovrFrameInit,
458                               currentTime: f64,
459                               textureSwapChain: *mut ovrTextureSwapChain)
460                               -> ovrFrameParms
461{
462    let projectionMatrix = ovrMatrix4f_CreateProjectionFov( 90.0, 90.0, 0.0, 0.0, 0.1, 0.0 );
463    let texCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &projectionMatrix );
464
465    let mut parms: ovrFrameParms = unsafe { mem::zeroed() };
466
467    parms.Type = VRAPI_STRUCTURE_TYPE_FRAME_PARMS;
468    for layer in 0..ovrFrameLayerType::VRAPI_FRAME_LAYER_TYPE_MAX as usize{
469        parms.Layers[layer].ColorScale = 1.0;
470        for eye in 0..ovrFrameLayerEye::VRAPI_FRAME_LAYER_EYE_MAX as usize {
471            parms.Layers[layer].Textures[eye].TexCoordsFromTanAngles = texCoordsFromTanAngles;
472            parms.Layers[layer].Textures[eye].TextureRect.width = 1.0;
473            parms.Layers[layer].Textures[eye].TextureRect.height = 1.0;
474            parms.Layers[layer].Textures[eye].HeadPose.Pose.Orientation.w = 1.0;
475            parms.Layers[layer].Textures[eye].HeadPose.TimeInSeconds = currentTime;
476        }
477    }
478    parms.LayerCount = 1;
479    parms.SwapInterval = 1;
480    parms.ExtraLatencyMode = ovrExtraLatencyMode::VRAPI_EXTRA_LATENCY_MODE_OFF;
481    parms.ExternalVelocity.M[0][0] = 1.0;
482    parms.ExternalVelocity.M[1][1] = 1.0;
483    parms.ExternalVelocity.M[2][2] = 1.0;
484    parms.ExternalVelocity.M[3][3] = 1.0;
485    parms.PerformanceParms = vrapi_DefaultPerformanceParms();
486    parms.Java = unsafe { *java };
487
488    parms.Layers[0].SrcBlend = ovrFrameLayerBlend::VRAPI_FRAME_LAYER_BLEND_ONE;
489    parms.Layers[0].DstBlend = ovrFrameLayerBlend::VRAPI_FRAME_LAYER_BLEND_ZERO;
490    parms.Layers[0].Flags = 0;
491
492    parms.Layers[1].SrcBlend = ovrFrameLayerBlend::VRAPI_FRAME_LAYER_BLEND_SRC_ALPHA;
493    parms.Layers[1].DstBlend = ovrFrameLayerBlend::VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA;
494    parms.Layers[1].Flags = 0;
495
496    match init
497    {
498        VRAPI_FRAME_INIT_DEFAULT =>
499        {
500            //break;
501        },
502        VRAPI_FRAME_INIT_BLACK |
503        VRAPI_FRAME_INIT_BLACK_FLUSH |
504        VRAPI_FRAME_INIT_BLACK_FINAL =>
505        {
506            parms.Flags = ovrFrameFlags::VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER as i32;
507            // NOTE: When requesting a solid black frame, set ColorScale to 0.0f 
508            parms.Layers[0].ColorScale = 0.0; 
509            for eye in 0..ovrFrameLayerEye::VRAPI_FRAME_LAYER_EYE_MAX as usize
510            {
511                parms.Layers[0].Textures[eye].ColorTextureSwapChain = unsafe { mem::transmute(ovrDefaultTextureSwapChain::VRAPI_DEFAULT_TEXTURE_SWAPCHAIN as usize) };
512            }
513        },
514        VRAPI_FRAME_INIT_LOADING_ICON |
515        VRAPI_FRAME_INIT_LOADING_ICON_FLUSH =>
516        {
517            parms.LayerCount = 2;
518            parms.Flags = ovrFrameFlags::VRAPI_FRAME_FLAG_INHIBIT_SRGB_FRAMEBUFFER as i32;
519            parms.Layers[1].Flags = ovrFrameLayerFlags::VRAPI_FRAME_LAYER_FLAG_SPIN as i32;
520            parms.Layers[1].SpinSpeed = 1.0;        // rotation in radians per second
521            parms.Layers[1].SpinScale = 16.0;        // icon size factor smaller than fullscreen
522            for eye in 0..ovrFrameLayerEye::VRAPI_FRAME_LAYER_EYE_MAX as usize
523            {
524                parms.Layers[0].Textures[eye].ColorTextureSwapChain = unsafe { mem::transmute(ovrDefaultTextureSwapChain::VRAPI_DEFAULT_TEXTURE_SWAPCHAIN as usize) };
525				parms.Layers[1].Textures[eye].ColorTextureSwapChain = if !textureSwapChain.is_null() {
526					textureSwapChain
527				} else {
528					unsafe { mem::transmute(ovrDefaultTextureSwapChain::VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_LOADING_ICON as usize) }
529				};
530            }
531        }
532    }
533
534    if init == VRAPI_FRAME_INIT_BLACK_FLUSH || init == VRAPI_FRAME_INIT_LOADING_ICON_FLUSH
535    {
536        parms.Flags |= ovrFrameFlags::VRAPI_FRAME_FLAG_FLUSH as i32;
537    }
538    if init == VRAPI_FRAME_INIT_BLACK_FINAL
539    {
540        parms.Flags |= ovrFrameFlags::VRAPI_FRAME_FLAG_FLUSH as i32 | ovrFrameFlags::VRAPI_FRAME_FLAG_FINAL as i32;
541    }
542
543    return parms;
544}
545
546//-----------------------------------------------------------------
547// Eye view matrix helper functions.
548//-----------------------------------------------------------------
549
550
551// Utility function to get the eye view matrix based on the center eye view matrix and the IPD.
552
553pub fn vrapi_GetInterpupillaryDistance(tracking2: &ovrTracking2) -> f32 {
554	let leftView = tracking2.Eye[0].ViewMatrix;
555	let rightView = tracking2.Eye[1].ViewMatrix;
556	let delta = ovrVector3f { 
557        x: rightView.M[0][3] - leftView.M[0][3],
558        y: rightView.M[1][3] - leftView.M[1][3],
559        z: rightView.M[2][3] - leftView.M[2][3]
560    };
561	(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z).sqrt()
562}
563
564pub fn vrapi_GetEyeHeight(eyeLevelTrackingPose: &ovrPosef, currentTrackingPose: &ovrPosef) -> f32 {
565	eyeLevelTrackingPose.Position.y - currentTrackingPose.Position.y
566}
567
568pub fn vrapi_GetTransformFromPose(pose: &ovrPosef) -> ovrMatrix4f {
569	let rotation = ovrMatrix4f_CreateFromQuaternion( &pose.Orientation );
570	let translation = ovrMatrix4f_CreateTranslation( pose.Position.x, pose.Position.y, pose.Position.z );
571	return ovrMatrix4f_Multiply( &translation, &rotation );
572}
573
574pub fn vrapi_GetViewMatrixFromPose(pose: &ovrPosef) -> ovrMatrix4f {
575	let transform = vrapi_GetTransformFromPose(pose);
576	return ovrMatrix4f_Inverse( &transform );
577}
578
579// Utility function to get the eye view matrix based on the center eye view matrix and the IPD.
580pub fn vrapi_GetEyeViewMatrix(
581    centerEyeViewMatrix: &ovrMatrix4f,
582	interpupillaryDistance: f32,
583	eye: i32)
584    -> ovrMatrix4f
585{
586	let eyeOffset = (if eye > 0 { -0.5f32 } else { 0.5f32 }) * interpupillaryDistance;
587	let eyeOffsetMatrix = ovrMatrix4f_CreateTranslation( eyeOffset, 0.0, 0.0 );
588	return ovrMatrix4f_Multiply( &eyeOffsetMatrix, centerEyeViewMatrix );
589}
590
591
592//-----------------------------------------------------------------
593// Layer Types - default initialization.
594//-----------------------------------------------------------------
595
596pub fn vrapi_DefaultLayerProjection2() -> ovrLayerProjection2 {
597	let mut layer: ovrLayerProjection2 = unsafe { mem::zeroed() };
598
599	let projectionMatrix = ovrMatrix4f_CreateProjectionFov( 90.0, 90.0, 0.0, 0.0, 0.1, 0.0 );
600	let texCoordsFromTanAngles	= ovrMatrix4f_TanAngleMatrixFromProjection( &projectionMatrix );
601
602	layer.Header.Type	= VRAPI_LAYER_TYPE_PROJECTION2;
603	layer.Header.Flags  = 0;
604	layer.Header.ColorScale.x	= 1.0;
605	layer.Header.ColorScale.y	= 1.0;
606	layer.Header.ColorScale.z	= 1.0;
607	layer.Header.ColorScale.w	= 1.0;
608	layer.Header.SrcBlend		= VRAPI_FRAME_LAYER_BLEND_ONE;
609	layer.Header.DstBlend		= VRAPI_FRAME_LAYER_BLEND_ZERO;
610	layer.Header.SurfaceTextureObject = ::std::ptr::null_mut();
611
612	layer.HeadPose.Pose.Orientation.w = 1.0;
613
614	for i in 0..VRAPI_FRAME_LAYER_EYE_MAX as usize {
615		layer.Textures[i].TexCoordsFromTanAngles		= texCoordsFromTanAngles;
616		layer.Textures[i].TextureRect.x					= 0.0;
617		layer.Textures[i].TextureRect.y					= 0.0;
618		layer.Textures[i].TextureRect.width				= 1.0;
619		layer.Textures[i].TextureRect.height			= 1.0;
620	}
621
622	layer
623}
624
625pub fn vrapi_DefaultLayerLoadingIcon2() -> ovrLayerLoadingIcon2 {
626	let mut layer: ovrLayerLoadingIcon2 = unsafe { mem::zeroed() };
627
628	layer.Header.Type	= VRAPI_LAYER_TYPE_LOADING_ICON2;
629	layer.Header.Flags  = 0;
630	layer.Header.ColorScale.x	= 1.0;
631	layer.Header.ColorScale.y	= 1.0;
632	layer.Header.ColorScale.z	= 1.0;
633	layer.Header.ColorScale.w	= 1.0;
634	layer.Header.SrcBlend		= VRAPI_FRAME_LAYER_BLEND_SRC_ALPHA;
635	layer.Header.DstBlend		= VRAPI_FRAME_LAYER_BLEND_ONE_MINUS_SRC_ALPHA;
636	layer.Header.SurfaceTextureObject = ::std::ptr::null_mut();;
637
638	layer.SpinSpeed			= 1.0;
639	layer.SpinScale			= 16.0;
640
641	layer.ColorSwapChain	= unsafe { mem::transmute(ovrDefaultTextureSwapChain::VRAPI_DEFAULT_TEXTURE_SWAPCHAIN_LOADING_ICON as usize) };
642	layer.SwapChainIndex	= 0;
643
644	return layer;
645}