Torque3D/Engine/source/gui/controls/gui3DProjectionCtrl.cpp

299 lines
8.6 KiB
C++

//-----------------------------------------------------------------------------
// Gui3DProjectionCtrl
// Doppelganger Inc
// Orion Elenzil 200701
//
// This control is meant to be merely a container for other controls.
// What's neat is that it's easy to 'attach' this control to a point in world-space
// or, more interestingly, to an object such as a player.
//
// Usage:
// * Create the Gui3DProjectionControl - by default it will be at 0, 0, 0.
// * You can change where it's located by setting the field "offsetWorld".
// - note you can specify that right in the .gui file
// * You can attach it to any SceneObject by calling "setAttachedTo()".
//
// Behaviour:
// * If you're attaching it to a player, by default it will center on the player's head.
// * If you attach it to an object, by default it will delete itself if the object is deleted.
// * Doesn't occlude w/r/t 3D objects.
//
// Console Methods:
// * SetAttachedTo(SceneObject)
// * GetAttachedTo()
//
// Params:
// * pointWorld - read/write point in worldspace. read-only if attached to an object.
// * offsetObject - an offset in objectspace. default 0, 0, 0.
// * offsetWorld - an offset in worldspace. default 0, 0, 0.
// * offsetScreen - an offset in screenspace. default 0, 0.
// * hAlign - horizontal alignment. 0 = left, 1 = center, 2 = right. default center.
// * vAlign - vertical alignment. 0 = top, 1 = center, 2 = bottomt. default center.
// * useEyePoint - H & V usage of the eyePoint, if player object. default 0, 1. (ie - use only the vertical component)
// * autoDelete - self-delete when attachedTo object is deleted. default true.
//
// Todo:
// * occlusion - hide the control when its anchor point is occluded.
// * integrate w/ zbuffer - this would actually be a change to the whole GuiControl system.
// * allow attaching to arbitrary nodes in a skeleton.
// * avoid projection when the object is out of the frustum.
//
// oxe 20070111
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "scene/SceneObject.h"
#include "T3D/player.h"
#include "gui/controls/Gui3DProjectionCtrl.h"
IMPLEMENT_CONOBJECT(Gui3DProjectionCtrl);
//-----------------------------------------------------------------------------
Gui3DProjectionCtrl::Gui3DProjectionCtrl()
{
mTSCtrl = NULL;
mAttachedTo = NULL;
mAttachedToPlayer = NULL;
mAutoDelete = true;
mHAlign = center;
mVAlign = center;
mUseEyePoint.x = 0;
mUseEyePoint.y = 1;
mPtWorld .set(0, 0, 0);
mPtProj .set(0, 0);
mOffsetObject.set(0, 0, 0);
mOffsetWorld .set(0, 0, 0);
mOffsetScreen.set(0, 0);
}
void Gui3DProjectionCtrl::initPersistFields()
{
Parent::initPersistFields();
addGroup("3DProjection");
addField("pointWorld" , TypePoint3F , Offset(mPtWorld , Gui3DProjectionCtrl));
addField("offsetObject" , TypePoint3F , Offset(mOffsetObject , Gui3DProjectionCtrl));
addField("offsetWorld" , TypePoint3F , Offset(mOffsetWorld , Gui3DProjectionCtrl));
addField("offsetScreen" , TypePoint2I , Offset(mOffsetScreen , Gui3DProjectionCtrl));
addField("hAlign" , TypeS32 , Offset(mHAlign , Gui3DProjectionCtrl));
addField("vAlign" , TypeS32 , Offset(mVAlign , Gui3DProjectionCtrl));
addField("useEyePoint" , TypePoint2I , Offset(mUseEyePoint , Gui3DProjectionCtrl));
addField("autoDelete" , TypeBool , Offset(mAutoDelete , Gui3DProjectionCtrl));
endGroup("3DProjection");
}
void Gui3DProjectionCtrl::onRender(Point2I offset, const RectI &updateRect)
{
doPositioning();
doProjection();
doAlignment();
Parent::onRender(offset, updateRect);
}
void Gui3DProjectionCtrl::resizeDuringRender()
{
doPositioning();
doProjection ();
doAlignment ();
}
bool Gui3DProjectionCtrl::onWake()
{
// walk up the GUI tree until we find a GuiTSCtrl.
mTSCtrl = NULL;
GuiControl* walkCtrl = getParent();
AssertFatal(walkCtrl != NULL, "Gui3DProjectionCtrl::onWake() - NULL parent");
bool doMore = true;
while (doMore)
{
mTSCtrl = dynamic_cast<GuiTSCtrl*>(walkCtrl);
walkCtrl = walkCtrl->getParent();
doMore = (mTSCtrl == NULL) && (walkCtrl != NULL);
}
if (!mTSCtrl)
Con::errorf("Gui3DProjectionCtrl::onWake() - no TSCtrl parent");
return Parent::onWake();
}
void Gui3DProjectionCtrl::onSleep()
{
mTSCtrl = NULL;
return Parent::onSleep();
}
void Gui3DProjectionCtrl::onDeleteNotify(SimObject* obj)
{
// - SimSet assumes that obj is a member of THIS, which in our case ain't true.
// oxe 20070116 - the following doesn't compile on GCC.
// SimSet::Parent::onDeleteNotify(obj);
if (!obj)
{
Con::warnf("Gui3DProjectionCtrl::onDeleteNotify - got NULL");
return;
}
if (obj != mAttachedTo)
{
if (mAttachedTo != NULL)
Con::warnf("Gui3DProjectionCtrl::onDeleteNotify - got unexpected object: %d vs. %d", obj->getId(), mAttachedTo->getId());
return;
}
if (mAutoDelete)
this->deleteObject();
}
//-----------------------------------------------------------------------------
void Gui3DProjectionCtrl::doPositioning()
{
if (mAttachedTo == NULL)
return;
Point3F ptBase; // the regular position of the object.
Point3F ptEye; // the render position of the eye node, if a player object.
Point3F pt; // combination of ptBase and ptEye.
MatrixF mat; // utility
mAttachedTo->getRenderTransform().getColumn(3, &ptBase);
if (mAttachedToPlayer != NULL)
{
mAttachedToPlayer->getRenderEyeTransform(&mat);
mat.getColumn(3, &ptEye);
}
else
{
ptEye = ptBase;
}
// use some components from ptEye but other position from ptBase
pt = ptBase;
if (mUseEyePoint.x != 0)
{
pt.x = ptEye.x;
pt.y = ptEye.y;
}
if (mUseEyePoint.y != 0)
{
pt.z = ptEye.z;
}
// object-space offset
Point3F offsetObj;
QuatF quat(mAttachedTo->getRenderTransform());
quat.mulP(mOffsetObject, &offsetObj);
pt += offsetObj;
// world-space offset
pt += mOffsetWorld;
mPtWorld = pt;
}
void Gui3DProjectionCtrl::doProjection()
{
if (!mTSCtrl)
return;
Point3F pt;
if (!mTSCtrl->project(mPtWorld, &pt))
return;
mPtProj.x = (S32)(pt.x + 0.5f);
mPtProj.y = (S32)(pt.y + 0.5f);
}
void Gui3DProjectionCtrl::doAlignment()
{
// alignment
Point2I offsetAlign;
switch(mHAlign)
{
default:
case center:
offsetAlign.x = -getBounds().extent.x / 2;
break;
case min:
offsetAlign.x = 0;
break;
case max:
offsetAlign.x = -getBounds().extent.x;
break;
}
switch(mVAlign)
{
default:
case center:
offsetAlign.y = -getBounds().extent.y / 2;
break;
case min:
offsetAlign.y = 0;
break;
case max:
offsetAlign.y = -getBounds().extent.y;
break;
}
// projected point
mPtScreen = mPtProj;
// alignment offset
mPtScreen += offsetAlign;
// screen offset
mPtScreen += mOffsetScreen;
// setTrgPosition(mPtScreen);
RectI bounds = getBounds();
bounds.point = mPtScreen;
setBounds(bounds);
}
//-----------------------------------------------------------------------------
void Gui3DProjectionCtrl::setAttachedTo(SceneObject* obj)
{
if (obj == mAttachedTo)
return;
if (mAttachedTo)
clearNotify(mAttachedTo);
mAttachedTo = obj;
mAttachedToPlayer = dynamic_cast<Player*>(obj);
if (mAttachedTo)
deleteNotify(mAttachedTo);
}
DefineEngineMethod(Gui3DProjectionCtrl, setAttachedTo, void, (SceneObject* target), (nullAsType<SceneObject*>()), "(object)")
{
if(target)
object->setAttachedTo(target);
}
DefineEngineMethod(Gui3DProjectionCtrl, getAttachedTo, S32, (),, "()")
{
SceneObject* obj = object->getAttachedTo();
if (!obj)
return 0;
else
return obj->getId();
}