Initial commit
This commit is contained in:
442
engine/editor/creator.cc
Executable file
442
engine/editor/creator.cc
Executable file
@ -0,0 +1,442 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "editor/creator.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(CreatorTree);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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());
|
||||
else
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
// Start drawing stuff
|
||||
if( node->isGroup() ) { // If we need a box...
|
||||
dglDrawRectFill( boxStart, boxEnd, mProfile->mFillColor ); // Box background
|
||||
dglDrawRect( boxStart, boxEnd, mProfile->mFontColor ); // Border
|
||||
|
||||
// Cross line
|
||||
dglDrawLine( boxStart.x + 2, boxStart.y + 4, boxStart.x + 7, boxStart.y + 4, mProfile->mFontColor );
|
||||
|
||||
if( !node->isExpanded() ) // If it's a [+] draw down line
|
||||
dglDrawLine( boxStart.x + 4, boxStart.y + 2, boxStart.x + 4, boxStart.y + 7, mProfile->mFontColor );
|
||||
}
|
||||
else {
|
||||
// Draw horizontal line
|
||||
dglDrawLine( 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
|
||||
dglDrawLine( boxStart.x + 4, boxStart.y - 6, boxStart.x + 4, boxStart.y + 10, mProfile->mFontColor );
|
||||
else // Otherwise, just a small one
|
||||
dglDrawLine( 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() ) {
|
||||
dglDrawLine( 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 );
|
||||
|
||||
dglSetBitmapModulation(fontColor); //node->isSelected() ? mProfile->mFontColorHL : mProfile->mFontColor);
|
||||
dglDrawText( mProfile->mFont,
|
||||
Point2I( offset.x + mTxtOffset + mTabSize * ( node->mTab + 1 ), offset.y ),
|
||||
node->mName);
|
||||
}
|
103
engine/editor/creator.h
Executable file
103
engine/editor/creator.h
Executable file
@ -0,0 +1,103 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CREATOR_H_
|
||||
#define _CREATOR_H_
|
||||
|
||||
#ifndef _SIMBASE_H_
|
||||
#include "console/simBase.h"
|
||||
#endif
|
||||
#ifndef _GUIARRAYCTRL_H_
|
||||
#include "gui/core/guiArrayCtrl.h"
|
||||
#endif
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
#endif
|
623
engine/editor/editTSCtrl.cc
Executable file
623
engine/editor/editTSCtrl.cc
Executable file
@ -0,0 +1,623 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "platform/event.h"
|
||||
#include "core/dnet.h"
|
||||
#include "editor/editTSCtrl.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
#include "editor/editor.h"
|
||||
#include "game/gameConnection.h"
|
||||
#include "game/gameBase.h"
|
||||
#include "game/missionArea.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "terrain/terrData.h"
|
||||
#include "game/game.h"
|
||||
#include "game/sphere.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(EditTSCtrl);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Point3F EditTSCtrl::smCamPos;
|
||||
EulerF EditTSCtrl::smCamRot;
|
||||
MatrixF EditTSCtrl::smCamMatrix;
|
||||
F32 EditTSCtrl::smVisibleDistance = 2100.f;
|
||||
|
||||
EditTSCtrl::EditTSCtrl() :
|
||||
mEditManager(0)
|
||||
{
|
||||
mRenderMissionArea = true;
|
||||
mMissionAreaFillColor.set(255,0,0,20);
|
||||
mMissionAreaFrameColor.set(255,0,0,128);
|
||||
|
||||
mConsoleFrameColor.set(255,0,0,255);
|
||||
mConsoleFillColor.set(255,0,0,120);
|
||||
mConsoleSphereLevel = 1;
|
||||
mConsoleCircleSegments = 32;
|
||||
mConsoleLineWidth = 1;
|
||||
mRightMousePassThru = true;
|
||||
|
||||
mConsoleRendering = false;
|
||||
}
|
||||
|
||||
EditTSCtrl::~EditTSCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool EditTSCtrl::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return(false);
|
||||
|
||||
// give all derived access to the fields
|
||||
setModStaticFields(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditTSCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
updateGuiInfo();
|
||||
Parent::onRender(offset, updateRect);
|
||||
|
||||
// We have to do this because of how GuiTSCtrl deals with filters.
|
||||
if(!mApplyFilterToChildren)
|
||||
Parent::renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void EditTSCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addGroup("Mission Area");
|
||||
addField("renderMissionArea", TypeBool, Offset(mRenderMissionArea, EditTSCtrl));
|
||||
addField("missionAreaFillColor", TypeColorI, Offset(mMissionAreaFillColor, EditTSCtrl));
|
||||
addField("missionAreaFrameColor", TypeColorI, Offset(mMissionAreaFrameColor, EditTSCtrl));
|
||||
endGroup("Mission Area");
|
||||
|
||||
addGroup("Misc");
|
||||
addField("consoleFrameColor", TypeColorI, Offset(mConsoleFrameColor, EditTSCtrl));
|
||||
addField("consoleFillColor", TypeColorI, Offset(mConsoleFillColor, EditTSCtrl));
|
||||
addField("consoleSphereLevel", TypeS32, Offset(mConsoleSphereLevel, EditTSCtrl));
|
||||
addField("consoleCircleSegments", TypeS32, Offset(mConsoleCircleSegments, EditTSCtrl));
|
||||
addField("consoleLineWidth", TypeS32, Offset(mConsoleLineWidth, EditTSCtrl));
|
||||
endGroup("Misc");
|
||||
}
|
||||
|
||||
void EditTSCtrl::consoleInit()
|
||||
{
|
||||
Con::addVariable("pref::Editor::visibleDistance", TypeF32, &EditTSCtrl::smVisibleDistance);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void EditTSCtrl::make3DMouseEvent(Gui3DMouseEvent & gui3DMouseEvent, const GuiEvent & event)
|
||||
{
|
||||
(GuiEvent&)(gui3DMouseEvent) = event;
|
||||
|
||||
// get the eye pos and the mouse vec from that...
|
||||
Point3F sp(event.mousePoint.x, event.mousePoint.y, 1);
|
||||
|
||||
Point3F wp;
|
||||
unproject(sp, &wp);
|
||||
|
||||
gui3DMouseEvent.pos = smCamPos;
|
||||
gui3DMouseEvent.vec = wp - smCamPos;
|
||||
gui3DMouseEvent.vec.normalize();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void EditTSCtrl::getCursor(GuiCursor *&cursor, bool &visible, const GuiEvent &event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
get3DCursor(cursor, visible, mLastEvent);
|
||||
}
|
||||
|
||||
void EditTSCtrl::get3DCursor(GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event)
|
||||
{
|
||||
event;
|
||||
cursor = NULL;
|
||||
visible = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void EditTSCtrl::onMouseUp(const GuiEvent & event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DMouseUp(mLastEvent);
|
||||
}
|
||||
|
||||
void EditTSCtrl::onMouseDown(const GuiEvent & event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DMouseDown(mLastEvent);
|
||||
}
|
||||
|
||||
void EditTSCtrl::onMouseMove(const GuiEvent & event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DMouseMove(mLastEvent);
|
||||
}
|
||||
|
||||
void EditTSCtrl::onMouseDragged(const GuiEvent & event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DMouseDragged(mLastEvent);
|
||||
|
||||
}
|
||||
|
||||
void EditTSCtrl::onMouseEnter(const GuiEvent & event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DMouseEnter(mLastEvent);
|
||||
}
|
||||
|
||||
void EditTSCtrl::onMouseLeave(const GuiEvent & event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DMouseLeave(mLastEvent);
|
||||
}
|
||||
|
||||
void EditTSCtrl::onRightMouseDown(const GuiEvent & event)
|
||||
{
|
||||
// always process the right mouse event first...
|
||||
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DRightMouseDown(mLastEvent);
|
||||
|
||||
if(mRightMousePassThru && mProfile->mCanKeyFocus)
|
||||
{
|
||||
// ok, gotta disable the mouse
|
||||
// script functions are lockMouse(true); Canvas.cursorOff();
|
||||
Platform::setWindowLocked(true);
|
||||
Canvas->setCursorON(false);
|
||||
setFirstResponder();
|
||||
}
|
||||
}
|
||||
|
||||
void EditTSCtrl::onRightMouseUp(const GuiEvent & event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DRightMouseUp(mLastEvent);
|
||||
}
|
||||
|
||||
void EditTSCtrl::onRightMouseDragged(const GuiEvent & event)
|
||||
{
|
||||
make3DMouseEvent(mLastEvent, event);
|
||||
on3DRightMouseDragged(mLastEvent);
|
||||
}
|
||||
|
||||
bool EditTSCtrl::onInputEvent(const InputEvent & event)
|
||||
{
|
||||
if(mRightMousePassThru && event.deviceType == MouseDeviceType &&
|
||||
event.objInst == KEY_BUTTON1 && event.action == SI_BREAK)
|
||||
{
|
||||
// if the right mouse pass thru is enabled,
|
||||
// we want to reactivate mouse on a right mouse button up
|
||||
Platform::setWindowLocked(false);
|
||||
Canvas->setCursorON(true);
|
||||
}
|
||||
// we return false so that the canvas can properly process the right mouse button up...
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void EditTSCtrl::renderWorld(const RectI & updateRect)
|
||||
{
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
|
||||
dglSetCanonicalState();
|
||||
gClientSceneGraph->renderScene();
|
||||
|
||||
if(mRenderMissionArea)
|
||||
renderMissionArea();
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// render through console callbacks
|
||||
SimSet * missionGroup = static_cast<SimSet*>(Sim::findObject("MissionGroup"));
|
||||
if(missionGroup)
|
||||
{
|
||||
mConsoleRendering = true;
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
for(SimSetIterator itr(missionGroup); *itr; ++itr)
|
||||
{
|
||||
char buf[2][16];
|
||||
dSprintf(buf[0], 16, (*itr)->isSelected() ? "true" : "false");
|
||||
dSprintf(buf[1], 16, (*itr)->isExpanded() ? "true" : "false");
|
||||
Con::executef(*itr, 4, "onEditorRender", getIdString(), buf[0], buf[1]);
|
||||
}
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
mConsoleRendering = false;
|
||||
}
|
||||
|
||||
// render the editor stuff
|
||||
renderScene(updateRect);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
|
||||
dglSetClipRect(updateRect);
|
||||
}
|
||||
|
||||
void EditTSCtrl::renderMissionArea()
|
||||
{
|
||||
MissionArea * obj = dynamic_cast<MissionArea*>(Sim::findObject("MissionArea"));
|
||||
TerrainBlock * terrain = dynamic_cast<TerrainBlock*>(Sim::findObject("Terrain"));
|
||||
if(!terrain)
|
||||
return;
|
||||
|
||||
GridSquare * gs = terrain->findSquare(TerrainBlock::BlockShift, Point2I(0,0));
|
||||
F32 height = F32(gs->maxHeight) * 0.03125f + 10.f;
|
||||
|
||||
//
|
||||
const RectI &area = obj->getArea();
|
||||
Point2F min(area.point.x, area.point.y);
|
||||
Point2F max(area.point.x + area.extent.x, area.point.y + area.extent.y);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
ColorI & a = mMissionAreaFillColor;
|
||||
ColorI & b = mMissionAreaFrameColor;
|
||||
for(U32 i = 0; i < 2; i++)
|
||||
{
|
||||
//
|
||||
if(i){glColor4ub(a.red,a.green,a.blue,a.alpha);glBegin(GL_QUADS);} else {glColor4f(b.red,b.green,b.blue,b.alpha); glBegin(GL_LINE_LOOP);}
|
||||
glVertex3f(min.x, min.y, 0);
|
||||
glVertex3f(max.x, min.y, 0);
|
||||
glVertex3f(max.x, min.y, height);
|
||||
glVertex3f(min.x, min.y, height);
|
||||
glEnd();
|
||||
|
||||
//
|
||||
if(i){glColor4ub(a.red,a.green,a.blue,a.alpha);glBegin(GL_QUADS);} else {glColor4f(b.red,b.green,b.blue,b.alpha); glBegin(GL_LINE_LOOP);}
|
||||
glVertex3f(min.x, max.y, 0);
|
||||
glVertex3f(max.x, max.y, 0);
|
||||
glVertex3f(max.x, max.y, height);
|
||||
glVertex3f(min.x, max.y, height);
|
||||
glEnd();
|
||||
|
||||
//
|
||||
if(i){glColor4ub(a.red,a.green,a.blue,a.alpha);glBegin(GL_QUADS);} else {glColor4f(b.red,b.green,b.blue,b.alpha); glBegin(GL_LINE_LOOP);}
|
||||
glVertex3f(min.x, min.y, 0);
|
||||
glVertex3f(min.x, max.y, 0);
|
||||
glVertex3f(min.x, max.y, height);
|
||||
glVertex3f(min.x, min.y, height);
|
||||
glEnd();
|
||||
|
||||
//
|
||||
if(i){glColor4ub(a.red,a.green,a.blue,a.alpha);glBegin(GL_QUADS);} else {glColor4f(b.red,b.green,b.blue,b.alpha); glBegin(GL_LINE_LOOP);}
|
||||
glVertex3f(max.x, min.y, 0);
|
||||
glVertex3f(max.x, max.y, 0);
|
||||
glVertex3f(max.x, max.y, height);
|
||||
glVertex3f(max.x, min.y, height);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool EditTSCtrl::processCameraQuery(CameraQuery * query)
|
||||
{
|
||||
GameConnection* connection = dynamic_cast<GameConnection *>(NetConnection::getConnectionToServer());
|
||||
if (connection)
|
||||
{
|
||||
if (connection->getControlCameraTransform(0.032,&query->cameraMatrix)) {
|
||||
query->nearPlane = 0.1;
|
||||
query->farPlane = getMax(smVisibleDistance, 50.f);
|
||||
query->fov = 3.1415 / 2;
|
||||
query->ortho = false;
|
||||
|
||||
smCamMatrix = query->cameraMatrix;
|
||||
smCamMatrix.getColumn(3,&smCamPos);
|
||||
smCamRot.set(0,0,0);
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// sort the surfaces: not correct when camera is inside sphere but not
|
||||
// inside tesselated representation of sphere....
|
||||
struct SortInfo
|
||||
{
|
||||
U32 idx;
|
||||
F32 dot;
|
||||
};
|
||||
|
||||
static int QSORT_CALLBACK alphaSort(const void* p1, const void* p2)
|
||||
{
|
||||
const SortInfo* ip1 = (const SortInfo*)p1;
|
||||
const SortInfo* ip2 = (const SortInfo*)p2;
|
||||
|
||||
if(ip1->dot > ip2->dot)
|
||||
return(1);
|
||||
if(ip1->dot == ip2->dot)
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleMethod(EditTSCtrl, renderSphere, void, 4, 5, "(Point3F pos, float radius, int subdivisions=NULL)")
|
||||
{
|
||||
if(!object->mConsoleRendering)
|
||||
return;
|
||||
|
||||
static Sphere sphere(Sphere::Icosahedron);
|
||||
|
||||
if(!object->mConsoleFrameColor.alpha && !object->mConsoleFillColor.alpha)
|
||||
return;
|
||||
|
||||
S32 sphereLevel = object->mConsoleSphereLevel;
|
||||
if(argc == 5)
|
||||
sphereLevel = dAtoi(argv[4]);
|
||||
|
||||
const Sphere::TriangleMesh * mesh = sphere.getMesh(sphereLevel);
|
||||
|
||||
Point3F pos;
|
||||
dSscanf(argv[2], "%g %g %g", &pos.x, &pos.y, &pos.z);
|
||||
|
||||
F32 radius = dAtoi(argv[3]);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// sort the surfaces back->front
|
||||
Vector<SortInfo> sortInfos;
|
||||
|
||||
Point3F camNormal = object->smCamPos - pos;
|
||||
camNormal.normalize();
|
||||
|
||||
sortInfos.setSize(mesh->numPoly);
|
||||
for(U32 i = 0; i < mesh->numPoly; i++)
|
||||
{
|
||||
sortInfos[i].idx = i;
|
||||
sortInfos[i].dot = mDot(camNormal, mesh->poly[i].normal);
|
||||
}
|
||||
dQsort(sortInfos.address(), sortInfos.size(), sizeof(SortInfo), alphaSort);
|
||||
|
||||
// frame
|
||||
if(object->mConsoleFrameColor.alpha)
|
||||
{
|
||||
glColor4ub(object->mConsoleFrameColor.red,
|
||||
object->mConsoleFrameColor.green,
|
||||
object->mConsoleFrameColor.blue,
|
||||
object->mConsoleFrameColor.alpha);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
glLineWidth(object->mConsoleLineWidth);
|
||||
glBegin(GL_TRIANGLES);
|
||||
for(U32 i = 0; i < mesh->numPoly; i++)
|
||||
{
|
||||
Sphere::Triangle & tri = mesh->poly[sortInfos[i].idx];
|
||||
for(S32 j = 2; j >= 0; j--)
|
||||
glVertex3f(tri.pnt[j].x * radius + pos.x,
|
||||
tri.pnt[j].y * radius + pos.y,
|
||||
tri.pnt[j].z * radius + pos.z);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glLineWidth(1);
|
||||
}
|
||||
|
||||
// fill
|
||||
if(object->mConsoleFillColor.alpha)
|
||||
{
|
||||
glColor4ub(object->mConsoleFillColor.red,
|
||||
object->mConsoleFillColor.green,
|
||||
object->mConsoleFillColor.blue,
|
||||
object->mConsoleFillColor.alpha);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
for(U32 i = 0; i < mesh->numPoly; i++)
|
||||
{
|
||||
Sphere::Triangle & tri = mesh->poly[sortInfos[i].idx];
|
||||
for(S32 j = 2; j >= 0; j--)
|
||||
glVertex3f(tri.pnt[j].x * radius + pos.x,
|
||||
tri.pnt[j].y * radius + pos.y,
|
||||
tri.pnt[j].z * radius + pos.z);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
ConsoleMethod( EditTSCtrl, renderCircle, void, 5, 6, "(Point3F pos, Point3F normal, float radius, int segments=NULL)")
|
||||
{
|
||||
if(!object->mConsoleRendering)
|
||||
return;
|
||||
|
||||
if(!object->mConsoleFrameColor.alpha && !object->mConsoleFillColor.alpha)
|
||||
return;
|
||||
|
||||
Point3F pos, normal;
|
||||
dSscanf(argv[2], "%g %g %g", &pos.x, &pos.y, &pos.z);
|
||||
dSscanf(argv[3], "%g %g %g", &normal.x, &normal.y, &normal.z);
|
||||
|
||||
F32 radius = dAtoi(argv[4]);
|
||||
|
||||
S32 segments = object->mConsoleCircleSegments;
|
||||
if(argc == 6)
|
||||
segments = dAtoi(argv[5]);
|
||||
|
||||
normal.normalize();
|
||||
|
||||
AngAxisF aa;
|
||||
mCross(normal, Point3F(0,0,1), &aa.axis);
|
||||
aa.axis.normalizeSafe();
|
||||
aa.angle = mAcos(mClampF(mDot(normal, Point3F(0,0,1)), -1.f, 1.f));
|
||||
|
||||
if(aa.angle == 0.f)
|
||||
aa.axis.set(0,0,1);
|
||||
|
||||
MatrixF mat;
|
||||
aa.setMatrix(&mat);
|
||||
|
||||
F32 step = M_2PI / segments;
|
||||
F32 angle = 0.f;
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
Vector<Point3F> points;
|
||||
segments--;
|
||||
for(U32 i = 0; i < segments; i++)
|
||||
{
|
||||
Point3F pnt(mCos(angle), mSin(angle), 0.f);
|
||||
|
||||
mat.mulP(pnt);
|
||||
pnt *= radius;
|
||||
pnt += pos;
|
||||
|
||||
points.push_back(pnt);
|
||||
angle += step;
|
||||
}
|
||||
|
||||
// framed
|
||||
if(object->mConsoleFrameColor.alpha)
|
||||
{
|
||||
glColor4ub(object->mConsoleFrameColor.red,
|
||||
object->mConsoleFrameColor.green,
|
||||
object->mConsoleFrameColor.blue,
|
||||
object->mConsoleFrameColor.alpha);
|
||||
glLineWidth(object->mConsoleLineWidth);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for(U32 i = 0; i < points.size(); i++)
|
||||
glVertex3f(points[i].x, points[i].y, points[i].z);
|
||||
glEnd();
|
||||
glLineWidth(1);
|
||||
}
|
||||
|
||||
// filled
|
||||
if(object->mConsoleFillColor.alpha)
|
||||
{
|
||||
glColor4ub(object->mConsoleFillColor.red,
|
||||
object->mConsoleFillColor.green,
|
||||
object->mConsoleFillColor.blue,
|
||||
object->mConsoleFillColor.alpha);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
for(S32 i = 0; i < points.size(); i++)
|
||||
{
|
||||
S32 j = (i + 1) % points.size();
|
||||
glVertex3f(points[i].x, points[i].y, points[i].z);
|
||||
glVertex3f(points[j].x, points[j].y, points[j].z);
|
||||
glVertex3f(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
ConsoleMethod( EditTSCtrl, renderTriangle, void, 5, 5, "(Point3F a, Point3F b, Point3F c)")
|
||||
{
|
||||
if(!object->mConsoleRendering)
|
||||
return;
|
||||
|
||||
if(!object->mConsoleFrameColor.alpha && !object->mConsoleFillColor.alpha)
|
||||
return;
|
||||
|
||||
Point3F pnts[3];
|
||||
for(U32 i = 0; i < 3; i++)
|
||||
dSscanf(argv[i+2], "%g %g %g", &pnts[i].x, &pnts[i].y, &pnts[i].z);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// frame
|
||||
if(object->mConsoleFrameColor.alpha)
|
||||
{
|
||||
glColor4ub(object->mConsoleFrameColor.red,
|
||||
object->mConsoleFrameColor.green,
|
||||
object->mConsoleFrameColor.blue,
|
||||
object->mConsoleFrameColor.alpha);
|
||||
glLineWidth(object->mConsoleLineWidth);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for(U32 i = 0; i < 3; i++)
|
||||
glVertex3f(pnts[i].x, pnts[i].y, pnts[i].z);
|
||||
glEnd();
|
||||
glLineWidth(1);
|
||||
}
|
||||
|
||||
// fill
|
||||
if(object->mConsoleFillColor.alpha)
|
||||
{
|
||||
glColor4ub(object->mConsoleFillColor.red,
|
||||
object->mConsoleFillColor.green,
|
||||
object->mConsoleFillColor.blue,
|
||||
object->mConsoleFillColor.alpha);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
for(U32 i = 0; i < 3; i++)
|
||||
glVertex3f(pnts[i].x, pnts[i].y, pnts[i].z);
|
||||
glEnd();
|
||||
}
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
ConsoleMethod( EditTSCtrl, renderLine, void, 4, 5, "(Point3F start, Point3F end, int width)")
|
||||
{
|
||||
if(!object->mConsoleRendering)
|
||||
return;
|
||||
|
||||
if(!object->mConsoleFrameColor.alpha)
|
||||
return;
|
||||
|
||||
Point3F start, end;
|
||||
dSscanf(argv[2], "%g %g %g", &start.x, &start.y, &start.z);
|
||||
dSscanf(argv[3], "%g %g %g", &end.x, &end.y, &end.z);
|
||||
|
||||
S32 width = object->mConsoleLineWidth;
|
||||
if(argc == 5)
|
||||
width = dAtoi(argv[4]);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glColor4ub(object->mConsoleFrameColor.red,
|
||||
object->mConsoleFrameColor.green,
|
||||
object->mConsoleFrameColor.blue,
|
||||
object->mConsoleFrameColor.alpha);
|
||||
|
||||
glLineWidth(width);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(start.x, start.y, start.z);
|
||||
glVertex3f(end.x, end.y, end.z);
|
||||
glEnd();
|
||||
|
||||
glLineWidth(1);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
103
engine/editor/editTSCtrl.h
Executable file
103
engine/editor/editTSCtrl.h
Executable file
@ -0,0 +1,103 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#define _EDITTSCTRL_H_
|
||||
|
||||
#ifndef _GUITSCONTROL_H_
|
||||
#include "gui/core/guiTSControl.h"
|
||||
#endif
|
||||
|
||||
struct Gui3DMouseEvent : public GuiEvent
|
||||
{
|
||||
Point3F vec;
|
||||
Point3F pos;
|
||||
};
|
||||
|
||||
class EditManager;
|
||||
|
||||
class EditTSCtrl : public GuiTSCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTSCtrl Parent;
|
||||
|
||||
// EditTSCtrl
|
||||
void make3DMouseEvent(Gui3DMouseEvent & gui3Devent, const GuiEvent &event);
|
||||
void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
|
||||
void onMouseUp(const GuiEvent & event);
|
||||
void onMouseDown(const GuiEvent & event);
|
||||
void onMouseMove(const GuiEvent & event);
|
||||
void onMouseDragged(const GuiEvent & event);
|
||||
void onMouseEnter(const GuiEvent & event);
|
||||
void onMouseLeave(const GuiEvent & event);
|
||||
void onRightMouseDown(const GuiEvent & event);
|
||||
void onRightMouseUp(const GuiEvent & event);
|
||||
void onRightMouseDragged(const GuiEvent & event);
|
||||
bool onInputEvent(const InputEvent & event);
|
||||
|
||||
virtual void updateGuiInfo() {};
|
||||
virtual void renderScene(const RectI &){};
|
||||
void renderMissionArea();
|
||||
|
||||
// GuiTSCtrl
|
||||
void renderWorld(const RectI & updateRect);
|
||||
|
||||
protected:
|
||||
EditManager * mEditManager;
|
||||
Gui3DMouseEvent mLastEvent;
|
||||
|
||||
public:
|
||||
|
||||
EditTSCtrl();
|
||||
~EditTSCtrl();
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
|
||||
//
|
||||
bool mRenderMissionArea;
|
||||
ColorI mMissionAreaFillColor;
|
||||
ColorI mMissionAreaFrameColor;
|
||||
|
||||
//
|
||||
ColorI mConsoleFrameColor;
|
||||
ColorI mConsoleFillColor;
|
||||
S32 mConsoleSphereLevel;
|
||||
S32 mConsoleCircleSegments;
|
||||
S32 mConsoleLineWidth;
|
||||
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
|
||||
//
|
||||
bool mConsoleRendering;
|
||||
bool mRightMousePassThru;
|
||||
|
||||
// all editors will share a camera
|
||||
static Point3F smCamPos;
|
||||
static EulerF smCamRot;
|
||||
static MatrixF smCamMatrix;
|
||||
static F32 smVisibleDistance;
|
||||
|
||||
// GuiTSCtrl
|
||||
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 get3DCursor(GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &);
|
||||
|
||||
DECLARE_CONOBJECT(EditTSCtrl);
|
||||
};
|
||||
|
||||
#endif
|
106
engine/editor/editor.cc
Executable file
106
engine/editor/editor.cc
Executable file
@ -0,0 +1,106 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "editor/editor.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "gui/controls/guiTextListCtrl.h"
|
||||
#include "platform/event.h"
|
||||
#include "game/shapeBase.h"
|
||||
#include "game/gameConnection.h"
|
||||
|
||||
bool gEditingMission = false;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class EditManager
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(EditManager);
|
||||
|
||||
EditManager::EditManager()
|
||||
{
|
||||
for(U32 i = 0; i < 10; i++)
|
||||
mBookmarks[i] = MatrixF(true);
|
||||
}
|
||||
|
||||
EditManager::~EditManager()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool EditManager::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return(false);
|
||||
|
||||
for(SimGroupIterator itr(Sim::getRootGroup()); *itr; ++itr)
|
||||
(*itr)->onEditorEnable();
|
||||
|
||||
gEditingMission = true;
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void EditManager::onSleep()
|
||||
{
|
||||
for(SimGroupIterator itr(Sim::getRootGroup()); *itr; ++itr)
|
||||
(*itr)->onEditorDisable();
|
||||
|
||||
gEditingMission = false;
|
||||
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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static GameBase * getControlObj()
|
||||
{
|
||||
GameConnection * connection = GameConnection::getLocalClientConnection();
|
||||
ShapeBase* control = 0;
|
||||
if(connection)
|
||||
control = 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]);
|
||||
}
|
43
engine/editor/editor.h
Executable file
43
engine/editor/editor.h
Executable file
@ -0,0 +1,43 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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();
|
||||
|
||||
MatrixF mBookmarks[10];
|
||||
DECLARE_CONOBJECT(EditManager);
|
||||
};
|
||||
|
||||
extern bool gEditingMission;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
310
engine/editor/guiTerrPreviewCtrl.cc
Executable file
310
engine/editor/guiTerrPreviewCtrl.cc
Executable file
@ -0,0 +1,310 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "game/game.h"
|
||||
#include "terrain/terrData.h"
|
||||
#include "editor/guiTerrPreviewCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTerrPreviewCtrl);
|
||||
|
||||
GuiTerrPreviewCtrl::GuiTerrPreviewCtrl(void)
|
||||
{
|
||||
mTerrainSize = 2048.0f;
|
||||
mRoot.set( 0, 0 );
|
||||
mOrigin.set( 0, 0 );
|
||||
mWorldScreenCenter.set( mTerrainSize*0.5f, mTerrainSize*0.5f );
|
||||
}
|
||||
|
||||
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 TextureHandle &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 + mOrigin - mWorldScreenCenter );
|
||||
result *= mBounds.extent.x / mTerrainSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void GuiTerrPreviewCtrl::onPreRender()
|
||||
{
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiTerrPreviewCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
struct CameraQuery query;
|
||||
GameProcessCameraQuery(&query);
|
||||
Point3F cameraRot;
|
||||
|
||||
MatrixF matrix = query.cameraMatrix;
|
||||
matrix.getColumn(3,&cameraRot); // get Camera translation
|
||||
mCamera.set(cameraRot.x, -cameraRot.y);
|
||||
matrix.getRow(1,&cameraRot); // get camera rotation
|
||||
|
||||
mTerrainSize = 8*256;
|
||||
TerrainBlock *terrBlock = dynamic_cast<TerrainBlock*>(Sim::findObject("Terrain"));
|
||||
if (terrBlock)
|
||||
mTerrainSize = terrBlock->getSquareSize()*TerrainBlock::BlockSize;
|
||||
|
||||
|
||||
//----------------------------------------- RENDER the Terrain Bitmap
|
||||
if (mTextureHandle)
|
||||
{
|
||||
TextureObject *texture = (TextureObject*)mTextureHandle;
|
||||
if (texture)
|
||||
{
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->texGLName);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
Point2F screenP1(offset.x - 0.5f, offset.y + 0.5f);
|
||||
Point2F screenP2(offset.x + mBounds.extent.x - 0.5f, offset.y + mBounds.extent.x + 0.5f);
|
||||
Point2F textureP1( worldToTexture( mCamera ) );
|
||||
Point2F textureP2(textureP1 + Point2F(1.0f, 1.0f));
|
||||
|
||||
// the texture if flipped horz to reflect how the terrain is really drawn
|
||||
glDisable(GL_CULL_FACE);
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glTexCoord2f(textureP1.x, textureP2.y);
|
||||
glVertex2f(screenP1.x, screenP2.y); // left bottom
|
||||
|
||||
glTexCoord2f(textureP2.x, textureP2.y);
|
||||
glVertex2f(screenP2.x, screenP2.y); // right bottom
|
||||
|
||||
glTexCoord2f(textureP2.x, textureP1.y);
|
||||
glVertex2f(screenP2.x, screenP1.y); // right top
|
||||
|
||||
glTexCoord2f(textureP1.x, textureP1.y);
|
||||
glVertex2f(screenP1.x, screenP1.y); // left top
|
||||
glEnd();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RectI rect(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
|
||||
dglDrawRectFill(rect, ColorI(0,0,0));
|
||||
}
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
//----------------------------------------- RENDER the '+' at the center of the Block
|
||||
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 0.7f);
|
||||
Point2F center( worldToCtrl(Point2F(0,0)) );
|
||||
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;
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(xoffset + center.x, yoffset + center.y-5);
|
||||
glVertex2f(xoffset + center.x, yoffset + center.y+6);
|
||||
glVertex2f(xoffset + center.x-5, yoffset + center.y);
|
||||
glVertex2f(xoffset + center.x+6, yoffset + center.y);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------- RENDER the Block Corners
|
||||
Point2F cornerf( worldToCtrl(Point2F(-mTerrainSize/2.0f, -mTerrainSize/2.0f)) );
|
||||
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;
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
glVertex2i(xoffset + corner.x, yoffset + corner.y-128);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 0.7f);
|
||||
glVertex2i(xoffset + corner.x, yoffset + corner.y);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
glVertex2i(xoffset + corner.x+128, yoffset + corner.y);
|
||||
glEnd();
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
glVertex2i(xoffset + corner.x, yoffset + corner.y+128);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 0.7f);
|
||||
glVertex2i(xoffset + corner.x, yoffset + corner.y);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
glVertex2i(xoffset + corner.x-128, yoffset + corner.y);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------- 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 + mBounds.extent.x / 2), (F32)(offset.y + mBounds.extent.y / 2 ));
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 0.7f);
|
||||
glVertex2i((S32)(center.x + point1.x), (S32)(center.y + point1.y));
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
glVertex2i((S32)center.x,(S32)center.y);
|
||||
glColor4f(1.0f, 0.0f, 0.0f, 0.7f);
|
||||
glVertex2i((S32)(center.x + point2.x), (S32)(center.y + point2.y));
|
||||
glEnd();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
/* debuging stuff
|
||||
Point2I loc(offset.x +5, offset.y+10);
|
||||
dglSetBitmapModulation(mProfile->mFontColor);
|
||||
dglDrawText(mProfile->mFont, loc, avar("mCamera(%3.2f, %3.2f)", mCamera.x, mCamera.y)); loc.y += 10;
|
||||
dglDrawText(mProfile->mFont, loc, avar("mRoot(%3.2f, %3.2f)", mRoot.x, mRoot.y)); loc.y += 10;
|
||||
dglDrawText(mProfile->mFont, loc, avar("mOrigin(%3.2f, %3.2f)", mOrigin.x, mOrigin.y)); loc.y += 10;
|
||||
*/
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
58
engine/editor/guiTerrPreviewCtrl.h
Executable file
58
engine/editor/guiTerrPreviewCtrl.h
Executable file
@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITERRPREVIEWCTRL_H_
|
||||
#define _GUITERRPREVIEWCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
#ifndef _GUITSCONTROL_H_
|
||||
#include "gui/core/guiTSControl.h"
|
||||
#endif
|
||||
|
||||
class GuiTerrPreviewCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
TextureHandle mTextureHandle;
|
||||
Point2F mRoot;
|
||||
Point2F mOrigin;
|
||||
Point2F mWorldScreenCenter;
|
||||
Point2F mCamera;
|
||||
F32 mTerrainSize;
|
||||
|
||||
Point2F& wrap(const Point2F &p);
|
||||
Point2F& worldToTexture(const Point2F &p);
|
||||
Point2F& worldToCtrl(const Point2F &p);
|
||||
|
||||
|
||||
public:
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiTerrPreviewCtrl);
|
||||
GuiTerrPreviewCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
void setBitmap(const TextureHandle &handle);
|
||||
|
||||
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
|
1126
engine/editor/missionAreaEditor.cc
Executable file
1126
engine/editor/missionAreaEditor.cc
Executable file
File diff suppressed because it is too large
Load Diff
145
engine/editor/missionAreaEditor.h
Executable file
145
engine/editor/missionAreaEditor.h
Executable file
@ -0,0 +1,145 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MISSIONAREAEDITOR_H_
|
||||
#define _MISSIONAREAEDITOR_H_
|
||||
|
||||
#ifndef _GUIBITMAPCTRL_H_
|
||||
#include "gui/controls/guiBitmapCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _MISSIONAREA_H_
|
||||
#include "game/missionArea.h"
|
||||
#endif
|
||||
|
||||
class GBitmap;
|
||||
class TerrainBlock;
|
||||
|
||||
class MissionAreaEditor : public GuiBitmapCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiBitmapCtrl Parent;
|
||||
|
||||
SimObjectPtr<MissionArea> mMissionArea;
|
||||
SimObjectPtr<TerrainBlock> mTerrainBlock;
|
||||
|
||||
GBitmap * createTerrainBitmap();
|
||||
void onUpdate();
|
||||
|
||||
void setControlObjPos(const Point2F & pos);
|
||||
bool clampArea(RectI & area);
|
||||
|
||||
// --------------------------------------------------
|
||||
// conversion
|
||||
VectorF mScale;
|
||||
Point2F mCenterPos;
|
||||
|
||||
Point2F worldToScreen(const Point2F &);
|
||||
Point2F screenToWorld(const Point2F &);
|
||||
|
||||
void getScreenMissionArea(RectI & rect);
|
||||
void getScreenMissionArea(RectF & rect);
|
||||
|
||||
void setupScreenTransform(const Point2I & offset);
|
||||
|
||||
// --------------------------------------------------
|
||||
// mouse
|
||||
enum {
|
||||
DefaultCursor = 0,
|
||||
HandCursor,
|
||||
GrabCursor,
|
||||
VertResizeCursor,
|
||||
HorizResizeCursor,
|
||||
DiagRightResizeCursor,
|
||||
DiagLeftResizeCursor,
|
||||
NumCursors
|
||||
};
|
||||
|
||||
bool grabCursors();
|
||||
GuiCursor * mCurrentCursor;
|
||||
GuiCursor * mCursors[NumCursors];
|
||||
void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
|
||||
void setCursor(U32 cursor);
|
||||
|
||||
S32 mLastHitMode;
|
||||
Point2I mLastMousePoint;
|
||||
|
||||
// --------------------------------------------------
|
||||
// mission area
|
||||
enum {
|
||||
NUT_SIZE = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
nothing = 0,
|
||||
sizingLeft = BIT(0),
|
||||
sizingRight = BIT(1),
|
||||
sizingTop = BIT(2),
|
||||
sizingBottom = BIT(3),
|
||||
moving = BIT(4)
|
||||
};
|
||||
|
||||
void updateCursor(S32 hit);
|
||||
bool inNut(const Point2I & pt, S32 x, S32 y);
|
||||
S32 getSizingHitKnobs(const Point2I & pt, const RectI & box);
|
||||
void drawNut(const Point2I & nut);
|
||||
void drawNuts(RectI & box);
|
||||
|
||||
public:
|
||||
|
||||
MissionAreaEditor();
|
||||
|
||||
//
|
||||
bool missionAreaObjValid() { return(!mMissionArea.isNull()); }
|
||||
bool terrainObjValid() { return(!mTerrainBlock.isNull()); }
|
||||
|
||||
TerrainBlock * getTerrainObj();
|
||||
|
||||
const RectI & getArea();
|
||||
void setArea(const RectI & area);
|
||||
|
||||
void updateTerrainBitmap();
|
||||
|
||||
// GuiControl
|
||||
void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
void onMouseUp(const GuiEvent & event);
|
||||
void onMouseDown(const GuiEvent & event);
|
||||
void onMouseMove(const GuiEvent & event);
|
||||
void onMouseDragged(const GuiEvent & event);
|
||||
void onMouseEnter(const GuiEvent & event);
|
||||
void onMouseLeave(const GuiEvent & event);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
|
||||
// field data..
|
||||
bool mSquareBitmap;
|
||||
bool mEnableEditing;
|
||||
bool mRenderCamera;
|
||||
|
||||
ColorI mHandleFrameColor;
|
||||
ColorI mHandleFillColor;
|
||||
ColorI mDefaultObjectColor;
|
||||
ColorI mWaterObjectColor;
|
||||
ColorI mMissionBoundsColor;
|
||||
ColorI mCameraColor;
|
||||
|
||||
bool mEnableMirroring;
|
||||
S32 mMirrorIndex;
|
||||
ColorI mMirrorLineColor;
|
||||
ColorI mMirrorArrowColor;
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
DECLARE_CONOBJECT(MissionAreaEditor);
|
||||
};
|
||||
|
||||
#endif
|
1346
engine/editor/terraformer.cc
Executable file
1346
engine/editor/terraformer.cc
Executable file
File diff suppressed because it is too large
Load Diff
230
engine/editor/terraformer.h
Executable file
230
engine/editor/terraformer.h
Executable file
@ -0,0 +1,230 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TERRAFORMER_H_
|
||||
#define _TERRAFORMER_H_
|
||||
|
||||
#ifndef _CONSOLE_H_
|
||||
#include "console/console.h"
|
||||
#endif
|
||||
#ifndef _SIMBASE_H_
|
||||
#include "console/simBase.h"
|
||||
#endif
|
||||
#ifndef _TERRDATA_H_
|
||||
#include "terrain/terrData.h"
|
||||
#endif
|
||||
#ifndef _GBITMAP_H_
|
||||
#include "dgl/gBitmap.h"
|
||||
#endif
|
||||
#ifndef _MRANDOM_H_
|
||||
#include "math/mRandom.h"
|
||||
#endif
|
||||
#ifndef _TERRAFORMER_NOISE_H_
|
||||
#include "editor/terraformerNoise.h"
|
||||
#endif
|
||||
#ifndef _GUIFILTERCTRL_H_
|
||||
#include "gui/editor/guiFilterCtrl.h"
|
||||
#endif
|
||||
|
||||
|
||||
struct Heightfield
|
||||
{
|
||||
static S32 *zoneOffset;
|
||||
static U32 instance;
|
||||
|
||||
U32 registerNumber;
|
||||
U32 mask;
|
||||
U32 shift;
|
||||
union
|
||||
{
|
||||
F32 *data;
|
||||
S32 *dataS32;
|
||||
};
|
||||
Heightfield(U32 r, U32 sz);
|
||||
~Heightfield();
|
||||
|
||||
Heightfield& operator=(const Heightfield &src);
|
||||
S32 offset(S32 x, S32 y);
|
||||
F32& val(S32 x, S32 y);
|
||||
F32& val(S32 index);
|
||||
void block(S32 x, S32 y, F32 *a );
|
||||
|
||||
S32& valS32(S32 x, S32 y);
|
||||
S32& valS32(S32 index);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Terraformer: public SimObject
|
||||
{
|
||||
public:
|
||||
typedef SimObject Parent;
|
||||
enum BlendOperation
|
||||
{
|
||||
OperationAdd,
|
||||
OperationSubtract,
|
||||
OperationMax,
|
||||
OperationMin,
|
||||
OperationMultiply,
|
||||
};
|
||||
|
||||
private:
|
||||
VectorPtr<Heightfield*> registerList;
|
||||
VectorPtr<Heightfield*> scratchList;
|
||||
MRandomR250 random;
|
||||
|
||||
Noise2D noise;
|
||||
|
||||
// used by wrap, val inlines
|
||||
U32 blockMask;
|
||||
U32 blockSize;
|
||||
F32 worldTileSize;
|
||||
F32 worldBaseHeight;
|
||||
F32 worldHeight;
|
||||
F32 worldWater;
|
||||
Point2F mShift;
|
||||
|
||||
S32 wrap(S32 p);
|
||||
|
||||
Heightfield* getRegister(U32 r);
|
||||
Heightfield* getScratch(U32 r);
|
||||
void getMinMax(U32 r, F32 *fmin, F32 *fmax);
|
||||
|
||||
public:
|
||||
Terraformer();
|
||||
~Terraformer();
|
||||
DECLARE_CONOBJECT(Terraformer);
|
||||
|
||||
void setSize(U32 n);
|
||||
void setTerrainInfo(U32 blockSize, F32 tileSize, F32 minHeight, F32 heightRange, F32 worldWater);
|
||||
void setShift( const Point2F &shift );
|
||||
void clearRegister(U32 r);
|
||||
|
||||
// I/O operations
|
||||
GBitmap* getScaledGreyscale(U32 r);
|
||||
GBitmap* getGreyscale(U32 r);
|
||||
bool saveGreyscale(U32 r, const char *filename);
|
||||
bool loadGreyscale(U32 r, const char *filename);
|
||||
bool saveHeightField(U32 r, const char *filename);
|
||||
bool setTerrain(U32 r);
|
||||
void setCameraPosition(const Point3F & pos);
|
||||
Point3F getCameraPosition();
|
||||
|
||||
|
||||
// Mathmatical operations
|
||||
bool scale(U32 r_src, U32 r_dst, F32 fmin, F32 fmax);
|
||||
bool smooth(U32 r_src, U32 r_dst, F32 factor, U32 iterations);
|
||||
bool smoothWater(U32 r_src, U32 r_dst, F32 factor, U32 iterations);
|
||||
bool smoothRidges(U32 r_src, U32 r_dst, F32 factor, U32 iterations, F32 threshold);
|
||||
bool blend(U32 r_srcA, U32 r_srcB, U32 r_dst, F32 factor, BlendOperation operation);
|
||||
bool filter(U32 r_src, U32 r_dst, const Filter &filter);
|
||||
bool turbulence(U32 r_src, U32 r_dst, F32 v, F32 r);
|
||||
bool shift(U32 r_src);
|
||||
|
||||
// Generation operations
|
||||
bool setHeight(U32 r, F32 height);
|
||||
bool terrainData(U32 r);
|
||||
bool terrainFile(U32 r, const char * terrFile);
|
||||
bool fBm(U32 r, U32 interval, F32 roughness, F32 detail, U32 seed);
|
||||
bool rigidMultiFractal(U32 r, U32 interval, F32 roughness, F32 detail, U32 seed);
|
||||
bool canyonFractal(U32 r, U32 f, F32 v, U32 seed);
|
||||
bool sinus(U32 r, const Filter &filter, U32 seed);
|
||||
|
||||
// effects
|
||||
bool erodeHydraulic(U32 r_src, U32 r_dst, U32 iterations, const Filter &filter);
|
||||
bool erodeThermal(U32 r_src, U32 r_dst, F32 slope, F32 materialLoss, U32 iterations);
|
||||
|
||||
// Texturing operations
|
||||
bool maskFBm(U32 r_dst, U32 interval, F32 roughness, U32 seed, const Filter &filter, bool distort, U32 r_distort);
|
||||
bool maskHeight(U32 r_src, U32 r_dst, const Filter &filter, bool distort, U32 r_distort);
|
||||
bool maskSlope(U32 r_src, U32 r_dst, const Filter &filter, bool distort, U32 r_distort);
|
||||
bool maskWater(U32 r_src, U32 r_dst, bool distort, U32 r_distort);
|
||||
|
||||
bool mergeMasks(const char *r_src, U32 r_dst);
|
||||
bool setMaterials(const char *r_src, const char *materials);
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
inline S32 Heightfield::offset(S32 x, S32 y)
|
||||
{
|
||||
return (y<<shift) + x;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
inline F32& Heightfield::val(S32 i)
|
||||
{
|
||||
return (data[i]);
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
inline F32& Heightfield::val(S32 x, S32 y)
|
||||
{
|
||||
return data[ (y<<shift) + x ];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
inline S32& Heightfield::valS32(S32 i)
|
||||
{
|
||||
return (dataS32[i]);
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
inline S32& Heightfield::valS32(S32 x, S32 y)
|
||||
{
|
||||
return dataS32[ (y<<shift) + x ];
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
inline S32 Terraformer::wrap(S32 p)
|
||||
{ // simply wrap the coordinate
|
||||
return (p & blockMask);
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
inline void Heightfield::block(S32 x, S32 y, F32 *a )
|
||||
{
|
||||
// zone = 0-8
|
||||
//
|
||||
// 0 1 2
|
||||
// 3 4 5
|
||||
// 5 6 8
|
||||
//
|
||||
|
||||
U32 zone = 0;
|
||||
if (x > 0)
|
||||
{
|
||||
zone++;
|
||||
if ((U32)x >= mask)
|
||||
zone++;
|
||||
}
|
||||
if (y > 0)
|
||||
{
|
||||
zone += 3;
|
||||
if ((U32)y >= mask)
|
||||
zone += 3;
|
||||
}
|
||||
|
||||
F32 *d = &data[ (y<<shift) + x ];
|
||||
S32 *p = &zoneOffset[ zone*9 ];
|
||||
|
||||
a[0] = d[ p[0] ];
|
||||
a[1] = d[ p[1] ];
|
||||
a[2] = d[ p[2] ];
|
||||
|
||||
a[3] = d[ p[3] ];
|
||||
a[4] = d[ p[4] ];
|
||||
a[5] = d[ p[5] ];
|
||||
|
||||
a[6] = d[ p[6] ];
|
||||
a[7] = d[ p[7] ];
|
||||
a[8] = d[ p[8] ];
|
||||
}
|
||||
|
||||
|
||||
#endif //_H_TERRAFORMER_
|
323
engine/editor/terraformerNoise.cc
Executable file
323
engine/editor/terraformerNoise.cc
Executable file
@ -0,0 +1,323 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "editor/terraformerNoise.h"
|
||||
#include "editor/terraformer.h"
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
Noise2D::Noise2D()
|
||||
{
|
||||
mSeed = 0;
|
||||
}
|
||||
|
||||
Noise2D::~Noise2D()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void Noise2D::normalize(F32 v[2])
|
||||
{
|
||||
F32 s;
|
||||
|
||||
s = mSqrt(v[0] * v[0] + v[1] * v[1]);
|
||||
v[0] = v[0] / s;
|
||||
v[1] = v[1] / s;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void Noise2D::setSeed(U32 seed)
|
||||
{
|
||||
if (mSeed == seed)
|
||||
return;
|
||||
mSeed = seed;
|
||||
mRandom.setSeed(mSeed);
|
||||
|
||||
S32 i, j, k;
|
||||
|
||||
for (i = 0 ; i < SIZE ; i++) {
|
||||
mPermutation[i] = i;
|
||||
|
||||
for (j = 0 ; j < 2 ; j++)
|
||||
mGradient[i][j] = mRandom.randF( -1.0f, 1.0f );
|
||||
normalize(mGradient[i]);
|
||||
}
|
||||
|
||||
while (--i) {
|
||||
k = mPermutation[i];
|
||||
j = mRandom.randI(0, SIZE-1);
|
||||
mPermutation[i] = mPermutation[j];
|
||||
mPermutation[j] = k;
|
||||
}
|
||||
|
||||
// extend the size of the arrays x2 to get rid of a bunch of MODs
|
||||
// we'd have to do later in the code
|
||||
for (i = 0 ; i < SIZE + 2 ; i++) {
|
||||
mPermutation[SIZE + i] = mPermutation[i];
|
||||
for (j = 0 ; j < 2 ; j++)
|
||||
mGradient[SIZE + i][j] = mGradient[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
U32 Noise2D::getSeed()
|
||||
{
|
||||
return mSeed;
|
||||
}
|
||||
|
||||
|
||||
inline F32 Noise2D::lerp(F32 t, F32 a, F32 b)
|
||||
{
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
|
||||
inline F32 Noise2D::curve(F32 t)
|
||||
{
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
}
|
||||
|
||||
|
||||
inline F32 clamp(F32 f, F32 m)
|
||||
{
|
||||
while (f > m)
|
||||
f -= m;
|
||||
while (f < 0.0f)
|
||||
f += m;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void Noise2D::fBm(Heightfield *dst, U32 size, U32 interval, F32 h, F32 octaves)
|
||||
{
|
||||
interval = getMin(U32(128), getMax(U32(1), interval));
|
||||
F32 H = getMin(1.0f, getMax(0.0f, h));
|
||||
octaves = getMin(5.0f, getMax(1.0f, octaves));
|
||||
F32 lacunarity = 2.0f;
|
||||
|
||||
F32 exponent_array[32];
|
||||
|
||||
// precompute and store spectral weights
|
||||
// seize required memory for exponent_array
|
||||
F32 frequency = 1.0;
|
||||
for (U32 i=0; i<=octaves; i++)
|
||||
{
|
||||
// compute weight for each frequency
|
||||
exponent_array[i] = mPow( frequency, -H );
|
||||
frequency *= lacunarity;
|
||||
}
|
||||
|
||||
// initialize dst
|
||||
for (S32 k=0; k < (size*size); k++)
|
||||
dst->val(k) = 0.0f;
|
||||
|
||||
F32 scale = 1.0f / (F32)size * interval;
|
||||
for (S32 o=0; o<octaves; o++)
|
||||
{
|
||||
F32 exp = exponent_array[o];
|
||||
for (S32 y=0; y<size; y++)
|
||||
{
|
||||
F32 fy = (F32)y * scale;
|
||||
for (S32 x=0; x<size; x++)
|
||||
{
|
||||
F32 fx = (F32)x * scale;
|
||||
F32 noise = getValue(fx, fy, interval);
|
||||
dst->val(x, y) += noise * exp;
|
||||
}
|
||||
}
|
||||
scale *= lacunarity;
|
||||
interval = (U32)(interval * lacunarity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void Noise2D::rigidMultiFractal(Heightfield *dst, Heightfield *sig, U32 size, U32 interval, F32 h, F32 octaves)
|
||||
{
|
||||
interval = getMin(U32(128), getMax(U32(1), interval));
|
||||
F32 H = getMin(1.0f, getMax(0.0f, h));
|
||||
octaves = getMin(5.0f, getMax(1.0f, octaves));
|
||||
F32 lacunarity = 2.0f;
|
||||
F32 offset = 1.0f;
|
||||
F32 gain = 2.0f;
|
||||
|
||||
F32 exponent_array[32];
|
||||
|
||||
// precompute and store spectral weights
|
||||
// seize required memory for exponent_array
|
||||
F32 frequency = 1.0;
|
||||
for (U32 i=0; i<=octaves; i++)
|
||||
{
|
||||
// compute weight for each frequency
|
||||
exponent_array[i] = mPow( frequency, -H );
|
||||
frequency *= lacunarity;
|
||||
}
|
||||
|
||||
F32 scale = 1.0f / (F32)size * interval;
|
||||
|
||||
//--------------------------------------
|
||||
// compute first octave
|
||||
for (S32 y=0; y<size; y++)
|
||||
{
|
||||
F32 fy = (F32)y * scale;
|
||||
for (S32 x=0; x<size; x++)
|
||||
{
|
||||
F32 fx = (F32)x * scale;
|
||||
|
||||
F32 signal = mFabs(getValue(fx,fy,interval)); // get absolute value of signal (this creates the ridges)
|
||||
//signal = mSqrt(signal);
|
||||
signal = offset - signal; // invert and translate (note that "offset" should be ~= 1.0)
|
||||
signal *= signal + 0.1; // square the signal, to increase "sharpness" of ridges
|
||||
|
||||
// assign initial values
|
||||
dst->val(x, y) = signal;
|
||||
sig->val(x, y) = signal;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
// compute remaining octaves
|
||||
for (S32 o=1; o<octaves; o++)
|
||||
{
|
||||
// increase the frequency
|
||||
scale *= lacunarity;
|
||||
interval = (U32)(interval * lacunarity);
|
||||
F32 exp = exponent_array[o];
|
||||
|
||||
for (S32 y=0; y<size; y++)
|
||||
{
|
||||
F32 fy = (F32)y * scale;
|
||||
for (S32 x=0; x<size; x++)
|
||||
{
|
||||
F32 fx = (F32)x * scale;
|
||||
U32 index = dst->offset(x,y);
|
||||
F32 result = dst->val(index);
|
||||
F32 signal = sig->val(index);
|
||||
|
||||
// weight successive contributions by previous signal
|
||||
F32 weight = mClampF(signal * gain, 0.0f, 1.0f);
|
||||
|
||||
signal = mFabs(getValue( fx, fy, interval ));
|
||||
|
||||
signal = offset - signal;
|
||||
signal *= signal + 0.2;
|
||||
// weight the contribution
|
||||
signal *= weight;
|
||||
result += signal * exp;
|
||||
|
||||
dst->val(index) = result;
|
||||
sig->val(index) = signal;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (S32 k=0; k < (size*size); k++)
|
||||
dst->val(k) = (dst->val(k)-1.0f)/2.0f;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
F32 Noise2D::turbulence(F32 x, F32 y, F32 freq)
|
||||
{
|
||||
F32 t, x2, y2;
|
||||
|
||||
for ( t = 0.0f ; freq >= 3.0f ; freq /= 2.0f)
|
||||
{
|
||||
x2 = freq * x;
|
||||
y2 = freq * y;
|
||||
t += mFabs(getValue(x2, y2, (S32)freq)) / freq;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
inline void Noise2D::setup(F32 t, S32 &b0, S32 &b1, F32 &r0, F32 &r1)
|
||||
{
|
||||
// find the bounding integers of u
|
||||
b0 = S32(t) & SIZE_MASK;
|
||||
b1 = (b0+1) & SIZE_MASK;
|
||||
|
||||
// seperate the fractional components
|
||||
r0 = t - (S32)t;
|
||||
r1 = r0 - 1.0f;
|
||||
}
|
||||
|
||||
inline F32 Noise2D::dot(const F32 *q, F32 rx, F32 ry)
|
||||
{
|
||||
return (rx * q[0] + ry * q[1] );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
F32 Noise2D::getValue(F32 x, F32 y, S32 interval)
|
||||
{
|
||||
S32 bx0, bx1, by0, by1;
|
||||
F32 rx0, rx1, ry0, ry1;
|
||||
|
||||
// Imagine having a square of the type
|
||||
// p0---p1 Where p0 = (bx0, by0) +----> U
|
||||
// |(u,v)| p1 = (bx1, by0) |
|
||||
// | | p2 = (bx0, by1) | Coordinate System
|
||||
// p2---p3 p3 = (bx1, by1) V
|
||||
// The u, v point in 2D texture space is bounded by this rectangle.
|
||||
|
||||
// Goal, determine the scalar at the points p0, p1, p2, p3.
|
||||
// Then the scalar of the point (u, v) will be found by linear interpolation.
|
||||
|
||||
// First step: Get the 2D coordinates of the points p0, p1, p2, p3.
|
||||
// We also need vectors pointing from each point in the square above and
|
||||
// ending at the (u,v) coordinate located inside the square.
|
||||
// The vector (rx0, ry0) goes from P0 to the (u,v) coordinate.
|
||||
// The vector (rx1, ry0) goes from P1 to the (u,v) coordinate.
|
||||
// The vector (rx0, ry1) goes from P2 to the (u,v) coordinate.
|
||||
// The vector (rx1, ry1) goes from P3 to the (u,v) coordinate.
|
||||
|
||||
setup(x, bx0, bx1, rx0, rx1);
|
||||
setup(y, by0, by1, ry0, ry1);
|
||||
|
||||
// Make sure the box corners fall within the interval
|
||||
// so that the final output will wrap on itself
|
||||
bx0 = bx0 % interval;
|
||||
bx1 = bx1 % interval;
|
||||
by0 = by0 % interval;
|
||||
by1 = by1 % interval;
|
||||
|
||||
S32 i = mPermutation[ bx0 ];
|
||||
S32 j = mPermutation[ bx1 ];
|
||||
|
||||
S32 b00 = mPermutation[ i + by0 ];
|
||||
S32 b10 = mPermutation[ j + by0 ];
|
||||
S32 b01 = mPermutation[ i + by1 ];
|
||||
S32 b11 = mPermutation[ j + by1 ];
|
||||
|
||||
// Next, calculate the dropoff component about the point p0.
|
||||
F32 sx = curve(rx0);
|
||||
F32 sy = curve(ry0);
|
||||
|
||||
// Now, for each point in the square shown above, calculate the dot
|
||||
// product of the gradiant vector and the vector going from each square
|
||||
// corner point to the (u,v) point inside the square.
|
||||
F32 u = dot(mGradient[ b00 ], rx0,ry0);
|
||||
F32 v = dot(mGradient[ b10 ], rx1,ry0);
|
||||
|
||||
// Interpolation along the X axis.
|
||||
F32 a = lerp(sx, u, v);
|
||||
|
||||
u = dot(mGradient[ b01 ], rx0,ry1);
|
||||
v = dot(mGradient[ b11 ], rx1,ry1);
|
||||
|
||||
// Interpolation along the Y axis.
|
||||
F32 b = lerp(sx, u, v);
|
||||
|
||||
// Final Interpolation
|
||||
return lerp(sy, a, b);
|
||||
}
|
||||
|
||||
|
58
engine/editor/terraformerNoise.h
Executable file
58
engine/editor/terraformerNoise.h
Executable file
@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TERRAFORMER_NOISE_H_
|
||||
#define _TERRAFORMER_NOISE_H_
|
||||
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _MMATH_H_
|
||||
#include "math/mMath.h"
|
||||
#endif
|
||||
#ifndef _MRANDOM_H_
|
||||
#include "math/mRandom.h"
|
||||
#endif
|
||||
|
||||
struct Heightfield;
|
||||
|
||||
class Noise2D
|
||||
{
|
||||
private:
|
||||
enum Constants {
|
||||
SIZE = 0x100,
|
||||
SIZE_MASK = 0x0ff
|
||||
};
|
||||
S32 mPermutation[SIZE + SIZE + 2];
|
||||
F32 mGradient[SIZE + SIZE + 2][2];
|
||||
|
||||
U32 mSeed;
|
||||
|
||||
MRandom mRandom;
|
||||
|
||||
F32 lerp(F32 t, F32 a, F32 b);
|
||||
F32 curve(F32 t);
|
||||
void setup(F32 t, S32 &b0, S32 &b1, F32 &r0, F32 &r1);
|
||||
F32 dot(const F32 *q, F32 rx, F32 ry);
|
||||
void normalize(F32 v[2]);
|
||||
|
||||
|
||||
public:
|
||||
Noise2D();
|
||||
~Noise2D();
|
||||
|
||||
void setSeed(U32 seed);
|
||||
U32 getSeed();
|
||||
|
||||
F32 getValue(F32 u, F32 v, S32 interval);
|
||||
void fBm(Heightfield *dst, U32 size, U32 interval, F32 h, F32 octave=5.0f);
|
||||
void rigidMultiFractal(Heightfield *dst, Heightfield *signal, U32 size, U32 interval, F32 h, F32 octave=5.0f);
|
||||
F32 turbulence(F32 x, F32 y, F32 freq);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // _H_TERRAFORMER_NOISE_
|
411
engine/editor/terraformerTexture.cc
Executable file
411
engine/editor/terraformerTexture.cc
Executable file
@ -0,0 +1,411 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "terrain/terrData.h"
|
||||
#include "editor/terraformer.h"
|
||||
#include "gui/editor/guiFilterCtrl.h"
|
||||
#include "editor/editor.h"
|
||||
#include "platform/event.h"
|
||||
#include "game/gameConnection.h"
|
||||
|
||||
#include "core/fileStream.h"
|
||||
|
||||
|
||||
|
||||
inline F32 lerp(F32 t, F32 a, F32 b)
|
||||
{
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
|
||||
inline F32 curve(F32 t)
|
||||
{
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
}
|
||||
|
||||
|
||||
F32 getAlpha(U32 x, U32 y, Heightfield *alpha)
|
||||
{
|
||||
F32 xFactor = F32(x & 7) * (1.0f/8.0f);
|
||||
F32 yFactor = F32(y & 7) * (1.0f/8.0f);
|
||||
U32 xi = x >> 3;
|
||||
U32 yi = y >> 3;
|
||||
|
||||
F32 a0 = alpha->val(xi, yi);
|
||||
F32 a1 = alpha->val(xi+1, yi);
|
||||
F32 a2 = alpha->val(xi+1, yi+1);
|
||||
F32 a3 = alpha->val(xi, yi+1);
|
||||
|
||||
// F32 ah0 = (a0 * (1.0f-xFactor)) + (a1 * xFactor);
|
||||
// F32 ah1 = (a3 * (1.0f-xFactor)) + (a2 * xFactor);
|
||||
//
|
||||
// F32 a = (ah0 * (1.0f-yFactor)) + (ah1 * yFactor);
|
||||
|
||||
//xFactor = curve(xFactor);
|
||||
//yFactor = curve(yFactor);
|
||||
|
||||
F32 ah0 = lerp(xFactor, a0, a1);
|
||||
F32 ah1 = lerp(xFactor, a3, a2);
|
||||
F32 a = lerp(yFactor, ah0, ah1);
|
||||
|
||||
return (a*a);
|
||||
}
|
||||
|
||||
|
||||
GBitmap* merge(VectorPtr<Heightfield*> &alpha, VectorPtr<GBitmap*> &material)
|
||||
{
|
||||
// due to memory constraints we build the the output bitmap one scan-line at a time.
|
||||
F32 sum[2048];
|
||||
GBitmap *bitmap = new GBitmap(2048, 2048, false, GBitmap::RGB);
|
||||
VectorPtr<Heightfield*>::iterator itrA;
|
||||
VectorPtr<GBitmap*>::iterator itrM;
|
||||
|
||||
for (S32 y = 0; y<2048; y++)
|
||||
{
|
||||
// first compute the sum of the alphas at each pixel
|
||||
S32 x;
|
||||
for (x = 0; x<2048; x++)
|
||||
{
|
||||
sum[x] = 0.0f;
|
||||
for (itrA = alpha.begin(); itrA != alpha.end(); itrA++)
|
||||
sum[x] += getAlpha(x,y,*itrA);
|
||||
}
|
||||
|
||||
// blend the pixels
|
||||
for (x = 0; x<2048; x++)
|
||||
{
|
||||
ColorI blend(0,0,0,0);
|
||||
if (sum[x] > 0.0f)
|
||||
{
|
||||
F32 fsum = sum[x];
|
||||
F32 scaleFactor = (1.0f/fsum);
|
||||
for (itrA = alpha.begin(), itrM = material.begin(); itrM != material.end(); itrM++, itrA++)
|
||||
{
|
||||
ColorI color;
|
||||
GBitmap *bmp = *itrM;
|
||||
bmp->getColor(x % bmp->getWidth(), y % bmp->getHeight(), color);
|
||||
color *= getAlpha(x,y,*itrA) * scaleFactor;
|
||||
blend.red += color.red;
|
||||
blend.green += color.green;
|
||||
blend.blue += color.blue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GBitmap *mat = *material.begin();
|
||||
mat->getColor(x % mat->getWidth(), y % mat->getHeight(), blend);
|
||||
}
|
||||
bitmap->setColor(x,y,blend);
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
bool Terraformer::setMaterials(const char *r_src, const char *materials )
|
||||
{
|
||||
TerrainBlock *serverTerrBlock = dynamic_cast<TerrainBlock*>(Sim::findObject("Terrain"));
|
||||
if (!serverTerrBlock)
|
||||
return false;
|
||||
|
||||
NetConnection* toServer = NetConnection::getConnectionToServer();
|
||||
NetConnection* toClient = NetConnection::getLocalClientConnection();
|
||||
|
||||
S32 index = toClient->getGhostIndex(serverTerrBlock);
|
||||
|
||||
TerrainBlock *clientTerrBlock = dynamic_cast<TerrainBlock*>(toServer->resolveGhost(index));
|
||||
if (!clientTerrBlock)
|
||||
return false;
|
||||
|
||||
VectorPtr<Heightfield*> src;
|
||||
VectorPtr<char*> dml;
|
||||
Vector<S32> dmlIndex;
|
||||
|
||||
//--------------------------------------
|
||||
// extract the source registers
|
||||
char buffer[1024];
|
||||
dStrcpy(buffer, r_src);
|
||||
char *str = dStrtok(buffer, " \0");
|
||||
while (str)
|
||||
{
|
||||
src.push_back( getRegister(dAtof(str)) );
|
||||
str = dStrtok(NULL, " \0");
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
// extract the materials
|
||||
dStrcpy(buffer, materials);
|
||||
str = dStrtok(buffer, " \0");
|
||||
while (str)
|
||||
{
|
||||
S32 i;
|
||||
for (i=0; i<dml.size(); i++)
|
||||
if (dStricmp(str, dml[i]) == 0)
|
||||
break;
|
||||
|
||||
// a unique material list ?
|
||||
if (i == dml.size())
|
||||
dml.push_back(str);
|
||||
|
||||
// map register to dml
|
||||
dmlIndex.push_back(i);
|
||||
|
||||
str = dStrtok(NULL, " \0");
|
||||
}
|
||||
|
||||
if (dml.size() > TerrainBlock::MaterialGroups)
|
||||
{
|
||||
Con::printf("maximum number of DML Material Exceeded");
|
||||
return false;
|
||||
}
|
||||
|
||||
// install the new DMLs
|
||||
clientTerrBlock->setBaseMaterials(dml.size(), (const char**)dml.address());
|
||||
|
||||
//--------------------------------------
|
||||
// build alpha masks for each material type
|
||||
|
||||
for (S32 y=0; y<blockSize; y++)
|
||||
{
|
||||
for (S32 x=0; x<blockSize; x++)
|
||||
{
|
||||
// skip? (cannot skip if index is out of range...)
|
||||
F32 total = 0;
|
||||
F32 matVals[TerrainBlock::MaterialGroups];
|
||||
S32 i;
|
||||
|
||||
for(i = 0; i < TerrainBlock::MaterialGroups; i++)
|
||||
matVals[i] = 0;
|
||||
|
||||
for(i = 0; i < src.size(); i++)
|
||||
{
|
||||
matVals[dmlIndex[i]] += src[i]->val(x,y);
|
||||
total += src[i]->val(x,y);
|
||||
}
|
||||
|
||||
if(total == 0)
|
||||
{
|
||||
matVals[0] = 1;
|
||||
total = 1;
|
||||
}
|
||||
|
||||
// axe out any amount that is less than the threshold
|
||||
F32 threshold = 0.15 * total;
|
||||
for(i = 0; i < TerrainBlock::MaterialGroups; i++)
|
||||
if(matVals[i] < threshold)
|
||||
matVals[i] = 0;
|
||||
|
||||
total = 0;
|
||||
for(i = 0; i < TerrainBlock::MaterialGroups; i++)
|
||||
total += matVals[i];
|
||||
|
||||
for(i = 0; i < TerrainBlock::MaterialGroups; i++)
|
||||
{
|
||||
U8 *map = clientTerrBlock->getMaterialAlphaMap(i);
|
||||
map[x + (y << TerrainBlock::BlockShift)] = (U8)(255 * matVals[i] / total);
|
||||
}
|
||||
|
||||
S32 material = 0;
|
||||
F32 best = 0.0f;
|
||||
for (i=0; i<src.size(); i++)
|
||||
{
|
||||
F32 value = src[i]->val(x,y);
|
||||
if ( value > best)
|
||||
{
|
||||
material = dmlIndex[i];
|
||||
best = value;
|
||||
}
|
||||
}
|
||||
// place the material
|
||||
*clientTerrBlock->getBaseMaterialAddress(x, y) = material;
|
||||
}
|
||||
}
|
||||
|
||||
// make it so!
|
||||
clientTerrBlock->buildGridMap();
|
||||
clientTerrBlock->buildMaterialMap();
|
||||
|
||||
// reload the material lists?
|
||||
if(gEditingMission)
|
||||
clientTerrBlock->refreshMaterialLists();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// for mow steal the first bitmap out of each dml
|
||||
|
||||
if (Con::getBoolVariable("$terrainTestBmp", false) == true)
|
||||
{
|
||||
VectorPtr<GBitmap*> mats;
|
||||
for (S32 i=0; i<dmlIndex.size(); i++)
|
||||
{
|
||||
Resource<MaterialList> mlist = ResourceManager->load(dml[dmlIndex[i]]);
|
||||
mlist->load();
|
||||
GBitmap *bmp = mlist->getMaterial(0).getBitmap();
|
||||
mats.push_back(bmp);
|
||||
}
|
||||
GBitmap *texture = merge(src,mats);
|
||||
|
||||
FileStream stream;
|
||||
stream.open("terrain.png", FileStream::Write);
|
||||
texture->writePNG(stream);
|
||||
stream.close();
|
||||
delete texture;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
bool Terraformer::mergeMasks(const char *r_src, U32 r_dst)
|
||||
{
|
||||
Heightfield *dst = getRegister(r_dst);
|
||||
VectorPtr<Heightfield*> src;
|
||||
|
||||
// extract the source registers
|
||||
char buffer[1024];
|
||||
dStrcpy(buffer, r_src);
|
||||
char *reg = dStrtok(buffer, " \0");
|
||||
while (reg)
|
||||
{
|
||||
src.push_back( getRegister(dAtoi(reg)) );
|
||||
reg = dStrtok(NULL, " \0");
|
||||
}
|
||||
|
||||
// if no masks set the destination to Zero
|
||||
if (src.size() == 0)
|
||||
{
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) = 0.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (src.size() == 1)
|
||||
{
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) = src[0]->val(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
// store the MAX of the masks into dst
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
{
|
||||
F32 value = src[0]->val(i);
|
||||
for (S32 j=1; j<src.size(); j++)
|
||||
value *= src[j]->val(i);
|
||||
dst->val(i) = value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
bool Terraformer::maskFBm(U32 r_dst, U32 interval, F32 roughness, U32 seed, const Filter &filter, bool distort, U32 r_distort)
|
||||
{
|
||||
Heightfield *dst = getRegister(r_dst);
|
||||
noise.setSeed(seed);
|
||||
noise.fBm(dst, blockSize, interval, 1.0-roughness, 3.0f);
|
||||
|
||||
scale(r_dst, r_dst, 0.0f, 1.0f);
|
||||
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) = filter.getValue( dst->val(i) );
|
||||
|
||||
if (distort)
|
||||
{
|
||||
Heightfield *d = getRegister(r_distort);
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) *= d->val(i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
bool Terraformer::maskHeight(U32 r_src, U32 r_dst, const Filter &filter, bool distort, U32 r_distort)
|
||||
{
|
||||
Heightfield *src = getRegister(r_src);
|
||||
Heightfield *dst = getRegister(r_dst);
|
||||
|
||||
scale(r_src, r_dst, 0.0f, 1.0f);
|
||||
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) = filter.getValue(dst->val(i));
|
||||
|
||||
if (distort)
|
||||
{
|
||||
Heightfield *d = getRegister(r_distort);
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) *= d->val(i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
bool Terraformer::maskSlope(U32 r_src, U32 r_dst, const Filter &filter, bool distort, U32 r_distort)
|
||||
{
|
||||
Heightfield *src = getRegister(r_src);
|
||||
Heightfield *dst = getRegister(r_dst);
|
||||
|
||||
F32 fmin, fmax;
|
||||
getMinMax(r_src, &fmin, &fmax);
|
||||
F32 scale = worldHeight / (fmax-fmin);
|
||||
|
||||
for (S32 y=0; y<blockSize; y++)
|
||||
{
|
||||
for (S32 x=0; x<blockSize; x++)
|
||||
{
|
||||
// for each height look at the immediate surrounding heights and find max slope
|
||||
F32 array[9];
|
||||
F32 maxDelta = 0;
|
||||
src->block(x,y,array);
|
||||
F32 height = array[4];
|
||||
|
||||
for (S32 i=0; i<9; i++)
|
||||
{
|
||||
F32 delta = mFabs(array[i] - height);
|
||||
if ( (i&1) == 0)
|
||||
delta *= 0.70711f; // compensate for diagonals
|
||||
|
||||
if (delta > maxDelta)
|
||||
maxDelta = delta;
|
||||
}
|
||||
F32 slopeVal = mAtan( maxDelta * scale, worldTileSize ) * (2.0f/M_PI);
|
||||
dst->val(x, y) = filter.getValue( mPow(slopeVal, 1.5f) );
|
||||
}
|
||||
}
|
||||
|
||||
if (distort)
|
||||
{
|
||||
Heightfield *d = getRegister(r_distort);
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) *= d->val(i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
bool Terraformer::maskWater(U32 r_src, U32 r_dst, bool distort, U32 r_distort)
|
||||
{
|
||||
Heightfield *src = getRegister(r_src);
|
||||
Heightfield *dst = getRegister(r_dst);
|
||||
|
||||
scale(r_src, r_dst, 0.0f, 1.0f);
|
||||
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) = (dst->val(i) > worldWater) ? 0.0f : 1.0f;
|
||||
|
||||
if (distort)
|
||||
{
|
||||
Heightfield *d = getRegister(r_distort);
|
||||
for (S32 i=0; i < (blockSize*blockSize); i++)
|
||||
dst->val(i) *= d->val(i);
|
||||
}
|
||||
return true;
|
||||
}
|
562
engine/editor/terrainActions.cc
Executable file
562
engine/editor/terrainActions.cc
Executable file
@ -0,0 +1,562 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "editor/terrainActions.h"
|
||||
#include "platform/event.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_CTRL)
|
||||
{
|
||||
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].mGridPos, 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 SoftSelectAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type type)
|
||||
{
|
||||
// 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 = mTerrainEditor->getTerrainBlock()->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(info.mGridPos.x, info.mGridPos.y);
|
||||
|
||||
//
|
||||
for(S32 x = info.mGridPos.x - offset; x < info.mGridPos.x + (offset << 1); x++)
|
||||
for(S32 y = info.mGridPos.y - offset; y < info.mGridPos.y + (offset << 1); y++)
|
||||
{
|
||||
//
|
||||
Point2F pos(x, y);
|
||||
|
||||
F32 dist = Point2F(pos - infoPos).len() * F32(squareSize);
|
||||
|
||||
if(dist > radius)
|
||||
continue;
|
||||
|
||||
F32 weight = mFilter.getValue(dist / radius);
|
||||
|
||||
//
|
||||
GridInfo gInfo;
|
||||
if(mTerrainEditor->getCurrentSel()->getInfo(Point2I(x, y), gInfo))
|
||||
{
|
||||
if(gInfo.mPrimarySelect)
|
||||
continue;
|
||||
|
||||
if(gInfo.mWeight < weight)
|
||||
{
|
||||
gInfo.mWeight = weight;
|
||||
mTerrainEditor->getCurrentSel()->setInfo(gInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mTerrainEditor->getGridInfo(Point2I(x, y), gInfo);
|
||||
gInfo.mWeight = weight;
|
||||
gInfo.mPrimarySelect = false;
|
||||
mTerrainEditor->getCurrentSel()->add(gInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void OutlineSelectAction::process(Selection * sel, const Gui3DMouseEvent & event, bool, Type type)
|
||||
{
|
||||
sel;event;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->getPaintMaterial();
|
||||
if(selChanged && mat != -1)
|
||||
{
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
GridInfo &inf = (*sel)[i];
|
||||
|
||||
mTerrainEditor->getUndoSel()->add(inf);
|
||||
inf.mMaterialChanged = true;
|
||||
|
||||
U32 dAmt = (U32)(inf.mWeight * 255);
|
||||
if(inf.mMaterialAlpha[mat] < dAmt)
|
||||
{
|
||||
inf.mMaterialAlpha[mat] = dAmt;
|
||||
U32 total = 0;
|
||||
|
||||
for(S32 i = 0; i < TerrainBlock::MaterialGroups; i++)
|
||||
{
|
||||
if(i != mat)
|
||||
total += inf.mMaterialAlpha[i];
|
||||
}
|
||||
if(total != 0)
|
||||
{
|
||||
// gotta scale them down...
|
||||
|
||||
F32 scaleFactor = (255 - dAmt) / F32(total);
|
||||
for(S32 i = 0; i < TerrainBlock::MaterialGroups; i++)
|
||||
{
|
||||
if(i != mat)
|
||||
inf.mMaterialAlpha[i] = (U8)(inf.mMaterialAlpha[i] * scaleFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
mTerrainEditor->setGridInfo(inf);
|
||||
}
|
||||
mTerrainEditor->materialUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void RaiseHeightAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
// ok the raise height action is our "dirt pour" action
|
||||
// only works on brushes...
|
||||
|
||||
Brush *brush = dynamic_cast<Brush *>(sel);
|
||||
if(!brush)
|
||||
return;
|
||||
Point2I brushPos = brush->getPosition();
|
||||
Point2I brushSize = brush->getSize();
|
||||
|
||||
GridInfo cur; // the height at the brush position
|
||||
mTerrainEditor->getGridInfo(brushPos, cur);
|
||||
|
||||
// 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.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->gridUpdateComplete();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void LowerHeightAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
// ok the lower height action is our "dirt dig" action
|
||||
// only works on brushes...
|
||||
|
||||
Brush *brush = dynamic_cast<Brush *>(sel);
|
||||
if(!brush)
|
||||
return;
|
||||
Point2I brushPos = brush->getPosition();
|
||||
Point2I brushSize = brush->getSize();
|
||||
|
||||
GridInfo cur; // the height at the brush position
|
||||
mTerrainEditor->getGridInfo(brushPos, cur);
|
||||
|
||||
// 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.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->gridUpdateComplete();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SetEmptyAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if(selChanged)
|
||||
{
|
||||
mTerrainEditor->setMissionDirty();
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
(*sel)[i].mMaterial.flags |= TerrainBlock::Material::Empty;
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ClearEmptyAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
|
||||
{
|
||||
if(selChanged)
|
||||
{
|
||||
mTerrainEditor->setMissionDirty();
|
||||
for(U32 i = 0; i < sel->size(); i++)
|
||||
{
|
||||
mTerrainEditor->getUndoSel()->add((*sel)[i]);
|
||||
(*sel)[i].mMaterial.flags &= ~TerrainBlock::Material::Empty;
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SetModifiedAction::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].mMaterial.flags |= TerrainBlock::Material::Modified;
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ClearModifiedAction::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].mMaterial.flags &= ~TerrainBlock::Material::Modified;
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void BrushAdjustHeightAction::process(Selection * sel, const Gui3DMouseEvent & event, bool, Type type)
|
||||
{
|
||||
if(type == Process)
|
||||
return;
|
||||
|
||||
//
|
||||
|
||||
if(type == Begin)
|
||||
{
|
||||
mTerrainEditor->lockSelection(true);
|
||||
|
||||
mFirstPos = mLastPos = event.mousePoint;
|
||||
Canvas->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);
|
||||
mTerrainEditor->getTerrainBlock()->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
|
||||
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;
|
||||
//
|
||||
//F32 diff = (event.mousePoint.x - mLastPos.x) * mTerrainEditor->mAdjustHeightMouseScale;
|
||||
|
||||
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->gridUpdateComplete();
|
||||
mLastPos = event.mousePoint;
|
||||
}
|
||||
else if(type == End)
|
||||
{
|
||||
Canvas->mouseUnlock(mTerrainEditor);
|
||||
Canvas->setCursorPos(mFirstPos);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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->gridUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void SetMaterialGroupAction::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].mMaterial.flags |= TerrainBlock::Material::Modified;
|
||||
(*sel)[i].mMaterialGroup = mTerrainEditor->mMaterialGroup;
|
||||
mTerrainEditor->setGridInfo((*sel)[i]);
|
||||
}
|
||||
mTerrainEditor->gridUpdateComplete();
|
||||
}
|
||||
}
|
246
engine/editor/terrainActions.h
Executable file
246
engine/editor/terrainActions.h
Executable file
@ -0,0 +1,246 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TERRAINACTIONS_H_
|
||||
#define _TERRAINACTIONS_H_
|
||||
|
||||
#ifndef _TERRAINEDITOR_H_
|
||||
#include "editor/terrainEditor.h"
|
||||
#endif
|
||||
#ifndef _GUIFILTERCTRL_H_
|
||||
#include "gui/editor/guiFilterCtrl.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 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 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 SetModifiedAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
SetModifiedAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("setModified");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ClearModifiedAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
ClearModifiedAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("clearModified");}
|
||||
|
||||
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;
|
||||
|
||||
Point2I mFirstPos;
|
||||
Point2I mLastPos;
|
||||
|
||||
// private:
|
||||
// //
|
||||
// Point3F mHitPos;
|
||||
// Point3F mLastPos;
|
||||
};
|
||||
|
||||
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 SetMaterialGroupAction : public TerrainAction
|
||||
{
|
||||
public:
|
||||
SetMaterialGroupAction(TerrainEditor * editor) : TerrainAction(editor){}
|
||||
StringTableEntry getName(){return("setMaterialGroup");}
|
||||
|
||||
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
|
||||
};
|
||||
|
||||
#endif
|
1872
engine/editor/terrainEditor.cc
Executable file
1872
engine/editor/terrainEditor.cc
Executable file
File diff suppressed because it is too large
Load Diff
319
engine/editor/terrainEditor.h
Executable file
319
engine/editor/terrainEditor.h
Executable file
@ -0,0 +1,319 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _TERRAINEDITOR_H_
|
||||
#define _TERRAINEDITOR_H_
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#include "editor/editTSCtrl.h"
|
||||
#endif
|
||||
#ifndef _TERRDATA_H_
|
||||
#include "terrain/terrData.h"
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GridInfo
|
||||
{
|
||||
public:
|
||||
Point2I mGridPos;
|
||||
TerrainBlock::Material mMaterial;
|
||||
U8 mMaterialAlpha[TerrainBlock::MaterialGroups];
|
||||
F32 mHeight;
|
||||
U8 mMaterialGroup;
|
||||
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);
|
||||
|
||||
Vector<S32> mHashLists;
|
||||
U32 mHashListSize;
|
||||
|
||||
public:
|
||||
|
||||
Selection();
|
||||
virtual ~Selection();
|
||||
|
||||
void reset();
|
||||
bool add(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();
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class TerrainEditor;
|
||||
class Brush : public Selection
|
||||
{
|
||||
protected:
|
||||
TerrainEditor * mTerrainEditor;
|
||||
Point2I mSize;
|
||||
Point2I mGridPos;
|
||||
|
||||
public:
|
||||
|
||||
enum {
|
||||
MaxBrushDim = 40
|
||||
};
|
||||
|
||||
Brush(TerrainEditor * editor);
|
||||
virtual ~Brush(){};
|
||||
|
||||
//
|
||||
void setPosition(const Point3F & pos);
|
||||
void setPosition(const Point2I & pos);
|
||||
const Point2I & getPosition();
|
||||
|
||||
void update();
|
||||
virtual void rebuild() = 0;
|
||||
|
||||
Point2I getSize(){return(mSize);}
|
||||
virtual void setSize(const Point2I & size){mSize = size;}
|
||||
};
|
||||
|
||||
class BoxBrush : public Brush
|
||||
{
|
||||
public:
|
||||
BoxBrush(TerrainEditor * editor) : Brush(editor){}
|
||||
void rebuild();
|
||||
};
|
||||
|
||||
class EllipseBrush : public Brush
|
||||
{
|
||||
public:
|
||||
EllipseBrush(TerrainEditor * editor) : Brush(editor){}
|
||||
void rebuild();
|
||||
};
|
||||
|
||||
class SelectionBrush : public Brush
|
||||
{
|
||||
public:
|
||||
SelectionBrush(TerrainEditor * editor);
|
||||
void rebuild();
|
||||
void setSize(const Point2I &){}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct BaseMaterialInfo
|
||||
{
|
||||
StringTableEntry mMaterialNames[TerrainBlock::MaterialGroups];
|
||||
U8 mBaseMaterials[TerrainBlock::BlockSize * TerrainBlock::BlockSize];
|
||||
};
|
||||
|
||||
class TerrainAction;
|
||||
class TerrainEditor : public EditTSCtrl
|
||||
{
|
||||
public:
|
||||
void attachTerrain(TerrainBlock *terrBlock);
|
||||
|
||||
void setBrushType(const char* type);
|
||||
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();
|
||||
S32 getNumActions();
|
||||
void processAction(const char* sAction);
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
void resetSelWeights(bool clear);
|
||||
void clearSelection();
|
||||
|
||||
void buildMaterialMap();
|
||||
S32 getNumTextures();
|
||||
const char* getTextureName(S32 index);
|
||||
|
||||
void markEmptySquares();
|
||||
void clearModifiedFlags();
|
||||
|
||||
void mirrorTerrain(S32 mirrorIndex);
|
||||
|
||||
void pushBaseMaterialInfo();
|
||||
void popBaseMaterialInfo();
|
||||
|
||||
void setLoneBaseMaterial(const char* materialListBaseName);
|
||||
|
||||
private:
|
||||
typedef EditTSCtrl Parent;
|
||||
TerrainBlock * mTerrainBlock;
|
||||
Point2I mGridUpdateMin;
|
||||
Point2I mGridUpdateMax;
|
||||
U32 mMouseDownSeq;
|
||||
|
||||
Point3F mMousePos;
|
||||
Brush * mMouseBrush;
|
||||
bool mRenderBrush;
|
||||
Point2I mBrushSize;
|
||||
Vector<TerrainAction *> mActions;
|
||||
TerrainAction * mCurrentAction;
|
||||
bool mInAction;
|
||||
Selection mDefaultSel;
|
||||
bool mSelectionLocked;
|
||||
GuiCursor * mDefaultCursor;
|
||||
GuiCursor * mCurrentCursor;
|
||||
bool mCursorVisible;
|
||||
StringTableEntry mPaintMaterial;
|
||||
|
||||
Selection * mCurrentSel;
|
||||
|
||||
//
|
||||
bool mRebuildEmpty;
|
||||
bool mRebuildTextures;
|
||||
void rebuild();
|
||||
|
||||
void addUndo(Vector<Selection *> & list, Selection * sel);
|
||||
bool processUndo(Vector<Selection *> & src, Vector<Selection *> & dest);
|
||||
void clearUndo(Vector<Selection *> & list);
|
||||
|
||||
U32 mUndoLimit;
|
||||
Selection * mUndoSel;
|
||||
|
||||
Vector<Selection*> mUndoList;
|
||||
Vector<Selection*> mRedoList;
|
||||
|
||||
Vector<BaseMaterialInfo*> mBaseMaterialInfos;
|
||||
bool mIsDirty; // dirty flag for writing terrain.
|
||||
bool mIsMissionDirty; // dirty flag for writing mission.
|
||||
public:
|
||||
|
||||
TerrainEditor();
|
||||
~TerrainEditor();
|
||||
|
||||
// conversion functions
|
||||
bool gridToWorld(const Point2I & gPos, Point3F & wPos);
|
||||
bool worldToGrid(const Point3F & wPos, Point2I & gPos);
|
||||
bool gridToCenter(const Point2I & gPos, Point2I & cPos);
|
||||
|
||||
bool getGridInfo(const Point3F & wPos, GridInfo & info);
|
||||
bool getGridInfo(const Point2I & gPos, GridInfo & info);
|
||||
void setGridInfo(const GridInfo & info);
|
||||
void setGridInfoHeight(const GridInfo & info);
|
||||
void gridUpdateComplete();
|
||||
void materialUpdateComplete();
|
||||
void processActionTick(U32 sequence);
|
||||
|
||||
bool 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 getPaintMaterial();
|
||||
|
||||
Point2I getBrushSize() { return(mBrushSize); }
|
||||
TerrainBlock * getTerrainBlock() { AssertFatal(mTerrainBlock!=NULL, "No terrain block"); return(mTerrainBlock); }
|
||||
TerrainBlock * getClientTerrain();
|
||||
bool terrainBlockValid() { return(mTerrainBlock ? true : false); }
|
||||
void setCursor(GuiCursor * cursor);
|
||||
void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
|
||||
void setDirty() { mIsDirty = true; }
|
||||
void setMissionDirty() { mIsMissionDirty = true; }
|
||||
|
||||
TerrainAction * lookupAction(const char * name);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
// terrain interface functions
|
||||
F32 getGridHeight(const Point2I & gPos);
|
||||
void setGridHeight(const Point2I & gPos, const F32 height);
|
||||
|
||||
TerrainBlock::Material getGridMaterial(const Point2I & gPos);
|
||||
void setGridMaterial(const Point2I & gPos, const TerrainBlock::Material & material);
|
||||
|
||||
U8 getGridMaterialGroup(const Point2I & gPos);
|
||||
void setGridMaterialGroup(const Point2I & gPos, U8 group);
|
||||
|
||||
//
|
||||
void updateBrush(Brush & brush, const Point2I & gPos);
|
||||
|
||||
//
|
||||
Point3F getMousePos(){return(mMousePos);};
|
||||
|
||||
//
|
||||
void renderSelection(const Selection & sel, 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 mEnableSoftBrushes;
|
||||
bool mRenderVertexSelection;
|
||||
bool mProcessUsesBrush;
|
||||
|
||||
//
|
||||
F32 mAdjustHeightVal;
|
||||
F32 mSetHeightVal;
|
||||
F32 mScaleVal;
|
||||
F32 mSmoothFactor;
|
||||
S32 mMaterialGroup;
|
||||
F32 mSoftSelectRadius;
|
||||
StringTableEntry mSoftSelectFilter;
|
||||
StringTableEntry mSoftSelectDefaultFilter;
|
||||
F32 mAdjustHeightMouseScale;
|
||||
|
||||
public:
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onDeleteNotify(SimObject * object);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
// EditTSCtrl
|
||||
void on3DMouseUp(const Gui3DMouseEvent & event);
|
||||
void on3DMouseDown(const Gui3DMouseEvent & event);
|
||||
void on3DMouseMove(const Gui3DMouseEvent & event);
|
||||
void on3DMouseDragged(const Gui3DMouseEvent & event);
|
||||
void updateGuiInfo();
|
||||
void renderScene(const RectI & updateRect);
|
||||
|
||||
DECLARE_CONOBJECT(TerrainEditor);
|
||||
};
|
||||
|
||||
inline void TerrainEditor::setGridInfoHeight(const GridInfo & info)
|
||||
{
|
||||
setGridHeight(info.mGridPos, info.mHeight);
|
||||
}
|
||||
|
||||
#endif
|
2775
engine/editor/worldEditor.cc
Executable file
2775
engine/editor/worldEditor.cc
Executable file
File diff suppressed because it is too large
Load Diff
362
engine/editor/worldEditor.h
Executable file
362
engine/editor/worldEditor.h
Executable file
@ -0,0 +1,362 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _WORLDEDITOR_H_
|
||||
#define _WORLDEDITOR_H_
|
||||
|
||||
#ifndef _EDITTSCTRL_H_
|
||||
#include "editor/editTSCtrl.h"
|
||||
#endif
|
||||
#ifndef _CONSOLETYPES_H_
|
||||
#include "console/consoleTypes.h"
|
||||
#endif
|
||||
#ifndef _GTEXMANAGER_H_
|
||||
#include "dgl/gTexManager.h"
|
||||
#endif
|
||||
|
||||
class Path;
|
||||
class SceneObject;
|
||||
class WorldEditor : public EditTSCtrl
|
||||
{
|
||||
typedef EditTSCtrl Parent;
|
||||
|
||||
public:
|
||||
|
||||
void ignoreObjClass(U32 argc, const char** argv);
|
||||
void clearIgnoreList();
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
void clearSelection();
|
||||
void selectObject(const char* obj);
|
||||
void unselectObject(const char* obj);
|
||||
|
||||
S32 getSelectionSize();
|
||||
S32 getSelectObject(S32 index);
|
||||
const char* getSelectionCentroid();
|
||||
|
||||
void dropCurrentSelection();
|
||||
void deleteCurrentSelection();
|
||||
void copyCurrentSelection();
|
||||
bool canPasteSelection();
|
||||
|
||||
const char* getMode();
|
||||
bool setMode(const char *mode);
|
||||
|
||||
void addUndoState();
|
||||
void redirectConsole(S32 objID);
|
||||
|
||||
public:
|
||||
|
||||
struct CollisionInfo
|
||||
{
|
||||
SceneObject * obj;
|
||||
Point3F pos;
|
||||
VectorF normal;
|
||||
};
|
||||
|
||||
class Selection : public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
|
||||
private:
|
||||
|
||||
Point3F mCentroid;
|
||||
Point3F mBoxCentroid;
|
||||
bool mCentroidValid;
|
||||
SimObjectList mObjectList;
|
||||
bool mAutoSelect;
|
||||
|
||||
void updateCentroid();
|
||||
|
||||
public:
|
||||
|
||||
Selection();
|
||||
~Selection();
|
||||
|
||||
//
|
||||
U32 size() { return(mObjectList.size()); }
|
||||
SceneObject * operator[] (S32 index) { return((SceneObject*)mObjectList[index]); }
|
||||
|
||||
bool objInSet(SceneObject *);
|
||||
|
||||
bool addObject(SceneObject *);
|
||||
bool removeObject(SceneObject *);
|
||||
void clear();
|
||||
|
||||
void onDeleteNotify(SimObject *);
|
||||
|
||||
const Point3F & getCentroid();
|
||||
const Point3F & getBoxCentroid();
|
||||
|
||||
void enableCollision();
|
||||
void disableCollision();
|
||||
|
||||
//
|
||||
void autoSelect(bool b) { mAutoSelect = b; }
|
||||
void invalidateCentroid() { mCentroidValid = false; }
|
||||
|
||||
//
|
||||
void offset(const Point3F &);
|
||||
void orient(const MatrixF &, const Point3F &);
|
||||
void rotate(const EulerF &, const Point3F &);
|
||||
void scale(const VectorF &);
|
||||
};
|
||||
|
||||
//
|
||||
static SceneObject * getClientObj(SceneObject *);
|
||||
static void setClientObjInfo(SceneObject *, const MatrixF &, const VectorF &);
|
||||
static void updateClientTransforms(Selection &);
|
||||
|
||||
// VERY basic undo functionality - only concerned with transform/scale/...
|
||||
private:
|
||||
|
||||
struct SelectionState
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
MatrixF mMatrix;
|
||||
VectorF mScale;
|
||||
|
||||
// validation
|
||||
U32 mObjId;
|
||||
U32 mObjNumber;
|
||||
};
|
||||
|
||||
Vector<Entry> mEntries;
|
||||
|
||||
SelectionState()
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mEntries);
|
||||
}
|
||||
};
|
||||
|
||||
SelectionState * createUndo(Selection &);
|
||||
void addUndo(Vector<SelectionState *> & list, SelectionState * sel);
|
||||
bool processUndo(Vector<SelectionState *> & src, Vector<SelectionState *> & dest);
|
||||
void clearUndo(Vector<SelectionState *> & list);
|
||||
|
||||
Vector<SelectionState*> mUndoList;
|
||||
Vector<SelectionState*> mRedoList;
|
||||
|
||||
// someday get around to creating a growing memory stream...
|
||||
Vector<U8[2048]> mStreamBufs;
|
||||
|
||||
public:
|
||||
|
||||
bool deleteSelection(Selection & sel);
|
||||
bool copySelection(Selection & sel);
|
||||
bool pasteSelection();
|
||||
void dropSelection(Selection & sel);
|
||||
|
||||
// work off of mSelected
|
||||
void hideSelection(bool hide);
|
||||
void lockSelection(bool lock);
|
||||
|
||||
private:
|
||||
SceneObject * getControlObject();
|
||||
bool collide(const Gui3DMouseEvent & event, CollisionInfo & info);
|
||||
|
||||
// render 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, Point2I sPos);
|
||||
|
||||
void renderPaths(SimObject *obj);
|
||||
void renderSplinePath(Path *path);
|
||||
|
||||
// axis gizmo methods...
|
||||
void calcAxisInfo();
|
||||
bool collideAxisGizmo(const Gui3DMouseEvent & event);
|
||||
void renderAxisGizmo();
|
||||
void renderAxisGizmoText();
|
||||
|
||||
// axis gizmo state...
|
||||
Point3F mAxisGizmoCenter;
|
||||
VectorF mAxisGizmoVector[3];
|
||||
F32 mAxisGizmoProjLen;
|
||||
S32 mAxisGizmoSelAxis;
|
||||
bool mUsingAxisGizmo;
|
||||
|
||||
//
|
||||
Point3F snapPoint(const Point3F & pnt);
|
||||
bool mIsDirty;
|
||||
|
||||
//
|
||||
bool mMouseDown;
|
||||
Selection mSelected;
|
||||
bool mUseVertMove;
|
||||
|
||||
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;
|
||||
|
||||
CollisionInfo mHitInfo;
|
||||
Point3F mHitOffset;
|
||||
SimObjectPtr<SceneObject> mHitObject;
|
||||
Point2I mHitMousePos;
|
||||
Point3F mHitCentroid;
|
||||
EulerF mHitRotation;
|
||||
bool mMouseDragged;
|
||||
Gui3DMouseEvent mLastMouseEvent;
|
||||
F32 mLastRotation;
|
||||
|
||||
//
|
||||
class ClassInfo
|
||||
{
|
||||
public:
|
||||
~ClassInfo();
|
||||
|
||||
struct Entry
|
||||
{
|
||||
StringTableEntry mName;
|
||||
bool mIgnoreCollision;
|
||||
TextureHandle mDefaultHandle;
|
||||
TextureHandle mSelectHandle;
|
||||
TextureHandle mLockedHandle;
|
||||
};
|
||||
|
||||
Vector<Entry*> mEntries;
|
||||
};
|
||||
|
||||
|
||||
ClassInfo mClassInfo;
|
||||
ClassInfo::Entry mDefaultClassEntry;
|
||||
|
||||
bool objClassIgnored(const SceneObject * obj);
|
||||
ClassInfo::Entry * getClassEntry(StringTableEntry name);
|
||||
ClassInfo::Entry * getClassEntry(const SceneObject * obj);
|
||||
bool addClassEntry(ClassInfo::Entry * entry);
|
||||
|
||||
// persist field data
|
||||
public:
|
||||
|
||||
enum {
|
||||
DropAtOrigin = 0,
|
||||
DropAtCamera,
|
||||
DropAtCameraWithRot,
|
||||
DropBelowCamera,
|
||||
DropAtScreenCenter,
|
||||
DropAtCentroid,
|
||||
DropToGround
|
||||
};
|
||||
|
||||
bool mPlanarMovement;
|
||||
S32 mUndoLimit;
|
||||
S32 mDropType;
|
||||
F32 mProjectDistance;
|
||||
bool mBoundingBoxCollision;
|
||||
bool mRenderPlane;
|
||||
bool mRenderPlaneHashes;
|
||||
ColorI mGridColor;
|
||||
F32 mPlaneDim;
|
||||
Point3F mGridSize;
|
||||
bool mRenderPopupBackground;
|
||||
ColorI mPopupBackgroundColor;
|
||||
ColorI mPopupTextColor;
|
||||
StringTableEntry mSelectHandle;
|
||||
StringTableEntry mDefaultHandle;
|
||||
StringTableEntry mLockedHandle;
|
||||
ColorI mObjectTextColor;
|
||||
bool mObjectsUseBoxCenter;
|
||||
S32 mAxisGizmoMaxScreenLen;
|
||||
bool mAxisGizmoActive;
|
||||
F32 mMouseMoveScale;
|
||||
F32 mMouseRotateScale;
|
||||
F32 mMouseScaleScale;
|
||||
F32 mMinScaleFactor;
|
||||
F32 mMaxScaleFactor;
|
||||
ColorI mObjSelectColor;
|
||||
ColorI mObjMouseOverSelectColor;
|
||||
ColorI mObjMouseOverColor;
|
||||
bool mShowMousePopupInfo;
|
||||
ColorI mDragRectColor;
|
||||
bool mRenderObjText;
|
||||
bool mRenderObjHandle;
|
||||
StringTableEntry mObjTextFormat;
|
||||
ColorI mFaceSelectColor;
|
||||
bool mRenderSelectionBox;
|
||||
ColorI mSelectionBoxColor;
|
||||
bool mSelectionLocked;
|
||||
bool mSnapToGrid;
|
||||
bool mSnapRotations;
|
||||
F32 mRotationSnap;
|
||||
bool mToggleIgnoreList;
|
||||
bool mRenderNav;
|
||||
bool mNoMouseDrag;
|
||||
|
||||
private:
|
||||
// cursor constants
|
||||
enum {
|
||||
HandCursor = 0,
|
||||
RotateCursor,
|
||||
ScaleCursor,
|
||||
MoveCursor,
|
||||
ArrowCursor,
|
||||
DefaultCursor,
|
||||
|
||||
//
|
||||
NumCursors
|
||||
};
|
||||
|
||||
GuiCursor * mCursors[NumCursors];
|
||||
GuiCursor * mCurrentCursor;
|
||||
bool grabCursors();
|
||||
void setCursor(U32 cursor);
|
||||
void get3DCursor(GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event);
|
||||
|
||||
public:
|
||||
|
||||
WorldEditor();
|
||||
~WorldEditor();
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onEditorEnable();
|
||||
void setDirty() { mIsDirty = true; }
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user