added everything

This commit is contained in:
Metario
2017-04-17 06:17:10 -06:00
commit 9c6ff74f19
6121 changed files with 1625704 additions and 0 deletions

442
engine/editor/creator.cc Executable file
View 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
View 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

627
engine/editor/editTSCtrl.cc Executable file
View File

@ -0,0 +1,627 @@
//-----------------------------------------------------------------------------
// 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 || !obj)
{
mRenderMissionArea = false;
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
View 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
{
typedef GuiTSCtrl Parent;
protected:
// 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
View 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
View 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

View 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);
}

View 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

1127
engine/editor/missionAreaEditor.cc Executable file

File diff suppressed because it is too large Load Diff

145
engine/editor/missionAreaEditor.h Executable file
View 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

File diff suppressed because it is too large Load Diff

230
engine/editor/terraformer.h Executable file
View 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
View 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);
}

View 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_

View 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;
}

596
engine/editor/terrainActions.cc Executable file
View File

@ -0,0 +1,596 @@
//-----------------------------------------------------------------------------
// 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;
// We have to limit to top 4 contributors... so drop the bottom
// one if we go over that.
U32 numContributors = 0;
for(S32 i = 0; i < TerrainBlock::MaterialGroups; i++)
{
if(i != mat)
total += inf.mMaterialAlpha[i];
if(inf.mMaterialAlpha[i] > 0)
numContributors++;
}
// And if we've got more than four, adjust to fit.
//
// Four is a magic number derived from the blender's limitations
// and may have to be updated...
if(numContributors > 4)
{
// Find the lowest material that's not the painted one...
S32 smallestContributor = -1, smallestContribAmt = S32_MAX;
for(S32 i=0; i < TerrainBlock::MaterialGroups; i++)
{
if(inf.mMaterialAlpha[i] < smallestContribAmt && i != mat)
{
smallestContribAmt = inf.mMaterialAlpha[i];
smallestContributor = i;
}
}
AssertFatal(smallestContributor != -1,
"PaintMaterialAction::process - didn't find a smallest contributor?!");
// Set it to zero and update the total so we'll scale properly.
total -= inf.mMaterialAlpha[smallestContributor];
inf.mMaterialAlpha[smallestContributor] = 0;
}
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
View 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

1869
engine/editor/terrainEditor.cc Executable file

File diff suppressed because it is too large Load Diff

319
engine/editor/terrainEditor.h Executable file
View 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

2947
engine/editor/worldEditor.cc Executable file

File diff suppressed because it is too large Load Diff

364
engine/editor/worldEditor.h Executable file
View File

@ -0,0 +1,364 @@
//-----------------------------------------------------------------------------
// 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);
bool objClassIgnored(const SceneObject * obj);
void renderObjectBox(SceneObject * obj, const ColorI & col);
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