📄 worldeditor.cc
字号:
continue;
// If it's an interior we're going to need to relight the scene
// since we've moved it, so notify script of this. Don't bother
// ourselves with dynamic lit interiors, of course.
InteriorInstance *ii = dynamic_cast<InteriorInstance*>(clientObj);
if(ii != NULL && ii->mUseGLLighting == false)
{
// Set it to be dynamically lit as well.
ii->mDoSimpleDynamicRender = true;
Con::executef( 1, "onNeedRelight" );
}
clientObj->setTransform(sel[i]->getTransform());
clientObj->setScale(sel[i]->getScale());
}
}
//------------------------------------------------------------------------------
// simple undo mechanism: bascially maintains stacks of state information
// from the selections (transform info only)
WorldEditor::SelectionState * WorldEditor::createUndo(Selection & sel)
{
SelectionState * sState = new SelectionState;
for(U32 i = 0; i < sel.size(); i++)
{
SelectionState::Entry entry;
entry.mMatrix = sel[i]->getTransform();
entry.mScale = sel[i]->getScale();
entry.mObjId = sel[i]->getId();
sState->mEntries.push_back(entry);
}
return(sState);
}
void WorldEditor::addUndo(Vector<SelectionState *> & list, SelectionState * sel)
{
AssertFatal(sel, "WorldEditor::addUndo - invalid selection");
list.push_front(sel);
if(list.size() == mUndoLimit)
{
SelectionState * ss = list[list.size()-1];
delete ss;
list.pop_back();
}
setDirty();
}
bool WorldEditor::processUndo(Vector<SelectionState*> & src, Vector<SelectionState*> & dest)
{
if(!src.size())
return(false);
SelectionState * task = src.front();
src.pop_front();
for(U32 i = 0; i < task->mEntries.size(); i++)
{
SceneObject * obj = static_cast<SceneObject*>(Sim::findObject(task->mEntries[i].mObjId));
if(obj)
{
setClientObjInfo(obj, task->mEntries[i].mMatrix, task->mEntries[i].mScale);
obj->setTransform(task->mEntries[i].mMatrix);
obj->setScale(task->mEntries[i].mScale);
}
}
addUndo(dest, task);
mSelected.invalidateCentroid();
return(true);
}
void WorldEditor::clearUndo(Vector<SelectionState *> & list)
{
for(U32 i = 0; i < list.size(); i++)
delete list[i];
list.clear();
}
//------------------------------------------------------------------------------
// edit stuff
bool WorldEditor::deleteSelection(Selection & sel)
{
if(sel.size())
setDirty();
while(sel.size())
sel[0]->deleteObject();
return(true);
}
bool WorldEditor::copySelection(Selection & sel)
{
mStreamBufs.clear();
for(U32 i = 0; i < sel.size(); i++)
{
// um.. can we say lame?
mStreamBufs.increment();
MemStream stream(2048, mStreamBufs.last(), false, true);
stream.write(7, (void*)"return ");
sel[i]->write(stream, 0);
if(stream.getStatus() != Stream::Ok)
{
mStreamBufs.clear();
return(false);
}
}
return(true);
}
bool WorldEditor::pasteSelection()
{
if(!mSelectionLocked)
mSelected.clear();
for(U32 i = 0; i < mStreamBufs.size(); i++)
{
const char * eval = Con::evaluate((const char *)mStreamBufs[i]);
SceneObject * obj = dynamic_cast<SceneObject*>(Sim::findObject(eval));
if(obj && !mSelectionLocked)
mSelected.addObject(obj);
}
// drop it ...
dropSelection(mSelected);
return(true);
}
//------------------------------------------------------------------------------
void WorldEditor::hideSelection(bool hide)
{
// set server/client objects hide field
for(U32 i = 0; i < mSelected.size(); i++)
{
// client
SceneObject * clientObj = getClientObj(mSelected[i]);
if(!clientObj)
continue;
clientObj->setHidden(hide);
// server
mSelected[i]->setHidden(hide);
}
}
void WorldEditor::lockSelection(bool lock)
{
//
for(U32 i = 0; i < mSelected.size(); i++)
mSelected[i]->setLocked(lock);
}
//------------------------------------------------------------------------------
// the centroid get's moved to the drop point...
void WorldEditor::dropSelection(Selection & sel)
{
if(!sel.size())
return;
setDirty();
Point3F centroid = mObjectsUseBoxCenter ? sel.getBoxCentroid() : sel.getCentroid();
switch(mDropType)
{
case DropAtCentroid:
// already there
break;
case DropAtOrigin:
{
sel.offset(Point3F(-centroid));
break;
}
case DropAtCameraWithRot:
{
sel.offset(Point3F(smCamPos - centroid));
sel.orient(smCamMatrix, centroid);
break;
}
case DropAtCamera:
{
sel.offset(Point3F(smCamPos - centroid));
break;
}
case DropBelowCamera:
{
Point3F offset = smCamPos - centroid;
offset.z -= 15.f;
sel.offset(offset);
break;
}
case DropAtScreenCenter:
{
Gui3DMouseEvent event;
event.pos = smCamPos;
Point2I offset = localToGlobalCoord(Point2I(0,0));
Point3F sp(offset.x + (getExtent().x / 2), offset.y + (getExtent().y / 2), 1);
Point3F wp;
unproject(sp, &wp);
event.vec = wp - smCamPos;
event.vec.normalizeSafe();
// if fails to hit screen, then place at camera
CollisionInfo info;
if(collide(event, info))
sel.offset(Point3F(info.pos - centroid));
else
sel.offset(Point3F(event.pos - centroid));
break;
}
case DropToGround:
{
for(U32 i = 0; i < sel.size(); i++)
{
Point3F start;
MatrixF mat = sel[i]->getTransform();
mat.getColumn(3, &start);
Point3F end = start;
start.z = -2000.f;
end.z = 2000.f;
RayInfo ri;
bool hit;
if(mBoundingBoxCollision)
hit = gServerContainer.collideBox(start, end, TerrainObjectType, &ri);
else
hit = gServerContainer.castRay(start, end, TerrainObjectType, &ri);
if(hit)
{
mat.setColumn(3, ri.point);
sel[i]->setTransform(mat);
}
else
sel.offset(Point3F(smCamPos - centroid));
}
break;
}
}
//
updateClientTransforms(sel);
}
//------------------------------------------------------------------------------
SceneObject * WorldEditor::getControlObject()
{
GameConnection * connection = GameConnection::getLocalClientConnection();
if(connection)
return(dynamic_cast<SceneObject*>(connection->getControlObject()));
return(0);
}
bool WorldEditor::collide(const Gui3DMouseEvent & event, CollisionInfo & info)
{
// turn off the collsion with the control object
SceneObject * controlObj = getControlObject();
if(controlObj)
controlObj->disableCollision();
//
Point3F startPnt = event.pos;
Point3F endPnt = event.pos + event.vec * mProjectDistance;
//
RayInfo ri;
bool hit;
if(mBoundingBoxCollision)
hit = gServerContainer.collideBox(startPnt, endPnt, 0xFFFFFFFF, &ri);
else
hit = gServerContainer.castRay(startPnt, endPnt, 0xFFFFFFFF, &ri);
//
if(hit)
{
info.pos = ri.point;
info.obj = ri.object;
info.normal = ri.normal;
AssertFatal(info.obj, "WorldEditor::collide - client container returned non SceneObject");
}
if(controlObj)
controlObj->enableCollision();
return(hit);
}
//------------------------------------------------------------------------------
// main render functions
void WorldEditor::renderSelectionWorldBox(Selection & sel)
{
if(!mRenderSelectionBox)
return;
//
if(!sel.size())
return;
// build the world bounds
Box3F selBox = sel[0]->getWorldBox();
U32 i;
for(i = 1; i < sel.size(); i++)
{
const Box3F & wBox = sel[i]->getWorldBox();
selBox.min.setMin(wBox.min);
selBox.max.setMax(wBox.max);
}
//
glDisable(GL_CULL_FACE);
glColor4ub(mSelectionBoxColor.red, mSelectionBoxColor.green,
mSelectionBoxColor.blue, mSelectionBoxColor.alpha);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// create the box points
Point3F projPnts[8];
for(i = 0; i < 8; i++)
{
Point3F pnt;
pnt.set(BoxPnts[i].x ? selBox.max.x : selBox.min.x,
BoxPnts[i].y ? selBox.max.y : selBox.min.y,
BoxPnts[i].z ? selBox.max.z : selBox.min.z);
projPnts[i] = pnt;
}
// do the box
for(U32 j = 0; j < 6; j++)
{
glBegin(GL_LINE_LOOP);
for(U32 k = 0; k < 4; k++)
glVertex3f(projPnts[BoxVerts[j][k]].x,
projPnts[BoxVerts[j][k]].y,
projPnts[BoxVerts[j][k]].z);
glEnd();
}
}
void WorldEditor::renderObjectBox(SceneObject * obj, const ColorI & col)
{
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
glDisable(GL_CULL_FACE);
glColor4ub(col.red, col.green, col.blue, col.alpha);
// project the points...
Box3F box = obj->getObjBox();
MatrixF mat = obj->getTransform();
VectorF scale = obj->getScale();
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]);
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// do the box
for(U32 j = 0; j < 6; j++)
{
glBegin(GL_LINE_LOOP);
for(U32 k = 0; k < 4; k++)
glVertex3f(projPnts[BoxVerts[j][k]].x,
projPnts[BoxVerts[j][k]].y,
projPnts[BoxVerts[j][k]].z);
glEnd();
}
// // render the collision polys?
// // jff - this is using the worldbox... use obj box? which sides?
// if(mRenderBoxIntersect)
// {
// obj->disableCollision();
// Box3F bBox = obj->getWorldBox();
//
// bBox.min.z -= mProjectDistance;
// bBox.max.z += mProjectDistance;
//
// ClippedPolyList polyList;
// polyList.mPlaneList.clear();
// polyList.mNormal.set(0,0,0);
// polyList.mPlaneList.setSize(4);
// polyList.mPlaneList[0].set(bBox.min, VectorF(-1,0,0));
// polyList.mPlaneList[1].set(bBox.max, VectorF(0,1,0));
// polyList.mPlaneList[2].set(bBox.max, VectorF(1,0,0));
// polyList.mPlaneList[3].set(bBox.min, VectorF(0,-1,0));
//
// // build the poly list
// if(gServerContainer.buildPolyList(bBox, -1, &polyList))
// {
// glEnable(GL_CULL_FACE);
// glDisable(GL_DEPTH_TEST);
// glVertexPointer(3,GL_FLOAT,sizeof(ClippedPolyList::Vertex), polyList.mVertexList.address());
// glEnableClientState(GL_VERTEX_ARRAY);
//
// glColor4ub(mBoxIntersectColor.red, mBoxIntersectColor.green, mBoxIntersectColor.blue, mBoxIntersectColor.alpha);
//
// glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//
// // render em...
// ClippedPolyList::Poly * p;
// for (p = polyList.mPolyList.begin(); p < polyList.mPolyList.end(); p++) {
// glDrawElements(GL_POLYGON,p->vertexCount,
// GL_UNSIGNED_INT,&polyList.mIndexList[p->vertexStart]);
// }
//
// glDisableClientState(GL_VERTEX_ARRAY);
// glEnable(GL_DEPTH_TEST);
// glDisable(GL_CULL_FACE);
// }
// obj->enableCollision();
// }
dglSetCanonicalState();
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
}
//------------------------------------------------------------------------------
void WorldEditor::renderObjectFace(SceneObject * obj, const VectorF & normal, const ColorI & col)
{
// get the normal index
VectorF objNorm;
obj->getWorldTransform().mulV(normal, &objNorm);
U32 normI = getBoxNormalIndex(objNorm);
//
Box3F box = obj->getObjBox();
MatrixF mat = obj->getTransform();
VectorF scale = obj->getScale();
Point3F projPnts[4];
for(U32 i = 0; i < 4; i++)
{
Point3F pnt;
pnt.set(BoxPnts[BoxVerts[normI][i]].x ? box.max.x : box.min.x,
BoxPnts[BoxVerts[normI][i]].y ? box.max.y : box.min.y,
BoxPnts[BoxVerts[normI][i]].z ? box.max.z : box.min.z);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -