mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 07:34:45 +00:00
* Adjustment: Update Bullet version to 3.24.
This commit is contained in:
parent
35de012ee7
commit
4a3f31df2a
6148 changed files with 2112532 additions and 56873 deletions
27
Engine/lib/bullet/examples/ThirdPartyLibs/openvr/LICENSE
Normal file
27
Engine/lib/bullet/examples/ThirdPartyLibs/openvr/LICENSE
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
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.
|
||||
9
Engine/lib/bullet/examples/ThirdPartyLibs/openvr/README
Normal file
9
Engine/lib/bullet/examples/ThirdPartyLibs/openvr/README
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
OpenVR is an API and runtime that allows access to VR hardware from multiple
|
||||
vendors without requiring that applications have specific knowledge of the
|
||||
hardware they are targeting. This repository is an SDK that contains the API
|
||||
and samples. The runtime is under SteamVR in Tools on Steam.
|
||||
|
||||
Documentation for the API is available in the wiki: https://github.com/ValveSoftware/openvr/wiki/API-Documentation
|
||||
|
||||
More information on OpenVR and SteamVR can be found on http://steamvr.com
|
||||
|
||||
3698
Engine/lib/bullet/examples/ThirdPartyLibs/openvr/headers/openvr.h
Normal file
3698
Engine/lib/bullet/examples/ThirdPartyLibs/openvr/headers/openvr.h
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
BIN
Engine/lib/bullet/examples/ThirdPartyLibs/openvr/lib/linux32/libopenvr_api.so
Executable file
BIN
Engine/lib/bullet/examples/ThirdPartyLibs/openvr/lib/linux32/libopenvr_api.so
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,589 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,855 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
|
|
@ -0,0 +1,640 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef OPENVR_SAMPLES_SHARED_COMPAT_H_
|
||||
#define OPENVR_SAMPLES_SHARED_COMPAT_H_
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
// Handle non standard code.
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <cstdbool>
|
||||
#include <unistd.h>
|
||||
|
||||
#define sprintf_s snprintf
|
||||
#define vsprintf_s sprintf
|
||||
#define _stricmp strcmp
|
||||
#define stricmp strcmp
|
||||
#define strnicmp strncasecmp
|
||||
#define strcpy_s(dst, n, src) int(strncpy(dst, src, n) != nullptr)
|
||||
#define fopen_s(fd, path, mode) int((*fd = fopen(path, mode)) != nullptr)
|
||||
#define _vsnprintf_s(buffer, size, fmt, ap) vsnprintf(buffer, size, fmt, ap)
|
||||
#define OutputDebugStringA(x) fprintf(stderr, "%s\n", x)
|
||||
|
||||
typedef int errno_t;
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // OPENVR_SAMPLES_SHARED_COMPAT_H_
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,798 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#include "compat.h"
|
||||
#include "strtools.h"
|
||||
#include "pathtools.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <shobjidl.h>
|
||||
#include <knownfolders.h>
|
||||
#include <shlobj.h>
|
||||
#include <share.h>
|
||||
|
||||
#undef GetEnvironmentVariable
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#if defined OSX
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#define _S_IFDIR S_IFDIR // really from tier0/platform.h which we dont have yet
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
/** Returns the path (including filename) to the current executable */
|
||||
std::string Path_GetExecutablePath()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
|
||||
char *pchPath = new char[MAX_UNICODE_PATH_IN_UTF8];
|
||||
::GetModuleFileNameW(NULL, pwchPath, MAX_UNICODE_PATH);
|
||||
WideCharToMultiByte(CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL);
|
||||
delete[] pwchPath;
|
||||
|
||||
std::string sPath = pchPath;
|
||||
delete[] pchPath;
|
||||
return sPath;
|
||||
#elif defined(OSX)
|
||||
char rchPath[1024];
|
||||
uint32_t nBuff = sizeof(rchPath);
|
||||
bool bSuccess = _NSGetExecutablePath(rchPath, &nBuff) == 0;
|
||||
rchPath[nBuff - 1] = '\0';
|
||||
if (bSuccess)
|
||||
return rchPath;
|
||||
else
|
||||
return "";
|
||||
#elif defined LINUX
|
||||
char rchPath[1024];
|
||||
size_t nBuff = sizeof(rchPath);
|
||||
ssize_t nRead = readlink("/proc/self/exe", rchPath, nBuff - 1);
|
||||
if (nRead != -1)
|
||||
{
|
||||
rchPath[nRead] = 0;
|
||||
return rchPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
#else
|
||||
AssertMsg(false, "Implement Plat_GetExecutablePath");
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Returns the path of the current working directory */
|
||||
std::string Path_GetWorkingDirectory()
|
||||
{
|
||||
std::string sPath;
|
||||
#if defined(_WIN32)
|
||||
wchar_t buf[MAX_UNICODE_PATH];
|
||||
sPath = UTF16to8(_wgetcwd(buf, MAX_UNICODE_PATH));
|
||||
#else
|
||||
char buf[1024];
|
||||
sPath = getcwd(buf, sizeof(buf));
|
||||
#endif
|
||||
return sPath;
|
||||
}
|
||||
|
||||
/** Sets the path of the current working directory. Returns true if this was successful. */
|
||||
bool Path_SetWorkingDirectory(const std::string &sPath)
|
||||
{
|
||||
bool bSuccess;
|
||||
#if defined(_WIN32)
|
||||
std::wstring wsPath = UTF8to16(sPath.c_str());
|
||||
bSuccess = 0 == _wchdir(wsPath.c_str());
|
||||
#else
|
||||
bSuccess = 0 == chdir(sPath.c_str());
|
||||
#endif
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/** Returns the specified path without its filename */
|
||||
std::string Path_StripFilename(const std::string &sPath, char slash)
|
||||
{
|
||||
if (slash == 0)
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string::size_type n = sPath.find_last_of(slash);
|
||||
if (n == std::string::npos)
|
||||
return sPath;
|
||||
else
|
||||
return std::string(sPath.begin(), sPath.begin() + n);
|
||||
}
|
||||
|
||||
/** returns just the filename from the provided full or relative path. */
|
||||
std::string Path_StripDirectory(const std::string &sPath, char slash)
|
||||
{
|
||||
if (slash == 0)
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string::size_type n = sPath.find_last_of(slash);
|
||||
if (n == std::string::npos)
|
||||
return sPath;
|
||||
else
|
||||
return std::string(sPath.begin() + n + 1, sPath.end());
|
||||
}
|
||||
|
||||
/** returns just the filename with no extension of the provided filename.
|
||||
* If there is a path the path is left intact. */
|
||||
std::string Path_StripExtension(const std::string &sPath)
|
||||
{
|
||||
for (std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++)
|
||||
{
|
||||
if (*i == '.')
|
||||
{
|
||||
return std::string(sPath.begin(), i.base() - 1);
|
||||
}
|
||||
|
||||
// if we find a slash there is no extension
|
||||
if (*i == '\\' || *i == '/')
|
||||
break;
|
||||
}
|
||||
|
||||
// we didn't find an extension
|
||||
return sPath;
|
||||
}
|
||||
|
||||
/** returns just extension of the provided filename (if any). */
|
||||
std::string Path_GetExtension(const std::string &sPath)
|
||||
{
|
||||
for (std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++)
|
||||
{
|
||||
if (*i == '.')
|
||||
{
|
||||
return std::string(i.base(), sPath.end());
|
||||
}
|
||||
|
||||
// if we find a slash there is no extension
|
||||
if (*i == '\\' || *i == '/')
|
||||
break;
|
||||
}
|
||||
|
||||
// we didn't find an extension
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Path_IsAbsolute(const std::string &sPath)
|
||||
{
|
||||
if (sPath.empty())
|
||||
return false;
|
||||
|
||||
#if defined(WIN32)
|
||||
if (sPath.size() < 3) // must be c:\x or \\x at least
|
||||
return false;
|
||||
|
||||
if (sPath[1] == ':') // drive letter plus slash, but must test both slash cases
|
||||
{
|
||||
if (sPath[2] == '\\' || sPath[2] == '/')
|
||||
return true;
|
||||
}
|
||||
else if (sPath[0] == '\\' && sPath[1] == '\\') // UNC path
|
||||
return true;
|
||||
#else
|
||||
if (sPath[0] == '\\' || sPath[0] == '/') // any leading slash
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Makes an absolute path from a relative path and a base path */
|
||||
std::string Path_MakeAbsolute(const std::string &sRelativePath, const std::string &sBasePath, char slash)
|
||||
{
|
||||
if (slash == 0)
|
||||
slash = Path_GetSlash();
|
||||
|
||||
if (Path_IsAbsolute(sRelativePath))
|
||||
return sRelativePath;
|
||||
else
|
||||
{
|
||||
if (!Path_IsAbsolute(sBasePath))
|
||||
return "";
|
||||
|
||||
std::string sCompacted = Path_Compact(Path_Join(sBasePath, sRelativePath, slash), slash);
|
||||
if (Path_IsAbsolute(sCompacted))
|
||||
return sCompacted;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/** Fixes the directory separators for the current platform */
|
||||
std::string Path_FixSlashes(const std::string &sPath, char slash)
|
||||
{
|
||||
if (slash == 0)
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string sFixed = sPath;
|
||||
for (std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++)
|
||||
{
|
||||
if (*i == '/' || *i == '\\')
|
||||
*i = slash;
|
||||
}
|
||||
|
||||
return sFixed;
|
||||
}
|
||||
|
||||
char Path_GetSlash()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return '\\';
|
||||
#else
|
||||
return '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Jams two paths together with the right kind of slash */
|
||||
std::string Path_Join(const std::string &first, const std::string &second, char slash)
|
||||
{
|
||||
if (slash == 0)
|
||||
slash = Path_GetSlash();
|
||||
|
||||
// only insert a slash if we don't already have one
|
||||
std::string::size_type nLen = first.length();
|
||||
if (!nLen)
|
||||
return second;
|
||||
#if defined(_WIN32)
|
||||
if (first.back() == '\\' || first.back() == '/')
|
||||
nLen--;
|
||||
#else
|
||||
char last_char = first[first.length() - 1];
|
||||
if (last_char == '\\' || last_char == '/')
|
||||
nLen--;
|
||||
#endif
|
||||
|
||||
return first.substr(0, nLen) + std::string(1, slash) + second;
|
||||
}
|
||||
|
||||
std::string Path_Join(const std::string &first, const std::string &second, const std::string &third, char slash)
|
||||
{
|
||||
return Path_Join(Path_Join(first, second, slash), third, slash);
|
||||
}
|
||||
|
||||
std::string Path_Join(const std::string &first, const std::string &second, const std::string &third, const std::string &fourth, char slash)
|
||||
{
|
||||
return Path_Join(Path_Join(Path_Join(first, second, slash), third, slash), fourth, slash);
|
||||
}
|
||||
|
||||
std::string Path_Join(
|
||||
const std::string &first,
|
||||
const std::string &second,
|
||||
const std::string &third,
|
||||
const std::string &fourth,
|
||||
const std::string &fifth,
|
||||
char slash)
|
||||
{
|
||||
return Path_Join(Path_Join(Path_Join(Path_Join(first, second, slash), third, slash), fourth, slash), fifth, slash);
|
||||
}
|
||||
|
||||
std::string Path_RemoveTrailingSlash(const std::string &sRawPath, char slash)
|
||||
{
|
||||
if (slash == 0)
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string sPath = sRawPath;
|
||||
std::string::size_type nCurrent = sRawPath.length();
|
||||
if (nCurrent == 0)
|
||||
return sPath;
|
||||
|
||||
int nLastFound = -1;
|
||||
nCurrent--;
|
||||
while (nCurrent != 0)
|
||||
{
|
||||
if (sRawPath[nCurrent] == slash)
|
||||
{
|
||||
nLastFound = (int)nCurrent;
|
||||
nCurrent--;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nLastFound >= 0)
|
||||
{
|
||||
sPath.erase(nLastFound, std::string::npos);
|
||||
}
|
||||
|
||||
return sPath;
|
||||
}
|
||||
|
||||
/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the
|
||||
* specified path has a broken number of directories for its number of ..s */
|
||||
std::string Path_Compact(const std::string &sRawPath, char slash)
|
||||
{
|
||||
if (slash == 0)
|
||||
slash = Path_GetSlash();
|
||||
|
||||
std::string sPath = Path_FixSlashes(sRawPath, slash);
|
||||
std::string sSlashString(1, slash);
|
||||
|
||||
// strip out all /./
|
||||
for (std::string::size_type i = 0; (i + 3) < sPath.length();)
|
||||
{
|
||||
if (sPath[i] == slash && sPath[i + 1] == '.' && sPath[i + 2] == slash)
|
||||
{
|
||||
sPath.replace(i, 3, sSlashString);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// get rid of trailing /. but leave the path separator
|
||||
if (sPath.length() > 2)
|
||||
{
|
||||
std::string::size_type len = sPath.length();
|
||||
if (sPath[len - 1] == '.' && sPath[len - 2] == slash)
|
||||
{
|
||||
// sPath.pop_back();
|
||||
sPath[len - 1] = 0; // for now, at least
|
||||
}
|
||||
}
|
||||
|
||||
// get rid of leading ./
|
||||
if (sPath.length() > 2)
|
||||
{
|
||||
if (sPath[0] == '.' && sPath[1] == slash)
|
||||
{
|
||||
sPath.replace(0, 2, "");
|
||||
}
|
||||
}
|
||||
|
||||
// each time we encounter .. back up until we've found the previous directory name
|
||||
// then get rid of both
|
||||
std::string::size_type i = 0;
|
||||
while (i < sPath.length())
|
||||
{
|
||||
if (i > 0 && sPath.length() - i >= 2 && sPath[i] == '.' && sPath[i + 1] == '.' && (i + 2 == sPath.length() || sPath[i + 2] == slash) && sPath[i - 1] == slash)
|
||||
{
|
||||
// check if we've hit the start of the string and have a bogus path
|
||||
if (i == 1)
|
||||
return "";
|
||||
|
||||
// find the separator before i-1
|
||||
std::string::size_type iDirStart = i - 2;
|
||||
while (iDirStart > 0 && sPath[iDirStart - 1] != slash)
|
||||
--iDirStart;
|
||||
|
||||
// remove everything from iDirStart to i+2
|
||||
sPath.replace(iDirStart, (i - iDirStart) + 3, "");
|
||||
|
||||
// start over
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return sPath;
|
||||
}
|
||||
|
||||
/** Returns the path to the current DLL or exe */
|
||||
std::string Path_GetThisModulePath()
|
||||
{
|
||||
// gets the path of vrclient.dll itself
|
||||
#ifdef WIN32
|
||||
HMODULE hmodule = NULL;
|
||||
|
||||
::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCTSTR>(Path_GetThisModulePath), &hmodule);
|
||||
|
||||
wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
|
||||
char *pchPath = new char[MAX_UNICODE_PATH_IN_UTF8];
|
||||
::GetModuleFileNameW(hmodule, pwchPath, MAX_UNICODE_PATH);
|
||||
WideCharToMultiByte(CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL);
|
||||
delete[] pwchPath;
|
||||
|
||||
std::string sPath = pchPath;
|
||||
delete[] pchPath;
|
||||
return sPath;
|
||||
|
||||
#elif defined(OSX) || defined(LINUX)
|
||||
// get the addr of a function in vrclient.so and then ask the dlopen system about it
|
||||
Dl_info info;
|
||||
dladdr((void *)Path_GetThisModulePath, &info);
|
||||
return info.dli_fname;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** returns true if the specified path exists and is a directory */
|
||||
bool Path_IsDirectory(const std::string &sPath)
|
||||
{
|
||||
std::string sFixedPath = Path_FixSlashes(sPath);
|
||||
if (sFixedPath.empty())
|
||||
return false;
|
||||
char cLast = sFixedPath[sFixedPath.length() - 1];
|
||||
if (cLast == '/' || cLast == '\\')
|
||||
sFixedPath.erase(sFixedPath.end() - 1, sFixedPath.end());
|
||||
|
||||
// see if the specified path actually exists.
|
||||
|
||||
#if defined(POSIX)
|
||||
struct stat buf;
|
||||
if (stat(sFixedPath.c_str(), &buf) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(LINUX) || defined(OSX)
|
||||
return S_ISDIR(buf.st_mode);
|
||||
#else
|
||||
return (buf.st_mode & _S_IFDIR) != 0;
|
||||
#endif
|
||||
|
||||
#else
|
||||
struct _stat buf;
|
||||
std::wstring wsFixedPath = UTF8to16(sFixedPath.c_str());
|
||||
if (_wstat(wsFixedPath.c_str(), &buf) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (buf.st_mode & _S_IFDIR) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** returns true if the specified path represents an app bundle */
|
||||
bool Path_IsAppBundle(const std::string &sPath)
|
||||
{
|
||||
#if defined(OSX)
|
||||
NSBundle *bundle = [NSBundle bundleWithPath:[NSString stringWithUTF8String:sPath.c_str()]];
|
||||
bool bisAppBundle = (nullptr != bundle);
|
||||
[bundle release];
|
||||
return bisAppBundle;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the the path exists
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Path_Exists(const std::string &sPath)
|
||||
{
|
||||
std::string sFixedPath = Path_FixSlashes(sPath);
|
||||
if (sFixedPath.empty())
|
||||
return false;
|
||||
|
||||
#if defined(WIN32)
|
||||
struct _stat buf;
|
||||
std::wstring wsFixedPath = UTF8to16(sFixedPath.c_str());
|
||||
if (_wstat(wsFixedPath.c_str(), &buf) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
struct stat buf;
|
||||
if (stat(sFixedPath.c_str(), &buf) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: helper to find a directory upstream from a given path
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string Path_FindParentDirectoryRecursively(const std::string &strStartDirectory, const std::string &strDirectoryName)
|
||||
{
|
||||
std::string strFoundPath = "";
|
||||
std::string strCurrentPath = Path_FixSlashes(strStartDirectory);
|
||||
if (strCurrentPath.length() == 0)
|
||||
return "";
|
||||
|
||||
bool bExists = Path_Exists(strCurrentPath);
|
||||
std::string strCurrentDirectoryName = Path_StripDirectory(strCurrentPath);
|
||||
if (bExists && stricmp(strCurrentDirectoryName.c_str(), strDirectoryName.c_str()) == 0)
|
||||
return strCurrentPath;
|
||||
|
||||
while (bExists && strCurrentPath.length() != 0)
|
||||
{
|
||||
strCurrentPath = Path_StripFilename(strCurrentPath);
|
||||
strCurrentDirectoryName = Path_StripDirectory(strCurrentPath);
|
||||
bExists = Path_Exists(strCurrentPath);
|
||||
if (bExists && stricmp(strCurrentDirectoryName.c_str(), strDirectoryName.c_str()) == 0)
|
||||
return strCurrentPath;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: helper to find a subdirectory upstream from a given path
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string Path_FindParentSubDirectoryRecursively(const std::string &strStartDirectory, const std::string &strDirectoryName)
|
||||
{
|
||||
std::string strFoundPath = "";
|
||||
std::string strCurrentPath = Path_FixSlashes(strStartDirectory);
|
||||
if (strCurrentPath.length() == 0)
|
||||
return "";
|
||||
|
||||
bool bExists = Path_Exists(strCurrentPath);
|
||||
while (bExists && strCurrentPath.length() != 0)
|
||||
{
|
||||
strCurrentPath = Path_StripFilename(strCurrentPath);
|
||||
bExists = Path_Exists(strCurrentPath);
|
||||
|
||||
if (Path_Exists(Path_Join(strCurrentPath, strDirectoryName)))
|
||||
{
|
||||
strFoundPath = Path_Join(strCurrentPath, strDirectoryName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return strFoundPath;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: reading and writing files in the vortex directory
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char *Path_ReadBinaryFile(const std::string &strFilename, int *pSize)
|
||||
{
|
||||
FILE *f;
|
||||
#if defined(POSIX)
|
||||
f = fopen(strFilename.c_str(), "rb");
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16(strFilename.c_str());
|
||||
// the open operation needs to be sharable, therefore use of _wfsopen instead of _wfopen_s
|
||||
f = _wfsopen(wstrFilename.c_str(), L"rb", _SH_DENYNO);
|
||||
#endif
|
||||
|
||||
unsigned char *buf = NULL;
|
||||
|
||||
if (f != NULL)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
int size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
buf = new unsigned char[size];
|
||||
if (buf && fread(buf, size, 1, f) == 1)
|
||||
{
|
||||
if (pSize)
|
||||
*pSize = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] buf;
|
||||
buf = 0;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
uint32_t Path_ReadBinaryFile(const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize)
|
||||
{
|
||||
FILE *f;
|
||||
#if defined(POSIX)
|
||||
f = fopen(strFilename.c_str(), "rb");
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16(strFilename.c_str());
|
||||
errno_t err = _wfopen_s(&f, wstrFilename.c_str(), L"rb");
|
||||
if (err != 0)
|
||||
{
|
||||
f = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t unSizeToReturn = 0;
|
||||
|
||||
if (f != NULL)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
uint32_t size = (uint32_t)ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (size > unSize || !pBuffer)
|
||||
{
|
||||
unSizeToReturn = (uint32_t)size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fread(pBuffer, size, 1, f) == 1)
|
||||
{
|
||||
unSizeToReturn = (uint32_t)size;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return unSizeToReturn;
|
||||
}
|
||||
|
||||
bool Path_WriteBinaryFile(const std::string &strFilename, unsigned char *pData, unsigned nSize)
|
||||
{
|
||||
FILE *f;
|
||||
#if defined(POSIX)
|
||||
f = fopen(strFilename.c_str(), "wb");
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16(strFilename.c_str());
|
||||
errno_t err = _wfopen_s(&f, wstrFilename.c_str(), L"wb");
|
||||
if (err != 0)
|
||||
{
|
||||
f = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t written = 0;
|
||||
if (f != NULL)
|
||||
{
|
||||
written = fwrite(pData, sizeof(unsigned char), nSize, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return written = nSize ? true : false;
|
||||
}
|
||||
|
||||
std::string Path_ReadTextFile(const std::string &strFilename)
|
||||
{
|
||||
// doing it this way seems backwards, but I don't
|
||||
// see an easy way to do this with C/C++ style IO
|
||||
// that isn't worse...
|
||||
int size;
|
||||
unsigned char *buf = Path_ReadBinaryFile(strFilename, &size);
|
||||
if (!buf)
|
||||
return "";
|
||||
|
||||
// convert CRLF -> LF
|
||||
size_t outsize = 1;
|
||||
for (int i = 1; i < size; i++)
|
||||
{
|
||||
if (buf[i] == '\n' && buf[i - 1] == '\r') // CRLF
|
||||
buf[outsize - 1] = '\n'; // ->LF
|
||||
else
|
||||
buf[outsize++] = buf[i]; // just copy
|
||||
}
|
||||
|
||||
std::string ret((char *)buf, outsize);
|
||||
delete[] buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Path_WriteStringToTextFile(const std::string &strFilename, const char *pchData)
|
||||
{
|
||||
FILE *f;
|
||||
#if defined(POSIX)
|
||||
f = fopen(strFilename.c_str(), "w");
|
||||
#else
|
||||
std::wstring wstrFilename = UTF8to16(strFilename.c_str());
|
||||
errno_t err = _wfopen_s(&f, wstrFilename.c_str(), L"w");
|
||||
if (err != 0)
|
||||
{
|
||||
f = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ok = false;
|
||||
|
||||
if (f != NULL)
|
||||
{
|
||||
ok = fputs(pchData, f) >= 0;
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Path_WriteStringToTextFileAtomic(const std::string &strFilename, const char *pchData)
|
||||
{
|
||||
std::string strTmpFilename = strFilename + ".tmp";
|
||||
|
||||
if (!Path_WriteStringToTextFile(strTmpFilename, pchData))
|
||||
return false;
|
||||
|
||||
// Platform specific atomic file replacement
|
||||
#if defined(_WIN32)
|
||||
std::wstring wsFilename = UTF8to16(strFilename.c_str());
|
||||
std::wstring wsTmpFilename = UTF8to16(strTmpFilename.c_str());
|
||||
if (!::ReplaceFileW(wsFilename.c_str(), wsTmpFilename.c_str(), nullptr, 0, 0, 0))
|
||||
{
|
||||
// if we couldn't ReplaceFile, try a non-atomic write as a fallback
|
||||
if (!Path_WriteStringToTextFile(strFilename, pchData))
|
||||
return false;
|
||||
}
|
||||
#elif defined(POSIX)
|
||||
if (rename(strTmpFilename.c_str(), strFilename.c_str()) == -1)
|
||||
return false;
|
||||
#else
|
||||
#error Do not know how to write atomic file
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
#define FILE_URL_PREFIX "file:///"
|
||||
#else
|
||||
#define FILE_URL_PREFIX "file://"
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
// Purpose: Turns a path to a file on disk into a URL (or just returns the value if it's already a URL)
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
std::string Path_FilePathToUrl(const std::string &sRelativePath, const std::string &sBasePath)
|
||||
{
|
||||
if (!strnicmp(sRelativePath.c_str(), "http://", 7) || !strnicmp(sRelativePath.c_str(), "https://", 8) || !strnicmp(sRelativePath.c_str(), "file://", 7))
|
||||
{
|
||||
return sRelativePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string sAbsolute = Path_MakeAbsolute(sRelativePath, sBasePath);
|
||||
if (sAbsolute.empty())
|
||||
return sAbsolute;
|
||||
return std::string(FILE_URL_PREFIX) + sAbsolute;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// Purpose: Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
std::string Path_UrlToFilePath(const std::string &sFileUrl)
|
||||
{
|
||||
if (!strnicmp(sFileUrl.c_str(), FILE_URL_PREFIX, strlen(FILE_URL_PREFIX)))
|
||||
{
|
||||
return sFileUrl.c_str() + strlen(FILE_URL_PREFIX);
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// Purpose: Returns the root of the directory the system wants us to store user documents in
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
std::string GetUserDocumentsPath()
|
||||
{
|
||||
#if defined(WIN32)
|
||||
WCHAR rwchPath[MAX_PATH];
|
||||
|
||||
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_MYDOCUMENTS | CSIDL_FLAG_CREATE, NULL, 0, rwchPath)))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// Convert the path to UTF-8 and store in the output
|
||||
std::string sUserPath = UTF16to8(rwchPath);
|
||||
|
||||
return sUserPath;
|
||||
#elif defined(OSX)
|
||||
@autoreleasepool
|
||||
{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
if ([paths count] == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return [[paths objectAtIndex:0] UTF8String];
|
||||
}
|
||||
#elif defined(LINUX)
|
||||
// @todo: not solved/changed as part of OSX - still not real - just removed old class based steam cut and paste
|
||||
const char *pchHome = getenv("HOME");
|
||||
if (pchHome == NULL)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return pchHome;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
/** Returns the path (including filename) to the current executable */
|
||||
std::string Path_GetExecutablePath();
|
||||
|
||||
/** Returns the path of the current working directory */
|
||||
std::string Path_GetWorkingDirectory();
|
||||
|
||||
/** Sets the path of the current working directory. Returns true if this was successful. */
|
||||
bool Path_SetWorkingDirectory(const std::string &sPath);
|
||||
|
||||
/** returns the path (including filename) of the current shared lib or DLL */
|
||||
std::string Path_GetThisModulePath();
|
||||
|
||||
/** Returns the specified path without its filename.
|
||||
* If slash is unspecified the native path separator of the current platform
|
||||
* will be used. */
|
||||
std::string Path_StripFilename(const std::string &sPath, char slash = 0);
|
||||
|
||||
/** returns just the filename from the provided full or relative path. */
|
||||
std::string Path_StripDirectory(const std::string &sPath, char slash = 0);
|
||||
|
||||
/** returns just the filename with no extension of the provided filename.
|
||||
* If there is a path the path is left intact. */
|
||||
std::string Path_StripExtension(const std::string &sPath);
|
||||
|
||||
/** returns just extension of the provided filename (if any). */
|
||||
std::string Path_GetExtension(const std::string &sPath);
|
||||
|
||||
/** Returns true if the path is absolute */
|
||||
bool Path_IsAbsolute(const std::string &sPath);
|
||||
|
||||
/** Makes an absolute path from a relative path and a base path */
|
||||
std::string Path_MakeAbsolute(const std::string &sRelativePath, const std::string &sBasePath, char slash = 0);
|
||||
|
||||
/** Fixes the directory separators for the current platform.
|
||||
* If slash is unspecified the native path separator of the current platform
|
||||
* will be used. */
|
||||
std::string Path_FixSlashes(const std::string &sPath, char slash = 0);
|
||||
|
||||
/** Returns the path separator for the current platform */
|
||||
char Path_GetSlash();
|
||||
|
||||
/** Jams two paths together with the right kind of slash */
|
||||
std::string Path_Join(const std::string &first, const std::string &second, char slash = 0);
|
||||
std::string Path_Join(const std::string &first, const std::string &second, const std::string &third, char slash = 0);
|
||||
std::string Path_Join(const std::string &first, const std::string &second, const std::string &third, const std::string &fourth, char slash = 0);
|
||||
std::string Path_Join(
|
||||
const std::string &first,
|
||||
const std::string &second,
|
||||
const std::string &third,
|
||||
const std::string &fourth,
|
||||
const std::string &fifth,
|
||||
char slash = 0);
|
||||
|
||||
/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the
|
||||
* specified path has a broken number of directories for its number of ..s.
|
||||
* If slash is unspecified the native path separator of the current platform
|
||||
* will be used. */
|
||||
std::string Path_Compact(const std::string &sRawPath, char slash = 0);
|
||||
|
||||
//** Removed trailing slashes */
|
||||
std::string Path_RemoveTrailingSlash(const std::string &sRawPath, char slash = 0);
|
||||
|
||||
/** returns true if the specified path exists and is a directory */
|
||||
bool Path_IsDirectory(const std::string &sPath);
|
||||
|
||||
/** returns true if the specified path represents an app bundle */
|
||||
bool Path_IsAppBundle(const std::string &sPath);
|
||||
|
||||
/** returns true if the the path exists */
|
||||
bool Path_Exists(const std::string &sPath);
|
||||
|
||||
/** Helper functions to find parent directories or subdirectories of parent directories */
|
||||
std::string Path_FindParentDirectoryRecursively(const std::string &strStartDirectory, const std::string &strDirectoryName);
|
||||
std::string Path_FindParentSubDirectoryRecursively(const std::string &strStartDirectory, const std::string &strDirectoryName);
|
||||
|
||||
/** Path operations to read or write text/binary files */
|
||||
unsigned char *Path_ReadBinaryFile(const std::string &strFilename, int *pSize);
|
||||
uint32_t Path_ReadBinaryFile(const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize);
|
||||
bool Path_WriteBinaryFile(const std::string &strFilename, unsigned char *pData, unsigned nSize);
|
||||
std::string Path_ReadTextFile(const std::string &strFilename);
|
||||
bool Path_WriteStringToTextFile(const std::string &strFilename, const char *pchData);
|
||||
bool Path_WriteStringToTextFileAtomic(const std::string &strFilename, const char *pchData);
|
||||
|
||||
/** Returns a file:// url for paths, or an http or https url if that's what was provided */
|
||||
std::string Path_FilePathToUrl(const std::string &sRelativePath, const std::string &sBasePath);
|
||||
|
||||
/** Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned */
|
||||
std::string Path_UrlToFilePath(const std::string &sFileUrl);
|
||||
|
||||
/** Returns the root of the directory the system wants us to store user documents in */
|
||||
std::string GetUserDocumentsPath();
|
||||
|
||||
#ifndef MAX_UNICODE_PATH
|
||||
#define MAX_UNICODE_PATH 32767
|
||||
#endif
|
||||
|
||||
#ifndef MAX_UNICODE_PATH_IN_UTF8
|
||||
#define MAX_UNICODE_PATH_IN_UTF8 (MAX_UNICODE_PATH * 4)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#if defined(_WIN32)
|
||||
#define DYNAMIC_LIB_EXT ".dll"
|
||||
#ifdef _WIN64
|
||||
#define PLATSUBDIR "win64"
|
||||
#else
|
||||
#define PLATSUBDIR "win32"
|
||||
#endif
|
||||
#elif defined(OSX)
|
||||
#define DYNAMIC_LIB_EXT ".dylib"
|
||||
#define PLATSUBDIR "osx32"
|
||||
#elif defined(LINUX)
|
||||
#define DYNAMIC_LIB_EXT ".so"
|
||||
#if defined(LINUX32)
|
||||
#define PLATSUBDIR "linux32"
|
||||
#else
|
||||
#define PLATSUBDIR "linux64"
|
||||
#endif
|
||||
#else
|
||||
#warning "Unknown platform for PLATSUBDIR"
|
||||
#define PLATSUBDIR "unknown_platform"
|
||||
#endif
|
||||
|
|
@ -0,0 +1,431 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#include "strtools.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool StringHasPrefix(const std::string &sString, const std::string &sPrefix)
|
||||
{
|
||||
return 0 == strnicmp(sString.c_str(), sPrefix.c_str(), sPrefix.length());
|
||||
}
|
||||
|
||||
bool StringHasPrefixCaseSensitive(const std::string &sString, const std::string &sPrefix)
|
||||
{
|
||||
return 0 == strncmp(sString.c_str(), sPrefix.c_str(), sPrefix.length());
|
||||
}
|
||||
|
||||
bool StringHasSuffix(const std::string &sString, const std::string &sSuffix)
|
||||
{
|
||||
size_t cStrLen = sString.length();
|
||||
size_t cSuffixLen = sSuffix.length();
|
||||
|
||||
if (cSuffixLen > cStrLen)
|
||||
return false;
|
||||
|
||||
std::string sStringSuffix = sString.substr(cStrLen - cSuffixLen, cSuffixLen);
|
||||
|
||||
return 0 == stricmp(sStringSuffix.c_str(), sSuffix.c_str());
|
||||
}
|
||||
|
||||
bool StringHasSuffixCaseSensitive(const std::string &sString, const std::string &sSuffix)
|
||||
{
|
||||
size_t cStrLen = sString.length();
|
||||
size_t cSuffixLen = sSuffix.length();
|
||||
|
||||
if (cSuffixLen > cStrLen)
|
||||
return false;
|
||||
|
||||
std::string sStringSuffix = sString.substr(cStrLen - cSuffixLen, cSuffixLen);
|
||||
|
||||
return 0 == strncmp(sStringSuffix.c_str(), sSuffix.c_str(), cSuffixLen);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string UTF16to8(const wchar_t *in)
|
||||
{
|
||||
std::string out;
|
||||
unsigned int codepoint = 0;
|
||||
for (; in && *in != 0; ++in)
|
||||
{
|
||||
if (*in >= 0xd800 && *in <= 0xdbff)
|
||||
codepoint = ((*in - 0xd800) << 10) + 0x10000;
|
||||
else
|
||||
{
|
||||
if (*in >= 0xdc00 && *in <= 0xdfff)
|
||||
codepoint |= *in - 0xdc00;
|
||||
else
|
||||
codepoint = *in;
|
||||
|
||||
if (codepoint <= 0x7f)
|
||||
out.append(1, static_cast<char>(codepoint));
|
||||
else if (codepoint <= 0x7ff)
|
||||
{
|
||||
out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
else if (codepoint <= 0xffff)
|
||||
{
|
||||
out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
codepoint = 0;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::wstring UTF8to16(const char *in)
|
||||
{
|
||||
std::wstring out;
|
||||
unsigned int codepoint = 0;
|
||||
int following = 0;
|
||||
for (; in && *in != 0; ++in)
|
||||
{
|
||||
unsigned char ch = *in;
|
||||
if (ch <= 0x7f)
|
||||
{
|
||||
codepoint = ch;
|
||||
following = 0;
|
||||
}
|
||||
else if (ch <= 0xbf)
|
||||
{
|
||||
if (following > 0)
|
||||
{
|
||||
codepoint = (codepoint << 6) | (ch & 0x3f);
|
||||
--following;
|
||||
}
|
||||
}
|
||||
else if (ch <= 0xdf)
|
||||
{
|
||||
codepoint = ch & 0x1f;
|
||||
following = 1;
|
||||
}
|
||||
else if (ch <= 0xef)
|
||||
{
|
||||
codepoint = ch & 0x0f;
|
||||
following = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
codepoint = ch & 0x07;
|
||||
following = 3;
|
||||
}
|
||||
if (following == 0)
|
||||
{
|
||||
if (codepoint > 0xffff)
|
||||
{
|
||||
out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10)));
|
||||
out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff)));
|
||||
}
|
||||
else
|
||||
out.append(1, static_cast<wchar_t>(codepoint));
|
||||
codepoint = 0;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void strcpy_safe(char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource)
|
||||
{
|
||||
pchBuffer[unBufferSizeBytes - 1] = '\0';
|
||||
strncpy(pchBuffer, pchSource, unBufferSizeBytes - 1);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Purpose: converts a string to upper case
|
||||
// --------------------------------------------------------------------
|
||||
std::string StringToUpper(const std::string &sString)
|
||||
{
|
||||
std::string sOut;
|
||||
sOut.reserve(sString.size() + 1);
|
||||
for (std::string::const_iterator i = sString.begin(); i != sString.end(); i++)
|
||||
{
|
||||
sOut.push_back((char)toupper(*i));
|
||||
}
|
||||
|
||||
return sOut;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Purpose: converts a string to lower case
|
||||
// --------------------------------------------------------------------
|
||||
std::string StringToLower(const std::string &sString)
|
||||
{
|
||||
std::string sOut;
|
||||
sOut.reserve(sString.size() + 1);
|
||||
for (std::string::const_iterator i = sString.begin(); i != sString.end(); i++)
|
||||
{
|
||||
sOut.push_back((char)tolower(*i));
|
||||
}
|
||||
|
||||
return sOut;
|
||||
}
|
||||
|
||||
uint32_t ReturnStdString(const std::string &sValue, char *pchBuffer, uint32_t unBufferLen)
|
||||
{
|
||||
uint32_t unLen = (uint32_t)sValue.length() + 1;
|
||||
if (!pchBuffer || !unBufferLen)
|
||||
return unLen;
|
||||
|
||||
if (unBufferLen < unLen)
|
||||
{
|
||||
pchBuffer[0] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pchBuffer, sValue.c_str(), unLen);
|
||||
}
|
||||
|
||||
return unLen;
|
||||
}
|
||||
|
||||
void BufferToStdString(std::string &sDest, const char *pchBuffer, uint32_t unBufferLen)
|
||||
{
|
||||
sDest.resize(unBufferLen + 1);
|
||||
memcpy(const_cast<char *>(sDest.c_str()), pchBuffer, unBufferLen);
|
||||
const_cast<char *>(sDest.c_str())[unBufferLen] = '\0';
|
||||
}
|
||||
|
||||
/** Returns a std::string from a uint64_t */
|
||||
std::string Uint64ToString(uint64_t ulValue)
|
||||
{
|
||||
char buf[22];
|
||||
#if defined(_WIN32)
|
||||
sprintf_s(buf, "%llu", ulValue);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "%llu", (long long unsigned int)ulValue);
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** returns a uint64_t from a string */
|
||||
uint64_t StringToUint64(const std::string &sValue)
|
||||
{
|
||||
return strtoull(sValue.c_str(), NULL, 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Helper for converting a numeric value to a hex digit, value should be 0-15.
|
||||
//-----------------------------------------------------------------------------
|
||||
char cIntToHexDigit(int nValue)
|
||||
{
|
||||
//Assert( nValue >= 0 && nValue <= 15 );
|
||||
return "0123456789ABCDEF"[nValue & 15];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Helper for converting a hex char value to numeric, return -1 if the char
|
||||
// is not a valid hex digit.
|
||||
//-----------------------------------------------------------------------------
|
||||
int iHexCharToInt(char cValue)
|
||||
{
|
||||
int32_t iValue = cValue;
|
||||
if ((uint32_t)(iValue - '0') < 10)
|
||||
return iValue - '0';
|
||||
|
||||
iValue |= 0x20;
|
||||
if ((uint32_t)(iValue - 'a') < 6)
|
||||
return iValue - 'a' + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Internal implementation of encode, works in the strict RFC manner, or
|
||||
// with spaces turned to + like HTML form encoding.
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_URLEncodeInternal(char *pchDest, int nDestLen, const char *pchSource, int nSourceLen, bool bUsePlusForSpace)
|
||||
{
|
||||
//AssertMsg( nDestLen > 3*nSourceLen, "Target buffer for V_URLEncode should be 3x source length, plus one for terminating null\n" );
|
||||
|
||||
int iDestPos = 0;
|
||||
for (int i = 0; i < nSourceLen; ++i)
|
||||
{
|
||||
// worst case we need 3 additional chars
|
||||
if ((iDestPos + 3) > nDestLen)
|
||||
{
|
||||
pchDest[0] = '\0';
|
||||
// AssertMsg( false, "Target buffer too short\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// We allow only a-z, A-Z, 0-9, period, underscore, and hyphen to pass through unescaped.
|
||||
// These are the characters allowed by both the original RFC 1738 and the latest RFC 3986.
|
||||
// Current specs also allow '~', but that is forbidden under original RFC 1738.
|
||||
if (!(pchSource[i] >= 'a' && pchSource[i] <= 'z') && !(pchSource[i] >= 'A' && pchSource[i] <= 'Z') && !(pchSource[i] >= '0' && pchSource[i] <= '9') && pchSource[i] != '-' && pchSource[i] != '_' && pchSource[i] != '.')
|
||||
{
|
||||
if (bUsePlusForSpace && pchSource[i] == ' ')
|
||||
{
|
||||
pchDest[iDestPos++] = '+';
|
||||
}
|
||||
else
|
||||
{
|
||||
pchDest[iDestPos++] = '%';
|
||||
uint8_t iValue = pchSource[i];
|
||||
if (iValue == 0)
|
||||
{
|
||||
pchDest[iDestPos++] = '0';
|
||||
pchDest[iDestPos++] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
char cHexDigit1 = cIntToHexDigit(iValue % 16);
|
||||
iValue /= 16;
|
||||
char cHexDigit2 = cIntToHexDigit(iValue);
|
||||
pchDest[iDestPos++] = cHexDigit2;
|
||||
pchDest[iDestPos++] = cHexDigit1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pchDest[iDestPos++] = pchSource[i];
|
||||
}
|
||||
}
|
||||
|
||||
if ((iDestPos + 1) > nDestLen)
|
||||
{
|
||||
pchDest[0] = '\0';
|
||||
//AssertMsg( false, "Target buffer too short to terminate\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Null terminate
|
||||
pchDest[iDestPos++] = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Internal implementation of decode, works in the strict RFC manner, or
|
||||
// with spaces turned to + like HTML form encoding.
|
||||
//
|
||||
// Returns the amount of space used in the output buffer.
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t V_URLDecodeInternal(char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen, bool bUsePlusForSpace)
|
||||
{
|
||||
if (nDecodeDestLen < nEncodedSourceLen)
|
||||
{
|
||||
//AssertMsg( false, "V_URLDecode needs a dest buffer at least as large as the source" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iDestPos = 0;
|
||||
for (int i = 0; i < nEncodedSourceLen; ++i)
|
||||
{
|
||||
if (bUsePlusForSpace && pchEncodedSource[i] == '+')
|
||||
{
|
||||
pchDecodeDest[iDestPos++] = ' ';
|
||||
}
|
||||
else if (pchEncodedSource[i] == '%')
|
||||
{
|
||||
// Percent signifies an encoded value, look ahead for the hex code, convert to numeric, and use that
|
||||
|
||||
// First make sure we have 2 more chars
|
||||
if (i < nEncodedSourceLen - 2)
|
||||
{
|
||||
char cHexDigit1 = pchEncodedSource[i + 1];
|
||||
char cHexDigit2 = pchEncodedSource[i + 2];
|
||||
|
||||
// Turn the chars into a hex value, if they are not valid, then we'll
|
||||
// just place the % and the following two chars direct into the string,
|
||||
// even though this really shouldn't happen, who knows what bad clients
|
||||
// may do with encoding.
|
||||
bool bValid = false;
|
||||
int iValue = iHexCharToInt(cHexDigit1);
|
||||
if (iValue != -1)
|
||||
{
|
||||
iValue *= 16;
|
||||
int iValue2 = iHexCharToInt(cHexDigit2);
|
||||
if (iValue2 != -1)
|
||||
{
|
||||
iValue += iValue2;
|
||||
pchDecodeDest[iDestPos++] = (char)iValue;
|
||||
bValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bValid)
|
||||
{
|
||||
pchDecodeDest[iDestPos++] = '%';
|
||||
pchDecodeDest[iDestPos++] = cHexDigit1;
|
||||
pchDecodeDest[iDestPos++] = cHexDigit2;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip ahead
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
pchDecodeDest[iDestPos++] = pchEncodedSource[i];
|
||||
}
|
||||
}
|
||||
|
||||
// We may not have extra room to NULL terminate, since this can be used on raw data, but if we do
|
||||
// go ahead and do it as this can avoid bugs.
|
||||
if (iDestPos < nDecodeDestLen)
|
||||
{
|
||||
pchDecodeDest[iDestPos] = 0;
|
||||
}
|
||||
|
||||
return (size_t)iDestPos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
|
||||
// This version of the call isn't a strict RFC implementation, but uses + for space as is
|
||||
// the standard in HTML form encoding, despite it not being part of the RFC.
|
||||
//
|
||||
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_URLEncode(char *pchDest, int nDestLen, const char *pchSource, int nSourceLen)
|
||||
{
|
||||
return V_URLEncodeInternal(pchDest, nDestLen, pchSource, nSourceLen, true);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
|
||||
// This version of the call isn't a strict RFC implementation, but uses + for space as is
|
||||
// the standard in HTML form encoding, despite it not being part of the RFC.
|
||||
//
|
||||
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
|
||||
// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t V_URLDecode(char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen)
|
||||
{
|
||||
return V_URLDecodeInternal(pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, true);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_StripExtension(std::string &in)
|
||||
{
|
||||
// Find the last dot. If it's followed by a dot or a slash, then it's part of a
|
||||
// directory specifier like ../../somedir/./blah.
|
||||
std::string::size_type test = in.rfind('.');
|
||||
if (test != std::string::npos)
|
||||
{
|
||||
// This handles things like ".\blah" or "c:\my@email.com\abc\def\geh"
|
||||
// Which would otherwise wind up with "" and "c:\my@email", respectively.
|
||||
if (in.rfind('\\') < test && in.rfind('/') < test)
|
||||
{
|
||||
in.resize(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
//========= Copyright Valve Corporation ============//
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/** returns true if the string has the prefix */
|
||||
bool StringHasPrefix(const std::string &sString, const std::string &sPrefix);
|
||||
bool StringHasPrefixCaseSensitive(const std::string &sString, const std::string &sPrefix);
|
||||
|
||||
/** returns if the string has the suffix */
|
||||
bool StringHasSuffix(const std::string &sString, const std::string &sSuffix);
|
||||
bool StringHasSuffixCaseSensitive(const std::string &sString, const std::string &sSuffix);
|
||||
|
||||
/** converts a UTF-16 string to a UTF-8 string */
|
||||
std::string UTF16to8(const wchar_t *in);
|
||||
|
||||
/** converts a UTF-8 string to a UTF-16 string */
|
||||
std::wstring UTF8to16(const char *in);
|
||||
#define Utf16FromUtf8 UTF8to16
|
||||
|
||||
/** safely copy a string into a buffer */
|
||||
void strcpy_safe(char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource);
|
||||
template <size_t bufferSize>
|
||||
void strcpy_safe(char (&buffer)[bufferSize], const char *pchSource)
|
||||
{
|
||||
strcpy_safe(buffer, bufferSize, pchSource);
|
||||
}
|
||||
|
||||
/** converts a string to upper case */
|
||||
std::string StringToUpper(const std::string &sString);
|
||||
|
||||
/** converts a string to lower case */
|
||||
std::string StringToLower(const std::string &sString);
|
||||
|
||||
// we stricmp (from WIN) but it isn't POSIX - OSX/LINUX have strcasecmp so just inline bridge to it
|
||||
#if defined(OSX) || defined(LINUX)
|
||||
#ifndef __THROW // If __THROW is defined, these will clash with throw() versions on gcc
|
||||
#include <strings.h>
|
||||
inline int stricmp(const char *pStr1, const char *pStr2)
|
||||
{
|
||||
return strcasecmp(pStr1, pStr2);
|
||||
}
|
||||
#ifndef _stricmp
|
||||
#define _stricmp stricmp
|
||||
#endif
|
||||
inline int strnicmp(const char *pStr1, const char *pStr2, size_t unBufferLen)
|
||||
{
|
||||
return strncasecmp(pStr1, pStr2, unBufferLen);
|
||||
}
|
||||
#define _strnicmp strnicmp
|
||||
#endif
|
||||
|
||||
#ifndef _vsnprintf_s
|
||||
#define _vsnprintf_s vsnprintf
|
||||
#endif
|
||||
|
||||
#define _TRUNCATE ((size_t)-1)
|
||||
|
||||
#endif // defined( OSX ) || defined( LINUX )
|
||||
|
||||
#if defined(OSX)
|
||||
// behaviors ensure NULL-termination at least as well as _TRUNCATE does, but
|
||||
// wcsncpy_s/strncpy_s can non-NULL-terminate, wcslcpy/strlcpy can not.
|
||||
inline errno_t wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
|
||||
{
|
||||
return wcslcpy(strDest, strSource, numberOfElements);
|
||||
}
|
||||
|
||||
inline errno_t strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
|
||||
{
|
||||
return strlcpy(strDest, strSource, numberOfElements);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(LINUX)
|
||||
// this implementation does not return whether or not the destination was
|
||||
// truncated, but that is straightforward to fix if anybody actually needs the
|
||||
// return code.
|
||||
#include "string.h"
|
||||
inline void wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
|
||||
{
|
||||
wcsncpy(strDest, strSource, numberOfElements);
|
||||
strDest[numberOfElements - 1] = '\0';
|
||||
}
|
||||
|
||||
inline void strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
|
||||
{
|
||||
strncpy(strDest, strSource, numberOfElements);
|
||||
strDest[numberOfElements - 1] = '\0';
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && _MSC_VER < 1800
|
||||
inline uint64_t strtoull(const char *str, char **endptr, int base)
|
||||
{
|
||||
return _strtoui64(str, endptr, base);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handles copying a std::string into a buffer as would be provided in an API */
|
||||
uint32_t ReturnStdString(const std::string &sValue, char *pchBuffer, uint32_t unBufferLen);
|
||||
|
||||
/* Handles copying a buffer into an std::string and auto adds null terminator */
|
||||
void BufferToStdString(std::string &sDest, const char *pchBuffer, uint32_t unBufferLen);
|
||||
|
||||
/** Returns a std::string from a uint64_t */
|
||||
std::string Uint64ToString(uint64_t ulValue);
|
||||
|
||||
/** returns a uint64_t from a string */
|
||||
uint64_t StringToUint64(const std::string &sValue);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
|
||||
// This version of the call isn't a strict RFC implementation, but uses + for space as is
|
||||
// the standard in HTML form encoding, despite it not being part of the RFC.
|
||||
//
|
||||
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_URLEncode(char *pchDest, int nDestLen, const char *pchSource, int nSourceLen);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
|
||||
// This version of the call isn't a strict RFC implementation, but uses + for space as is
|
||||
// the standard in HTML form encoding, despite it not being part of the RFC.
|
||||
//
|
||||
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
|
||||
// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t V_URLDecode(char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: strip extension from a path
|
||||
//-----------------------------------------------------------------------------
|
||||
void V_StripExtension(std::string &in);
|
||||
Loading…
Add table
Add a link
Reference in a new issue