📄 terraineditor.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "editor/terrainEditor.h"
#include "game/collisionTest.h"
#include "terrain/terrData.h"
#include "gui/core/guiCanvas.h"
#include "console/consoleTypes.h"
#include "editor/terrainActions.h"
#include "interior/interiorInstance.h"
#include "interior/interior.h"
#include "game/gameConnection.h"
#include "sim/netObject.h"
#include "core/frameAllocator.h"
IMPLEMENT_CONOBJECT(TerrainEditor);
Selection::Selection() :
Vector<GridInfo>(__FILE__, __LINE__),
mName(0),
mUndoFlags(0),
mHashListSize(1024)
{
VECTOR_SET_ASSOCIATION(mHashLists);
// clear the hash list
mHashLists.setSize(mHashListSize);
reset();
}
Selection::~Selection()
{
}
void Selection::reset()
{
for(U32 i = 0; i < mHashListSize; i++)
mHashLists[i] = -1;
clear();
}
U32 Selection::getHashIndex(const Point2I & pos)
{
Point2F pnt = Point2F(pos.x, pos.y) + Point2F(1.3f,3.5f);
return( (U32)(mFloor(mHashLists.size() * mFmod(pnt.len() * 0.618f, 1))) );
}
S32 Selection::lookup(const Point2I & pos)
{
U32 index = getHashIndex(pos);
S32 entry = mHashLists[index];
while(entry != -1)
{
if((*this)[entry].mGridPos == pos)
return(entry);
entry = (*this)[entry].mNext;
}
return(-1);
}
void Selection::insert(GridInfo & info)
{
U32 index = getHashIndex(info.mGridPos);
info.mNext = mHashLists[index];
info.mPrev = -1;
if(info.mNext != -1)
(*this)[info.mNext].mPrev = size();
mHashLists[index] = size();
push_back(info);
}
bool Selection::remove(const GridInfo & info)
{
U32 index = getHashIndex(info.mGridPos);
S32 entry = mHashLists[index];
if(entry == -1)
return(false);
// front?
if((*this)[entry].mGridPos == info.mGridPos)
mHashLists[index] = (*this)[entry].mNext;
while(entry != -1)
{
if((*this)[entry].mGridPos == info.mGridPos)
{
if((*this)[entry].mPrev != -1)
(*this)[(*this)[entry].mPrev].mNext = (*this)[entry].mNext;
if((*this)[entry].mNext != -1)
(*this)[(*this)[entry].mNext].mPrev = (*this)[entry].mPrev;
// swap?
if(entry != (size() - 1))
{
U32 last = size() - 1;
(*this)[entry] = (*this)[size()-1];
if((*this)[entry].mPrev != -1)
(*this)[(*this)[entry].mPrev].mNext = entry;
else
{
U32 idx = getHashIndex((*this)[entry].mGridPos);
AssertFatal(mHashLists[idx] == ((*this).size() - 1), "doh");
mHashLists[idx] = entry;
}
if((*this)[entry].mNext != -1)
(*this)[(*this)[entry].mNext].mPrev = entry;
}
pop_back();
return(true);
}
entry = (*this)[entry].mNext;
}
return(false);
}
// add unique grid info into the selection - test uniqueness by grid position
bool Selection::add(GridInfo & info)
{
S32 index = lookup(info.mGridPos);
if(index != -1)
return(false);
insert(info);
return(true);
}
bool Selection::getInfo(Point2I pos, GridInfo & info)
{
S32 index = lookup(pos);
if(index == -1)
return(false);
info = (*this)[index];
return(true);
}
bool Selection::setInfo(GridInfo & info)
{
S32 index = lookup(info.mGridPos);
if(index == -1)
return(false);
S32 next = (*this)[index].mNext;
S32 prev = (*this)[index].mPrev;
(*this)[index] = info;
(*this)[index].mNext = next;
(*this)[index].mPrev = prev;
return(true);
}
F32 Selection::getAvgHeight()
{
if(!size())
return(0);
F32 avg = 0.f;
for(U32 i = 0; i < size(); i++)
avg += (*this)[i].mHeight;
return(avg / size());
}
//------------------------------------------------------------------------------
Brush::Brush(TerrainEditor * editor) :
mTerrainEditor(editor)
{
mSize = mTerrainEditor->getBrushSize();
}
const Point2I & Brush::getPosition()
{
return(mGridPos);
}
void Brush::setPosition(const Point3F & pos)
{
Point2I gPos;
mTerrainEditor->worldToGrid(pos, gPos);
setPosition(gPos);
}
void Brush::setPosition(const Point2I & pos)
{
mGridPos = pos;
update();
}
//------------------------------------------------------------------------------
void Brush::update()
{
rebuild();
// soft selection?
// if(mTerrainEditor->mEnableSoftBrushes)
// {
// Gui3DMouseEvent event;
// TerrainAction * action = mTerrainEditor->lookupAction("softSelect");
// AssertFatal(action, "Brush::update: no 'softSelect' action found!");
//
// mTerrainEditor->setCurrentSel(this);
// action->process(this, event, true, TerrainAction::Process);
// mTerrainEditor->resetCurrentSel();
// }
}
//------------------------------------------------------------------------------
#ifdef TGE_RPG /// TGE_TerrainScene
void HLineBrush::rebuild()
{
reset();
Filter filter;
filter.set(1, &mTerrainEditor->mSoftSelectFilter);
//
// mSize should always be odd.
S32 centerX = (mSize.x - 1) / 2;
//S32 centerY = (mSize.y - 1) / 2;
F32 xFactorScale = F32(centerX) / (F32(centerX) + 0.5);
for(S32 x = 0; x < mSize.x; x++)
{
GridInfo info;
mTerrainEditor->getGridInfo(Point2I(mGridPos.x + x - centerX, mGridPos.y), info);
if(mTerrainEditor->mEnableSoftBrushes && centerX != 0)
{
F32 xFactor = (mFabs(centerX - x) / F32(centerX)) * xFactorScale;
info.mWeight = filter.getValue(xFactor);
}
push_back(info);
}
}
void VLineBrush::rebuild()
{
reset();
Filter filter;
filter.set(1, &mTerrainEditor->mSoftSelectFilter);
//
// mSize should always be odd.
//S32 centerX = (mSize.x - 1) / 2;
S32 centerY = (mSize.y - 1) / 2;
F32 yFactorScale = F32(centerY) / (F32(centerY) + 0.5);
for(S32 y = 0; y < mSize.y; y++)
{
GridInfo info;
mTerrainEditor->getGridInfo(Point2I(mGridPos.x, mGridPos.y + y - centerY), info);
if(mTerrainEditor->mEnableSoftBrushes && centerY != 0)
{
F32 yFactor = (mFabs(centerY - y) / F32(centerY)) * yFactorScale;
info.mWeight = filter.getValue( yFactor);
}
push_back(info);
}
}
#endif//#ifdef TGE_RPG /// TGE_TerrainScene
void BoxBrush::rebuild()
{
reset();
Filter filter;
filter.set(1, &mTerrainEditor->mSoftSelectFilter);
//
// mSize should always be odd.
S32 centerX = (mSize.x - 1) / 2;
S32 centerY = (mSize.y - 1) / 2;
F32 xFactorScale = F32(centerX) / (F32(centerX) + 0.5);
F32 yFactorScale = F32(centerY) / (F32(centerY) + 0.5);
for(S32 x = 0; x < mSize.x; x++)
{
for(S32 y = 0; y < mSize.y; y++)
{
GridInfo info;
mTerrainEditor->getGridInfo(Point2I(mGridPos.x + x - centerX, mGridPos.y + y - centerY), info);
if(mTerrainEditor->mEnableSoftBrushes && centerX != 0 && centerY != 0)
{
F32 xFactor = (mFabs(centerX - x) / F32(centerX)) * xFactorScale;
F32 yFactor = (mFabs(centerY - y) / F32(centerY)) * yFactorScale;
info.mWeight = filter.getValue(xFactor > yFactor ? xFactor : yFactor);
}
push_back(info);
}
}
}
//------------------------------------------------------------------------------
void EllipseBrush::rebuild()
{
reset();
Point3F center(F32(mSize.x - 1) / 2, F32(mSize.y - 1) / 2, 0);
Filter filter;
filter.set(1, &mTerrainEditor->mSoftSelectFilter);
// a point is in a circle if:
// x^2 + y^2 <= r^2
// a point is in an ellipse if:
// (ax)^2 + (by)^2 <= 1
// where a = 1/halfEllipseWidth and b = 1/halfEllipseHeight
// for a soft-selected ellipse,
// the factor is simply the filtered: ((ax)^2 + (by)^2)
F32 a = 1 / (F32(mSize.x) * 0.5);
F32 b = 1 / (F32(mSize.y) * 0.5);
for(U32 x = 0; x < mSize.x; x++)
{
for(U32 y = 0; y < mSize.y; y++)
{
F32 xp = center.x - x;
F32 yp = center.y - y;
F32 factor = (a * a * xp * xp) + (b * b * yp * yp);
if(factor > 1)
continue;
GridInfo info;
mTerrainEditor->getGridInfo(Point2I((S32)(mGridPos.x + x - center.x), (S32)(mGridPos.y + y - center.y)), info);
if(mTerrainEditor->mEnableSoftBrushes)
info.mWeight = filter.getValue(factor);
push_back(info);
}
}
}
//------------------------------------------------------------------------------
SelectionBrush::SelectionBrush(TerrainEditor * editor) :
Brush(editor)
{
//... grab the current selection
}
void SelectionBrush::rebuild()
{
reset();
//... move the selection
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
TerrainEditor::TerrainEditor() :
mTerrainBlock(0),
mMousePos(0,0,0),
mMouseBrush(0),
mInAction(false),
mUndoLimit(20),
mUndoSel(0),
mRebuildEmpty(false),
mRebuildTextures(false),
mGridUpdateMin(255, 255),
mGridUpdateMax(0, 0)
{
VECTOR_SET_ASSOCIATION(mActions);
VECTOR_SET_ASSOCIATION(mUndoList);
VECTOR_SET_ASSOCIATION(mRedoList);
VECTOR_SET_ASSOCIATION(mBaseMaterialInfos);
//
resetCurrentSel();
//
mBrushSize.set(1,1);
mMouseBrush = new BoxBrush(this);
mMouseDownSeq = 0;
mIsDirty = false;
mIsMissionDirty = false;
mPaintMaterial = NULL;
// add in all the actions here..
mActions.push_back(new SelectAction(this));
mActions.push_back(new SoftSelectAction(this));
mActions.push_back(new OutlineSelectAction(this));
mActions.push_back(new PaintMaterialAction(this));
mActions.push_back(new RaiseHeightAction(this));
mActions.push_back(new LowerHeightAction(this));
mActions.push_back(new SetHeightAction(this));
mActions.push_back(new SetEmptyAction(this));
mActions.push_back(new ClearEmptyAction(this));
mActions.push_back(new ScaleHeightAction(this));
mActions.push_back(new BrushAdjustHeightAction(this));
mActions.push_back(new AdjustHeightAction(this));
mActions.push_back(new FlattenHeightAction(this));
mActions.push_back(new SmoothHeightAction(this));
mActions.push_back(new SetMaterialGroupAction(this));
mActions.push_back(new SetModifiedAction(this));
mActions.push_back(new ClearModifiedAction(this));
#ifdef TGE_RPG /// TGE_TerrainScene
mActions.push_back(new SetBlockAction(this));
#endif
// set the default action
mCurrentAction = mActions[0];
mRenderBrush = mCurrentAction->useMouseBrush();
// persist data defaults
mRenderBorder = true;
mBorderHeight = 10;
mBorderFillColor.set(0,255,0,20);
mBorderFrameColor.set(0,255,0,128);
mBorderLineMode = false;
mSelectionHidden = false;
mEnableSoftBrushes = false;
mRenderVertexSelection = false;
mProcessUsesBrush = false;
mCurrentCursor = NULL;
mCursorVisible = true;
//
mAdjustHeightVal = 10;
mSetHeightVal = 100;
mScaleVal = 1;
mSmoothFactor = 0.1f;
mMaterialGroup = 0;
mSoftSelectRadius = 50.f;
mAdjustHeightMouseScale = 0.1f;
mSoftSelectDefaultFilter = StringTable->insert("1.000000 0.833333 0.666667 0.500000 0.333333 0.166667 0.000000");
mSoftSelectFilter = mSoftSelectDefaultFilter;
#ifdef TGE_RPG /// TGE_TerrainScene
m_uSceneFlag = TerrainScene::BALK_WALK;
#endif
}
TerrainEditor::~TerrainEditor()
{
// mouse
delete mMouseBrush;
// terrain actions
U32 i;
for(i = 0; i < mActions.size(); i++)
delete mActions[i];
// undo stuff
clearUndo(mUndoList);
clearUndo(mRedoList);
delete mUndoSel;
// base material infos
for(i = 0; i < mBaseMaterialInfos.size(); i++)
delete mBaseMaterialInfos[i];
}
//------------------------------------------------------------------------------
TerrainAction * TerrainEditor::lookupAction(const char * name)
{
for(U32 i = 0; i < mActions.size(); i++)
if(!dStricmp(mActions[i]->getName(), name))
return(mActions[i]);
return(0);
}
//------------------------------------------------------------------------------
bool TerrainEditor::onAdd()
{
if(!Parent::onAdd())
return(false);
SimObject * obj = Sim::findObject("EditorArrowCursor");
if(!obj)
{
Con::errorf(ConsoleLogEntry::General, "TerrainEditor::onAdd: failed to load cursor");
return(false);
}
mDefaultCursor = dynamic_cast<GuiCursor*>(obj);
return(true);
}
//------------------------------------------------------------------------------
void TerrainEditor::onDeleteNotify(SimObject * object)
{
Parent::onDeleteNotify(object);
if(mTerrainBlock != dynamic_cast<TerrainBlock*>(object))
return;
mTerrainBlock = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -