mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
Merge pull request #2103 from Areloch/ConvexProxies
Adds functionality to automate convex proxy objects
This commit is contained in:
commit
c8d685d8c4
|
|
@ -201,6 +201,8 @@ public:
|
|||
|
||||
/// @}
|
||||
|
||||
String getMaterialName() { return mMaterialName; }
|
||||
|
||||
protected:
|
||||
|
||||
void _updateMaterial();
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@
|
|||
#include "core/volume.h"
|
||||
#include "gui/worldEditor/worldEditor.h"
|
||||
#include "T3D/prefab.h"
|
||||
#include "T3D/trigger.h"
|
||||
#include "T3D/zone.h"
|
||||
#include "T3D/portal.h"
|
||||
#include "math/mPolyhedron.impl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiConvexEditorCtrl );
|
||||
|
||||
|
|
@ -161,6 +165,35 @@ void GuiConvexEditorCtrl::setVisible( bool val )
|
|||
mGizmoProfile->flags = mSavedGizmoFlags;
|
||||
mSavedGizmoFlags = -1;
|
||||
}
|
||||
|
||||
SimGroup* misGroup;
|
||||
if (Sim::findObject("MissionGroup", misGroup))
|
||||
{
|
||||
//Make our proxy objects "real" again
|
||||
for (U32 i = 0; i < mProxyObjects.size(); ++i)
|
||||
{
|
||||
if (!mProxyObjects[i].shapeProxy || !mProxyObjects[i].targetObject)
|
||||
continue;
|
||||
|
||||
AbstractClassRep* classRep = AbstractClassRep::findClassRep(mProxyObjects[i].targetObjectClass);
|
||||
if (!classRep)
|
||||
{
|
||||
Con::errorf("WorldEditor::createPolyhedralObject - No such class: %s", mProxyObjects[i].targetObjectClass);
|
||||
continue;
|
||||
}
|
||||
|
||||
SceneObject* polyObj = createPolyhedralObject(mProxyObjects[i].targetObjectClass.c_str(), mProxyObjects[i].shapeProxy);
|
||||
|
||||
misGroup->addObject(polyObj);
|
||||
|
||||
//Now, remove the convex proxy
|
||||
mProxyObjects[i].shapeProxy->deleteObject();
|
||||
mProxyObjects[i].targetObject->deleteObject();
|
||||
mProxyObjects.erase(i);
|
||||
--i;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -188,6 +221,60 @@ void GuiConvexEditorCtrl::setVisible( bool val )
|
|||
}
|
||||
updateGizmoPos();
|
||||
mSavedGizmoFlags = mGizmoProfile->flags;
|
||||
|
||||
SimGroup* misGroup;
|
||||
if (Sim::findObject("MissionGroup", misGroup))
|
||||
{
|
||||
for (U32 c = 0; c < misGroup->size(); ++c)
|
||||
{
|
||||
bool isTrigger = (misGroup->at(c)->getClassName() == StringTable->insert("Trigger"));
|
||||
bool isZone = (misGroup->at(c)->getClassName() == StringTable->insert("Zone"));
|
||||
bool isPortal = (misGroup->at(c)->getClassName() == StringTable->insert("Portal"));
|
||||
bool isOccluder = (misGroup->at(c)->getClassName() == StringTable->insert("OcclusionVolume"));
|
||||
|
||||
if (isZone || isPortal || isOccluder)
|
||||
{
|
||||
SceneObject* sceneObj = static_cast<SceneObject*>(misGroup->at(c));
|
||||
if (!sceneObj)
|
||||
{
|
||||
Con::errorf("WorldEditor::createConvexShapeFrom - Invalid object");
|
||||
continue;
|
||||
}
|
||||
|
||||
ConvexShape* proxyShape = createConvexShapeFrom(sceneObj);
|
||||
|
||||
//Set the texture to a representatory one so we know what's what
|
||||
if (isTrigger)
|
||||
proxyShape->mMaterialName = "TriggerProxyMaterial";
|
||||
else if (isPortal)
|
||||
proxyShape->mMaterialName = "PortalProxyMaterial";
|
||||
else if (isZone)
|
||||
proxyShape->mMaterialName = "ZoneProxyMaterial";
|
||||
else if (isOccluder)
|
||||
proxyShape->mMaterialName = "OccluderProxyMaterial";
|
||||
|
||||
proxyShape->_updateMaterial();
|
||||
|
||||
sceneObj->setHidden(true);
|
||||
|
||||
//set up the proxy object
|
||||
ConvexShapeProxy newProxy;
|
||||
newProxy.shapeProxy = proxyShape;
|
||||
newProxy.targetObject = sceneObj;
|
||||
|
||||
if (isTrigger)
|
||||
newProxy.targetObjectClass = "Trigger";
|
||||
else if (isPortal)
|
||||
newProxy.targetObjectClass = "Portal";
|
||||
else if (isZone)
|
||||
newProxy.targetObjectClass = "Zone";
|
||||
else
|
||||
newProxy.targetObjectClass = "OcclusionVolume";
|
||||
|
||||
mProxyObjects.push_back(newProxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -438,6 +525,8 @@ void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
|
|||
|
||||
setupShape( newShape );
|
||||
|
||||
newShape->setField("material", mConvexSEL->getMaterialName());
|
||||
|
||||
submitUndo( CreateShape, newShape );
|
||||
|
||||
setSelection( newShape, -1 );
|
||||
|
|
@ -2033,7 +2122,8 @@ ConvexShape* ConvexEditorCreateTool::extrudeShapeFromFace( ConvexShape *inShape,
|
|||
surf.mulL( worldToShape );
|
||||
}
|
||||
|
||||
newShape->setField( "material", Parent::mEditor->mMaterialName );
|
||||
//newShape->setField( "material", Parent::mEditor->mMaterialName );
|
||||
newShape->setField("material", inShape->getMaterialName());
|
||||
|
||||
newShape->registerObject();
|
||||
mEditor->updateShape( newShape );
|
||||
|
|
@ -2179,6 +2269,211 @@ void GuiConvexEditorCtrl::splitSelectedFace()
|
|||
updateGizmoPos();
|
||||
}
|
||||
|
||||
SceneObject* GuiConvexEditorCtrl::createPolyhedralObject(const char* className, SceneObject* geometryProvider)
|
||||
{
|
||||
if (!geometryProvider)
|
||||
{
|
||||
Con::errorf("WorldEditor::createPolyhedralObject - Invalid geometry provider!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!className || !className[0])
|
||||
{
|
||||
Con::errorf("WorldEditor::createPolyhedralObject - Invalid class name");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AbstractClassRep* classRep = AbstractClassRep::findClassRep(className);
|
||||
if (!classRep)
|
||||
{
|
||||
Con::errorf("WorldEditor::createPolyhedralObject - No such class: %s", className);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We don't want the extracted poly list to be affected by the object's
|
||||
// current transform and scale so temporarily reset them.
|
||||
|
||||
MatrixF savedTransform = geometryProvider->getTransform();
|
||||
Point3F savedScale = geometryProvider->getScale();
|
||||
|
||||
geometryProvider->setTransform(MatrixF::Identity);
|
||||
geometryProvider->setScale(Point3F(1.f, 1.f, 1.f));
|
||||
|
||||
// Extract the geometry. Use the object-space bounding volumes
|
||||
// as we have moved the object to the origin for the moment.
|
||||
|
||||
OptimizedPolyList polyList;
|
||||
if (!geometryProvider->buildPolyList(PLC_Export, &polyList, geometryProvider->getObjBox(), geometryProvider->getObjBox().getBoundingSphere()))
|
||||
{
|
||||
Con::errorf("WorldEditor::createPolyhedralObject - Failed to extract geometry!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Restore the object's original transform.
|
||||
|
||||
geometryProvider->setTransform(savedTransform);
|
||||
geometryProvider->setScale(savedScale);
|
||||
|
||||
// Create the object.
|
||||
|
||||
SceneObject* object = dynamic_cast< SceneObject* >(classRep->create());
|
||||
if (!Object)
|
||||
{
|
||||
Con::errorf("WorldEditor::createPolyhedralObject - Could not create SceneObject with class '%s'", className);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert the polylist to a polyhedron.
|
||||
|
||||
Polyhedron polyhedron = polyList.toPolyhedron();
|
||||
|
||||
// Add the vertex data.
|
||||
|
||||
const U32 numPoints = polyhedron.getNumPoints();
|
||||
const Point3F* points = polyhedron.getPoints();
|
||||
|
||||
for (U32 i = 0; i < numPoints; ++i)
|
||||
{
|
||||
static StringTableEntry sPoint = StringTable->insert("point");
|
||||
object->setDataField(sPoint, NULL, EngineMarshallData(points[i]));
|
||||
}
|
||||
|
||||
// Add the plane data.
|
||||
|
||||
const U32 numPlanes = polyhedron.getNumPlanes();
|
||||
const PlaneF* planes = polyhedron.getPlanes();
|
||||
|
||||
for (U32 i = 0; i < numPlanes; ++i)
|
||||
{
|
||||
static StringTableEntry sPlane = StringTable->insert("plane");
|
||||
const PlaneF& plane = planes[i];
|
||||
|
||||
char buffer[1024];
|
||||
dSprintf(buffer, sizeof(buffer), "%g %g %g %g", plane.x, plane.y, plane.z, plane.d);
|
||||
|
||||
object->setDataField(sPlane, NULL, buffer);
|
||||
}
|
||||
|
||||
// Add the edge data.
|
||||
|
||||
const U32 numEdges = polyhedron.getNumEdges();
|
||||
const Polyhedron::Edge* edges = polyhedron.getEdges();
|
||||
|
||||
for (U32 i = 0; i < numEdges; ++i)
|
||||
{
|
||||
static StringTableEntry sEdge = StringTable->insert("edge");
|
||||
const Polyhedron::Edge& edge = edges[i];
|
||||
|
||||
char buffer[1024];
|
||||
dSprintf(buffer, sizeof(buffer), "%i %i %i %i ",
|
||||
edge.face[0], edge.face[1],
|
||||
edge.vertex[0], edge.vertex[1]
|
||||
);
|
||||
|
||||
object->setDataField(sEdge, NULL, buffer);
|
||||
}
|
||||
|
||||
// Set the transform.
|
||||
|
||||
object->setTransform(savedTransform);
|
||||
object->setScale(savedScale);
|
||||
|
||||
// Register and return the object.
|
||||
|
||||
if (!object->registerObject())
|
||||
{
|
||||
Con::errorf("WorldEditor::createPolyhedralObject - Failed to register object!");
|
||||
delete object;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
ConvexShape* GuiConvexEditorCtrl::createConvexShapeFrom(SceneObject* polyObject)
|
||||
{
|
||||
if (!polyObject)
|
||||
{
|
||||
Con::errorf("WorldEditor::createConvexShapeFrom - Invalid object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IScenePolyhedralObject* iPoly = dynamic_cast< IScenePolyhedralObject* >(polyObject);
|
||||
if (!iPoly)
|
||||
{
|
||||
Con::errorf("WorldEditor::createConvexShapeFrom - Not a polyhedral object!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get polyhedron.
|
||||
|
||||
AnyPolyhedron polyhedron = iPoly->ToAnyPolyhedron();
|
||||
const U32 numPlanes = polyhedron.getNumPlanes();
|
||||
if (!numPlanes)
|
||||
{
|
||||
Con::errorf("WorldEditor::createConvexShapeFrom - Object returned no valid polyhedron");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create a ConvexShape.
|
||||
|
||||
ConvexShape* shape = new ConvexShape();
|
||||
|
||||
// Add all planes.
|
||||
|
||||
for (U32 i = 0; i < numPlanes; ++i)
|
||||
{
|
||||
const PlaneF& plane = polyhedron.getPlanes()[i];
|
||||
|
||||
// Polyhedron planes are facing inwards so we need to
|
||||
// invert the normal here.
|
||||
|
||||
Point3F normal = plane.getNormal();
|
||||
normal.neg();
|
||||
|
||||
// Turn the orientation of the plane into a quaternion.
|
||||
// The normal is our up vector (that's what's expected
|
||||
// by ConvexShape for the surface orientation).
|
||||
|
||||
MatrixF orientation(true);
|
||||
MathUtils::getMatrixFromUpVector(normal, &orientation);
|
||||
const QuatF quat(orientation);
|
||||
|
||||
// Get the plane position.
|
||||
|
||||
const Point3F position = plane.getPosition();
|
||||
|
||||
// Turn everything into a "surface" property for the ConvexShape.
|
||||
|
||||
char buffer[1024];
|
||||
dSprintf(buffer, sizeof(buffer), "%g %g %g %g %g %g %g",
|
||||
quat.x, quat.y, quat.z, quat.w,
|
||||
position.x, position.y, position.z
|
||||
);
|
||||
|
||||
// Add the surface.
|
||||
|
||||
static StringTableEntry sSurface = StringTable->insert("surface");
|
||||
shape->setDataField(sSurface, NULL, buffer);
|
||||
}
|
||||
|
||||
// Copy the transform.
|
||||
|
||||
shape->setTransform(polyObject->getTransform());
|
||||
shape->setScale(polyObject->getScale());
|
||||
|
||||
// Register the shape.
|
||||
|
||||
if (!shape->registerObject())
|
||||
{
|
||||
Con::errorf("WorldEditor::createConvexShapeFrom - Could not register ConvexShape!");
|
||||
delete shape;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiConvexEditorCtrl, hollowSelection, void, (), , "" )
|
||||
{
|
||||
object->hollowSelection();
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@ public:
|
|||
void dropSelectionAtScreenCenter();
|
||||
void splitSelectedFace();
|
||||
|
||||
SceneObject* createPolyhedralObject(const char* className, SceneObject* geometryProvider);
|
||||
ConvexShape* createConvexShapeFrom(SceneObject* polyObject);
|
||||
/// Interface with Tools.
|
||||
/// @{
|
||||
|
||||
|
|
@ -192,6 +194,16 @@ protected:
|
|||
UndoAction *mLastUndo;
|
||||
UndoManager *mUndoManager;
|
||||
|
||||
struct ConvexShapeProxy
|
||||
{
|
||||
ConvexShape* shapeProxy;
|
||||
SceneObject* targetObject;
|
||||
String targetObjectClass;
|
||||
bool dirty;
|
||||
};
|
||||
|
||||
Vector<ConvexShapeProxy> mProxyObjects;
|
||||
|
||||
ConvexEditorTool *mActiveTool;
|
||||
ConvexEditorCreateTool *mCreateTool;
|
||||
};
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
Templates/Full/game/tools/convexEditor/images/zoneProxyImage.png
Normal file
BIN
Templates/Full/game/tools/convexEditor/images/zoneProxyImage.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
39
Templates/Full/game/tools/convexEditor/materials.cs
Normal file
39
Templates/Full/game/tools/convexEditor/materials.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
singleton Material( ZoneProxyMaterial )
|
||||
{
|
||||
mapTo = "ZoneProxyMaterial";
|
||||
diffuseMap[0] = "./images/zoneProxyImage";
|
||||
materialTag0 = "TestMaterial";
|
||||
translucent = true;
|
||||
translucentBlendOp = "LerpAlpha";
|
||||
castShadows = false;
|
||||
};
|
||||
|
||||
singleton Material( TriggerProxyMaterial )
|
||||
{
|
||||
mapTo = "TriggerProxyMaterial";
|
||||
diffuseMap[0] = "./images/triggerProxyImage";
|
||||
materialTag0 = "TestMaterial";
|
||||
translucent = true;
|
||||
translucentBlendOp = "LerpAlpha";
|
||||
castShadows = false;
|
||||
};
|
||||
|
||||
singleton Material( PortalProxyMaterial )
|
||||
{
|
||||
mapTo = "PortalProxyMaterial";
|
||||
diffuseMap[0] = "./images/portalProxyImage";
|
||||
materialTag0 = "TestMaterial";
|
||||
translucent = true;
|
||||
translucentBlendOp = "LerpAlpha";
|
||||
castShadows = false;
|
||||
};
|
||||
|
||||
singleton Material( OccluderProxyMaterial )
|
||||
{
|
||||
mapTo = "OccluderProxyMaterial";
|
||||
diffuseMap[0] = "./images/occluderProxyImage";
|
||||
materialTag0 = "TestMaterial";
|
||||
translucent = true;
|
||||
translucentBlendOp = "LerpAlpha";
|
||||
castShadows = false;
|
||||
};
|
||||
Loading…
Reference in a new issue