sceneObject.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26. #include "platform/platform.h"
  27. #include "scene/sceneObject.h"
  28. #include "platform/profiler.h"
  29. #include "console/consoleTypes.h"
  30. #include "console/engineAPI.h"
  31. #include "console/simPersistID.h"
  32. #include "sim/netConnection.h"
  33. #include "core/stream/bitStream.h"
  34. #include "scene/sceneManager.h"
  35. #include "scene/sceneTracker.h"
  36. #include "scene/sceneRenderState.h"
  37. #include "scene/zones/sceneZoneSpace.h"
  38. #include "collision/extrudedPolyList.h"
  39. #include "collision/earlyOutPolyList.h"
  40. #include "collision/optimizedPolyList.h"
  41. #include "math/mPolyhedron.h"
  42. #include "gfx/bitmap/gBitmap.h"
  43. #include "math/util/frustum.h"
  44. #include "math/mathIO.h"
  45. #include "math/mTransform.h"
  46. #include "T3D/gameBase/gameProcess.h"
  47. #include "T3D/gameBase/gameConnection.h"
  48. #include "T3D/accumulationVolume.h"
  49. IMPLEMENT_CONOBJECT(SceneObject);
  50. ConsoleDocClass( SceneObject,
  51. "@brief A networkable object that exists in the 3D world.\n\n"
  52. "The SceneObject class provides the foundation for 3D objects in the Engine. It "
  53. "exposes the functionality for:\n\n"
  54. "<ul><li>Position, rotation and scale within the world.</li>"
  55. "<li>Working with a scene graph (in the Zone and Portal sections), allowing efficient "
  56. "and robust rendering of the game scene.</li>"
  57. "<li>Various helper functions, including functions to get bounding information "
  58. "and momentum/velocity.</li>"
  59. "<li>Mounting one SceneObject to another.</li>"
  60. "<li>An interface for collision detection, as well as ray casting.</li>"
  61. "<li>Lighting. SceneObjects can register lights both at lightmap generation "
  62. "time, and dynamic lights at runtime (for special effects, such as from flame "
  63. "or a projectile, or from an explosion).</li></ul>\n\n"
  64. "You do not typically work with SceneObjects themselves. The SceneObject provides a reference "
  65. "within the game world (the scene), but does not render to the client on its own. The "
  66. "same is true of collision detection beyond that of the bounding box. Instead you "
  67. "use one of the many classes that derrive from SceneObject, such as TSStatic.\n\n"
  68. "@section SceneObject_Hiding Difference Between setHidden() and isRenderEnabled\n\n"
  69. "When it comes time to decide if a SceneObject should render or not, there are two "
  70. "methods that can stop the SceneObject from rendering at all. You need to be aware of "
  71. "the differences between these two methods as they impact how the SceneObject is networked "
  72. "from the server to the client.\n\n"
  73. "The first method of manually controlling if a SceneObject is rendered is through its "
  74. "SceneObject::isRenderEnabled property. When set to false the SceneObject is considered invisible but "
  75. "still present within the scene. This means it still takes part in collisions and continues "
  76. "to be networked.\n\n"
  77. "The second method is using the setHidden() method. This will actually remove a SceneObject "
  78. "from the scene and it will no longer be networked from the server to the cleint. Any client-side "
  79. "ghost of the object will be deleted as the server no longer considers the object to be in scope.\n\n"
  80. "@ingroup gameObjects\n"
  81. );
  82. IMPLEMENT_CALLBACK(SceneObject, onInspectPostApply, void, (SceneObject* obj), (obj),"Generic callback for when an object is edited");
  83. #ifdef TORQUE_TOOLS
  84. extern bool gEditingMission;
  85. #endif
  86. Signal< void( SceneObject* ) > SceneObject::smSceneObjectAdd;
  87. Signal< void( SceneObject* ) > SceneObject::smSceneObjectRemove;
  88. //-----------------------------------------------------------------------------
  89. SceneObject::SceneObject()
  90. {
  91. mContainer = 0;
  92. mTypeMask = DefaultObjectType;
  93. mCollisionCount = 0;
  94. mGlobalBounds = false;
  95. mObjScale.set(1,1,1);
  96. mObjToWorld.identity();
  97. mWorldToObj.identity();
  98. mObjBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0));
  99. mWorldBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0));
  100. mWorldSphere = SphereF(Point3F(0, 0, 0), 0);
  101. mRenderObjToWorld.identity();
  102. mRenderWorldToObj.identity();
  103. mRenderWorldBox = Box3F(Point3F(0, 0, 0), Point3F(0, 0, 0));
  104. mRenderWorldSphere = SphereF(Point3F(0, 0, 0), 0);
  105. mContainerSeqKey = 0;
  106. mBinRefHead = NULL;
  107. mSceneManager = NULL;
  108. mNumCurrZones = 0;
  109. mZoneRefHead = NULL;
  110. mZoneRefDirty = false;
  111. mBinMinX = 0xFFFFFFFF;
  112. mBinMaxX = 0xFFFFFFFF;
  113. mBinMinY = 0xFFFFFFFF;
  114. mBinMaxY = 0xFFFFFFFF;
  115. mLightPlugin = NULL;
  116. mMount.object = NULL;
  117. mMount.link = NULL;
  118. mMount.list = NULL;
  119. mMount.node = -1;
  120. mMount.xfm = MatrixF::Identity;
  121. mMountPID = NULL;
  122. mSceneObjectLinks = NULL;
  123. mObjectFlags.set( RenderEnabledFlag | SelectionEnabledFlag );
  124. mIsScopeAlways = false;
  125. mAccuTex = NULL;
  126. mSelectionFlags = 0;
  127. mPathfindingIgnore = false;
  128. mGameObjectAssetId = StringTable->insert("");
  129. mDirtyGameObject = false;
  130. }
  131. //-----------------------------------------------------------------------------
  132. SceneObject::~SceneObject()
  133. {
  134. AssertFatal( mZoneRefHead == NULL && mBinRefHead == NULL,
  135. "SceneObject::~SceneObject - Object still linked in reference lists!");
  136. AssertFatal( !mSceneObjectLinks,
  137. "SceneObject::~SceneObject() - object is still linked to SceneTrackers" );
  138. mAccuTex = NULL;
  139. unlink();
  140. }
  141. //-----------------------------------------------------------------------------
  142. bool SceneObject::castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info)
  143. {
  144. // By default, all ray checking against the rendered mesh will be passed
  145. // on to the collision mesh. This saves having to define both methods
  146. // for simple objects.
  147. return castRay( start, end, info );
  148. }
  149. //-----------------------------------------------------------------------------
  150. bool SceneObject::containsPoint( const Point3F& point )
  151. {
  152. // If it's not in the AABB, then it can't be in the OBB either,
  153. // so early out.
  154. if( !mWorldBox.isContained( point ) )
  155. return false;
  156. // Transform point into object space and test it against
  157. // our object space bounding box.
  158. Point3F objPoint( 0, 0, 0 );
  159. getWorldTransform().mulP( point, &objPoint );
  160. objPoint.convolveInverse( getScale() );
  161. return ( mObjBox.isContained( objPoint ) );
  162. }
  163. //-----------------------------------------------------------------------------
  164. bool SceneObject::collideBox(const Point3F &start, const Point3F &end, RayInfo *info)
  165. {
  166. const F32 * pStart = (const F32*)start;
  167. const F32 * pEnd = (const F32*)end;
  168. const F32 * pMin = (const F32*)mObjBox.minExtents;
  169. const F32 * pMax = (const F32*)mObjBox.maxExtents;
  170. F32 maxStartTime = -1;
  171. F32 minEndTime = 1;
  172. F32 startTime;
  173. F32 endTime;
  174. // used for getting normal
  175. U32 hitIndex = 0xFFFFFFFF;
  176. U32 side;
  177. // walk the axis
  178. for(U32 i = 0; i < 3; i++)
  179. {
  180. //
  181. if(pStart[i] < pEnd[i])
  182. {
  183. if(pEnd[i] < pMin[i] || pStart[i] > pMax[i])
  184. return(false);
  185. F32 dist = pEnd[i] - pStart[i];
  186. startTime = (pStart[i] < pMin[i]) ? (pMin[i] - pStart[i]) / dist : -1;
  187. endTime = (pEnd[i] > pMax[i]) ? (pMax[i] - pStart[i]) / dist : 1;
  188. side = 1;
  189. }
  190. else
  191. {
  192. if(pStart[i] < pMin[i] || pEnd[i] > pMax[i])
  193. return(false);
  194. F32 dist = pStart[i] - pEnd[i];
  195. startTime = (pStart[i] > pMax[i]) ? (pStart[i] - pMax[i]) / dist : -1;
  196. endTime = (pEnd[i] < pMin[i]) ? (pStart[i] - pMin[i]) / dist : 1;
  197. side = 0;
  198. }
  199. //
  200. if(startTime > maxStartTime)
  201. {
  202. maxStartTime = startTime;
  203. hitIndex = i * 2 + side;
  204. }
  205. if(endTime < minEndTime)
  206. minEndTime = endTime;
  207. if(minEndTime < maxStartTime)
  208. return(false);
  209. }
  210. // fail if inside
  211. if(maxStartTime < 0.f)
  212. return(false);
  213. //
  214. static Point3F boxNormals[] = {
  215. Point3F( 1, 0, 0),
  216. Point3F(-1, 0, 0),
  217. Point3F( 0, 1, 0),
  218. Point3F( 0,-1, 0),
  219. Point3F( 0, 0, 1),
  220. Point3F( 0, 0,-1),
  221. };
  222. //
  223. AssertFatal(hitIndex != 0xFFFFFFFF, "SceneObject::collideBox");
  224. info->t = maxStartTime;
  225. info->object = this;
  226. mObjToWorld.mulV(boxNormals[hitIndex], &info->normal);
  227. info->material = 0;
  228. return(true);
  229. }
  230. //-----------------------------------------------------------------------------
  231. void SceneObject::disableCollision()
  232. {
  233. mCollisionCount++;
  234. AssertFatal(mCollisionCount < 50, "SceneObject::disableCollision called 50 times on the same object. Is this inside a circular loop?" );
  235. }
  236. //-----------------------------------------------------------------------------
  237. void SceneObject::enableCollision()
  238. {
  239. if (mCollisionCount)
  240. --mCollisionCount;
  241. }
  242. //-----------------------------------------------------------------------------
  243. bool SceneObject::onAdd()
  244. {
  245. if ( !Parent::onAdd() )
  246. return false;
  247. mIsScopeAlways = mNetFlags.test( ScopeAlways );
  248. mWorldToObj = mObjToWorld;
  249. mWorldToObj.affineInverse();
  250. resetWorldBox();
  251. setRenderTransform(mObjToWorld);
  252. resolveMountPID();
  253. smSceneObjectAdd.trigger(this);
  254. return true;
  255. }
  256. //-----------------------------------------------------------------------------
  257. void SceneObject::onRemove()
  258. {
  259. smSceneObjectRemove.trigger(this);
  260. unmount();
  261. plUnlink();
  262. Parent::onRemove();
  263. }
  264. //-----------------------------------------------------------------------------
  265. void SceneObject::addToScene()
  266. {
  267. if( mSceneManager )
  268. return;
  269. if( isClientObject() )
  270. gClientSceneGraph->addObjectToScene( this );
  271. else
  272. gServerSceneGraph->addObjectToScene( this );
  273. }
  274. //-----------------------------------------------------------------------------
  275. void SceneObject::removeFromScene()
  276. {
  277. if( !mSceneManager )
  278. return;
  279. mSceneManager->removeObjectFromScene( this );
  280. }
  281. //-----------------------------------------------------------------------------
  282. void SceneObject::onDeleteNotify( SimObject *obj )
  283. {
  284. // We are comparing memory addresses so even if obj really is not a
  285. // ProcessObject this cast shouldn't break anything.
  286. if ( obj == mAfterObject )
  287. mAfterObject = NULL;
  288. if ( obj == mMount.object )
  289. unmount();
  290. Parent::onDeleteNotify( obj );
  291. }
  292. //-----------------------------------------------------------------------------
  293. void SceneObject::inspectPostApply()
  294. {
  295. if( isServerObject() )
  296. setMaskBits( MountedMask );
  297. onInspectPostApply_callback(this);
  298. Parent::inspectPostApply();
  299. }
  300. //-----------------------------------------------------------------------------
  301. void SceneObject::setGlobalBounds()
  302. {
  303. mGlobalBounds = true;
  304. mObjBox.minExtents.set( -1e10, -1e10, -1e10 );
  305. mObjBox.maxExtents.set( 1e10, 1e10, 1e10 );
  306. if( mSceneManager )
  307. mSceneManager->notifyObjectDirty( this );
  308. }
  309. //-----------------------------------------------------------------------------
  310. void SceneObject::setTransform( const MatrixF& mat )
  311. {
  312. // This test is a bit expensive so turn it off in release.
  313. #ifdef TORQUE_DEBUG
  314. //AssertFatal( mat.isAffine(), "SceneObject::setTransform() - Bad transform (non affine)!" );
  315. #endif
  316. PROFILE_SCOPE( SceneObject_setTransform );
  317. // Update the transforms.
  318. mObjToWorld = mWorldToObj = mat;
  319. mWorldToObj.affineInverse();
  320. // Update the world-space AABB.
  321. resetWorldBox();
  322. // If we're in a SceneManager, sync our scene state.
  323. if( mSceneManager != NULL )
  324. mSceneManager->notifyObjectDirty( this );
  325. setRenderTransform( mat );
  326. }
  327. //-----------------------------------------------------------------------------
  328. void SceneObject::setScale( const VectorF &scale )
  329. {
  330. AssertFatal( !mIsNaN( scale ), "SceneObject::setScale() - The scale is NaN!" );
  331. // Avoid unnecessary scaling operations.
  332. if ( mObjScale.equal( scale ) )
  333. return;
  334. mObjScale = scale;
  335. setTransform(MatrixF(mObjToWorld));
  336. // Make sure that any subclasses of me get a chance to react to the
  337. // scale being changed.
  338. onScaleChanged();
  339. setMaskBits( ScaleMask );
  340. }
  341. void SceneObject::setForwardVector(VectorF newForward, VectorF upVector)
  342. {
  343. MatrixF mat = getTransform();
  344. VectorF up(0.0f, 0.0f, 1.0f);
  345. VectorF axisX;
  346. VectorF axisY = newForward;
  347. VectorF axisZ;
  348. if (upVector != VectorF::Zero)
  349. up = upVector;
  350. // Validate and normalize input:
  351. F32 lenSq;
  352. lenSq = axisY.lenSquared();
  353. if (lenSq < 0.000001f)
  354. {
  355. axisY.set(0.0f, 1.0f, 0.0f);
  356. Con::errorf("SceneObject::setForwardVector() - degenerate forward vector");
  357. }
  358. else
  359. {
  360. axisY /= mSqrt(lenSq);
  361. }
  362. lenSq = up.lenSquared();
  363. if (lenSq < 0.000001f)
  364. {
  365. up.set(0.0f, 0.0f, 1.0f);
  366. Con::errorf("SceneObject::setForwardVector() - degenerate up vector - too small");
  367. }
  368. else
  369. {
  370. up /= mSqrt(lenSq);
  371. }
  372. if (fabsf(mDot(up, axisY)) > 0.9999f)
  373. {
  374. Con::errorf("SceneObject::setForwardVector() - degenerate up vector - same as forward");
  375. // I haven't really tested this, but i think it generates something which should be not parallel to the previous vector:
  376. F32 tmp = up.x;
  377. up.x = -up.y;
  378. up.y = up.z;
  379. up.z = tmp;
  380. }
  381. // construct the remaining axes:
  382. mCross(axisY, up, &axisX);
  383. mCross(axisX, axisY, &axisZ);
  384. mat.setColumn(0, axisX);
  385. mat.setColumn(1, axisY);
  386. mat.setColumn(2, axisZ);
  387. setTransform(mat);
  388. }
  389. //-----------------------------------------------------------------------------
  390. void SceneObject::resetWorldBox()
  391. {
  392. AssertFatal(mObjBox.isValidBox(), "SceneObject::resetWorldBox - Bad object box!");
  393. mWorldBox = mObjBox;
  394. mWorldBox.minExtents.convolve(mObjScale);
  395. mWorldBox.maxExtents.convolve(mObjScale);
  396. mObjToWorld.mul(mWorldBox);
  397. AssertFatal(mWorldBox.isValidBox(), "SceneObject::resetWorldBox - Bad world box!");
  398. // Create mWorldSphere from mWorldBox
  399. mWorldBox.getCenter(&mWorldSphere.center);
  400. mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len();
  401. // Update tracker links.
  402. for( SceneObjectLink* link = mSceneObjectLinks; link != NULL;
  403. link = link->getNextLink() )
  404. link->update();
  405. }
  406. //-----------------------------------------------------------------------------
  407. void SceneObject::resetObjectBox()
  408. {
  409. AssertFatal( mWorldBox.isValidBox(), "SceneObject::resetObjectBox - Bad world box!" );
  410. mObjBox = mWorldBox;
  411. mWorldToObj.mul( mObjBox );
  412. Point3F objScale( mObjScale );
  413. objScale.setMax( Point3F( (F32)POINT_EPSILON, (F32)POINT_EPSILON, (F32)POINT_EPSILON ) );
  414. mObjBox.minExtents.convolveInverse( objScale );
  415. mObjBox.maxExtents.convolveInverse( objScale );
  416. AssertFatal( mObjBox.isValidBox(), "SceneObject::resetObjectBox - Bad object box!" );
  417. // Update the mWorldSphere from mWorldBox
  418. mWorldBox.getCenter( &mWorldSphere.center );
  419. mWorldSphere.radius = ( mWorldBox.maxExtents - mWorldSphere.center ).len();
  420. // Update scene managers.
  421. for( SceneObjectLink* link = mSceneObjectLinks; link != NULL;
  422. link = link->getNextLink() )
  423. link->update();
  424. }
  425. //-----------------------------------------------------------------------------
  426. void SceneObject::setRenderTransform(const MatrixF& mat)
  427. {
  428. PROFILE_START(SceneObj_setRenderTransform);
  429. mRenderObjToWorld = mRenderWorldToObj = mat;
  430. mRenderWorldToObj.affineInverse();
  431. AssertFatal(mObjBox.isValidBox(), "Bad object box!");
  432. resetRenderWorldBox();
  433. PROFILE_END();
  434. }
  435. //-----------------------------------------------------------------------------
  436. void SceneObject::resetRenderWorldBox()
  437. {
  438. AssertFatal( mObjBox.isValidBox(), "Bad object box!" );
  439. mRenderWorldBox = mObjBox;
  440. mRenderWorldBox.minExtents.convolve( mObjScale );
  441. mRenderWorldBox.maxExtents.convolve( mObjScale );
  442. mRenderObjToWorld.mul( mRenderWorldBox );
  443. AssertFatal( mRenderWorldBox.isValidBox(), "Bad world box!" );
  444. // Create mRenderWorldSphere from mRenderWorldBox.
  445. mRenderWorldBox.getCenter( &mRenderWorldSphere.center );
  446. mRenderWorldSphere.radius = ( mRenderWorldBox.maxExtents - mRenderWorldSphere.center ).len();
  447. }
  448. //-----------------------------------------------------------------------------
  449. void SceneObject::setHidden( bool hidden )
  450. {
  451. if( hidden != isHidden() )
  452. {
  453. // Add/remove the object from the scene. Removing it
  454. // will also cause the NetObject to go out of scope since
  455. // the container query will not find it anymore. However,
  456. // ScopeAlways objects need to be treated separately as we
  457. // do next.
  458. if( !hidden )
  459. addToScene();
  460. else
  461. removeFromScene();
  462. // ScopeAlways objects stay in scope no matter what, i.e. even
  463. // if they aren't in the scene query anymore. So, to force ghosts
  464. // to go away, we need to clear ScopeAlways while we are hidden.
  465. if( hidden && mIsScopeAlways )
  466. clearScopeAlways();
  467. else if( !hidden && mIsScopeAlways )
  468. setScopeAlways();
  469. Parent::setHidden( hidden );
  470. }
  471. }
  472. //-----------------------------------------------------------------------------
  473. void SceneObject::initPersistFields()
  474. {
  475. addGroup("GameObject");
  476. addField("GameObject", TypeGameObjectAssetPtr, Offset(mGameObjectAsset, SceneObject), "The asset Id used for the game object this entity is based on.");
  477. addField("dirtyGameObject", TypeBool, Offset(mDirtyGameObject, SceneObject), "If this entity is a GameObject, it flags if this instance delinates from the template.",
  478. AbstractClassRep::FieldFlags::FIELD_HideInInspectors);
  479. endGroup("GameObject");
  480. addGroup( "Transform" );
  481. addProtectedField( "position", TypeMatrixPosition, Offset( mObjToWorld, SceneObject ),
  482. &_setFieldPosition, &defaultProtectedGetFn,
  483. "Object world position." );
  484. addProtectedField( "rotation", TypeMatrixRotation, Offset( mObjToWorld, SceneObject ),
  485. &_setFieldRotation, &defaultProtectedGetFn,
  486. "Object world orientation." );
  487. addProtectedField( "scale", TypePoint3F, Offset( mObjScale, SceneObject ),
  488. &_setFieldScale, &defaultProtectedGetFn,
  489. "Object world scale." );
  490. endGroup( "Transform" );
  491. addGroup( "Editing" );
  492. addProtectedField( "isRenderEnabled", TypeBool, Offset( mObjectFlags, SceneObject ),
  493. &_setRenderEnabled, &_getRenderEnabled,
  494. "Controls client-side rendering of the object.\n"
  495. "@see isRenderable()\n" );
  496. addProtectedField( "isSelectionEnabled", TypeBool, Offset( mObjectFlags, SceneObject ),
  497. &_setSelectionEnabled, &_getSelectionEnabled,
  498. "Determines if the object may be selected from wihin the Tools.\n"
  499. "@see isSelectable()\n" );
  500. endGroup( "Editing" );
  501. addGroup( "Mounting" );
  502. addProtectedField( "mountPID", TypePID, Offset( mMountPID, SceneObject ), &_setMountPID, &defaultProtectedGetFn,
  503. "@brief PersistentID of object we are mounted to.\n\n"
  504. "Unlike the SimObjectID that is determined at run time, the PersistentID of an object is saved with the level/mission and "
  505. "may be used to form a link between objects." );
  506. addField( "mountNode", TypeS32, Offset( mMount.node, SceneObject ), "Node we are mounted to." );
  507. addField( "mountPos", TypeMatrixPosition, Offset( mMount.xfm, SceneObject ), "Position we are mounted at ( object space of our mount object )." );
  508. addField( "mountRot", TypeMatrixRotation, Offset( mMount.xfm, SceneObject ), "Rotation we are mounted at ( object space of our mount object )." );
  509. endGroup( "Mounting" );
  510. Parent::initPersistFields();
  511. }
  512. bool SceneObject::_setGameObject(void* object, const char* index, const char* data)
  513. {
  514. // Sanity!
  515. AssertFatal(data != NULL, "Cannot use a NULL asset Id.");
  516. return true; //rbI->setMeshAsset(data);
  517. }
  518. //-----------------------------------------------------------------------------
  519. bool SceneObject::_setFieldPosition( void *object, const char *index, const char *data )
  520. {
  521. SceneObject* so = static_cast<SceneObject*>( object );
  522. if ( so )
  523. {
  524. MatrixF txfm( so->getTransform() );
  525. Con::setData( TypeMatrixPosition, &txfm, 0, 1, &data );
  526. so->setTransform( txfm );
  527. }
  528. return false;
  529. }
  530. //-----------------------------------------------------------------------------
  531. bool SceneObject::_setFieldRotation( void *object, const char *index, const char *data )
  532. {
  533. SceneObject* so = static_cast<SceneObject*>( object );
  534. if ( so )
  535. {
  536. MatrixF txfm( so->getTransform() );
  537. Con::setData( TypeMatrixRotation, &txfm, 0, 1, &data );
  538. so->setTransform( txfm );
  539. }
  540. return false;
  541. }
  542. //-----------------------------------------------------------------------------
  543. bool SceneObject::_setFieldScale( void *object, const char *index, const char *data )
  544. {
  545. SceneObject* so = static_cast<SceneObject*>( object );
  546. if ( so )
  547. {
  548. Point3F scale;
  549. Con::setData( TypePoint3F, &scale, 0, 1, &data );
  550. so->setScale( scale );
  551. }
  552. return false;
  553. }
  554. //-----------------------------------------------------------------------------
  555. bool SceneObject::writeField( StringTableEntry fieldName, const char* value )
  556. {
  557. if( !Parent::writeField( fieldName, value ) )
  558. return false;
  559. static StringTableEntry sIsRenderEnabled = StringTable->insert( "isRenderEnabled" );
  560. static StringTableEntry sIsSelectionEnabled = StringTable->insert( "isSelectionEnabled" );
  561. static StringTableEntry sMountNode = StringTable->insert( "mountNode" );
  562. static StringTableEntry sMountPos = StringTable->insert( "mountPos" );
  563. static StringTableEntry sMountRot = StringTable->insert( "mountRot" );
  564. // Don't write flag fields if they are at their default values.
  565. if( fieldName == sIsRenderEnabled && dAtob( value ) )
  566. return false;
  567. else if( fieldName == sIsSelectionEnabled && dAtob( value ) )
  568. return false;
  569. else if ( mMountPID == NULL && ( fieldName == sMountNode ||
  570. fieldName == sMountPos ||
  571. fieldName == sMountRot ) )
  572. {
  573. return false;
  574. }
  575. return true;
  576. }
  577. //-----------------------------------------------------------------------------
  578. static void scopeCallback( SceneObject* obj, void* conPtr )
  579. {
  580. NetConnection* ptr = reinterpret_cast< NetConnection* >( conPtr );
  581. if( obj->isScopeable() )
  582. ptr->objectInScope(obj);
  583. }
  584. void SceneObject::onCameraScopeQuery( NetConnection* connection, CameraScopeQuery* query )
  585. {
  586. SceneManager* sceneManager = getSceneManager();
  587. GameConnection* conn = dynamic_cast<GameConnection*> (connection);
  588. if (conn && (query->visibleDistance = conn->getVisibleGhostDistance()) == 0.0f)
  589. if ((query->visibleDistance = sceneManager->getVisibleGhostDistance()) == 0.0f)
  590. query->visibleDistance = sceneManager->getVisibleDistance();
  591. // Object itself is in scope.
  592. if( this->isScopeable() )
  593. connection->objectInScope( this );
  594. // If we're mounted to something, that object is in scope too.
  595. if( isMounted() )
  596. connection->objectInScope( mMount.object );
  597. // If we're added to a scene graph, let the graph do the scene scoping.
  598. // Otherwise just put everything in the server container in scope.
  599. if( getSceneManager() )
  600. getSceneManager()->scopeScene( query, connection );
  601. else
  602. gServerContainer.findObjects( 0xFFFFFFFF, scopeCallback, connection );
  603. }
  604. //-----------------------------------------------------------------------------
  605. bool SceneObject::isRenderEnabled() const
  606. {
  607. #ifdef TORQUE_TOOLS
  608. if (gEditingMission)
  609. {
  610. AbstractClassRep *classRep = getClassRep();
  611. return (mObjectFlags.test(RenderEnabledFlag) && classRep->isRenderEnabled());
  612. }
  613. #endif
  614. return (mObjectFlags.test(RenderEnabledFlag));
  615. }
  616. //-----------------------------------------------------------------------------
  617. void SceneObject::setRenderEnabled( bool value )
  618. {
  619. if( value )
  620. mObjectFlags.set( RenderEnabledFlag );
  621. else
  622. mObjectFlags.clear( RenderEnabledFlag );
  623. setMaskBits( FlagMask );
  624. }
  625. //-----------------------------------------------------------------------------
  626. const char* SceneObject::_getRenderEnabled( void* object, const char* data )
  627. {
  628. SceneObject* obj = reinterpret_cast< SceneObject* >( object );
  629. if( obj->mObjectFlags.test( RenderEnabledFlag ) )
  630. return "1";
  631. else
  632. return "0";
  633. }
  634. //-----------------------------------------------------------------------------
  635. bool SceneObject::_setRenderEnabled( void *object, const char *index, const char *data )
  636. {
  637. SceneObject* obj = reinterpret_cast< SceneObject* >( object );
  638. obj->setRenderEnabled( dAtob( data ) );
  639. return false;
  640. }
  641. //-----------------------------------------------------------------------------
  642. bool SceneObject::isSelectionEnabled() const
  643. {
  644. AbstractClassRep *classRep = getClassRep();
  645. return ( mObjectFlags.test( SelectionEnabledFlag ) && classRep->isSelectionEnabled() );
  646. }
  647. //-----------------------------------------------------------------------------
  648. void SceneObject::setSelectionEnabled( bool value )
  649. {
  650. if( value )
  651. mObjectFlags.set( SelectionEnabledFlag );
  652. else
  653. mObjectFlags.clear( SelectionEnabledFlag );
  654. // Not synchronized on network so don't set dirty bit.
  655. }
  656. //-----------------------------------------------------------------------------
  657. const char* SceneObject::_getSelectionEnabled( void* object, const char* data )
  658. {
  659. SceneObject* obj = reinterpret_cast< SceneObject* >( object );
  660. if( obj->mObjectFlags.test( SelectionEnabledFlag ) )
  661. return "true";
  662. else
  663. return "false";
  664. }
  665. //-----------------------------------------------------------------------------
  666. bool SceneObject::_setSelectionEnabled( void *object, const char *index, const char *data )
  667. {
  668. SceneObject* obj = reinterpret_cast< SceneObject* >( object );
  669. obj->setSelectionEnabled( dAtob( data ) );
  670. return false;
  671. }
  672. //--------------------------------------------------------------------------
  673. U32 SceneObject::packUpdate( NetConnection* conn, U32 mask, BitStream* stream )
  674. {
  675. U32 retMask = Parent::packUpdate( conn, mask, stream );
  676. if ( stream->writeFlag( mask & FlagMask ) )
  677. stream->writeRangedU32( (U32)mObjectFlags, 0, getObjectFlagMax() );
  678. if ( mask & MountedMask )
  679. {
  680. if ( mMount.object )
  681. {
  682. S32 gIndex = conn->getGhostIndex( mMount.object );
  683. if ( stream->writeFlag( gIndex != -1 ) )
  684. {
  685. stream->writeFlag( true );
  686. stream->writeInt( gIndex, NetConnection::GhostIdBitSize );
  687. if ( stream->writeFlag( mMount.node != -1 ) )
  688. stream->writeInt( mMount.node, NumMountPointBits );
  689. mathWrite( *stream, mMount.xfm );
  690. }
  691. else
  692. // Will have to try again later
  693. retMask |= MountedMask;
  694. }
  695. else
  696. // Unmount if this isn't the initial packet
  697. if ( stream->writeFlag( !(mask & InitialUpdateMask) ) )
  698. stream->writeFlag( false );
  699. }
  700. else
  701. stream->writeFlag( false );
  702. return retMask;
  703. }
  704. //-----------------------------------------------------------------------------
  705. void SceneObject::unpackUpdate( NetConnection* conn, BitStream* stream )
  706. {
  707. Parent::unpackUpdate( conn, stream );
  708. // FlagMask
  709. if ( stream->readFlag() )
  710. mObjectFlags = stream->readRangedU32( 0, getObjectFlagMax() );
  711. // MountedMask
  712. if ( stream->readFlag() )
  713. {
  714. if ( stream->readFlag() )
  715. {
  716. S32 gIndex = stream->readInt( NetConnection::GhostIdBitSize );
  717. SceneObject* obj = dynamic_cast<SceneObject*>( conn->resolveGhost( gIndex ) );
  718. S32 node = -1;
  719. if ( stream->readFlag() ) // node != -1
  720. node = stream->readInt( NumMountPointBits );
  721. MatrixF xfm;
  722. mathRead( *stream, &xfm );
  723. if ( !obj )
  724. {
  725. conn->setLastError( "Invalid packet from server." );
  726. return;
  727. }
  728. obj->mountObject( this, node, xfm );
  729. }
  730. else
  731. unmount();
  732. }
  733. }
  734. //-----------------------------------------------------------------------------
  735. void SceneObject::_updateZoningState() const
  736. {
  737. if( mZoneRefDirty )
  738. {
  739. SceneZoneSpaceManager* manager = getSceneManager()->getZoneManager();
  740. if( manager )
  741. manager->updateObject( const_cast< SceneObject* >( this ) );
  742. else
  743. mZoneRefDirty = false;
  744. }
  745. }
  746. //-----------------------------------------------------------------------------
  747. U32 SceneObject::_getCurrZone( const U32 index ) const
  748. {
  749. _updateZoningState();
  750. // Not the most efficient way to do this, walking the list,
  751. // but it's an uncommon call...
  752. ZoneRef* walk = mZoneRefHead;
  753. for( U32 i = 0; i < index; ++ i )
  754. {
  755. walk = walk->nextInObj;
  756. AssertFatal( walk != NULL, "SceneObject::_getCurrZone - Too few object refs!" );
  757. }
  758. AssertFatal( walk != NULL, "SceneObject::_getCurrZone - Too few object refs!" );
  759. return walk->zone;
  760. }
  761. //-----------------------------------------------------------------------------
  762. Point3F SceneObject::getPosition() const
  763. {
  764. Point3F pos;
  765. mObjToWorld.getColumn(3, &pos);
  766. return pos;
  767. }
  768. //-----------------------------------------------------------------------------
  769. Point3F SceneObject::getRenderPosition() const
  770. {
  771. Point3F pos;
  772. mRenderObjToWorld.getColumn(3, &pos);
  773. return pos;
  774. }
  775. //-----------------------------------------------------------------------------
  776. void SceneObject::setPosition(const Point3F &pos)
  777. {
  778. AssertFatal( !mIsNaN( pos ), "SceneObject::setPosition() - The position is NaN!" );
  779. MatrixF xform = mObjToWorld;
  780. xform.setColumn(3, pos);
  781. setTransform(xform);
  782. }
  783. //-----------------------------------------------------------------------------
  784. F32 SceneObject::distanceTo(const Point3F &pnt) const
  785. {
  786. return mWorldBox.getDistanceToPoint( pnt );
  787. }
  788. //-----------------------------------------------------------------------------
  789. void SceneObject::processAfter( ProcessObject *obj )
  790. {
  791. AssertFatal( dynamic_cast<SceneObject*>( obj ), "SceneObject::processAfter - Got non-SceneObject!" );
  792. mAfterObject = (SceneObject*)obj;
  793. if ( mAfterObject->mAfterObject == this )
  794. mAfterObject->mAfterObject = NULL;
  795. getProcessList()->markDirty();
  796. }
  797. //-----------------------------------------------------------------------------
  798. void SceneObject::clearProcessAfter()
  799. {
  800. mAfterObject = NULL;
  801. }
  802. //-----------------------------------------------------------------------------
  803. void SceneObject::setProcessTick( bool t )
  804. {
  805. if ( t == mProcessTick )
  806. return;
  807. if ( mProcessTick )
  808. {
  809. if ( !getMountedObjectCount() )
  810. plUnlink(); // Only unlink if there is nothing mounted to us
  811. mProcessTick = false;
  812. }
  813. else
  814. {
  815. // Just to be sure...
  816. plUnlink();
  817. getProcessList()->addObject( this );
  818. mProcessTick = true;
  819. }
  820. }
  821. //-----------------------------------------------------------------------------
  822. ProcessList* SceneObject::getProcessList() const
  823. {
  824. if ( isClientObject() )
  825. return ClientProcessList::get();
  826. else
  827. return ServerProcessList::get();
  828. }
  829. //-------------------------------------------------------------------------
  830. bool SceneObject::isMounted()
  831. {
  832. resolveMountPID();
  833. return mMount.object != NULL;
  834. }
  835. //-----------------------------------------------------------------------------
  836. S32 SceneObject::getMountedObjectCount()
  837. {
  838. S32 count = 0;
  839. for (SceneObject* itr = mMount.list; itr; itr = itr->mMount.link)
  840. count++;
  841. return count;
  842. }
  843. //-----------------------------------------------------------------------------
  844. SceneObject* SceneObject::getMountedObject(S32 idx)
  845. {
  846. if (idx >= 0) {
  847. S32 count = 0;
  848. for (SceneObject* itr = mMount.list; itr; itr = itr->mMount.link)
  849. if (count++ == idx)
  850. return itr;
  851. }
  852. return NULL;
  853. }
  854. //-----------------------------------------------------------------------------
  855. S32 SceneObject::getMountedObjectNode(S32 idx)
  856. {
  857. if (idx >= 0) {
  858. S32 count = 0;
  859. for (SceneObject* itr = mMount.list; itr; itr = itr->mMount.link)
  860. if (count++ == idx)
  861. return itr->mMount.node;
  862. }
  863. return -1;
  864. }
  865. //-----------------------------------------------------------------------------
  866. SceneObject* SceneObject::getMountNodeObject(S32 node)
  867. {
  868. for (SceneObject* itr = mMount.list; itr; itr = itr->mMount.link)
  869. if (itr->mMount.node == node)
  870. return itr;
  871. return NULL;
  872. }
  873. //-----------------------------------------------------------------------------
  874. bool SceneObject::_setMountPID( void* object, const char* index, const char* data )
  875. {
  876. SceneObject* so = static_cast<SceneObject*>( object );
  877. if ( so )
  878. {
  879. // Unmount old object (PID reference is released even if it had been resolved yet)
  880. if ( so->mMountPID )
  881. {
  882. so->mMountPID->decRefCount();
  883. so->mMountPID = NULL;
  884. }
  885. so->unmount();
  886. // Get the new PID (new object will be mounted on demand)
  887. Con::setData( TypePID, &so->mMountPID, 0, 1, &data );
  888. if ( so->mMountPID )
  889. so->mMountPID->incRefCount(); // Prevent PID from being deleted out from under us!
  890. }
  891. return false;
  892. }
  893. void SceneObject::resolveMountPID()
  894. {
  895. if ( mMountPID && !mMount.object )
  896. {
  897. SceneObject *obj = dynamic_cast< SceneObject* >( mMountPID->getObject() );
  898. if ( obj )
  899. obj->mountObject( this, mMount.node, mMount.xfm );
  900. }
  901. }
  902. //-----------------------------------------------------------------------------
  903. void SceneObject::mountObject( SceneObject *obj, S32 node, const MatrixF &xfm )
  904. {
  905. if ( obj->mMount.object == this )
  906. {
  907. // Already mounted to this
  908. // So update our node and xfm which may have changed.
  909. obj->mMount.node = node;
  910. obj->mMount.xfm = xfm;
  911. }
  912. else
  913. {
  914. if ( obj->mMount.object )
  915. obj->unmount();
  916. obj->mMount.object = this;
  917. obj->mMount.node = node;
  918. obj->mMount.link = mMount.list;
  919. obj->mMount.xfm = xfm;
  920. mMount.list = obj;
  921. // Assign PIDs to both objects
  922. if ( isServerObject() )
  923. {
  924. obj->getOrCreatePersistentId();
  925. if ( !obj->mMountPID )
  926. {
  927. obj->mMountPID = getOrCreatePersistentId();
  928. obj->mMountPID->incRefCount();
  929. }
  930. }
  931. obj->onMount( this, node );
  932. }
  933. }
  934. //-----------------------------------------------------------------------------
  935. void SceneObject::unmountObject( SceneObject *obj )
  936. {
  937. if ( obj->mMount.object == this )
  938. {
  939. // Find and unlink the object
  940. for ( SceneObject **ptr = &mMount.list; *ptr; ptr = &(*ptr)->mMount.link )
  941. {
  942. if ( *ptr == obj )
  943. {
  944. *ptr = obj->mMount.link;
  945. break;
  946. }
  947. }
  948. obj->mMount.object = NULL;
  949. obj->mMount.link = NULL;
  950. if( obj->mMountPID != NULL ) // Only on server.
  951. {
  952. obj->mMountPID->decRefCount();
  953. obj->mMountPID = NULL;
  954. }
  955. obj->onUnmount( this, obj->mMount.node );
  956. }
  957. }
  958. //-----------------------------------------------------------------------------
  959. void SceneObject::unmount()
  960. {
  961. if (mMount.object)
  962. mMount.object->unmountObject(this);
  963. }
  964. //-----------------------------------------------------------------------------
  965. void SceneObject::onMount( SceneObject *obj, S32 node )
  966. {
  967. deleteNotify( obj );
  968. if ( !isGhost() )
  969. {
  970. setMaskBits( MountedMask );
  971. //onMount_callback( node );
  972. }
  973. }
  974. //-----------------------------------------------------------------------------
  975. void SceneObject::onUnmount( SceneObject *obj, S32 node )
  976. {
  977. clearNotify(obj);
  978. if ( !isGhost() )
  979. {
  980. setMaskBits( MountedMask );
  981. //onUnmount_callback( node );
  982. }
  983. }
  984. //-----------------------------------------------------------------------------
  985. void SceneObject::getMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat )
  986. {
  987. MatrixF mountTransform( xfm );
  988. const Point3F &scale = getScale();
  989. Point3F position = mountTransform.getPosition();
  990. position.convolve( scale );
  991. mountTransform.setPosition( position );
  992. outMat->mul( mObjToWorld, mountTransform );
  993. }
  994. //-----------------------------------------------------------------------------
  995. void SceneObject::getRenderMountTransform( F32 delta, S32 index, const MatrixF &xfm, MatrixF *outMat )
  996. {
  997. MatrixF mountTransform( xfm );
  998. const Point3F &scale = getScale();
  999. Point3F position = mountTransform.getPosition();
  1000. position.convolve( scale );
  1001. mountTransform.setPosition( position );
  1002. outMat->mul( mRenderObjToWorld, mountTransform );
  1003. }
  1004. //=============================================================================
  1005. // Console API.
  1006. //=============================================================================
  1007. // MARK: ---- Console API ----
  1008. //-----------------------------------------------------------------------------
  1009. DefineEngineMethod( SceneObject, getType, S32, (),,
  1010. "Return the type mask for this object.\n"
  1011. "@return The numeric type mask for the object." )
  1012. {
  1013. return object->getTypeMask();
  1014. }
  1015. //-----------------------------------------------------------------------------
  1016. DefineEngineMethod( SceneObject, mountObject, bool,
  1017. ( SceneObject* objB, S32 slot, TransformF txfm ), ( TransformF::Identity ),
  1018. "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
  1019. "@param objB Object to mount onto us\n"
  1020. "@param slot Mount slot ID\n"
  1021. "@param txfm (optional) mount offset transform\n"
  1022. "@return true if successful, false if failed (objB is not valid)" )
  1023. {
  1024. if ( objB )
  1025. {
  1026. object->mountObject( objB, slot, txfm.getMatrix() );
  1027. return true;
  1028. }
  1029. return false;
  1030. }
  1031. //-----------------------------------------------------------------------------
  1032. DefineEngineMethod( SceneObject, unmountObject, bool, ( SceneObject* target ),,
  1033. "@brief Unmount an object from ourselves.\n\n"
  1034. "@param target object to unmount\n"
  1035. "@return true if successful, false if failed\n" )
  1036. {
  1037. if ( target )
  1038. {
  1039. object->unmountObject(target);
  1040. return true;
  1041. }
  1042. return false;
  1043. }
  1044. //-----------------------------------------------------------------------------
  1045. DefineEngineMethod( SceneObject, unmount, void, (),,
  1046. "Unmount us from the currently mounted object if any.\n" )
  1047. {
  1048. object->unmount();
  1049. }
  1050. //-----------------------------------------------------------------------------
  1051. DefineEngineMethod( SceneObject, isMounted, bool, (),,
  1052. "@brief Check if we are mounted to another object.\n\n"
  1053. "@return true if mounted to another object, false if not mounted." )
  1054. {
  1055. return object->isMounted();
  1056. }
  1057. //-----------------------------------------------------------------------------
  1058. DefineEngineMethod( SceneObject, getObjectMount, S32, (),,
  1059. "@brief Get the object we are mounted to.\n\n"
  1060. "@return the SimObjectID of the object we're mounted to, or 0 if not mounted." )
  1061. {
  1062. return object->isMounted()? object->getObjectMount()->getId(): 0;
  1063. }
  1064. //-----------------------------------------------------------------------------
  1065. DefineEngineMethod( SceneObject, getMountedObjectCount, S32, (),,
  1066. "Get the number of objects mounted to us.\n"
  1067. "@return the number of mounted objects." )
  1068. {
  1069. return object->getMountedObjectCount();
  1070. }
  1071. //-----------------------------------------------------------------------------
  1072. DefineEngineMethod( SceneObject, getMountedObject, S32, ( S32 slot ),,
  1073. "Get the object mounted at a particular slot.\n"
  1074. "@param slot mount slot index to query\n"
  1075. "@return ID of the object mounted in the slot, or 0 if no object." )
  1076. {
  1077. SceneObject* mobj = object->getMountedObject( slot );
  1078. return mobj? mobj->getId(): 0;
  1079. }
  1080. //-----------------------------------------------------------------------------
  1081. DefineEngineMethod( SceneObject, getMountedObjectNode, S32, ( S32 slot ),,
  1082. "@brief Get the mount node index of the object mounted at our given slot.\n\n"
  1083. "@param slot mount slot index to query\n"
  1084. "@return index of the mount node used by the object mounted in this slot." )
  1085. {
  1086. return object->getMountedObjectNode( slot );
  1087. }
  1088. //-----------------------------------------------------------------------------
  1089. DefineEngineMethod( SceneObject, getMountNodeObject, S32, ( S32 node ),,
  1090. "@brief Get the object mounted at our given node index.\n\n"
  1091. "@param node mount node index to query\n"
  1092. "@return ID of the first object mounted at the node, or 0 if none found." )
  1093. {
  1094. SceneObject* mobj = object->getMountNodeObject( node );
  1095. return mobj? mobj->getId(): 0;
  1096. }
  1097. //-----------------------------------------------------------------------------
  1098. DefineEngineMethod( SceneObject, getTransform, TransformF, (),,
  1099. "Get the object's transform.\n"
  1100. "@return the current transform of the object\n" )
  1101. {
  1102. return object->getTransform();
  1103. }
  1104. //-----------------------------------------------------------------------------
  1105. DefineEngineMethod( SceneObject, getInverseTransform, TransformF, (),,
  1106. "Get the object's inverse transform.\n"
  1107. "@return the inverse transform of the object\n" )
  1108. {
  1109. return object->getWorldTransform();
  1110. }
  1111. //-----------------------------------------------------------------------------
  1112. DefineEngineMethod( SceneObject, getPosition, Point3F, (),,
  1113. "Get the object's world position.\n"
  1114. "@return the current world position of the object\n" )
  1115. {
  1116. return object->getTransform().getPosition();
  1117. }
  1118. DefineEngineMethod( SceneObject, setPosition, void, (Point3F pos),,
  1119. "Set the object's world position.\n"
  1120. "@param pos the new world position of the object\n" )
  1121. {
  1122. return object->setPosition(pos);
  1123. }
  1124. //-----------------------------------------------------------------------------
  1125. DefineEngineMethod( SceneObject, getEulerRotation, Point3F, (),,
  1126. "Get Euler rotation of this object.\n"
  1127. "@return the orientation of the object in the form of rotations around the "
  1128. "X, Y and Z axes in degrees.\n" )
  1129. {
  1130. Point3F euler = object->getTransform().toEuler();
  1131. // Convert to degrees.
  1132. euler.x = mRadToDeg( euler.x );
  1133. euler.y = mRadToDeg( euler.y );
  1134. euler.z = mRadToDeg( euler.z );
  1135. return euler;
  1136. }
  1137. //-----------------------------------------------------------------------------
  1138. DefineEngineMethod( SceneObject, getForwardVector, VectorF, (),,
  1139. "Get the direction this object is facing.\n"
  1140. "@return a vector indicating the direction this object is facing.\n"
  1141. "@note This is the object's y axis." )
  1142. {
  1143. return object->getTransform().getForwardVector();
  1144. }
  1145. //-----------------------------------------------------------------------------
  1146. DefineEngineMethod( SceneObject, getRightVector, VectorF, (),,
  1147. "Get the right vector of the object.\n"
  1148. "@return a vector indicating the right direction of this object."
  1149. "@note This is the object's x axis." )
  1150. {
  1151. return object->getTransform().getRightVector();
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. DefineEngineMethod( SceneObject, getUpVector, VectorF, (),,
  1155. "Get the up vector of the object.\n"
  1156. "@return a vector indicating the up direction of this object."
  1157. "@note This is the object's z axis." )
  1158. {
  1159. return object->getTransform().getUpVector();
  1160. }
  1161. //-----------------------------------------------------------------------------
  1162. DefineEngineMethod( SceneObject, setTransform, void, ( TransformF txfm ),,
  1163. "Set the object's transform (orientation and position)."
  1164. "@param txfm object transform to set" )
  1165. {
  1166. if ( !txfm.hasRotation() )
  1167. object->setPosition( txfm.getPosition() );
  1168. else
  1169. object->setTransform( txfm.getMatrix() );
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. DefineEngineMethod( SceneObject, getScale, Point3F, (),,
  1173. "Get the object's scale.\n"
  1174. "@return object scale as a Point3F" )
  1175. {
  1176. return object->getScale();
  1177. }
  1178. //-----------------------------------------------------------------------------
  1179. DefineEngineMethod( SceneObject, setScale, void, ( Point3F scale ),,
  1180. "Set the object's scale.\n"
  1181. "@param scale object scale to set\n" )
  1182. {
  1183. object->setScale( scale );
  1184. }
  1185. //-----------------------------------------------------------------------------
  1186. DefineEngineMethod( SceneObject, getWorldBox, Box3F, (),,
  1187. "Get the object's world bounding box.\n"
  1188. "@return six fields, two Point3Fs, containing the min and max points of the "
  1189. "worldbox." )
  1190. {
  1191. return object->getWorldBox();
  1192. }
  1193. //-----------------------------------------------------------------------------
  1194. DefineEngineMethod( SceneObject, getWorldBoxCenter, Point3F, (),,
  1195. "Get the center of the object's world bounding box.\n"
  1196. "@return the center of the world bounding box for this object." )
  1197. {
  1198. Point3F center;
  1199. object->getWorldBox().getCenter( &center );
  1200. return center;
  1201. }
  1202. //-----------------------------------------------------------------------------
  1203. DefineEngineMethod( SceneObject, getObjectBox, Box3F, (),,
  1204. "Get the object's bounding box (relative to the object's origin).\n"
  1205. "@return six fields, two Point3Fs, containing the min and max points of the "
  1206. "objectbox." )
  1207. {
  1208. return object->getObjBox();
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. DefineEngineMethod( SceneObject, isGlobalBounds, bool, (),,
  1212. "Check if this object has a global bounds set.\n"
  1213. "If global bounds are set to be true, then the object is assumed to have an "
  1214. "infinitely large bounding box for collision and rendering purposes.\n"
  1215. "@return true if the object has a global bounds." )
  1216. {
  1217. return object->isGlobalBounds();
  1218. }
  1219. DefineEngineMethod(SceneObject, setForwardVector, void, (VectorF newForward, VectorF upVector), (VectorF(0, 0, 0), VectorF(0, 0, 1)),
  1220. "Sets the forward vector of a scene object, making it face Y+ along the new vector.\n"
  1221. "@param The new forward vector to set.\n"
  1222. "@param (Optional) The up vector to use to help orient the rotation.")
  1223. {
  1224. object->setForwardVector(newForward, upVector);
  1225. }