SceneGroup.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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. //Put the SubScene group before everything that'd be SubScene-effecting, for orginazational purposes
  92. GuiInspectorGroup* sceneGroupGrp = inspector->findExistentGroup(StringTable->insert("Editing"));
  93. if (!sceneGroupGrp)
  94. return;
  95. GuiControl* stack = dynamic_cast<GuiControl*>(sceneGroupGrp->findObjectByInternalName(StringTable->insert("Stack")));
  96. //Regen bounds button
  97. GuiInspectorField* regenFieldGui = sceneGroupGrp->createInspectorField();
  98. regenFieldGui->init(inspector, sceneGroupGrp);
  99. regenFieldGui->setSpecialEditField(true);
  100. regenFieldGui->setTargetObject(this);
  101. StringTableEntry fldnm = StringTable->insert("RegenerateBounds");
  102. regenFieldGui->setSpecialEditVariableName(fldnm);
  103. regenFieldGui->setInspectorField(NULL, fldnm);
  104. regenFieldGui->setDocs("");
  105. stack->addObject(regenFieldGui);
  106. GuiButtonCtrl* regenButton = new GuiButtonCtrl();
  107. regenButton->registerObject();
  108. regenButton->setDataField(StringTable->insert("profile"), NULL, "ToolsGuiButtonProfile");
  109. regenButton->setText("Regenerate Bounds");
  110. regenButton->resize(Point2I::Zero, regenFieldGui->getExtent());
  111. regenButton->setHorizSizing(GuiControl::horizResizeWidth);
  112. regenButton->setVertSizing(GuiControl::vertResizeHeight);
  113. char rgBuffer[512];
  114. dSprintf(rgBuffer, 512, "%d.recalculateBounds();", this->getId());
  115. regenButton->setConsoleCommand(rgBuffer);
  116. regenFieldGui->addObject(regenButton);
  117. }
  118. void SceneGroup::setTransform(const MatrixF& mat)
  119. {
  120. if (isServerObject())
  121. {
  122. setMaskBits(TransformMask);
  123. MatrixF newXform = mat;
  124. MatrixF oldXform = getTransform();
  125. oldXform.affineInverse();
  126. MatrixF offset;
  127. offset.mul(newXform, oldXform);
  128. // Update all child transforms
  129. for (SimSetIterator itr(this); *itr; ++itr)
  130. {
  131. SceneObject* child = dynamic_cast<SceneObject*>(*itr);
  132. if (child)
  133. {
  134. MatrixF childMat;
  135. //add the "offset" caused by the parents change, and add it to it's own
  136. // This is needed by objects that update their own render transform thru interpolate tick
  137. // Mostly for stationary objects.
  138. childMat.mul(offset, child->getTransform());
  139. child->setTransform(childMat);
  140. PhysicsShape* childPS = dynamic_cast<PhysicsShape*>(child);
  141. if (childPS)
  142. childPS->storeRestorePos();
  143. }
  144. }
  145. }
  146. Parent::setTransform(mat);
  147. }
  148. void SceneGroup::setRenderTransform(const MatrixF& mat)
  149. {
  150. MatrixF newXform = mat;
  151. MatrixF oldXform = getRenderTransform();
  152. oldXform.affineInverse();
  153. MatrixF offset;
  154. offset.mul(newXform, oldXform);
  155. // Update all child transforms
  156. for (SimSetIterator itr(this); *itr; ++itr)
  157. {
  158. SceneObject* child = dynamic_cast<SceneObject*>(*itr);
  159. if (child)
  160. {
  161. MatrixF childMat;
  162. //add the "offset" caused by the parents change, and add it to it's own
  163. // This is needed by objects that update their own render transform thru interpolate tick
  164. // Mostly for stationary objects.
  165. childMat.mul(offset, child->getRenderTransform());
  166. child->setRenderTransform(childMat);
  167. PhysicsShape* childPS = dynamic_cast<PhysicsShape*>(child);
  168. if (childPS)
  169. childPS->storeRestorePos();
  170. }
  171. }
  172. Parent::setRenderTransform(mat);
  173. }
  174. void SceneGroup::addObject(SimObject* object)
  175. {
  176. Parent::addObject(object);
  177. // Recalculate the bounding box from scratch (simpler but potentially costly)
  178. recalculateBoundingBox();
  179. }
  180. void SceneGroup::removeObject(SimObject* object)
  181. {
  182. Parent::removeObject(object);
  183. // Recalculate the bounding box from scratch (simpler but potentially costly)
  184. recalculateBoundingBox();
  185. }
  186. void SceneGroup::recalculateBoundingBox()
  187. {
  188. if (empty())
  189. return;
  190. // Reset the bounding box
  191. Box3F bounds;
  192. bounds.minExtents.set(1e10, 1e10, 1e10);
  193. bounds.maxExtents.set(-1e10, -1e10, -1e10);
  194. // Extend the bounding box to include each child's bounding box
  195. for (SimSetIterator itr(this); *itr; ++itr)
  196. {
  197. SceneObject* child = dynamic_cast<SceneObject*>(*itr);
  198. if (child)
  199. {
  200. const Box3F& childBox = child->getWorldBox();
  201. bounds.minExtents.setMin(childBox.minExtents);
  202. bounds.maxExtents.setMax(childBox.maxExtents);
  203. }
  204. }
  205. MatrixF newTrans = mObjToWorld;
  206. newTrans.setPosition(bounds.getCenter());
  207. Parent::setTransform(newTrans);
  208. mObjScale = Point3F(bounds.len_x(), bounds.len_y(), bounds.len_z());
  209. mWorldBox = bounds;
  210. resetObjectBox();
  211. setMaskBits(TransformMask);
  212. }
  213. U32 SceneGroup::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
  214. {
  215. U32 retMask = Parent::packUpdate(conn, mask, stream);
  216. mathWrite(*stream, mObjBox);
  217. if (stream->writeFlag(mask & TransformMask))
  218. {
  219. mathWrite(*stream, getTransform());
  220. mathWrite(*stream, getScale());
  221. }
  222. return retMask;
  223. }
  224. void SceneGroup::unpackUpdate(NetConnection* conn, BitStream* stream)
  225. {
  226. Parent::unpackUpdate(conn, stream);
  227. mathRead(*stream, &mObjBox);
  228. resetWorldBox();
  229. // TransformMask
  230. if (stream->readFlag())
  231. {
  232. mathRead(*stream, &mObjToWorld);
  233. mathRead(*stream, &mObjScale);
  234. setTransform(mObjToWorld);
  235. }
  236. }
  237. bool SceneGroup::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere)
  238. {
  239. Vector<SceneObject*> foundObjects;
  240. if (empty())
  241. {
  242. Con::warnf("SceneGroup::buildPolyList() - SceneGroup %s is empty!", getName());
  243. return false;
  244. }
  245. findObjectByType(foundObjects);
  246. for (S32 i = 0; i < foundObjects.size(); i++)
  247. {
  248. foundObjects[i]->buildPolyList(context, polyList, box, sphere);
  249. }
  250. return true;
  251. }
  252. bool SceneGroup::buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F& box, const SphereF& sphere)
  253. {
  254. Vector<SceneObject*> foundObjects;
  255. findObjectByType(foundObjects);
  256. for (S32 i = 0; i < foundObjects.size(); i++)
  257. {
  258. foundObjects[i]->buildExportPolyList(exportData, box, sphere);
  259. }
  260. return true;
  261. }
  262. void SceneGroup::getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList)
  263. {
  264. //if (empty())
  265. return;
  266. Vector<SceneObject*> foundObjects;
  267. findObjectByType(foundObjects);
  268. for (S32 i = 0; i < foundObjects.size(); i++)
  269. {
  270. SceneObject* child = foundObjects[i];
  271. child->getUtilizedAssets(usedAssetsList);
  272. }
  273. }
  274. DefineEngineMethod(SceneGroup, recalculateBounds, void, (), ,
  275. "Recalculates the SceneGroups' bounds and centerpoint.\n")
  276. {
  277. object->recalculateBoundingBox();
  278. }