SceneGroup.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. #include "SceneGroup.h"
  2. #include "gameBase/gameConnection.h"
  3. #include "gfx/gfxDrawUtil.h"
  4. #include "gfx/gfxTransformSaver.h"
  5. #include "gui/editor/inspector/group.h"
  6. #include "gui/worldEditor/editor.h"
  7. #include "math/mathIO.h"
  8. #include "physics/physicsShape.h"
  9. #include "renderInstance/renderPassManager.h"
  10. #include "scene/sceneRenderState.h"
  11. #include "Scene.h"
  12. IMPLEMENT_CO_NETOBJECT_V1(SceneGroup);
  13. ConsoleDocClass(SceneGroup,
  14. "@brief A collection of arbitrary objects which can be allocated and manipulated as a group.\n\n"
  15. "%SceneGroup always points to a (.SceneGroup) file which defines its objects. In "
  16. "fact more than one %SceneGroup can reference this file and both will update "
  17. "if the file is modified.\n\n"
  18. "%SceneGroup is a very simple object and only exists on the server. When it is "
  19. "created it allocates children objects by reading the (.SceneGroup) file like "
  20. "a list of instructions. It then sets their transform relative to the %SceneGroup "
  21. "and Torque networking handles the rest by ghosting the new objects to clients. "
  22. "%SceneGroup itself is not ghosted.\n\n"
  23. "@ingroup enviroMisc"
  24. );
  25. SceneGroup::SceneGroup()
  26. {
  27. // Not ghosted unless we're editing
  28. mNetFlags.clear(Ghostable | ScopeAlways);
  29. mTypeMask |= StaticObjectType;
  30. }
  31. SceneGroup::~SceneGroup()
  32. {
  33. }
  34. void SceneGroup::initPersistFields()
  35. {
  36. docsURL;
  37. addGroup("SceneGroup");
  38. endGroup("SceneGroup");
  39. Parent::initPersistFields();
  40. }
  41. bool SceneGroup::onAdd()
  42. {
  43. if (!Parent::onAdd())
  44. return false;
  45. mObjBox.set(Point3F(-0.5f, -0.5f, -0.5f),
  46. Point3F(0.5f, 0.5f, 0.5f));
  47. resetWorldBox();
  48. // Not added to the scene unless we are editing.
  49. if (gEditingMission)
  50. onEditorEnable();
  51. addToScene();
  52. return true;
  53. }
  54. void SceneGroup::onRemove()
  55. {
  56. removeFromScene();
  57. Parent::onRemove();
  58. }
  59. void SceneGroup::onEditorEnable()
  60. {
  61. if (isClientObject())
  62. return;
  63. // Just in case we are already in the scene, lets not cause an assert.
  64. if (mContainer != NULL)
  65. return;
  66. // Enable ghosting so we can see this on the client.
  67. mNetFlags.set(Ghostable);
  68. setScopeAlways();
  69. addToScene();
  70. Parent::onEditorEnable();
  71. }
  72. void SceneGroup::onEditorDisable()
  73. {
  74. if (isClientObject())
  75. return;
  76. // Just in case we are not in the scene, lets not cause an assert.
  77. if (mContainer == NULL)
  78. return;
  79. // Do not need this on the client if we are not editing.
  80. removeFromScene();
  81. mNetFlags.clear(Ghostable);
  82. clearScopeAlways();
  83. Parent::onEditorDisable();
  84. }
  85. void SceneGroup::inspectPostApply()
  86. {
  87. Parent::inspectPostApply();
  88. }
  89. void SceneGroup::onInspect(GuiInspector* inspector)
  90. {
  91. Parent::onInspect(inspector);
  92. #ifdef TORQUE_TOOLS
  93. //Put the SubScene group before everything that'd be SubScene-effecting, for orginazational purposes
  94. GuiInspectorGroup* sceneGroupGrp = inspector->findExistentGroup(StringTable->insert("Editing"));
  95. if (!sceneGroupGrp)
  96. return;
  97. GuiControl* stack = dynamic_cast<GuiControl*>(sceneGroupGrp->findObjectByInternalName(StringTable->insert("Stack")));
  98. //Regen bounds button
  99. GuiInspectorField* regenFieldGui = sceneGroupGrp->createInspectorField();
  100. regenFieldGui->init(inspector, sceneGroupGrp);
  101. regenFieldGui->setSpecialEditField(true);
  102. regenFieldGui->setTargetObject(this);
  103. StringTableEntry fldnm = StringTable->insert("RegenerateBounds");
  104. regenFieldGui->setSpecialEditVariableName(fldnm);
  105. regenFieldGui->setInspectorField(NULL, fldnm);
  106. regenFieldGui->setDocs("");
  107. stack->addObject(regenFieldGui);
  108. GuiButtonCtrl* regenButton = new GuiButtonCtrl();
  109. regenButton->registerObject();
  110. regenButton->setDataField(StringTable->insert("profile"), NULL, "ToolsGuiButtonProfile");
  111. regenButton->setText("Regenerate Bounds");
  112. regenButton->resize(Point2I::Zero, regenFieldGui->getExtent());
  113. regenButton->setHorizSizing(GuiControl::horizResizeWidth);
  114. regenButton->setVertSizing(GuiControl::vertResizeHeight);
  115. char rgBuffer[512];
  116. dSprintf(rgBuffer, 512, "%d.recalculateBounds();", this->getId());
  117. regenButton->setConsoleCommand(rgBuffer);
  118. regenFieldGui->addObject(regenButton);
  119. //
  120. //Regen bounds button
  121. GuiInspectorField* reparentFieldGui = sceneGroupGrp->createInspectorField();
  122. reparentFieldGui->init(inspector, sceneGroupGrp);
  123. reparentFieldGui->setSpecialEditField(true);
  124. reparentFieldGui->setTargetObject(this);
  125. fldnm = StringTable->insert("ReparentOOBObjs");
  126. reparentFieldGui->setSpecialEditVariableName(fldnm);
  127. reparentFieldGui->setInspectorField(NULL, fldnm);
  128. reparentFieldGui->setDocs("");
  129. stack->addObject(reparentFieldGui);
  130. GuiButtonCtrl* reparentButton = new GuiButtonCtrl();
  131. reparentButton->registerObject();
  132. reparentButton->setDataField(StringTable->insert("profile"), NULL, "ToolsGuiButtonProfile");
  133. reparentButton->setText("Reparent Out-of-bounds Objs");
  134. reparentButton->resize(Point2I::Zero, regenFieldGui->getExtent());
  135. reparentButton->setHorizSizing(GuiControl::horizResizeWidth);
  136. reparentButton->setVertSizing(GuiControl::vertResizeHeight);
  137. char rprntBuffer[512];
  138. dSprintf(rprntBuffer, 512, "%d.reparentOOBObjects();", this->getId());
  139. reparentButton->setConsoleCommand(rprntBuffer);
  140. reparentFieldGui->addObject(reparentButton);
  141. #endif
  142. }
  143. void SceneGroup::setTransform(const MatrixF& mat)
  144. {
  145. if (isServerObject())
  146. {
  147. setMaskBits(TransformMask);
  148. MatrixF newXform = mat;
  149. MatrixF oldXform = getTransform();
  150. oldXform.affineInverse();
  151. MatrixF offset;
  152. offset.mul(newXform, oldXform);
  153. // Update all child transforms
  154. for (SimSetIterator itr(this); *itr; ++itr)
  155. {
  156. SceneObject* child = dynamic_cast<SceneObject*>(*itr);
  157. if (child)
  158. {
  159. MatrixF childMat;
  160. //add the "offset" caused by the parents change, and add it to it's own
  161. // This is needed by objects that update their own render transform thru interpolate tick
  162. // Mostly for stationary objects.
  163. childMat.mul(offset, child->getTransform());
  164. child->setTransform(childMat);
  165. PhysicsShape* childPS = dynamic_cast<PhysicsShape*>(child);
  166. if (childPS)
  167. childPS->storeRestorePos();
  168. }
  169. }
  170. }
  171. Parent::setTransform(mat);
  172. }
  173. void SceneGroup::setRenderTransform(const MatrixF& mat)
  174. {
  175. MatrixF newXform = mat;
  176. MatrixF oldXform = getRenderTransform();
  177. oldXform.affineInverse();
  178. MatrixF offset;
  179. offset.mul(newXform, oldXform);
  180. // Update all child transforms
  181. for (SimSetIterator itr(this); *itr; ++itr)
  182. {
  183. SceneObject* child = dynamic_cast<SceneObject*>(*itr);
  184. if (child)
  185. {
  186. MatrixF childMat;
  187. //add the "offset" caused by the parents change, and add it to it's own
  188. // This is needed by objects that update their own render transform thru interpolate tick
  189. // Mostly for stationary objects.
  190. childMat.mul(offset, child->getRenderTransform());
  191. child->setRenderTransform(childMat);
  192. PhysicsShape* childPS = dynamic_cast<PhysicsShape*>(child);
  193. if (childPS)
  194. childPS->storeRestorePos();
  195. }
  196. }
  197. Parent::setRenderTransform(mat);
  198. }
  199. void SceneGroup::addObject(SimObject* object)
  200. {
  201. Parent::addObject(object);
  202. // Recalculate the bounding box from scratch (simpler but potentially costly)
  203. recalculateBoundingBox();
  204. }
  205. void SceneGroup::removeObject(SimObject* object)
  206. {
  207. Parent::removeObject(object);
  208. // Recalculate the bounding box from scratch (simpler but potentially costly)
  209. recalculateBoundingBox();
  210. }
  211. void SceneGroup::recalculateBoundingBox()
  212. {
  213. if (empty())
  214. return;
  215. // Reset the bounding box
  216. Box3F bounds;
  217. bounds.minExtents.set(1e10, 1e10, 1e10);
  218. bounds.maxExtents.set(-1e10, -1e10, -1e10);
  219. // Extend the bounding box to include each child's bounding box
  220. for (SimSetIterator itr(this); *itr; ++itr)
  221. {
  222. SceneObject* child = dynamic_cast<SceneObject*>(*itr);
  223. if (child)
  224. {
  225. const Box3F& childBox = child->getWorldBox();
  226. bounds.minExtents.setMin(childBox.minExtents);
  227. bounds.maxExtents.setMax(childBox.maxExtents);
  228. }
  229. }
  230. MatrixF newTrans = mObjToWorld;
  231. newTrans.setPosition(bounds.getCenter());
  232. Parent::setTransform(newTrans);
  233. mObjScale = Point3F(bounds.len_x(), bounds.len_y(), bounds.len_z());
  234. mWorldBox = bounds;
  235. resetObjectBox();
  236. setMaskBits(TransformMask);
  237. }
  238. void SceneGroup::reparentOOBObjects()
  239. {
  240. if (empty())
  241. return;
  242. // Extend the bounding box to include each child's bounding box
  243. for (SimSetIterator itr(this); *itr; ++itr)
  244. {
  245. SceneObject* child = dynamic_cast<SceneObject*>(*itr);
  246. if (child)
  247. {
  248. const Box3F& childBox = child->getWorldBox();
  249. if(!mWorldBox.isOverlapped(childBox))
  250. {
  251. Scene::getRootScene()->addObject(child);
  252. }
  253. }
  254. }
  255. }
  256. U32 SceneGroup::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
  257. {
  258. U32 retMask = Parent::packUpdate(conn, mask, stream);
  259. mathWrite(*stream, mObjBox);
  260. if (stream->writeFlag(mask & TransformMask))
  261. {
  262. mathWrite(*stream, getTransform());
  263. mathWrite(*stream, getScale());
  264. }
  265. return retMask;
  266. }
  267. void SceneGroup::unpackUpdate(NetConnection* conn, BitStream* stream)
  268. {
  269. Parent::unpackUpdate(conn, stream);
  270. mathRead(*stream, &mObjBox);
  271. resetWorldBox();
  272. // TransformMask
  273. if (stream->readFlag())
  274. {
  275. mathRead(*stream, &mObjToWorld);
  276. mathRead(*stream, &mObjScale);
  277. setTransform(mObjToWorld);
  278. }
  279. }
  280. void SceneGroup::getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList)
  281. {
  282. }
  283. DefineEngineMethod(SceneGroup, recalculateBounds, void, (), ,
  284. "Recalculates the SceneGroups' bounds and centerpoint.\n")
  285. {
  286. object->recalculateBoundingBox();
  287. }
  288. DefineEngineMethod(SceneGroup, reparentOOBObjects, void, (), ,
  289. "Finds objects that are children of the SceneGroup and, if not overlapping or in the bounds, reparents them to the root scene.\n")
  290. {
  291. object->reparentOOBObjects();
  292. }