📄 worldeditor.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "editor/worldEditor.h"
#include "sceneGraph/sceneGraph.h"
#include "sceneGraph/sceneState.h"
#include "sim/sceneObject.h"
#include "platform/event.h"
#include "gui/core/guiCanvas.h"
#include "game/gameConnection.h"
#include "core/memstream.h"
#include "collision/clippedPolyList.h"
#include "game/shapeBase.h"
#include "console/consoleInternal.h"
#include "game/sphere.h"
#include "sim/simPath.h"
#include "game/cameraSpline.h"
#include "interior/interiorInstance.h"
//#include "terrain/terrdata.h" /// TGE_Map
IMPLEMENT_CONOBJECT(WorldEditor);
// unnamed namespace for static data
namespace {
static Point3F BoxPnts[] = {
Point3F(0,0,0),
Point3F(0,0,1),
Point3F(0,1,0),
Point3F(0,1,1),
Point3F(1,0,0),
Point3F(1,0,1),
Point3F(1,1,0),
Point3F(1,1,1)
};
static U32 BoxVerts[][4] = {
{0,2,3,1}, // -x
{7,6,4,5}, // +x
{0,1,5,4}, // -y
{3,2,6,7}, // +y
{0,4,6,2}, // -z
{3,7,5,1} // +z
};
static Point3F BoxNormals[] = {
Point3F(-1, 0, 0),
Point3F( 1, 0, 0),
Point3F( 0,-1, 0),
Point3F( 0, 1, 0),
Point3F( 0, 0,-1),
Point3F( 0, 0, 1)
};
//
U32 getBoxNormalIndex(const VectorF & normal)
{
const F32 * pNormal = ((const F32 *)normal);
F32 max = 0;
S32 index = -1;
for(U32 i = 0; i < 3; i++)
if(mFabs(pNormal[i]) >= mFabs(max))
{
max = pNormal[i];
index = i*2;
}
AssertFatal(index >= 0, "Failed to get best normal");
if(max > 0.f)
index++;
return(index);
}
//
Point3F getBoundingBoxCenter(SceneObject * obj)
{
Box3F box = obj->getObjBox();
MatrixF mat = obj->getTransform();
VectorF scale = obj->getScale();
Point3F center(0,0,0);
Point3F projPnts[8];
for(U32 i = 0; i < 8; i++)
{
Point3F pnt;
pnt.set(BoxPnts[i].x ? box.max.x : box.min.x,
BoxPnts[i].y ? box.max.y : box.min.y,
BoxPnts[i].z ? box.max.z : box.min.z);
// scale it
pnt.convolve(scale);
mat.mulP(pnt, &projPnts[i]);
center += projPnts[i];
}
center /= 8;
return(center);
}
//
const char * parseObjectFormat(SimObject * obj, const char * format)
{
static char buf[1024];
U32 curPos = 0;
U32 len = dStrlen(format);
for(U32 i = 0; i < len; i++)
{
if(format[i] == '$')
{
U32 j;
for(j = i+1; j < len; j++)
if(format[j] == '$')
break;
if(j == len)
break;
char token[80];
AssertFatal((j - i) < (sizeof(token) - 1), "token too long");
dStrncpy(token, &format[i+1], (j - i - 1));
token[j-i-1] = 0;
U32 remaining = sizeof(buf) - curPos - 1;
// look at the token
if(!dStricmp(token, "id"))
curPos += dSprintf(buf + curPos, remaining, "%d", obj->getId());
else if(!dStricmp(token, "name"))
curPos += dSprintf(buf + curPos, remaining, "%s", obj->getName());
else if(!dStricmp(token, "class"))
curPos += dSprintf(buf + curPos, remaining, "%s", obj->getClassName());
else if(!dStricmp(token, "namespace") && obj->getNamespace())
curPos += dSprintf(buf + curPos, remaining, "%s", obj->getNamespace()->mName);
//
i = j;
}
else
buf[curPos++] = format[i];
}
buf[curPos] = 0;
return(buf);
}
//
F32 snapFloat(F32 val, F32 snap)
{
if(snap == 0.f)
return(val);
F32 a = mFmod(val, snap);
if(mFabs(a) > (snap / 2))
val < 0.f ? val -= snap : val += snap;
return(val - a);
}
//
EulerF extractEuler(const MatrixF & matrix)
{
const F32 * mat = (const F32*)matrix;
EulerF r;
r.x = mAsin(mat[MatrixF::idx(2,1)]);
if(mCos(r.x) != 0.f)
{
r.y = mAtan(-mat[MatrixF::idx(2,0)], mat[MatrixF::idx(2,2)]);
r.z = mAtan(-mat[MatrixF::idx(0,1)], mat[MatrixF::idx(1,1)]);
}
else
{
r.y = 0.f;
r.z = mAtan(mat[MatrixF::idx(1,0)], mat[MatrixF::idx(0,0)]);
}
return(r);
}
}
//------------------------------------------------------------------------------
// Class WorldEditor::Selection
//------------------------------------------------------------------------------
WorldEditor::Selection::Selection() :
mCentroidValid(false),
mAutoSelect(false)
{
registerObject();
}
WorldEditor::Selection::~Selection()
{
unregisterObject();
}
bool WorldEditor::Selection::objInSet(SceneObject * obj)
{
for(U32 i = 0; i < mObjectList.size(); i++)
if(mObjectList[i] == (SimObject*)obj)
return(true);
return(false);
}
bool WorldEditor::Selection::addObject(SceneObject * obj)
{
if(objInSet(obj))
return(false);
mCentroidValid = false;
mObjectList.pushBack(obj);
deleteNotify(obj);
if(mAutoSelect)
{
obj->setSelected(true);
SceneObject * clientObj = WorldEditor::getClientObj(obj);
if(clientObj)
clientObj->setSelected(true);
}
return(true);
}
bool WorldEditor::Selection::removeObject(SceneObject * obj)
{
if(!objInSet(obj))
return(false);
mCentroidValid = false;
mObjectList.remove(obj);
clearNotify(obj);
if(mAutoSelect)
{
obj->setSelected(false);
SceneObject * clientObj = WorldEditor::getClientObj(obj);
if(clientObj)
clientObj->setSelected(false);
}
return(true);
}
void WorldEditor::Selection::clear()
{
while(mObjectList.size())
removeObject((SceneObject*)mObjectList[0]);
}
void WorldEditor::Selection::onDeleteNotify(SimObject * obj)
{
removeObject((SceneObject*)obj);
}
void WorldEditor::Selection::updateCentroid()
{
if(mCentroidValid)
return;
mCentroidValid = true;
//
mCentroid.set(0,0,0);
mBoxCentroid = mCentroid;
if(!mObjectList.size())
return;
//
for(U32 i = 0; i < mObjectList.size(); i++)
{
const MatrixF & mat = ((SceneObject*)mObjectList[i])->getTransform();
Point3F wPos;
mat.getColumn(3, &wPos);
//
mBoxCentroid += getBoundingBoxCenter((SceneObject*)mObjectList[i]);
mCentroid += wPos;
}
mCentroid /= mObjectList.size();
mBoxCentroid /= mObjectList.size();
}
const Point3F & WorldEditor::Selection::getCentroid()
{
updateCentroid();
return(mCentroid);
}
const Point3F & WorldEditor::Selection::getBoxCentroid()
{
updateCentroid();
return(mBoxCentroid);
}
void WorldEditor::Selection::enableCollision()
{
for(U32 i = 0; i < mObjectList.size(); i++)
((SceneObject*)mObjectList[i])->enableCollision();
}
void WorldEditor::Selection::disableCollision()
{
for(U32 i = 0; i < mObjectList.size(); i++)
((SceneObject*)mObjectList[i])->disableCollision();
}
//------------------------------------------------------------------------------
void WorldEditor::Selection::offset(const Point3F & offset)
{
for(U32 i = 0; i < mObjectList.size(); i++)
{
MatrixF mat = ((SceneObject*)mObjectList[i])->getTransform();
Point3F wPos;
mat.getColumn(3, &wPos);
// adjust
wPos += offset;
mat.setColumn(3, wPos);
((SceneObject*)mObjectList[i])->setTransform(mat);
}
mCentroidValid = false;
}
void WorldEditor::Selection::orient(const MatrixF & rot, const Point3F & center)
{
// Orient all the selected objects to the given rotation
for(U32 i = 0; i < size(); i++)
{
MatrixF mat = rot;
mat.setPosition(((SceneObject*)mObjectList[i])->getPosition());
((SceneObject*)mObjectList[i])->setTransform(mat);
}
mCentroidValid = false;
}
void WorldEditor::Selection::rotate(const EulerF & rot, const Point3F & center)
{
// single selections will rotate around own axis, multiple about world
if(mObjectList.size() == 1)
{
MatrixF mat = ((SceneObject*)mObjectList[0])->getTransform();
Point3F pos;
mat.getColumn(3, &pos);
// get offset in obj space
Point3F offset = pos - center;
MatrixF wMat = ((SceneObject*)mObjectList[0])->getWorldTransform();
wMat.mulV(offset);
//
MatrixF transform(EulerF(0,0,0), -offset);
transform.mul(MatrixF(rot));
transform.mul(MatrixF(EulerF(0,0,0), offset));
mat.mul(transform);
((SceneObject*)mObjectList[0])->setTransform(mat);
}
else
{
for(U32 i = 0; i < size(); i++)
{
MatrixF mat = ((SceneObject*)mObjectList[i])->getTransform();
Point3F pos;
mat.getColumn(3, &pos);
// get offset in obj space
Point3F offset = pos - center;
MatrixF transform(rot);
Point3F wOffset;
transform.mulV(offset, &wOffset);
MatrixF wMat = ((SceneObject*)mObjectList[i])->getWorldTransform();
wMat.mulV(offset);
//
transform.set(EulerF(0,0,0), -offset);
mat.setColumn(3, Point3F(0,0,0));
wMat.setColumn(3, Point3F(0,0,0));
transform.mul(wMat);
transform.mul(MatrixF(rot));
transform.mul(mat);
mat.mul(transform);
mat.normalize();
mat.setColumn(3, wOffset + center);
((SceneObject*)mObjectList[i])->setTransform(mat);
}
}
mCentroidValid = false;
}
void WorldEditor::Selection::scale(const VectorF & scale)
{
for(U32 i = 0; i < mObjectList.size(); i++)
{
VectorF current = ((SceneObject*)mObjectList[i])->getScale();
current.convolve(scale);
((SceneObject*)mObjectList[i])->setScale(current);
}
mCentroidValid = false;
}
//------------------------------------------------------------------------------
SceneObject * WorldEditor::getClientObj(SceneObject * obj)
{
#ifdef TGE_RPGCLIENT2 /// TGE_RPGGhost
return obj;
#else
AssertFatal(obj->isServerObject(), "WorldEditor::getClientObj: not a server object!");
NetConnection * toServer = NetConnection::getConnectionToServer();
NetConnection * toClient = NetConnection::getLocalClientConnection();
S32 index = toClient->getGhostIndex(obj);
if(index == -1)
return(0);
return(dynamic_cast<SceneObject*>(toServer->resolveGhost(index)));
#endif
}
void WorldEditor::setClientObjInfo(SceneObject * obj, const MatrixF & mat, const VectorF & scale)
{
SceneObject * clientObj = getClientObj(obj);
if(!clientObj)
return;
clientObj->setTransform(mat);
clientObj->setScale(scale);
}
void WorldEditor::updateClientTransforms(Selection & sel)
{
for(U32 i = 0; i < sel.size(); i++)
{
SceneObject * clientObj = getClientObj(sel[i]);
if(!clientObj)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -