physicalZone.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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 "T3D/physicalZone.h"
  27. #include "core/stream/bitStream.h"
  28. #include "collision/boxConvex.h"
  29. #include "collision/clippedPolyList.h"
  30. #include "console/consoleTypes.h"
  31. #include "math/mathIO.h"
  32. #include "scene/sceneRenderState.h"
  33. #include "T3D/trigger.h"
  34. #include "gfx/gfxTransformSaver.h"
  35. #include "renderInstance/renderPassManager.h"
  36. #include "gfx/gfxDrawUtil.h"
  37. #include "console/engineAPI.h"
  38. //#include "console/engineTypes.h"
  39. #include "sim/netConnection.h"
  40. IMPLEMENT_CO_NETOBJECT_V1(PhysicalZone);
  41. ConsoleDocClass( PhysicalZone,
  42. "@brief Physical Zones are areas that modify the player's gravity and/or velocity and/or applied force.\n\n"
  43. "The datablock properties determine how the physics, velocity and applied forces affect a player who enters this zone.\n"
  44. "@tsexample\n"
  45. "new PhysicalZone(Team1JumpPad) {\n"
  46. "velocityMod = \"1\";"
  47. "gravityMod = \"0\";\n"
  48. "appliedForce = \"0 0 20000\";\n"
  49. "polyhedron = \"0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000\";\n"
  50. "position = \"273.559 -166.371 249.856\";\n"
  51. "rotation = \"0 0 1 13.0216\";\n"
  52. "scale = \"8 4.95 28.31\";\n"
  53. "isRenderEnabled = \"true\";\n"
  54. "canSaveDynamicFields = \"1\";\n"
  55. "enabled = \"1\";\n"
  56. "};\n"
  57. "@endtsexample\n\n"
  58. "@ingroup enviroMisc\n"
  59. );
  60. bool PhysicalZone::smRenderPZones = false;
  61. DefineEngineMethod(PhysicalZone, activate, void, (),, "Activate the physical zone's effects.\n"
  62. "@tsexample\n"
  63. "// Activate effects for a specific physical zone.\n"
  64. "%thisPhysicalZone.activate();\n"
  65. "@endtsexample\n"
  66. "@ingroup Datablocks\n"
  67. )
  68. {
  69. if (object->isClientObject())
  70. return;
  71. object->activate();
  72. }
  73. DefineEngineMethod(PhysicalZone, deactivate, void, (),, "Deactivate the physical zone's effects.\n"
  74. "@tsexample\n"
  75. "// Deactivate effects for a specific physical zone.\n"
  76. "%thisPhysicalZone.deactivate();\n"
  77. "@endtsexample\n"
  78. "@ingroup Datablocks\n"
  79. )
  80. {
  81. if (object->isClientObject())
  82. return;
  83. object->deactivate();
  84. }
  85. //--------------------------------------------------------------------------
  86. //--------------------------------------
  87. //
  88. PhysicalZone::PhysicalZone()
  89. {
  90. mNetFlags.set(Ghostable | ScopeAlways);
  91. mTypeMask |= PhysicalZoneObjectType;
  92. mVelocityMod = 1.0f;
  93. mGravityMod = 1.0f;
  94. mAppliedForce.set(0, 0, 0);
  95. mConvexList = new Convex;
  96. mActive = true;
  97. force_type = VECTOR;
  98. force_mag = 0.0f;
  99. orient_force = false;
  100. fade_amt = 1.0f;
  101. //Default up a basic square
  102. Point3F vecs[3] = { Point3F(1.0, 0.0, 0.0),
  103. Point3F(0.0, -1.0, 0.0),
  104. Point3F(0.0, 0.0, 1.0) };
  105. mPolyhedron = Polyhedron(Point3F(-0.5, 0.5, 0.0), vecs);
  106. }
  107. PhysicalZone::~PhysicalZone()
  108. {
  109. delete mConvexList;
  110. mConvexList = NULL;
  111. }
  112. ImplementEnumType( PhysicalZone_ForceType, "Possible physical zone force types.\n" "@ingroup PhysicalZone\n\n" )
  113. { PhysicalZone::VECTOR, "vector", "..." },
  114. { PhysicalZone::SPHERICAL, "spherical", "..." },
  115. { PhysicalZone::CYLINDRICAL, "cylindrical", "..." },
  116. // aliases
  117. { PhysicalZone::SPHERICAL, "sphere", "..." },
  118. { PhysicalZone::CYLINDRICAL, "cylinder", "..." },
  119. EndImplementEnumType;
  120. //--------------------------------------------------------------------------
  121. void PhysicalZone::consoleInit()
  122. {
  123. Con::addVariable( "$PhysicalZone::renderZones", TypeBool, &smRenderPZones, "If true, a box will render around the location of all PhysicalZones.\n"
  124. "@ingroup EnviroMisc\n");
  125. }
  126. FRangeValidator velocityModRange(-40.0f, 40.0f);
  127. FRangeValidator gravityModRange(-40.0f, 40.0f);
  128. void PhysicalZone::initPersistFields()
  129. {
  130. docsURL;
  131. addGroup("Misc");
  132. addFieldV("velocityMod", TypeRangedF32, Offset(mVelocityMod, PhysicalZone), &velocityModRange, "Multiply velocity of objects entering zone by this value every tick.");
  133. addFieldV("gravityMod", TypeRangedF32, Offset(mGravityMod, PhysicalZone), &gravityModRange, "Gravity in PhysicalZone. Multiplies against standard gravity.");
  134. addField("appliedForce", TypePoint3F, Offset(mAppliedForce, PhysicalZone), "Three-element floating point value representing forces in three axes to apply to objects entering PhysicalZone.");
  135. addField("polyhedron", TypeTriggerPolyhedron, Offset(mPolyhedron, PhysicalZone),
  136. "The polyhedron type is really a quadrilateral and consists of a corner"
  137. "point followed by three vectors representing the edges extending from the corner." );
  138. endGroup("Misc");
  139. addGroup("AFX");
  140. addField("forceType", TYPEID<PhysicalZone::ForceType>(), Offset(force_type, PhysicalZone));
  141. addField("orientForce", TypeBool, Offset(orient_force, PhysicalZone));
  142. endGroup("AFX");
  143. Parent::initPersistFields();
  144. }
  145. //--------------------------------------------------------------------------
  146. bool PhysicalZone::onAdd()
  147. {
  148. if(!Parent::onAdd())
  149. return false;
  150. if (mVelocityMod < -40.0f || mVelocityMod > 40.0f) {
  151. Con::errorf("PhysicalZone: velocity mod out of range. [-40, 40]");
  152. mVelocityMod = mVelocityMod < -40.0f ? -40.0f : 40.0f;
  153. }
  154. if (mGravityMod < -40.0f || mGravityMod > 40.0f) {
  155. Con::errorf("PhysicalZone: GravityMod out of range. [-40, 40]");
  156. mGravityMod = mGravityMod < -40.0f ? -40.0f : 40.0f;
  157. }
  158. static const char* coordString[] = { "x", "y", "z" };
  159. F32* p = mAppliedForce;
  160. for (U32 i = 0; i < 3; i++) {
  161. if (p[i] < -40000.0f || p[i] > 40000.0f) {
  162. Con::errorf("PhysicalZone: applied force: %s out of range. [-40000, 40000]", coordString[i]);
  163. p[i] = p[i] < -40000.0f ? -40000.0f : 40000.0f;
  164. }
  165. }
  166. Polyhedron temp = mPolyhedron;
  167. setPolyhedron(temp);
  168. switch (force_type)
  169. {
  170. case SPHERICAL:
  171. force_mag = mAppliedForce.magnitudeSafe();
  172. break;
  173. case CYLINDRICAL:
  174. {
  175. Point3F force_vec = mAppliedForce;
  176. force_vec.z = 0.0;
  177. force_mag = force_vec.magnitudeSafe();
  178. }
  179. break;
  180. }
  181. addToScene();
  182. return true;
  183. }
  184. void PhysicalZone::onRemove()
  185. {
  186. mConvexList->nukeList();
  187. removeFromScene();
  188. Parent::onRemove();
  189. }
  190. void PhysicalZone::inspectPostApply()
  191. {
  192. Parent::inspectPostApply();
  193. setPolyhedron(mPolyhedron);
  194. setMaskBits(PolyhedronMask | MoveMask | SettingsMask | FadeMask);
  195. }
  196. //------------------------------------------------------------------------------
  197. void PhysicalZone::setTransform(const MatrixF & mat)
  198. {
  199. Parent::setTransform(mat);
  200. MatrixF base(true);
  201. base.scale(Point3F(1.0/mObjScale.x,
  202. 1.0/mObjScale.y,
  203. 1.0/mObjScale.z));
  204. base.mul(mWorldToObj);
  205. mClippedList.setBaseTransform(base);
  206. if (isServerObject())
  207. setMaskBits(MoveMask);
  208. }
  209. void PhysicalZone::prepRenderImage( SceneRenderState *state )
  210. {
  211. // only render if selected or render flag is set
  212. if ( !smRenderPZones && !isSelected() )
  213. return;
  214. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  215. ri->renderDelegate.bind( this, &PhysicalZone::renderObject );
  216. ri->type = RenderPassManager::RIT_Editor;
  217. ri->defaultKey = 0;
  218. ri->defaultKey2 = 0;
  219. state->getRenderPass()->addInst( ri );
  220. }
  221. void PhysicalZone::renderObject(ObjectRenderInst *ri,
  222. SceneRenderState *state,
  223. BaseMatInstance *overrideMat)
  224. {
  225. if (overrideMat)
  226. return;
  227. GFXStateBlockDesc desc;
  228. desc.setZReadWrite(true, false);
  229. desc.setBlend(true);
  230. desc.setCullMode(GFXCullNone);
  231. GFXTransformSaver saver;
  232. GFXDrawUtil *drawer = GFX->getDrawUtil();
  233. Point3F start = getBoxCenter();
  234. Box3F obb = mObjBox; //object bounding box
  235. F32 baseForce = 10000; //roughly the ammount of force needed to push a player back as it walks into a zone. (used for visual scaling)
  236. Point3F forceDir = getForce(&start);
  237. F32 forceLen = forceDir.len()/ baseForce;
  238. forceDir.normalizeSafe();
  239. ColorI guideCol = LinearColorF(mFabs(forceDir.x), mFabs(forceDir.y), mFabs(forceDir.z), 0.125).toColorI();
  240. if (force_type == VECTOR)
  241. {
  242. Point3F endPos = start + (forceDir * mMax(forceLen,0.75f));
  243. drawer->drawArrow(desc, start, endPos, guideCol, 0.05f);
  244. }
  245. MatrixF mat = getRenderTransform();
  246. mat.scale(getScale());
  247. GFX->multWorld(mat);
  248. start = obb.getCenter();
  249. if (force_type == VECTOR)
  250. {
  251. drawer->drawPolyhedron(desc, mPolyhedron, ColorI(0, 255, 0, 45));
  252. }
  253. else if (force_type == SPHERICAL)
  254. {
  255. F32 rad = obb.getBoundingSphere().radius/ 2;
  256. drawer->drawSphere(desc, rad, start, ColorI(0, 255, 0, 45));
  257. rad = (rad + (mAppliedForce.most() / baseForce))/2;
  258. desc.setFillModeWireframe();
  259. drawer->drawSphere(desc, rad, start, ColorI(0, 0, 255, 255));
  260. }
  261. else
  262. {
  263. Point3F bottomPos = start;
  264. bottomPos.z -= obb.len_z() / 2;
  265. Point3F topPos = start;
  266. topPos.z += obb.len_z() / 2;
  267. F32 rad = obb.len_x() / 2;
  268. drawer->drawCylinder(desc, bottomPos, topPos, rad, ColorI(0, 255, 0, 45));
  269. Point3F force_vec = mAppliedForce; //raw relative-applied force here as oposed to derived
  270. F32 hieght = (force_vec.z / baseForce);
  271. if (force_vec.z<0)
  272. bottomPos.z = (bottomPos.z + hieght)/2;
  273. else
  274. topPos.z = (topPos.z + hieght) / 2;
  275. if (force_vec.x > force_vec.y)
  276. rad = (rad + (force_vec.x / baseForce)) / 2;
  277. else
  278. rad = (rad + (force_vec.y / baseForce)) / 2;
  279. desc.setFillModeWireframe();
  280. drawer->drawCylinder(desc, bottomPos, topPos, rad, guideCol);
  281. }
  282. desc.setFillModeWireframe();
  283. drawer->drawPolyhedron(desc, mPolyhedron, ColorI::BLACK);
  284. }
  285. //--------------------------------------------------------------------------
  286. U32 PhysicalZone::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
  287. {
  288. U32 i;
  289. U32 retMask = Parent::packUpdate(con, mask, stream);
  290. if (stream->writeFlag(mask & PolyhedronMask))
  291. {
  292. // Write the polyhedron
  293. stream->write(mPolyhedron.mPointList.size());
  294. for (i = 0; i < mPolyhedron.mPointList.size(); i++)
  295. mathWrite(*stream, mPolyhedron.mPointList[i]);
  296. stream->write(mPolyhedron.mPlaneList.size());
  297. for (i = 0; i < mPolyhedron.mPlaneList.size(); i++)
  298. mathWrite(*stream, mPolyhedron.mPlaneList[i]);
  299. stream->write(mPolyhedron.mEdgeList.size());
  300. for (i = 0; i < mPolyhedron.mEdgeList.size(); i++) {
  301. const Polyhedron::Edge& rEdge = mPolyhedron.mEdgeList[i];
  302. stream->write(rEdge.face[0]);
  303. stream->write(rEdge.face[1]);
  304. stream->write(rEdge.vertex[0]);
  305. stream->write(rEdge.vertex[1]);
  306. }
  307. }
  308. if (stream->writeFlag(mask & MoveMask))
  309. {
  310. stream->writeAffineTransform(mObjToWorld);
  311. mathWrite(*stream, mObjScale);
  312. }
  313. if (stream->writeFlag(mask & SettingsMask))
  314. {
  315. stream->write(mVelocityMod);
  316. stream->write(mGravityMod);
  317. mathWrite(*stream, mAppliedForce);
  318. stream->writeInt(force_type, FORCE_TYPE_BITS);
  319. stream->writeFlag(orient_force);
  320. }
  321. if (stream->writeFlag(mask & FadeMask))
  322. {
  323. U8 fade_byte = (U8)(fade_amt*255.0f);
  324. stream->write(fade_byte);
  325. }
  326. stream->writeFlag(mActive);
  327. return retMask;
  328. }
  329. void PhysicalZone::unpackUpdate(NetConnection* con, BitStream* stream)
  330. {
  331. Parent::unpackUpdate(con, stream);
  332. bool new_ph = false;
  333. if (stream->readFlag()) // PolyhedronMask
  334. {
  335. U32 i, size;
  336. Polyhedron tempPH;
  337. // Read the polyhedron
  338. stream->read(&size);
  339. tempPH.mPointList.setSize(size);
  340. for (i = 0; i < tempPH.mPointList.size(); i++)
  341. mathRead(*stream, &tempPH.mPointList[i]);
  342. stream->read(&size);
  343. tempPH.mPlaneList.setSize(size);
  344. for (i = 0; i < tempPH.mPlaneList.size(); i++)
  345. mathRead(*stream, &tempPH.mPlaneList[i]);
  346. stream->read(&size);
  347. tempPH.mEdgeList.setSize(size);
  348. for (i = 0; i < tempPH.mEdgeList.size(); i++) {
  349. Polyhedron::Edge& rEdge = tempPH.mEdgeList[i];
  350. stream->read(&rEdge.face[0]);
  351. stream->read(&rEdge.face[1]);
  352. stream->read(&rEdge.vertex[0]);
  353. stream->read(&rEdge.vertex[1]);
  354. }
  355. setPolyhedron(tempPH);
  356. new_ph = true;
  357. }
  358. if (stream->readFlag()) // MoveMask
  359. {
  360. MatrixF temp;
  361. stream->readAffineTransform(&temp);
  362. Point3F tempScale;
  363. mathRead(*stream, &tempScale);
  364. //if (!new_ph)
  365. //{
  366. // Polyhedron rPolyhedron = mPolyhedron;
  367. // setPolyhedron(rPolyhedron);
  368. //}
  369. setScale(tempScale);
  370. setTransform(temp);
  371. }
  372. if (stream->readFlag()) //SettingsMask
  373. {
  374. stream->read(&mVelocityMod);
  375. stream->read(&mGravityMod);
  376. mathRead(*stream, &mAppliedForce);
  377. force_type = stream->readInt(FORCE_TYPE_BITS); // AFX
  378. orient_force = stream->readFlag(); // AFX
  379. }
  380. if (stream->readFlag()) //FadeMask
  381. {
  382. U8 fade_byte;
  383. stream->read(&fade_byte);
  384. fade_amt = ((F32)fade_byte)/255.0f;
  385. }
  386. else
  387. fade_amt = 1.0f;
  388. mActive = stream->readFlag();
  389. }
  390. //--------------------------------------------------------------------------
  391. void PhysicalZone::setPolyhedron(const Polyhedron& rPolyhedron)
  392. {
  393. mPolyhedron = rPolyhedron;
  394. if (mPolyhedron.mPointList.size() != 0) {
  395. mObjBox.minExtents.set(1e10, 1e10, 1e10);
  396. mObjBox.maxExtents.set(-1e10, -1e10, -1e10);
  397. for (U32 i = 0; i < mPolyhedron.mPointList.size(); i++) {
  398. mObjBox.minExtents.setMin(mPolyhedron.mPointList[i]);
  399. mObjBox.maxExtents.setMax(mPolyhedron.mPointList[i]);
  400. }
  401. } else {
  402. mObjBox.minExtents.set(-0.5, -0.5, -0.5);
  403. mObjBox.maxExtents.set( 0.5, 0.5, 0.5);
  404. }
  405. MatrixF xform = getTransform();
  406. setTransform(xform);
  407. mClippedList.clear();
  408. mClippedList.mPlaneList = mPolyhedron.mPlaneList;
  409. MatrixF base(true);
  410. base.scale(Point3F(1.0/mObjScale.x,
  411. 1.0/mObjScale.y,
  412. 1.0/mObjScale.z));
  413. base.mul(mWorldToObj);
  414. mClippedList.setBaseTransform(base);
  415. }
  416. //--------------------------------------------------------------------------
  417. void PhysicalZone::buildConvex(const Box3F& box, Convex* convex)
  418. {
  419. // These should really come out of a pool
  420. mConvexList->collectGarbage();
  421. Box3F realBox = box;
  422. mWorldToObj.mul(realBox);
  423. realBox.minExtents.convolveInverse(mObjScale);
  424. realBox.maxExtents.convolveInverse(mObjScale);
  425. if (realBox.isOverlapped(getObjBox()) == false)
  426. return;
  427. // Just return a box convex for the entire shape...
  428. Convex* cc = 0;
  429. CollisionWorkingList& wl = convex->getWorkingList();
  430. for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext) {
  431. if (itr->mConvex->getType() == BoxConvexType &&
  432. itr->mConvex->getObject() == this) {
  433. cc = itr->mConvex;
  434. break;
  435. }
  436. }
  437. if (cc)
  438. return;
  439. // Create a new convex.
  440. BoxConvex* cp = new BoxConvex;
  441. mConvexList->registerObject(cp);
  442. convex->addToWorkingList(cp);
  443. cp->init(this);
  444. mObjBox.getCenter(&cp->mCenter);
  445. cp->mSize.x = mObjBox.len_x() / 2.0f;
  446. cp->mSize.y = mObjBox.len_y() / 2.0f;
  447. cp->mSize.z = mObjBox.len_z() / 2.0f;
  448. }
  449. bool PhysicalZone::testObject(SceneObject* enter)
  450. {
  451. // TODO: This doesn't look like it's testing against the polyhedron at
  452. // all. And whats the point of building a convex if no collision methods
  453. // are implemented?
  454. if (mPolyhedron.mPointList.size() == 0)
  455. return false;
  456. mClippedList.clear();
  457. SphereF sphere;
  458. sphere.center = (mWorldBox.minExtents + mWorldBox.maxExtents) * 0.5;
  459. VectorF bv = mWorldBox.maxExtents - sphere.center;
  460. sphere.radius = bv.len();
  461. enter->buildPolyList(PLC_Collision, &mClippedList, mWorldBox, sphere);
  462. return mClippedList.isEmpty() == false;
  463. }
  464. bool PhysicalZone::testBox( const Box3F &box ) const
  465. {
  466. return mWorldBox.isOverlapped( box );
  467. }
  468. void PhysicalZone::activate()
  469. {
  470. AssertFatal(isServerObject(), "Client objects not allowed in ForceFieldInstance::open()");
  471. if (mActive != true)
  472. setMaskBits(ActiveMask);
  473. mActive = true;
  474. }
  475. void PhysicalZone::deactivate()
  476. {
  477. AssertFatal(isServerObject(), "Client objects not allowed in ForceFieldInstance::close()");
  478. if (mActive != false)
  479. setMaskBits(ActiveMask);
  480. mActive = false;
  481. }
  482. void PhysicalZone::onStaticModified(const char* slotName, const char*newValue)
  483. {
  484. if (dStricmp(slotName, "appliedForce") == 0 || dStricmp(slotName, "forceType") == 0)
  485. {
  486. switch (force_type)
  487. {
  488. case SPHERICAL:
  489. force_mag = mAppliedForce.magnitudeSafe();
  490. break;
  491. case CYLINDRICAL:
  492. {
  493. Point3F force_vec = mAppliedForce;
  494. force_vec.z = 0.0;
  495. force_mag = force_vec.magnitudeSafe();
  496. }
  497. break;
  498. }
  499. }
  500. }
  501. const Point3F& PhysicalZone::getForce(const Point3F* center) const
  502. {
  503. static Point3F force_vec;
  504. if (force_type == VECTOR)
  505. {
  506. if (orient_force)
  507. {
  508. getTransform().mulV(mAppliedForce, &force_vec);
  509. force_vec *= fade_amt;
  510. return force_vec;
  511. }
  512. force_vec = mAppliedForce;
  513. force_vec *= fade_amt;
  514. return force_vec;
  515. }
  516. if (!center)
  517. {
  518. force_vec.zero();
  519. return force_vec;
  520. }
  521. if (force_type == SPHERICAL)
  522. {
  523. force_vec = *center - getPosition();
  524. force_vec.normalizeSafe();
  525. force_vec *= force_mag*fade_amt;
  526. return force_vec;
  527. }
  528. if (orient_force)
  529. {
  530. force_vec = *center - getPosition();
  531. getWorldTransform().mulV(force_vec);
  532. force_vec.z = 0.0f;
  533. force_vec.normalizeSafe();
  534. force_vec *= force_mag;
  535. force_vec.z = mAppliedForce.z;
  536. getTransform().mulV(force_vec);
  537. force_vec *= fade_amt;
  538. return force_vec;
  539. }
  540. force_vec = *center - getPosition();
  541. force_vec.z = 0.0f;
  542. force_vec.normalizeSafe();
  543. force_vec *= force_mag;
  544. force_vec *= fade_amt;
  545. return force_vec;
  546. }
  547. bool PhysicalZone::isExcludedObject(SceneObject* obj) const
  548. {
  549. for (S32 i = 0; i < excluded_objects.size(); i++)
  550. if (excluded_objects[i] == obj)
  551. return true;
  552. return false;
  553. }
  554. void PhysicalZone::registerExcludedObject(SceneObject* obj)
  555. {
  556. if (isExcludedObject(obj))
  557. return;
  558. excluded_objects.push_back(obj);
  559. setMaskBits(FadeMask);
  560. }
  561. void PhysicalZone::unregisterExcludedObject(SceneObject* obj)
  562. {
  563. for (S32 i = 0; i < excluded_objects.size(); i++)
  564. if (excluded_objects[i] == obj)
  565. {
  566. excluded_objects.erase(i);
  567. setMaskBits(FadeMask);
  568. return;
  569. }
  570. }