123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- //-----------------------------------------------------------------------------
- // 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();
- }
|