SceneGroup.cpp 9.2 KB

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