|
@@ -47,7 +47,7 @@
|
|
|
#include "platform/typetraits.h"
|
|
|
#include "T3D/prefab.h"
|
|
|
#include "math/mEase.h"
|
|
|
-
|
|
|
+#include "T3D/tsStatic.h"
|
|
|
|
|
|
|
|
|
IMPLEMENT_CONOBJECT( WorldEditor );
|
|
@@ -3753,6 +3753,158 @@ void WorldEditor::explodeSelectedPrefab()
|
|
|
setDirty();
|
|
|
}
|
|
|
|
|
|
+void WorldEditor::bakeSelectionToMesh(const char *filename)
|
|
|
+{
|
|
|
+ if (mSelected->size() == 0)
|
|
|
+ {
|
|
|
+ Con::errorf("WorldEditor::makeSelectionPrefab - Nothing selected.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ SimGroup *missionGroup;
|
|
|
+ if (!Sim::findObject("MissionGroup", missionGroup))
|
|
|
+ {
|
|
|
+ Con::errorf("WorldEditor::makeSelectionPrefab - Could not find MissionGroup.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector< SimObject* > stack;
|
|
|
+ Vector< SimObject* > found;
|
|
|
+
|
|
|
+ for (S32 i = 0; i < mSelected->size(); i++)
|
|
|
+ {
|
|
|
+ SimObject *obj = (*mSelected)[i];
|
|
|
+ stack.push_back(obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector< SimGroup* > cleanup;
|
|
|
+
|
|
|
+ while (!stack.empty())
|
|
|
+ {
|
|
|
+ SimObject *obj = stack.last();
|
|
|
+ SimGroup *grp = dynamic_cast< SimGroup* >(obj);
|
|
|
+
|
|
|
+ stack.pop_back();
|
|
|
+
|
|
|
+ if (grp)
|
|
|
+ {
|
|
|
+ for (S32 i = 0; i < grp->size(); i++)
|
|
|
+ stack.push_back(grp->at(i));
|
|
|
+
|
|
|
+ SceneObject* scn = dynamic_cast< SceneObject* >(grp);
|
|
|
+ if (scn)
|
|
|
+ {
|
|
|
+ if (Prefab::isValidChild(obj, true))
|
|
|
+ found.push_back(obj);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //Only push the cleanup of the group if it's ONLY a SimGroup.
|
|
|
+ cleanup.push_back(grp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (Prefab::isValidChild(obj, true))
|
|
|
+ found.push_back(obj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (found.empty())
|
|
|
+ {
|
|
|
+ Con::warnf("WorldEditor::makeSelectionPrefab - No valid objects selected.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // SimGroup we collect prefab objects into.
|
|
|
+ SimGroup *group = new SimGroup();
|
|
|
+ group->registerObject();
|
|
|
+
|
|
|
+ // Transform from World to Prefab space.
|
|
|
+ MatrixF fabMat(true);
|
|
|
+ fabMat.setPosition(mSelected->getCentroid());
|
|
|
+ fabMat.inverse();
|
|
|
+
|
|
|
+ MatrixF objMat;
|
|
|
+ SimObject *obj = NULL;
|
|
|
+ SceneObject *sObj = NULL;
|
|
|
+
|
|
|
+ Vector< SceneObject* > objectList;
|
|
|
+
|
|
|
+ for ( S32 i = 0; i < mSelected->size(); i++ )
|
|
|
+ {
|
|
|
+ SceneObject *pObj = dynamic_cast< SceneObject* >( ( *mSelected )[i] );
|
|
|
+ if ( pObj )
|
|
|
+ objectList.push_back( pObj );
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( objectList.empty() )
|
|
|
+ return;
|
|
|
+
|
|
|
+ //
|
|
|
+ Point3F centroid;
|
|
|
+ MatrixF orientation;
|
|
|
+
|
|
|
+ if (objectList.size() == 1)
|
|
|
+ {
|
|
|
+ orientation = objectList[0]->getTransform();
|
|
|
+ centroid = objectList[0]->getPosition();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ orientation.identity();
|
|
|
+ centroid.zero();
|
|
|
+
|
|
|
+ S32 count = 0;
|
|
|
+
|
|
|
+ for (S32 i = 0; i < objectList.size(); i++)
|
|
|
+ {
|
|
|
+ SceneObject *pObj = objectList[i];
|
|
|
+ if (pObj->isGlobalBounds())
|
|
|
+ continue;
|
|
|
+
|
|
|
+ centroid += pObj->getPosition();
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+
|
|
|
+ centroid /= count;
|
|
|
+ }
|
|
|
+
|
|
|
+ orientation.setPosition(centroid);
|
|
|
+ orientation.inverse();
|
|
|
+
|
|
|
+ OptimizedPolyList polyList;
|
|
|
+ polyList.setBaseTransform(orientation);
|
|
|
+
|
|
|
+ for (S32 i = 0; i < objectList.size(); i++)
|
|
|
+ {
|
|
|
+ SceneObject *pObj = objectList[i];
|
|
|
+ if (!pObj->buildPolyList(PLC_Export, &polyList, pObj->getWorldBox(), pObj->getWorldSphere()))
|
|
|
+ Con::warnf("colladaExportObjectList() - object %i returned no geometry.", pObj->getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Use a ColladaUtils function to do the actual export to a Collada file
|
|
|
+ ColladaUtils::exportToCollada(filename, polyList);
|
|
|
+ //
|
|
|
+
|
|
|
+ // Allocate TSStatic object and add to level.
|
|
|
+ TSStatic *ts = new TSStatic();
|
|
|
+ ts->setShapeFileName(StringTable->insert(filename));
|
|
|
+ fabMat.inverse();
|
|
|
+ ts->setTransform(fabMat);
|
|
|
+ ts->registerObject();
|
|
|
+ missionGroup->addObject(ts);
|
|
|
+
|
|
|
+ // Select it, mark level as dirty.
|
|
|
+ clearSelection();
|
|
|
+ selectObject(ts);
|
|
|
+ setDirty();
|
|
|
+
|
|
|
+ // Delete original objects and temporary SimGroup.
|
|
|
+ for (S32 i = 0; i < objectList.size(); i++)
|
|
|
+ objectList[i]->deleteObject();
|
|
|
+}
|
|
|
+
|
|
|
DefineEngineMethod( WorldEditor, makeSelectionPrefab, void, ( const char* filename ),,
|
|
|
"Save selected objects to a .prefab file and replace them in the level with a Prefab object."
|
|
|
"@param filename Prefab file to save the selected objects to.")
|
|
@@ -3766,6 +3918,13 @@ DefineEngineMethod( WorldEditor, explodeSelectedPrefab, void, (),,
|
|
|
object->explodeSelectedPrefab();
|
|
|
}
|
|
|
|
|
|
+DefineEngineMethod(WorldEditor, bakeSelectionToMesh, void, (const char* filename), ,
|
|
|
+ "Save selected objects to a .dae collada file and replace them in the level with a TSStatic object."
|
|
|
+ "@param filename collada file to save the selected objects to.")
|
|
|
+{
|
|
|
+ object->bakeSelectionToMesh(filename);
|
|
|
+}
|
|
|
+
|
|
|
DefineEngineMethod( WorldEditor, mountRelative, void, ( SceneObject *objA, SceneObject *objB ),,
|
|
|
"Mount object B relatively to object A."
|
|
|
"@param objA Object to mount to."
|