summaryrefslogtreecommitdiff
path: root/indra/llmath/llcoordframe.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llmath/llcoordframe.cpp
Print done when done.
Diffstat (limited to 'indra/llmath/llcoordframe.cpp')
-rw-r--r--indra/llmath/llcoordframe.cpp729
1 files changed, 729 insertions, 0 deletions
diff --git a/indra/llmath/llcoordframe.cpp b/indra/llmath/llcoordframe.cpp
new file mode 100644
index 0000000000..c8b69e57cd
--- /dev/null
+++ b/indra/llmath/llcoordframe.cpp
@@ -0,0 +1,729 @@
+/**
+ * @file llcoordframe.cpp
+ * @brief LLCoordFrame class implementation.
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+
+LLCoordFrame::LLCoordFrame(const LLVector3 &origin, const LLVector3 &direction) :
+ mOrigin(origin)
+{
+ lookDir(direction);
+
+ if( !isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+
+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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+
+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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+
+
+LLCoordFrame::LLCoordFrame(const LLVector3 &origin,
+ const LLMatrix3 &rotation) :
+ mOrigin(origin),
+ mXAxis(rotation.mMatrix[VX]),
+ mYAxis(rotation.mMatrix[VY]),
+ mZAxis(rotation.mMatrix[VZ])
+{
+ if( !isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+
+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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+
+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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+
+LLCoordFrame::LLCoordFrame(const LLMatrix4 &mat) :
+ mOrigin(mat.mMatrix[VW]),
+ mXAxis(mat.mMatrix[VX]),
+ mYAxis(mat.mMatrix[VY]),
+ mZAxis(mat.mMatrix[VZ])
+{
+ if( !isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+
+
+// 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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+*/
+
+/*
+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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::LLCoordFrame()" << llendl;
+ }
+}
+*/
+
+
+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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setOrigin()" << llendl;
+ }
+}
+
+void LLCoordFrame::setOrigin(const LLVector3 &new_origin)
+{
+ mOrigin = new_origin;
+ if( !mOrigin.isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setOrigin()" << llendl;
+ }
+}
+
+void LLCoordFrame::setOrigin(const F32 *origin)
+{
+ mOrigin.mV[VX] = *(origin + VX);
+ mOrigin.mV[VY] = *(origin + VY);
+ mOrigin.mV[VZ] = *(origin + VZ);
+
+ if( !mOrigin.isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setOrigin()" << llendl;
+ }
+}
+
+void LLCoordFrame::setOrigin(const LLCoordFrame &frame)
+{
+ mOrigin = frame.getOrigin();
+
+ if( !mOrigin.isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setOrigin()" << llendl;
+ }
+}
+
+// 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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
+ }
+}
+
+
+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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
+ }
+}
+
+
+void LLCoordFrame::setAxes(const LLQuaternion &q )
+{
+ LLMatrix3 rotation_matrix(q);
+ setAxes(rotation_matrix);
+ if( !isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
+ }
+}
+
+
+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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
+ }
+}
+
+
+void LLCoordFrame::setAxes(const LLCoordFrame &frame)
+{
+ mXAxis = frame.getXAxis();
+ mYAxis = frame.getYAxis();
+ mZAxis = frame.getZAxis();
+
+ if( !isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::setAxes()" << llendl;
+ }
+}
+
+
+// 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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::translate()" << llendl;
+ }
+}
+
+
+void LLCoordFrame::translate(const LLVector3 &v)
+{
+ mOrigin += v;
+
+ if( !mOrigin.isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::translate()" << llendl;
+ }
+}
+
+
+void LLCoordFrame::translate(const F32 *origin)
+{
+ mOrigin.mV[VX] += *(origin + VX);
+ mOrigin.mV[VY] += *(origin + VY);
+ mOrigin.mV[VZ] += *(origin + VZ);
+
+ if( !mOrigin.isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::translate()" << llendl;
+ }
+}
+
+
+// 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() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::rotate()" << llendl;
+ }
+}
+
+
+void LLCoordFrame::roll(F32 angle)
+{
+ LLQuaternion q(angle, mXAxis);
+ LLMatrix3 rotation_matrix(q);
+ rotate(rotation_matrix);
+
+ if( !mYAxis.isFinite() || !mZAxis.isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::roll()" << llendl;
+ }
+}
+
+void LLCoordFrame::pitch(F32 angle)
+{
+ LLQuaternion q(angle, mYAxis);
+ LLMatrix3 rotation_matrix(q);
+ rotate(rotation_matrix);
+
+ if( !mXAxis.isFinite() || !mZAxis.isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::pitch()" << llendl;
+ }
+}
+
+void LLCoordFrame::yaw(F32 angle)
+{
+ LLQuaternion q(angle, mZAxis);
+ LLMatrix3 rotation_matrix(q);
+ rotate(rotation_matrix);
+
+ if( !mXAxis.isFinite() || !mYAxis.isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::yaw()" << llendl;
+ }
+}
+
+// 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));
+ buffer += 3*sizeof(F32);
+ memcpy(buffer, mXAxis.mV, 3*sizeof(F32));
+ buffer += 3*sizeof(F32);
+ memcpy(buffer, mYAxis.mV, 3*sizeof(F32));
+ buffer += 3*sizeof(F32);
+ memcpy(buffer, mZAxis.mV, 3*sizeof(F32));
+ return 12*sizeof(F32);
+}
+
+
+size_t LLCoordFrame::readOrientation(const char *buffer)
+{
+ memcpy(mOrigin.mV, buffer, 3*sizeof(F32));
+ buffer += 3*sizeof(F32);
+ memcpy(mXAxis.mV, buffer, 3*sizeof(F32));
+ buffer += 3*sizeof(F32);
+ memcpy(mYAxis.mV, buffer, 3*sizeof(F32));
+ buffer += 3*sizeof(F32);
+ memcpy(mZAxis.mV, buffer, 3*sizeof(F32));
+
+ if( !isFinite() )
+ {
+ llerrs << "Non Finite in LLCoordFrame::readOrientation()" << llendl;
+ }
+
+ 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;
+ 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