322 lines
8.0 KiB
C++
322 lines
8.0 KiB
C++
/**
|
|
* @file xform.h
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2001-2009, Linden Research, Inc.
|
|
*
|
|
* Second Life Viewer Source Code
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at
|
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#ifndef LL_XFORM_H
|
|
#define LL_XFORM_H
|
|
|
|
#include "v3math.h"
|
|
#include "m4math.h"
|
|
#include "llquaternion.h"
|
|
|
|
const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f
|
|
const F32 MIN_OBJECT_Z = -256.f;
|
|
const F32 DEFAULT_MAX_PRIM_SCALE = 256.f;
|
|
const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = DEFAULT_MAX_PRIM_SCALE;
|
|
//const F32 MIN_PRIM_SCALE = 0.01f;
|
|
const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
|
|
|
|
class LLXform
|
|
{
|
|
protected:
|
|
LLVector3 mPosition;
|
|
LLQuaternion mRotation;
|
|
LLVector3 mScale;
|
|
|
|
//RN: TODO: move these world transform members to LLXformMatrix
|
|
// as they are *never* updated or accessed in the base class
|
|
LLVector3 mWorldPosition;
|
|
LLQuaternion mWorldRotation;
|
|
|
|
LLXform* mParent;
|
|
U32 mChanged;
|
|
|
|
BOOL mScaleChildOffset;
|
|
|
|
public:
|
|
typedef enum e_changed_flags
|
|
{
|
|
UNCHANGED = 0x00,
|
|
TRANSLATED = 0x01,
|
|
ROTATED = 0x02,
|
|
SCALED = 0x04,
|
|
SHIFTED = 0x08,
|
|
GEOMETRY = 0x10,
|
|
TEXTURE = 0x20,
|
|
MOVED = TRANSLATED|ROTATED|SCALED,
|
|
SILHOUETTE = 0x40,
|
|
ALL_CHANGED = 0x7f
|
|
}EChangedFlags;
|
|
|
|
void init()
|
|
{
|
|
mParent = NULL;
|
|
mChanged = UNCHANGED;
|
|
mPosition.setVec(0,0,0);
|
|
mRotation.loadIdentity();
|
|
mScale. setVec(1,1,1);
|
|
mWorldPosition.clearVec();
|
|
mWorldRotation.loadIdentity();
|
|
mScaleChildOffset = FALSE;
|
|
}
|
|
|
|
LLXform();
|
|
virtual ~LLXform();
|
|
|
|
void getLocalMat4(LLMatrix4 &mat) const { mat.initAll(mScale, mRotation, mPosition); }
|
|
|
|
inline BOOL setParent(LLXform *parent);
|
|
|
|
inline void setPosition(const LLVector3& pos);
|
|
inline void setPosition(const F32 x, const F32 y, const F32 z);
|
|
inline void setPositionX(const F32 x);
|
|
inline void setPositionY(const F32 y);
|
|
inline void setPositionZ(const F32 z);
|
|
inline void addPosition(const LLVector3& pos);
|
|
|
|
|
|
inline void setScale(const LLVector3& scale);
|
|
inline void setScale(const F32 x, const F32 y, const F32 z);
|
|
inline void setRotation(const LLQuaternion& rot);
|
|
inline void setRotation(const F32 x, const F32 y, const F32 z);
|
|
inline void setRotation(const F32 x, const F32 y, const F32 z, const F32 s);
|
|
|
|
// Above functions must be inline for speed, but also
|
|
// need to emit warnings. llwarns causes inline LLError::CallSite
|
|
// static objects that make more work for the linker.
|
|
// Avoid inline llwarns by calling this function.
|
|
void warn(const char* const msg);
|
|
|
|
void setChanged(const U32 bits) { mChanged |= bits; }
|
|
BOOL isChanged() const { return mChanged; }
|
|
BOOL isChanged(const U32 bits) const { return mChanged & bits; }
|
|
void clearChanged() { mChanged = 0; }
|
|
void clearChanged(U32 bits) { mChanged &= ~bits; }
|
|
|
|
void setScaleChildOffset(BOOL scale) { mScaleChildOffset = scale; }
|
|
BOOL getScaleChildOffset() { return mScaleChildOffset; }
|
|
|
|
LLXform* getParent() const { return mParent; }
|
|
LLXform* getRoot() const;
|
|
virtual BOOL isRoot() const;
|
|
virtual BOOL isRootEdit() const;
|
|
|
|
const LLVector3& getPosition() const { return mPosition; }
|
|
const LLVector3& getScale() const { return mScale; }
|
|
const LLQuaternion& getRotation() const { return mRotation; }
|
|
const LLVector3& getPositionW() const { return mWorldPosition; }
|
|
const LLQuaternion& getWorldRotation() const { return mWorldRotation; }
|
|
const LLVector3& getWorldPosition() const { return mWorldPosition; }
|
|
};
|
|
|
|
class LLXformMatrix : public LLXform
|
|
{
|
|
public:
|
|
LLXformMatrix() : LLXform() {};
|
|
virtual ~LLXformMatrix();
|
|
|
|
const LLMatrix4& getWorldMatrix() const { return mWorldMatrix; }
|
|
void setWorldMatrix (const LLMatrix4& mat) { mWorldMatrix = mat; }
|
|
|
|
void init()
|
|
{
|
|
mWorldMatrix.setIdentity();
|
|
mMin.clearVec();
|
|
mMax.clearVec();
|
|
|
|
LLXform::init();
|
|
}
|
|
|
|
void update();
|
|
void updateMatrix(BOOL update_bounds = TRUE);
|
|
void getMinMax(LLVector3& min,LLVector3& max) const;
|
|
|
|
protected:
|
|
LLMatrix4 mWorldMatrix;
|
|
LLVector3 mMin;
|
|
LLVector3 mMax;
|
|
|
|
};
|
|
|
|
BOOL LLXform::setParent(LLXform* parent)
|
|
{
|
|
// Validate and make sure we're not creating a loop
|
|
if (parent == mParent)
|
|
{
|
|
return TRUE;
|
|
}
|
|
if (parent)
|
|
{
|
|
LLXform *cur_par = parent->mParent;
|
|
while (cur_par)
|
|
{
|
|
if (cur_par == this)
|
|
{
|
|
//warn("LLXform::setParent Creating loop when setting parent!");
|
|
return FALSE;
|
|
}
|
|
cur_par = cur_par->mParent;
|
|
}
|
|
}
|
|
mParent = parent;
|
|
return TRUE;
|
|
}
|
|
|
|
void LLXform::setPosition(const LLVector3& pos)
|
|
{
|
|
setChanged(TRANSLATED);
|
|
if (pos.isFinite())
|
|
mPosition = pos;
|
|
else
|
|
{
|
|
mPosition.clearVec();
|
|
warn("Non Finite in LLXform::setPosition(LLVector3)");
|
|
}
|
|
}
|
|
|
|
void LLXform::setPosition(const F32 x, const F32 y, const F32 z)
|
|
{
|
|
setChanged(TRANSLATED);
|
|
if (llfinite(x) && llfinite(y) && llfinite(z))
|
|
mPosition.setVec(x,y,z);
|
|
else
|
|
{
|
|
mPosition.clearVec();
|
|
warn("Non Finite in LLXform::setPosition(F32,F32,F32)");
|
|
}
|
|
}
|
|
|
|
void LLXform::setPositionX(const F32 x)
|
|
{
|
|
setChanged(TRANSLATED);
|
|
if (llfinite(x))
|
|
mPosition.mV[VX] = x;
|
|
else
|
|
{
|
|
mPosition.mV[VX] = 0.f;
|
|
warn("Non Finite in LLXform::setPositionX");
|
|
}
|
|
}
|
|
|
|
void LLXform::setPositionY(const F32 y)
|
|
{
|
|
setChanged(TRANSLATED);
|
|
if (llfinite(y))
|
|
mPosition.mV[VY] = y;
|
|
else
|
|
{
|
|
mPosition.mV[VY] = 0.f;
|
|
warn("Non Finite in LLXform::setPositionY");
|
|
}
|
|
}
|
|
|
|
void LLXform::setPositionZ(const F32 z)
|
|
{
|
|
setChanged(TRANSLATED);
|
|
if (llfinite(z))
|
|
mPosition.mV[VZ] = z;
|
|
else
|
|
{
|
|
mPosition.mV[VZ] = 0.f;
|
|
warn("Non Finite in LLXform::setPositionZ");
|
|
}
|
|
}
|
|
|
|
void LLXform::addPosition(const LLVector3& pos)
|
|
{
|
|
setChanged(TRANSLATED);
|
|
if (pos.isFinite())
|
|
mPosition += pos;
|
|
else
|
|
warn("Non Finite in LLXform::addPosition");
|
|
}
|
|
|
|
void LLXform::setScale(const LLVector3& scale)
|
|
{
|
|
setChanged(SCALED);
|
|
if (scale.isFinite())
|
|
mScale = scale;
|
|
else
|
|
{
|
|
mScale.setVec(1.f, 1.f, 1.f);
|
|
warn("Non Finite in LLXform::setScale");
|
|
}
|
|
}
|
|
void LLXform::setScale(const F32 x, const F32 y, const F32 z)
|
|
{
|
|
setChanged(SCALED);
|
|
if (llfinite(x) && llfinite(y) && llfinite(z))
|
|
mScale.setVec(x,y,z);
|
|
else
|
|
{
|
|
mScale.setVec(1.f, 1.f, 1.f);
|
|
warn("Non Finite in LLXform::setScale");
|
|
}
|
|
}
|
|
void LLXform::setRotation(const LLQuaternion& rot)
|
|
{
|
|
setChanged(ROTATED);
|
|
if (rot.isFinite())
|
|
mRotation = rot;
|
|
else
|
|
{
|
|
mRotation.loadIdentity();
|
|
warn("Non Finite in LLXform::setRotation");
|
|
}
|
|
}
|
|
void LLXform::setRotation(const F32 x, const F32 y, const F32 z)
|
|
{
|
|
setChanged(ROTATED);
|
|
if (llfinite(x) && llfinite(y) && llfinite(z))
|
|
{
|
|
mRotation.setQuat(x,y,z);
|
|
}
|
|
else
|
|
{
|
|
mRotation.loadIdentity();
|
|
warn("Non Finite in LLXform::setRotation");
|
|
}
|
|
}
|
|
void LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s)
|
|
{
|
|
setChanged(ROTATED);
|
|
if (llfinite(x) && llfinite(y) && llfinite(z) && llfinite(s))
|
|
{
|
|
mRotation.mQ[VX] = x; mRotation.mQ[VY] = y; mRotation.mQ[VZ] = z; mRotation.mQ[VS] = s;
|
|
}
|
|
else
|
|
{
|
|
mRotation.loadIdentity();
|
|
warn("Non Finite in LLXform::setRotation");
|
|
}
|
|
}
|
|
|
|
#endif
|