Files
SingularityViewer/indra/llmath/llcoordframe.cpp

779 lines
18 KiB
C++

/**
* @file llcoordframe.cpp
* @brief LLCoordFrame class implementation.
*
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
//#include "vmath.h"
#include "v3math.h"
#include "m3math.h"
#include "v4math.h"
#include "m4math.h"
#include "llquaternion.h"
#include "llcoordframe.h"
#ifndef X_AXIS
#define X_AXIS 1.0f,0.0f,0.0f
#define Y_AXIS 0.0f,1.0f,0.0f
#define Z_AXIS 0.0f,0.0f,1.0f
#endif
// Constructors
LLCoordFrame::LLCoordFrame() :
mOrigin(0.f, 0.f, 0.f),
mXAxis(X_AXIS),
mYAxis(Y_AXIS),
mZAxis(Z_AXIS)
{
}
LLCoordFrame::LLCoordFrame(const LLVector3 &origin) :
mOrigin(origin),
mXAxis(X_AXIS),
mYAxis(Y_AXIS),
mZAxis(Z_AXIS)
{
if( !mOrigin.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLVector3 &direction) :
mOrigin(origin)
{
lookDir(direction);
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
LLCoordFrame::LLCoordFrame(const LLVector3 &x_axis,
const LLVector3 &y_axis,
const LLVector3 &z_axis) :
mOrigin(0.f, 0.f, 0.f),
mXAxis(x_axis),
mYAxis(y_axis),
mZAxis(z_axis)
{
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
LLCoordFrame::LLCoordFrame(const LLVector3 &origin,
const LLVector3 &x_axis,
const LLVector3 &y_axis,
const LLVector3 &z_axis) :
mOrigin(origin),
mXAxis(x_axis),
mYAxis(y_axis),
mZAxis(z_axis)
{
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
LLCoordFrame::LLCoordFrame(const LLVector3 &origin,
const LLMatrix3 &rotation) :
mOrigin(origin),
mXAxis(rotation.mMatrix[VX]),
mYAxis(rotation.mMatrix[VY]),
mZAxis(rotation.mMatrix[VZ])
{
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
LLCoordFrame::LLCoordFrame(const LLQuaternion &q) :
mOrigin(0.f, 0.f, 0.f)
{
LLMatrix3 rotation_matrix(q);
mXAxis.setVec(rotation_matrix.mMatrix[VX]);
mYAxis.setVec(rotation_matrix.mMatrix[VY]);
mZAxis.setVec(rotation_matrix.mMatrix[VZ]);
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLQuaternion &q) :
mOrigin(origin)
{
LLMatrix3 rotation_matrix(q);
mXAxis.setVec(rotation_matrix.mMatrix[VX]);
mYAxis.setVec(rotation_matrix.mMatrix[VY]);
mZAxis.setVec(rotation_matrix.mMatrix[VZ]);
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
LLCoordFrame::LLCoordFrame(const LLMatrix4 &mat) :
mOrigin(mat.mMatrix[VW]),
mXAxis(mat.mMatrix[VX]),
mYAxis(mat.mMatrix[VY]),
mZAxis(mat.mMatrix[VZ])
{
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
// The folowing two constructors are dangerous due to implicit casting and have been disabled - SJB
/*
LLCoordFrame::LLCoordFrame(const F32 *origin, const F32 *rotation) :
mOrigin(origin),
mXAxis(rotation+3*VX),
mYAxis(rotation+3*VY),
mZAxis(rotation+3*VZ)
{
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
*/
/*
LLCoordFrame::LLCoordFrame(const F32 *origin_and_rotation) :
mOrigin(origin_and_rotation),
mXAxis(origin_and_rotation + 3*(VX+1)),
mYAxis(origin_and_rotation + 3*(VY+1)),
mZAxis(origin_and_rotation + 3*(VZ+1))
{
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::LLCoordFrame()" << LL_ENDL;
}
}
*/
void LLCoordFrame::reset()
{
mOrigin.setVec(0.0f, 0.0f, 0.0f);
resetAxes();
}
void LLCoordFrame::resetAxes()
{
mXAxis.setVec(1.0f, 0.0f, 0.0f);
mYAxis.setVec(0.0f, 1.0f, 0.0f);
mZAxis.setVec(0.0f, 0.0f, 1.0f);
}
// setOrigin() member functions set mOrigin
void LLCoordFrame::setOrigin(F32 x, F32 y, F32 z)
{
mOrigin.setVec(x, y, z);
if( !mOrigin.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setOrigin()" << LL_ENDL;
}
}
void LLCoordFrame::setOrigin(const LLVector3 &new_origin)
{
mOrigin = new_origin;
if( !mOrigin.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setOrigin()" << LL_ENDL;
}
}
void LLCoordFrame::setOrigin(const F32 *origin)
{
mOrigin.mV[VX] = *(origin + VX);
mOrigin.mV[VY] = *(origin + VY);
mOrigin.mV[VZ] = *(origin + VZ);
if( !mOrigin.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setOrigin()" << LL_ENDL;
}
}
void LLCoordFrame::setOrigin(const LLCoordFrame &frame)
{
mOrigin = frame.getOrigin();
if( !mOrigin.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setOrigin()" << LL_ENDL;
}
}
// setAxes() member functions set the axes, and assume that
// the arguments are orthogonal and normalized.
void LLCoordFrame::setAxes(const LLVector3 &x_axis,
const LLVector3 &y_axis,
const LLVector3 &z_axis)
{
mXAxis = x_axis;
mYAxis = y_axis;
mZAxis = z_axis;
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL;
}
}
void LLCoordFrame::setAxes(const LLMatrix3 &rotation_matrix)
{
mXAxis.setVec(rotation_matrix.mMatrix[VX]);
mYAxis.setVec(rotation_matrix.mMatrix[VY]);
mZAxis.setVec(rotation_matrix.mMatrix[VZ]);
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL;
}
}
void LLCoordFrame::setAxes(const LLQuaternion &q )
{
LLMatrix3 rotation_matrix(q);
setAxes(rotation_matrix);
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL;
}
}
void LLCoordFrame::setAxes( const F32 *rotation_matrix )
{
mXAxis.mV[VX] = *(rotation_matrix + 3*VX + VX);
mXAxis.mV[VY] = *(rotation_matrix + 3*VX + VY);
mXAxis.mV[VZ] = *(rotation_matrix + 3*VX + VZ);
mYAxis.mV[VX] = *(rotation_matrix + 3*VY + VX);
mYAxis.mV[VY] = *(rotation_matrix + 3*VY + VY);
mYAxis.mV[VZ] = *(rotation_matrix + 3*VY + VZ);
mZAxis.mV[VX] = *(rotation_matrix + 3*VZ + VX);
mZAxis.mV[VY] = *(rotation_matrix + 3*VZ + VY);
mZAxis.mV[VZ] = *(rotation_matrix + 3*VZ + VZ);
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL;
}
}
void LLCoordFrame::setAxes(const LLCoordFrame &frame)
{
mXAxis = frame.getXAxis();
mYAxis = frame.getYAxis();
mZAxis = frame.getZAxis();
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::setAxes()" << LL_ENDL;
}
}
// translate() member functions move mOrigin to a relative position
void LLCoordFrame::translate(F32 x, F32 y, F32 z)
{
mOrigin.mV[VX] += x;
mOrigin.mV[VY] += y;
mOrigin.mV[VZ] += z;
if( !mOrigin.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::translate()" << LL_ENDL;
}
}
void LLCoordFrame::translate(const LLVector3 &v)
{
mOrigin += v;
if( !mOrigin.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::translate()" << LL_ENDL;
}
}
void LLCoordFrame::translate(const F32 *origin)
{
mOrigin.mV[VX] += *(origin + VX);
mOrigin.mV[VY] += *(origin + VY);
mOrigin.mV[VZ] += *(origin + VZ);
if( !mOrigin.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::translate()" << LL_ENDL;
}
}
// Rotate move the axes to a relative rotation
void LLCoordFrame::rotate(F32 angle, F32 x, F32 y, F32 z)
{
LLQuaternion q(angle, LLVector3(x,y,z));
rotate(q);
}
void LLCoordFrame::rotate(F32 angle, const LLVector3 &rotation_axis)
{
LLQuaternion q(angle, rotation_axis);
rotate(q);
}
void LLCoordFrame::rotate(const LLQuaternion &q)
{
LLMatrix3 rotation_matrix(q);
rotate(rotation_matrix);
}
void LLCoordFrame::rotate(const LLMatrix3 &rotation_matrix)
{
mXAxis.rotVec(rotation_matrix);
mYAxis.rotVec(rotation_matrix);
orthonormalize();
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::rotate()" << LL_ENDL;
}
}
void LLCoordFrame::roll(F32 angle)
{
LLQuaternion q(angle, mXAxis);
LLMatrix3 rotation_matrix(q);
rotate(rotation_matrix);
if( !mYAxis.isFinite() || !mZAxis.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::roll()" << LL_ENDL;
}
}
void LLCoordFrame::pitch(F32 angle)
{
LLQuaternion q(angle, mYAxis);
LLMatrix3 rotation_matrix(q);
rotate(rotation_matrix);
if( !mXAxis.isFinite() || !mZAxis.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::pitch()" << LL_ENDL;
}
}
void LLCoordFrame::yaw(F32 angle)
{
LLQuaternion q(angle, mZAxis);
LLMatrix3 rotation_matrix(q);
rotate(rotation_matrix);
if( !mXAxis.isFinite() || !mYAxis.isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::yaw()" << LL_ENDL;
}
}
// get*() routines
LLQuaternion LLCoordFrame::getQuaternion() const
{
LLQuaternion quat(mXAxis, mYAxis, mZAxis);
return quat;
}
void LLCoordFrame::getMatrixToLocal(LLMatrix4& mat) const
{
mat.setFwdCol(mXAxis);
mat.setLeftCol(mYAxis);
mat.setUpCol(mZAxis);
mat.mMatrix[3][0] = -(mOrigin * LLVector3(mat.mMatrix[0][0], mat.mMatrix[1][0], mat.mMatrix[2][0]));
mat.mMatrix[3][1] = -(mOrigin * LLVector3(mat.mMatrix[0][1], mat.mMatrix[1][1], mat.mMatrix[2][1]));
mat.mMatrix[3][2] = -(mOrigin * LLVector3(mat.mMatrix[0][2], mat.mMatrix[1][2], mat.mMatrix[2][2]));
}
void LLCoordFrame::getRotMatrixToParent(LLMatrix4& mat) const
{
// Note: moves into CFR
mat.setFwdRow( -mYAxis );
mat.setLeftRow( mZAxis );
mat.setUpRow( -mXAxis );
}
size_t LLCoordFrame::writeOrientation(char *buffer) const
{
memcpy(buffer, mOrigin.mV, 3*sizeof(F32)); /*Flawfinder: ignore */
buffer += 3*sizeof(F32);
memcpy(buffer, mXAxis.mV, 3*sizeof(F32)); /*Flawfinder: ignore */
buffer += 3*sizeof(F32);
memcpy(buffer, mYAxis.mV, 3*sizeof(F32));/*Flawfinder: ignore */
buffer += 3*sizeof(F32);
memcpy(buffer, mZAxis.mV, 3*sizeof(F32)); /*Flawfinder: ignore */
return 12*sizeof(F32);
}
size_t LLCoordFrame::readOrientation(const char *buffer)
{
memcpy(mOrigin.mV, buffer, 3*sizeof(F32)); /*Flawfinder: ignore */
buffer += 3*sizeof(F32);
memcpy(mXAxis.mV, buffer, 3*sizeof(F32)); /*Flawfinder: ignore */
buffer += 3*sizeof(F32);
memcpy(mYAxis.mV, buffer, 3*sizeof(F32)); /*Flawfinder: ignore */
buffer += 3*sizeof(F32);
memcpy(mZAxis.mV, buffer, 3*sizeof(F32)); /*Flawfinder: ignore */
if( !isFinite() )
{
reset();
LL_WARNS() << "Non Finite in LLCoordFrame::readOrientation()" << LL_ENDL;
}
return 12*sizeof(F32);
}
// rotation and transform vectors between reference frames
LLVector3 LLCoordFrame::rotateToLocal(const LLVector3 &absolute_vector) const
{
LLVector3 local_vector(mXAxis * absolute_vector,
mYAxis * absolute_vector,
mZAxis * absolute_vector);
return local_vector;
}
LLVector4 LLCoordFrame::rotateToLocal(const LLVector4 &absolute_vector) const
{
LLVector4 local_vector;
local_vector.mV[VX] = mXAxis.mV[VX] * absolute_vector.mV[VX] +
mXAxis.mV[VY] * absolute_vector.mV[VY] +
mXAxis.mV[VZ] * absolute_vector.mV[VZ];
local_vector.mV[VY] = mYAxis.mV[VX] * absolute_vector.mV[VX] +
mYAxis.mV[VY] * absolute_vector.mV[VY] +
mYAxis.mV[VZ] * absolute_vector.mV[VZ];
local_vector.mV[VZ] = mZAxis.mV[VX] * absolute_vector.mV[VX] +
mZAxis.mV[VY] * absolute_vector.mV[VY] +
mZAxis.mV[VZ] * absolute_vector.mV[VZ];
local_vector.mV[VW] = absolute_vector.mV[VW];
return local_vector;
}
LLVector3 LLCoordFrame::rotateToAbsolute(const LLVector3 &local_vector) const
{
LLVector3 absolute_vector;
absolute_vector.mV[VX] = mXAxis.mV[VX] * local_vector.mV[VX] +
mYAxis.mV[VX] * local_vector.mV[VY] +
mZAxis.mV[VX] * local_vector.mV[VZ];
absolute_vector.mV[VY] = mXAxis.mV[VY] * local_vector.mV[VX] +
mYAxis.mV[VY] * local_vector.mV[VY] +
mZAxis.mV[VY] * local_vector.mV[VZ];
absolute_vector.mV[VZ] = mXAxis.mV[VZ] * local_vector.mV[VX] +
mYAxis.mV[VZ] * local_vector.mV[VY] +
mZAxis.mV[VZ] * local_vector.mV[VZ];
return absolute_vector;
}
LLVector4 LLCoordFrame::rotateToAbsolute(const LLVector4 &local_vector) const
{
LLVector4 absolute_vector;
absolute_vector.mV[VX] = mXAxis.mV[VX] * local_vector.mV[VX] +
mYAxis.mV[VX] * local_vector.mV[VY] +
mZAxis.mV[VX] * local_vector.mV[VZ];
absolute_vector.mV[VY] = mXAxis.mV[VY] * local_vector.mV[VX] +
mYAxis.mV[VY] * local_vector.mV[VY] +
mZAxis.mV[VY] * local_vector.mV[VZ];
absolute_vector.mV[VZ] = mXAxis.mV[VZ] * local_vector.mV[VX] +
mYAxis.mV[VZ] * local_vector.mV[VY] +
mZAxis.mV[VZ] * local_vector.mV[VZ];
absolute_vector.mV[VW] = local_vector[VW];
return absolute_vector;
}
void LLCoordFrame::orthonormalize()
// Makes sure the axes are orthogonal and normalized.
{
mXAxis.normVec(); // X is renormalized
mYAxis -= mXAxis * (mXAxis * mYAxis); // Y remains in X-Y plane
mYAxis.normVec(); // Y is normalized
mZAxis = mXAxis % mYAxis; // Z = X cross Y
}
LLVector3 LLCoordFrame::transformToLocal(const LLVector3 &absolute_vector) const
{
return rotateToLocal(absolute_vector - mOrigin);
}
LLVector4 LLCoordFrame::transformToLocal(const LLVector4 &absolute_vector) const
{
LLVector4 local_vector(absolute_vector);
local_vector.mV[VX] -= mOrigin.mV[VX];
local_vector.mV[VY] -= mOrigin.mV[VY];
local_vector.mV[VZ] -= mOrigin.mV[VZ];
return rotateToLocal(local_vector);
}
LLVector3 LLCoordFrame::transformToAbsolute(const LLVector3 &local_vector) const
{
return (rotateToAbsolute(local_vector) + mOrigin);
}
LLVector4 LLCoordFrame::transformToAbsolute(const LLVector4 &local_vector) const
{
LLVector4 absolute_vector;
absolute_vector = rotateToAbsolute(local_vector);
absolute_vector.mV[VX] += mOrigin.mV[VX];
absolute_vector.mV[VY] += mOrigin.mV[VY];
absolute_vector.mV[VZ] += mOrigin.mV[VZ];
return absolute_vector;
}
// This is how you combine a translation and rotation of a
// coordinate frame to get an OpenGL transformation matrix:
//
// translation * rotation = transformation matrix
//
// (i)->
// (j)| 1 0 0 0 | | a d g 0 | | a d g 0 |
// | | 0 1 0 0 | * | b e h 0 | = | b e h 0 |
// V | 0 0 1 0 | | c f i 0 | | c f i 0 |
// |-x -y -z 1 | | 0 0 0 1 | |-(ax+by+cz) -(dx+ey+fz) -(gx+hy+iz) 1 |
//
// where {a,b,c} = x-axis
// {d,e,f} = y-axis
// {g,h,i} = z-axis
// {x,y,z} = origin
void LLCoordFrame::getOpenGLTranslation(F32 *ogl_matrix) const
{
*(ogl_matrix + 0) = 1.0f;
*(ogl_matrix + 1) = 0.0f;
*(ogl_matrix + 2) = 0.0f;
*(ogl_matrix + 3) = 0.0f;
*(ogl_matrix + 4) = 0.0f;
*(ogl_matrix + 5) = 1.0f;
*(ogl_matrix + 6) = 0.0f;
*(ogl_matrix + 7) = 0.0f;
*(ogl_matrix + 8) = 0.0f;
*(ogl_matrix + 9) = 0.0f;
*(ogl_matrix + 10) = 1.0f;
*(ogl_matrix + 11) = 0.0f;
*(ogl_matrix + 12) = -mOrigin.mV[VX];
*(ogl_matrix + 13) = -mOrigin.mV[VY];
*(ogl_matrix + 14) = -mOrigin.mV[VZ];
*(ogl_matrix + 15) = 1.0f;
}
void LLCoordFrame::getOpenGLRotation(F32 *ogl_matrix) const
{
*(ogl_matrix + 0) = mXAxis.mV[VX];
*(ogl_matrix + 4) = mXAxis.mV[VY];
*(ogl_matrix + 8) = mXAxis.mV[VZ];
*(ogl_matrix + 1) = mYAxis.mV[VX];
*(ogl_matrix + 5) = mYAxis.mV[VY];
*(ogl_matrix + 9) = mYAxis.mV[VZ];
*(ogl_matrix + 2) = mZAxis.mV[VX];
*(ogl_matrix + 6) = mZAxis.mV[VY];
*(ogl_matrix + 10) = mZAxis.mV[VZ];
*(ogl_matrix + 3) = 0.0f;
*(ogl_matrix + 7) = 0.0f;
*(ogl_matrix + 11) = 0.0f;
*(ogl_matrix + 12) = 0.0f;
*(ogl_matrix + 13) = 0.0f;
*(ogl_matrix + 14) = 0.0f;
*(ogl_matrix + 15) = 1.0f;
}
void LLCoordFrame::getOpenGLTransform(F32 *ogl_matrix) const
{
*(ogl_matrix + 0) = mXAxis.mV[VX];
*(ogl_matrix + 4) = mXAxis.mV[VY];
*(ogl_matrix + 8) = mXAxis.mV[VZ];
*(ogl_matrix + 12) = -mOrigin * mXAxis;
*(ogl_matrix + 1) = mYAxis.mV[VX];
*(ogl_matrix + 5) = mYAxis.mV[VY];
*(ogl_matrix + 9) = mYAxis.mV[VZ];
*(ogl_matrix + 13) = -mOrigin * mYAxis;
*(ogl_matrix + 2) = mZAxis.mV[VX];
*(ogl_matrix + 6) = mZAxis.mV[VY];
*(ogl_matrix + 10) = mZAxis.mV[VZ];
*(ogl_matrix + 14) = -mOrigin * mZAxis;
*(ogl_matrix + 3) = 0.0f;
*(ogl_matrix + 7) = 0.0f;
*(ogl_matrix + 11) = 0.0f;
*(ogl_matrix + 15) = 1.0f;
}
// at and up_direction are presumed to be normalized
void LLCoordFrame::lookDir(const LLVector3 &at, const LLVector3 &up_direction)
{
// Make sure 'at' and 'up_direction' are not parallel
// and that neither are zero-length vectors
LLVector3 left(up_direction % at);
if (left.isNull())
{
//tweak lookat pos so we don't get a degenerate matrix
LLVector3 tempat(at[VX] + 0.01f, at[VY], at[VZ]);
tempat.normVec();
left = (up_direction % tempat);
}
left.normVec();
LLVector3 up = at % left;
if (at.isFinite() && left.isFinite() && up.isFinite())
{
setAxes(at, left, up);
}
}
void LLCoordFrame::lookDir(const LLVector3 &xuv)
{
static LLVector3 up_direction(0.0f, 0.0f, 1.0f);
lookDir(xuv, up_direction);
}
void LLCoordFrame::lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest, const LLVector3 &up_direction)
{
setOrigin(origin);
LLVector3 at(point_of_interest - origin);
at.normVec();
lookDir(at, up_direction);
}
void LLCoordFrame::lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest)
{
static LLVector3 up_direction(0.0f, 0.0f, 1.0f);
setOrigin(origin);
LLVector3 at(point_of_interest - origin);
at.normVec();
lookDir(at, up_direction);
}
// Operators and friends
std::ostream& operator<<(std::ostream &s, const LLCoordFrame &C)
{
s << "{ "
<< " origin = " << C.mOrigin
<< " x_axis = " << C.mXAxis
<< " y_axis = " << C.mYAxis
<< " z_axis = " << C.mZAxis
<< " }";
return s;
}
// Private member functions
//EOF