gui3DProjectionCtrl.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //-----------------------------------------------------------------------------
  2. // Gui3DProjectionCtrl
  3. // Doppelganger Inc
  4. // Orion Elenzil 200701
  5. //
  6. // This control is meant to be merely a container for other controls.
  7. // What's neat is that it's easy to 'attach' this control to a point in world-space
  8. // or, more interestingly, to an object such as a player.
  9. //
  10. // Usage:
  11. // * Create the Gui3DProjectionControl - by default it will be at 0, 0, 0.
  12. // * You can change where it's located by setting the field "offsetWorld".
  13. // - note you can specify that right in the .gui file
  14. // * You can attach it to any SceneObject by calling "setAttachedTo()".
  15. //
  16. // Behaviour:
  17. // * If you're attaching it to a player, by default it will center on the player's head.
  18. // * If you attach it to an object, by default it will delete itself if the object is deleted.
  19. // * Doesn't occlude w/r/t 3D objects.
  20. //
  21. // Console Methods:
  22. // * SetAttachedTo(SceneObject)
  23. // * GetAttachedTo()
  24. //
  25. // Params:
  26. // * pointWorld - read/write point in worldspace. read-only if attached to an object.
  27. // * offsetObject - an offset in objectspace. default 0, 0, 0.
  28. // * offsetWorld - an offset in worldspace. default 0, 0, 0.
  29. // * offsetScreen - an offset in screenspace. default 0, 0.
  30. // * hAlign - horizontal alignment. 0 = left, 1 = center, 2 = right. default center.
  31. // * vAlign - vertical alignment. 0 = top, 1 = center, 2 = bottomt. default center.
  32. // * useEyePoint - H & V usage of the eyePoint, if player object. default 0, 1. (ie - use only the vertical component)
  33. // * autoDelete - self-delete when attachedTo object is deleted. default true.
  34. //
  35. // Todo:
  36. // * occlusion - hide the control when its anchor point is occluded.
  37. // * integrate w/ zbuffer - this would actually be a change to the whole GuiControl system.
  38. // * allow attaching to arbitrary nodes in a skeleton.
  39. // * avoid projection when the object is out of the frustum.
  40. //
  41. // oxe 20070111
  42. //-----------------------------------------------------------------------------
  43. #include "console/console.h"
  44. #include "console/consoleTypes.h"
  45. #include "scene/sceneObject.h"
  46. #include "T3D/player.h"
  47. #include "gui/controls/gui3DProjectionCtrl.h"
  48. IMPLEMENT_CONOBJECT(Gui3DProjectionCtrl);
  49. //-----------------------------------------------------------------------------
  50. Gui3DProjectionCtrl::Gui3DProjectionCtrl()
  51. {
  52. mTSCtrl = NULL;
  53. mAttachedTo = NULL;
  54. mAttachedToPlayer = NULL;
  55. mAutoDelete = true;
  56. mHAlign = center;
  57. mVAlign = center;
  58. mUseEyePoint.x = 0;
  59. mUseEyePoint.y = 1;
  60. mPtWorld .set(0, 0, 0);
  61. mPtProj .set(0, 0);
  62. mOffsetObject.set(0, 0, 0);
  63. mOffsetWorld .set(0, 0, 0);
  64. mOffsetScreen.set(0, 0);
  65. }
  66. void Gui3DProjectionCtrl::initPersistFields()
  67. {
  68. docsURL;
  69. Parent::initPersistFields();
  70. addGroup("3DProjection");
  71. addField("pointWorld" , TypePoint3F , Offset(mPtWorld , Gui3DProjectionCtrl));
  72. addField("offsetObject" , TypePoint3F , Offset(mOffsetObject , Gui3DProjectionCtrl));
  73. addField("offsetWorld" , TypePoint3F , Offset(mOffsetWorld , Gui3DProjectionCtrl));
  74. addField("offsetScreen" , TypePoint2I , Offset(mOffsetScreen , Gui3DProjectionCtrl));
  75. addField("hAlign" , TypeS32 , Offset(mHAlign , Gui3DProjectionCtrl));
  76. addField("vAlign" , TypeS32 , Offset(mVAlign , Gui3DProjectionCtrl));
  77. addField("useEyePoint" , TypePoint2I , Offset(mUseEyePoint , Gui3DProjectionCtrl));
  78. addField("autoDelete" , TypeBool , Offset(mAutoDelete , Gui3DProjectionCtrl));
  79. endGroup("3DProjection");
  80. }
  81. void Gui3DProjectionCtrl::onRender(Point2I offset, const RectI &updateRect)
  82. {
  83. doPositioning();
  84. doProjection();
  85. doAlignment();
  86. Parent::onRender(offset, updateRect);
  87. }
  88. void Gui3DProjectionCtrl::resizeDuringRender()
  89. {
  90. doPositioning();
  91. doProjection ();
  92. doAlignment ();
  93. }
  94. bool Gui3DProjectionCtrl::onWake()
  95. {
  96. // walk up the GUI tree until we find a GuiTSCtrl.
  97. mTSCtrl = NULL;
  98. GuiControl* walkCtrl = getParent();
  99. AssertFatal(walkCtrl != NULL, "Gui3DProjectionCtrl::onWake() - NULL parent");
  100. bool doMore = true;
  101. while (doMore)
  102. {
  103. mTSCtrl = dynamic_cast<GuiTSCtrl*>(walkCtrl);
  104. walkCtrl = walkCtrl->getParent();
  105. doMore = (mTSCtrl == NULL) && (walkCtrl != NULL);
  106. }
  107. if (!mTSCtrl)
  108. Con::errorf("Gui3DProjectionCtrl::onWake() - no TSCtrl parent");
  109. return Parent::onWake();
  110. }
  111. void Gui3DProjectionCtrl::onSleep()
  112. {
  113. mTSCtrl = NULL;
  114. return Parent::onSleep();
  115. }
  116. void Gui3DProjectionCtrl::onDeleteNotify(SimObject* obj)
  117. {
  118. // - SimSet assumes that obj is a member of THIS, which in our case ain't true.
  119. // oxe 20070116 - the following doesn't compile on GCC.
  120. // SimSet::Parent::onDeleteNotify(obj);
  121. if (!obj)
  122. {
  123. Con::warnf("Gui3DProjectionCtrl::onDeleteNotify - got NULL");
  124. return;
  125. }
  126. if (obj != mAttachedTo)
  127. {
  128. if (mAttachedTo != NULL)
  129. Con::warnf("Gui3DProjectionCtrl::onDeleteNotify - got unexpected object: %d vs. %d", obj->getId(), mAttachedTo->getId());
  130. return;
  131. }
  132. if (mAutoDelete)
  133. this->deleteObject();
  134. }
  135. //-----------------------------------------------------------------------------
  136. void Gui3DProjectionCtrl::doPositioning()
  137. {
  138. if (mAttachedTo == NULL)
  139. return;
  140. Point3F ptBase; // the regular position of the object.
  141. Point3F ptEye; // the render position of the eye node, if a player object.
  142. Point3F pt; // combination of ptBase and ptEye.
  143. MatrixF mat; // utility
  144. mAttachedTo->getRenderTransform().getColumn(3, &ptBase);
  145. if (mAttachedToPlayer != NULL)
  146. {
  147. mAttachedToPlayer->getRenderEyeTransform(&mat);
  148. mat.getColumn(3, &ptEye);
  149. }
  150. else
  151. {
  152. ptEye = ptBase;
  153. }
  154. // use some components from ptEye but other position from ptBase
  155. pt = ptBase;
  156. if (mUseEyePoint.x != 0)
  157. {
  158. pt.x = ptEye.x;
  159. pt.y = ptEye.y;
  160. }
  161. if (mUseEyePoint.y != 0)
  162. {
  163. pt.z = ptEye.z;
  164. }
  165. // object-space offset
  166. Point3F offsetObj;
  167. QuatF quat(mAttachedTo->getRenderTransform());
  168. quat.mulP(mOffsetObject, &offsetObj);
  169. pt += offsetObj;
  170. // world-space offset
  171. pt += mOffsetWorld;
  172. mPtWorld = pt;
  173. }
  174. void Gui3DProjectionCtrl::doProjection()
  175. {
  176. if (!mTSCtrl)
  177. return;
  178. Point3F pt;
  179. if (!mTSCtrl->project(mPtWorld, &pt))
  180. return;
  181. mPtProj.x = (S32)(pt.x + 0.5f);
  182. mPtProj.y = (S32)(pt.y + 0.5f);
  183. }
  184. void Gui3DProjectionCtrl::doAlignment()
  185. {
  186. // alignment
  187. Point2I offsetAlign;
  188. switch(mHAlign)
  189. {
  190. default:
  191. case center:
  192. offsetAlign.x = -getBounds().extent.x / 2;
  193. break;
  194. case min:
  195. offsetAlign.x = 0;
  196. break;
  197. case max:
  198. offsetAlign.x = -getBounds().extent.x;
  199. break;
  200. }
  201. switch(mVAlign)
  202. {
  203. default:
  204. case center:
  205. offsetAlign.y = -getBounds().extent.y / 2;
  206. break;
  207. case min:
  208. offsetAlign.y = 0;
  209. break;
  210. case max:
  211. offsetAlign.y = -getBounds().extent.y;
  212. break;
  213. }
  214. // projected point
  215. mPtScreen = mPtProj;
  216. // alignment offset
  217. mPtScreen += offsetAlign;
  218. // screen offset
  219. mPtScreen += mOffsetScreen;
  220. // setTrgPosition(mPtScreen);
  221. RectI bounds = getBounds();
  222. bounds.point = mPtScreen;
  223. setBounds(bounds);
  224. }
  225. //-----------------------------------------------------------------------------
  226. void Gui3DProjectionCtrl::setAttachedTo(SceneObject* obj)
  227. {
  228. if (obj == mAttachedTo)
  229. return;
  230. if (mAttachedTo)
  231. clearNotify(mAttachedTo);
  232. mAttachedTo = obj;
  233. mAttachedToPlayer = dynamic_cast<Player*>(obj);
  234. if (mAttachedTo)
  235. deleteNotify(mAttachedTo);
  236. }
  237. DefineEngineMethod(Gui3DProjectionCtrl, setAttachedTo, void, (SceneObject* target), (nullAsType<SceneObject*>()), "(object)")
  238. {
  239. if(target)
  240. object->setAttachedTo(target);
  241. }
  242. DefineEngineMethod(Gui3DProjectionCtrl, getAttachedTo, S32, (),, "()")
  243. {
  244. SceneObject* obj = object->getAttachedTo();
  245. if (!obj)
  246. return 0;
  247. else
  248. return obj->getId();
  249. }