mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-24 05:45:40 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
475
Engine/source/gui/worldEditor/creator.cpp
Normal file
475
Engine/source/gui/worldEditor/creator.cpp
Normal file
|
|
@ -0,0 +1,475 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/worldEditor/creator.h"
|
||||
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT(CreatorTree);
|
||||
|
||||
ConsoleDocClass( CreatorTree,
|
||||
"@brief Creator tree from old editor. Not used in current editor.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class CreatorTree::Node
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
CreatorTree::Node::Node() :
|
||||
mFlags(0),
|
||||
mParent(0),
|
||||
mName(0),
|
||||
mValue(0),
|
||||
mId(0),
|
||||
mTab(0)
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mChildren);
|
||||
}
|
||||
|
||||
CreatorTree::Node::~Node()
|
||||
{
|
||||
for(U32 i = 0; i < mChildren.size(); i++)
|
||||
delete mChildren[i];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CreatorTree::Node::expand(bool exp)
|
||||
{
|
||||
if(exp)
|
||||
{
|
||||
if(mParent)
|
||||
mParent->expand(exp);
|
||||
mFlags.set(Node::Expanded);
|
||||
}
|
||||
else if(!isRoot())
|
||||
{
|
||||
if(isGroup())
|
||||
for(U32 i = 0; i < mChildren.size(); i++)
|
||||
mChildren[i]->expand(exp);
|
||||
|
||||
mFlags.clear(Selected);
|
||||
mFlags.clear(Expanded);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
CreatorTree::Node * CreatorTree::Node::find(S32 id)
|
||||
{
|
||||
if(mId == id)
|
||||
return(this);
|
||||
|
||||
if(!isGroup())
|
||||
return(0);
|
||||
|
||||
for(U32 i = 0; i < mChildren.size(); i++)
|
||||
{
|
||||
Node * node = mChildren[i]->find(id);
|
||||
if(node)
|
||||
return(node);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool CreatorTree::Node::isFirst()
|
||||
{
|
||||
AssertFatal(!isRoot(), "CreatorTree::Node::isFirst - cannot call on root node");
|
||||
return(this == mParent->mChildren[0]);
|
||||
}
|
||||
|
||||
bool CreatorTree::Node::isLast()
|
||||
{
|
||||
AssertFatal(!isRoot(), "CreatorTree::Node::isLast - cannot call on root node");
|
||||
return(this == mParent->mChildren[mParent->mChildren.size()-1]);
|
||||
}
|
||||
|
||||
bool CreatorTree::Node::hasChildItem()
|
||||
{
|
||||
for(U32 i = 0; i < mChildren.size(); i++)
|
||||
{
|
||||
if(mChildren[i]->isGroup() && mChildren[i]->hasChildItem())
|
||||
return(true);
|
||||
|
||||
if(!mChildren[i]->isGroup())
|
||||
return(true);
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
S32 CreatorTree::Node::getSelected()
|
||||
{
|
||||
for(U32 i = 0; i < mChildren.size(); i++)
|
||||
{
|
||||
if(mChildren[i]->isSelected())
|
||||
return(mChildren[i]->mId);
|
||||
else if(mChildren[i]->isGroup())
|
||||
{
|
||||
S32 ret = mChildren[i]->getSelected();
|
||||
if(ret != -1)
|
||||
return(ret);
|
||||
}
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class CreatorTree
|
||||
//------------------------------------------------------------------------------
|
||||
CreatorTree::CreatorTree() :
|
||||
mCurId(0),
|
||||
mTxtOffset(5),
|
||||
mRoot(0)
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mNodeList);
|
||||
clear();
|
||||
}
|
||||
|
||||
CreatorTree::~CreatorTree()
|
||||
{
|
||||
delete mRoot;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
CreatorTree::Node * CreatorTree::createNode(const char * name, const char * value, bool group, Node * parent)
|
||||
{
|
||||
Node * node = new Node();
|
||||
node->mId = mCurId++;
|
||||
node->mName = name ? StringTable->insert(name) : 0;
|
||||
node->mValue = value ? StringTable->insert(value) : 0;
|
||||
node->mFlags.set(Node::Group, group);
|
||||
|
||||
// add to the parent group
|
||||
if(parent)
|
||||
{
|
||||
node->mParent = parent;
|
||||
if(!addNode(parent, node))
|
||||
{
|
||||
delete node;
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
return(node);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CreatorTree::clear()
|
||||
{
|
||||
delete mRoot;
|
||||
mCurId = 0;
|
||||
mRoot = createNode(0, 0, true);
|
||||
mRoot->mFlags.set(Node::Root | Node::Expanded);
|
||||
mSize = Point2I(1,0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool CreatorTree::addNode(Node * parent, Node * node)
|
||||
{
|
||||
if(!parent->isGroup())
|
||||
return(false);
|
||||
|
||||
//
|
||||
parent->mChildren.push_back(node);
|
||||
return(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
CreatorTree::Node * CreatorTree::findNode(S32 id)
|
||||
{
|
||||
return(mRoot->find(id));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CreatorTree::sort()
|
||||
{
|
||||
// groups then items by alpha
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleMethod( CreatorTree, addGroup, S32, 4, 4, "(string group, string name, string value)")
|
||||
{
|
||||
CreatorTree::Node * grp = object->findNode(dAtoi(argv[2]));
|
||||
|
||||
if(!grp || !grp->isGroup())
|
||||
return(-1);
|
||||
|
||||
// return same named group if found...
|
||||
for(U32 i = 0; i < grp->mChildren.size(); i++)
|
||||
if(!dStricmp(argv[3], grp->mChildren[i]->mName))
|
||||
return(grp->mChildren[i]->mId);
|
||||
|
||||
CreatorTree::Node * node = object->createNode(argv[3], 0, true, grp);
|
||||
object->build();
|
||||
return(node ? node->getId() : -1);
|
||||
}
|
||||
|
||||
ConsoleMethod( CreatorTree, addItem, S32, 5, 5, "(Node group, string name, string value)")
|
||||
{
|
||||
CreatorTree::Node * grp = object->findNode(dAtoi(argv[2]));
|
||||
|
||||
if(!grp || !grp->isGroup())
|
||||
return -1;
|
||||
|
||||
CreatorTree::Node * node = object->createNode(argv[3], argv[4], false, grp);
|
||||
object->build();
|
||||
return(node ? node->getId() : -1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleMethod( CreatorTree, fileNameMatch, bool, 5, 5, "(string world, string type, string filename)"){
|
||||
// argv[2] - world short
|
||||
// argv[3] - type short
|
||||
// argv[4] - filename
|
||||
|
||||
// interior filenames
|
||||
// 0 - world short ('b', 'x', ...)
|
||||
// 1-> - type short ('towr', 'bunk', ...)
|
||||
U32 typeLen = dStrlen(argv[3]);
|
||||
if(dStrlen(argv[4]) < (typeLen + 1))
|
||||
return(false);
|
||||
|
||||
// world
|
||||
if(dToupper(argv[4][0]) != dToupper(argv[2][0]))
|
||||
return(false);
|
||||
|
||||
return(!dStrnicmp(argv[4]+1, argv[3], typeLen));
|
||||
}
|
||||
|
||||
ConsoleMethod( CreatorTree, getSelected, S32, 2, 2, "Return a handle to the currently selected item.")
|
||||
{
|
||||
return(object->getSelected());
|
||||
}
|
||||
|
||||
ConsoleMethod( CreatorTree, isGroup, bool, 3, 3, "(Group g)")
|
||||
{
|
||||
CreatorTree::Node * node = object->findNode(dAtoi(argv[2]));
|
||||
if(node && node->isGroup())
|
||||
return(true);
|
||||
return(false);
|
||||
}
|
||||
|
||||
ConsoleMethod( CreatorTree, getName, const char*, 3, 3, "(Node item)")
|
||||
{
|
||||
CreatorTree::Node * node = object->findNode(dAtoi(argv[2]));
|
||||
return(node ? node->mName : 0);
|
||||
}
|
||||
|
||||
ConsoleMethod( CreatorTree, getValue, const char*, 3, 3, "(Node n)")
|
||||
{
|
||||
CreatorTree::Node * node = object->findNode(dAtoi(argv[2]));
|
||||
return(node ? node->mValue : 0);
|
||||
}
|
||||
|
||||
ConsoleMethod( CreatorTree, clear, void, 2, 2, "Clear the tree.")
|
||||
{
|
||||
object->clear();
|
||||
}
|
||||
|
||||
ConsoleMethod( CreatorTree, getParent, S32, 3, 3, "(Node n)")
|
||||
{
|
||||
CreatorTree::Node * node = object->findNode(dAtoi(argv[2]));
|
||||
if(node && node->mParent)
|
||||
return(node->mParent->getId());
|
||||
|
||||
return(-1);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CreatorTree::buildNode(Node * node, U32 tab)
|
||||
{
|
||||
if(node->isExpanded())
|
||||
for(U32 i = 0; i < node->mChildren.size(); i++)
|
||||
{
|
||||
Node * child = node->mChildren[i];
|
||||
child->mTab = tab;
|
||||
child->select(false);
|
||||
mNodeList.push_back(child);
|
||||
|
||||
// grab width
|
||||
if(bool(mProfile->mFont) && child->mName)
|
||||
{
|
||||
S32 width = (tab + 1) * mTabSize + mProfile->mFont->getStrWidth(child->mName) + mTxtOffset;
|
||||
if(width > mMaxWidth)
|
||||
mMaxWidth = width;
|
||||
}
|
||||
|
||||
if(node->mChildren[i]->isGroup())
|
||||
buildNode(node->mChildren[i], tab+1);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CreatorTree::build()
|
||||
{
|
||||
mMaxWidth = 0;
|
||||
mNodeList.clear();
|
||||
buildNode(mRoot, 0);
|
||||
mCellSize.set( mMaxWidth + 1, 11 );
|
||||
setSize(Point2I(1, mNodeList.size()));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool CreatorTree::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return(false);
|
||||
|
||||
mTabSize = 11;
|
||||
|
||||
|
||||
//
|
||||
build();
|
||||
mCellSize.set( mMaxWidth + 1, 11 );
|
||||
setSize(Point2I(1, mNodeList.size()));
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CreatorTree::onMouseUp(const GuiEvent & event)
|
||||
{
|
||||
onAction();
|
||||
}
|
||||
|
||||
void CreatorTree::onMouseDown(const GuiEvent & event)
|
||||
{
|
||||
Point2I pos = globalToLocalCoord(event.mousePoint);
|
||||
|
||||
bool dblClick = event.mouseClickCount > 1;
|
||||
|
||||
// determine cell
|
||||
Point2I cell(pos.x < 0 ? -1 : pos.x / mCellSize.x, pos.y < 0 ? -1 : pos.y / mCellSize.y);
|
||||
if(cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
|
||||
{
|
||||
Node * node = mNodeList[cell.y];
|
||||
S32 offset = mTabSize * node->mTab;
|
||||
if(node->isGroup() && node->mChildren.size() && pos.x >= offset && pos.x <= (offset + mTabSize))
|
||||
{
|
||||
node->expand(!node->isExpanded());
|
||||
build();
|
||||
dblClick = false;
|
||||
}
|
||||
|
||||
if(pos.x >= offset)
|
||||
{
|
||||
if(dblClick)
|
||||
node->expand(!node->isExpanded());
|
||||
build();
|
||||
node->select(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void CreatorTree::onMouseDragged(const GuiEvent & event)
|
||||
{
|
||||
TORQUE_UNUSED(event);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void CreatorTree::onRenderCell(Point2I offset, Point2I cell, bool, bool)
|
||||
{
|
||||
Point2I cellOffset = offset;
|
||||
|
||||
Node *node = mNodeList[cell.y];
|
||||
|
||||
// Get our points
|
||||
Point2I boxStart( cellOffset.x + mTabSize * node->mTab, cellOffset.y );
|
||||
|
||||
boxStart.x += 2;
|
||||
boxStart.y += 1;
|
||||
|
||||
Point2I boxEnd = Point2I( boxStart );
|
||||
|
||||
boxEnd.x += 8;
|
||||
boxEnd.y += 8;
|
||||
|
||||
GFXDrawUtil *drawer = GFX->getDrawUtil();
|
||||
|
||||
// Start drawing stuff
|
||||
if( node->isGroup() )
|
||||
{
|
||||
// If we need a box...
|
||||
drawer->drawRectFill( boxStart, boxEnd, mProfile->mFillColor ); // Box background
|
||||
drawer->drawRect( boxStart, boxEnd, mProfile->mFontColor ); // Border
|
||||
|
||||
// Cross line
|
||||
drawer->drawLine( boxStart.x + 2, boxStart.y + 4, boxStart.x + 7, boxStart.y + 4, mProfile->mFontColor );
|
||||
|
||||
if( !node->isExpanded() ) // If it's a [+] draw down line
|
||||
drawer->drawLine( boxStart.x + 4, boxStart.y + 2, boxStart.x + 4, boxStart.y + 7, mProfile->mFontColor );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw horizontal line
|
||||
drawer->drawLine( boxStart.x + 4, boxStart.y + 4, boxStart.x + 9, boxStart.y + 4, mProfile->mFontColor );
|
||||
|
||||
if( !node->isLast() ) // If it's a continuing one, draw a long down line
|
||||
drawer->drawLine( boxStart.x + 4, boxStart.y - 6, boxStart.x + 4, boxStart.y + 10, mProfile->mFontColor );
|
||||
else // Otherwise, just a small one
|
||||
drawer->drawLine( boxStart.x + 4, boxStart.y - 2, boxStart.x + 4, boxStart.y + 4, mProfile->mFontColor );
|
||||
}
|
||||
|
||||
//draw in all the required continuation lines
|
||||
Node *parent = node->mParent;
|
||||
|
||||
while( !parent->isRoot() )
|
||||
{
|
||||
if( !parent->isLast() )
|
||||
{
|
||||
drawer->drawLine( cellOffset.x + ( parent->mTab * mTabSize ) + 6,
|
||||
cellOffset.y - 2,
|
||||
cellOffset.x + ( parent->mTab * mTabSize ) + 6,
|
||||
cellOffset.y + 11,
|
||||
mProfile->mFontColor );
|
||||
}
|
||||
parent = parent->mParent;
|
||||
}
|
||||
|
||||
ColorI fontColor = mProfile->mFontColor;
|
||||
if( node->isSelected() )
|
||||
fontColor = mProfile->mFontColorHL;
|
||||
else if( node->isGroup() && node->hasChildItem() )
|
||||
fontColor.set( 128, 0, 0 );
|
||||
else if( !node->isGroup() )
|
||||
fontColor.set( 0, 0, 128 );
|
||||
|
||||
drawer->setBitmapModulation(fontColor); //node->isSelected() ? mProfile->mFontColorHL : mProfile->mFontColor);
|
||||
drawer->drawText( mProfile->mFont,
|
||||
Point2I( offset.x + mTxtOffset + mTabSize * ( node->mTab + 1 ), offset.y ),
|
||||
node->mName);
|
||||
}
|
||||
120
Engine/source/gui/worldEditor/creator.h
Normal file
120
Engine/source/gui/worldEditor/creator.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CREATOR_H_
|
||||
#define _CREATOR_H_
|
||||
|
||||
#ifndef _GUIARRAYCTRL_H_
|
||||
#include "gui/core/guiArrayCtrl.h"
|
||||
#endif
|
||||
|
||||
|
||||
/// Creator tree from old editor. Not used in current editor.
|
||||
class CreatorTree : public GuiArrayCtrl
|
||||
{
|
||||
typedef GuiArrayCtrl Parent;
|
||||
public:
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
Node();
|
||||
~Node();
|
||||
|
||||
enum {
|
||||
Group = BIT(0),
|
||||
Expanded = BIT(1),
|
||||
Selected = BIT(2),
|
||||
Root = BIT(3)
|
||||
};
|
||||
|
||||
BitSet32 mFlags;
|
||||
S32 mId;
|
||||
U32 mTab;
|
||||
Node * mParent;
|
||||
Vector<Node*> mChildren;
|
||||
StringTableEntry mName;
|
||||
StringTableEntry mValue;
|
||||
|
||||
void expand(bool exp);
|
||||
void select(bool sel){mFlags.set(Selected, sel);}
|
||||
|
||||
Node * find(S32 id);
|
||||
|
||||
//
|
||||
bool isGroup(){return(mFlags.test(Group));}
|
||||
bool isExpanded(){return(mFlags.test(Expanded));}
|
||||
bool isSelected(){return(mFlags.test(Selected));}
|
||||
bool isRoot(){return(mFlags.test(Root));}
|
||||
S32 getId(){return(mId);}
|
||||
bool hasChildItem();
|
||||
S32 getSelected();
|
||||
|
||||
//
|
||||
bool isFirst();
|
||||
bool isLast();
|
||||
};
|
||||
|
||||
CreatorTree();
|
||||
~CreatorTree();
|
||||
|
||||
//
|
||||
S32 mCurId;
|
||||
Node * mRoot;
|
||||
Vector<Node*> mNodeList;
|
||||
|
||||
//
|
||||
void buildNode(Node * node, U32 tab);
|
||||
void build();
|
||||
|
||||
//
|
||||
bool addNode(Node * parent, Node * node);
|
||||
Node * createNode(const char * name, const char * value, bool group = false, Node * parent = 0);
|
||||
Node * findNode(S32 id);
|
||||
S32 getSelected(){return(mRoot->getSelected());}
|
||||
|
||||
//
|
||||
void expandNode(Node * node, bool expand);
|
||||
void selectNode(Node * node, bool select);
|
||||
|
||||
//
|
||||
void sort();
|
||||
void clear();
|
||||
|
||||
S32 mTabSize;
|
||||
S32 mMaxWidth;
|
||||
S32 mTxtOffset;
|
||||
|
||||
// GuiControl
|
||||
void onMouseDown(const GuiEvent & event);
|
||||
void onMouseDragged(const GuiEvent & event);
|
||||
void onMouseUp(const GuiEvent & event);
|
||||
bool onWake();
|
||||
|
||||
// GuiArrayCtrl
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool, bool);
|
||||
|
||||
DECLARE_CONOBJECT(CreatorTree);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
};
|
||||
|
||||
#endif
|
||||
1395
Engine/source/gui/worldEditor/editTSCtrl.cpp
Normal file
1395
Engine/source/gui/worldEditor/editTSCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
218
Engine/source/gui/worldEditor/editTSCtrl.h
Normal file
218
Engine/source/gui/worldEditor/editTSCtrl.h
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#define _EDITTSCTRL_H_
|
||||
|
||||
#ifndef _GUITSCONTROL_H_
|
||||
#include "gui/3d/guiTSControl.h"
|
||||
#endif
|
||||
#ifndef _GIZMO_H_
|
||||
#include "gizmo.h"
|
||||
#endif
|
||||
|
||||
class TerrainBlock;
|
||||
class MissionArea;
|
||||
class Gizmo;
|
||||
class EditManager;
|
||||
struct ObjectRenderInst;
|
||||
class SceneRenderState;
|
||||
class BaseMatInstance;
|
||||
|
||||
|
||||
class EditTSCtrl : public GuiTSCtrl
|
||||
{
|
||||
typedef GuiTSCtrl Parent;
|
||||
|
||||
protected:
|
||||
|
||||
void make3DMouseEvent(Gui3DMouseEvent & gui3Devent, const GuiEvent &event);
|
||||
|
||||
// GuiControl
|
||||
virtual void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
|
||||
virtual void onMouseUp(const GuiEvent & event);
|
||||
virtual void onMouseDown(const GuiEvent & event);
|
||||
virtual void onMouseMove(const GuiEvent & event);
|
||||
virtual void onMouseDragged(const GuiEvent & event);
|
||||
virtual void onMouseEnter(const GuiEvent & event);
|
||||
virtual void onMouseLeave(const GuiEvent & event);
|
||||
virtual void onRightMouseDown(const GuiEvent & event);
|
||||
virtual void onRightMouseUp(const GuiEvent & event);
|
||||
virtual void onRightMouseDragged(const GuiEvent & event);
|
||||
virtual void onMiddleMouseDown(const GuiEvent & event);
|
||||
virtual void onMiddleMouseUp(const GuiEvent & event);
|
||||
virtual void onMiddleMouseDragged(const GuiEvent & event);
|
||||
virtual bool onInputEvent(const InputEventInfo & event);
|
||||
virtual bool onMouseWheelUp(const GuiEvent &event);
|
||||
virtual bool onMouseWheelDown(const GuiEvent &event);
|
||||
|
||||
|
||||
virtual void updateGuiInfo() {};
|
||||
virtual void renderScene(const RectI &){};
|
||||
void renderMissionArea();
|
||||
virtual void renderCameraAxis();
|
||||
virtual void renderGrid();
|
||||
|
||||
// GuiTSCtrl
|
||||
void renderWorld(const RectI & updateRect);
|
||||
|
||||
void _renderScene(ObjectRenderInst*, SceneRenderState *state, BaseMatInstance*);
|
||||
|
||||
/// Zoom in/out in ortho views by "steps".
|
||||
void orthoZoom( F32 steps );
|
||||
|
||||
protected:
|
||||
enum DisplayType
|
||||
{
|
||||
DisplayTypeTop,
|
||||
DisplayTypeBottom,
|
||||
DisplayTypeFront,
|
||||
DisplayTypeBack,
|
||||
DisplayTypeLeft,
|
||||
DisplayTypeRight,
|
||||
DisplayTypePerspective,
|
||||
DisplayTypeIsometric,
|
||||
};
|
||||
|
||||
S32 mDisplayType;
|
||||
F32 mOrthoFOV;
|
||||
Point3F mOrthoCamTrans;
|
||||
EulerF mIsoCamRot;
|
||||
Point3F mIsoCamRotCenter;
|
||||
F32 mIsoCamAngle;
|
||||
Point3F mRawCamPos;
|
||||
Point2I mLastMousePos;
|
||||
bool mLastMouseClamping;
|
||||
|
||||
bool mAllowBorderMove;
|
||||
S32 mMouseMoveBorder;
|
||||
F32 mMouseMoveSpeed;
|
||||
U32 mLastBorderMoveTime;
|
||||
|
||||
Gui3DMouseEvent mLastEvent;
|
||||
bool mLeftMouseDown;
|
||||
bool mRightMouseDown;
|
||||
bool mMiddleMouseDown;
|
||||
bool mMiddleMouseTriggered;
|
||||
bool mMouseLeft;
|
||||
|
||||
SimObjectPtr<Gizmo> mGizmo;
|
||||
GizmoProfile *mGizmoProfile;
|
||||
|
||||
public:
|
||||
|
||||
EditTSCtrl();
|
||||
~EditTSCtrl();
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
//
|
||||
bool mRenderMissionArea;
|
||||
ColorI mMissionAreaFillColor;
|
||||
ColorI mMissionAreaFrameColor;
|
||||
F32 mMissionAreaHeightAdjust;
|
||||
|
||||
//
|
||||
ColorI mConsoleFrameColor;
|
||||
ColorI mConsoleFillColor;
|
||||
S32 mConsoleSphereLevel;
|
||||
S32 mConsoleCircleSegments;
|
||||
S32 mConsoleLineWidth;
|
||||
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
|
||||
//
|
||||
bool mConsoleRendering;
|
||||
bool mRightMousePassThru;
|
||||
bool mMiddleMousePassThru;
|
||||
|
||||
// all editors will share a camera
|
||||
static Point3F smCamPos;
|
||||
static MatrixF smCamMatrix;
|
||||
static bool smCamOrtho;
|
||||
static F32 smCamNearPlane;
|
||||
static F32 smCamFOV;
|
||||
static F32 smVisibleDistanceScale;
|
||||
|
||||
static U32 smSceneBoundsMask;
|
||||
static Point3F smMinSceneBounds;
|
||||
|
||||
bool mRenderGridPlane;
|
||||
ColorI mGridPlaneColor;
|
||||
F32 mGridPlaneSize;
|
||||
F32 mGridPlaneSizePixelBias;
|
||||
S32 mGridPlaneMinorTicks;
|
||||
ColorI mGridPlaneMinorTickColor;
|
||||
ColorI mGridPlaneOriginColor;
|
||||
|
||||
GFXStateBlockRef mBlendSB;
|
||||
|
||||
// GuiTSCtrl
|
||||
virtual bool getCameraTransform(MatrixF* cameraMatrix);
|
||||
virtual void computeSceneBounds(Box3F& bounds);
|
||||
bool processCameraQuery(CameraQuery * query);
|
||||
|
||||
// guiControl
|
||||
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||
virtual void on3DMouseUp(const Gui3DMouseEvent &){};
|
||||
virtual void on3DMouseDown(const Gui3DMouseEvent &){};
|
||||
virtual void on3DMouseMove(const Gui3DMouseEvent &){};
|
||||
virtual void on3DMouseDragged(const Gui3DMouseEvent &){};
|
||||
virtual void on3DMouseEnter(const Gui3DMouseEvent &){};
|
||||
virtual void on3DMouseLeave(const Gui3DMouseEvent &){};
|
||||
virtual void on3DRightMouseDown(const Gui3DMouseEvent &){};
|
||||
virtual void on3DRightMouseUp(const Gui3DMouseEvent &){};
|
||||
virtual void on3DRightMouseDragged(const Gui3DMouseEvent &){};
|
||||
virtual void on3DMouseWheelUp(const Gui3DMouseEvent &){};
|
||||
virtual void on3DMouseWheelDown(const Gui3DMouseEvent &){};
|
||||
virtual void get3DCursor(GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &);
|
||||
|
||||
virtual bool isMiddleMouseDown() {return mMiddleMouseDown;}
|
||||
|
||||
S32 getDisplayType() const {return mDisplayType;}
|
||||
virtual void setDisplayType(S32 type);
|
||||
|
||||
/// Return true if the current view is an ortho projection along one of the world axes.
|
||||
bool isOrthoDisplayType() const { return ( mDisplayType != DisplayTypePerspective && mDisplayType != DisplayTypeIsometric ); }
|
||||
|
||||
F32 getOrthoFOV() const { return mOrthoFOV; }
|
||||
void setOrthoFOV( F32 fov ) { mOrthoFOV = fov; }
|
||||
|
||||
virtual TerrainBlock* getActiveTerrain();
|
||||
|
||||
virtual void calcOrthoCamOffset(F32 mousex, F32 mousey, U8 modifier=0);
|
||||
|
||||
Gizmo* getGizmo() { return mGizmo; }
|
||||
|
||||
/// Set flags or other Gizmo state appropriate for the current situation.
|
||||
/// For example derived classes may override this to disable certain
|
||||
/// axes of modes of manipulation.
|
||||
virtual void updateGizmo();
|
||||
|
||||
DECLARE_CONOBJECT(EditTSCtrl);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
};
|
||||
|
||||
#endif // _EDITTSCTRL_H_
|
||||
165
Engine/source/gui/worldEditor/editor.cpp
Normal file
165
Engine/source/gui/worldEditor/editor.cpp
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/worldEditor/editor.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "gui/controls/guiTextListCtrl.h"
|
||||
#include "T3D/shapeBase.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
|
||||
#ifndef TORQUE_PLAYER
|
||||
// See matching #ifdef in app/game.cpp
|
||||
bool gEditingMission = false;
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class EditManager
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(EditManager);
|
||||
|
||||
ConsoleDocClass( EditManager,
|
||||
"@brief For Editor use only, deprecated\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
EditManager::EditManager()
|
||||
{
|
||||
for(U32 i = 0; i < 10; i++)
|
||||
mBookmarks[i] = MatrixF(true);
|
||||
}
|
||||
|
||||
EditManager::~EditManager()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool EditManager::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void EditManager::onSleep()
|
||||
{
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool EditManager::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return(false);
|
||||
|
||||
// hook the namespace
|
||||
const char * name = getName();
|
||||
if(name && name[0] && getClassRep())
|
||||
{
|
||||
Namespace * parent = getClassRep()->getNameSpace();
|
||||
Con::linkNamespaces(parent->mName, name);
|
||||
mNameSpace = Con::lookupNamespace(name);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// NOTE: since EditManager is not actually used as a gui anymore, onWake/Sleep
|
||||
// were never called, which broke anyone hooking into onEditorEnable/onEditorDisable
|
||||
// and gEditingMission. So, moved these to happen in response to console methods
|
||||
// which should be called at the appropriate time.
|
||||
//
|
||||
// This is a quick fix and this system is still "begging" for a remake.
|
||||
|
||||
void EditManager::editorEnabled()
|
||||
{
|
||||
for(SimGroupIterator itr(Sim::getRootGroup()); *itr; ++itr)
|
||||
(*itr)->onEditorEnable();
|
||||
|
||||
gEditingMission = true;
|
||||
}
|
||||
|
||||
void EditManager::editorDisabled()
|
||||
{
|
||||
for(SimGroupIterator itr(Sim::getRootGroup()); *itr; ++itr)
|
||||
{
|
||||
SimObject *so = *itr;
|
||||
AssertFatal(so->isProperlyAdded() && !so->isRemoved(), "bad");
|
||||
so->onEditorDisable();
|
||||
}
|
||||
|
||||
gEditingMission = false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static GameBase * getControlObj()
|
||||
{
|
||||
GameConnection * connection = GameConnection::getLocalClientConnection();
|
||||
ShapeBase* control = 0;
|
||||
if(connection)
|
||||
control = dynamic_cast<ShapeBase*>(connection->getControlObject());
|
||||
return(control);
|
||||
}
|
||||
|
||||
ConsoleMethod( EditManager, setBookmark, void, 3, 3, "(int slot)")
|
||||
{
|
||||
S32 val = dAtoi(argv[2]);
|
||||
if(val < 0 || val > 9)
|
||||
return;
|
||||
|
||||
GameBase * control = getControlObj();
|
||||
if(control)
|
||||
object->mBookmarks[val] = control->getTransform();
|
||||
}
|
||||
|
||||
ConsoleMethod( EditManager, gotoBookmark, void, 3, 3, "(int slot)")
|
||||
{
|
||||
S32 val = dAtoi(argv[2]);
|
||||
if(val < 0 || val > 9)
|
||||
return;
|
||||
|
||||
GameBase * control = getControlObj();
|
||||
if(control)
|
||||
control->setTransform(object->mBookmarks[val]);
|
||||
}
|
||||
|
||||
ConsoleMethod( EditManager, editorEnabled, void, 2, 2, "Perform the onEditorEnabled callback on all SimObjects and set gEditingMission true" )
|
||||
{
|
||||
object->editorEnabled();
|
||||
}
|
||||
|
||||
ConsoleMethod( EditManager, editorDisabled, void, 2, 2, "Perform the onEditorDisabled callback on all SimObjects and set gEditingMission false" )
|
||||
{
|
||||
object->editorDisabled();
|
||||
}
|
||||
|
||||
ConsoleMethod( EditManager, isEditorEnabled, bool, 2, 2, "Return the value of gEditingMission." )
|
||||
{
|
||||
return gEditingMission;
|
||||
}
|
||||
69
Engine/source/gui/worldEditor/editor.h
Normal file
69
Engine/source/gui/worldEditor/editor.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _EDITOR_H_
|
||||
#define _EDITOR_H_
|
||||
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
class GameBase;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class EditManager : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
|
||||
public:
|
||||
EditManager();
|
||||
~EditManager();
|
||||
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
|
||||
/// Perform the onEditorEnabled callback on all SimObjects
|
||||
/// and set gEditingMission true.
|
||||
void editorEnabled();
|
||||
|
||||
/// Perform the onEditorDisabled callback on all SimObjects
|
||||
/// and set gEditingMission false.
|
||||
void editorDisabled();
|
||||
|
||||
MatrixF mBookmarks[10];
|
||||
DECLARE_CONOBJECT(EditManager);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
};
|
||||
|
||||
extern bool gEditingMission;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
225
Engine/source/gui/worldEditor/editorIconRegistry.cpp
Normal file
225
Engine/source/gui/worldEditor/editorIconRegistry.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/worldEditor/editorIconRegistry.h"
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/simBase.h"
|
||||
|
||||
|
||||
EditorIconRegistry gEditorIcons;
|
||||
|
||||
ConsoleDoc(
|
||||
"@class EditorIconRegistry\n"
|
||||
"@brief This class is used to find the correct icon file path for different SimObject class types.\n\n"
|
||||
"It is typically used by the editors, not intended for actual game development\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
EditorIconRegistry::EditorIconRegistry()
|
||||
{
|
||||
}
|
||||
|
||||
EditorIconRegistry::~EditorIconRegistry()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void EditorIconRegistry::loadFromPath( const String &path, bool overwrite )
|
||||
{
|
||||
AbstractClassRep *classRep = AbstractClassRep::getClassList();
|
||||
while ( classRep )
|
||||
{
|
||||
String iconFile = String::ToString( "%s%s", path.c_str(), classRep->getClassName() );
|
||||
add( classRep->getClassName(), iconFile.c_str(), overwrite );
|
||||
classRep = classRep->getNextClass();
|
||||
}
|
||||
|
||||
String defaultIconFile = path + "default";
|
||||
|
||||
mDefaultIcon.set( defaultIconFile,
|
||||
&GFXDefaultPersistentProfile,
|
||||
avar("%s() - mIcons[] (line %d)",
|
||||
__FUNCTION__, __LINE__) );
|
||||
}
|
||||
|
||||
void EditorIconRegistry::add( const String &className, const String &imageFile, bool overwrite )
|
||||
{
|
||||
// First see if we can load the image.
|
||||
GFXTexHandle icon( imageFile, &GFXDefaultPersistentProfile,
|
||||
avar("%s() - mIcons[] (line %d)", __FUNCTION__, __LINE__) );
|
||||
if ( icon.isNull() )
|
||||
return;
|
||||
|
||||
// Look it up in the map.
|
||||
StringNoCase key( className );
|
||||
IconMap::Iterator iter = mIcons.find( key );
|
||||
if ( iter != mIcons.end() )
|
||||
{
|
||||
if ( !overwrite )
|
||||
return;
|
||||
|
||||
iter->value = icon;
|
||||
}
|
||||
else
|
||||
mIcons.insertUnique( key, icon );
|
||||
}
|
||||
|
||||
GFXTexHandle EditorIconRegistry::findIcon( AbstractClassRep *classRep )
|
||||
{
|
||||
while ( classRep )
|
||||
{
|
||||
StringNoCase key( classRep->getClassName() );
|
||||
IconMap::Iterator icon = mIcons.find( key );
|
||||
|
||||
if ( icon != mIcons.end() && icon->value.isValid() )
|
||||
return icon->value;
|
||||
|
||||
classRep = classRep->getParentClass();
|
||||
}
|
||||
|
||||
return mDefaultIcon;
|
||||
}
|
||||
|
||||
GFXTexHandle EditorIconRegistry::findIcon( const SimObject *object )
|
||||
{
|
||||
if( object == NULL )
|
||||
return mDefaultIcon;
|
||||
|
||||
AbstractClassRep *classRep = object->getClassRep();
|
||||
|
||||
return findIcon( classRep );
|
||||
}
|
||||
|
||||
GFXTexHandle EditorIconRegistry::findIcon( const char *className )
|
||||
{
|
||||
// On the chance we have this className already in the map,
|
||||
// check there first because its a lot faster...
|
||||
|
||||
StringNoCase key( className );
|
||||
IconMap::Iterator icon = mIcons.find( key );
|
||||
|
||||
if ( icon != mIcons.end() && icon->value.isValid() )
|
||||
return icon->value;
|
||||
|
||||
// Well, we could still have an icon for a parent class,
|
||||
// so find the AbstractClassRep for the className.
|
||||
//
|
||||
// Unfortunately the only way to do this is looping through
|
||||
// the AbstractClassRep linked list.
|
||||
|
||||
bool found = false;
|
||||
AbstractClassRep* pClassRep = AbstractClassRep::getClassList();
|
||||
|
||||
while ( pClassRep )
|
||||
{
|
||||
if ( key.equal( pClassRep->getClassName(), String::NoCase ) )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
pClassRep = pClassRep->getNextClass();
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
{
|
||||
Con::errorf( "EditorIconRegistry::findIcon, passed className %s was not an AbstractClassRep!", key.c_str() );
|
||||
return mDefaultIcon;
|
||||
}
|
||||
|
||||
// Now do a find by AbstractClassRep recursively up the class tree...
|
||||
return findIcon( pClassRep );
|
||||
}
|
||||
|
||||
bool EditorIconRegistry::hasIconNoRecurse( const SimObject *object )
|
||||
{
|
||||
AbstractClassRep *classRep = object->getClassRep();
|
||||
|
||||
StringNoCase key( classRep->getClassName() );
|
||||
|
||||
IconMap::Iterator icon = mIcons.find( key );
|
||||
|
||||
return icon != mIcons.end();
|
||||
}
|
||||
|
||||
void EditorIconRegistry::clear()
|
||||
{
|
||||
mIcons.clear();
|
||||
mDefaultIcon.free();
|
||||
}
|
||||
|
||||
ConsoleStaticMethod( EditorIconRegistry, add, void, 3, 4, "( String className, String imageFile [, bool overwrite = true] )"
|
||||
"@internal")
|
||||
{
|
||||
bool overwrite = true;
|
||||
if ( argc > 3 )
|
||||
overwrite = dAtob( argv[3] );
|
||||
|
||||
gEditorIcons.add( argv[1], argv[2], overwrite );
|
||||
}
|
||||
|
||||
ConsoleStaticMethod( EditorIconRegistry, loadFromPath, void, 2, 3, "( String imagePath [, bool overwrite = true] )"
|
||||
"@internal")
|
||||
{
|
||||
bool overwrite = true;
|
||||
if ( argc > 2 )
|
||||
overwrite = dAtob( argv[2] );
|
||||
|
||||
gEditorIcons.loadFromPath( argv[1], overwrite );
|
||||
}
|
||||
|
||||
ConsoleStaticMethod( EditorIconRegistry, clear, void, 1, 1, ""
|
||||
"@internal")
|
||||
{
|
||||
gEditorIcons.clear();
|
||||
}
|
||||
|
||||
ConsoleStaticMethod( EditorIconRegistry, findIconByClassName, const char*, 2, 2, "( String className )\n"
|
||||
"Returns the file path to the icon file if found."
|
||||
"@internal")
|
||||
{
|
||||
GFXTexHandle icon = gEditorIcons.findIcon( argv[1] );
|
||||
if ( icon.isNull() )
|
||||
return NULL;
|
||||
|
||||
return icon->mPath;
|
||||
}
|
||||
|
||||
ConsoleStaticMethod( EditorIconRegistry, findIconBySimObject, const char*, 2, 2, "( SimObject )\n"
|
||||
"Returns the file path to the icon file if found."
|
||||
"@internal")
|
||||
{
|
||||
SimObject *obj = NULL;
|
||||
if ( !Sim::findObject( argv[1], obj ) )
|
||||
{
|
||||
Con::warnf( "EditorIconRegistry::findIcon, parameter %d was not a SimObject!", argv[1] );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GFXTexHandle icon = gEditorIcons.findIcon( obj );
|
||||
if ( icon.isNull() )
|
||||
return NULL;
|
||||
|
||||
return icon->mPath;
|
||||
}
|
||||
|
||||
82
Engine/source/gui/worldEditor/editorIconRegistry.h
Normal file
82
Engine/source/gui/worldEditor/editorIconRegistry.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _EDITORICONREGISTRY_H_
|
||||
#define _EDITORICONREGISTRY_H_
|
||||
|
||||
#ifndef _GFXTEXTUREHANDLE_H_
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
#endif
|
||||
#ifndef _TDICTIONARY_H_
|
||||
#include "core/util/tDictionary.h"
|
||||
#endif
|
||||
|
||||
class SimObject;
|
||||
class AbstractClassRep;
|
||||
|
||||
|
||||
/// This class is used to find the correct icon file
|
||||
/// path for different SimObject class types. It is
|
||||
/// typically used by the editors.
|
||||
class EditorIconRegistry
|
||||
{
|
||||
public:
|
||||
|
||||
EditorIconRegistry();
|
||||
~EditorIconRegistry();
|
||||
|
||||
/// Loops thru all the AbstractClassReps looking for icons in the path.
|
||||
void loadFromPath( const String &path, bool overwrite );
|
||||
|
||||
/// Adds a single icon to the registry.
|
||||
void add( const String &className, const String &imageFile, bool overwrite );
|
||||
|
||||
/// Clears all the icons from the registry.
|
||||
void clear();
|
||||
|
||||
/// Looks up an icon given an AbstractClassRep.
|
||||
/// Other findIcon methods redirect to this.
|
||||
GFXTexHandle findIcon( AbstractClassRep *classRep );
|
||||
|
||||
/// Looks up an icon given a SimObject.
|
||||
GFXTexHandle findIcon( const SimObject *object );
|
||||
|
||||
/// Looks up an icon given a className.
|
||||
GFXTexHandle findIcon( const char *className );
|
||||
|
||||
/// Returns true if an icon is defined this object's class.
|
||||
/// Does not recurse up the class hierarchy.
|
||||
bool hasIconNoRecurse( const SimObject *object );
|
||||
|
||||
protected:
|
||||
|
||||
typedef HashTable<StringNoCase,GFXTexHandle> IconMap;
|
||||
IconMap mIcons;
|
||||
|
||||
/// The default icon returned when no matching icon is found.
|
||||
GFXTexHandle mDefaultIcon;
|
||||
};
|
||||
|
||||
/// The global registry of editor icons.
|
||||
extern EditorIconRegistry gEditorIcons;
|
||||
|
||||
#endif // _EDITORICONREGISTRY_H_
|
||||
2021
Engine/source/gui/worldEditor/gizmo.cpp
Normal file
2021
Engine/source/gui/worldEditor/gizmo.cpp
Normal file
File diff suppressed because it is too large
Load diff
418
Engine/source/gui/worldEditor/gizmo.h
Normal file
418
Engine/source/gui/worldEditor/gizmo.h
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GIZMO_H_
|
||||
#define _GIZMO_H_
|
||||
|
||||
#ifndef _SIMBASE_H_
|
||||
#include "console/simBase.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MATHUTILS_H_
|
||||
#include "math/mathUtils.h"
|
||||
#endif
|
||||
|
||||
#ifndef _DYNAMIC_CONSOLETYPES_H_
|
||||
#include "console/dynamicTypes.h"
|
||||
#endif
|
||||
|
||||
|
||||
enum GizmoMode
|
||||
{
|
||||
NoneMode = 0,
|
||||
MoveMode, // 1
|
||||
RotateMode, // 2
|
||||
ScaleMode, // 3
|
||||
ModeEnumCount
|
||||
};
|
||||
|
||||
enum GizmoAlignment
|
||||
{
|
||||
World = 0,
|
||||
Object,
|
||||
AlignEnumCount
|
||||
};
|
||||
|
||||
DefineEnumType( GizmoMode );
|
||||
DefineEnumType( GizmoAlignment );
|
||||
|
||||
|
||||
//
|
||||
class GizmoProfile : public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
|
||||
public:
|
||||
|
||||
GizmoProfile();
|
||||
virtual ~GizmoProfile() {}
|
||||
|
||||
DECLARE_CONOBJECT( GizmoProfile );
|
||||
|
||||
virtual bool onAdd();
|
||||
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
|
||||
/// Set flags to default values.
|
||||
void restoreDefaultState();
|
||||
|
||||
// Data Fields
|
||||
|
||||
GizmoMode mode;
|
||||
GizmoAlignment alignment;
|
||||
|
||||
F32 rotateScalar;
|
||||
F32 scaleScalar;
|
||||
U32 screenLen;
|
||||
ColorI axisColors[3];
|
||||
ColorI activeColor;
|
||||
ColorI inActiveColor;
|
||||
ColorI centroidColor;
|
||||
ColorI centroidHighlightColor;
|
||||
Resource<GFont> font;
|
||||
|
||||
bool snapToGrid;
|
||||
F32 scaleSnap;
|
||||
bool allowSnapScale;
|
||||
F32 rotationSnap;
|
||||
bool allowSnapRotations;
|
||||
|
||||
bool renderWhenUsed;
|
||||
bool renderInfoText;
|
||||
|
||||
Point3F gridSize;
|
||||
bool renderPlane;
|
||||
bool renderPlaneHashes;
|
||||
ColorI gridColor;
|
||||
F32 planeDim;
|
||||
bool renderSolid;
|
||||
|
||||
/// Whether to render a transparent grid overlay when using the move gizmo.
|
||||
bool renderMoveGrid;
|
||||
|
||||
enum Flags {
|
||||
CanRotate = 1 << 0, // 0
|
||||
CanRotateX = 1 << 1,
|
||||
CanRotateY = 1 << 2,
|
||||
CanRotateZ = 1 << 3,
|
||||
CanRotateScreen = 1 << 4,
|
||||
CanRotateUniform = 1 << 5,
|
||||
CanScale = 1 << 6,
|
||||
CanScaleX = 1 << 7,
|
||||
CanScaleY = 1 << 8,
|
||||
CanScaleZ = 1 << 9,
|
||||
CanScaleUniform = 1 << 10,
|
||||
CanTranslate = 1 << 11,
|
||||
CanTranslateX = 1 << 12,
|
||||
CanTranslateY = 1 << 13,
|
||||
CanTranslateZ = 1 << 14,
|
||||
CanTranslateUniform = 1 << 15,
|
||||
PlanarHandlesOn = 1 << 16
|
||||
};
|
||||
|
||||
S32 flags;
|
||||
|
||||
bool hideDisabledAxes;
|
||||
|
||||
bool allAxesScaleUniform;
|
||||
};
|
||||
|
||||
|
||||
// This class contains code for rendering and manipulating a 3D gizmo, it
|
||||
// is usually used as a helper within a TSEdit-derived control.
|
||||
//
|
||||
// The Gizmo has a MatrixF transform and Point3F scale on which it will
|
||||
// operate by passing it Gui3DMouseEvent(s).
|
||||
//
|
||||
// The idea is to set the Gizmo transform/scale to that of another 3D object
|
||||
// which is being manipulated, pass mouse events into the Gizmo, read the
|
||||
// new transform/scale out, and set it to onto the object.
|
||||
// And of course the Gizmo can be rendered.
|
||||
//
|
||||
// Gizmo derives from SimObject only because this allows its properties
|
||||
// to be initialized directly from script via fields.
|
||||
|
||||
class Gizmo : public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
|
||||
friend class WorldEditor;
|
||||
|
||||
public:
|
||||
|
||||
enum Selection {
|
||||
None = -1,
|
||||
Axis_X = 0,
|
||||
Axis_Y = 1,
|
||||
Axis_Z = 2,
|
||||
Plane_XY = 3, // Normal = Axis_Z
|
||||
Plane_XZ = 4, // Normal = Axis_Y
|
||||
Plane_YZ = 5, // Normal = Axis_X
|
||||
Centroid = 6,
|
||||
Custom1 = 7, // screen-aligned rotation
|
||||
Custom2 = 8
|
||||
};
|
||||
|
||||
Gizmo();
|
||||
~Gizmo();
|
||||
|
||||
DECLARE_CONOBJECT( Gizmo );
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
static void initPersistFields();
|
||||
|
||||
// Mutators
|
||||
void set( const MatrixF &objMat, const Point3F &worldPos, const Point3F &objScale );
|
||||
void setProfile( GizmoProfile *profile )
|
||||
{
|
||||
AssertFatal( profile != NULL, "NULL passed to Gizmo::setProfile - Gizmo must always have a profile!" );
|
||||
mProfile = profile;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
GizmoProfile* getProfile() { return mProfile; }
|
||||
|
||||
GizmoMode getMode() const { return mCurrentMode; }
|
||||
|
||||
GizmoAlignment getAlignment() const { return mCurrentAlignment; }
|
||||
|
||||
/// Returns current object to world transform of the object being manipulated.
|
||||
const MatrixF& getTransform() const { return mCurrentTransform; }
|
||||
|
||||
Point3F getPosition() const { return mCurrentTransform.getPosition(); }
|
||||
|
||||
const Point3F& getScale() const { return mScale; }
|
||||
|
||||
|
||||
// Returns change in position in last call to on3DMouseDragged.
|
||||
const Point3F& getOffset() const { return mDeltaPos; }
|
||||
|
||||
// Returns change is position since on3DMouseDown.
|
||||
const Point3F& getTotalOffset() const { return mDeltaTotalPos; }
|
||||
|
||||
const Point3F& getDeltaScale() const { return mDeltaScale; }
|
||||
|
||||
const Point3F& getDeltaTotalScale() const { return mDeltaTotalScale; }
|
||||
|
||||
const Point3F& getDeltaRot() const { return mDeltaRot; }
|
||||
|
||||
const Point3F& getDeltaTotalRot() const { return mDeltaTotalRot; }
|
||||
|
||||
/// Set whether to render the grid plane.
|
||||
void setGridPlaneEnabled( bool value ) { mGridPlaneEnabled = value; }
|
||||
|
||||
/// Set whether to a transparent grid overlay when using the move gizmo.
|
||||
void setMoveGridEnabled( bool value ) { mMoveGridEnabled = value; }
|
||||
|
||||
/// Set the size of the move grid along one dimension. The total size of the
|
||||
/// move grid is @a value * @a value.
|
||||
void setMoveGridSize( F32 value ) { mMoveGridSize = value; }
|
||||
|
||||
/// Set the spacing between grid lines on the move grid.
|
||||
void setMoveGridSpacing( F32 value ) { mMoveGridSpacing = value; }
|
||||
|
||||
// Gizmo Interface methods...
|
||||
|
||||
// Set the current highlight mode on the gizmo's centroid handle
|
||||
void setCentroidHandleHighlight( bool state ) { mHighlightCentroidHandle = state; }
|
||||
|
||||
// Must be called before on3DMouseDragged to save state
|
||||
void on3DMouseDown( const Gui3DMouseEvent &event );
|
||||
|
||||
// So Gizmo knows the current mouse button state.
|
||||
void on3DMouseUp( const Gui3DMouseEvent &event );
|
||||
|
||||
// Test Gizmo for collisions and set the Gizmo Selection (the part under the cursor)
|
||||
void on3DMouseMove( const Gui3DMouseEvent &event );
|
||||
|
||||
// Make changes to the Gizmo transform/scale (depending on mode)
|
||||
void on3DMouseDragged( const Gui3DMouseEvent &event );
|
||||
|
||||
// Returns an enum describing the part of the Gizmo that is Selected
|
||||
// ( under the cursor ). This should be called AFTER calling onMouseMove
|
||||
// or collideAxisGizmo
|
||||
//
|
||||
// -1 None
|
||||
// 0 Axis_X
|
||||
// 1 Axis_Y
|
||||
// 2 Axis_Z
|
||||
// 3 Plane_XY
|
||||
// 4 Plane_XZ
|
||||
// 5 Plane_YZ
|
||||
Selection getSelection();
|
||||
void setSelection( Selection sel ) { mSelectionIdx = sel; }
|
||||
|
||||
// Returns the object space vector corresponding to a Selection.
|
||||
Point3F selectionToAxisVector( Selection axis );
|
||||
|
||||
// These provide the user an easy way to check if the Gizmo's transform
|
||||
// or scale have changed by calling markClean prior to calling
|
||||
// on3DMouseDragged, and calling isDirty after.
|
||||
bool isDirty() { return mDirty; }
|
||||
void markClean() { mDirty = false; }
|
||||
|
||||
// Renders the 3D Gizmo in the scene, GFX must be setup for proper
|
||||
// 3D rendering before calling this!
|
||||
// Calling this will change the GFXStateBlock!
|
||||
void renderGizmo( const MatrixF &cameraTransform, F32 camerFOV = 1.5f );
|
||||
|
||||
// Renders text associated with the Gizmo, GFX must be setup for proper
|
||||
// 2D rendering before calling this!
|
||||
// Calling this will change the GFXStateBlock!
|
||||
void renderText( const RectI &viewPort, const MatrixF &modelView, const MatrixF &projection );
|
||||
|
||||
// Returns true if the mouse event collides with any part of the Gizmo
|
||||
// and sets the Gizmo's current Selection.
|
||||
// You can call this or on3DMouseMove, they are identical
|
||||
bool collideAxisGizmo( const Gui3DMouseEvent & event );
|
||||
|
||||
protected:
|
||||
|
||||
void _calcAxisInfo();
|
||||
void _setStateBlock();
|
||||
void _renderPrimaryAxis();
|
||||
void _renderAxisArrows();
|
||||
void _renderAxisBoxes();
|
||||
void _renderAxisCircles();
|
||||
void _renderAxisText();
|
||||
void _renderPlane();
|
||||
Point3F _snapPoint( const Point3F &pnt ) const;
|
||||
F32 _snapFloat( const F32 &val, const F32 &snap ) const;
|
||||
GizmoAlignment _filteredAlignment();
|
||||
void _updateState( bool collideGizmo = true );
|
||||
void _updateEnabledAxices();
|
||||
|
||||
F32 _getProjectionLength( F32 dist ) const
|
||||
{
|
||||
if( GFX->isFrustumOrtho() )
|
||||
return mLastCameraFOV * dist * 0.002f;
|
||||
else
|
||||
{
|
||||
Point3F dir = mOrigin - mCameraPos;
|
||||
return ( dist * dir.len() ) / mLastWorldToScreenScale.y;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
GizmoProfile *mProfile;
|
||||
|
||||
MatrixF mObjectMat;
|
||||
MatrixF mObjectMatInv;
|
||||
MatrixF mTransform;
|
||||
MatrixF mCurrentTransform;
|
||||
MatrixF mSavedTransform;
|
||||
|
||||
GizmoAlignment mCurrentAlignment;
|
||||
GizmoMode mCurrentMode;
|
||||
|
||||
MatrixF mCameraMat;
|
||||
Point3F mCameraPos;
|
||||
|
||||
Point3F mScale;
|
||||
Point3F mSavedScale;
|
||||
Point3F mDeltaScale;
|
||||
Point3F mDeltaTotalScale;
|
||||
Point3F mLastScale;
|
||||
Point3F mScaleInfluence;
|
||||
|
||||
EulerF mRot;
|
||||
EulerF mSavedRot;
|
||||
EulerF mDeltaRot;
|
||||
EulerF mDeltaTotalRot;
|
||||
F32 mDeltaAngle;
|
||||
F32 mLastAngle;
|
||||
Point2I mMouseDownPos;
|
||||
Point3F mMouseDownProjPnt;
|
||||
Point3F mDeltaPos;
|
||||
Point3F mDeltaTotalPos;
|
||||
Point3F mProjPnt;
|
||||
Point3F mOrigin;
|
||||
Point3F mProjAxisVector[3];
|
||||
F32 mProjLen;
|
||||
S32 mSelectionIdx;
|
||||
bool mDirty;
|
||||
Gui3DMouseEvent mLastMouseEvent;
|
||||
GFXStateBlockRef mStateBlock;
|
||||
GFXStateBlockRef mSolidStateBlock;
|
||||
|
||||
PlaneF mMouseCollidePlane;
|
||||
MathUtils::Line mMouseCollideLine;
|
||||
|
||||
bool mMouseDown;
|
||||
|
||||
F32 mSign;
|
||||
|
||||
/// If false, don't render the grid plane even if it is enabled in the profile.
|
||||
bool mGridPlaneEnabled;
|
||||
|
||||
/// If false, don't render a transparent grid overlay when using the move gizmo.
|
||||
bool mMoveGridEnabled;
|
||||
|
||||
/// Size of the move grid along one dimension.
|
||||
F32 mMoveGridSize;
|
||||
|
||||
/// Spacing between grid lines on the move grid.
|
||||
U32 mMoveGridSpacing;
|
||||
|
||||
bool mAxisEnabled[3];
|
||||
bool mUniformHandleEnabled;
|
||||
bool mScreenRotateHandleEnabled;
|
||||
|
||||
// Used to override rendering of handles.
|
||||
bool mHighlightCentroidHandle;
|
||||
bool mHighlightAll;
|
||||
|
||||
// Initialized in renderGizmo and saved for later use when projecting
|
||||
// to screen space for selection testing.
|
||||
MatrixF mLastWorldMat;
|
||||
MatrixF mLastProjMat;
|
||||
RectI mLastViewport;
|
||||
Point2F mLastWorldToScreenScale;
|
||||
F32 mLastCameraFOV;
|
||||
|
||||
// Screenspace cursor collision information used in rotation mode.
|
||||
Point3F mElipseCursorCollidePntSS;
|
||||
Point3F mElipseCursorCollideVecSS;
|
||||
|
||||
/// A large hard coded distance used to test
|
||||
/// gizmo axis selection.
|
||||
static F32 smProjectDistance;
|
||||
};
|
||||
|
||||
#endif // _GIZMO_H_
|
||||
2214
Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp
Normal file
2214
Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
294
Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.h
Normal file
294
Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.h
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUICONVEXSHAPEEDITORCTRL_H_
|
||||
#define _GUICONVEXSHAPEEDITORCTRL_H_
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#include "gui/worldEditor/editTSCtrl.h"
|
||||
#endif
|
||||
#ifndef _UNDO_H_
|
||||
#include "util/undo.h"
|
||||
#endif
|
||||
#ifndef _GIZMO_H_
|
||||
#include "gui/worldEditor/gizmo.h"
|
||||
#endif
|
||||
#ifndef _CONVEXSHAPE_H_
|
||||
#include "T3D/convexShape.h"
|
||||
#endif
|
||||
|
||||
class GameBase;
|
||||
class GuiConvexEditorUndoAction;
|
||||
class ConvexEditorTool;
|
||||
class ConvexEditorCreateTool;
|
||||
|
||||
class GuiConvexEditorCtrl : public EditTSCtrl
|
||||
{
|
||||
typedef EditTSCtrl Parent;
|
||||
|
||||
friend class GuiConvexEditorUndoAction;
|
||||
|
||||
public:
|
||||
|
||||
GuiConvexEditorCtrl();
|
||||
virtual ~GuiConvexEditorCtrl();
|
||||
|
||||
DECLARE_CONOBJECT( GuiConvexEditorCtrl );
|
||||
|
||||
// SimObject
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
static void initPersistFields();
|
||||
|
||||
// GuiControl
|
||||
virtual bool onWake();
|
||||
virtual void onSleep();
|
||||
virtual void setVisible(bool value);
|
||||
|
||||
// EditTSCtrl
|
||||
bool onKeyDown( const GuiEvent &event );
|
||||
bool onKeyUp( const GuiEvent &event );
|
||||
void get3DCursor( GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event_ );
|
||||
void on3DMouseDown( const Gui3DMouseEvent &event );
|
||||
void on3DMouseUp( const Gui3DMouseEvent &event );
|
||||
void on3DMouseMove( const Gui3DMouseEvent &event );
|
||||
void on3DMouseDragged( const Gui3DMouseEvent &event );
|
||||
void on3DMouseEnter( const Gui3DMouseEvent &event );
|
||||
void on3DMouseLeave( const Gui3DMouseEvent &event );
|
||||
void on3DRightMouseDown( const Gui3DMouseEvent &event );
|
||||
void on3DRightMouseUp( const Gui3DMouseEvent &event );
|
||||
void renderScene(const RectI & updateRect);
|
||||
void updateGizmo();
|
||||
|
||||
void updateShape( ConvexShape *shape, S32 offsetFace = -1 );
|
||||
static void synchClientObject( const ConvexShape *serverConvex );
|
||||
|
||||
void updateGizmoPos();
|
||||
|
||||
bool setActiveTool( ConvexEditorTool *tool );
|
||||
|
||||
void drawFacePlane( ConvexShape *shape, S32 faceId );
|
||||
|
||||
void scaleFace( ConvexShape *shape, S32 faceId, Point3F scale );
|
||||
|
||||
void translateFace( ConvexShape *shape, S32 faceId, const Point3F &displace );
|
||||
|
||||
void updateModifiedFace( ConvexShape *shape, S32 faceId );
|
||||
|
||||
bool isShapeValid( ConvexShape *shape );
|
||||
|
||||
void setupShape( ConvexShape *shape );
|
||||
|
||||
void setPivotPos( ConvexShape *shape, S32 faceId, const Gui3DMouseEvent &event );
|
||||
|
||||
void cleanMatrix( MatrixF &mat );
|
||||
|
||||
S32 getEdgeByPoints( ConvexShape *shape, S32 faceId, S32 pId0, S32 pId1 );
|
||||
|
||||
bool getEdgesTouchingPoint( ConvexShape *shape, S32 faceId, S32 pId, Vector< U32 > &edgeIdxList, S32 excludeEdge = -1 );
|
||||
|
||||
void hollowSelection();
|
||||
void hollowShape( ConvexShape *shape, F32 thickness );
|
||||
|
||||
void recenterSelection();
|
||||
void recenterShape( ConvexShape *shape );
|
||||
void dropSelectionAtScreenCenter();
|
||||
void splitSelectedFace();
|
||||
|
||||
/// Interface with Tools.
|
||||
/// @{
|
||||
|
||||
MatrixF getCameraMat() const { return mLastCameraQuery.cameraMatrix; }
|
||||
|
||||
enum UndoType
|
||||
{
|
||||
ModifyShape = 0,
|
||||
CreateShape,
|
||||
DeleteShape,
|
||||
HollowShape
|
||||
};
|
||||
|
||||
void submitUndo( UndoType type, ConvexShape *shape );
|
||||
void submitUndo( UndoType type, const Vector< ConvexShape* > &shape );
|
||||
|
||||
/// @}
|
||||
|
||||
bool hasSelection() const;
|
||||
void clearSelection();
|
||||
void setSelection( ConvexShape *shape, S32 faceId );
|
||||
void handleDeselect();
|
||||
bool handleEscape();
|
||||
bool handleDelete();
|
||||
bool handleTab();
|
||||
public:
|
||||
|
||||
StringTableEntry mMaterialName;
|
||||
protected:
|
||||
|
||||
void _prepRenderImage( SceneManager* sceneGraph, const SceneRenderState* sceneState );
|
||||
void _renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *matInst );
|
||||
|
||||
bool _cursorCast( const Gui3DMouseEvent &event, ConvexShape **hitShape, S32 *hitFace );
|
||||
static bool _cursorCastCallback( RayInfo* ri );
|
||||
|
||||
protected:
|
||||
|
||||
bool mIsDirty;
|
||||
|
||||
U32 mSavedGizmoFlags;
|
||||
|
||||
/// The selected ConvexShape.
|
||||
SimObjectPtr<ConvexShape> mConvexSEL;
|
||||
|
||||
/// The highlighted ConvexShape ( mouse over ).
|
||||
SimObjectPtr<ConvexShape> mConvexHL;
|
||||
|
||||
S32 mFaceSEL;
|
||||
S32 mFaceHL;
|
||||
|
||||
MatrixF mFaceSavedXfm;
|
||||
|
||||
ConvexShape::Geometry mSavedGeometry;
|
||||
Vector< MatrixF > mSavedSurfaces;
|
||||
Vector< MatrixF > mLastValidShape;
|
||||
|
||||
Point3F mSavedPivotPos;
|
||||
|
||||
bool mCtrlDown;
|
||||
bool mSavedUndo;
|
||||
bool mHasGeometry;
|
||||
bool mDragging;
|
||||
bool mMouseDown;
|
||||
bool mHasCopied;
|
||||
RayInfo mLastRayInfo;
|
||||
|
||||
Gui3DMouseEvent mMouseDownEvent;
|
||||
|
||||
Point3F mGizmoMatOffset;
|
||||
|
||||
Point3F mPivotPos;
|
||||
bool mUsingPivot;
|
||||
bool mSettingPivot;
|
||||
|
||||
UndoAction *mLastUndo;
|
||||
UndoManager *mUndoManager;
|
||||
|
||||
ConvexEditorTool *mActiveTool;
|
||||
ConvexEditorCreateTool *mCreateTool;
|
||||
};
|
||||
|
||||
class GuiConvexEditorUndoAction : public UndoAction
|
||||
{
|
||||
friend class GuiConvexEditorCtrl;
|
||||
public:
|
||||
|
||||
GuiConvexEditorUndoAction( const UTF8* actionName ) : UndoAction( actionName )
|
||||
{
|
||||
}
|
||||
|
||||
GuiConvexEditorCtrl *mEditor;
|
||||
|
||||
SimObjectId mObjId;
|
||||
|
||||
Vector< MatrixF > mSavedSurfaces;
|
||||
MatrixF mSavedObjToWorld;
|
||||
Point3F mSavedScale;
|
||||
|
||||
virtual void undo();
|
||||
virtual void redo() { undo(); }
|
||||
};
|
||||
|
||||
class ConvexEditorTool
|
||||
{
|
||||
public:
|
||||
|
||||
enum EventResult
|
||||
{
|
||||
NotHandled = 0,
|
||||
Handled = 1,
|
||||
Done = 2,
|
||||
Failed = 3
|
||||
};
|
||||
|
||||
ConvexEditorTool( GuiConvexEditorCtrl *editor )
|
||||
: mEditor( editor ), mDone( false ) {}
|
||||
virtual ~ConvexEditorTool() {}
|
||||
|
||||
virtual void onActivated( ConvexEditorTool *prevTool ) {}
|
||||
virtual void onDeactivated( ConvexEditorTool *newTool ) {}
|
||||
|
||||
virtual EventResult onKeyDown( const GuiEvent &event ) { return NotHandled; }
|
||||
virtual EventResult on3DMouseDown( const Gui3DMouseEvent &event ) { return NotHandled; }
|
||||
virtual EventResult on3DMouseUp( const Gui3DMouseEvent &event ) { return NotHandled; }
|
||||
virtual EventResult on3DMouseMove( const Gui3DMouseEvent &event ) { return NotHandled; }
|
||||
virtual EventResult on3DMouseDragged( const Gui3DMouseEvent &event ) { return NotHandled; }
|
||||
virtual EventResult on3DMouseEnter( const Gui3DMouseEvent &event ) { return NotHandled; }
|
||||
virtual EventResult on3DMouseLeave( const Gui3DMouseEvent &event ) { return NotHandled; }
|
||||
virtual EventResult on3DRightMouseDown( const Gui3DMouseEvent &event ) { return NotHandled; }
|
||||
virtual EventResult on3DRightMouseUp( const Gui3DMouseEvent &event ) { return NotHandled; }
|
||||
|
||||
virtual void renderScene(const RectI & updateRect) {}
|
||||
virtual void render2D() {}
|
||||
|
||||
bool isDone() { return mDone; }
|
||||
|
||||
public:
|
||||
GuiConvexEditorCtrl *mEditor;
|
||||
protected:
|
||||
bool mDone;
|
||||
};
|
||||
|
||||
class ConvexEditorCreateTool : public ConvexEditorTool
|
||||
{
|
||||
typedef ConvexEditorTool Parent;
|
||||
public:
|
||||
ConvexEditorCreateTool( GuiConvexEditorCtrl *editor );
|
||||
virtual ~ConvexEditorCreateTool() {}
|
||||
|
||||
virtual void onActivated( ConvexEditorTool *prevTool );
|
||||
virtual void onDeactivated( ConvexEditorTool *newTool );
|
||||
|
||||
virtual EventResult on3DMouseDown( const Gui3DMouseEvent &event );
|
||||
virtual EventResult on3DMouseUp( const Gui3DMouseEvent &event );
|
||||
virtual EventResult on3DMouseMove( const Gui3DMouseEvent &event );
|
||||
virtual EventResult on3DMouseDragged( const Gui3DMouseEvent &event );
|
||||
|
||||
virtual void renderScene(const RectI & updateRect);
|
||||
|
||||
ConvexShape* extrudeShapeFromFace( ConvexShape *shape, S32 face );
|
||||
|
||||
protected:
|
||||
|
||||
S32 mStage;
|
||||
ConvexShape *mNewConvex;
|
||||
PlaneF mCreatePlane;
|
||||
|
||||
MatrixF mTransform;
|
||||
Point3F mStart;
|
||||
Point3F mEnd;
|
||||
Point3F mPlaneSizes;
|
||||
};
|
||||
|
||||
#endif // _GUICONVEXSHAPEEDITORCTRL_H_
|
||||
|
||||
|
||||
|
||||
1244
Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp
Normal file
1244
Engine/source/gui/worldEditor/guiDecalEditorCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
231
Engine/source/gui/worldEditor/guiDecalEditorCtrl.h
Normal file
231
Engine/source/gui/worldEditor/guiDecalEditorCtrl.h
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIDECALEDITORCTRL_H_
|
||||
#define _GUIDECALEDITORCTRL_H_
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#include "gui/worldEditor/editTSCtrl.h"
|
||||
#endif
|
||||
#ifndef _UNDO_H_
|
||||
#include "util/undo.h"
|
||||
#endif
|
||||
#ifndef _DECALINSTANCE_H_
|
||||
#include "T3D/decal/decalInstance.h"
|
||||
#endif
|
||||
|
||||
class GameBase;
|
||||
class Gizmo;
|
||||
struct RayInfo;
|
||||
class DecalInstance;
|
||||
class DecalData;
|
||||
|
||||
class GuiDecalEditorCtrl : public EditTSCtrl
|
||||
{
|
||||
typedef EditTSCtrl Parent;
|
||||
|
||||
public:
|
||||
|
||||
GuiDecalEditorCtrl();
|
||||
~GuiDecalEditorCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiDecalEditorCtrl);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
void onEditorDisable();
|
||||
|
||||
// GuiControl
|
||||
virtual bool onWake();
|
||||
virtual void onSleep();
|
||||
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
// EditTSCtrl
|
||||
void get3DCursor( GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event_ );
|
||||
void on3DMouseDown(const Gui3DMouseEvent & event);
|
||||
void on3DMouseUp(const Gui3DMouseEvent & event);
|
||||
void on3DMouseMove(const Gui3DMouseEvent & event);
|
||||
void on3DMouseDragged(const Gui3DMouseEvent & event);
|
||||
void on3DMouseEnter(const Gui3DMouseEvent & event);
|
||||
void on3DMouseLeave(const Gui3DMouseEvent & event);
|
||||
void on3DRightMouseDown(const Gui3DMouseEvent & event);
|
||||
void on3DRightMouseUp(const Gui3DMouseEvent & event);
|
||||
void updateGuiInfo();
|
||||
void renderScene(const RectI & updateRect);
|
||||
void renderGui(Point2I offset, const RectI &updateRect);
|
||||
|
||||
/// Find clicked point on "static collision" objects.
|
||||
bool getRayInfo( const Gui3DMouseEvent &event, RayInfo *rInfo );
|
||||
|
||||
void selectDecal( DecalInstance *inst );
|
||||
void deleteSelectedDecal();
|
||||
void deleteDecalDatablock( String lookupName );
|
||||
void retargetDecalDatablock( String dbFrom, String dbTo );
|
||||
void setMode( String mode, bool sourceShortcut );
|
||||
|
||||
void forceRedraw( DecalInstance * decalInstance );
|
||||
void setGizmoFocus( DecalInstance * decalInstance );
|
||||
|
||||
public:
|
||||
|
||||
String mMode;
|
||||
DecalInstance *mSELDecal;
|
||||
DecalInstance *mHLDecal;
|
||||
|
||||
static bool smRenderDecalPixelSize;
|
||||
|
||||
protected:
|
||||
|
||||
bool mPerformedDragCopy;
|
||||
|
||||
DecalData *mCurrentDecalData;
|
||||
|
||||
Vector<Point3F> mSELEdgeVerts;
|
||||
Vector<Point3F> mHLEdgeVerts;
|
||||
|
||||
void _renderDecalEdge( const Vector<Point3F> &verts, const ColorI &color );
|
||||
};
|
||||
|
||||
//Decal Instance Create Undo Actions
|
||||
class DICreateUndoAction : public UndoAction
|
||||
{
|
||||
typedef UndoAction Parent;
|
||||
|
||||
public:
|
||||
GuiDecalEditorCtrl *mEditor;
|
||||
|
||||
protected:
|
||||
|
||||
/// The captured object state.
|
||||
DecalInstance mDecalInstance;
|
||||
S32 mDatablockId;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT( DICreateUndoAction );
|
||||
static void initPersistFields();
|
||||
|
||||
DICreateUndoAction( const UTF8* actionName = "Create Decal " );
|
||||
virtual ~DICreateUndoAction();
|
||||
|
||||
void addDecal( DecalInstance decal );
|
||||
|
||||
// UndoAction
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
};
|
||||
|
||||
//Decal Instance Delete Undo Actions
|
||||
class DIDeleteUndoAction : public UndoAction
|
||||
{
|
||||
typedef UndoAction Parent;
|
||||
|
||||
public:
|
||||
GuiDecalEditorCtrl *mEditor;
|
||||
|
||||
protected:
|
||||
|
||||
/// The captured object state.
|
||||
DecalInstance mDecalInstance;
|
||||
S32 mDatablockId;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT( DIDeleteUndoAction );
|
||||
static void initPersistFields();
|
||||
|
||||
DIDeleteUndoAction( const UTF8* actionName = "Delete Decal" );
|
||||
virtual ~DIDeleteUndoAction();
|
||||
|
||||
///
|
||||
void deleteDecal( DecalInstance decal );
|
||||
|
||||
// UndoAction
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
};
|
||||
|
||||
//Decal Datablock Delete Undo Actions
|
||||
class DBDeleteUndoAction : public UndoAction
|
||||
{
|
||||
typedef UndoAction Parent;
|
||||
|
||||
public:
|
||||
GuiDecalEditorCtrl *mEditor;
|
||||
S32 mDatablockId;
|
||||
|
||||
protected:
|
||||
|
||||
// The captured decalInstance states
|
||||
Vector<DecalInstance> mDecalInstanceVec;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT( DBDeleteUndoAction );
|
||||
static void initPersistFields();
|
||||
|
||||
DBDeleteUndoAction( const UTF8* actionName = "Delete Decal Datablock" );
|
||||
virtual ~DBDeleteUndoAction();
|
||||
|
||||
void deleteDecal( DecalInstance decal );
|
||||
|
||||
// UndoAction
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
};
|
||||
|
||||
//Decal Datablock Retarget Undo Actions
|
||||
class DBRetargetUndoAction : public UndoAction
|
||||
{
|
||||
typedef UndoAction Parent;
|
||||
|
||||
public:
|
||||
GuiDecalEditorCtrl *mEditor;
|
||||
S32 mDBFromId;
|
||||
S32 mDBToId;
|
||||
|
||||
protected:
|
||||
|
||||
// The captured decalInstance states
|
||||
Vector<DecalInstance*> mDecalInstanceVec;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT( DBRetargetUndoAction );
|
||||
static void initPersistFields();
|
||||
|
||||
DBRetargetUndoAction( const UTF8* actionName = "Retarget Decal Datablock" );
|
||||
virtual ~DBRetargetUndoAction();
|
||||
|
||||
void retargetDecal( DecalInstance* decal );
|
||||
|
||||
// UndoAction
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
};
|
||||
|
||||
#endif // _GUIDECALEDITORCTRL_H_
|
||||
|
||||
|
||||
|
||||
720
Engine/source/gui/worldEditor/guiMissionArea.cpp
Normal file
720
Engine/source/gui/worldEditor/guiMissionArea.cpp
Normal file
|
|
@ -0,0 +1,720 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/worldEditor/guiMissionArea.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "gfx/bitmap/gBitmap.h"
|
||||
#include "gui/3d/guiTSControl.h"
|
||||
#include "T3D/gameFunctions.h"
|
||||
#include "terrain/terrData.h"
|
||||
|
||||
namespace {
|
||||
F32 round_local(F32 val)
|
||||
{
|
||||
if(val >= 0.f)
|
||||
{
|
||||
F32 floor = mFloor(val);
|
||||
if((val - floor) >= 0.5f)
|
||||
return(floor + 1.f);
|
||||
return(floor);
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 ceil = mCeil(val);
|
||||
if((val - ceil) <= -0.5f)
|
||||
return(ceil - 1.f);
|
||||
return(ceil);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiMissionAreaCtrl);
|
||||
|
||||
ConsoleDocClass( GuiMissionAreaCtrl,
|
||||
"@brief Visual representation of Mission Area Editor.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
GuiMissionAreaCtrl::GuiMissionAreaCtrl()
|
||||
{
|
||||
mHandleBitmap = StringTable->EmptyString();
|
||||
mHandleTexture = NULL;
|
||||
mHandleTextureSize = Point2I::Zero;
|
||||
mHandleTextureHalfSize = Point2F::Zero;
|
||||
|
||||
mSquareBitmap = true;
|
||||
|
||||
mMissionArea = 0;
|
||||
mTerrainBlock = 0;
|
||||
|
||||
mMissionBoundsColor.set(255,0,0);
|
||||
mCameraColor.set(255,0,0);
|
||||
|
||||
mBlendStateBlock = NULL;
|
||||
mSolidStateBlock = NULL;
|
||||
|
||||
mLastHitMode = Handle_None;
|
||||
mSavedDrag = false;
|
||||
}
|
||||
|
||||
GuiMissionAreaCtrl::~GuiMissionAreaCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMissionAreaCtrl::initPersistFields()
|
||||
{
|
||||
addField( "squareBitmap", TypeBool, Offset(mSquareBitmap, GuiMissionAreaCtrl));
|
||||
|
||||
addField( "handleBitmap", TypeFilename, Offset( mHandleBitmap, GuiMissionAreaCtrl ),
|
||||
"Bitmap file for the mission area handles.\n");
|
||||
|
||||
addField( "missionBoundsColor", TypeColorI, Offset(mMissionBoundsColor, GuiMissionAreaCtrl));
|
||||
addField( "cameraColor", TypeColorI, Offset(mCameraColor, GuiMissionAreaCtrl));
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool GuiMissionAreaCtrl::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return(false);
|
||||
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setCullMode(GFXCullNone);
|
||||
desc.setZReadWrite(false);
|
||||
desc.setBlend(false, GFXBlendOne, GFXBlendZero);
|
||||
mSolidStateBlock = GFX->createStateBlock( desc );
|
||||
|
||||
desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
|
||||
mBlendStateBlock = GFX->createStateBlock( desc );
|
||||
|
||||
if (*mHandleBitmap)
|
||||
{
|
||||
mHandleTexture = GFXTexHandle( mHandleBitmap, &GFXDefaultPersistentProfile, avar("%s() - mHandleTexture (line %d)", __FUNCTION__, __LINE__) );
|
||||
mHandleTextureSize = Point2I( mHandleTexture->getWidth(), mHandleTexture->getHeight() );
|
||||
mHandleTextureHalfSize = Point2F(mHandleTextureSize.x, mHandleTextureSize.y) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mHandleTexture = NULL;
|
||||
mHandleTextureSize = Point2I::Zero;
|
||||
mHandleTextureHalfSize = Point2F::Zero;
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool GuiMissionAreaCtrl::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return(false);
|
||||
|
||||
//mMissionArea = const_cast<MissionArea*>(MissionArea::getServerObject());
|
||||
//if(!bool(mMissionArea))
|
||||
// Con::warnf(ConsoleLogEntry::General, "GuiMissionAreaCtrl::onWake: no MissionArea object.");
|
||||
|
||||
//mTerrainBlock = getTerrainObj();
|
||||
//if(!bool(mTerrainBlock))
|
||||
// Con::warnf(ConsoleLogEntry::General, "GuiMissionAreaCtrl::onWake: no TerrainBlock object.");
|
||||
|
||||
//if ( !bool(mMissionArea) || !bool(mTerrainBlock) )
|
||||
// return true;
|
||||
|
||||
updateTerrainBitmap();
|
||||
|
||||
// make sure mission area is clamped
|
||||
setArea(getArea());
|
||||
|
||||
//onUpdate();
|
||||
setActive(true);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::onSleep()
|
||||
{
|
||||
mTextureObject = NULL;
|
||||
mMissionArea = 0;
|
||||
mTerrainBlock = 0;
|
||||
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMissionAreaCtrl::onMouseUp(const GuiEvent & event)
|
||||
{
|
||||
if(!bool(mMissionArea))
|
||||
return;
|
||||
|
||||
RectI box;
|
||||
getScreenMissionArea(box);
|
||||
S32 hit = getHitHandles(event.mousePoint, box);
|
||||
|
||||
// set the current cursor
|
||||
//updateCursor(hit);
|
||||
mLastHitMode = hit;
|
||||
|
||||
if(mSavedDrag)
|
||||
{
|
||||
// Let the script get a chance at it.
|
||||
Con::executef( this, "onMissionAreaModified" );
|
||||
}
|
||||
mSavedDrag = false;
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::onMouseDown(const GuiEvent & event)
|
||||
{
|
||||
if(!bool(mMissionArea))
|
||||
return;
|
||||
|
||||
RectI box;
|
||||
getScreenMissionArea(box);
|
||||
|
||||
mLastHitMode = getHitHandles(event.mousePoint, box);
|
||||
//if(mLastHitMode == Handle_Middle)
|
||||
// setCursor(GrabCursor);
|
||||
mLastMousePoint = event.mousePoint;
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::onMouseMove(const GuiEvent & event)
|
||||
{
|
||||
if(!bool(mMissionArea))
|
||||
return;
|
||||
|
||||
RectI box;
|
||||
getScreenMissionArea(box);
|
||||
S32 hit = getHitHandles(event.mousePoint, box);
|
||||
|
||||
// set the current cursor...
|
||||
//updateCursor(hit);
|
||||
mLastHitMode = hit;
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::onMouseDragged(const GuiEvent & event)
|
||||
{
|
||||
if(!bool(mMissionArea))
|
||||
return;
|
||||
|
||||
if(mLastHitMode == Handle_None)
|
||||
return;
|
||||
|
||||
// If we haven't already saved,
|
||||
// save an undo action to get back to this state,
|
||||
// before we make any modifications.
|
||||
if ( !mSavedDrag )
|
||||
{
|
||||
submitUndo( "Modify Node" );
|
||||
mSavedDrag = true;
|
||||
}
|
||||
|
||||
RectI box;
|
||||
getScreenMissionArea(box);
|
||||
Point2I mouseDiff(event.mousePoint.x - mLastMousePoint.x,
|
||||
event.mousePoint.y - mLastMousePoint.y);
|
||||
|
||||
// what we drag'n?
|
||||
RectI area = getArea();
|
||||
Point2I wp = screenDeltaToWorldDelta(mouseDiff);
|
||||
|
||||
if (mLastHitMode == Handle_Middle)
|
||||
{
|
||||
area.point += wp;
|
||||
}
|
||||
|
||||
if (mLastHitMode & Handle_Left)
|
||||
{
|
||||
if ((area.extent.x - wp.x) >= 1)
|
||||
{
|
||||
area.point.x += wp.x;
|
||||
area.extent.x -= wp.x;
|
||||
}
|
||||
}
|
||||
|
||||
if (mLastHitMode & Handle_Right)
|
||||
{
|
||||
if ((area.extent.x + wp.x) >= 1)
|
||||
{
|
||||
area.extent.x += wp.x;
|
||||
}
|
||||
}
|
||||
|
||||
if (mLastHitMode & Handle_Bottom)
|
||||
{
|
||||
if ((area.extent.y - wp.y) >= 1)
|
||||
{
|
||||
area.point.y += wp.y;
|
||||
area.extent.y -= wp.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (mLastHitMode & Handle_Top)
|
||||
{
|
||||
if ((area.extent.y + wp.y) >= 1)
|
||||
{
|
||||
area.extent.y += wp.y;
|
||||
}
|
||||
}
|
||||
|
||||
setArea(area);
|
||||
mLastMousePoint = event.mousePoint;
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::onMouseEnter(const GuiEvent &)
|
||||
{
|
||||
mLastHitMode = Handle_None;
|
||||
//setCursor(DefaultCursor);
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::onMouseLeave(const GuiEvent &)
|
||||
{
|
||||
mLastHitMode = Handle_None;
|
||||
//setCursor(DefaultCursor);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMissionAreaCtrl::submitUndo( const UTF8 *name )
|
||||
{
|
||||
// Grab the mission editor undo manager.
|
||||
UndoManager *undoMan = NULL;
|
||||
if ( !Sim::findObject( "EUndoManager", undoMan ) )
|
||||
{
|
||||
Con::errorf( "GuiRiverEditorCtrl::submitUndo() - EUndoManager not found!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup the action.
|
||||
GuiMissionAreaUndoAction *action = new GuiMissionAreaUndoAction( name );
|
||||
|
||||
action->mMissionAreaEditor = this;
|
||||
|
||||
action->mObjId = mMissionArea->getId();
|
||||
action->mArea = mMissionArea->getArea();
|
||||
|
||||
undoMan->addAction( action );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMissionAreaCtrl::updateTerrain()
|
||||
{
|
||||
mTerrainBlock = getTerrainObj();
|
||||
updateTerrainBitmap();
|
||||
}
|
||||
|
||||
TerrainBlock * GuiMissionAreaCtrl::getTerrainObj()
|
||||
{
|
||||
SimSet * scopeAlwaysSet = Sim::getGhostAlwaysSet();
|
||||
for(SimSet::iterator itr = scopeAlwaysSet->begin(); itr != scopeAlwaysSet->end(); itr++)
|
||||
{
|
||||
TerrainBlock * terrain = dynamic_cast<TerrainBlock*>(*itr);
|
||||
if(terrain)
|
||||
return(terrain);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::updateTerrainBitmap()
|
||||
{
|
||||
GBitmap * bitmap = createTerrainBitmap();
|
||||
if( bitmap )
|
||||
setBitmapHandle( GFXTexHandle( bitmap, &GFXDefaultGUIProfile, true, String("Terrain Bitmap Update") ) );
|
||||
else
|
||||
setBitmap( "" );
|
||||
}
|
||||
|
||||
GBitmap * GuiMissionAreaCtrl::createTerrainBitmap()
|
||||
{
|
||||
if(!mTerrainBlock)
|
||||
return NULL;
|
||||
|
||||
GBitmap * bitmap = new GBitmap(mTerrainBlock->getBlockSize(), mTerrainBlock->getBlockSize(), false, GFXFormatR8G8B8 );
|
||||
|
||||
if(!bitmap)
|
||||
return NULL;
|
||||
|
||||
// get the min/max
|
||||
F32 min, max;
|
||||
mTerrainBlock->getMinMaxHeight(&min, &max);
|
||||
|
||||
F32 diff = max - min;
|
||||
F32 colRange = 255.0f / diff;
|
||||
|
||||
// This method allocates it's bitmap above, and does all assignment
|
||||
// in the following loop. It is not subject to 24-bit -> 32-bit conversion
|
||||
// problems, because the texture handle creation is where the conversion would
|
||||
// occur, if it occurs. Since the data in the texture is never read back, and
|
||||
// the bitmap is deleted after texture-upload, this is not a problem.
|
||||
for(S32 y = 0; y < mTerrainBlock->getBlockSize() ; y++)
|
||||
{
|
||||
for(S32 x = 0; x < mTerrainBlock->getBlockSize(); x++)
|
||||
{
|
||||
F32 height;
|
||||
height = mTerrainBlock->getHeight(Point2I(x, y));
|
||||
|
||||
U8 col = U8((height - min) * colRange);
|
||||
ColorI color(col, col, col);
|
||||
bitmap->setColor(x, y, color);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return(bitmap);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMissionAreaCtrl::setMissionArea( MissionArea* area )
|
||||
{
|
||||
mMissionArea = area;
|
||||
if( mMissionArea )
|
||||
{
|
||||
setArea(getArea());
|
||||
}
|
||||
}
|
||||
|
||||
const RectI & GuiMissionAreaCtrl::getArea()
|
||||
{
|
||||
if( !bool(mMissionArea) )
|
||||
return(MissionArea::smMissionArea);
|
||||
|
||||
return(mMissionArea->getArea());
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::setArea(const RectI & area)
|
||||
{
|
||||
if( bool(mMissionArea) )
|
||||
{
|
||||
mMissionArea->setArea(area);
|
||||
mMissionArea->inspectPostApply();
|
||||
//onUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMissionAreaCtrl::drawHandle(const Point2F & pos)
|
||||
{
|
||||
Point2F pnt(pos.x-mHandleTextureHalfSize.x, pos.y-mHandleTextureHalfSize.y);
|
||||
GFX->getDrawUtil()->drawBitmap(mHandleTexture, pnt);
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::drawHandles(RectI & box)
|
||||
{
|
||||
F32 fillOffset = GFX->getFillConventionOffset();
|
||||
|
||||
F32 lx = box.point.x + fillOffset, rx = box.point.x + box.extent.x + fillOffset;
|
||||
F32 cx = (lx + rx) * 0.5f;
|
||||
F32 by = box.point.y + fillOffset, ty = box.point.y + box.extent.y + fillOffset;
|
||||
F32 cy = (ty + by) * 0.5f;
|
||||
|
||||
GFX->getDrawUtil()->clearBitmapModulation();
|
||||
drawHandle(Point2F(lx, ty));
|
||||
drawHandle(Point2F(lx, cy));
|
||||
drawHandle(Point2F(lx, by));
|
||||
drawHandle(Point2F(rx, ty));
|
||||
drawHandle(Point2F(rx, cy));
|
||||
drawHandle(Point2F(rx, by));
|
||||
drawHandle(Point2F(cx, ty));
|
||||
drawHandle(Point2F(cx, by));
|
||||
}
|
||||
|
||||
bool GuiMissionAreaCtrl::testWithinHandle(const Point2I & testPoint, S32 handleX, S32 handleY)
|
||||
{
|
||||
S32 dx = testPoint.x - handleX;
|
||||
S32 dy = testPoint.y - handleY;
|
||||
return dx <= Handle_Pixel_Size && dx >= -Handle_Pixel_Size && dy <= Handle_Pixel_Size && dy >= -Handle_Pixel_Size;
|
||||
}
|
||||
|
||||
S32 GuiMissionAreaCtrl::getHitHandles(const Point2I & mousePnt, const RectI & box)
|
||||
{
|
||||
S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1;
|
||||
S32 cx = (lx + rx) >> 1;
|
||||
S32 by = box.point.y, ty = box.point.y + box.extent.y - 1;
|
||||
S32 cy = (ty + by) >> 1;
|
||||
|
||||
if (testWithinHandle(mousePnt, lx, ty))
|
||||
return Handle_Left | Handle_Top;
|
||||
if (testWithinHandle(mousePnt, cx, ty))
|
||||
return Handle_Top;
|
||||
if (testWithinHandle(mousePnt, rx, ty))
|
||||
return Handle_Right | Handle_Top;
|
||||
if (testWithinHandle(mousePnt, lx, by))
|
||||
return Handle_Left | Handle_Bottom;
|
||||
if (testWithinHandle(mousePnt, cx, by))
|
||||
return Handle_Bottom;
|
||||
if (testWithinHandle(mousePnt, rx, by))
|
||||
return Handle_Right | Handle_Bottom;
|
||||
if (testWithinHandle(mousePnt, lx, cy))
|
||||
return Handle_Left;
|
||||
if (testWithinHandle(mousePnt, rx, cy))
|
||||
return Handle_Right;
|
||||
if(mousePnt.x >= lx && mousePnt.x <= rx &&
|
||||
mousePnt.y >= ty && mousePnt.y <= by)
|
||||
return(Handle_Middle);
|
||||
|
||||
return Handle_None;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Point2F GuiMissionAreaCtrl::worldToScreen(const Point2F & pos)
|
||||
{
|
||||
return(Point2F(mCenterPos.x + (pos.x * mScale.x), mCenterPos.y + (pos.y * mScale.y)));
|
||||
}
|
||||
|
||||
Point2I GuiMissionAreaCtrl::worldToScreen(const Point2I &pos)
|
||||
{
|
||||
return(Point2I(S32(mCenterPos.x + (pos.x * mScale.x)), S32(mCenterPos.y + (pos.y * mScale.y))));
|
||||
}
|
||||
|
||||
Point2F GuiMissionAreaCtrl::screenToWorld(const Point2F & pos)
|
||||
{
|
||||
return(Point2F((pos.x - mCenterPos.x) / mScale.x, (pos.y - mCenterPos.y) / mScale.y));
|
||||
}
|
||||
|
||||
Point2I GuiMissionAreaCtrl::screenToWorld(const Point2I &pos)
|
||||
{
|
||||
return(Point2I(S32((pos.x - mCenterPos.x) / mScale.x), S32((pos.y - mCenterPos.y) / mScale.y)));
|
||||
}
|
||||
|
||||
Point2I GuiMissionAreaCtrl::screenDeltaToWorldDelta(const Point2I &screenPoint)
|
||||
{
|
||||
return(Point2I(S32(screenPoint.x / mScale.x), S32(screenPoint.y / mScale.y)));
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::setupScreenTransform(const Point2I & offset)
|
||||
{
|
||||
const MatrixF & terrMat = mTerrainBlock->getTransform();
|
||||
Point3F terrPos;
|
||||
terrMat.getColumn(3, &terrPos);
|
||||
terrPos.z = 0;
|
||||
|
||||
F32 terrDim = mTerrainBlock->getWorldBlockSize();
|
||||
|
||||
const Point2I& extenti = getExtent( );
|
||||
Point2F extent( static_cast<F32>( extenti.x ), static_cast<F32>( extenti.y ) );
|
||||
|
||||
if(mSquareBitmap)
|
||||
extent.x > extent.y ? extent.x = extent.y : extent.y = extent.x;
|
||||
|
||||
// We need to negate the y-axis so we are correctly oriented with
|
||||
// positive y increase up the screen.
|
||||
mScale.set(extent.x / terrDim, -extent.y / terrDim, 0);
|
||||
|
||||
Point3F terrOffset = -terrPos;
|
||||
terrOffset.convolve(mScale);
|
||||
|
||||
// We need to add the y extent so we start from the bottom left of the control
|
||||
// rather than the top left.
|
||||
mCenterPos.set(terrOffset.x + F32(offset.x), terrOffset.y + F32(offset.y) + extent.y);
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::getScreenMissionArea(RectI & rect)
|
||||
{
|
||||
RectI area = mMissionArea->getArea();
|
||||
Point2F pos = worldToScreen(Point2F(F32(area.point.x), F32(area.point.y)));
|
||||
Point2F end = worldToScreen(Point2F(F32(area.point.x + area.extent.x), F32(area.point.y + area.extent.y)));
|
||||
|
||||
//
|
||||
rect.point.x = S32(round_local(pos.x));
|
||||
rect.point.y = S32(round_local(pos.y));
|
||||
rect.extent.x = S32(round_local(end.x - pos.x));
|
||||
rect.extent.y = S32(round_local(end.y - pos.y));
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::getScreenMissionArea(RectF & rect)
|
||||
{
|
||||
RectI area = mMissionArea->getArea();
|
||||
Point2F pos = worldToScreen(Point2F(F32(area.point.x), F32(area.point.y)));
|
||||
Point2F end = worldToScreen(Point2F(F32(area.point.x + area.extent.x), F32(area.point.y + area.extent.y)));
|
||||
|
||||
//
|
||||
rect.point.x = pos.x;
|
||||
rect.point.y = pos.y;
|
||||
rect.extent.x = end.x - pos.x;
|
||||
rect.extent.y = end.y - pos.y;
|
||||
}
|
||||
|
||||
Point2I GuiMissionAreaCtrl::convertOrigin(const Point2I &pos)
|
||||
{
|
||||
// Convert screen point to our bottom left origin
|
||||
Point2I pnt = globalToLocalCoord(pos);
|
||||
const Point2I& extent = getExtent( );
|
||||
pnt.y = extent.y - pnt.y;
|
||||
Point2I pt = localToGlobalCoord(pnt);
|
||||
return pt;
|
||||
}
|
||||
|
||||
void GuiMissionAreaCtrl::onRender(Point2I offset, const RectI & updateRect)
|
||||
{
|
||||
|
||||
RectI rect(offset, getExtent());
|
||||
F32 fillOffset = GFX->getFillConventionOffset();
|
||||
|
||||
setUpdate();
|
||||
|
||||
// draw an x
|
||||
if(!bool(mMissionArea) || !bool(mTerrainBlock))
|
||||
{
|
||||
GFX->setStateBlock(mSolidStateBlock);
|
||||
PrimBuild::color3i( 0, 0, 0 );
|
||||
PrimBuild::begin( GFXLineList, 4 );
|
||||
|
||||
PrimBuild::vertex2f( rect.point.x + fillOffset, updateRect.point.y + fillOffset );
|
||||
PrimBuild::vertex2f( rect.point.x + updateRect.extent.x + fillOffset, updateRect.point.y + updateRect.extent.y + fillOffset );
|
||||
PrimBuild::vertex2f( rect.point.x + fillOffset, updateRect.point.y + updateRect.extent.y + fillOffset );
|
||||
PrimBuild::vertex2f( rect.point.x + updateRect.extent.x + fillOffset, updateRect.point.y + fillOffset );
|
||||
|
||||
PrimBuild::end();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
setupScreenTransform(offset);
|
||||
|
||||
// draw the terrain
|
||||
if(mSquareBitmap)
|
||||
rect.extent.x > rect.extent.y ? rect.extent.x = rect.extent.y : rect.extent.y = rect.extent.x;
|
||||
|
||||
GFXDrawUtil *drawer = GFX->getDrawUtil();
|
||||
drawer->clearBitmapModulation();
|
||||
drawer->drawBitmapStretch(mTextureObject, rect, GFXBitmapFlip_Y, GFXTextureFilterLinear, false);
|
||||
|
||||
GFX->setStateBlock(mSolidStateBlock);
|
||||
drawer->clearBitmapModulation();
|
||||
|
||||
// draw the reference axis
|
||||
PrimBuild::begin( GFXLineList, 4 );
|
||||
PrimBuild::color3i( 255, 0, 0 );
|
||||
PrimBuild::vertex2f( rect.point.x + 5 + fillOffset, rect.point.y + rect.extent.y - 5 + fillOffset );
|
||||
PrimBuild::vertex2f( rect.point.x + 25 + fillOffset, rect.point.y + rect.extent.y - 5 + fillOffset );
|
||||
PrimBuild::color3i( 0, 255, 0 );
|
||||
PrimBuild::vertex2f( rect.point.x + 5 + fillOffset, rect.point.y + rect.extent.y - 5 + fillOffset );
|
||||
PrimBuild::vertex2f( rect.point.x + 5 + fillOffset, rect.point.y + rect.extent.y - 25 + fillOffset );
|
||||
PrimBuild::end();
|
||||
|
||||
RectF area;
|
||||
getScreenMissionArea(area);
|
||||
|
||||
// render the mission area box
|
||||
PrimBuild::color( mMissionBoundsColor );
|
||||
PrimBuild::begin( GFXLineStrip, 5 );
|
||||
PrimBuild::vertex2f(area.point.x + fillOffset, area.point.y + fillOffset);
|
||||
PrimBuild::vertex2f(area.point.x + area.extent.x + fillOffset, area.point.y + fillOffset);
|
||||
PrimBuild::vertex2f(area.point.x + area.extent.x + fillOffset, area.point.y + area.extent.y + fillOffset);
|
||||
PrimBuild::vertex2f(area.point.x + fillOffset, area.point.y + area.extent.y + fillOffset);
|
||||
PrimBuild::vertex2f(area.point.x + fillOffset, area.point.y + fillOffset);
|
||||
PrimBuild::end();
|
||||
|
||||
// render the camera
|
||||
//if(mRenderCamera)
|
||||
{
|
||||
CameraQuery camera;
|
||||
GameProcessCameraQuery(&camera);
|
||||
|
||||
// farplane too far, 90' looks wrong...
|
||||
camera.fov = mDegToRad(60.f);
|
||||
camera.farPlane = 500.f;
|
||||
|
||||
//
|
||||
F32 rot = camera.fov / 2;
|
||||
|
||||
//
|
||||
VectorF ray;
|
||||
VectorF projRayA, projRayB;
|
||||
|
||||
ray.set(camera.farPlane * -mSin(rot), camera.farPlane * mCos(rot), 0);
|
||||
camera.cameraMatrix.mulV(ray, &projRayA);
|
||||
|
||||
ray.set(camera.farPlane * -mSin(-rot), camera.farPlane * mCos(-rot), 0);
|
||||
camera.cameraMatrix.mulV(ray, &projRayB);
|
||||
|
||||
Point3F camPos;
|
||||
camera.cameraMatrix.getColumn(3, &camPos);
|
||||
|
||||
Point2F s = worldToScreen(Point2F(camPos.x, camPos.y));
|
||||
Point2F e1 = worldToScreen(Point2F(camPos.x + projRayA.x, camPos.y + projRayA.y));
|
||||
Point2F e2 = worldToScreen(Point2F(camPos.x + projRayB.x, camPos.y + projRayB.y));
|
||||
|
||||
PrimBuild::color( mCameraColor );
|
||||
PrimBuild::begin( GFXLineList, 4 );
|
||||
PrimBuild::vertex2f( s.x + fillOffset, s.y + fillOffset );
|
||||
PrimBuild::vertex2f( e1.x + fillOffset, e1.y + fillOffset );
|
||||
PrimBuild::vertex2f( s.x + fillOffset, s.y + fillOffset );
|
||||
PrimBuild::vertex2f( e2.x + fillOffset, e2.y + fillOffset );
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
// render the handles
|
||||
RectI iArea;
|
||||
getScreenMissionArea(iArea);
|
||||
drawHandles(iArea);
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DefineEngineMethod( GuiMissionAreaCtrl, setMissionArea, void, ( MissionArea* area ),,
|
||||
"@brief Set the MissionArea to edit.\n\n")
|
||||
{
|
||||
object->setMissionArea( area );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiMissionAreaCtrl, updateTerrain, void, ( ),,
|
||||
"@brief Update the terrain bitmap.\n\n")
|
||||
{
|
||||
object->updateTerrain();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMissionAreaUndoAction::undo()
|
||||
{
|
||||
MissionArea *ma = NULL;
|
||||
if ( !Sim::findObject( mObjId, ma ) )
|
||||
return;
|
||||
|
||||
// Temporarily save the MissionArea's current data.
|
||||
RectI area = ma->getArea();
|
||||
|
||||
// Restore the MissionArea properties saved in the UndoAction
|
||||
ma->setArea( mArea );
|
||||
ma->inspectPostApply();
|
||||
|
||||
// Now save the previous Mission data in this UndoAction
|
||||
// since an undo action must become a redo action and vice-versa
|
||||
mArea = area;
|
||||
|
||||
// Let the script get a chance at it.
|
||||
Con::executef( mMissionAreaEditor, "onUndo" );
|
||||
}
|
||||
158
Engine/source/gui/worldEditor/guiMissionArea.h
Normal file
158
Engine/source/gui/worldEditor/guiMissionArea.h
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIMISSIONAREA_H_
|
||||
#define _GUIMISSIONAREA_H_
|
||||
|
||||
#ifndef _GUIBITMAPCTRL_H_
|
||||
#include "gui/controls/guiBitmapCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _MISSIONAREA_H_
|
||||
#include "T3D/missionArea.h"
|
||||
#endif
|
||||
#ifndef _UNDO_H_
|
||||
#include "util/undo.h"
|
||||
#endif
|
||||
|
||||
class GBitmap;
|
||||
class TerrainBlock;
|
||||
|
||||
class GuiMissionAreaCtrl : public GuiBitmapCtrl
|
||||
{
|
||||
typedef GuiBitmapCtrl Parent;
|
||||
|
||||
protected:
|
||||
enum HandleInfo
|
||||
{
|
||||
// Handle in use
|
||||
Handle_None = 0,
|
||||
Handle_Left = BIT(0),
|
||||
Handle_Right = BIT(1),
|
||||
Handle_Top = BIT(2),
|
||||
Handle_Bottom = BIT(3),
|
||||
Handle_Middle = BIT(4), // Used to drag the whole area
|
||||
|
||||
Handle_Pixel_Size = 3,
|
||||
};
|
||||
|
||||
SimObjectPtr<MissionArea> mMissionArea;
|
||||
SimObjectPtr<TerrainBlock> mTerrainBlock;
|
||||
|
||||
GFXStateBlockRef mBlendStateBlock;
|
||||
GFXStateBlockRef mSolidStateBlock;
|
||||
|
||||
StringTableEntry mHandleBitmap;
|
||||
GFXTexHandle mHandleTexture;
|
||||
Point2I mHandleTextureSize;
|
||||
Point2F mHandleTextureHalfSize;
|
||||
|
||||
ColorI mMissionBoundsColor;
|
||||
ColorI mCameraColor;
|
||||
|
||||
bool mSquareBitmap;
|
||||
|
||||
VectorF mScale;
|
||||
Point2F mCenterPos;
|
||||
|
||||
S32 mLastHitMode;
|
||||
Point2I mLastMousePoint;
|
||||
bool mSavedDrag;
|
||||
|
||||
void submitUndo( const UTF8 *name = "Action" );
|
||||
|
||||
TerrainBlock * getTerrainObj();
|
||||
GBitmap * createTerrainBitmap();
|
||||
void updateTerrainBitmap();
|
||||
|
||||
//void onUpdate();
|
||||
|
||||
void setupScreenTransform(const Point2I & offset);
|
||||
|
||||
Point2F worldToScreen(const Point2F &);
|
||||
Point2F screenToWorld(const Point2F &);
|
||||
|
||||
Point2I worldToScreen(const Point2I &);
|
||||
Point2I screenToWorld(const Point2I &);
|
||||
|
||||
Point2I screenDeltaToWorldDelta(const Point2I &screenPoint);
|
||||
|
||||
void getScreenMissionArea(RectI & rect);
|
||||
void getScreenMissionArea(RectF & rect);
|
||||
|
||||
Point2I convertOrigin(const Point2I &);
|
||||
|
||||
void drawHandle(const Point2F & pos);
|
||||
void drawHandles(RectI & box);
|
||||
|
||||
bool testWithinHandle(const Point2I & testPoint, S32 handleX, S32 handleY);
|
||||
S32 getHitHandles(const Point2I & mousePnt, const RectI & box);
|
||||
|
||||
public:
|
||||
GuiMissionAreaCtrl();
|
||||
virtual ~GuiMissionAreaCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiMissionAreaCtrl);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
static void initPersistFields();
|
||||
|
||||
// GuiControl
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
virtual void onMouseUp(const GuiEvent & event);
|
||||
virtual void onMouseDown(const GuiEvent & event);
|
||||
virtual void onMouseMove(const GuiEvent & event);
|
||||
virtual void onMouseDragged(const GuiEvent & event);
|
||||
virtual void onMouseEnter(const GuiEvent & event);
|
||||
virtual void onMouseLeave(const GuiEvent & event);
|
||||
|
||||
void setMissionArea( MissionArea* area );
|
||||
void updateTerrain();
|
||||
|
||||
const RectI & getArea();
|
||||
void setArea(const RectI & area);
|
||||
};
|
||||
|
||||
class GuiMissionAreaUndoAction : public UndoAction
|
||||
{
|
||||
public:
|
||||
|
||||
GuiMissionAreaUndoAction( const UTF8* actionName ) : UndoAction( actionName )
|
||||
{
|
||||
}
|
||||
|
||||
GuiMissionAreaCtrl *mMissionAreaEditor;
|
||||
|
||||
SimObjectId mObjId;
|
||||
RectI mArea;
|
||||
|
||||
virtual void undo();
|
||||
virtual void redo() { undo(); }
|
||||
};
|
||||
|
||||
#endif // _GUIMISSIONAREA_H_
|
||||
116
Engine/source/gui/worldEditor/guiMissionAreaEditor.cpp
Normal file
116
Engine/source/gui/worldEditor/guiMissionAreaEditor.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/worldEditor/guiMissionAreaEditor.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiMissionAreaEditorCtrl);
|
||||
|
||||
ConsoleDocClass( GuiMissionAreaEditorCtrl,
|
||||
"@brief Specialized GUI used for editing the MissionArea in a level\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
GuiMissionAreaEditorCtrl::GuiMissionAreaEditorCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
GuiMissionAreaEditorCtrl::~GuiMissionAreaEditorCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
bool GuiMissionAreaEditorCtrl::onAdd()
|
||||
{
|
||||
if( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiMissionAreaEditorCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void GuiMissionAreaEditorCtrl::get3DCursor( GuiCursor *&cursor,
|
||||
bool &visible,
|
||||
const Gui3DMouseEvent &event_ )
|
||||
{
|
||||
//cursor = mAddNodeCursor;
|
||||
//visible = false;
|
||||
|
||||
cursor = NULL;
|
||||
visible = false;
|
||||
|
||||
GuiCanvas *root = getRoot();
|
||||
if ( !root )
|
||||
return;
|
||||
|
||||
S32 currCursor = PlatformCursorController::curArrow;
|
||||
|
||||
if ( root->mCursorChanged == currCursor )
|
||||
return;
|
||||
|
||||
PlatformWindow *window = root->getPlatformWindow();
|
||||
PlatformCursorController *controller = window->getCursorController();
|
||||
|
||||
// We've already changed the cursor,
|
||||
// so set it back before we change it again.
|
||||
if( root->mCursorChanged != -1)
|
||||
controller->popCursor();
|
||||
|
||||
// Now change the cursor shape
|
||||
controller->pushCursor(currCursor);
|
||||
root->mCursorChanged = currCursor;
|
||||
}
|
||||
|
||||
void GuiMissionAreaEditorCtrl::setSelectedMissionArea( MissionArea *missionArea )
|
||||
{
|
||||
mSelMissionArea = missionArea;
|
||||
|
||||
if ( mSelMissionArea != NULL )
|
||||
Con::executef( this, "onMissionAreaSelected", missionArea->getIdString() );
|
||||
else
|
||||
Con::executef( this, "onMissionAreaSelected" );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiMissionAreaEditorCtrl, setSelectedMissionArea, void, 2, 3, "" )
|
||||
{
|
||||
if ( argc == 2 )
|
||||
object->setSelectedMissionArea(NULL);
|
||||
else
|
||||
{
|
||||
MissionArea *missionArea = NULL;
|
||||
if ( Sim::findObject( argv[2], missionArea ) )
|
||||
object->setSelectedMissionArea(missionArea);
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiMissionAreaEditorCtrl, getSelectedMissionArea, const char*, 2, 2, "" )
|
||||
{
|
||||
MissionArea *missionArea = object->getSelectedMissionArea();
|
||||
if ( !missionArea )
|
||||
return NULL;
|
||||
|
||||
return missionArea->getIdString();
|
||||
}
|
||||
57
Engine/source/gui/worldEditor/guiMissionAreaEditor.h
Normal file
57
Engine/source/gui/worldEditor/guiMissionAreaEditor.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIMISSIONAREAEDITORCTRL_H_
|
||||
#define _GUIMISSIONAREAEDITORCTRL_H_
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#include "gui/worldEditor/editTSCtrl.h"
|
||||
#endif
|
||||
#ifndef _MISSIONAREA_H_
|
||||
#include "T3D/missionArea.h"
|
||||
#endif
|
||||
|
||||
class GuiMissionAreaEditorCtrl : public EditTSCtrl
|
||||
{
|
||||
typedef EditTSCtrl Parent;
|
||||
|
||||
protected:
|
||||
SimObjectPtr<MissionArea> mSelMissionArea;
|
||||
|
||||
public:
|
||||
GuiMissionAreaEditorCtrl();
|
||||
virtual ~GuiMissionAreaEditorCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiMissionAreaEditorCtrl);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
static void initPersistFields();
|
||||
|
||||
// EditTSCtrl
|
||||
void get3DCursor( GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event_ );
|
||||
|
||||
void setSelectedMissionArea( MissionArea *missionArea );
|
||||
MissionArea* getSelectedMissionArea() { return mSelMissionArea; };
|
||||
};
|
||||
|
||||
#endif // _GUIMISSIONAREAEDITORCTRL_H_
|
||||
366
Engine/source/gui/worldEditor/guiTerrPreviewCtrl.cpp
Normal file
366
Engine/source/gui/worldEditor/guiTerrPreviewCtrl.cpp
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "terrain/terrData.h"
|
||||
#include "gui/worldEditor/guiTerrPreviewCtrl.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "T3D/gameFunctions.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTerrPreviewCtrl);
|
||||
|
||||
ConsoleDocClass( GuiTerrPreviewCtrl,
|
||||
"@brief Very old GUI used for terrain preview\n\n"
|
||||
"Deprecated\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
GuiTerrPreviewCtrl::GuiTerrPreviewCtrl(void) : mTerrainEditor(NULL), mTerrainSize(2048.0f)
|
||||
{
|
||||
mRoot.set( 0, 0 );
|
||||
mOrigin.set( 0, 0 );
|
||||
mWorldScreenCenter.set( mTerrainSize*0.5f, mTerrainSize*0.5f );
|
||||
mControlsStateBlock = NULL;
|
||||
mTerrainBitmapStateBlock = NULL;
|
||||
}
|
||||
|
||||
bool GuiTerrPreviewCtrl::onAdd()
|
||||
{
|
||||
if(Parent::onAdd() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SimObject* inTerrEditor = Sim::findObject("ETerrainEditor");
|
||||
if(!inTerrEditor)
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::General, "TerrainEditor::onAdd: failed to load Terrain Editor");
|
||||
return false;
|
||||
}
|
||||
|
||||
mTerrainEditor = dynamic_cast<TerrainEditor*>(inTerrEditor);
|
||||
|
||||
GFXStateBlockDesc desc;
|
||||
|
||||
desc.setBlend(false, GFXBlendOne, GFXBlendZero);
|
||||
|
||||
desc.samplersDefined = true;
|
||||
desc.samplers[0].addressModeU = GFXAddressWrap;
|
||||
desc.samplers[0].addressModeV = GFXAddressWrap;
|
||||
desc.samplers[0].textureColorOp = GFXTOPSelectARG1;
|
||||
desc.samplers[0].colorArg1 = GFXTATexture;
|
||||
desc.setCullMode(GFXCullNone);
|
||||
desc.setZReadWrite(false);
|
||||
|
||||
mTerrainBitmapStateBlock = GFX->createStateBlock(desc);
|
||||
|
||||
desc.samplers[0].textureColorOp = GFXTOPDisable;
|
||||
|
||||
mControlsStateBlock = GFX->createStateBlock(desc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTerrPreviewCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiTerrPreviewCtrl, reset, void, 2, 2, "Reset the view of the terrain.")
|
||||
{
|
||||
object->reset();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTerrPreviewCtrl, setRoot, void, 2, 2, "Add the origin to the root and reset the origin.")
|
||||
{
|
||||
object->setRoot();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTerrPreviewCtrl, getRoot, const char *, 2, 2, "Return a Point2F representing the position of the root.")
|
||||
{
|
||||
Point2F p = object->getRoot();
|
||||
|
||||
static char rootbuf[32];
|
||||
dSprintf(rootbuf,sizeof(rootbuf),"%g %g", p.x, -p.y);
|
||||
return rootbuf;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTerrPreviewCtrl, setOrigin, void, 4, 4, "(float x, float y)"
|
||||
"Set the origin of the view.")
|
||||
{
|
||||
object->setOrigin( Point2F( dAtof(argv[2]), -dAtof(argv[3]) ) );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTerrPreviewCtrl, getOrigin, const char*, 2, 2, "Return a Point2F containing the position of the origin.")
|
||||
{
|
||||
Point2F p = object->getOrigin();
|
||||
|
||||
static char originbuf[32];
|
||||
dSprintf(originbuf,sizeof(originbuf),"%g %g", p.x, -p.y);
|
||||
return originbuf;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTerrPreviewCtrl, getValue, const char*, 2, 2, "Returns a 4-tuple containing: root_x root_y origin_x origin_y")
|
||||
{
|
||||
Point2F r = object->getRoot();
|
||||
Point2F o = object->getOrigin();
|
||||
|
||||
static char valuebuf[64];
|
||||
dSprintf(valuebuf,sizeof(valuebuf),"%g %g %g %g", r.x, -r.y, o.x, -o.y);
|
||||
return valuebuf;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTerrPreviewCtrl, setValue, void, 3, 3, "Accepts a 4-tuple in the same form as getValue returns.\n\n"
|
||||
"@see GuiTerrPreviewCtrl::getValue()")
|
||||
{
|
||||
Point2F r,o;
|
||||
dSscanf(argv[2],"%g %g %g %g", &r.x, &r.y, &o.x, &o.y);
|
||||
r.y = -r.y;
|
||||
o.y = -o.y;
|
||||
object->reset();
|
||||
object->setRoot(r);
|
||||
object->setOrigin(o);
|
||||
}
|
||||
|
||||
bool GuiTerrPreviewCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTerrPreviewCtrl::onSleep()
|
||||
{
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
void GuiTerrPreviewCtrl::setBitmap(const GFXTexHandle &handle)
|
||||
{
|
||||
mTextureHandle = handle;
|
||||
}
|
||||
|
||||
|
||||
void GuiTerrPreviewCtrl::reset()
|
||||
{
|
||||
mRoot.set(0,0);
|
||||
mOrigin.set(0,0);
|
||||
}
|
||||
|
||||
void GuiTerrPreviewCtrl::setRoot()
|
||||
{
|
||||
mRoot += mOrigin;
|
||||
mOrigin.set(0,0);
|
||||
}
|
||||
|
||||
void GuiTerrPreviewCtrl::setRoot(const Point2F &p)
|
||||
{
|
||||
mRoot = p;
|
||||
}
|
||||
|
||||
void GuiTerrPreviewCtrl::setOrigin(const Point2F &p)
|
||||
{
|
||||
mOrigin = p;
|
||||
}
|
||||
|
||||
|
||||
Point2F& GuiTerrPreviewCtrl::wrap(const Point2F &p)
|
||||
{
|
||||
static Point2F result;
|
||||
result = p;
|
||||
|
||||
while (result.x < 0.0f)
|
||||
result.x += mTerrainSize;
|
||||
while (result.x > mTerrainSize)
|
||||
result.x -= mTerrainSize;
|
||||
while (result.y < 0.0f)
|
||||
result.y += mTerrainSize;
|
||||
while (result.y > mTerrainSize)
|
||||
result.y -= mTerrainSize;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Point2F& GuiTerrPreviewCtrl::worldToTexture(const Point2F &p)
|
||||
{
|
||||
static Point2F result;
|
||||
result = wrap( p + mRoot ) / mTerrainSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Point2F& GuiTerrPreviewCtrl::worldToCtrl(const Point2F &p)
|
||||
{
|
||||
static Point2F result;
|
||||
result = wrap( p - mCamera - mWorldScreenCenter );
|
||||
result *= getWidth() / mTerrainSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void GuiTerrPreviewCtrl::onPreRender()
|
||||
{
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiTerrPreviewCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
CameraQuery query;
|
||||
GameProcessCameraQuery(&query);
|
||||
Point3F cameraRot;
|
||||
TerrainBlock *terrBlock = NULL;
|
||||
|
||||
MatrixF matrix = query.cameraMatrix;
|
||||
matrix.getColumn(3,&cameraRot); // get Camera translation
|
||||
mCamera.set(cameraRot.x, -cameraRot.y);
|
||||
matrix.getRow(1,&cameraRot); // get camera rotation
|
||||
|
||||
if (mTerrainEditor != NULL)
|
||||
terrBlock = mTerrainEditor->getActiveTerrain();
|
||||
|
||||
if (!terrBlock)
|
||||
return;
|
||||
|
||||
for(U32 i = 0; i < GFX->getNumSamplers(); i++)
|
||||
GFX->setTexture(i, NULL);
|
||||
|
||||
GFX->disableShaders();
|
||||
|
||||
Point2F terrPos(terrBlock->getPosition().x, terrBlock->getPosition().y);
|
||||
|
||||
mTerrainSize = terrBlock->getWorldBlockSize();
|
||||
|
||||
|
||||
//----------------------------------------- RENDER the Terrain Bitmap
|
||||
if (mTextureHandle)
|
||||
{
|
||||
|
||||
GFXTextureObject *texture = (GFXTextureObject*)mTextureHandle;
|
||||
if (texture)
|
||||
{
|
||||
//GFX->setLightingEnable(false);
|
||||
GFX->setStateBlock(mTerrainBitmapStateBlock);
|
||||
GFX->setTexture(0, texture);
|
||||
|
||||
Point2F screenP1(offset.x - 0.5f, offset.y + 0.5f);
|
||||
Point2F screenP2(offset.x + getWidth() - 0.5f, offset.y + getWidth() + 0.5f);
|
||||
Point2F textureP1( worldToTexture( mCamera - terrPos ) - Point2F(0.5f, 0.5f));
|
||||
Point2F textureP2(textureP1 + Point2F(1.0f, 1.0f));
|
||||
|
||||
// the texture if flipped horz to reflect how the terrain is really drawn
|
||||
PrimBuild::color3f(1.0f, 1.0f, 1.0f);
|
||||
PrimBuild::begin(GFXTriangleFan, 4);
|
||||
PrimBuild::texCoord2f(textureP1.x, textureP2.y);
|
||||
PrimBuild::vertex2f(screenP1.x, screenP2.y); // left bottom
|
||||
|
||||
|
||||
PrimBuild::texCoord2f(textureP2.x, textureP2.y);
|
||||
PrimBuild::vertex2f(screenP2.x, screenP2.y); // right bottom
|
||||
PrimBuild::texCoord2f(textureP2.x, textureP1.y);
|
||||
PrimBuild::vertex2f(screenP2.x, screenP1.y); // right top
|
||||
|
||||
PrimBuild::texCoord2f(textureP1.x, textureP1.y);
|
||||
PrimBuild::vertex2f(screenP1.x, screenP1.y); // left top
|
||||
PrimBuild::end();
|
||||
}
|
||||
}
|
||||
//Draw blank texture
|
||||
else
|
||||
{
|
||||
RectI rect(offset.x, offset.y, getWidth(), getHeight());
|
||||
GFX->getDrawUtil()->drawRect(rect, ColorI(0,0,0));
|
||||
}
|
||||
|
||||
GFX->setStateBlock(mControlsStateBlock);
|
||||
|
||||
//----------------------------------------- RENDER the '+' at the center of the Block
|
||||
|
||||
PrimBuild::color4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
Point2F center( worldToCtrl(terrPos + Point2F(mTerrainSize * 0.5f, mTerrainSize * 0.5f)) );
|
||||
S32 y;
|
||||
for (y=-1; y<=1; y++)
|
||||
{
|
||||
F32 yoffset = offset.y + y*256.0f;
|
||||
for (S32 x=-1; x<=1; x++)
|
||||
{
|
||||
F32 xoffset = offset.x + x*256.0f;
|
||||
PrimBuild::begin(GFXLineList, 4);
|
||||
PrimBuild::vertex2f(xoffset + center.x, yoffset + center.y-5);
|
||||
PrimBuild::vertex2f(xoffset + center.x, yoffset + center.y+6);
|
||||
PrimBuild::vertex2f(xoffset + center.x-5, yoffset + center.y);
|
||||
PrimBuild::vertex2f(xoffset + center.x+6, yoffset + center.y);
|
||||
PrimBuild::end();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------- RENDER the Block Corners
|
||||
Point2F cornerf( worldToCtrl(terrPos) + Point2F(0.125f, 0.125f));
|
||||
Point2I corner=Point2I((S32)cornerf.x,(S32)cornerf.y);
|
||||
for (y=-1; y<=1; y++)
|
||||
{
|
||||
S32 yoffset = offset.y + y*256;
|
||||
for (S32 x=-1; x<=1; x++)
|
||||
{
|
||||
S32 xoffset = offset.x + x*256;
|
||||
PrimBuild::begin(GFXLineStrip, 3);
|
||||
PrimBuild::color4f(1.0f, 1.0f, 1.0f, 0.3f);
|
||||
PrimBuild::vertex2i(xoffset + corner.x, yoffset + corner.y-128);
|
||||
PrimBuild::color4f(1.0f, 1.0f, 1.0f, 0.7f);
|
||||
PrimBuild::vertex2i(xoffset + corner.x, yoffset + corner.y);
|
||||
PrimBuild::color4f(1.0f, 1.0f, 1.0f, 0.3f);
|
||||
PrimBuild::vertex2i(xoffset + corner.x+128, yoffset + corner.y);
|
||||
PrimBuild::end();
|
||||
PrimBuild::begin(GFXLineStrip, 3);
|
||||
PrimBuild::color4f(1.0f, 1.0f, 1.0f, 0.3f);
|
||||
PrimBuild::vertex2i(xoffset + corner.x, yoffset + corner.y+128);
|
||||
PrimBuild::color4f(1.0f, 1.0f, 1.0f, 0.7f);
|
||||
PrimBuild::vertex2i(xoffset + corner.x, yoffset + corner.y);
|
||||
PrimBuild::color4f(1.0f, 1.0f, 1.0f, 0.3f);
|
||||
PrimBuild::vertex2i(xoffset + corner.x-128, yoffset + corner.y);
|
||||
PrimBuild::end();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------- RENDER the Viewcone
|
||||
Point2F pointA(cameraRot.x * -40, cameraRot.y * -40);
|
||||
Point2F pointB(-pointA.y, pointA.x);
|
||||
|
||||
F32 tann = mTan(0.5f);
|
||||
Point2F point1( pointA + pointB * tann );
|
||||
Point2F point2( pointA - pointB * tann );
|
||||
|
||||
center.set((F32)(offset.x + getWidth() / 2), (F32)(offset.y + getHeight() / 2 ));
|
||||
PrimBuild::begin(GFXLineStrip, 3);
|
||||
PrimBuild::color4f(1.0f, 0.0f, 0.0f, 0.7f);
|
||||
PrimBuild::vertex2i((S32)(center.x + point1.x), (S32)(center.y + point1.y));
|
||||
PrimBuild::color4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
PrimBuild::vertex2i((S32)center.x,(S32)center.y);
|
||||
PrimBuild::color4f(1.0f, 0.0f, 0.0f, 0.7f);
|
||||
PrimBuild::vertex2i((S32)(center.x + point2.x), (S32)(center.y + point2.y));
|
||||
PrimBuild::end();
|
||||
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
88
Engine/source/gui/worldEditor/guiTerrPreviewCtrl.h
Normal file
88
Engine/source/gui/worldEditor/guiTerrPreviewCtrl.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITERRPREVIEWCTRL_H_
|
||||
#define _GUITERRPREVIEWCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
#ifndef _GUITSCONTROL_H_
|
||||
#include "gui/3d/guiTSControl.h"
|
||||
#endif
|
||||
#ifndef _GFX_GFXDRAWER_H_
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#endif
|
||||
#ifndef _TERRAINEDITOR_H_
|
||||
#include "gui/worldEditor/terrainEditor.h"
|
||||
#endif
|
||||
|
||||
|
||||
class GuiTerrPreviewCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
GFXTexHandle mTextureHandle;
|
||||
GFXStateBlockRef mTerrainBitmapStateBlock;
|
||||
GFXStateBlockRef mControlsStateBlock;
|
||||
Point2F mRoot;
|
||||
Point2F mOrigin;
|
||||
Point2F mWorldScreenCenter;
|
||||
Point2F mCamera;
|
||||
F32 mTerrainSize;
|
||||
|
||||
TerrainEditor* mTerrainEditor;
|
||||
|
||||
Point2F& wrap(const Point2F &p);
|
||||
Point2F& worldToTexture(const Point2F &p);
|
||||
Point2F& worldToCtrl(const Point2F &p);
|
||||
|
||||
|
||||
public:
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiTerrPreviewCtrl);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
GuiTerrPreviewCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
bool onAdd();
|
||||
|
||||
void setBitmap(const GFXTexHandle&);
|
||||
|
||||
void reset();
|
||||
void setRoot();
|
||||
void setRoot(const Point2F &root);
|
||||
void setOrigin(const Point2F &origin);
|
||||
const Point2F& getRoot() { return mRoot; }
|
||||
const Point2F& getOrigin() { return mOrigin; }
|
||||
|
||||
//void setValue(const Point2F *center, const Point2F *camera);
|
||||
//const char *getScriptValue();
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
25
Engine/source/gui/worldEditor/tSelection.cpp
Normal file
25
Engine/source/gui/worldEditor/tSelection.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/worldEditor/tSelection.h"
|
||||
|
||||
91
Engine/source/gui/worldEditor/tSelection.h
Normal file
91
Engine/source/gui/worldEditor/tSelection.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TSELECTION_H_
|
||||
#define _TSELECTION_H_
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
|
||||
|
||||
template <class T>
|
||||
class Selection : public Vector<T>
|
||||
{
|
||||
public:
|
||||
|
||||
// Use explicit specialization to define these for your type.
|
||||
MatrixF getOrientation() { return MatrixF(); }
|
||||
Point3F getOrigin() { return Point3F(); }
|
||||
Point3F getScale() { return Point3F(); }
|
||||
|
||||
void offset( const Point3F &delta );
|
||||
void rotate( const EulerF &delta );
|
||||
void scale( const Point3F &delta );
|
||||
|
||||
protected:
|
||||
|
||||
// Use explicit specialization to define these for your type.
|
||||
virtual void offsetObject( T &object, const Point3F &delta ) {}
|
||||
virtual void rotateObject( T &object, const EulerF &delta, const Point3F &origin ) {}
|
||||
virtual void scaleObject( T &object, const Point3F &delta ) {}
|
||||
|
||||
protected:
|
||||
|
||||
//Point3F mCentroid;
|
||||
//Point3F mBoxCentroid;
|
||||
//Box3F mBoxBounds;
|
||||
//bool mCentroidValid;
|
||||
};
|
||||
|
||||
|
||||
template<class T> inline void Selection<T>::offset( const Point3F &delta )
|
||||
{
|
||||
typename Selection<T>::iterator itr = this->begin();
|
||||
|
||||
for ( ; itr != this->end(); itr++ )
|
||||
offsetObject( *itr, delta );
|
||||
}
|
||||
|
||||
template<class T> inline void Selection<T>::rotate( const EulerF &delta )
|
||||
{
|
||||
typename Selection<T>::iterator itr = this->begin();
|
||||
Point3F origin = getOrigin();
|
||||
|
||||
for ( ; itr != this->end(); itr++ )
|
||||
rotateObject( *itr, delta, origin );
|
||||
}
|
||||
|
||||
template<class T> inline void Selection<T>::scale( const Point3F &delta )
|
||||
{
|
||||
// Can only scale a single selection.
|
||||
if ( this->size() != 1 )
|
||||
return;
|
||||
|
||||
scaleObject( this->mArray[0], delta );
|
||||
}
|
||||
|
||||
#endif // _TSELECTION_H_
|
||||
795
Engine/source/gui/worldEditor/terrainActions.cpp
Normal file
795
Engine/source/gui/worldEditor/terrainActions.cpp
Normal file
|
|
@ -0,0 +1,795 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/worldEditor/terrainActions.h"
|
||||
|
||||
#include "gui/core/guiCanvas.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SelectAction::process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type)
|
||||
{
|
||||
if(sel == mTerrainEditor->getCurrentSel())
|
||||
return;
|
||||
|
||||
if(type == Process)
|
||||
return;
|
||||
|
||||
if(selChanged)
|
||||
{
|
||||
if(event.modifier & SI_MULTISELECT)
|
||||
{
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
mTerrainEditor->getCurrentSel()->remove((*sel)[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
GridInfo gInfo;
|
||||
if(mTerrainEditor->getCurrentSel()->getInfo((*sel)[i].mGridPoint.gridPos, gInfo))
|
||||
{
|
||||
if(!gInfo.mPrimarySelect)
|
||||
gInfo.mPrimarySelect = (*sel)[i].mPrimarySelect;
|
||||
|
||||
if(gInfo.mWeight < (*sel)[i].mWeight)
|
||||
gInfo.mWeight = (*sel)[i].mWeight;
|
||||
|
||||
mTerrainEditor->getCurrentSel()->setInfo(gInfo);
|
||||
}
|
||||
else
|
||||
mTerrainEditor->getCurrentSel()->add((*sel)[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeselectAction::process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type)
|
||||
{
|
||||
if(sel == mTerrainEditor->getCurrentSel())
|
||||
return;
|
||||
|
||||
if(type == Process)
|
||||
return;
|
||||
|
||||
if(selChanged)
|
||||
{
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
mTerrainEditor->getCurrentSel()->remove((*sel)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SoftSelectAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type type)
|
||||
{
|
||||
TerrainBlock *terrBlock = mTerrainEditor->getActiveTerrain();
|
||||
if ( !terrBlock )
|
||||
return;
|
||||
|
||||
// allow process of current selection
|
||||
Selection tmpSel;
|
||||
if(sel == mTerrainEditor->getCurrentSel())
|
||||
{
|
||||
tmpSel = *sel;
|
||||
sel = &tmpSel;
|
||||
}
|
||||
|
||||
if(type == Begin || type == Process)
|
||||
mFilter.set(1, &mTerrainEditor->mSoftSelectFilter);
|
||||
|
||||
//
|
||||
if(selChanged)
|
||||
{
|
||||
F32 radius = mTerrainEditor->mSoftSelectRadius;
|
||||
if(radius == 0.f)
|
||||
return;
|
||||
|
||||
S32 squareSize = terrBlock->getSquareSize();
|
||||
U32 offset = U32(radius / F32(squareSize)) + 1;
|
||||
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
GridInfo & info = (*sel)[i];
|
||||
|
||||
info.mPrimarySelect = true;
|
||||
info.mWeight = mFilter.getValue(0);
|
||||
|
||||
if(!mTerrainEditor->getCurrentSel()->add(info))
|
||||
mTerrainEditor->getCurrentSel()->setInfo(info);
|
||||
|
||||
Point2F infoPos((F32)info.mGridPoint.gridPos.x, (F32)info.mGridPoint.gridPos.y);
|
||||
|
||||
//
|
||||
for(S32 x = info.mGridPoint.gridPos.x - offset; x < info.mGridPoint.gridPos.x + (offset << 1); x++)
|
||||
for(S32 y = info.mGridPoint.gridPos.y - offset; y < info.mGridPoint.gridPos.y + (offset << 1); y++)
|
||||
{
|
||||
//
|
||||
Point2F pos((F32)x, (F32)y);
|
||||
|
||||
F32 dist = Point2F(pos - infoPos).len() * F32(squareSize);
|
||||
|
||||
if(dist > radius)
|
||||
continue;
|
||||
|
||||
F32 weight = mFilter.getValue(dist / radius);
|
||||
|
||||
//
|
||||
GridInfo gInfo;
|
||||
GridPoint gridPoint = info.mGridPoint;
|
||||
gridPoint.gridPos.set(x, y);
|
||||
|
||||
if(mTerrainEditor->getCurrentSel()->getInfo(Point2I(x, y), gInfo))
|
||||
{
|
||||
if(gInfo.mPrimarySelect)
|
||||
continue;
|
||||
|
||||
if(gInfo.mWeight < weight)
|
||||
{
|
||||
gInfo.mWeight = weight;
|
||||
mTerrainEditor->getCurrentSel()->setInfo(gInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector<GridInfo> gInfos;
|
||||
mTerrainEditor->getGridInfos(gridPoint, gInfos);
|
||||
|
||||
for (U32 z = 0; z < gInfos.size(); z++)
|
||||
{
|
||||
gInfos[z].mWeight = weight;
|
||||
gInfos[z].mPrimarySelect = false;
|
||||
mTerrainEditor->getCurrentSel()->add(gInfos[z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void OutlineSelectAction::process(Selection * sel, const Gui3DMouseEvent & event, bool, Type type)
|
||||
{
|
||||
TORQUE_UNUSED(sel); TORQUE_UNUSED(event); TORQUE_UNUSED(type);
|
||||
switch(type)
|
||||
{
|
||||
case Begin:
|
||||
if(event.modifier & SI_SHIFT)
|
||||
break;
|
||||
|
||||
mTerrainEditor->getCurrentSel()->reset();
|
||||
break;
|
||||
|
||||
case End:
|
||||
case Update:
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
mLastEvent = event;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void PaintMaterialAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
S32 mat = mTerrainEditor->getPaintMaterialIndex();
|
||||
if ( !selChanged || mat < 0 )
|
||||
return;
|
||||
|
||||
const bool slopeLimit = mTerrainEditor->mSlopeMinAngle > 0.0f || mTerrainEditor->mSlopeMaxAngle < 90.0f;
|
||||
const F32 minSlope = mSin( mDegToRad( 90.0f - mTerrainEditor->mSlopeMinAngle ) );
|
||||
const F32 maxSlope = mSin( mDegToRad( 90.0f - mTerrainEditor->mSlopeMaxAngle ) );
|
||||
|
||||
const TerrainBlock *terrain = mTerrainEditor->getActiveTerrain();
|
||||
const F32 squareSize = terrain->getSquareSize();
|
||||
|
||||
Point2F p;
|
||||
Point3F norm;
|
||||
|
||||
|
||||
for( U32 i = 0; i < sel->size(); i++ )
|
||||
{
|
||||
GridInfo &inf = (*sel)[i];
|
||||
|
||||
if ( slopeLimit )
|
||||
{
|
||||
p.x = inf.mGridPoint.gridPos.x * squareSize;
|
||||
p.y = inf.mGridPoint.gridPos.y * squareSize;
|
||||
if ( !terrain->getNormal( p, &norm, true ) )
|
||||
continue;
|
||||
|
||||
if ( norm.z > minSlope ||
|
||||
norm.z < maxSlope )
|
||||
continue;
|
||||
}
|
||||
|
||||
// If grid is already set to our material, or it is an
|
||||
// empty grid spot, then skip painting.
|
||||
if ( inf.mMaterial == mat || inf.mMaterial == U8_MAX )
|
||||
continue;
|
||||
|
||||
if ( mRandF() > mTerrainEditor->getBrushPressure() )
|
||||
continue;
|
||||
|
||||
inf.mMaterialChanged = true;
|
||||
mTerrainEditor->getUndoSel()->add(inf);
|
||||
|
||||
// Painting is really simple now... set the one mat index.
|
||||
inf.mMaterial = mat;
|
||||
mTerrainEditor->setGridInfo(inf, true);
|
||||
}
|
||||
|
||||
mTerrainEditor->scheduleMaterialUpdate();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ClearMaterialsAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if(selChanged)
|
||||
{
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
GridInfo &inf = (*sel)[i];
|
||||
|
||||
mTerrainEditor->getUndoSel()->add(inf);
|
||||
inf.mMaterialChanged = true;
|
||||
|
||||
// Reset to the first texture layer.
|
||||
inf.mMaterial = 0;
|
||||
mTerrainEditor->setGridInfo(inf);
|
||||
}
|
||||
mTerrainEditor->scheduleMaterialUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void RaiseHeightAction::process( Selection *sel, const Gui3DMouseEvent &evt, bool selChanged, Type type )
|
||||
{
|
||||
// ok the raise height action is our "dirt pour" action
|
||||
// only works on brushes...
|
||||
|
||||
Brush *brush = dynamic_cast<Brush*>(sel);
|
||||
if ( !brush )
|
||||
return;
|
||||
|
||||
if ( type == End )
|
||||
return;
|
||||
|
||||
Point2I brushPos = brush->getPosition();
|
||||
Point2I brushSize = brush->getSize();
|
||||
GridPoint brushGridPoint = brush->getGridPoint();
|
||||
|
||||
Vector<GridInfo> cur; // the height at the brush position
|
||||
mTerrainEditor->getGridInfos(brushGridPoint, cur);
|
||||
|
||||
if ( cur.size() == 0 )
|
||||
return;
|
||||
|
||||
// we get 30 process actions per second (at least)
|
||||
F32 heightAdjust = mTerrainEditor->mAdjustHeightVal / 30;
|
||||
// nothing can get higher than the current brush pos adjusted height
|
||||
|
||||
F32 maxHeight = cur[0].mHeight + heightAdjust;
|
||||
|
||||
for ( U32 i = 0; i < sel->size(); i++ )
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
if ( (*sel)[i].mHeight < maxHeight )
|
||||
{
|
||||
(*sel)[i].mHeight += heightAdjust * (*sel)[i].mWeight;
|
||||
if ( (*sel)[i].mHeight > maxHeight )
|
||||
(*sel)[i].mHeight = maxHeight;
|
||||
}
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void LowerHeightAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type type)
|
||||
{
|
||||
// ok the lower height action is our "dirt dig" action
|
||||
// only works on brushes...
|
||||
|
||||
Brush *brush = dynamic_cast<Brush *>(sel);
|
||||
if(!brush)
|
||||
return;
|
||||
|
||||
if ( type == End )
|
||||
return;
|
||||
|
||||
Point2I brushPos = brush->getPosition();
|
||||
Point2I brushSize = brush->getSize();
|
||||
GridPoint brushGridPoint = brush->getGridPoint();
|
||||
|
||||
Vector<GridInfo> cur; // the height at the brush position
|
||||
mTerrainEditor->getGridInfos(brushGridPoint, cur);
|
||||
|
||||
if (cur.size() == 0)
|
||||
return;
|
||||
|
||||
// we get 30 process actions per second (at least)
|
||||
F32 heightAdjust = -mTerrainEditor->mAdjustHeightVal / 30;
|
||||
// nothing can get higher than the current brush pos adjusted height
|
||||
|
||||
F32 maxHeight = cur[0].mHeight + heightAdjust;
|
||||
if(maxHeight < 0)
|
||||
maxHeight = 0;
|
||||
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
if((*sel)[i].mHeight > maxHeight)
|
||||
{
|
||||
(*sel)[i].mHeight += heightAdjust * (*sel)[i].mWeight;
|
||||
if((*sel)[i].mHeight < maxHeight)
|
||||
(*sel)[i].mHeight = maxHeight;
|
||||
}
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SetHeightAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if(selChanged)
|
||||
{
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
(*sel)[i].mHeight = mTerrainEditor->mSetHeightVal;
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SetEmptyAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if ( !selChanged )
|
||||
return;
|
||||
|
||||
mTerrainEditor->setMissionDirty();
|
||||
|
||||
for ( U32 i = 0; i < sel->size(); i++ )
|
||||
{
|
||||
GridInfo &inf = (*sel)[i];
|
||||
|
||||
// Skip already empty blocks.
|
||||
if ( inf.mMaterial == U8_MAX )
|
||||
continue;
|
||||
|
||||
// The change flag needs to be set on the undo
|
||||
// so that it knows to restore materials.
|
||||
inf.mMaterialChanged = true;
|
||||
mTerrainEditor->getUndoSel()->add( inf );
|
||||
|
||||
// Set the material to empty.
|
||||
inf.mMaterial = -1;
|
||||
mTerrainEditor->setGridInfo( inf );
|
||||
}
|
||||
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ClearEmptyAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if ( !selChanged )
|
||||
return;
|
||||
|
||||
mTerrainEditor->setMissionDirty();
|
||||
|
||||
for ( U32 i = 0; i < sel->size(); i++ )
|
||||
{
|
||||
GridInfo &inf = (*sel)[i];
|
||||
|
||||
// Skip if not empty.
|
||||
if ( inf.mMaterial != U8_MAX )
|
||||
continue;
|
||||
|
||||
// The change flag needs to be set on the undo
|
||||
// so that it knows to restore materials.
|
||||
inf.mMaterialChanged = true;
|
||||
mTerrainEditor->getUndoSel()->add( inf );
|
||||
|
||||
// Set the material
|
||||
inf.mMaterial = 0;
|
||||
mTerrainEditor->setGridInfo( inf );
|
||||
}
|
||||
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ScaleHeightAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if(selChanged)
|
||||
{
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
(*sel)[i].mHeight *= mTerrainEditor->mScaleVal;
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void BrushAdjustHeightAction::process(Selection * sel, const Gui3DMouseEvent & event, bool, Type type)
|
||||
{
|
||||
if(type == Process)
|
||||
return;
|
||||
|
||||
TerrainBlock *terrBlock = mTerrainEditor->getActiveTerrain();
|
||||
if ( !terrBlock )
|
||||
return;
|
||||
|
||||
if(type == Begin)
|
||||
{
|
||||
mTerrainEditor->lockSelection(true);
|
||||
mTerrainEditor->getRoot()->mouseLock(mTerrainEditor);
|
||||
|
||||
// the way this works is:
|
||||
// construct a plane that goes through the collision point
|
||||
// with one axis up the terrain Z, and horizontally parallel to the
|
||||
// plane of projection
|
||||
|
||||
// the cross of the camera ffdv and the terrain up vector produces
|
||||
// the cross plane vector.
|
||||
|
||||
// all subsequent mouse actions are collided against the plane and the deltaZ
|
||||
// from the previous position is used to delta the selection up and down.
|
||||
Point3F cameraDir;
|
||||
|
||||
EditTSCtrl::smCamMatrix.getColumn(1, &cameraDir);
|
||||
terrBlock->getTransform().getColumn(2, &mTerrainUpVector);
|
||||
|
||||
// ok, get the cross vector for the plane:
|
||||
Point3F planeCross;
|
||||
mCross(cameraDir, mTerrainUpVector, &planeCross);
|
||||
|
||||
planeCross.normalize();
|
||||
Point3F planeNormal;
|
||||
|
||||
Point3F intersectPoint;
|
||||
mTerrainEditor->collide(event, intersectPoint);
|
||||
|
||||
mCross(mTerrainUpVector, planeCross, &planeNormal);
|
||||
mIntersectionPlane.set(intersectPoint, planeNormal);
|
||||
|
||||
// ok, we have the intersection point...
|
||||
// project the collision point onto the up vector of the terrain
|
||||
|
||||
mPreviousZ = mDot(mTerrainUpVector, intersectPoint);
|
||||
|
||||
// add to undo
|
||||
// and record the starting heights
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
(*sel)[i].mStartHeight = (*sel)[i].mHeight;
|
||||
}
|
||||
}
|
||||
else if(type == Update)
|
||||
{
|
||||
// ok, collide the ray from the event with the intersection plane:
|
||||
|
||||
Point3F intersectPoint;
|
||||
Point3F start = event.pos;
|
||||
Point3F end = start + event.vec * 1000;
|
||||
|
||||
F32 t = mIntersectionPlane.intersect(start, end);
|
||||
|
||||
m_point3F_interpolate( start, end, t, intersectPoint);
|
||||
F32 currentZ = mDot(mTerrainUpVector, intersectPoint);
|
||||
|
||||
F32 diff = currentZ - mPreviousZ;
|
||||
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
(*sel)[i].mHeight = (*sel)[i].mStartHeight + diff * (*sel)[i].mWeight;
|
||||
|
||||
// clamp it
|
||||
if((*sel)[i].mHeight < 0.f)
|
||||
(*sel)[i].mHeight = 0.f;
|
||||
if((*sel)[i].mHeight > 2047.f)
|
||||
(*sel)[i].mHeight = 2047.f;
|
||||
|
||||
mTerrainEditor->setGridInfoHeight((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
else if(type == End)
|
||||
{
|
||||
mTerrainEditor->getRoot()->mouseUnlock(mTerrainEditor);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
AdjustHeightAction::AdjustHeightAction(TerrainEditor * editor) :
|
||||
BrushAdjustHeightAction(editor)
|
||||
{
|
||||
mCursor = 0;
|
||||
}
|
||||
|
||||
void AdjustHeightAction::process(Selection *sel, const Gui3DMouseEvent & event, bool b, Type type)
|
||||
{
|
||||
Selection * curSel = mTerrainEditor->getCurrentSel();
|
||||
BrushAdjustHeightAction::process(curSel, event, b, type);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// flatten the primary selection then blend in the rest...
|
||||
|
||||
void FlattenHeightAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if(!sel->size())
|
||||
return;
|
||||
|
||||
if(selChanged)
|
||||
{
|
||||
F32 average = 0.f;
|
||||
|
||||
// get the average height
|
||||
U32 cPrimary = 0;
|
||||
for(U32 k = 0; k < sel->size(); k++)
|
||||
if((*sel)[k].mPrimarySelect)
|
||||
{
|
||||
cPrimary++;
|
||||
average += (*sel)[k].mHeight;
|
||||
}
|
||||
|
||||
average /= cPrimary;
|
||||
|
||||
// set it
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
|
||||
//
|
||||
if((*sel)[i].mPrimarySelect)
|
||||
(*sel)[i].mHeight = average;
|
||||
else
|
||||
{
|
||||
F32 h = average - (*sel)[i].mHeight;
|
||||
(*sel)[i].mHeight += (h * (*sel)[i].mWeight);
|
||||
}
|
||||
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SmoothHeightAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if(!sel->size())
|
||||
return;
|
||||
|
||||
if(selChanged)
|
||||
{
|
||||
F32 avgHeight = 0.f;
|
||||
for(U32 k = 0; k < sel->size(); k++)
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[k]);
|
||||
avgHeight += (*sel)[k].mHeight;
|
||||
}
|
||||
|
||||
avgHeight /= sel->size();
|
||||
|
||||
// clamp the terrain smooth factor...
|
||||
if(mTerrainEditor->mSmoothFactor < 0.f)
|
||||
mTerrainEditor->mSmoothFactor = 0.f;
|
||||
if(mTerrainEditor->mSmoothFactor > 1.f)
|
||||
mTerrainEditor->mSmoothFactor = 1.f;
|
||||
|
||||
// linear
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
(*sel)[i].mHeight += (avgHeight - (*sel)[i].mHeight) * mTerrainEditor->mSmoothFactor * (*sel)[i].mWeight;
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void PaintNoiseAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type type)
|
||||
{
|
||||
// If this is the ending
|
||||
// mouse down event, then
|
||||
// update the noise values.
|
||||
if ( type == Begin )
|
||||
{
|
||||
mNoise.setSeed( Sim::getCurrentTime() );
|
||||
mNoise.fBm( &mNoiseData, mNoiseSize, 12, 1.0f, 5.0f );
|
||||
mNoise.getMinMax( &mNoiseData, &mMinMaxNoise.x, &mMinMaxNoise.y, mNoiseSize );
|
||||
|
||||
mScale = 1.5f / ( mMinMaxNoise.x - mMinMaxNoise.y);
|
||||
}
|
||||
|
||||
if( selChanged )
|
||||
{
|
||||
for( U32 i = 0; i < sel->size(); i++ )
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
|
||||
const Point2I &gridPos = (*sel)[i].mGridPoint.gridPos;
|
||||
|
||||
const F32 noiseVal = mNoiseData[ ( gridPos.x % mNoiseSize ) +
|
||||
( ( gridPos.y % mNoiseSize ) * mNoiseSize ) ];
|
||||
|
||||
(*sel)[i].mHeight += (noiseVal - mMinMaxNoise.y * mScale) * (*sel)[i].mWeight * mTerrainEditor->mNoiseFactor;
|
||||
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
|
||||
mTerrainEditor->scheduleGridUpdate();
|
||||
}
|
||||
}
|
||||
/*
|
||||
void ThermalErosionAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if( selChanged )
|
||||
{
|
||||
TerrainBlock *tblock = mTerrainEditor->getActiveTerrain();
|
||||
if ( !tblock )
|
||||
return;
|
||||
|
||||
F32 height = 0;
|
||||
F32 maxHeight = 0;
|
||||
U32 shift = getBinLog2( TerrainBlock::BlockSize );
|
||||
|
||||
for ( U32 x = 0; x < TerrainBlock::BlockSize; x++ )
|
||||
{
|
||||
for ( U32 y = 0; y < TerrainBlock::BlockSize; y++ )
|
||||
{
|
||||
height = fixedToFloat( tblock->getHeight( x, y ) );
|
||||
mTerrainHeights[ x + (y << 8)] = height;
|
||||
|
||||
if ( height > maxHeight )
|
||||
maxHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
//mNoise.erodeThermal( &mTerrainHeights, &mNoiseData, 30.0f, 5.0f, 5, TerrainBlock::BlockSize, tblock->getSquareSize(), maxHeight );
|
||||
|
||||
mNoise.erodeHydraulic( &mTerrainHeights, &mNoiseData, 1, TerrainBlock::BlockSize );
|
||||
|
||||
F32 heightDiff = 0;
|
||||
|
||||
for( U32 i = 0; i < sel->size(); i++ )
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
|
||||
const Point2I &gridPos = (*sel)[i].mGridPoint.gridPos;
|
||||
|
||||
// Need to get the height difference
|
||||
// between the current height and the
|
||||
// erosion height to properly apply the
|
||||
// softness and pressure settings of the brush
|
||||
// for this selection.
|
||||
heightDiff = (*sel)[i].mHeight - mNoiseData[ gridPos.x + (gridPos.y << shift)];
|
||||
|
||||
(*sel)[i].mHeight -= (heightDiff * (*sel)[i].mWeight);
|
||||
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
|
||||
mTerrainEditor->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT( TerrainSmoothAction );
|
||||
|
||||
ConsoleDocClass( TerrainSmoothAction,
|
||||
"@brief Terrain action used for leveling varying terrain heights smoothly.\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
TerrainSmoothAction::TerrainSmoothAction()
|
||||
: UndoAction( "Terrain Smoothing" )
|
||||
{
|
||||
}
|
||||
|
||||
void TerrainSmoothAction::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void TerrainSmoothAction::smooth( TerrainBlock *terrain, F32 factor, U32 steps )
|
||||
{
|
||||
AssertFatal( terrain, "TerrainSmoothAction::smooth() - Got null object!" );
|
||||
|
||||
// Store our input parameters.
|
||||
mTerrainId = terrain->getId();
|
||||
mSteps = steps;
|
||||
mFactor = factor;
|
||||
|
||||
// The redo can do the rest.
|
||||
redo();
|
||||
}
|
||||
|
||||
ConsoleMethod( TerrainSmoothAction, smooth, void, 5, 5, "( TerrainBlock obj, F32 factor, U32 steps )")
|
||||
{
|
||||
TerrainBlock *terrain = NULL;
|
||||
if ( Sim::findObject( argv[2], terrain ) && terrain )
|
||||
object->smooth( terrain, dAtof( argv[3] ), mClamp( dAtoi( argv[4] ), 1, 13 ) );
|
||||
}
|
||||
|
||||
void TerrainSmoothAction::undo()
|
||||
{
|
||||
// First find the terrain from the id.
|
||||
TerrainBlock *terrain;
|
||||
if ( !Sim::findObject( mTerrainId, terrain ) || !terrain )
|
||||
return;
|
||||
|
||||
// Get the terrain file.
|
||||
TerrainFile *terrFile = terrain->getFile();
|
||||
|
||||
// Copy our stored heightmap to the file.
|
||||
terrFile->setHeightMap( mUnsmoothedHeights, false );
|
||||
|
||||
// Tell the terrain to update itself.
|
||||
terrain->updateGrid( Point2I::Zero, Point2I::Max, true );
|
||||
}
|
||||
|
||||
void TerrainSmoothAction::redo()
|
||||
{
|
||||
// First find the terrain from the id.
|
||||
TerrainBlock *terrain;
|
||||
if ( !Sim::findObject( mTerrainId, terrain ) || !terrain )
|
||||
return;
|
||||
|
||||
// Get the terrain file.
|
||||
TerrainFile *terrFile = terrain->getFile();
|
||||
|
||||
// First copy the heightmap state.
|
||||
mUnsmoothedHeights = terrFile->getHeightMap();
|
||||
|
||||
// Do the smooth.
|
||||
terrFile->smooth( mFactor, mSteps, false );
|
||||
|
||||
// Tell the terrain to update itself.
|
||||
terrain->updateGrid( Point2I::Zero, Point2I::Max, true );
|
||||
}
|
||||
351
Engine/source/gui/worldEditor/terrainActions.h
Normal file
351
Engine/source/gui/worldEditor/terrainActions.h
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TERRAINACTIONS_H_
|
||||
#define _TERRAINACTIONS_H_
|
||||
|
||||
#ifndef _TERRAINEDITOR_H_
|
||||
#include "gui/worldEditor/terrainEditor.h"
|
||||
#endif
|
||||
#ifndef _GUIFILTERCTRL_H_
|
||||
#include "gui/editor/guiFilterCtrl.h"
|
||||
#endif
|
||||
#ifndef _UNDO_H_
|
||||
#include "util/undo.h"
|
||||
#endif
|
||||
#ifndef _NOISE2D_H_
|
||||
#include "util/noise2d.h"
|
||||
#endif
|
||||
|
||||
class TerrainAction
|
||||
{
|
||||
protected:
|
||||
TerrainEditor * mTerrainEditor;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~TerrainAction(){};
|
||||
TerrainAction(TerrainEditor * editor) : mTerrainEditor(editor){}
|
||||
|
||||
virtual StringTableEntry getName() = 0;
|
||||
|
||||
enum Type {
|
||||
Begin = 0,
|
||||
Update,
|
||||
End,
|
||||
Process
|
||||
};
|
||||
|
||||
//
|
||||
virtual void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type) = 0;
|
||||
virtual bool useMouseBrush() { return(true); }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class SelectAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
SelectAction(TerrainEditor * editor) : TerrainAction(editor){};
|
||||
StringTableEntry getName(){return("select");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
class DeselectAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
DeselectAction(TerrainEditor * editor) : TerrainAction(editor){};
|
||||
StringTableEntry getName(){return("deselect");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
class ClearAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
ClearAction(TerrainEditor * editor) : TerrainAction(editor){};
|
||||
StringTableEntry getName(){return("clear");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type) {};
|
||||
bool useMouseBrush() { mTerrainEditor->getCurrentSel()->reset(); return true; }
|
||||
};
|
||||
|
||||
|
||||
class SoftSelectAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
SoftSelectAction(TerrainEditor * editor) : TerrainAction(editor){};
|
||||
StringTableEntry getName(){return("softSelect");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
|
||||
Filter mFilter;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class OutlineSelectAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
OutlineSelectAction(TerrainEditor * editor) : TerrainAction(editor){};
|
||||
StringTableEntry getName(){return("outlineSelect");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
bool useMouseBrush() { return(false); }
|
||||
|
||||
private:
|
||||
|
||||
Gui3DMouseEvent mLastEvent;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class PaintMaterialAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
PaintMaterialAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("paintMaterial");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ClearMaterialsAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
ClearMaterialsAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("clearMaterials");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class RaiseHeightAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
RaiseHeightAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("raiseHeight");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class LowerHeightAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
LowerHeightAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("lowerHeight");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class SetHeightAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
SetHeightAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("setHeight");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class SetEmptyAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
SetEmptyAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("setEmpty");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ClearEmptyAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
ClearEmptyAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("clearEmpty");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ScaleHeightAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
ScaleHeightAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("scaleHeight");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class BrushAdjustHeightAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
BrushAdjustHeightAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("brushAdjustHeight");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
|
||||
private:
|
||||
PlaneF mIntersectionPlane;
|
||||
Point3F mTerrainUpVector;
|
||||
F32 mPreviousZ;
|
||||
};
|
||||
|
||||
class AdjustHeightAction : public BrushAdjustHeightAction
|
||||
{
|
||||
public:
|
||||
AdjustHeightAction(TerrainEditor * editor);
|
||||
StringTableEntry getName(){return("adjustHeight");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
bool useMouseBrush() { return(false); }
|
||||
|
||||
private:
|
||||
//
|
||||
Point3F mHitPos;
|
||||
Point3F mLastPos;
|
||||
SimObjectPtr<GuiCursor> mCursor;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class FlattenHeightAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
FlattenHeightAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("flattenHeight");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
class SmoothHeightAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
SmoothHeightAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("smoothHeight");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
class PaintNoiseAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
|
||||
PaintNoiseAction( TerrainEditor *editor )
|
||||
: TerrainAction( editor ),
|
||||
mNoiseSize( 256 )
|
||||
{
|
||||
mNoise.setSeed( 5342219 );
|
||||
mNoiseData.setSize( mNoiseSize * mNoiseSize );
|
||||
mNoise.fBm( &mNoiseData, mNoiseSize, 12, 1.0f, 5.0f );
|
||||
//Vector<F32> scratch = mNoiseData;
|
||||
//mNoise.rigidMultiFractal( &mNoiseData, &scratch, TerrainBlock::BlockSize, 12, 1.0f, 5.0f );
|
||||
mNoise.getMinMax( &mNoiseData, &mMinMaxNoise.x, &mMinMaxNoise.y, mNoiseSize );
|
||||
|
||||
mScale = 1.5f / ( mMinMaxNoise.x - mMinMaxNoise.y);
|
||||
}
|
||||
|
||||
StringTableEntry getName() { return "paintNoise"; }
|
||||
|
||||
void process( Selection *sel, const Gui3DMouseEvent &event, bool selChanged, Type type );
|
||||
|
||||
protected:
|
||||
|
||||
const U32 mNoiseSize;
|
||||
|
||||
Noise2D mNoise;
|
||||
|
||||
Vector<F32> mNoiseData;
|
||||
|
||||
Point2F mMinMaxNoise;
|
||||
|
||||
F32 mScale;
|
||||
};
|
||||
|
||||
/*
|
||||
class ThermalErosionAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
ThermalErosionAction(TerrainEditor * editor)
|
||||
: TerrainAction(editor)
|
||||
{
|
||||
mNoise.setSeed( 1 );//Sim::getCurrentTime() );
|
||||
mNoiseData.setSize( TerrainBlock::BlockSize * TerrainBlock::BlockSize );
|
||||
mTerrainHeights.setSize( TerrainBlock::BlockSize * TerrainBlock::BlockSize );
|
||||
}
|
||||
|
||||
StringTableEntry getName(){return("thermalErode");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
|
||||
Noise2D mNoise;
|
||||
Vector<F32> mNoiseData;
|
||||
Vector<F32> mTerrainHeights;
|
||||
};
|
||||
*/
|
||||
|
||||
/// An undo action used to perform terrain wide smoothing.
|
||||
class TerrainSmoothAction : public UndoAction
|
||||
{
|
||||
typedef UndoAction Parent;
|
||||
|
||||
protected:
|
||||
|
||||
SimObjectId mTerrainId;
|
||||
|
||||
U32 mSteps;
|
||||
|
||||
F32 mFactor;
|
||||
|
||||
Vector<U16> mUnsmoothedHeights;
|
||||
|
||||
public:
|
||||
|
||||
TerrainSmoothAction();
|
||||
|
||||
// SimObject
|
||||
DECLARE_CONOBJECT( TerrainSmoothAction );
|
||||
static void initPersistFields();
|
||||
|
||||
// UndoAction
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
|
||||
/// Performs the initial smoothing and stores
|
||||
/// the heighfield state for later undo.
|
||||
void smooth( TerrainBlock *terrain, F32 factor, U32 steps );
|
||||
};
|
||||
|
||||
|
||||
#endif // _TERRAINACTIONS_H_
|
||||
2935
Engine/source/gui/worldEditor/terrainEditor.cpp
Normal file
2935
Engine/source/gui/worldEditor/terrainEditor.cpp
Normal file
File diff suppressed because it is too large
Load diff
497
Engine/source/gui/worldEditor/terrainEditor.h
Normal file
497
Engine/source/gui/worldEditor/terrainEditor.h
Normal file
|
|
@ -0,0 +1,497 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TERRAINEDITOR_H_
|
||||
#define _TERRAINEDITOR_H_
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#include "gui/worldEditor/editTSCtrl.h"
|
||||
#endif
|
||||
#ifndef _TERRDATA_H_
|
||||
#include "terrain/terrData.h"
|
||||
#endif
|
||||
#ifndef _UNDO_H_
|
||||
#include "util/undo.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Each 2D grid position must be associated with a terrainBlock
|
||||
struct GridPoint
|
||||
{
|
||||
Point2I gridPos;
|
||||
TerrainBlock* terrainBlock;
|
||||
|
||||
GridPoint() { gridPos.set(0, 0); terrainBlock = NULL; };
|
||||
};
|
||||
|
||||
class GridInfo
|
||||
{
|
||||
public:
|
||||
|
||||
GridPoint mGridPoint;
|
||||
U8 mMaterial;
|
||||
F32 mHeight;
|
||||
F32 mWeight;
|
||||
F32 mStartHeight;
|
||||
|
||||
bool mPrimarySelect;
|
||||
bool mMaterialChanged;
|
||||
|
||||
// hash table
|
||||
S32 mNext;
|
||||
S32 mPrev;
|
||||
};
|
||||
|
||||
|
||||
class Selection : public Vector<GridInfo>
|
||||
{
|
||||
private:
|
||||
|
||||
StringTableEntry mName;
|
||||
BitSet32 mUndoFlags;
|
||||
|
||||
// hash table
|
||||
S32 lookup(const Point2I & pos);
|
||||
void insert(GridInfo info);
|
||||
U32 getHashIndex(const Point2I & pos);
|
||||
bool validate();
|
||||
|
||||
Vector<S32> mHashLists;
|
||||
U32 mHashListSize;
|
||||
|
||||
public:
|
||||
|
||||
Selection();
|
||||
virtual ~Selection();
|
||||
|
||||
void reset();
|
||||
|
||||
/// add unique grid info into the selection - test uniqueness by grid position
|
||||
bool add(const GridInfo &info);
|
||||
bool getInfo(Point2I pos, GridInfo & info);
|
||||
bool setInfo(GridInfo & info);
|
||||
bool remove(const GridInfo &info);
|
||||
void setName(StringTableEntry name);
|
||||
StringTableEntry getName(){return(mName);}
|
||||
F32 getAvgHeight();
|
||||
F32 getMinHeight();
|
||||
F32 getMaxHeight();
|
||||
};
|
||||
|
||||
|
||||
class TerrainEditor;
|
||||
|
||||
class Brush : public Selection
|
||||
{
|
||||
protected:
|
||||
|
||||
TerrainEditor * mTerrainEditor;
|
||||
Point2I mSize;
|
||||
GridPoint mGridPoint;
|
||||
Vector<S32> mRenderList;
|
||||
|
||||
public:
|
||||
|
||||
enum { MaxBrushDim = 40 };
|
||||
|
||||
Brush(TerrainEditor * editor);
|
||||
virtual ~Brush(){};
|
||||
|
||||
virtual const char *getType() const = 0;
|
||||
|
||||
// Brush appears to intentionally bypass Selection's hash table, so we
|
||||
// override validate() here.
|
||||
bool validate() { return true; }
|
||||
void setPosition(const Point3F & pos);
|
||||
void setPosition(const Point2I & pos);
|
||||
const Point2I & getPosition();
|
||||
const GridPoint & getGridPoint();
|
||||
void setTerrain(TerrainBlock* terrain) { mGridPoint.terrainBlock = terrain; };
|
||||
Point2I getSize() const {return(mSize);}
|
||||
virtual void setSize(const Point2I & size){mSize = size;}
|
||||
|
||||
void update();
|
||||
void render();
|
||||
|
||||
virtual void rebuild() = 0;
|
||||
virtual void _renderOutline() = 0;
|
||||
};
|
||||
|
||||
class BoxBrush : public Brush
|
||||
{
|
||||
public:
|
||||
|
||||
BoxBrush(TerrainEditor * editor) : Brush(editor){}
|
||||
|
||||
const char *getType() const { return "box"; }
|
||||
void rebuild();
|
||||
|
||||
protected:
|
||||
|
||||
void _renderOutline();
|
||||
};
|
||||
|
||||
class EllipseBrush : public Brush
|
||||
{
|
||||
public:
|
||||
|
||||
EllipseBrush(TerrainEditor * editor) : Brush(editor){}
|
||||
|
||||
const char *getType() const { return "ellipse"; }
|
||||
void rebuild();
|
||||
|
||||
protected:
|
||||
|
||||
void _renderOutline();
|
||||
};
|
||||
|
||||
class SelectionBrush : public Brush
|
||||
{
|
||||
public:
|
||||
|
||||
SelectionBrush(TerrainEditor * editor);
|
||||
|
||||
const char *getType() const { return "selection"; }
|
||||
void rebuild();
|
||||
void render(Vector<GFXVertexPC> & vertexBuffer, S32 & verts, S32 & elems, S32 & prims, const ColorF & inColorFull, const ColorF & inColorNone, const ColorF & outColorFull, const ColorF & outColorNone) const;
|
||||
void setSize(const Point2I &){}
|
||||
|
||||
protected:
|
||||
|
||||
void _renderOutline() {}
|
||||
};
|
||||
|
||||
|
||||
class TerrainAction;
|
||||
|
||||
class TerrainEditor : public EditTSCtrl
|
||||
{
|
||||
// XA: This methods where added to replace the friend consoleMethods.
|
||||
public:
|
||||
void attachTerrain(TerrainBlock *terrBlock);
|
||||
void detachTerrain(TerrainBlock *terrBlock);
|
||||
|
||||
S32 getTerrainBlockCount() {return mTerrainBlocks.size();}
|
||||
TerrainBlock* getTerrainBlock(S32 index);
|
||||
void getTerrainBlocksMaterialList(Vector<StringTableEntry>& list); // Returns consolidated list of all materials used on all terrain blocks
|
||||
|
||||
void setBrushType(const char* type);
|
||||
const char* getBrushType() const;
|
||||
|
||||
void setBrushSize(S32 w, S32 h);
|
||||
const char* getBrushPos();
|
||||
void setBrushPos(Point2I pos);
|
||||
|
||||
void setAction(const char* action);
|
||||
const char* getActionName(U32 index);
|
||||
const char* getCurrentAction() const;
|
||||
S32 getNumActions();
|
||||
void processAction(const char* sAction);
|
||||
|
||||
void resetSelWeights(bool clear);
|
||||
void clearSelection();
|
||||
|
||||
S32 getNumTextures();
|
||||
|
||||
void markEmptySquares();
|
||||
|
||||
void mirrorTerrain(S32 mirrorIndex);
|
||||
|
||||
TerrainBlock* getActiveTerrain() { return mActiveTerrain; };
|
||||
|
||||
void scheduleGridUpdate() { mNeedsGridUpdate = true; }
|
||||
void scheduleMaterialUpdate() { mNeedsMaterialUpdate = true; }
|
||||
void setGridUpdateMinMax()
|
||||
{
|
||||
mGridUpdateMax.set( S32_MAX, S32_MAX );
|
||||
mGridUpdateMin.set( 0, 0 );
|
||||
}
|
||||
|
||||
void submitMaterialUndo( String actionName );
|
||||
void onMaterialUndo( TerrainBlock *terr );
|
||||
|
||||
private:
|
||||
|
||||
typedef EditTSCtrl Parent;
|
||||
|
||||
TerrainBlock* mActiveTerrain;
|
||||
|
||||
// A list of all of the TerrainBlocks this editor can edit
|
||||
VectorPtr<TerrainBlock*> mTerrainBlocks;
|
||||
|
||||
Point2I mGridUpdateMin;
|
||||
Point2I mGridUpdateMax;
|
||||
U32 mMouseDownSeq;
|
||||
|
||||
/// If one of these flags when the terrainEditor goes to render
|
||||
/// an appropriate update method will be called on the terrain.
|
||||
/// This prevents unnecessary work from happening from directly
|
||||
/// within an editor event's process method.
|
||||
bool mNeedsGridUpdate;
|
||||
bool mNeedsMaterialUpdate;
|
||||
|
||||
bool mMouseDown;
|
||||
PlaneF mMousePlane;
|
||||
Point3F mMousePos;
|
||||
Brush * mMouseBrush;
|
||||
bool mBrushChanged;
|
||||
bool mRenderBrush;
|
||||
F32 mBrushPressure;
|
||||
Point2I mBrushSize;
|
||||
F32 mBrushSoftness;
|
||||
Vector<TerrainAction *> mActions;
|
||||
TerrainAction * mCurrentAction;
|
||||
bool mInAction;
|
||||
Selection mDefaultSel;
|
||||
bool mSelectionLocked;
|
||||
|
||||
S32 mPaintIndex;
|
||||
|
||||
Selection * mCurrentSel;
|
||||
|
||||
class TerrainEditorUndoAction : public UndoAction
|
||||
{
|
||||
public:
|
||||
|
||||
TerrainEditorUndoAction( const UTF8* actionName )
|
||||
: UndoAction( actionName ),
|
||||
mTerrainEditor( NULL ),
|
||||
mSel( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TerrainEditorUndoAction()
|
||||
{
|
||||
delete mSel;
|
||||
}
|
||||
|
||||
TerrainEditor *mTerrainEditor;
|
||||
|
||||
Selection *mSel;
|
||||
|
||||
virtual void undo();
|
||||
virtual void redo() { undo(); }
|
||||
};
|
||||
|
||||
void submitUndo( Selection *sel );
|
||||
|
||||
Selection *mUndoSel;
|
||||
|
||||
class TerrainMaterialUndoAction : public UndoAction
|
||||
{
|
||||
public:
|
||||
|
||||
TerrainMaterialUndoAction( const UTF8 *actionName )
|
||||
: UndoAction( actionName ),
|
||||
mEditor( NULL ),
|
||||
mTerrain( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
TerrainEditor *mEditor;
|
||||
TerrainBlock *mTerrain;
|
||||
Vector<U8> mLayerMap;
|
||||
Vector<TerrainMaterial*> mMaterials;
|
||||
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
};
|
||||
|
||||
bool mIsDirty; // dirty flag for writing terrain.
|
||||
bool mIsMissionDirty; // dirty flag for writing mission.
|
||||
|
||||
GFXStateBlockRef mStateBlock;
|
||||
|
||||
public:
|
||||
|
||||
TerrainEditor();
|
||||
~TerrainEditor();
|
||||
|
||||
// conversion functions
|
||||
// Returns true if the grid position is on the main tile
|
||||
bool isMainTile(const GridPoint & gPoint) const;
|
||||
|
||||
// Takes a world point and find the "highest" terrain underneath it
|
||||
// Returns true if the returned GridPoint includes a valid terrain and grid position
|
||||
TerrainBlock* getTerrainUnderWorldPoint(const Point3F & wPos);
|
||||
|
||||
// Converts a GridPoint to a world position
|
||||
bool gridToWorld(const GridPoint & gPoint, Point3F & wPos);
|
||||
bool gridToWorld(const Point2I & gPos, Point3F & wPos, TerrainBlock* terrain);
|
||||
|
||||
// Converts a world position to a grid point
|
||||
// If the grid point does not have a TerrainBlock already it will find the nearest
|
||||
// terrian under the world position
|
||||
bool worldToGrid(const Point3F & wPos, GridPoint & gPoint);
|
||||
bool worldToGrid(const Point3F & wPos, Point2I & gPos, TerrainBlock* terrain = NULL);
|
||||
|
||||
// Converts any point that is off of the main tile to its equivalent on the main tile
|
||||
// Returns true if the point was already on the main tile
|
||||
bool gridToCenter(const Point2I & gPos, Point2I & cPos) const;
|
||||
|
||||
//bool getGridInfo(const Point3F & wPos, GridInfo & info);
|
||||
// Gets the grid info for a point on a TerrainBlock's grid
|
||||
bool getGridInfo(const GridPoint & gPoint, GridInfo & info);
|
||||
bool getGridInfo(const Point2I & gPos, GridInfo & info, TerrainBlock* terrain);
|
||||
|
||||
// Returns a list of infos for all points on the terrain that are at that point in space
|
||||
void getGridInfos(const GridPoint & gPoint, Vector<GridInfo>& infos);
|
||||
|
||||
void setGridInfo(const GridInfo & info, bool checkActive = false);
|
||||
void setGridInfoHeight(const GridInfo & info);
|
||||
void gridUpdateComplete( bool materialChanged = false );
|
||||
void materialUpdateComplete();
|
||||
void processActionTick(U32 sequence);
|
||||
|
||||
TerrainBlock* collide(const Gui3DMouseEvent & event, Point3F & pos);
|
||||
void lockSelection(bool lock) { mSelectionLocked = lock; };
|
||||
|
||||
Selection * getUndoSel(){return(mUndoSel);}
|
||||
Selection * getCurrentSel(){return(mCurrentSel);}
|
||||
void setCurrentSel(Selection * sel) { mCurrentSel = sel; }
|
||||
void resetCurrentSel() {mCurrentSel = &mDefaultSel; }
|
||||
|
||||
S32 getPaintMaterialIndex() const { return mPaintIndex; }
|
||||
|
||||
void setBrushPressure( F32 pressure );
|
||||
F32 getBrushPressure() const { return mBrushPressure; }
|
||||
|
||||
void setBrushSoftness( F32 softness );
|
||||
F32 getBrushSoftness() const { return mBrushSoftness; }
|
||||
|
||||
Point2I getBrushSize() { return(mBrushSize); }
|
||||
|
||||
TerrainBlock* getTerrainBlock() const { return mActiveTerrain; }
|
||||
TerrainBlock* getClientTerrain( TerrainBlock *serverTerrain = NULL ) const;
|
||||
bool terrainBlockValid() { return(mActiveTerrain ? true : false); }
|
||||
void setDirty() { mIsDirty = true; }
|
||||
void setMissionDirty() { mIsMissionDirty = true; }
|
||||
|
||||
TerrainAction * lookupAction(const char * name);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
// terrain interface functions
|
||||
// Returns the height at a grid point
|
||||
F32 getGridHeight(const GridPoint & gPoint);
|
||||
// Sets a height at a grid point
|
||||
void setGridHeight(const GridPoint & gPoint, const F32 height);
|
||||
|
||||
///
|
||||
U8 getGridMaterial( const GridPoint &gPoint ) const;
|
||||
|
||||
///
|
||||
void setGridMaterial( const GridPoint & gPoint, U8 index );
|
||||
|
||||
// Gets the material group of a specific spot on a TerrainBlock's grid
|
||||
U8 getGridMaterialGroup(const GridPoint & gPoint);
|
||||
|
||||
// Sets a material group for a spot on a TerrainBlock's grid
|
||||
void setGridMaterialGroup(const GridPoint & gPoint, U8 group);
|
||||
|
||||
//
|
||||
void updateBrush(Brush & brush, const Point2I & gPos);
|
||||
|
||||
//
|
||||
void renderSelection(const Selection & sel, const ColorF & inColorFull, const ColorF & inColorNone, const ColorF & outColorFull, const ColorF & outColorNone, bool renderFill, bool renderFrame);
|
||||
void renderBrush(const Brush & brush, const ColorF & inColorFull, const ColorF & inColorNone, const ColorF & outColorFull, const ColorF & outColorNone, bool renderFill, bool renderFrame);
|
||||
void renderBorder();
|
||||
|
||||
public:
|
||||
|
||||
// persist field data - these are dynamic
|
||||
bool mRenderBorder;
|
||||
F32 mBorderHeight;
|
||||
ColorI mBorderFillColor;
|
||||
ColorI mBorderFrameColor;
|
||||
bool mBorderLineMode;
|
||||
bool mSelectionHidden;
|
||||
bool mRenderVertexSelection;
|
||||
bool mRenderSolidBrush;
|
||||
bool mProcessUsesBrush;
|
||||
|
||||
//
|
||||
F32 mAdjustHeightVal;
|
||||
F32 mSetHeightVal;
|
||||
F32 mScaleVal;
|
||||
F32 mSmoothFactor;
|
||||
F32 mNoiseFactor;
|
||||
S32 mMaterialGroup;
|
||||
F32 mSoftSelectRadius;
|
||||
StringTableEntry mSoftSelectFilter;
|
||||
StringTableEntry mSoftSelectDefaultFilter;
|
||||
F32 mAdjustHeightMouseScale;
|
||||
Point2I mMaxBrushSize;
|
||||
|
||||
F32 mSlopeMinAngle;
|
||||
F32 mSlopeMaxAngle;
|
||||
|
||||
public:
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onDeleteNotify(SimObject * object);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
// GuiControl
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
// EditTSCtrl
|
||||
bool onInputEvent( const InputEventInfo & evt );
|
||||
void on3DMouseUp( const Gui3DMouseEvent & evt );
|
||||
void on3DMouseDown( const Gui3DMouseEvent & evt );
|
||||
void on3DMouseMove( const Gui3DMouseEvent & evt );
|
||||
void on3DMouseDragged( const Gui3DMouseEvent & evt );
|
||||
bool onMouseWheelUp( const GuiEvent & evt );
|
||||
bool onMouseWheelDown( const GuiEvent & evt );
|
||||
void get3DCursor( GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &evt );
|
||||
void onPreRender();
|
||||
void renderScene(const RectI & updateRect);
|
||||
void renderGui( Point2I offset, const RectI &updateRect );
|
||||
void updateGuiInfo();
|
||||
|
||||
// Determine if the given grid point is valid within a non-wrap
|
||||
// around terrain.
|
||||
bool isPointInTerrain( const GridPoint & gPoint);
|
||||
|
||||
/// Reorder material at the given index to the new position, changing the order in which it is rendered / blended
|
||||
void reorderMaterial( S32 index, S32 orderPos );
|
||||
|
||||
//
|
||||
Point3F getMousePos(){return(mMousePos);};
|
||||
|
||||
void renderPoints( const Vector<GFXVertexPCT> &pointList );
|
||||
|
||||
|
||||
DECLARE_CONOBJECT(TerrainEditor);
|
||||
};
|
||||
|
||||
inline void TerrainEditor::setGridInfoHeight(const GridInfo & info)
|
||||
{
|
||||
setGridHeight(info.mGridPoint, info.mHeight);
|
||||
}
|
||||
|
||||
#endif
|
||||
272
Engine/source/gui/worldEditor/undoActions.cpp
Normal file
272
Engine/source/gui/worldEditor/undoActions.cpp
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/worldEditor/undoActions.h"
|
||||
|
||||
#include "gui/editor/inspector/field.h"
|
||||
#include "gui/editor/guiInspector.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT( MECreateUndoAction );
|
||||
|
||||
ConsoleDocClass( MECreateUndoAction,
|
||||
"@brief Material Editor create undo instance\n\n"
|
||||
"Not intended for game development, for editors or internal use only.\n\n "
|
||||
"@internal");
|
||||
|
||||
MECreateUndoAction::MECreateUndoAction( const UTF8* actionName )
|
||||
: UndoAction( actionName )
|
||||
{
|
||||
}
|
||||
|
||||
MECreateUndoAction::~MECreateUndoAction()
|
||||
{
|
||||
}
|
||||
|
||||
void MECreateUndoAction::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void MECreateUndoAction::addObject( SimObject *object )
|
||||
{
|
||||
AssertFatal( object, "MECreateUndoAction::addObject() - Got null object!" );
|
||||
|
||||
mObjects.increment();
|
||||
mObjects.last().id = object->getId();
|
||||
}
|
||||
|
||||
ConsoleMethod( MECreateUndoAction, addObject, void, 3, 3, "( SimObject obj )")
|
||||
{
|
||||
SimObject *obj = NULL;
|
||||
if ( Sim::findObject( argv[2], obj ) && obj )
|
||||
object->addObject( obj );
|
||||
}
|
||||
|
||||
void MECreateUndoAction::undo()
|
||||
{
|
||||
for ( S32 i= mObjects.size()-1; i >= 0; i-- )
|
||||
{
|
||||
ObjectState &state = mObjects[i];
|
||||
|
||||
SimObject *object = Sim::findObject( state.id );
|
||||
if ( !object )
|
||||
continue;
|
||||
|
||||
// Save the state.
|
||||
if ( !state.memento.hasState() )
|
||||
state.memento.save( object );
|
||||
|
||||
// Store the group.
|
||||
SimGroup *group = object->getGroup();
|
||||
if ( group )
|
||||
state.groupId = group->getId();
|
||||
|
||||
// We got what we need... delete it.
|
||||
object->deleteObject();
|
||||
}
|
||||
|
||||
Con::executef( this, "onUndone" );
|
||||
}
|
||||
|
||||
void MECreateUndoAction::redo()
|
||||
{
|
||||
for ( S32 i=0; i < mObjects.size(); i++ )
|
||||
{
|
||||
const ObjectState &state = mObjects[i];
|
||||
|
||||
// Create the object.
|
||||
SimObject::setForcedId(state.id); // Restore the object's Id
|
||||
SimObject *object = state.memento.restore();
|
||||
if ( !object )
|
||||
continue;
|
||||
|
||||
// Now restore its group.
|
||||
SimGroup *group;
|
||||
if ( Sim::findObject( state.groupId, group ) )
|
||||
group->addObject( object );
|
||||
}
|
||||
|
||||
Con::executef( this, "onRedone" );
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT( MEDeleteUndoAction );
|
||||
|
||||
ConsoleDocClass( MEDeleteUndoAction,
|
||||
"@brief Material Editor delete undo instance\n\n"
|
||||
"Not intended for game development, for editors or internal use only.\n\n "
|
||||
"@internal");
|
||||
|
||||
MEDeleteUndoAction::MEDeleteUndoAction( const UTF8 *actionName )
|
||||
: UndoAction( actionName )
|
||||
{
|
||||
}
|
||||
|
||||
MEDeleteUndoAction::~MEDeleteUndoAction()
|
||||
{
|
||||
}
|
||||
|
||||
void MEDeleteUndoAction::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void MEDeleteUndoAction::deleteObject( SimObject *object )
|
||||
{
|
||||
AssertFatal( object, "MEDeleteUndoAction::deleteObject() - Got null object!" );
|
||||
AssertFatal( object->isProperlyAdded(),
|
||||
"MEDeleteUndoAction::deleteObject() - Object should be registered!" );
|
||||
|
||||
mObjects.increment();
|
||||
ObjectState& state = mObjects.last();
|
||||
|
||||
// Capture the object id.
|
||||
state.id = object->getId();
|
||||
|
||||
// Save the state.
|
||||
state.memento.save( object );
|
||||
|
||||
// Store the group.
|
||||
SimGroup *group = object->getGroup();
|
||||
if ( group )
|
||||
state.groupId = group->getId();
|
||||
|
||||
// Now delete the object.
|
||||
object->deleteObject();
|
||||
}
|
||||
|
||||
void MEDeleteUndoAction::deleteObject( const Vector<SimObject*> &objectList )
|
||||
{
|
||||
for ( S32 i = 0; i < objectList.size(); i++ )
|
||||
deleteObject( objectList[i] );
|
||||
}
|
||||
|
||||
ConsoleMethod( MEDeleteUndoAction, deleteObject, void, 3, 3, "( SimObject obj )")
|
||||
{
|
||||
SimObject *obj = NULL;
|
||||
if ( Sim::findObject( argv[2], obj ) && obj )
|
||||
object->deleteObject( obj );
|
||||
}
|
||||
|
||||
void MEDeleteUndoAction::undo()
|
||||
{
|
||||
for ( S32 i= mObjects.size()-1; i >= 0; i-- )
|
||||
{
|
||||
const ObjectState &state = mObjects[i];
|
||||
|
||||
// Create the object.
|
||||
SimObject::setForcedId(state.id); // Restore the object's Id
|
||||
SimObject *object = state.memento.restore();
|
||||
if ( !object )
|
||||
continue;
|
||||
|
||||
// Now restore its group.
|
||||
SimGroup *group;
|
||||
if ( Sim::findObject( state.groupId, group ) )
|
||||
group->addObject( object );
|
||||
}
|
||||
|
||||
Con::executef( this, "onUndone" );
|
||||
}
|
||||
|
||||
void MEDeleteUndoAction::redo()
|
||||
{
|
||||
for ( S32 i=0; i < mObjects.size(); i++ )
|
||||
{
|
||||
const ObjectState& state = mObjects[i];
|
||||
SimObject *object = Sim::findObject( state.id );
|
||||
if ( object )
|
||||
object->deleteObject();
|
||||
}
|
||||
|
||||
Con::executef( this, "onRedone" );
|
||||
}
|
||||
|
||||
IMPLEMENT_CONOBJECT( InspectorFieldUndoAction );
|
||||
|
||||
ConsoleDocClass( InspectorFieldUndoAction,
|
||||
"@brief Inspector Field undo action instance\n\n"
|
||||
"Not intended for game development, for editors or internal use only.\n\n "
|
||||
"@internal");
|
||||
|
||||
InspectorFieldUndoAction::InspectorFieldUndoAction()
|
||||
{
|
||||
mObjId = 0;
|
||||
mField = NULL;
|
||||
mSlotName = StringTable->insert("");
|
||||
mArrayIdx = StringTable->insert("");
|
||||
}
|
||||
|
||||
InspectorFieldUndoAction::InspectorFieldUndoAction( const UTF8 *actionName )
|
||||
: UndoAction( actionName )
|
||||
{
|
||||
mInspector = NULL;
|
||||
mObjId = 0;
|
||||
mField = NULL;
|
||||
mSlotName = StringTable->insert("");
|
||||
mArrayIdx = StringTable->insert("");
|
||||
}
|
||||
|
||||
void InspectorFieldUndoAction::initPersistFields()
|
||||
{
|
||||
addField( "inspectorGui", TYPEID< GuiInspector >(), Offset( mInspector, InspectorFieldUndoAction ) );
|
||||
addField( "objectId", TypeS32, Offset( mObjId, InspectorFieldUndoAction ) );
|
||||
addField( "fieldName", TypeString, Offset( mSlotName, InspectorFieldUndoAction ) );
|
||||
addField( "fieldValue", TypeRealString, Offset( mData, InspectorFieldUndoAction ) );
|
||||
addField( "arrayIndex", TypeString, Offset( mArrayIdx, InspectorFieldUndoAction ) );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void InspectorFieldUndoAction::undo()
|
||||
{
|
||||
SimObject *obj = NULL;
|
||||
if ( !Sim::findObject( mObjId, obj ) )
|
||||
return;
|
||||
|
||||
if ( mArrayIdx && dStricmp( mArrayIdx, "(null)" ) == 0 )
|
||||
mArrayIdx = NULL;
|
||||
|
||||
// Grab the current data.
|
||||
String data = obj->getDataField( mSlotName, mArrayIdx );
|
||||
|
||||
// Call this to mirror the way field changes are done through the inspector.
|
||||
obj->inspectPreApply();
|
||||
|
||||
// Restore the data from the UndoAction
|
||||
obj->setDataField( mSlotName, mArrayIdx, mData.c_str() );
|
||||
|
||||
// Call this to mirror the way field changes are done through the inspector.
|
||||
obj->inspectPostApply();
|
||||
|
||||
// If the affected object is still being inspected,
|
||||
// update the InspectorField to reflect the changed value.
|
||||
if ( mInspector && mInspector->getNumInspectObjects() > 0 && mInspector->getInspectObject() == obj )
|
||||
mInspector->updateFieldValue( mSlotName, mArrayIdx );
|
||||
|
||||
// Now save the previous data in this UndoAction
|
||||
// since an undo action must become a redo action and vice-versa
|
||||
mData = data;
|
||||
}
|
||||
135
Engine/source/gui/worldEditor/undoActions.h
Normal file
135
Engine/source/gui/worldEditor/undoActions.h
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUI_WORLDEDITOR_UNDOACTIONS_H_
|
||||
#define _GUI_WORLDEDITOR_UNDOACTIONS_H_
|
||||
|
||||
#ifndef _UNDO_H_
|
||||
#include "util/undo.h"
|
||||
#endif
|
||||
#ifndef _CONSOLE_SIMOBJECTMEMENTO_H_
|
||||
#include "console/simObjectMemento.h"
|
||||
#endif
|
||||
|
||||
class GuiInspectorField;
|
||||
class GuiInspector;
|
||||
|
||||
class MECreateUndoAction : public UndoAction
|
||||
{
|
||||
typedef UndoAction Parent;
|
||||
|
||||
protected:
|
||||
|
||||
struct ObjectState
|
||||
{
|
||||
/// The object we created and will delete in undo.
|
||||
SimObjectId id;
|
||||
|
||||
/// The captured object state.
|
||||
SimObjectMemento memento;
|
||||
|
||||
/// Keep track of the parent group.
|
||||
SimObjectId groupId;
|
||||
};
|
||||
|
||||
/// All the objects that were created.
|
||||
Vector<ObjectState> mObjects;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT( MECreateUndoAction );
|
||||
static void initPersistFields();
|
||||
|
||||
MECreateUndoAction( const UTF8* actionName = " " );
|
||||
virtual ~MECreateUndoAction();
|
||||
|
||||
void addObject( SimObject *object );
|
||||
|
||||
// UndoAction
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
};
|
||||
|
||||
|
||||
class MEDeleteUndoAction : public UndoAction
|
||||
{
|
||||
typedef UndoAction Parent;
|
||||
|
||||
protected:
|
||||
|
||||
struct ObjectState
|
||||
{
|
||||
/// The object we deleted and will restore in undo.
|
||||
SimObjectId id;
|
||||
|
||||
/// The captured object state.
|
||||
SimObjectMemento memento;
|
||||
|
||||
/// Keep track of the parent group.
|
||||
SimObjectId groupId;
|
||||
};
|
||||
|
||||
/// All the objects we're deleting.
|
||||
Vector<ObjectState> mObjects;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT( MEDeleteUndoAction );
|
||||
static void initPersistFields();
|
||||
|
||||
MEDeleteUndoAction( const UTF8* actionName = "Delete Object" );
|
||||
virtual ~MEDeleteUndoAction();
|
||||
|
||||
///
|
||||
void deleteObject( SimObject *object );
|
||||
void deleteObject( const Vector<SimObject*> &objectList );
|
||||
|
||||
// UndoAction
|
||||
virtual void undo();
|
||||
virtual void redo();
|
||||
};
|
||||
|
||||
class InspectorFieldUndoAction : public UndoAction
|
||||
{
|
||||
typedef UndoAction Parent;
|
||||
|
||||
public:
|
||||
|
||||
InspectorFieldUndoAction();
|
||||
InspectorFieldUndoAction( const UTF8* actionName );
|
||||
|
||||
DECLARE_CONOBJECT( InspectorFieldUndoAction );
|
||||
static void initPersistFields();
|
||||
|
||||
GuiInspector *mInspector;
|
||||
SimObjectId mObjId;
|
||||
SimObjectPtr<GuiInspectorField> mField;
|
||||
StringTableEntry mSlotName;
|
||||
StringTableEntry mArrayIdx;
|
||||
String mData;
|
||||
|
||||
// UndoAction
|
||||
virtual void undo();
|
||||
virtual void redo() { undo(); }
|
||||
};
|
||||
|
||||
#endif // _GUI_WORLDEDITOR_UNDOACTIONS_H_
|
||||
3941
Engine/source/gui/worldEditor/worldEditor.cpp
Normal file
3941
Engine/source/gui/worldEditor/worldEditor.cpp
Normal file
File diff suppressed because it is too large
Load diff
419
Engine/source/gui/worldEditor/worldEditor.h
Normal file
419
Engine/source/gui/worldEditor/worldEditor.h
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _WORLDEDITOR_H_
|
||||
#define _WORLDEDITOR_H_
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#include "gui/worldEditor/editTSCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _CONSOLETYPES_H_
|
||||
#include "console/consoleTypes.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GFXTEXTUREHANDLE_H_
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
#endif
|
||||
|
||||
#ifndef _TSIGNAL_H_
|
||||
#include "core/util/tSignal.h"
|
||||
#endif
|
||||
|
||||
#ifndef _CONSOLE_SIMOBJECTMEMENTO_H_
|
||||
#include "console/simObjectMemento.h"
|
||||
#endif
|
||||
|
||||
#ifndef _UNDO_H_
|
||||
#include "util/undo.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SIMPATH_H_
|
||||
#include "scene/simPath.h"
|
||||
#endif
|
||||
|
||||
#ifndef _DYNAMIC_CONSOLETYPES_H_
|
||||
#include "console/dynamicTypes.h"
|
||||
#endif
|
||||
|
||||
|
||||
class SceneObject;
|
||||
class WorldEditorSelection;
|
||||
|
||||
|
||||
///
|
||||
class WorldEditor : public EditTSCtrl
|
||||
{
|
||||
typedef EditTSCtrl Parent;
|
||||
|
||||
public:
|
||||
|
||||
typedef WorldEditorSelection Selection;
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
Point3F p0;
|
||||
Point3F p1;
|
||||
Point3F p2;
|
||||
};
|
||||
|
||||
void ignoreObjClass(U32 argc, const char** argv);
|
||||
void clearIgnoreList();
|
||||
|
||||
static bool setObjectsUseBoxCenter( void *object, const char *index, const char *data ) { static_cast<WorldEditor*>(object)->setObjectsUseBoxCenter( dAtob( data ) ); return false; };
|
||||
void setObjectsUseBoxCenter(bool state);
|
||||
bool getObjectsUseBoxCenter() { return mObjectsUseBoxCenter; }
|
||||
|
||||
void clearSelection();
|
||||
void selectObject(SimObject *obj);
|
||||
void selectObject(const char* obj);
|
||||
void unselectObject(SimObject *obj);
|
||||
void unselectObject(const char* obj);
|
||||
|
||||
S32 getSelectionSize();
|
||||
S32 getSelectObject(S32 index);
|
||||
const Point3F& getSelectionCentroid();
|
||||
const char* getSelectionCentroidText();
|
||||
const Box3F& getSelectionBounds();
|
||||
Point3F getSelectionExtent();
|
||||
F32 getSelectionRadius();
|
||||
|
||||
void dropCurrentSelection( bool skipUndo );
|
||||
void copyCurrentSelection();
|
||||
void cutCurrentSelection();
|
||||
bool canPasteSelection();
|
||||
|
||||
bool alignByBounds(S32 boundsAxis);
|
||||
bool alignByAxis(S32 axis);
|
||||
|
||||
void transformSelection(bool position, Point3F& p, bool relativePos, bool rotate, EulerF& r, bool relativeRot, bool rotLocal, S32 scaleType, Point3F& s, bool sRelative, bool sLocal);
|
||||
|
||||
void resetSelectedRotation();
|
||||
void resetSelectedScale();
|
||||
|
||||
void addUndoState();
|
||||
void redirectConsole(S32 objID);
|
||||
|
||||
void colladaExportSelection( const String &path );
|
||||
|
||||
void makeSelectionPrefab( const char *filename );
|
||||
void explodeSelectedPrefab();
|
||||
|
||||
//
|
||||
static SceneObject* getClientObj(SceneObject *);
|
||||
static void markAsSelected( SimObject* object, bool state );
|
||||
static void setClientObjInfo(SceneObject *, const MatrixF &, const VectorF &);
|
||||
static void updateClientTransforms(Selection* );
|
||||
|
||||
protected:
|
||||
|
||||
class WorldEditorUndoAction : public UndoAction
|
||||
{
|
||||
public:
|
||||
|
||||
WorldEditorUndoAction( const UTF8* actionName ) : UndoAction( actionName )
|
||||
{
|
||||
}
|
||||
|
||||
WorldEditor *mWorldEditor;
|
||||
|
||||
struct Entry
|
||||
{
|
||||
MatrixF mMatrix;
|
||||
VectorF mScale;
|
||||
|
||||
// validation
|
||||
U32 mObjId;
|
||||
U32 mObjNumber;
|
||||
};
|
||||
|
||||
Vector<Entry> mEntries;
|
||||
|
||||
virtual void undo();
|
||||
virtual void redo() { undo(); }
|
||||
};
|
||||
|
||||
void submitUndo( Selection* sel, const UTF8* label="World Editor Action" );
|
||||
|
||||
public:
|
||||
|
||||
/// The objects currently in the copy buffer.
|
||||
Vector<SimObjectMemento> mCopyBuffer;
|
||||
|
||||
bool cutSelection(Selection* sel);
|
||||
bool copySelection(Selection* sel);
|
||||
bool pasteSelection(bool dropSel=true);
|
||||
void dropSelection(Selection* sel);
|
||||
void dropBelowSelection(Selection* sel, const Point3F & centroid, bool useBottomBounds=false);
|
||||
|
||||
void terrainSnapSelection(Selection* sel, U8 modifier, Point3F gizmoPos, bool forceStick=false);
|
||||
void softSnapSelection(Selection* sel, U8 modifier, Point3F gizmoPos);
|
||||
|
||||
Selection* getActiveSelectionSet() const;
|
||||
void makeActiveSelectionSet( Selection* sel );
|
||||
|
||||
void hideObject(SceneObject* obj, bool hide);
|
||||
|
||||
// work off of mSelected
|
||||
void hideSelection(bool hide);
|
||||
void lockSelection(bool lock);
|
||||
|
||||
public:
|
||||
bool objClassIgnored(const SimObject * obj);
|
||||
void renderObjectBox(SceneObject * obj, const ColorI & col);
|
||||
|
||||
private:
|
||||
SceneObject * getControlObject();
|
||||
bool collide(const Gui3DMouseEvent & event, SceneObject **hitObj );
|
||||
|
||||
// gfx methods
|
||||
//void renderObjectBox(SceneObject * obj, const ColorI & col);
|
||||
void renderObjectFace(SceneObject * obj, const VectorF & normal, const ColorI & col);
|
||||
void renderSelectionWorldBox(Selection* sel);
|
||||
|
||||
void renderPlane(const Point3F & origin);
|
||||
void renderMousePopupInfo();
|
||||
void renderScreenObj( SceneObject * obj, const Point3F& sPos, const Point3F& wPos );
|
||||
|
||||
void renderPaths(SimObject *obj);
|
||||
void renderSplinePath(SimPath::Path *path);
|
||||
|
||||
// axis gizmo
|
||||
bool mUsingAxisGizmo;
|
||||
|
||||
GFXStateBlockRef mRenderSelectionBoxSB;
|
||||
GFXStateBlockRef mRenderObjectBoxSB;
|
||||
GFXStateBlockRef mRenderObjectFaceSB;
|
||||
GFXStateBlockRef mSplineSB;
|
||||
|
||||
//
|
||||
bool mIsDirty;
|
||||
|
||||
//
|
||||
bool mMouseDown;
|
||||
SimObjectPtr< Selection > mSelected;
|
||||
|
||||
SimObjectPtr< Selection > mDragSelected;
|
||||
bool mDragSelect;
|
||||
RectI mDragRect;
|
||||
Point2I mDragStart;
|
||||
|
||||
// modes for when dragging a selection
|
||||
enum {
|
||||
Move = 0,
|
||||
Rotate,
|
||||
Scale
|
||||
};
|
||||
|
||||
//
|
||||
//U32 mCurrentMode;
|
||||
//U32 mDefaultMode;
|
||||
|
||||
S32 mRedirectID;
|
||||
|
||||
/// @name Object Icons
|
||||
/// @{
|
||||
|
||||
struct IconObject
|
||||
{
|
||||
SceneObject *object;
|
||||
F32 dist;
|
||||
RectI rect;
|
||||
U32 alpha;
|
||||
};
|
||||
|
||||
Vector< IconObject > mIcons;
|
||||
|
||||
/// If true, icons fade out with distance to mouse cursor.
|
||||
bool mFadeIcons;
|
||||
|
||||
/// Distance at which to start fading out icons.
|
||||
F32 mFadeIconsDist;
|
||||
|
||||
/// @}
|
||||
|
||||
SimObjectPtr<SceneObject> mHitObject;
|
||||
SimObjectPtr<SceneObject> mPossibleHitObject;
|
||||
bool mMouseDragged;
|
||||
Gui3DMouseEvent mLastMouseEvent;
|
||||
Gui3DMouseEvent mLastMouseDownEvent;
|
||||
|
||||
//
|
||||
class ClassInfo
|
||||
{
|
||||
public:
|
||||
~ClassInfo();
|
||||
|
||||
struct Entry
|
||||
{
|
||||
StringTableEntry mName;
|
||||
bool mIgnoreCollision;
|
||||
GFXTexHandle mDefaultHandle;
|
||||
GFXTexHandle mSelectHandle;
|
||||
GFXTexHandle mLockedHandle;
|
||||
};
|
||||
|
||||
Vector<Entry*> mEntries;
|
||||
};
|
||||
|
||||
|
||||
ClassInfo mClassInfo;
|
||||
ClassInfo::Entry mDefaultClassEntry;
|
||||
|
||||
ClassInfo::Entry * getClassEntry(StringTableEntry name);
|
||||
ClassInfo::Entry * getClassEntry(const SimObject * obj);
|
||||
bool addClassEntry(ClassInfo::Entry * entry);
|
||||
|
||||
// persist field data
|
||||
public:
|
||||
|
||||
enum DropType
|
||||
{
|
||||
DropAtOrigin = 0,
|
||||
DropAtCamera,
|
||||
DropAtCameraWithRot,
|
||||
DropBelowCamera,
|
||||
DropAtScreenCenter,
|
||||
DropAtCentroid,
|
||||
DropToTerrain,
|
||||
DropBelowSelection
|
||||
};
|
||||
|
||||
// Snapping alignment mode
|
||||
enum AlignmentType
|
||||
{
|
||||
AlignNone = 0,
|
||||
AlignPosX,
|
||||
AlignPosY,
|
||||
AlignPosZ,
|
||||
AlignNegX,
|
||||
AlignNegY,
|
||||
AlignNegZ
|
||||
};
|
||||
|
||||
/// A large hard coded distance used to test
|
||||
/// object and icon selection.
|
||||
static F32 smProjectDistance;
|
||||
|
||||
S32 mDropType;
|
||||
bool mBoundingBoxCollision;
|
||||
bool mObjectMeshCollision;
|
||||
bool mRenderPopupBackground;
|
||||
ColorI mPopupBackgroundColor;
|
||||
ColorI mPopupTextColor;
|
||||
StringTableEntry mSelectHandle;
|
||||
StringTableEntry mDefaultHandle;
|
||||
StringTableEntry mLockedHandle;
|
||||
ColorI mObjectTextColor;
|
||||
bool mObjectsUseBoxCenter;
|
||||
ColorI mObjSelectColor;
|
||||
ColorI mObjMultiSelectColor;
|
||||
ColorI mObjMouseOverSelectColor;
|
||||
ColorI mObjMouseOverColor;
|
||||
bool mShowMousePopupInfo;
|
||||
ColorI mDragRectColor;
|
||||
bool mRenderObjText;
|
||||
bool mRenderObjHandle;
|
||||
StringTableEntry mObjTextFormat;
|
||||
ColorI mFaceSelectColor;
|
||||
bool mRenderSelectionBox;
|
||||
ColorI mSelectionBoxColor;
|
||||
bool mSelectionLocked;
|
||||
bool mPerformedDragCopy;
|
||||
bool mDragGridSnapToggle; ///< Grid snap setting temporarily toggled during drag.
|
||||
bool mToggleIgnoreList;
|
||||
bool mNoMouseDrag;
|
||||
bool mDropAtBounds;
|
||||
F32 mDropBelowCameraOffset;
|
||||
F32 mDropAtScreenCenterScalar;
|
||||
F32 mDropAtScreenCenterMax;
|
||||
|
||||
bool mGridSnap;
|
||||
bool mStickToGround;
|
||||
bool mStuckToGround; ///< Selection is stuck to the ground
|
||||
AlignmentType mTerrainSnapAlignment; ///< How does the stickied object align to the terrain
|
||||
|
||||
bool mSoftSnap; ///< Allow soft snapping all of the time
|
||||
bool mSoftSnapActivated; ///< Soft snap has been activated by the user and allowed by the current rules
|
||||
bool mSoftSnapIsStuck; ///< Are we snapping?
|
||||
AlignmentType mSoftSnapAlignment; ///< How does the snapped object align to the snapped surface
|
||||
bool mSoftSnapRender; ///< Render the soft snapping bounds
|
||||
bool mSoftSnapRenderTriangle; ///< Render the soft snapped triangle
|
||||
Triangle mSoftSnapTriangle; ///< The triangle we are snapping to
|
||||
bool mSoftSnapSizeByBounds; ///< Use the selection bounds for the size
|
||||
F32 mSoftSnapSize; ///< If not the selection bounds, use this size
|
||||
Box3F mSoftSnapBounds; ///< The actual bounds used for the soft snap
|
||||
Box3F mSoftSnapPreBounds; ///< The bounds prior to any soft snapping (used when rendering the snap bounds)
|
||||
F32 mSoftSnapBackfaceTolerance; ///< Fraction of mSoftSnapSize for backface polys to have an influence
|
||||
|
||||
bool mSoftSnapDebugRender; ///< Activates debug rendering
|
||||
Point3F mSoftSnapDebugPoint; ///< The point we're attempting to snap to
|
||||
Triangle mSoftSnapDebugSnapTri; ///< The triangle we are snapping to
|
||||
Vector<Triangle> mSoftSnapDebugTriangles; ///< The triangles that are considered for snapping
|
||||
|
||||
protected:
|
||||
|
||||
S32 mCurrentCursor;
|
||||
void setCursor(U32 cursor);
|
||||
void get3DCursor(GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event);
|
||||
|
||||
public:
|
||||
|
||||
WorldEditor();
|
||||
~WorldEditor();
|
||||
|
||||
void setDirty() { mIsDirty = true; }
|
||||
|
||||
// SimObject
|
||||
virtual bool onAdd();
|
||||
virtual void onEditorEnable();
|
||||
|
||||
// EditTSCtrl
|
||||
void on3DMouseMove(const Gui3DMouseEvent & event);
|
||||
void on3DMouseDown(const Gui3DMouseEvent & event);
|
||||
void on3DMouseUp(const Gui3DMouseEvent & event);
|
||||
void on3DMouseDragged(const Gui3DMouseEvent & event);
|
||||
void on3DMouseEnter(const Gui3DMouseEvent & event);
|
||||
void on3DMouseLeave(const Gui3DMouseEvent & event);
|
||||
void on3DRightMouseDown(const Gui3DMouseEvent & event);
|
||||
void on3DRightMouseUp(const Gui3DMouseEvent & event);
|
||||
|
||||
void updateGuiInfo();
|
||||
|
||||
//
|
||||
void renderScene(const RectI & updateRect);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
DECLARE_CONOBJECT(WorldEditor);
|
||||
|
||||
static Signal<void(WorldEditor*)> smRenderSceneSignal;
|
||||
};
|
||||
|
||||
typedef WorldEditor::DropType WorldEditorDropType;
|
||||
typedef WorldEditor::AlignmentType WorldEditorAlignmentType;
|
||||
|
||||
DefineEnumType( WorldEditorDropType );
|
||||
DefineEnumType( WorldEditorAlignmentType );
|
||||
|
||||
#endif // _WORLDEDITOR_H_
|
||||
|
||||
708
Engine/source/gui/worldEditor/worldEditorSelection.cpp
Normal file
708
Engine/source/gui/worldEditor/worldEditorSelection.cpp
Normal file
|
|
@ -0,0 +1,708 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/worldEditor/worldEditorSelection.h"
|
||||
#include "gui/worldEditor/worldEditor.h"
|
||||
#include "scene/sceneObject.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT( WorldEditorSelection );
|
||||
|
||||
ConsoleDocClass( WorldEditorSelection,
|
||||
"@brief Specialized simset that stores the objects selected by the World Editor\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
WorldEditorSelection::WorldEditorSelection()
|
||||
: mCentroidValid(false),
|
||||
mAutoSelect(false),
|
||||
mPrevCentroid(0.0f, 0.0f, 0.0f),
|
||||
mContainsGlobalBounds(false)
|
||||
{
|
||||
// Selections are transient by default.
|
||||
setCanSave( false );
|
||||
setEditorOnly( true );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
WorldEditorSelection::~WorldEditorSelection()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::setCanSave( bool value )
|
||||
{
|
||||
if( getCanSave() == value )
|
||||
return;
|
||||
|
||||
Parent::setCanSave( value );
|
||||
|
||||
// If we went from being transient to being persistent,
|
||||
// make sure all objects in the selection have persistent IDs.
|
||||
|
||||
if( getCanSave() )
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
( *iter )->getOrCreatePersistentId();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool WorldEditorSelection::objInSet( SimObject* obj )
|
||||
{
|
||||
if( !mIsResolvingPIDs )
|
||||
resolvePIDs();
|
||||
|
||||
lock();
|
||||
|
||||
bool result = false;
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
if( obj == *iter )
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
WorldEditorSelection* set = dynamic_cast< WorldEditorSelection* >( *iter );
|
||||
if( set && set->objInSet( obj ) )
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::addObject( SimObject* obj )
|
||||
{
|
||||
// Return if object is already in selection.
|
||||
|
||||
if( objInSet( obj ) )
|
||||
return;
|
||||
|
||||
// Refuse to add object if this selection is locked.
|
||||
|
||||
if( isLocked() )
|
||||
return;
|
||||
|
||||
// Prevent adding us to ourselves.
|
||||
|
||||
if( obj == this )
|
||||
return;
|
||||
|
||||
// If the object is itself a selection set, make sure we
|
||||
// don't create a cycle.
|
||||
|
||||
WorldEditorSelection* selection = dynamic_cast< WorldEditorSelection* >( obj );
|
||||
if( selection && !selection->objInSet( this ) )
|
||||
return;
|
||||
|
||||
// Refuse to add any of our parents.
|
||||
|
||||
for( SimGroup* group = getGroup(); group != NULL; group = group->getGroup() )
|
||||
if( obj == group )
|
||||
return;
|
||||
|
||||
invalidateCentroid();
|
||||
|
||||
Parent::addObject( obj );
|
||||
|
||||
if( mAutoSelect )
|
||||
WorldEditor::markAsSelected( obj, true );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::removeObject( SimObject* obj )
|
||||
{
|
||||
if( !objInSet( obj ) )
|
||||
return;
|
||||
|
||||
// Refuse to remove object if this selection is locked.
|
||||
|
||||
if( isLocked() )
|
||||
return;
|
||||
|
||||
invalidateCentroid();
|
||||
|
||||
Parent::removeObject( obj );
|
||||
|
||||
if( mAutoSelect )
|
||||
WorldEditor::markAsSelected( obj, false );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool WorldEditorSelection::containsGlobalBounds()
|
||||
{
|
||||
updateCentroid();
|
||||
return mContainsGlobalBounds;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::updateCentroid()
|
||||
{
|
||||
if( mCentroidValid )
|
||||
return;
|
||||
|
||||
resolvePIDs();
|
||||
|
||||
mCentroidValid = true;
|
||||
|
||||
mCentroid.set(0,0,0);
|
||||
mBoxCentroid = mCentroid;
|
||||
mBoxBounds.minExtents.set(1e10, 1e10, 1e10);
|
||||
mBoxBounds.maxExtents.set(-1e10, -1e10, -1e10);
|
||||
|
||||
mContainsGlobalBounds = false;
|
||||
|
||||
if( empty() )
|
||||
return;
|
||||
|
||||
//
|
||||
for( SimSet::iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* obj = dynamic_cast<SceneObject*>( *iter );
|
||||
if( !obj )
|
||||
continue;
|
||||
|
||||
const MatrixF & mat = obj->getTransform();
|
||||
Point3F wPos;
|
||||
mat.getColumn(3, &wPos);
|
||||
|
||||
//
|
||||
mCentroid += wPos;
|
||||
|
||||
//
|
||||
const Box3F& bounds = obj->getWorldBox();
|
||||
mBoxBounds.minExtents.setMin(bounds.minExtents);
|
||||
mBoxBounds.maxExtents.setMax(bounds.maxExtents);
|
||||
|
||||
if(obj->isGlobalBounds())
|
||||
mContainsGlobalBounds = true;
|
||||
}
|
||||
|
||||
mCentroid /= (F32) size();
|
||||
mBoxCentroid = mBoxBounds.getCenter();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const Point3F & WorldEditorSelection::getCentroid()
|
||||
{
|
||||
updateCentroid();
|
||||
return(mCentroid);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const Point3F & WorldEditorSelection::getBoxCentroid()
|
||||
{
|
||||
updateCentroid();
|
||||
return(mBoxCentroid);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const Box3F & WorldEditorSelection::getBoxBounds()
|
||||
{
|
||||
updateCentroid();
|
||||
return(mBoxBounds);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Point3F WorldEditorSelection::getBoxBottomCenter()
|
||||
{
|
||||
updateCentroid();
|
||||
|
||||
Point3F bottomCenter = mBoxCentroid;
|
||||
bottomCenter.z -= mBoxBounds.len_z() * 0.5f;
|
||||
|
||||
return bottomCenter;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::enableCollision()
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast<SceneObject*>( *iter );
|
||||
if( object )
|
||||
object->enableCollision();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::disableCollision()
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( object )
|
||||
object->disableCollision();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::offset( const Point3F& offset, F32 gridSnap )
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* obj = dynamic_cast<SceneObject*>( *iter );
|
||||
if( !obj )
|
||||
continue;
|
||||
|
||||
MatrixF mat = obj->getTransform();
|
||||
Point3F wPos;
|
||||
mat.getColumn(3, &wPos);
|
||||
|
||||
// adjust
|
||||
wPos += offset;
|
||||
|
||||
if( gridSnap != 0.f )
|
||||
{
|
||||
wPos.x -= mFmod( wPos.x, gridSnap );
|
||||
wPos.y -= mFmod( wPos.y, gridSnap );
|
||||
wPos.z -= mFmod( wPos.z, gridSnap );
|
||||
}
|
||||
|
||||
mat.setColumn(3, wPos);
|
||||
obj->setTransform(mat);
|
||||
}
|
||||
|
||||
mCentroidValid = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::setPosition(const Point3F & pos)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast<SceneObject*>( *iter );
|
||||
if( object )
|
||||
object->setPosition(pos);
|
||||
}
|
||||
|
||||
mCentroidValid = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::setCentroidPosition(bool useBoxCenter, const Point3F & pos)
|
||||
{
|
||||
Point3F centroid;
|
||||
if( containsGlobalBounds() )
|
||||
{
|
||||
centroid = getCentroid();
|
||||
}
|
||||
else
|
||||
{
|
||||
centroid = useBoxCenter ? getBoxCentroid() : getCentroid();
|
||||
}
|
||||
|
||||
offset(pos - centroid);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::orient(const MatrixF & rot, const Point3F & center)
|
||||
{
|
||||
// Orient all the selected objects to the given rotation
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
MatrixF mat = rot;
|
||||
mat.setPosition( object->getPosition() );
|
||||
object->setTransform(mat);
|
||||
}
|
||||
|
||||
mCentroidValid = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::rotate(const EulerF &rot)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
MatrixF mat = object->getTransform();
|
||||
|
||||
MatrixF transform(rot);
|
||||
mat.mul(transform);
|
||||
|
||||
object->setTransform(mat);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::rotate(const EulerF & rot, const Point3F & center)
|
||||
{
|
||||
// single selections will rotate around own axis, multiple about world
|
||||
if(size() == 1)
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( at( 0 ) );
|
||||
if( object )
|
||||
{
|
||||
MatrixF mat = object->getTransform();
|
||||
|
||||
Point3F pos;
|
||||
mat.getColumn(3, &pos);
|
||||
|
||||
// get offset in obj space
|
||||
Point3F offset = pos - center;
|
||||
MatrixF wMat = object->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);
|
||||
|
||||
object->setTransform(mat);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
MatrixF mat = object->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 = object->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);
|
||||
|
||||
object->setTransform(mat);
|
||||
}
|
||||
}
|
||||
|
||||
mCentroidValid = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::setRotate(const EulerF & rot)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
MatrixF mat = object->getTransform();
|
||||
Point3F pos;
|
||||
mat.getColumn(3, &pos);
|
||||
|
||||
MatrixF rmat(rot);
|
||||
rmat.setPosition(pos);
|
||||
|
||||
object->setTransform(rmat);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::scale(const VectorF & scale)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
VectorF current = object->getScale();
|
||||
current.convolve(scale);
|
||||
|
||||
// clamp scale to sensible limits
|
||||
current.setMax( Point3F( 0.01f ) );
|
||||
current.setMin( Point3F( 1000.0f ) );
|
||||
|
||||
object->setScale(current);
|
||||
}
|
||||
|
||||
mCentroidValid = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::scale(const VectorF & scale, const Point3F & center)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
VectorF current = object->getScale();
|
||||
current.convolve(scale);
|
||||
|
||||
// clamp scale to sensible limits
|
||||
current.setMax( Point3F( 0.01f ) );
|
||||
current.setMin( Point3F( 1000.0f ) );
|
||||
|
||||
// Apply the scale first. If the object's scale doesn't change with
|
||||
// this operation then this object doesn't scale. In this case
|
||||
// we don't want to continue with the offset operation.
|
||||
VectorF prevScale = object->getScale();
|
||||
object->setScale(current);
|
||||
if( !object->getScale().equal(current) )
|
||||
continue;
|
||||
|
||||
// determine the actual scale factor to apply to the object offset
|
||||
// need to account for the scale limiting above to prevent offsets
|
||||
// being reduced to 0 which then cannot be restored by unscaling
|
||||
VectorF adjustedScale = current / prevScale;
|
||||
|
||||
MatrixF mat = object->getTransform();
|
||||
|
||||
Point3F pos;
|
||||
mat.getColumn(3, &pos);
|
||||
|
||||
Point3F offset = pos - center;
|
||||
offset *= adjustedScale;
|
||||
|
||||
object->setPosition(offset + center);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::setScale(const VectorF & scale)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( object )
|
||||
object->setScale( scale );
|
||||
}
|
||||
|
||||
mCentroidValid = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::setScale(const VectorF & scale, const Point3F & center)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
MatrixF mat = object->getTransform();
|
||||
|
||||
Point3F pos;
|
||||
mat.getColumn(3, &pos);
|
||||
|
||||
Point3F offset = pos - center;
|
||||
offset *= scale;
|
||||
|
||||
object->setPosition(offset + center);
|
||||
object->setScale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::addSize(const VectorF & newsize)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
if( object->isGlobalBounds() )
|
||||
continue;
|
||||
|
||||
const Box3F& bounds = object->getObjBox();
|
||||
VectorF extent = bounds.getExtents();
|
||||
VectorF scaledextent = object->getScale() * extent;
|
||||
|
||||
VectorF scale = (newsize + scaledextent) / scaledextent;
|
||||
object->setScale( object->getScale() * scale );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void WorldEditorSelection::setSize(const VectorF & newsize)
|
||||
{
|
||||
for( iterator iter = begin(); iter != end(); ++ iter )
|
||||
{
|
||||
SceneObject* object = dynamic_cast< SceneObject* >( *iter );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
if( object->isGlobalBounds() )
|
||||
continue;
|
||||
|
||||
const Box3F& bounds = object->getObjBox();
|
||||
VectorF extent = bounds.getExtents();
|
||||
|
||||
VectorF scale = newsize / extent;
|
||||
object->setScale( scale );
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Console Methods.
|
||||
//=============================================================================
|
||||
// MARK: ---- Console Methods ----
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ConsoleMethod( WorldEditorSelection, containsGlobalBounds, bool, 2, 2, "() - True if an object with global bounds is contained in the selection." )
|
||||
{
|
||||
return object->containsGlobalBounds();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ConsoleMethod( WorldEditorSelection, getCentroid, const char*, 2, 2, "() - Return the median of all object positions in the selection." )
|
||||
{
|
||||
char* buffer = Con::getReturnBuffer( 256 );
|
||||
const Point3F& centroid = object->getCentroid();
|
||||
|
||||
dSprintf( buffer, 256, "%g %g %g", centroid.x, centroid.y, centroid.z );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ConsoleMethod( WorldEditorSelection, getBoxCentroid, const char*, 2, 2, "() - Return the center of the bounding box around the selection." )
|
||||
{
|
||||
char* buffer = Con::getReturnBuffer( 256 );
|
||||
const Point3F& boxCentroid = object->getBoxCentroid();
|
||||
|
||||
dSprintf( buffer, 256, "%g %g %g", boxCentroid.x, boxCentroid.y, boxCentroid.z );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ConsoleMethod( WorldEditorSelection, offset, void, 3, 4, "( vector delta, float gridSnap=0 ) - Move all objects in the selection by the given delta." )
|
||||
{
|
||||
F32 x, y, z;
|
||||
dSscanf( argv[ 3 ], "%g %g %g", &x, &y, &z );
|
||||
|
||||
F32 gridSnap = 0.f;
|
||||
if( argc > 3 )
|
||||
gridSnap = dAtof( argv[ 3 ] );
|
||||
|
||||
object->offset( Point3F( x, y, z ), gridSnap );
|
||||
WorldEditor::updateClientTransforms( object );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ConsoleMethod( WorldEditorSelection, union, void, 3, 3, "( SimSet set ) - Add all objects in the given set to this selection." )
|
||||
{
|
||||
SimSet* selection;
|
||||
if( !Sim::findObject( argv[ 2 ], selection ) )
|
||||
{
|
||||
Con::errorf( "WorldEditorSelection::union - no SimSet '%s'", argv[ 2 ] );
|
||||
return;
|
||||
}
|
||||
|
||||
const U32 numObjects = selection->size();
|
||||
for( U32 i = 0; i < numObjects; ++ i )
|
||||
object->addObject( selection->at( i ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ConsoleMethod( WorldEditorSelection, subtract, void, 3, 3, "( SimSet ) - Remove all objects in the given set from this selection." )
|
||||
{
|
||||
SimSet* selection;
|
||||
if( !Sim::findObject( argv[ 2 ], selection ) )
|
||||
{
|
||||
Con::errorf( "WorldEditorSelection::subtract - no SimSet '%s'", argv[ 2 ] );
|
||||
return;
|
||||
}
|
||||
|
||||
const U32 numObjects = selection->size();
|
||||
for( U32 i = 0; i < numObjects; ++ i )
|
||||
object->removeObject( selection->at( i ) );
|
||||
}
|
||||
150
Engine/source/gui/worldEditor/worldEditorSelection.h
Normal file
150
Engine/source/gui/worldEditor/worldEditorSelection.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _WORLDEDITORSELECTION_H_
|
||||
#define _WORLDEDITORSELECTION_H_
|
||||
|
||||
#ifndef _SIMPERSISTSET_H_
|
||||
#include "console/simPersistSet.h"
|
||||
#endif
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
|
||||
class SceneObject;
|
||||
|
||||
|
||||
/// A selection set in the World Editor.
|
||||
///
|
||||
/// Selections are by default transient objects, but can be made persistent and
|
||||
/// saved to disk.
|
||||
///
|
||||
class WorldEditorSelection : public SimPersistSet
|
||||
{
|
||||
public:
|
||||
|
||||
typedef SimPersistSet Parent;
|
||||
|
||||
private:
|
||||
|
||||
/// The averaged positions of all objects in the selection.
|
||||
Point3F mCentroid;
|
||||
|
||||
/// The center point of the bounding box around the selection.
|
||||
Point3F mBoxCentroid;
|
||||
|
||||
/// The bounding box around the selection.
|
||||
Box3F mBoxBounds;
|
||||
|
||||
///
|
||||
MatrixF mTransform;
|
||||
|
||||
/// If false, the selection has been modified and bounding box values
|
||||
/// and center points need to be recomputed.
|
||||
bool mCentroidValid;
|
||||
|
||||
/// If true, the selection contains one or more objects that have
|
||||
/// global bounds enabled.
|
||||
bool mContainsGlobalBounds;
|
||||
|
||||
bool mAutoSelect;
|
||||
Point3F mPrevCentroid;
|
||||
|
||||
void updateCentroid();
|
||||
|
||||
public:
|
||||
|
||||
WorldEditorSelection();
|
||||
~WorldEditorSelection();
|
||||
|
||||
/// Return true if "object" is contained in the selection.
|
||||
bool objInSet( SimObject* object );
|
||||
|
||||
void storeCurrentCentroid() { mPrevCentroid = getCentroid(); }
|
||||
bool hasCentroidChanged() { return (mPrevCentroid != getCentroid()); }
|
||||
|
||||
bool containsGlobalBounds();
|
||||
|
||||
/// @name Transforms
|
||||
///
|
||||
/// Note that these methods do not update transforms of client objects.
|
||||
/// Use WorldEditor::updateClientTransforms to do that.
|
||||
///
|
||||
/// @{
|
||||
|
||||
///
|
||||
const Point3F& getCentroid();
|
||||
const Point3F& getBoxCentroid();
|
||||
const Box3F& getBoxBounds();
|
||||
Point3F getBoxBottomCenter();
|
||||
const MatrixF& getTransform();
|
||||
|
||||
//
|
||||
void offset(const Point3F& delta, F32 gridSnap = 0.f );
|
||||
void setPosition(const Point3F & pos);
|
||||
void setCentroidPosition(bool useBoxCenter, const Point3F & pos);
|
||||
|
||||
void orient(const MatrixF &, const Point3F &);
|
||||
void rotate(const EulerF &);
|
||||
void rotate(const EulerF &, const Point3F &);
|
||||
void setRotate(const EulerF &);
|
||||
|
||||
void scale(const VectorF &);
|
||||
void scale(const VectorF &, const Point3F &);
|
||||
void setScale(const VectorF &);
|
||||
void setScale(const VectorF &, const Point3F &);
|
||||
|
||||
void addSize(const VectorF &);
|
||||
void setSize(const VectorF &);
|
||||
|
||||
/// @}
|
||||
|
||||
/// Enable collision for all objects in the selection.
|
||||
void enableCollision();
|
||||
|
||||
/// Disable collision for all objects in the selection.
|
||||
void disableCollision();
|
||||
|
||||
//
|
||||
void setAutoSelect(bool b) { mAutoSelect = b; }
|
||||
void invalidateCentroid() { mCentroidValid = false; }
|
||||
|
||||
// SimSet.
|
||||
virtual void addObject( SimObject* );
|
||||
virtual void removeObject( SimObject* );
|
||||
virtual void setCanSave( bool value );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
DECLARE_CONOBJECT( WorldEditorSelection );
|
||||
DECLARE_CATEGORY( "Editor World" );
|
||||
DECLARE_DESCRIPTION( "A selection set for the World Editor." );
|
||||
};
|
||||
|
||||
#endif // !_WORLDEDITORSELECTION_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue