aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--LICENSE57
-rw-r--r--README.md3
-rw-r--r--config/hellovr_actions.json59
-rw-r--r--config/hellovr_bindings_generic.json94
-rw-r--r--config/hellovr_bindings_vive_controller.json94
-rw-r--r--project.conf14
-rw-r--r--shared/Matrices.cpp581
-rw-r--r--shared/Matrices.h909
-rw-r--r--shared/Vectors.h530
-rw-r--r--src/main.cpp2130
-rw-r--r--tests/main.cpp7
12 files changed, 4483 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..636c6b9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+# Compiled sibs files
+sibs-build/
+compile_commands.json
+tests/sibs-build/
+tests/compile_commands.json
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c6b1dc1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,57 @@
+Original license, from openvr samples (https://github.com/ValveSoftware/openvr/tree/master/samples):
+Copyright (c) 2015, Valve Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+may be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License of modified code:
+Copyright (c) 2019, DEC05EBA
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+may be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8e4c1f1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+A virtual reality window manager for Linux running X11, based on Valve's openvr `hellovr_opengl` sample code: https://github.com/ValveSoftware/openvr/tree/master/samples\
+Still early in development, not ready to be used yet.
+
diff --git a/config/hellovr_actions.json b/config/hellovr_actions.json
new file mode 100644
index 0000000..dab1e9a
--- /dev/null
+++ b/config/hellovr_actions.json
@@ -0,0 +1,59 @@
+{
+ "default_bindings": [
+ {
+ "controller_type" : "vive_controller",
+ "binding_url" : "hellovr_bindings_vive_controller.json"
+ },
+ {
+ "controller_type" : "generic",
+ "binding_url" : "hellovr_bindings_generic.json"
+ }
+ ],
+ "actions": [
+ {
+ "name": "/actions/demo/in/HideCubes",
+ "type": "boolean"
+ },
+ {
+ "name": "/actions/demo/in/HideThisController",
+ "type": "boolean"
+ },
+ {
+ "name": "/actions/demo/in/triggerhaptic",
+ "type": "boolean"
+ },
+ {
+ "name": "/actions/demo/in/AnalogInput",
+ "type": "vector2"
+ },
+ {
+ "name": "/actions/demo/in/Hand_Right",
+ "type": "pose"
+ },
+ {
+ "name": "/actions/demo/in/Hand_Left",
+ "type": "pose"
+ },
+ {
+ "name": "/actions/demo/out/haptic_left",
+ "type": "vibration"
+ },
+ {
+ "name": "/actions/demo/out/haptic_right",
+ "type": "vibration"
+ }
+ ],
+ "localization" : [
+ {
+ "language_tag": "en_US",
+ "/actions/demo/in/HideCubes" : "Hide Cubes",
+ "/actions/demo/in/HideThisController" : "Hide this Controller",
+ "/actions/demo/in/triggerhaptic" : "Trigger Haptic Pulse",
+ "/actions/demo/in/AnalogInput" : "Analog Input",
+ "/actions/demo/in/Hand_Right" : "Right Hand Pose",
+ "/actions/demo/in/Hand_Left" : "Left Hand Pose",
+ "/actions/demo/out/haptic_left" : "Left Haptic Feedback",
+ "/actions/demo/out/haptic_right" : "Right Haptic Feedback"
+ }
+ ]
+}
diff --git a/config/hellovr_bindings_generic.json b/config/hellovr_bindings_generic.json
new file mode 100644
index 0000000..ae5fb46
--- /dev/null
+++ b/config/hellovr_bindings_generic.json
@@ -0,0 +1,94 @@
+{
+ "bindings" : {
+ "/actions/demo" : {
+ "poses" : [
+ {
+ "output" : "/actions/demo/in/hand_left",
+ "path" : "/user/hand/left/pose/raw"
+ },
+ {
+ "output" : "/actions/demo/in/hand_right",
+ "path" : "/user/hand/right/pose/raw"
+ }
+ ],
+ "haptics" : [
+ {
+ "output" : "/actions/demo/out/haptic_right",
+ "path" : "/user/hand/right/output/haptic"
+ },
+ {
+ "output" : "/actions/demo/out/haptic_left",
+ "path" : "/user/hand/left/output/haptic"
+ }
+ ],
+ "sources" : [
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/hidecubes"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/right/input/trigger"
+ },
+ {
+ "inputs" : {
+ "position" : {
+ "output" : "/actions/demo/in/analoginput"
+ }
+ },
+ "mode" : "trackpad",
+ "path" : "/user/hand/right/input/trackpad"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/triggerhaptic"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/right/input/grip"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/hidecubes"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/left/input/trigger"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/triggerhaptic"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/left/input/grip"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/hidethiscontroller"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/left/input/application_menu"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/hidethiscontroller"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/right/input/application_menu"
+ }
+ ]
+ }
+ },
+ "controller_type" : "generic",
+ "description" : "Bindings for the OpenVR SDK \"hellovr_opengl\" demo for a generic controller",
+ "name" : "HelloVR bindings for a generic controller"
+}
diff --git a/config/hellovr_bindings_vive_controller.json b/config/hellovr_bindings_vive_controller.json
new file mode 100644
index 0000000..0a95efd
--- /dev/null
+++ b/config/hellovr_bindings_vive_controller.json
@@ -0,0 +1,94 @@
+{
+ "bindings" : {
+ "/actions/demo" : {
+ "poses" : [
+ {
+ "output" : "/actions/demo/in/hand_left",
+ "path" : "/user/hand/left/pose/raw"
+ },
+ {
+ "output" : "/actions/demo/in/hand_right",
+ "path" : "/user/hand/right/pose/raw"
+ }
+ ],
+ "haptics" : [
+ {
+ "output" : "/actions/demo/out/haptic_right",
+ "path" : "/user/hand/right/output/haptic"
+ },
+ {
+ "output" : "/actions/demo/out/haptic_left",
+ "path" : "/user/hand/left/output/haptic"
+ }
+ ],
+ "sources" : [
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/hidecubes"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/right/input/trigger"
+ },
+ {
+ "inputs" : {
+ "position" : {
+ "output" : "/actions/demo/in/analoginput"
+ }
+ },
+ "mode" : "trackpad",
+ "path" : "/user/hand/right/input/trackpad"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/triggerhaptic"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/right/input/grip"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/hidecubes"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/left/input/trigger"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/triggerhaptic"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/left/input/grip"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/hidethiscontroller"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/left/input/application_menu"
+ },
+ {
+ "inputs" : {
+ "click" : {
+ "output" : "/actions/demo/in/hidethiscontroller"
+ }
+ },
+ "mode" : "button",
+ "path" : "/user/hand/right/input/application_menu"
+ }
+ ]
+ }
+ },
+ "controller_type" : "vive_controller",
+ "description" : "Bindings for the OpenVR SDK \"hellovr_opengl\" demo for the Vive controller",
+ "name" : "HelloVR bindings for Vive Controller"
+}
diff --git a/project.conf b/project.conf
new file mode 100644
index 0000000..559a408
--- /dev/null
+++ b/project.conf
@@ -0,0 +1,14 @@
+[package]
+name = "vr_window_manager"
+type = "executable"
+version = "0.1.0"
+platforms = ["linux"]
+
+[dependencies]
+glm = "0"
+glx = "1"
+glew = "2"
+sdl2 = "2"
+openvr = "1"
+x11 = "1"
+xcomposite = ">=0.2"
diff --git a/shared/Matrices.cpp b/shared/Matrices.cpp
new file mode 100644
index 0000000..582b285
--- /dev/null
+++ b/shared/Matrices.cpp
@@ -0,0 +1,581 @@
+///////////////////////////////////////////////////////////////////////////////
+// Matrice.cpp
+// ===========
+// NxN Matrix Math classes
+//
+// The elements of the matrix are stored as column major order.
+// | 0 2 | | 0 3 6 | | 0 4 8 12 |
+// | 1 3 | | 1 4 7 | | 1 5 9 13 |
+// | 2 5 8 | | 2 6 10 14 |
+// | 3 7 11 15 |
+//
+// AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
+// CREATED: 2005-06-24
+// UPDATED: 2014-09-21
+//
+// Copyright (C) 2005 Song Ho Ahn
+///////////////////////////////////////////////////////////////////////////////
+
+#include <cmath>
+#include <algorithm>
+#include "Matrices.h"
+
+const float DEG2RAD = 3.141593f / 180;
+const float EPSILON = 0.00001f;
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// transpose 2x2 matrix
+///////////////////////////////////////////////////////////////////////////////
+Matrix2& Matrix2::transpose()
+{
+ std::swap(m[1], m[2]);
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// return the determinant of 2x2 matrix
+///////////////////////////////////////////////////////////////////////////////
+float Matrix2::getDeterminant()
+{
+ return m[0] * m[3] - m[1] * m[2];
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// inverse of 2x2 matrix
+// If cannot find inverse, set identity matrix
+///////////////////////////////////////////////////////////////////////////////
+Matrix2& Matrix2::invert()
+{
+ float determinant = getDeterminant();
+ if(fabs(determinant) <= EPSILON)
+ {
+ return identity();
+ }
+
+ float tmp = m[0]; // copy the first element
+ float invDeterminant = 1.0f / determinant;
+ m[0] = invDeterminant * m[3];
+ m[1] = -invDeterminant * m[1];
+ m[2] = -invDeterminant * m[2];
+ m[3] = invDeterminant * tmp;
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// transpose 3x3 matrix
+///////////////////////////////////////////////////////////////////////////////
+Matrix3& Matrix3::transpose()
+{
+ std::swap(m[1], m[3]);
+ std::swap(m[2], m[6]);
+ std::swap(m[5], m[7]);
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// return determinant of 3x3 matrix
+///////////////////////////////////////////////////////////////////////////////
+float Matrix3::getDeterminant()
+{
+ return m[0] * (m[4] * m[8] - m[5] * m[7]) -
+ m[1] * (m[3] * m[8] - m[5] * m[6]) +
+ m[2] * (m[3] * m[7] - m[4] * m[6]);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// inverse 3x3 matrix
+// If cannot find inverse, set identity matrix
+///////////////////////////////////////////////////////////////////////////////
+Matrix3& Matrix3::invert()
+{
+ float determinant, invDeterminant;
+ float tmp[9];
+
+ tmp[0] = m[4] * m[8] - m[5] * m[7];
+ tmp[1] = m[2] * m[7] - m[1] * m[8];
+ tmp[2] = m[1] * m[5] - m[2] * m[4];
+ tmp[3] = m[5] * m[6] - m[3] * m[8];
+ tmp[4] = m[0] * m[8] - m[2] * m[6];
+ tmp[5] = m[2] * m[3] - m[0] * m[5];
+ tmp[6] = m[3] * m[7] - m[4] * m[6];
+ tmp[7] = m[1] * m[6] - m[0] * m[7];
+ tmp[8] = m[0] * m[4] - m[1] * m[3];
+
+ // check determinant if it is 0
+ determinant = m[0] * tmp[0] + m[1] * tmp[3] + m[2] * tmp[6];
+ if(fabs(determinant) <= EPSILON)
+ {
+ return identity(); // cannot inverse, make it idenety matrix
+ }
+
+ // divide by the determinant
+ invDeterminant = 1.0f / determinant;
+ m[0] = invDeterminant * tmp[0];
+ m[1] = invDeterminant * tmp[1];
+ m[2] = invDeterminant * tmp[2];
+ m[3] = invDeterminant * tmp[3];
+ m[4] = invDeterminant * tmp[4];
+ m[5] = invDeterminant * tmp[5];
+ m[6] = invDeterminant * tmp[6];
+ m[7] = invDeterminant * tmp[7];
+ m[8] = invDeterminant * tmp[8];
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// transpose 4x4 matrix
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::transpose()
+{
+ std::swap(m[1], m[4]);
+ std::swap(m[2], m[8]);
+ std::swap(m[3], m[12]);
+ std::swap(m[6], m[9]);
+ std::swap(m[7], m[13]);
+ std::swap(m[11], m[14]);
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// inverse 4x4 matrix
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::invert()
+{
+ // If the 4th row is [0,0,0,1] then it is affine matrix and
+ // it has no projective transformation.
+ if(m[3] == 0 && m[7] == 0 && m[11] == 0 && m[15] == 1)
+ this->invertAffine();
+ else
+ {
+ this->invertGeneral();
+ /*@@ invertProjective() is not optimized (slower than generic one)
+ if(fabs(m[0]*m[5] - m[1]*m[4]) > EPSILON)
+ this->invertProjective(); // inverse using matrix partition
+ else
+ this->invertGeneral(); // generalized inverse
+ */
+ }
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// compute the inverse of 4x4 Euclidean transformation matrix
+//
+// Euclidean transformation is translation, rotation, and reflection.
+// With Euclidean transform, only the position and orientation of the object
+// will be changed. Euclidean transform does not change the shape of an object
+// (no scaling). Length and angle are reserved.
+//
+// Use inverseAffine() if the matrix has scale and shear transformation.
+//
+// M = [ R | T ]
+// [ --+-- ] (R denotes 3x3 rotation/reflection matrix)
+// [ 0 | 1 ] (T denotes 1x3 translation matrix)
+//
+// y = M*x -> y = R*x + T -> x = R^-1*(y - T) -> x = R^T*y - R^T*T
+// (R is orthogonal, R^-1 = R^T)
+//
+// [ R | T ]-1 [ R^T | -R^T * T ] (R denotes 3x3 rotation matrix)
+// [ --+-- ] = [ ----+--------- ] (T denotes 1x3 translation)
+// [ 0 | 1 ] [ 0 | 1 ] (R^T denotes R-transpose)
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::invertEuclidean()
+{
+ // transpose 3x3 rotation matrix part
+ // | R^T | 0 |
+ // | ----+-- |
+ // | 0 | 1 |
+ float tmp;
+ tmp = m[1]; m[1] = m[4]; m[4] = tmp;
+ tmp = m[2]; m[2] = m[8]; m[8] = tmp;
+ tmp = m[6]; m[6] = m[9]; m[9] = tmp;
+
+ // compute translation part -R^T * T
+ // | 0 | -R^T x |
+ // | --+------- |
+ // | 0 | 0 |
+ float x = m[12];
+ float y = m[13];
+ float z = m[14];
+ m[12] = -(m[0] * x + m[4] * y + m[8] * z);
+ m[13] = -(m[1] * x + m[5] * y + m[9] * z);
+ m[14] = -(m[2] * x + m[6] * y + m[10]* z);
+
+ // last row should be unchanged (0,0,0,1)
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// compute the inverse of a 4x4 affine transformation matrix
+//
+// Affine transformations are generalizations of Euclidean transformations.
+// Affine transformation includes translation, rotation, reflection, scaling,
+// and shearing. Length and angle are NOT preserved.
+// M = [ R | T ]
+// [ --+-- ] (R denotes 3x3 rotation/scale/shear matrix)
+// [ 0 | 1 ] (T denotes 1x3 translation matrix)
+//
+// y = M*x -> y = R*x + T -> x = R^-1*(y - T) -> x = R^-1*y - R^-1*T
+//
+// [ R | T ]-1 [ R^-1 | -R^-1 * T ]
+// [ --+-- ] = [ -----+---------- ]
+// [ 0 | 1 ] [ 0 + 1 ]
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::invertAffine()
+{
+ // R^-1
+ Matrix3 r(m[0],m[1],m[2], m[4],m[5],m[6], m[8],m[9],m[10]);
+ r.invert();
+ m[0] = r[0]; m[1] = r[1]; m[2] = r[2];
+ m[4] = r[3]; m[5] = r[4]; m[6] = r[5];
+ m[8] = r[6]; m[9] = r[7]; m[10]= r[8];
+
+ // -R^-1 * T
+ float x = m[12];
+ float y = m[13];
+ float z = m[14];
+ m[12] = -(r[0] * x + r[3] * y + r[6] * z);
+ m[13] = -(r[1] * x + r[4] * y + r[7] * z);
+ m[14] = -(r[2] * x + r[5] * y + r[8] * z);
+
+ // last row should be unchanged (0,0,0,1)
+ //m[3] = m[7] = m[11] = 0.0f;
+ //m[15] = 1.0f;
+
+ return * this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// inverse matrix using matrix partitioning (blockwise inverse)
+// It devides a 4x4 matrix into 4 of 2x2 matrices. It works in case of where
+// det(A) != 0. If not, use the generic inverse method
+// inverse formula.
+// M = [ A | B ] A, B, C, D are 2x2 matrix blocks
+// [ --+-- ] det(M) = |A| * |D - ((C * A^-1) * B)|
+// [ C | D ]
+//
+// M^-1 = [ A' | B' ] A' = A^-1 - (A^-1 * B) * C'
+// [ ---+--- ] B' = (A^-1 * B) * -D'
+// [ C' | D' ] C' = -D' * (C * A^-1)
+// D' = (D - ((C * A^-1) * B))^-1
+//
+// NOTE: I wrap with () if it it used more than once.
+// The matrix is invertable even if det(A)=0, so must check det(A) before
+// calling this function, and use invertGeneric() instead.
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::invertProjective()
+{
+ // partition
+ Matrix2 a(m[0], m[1], m[4], m[5]);
+ Matrix2 b(m[8], m[9], m[12], m[13]);
+ Matrix2 c(m[2], m[3], m[6], m[7]);
+ Matrix2 d(m[10], m[11], m[14], m[15]);
+
+ // pre-compute repeated parts
+ a.invert(); // A^-1
+ Matrix2 ab = a * b; // A^-1 * B
+ Matrix2 ca = c * a; // C * A^-1
+ Matrix2 cab = ca * b; // C * A^-1 * B
+ Matrix2 dcab = d - cab; // D - C * A^-1 * B
+
+ // check determinant if |D - C * A^-1 * B| = 0
+ //NOTE: this function assumes det(A) is already checked. if |A|=0 then,
+ // cannot use this function.
+ float determinant = dcab[0] * dcab[3] - dcab[1] * dcab[2];
+ if(fabs(determinant) <= EPSILON)
+ {
+ return identity();
+ }
+
+ // compute D' and -D'
+ Matrix2 d1 = dcab; // (D - C * A^-1 * B)
+ d1.invert(); // (D - C * A^-1 * B)^-1
+ Matrix2 d2 = -d1; // -(D - C * A^-1 * B)^-1
+
+ // compute C'
+ Matrix2 c1 = d2 * ca; // -D' * (C * A^-1)
+
+ // compute B'
+ Matrix2 b1 = ab * d2; // (A^-1 * B) * -D'
+
+ // compute A'
+ Matrix2 a1 = a - (ab * c1); // A^-1 - (A^-1 * B) * C'
+
+ // assemble inverse matrix
+ m[0] = a1[0]; m[4] = a1[2]; /*|*/ m[8] = b1[0]; m[12]= b1[2];
+ m[1] = a1[1]; m[5] = a1[3]; /*|*/ m[9] = b1[1]; m[13]= b1[3];
+ /*-----------------------------+-----------------------------*/
+ m[2] = c1[0]; m[6] = c1[2]; /*|*/ m[10]= d1[0]; m[14]= d1[2];
+ m[3] = c1[1]; m[7] = c1[3]; /*|*/ m[11]= d1[1]; m[15]= d1[3];
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// compute the inverse of a general 4x4 matrix using Cramer's Rule
+// If cannot find inverse, return indentity matrix
+// M^-1 = adj(M) / det(M)
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::invertGeneral()
+{
+ // get cofactors of minor matrices
+ float cofactor0 = getCofactor(m[5],m[6],m[7], m[9],m[10],m[11], m[13],m[14],m[15]);
+ float cofactor1 = getCofactor(m[4],m[6],m[7], m[8],m[10],m[11], m[12],m[14],m[15]);
+ float cofactor2 = getCofactor(m[4],m[5],m[7], m[8],m[9], m[11], m[12],m[13],m[15]);
+ float cofactor3 = getCofactor(m[4],m[5],m[6], m[8],m[9], m[10], m[12],m[13],m[14]);
+
+ // get determinant
+ float determinant = m[0] * cofactor0 - m[1] * cofactor1 + m[2] * cofactor2 - m[3] * cofactor3;
+ if(fabs(determinant) <= EPSILON)
+ {
+ return identity();
+ }
+
+ // get rest of cofactors for adj(M)
+ float cofactor4 = getCofactor(m[1],m[2],m[3], m[9],m[10],m[11], m[13],m[14],m[15]);
+ float cofactor5 = getCofactor(m[0],m[2],m[3], m[8],m[10],m[11], m[12],m[14],m[15]);
+ float cofactor6 = getCofactor(m[0],m[1],m[3], m[8],m[9], m[11], m[12],m[13],m[15]);
+ float cofactor7 = getCofactor(m[0],m[1],m[2], m[8],m[9], m[10], m[12],m[13],m[14]);
+
+ float cofactor8 = getCofactor(m[1],m[2],m[3], m[5],m[6], m[7], m[13],m[14],m[15]);
+ float cofactor9 = getCofactor(m[0],m[2],m[3], m[4],m[6], m[7], m[12],m[14],m[15]);
+ float cofactor10= getCofactor(m[0],m[1],m[3], m[4],m[5], m[7], m[12],m[13],m[15]);
+ float cofactor11= getCofactor(m[0],m[1],m[2], m[4],m[5], m[6], m[12],m[13],m[14]);
+
+ float cofactor12= getCofactor(m[1],m[2],m[3], m[5],m[6], m[7], m[9], m[10],m[11]);
+ float cofactor13= getCofactor(m[0],m[2],m[3], m[4],m[6], m[7], m[8], m[10],m[11]);
+ float cofactor14= getCofactor(m[0],m[1],m[3], m[4],m[5], m[7], m[8], m[9], m[11]);
+ float cofactor15= getCofactor(m[0],m[1],m[2], m[4],m[5], m[6], m[8], m[9], m[10]);
+
+ // build inverse matrix = adj(M) / det(M)
+ // adjugate of M is the transpose of the cofactor matrix of M
+ float invDeterminant = 1.0f / determinant;
+ m[0] = invDeterminant * cofactor0;
+ m[1] = -invDeterminant * cofactor4;
+ m[2] = invDeterminant * cofactor8;
+ m[3] = -invDeterminant * cofactor12;
+
+ m[4] = -invDeterminant * cofactor1;
+ m[5] = invDeterminant * cofactor5;
+ m[6] = -invDeterminant * cofactor9;
+ m[7] = invDeterminant * cofactor13;
+
+ m[8] = invDeterminant * cofactor2;
+ m[9] = -invDeterminant * cofactor6;
+ m[10]= invDeterminant * cofactor10;
+ m[11]= -invDeterminant * cofactor14;
+
+ m[12]= -invDeterminant * cofactor3;
+ m[13]= invDeterminant * cofactor7;
+ m[14]= -invDeterminant * cofactor11;
+ m[15]= invDeterminant * cofactor15;
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// return determinant of 4x4 matrix
+///////////////////////////////////////////////////////////////////////////////
+float Matrix4::getDeterminant()
+{
+ return m[0] * getCofactor(m[5],m[6],m[7], m[9],m[10],m[11], m[13],m[14],m[15]) -
+ m[1] * getCofactor(m[4],m[6],m[7], m[8],m[10],m[11], m[12],m[14],m[15]) +
+ m[2] * getCofactor(m[4],m[5],m[7], m[8],m[9], m[11], m[12],m[13],m[15]) -
+ m[3] * getCofactor(m[4],m[5],m[6], m[8],m[9], m[10], m[12],m[13],m[14]);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// compute cofactor of 3x3 minor matrix without sign
+// input params are 9 elements of the minor matrix
+// NOTE: The caller must know its sign.
+///////////////////////////////////////////////////////////////////////////////
+float Matrix4::getCofactor(float m0, float m1, float m2,
+ float m3, float m4, float m5,
+ float m6, float m7, float m8)
+{
+ return m0 * (m4 * m8 - m5 * m7) -
+ m1 * (m3 * m8 - m5 * m6) +
+ m2 * (m3 * m7 - m4 * m6);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// translate this matrix by (x, y, z)
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::translate(const Vector3& v)
+{
+ return translate(v.x, v.y, v.z);
+}
+
+Matrix4& Matrix4::translate(float x, float y, float z)
+{
+ m[0] += m[3] * x; m[4] += m[7] * x; m[8] += m[11]* x; m[12]+= m[15]* x;
+ m[1] += m[3] * y; m[5] += m[7] * y; m[9] += m[11]* y; m[13]+= m[15]* y;
+ m[2] += m[3] * z; m[6] += m[7] * z; m[10]+= m[11]* z; m[14]+= m[15]* z;
+
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// uniform scale
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::scale(float s)
+{
+ return scale(s, s, s);
+}
+
+Matrix4& Matrix4::scale(float x, float y, float z)
+{
+ m[0] *= x; m[4] *= x; m[8] *= x; m[12] *= x;
+ m[1] *= y; m[5] *= y; m[9] *= y; m[13] *= y;
+ m[2] *= z; m[6] *= z; m[10]*= z; m[14] *= z;
+ return *this;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// build a rotation matrix with given angle(degree) and rotation axis, then
+// multiply it with this object
+///////////////////////////////////////////////////////////////////////////////
+Matrix4& Matrix4::rotate(float angle, const Vector3& axis)
+{
+ return rotate(angle, axis.x, axis.y, axis.z);
+}
+
+Matrix4& Matrix4::rotate(float angle, float x, float y, float z)
+{
+ float c = cosf(angle * DEG2RAD); // cosine
+ float s = sinf(angle * DEG2RAD); // sine
+ float c1 = 1.0f - c; // 1 - c
+ float m0 = m[0], m4 = m[4], m8 = m[8], m12= m[12],
+ m1 = m[1], m5 = m[5], m9 = m[9], m13= m[13],
+ m2 = m[2], m6 = m[6], m10= m[10], m14= m[14];
+
+ // build rotation matrix
+ float r0 = x * x * c1 + c;
+ float r1 = x * y * c1 + z * s;
+ float r2 = x * z * c1 - y * s;
+ float r4 = x * y * c1 - z * s;
+ float r5 = y * y * c1 + c;
+ float r6 = y * z * c1 + x * s;
+ float r8 = x * z * c1 + y * s;
+ float r9 = y * z * c1 - x * s;
+ float r10= z * z * c1 + c;
+
+ // multiply rotation matrix
+ m[0] = r0 * m0 + r4 * m1 + r8 * m2;
+ m[1] = r1 * m0 + r5 * m1 + r9 * m2;
+ m[2] = r2 * m0 + r6 * m1 + r10* m2;
+ m[4] = r0 * m4 + r4 * m5 + r8 * m6;
+ m[5] = r1 * m4 + r5 * m5 + r9 * m6;
+ m[6] = r2 * m4 + r6 * m5 + r10* m6;
+ m[8] = r0 * m8 + r4 * m9 + r8 * m10;
+ m[9] = r1 * m8 + r5 * m9 + r9 * m10;
+ m[10]= r2 * m8 + r6 * m9 + r10* m10;
+ m[12]= r0 * m12+ r4 * m13+ r8 * m14;
+ m[13]= r1 * m12+ r5 * m13+ r9 * m14;
+ m[14]= r2 * m12+ r6 * m13+ r10* m14;
+
+ return *this;
+}
+
+Matrix4& Matrix4::rotateX(float angle)
+{
+ float c = cosf(angle * DEG2RAD);
+ float s = sinf(angle * DEG2RAD);
+ float m1 = m[1], m2 = m[2],
+ m5 = m[5], m6 = m[6],
+ m9 = m[9], m10= m[10],
+ m13= m[13], m14= m[14];
+
+ m[1] = m1 * c + m2 *-s;
+ m[2] = m1 * s + m2 * c;
+ m[5] = m5 * c + m6 *-s;
+ m[6] = m5 * s + m6 * c;
+ m[9] = m9 * c + m10*-s;
+ m[10]= m9 * s + m10* c;
+ m[13]= m13* c + m14*-s;
+ m[14]= m13* s + m14* c;
+
+ return *this;
+}
+
+Matrix4& Matrix4::rotateY(float angle)
+{
+ float c = cosf(angle * DEG2RAD);
+ float s = sinf(angle * DEG2RAD);
+ float m0 = m[0], m2 = m[2],
+ m4 = m[4], m6 = m[6],
+ m8 = m[8], m10= m[10],
+ m12= m[12], m14= m[14];
+
+ m[0] = m0 * c + m2 * s;
+ m[2] = m0 *-s + m2 * c;
+ m[4] = m4 * c + m6 * s;
+ m[6] = m4 *-s + m6 * c;
+ m[8] = m8 * c + m10* s;
+ m[10]= m8 *-s + m10* c;
+ m[12]= m12* c + m14* s;
+ m[14]= m12*-s + m14* c;
+
+ return *this;
+}
+
+Matrix4& Matrix4::rotateZ(float angle)
+{
+ float c = cosf(angle * DEG2RAD);
+ float s = sinf(angle * DEG2RAD);
+ float m0 = m[0], m1 = m[1],
+ m4 = m[4], m5 = m[5],
+ m8 = m[8], m9 = m[9],
+ m12= m[12], m13= m[13];
+
+ m[0] = m0 * c + m1 *-s;
+ m[1] = m0 * s + m1 * c;
+ m[4] = m4 * c + m5 *-s;
+ m[5] = m4 * s + m5 * c;
+ m[8] = m8 * c + m9 *-s;
+ m[9] = m8 * s + m9 * c;
+ m[12]= m12* c + m13*-s;
+ m[13]= m12* s + m13* c;
+
+ return *this;
+}
diff --git a/shared/Matrices.h b/shared/Matrices.h
new file mode 100644
index 0000000..3515f54
--- /dev/null
+++ b/shared/Matrices.h
@@ -0,0 +1,909 @@
+///////////////////////////////////////////////////////////////////////////////
+// Matrice.h
+// =========
+// NxN Matrix Math classes
+//
+// The elements of the matrix are stored as column major order.
+// | 0 2 | | 0 3 6 | | 0 4 8 12 |
+// | 1 3 | | 1 4 7 | | 1 5 9 13 |
+// | 2 5 8 | | 2 6 10 14 |
+// | 3 7 11 15 |
+//
+// AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
+// CREATED: 2005-06-24
+// UPDATED: 2013-09-30
+//
+// Copyright (C) 2005 Song Ho Ahn
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef MATH_MATRICES_H
+#define MATH_MATRICES_H
+
+#include <iostream>
+#include <iomanip>
+#include "Vectors.h"
+
+///////////////////////////////////////////////////////////////////////////
+// 2x2 matrix
+///////////////////////////////////////////////////////////////////////////
+class Matrix2
+{
+public:
+ // constructors
+ Matrix2(); // init with identity
+ Matrix2(const float src[4]);
+ Matrix2(float m0, float m1, float m2, float m3);
+
+ void set(const float src[4]);
+ void set(float m0, float m1, float m2, float m3);
+ void setRow(int index, const float row[2]);
+ void setRow(int index, const Vector2& v);
+ void setColumn(int index, const float col[2]);
+ void setColumn(int index, const Vector2& v);
+
+ const float* get() const;
+ float getDeterminant();
+
+ Matrix2& identity();
+ Matrix2& transpose(); // transpose itself and return reference
+ Matrix2& invert();
+
+ // operators
+ Matrix2 operator+(const Matrix2& rhs) const; // add rhs
+ Matrix2 operator-(const Matrix2& rhs) const; // subtract rhs
+ Matrix2& operator+=(const Matrix2& rhs); // add rhs and update this object
+ Matrix2& operator-=(const Matrix2& rhs); // subtract rhs and update this object
+ Vector2 operator*(const Vector2& rhs) const; // multiplication: v' = M * v
+ Matrix2 operator*(const Matrix2& rhs) const; // multiplication: M3 = M1 * M2
+ Matrix2& operator*=(const Matrix2& rhs); // multiplication: M1' = M1 * M2
+ bool operator==(const Matrix2& rhs) const; // exact compare, no epsilon
+ bool operator!=(const Matrix2& rhs) const; // exact compare, no epsilon
+ float operator[](int index) const; // subscript operator v[0], v[1]
+ float& operator[](int index); // subscript operator v[0], v[1]
+
+ friend Matrix2 operator-(const Matrix2& m); // unary operator (-)
+ friend Matrix2 operator*(float scalar, const Matrix2& m); // pre-multiplication
+ friend Vector2 operator*(const Vector2& vec, const Matrix2& m); // pre-multiplication
+ friend std::ostream& operator<<(std::ostream& os, const Matrix2& m);
+
+protected:
+
+private:
+ float m[4];
+
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////
+// 3x3 matrix
+///////////////////////////////////////////////////////////////////////////
+class Matrix3
+{
+public:
+ // constructors
+ Matrix3(); // init with identity
+ Matrix3(const float src[9]);
+ Matrix3(float m0, float m1, float m2, // 1st column
+ float m3, float m4, float m5, // 2nd column
+ float m6, float m7, float m8); // 3rd column
+
+ void set(const float src[9]);
+ void set(float m0, float m1, float m2, // 1st column
+ float m3, float m4, float m5, // 2nd column
+ float m6, float m7, float m8); // 3rd column
+ void setRow(int index, const float row[3]);
+ void setRow(int index, const Vector3& v);
+ void setColumn(int index, const float col[3]);
+ void setColumn(int index, const Vector3& v);
+
+ const float* get() const;
+ float getDeterminant();
+
+ Matrix3& identity();
+ Matrix3& transpose(); // transpose itself and return reference
+ Matrix3& invert();
+
+ // operators
+ Matrix3 operator+(const Matrix3& rhs) const; // add rhs
+ Matrix3 operator-(const Matrix3& rhs) const; // subtract rhs
+ Matrix3& operator+=(const Matrix3& rhs); // add rhs and update this object
+ Matrix3& operator-=(const Matrix3& rhs); // subtract rhs and update this object
+ Vector3 operator*(const Vector3& rhs) const; // multiplication: v' = M * v
+ Matrix3 operator*(const Matrix3& rhs) const; // multiplication: M3 = M1 * M2
+ Matrix3& operator*=(const Matrix3& rhs); // multiplication: M1' = M1 * M2
+ bool operator==(const Matrix3& rhs) const; // exact compare, no epsilon
+ bool operator!=(const Matrix3& rhs) const; // exact compare, no epsilon
+ float operator[](int index) const; // subscript operator v[0], v[1]
+ float& operator[](int index); // subscript operator v[0], v[1]
+
+ friend Matrix3 operator-(const Matrix3& m); // unary operator (-)
+ friend Matrix3 operator*(float scalar, const Matrix3& m); // pre-multiplication
+ friend Vector3 operator*(const Vector3& vec, const Matrix3& m); // pre-multiplication
+ friend std::ostream& operator<<(std::ostream& os, const Matrix3& m);
+
+protected:
+
+private:
+ float m[9];
+
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////
+// 4x4 matrix
+///////////////////////////////////////////////////////////////////////////
+class Matrix4
+{
+public:
+ // constructors
+ Matrix4(); // init with identity
+ Matrix4(const float src[16]);
+ Matrix4(float m00, float m01, float m02, float m03, // 1st column
+ float m04, float m05, float m06, float m07, // 2nd column
+ float m08, float m09, float m10, float m11, // 3rd column
+ float m12, float m13, float m14, float m15);// 4th column
+
+ void set(const float src[16]);
+ void set(float m00, float m01, float m02, float m03, // 1st column
+ float m04, float m05, float m06, float m07, // 2nd column
+ float m08, float m09, float m10, float m11, // 3rd column
+ float m12, float m13, float m14, float m15);// 4th column
+ void setRow(int index, const float row[4]);
+ void setRow(int index, const Vector4& v);
+ void setRow(int index, const Vector3& v);
+ void setColumn(int index, const float col[4]);
+ void setColumn(int index, const Vector4& v);
+ void setColumn(int index, const Vector3& v);
+
+ const float* get() const;
+ const float* getTranspose(); // return transposed matrix
+ float getDeterminant();
+
+ Matrix4& identity();
+ Matrix4& transpose(); // transpose itself and return reference
+ Matrix4& invert(); // check best inverse method before inverse
+ Matrix4& invertEuclidean(); // inverse of Euclidean transform matrix
+ Matrix4& invertAffine(); // inverse of affine transform matrix
+ Matrix4& invertProjective(); // inverse of projective matrix using partitioning
+ Matrix4& invertGeneral(); // inverse of generic matrix
+
+ // transform matrix
+ Matrix4& translate(float x, float y, float z); // translation by (x,y,z)
+ Matrix4& translate(const Vector3& v); //
+ Matrix4& rotate(float angle, const Vector3& axis); // rotate angle(degree) along the given axix
+ Matrix4& rotate(float angle, float x, float y, float z);
+ Matrix4& rotateX(float angle); // rotate on X-axis with degree
+ Matrix4& rotateY(float angle); // rotate on Y-axis with degree
+ Matrix4& rotateZ(float angle); // rotate on Z-axis with degree
+ Matrix4& scale(float scale); // uniform scale
+ Matrix4& scale(float sx, float sy, float sz); // scale by (sx, sy, sz) on each axis
+
+ // operators
+ Matrix4 operator+(const Matrix4& rhs) const; // add rhs
+ Matrix4 operator-(const Matrix4& rhs) const; // subtract rhs
+ Matrix4& operator+=(const Matrix4& rhs); // add rhs and update this object
+ Matrix4& operator-=(const Matrix4& rhs); // subtract rhs and update this object
+ Vector4 operator*(const Vector4& rhs) const; // multiplication: v' = M * v
+ Vector3 operator*(const Vector3& rhs) const; // multiplication: v' = M * v
+ Matrix4 operator*(const Matrix4& rhs) const; // multiplication: M3 = M1 * M2
+ Matrix4& operator*=(const Matrix4& rhs); // multiplication: M1' = M1 * M2
+ bool operator==(const Matrix4& rhs) const; // exact compare, no epsilon
+ bool operator!=(const Matrix4& rhs) const; // exact compare, no epsilon
+ float operator[](int index) const; // subscript operator v[0], v[1]
+ float& operator[](int index); // subscript operator v[0], v[1]
+
+ friend Matrix4 operator-(const Matrix4& m); // unary operator (-)
+ friend Matrix4 operator*(float scalar, const Matrix4& m); // pre-multiplication
+ friend Vector3 operator*(const Vector3& vec, const Matrix4& m); // pre-multiplication
+ friend Vector4 operator*(const Vector4& vec, const Matrix4& m); // pre-multiplication
+ friend std::ostream& operator<<(std::ostream& os, const Matrix4& m);
+
+protected:
+
+private:
+ float getCofactor(float m0, float m1, float m2,
+ float m3, float m4, float m5,
+ float m6, float m7, float m8);
+
+ float m[16];
+ float tm[16]; // transpose m
+
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////
+// inline functions for Matrix2
+///////////////////////////////////////////////////////////////////////////
+inline Matrix2::Matrix2()
+{
+ // initially identity matrix
+ identity();
+}
+
+
+
+inline Matrix2::Matrix2(const float src[4])
+{
+ set(src);
+}
+
+
+
+inline Matrix2::Matrix2(float m0, float m1, float m2, float m3)
+{
+ set(m0, m1, m2, m3);
+}
+
+
+
+inline void Matrix2::set(const float src[4])
+{
+ m[0] = src[0]; m[1] = src[1]; m[2] = src[2]; m[3] = src[3];
+}
+
+
+
+inline void Matrix2::set(float m0, float m1, float m2, float m3)
+{
+ m[0]= m0; m[1] = m1; m[2] = m2; m[3]= m3;
+}
+
+
+
+inline void Matrix2::setRow(int index, const float row[2])
+{
+ m[index] = row[0]; m[index + 2] = row[1];
+}
+
+
+
+inline void Matrix2::setRow(int index, const Vector2& v)
+{
+ m[index] = v.x; m[index + 2] = v.y;
+}
+
+
+
+inline void Matrix2::setColumn(int index, const float col[2])
+{
+ m[index*2] = col[0]; m[index*2 + 1] = col[1];
+}
+
+
+
+inline void Matrix2::setColumn(int index, const Vector2& v)
+{
+ m[index*2] = v.x; m[index*2 + 1] = v.y;
+}
+
+
+
+inline const float* Matrix2::get() const
+{
+ return m;
+}
+
+
+
+inline Matrix2& Matrix2::identity()
+{
+ m[0] = m[3] = 1.0f;
+ m[1] = m[2] = 0.0f;
+ return *this;
+}
+
+
+
+inline Matrix2 Matrix2::operator+(const Matrix2& rhs) const
+{
+ return Matrix2(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2], m[3]+rhs[3]);
+}
+
+
+
+inline Matrix2 Matrix2::operator-(const Matrix2& rhs) const
+{
+ return Matrix2(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2], m[3]-rhs[3]);
+}
+
+
+
+inline Matrix2& Matrix2::operator+=(const Matrix2& rhs)
+{
+ m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2]; m[3] += rhs[3];
+ return *this;
+}
+
+
+
+inline Matrix2& Matrix2::operator-=(const Matrix2& rhs)
+{
+ m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2]; m[3] -= rhs[3];
+ return *this;
+}
+
+
+
+inline Vector2 Matrix2::operator*(const Vector2& rhs) const
+{
+ return Vector2(m[0]*rhs.x + m[2]*rhs.y, m[1]*rhs.x + m[3]*rhs.y);
+}
+
+
+
+inline Matrix2 Matrix2::operator*(const Matrix2& rhs) const
+{
+ return Matrix2(m[0]*rhs[0] + m[2]*rhs[1], m[1]*rhs[0] + m[3]*rhs[1],
+ m[0]*rhs[2] + m[2]*rhs[3], m[1]*rhs[2] + m[3]*rhs[3]);
+}
+
+
+
+inline Matrix2& Matrix2::operator*=(const Matrix2& rhs)
+{
+ *this = *this * rhs;
+ return *this;
+}
+
+
+
+inline bool Matrix2::operator==(const Matrix2& rhs) const
+{
+ return (m[0] == rhs[0]) && (m[1] == rhs[1]) && (m[2] == rhs[2]) && (m[3] == rhs[3]);
+}
+
+
+
+inline bool Matrix2::operator!=(const Matrix2& rhs) const
+{
+ return (m[0] != rhs[0]) || (m[1] != rhs[1]) || (m[2] != rhs[2]) || (m[3] != rhs[3]);
+}
+
+
+
+inline float Matrix2::operator[](int index) const
+{
+ return m[index];
+}
+
+
+
+inline float& Matrix2::operator[](int index)
+{
+ return m[index];
+}
+
+
+
+inline Matrix2 operator-(const Matrix2& rhs)
+{
+ return Matrix2(-rhs[0], -rhs[1], -rhs[2], -rhs[3]);
+}
+
+
+
+inline Matrix2 operator*(float s, const Matrix2& rhs)
+{
+ return Matrix2(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3]);
+}
+
+
+
+inline Vector2 operator*(const Vector2& v, const Matrix2& rhs)
+{
+ return Vector2(v.x*rhs[0] + v.y*rhs[1], v.x*rhs[2] + v.y*rhs[3]);
+}
+
+
+
+inline std::ostream& operator<<(std::ostream& os, const Matrix2& m)
+{
+ os << std::fixed << std::setprecision(5);
+ os << "[" << std::setw(10) << m[0] << " " << std::setw(10) << m[2] << "]\n"
+ << "[" << std::setw(10) << m[1] << " " << std::setw(10) << m[3] << "]\n";
+ os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);
+ return os;
+}
+// END OF MATRIX2 INLINE //////////////////////////////////////////////////////
+
+
+
+
+///////////////////////////////////////////////////////////////////////////
+// inline functions for Matrix3
+///////////////////////////////////////////////////////////////////////////
+inline Matrix3::Matrix3()
+{
+ // initially identity matrix
+ identity();
+}
+
+
+
+inline Matrix3::Matrix3(const float src[9])
+{
+ set(src);
+}
+
+
+
+inline Matrix3::Matrix3(float m0, float m1, float m2,
+ float m3, float m4, float m5,
+ float m6, float m7, float m8)
+{
+ set(m0, m1, m2, m3, m4, m5, m6, m7, m8);
+}
+
+
+
+inline void Matrix3::set(const float src[9])
+{
+ m[0] = src[0]; m[1] = src[1]; m[2] = src[2];
+ m[3] = src[3]; m[4] = src[4]; m[5] = src[5];
+ m[6] = src[6]; m[7] = src[7]; m[8] = src[8];
+}
+
+
+
+inline void Matrix3::set(float m0, float m1, float m2,
+ float m3, float m4, float m5,
+ float m6, float m7, float m8)
+{
+ m[0] = m0; m[1] = m1; m[2] = m2;
+ m[3] = m3; m[4] = m4; m[5] = m5;
+ m[6] = m6; m[7] = m7; m[8] = m8;
+}
+
+
+
+inline void Matrix3::setRow(int index, const float row[3])
+{
+ m[index] = row[0]; m[index + 3] = row[1]; m[index + 6] = row[2];
+}
+
+
+
+inline void Matrix3::setRow(int index, const Vector3& v)
+{
+ m[index] = v.x; m[index + 3] = v.y; m[index + 6] = v.z;
+}
+
+
+
+inline void Matrix3::setColumn(int index, const float col[3])
+{
+ m[index*3] = col[0]; m[index*3 + 1] = col[1]; m[index*3 + 2] = col[2];
+}
+
+
+
+inline void Matrix3::setColumn(int index, const Vector3& v)
+{
+ m[index*3] = v.x; m[index*3 + 1] = v.y; m[index*3 + 2] = v.z;
+}
+
+
+
+inline const float* Matrix3::get() const
+{
+ return m;
+}
+
+
+
+inline Matrix3& Matrix3::identity()
+{
+ m[0] = m[4] = m[8] = 1.0f;
+ m[1] = m[2] = m[3] = m[5] = m[6] = m[7] = 0.0f;
+ return *this;
+}
+
+
+
+inline Matrix3 Matrix3::operator+(const Matrix3& rhs) const
+{
+ return Matrix3(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2],
+ m[3]+rhs[3], m[4]+rhs[4], m[5]+rhs[5],
+ m[6]+rhs[6], m[7]+rhs[7], m[8]+rhs[8]);
+}
+
+
+
+inline Matrix3 Matrix3::operator-(const Matrix3& rhs) const
+{
+ return Matrix3(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2],
+ m[3]-rhs[3], m[4]-rhs[4], m[5]-rhs[5],
+ m[6]-rhs[6], m[7]-rhs[7], m[8]-rhs[8]);
+}
+
+
+
+inline Matrix3& Matrix3::operator+=(const Matrix3& rhs)
+{
+ m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2];
+ m[3] += rhs[3]; m[4] += rhs[4]; m[5] += rhs[5];
+ m[6] += rhs[6]; m[7] += rhs[7]; m[8] += rhs[8];
+ return *this;
+}
+
+
+
+inline Matrix3& Matrix3::operator-=(const Matrix3& rhs)
+{
+ m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2];
+ m[3] -= rhs[3]; m[4] -= rhs[4]; m[5] -= rhs[5];
+ m[6] -= rhs[6]; m[7] -= rhs[7]; m[8] -= rhs[8];
+ return *this;
+}
+
+
+
+inline Vector3 Matrix3::operator*(const Vector3& rhs) const
+{
+ return Vector3(m[0]*rhs.x + m[3]*rhs.y + m[6]*rhs.z,
+ m[1]*rhs.x + m[4]*rhs.y + m[7]*rhs.z,
+ m[2]*rhs.x + m[5]*rhs.y + m[8]*rhs.z);
+}
+
+
+
+inline Matrix3 Matrix3::operator*(const Matrix3& rhs) const
+{
+ return Matrix3(m[0]*rhs[0] + m[3]*rhs[1] + m[6]*rhs[2], m[1]*rhs[0] + m[4]*rhs[1] + m[7]*rhs[2], m[2]*rhs[0] + m[5]*rhs[1] + m[8]*rhs[2],
+ m[0]*rhs[3] + m[3]*rhs[4] + m[6]*rhs[5], m[1]*rhs[3] + m[4]*rhs[4] + m[7]*rhs[5], m[2]*rhs[3] + m[5]*rhs[4] + m[8]*rhs[5],
+ m[0]*rhs[6] + m[3]*rhs[7] + m[6]*rhs[8], m[1]*rhs[6] + m[4]*rhs[7] + m[7]*rhs[8], m[2]*rhs[6] + m[5]*rhs[7] + m[8]*rhs[8]);
+}
+
+
+
+inline Matrix3& Matrix3::operator*=(const Matrix3& rhs)
+{
+ *this = *this * rhs;
+ return *this;
+}
+
+
+
+inline bool Matrix3::operator==(const Matrix3& rhs) const
+{
+ return (m[0] == rhs[0]) && (m[1] == rhs[1]) && (m[2] == rhs[2]) &&
+ (m[3] == rhs[3]) && (m[4] == rhs[4]) && (m[5] == rhs[5]) &&
+ (m[6] == rhs[6]) && (m[7] == rhs[7]) && (m[8] == rhs[8]);
+}
+
+
+
+inline bool Matrix3::operator!=(const Matrix3& rhs) const
+{
+ return (m[0] != rhs[0]) || (m[1] != rhs[1]) || (m[2] != rhs[2]) ||
+ (m[3] != rhs[3]) || (m[4] != rhs[4]) || (m[5] != rhs[5]) ||
+ (m[6] != rhs[6]) || (m[7] != rhs[7]) || (m[8] != rhs[8]);
+}
+
+
+
+inline float Matrix3::operator[](int index) const
+{
+ return m[index];
+}
+
+
+
+inline float& Matrix3::operator[](int index)
+{
+ return m[index];
+}
+
+
+
+inline Matrix3 operator-(const Matrix3& rhs)
+{
+ return Matrix3(-rhs[0], -rhs[1], -rhs[2], -rhs[3], -rhs[4], -rhs[5], -rhs[6], -rhs[7], -rhs[8]);
+}
+
+
+
+inline Matrix3 operator*(float s, const Matrix3& rhs)
+{
+ return Matrix3(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3], s*rhs[4], s*rhs[5], s*rhs[6], s*rhs[7], s*rhs[8]);
+}
+
+
+
+inline Vector3 operator*(const Vector3& v, const Matrix3& m)
+{
+ return Vector3(v.x*m[0] + v.y*m[1] + v.z*m[2], v.x*m[3] + v.y*m[4] + v.z*m[5], v.x*m[6] + v.y*m[7] + v.z*m[8]);
+}
+
+
+
+inline std::ostream& operator<<(std::ostream& os, const Matrix3& m)
+{
+ os << std::fixed << std::setprecision(5);
+ os << "[" << std::setw(10) << m[0] << " " << std::setw(10) << m[3] << " " << std::setw(10) << m[6] << "]\n"
+ << "[" << std::setw(10) << m[1] << " " << std::setw(10) << m[4] << " " << std::setw(10) << m[7] << "]\n"
+ << "[" << std::setw(10) << m[2] << " " << std::setw(10) << m[5] << " " << std::setw(10) << m[8] << "]\n";
+ os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);
+ return os;
+}
+// END OF MATRIX3 INLINE //////////////////////////////////////////////////////
+
+
+
+
+///////////////////////////////////////////////////////////////////////////
+// inline functions for Matrix4
+///////////////////////////////////////////////////////////////////////////
+inline Matrix4::Matrix4()
+{
+ // initially identity matrix
+ identity();
+}
+
+
+
+inline Matrix4::Matrix4(const float src[16])
+{
+ set(src);
+}
+
+
+
+inline Matrix4::Matrix4(float m00, float m01, float m02, float m03,
+ float m04, float m05, float m06, float m07,
+ float m08, float m09, float m10, float m11,
+ float m12, float m13, float m14, float m15)
+{
+ set(m00, m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12, m13, m14, m15);
+}
+
+
+
+inline void Matrix4::set(const float src[16])
+{
+ m[0] = src[0]; m[1] = src[1]; m[2] = src[2]; m[3] = src[3];
+ m[4] = src[4]; m[5] = src[5]; m[6] = src[6]; m[7] = src[7];
+ m[8] = src[8]; m[9] = src[9]; m[10]= src[10]; m[11]= src[11];
+ m[12]= src[12]; m[13]= src[13]; m[14]= src[14]; m[15]= src[15];
+}
+
+
+
+inline void Matrix4::set(float m00, float m01, float m02, float m03,
+ float m04, float m05, float m06, float m07,
+ float m08, float m09, float m10, float m11,
+ float m12, float m13, float m14, float m15)
+{
+ m[0] = m00; m[1] = m01; m[2] = m02; m[3] = m03;
+ m[4] = m04; m[5] = m05; m[6] = m06; m[7] = m07;
+ m[8] = m08; m[9] = m09; m[10]= m10; m[11]= m11;
+ m[12]= m12; m[13]= m13; m[14]= m14; m[15]= m15;
+}
+
+
+
+inline void Matrix4::setRow(int index, const float row[4])
+{
+ m[index] = row[0]; m[index + 4] = row[1]; m[index + 8] = row[2]; m[index + 12] = row[3];
+}
+
+
+
+inline void Matrix4::setRow(int index, const Vector4& v)
+{
+ m[index] = v.x; m[index + 4] = v.y; m[index + 8] = v.z; m[index + 12] = v.w;
+}
+
+
+
+inline void Matrix4::setRow(int index, const Vector3& v)
+{
+ m[index] = v.x; m[index + 4] = v.y; m[index + 8] = v.z;
+}
+
+
+
+inline void Matrix4::setColumn(int index, const float col[4])
+{
+ m[index*4] = col[0]; m[index*4 + 1] = col[1]; m[index*4 + 2] = col[2]; m[index*4 + 3] = col[3];
+}
+
+
+
+inline void Matrix4::setColumn(int index, const Vector4& v)
+{
+ m[index*4] = v.x; m[index*4 + 1] = v.y; m[index*4 + 2] = v.z; m[index*4 + 3] = v.w;
+}
+
+
+
+inline void Matrix4::setColumn(int index, const Vector3& v)
+{
+ m[index*4] = v.x; m[index*4 + 1] = v.y; m[index*4 + 2] = v.z;
+}
+
+
+
+inline const float* Matrix4::get() const
+{
+ return m;
+}
+
+
+
+inline const float* Matrix4::getTranspose()
+{
+ tm[0] = m[0]; tm[1] = m[4]; tm[2] = m[8]; tm[3] = m[12];
+ tm[4] = m[1]; tm[5] = m[5]; tm[6] = m[9]; tm[7] = m[13];
+ tm[8] = m[2]; tm[9] = m[6]; tm[10]= m[10]; tm[11]= m[14];
+ tm[12]= m[3]; tm[13]= m[7]; tm[14]= m[11]; tm[15]= m[15];
+ return tm;
+}
+
+
+
+inline Matrix4& Matrix4::identity()
+{
+ m[0] = m[5] = m[10] = m[15] = 1.0f;
+ m[1] = m[2] = m[3] = m[4] = m[6] = m[7] = m[8] = m[9] = m[11] = m[12] = m[13] = m[14] = 0.0f;
+ return *this;
+}
+
+
+
+inline Matrix4 Matrix4::operator+(const Matrix4& rhs) const
+{
+ return Matrix4(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2], m[3]+rhs[3],
+ m[4]+rhs[4], m[5]+rhs[5], m[6]+rhs[6], m[7]+rhs[7],
+ m[8]+rhs[8], m[9]+rhs[9], m[10]+rhs[10], m[11]+rhs[11],
+ m[12]+rhs[12], m[13]+rhs[13], m[14]+rhs[14], m[15]+rhs[15]);
+}
+
+
+
+inline Matrix4 Matrix4::operator-(const Matrix4& rhs) const
+{
+ return Matrix4(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2], m[3]-rhs[3],
+ m[4]-rhs[4], m[5]-rhs[5], m[6]-rhs[6], m[7]-rhs[7],
+ m[8]-rhs[8], m[9]-rhs[9], m[10]-rhs[10], m[11]-rhs[11],
+ m[12]-rhs[12], m[13]-rhs[13], m[14]-rhs[14], m[15]-rhs[15]);
+}
+
+
+
+inline Matrix4& Matrix4::operator+=(const Matrix4& rhs)
+{
+ m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2]; m[3] += rhs[3];
+ m[4] += rhs[4]; m[5] += rhs[5]; m[6] += rhs[6]; m[7] += rhs[7];
+ m[8] += rhs[8]; m[9] += rhs[9]; m[10]+= rhs[10]; m[11]+= rhs[11];
+ m[12]+= rhs[12]; m[13]+= rhs[13]; m[14]+= rhs[14]; m[15]+= rhs[15];
+ return *this;
+}
+
+
+
+inline Matrix4& Matrix4::operator-=(const Matrix4& rhs)
+{
+ m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2]; m[3] -= rhs[3];
+ m[4] -= rhs[4]; m[5] -= rhs[5]; m[6] -= rhs[6]; m[7] -= rhs[7];
+ m[8] -= rhs[8]; m[9] -= rhs[9]; m[10]-= rhs[10]; m[11]-= rhs[11];
+ m[12]-= rhs[12]; m[13]-= rhs[13]; m[14]-= rhs[14]; m[15]-= rhs[15];
+ return *this;
+}
+
+
+
+inline Vector4 Matrix4::operator*(const Vector4& rhs) const
+{
+ return Vector4(m[0]*rhs.x + m[4]*rhs.y + m[8]*rhs.z + m[12]*rhs.w,
+ m[1]*rhs.x + m[5]*rhs.y + m[9]*rhs.z + m[13]*rhs.w,
+ m[2]*rhs.x + m[6]*rhs.y + m[10]*rhs.z + m[14]*rhs.w,
+ m[3]*rhs.x + m[7]*rhs.y + m[11]*rhs.z + m[15]*rhs.w);
+}
+
+
+
+inline Vector3 Matrix4::operator*(const Vector3& rhs) const
+{
+ return Vector3(m[0]*rhs.x + m[4]*rhs.y + m[8]*rhs.z,
+ m[1]*rhs.x + m[5]*rhs.y + m[9]*rhs.z,
+ m[2]*rhs.x + m[6]*rhs.y + m[10]*rhs.z);
+}
+
+
+
+inline Matrix4 Matrix4::operator*(const Matrix4& n) const
+{
+ return Matrix4(m[0]*n[0] + m[4]*n[1] + m[8]*n[2] + m[12]*n[3], m[1]*n[0] + m[5]*n[1] + m[9]*n[2] + m[13]*n[3], m[2]*n[0] + m[6]*n[1] + m[10]*n[2] + m[14]*n[3], m[3]*n[0] + m[7]*n[1] + m[11]*n[2] + m[15]*n[3],
+ m[0]*n[4] + m[4]*n[5] + m[8]*n[6] + m[12]*n[7], m[1]*n[4] + m[5]*n[5] + m[9]*n[6] + m[13]*n[7], m[2]*n[4] + m[6]*n[5] + m[10]*n[6] + m[14]*n[7], m[3]*n[4] + m[7]*n[5] + m[11]*n[6] + m[15]*n[7],
+ m[0]*n[8] + m[4]*n[9] + m[8]*n[10] + m[12]*n[11], m[1]*n[8] + m[5]*n[9] + m[9]*n[10] + m[13]*n[11], m[2]*n[8] + m[6]*n[9] + m[10]*n[10] + m[14]*n[11], m[3]*n[8] + m[7]*n[9] + m[11]*n[10] + m[15]*n[11],
+ m[0]*n[12] + m[4]*n[13] + m[8]*n[14] + m[12]*n[15], m[1]*n[12] + m[5]*n[13] + m[9]*n[14] + m[13]*n[15], m[2]*n[12] + m[6]*n[13] + m[10]*n[14] + m[14]*n[15], m[3]*n[12] + m[7]*n[13] + m[11]*n[14] + m[15]*n[15]);
+}
+
+
+
+inline Matrix4& Matrix4::operator*=(const Matrix4& rhs)
+{
+ *this = *this * rhs;
+ return *this;
+}
+
+
+
+inline bool Matrix4::operator==(const Matrix4& n) const
+{
+ return (m[0] == n[0]) && (m[1] == n[1]) && (m[2] == n[2]) && (m[3] == n[3]) &&
+ (m[4] == n[4]) && (m[5] == n[5]) && (m[6] == n[6]) && (m[7] == n[7]) &&
+ (m[8] == n[8]) && (m[9] == n[9]) && (m[10]== n[10]) && (m[11]== n[11]) &&
+ (m[12]== n[12]) && (m[13]== n[13]) && (m[14]== n[14]) && (m[15]== n[15]);
+}
+
+
+
+inline bool Matrix4::operator!=(const Matrix4& n) const
+{
+ return (m[0] != n[0]) || (m[1] != n[1]) || (m[2] != n[2]) || (m[3] != n[3]) ||
+ (m[4] != n[4]) || (m[5] != n[5]) || (m[6] != n[6]) || (m[7] != n[7]) ||
+ (m[8] != n[8]) || (m[9] != n[9]) || (m[10]!= n[10]) || (m[11]!= n[11]) ||
+ (m[12]!= n[12]) || (m[13]!= n[13]) || (m[14]!= n[14]) || (m[15]!= n[15]);
+}
+
+
+
+inline float Matrix4::operator[](int index) const
+{
+ return m[index];
+}
+
+
+
+inline float& Matrix4::operator[](int index)
+{
+ return m[index];
+}
+
+
+
+inline Matrix4 operator-(const Matrix4& rhs)
+{
+ return Matrix4(-rhs[0], -rhs[1], -rhs[2], -rhs[3], -rhs[4], -rhs[5], -rhs[6], -rhs[7], -rhs[8], -rhs[9], -rhs[10], -rhs[11], -rhs[12], -rhs[13], -rhs[14], -rhs[15]);
+}
+
+
+
+inline Matrix4 operator*(float s, const Matrix4& rhs)
+{
+ return Matrix4(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3], s*rhs[4], s*rhs[5], s*rhs[6], s*rhs[7], s*rhs[8], s*rhs[9], s*rhs[10], s*rhs[11], s*rhs[12], s*rhs[13], s*rhs[14], s*rhs[15]);
+}
+
+
+
+inline Vector4 operator*(const Vector4& v, const Matrix4& m)
+{
+ return Vector4(v.x*m[0] + v.y*m[1] + v.z*m[2] + v.w*m[3], v.x*m[4] + v.y*m[5] + v.z*m[6] + v.w*m[7], v.x*m[8] + v.y*m[9] + v.z*m[10] + v.w*m[11], v.x*m[12] + v.y*m[13] + v.z*m[14] + v.w*m[15]);
+}
+
+
+
+inline Vector3 operator*(const Vector3& v, const Matrix4& m)
+{
+ return Vector3(v.x*m[0] + v.y*m[1] + v.z*m[2], v.x*m[4] + v.y*m[5] + v.z*m[6], v.x*m[8] + v.y*m[9] + v.z*m[10]);
+}
+
+
+
+inline std::ostream& operator<<(std::ostream& os, const Matrix4& m)
+{
+ os << std::fixed << std::setprecision(5);
+ os << "[" << std::setw(10) << m[0] << " " << std::setw(10) << m[4] << " " << std::setw(10) << m[8] << " " << std::setw(10) << m[12] << "]\n"
+ << "[" << std::setw(10) << m[1] << " " << std::setw(10) << m[5] << " " << std::setw(10) << m[9] << " " << std::setw(10) << m[13] << "]\n"
+ << "[" << std::setw(10) << m[2] << " " << std::setw(10) << m[6] << " " << std::setw(10) << m[10] << " " << std::setw(10) << m[14] << "]\n"
+ << "[" << std::setw(10) << m[3] << " " << std::setw(10) << m[7] << " " << std::setw(10) << m[11] << " " << std::setw(10) << m[15] << "]\n";
+ os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);
+ return os;
+}
+// END OF MATRIX4 INLINE //////////////////////////////////////////////////////
+#endif
diff --git a/shared/Vectors.h b/shared/Vectors.h
new file mode 100644
index 0000000..2efb840
--- /dev/null
+++ b/shared/Vectors.h
@@ -0,0 +1,530 @@
+///////////////////////////////////////////////////////////////////////////////
+// Vectors.h
+// =========
+// 2D/3D/4D vectors
+//
+// AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
+// CREATED: 2007-02-14
+// UPDATED: 2013-01-20
+//
+// Copyright (C) 2007-2013 Song Ho Ahn
+///////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef VECTORS_H_DEF
+#define VECTORS_H_DEF
+
+#include <cmath>
+#include <iostream>
+
+///////////////////////////////////////////////////////////////////////////////
+// 2D vector
+///////////////////////////////////////////////////////////////////////////////
+struct Vector2
+{
+ float x;
+ float y;
+
+ // ctors
+ Vector2() : x(0), y(0) {};
+ Vector2(float x, float y) : x(x), y(y) {};
+
+ // utils functions
+ void set(float x, float y);
+ float length() const; //
+ float distance(const Vector2& vec) const; // distance between two vectors
+ Vector2& normalize(); //
+ float dot(const Vector2& vec) const; // dot product
+ bool equal(const Vector2& vec, float e) const; // compare with epsilon
+
+ // operators
+ Vector2 operator-() const; // unary operator (negate)
+ Vector2 operator+(const Vector2& rhs) const; // add rhs
+ Vector2 operator-(const Vector2& rhs) const; // subtract rhs
+ Vector2& operator+=(const Vector2& rhs); // add rhs and update this object
+ Vector2& operator-=(const Vector2& rhs); // subtract rhs and update this object
+ Vector2 operator*(const float scale) const; // scale
+ Vector2 operator*(const Vector2& rhs) const; // multiply each element
+ Vector2& operator*=(const float scale); // scale and update this object
+ Vector2& operator*=(const Vector2& rhs); // multiply each element and update this object
+ Vector2 operator/(const float scale) const; // inverse scale
+ Vector2& operator/=(const float scale); // scale and update this object
+ bool operator==(const Vector2& rhs) const; // exact compare, no epsilon
+ bool operator!=(const Vector2& rhs) const; // exact compare, no epsilon
+ bool operator<(const Vector2& rhs) const; // comparison for sort
+ float operator[](int index) const; // subscript operator v[0], v[1]
+ float& operator[](int index); // subscript operator v[0], v[1]
+
+ friend Vector2 operator*(const float a, const Vector2 vec);
+ friend std::ostream& operator<<(std::ostream& os, const Vector2& vec);
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 3D vector
+///////////////////////////////////////////////////////////////////////////////
+struct Vector3
+{
+ float x;
+ float y;
+ float z;
+
+ // ctors
+ Vector3() : x(0), y(0), z(0) {};
+ Vector3(float x, float y, float z) : x(x), y(y), z(z) {};
+
+ // utils functions
+ void set(float x, float y, float z);
+ float length() const; //
+ float distance(const Vector3& vec) const; // distance between two vectors
+ Vector3& normalize(); //
+ float dot(const Vector3& vec) const; // dot product
+ Vector3 cross(const Vector3& vec) const; // cross product
+ bool equal(const Vector3& vec, float e) const; // compare with epsilon
+
+ // operators
+ Vector3 operator-() const; // unary operator (negate)
+ Vector3 operator+(const Vector3& rhs) const; // add rhs
+ Vector3 operator-(const Vector3& rhs) const; // subtract rhs
+ Vector3& operator+=(const Vector3& rhs); // add rhs and update this object
+ Vector3& operator-=(const Vector3& rhs); // subtract rhs and update this object
+ Vector3 operator*(const float scale) const; // scale
+ Vector3 operator*(const Vector3& rhs) const; // multiplay each element
+ Vector3& operator*=(const float scale); // scale and update this object
+ Vector3& operator*=(const Vector3& rhs); // product each element and update this object
+ Vector3 operator/(const float scale) const; // inverse scale
+ Vector3& operator/=(const float scale); // scale and update this object
+ bool operator==(const Vector3& rhs) const; // exact compare, no epsilon
+ bool operator!=(const Vector3& rhs) const; // exact compare, no epsilon
+ bool operator<(const Vector3& rhs) const; // comparison for sort
+ float operator[](int index) const; // subscript operator v[0], v[1]
+ float& operator[](int index); // subscript operator v[0], v[1]
+
+ friend Vector3 operator*(const float a, const Vector3 vec);
+ friend std::ostream& operator<<(std::ostream& os, const Vector3& vec);
+};
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 4D vector
+///////////////////////////////////////////////////////////////////////////////
+struct Vector4
+{
+ float x;
+ float y;
+ float z;
+ float w;
+
+ // ctors
+ Vector4() : x(0), y(0), z(0), w(0) {};
+ Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {};
+
+ // utils functions
+ void set(float x, float y, float z, float w);
+ float length() const; //
+ float distance(const Vector4& vec) const; // distance between two vectors
+ Vector4& normalize(); //
+ float dot(const Vector4& vec) const; // dot product
+ bool equal(const Vector4& vec, float e) const; // compare with epsilon
+
+ // operators
+ Vector4 operator-() const; // unary operator (negate)
+ Vector4 operator+(const Vector4& rhs) const; // add rhs
+ Vector4 operator-(const Vector4& rhs) const; // subtract rhs
+ Vector4& operator+=(const Vector4& rhs); // add rhs and update this object
+ Vector4& operator-=(const Vector4& rhs); // subtract rhs and update this object
+ Vector4 operator*(const float scale) const; // scale
+ Vector4 operator*(const Vector4& rhs) const; // multiply each element
+ Vector4& operator*=(const float scale); // scale and update this object
+ Vector4& operator*=(const Vector4& rhs); // multiply each element and update this object
+ Vector4 operator/(const float scale) const; // inverse scale
+ Vector4& operator/=(const float scale); // scale and update this object
+ bool operator==(const Vector4& rhs) const; // exact compare, no epsilon
+ bool operator!=(const Vector4& rhs) const; // exact compare, no epsilon
+ bool operator<(const Vector4& rhs) const; // comparison for sort
+ float operator[](int index) const; // subscript operator v[0], v[1]
+ float& operator[](int index); // subscript operator v[0], v[1]
+
+ friend Vector4 operator*(const float a, const Vector4 vec);
+ friend std::ostream& operator<<(std::ostream& os, const Vector4& vec);
+};
+
+
+
+// fast math routines from Doom3 SDK
+inline float invSqrt(float x)
+{
+ float xhalf = 0.5f * x;
+ int i = *(int*)&x; // get bits for floating value
+ i = 0x5f3759df - (i>>1); // gives initial guess
+ x = *(float*)&i; // convert bits back to float
+ x = x * (1.5f - xhalf*x*x); // Newton step
+ return x;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// inline functions for Vector2
+///////////////////////////////////////////////////////////////////////////////
+inline Vector2 Vector2::operator-() const {
+ return Vector2(-x, -y);
+}
+
+inline Vector2 Vector2::operator+(const Vector2& rhs) const {
+ return Vector2(x+rhs.x, y+rhs.y);
+}
+
+inline Vector2 Vector2::operator-(const Vector2& rhs) const {
+ return Vector2(x-rhs.x, y-rhs.y);
+}
+
+inline Vector2& Vector2::operator+=(const Vector2& rhs) {
+ x += rhs.x; y += rhs.y; return *this;
+}
+
+inline Vector2& Vector2::operator-=(const Vector2& rhs) {
+ x -= rhs.x; y -= rhs.y; return *this;
+}
+
+inline Vector2 Vector2::operator*(const float a) const {
+ return Vector2(x*a, y*a);
+}
+
+inline Vector2 Vector2::operator*(const Vector2& rhs) const {
+ return Vector2(x*rhs.x, y*rhs.y);
+}
+
+inline Vector2& Vector2::operator*=(const float a) {
+ x *= a; y *= a; return *this;
+}
+
+inline Vector2& Vector2::operator*=(const Vector2& rhs) {
+ x *= rhs.x; y *= rhs.y; return *this;
+}
+
+inline Vector2 Vector2::operator/(const float a) const {
+ return Vector2(x/a, y/a);
+}
+
+inline Vector2& Vector2::operator/=(const float a) {
+ x /= a; y /= a; return *this;
+}
+
+inline bool Vector2::operator==(const Vector2& rhs) const {
+ return (x == rhs.x) && (y == rhs.y);
+}
+
+inline bool Vector2::operator!=(const Vector2& rhs) const {
+ return (x != rhs.x) || (y != rhs.y);
+}
+
+inline bool Vector2::operator<(const Vector2& rhs) const {
+ if(x < rhs.x) return true;
+ if(x > rhs.x) return false;
+ if(y < rhs.y) return true;
+ if(y > rhs.y) return false;
+ return false;
+}
+
+inline float Vector2::operator[](int index) const {
+ return (&x)[index];
+}
+
+inline float& Vector2::operator[](int index) {
+ return (&x)[index];
+}
+
+inline void Vector2::set(float x_, float y_) {
+ this->x = x_; this->y = y_;
+}
+
+inline float Vector2::length() const {
+ return sqrtf(x*x + y*y);
+}
+
+inline float Vector2::distance(const Vector2& vec) const {
+ return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y));
+}
+
+inline Vector2& Vector2::normalize() {
+ //@@const float EPSILON = 0.000001f;
+ float xxyy = x*x + y*y;
+ //@@if(xxyy < EPSILON)
+ //@@ return *this;
+
+ //float invLength = invSqrt(xxyy);
+ float invLength = 1.0f / sqrtf(xxyy);
+ x *= invLength;
+ y *= invLength;
+ return *this;
+}
+
+inline float Vector2::dot(const Vector2& rhs) const {
+ return (x*rhs.x + y*rhs.y);
+}
+
+inline bool Vector2::equal(const Vector2& rhs, float epsilon) const {
+ return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon;
+}
+
+inline Vector2 operator*(const float a, const Vector2 vec) {
+ return Vector2(a*vec.x, a*vec.y);
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Vector2& vec) {
+ os << "(" << vec.x << ", " << vec.y << ")";
+ return os;
+}
+// END OF VECTOR2 /////////////////////////////////////////////////////////////
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// inline functions for Vector3
+///////////////////////////////////////////////////////////////////////////////
+inline Vector3 Vector3::operator-() const {
+ return Vector3(-x, -y, -z);
+}
+
+inline Vector3 Vector3::operator+(const Vector3& rhs) const {
+ return Vector3(x+rhs.x, y+rhs.y, z+rhs.z);
+}
+
+inline Vector3 Vector3::operator-(const Vector3& rhs) const {
+ return Vector3(x-rhs.x, y-rhs.y, z-rhs.z);
+}
+
+inline Vector3& Vector3::operator+=(const Vector3& rhs) {
+ x += rhs.x; y += rhs.y; z += rhs.z; return *this;
+}
+
+inline Vector3& Vector3::operator-=(const Vector3& rhs) {
+ x -= rhs.x; y -= rhs.y; z -= rhs.z; return *this;
+}
+
+inline Vector3 Vector3::operator*(const float a) const {
+ return Vector3(x*a, y*a, z*a);
+}
+
+inline Vector3 Vector3::operator*(const Vector3& rhs) const {
+ return Vector3(x*rhs.x, y*rhs.y, z*rhs.z);
+}
+
+inline Vector3& Vector3::operator*=(const float a) {
+ x *= a; y *= a; z *= a; return *this;
+}
+
+inline Vector3& Vector3::operator*=(const Vector3& rhs) {
+ x *= rhs.x; y *= rhs.y; z *= rhs.z; return *this;
+}
+
+inline Vector3 Vector3::operator/(const float a) const {
+ return Vector3(x/a, y/a, z/a);
+}
+
+inline Vector3& Vector3::operator/=(const float a) {
+ x /= a; y /= a; z /= a; return *this;
+}
+
+inline bool Vector3::operator==(const Vector3& rhs) const {
+ return (x == rhs.x) && (y == rhs.y) && (z == rhs.z);
+}
+
+inline bool Vector3::operator!=(const Vector3& rhs) const {
+ return (x != rhs.x) || (y != rhs.y) || (z != rhs.z);
+}
+
+inline bool Vector3::operator<(const Vector3& rhs) const {
+ if(x < rhs.x) return true;
+ if(x > rhs.x) return false;
+ if(y < rhs.y) return true;
+ if(y > rhs.y) return false;
+ if(z < rhs.z) return true;
+ if(z > rhs.z) return false;
+ return false;
+}
+
+inline float Vector3::operator[](int index) const {
+ return (&x)[index];
+}
+
+inline float& Vector3::operator[](int index) {
+ return (&x)[index];
+}
+
+inline void Vector3::set(float x_, float y_, float z_) {
+ this->x = x_; this->y = y_; this->z = z_;
+}
+
+inline float Vector3::length() const {
+ return sqrtf(x*x + y*y + z*z);
+}
+
+inline float Vector3::distance(const Vector3& vec) const {
+ return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y) + (vec.z-z)*(vec.z-z));
+}
+
+inline Vector3& Vector3::normalize() {
+ //@@const float EPSILON = 0.000001f;
+ float xxyyzz = x*x + y*y + z*z;
+ //@@if(xxyyzz < EPSILON)
+ //@@ return *this; // do nothing if it is ~zero vector
+
+ //float invLength = invSqrt(xxyyzz);
+ float invLength = 1.0f / sqrtf(xxyyzz);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ return *this;
+}
+
+inline float Vector3::dot(const Vector3& rhs) const {
+ return (x*rhs.x + y*rhs.y + z*rhs.z);
+}
+
+inline Vector3 Vector3::cross(const Vector3& rhs) const {
+ return Vector3(y*rhs.z - z*rhs.y, z*rhs.x - x*rhs.z, x*rhs.y - y*rhs.x);
+}
+
+inline bool Vector3::equal(const Vector3& rhs, float epsilon) const {
+ return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon && fabs(z - rhs.z) < epsilon;
+}
+
+inline Vector3 operator*(const float a, const Vector3 vec) {
+ return Vector3(a*vec.x, a*vec.y, a*vec.z);
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Vector3& vec) {
+ os << "(" << vec.x << ", " << vec.y << ", " << vec.z << ")";
+ return os;
+}
+// END OF VECTOR3 /////////////////////////////////////////////////////////////
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// inline functions for Vector4
+///////////////////////////////////////////////////////////////////////////////
+inline Vector4 Vector4::operator-() const {
+ return Vector4(-x, -y, -z, -w);
+}
+
+inline Vector4 Vector4::operator+(const Vector4& rhs) const {
+ return Vector4(x+rhs.x, y+rhs.y, z+rhs.z, w+rhs.w);
+}
+
+inline Vector4 Vector4::operator-(const Vector4& rhs) const {
+ return Vector4(x-rhs.x, y-rhs.y, z-rhs.z, w-rhs.w);
+}
+
+inline Vector4& Vector4::operator+=(const Vector4& rhs) {
+ x += rhs.x; y += rhs.y; z += rhs.z; w += rhs.w; return *this;
+}
+
+inline Vector4& Vector4::operator-=(const Vector4& rhs) {
+ x -= rhs.x; y -= rhs.y; z -= rhs.z; w -= rhs.w; return *this;
+}
+
+inline Vector4 Vector4::operator*(const float a) const {
+ return Vector4(x*a, y*a, z*a, w*a);
+}
+
+inline Vector4 Vector4::operator*(const Vector4& rhs) const {
+ return Vector4(x*rhs.x, y*rhs.y, z*rhs.z, w*rhs.w);
+}
+
+inline Vector4& Vector4::operator*=(const float a) {
+ x *= a; y *= a; z *= a; w *= a; return *this;
+}
+
+inline Vector4& Vector4::operator*=(const Vector4& rhs) {
+ x *= rhs.x; y *= rhs.y; z *= rhs.z; w *= rhs.w; return *this;
+}
+
+inline Vector4 Vector4::operator/(const float a) const {
+ return Vector4(x/a, y/a, z/a, w/a);
+}
+
+inline Vector4& Vector4::operator/=(const float a) {
+ x /= a; y /= a; z /= a; w /= a; return *this;
+}
+
+inline bool Vector4::operator==(const Vector4& rhs) const {
+ return (x == rhs.x) && (y == rhs.y) && (z == rhs.z) && (w == rhs.w);
+}
+
+inline bool Vector4::operator!=(const Vector4& rhs) const {
+ return (x != rhs.x) || (y != rhs.y) || (z != rhs.z) || (w != rhs.w);
+}
+
+inline bool Vector4::operator<(const Vector4& rhs) const {
+ if(x < rhs.x) return true;
+ if(x > rhs.x) return false;
+ if(y < rhs.y) return true;
+ if(y > rhs.y) return false;
+ if(z < rhs.z) return true;
+ if(z > rhs.z) return false;
+ if(w < rhs.w) return true;
+ if(w > rhs.w) return false;
+ return false;
+}
+
+inline float Vector4::operator[](int index) const {
+ return (&x)[index];
+}
+
+inline float& Vector4::operator[](int index) {
+ return (&x)[index];
+}
+
+inline void Vector4::set(float x_, float y_, float z_, float w_) {
+ this->x = x_; this->y = y_; this->z = z_; this->w = w_;
+}
+
+inline float Vector4::length() const {
+ return sqrtf(x*x + y*y + z*z + w*w);
+}
+
+inline float Vector4::distance(const Vector4& vec) const {
+ return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y) + (vec.z-z)*(vec.z-z) + (vec.w-w)*(vec.w-w));
+}
+
+inline Vector4& Vector4::normalize() {
+ //NOTE: leave w-component untouched
+ //@@const float EPSILON = 0.000001f;
+ float xxyyzz = x*x + y*y + z*z;
+ //@@if(xxyyzz < EPSILON)
+ //@@ return *this; // do nothing if it is zero vector
+
+ //float invLength = invSqrt(xxyyzz);
+ float invLength = 1.0f / sqrtf(xxyyzz);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ return *this;
+}
+
+inline float Vector4::dot(const Vector4& rhs) const {
+ return (x*rhs.x + y*rhs.y + z*rhs.z + w*rhs.w);
+}
+
+inline bool Vector4::equal(const Vector4& rhs, float epsilon) const {
+ return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon &&
+ fabs(z - rhs.z) < epsilon && fabs(w - rhs.w) < epsilon;
+}
+
+inline Vector4 operator*(const float a, const Vector4 vec) {
+ return Vector4(a*vec.x, a*vec.y, a*vec.z, a*vec.w);
+}
+
+inline std::ostream& operator<<(std::ostream& os, const Vector4& vec) {
+ os << "(" << vec.x << ", " << vec.y << ", " << vec.z << ", " << vec.w << ")";
+ return os;
+}
+// END OF VECTOR4 /////////////////////////////////////////////////////////////
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..ba98f14
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,2130 @@
+//========= Copyright Valve Corporation ============//
+//Original BSD 3 License by Valve Corporation:
+//Copyright (c) 2015, Valve Corporation
+//All rights reserved.
+
+//Redistribution and use in source and binary forms, with or without modification,
+//are permitted provided that the following conditions are met:
+
+//1. Redistributions of source code must retain the above copyright notice, this
+//list of conditions and the following disclaimer.
+
+//2. Redistributions in binary form must reproduce the above copyright notice,
+//this list of conditions and the following disclaimer in the documentation and/or
+//other materials provided with the distribution.
+
+//3. Neither the name of the copyright holder nor the names of its contributors
+//may be used to endorse or promote products derived from this software without
+//specific prior written permission.
+
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Modified by: DEC05EBA
+
+#include <SDL.h>
+#include <GL/glew.h>
+#include <SDL_opengl.h>
+#include <GL/glu.h>
+#include <openvr.h>
+#define GLX_GLXEXT_PROTOTYPES
+#include <GL/glx.h>
+#include <GL/glxext.h>
+#include <glm/glm.hpp>
+#include <X11/extensions/Xcomposite.h>
+
+#include <stdio.h>
+#include <string>
+#include <cstdlib>
+#include <vector>
+
+#include <unistd.h>
+#include <libgen.h>
+
+#include "../shared/Matrices.h"
+
+#ifndef _countof
+#define _countof(x) (sizeof(x)/sizeof((x)[0]))
+#endif
+
+void ThreadSleep( unsigned long nMilliseconds )
+{
+ usleep( nMilliseconds * 1000 );
+}
+
+class CGLRenderModel
+{
+public:
+ CGLRenderModel( const std::string & sRenderModelName );
+ ~CGLRenderModel();
+
+ bool BInit( const vr::RenderModel_t & vrModel, const vr::RenderModel_TextureMap_t & vrDiffuseTexture );
+ void Cleanup();
+ void Draw();
+ const std::string & GetName() const { return m_sModelName; }
+
+private:
+ GLuint m_glVertBuffer;
+ GLuint m_glIndexBuffer;
+ GLuint m_glVertArray;
+ GLuint m_glTexture;
+ GLsizei m_unVertexCount;
+ std::string m_sModelName;
+};
+
+static bool g_bPrintf = true;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//------------------------------------------------------------------------------
+class CMainApplication
+{
+public:
+ CMainApplication( int argc, char *argv[] );
+ virtual ~CMainApplication();
+
+ bool BInit();
+ bool BInitGL();
+ bool BInitCompositor();
+
+ void Shutdown();
+
+ void RunMainLoop();
+ bool HandleInput();
+ void ProcessVREvent( const vr::VREvent_t & event );
+ void RenderFrame();
+
+ bool SetupTexturemaps();
+
+ void SetupScene();
+ void AddCubeToScene( Matrix4 mat, std::vector<float> &vertdata );
+ void AddCubeVertex( float fl0, float fl1, float fl2, float fl3, float fl4, std::vector<float> &vertdata );
+
+ void RenderControllerAxes();
+
+ bool SetupStereoRenderTargets();
+ void SetupCompanionWindow();
+ void SetupCameras();
+
+ void RenderStereoTargets();
+ void RenderCompanionWindow();
+ void RenderScene( vr::Hmd_Eye nEye );
+
+ Matrix4 GetHMDMatrixProjectionEye( vr::Hmd_Eye nEye );
+ Matrix4 GetHMDMatrixPoseEye( vr::Hmd_Eye nEye );
+ Matrix4 GetCurrentViewProjectionMatrix( vr::Hmd_Eye nEye );
+ void UpdateHMDMatrixPose();
+
+ Matrix4 ConvertSteamVRMatrixToMatrix4( const vr::HmdMatrix34_t &matPose );
+
+ GLuint CompileGLShader( const char *pchShaderName, const char *pchVertexShader, const char *pchFragmentShader );
+ bool CreateAllShaders();
+
+ CGLRenderModel *FindOrLoadRenderModel( const char *pchRenderModelName );
+
+private:
+ bool m_bDebugOpenGL;
+ bool m_bVerbose;
+ bool m_bPerf;
+ bool m_bVblank;
+ bool m_bGlFinishHack;
+
+ vr::IVRSystem *m_pHMD;
+ std::string m_strDriver;
+ std::string m_strDisplay;
+ vr::TrackedDevicePose_t m_rTrackedDevicePose[ vr::k_unMaxTrackedDeviceCount ];
+ Matrix4 m_rmat4DevicePose[ vr::k_unMaxTrackedDeviceCount ];
+
+ struct ControllerInfo_t
+ {
+ vr::VRInputValueHandle_t m_source = vr::k_ulInvalidInputValueHandle;
+ vr::VRActionHandle_t m_actionPose = vr::k_ulInvalidActionHandle;
+ vr::VRActionHandle_t m_actionHaptic = vr::k_ulInvalidActionHandle;
+ Matrix4 m_rmat4Pose;
+ CGLRenderModel *m_pRenderModel = nullptr;
+ std::string m_sRenderModelName;
+ bool m_bShowController;
+ };
+
+ enum EHand
+ {
+ Left = 0,
+ Right = 1,
+ };
+ ControllerInfo_t m_rHand[2];
+
+private: // SDL bookkeeping
+ SDL_Window *m_pCompanionWindow;
+ uint32_t m_nCompanionWindowWidth;
+ uint32_t m_nCompanionWindowHeight;
+
+ SDL_GLContext m_pContext;
+
+private: // OpenGL bookkeeping
+ int m_iTrackedControllerCount;
+ int m_iTrackedControllerCount_Last;
+ int m_iValidPoseCount;
+ int m_iValidPoseCount_Last;
+ bool m_bShowCubes;
+ Vector2 m_vAnalogValue;
+
+ std::string m_strPoseClasses; // what classes we saw poses for this frame
+ char m_rDevClassChar[ vr::k_unMaxTrackedDeviceCount ]; // for each device, a character representing its class
+
+ int m_iSceneVolumeWidth;
+ int m_iSceneVolumeHeight;
+ int m_iSceneVolumeDepth;
+ float m_fScaleSpacing;
+ float m_fScale;
+
+ int m_iSceneVolumeInit; // if you want something other than the default 20x20x20
+
+ float m_fNearClip;
+ float m_fFarClip;
+
+ GLuint m_iTexture;
+
+ unsigned int m_uiVertcount;
+
+ GLuint m_glSceneVertBuffer;
+ GLuint m_unSceneVAO;
+ GLuint m_unCompanionWindowVAO;
+ GLuint m_glCompanionWindowIDVertBuffer;
+ GLuint m_glCompanionWindowIDIndexBuffer;
+ unsigned int m_uiCompanionWindowIndexSize;
+
+ GLuint m_glControllerVertBuffer;
+ GLuint m_unControllerVAO;
+ unsigned int m_uiControllerVertcount;
+
+ Matrix4 m_mat4HMDPose;
+ Matrix4 m_mat4eyePosLeft;
+ Matrix4 m_mat4eyePosRight;
+
+ Matrix4 m_resetPos;
+
+ Matrix4 m_mat4ProjectionCenter;
+ Matrix4 m_mat4ProjectionLeft;
+ Matrix4 m_mat4ProjectionRight;
+
+ struct VertexDataScene
+ {
+ Vector3 position;
+ Vector2 texCoord;
+ };
+
+ struct VertexDataWindow
+ {
+ Vector2 position;
+ Vector2 texCoord;
+
+ VertexDataWindow( const Vector2 & pos, const Vector2 tex ) : position(pos), texCoord(tex) { }
+ };
+
+ GLuint m_unSceneProgramID;
+ GLuint m_unCompanionWindowProgramID;
+ GLuint m_unControllerTransformProgramID;
+ GLuint m_unRenderModelProgramID;
+
+ GLint m_nSceneMatrixLocation;
+ GLint m_nControllerMatrixLocation;
+ GLint m_nRenderModelMatrixLocation;
+
+ struct FramebufferDesc
+ {
+ GLuint m_nDepthBufferId;
+ GLuint m_nRenderTextureId;
+ GLuint m_nRenderFramebufferId;
+ GLuint m_nResolveTextureId;
+ GLuint m_nResolveFramebufferId;
+ };
+ FramebufferDesc leftEyeDesc;
+ FramebufferDesc rightEyeDesc;
+
+ bool CreateFrameBuffer( int nWidth, int nHeight, FramebufferDesc &framebufferDesc );
+
+ uint32_t m_nRenderWidth;
+ uint32_t m_nRenderHeight;
+
+ std::vector< CGLRenderModel * > m_vecRenderModels;
+
+ vr::VRActionHandle_t m_actionHideCubes = vr::k_ulInvalidActionHandle;
+ vr::VRActionHandle_t m_actionHideThisController = vr::k_ulInvalidActionHandle;
+ vr::VRActionHandle_t m_actionTriggerHaptic = vr::k_ulInvalidActionHandle;
+ vr::VRActionHandle_t m_actionAnalongInput = vr::k_ulInvalidActionHandle;
+
+ vr::VRActionSetHandle_t m_actionsetDemo = vr::k_ulInvalidActionSetHandle;
+
+private: // X compositor
+ Display *x_display = nullptr;
+ Window src_window_id;
+ Pixmap src_window_pixmap;
+ GLXFBConfig *configs;
+ GLXPixmap glxpixmap;
+};
+
+
+//---------------------------------------------------------------------------------------------------------------------
+// Purpose: Returns true if the action is active and had a rising edge
+//---------------------------------------------------------------------------------------------------------------------
+bool GetDigitalActionRisingEdge(vr::VRActionHandle_t action, vr::VRInputValueHandle_t *pDevicePath = nullptr )
+{
+ vr::InputDigitalActionData_t actionData;
+ vr::VRInput()->GetDigitalActionData(action, &actionData, sizeof(actionData), vr::k_ulInvalidInputValueHandle );
+ if (pDevicePath)
+ {
+ *pDevicePath = vr::k_ulInvalidInputValueHandle;
+ if (actionData.bActive)
+ {
+ vr::InputOriginInfo_t originInfo;
+ if (vr::VRInputError_None == vr::VRInput()->GetOriginTrackedDeviceInfo(actionData.activeOrigin, &originInfo, sizeof(originInfo)))
+ {
+ *pDevicePath = originInfo.devicePath;
+ }
+ }
+ }
+ return actionData.bActive && actionData.bChanged && actionData.bState;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------
+// Purpose: Returns true if the action is active and had a falling edge
+//---------------------------------------------------------------------------------------------------------------------
+bool GetDigitalActionFallingEdge(vr::VRActionHandle_t action, vr::VRInputValueHandle_t *pDevicePath = nullptr )
+{
+ vr::InputDigitalActionData_t actionData;
+ vr::VRInput()->GetDigitalActionData(action, &actionData, sizeof(actionData), vr::k_ulInvalidInputValueHandle );
+ if (pDevicePath)
+ {
+ *pDevicePath = vr::k_ulInvalidInputValueHandle;
+ if (actionData.bActive)
+ {
+ vr::InputOriginInfo_t originInfo;
+ if (vr::VRInputError_None == vr::VRInput()->GetOriginTrackedDeviceInfo(actionData.activeOrigin, &originInfo, sizeof(originInfo)))
+ {
+ *pDevicePath = originInfo.devicePath;
+ }
+ }
+ }
+ return actionData.bActive && actionData.bChanged && !actionData.bState;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------
+// Purpose: Returns true if the action is active and its state is true
+//---------------------------------------------------------------------------------------------------------------------
+bool GetDigitalActionState(vr::VRActionHandle_t action, vr::VRInputValueHandle_t *pDevicePath = nullptr )
+{
+ vr::InputDigitalActionData_t actionData;
+ vr::VRInput()->GetDigitalActionData(action, &actionData, sizeof(actionData), vr::k_ulInvalidInputValueHandle );
+ if (pDevicePath)
+ {
+ *pDevicePath = vr::k_ulInvalidInputValueHandle;
+ if (actionData.bActive)
+ {
+ vr::InputOriginInfo_t originInfo;
+ if (vr::VRInputError_None == vr::VRInput()->GetOriginTrackedDeviceInfo(actionData.activeOrigin, &originInfo, sizeof(originInfo)))
+ {
+ *pDevicePath = originInfo.devicePath;
+ }
+ }
+ }
+ return actionData.bActive && actionData.bState;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Outputs a set of optional arguments to debugging output, using
+// the printf format setting specified in fmt*.
+//-----------------------------------------------------------------------------
+void dprintf( const char *fmt, ... )
+{
+ va_list args;
+ char buffer[ 2048 ];
+
+ va_start( args, fmt );
+ vsnprintf( buffer, sizeof(buffer), fmt, args );
+ va_end( args );
+
+ if ( g_bPrintf )
+ printf( "%s", buffer );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CMainApplication::CMainApplication( int argc, char *argv[] )
+ : m_pCompanionWindow(NULL)
+ , m_pContext(NULL)
+ , m_nCompanionWindowWidth( 1920 )
+ , m_nCompanionWindowHeight( 1080 )
+ , m_unSceneProgramID( 0 )
+ , m_unCompanionWindowProgramID( 0 )
+ , m_unControllerTransformProgramID( 0 )
+ , m_unRenderModelProgramID( 0 )
+ , m_pHMD( NULL )
+ , m_bDebugOpenGL( false )
+ , m_bVerbose( false )
+ , m_bPerf( false )
+ , m_bVblank( false )
+ , m_bGlFinishHack( true )
+ , m_glControllerVertBuffer( 0 )
+ , m_unControllerVAO( 0 )
+ , m_unSceneVAO( 0 )
+ , m_nSceneMatrixLocation( -1 )
+ , m_nControllerMatrixLocation( -1 )
+ , m_nRenderModelMatrixLocation( -1 )
+ , m_iTrackedControllerCount( 0 )
+ , m_iTrackedControllerCount_Last( -1 )
+ , m_iValidPoseCount( 0 )
+ , m_iValidPoseCount_Last( -1 )
+ , m_iSceneVolumeInit( 10 )
+ , m_strPoseClasses("")
+ , m_bShowCubes( true )
+{
+ if(argc < 2) {
+ fprintf(stderr, "usage: vr_window_manager [window_id]\n");
+ exit(1);
+ }
+
+ src_window_id = strtol(argv[1], nullptr, 0);
+ printf("src window id: %d\n", src_window_id);
+
+#if 0
+ for( int i = 1; i < argc; i++ )
+ {
+ if( !strcmp( argv[i], "-gldebug" ) )
+ {
+ m_bDebugOpenGL = true;
+ }
+ else if( !strcmp( argv[i], "-verbose" ) )
+ {
+ m_bVerbose = true;
+ }
+ else if( !strcmp( argv[i], "-novblank" ) )
+ {
+ m_bVblank = false;
+ }
+ else if( !strcmp( argv[i], "-noglfinishhack" ) )
+ {
+ m_bGlFinishHack = false;
+ }
+ else if( !strcmp( argv[i], "-noprintf" ) )
+ {
+ g_bPrintf = false;
+ }
+ else if ( !strcmp( argv[i], "-cubevolume" ) && ( argc > i + 1 ) && ( *argv[ i + 1 ] != '-' ) )
+ {
+ m_iSceneVolumeInit = atoi( argv[ i + 1 ] );
+ i++;
+ }
+ }
+#endif
+ // other initialization tasks are done in BInit
+ memset(m_rDevClassChar, 0, sizeof(m_rDevClassChar));
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CMainApplication::~CMainApplication()
+{
+ // work is done in Shutdown
+ dprintf( "Shutdown" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper to get a string from a tracked device property and turn it
+// into a std::string
+//-----------------------------------------------------------------------------
+std::string GetTrackedDeviceString( vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL )
+{
+ uint32_t unRequiredBufferLen = vr::VRSystem()->GetStringTrackedDeviceProperty( unDevice, prop, NULL, 0, peError );
+ if( unRequiredBufferLen == 0 )
+ return "";
+
+ char *pchBuffer = new char[ unRequiredBufferLen ];
+ unRequiredBufferLen = vr::VRSystem()->GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
+ std::string sResult = pchBuffer;
+ delete [] pchBuffer;
+ return sResult;
+}
+
+static bool x11_supports_composite_named_window_pixmap(Display *dpy)
+{
+ int extension_major;
+ int extension_minor;
+ if(!XCompositeQueryExtension(dpy, &extension_major, &extension_minor))
+ return false;
+
+ int major_version;
+ int minor_version;
+ return XCompositeQueryVersion(dpy, &major_version, &minor_version) && (major_version > 0 || minor_version >= 2);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CMainApplication::BInit()
+{
+ x_display = XOpenDisplay(nullptr);
+ if (!x_display)
+ {
+ printf("Failed to open x display\n");
+ return false;
+ }
+
+ bool has_name_pixmap = x11_supports_composite_named_window_pixmap(x_display);
+ if(!has_name_pixmap)
+ {
+ fprintf(stderr, "Error: XComposite name pixmap is not supported by your X11 server\n");
+ return false;
+ }
+
+ int screen_count = ScreenCount(x_display);
+ for(int i = 0; i < screen_count; ++i)
+ {
+ XCompositeRedirectSubwindows(x_display, RootWindow(x_display, i), CompositeRedirectAutomatic);
+ }
+
+ if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 )
+ {
+ printf("%s - SDL could not initialize! SDL Error: %s\n", __FUNCTION__, SDL_GetError());
+ return false;
+ }
+
+ // Loading the SteamVR Runtime
+ vr::EVRInitError eError = vr::VRInitError_None;
+ m_pHMD = vr::VR_Init( &eError, vr::VRApplication_Scene );
+
+ if ( eError != vr::VRInitError_None )
+ {
+ m_pHMD = NULL;
+ char buf[1024];
+ snprintf( buf, sizeof( buf ), "Unable to init VR runtime: %s", vr::VR_GetVRInitErrorAsEnglishDescription( eError ) );
+ SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "VR_Init Failed", buf, NULL );
+ return false;
+ }
+
+
+ int nWindowPosX = 700;
+ int nWindowPosY = 100;
+ Uint32 unWindowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
+
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 4 );
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 );
+ //SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY );
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
+
+ SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 0 );
+ SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 0 );
+ if( m_bDebugOpenGL )
+ SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG );
+
+ m_pCompanionWindow = SDL_CreateWindow( "hellovr", nWindowPosX, nWindowPosY, m_nCompanionWindowWidth, m_nCompanionWindowHeight, unWindowFlags );
+ if (m_pCompanionWindow == NULL)
+ {
+ printf( "%s - Window could not be created! SDL Error: %s\n", __FUNCTION__, SDL_GetError() );
+ return false;
+ }
+
+ m_pContext = SDL_GL_CreateContext(m_pCompanionWindow);
+ if (m_pContext == NULL)
+ {
+ printf( "%s - OpenGL context could not be created! SDL Error: %s\n", __FUNCTION__, SDL_GetError() );
+ return false;
+ }
+
+ glewExperimental = GL_TRUE;
+ GLenum nGlewError = glewInit();
+ if (nGlewError != GLEW_OK)
+ {
+ printf( "%s - Error initializing GLEW! %s\n", __FUNCTION__, glewGetErrorString( nGlewError ) );
+ return false;
+ }
+ glGetError(); // to clear the error caused deep in GLEW
+
+ if ( SDL_GL_SetSwapInterval( m_bVblank ? 1 : 0 ) < 0 )
+ {
+ printf( "%s - Warning: Unable to set VSync! SDL Error: %s\n", __FUNCTION__, SDL_GetError() );
+ return false;
+ }
+
+
+ m_strDriver = "No Driver";
+ m_strDisplay = "No Display";
+
+ m_strDriver = GetTrackedDeviceString( vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_TrackingSystemName_String );
+ m_strDisplay = GetTrackedDeviceString( vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SerialNumber_String );
+
+ std::string strWindowTitle = "hellovr - " + m_strDriver + " " + m_strDisplay;
+ SDL_SetWindowTitle( m_pCompanionWindow, strWindowTitle.c_str() );
+
+ // cube array
+ m_iSceneVolumeWidth = m_iSceneVolumeInit;
+ m_iSceneVolumeHeight = m_iSceneVolumeInit;
+ m_iSceneVolumeDepth = m_iSceneVolumeInit;
+
+ m_fScale = 1.0f;
+ m_fScaleSpacing = 2.0f;
+
+ m_fNearClip = 0.1f;
+ m_fFarClip = 30.0f;
+
+ m_iTexture = 0;
+ m_uiVertcount = 0;
+
+// m_MillisecondsTimer.start(1, this);
+// m_SecondsTimer.start(1000, this);
+
+ if (!BInitGL())
+ {
+ printf("%s - Unable to initialize OpenGL!\n", __FUNCTION__);
+ return false;
+ }
+
+ if (!BInitCompositor())
+ {
+ printf("%s - Failed to initialize VR Compositor!\n", __FUNCTION__);
+ return false;
+ }
+
+ //char cwd[4096];
+ //getcwd(cwd, sizeof(cwd));
+ //dirname(cwd);
+
+ vr::VRInput()->SetActionManifestPath("../config/hellovr_actions.json");
+
+ vr::VRInput()->GetActionHandle( "/actions/demo/in/HideCubes", &m_actionHideCubes );
+ vr::VRInput()->GetActionHandle( "/actions/demo/in/HideThisController", &m_actionHideThisController);
+ vr::VRInput()->GetActionHandle( "/actions/demo/in/TriggerHaptic", &m_actionTriggerHaptic );
+ vr::VRInput()->GetActionHandle( "/actions/demo/in/AnalogInput", &m_actionAnalongInput );
+
+ vr::VRInput()->GetActionSetHandle( "/actions/demo", &m_actionsetDemo );
+
+ vr::VRInput()->GetActionHandle( "/actions/demo/out/Haptic_Left", &m_rHand[Left].m_actionHaptic );
+ vr::VRInput()->GetInputSourceHandle( "/user/hand/left", &m_rHand[Left].m_source );
+ vr::VRInput()->GetActionHandle( "/actions/demo/in/Hand_Left", &m_rHand[Left].m_actionPose );
+
+ vr::VRInput()->GetActionHandle( "/actions/demo/out/Haptic_Right", &m_rHand[Right].m_actionHaptic );
+ vr::VRInput()->GetInputSourceHandle( "/user/hand/right", &m_rHand[Right].m_source );
+ vr::VRInput()->GetActionHandle( "/actions/demo/in/Hand_Right", &m_rHand[Right].m_actionPose );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Outputs the string in message to debugging output.
+// All other parameters are ignored.
+// Does not return any meaningful value or reference.
+//-----------------------------------------------------------------------------
+void DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam)
+{
+ dprintf( "GL Error: %s\n", message );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize OpenGL. Returns true if OpenGL has been successfully
+// initialized, false if shaders could not be created.
+// If failure occurred in a module other than shaders, the function
+// may return true or throw an error.
+//-----------------------------------------------------------------------------
+bool CMainApplication::BInitGL()
+{
+ if( m_bDebugOpenGL )
+ {
+ glDebugMessageCallback( (GLDEBUGPROC)DebugCallback, nullptr);
+ glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE );
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+ }
+
+ if( !CreateAllShaders() )
+ return false;
+
+ if(!SetupTexturemaps())
+ return false;
+ SetupScene();
+ SetupCameras();
+ if(!SetupStereoRenderTargets())
+ return false;
+ SetupCompanionWindow();
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize Compositor. Returns true if the compositor was
+// successfully initialized, false otherwise.
+//-----------------------------------------------------------------------------
+bool CMainApplication::BInitCompositor()
+{
+ vr::EVRInitError peError = vr::VRInitError_None;
+
+ if ( !vr::VRCompositor() )
+ {
+ printf( "Compositor initialization failed. See log file for details\n" );
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::Shutdown()
+{
+ if( m_pHMD )
+ {
+ vr::VR_Shutdown();
+ m_pHMD = NULL;
+ }
+
+ for( std::vector< CGLRenderModel * >::iterator i = m_vecRenderModels.begin(); i != m_vecRenderModels.end(); i++ )
+ {
+ delete (*i);
+ }
+ m_vecRenderModels.clear();
+
+ if( m_pContext )
+ {
+ if( m_bDebugOpenGL )
+ {
+ glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_FALSE );
+ glDebugMessageCallback(nullptr, nullptr);
+ }
+ glDeleteBuffers(1, &m_glSceneVertBuffer);
+
+ if ( m_unSceneProgramID )
+ {
+ glDeleteProgram( m_unSceneProgramID );
+ }
+ if ( m_unControllerTransformProgramID )
+ {
+ glDeleteProgram( m_unControllerTransformProgramID );
+ }
+ if ( m_unRenderModelProgramID )
+ {
+ glDeleteProgram( m_unRenderModelProgramID );
+ }
+ if ( m_unCompanionWindowProgramID )
+ {
+ glDeleteProgram( m_unCompanionWindowProgramID );
+ }
+
+ glDeleteRenderbuffers( 1, &leftEyeDesc.m_nDepthBufferId );
+ glDeleteTextures( 1, &leftEyeDesc.m_nRenderTextureId );
+ glDeleteFramebuffers( 1, &leftEyeDesc.m_nRenderFramebufferId );
+ glDeleteTextures( 1, &leftEyeDesc.m_nResolveTextureId );
+ glDeleteFramebuffers( 1, &leftEyeDesc.m_nResolveFramebufferId );
+
+ glDeleteRenderbuffers( 1, &rightEyeDesc.m_nDepthBufferId );
+ glDeleteTextures( 1, &rightEyeDesc.m_nRenderTextureId );
+ glDeleteFramebuffers( 1, &rightEyeDesc.m_nRenderFramebufferId );
+ glDeleteTextures( 1, &rightEyeDesc.m_nResolveTextureId );
+ glDeleteFramebuffers( 1, &rightEyeDesc.m_nResolveFramebufferId );
+
+ if( m_unCompanionWindowVAO != 0 )
+ {
+ glDeleteVertexArrays( 1, &m_unCompanionWindowVAO );
+ }
+ if( m_unSceneVAO != 0 )
+ {
+ glDeleteVertexArrays( 1, &m_unSceneVAO );
+ }
+ if( m_unControllerVAO != 0 )
+ {
+ glDeleteVertexArrays( 1, &m_unControllerVAO );
+ }
+ }
+
+ if( m_pCompanionWindow )
+ {
+ SDL_DestroyWindow(m_pCompanionWindow);
+ m_pCompanionWindow = NULL;
+ }
+
+ SDL_Quit();
+
+ if (x_display) {
+ glXReleaseTexImageEXT(x_display, glxpixmap, GLX_FRONT_EXT);
+ glXDestroyPixmap(x_display, glxpixmap);
+ XFree(configs);
+ XFreePixmap(x_display, src_window_pixmap);
+ XCloseDisplay(x_display);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CMainApplication::HandleInput()
+{
+ SDL_Event sdlEvent;
+ bool bRet = false;
+
+ while ( SDL_PollEvent( &sdlEvent ) != 0 )
+ {
+ if ( sdlEvent.type == SDL_QUIT )
+ {
+ bRet = true;
+ }
+ else if ( sdlEvent.type == SDL_KEYDOWN )
+ {
+ if ( sdlEvent.key.keysym.sym == SDLK_ESCAPE
+ || sdlEvent.key.keysym.sym == SDLK_q )
+ {
+ bRet = true;
+ }
+ if( sdlEvent.key.keysym.sym == SDLK_c )
+ {
+ m_bShowCubes = !m_bShowCubes;
+ }
+ }
+ }
+
+ XEvent x_event;
+
+#if 0
+ if(XCheckTypedWindowEvent(x_display, src_window_id, damage_event + XDamageNotify, &x_event)) {
+ }
+#endif
+
+
+
+ // Process SteamVR events
+ vr::VREvent_t event;
+ while( m_pHMD->PollNextEvent( &event, sizeof( event ) ) )
+ {
+ ProcessVREvent( event );
+ }
+
+ // Process SteamVR action state
+ // UpdateActionState is called each frame to update the state of the actions themselves. The application
+ // controls which action sets are active with the provided array of VRActiveActionSet_t structs.
+ vr::VRActiveActionSet_t actionSet = { 0 };
+ actionSet.ulActionSet = m_actionsetDemo;
+ vr::VRInput()->UpdateActionState( &actionSet, sizeof(actionSet), 1 );
+
+ m_bShowCubes = !GetDigitalActionState( m_actionHideCubes );
+ if(GetDigitalActionState( m_actionHideCubes )) {
+ printf("reset position!\n");
+ //m_resetPos = m_mat4HMDPose;
+ }
+
+ vr::VRInputValueHandle_t ulHapticDevice;
+ if ( GetDigitalActionRisingEdge( m_actionTriggerHaptic, &ulHapticDevice ) )
+ {
+ if ( ulHapticDevice == m_rHand[Left].m_source )
+ {
+ vr::VRInput()->TriggerHapticVibrationAction( m_rHand[Left].m_actionHaptic, 0, 1, 4.f, 1.0f, vr::k_ulInvalidInputValueHandle );
+ }
+ if ( ulHapticDevice == m_rHand[Right].m_source )
+ {
+ vr::VRInput()->TriggerHapticVibrationAction( m_rHand[Right].m_actionHaptic, 0, 1, 4.f, 1.0f, vr::k_ulInvalidInputValueHandle );
+ }
+ }
+
+ vr::InputAnalogActionData_t analogData;
+ if ( vr::VRInput()->GetAnalogActionData( m_actionAnalongInput, &analogData, sizeof( analogData ), vr::k_ulInvalidInputValueHandle ) == vr::VRInputError_None && analogData.bActive )
+ {
+ m_vAnalogValue[0] = analogData.x;
+ m_vAnalogValue[1] = analogData.y;
+ }
+
+ m_rHand[Left].m_bShowController = true;
+ m_rHand[Right].m_bShowController = true;
+
+ vr::VRInputValueHandle_t ulHideDevice;
+ if ( GetDigitalActionState( m_actionHideThisController, &ulHideDevice ) )
+ {
+ if ( ulHideDevice == m_rHand[Left].m_source )
+ {
+ m_rHand[Left].m_bShowController = false;
+ }
+ if ( ulHideDevice == m_rHand[Right].m_source )
+ {
+ m_rHand[Right].m_bShowController = false;
+ }
+ }
+
+ for ( EHand eHand = Left; eHand <= Right; ((int&)eHand)++ )
+ {
+ vr::InputPoseActionData_t poseData;
+ if ( vr::VRInput()->GetPoseActionDataForNextFrame( m_rHand[eHand].m_actionPose, vr::TrackingUniverseStanding, &poseData, sizeof( poseData ), vr::k_ulInvalidInputValueHandle ) != vr::VRInputError_None
+ || !poseData.bActive || !poseData.pose.bPoseIsValid )
+ {
+ m_rHand[eHand].m_bShowController = false;
+ }
+ else
+ {
+ m_rHand[eHand].m_rmat4Pose = ConvertSteamVRMatrixToMatrix4( poseData.pose.mDeviceToAbsoluteTracking );
+
+ vr::InputOriginInfo_t originInfo;
+ if ( vr::VRInput()->GetOriginTrackedDeviceInfo( poseData.activeOrigin, &originInfo, sizeof( originInfo ) ) == vr::VRInputError_None
+ && originInfo.trackedDeviceIndex != vr::k_unTrackedDeviceIndexInvalid )
+ {
+ std::string sRenderModelName = GetTrackedDeviceString( originInfo.trackedDeviceIndex, vr::Prop_RenderModelName_String );
+ if ( sRenderModelName != m_rHand[eHand].m_sRenderModelName )
+ {
+ m_rHand[eHand].m_pRenderModel = FindOrLoadRenderModel( sRenderModelName.c_str() );
+ m_rHand[eHand].m_sRenderModelName = sRenderModelName;
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::RunMainLoop()
+{
+ bool bQuit = false;
+
+ SDL_StartTextInput();
+ SDL_ShowCursor( SDL_DISABLE );
+
+ while ( !bQuit )
+ {
+ bQuit = HandleInput();
+
+ RenderFrame();
+ }
+
+ SDL_StopTextInput();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Processes a single VR event
+//-----------------------------------------------------------------------------
+void CMainApplication::ProcessVREvent( const vr::VREvent_t & event )
+{
+ switch( event.eventType )
+ {
+ case vr::VREvent_TrackedDeviceDeactivated:
+ {
+ dprintf( "Device %u detached.\n", event.trackedDeviceIndex );
+ }
+ break;
+ case vr::VREvent_TrackedDeviceUpdated:
+ {
+ dprintf( "Device %u updated.\n", event.trackedDeviceIndex );
+ }
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::RenderFrame()
+{
+ // for now as fast as possible
+ if ( m_pHMD )
+ {
+ RenderControllerAxes();
+ RenderStereoTargets();
+ RenderCompanionWindow();
+
+ vr::Texture_t leftEyeTexture = {(void*)(uintptr_t)leftEyeDesc.m_nResolveTextureId, vr::TextureType_OpenGL, vr::ColorSpace_Gamma };
+ vr::VRCompositor()->Submit(vr::Eye_Left, &leftEyeTexture );
+ vr::Texture_t rightEyeTexture = {(void*)(uintptr_t)rightEyeDesc.m_nResolveTextureId, vr::TextureType_OpenGL, vr::ColorSpace_Gamma };
+ vr::VRCompositor()->Submit(vr::Eye_Right, &rightEyeTexture );
+ }
+
+ if ( m_bVblank && m_bGlFinishHack )
+ {
+ //$ HACKHACK. From gpuview profiling, it looks like there is a bug where two renders and a present
+ // happen right before and after the vsync causing all kinds of jittering issues. This glFinish()
+ // appears to clear that up. Temporary fix while I try to get nvidia to investigate this problem.
+ // 1/29/2014 mikesart
+ glFinish();
+ }
+
+ // SwapWindow
+ {
+ SDL_GL_SwapWindow( m_pCompanionWindow );
+ }
+
+ // Clear
+ {
+ // We want to make sure the glFinish waits for the entire present to complete, not just the submission
+ // of the command. So, we do a clear here right here so the glFinish will wait fully for the swap.
+ glClearColor( 0, 0, 0, 1 );
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ }
+
+ // Flush and wait for swap.
+ if ( m_bVblank )
+ {
+ glFlush();
+ glFinish();
+ }
+
+ // Spew out the controller and pose count whenever they change.
+ if ( m_iTrackedControllerCount != m_iTrackedControllerCount_Last || m_iValidPoseCount != m_iValidPoseCount_Last )
+ {
+ m_iValidPoseCount_Last = m_iValidPoseCount;
+ m_iTrackedControllerCount_Last = m_iTrackedControllerCount;
+
+ dprintf( "PoseCount:%d(%s) Controllers:%d\n", m_iValidPoseCount, m_strPoseClasses.c_str(), m_iTrackedControllerCount );
+ }
+
+ UpdateHMDMatrixPose();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Compiles a GL shader program and returns the handle. Returns 0 if
+// the shader couldn't be compiled for some reason.
+//-----------------------------------------------------------------------------
+GLuint CMainApplication::CompileGLShader( const char *pchShaderName, const char *pchVertexShader, const char *pchFragmentShader )
+{
+ GLuint unProgramID = glCreateProgram();
+
+ GLuint nSceneVertexShader = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource( nSceneVertexShader, 1, &pchVertexShader, NULL);
+ glCompileShader( nSceneVertexShader );
+
+ GLint vShaderCompiled = GL_FALSE;
+ glGetShaderiv( nSceneVertexShader, GL_COMPILE_STATUS, &vShaderCompiled);
+ if ( vShaderCompiled != GL_TRUE)
+ {
+ dprintf("%s - Unable to compile vertex shader %d!\n", pchShaderName, nSceneVertexShader);
+ glDeleteProgram( unProgramID );
+ glDeleteShader( nSceneVertexShader );
+ return 0;
+ }
+ glAttachShader( unProgramID, nSceneVertexShader);
+ glDeleteShader( nSceneVertexShader ); // the program hangs onto this once it's attached
+
+ GLuint nSceneFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource( nSceneFragmentShader, 1, &pchFragmentShader, NULL);
+ glCompileShader( nSceneFragmentShader );
+
+ GLint fShaderCompiled = GL_FALSE;
+ glGetShaderiv( nSceneFragmentShader, GL_COMPILE_STATUS, &fShaderCompiled);
+ if (fShaderCompiled != GL_TRUE)
+ {
+ dprintf("%s - Unable to compile fragment shader %d!\n", pchShaderName, nSceneFragmentShader );
+ glDeleteProgram( unProgramID );
+ glDeleteShader( nSceneFragmentShader );
+ return 0;
+ }
+
+ glAttachShader( unProgramID, nSceneFragmentShader );
+ glDeleteShader( nSceneFragmentShader ); // the program hangs onto this once it's attached
+
+ glLinkProgram( unProgramID );
+
+ GLint programSuccess = GL_TRUE;
+ glGetProgramiv( unProgramID, GL_LINK_STATUS, &programSuccess);
+ if ( programSuccess != GL_TRUE )
+ {
+ dprintf("%s - Error linking program %d!\n", pchShaderName, unProgramID);
+ glDeleteProgram( unProgramID );
+ return 0;
+ }
+
+ glUseProgram( unProgramID );
+ glUseProgram( 0 );
+
+ return unProgramID;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates all the shaders used by HelloVR SDL
+//-----------------------------------------------------------------------------
+bool CMainApplication::CreateAllShaders()
+{
+ m_unSceneProgramID = CompileGLShader(
+ "Scene",
+
+ // Vertex Shader
+ "#version 410\n"
+ "uniform mat4 matrix;\n"
+ "layout(location = 0) in vec4 position;\n"
+ "layout(location = 1) in vec2 v2UVcoordsIn;\n"
+ "layout(location = 2) in vec3 v3NormalIn;\n"
+ "out vec2 v2UVcoords;\n"
+ "void main()\n"
+ "{\n"
+ " v2UVcoords = v2UVcoordsIn;\n"
+ " gl_Position = matrix * position;\n"
+ "}\n",
+
+ // Fragment Shader
+ "#version 410 core\n"
+ "uniform sampler2D mytexture;\n"
+ "in vec2 v2UVcoords;\n"
+ "out vec4 outputColor;\n"
+ "void main()\n"
+ "{\n"
+ " vec4 col = texture(mytexture, v2UVcoords);\n"
+ " outputColor = col.rgba;\n"
+ "}\n"
+ );
+ m_nSceneMatrixLocation = glGetUniformLocation( m_unSceneProgramID, "matrix" );
+ if( m_nSceneMatrixLocation == -1 )
+ {
+ dprintf( "Unable to find matrix uniform in scene shader\n" );
+ return false;
+ }
+
+ m_unControllerTransformProgramID = CompileGLShader(
+ "Controller",
+
+ // vertex shader
+ "#version 410\n"
+ "uniform mat4 matrix;\n"
+ "layout(location = 0) in vec4 position;\n"
+ "layout(location = 1) in vec3 v3ColorIn;\n"
+ "out vec4 v4Color;\n"
+ "void main()\n"
+ "{\n"
+ " v4Color.xyz = v3ColorIn; v4Color.a = 1.0;\n"
+ " gl_Position = matrix * position;\n"
+ "}\n",
+
+ // fragment shader
+ "#version 410\n"
+ "in vec4 v4Color;\n"
+ "out vec4 outputColor;\n"
+ "void main()\n"
+ "{\n"
+ " outputColor = v4Color;\n"
+ "}\n"
+ );
+ m_nControllerMatrixLocation = glGetUniformLocation( m_unControllerTransformProgramID, "matrix" );
+ if( m_nControllerMatrixLocation == -1 )
+ {
+ dprintf( "Unable to find matrix uniform in controller shader\n" );
+ return false;
+ }
+
+ m_unRenderModelProgramID = CompileGLShader(
+ "render model",
+
+ // vertex shader
+ "#version 410\n"
+ "uniform mat4 matrix;\n"
+ "layout(location = 0) in vec4 position;\n"
+ "layout(location = 1) in vec3 v3NormalIn;\n"
+ "layout(location = 2) in vec2 v2TexCoordsIn;\n"
+ "out vec2 v2TexCoord;\n"
+ "void main()\n"
+ "{\n"
+ " v2TexCoord = v2TexCoordsIn;\n"
+ " gl_Position = matrix * vec4(position.xyz, 1);\n"
+ "}\n",
+
+ //fragment shader
+ "#version 410 core\n"
+ "uniform sampler2D diffuse;\n"
+ "in vec2 v2TexCoord;\n"
+ "out vec4 outputColor;\n"
+ "void main()\n"
+ "{\n"
+ " outputColor = texture( diffuse, v2TexCoord);\n"
+ "}\n"
+
+ );
+ m_nRenderModelMatrixLocation = glGetUniformLocation( m_unRenderModelProgramID, "matrix" );
+ if( m_nRenderModelMatrixLocation == -1 )
+ {
+ dprintf( "Unable to find matrix uniform in render model shader\n" );
+ return false;
+ }
+
+ m_unCompanionWindowProgramID = CompileGLShader(
+ "CompanionWindow",
+
+ // vertex shader
+ "#version 410 core\n"
+ "layout(location = 0) in vec4 position;\n"
+ "layout(location = 1) in vec2 v2UVIn;\n"
+ "noperspective out vec2 v2UV;\n"
+ "void main()\n"
+ "{\n"
+ " v2UV = vec2(v2UVIn.x, 1.0 - v2UVIn.y);\n"
+ " gl_Position = position;\n"
+ "}\n",
+
+ // fragment shader
+ "#version 410 core\n"
+ "uniform sampler2D mytexture;\n"
+ "noperspective in vec2 v2UV;\n"
+ "out vec4 outputColor;\n"
+ "void main()\n"
+ "{\n"
+ " vec4 col = texture(mytexture, v2UV);\n"
+ " outputColor = col.rgba;\n"
+ "}\n"
+ );
+
+ return m_unSceneProgramID != 0
+ && m_unControllerTransformProgramID != 0
+ && m_unRenderModelProgramID != 0
+ && m_unCompanionWindowProgramID != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CMainApplication::SetupTexturemaps()
+{
+ const int pixmap_config[] = {
+ GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+ //GLX_BIND_TO_MIPMAP_TEXTURE_EXT, True,
+ GLX_DOUBLEBUFFER, False,
+ GLX_Y_INVERTED_EXT, (int)GLX_DONT_CARE,
+ None
+ };
+
+ const int pixmap_attribs[] = {
+ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
+ None
+ };
+
+ int c;
+ configs = glXChooseFBConfig(x_display, 0, pixmap_config, &c);
+ if (!configs)
+ {
+ printf("Failed too choose fb config\n");
+ return false;
+ }
+
+ src_window_pixmap = XCompositeNameWindowPixmap(x_display, src_window_id);
+ if (!src_window_pixmap)
+ {
+ printf("Failed to get pixmap for window %ld\n", src_window_id);
+ return false;
+ }
+
+ glxpixmap = glXCreatePixmap(x_display, *configs, src_window_pixmap, pixmap_attribs);
+ if (!glxpixmap)
+ {
+ printf("Failed to create pixmap\n");
+ return false;
+ }
+
+
+ glGenTextures(1, &m_iTexture );
+ glBindTexture( GL_TEXTURE_2D, m_iTexture );
+
+ glXBindTexImageEXT(x_display, glxpixmap, GLX_FRONT_EXT, NULL);
+
+ //glGenerateMipmap(GL_TEXTURE_2D);
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*GL_LINEAR_MIPMAP_LINEAR*/ );
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ GLfloat fLargest;
+ glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
+
+ glBindTexture( GL_TEXTURE_2D, 0 );
+
+ return ( m_iTexture != 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: create a sea of cubes
+//-----------------------------------------------------------------------------
+void CMainApplication::SetupScene()
+{
+ if ( !m_pHMD )
+ return;
+
+ std::vector<float> vertdataarray;
+#if 0
+ Matrix4 matScale;
+ matScale.scale( m_fScale, m_fScale, m_fScale );
+ Matrix4 matTransform;
+ matTransform.translate(
+ -( (float)m_iSceneVolumeWidth * m_fScaleSpacing ) / 2.f,
+ -( (float)m_iSceneVolumeHeight * m_fScaleSpacing ) / 2.f,
+ -( (float)m_iSceneVolumeDepth * m_fScaleSpacing ) / 2.f);
+
+ Matrix4 mat = matScale * matTransform;
+
+ for( int z = 0; z< m_iSceneVolumeDepth; z++ )
+ {
+ for( int y = 0; y< m_iSceneVolumeHeight; y++ )
+ {
+ for( int x = 0; x< m_iSceneVolumeWidth; x++ )
+ {
+ AddCubeToScene( mat, vertdataarray );
+ mat = mat * Matrix4().translate( m_fScaleSpacing, 0, 0 );
+ }
+ mat = mat * Matrix4().translate( -((float)m_iSceneVolumeWidth) * m_fScaleSpacing, m_fScaleSpacing, 0 );
+ }
+ mat = mat * Matrix4().translate( 0, -((float)m_iSceneVolumeHeight) * m_fScaleSpacing, m_fScaleSpacing );
+ }
+#endif
+
+ Matrix4 matScale;
+ matScale.scale( m_fScale, m_fScale, m_fScale );
+ Matrix4 matTransform;
+ // matTransform.translate(
+ // -( (float)m_fScale ) * 2.f,
+ // -( (float)m_fScale) * 2.f,
+ // -( (float)m_fScale) * 1.0f);
+
+ Matrix4 mat = matScale * matTransform;
+ AddCubeToScene( mat, vertdataarray );
+
+ m_uiVertcount = vertdataarray.size()/5;
+
+ glGenVertexArrays( 1, &m_unSceneVAO );
+ glBindVertexArray( m_unSceneVAO );
+
+ glGenBuffers( 1, &m_glSceneVertBuffer );
+ glBindBuffer( GL_ARRAY_BUFFER, m_glSceneVertBuffer );
+ glBufferData( GL_ARRAY_BUFFER, sizeof(float) * vertdataarray.size(), &vertdataarray[0], GL_STATIC_DRAW);
+
+ GLsizei stride = sizeof(VertexDataScene);
+ uintptr_t offset = 0;
+
+ glEnableVertexAttribArray( 0 );
+ glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride , (const void *)offset);
+
+ offset += sizeof(Vector3);
+ glEnableVertexAttribArray( 1 );
+ glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, stride, (const void *)offset);
+
+ glBindVertexArray( 0 );
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::AddCubeVertex( float fl0, float fl1, float fl2, float fl3, float fl4, std::vector<float> &vertdata )
+{
+ vertdata.push_back( fl0 );
+ vertdata.push_back( fl1 );
+ vertdata.push_back( fl2 );
+ vertdata.push_back( fl3 );
+ vertdata.push_back( fl4 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::AddCubeToScene( Matrix4 mat, std::vector<float> &vertdata )
+{
+ // Matrix4 mat( outermat.data() );
+
+ Vector4 A = mat * Vector4( 0, 0, 0, 1 );
+ Vector4 B = mat * Vector4( 1, 0, 0, 1 );
+ Vector4 C = mat * Vector4( 1, 1, 0, 1 );
+ Vector4 D = mat * Vector4( 0, 1, 0, 1 );
+ Vector4 E = mat * Vector4( 0, 0, 1, 1 );
+ Vector4 F = mat * Vector4( 1, 0, 1, 1 );
+ Vector4 G = mat * Vector4( 1, 1, 1, 1 );
+ Vector4 H = mat * Vector4( 0, 1, 1, 1 );
+
+ // triangles instead of quads
+ // AddCubeVertex( E.x, E.y, E.z, 0, 1, vertdata ); //Front
+ // AddCubeVertex( F.x, F.y, F.z, 1, 1, vertdata );
+ // AddCubeVertex( G.x, G.y, G.z, 1, 0, vertdata );
+ // AddCubeVertex( G.x, G.y, G.z, 1, 0, vertdata );
+ // AddCubeVertex( H.x, H.y, H.z, 0, 0, vertdata );
+ // AddCubeVertex( E.x, E.y, E.z, 0, 1, vertdata );
+
+ AddCubeVertex( B.x, B.y, B.z, 0, 1, vertdata ); //Back
+ AddCubeVertex( A.x, A.y, A.z, 1, 1, vertdata );
+ AddCubeVertex( D.x, D.y, D.z, 1, 0, vertdata );
+ AddCubeVertex( D.x, D.y, D.z, 1, 0, vertdata );
+ AddCubeVertex( C.x, C.y, C.z, 0, 0, vertdata );
+ AddCubeVertex( B.x, B.y, B.z, 0, 1, vertdata );
+#if 0
+ long columns = 32;
+ long rows = 32;
+ double angle_x = 3.14;
+ double angle_y = 3.14;
+ double radius = 1.0;
+ double radius_depth = 1.0;
+
+ for(long row = 0; row < rows-1; ++row) {
+ for(long column = 0; column < columns-1; ++column) {
+ double z1 = sin((double)column / (double)columns * angle_x);
+ double z2 = sin((double)(column + 1) / (double)columns * angle_x);
+ double z3 = z1;
+
+ double z4 = z3;
+ double z5 = z2;
+ double z6 = z2;
+
+ double x1 = -cos((double)column / (double)columns * angle_x) ;
+ double x2 = -cos((double)(column + 1) / (double)columns * angle_x);
+ double x3 = x1;
+
+ double x4 = x3;
+ double x5 = x2;
+ double x6 = x2;
+
+ double y1 = cos((double)row / (double)rows * angle_y) * radius;
+ double y2 = y1;
+ double y3 = cos((double)(row + 1) / (double)rows * angle_y) * radius;
+
+ double y4 = y3;
+ double y5 = y3;
+ double y6 = y1;
+
+ z1 *= sin((double)row / (double)rows * angle_y) * radius_depth;
+ z2 *= sin((double)row / (double)rows * angle_y) * radius_depth;
+ z3 *= sin((double)(row + 1) / (double)rows * angle_y) * radius_depth;
+ z4 *= sin((double)(row + 1) / (double)rows * angle_y) * radius_depth;
+ z5 *= sin((double)(row + 1) / (double)rows * angle_y) * radius_depth;
+ z6 *= sin((double)row / (double)rows * angle_y) * radius_depth;
+
+ x1 *= sin((double)row / (double)rows * angle_y) * radius_depth;
+ x2 *= sin((double)row / (double)rows * angle_y) * radius_depth;
+ x3 *= sin((double)(row + 1) / (double)rows * angle_y) * radius_depth;
+ x4 *= sin((double)(row + 1) / (double)rows * angle_y) * radius_depth;
+ x5 *= sin((double)(row + 1) / (double)rows * angle_y) * radius_depth;
+ x6 *= sin((double)row / (double)rows * angle_y) * radius_depth;
+
+ Vector4 v1 = mat * Vector4(x1, y1, z1, 1.0);
+ Vector4 v2 = mat * Vector4(x2, y2, z2, 1.0);
+ Vector4 v3 = mat * Vector4(x3, y3, z3, 1.0);
+ Vector4 v4 = mat * Vector4(x4, y4, z4, 1.0);
+ Vector4 v5 = mat * Vector4(x5, y5, z5, 1.0);
+ Vector4 v6 = mat * Vector4(x6, y6, z6, 1.0);
+
+ AddCubeVertex(v1.x, v1.y, v1.z, 1.0 - (double)column / (double)columns, (double)row / (double)rows, vertdata);
+ AddCubeVertex(v2.x, v2.y, v2.z, 1.0 - (double)(column + 1) / (double)columns, (double)row / (double)rows, vertdata);
+ AddCubeVertex(v3.x, v3.y, v3.z, 1.0 - (double)column / (double)columns, (double)(row + 1) / (double)rows, vertdata);
+
+ AddCubeVertex(v4.x, v4.y, v4.z, 1.0 - (double)column / (double)columns, (double)(row + 1) / (double)rows, vertdata);
+ AddCubeVertex(v5.x, v5.y, v5.z, 1.0 - (double)(column + 1) / (double)columns, (double)(row + 1) / (double)rows, vertdata);
+ AddCubeVertex(v6.x, v6.y, v6.z, 1.0 - (double)(column + 1) / (double)columns, (double)row / (double)rows, vertdata);
+ }
+ }
+#endif
+
+ // AddCubeVertex( H.x, H.y, H.z, 0, 1, vertdata ); //Top
+ // AddCubeVertex( G.x, G.y, G.z, 1, 1, vertdata );
+ // AddCubeVertex( C.x, C.y, C.z, 1, 0, vertdata );
+ // AddCubeVertex( C.x, C.y, C.z, 1, 0, vertdata );
+ // AddCubeVertex( D.x, D.y, D.z, 0, 0, vertdata );
+ // AddCubeVertex( H.x, H.y, H.z, 0, 1, vertdata );
+
+ // AddCubeVertex( A.x, A.y, A.z, 0, 1, vertdata ); //Bottom
+ // AddCubeVertex( B.x, B.y, B.z, 1, 1, vertdata );
+ // AddCubeVertex( F.x, F.y, F.z, 1, 0, vertdata );
+ // AddCubeVertex( F.x, F.y, F.z, 1, 0, vertdata );
+ // AddCubeVertex( E.x, E.y, E.z, 0, 0, vertdata );
+ // AddCubeVertex( A.x, A.y, A.z, 0, 1, vertdata );
+
+ // AddCubeVertex( A.x, A.y, A.z, 0, 1, vertdata ); //Left
+ // AddCubeVertex( E.x, E.y, E.z, 1, 1, vertdata );
+ // AddCubeVertex( H.x, H.y, H.z, 1, 0, vertdata );
+ // AddCubeVertex( H.x, H.y, H.z, 1, 0, vertdata );
+ // AddCubeVertex( D.x, D.y, D.z, 0, 0, vertdata );
+ // AddCubeVertex( A.x, A.y, A.z, 0, 1, vertdata );
+
+ // AddCubeVertex( F.x, F.y, F.z, 0, 1, vertdata ); //Right
+ // AddCubeVertex( B.x, B.y, B.z, 1, 1, vertdata );
+ // AddCubeVertex( C.x, C.y, C.z, 1, 0, vertdata );
+ // AddCubeVertex( C.x, C.y, C.z, 1, 0, vertdata );
+ // AddCubeVertex( G.x, G.y, G.z, 0, 0, vertdata );
+ // AddCubeVertex( F.x, F.y, F.z, 0, 1, vertdata );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw all of the controllers as X/Y/Z lines
+//-----------------------------------------------------------------------------
+void CMainApplication::RenderControllerAxes()
+{
+ // Don't attempt to update controllers if input is not available
+ if( !m_pHMD->IsInputAvailable() )
+ return;
+
+ std::vector<float> vertdataarray;
+
+ m_uiControllerVertcount = 0;
+ m_iTrackedControllerCount = 0;
+
+ for ( EHand eHand = Left; eHand <= Right; ((int&)eHand)++ )
+ {
+ if ( !m_rHand[eHand].m_bShowController )
+ continue;
+
+ const Matrix4 & mat = m_rHand[eHand].m_rmat4Pose;
+
+ Vector4 center = mat * Vector4( 0, 0, 0, 1 );
+
+ for ( int i = 0; i < 3; ++i )
+ {
+ Vector3 color( 0, 0, 0 );
+ Vector4 point( 0, 0, 0, 1 );
+ point[i] += 0.05f; // offset in X, Y, Z
+ color[i] = 1.0; // R, G, B
+ point = mat * point;
+ vertdataarray.push_back( center.x );
+ vertdataarray.push_back( center.y );
+ vertdataarray.push_back( center.z );
+
+ vertdataarray.push_back( color.x );
+ vertdataarray.push_back( color.y );
+ vertdataarray.push_back( color.z );
+
+ vertdataarray.push_back( point.x );
+ vertdataarray.push_back( point.y );
+ vertdataarray.push_back( point.z );
+
+ vertdataarray.push_back( color.x );
+ vertdataarray.push_back( color.y );
+ vertdataarray.push_back( color.z );
+
+ m_uiControllerVertcount += 2;
+ }
+
+ Vector4 start = mat * Vector4( 0, 0, -0.02f, 1 );
+ Vector4 end = mat * Vector4( 0, 0, -39.f, 1 );
+ Vector3 color( .92f, .92f, .71f );
+
+ vertdataarray.push_back( start.x );vertdataarray.push_back( start.y );vertdataarray.push_back( start.z );
+ vertdataarray.push_back( color.x );vertdataarray.push_back( color.y );vertdataarray.push_back( color.z );
+
+ vertdataarray.push_back( end.x );vertdataarray.push_back( end.y );vertdataarray.push_back( end.z );
+ vertdataarray.push_back( color.x );vertdataarray.push_back( color.y );vertdataarray.push_back( color.z );
+ m_uiControllerVertcount += 2;
+ }
+
+ // Setup the VAO the first time through.
+ if ( m_unControllerVAO == 0 )
+ {
+ glGenVertexArrays( 1, &m_unControllerVAO );
+ glBindVertexArray( m_unControllerVAO );
+
+ glGenBuffers( 1, &m_glControllerVertBuffer );
+ glBindBuffer( GL_ARRAY_BUFFER, m_glControllerVertBuffer );
+
+ GLuint stride = 2 * 3 * sizeof( float );
+ uintptr_t offset = 0;
+
+ glEnableVertexAttribArray( 0 );
+ glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (const void *)offset);
+
+ offset += sizeof( Vector3 );
+ glEnableVertexAttribArray( 1 );
+ glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, stride, (const void *)offset);
+
+ glBindVertexArray( 0 );
+ }
+
+ glBindBuffer( GL_ARRAY_BUFFER, m_glControllerVertBuffer );
+
+ // set vertex data if we have some
+ if( vertdataarray.size() > 0 )
+ {
+ //$ TODO: Use glBufferSubData for this...
+ glBufferData( GL_ARRAY_BUFFER, sizeof(float) * vertdataarray.size(), &vertdataarray[0], GL_STREAM_DRAW );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::SetupCameras()
+{
+ m_mat4ProjectionLeft = GetHMDMatrixProjectionEye( vr::Eye_Left );
+ m_mat4ProjectionRight = GetHMDMatrixProjectionEye( vr::Eye_Right );
+ m_mat4eyePosLeft = GetHMDMatrixPoseEye( vr::Eye_Left );
+ m_mat4eyePosRight = GetHMDMatrixPoseEye( vr::Eye_Right );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a frame buffer. Returns true if the buffer was set up.
+// Returns false if the setup failed.
+//-----------------------------------------------------------------------------
+bool CMainApplication::CreateFrameBuffer( int nWidth, int nHeight, FramebufferDesc &framebufferDesc )
+{
+ glGenFramebuffers(1, &framebufferDesc.m_nRenderFramebufferId );
+ glBindFramebuffer(GL_FRAMEBUFFER, framebufferDesc.m_nRenderFramebufferId);
+
+ glGenRenderbuffers(1, &framebufferDesc.m_nDepthBufferId);
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferDesc.m_nDepthBufferId);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT, nWidth, nHeight );
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, framebufferDesc.m_nDepthBufferId );
+
+ glGenTextures(1, &framebufferDesc.m_nRenderTextureId );
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, framebufferDesc.m_nRenderTextureId );
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, nWidth, nHeight, true);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, framebufferDesc.m_nRenderTextureId, 0);
+
+ glGenFramebuffers(1, &framebufferDesc.m_nResolveFramebufferId );
+ glBindFramebuffer(GL_FRAMEBUFFER, framebufferDesc.m_nResolveFramebufferId);
+
+ glGenTextures(1, &framebufferDesc.m_nResolveTextureId );
+ glBindTexture(GL_TEXTURE_2D, framebufferDesc.m_nResolveTextureId );
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebufferDesc.m_nResolveTextureId, 0);
+
+ // check FBO status
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return false;
+ }
+
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CMainApplication::SetupStereoRenderTargets()
+{
+ if ( !m_pHMD )
+ return false;
+
+ m_pHMD->GetRecommendedRenderTargetSize( &m_nRenderWidth, &m_nRenderHeight );
+
+ CreateFrameBuffer( m_nRenderWidth, m_nRenderHeight, leftEyeDesc );
+ CreateFrameBuffer( m_nRenderWidth, m_nRenderHeight, rightEyeDesc );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::SetupCompanionWindow()
+{
+ if ( !m_pHMD )
+ return;
+
+ std::vector<VertexDataWindow> vVerts;
+
+ // left eye verts
+ vVerts.push_back( VertexDataWindow( Vector2(-1, -1), Vector2(0, 1)) );
+ vVerts.push_back( VertexDataWindow( Vector2(0, -1), Vector2(1, 1)) );
+ vVerts.push_back( VertexDataWindow( Vector2(-1, 1), Vector2(0, 0)) );
+ vVerts.push_back( VertexDataWindow( Vector2(0, 1), Vector2(1, 0)) );
+
+ // right eye verts
+ vVerts.push_back( VertexDataWindow( Vector2(0, -1), Vector2(0, 1)) );
+ vVerts.push_back( VertexDataWindow( Vector2(1, -1), Vector2(1, 1)) );
+ vVerts.push_back( VertexDataWindow( Vector2(0, 1), Vector2(0, 0)) );
+ vVerts.push_back( VertexDataWindow( Vector2(1, 1), Vector2(1, 0)) );
+
+ GLushort vIndices[] = { 0, 1, 3, 0, 3, 2, 4, 5, 7, 4, 7, 6 };
+ m_uiCompanionWindowIndexSize = _countof(vIndices);
+
+ glGenVertexArrays( 1, &m_unCompanionWindowVAO );
+ glBindVertexArray( m_unCompanionWindowVAO );
+
+ glGenBuffers( 1, &m_glCompanionWindowIDVertBuffer );
+ glBindBuffer( GL_ARRAY_BUFFER, m_glCompanionWindowIDVertBuffer );
+ glBufferData( GL_ARRAY_BUFFER, vVerts.size()*sizeof(VertexDataWindow), &vVerts[0], GL_STATIC_DRAW );
+
+ glGenBuffers( 1, &m_glCompanionWindowIDIndexBuffer );
+ glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_glCompanionWindowIDIndexBuffer );
+ glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_uiCompanionWindowIndexSize*sizeof(GLushort), &vIndices[0], GL_STATIC_DRAW );
+
+ glEnableVertexAttribArray( 0 );
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexDataWindow), (void *)offsetof( VertexDataWindow, position ) );
+
+ glEnableVertexAttribArray( 1 );
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexDataWindow), (void *)offsetof( VertexDataWindow, texCoord ) );
+
+ glBindVertexArray( 0 );
+
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::RenderStereoTargets()
+{
+ glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
+ glEnable( GL_MULTISAMPLE );
+
+ // Left Eye
+ glBindFramebuffer( GL_FRAMEBUFFER, leftEyeDesc.m_nRenderFramebufferId );
+ glViewport(0, 0, m_nRenderWidth, m_nRenderHeight );
+ RenderScene( vr::Eye_Left );
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ glDisable( GL_MULTISAMPLE );
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, leftEyeDesc.m_nRenderFramebufferId);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, leftEyeDesc.m_nResolveFramebufferId );
+
+ glBlitFramebuffer( 0, 0, m_nRenderWidth, m_nRenderHeight, 0, 0, m_nRenderWidth, m_nRenderHeight,
+ GL_COLOR_BUFFER_BIT,
+ GL_LINEAR );
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0 );
+
+ glEnable( GL_MULTISAMPLE );
+
+ // Right Eye
+ glBindFramebuffer( GL_FRAMEBUFFER, rightEyeDesc.m_nRenderFramebufferId );
+ glViewport(0, 0, m_nRenderWidth, m_nRenderHeight );
+ RenderScene( vr::Eye_Right );
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ glDisable( GL_MULTISAMPLE );
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, rightEyeDesc.m_nRenderFramebufferId );
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rightEyeDesc.m_nResolveFramebufferId );
+
+ glBlitFramebuffer( 0, 0, m_nRenderWidth, m_nRenderHeight, 0, 0, m_nRenderWidth, m_nRenderHeight,
+ GL_COLOR_BUFFER_BIT,
+ GL_LINEAR );
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Renders a scene with respect to nEye.
+//-----------------------------------------------------------------------------
+void CMainApplication::RenderScene( vr::Hmd_Eye nEye )
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+
+ if( m_bShowCubes )
+ {
+ glUseProgram( m_unSceneProgramID );
+ glUniformMatrix4fv( m_nSceneMatrixLocation, 1, GL_FALSE, GetCurrentViewProjectionMatrix( nEye ).get() );
+ glBindVertexArray( m_unSceneVAO );
+ glBindTexture( GL_TEXTURE_2D, m_iTexture );
+ glDrawArrays( GL_TRIANGLES, 0, m_uiVertcount );
+ glBindVertexArray( 0 );
+ }
+
+ bool bIsInputAvailable = m_pHMD->IsInputAvailable();
+
+ if( bIsInputAvailable )
+ {
+ // draw the controller axis lines
+ glUseProgram( m_unControllerTransformProgramID );
+ glUniformMatrix4fv( m_nControllerMatrixLocation, 1, GL_FALSE, GetCurrentViewProjectionMatrix( nEye ).get() );
+ glBindVertexArray( m_unControllerVAO );
+ glDrawArrays( GL_LINES, 0, m_uiControllerVertcount );
+ glBindVertexArray( 0 );
+ }
+
+ // ----- Render Model rendering -----
+ glUseProgram( m_unRenderModelProgramID );
+
+ for ( EHand eHand = Left; eHand <= Right; ((int&)eHand)++ )
+ {
+ if ( !m_rHand[eHand].m_bShowController || !m_rHand[eHand].m_pRenderModel )
+ continue;
+
+ const Matrix4 & matDeviceToTracking = m_rHand[eHand].m_rmat4Pose;
+ Matrix4 matMVP = GetCurrentViewProjectionMatrix( nEye ) * matDeviceToTracking;
+ glUniformMatrix4fv( m_nRenderModelMatrixLocation, 1, GL_FALSE, matMVP.get() );
+
+ m_rHand[eHand].m_pRenderModel->Draw();
+ }
+
+ glUseProgram( 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::RenderCompanionWindow()
+{
+ glDisable(GL_DEPTH_TEST);
+ glViewport( 0, 0, m_nCompanionWindowWidth, m_nCompanionWindowHeight );
+
+ glBindVertexArray( m_unCompanionWindowVAO );
+ glUseProgram( m_unCompanionWindowProgramID );
+
+ // render left eye (first half of index array )
+ glBindTexture(GL_TEXTURE_2D, leftEyeDesc.m_nResolveTextureId );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glDrawElements( GL_TRIANGLES, m_uiCompanionWindowIndexSize/2, GL_UNSIGNED_SHORT, 0 );
+
+ // render right eye (second half of index array )
+ glBindTexture(GL_TEXTURE_2D, rightEyeDesc.m_nResolveTextureId );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glDrawElements( GL_TRIANGLES, m_uiCompanionWindowIndexSize/2, GL_UNSIGNED_SHORT, (const void *)(uintptr_t)(m_uiCompanionWindowIndexSize) );
+
+ glBindVertexArray( 0 );
+ glUseProgram( 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets a Matrix Projection Eye with respect to nEye.
+//-----------------------------------------------------------------------------
+Matrix4 CMainApplication::GetHMDMatrixProjectionEye( vr::Hmd_Eye nEye )
+{
+ if ( !m_pHMD )
+ return Matrix4();
+
+ vr::HmdMatrix44_t mat = m_pHMD->GetProjectionMatrix( nEye, m_fNearClip, m_fFarClip );
+
+ return Matrix4(
+ mat.m[0][0], mat.m[1][0], mat.m[2][0], mat.m[3][0],
+ mat.m[0][1], mat.m[1][1], mat.m[2][1], mat.m[3][1],
+ mat.m[0][2], mat.m[1][2], mat.m[2][2], mat.m[3][2],
+ mat.m[0][3], mat.m[1][3], mat.m[2][3], mat.m[3][3]
+ );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets an HMDMatrixPoseEye with respect to nEye.
+//-----------------------------------------------------------------------------
+Matrix4 CMainApplication::GetHMDMatrixPoseEye( vr::Hmd_Eye nEye )
+{
+ if ( !m_pHMD )
+ return Matrix4();
+
+ vr::HmdMatrix34_t matEyeRight = m_pHMD->GetEyeToHeadTransform( nEye );
+ Matrix4 matrixObj(
+ matEyeRight.m[0][0], matEyeRight.m[1][0], matEyeRight.m[2][0], 0.0,
+ matEyeRight.m[0][1], matEyeRight.m[1][1], matEyeRight.m[2][1], 0.0,
+ matEyeRight.m[0][2], matEyeRight.m[1][2], matEyeRight.m[2][2], 0.0,
+ matEyeRight.m[0][3], matEyeRight.m[1][3], matEyeRight.m[2][3], 1.0f
+ );
+
+ return matrixObj.invert();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets a Current View Projection Matrix with respect to nEye,
+// which may be an Eye_Left or an Eye_Right.
+//-----------------------------------------------------------------------------
+Matrix4 CMainApplication::GetCurrentViewProjectionMatrix( vr::Hmd_Eye nEye )
+{
+ Matrix4 matMVP;
+ //glm::mat4 pp(m_mat4HMDPose.get());
+ if( nEye == vr::Eye_Left )
+ {
+ matMVP = m_mat4ProjectionLeft * m_mat4eyePosLeft * m_mat4HMDPose;
+ }
+ else if( nEye == vr::Eye_Right )
+ {
+ matMVP = m_mat4ProjectionRight * m_mat4eyePosRight * m_mat4HMDPose;
+ }
+
+ return matMVP;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainApplication::UpdateHMDMatrixPose()
+{
+ if ( !m_pHMD )
+ return;
+
+ vr::VRCompositor()->WaitGetPoses(m_rTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, NULL, 0 );
+
+ m_iValidPoseCount = 0;
+ m_strPoseClasses = "";
+ for ( int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice )
+ {
+ if ( m_rTrackedDevicePose[nDevice].bPoseIsValid )
+ {
+ m_iValidPoseCount++;
+ m_rmat4DevicePose[nDevice] = ConvertSteamVRMatrixToMatrix4( m_rTrackedDevicePose[nDevice].mDeviceToAbsoluteTracking );
+ if (m_rDevClassChar[nDevice]==0)
+ {
+ switch (m_pHMD->GetTrackedDeviceClass(nDevice))
+ {
+ case vr::TrackedDeviceClass_Controller: m_rDevClassChar[nDevice] = 'C'; break;
+ case vr::TrackedDeviceClass_HMD: m_rDevClassChar[nDevice] = 'H'; break;
+ case vr::TrackedDeviceClass_Invalid: m_rDevClassChar[nDevice] = 'I'; break;
+ case vr::TrackedDeviceClass_GenericTracker: m_rDevClassChar[nDevice] = 'G'; break;
+ case vr::TrackedDeviceClass_TrackingReference: m_rDevClassChar[nDevice] = 'T'; break;
+ default: m_rDevClassChar[nDevice] = '?'; break;
+ }
+ }
+ m_strPoseClasses += m_rDevClassChar[nDevice];
+ }
+ }
+
+ if ( m_rTrackedDevicePose[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid )
+ {
+ m_mat4HMDPose = m_rmat4DevicePose[vr::k_unTrackedDeviceIndex_Hmd];
+ m_mat4HMDPose.invert();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Finds a render model we've already loaded or loads a new one
+//-----------------------------------------------------------------------------
+CGLRenderModel *CMainApplication::FindOrLoadRenderModel( const char *pchRenderModelName )
+{
+ CGLRenderModel *pRenderModel = NULL;
+ for( std::vector< CGLRenderModel * >::iterator i = m_vecRenderModels.begin(); i != m_vecRenderModels.end(); i++ )
+ {
+ if( !strcmp( (*i)->GetName().c_str(), pchRenderModelName ) )
+ {
+ pRenderModel = *i;
+ break;
+ }
+ }
+
+ // load the model if we didn't find one
+ if( !pRenderModel )
+ {
+ vr::RenderModel_t *pModel;
+ vr::EVRRenderModelError error;
+ while ( 1 )
+ {
+ error = vr::VRRenderModels()->LoadRenderModel_Async( pchRenderModelName, &pModel );
+ if ( error != vr::VRRenderModelError_Loading )
+ break;
+
+ ThreadSleep( 1 );
+ }
+
+ if ( error != vr::VRRenderModelError_None )
+ {
+ dprintf( "Unable to load render model %s - %s\n", pchRenderModelName, vr::VRRenderModels()->GetRenderModelErrorNameFromEnum( error ) );
+ return NULL; // move on to the next tracked device
+ }
+
+ vr::RenderModel_TextureMap_t *pTexture;
+ while ( 1 )
+ {
+ error = vr::VRRenderModels()->LoadTexture_Async( pModel->diffuseTextureId, &pTexture );
+ if ( error != vr::VRRenderModelError_Loading )
+ break;
+
+ ThreadSleep( 1 );
+ }
+
+ if ( error != vr::VRRenderModelError_None )
+ {
+ dprintf( "Unable to load render texture id:%d for render model %s\n", pModel->diffuseTextureId, pchRenderModelName );
+ vr::VRRenderModels()->FreeRenderModel( pModel );
+ return NULL; // move on to the next tracked device
+ }
+
+ pRenderModel = new CGLRenderModel( pchRenderModelName );
+ if ( !pRenderModel->BInit( *pModel, *pTexture ) )
+ {
+ dprintf( "Unable to create GL model from render model %s\n", pchRenderModelName );
+ delete pRenderModel;
+ pRenderModel = NULL;
+ }
+ else
+ {
+ m_vecRenderModels.push_back( pRenderModel );
+ }
+ vr::VRRenderModels()->FreeRenderModel( pModel );
+ vr::VRRenderModels()->FreeTexture( pTexture );
+ }
+ return pRenderModel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Converts a SteamVR matrix to our local matrix class
+//-----------------------------------------------------------------------------
+Matrix4 CMainApplication::ConvertSteamVRMatrixToMatrix4( const vr::HmdMatrix34_t &matPose )
+{
+ Matrix4 matrixObj(
+ matPose.m[0][0], matPose.m[1][0], matPose.m[2][0], 0.0,
+ matPose.m[0][1], matPose.m[1][1], matPose.m[2][1], 0.0,
+ matPose.m[0][2], matPose.m[1][2], matPose.m[2][2], 0.0,
+ matPose.m[0][3], matPose.m[1][3], matPose.m[2][3], 1.0f
+ );
+ return matrixObj;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Create/destroy GL Render Models
+//-----------------------------------------------------------------------------
+CGLRenderModel::CGLRenderModel( const std::string & sRenderModelName )
+ : m_sModelName( sRenderModelName )
+{
+ m_glIndexBuffer = 0;
+ m_glVertArray = 0;
+ m_glVertBuffer = 0;
+ m_glTexture = 0;
+}
+
+
+CGLRenderModel::~CGLRenderModel()
+{
+ Cleanup();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Allocates and populates the GL resources for a render model
+//-----------------------------------------------------------------------------
+bool CGLRenderModel::BInit( const vr::RenderModel_t & vrModel, const vr::RenderModel_TextureMap_t & vrDiffuseTexture )
+{
+ // create and bind a VAO to hold state for this model
+ glGenVertexArrays( 1, &m_glVertArray );
+ glBindVertexArray( m_glVertArray );
+
+ // Populate a vertex buffer
+ glGenBuffers( 1, &m_glVertBuffer );
+ glBindBuffer( GL_ARRAY_BUFFER, m_glVertBuffer );
+ glBufferData( GL_ARRAY_BUFFER, sizeof( vr::RenderModel_Vertex_t ) * vrModel.unVertexCount, vrModel.rVertexData, GL_STATIC_DRAW );
+
+ // Identify the components in the vertex buffer
+ glEnableVertexAttribArray( 0 );
+ glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( vr::RenderModel_Vertex_t ), (void *)offsetof( vr::RenderModel_Vertex_t, vPosition ) );
+ glEnableVertexAttribArray( 1 );
+ glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, sizeof( vr::RenderModel_Vertex_t ), (void *)offsetof( vr::RenderModel_Vertex_t, vNormal ) );
+ glEnableVertexAttribArray( 2 );
+ glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE, sizeof( vr::RenderModel_Vertex_t ), (void *)offsetof( vr::RenderModel_Vertex_t, rfTextureCoord ) );
+
+ // Create and populate the index buffer
+ glGenBuffers( 1, &m_glIndexBuffer );
+ glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_glIndexBuffer );
+ glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( uint16_t ) * vrModel.unTriangleCount * 3, vrModel.rIndexData, GL_STATIC_DRAW );
+
+ glBindVertexArray( 0 );
+
+ // create and populate the texture
+ glGenTextures(1, &m_glTexture );
+ glBindTexture( GL_TEXTURE_2D, m_glTexture );
+
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, vrDiffuseTexture.unWidth, vrDiffuseTexture.unHeight,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, vrDiffuseTexture.rubTextureMapData );
+
+ // If this renders black ask McJohn what's wrong.
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+
+ GLfloat fLargest;
+ glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest );
+
+ glBindTexture( GL_TEXTURE_2D, 0 );
+
+ m_unVertexCount = vrModel.unTriangleCount * 3;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees the GL resources for a render model
+//-----------------------------------------------------------------------------
+void CGLRenderModel::Cleanup()
+{
+ if( m_glVertBuffer )
+ {
+ glDeleteBuffers(1, &m_glIndexBuffer);
+ glDeleteVertexArrays( 1, &m_glVertArray );
+ glDeleteBuffers(1, &m_glVertBuffer);
+ m_glIndexBuffer = 0;
+ m_glVertArray = 0;
+ m_glVertBuffer = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the render model
+//-----------------------------------------------------------------------------
+void CGLRenderModel::Draw()
+{
+ glBindVertexArray( m_glVertArray );
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_2D, m_glTexture );
+
+ glDrawElements( GL_TRIANGLES, m_unVertexCount, GL_UNSIGNED_SHORT, 0 );
+
+ glBindVertexArray( 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int main(int argc, char *argv[])
+{
+ CMainApplication *pMainApplication = new CMainApplication( argc, argv );
+
+ if (!pMainApplication->BInit())
+ {
+ pMainApplication->Shutdown();
+ return 1;
+ }
+
+ pMainApplication->RunMainLoop();
+
+ pMainApplication->Shutdown();
+
+ return 0;
+}
diff --git a/tests/main.cpp b/tests/main.cpp
new file mode 100644
index 0000000..9ad80a6
--- /dev/null
+++ b/tests/main.cpp
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ printf("hello, world!\n");
+ return 0;
+}