Example #1
0
bool Mode::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex) {
	_x = (int)(x + getX() + _container->getX() + app->_stage->getX());
	_y = (int)(y + getY() + _container->getY() + app->_stage->getY());
	if(isSelecting()) _touchPt.set(evt, _x, _y, true);
	else _touchPt.set(evt, _x, _y, _plane);
	_camera->pickRay(app->getViewport(), _x, _y, &_ray);
	switch(evt) {
		case Touch::TOUCH_PRESS: {
			cout << "mode ray: " << app->pv(_ray.getOrigin()) << " => " << app->pv(_ray.getDirection()) << endl;
			MyNode *node = getTouchNode();
			if(node) node->updateTransform();
			if(isSelecting()) {
				Vector3 point = getTouchPoint();
				if(node) node->setBase();
				setSelectedNode(node, point);
				if(node) cout << "selected: " << node->getId() << " at " << app->pv(point) << endl;
			} else {
				_cameraBase->getNode()->set(*_camera->getNode());
				_viewportBase = app->getViewport();
				app->copyCameraState(app->_cameraState, _cameraStateBase);
				cout << "touched: camera at " << app->pcam(_cameraStateBase) << endl;
			}
			break;
		} case Touch::TOUCH_MOVE: {
			if(isTouching() && app->_navMode >= 0) {
				placeCamera();
			}
			break;
		} case Touch::TOUCH_RELEASE: {
			break;
		}
	}
	return true;
}
void CExpressionTreeDlg::OnSelchangedTreeExpression(NMHDR *pNMHDR, LRESULT *pResult) {
  NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  TVITEM &tvItem = ((NMTREEVIEW*)pNMTreeView)->itemNew;
  if(tvItem.hItem) {
    setSelectedNode((const ExpressionNode*)m_treeCtrl.GetItemData(tvItem.hItem));
  }
  *pResult = 0;
}
Example #3
0
void Mode::gestureEvent(Gesture::GestureEvent evt, int x, int y, ...)
{
    if(app->hasOverlay()) return;
    va_list arguments;
    va_start(arguments, y);
    switch(evt) {
        case Gesture::GESTURE_TAP: {
            if(isSelecting()) {
                MyNode *node = getTouchNode();
                Vector3 point = getTouchPoint();
                if(node) {
                    node->updateTransform();
                    node->setBase();
                }
                setSelectedNode(node, point);
                if(node) GP_WARN("selected %s at %s", node->getId(), app->pv(point).c_str());
            }
            break;
        }
        case Gesture::GESTURE_LONG_TAP:
            break;
        case Gesture::GESTURE_PINCH: {
            float scale = (float) va_arg(arguments, double);
            if(app->_navMode >= 0) {
                float baseRadius = _cameraStateBase->radius;
                app->setCameraZoom(fminf(300.0f, fmaxf(3.0f, baseRadius / fmaxf(scale, 0.01f))));
            }
            break;
        }
        case Gesture::GESTURE_DRAG: {
            if(app->_navMode >= 0) {
                Vector2 touch = getTouchPix(), delta(x - touch.x, y - touch.y);
                float radius = _cameraStateBase->radius, theta = _cameraStateBase->theta, phi = _cameraStateBase->phi;
                GP_WARN("drag delta %f, %f", delta.x, delta.y);
                GP_WARN("camera from %f, %f, %f", radius, theta, phi);
                float deltaPhi = delta.y * M_PI / 400.0f, deltaTheta = delta.x * M_PI / 400.0f;
                phi = fmin(89.9f * M_PI/180, fmax(-89.9f * M_PI/180, phi + deltaPhi));
                theta += deltaTheta;
                GP_WARN("to %f, %f, %f", radius, theta, phi);
                app->setCameraEye(radius, theta, phi);
            }
            break;
        }
        case Gesture::GESTURE_DROP: {
            break;
        }
        case Gesture::GESTURE_ROTATE: {
            float rotation = (float) va_arg(arguments, double), velocity = (float) va_arg(arguments, double);
            if(app->_navMode >= 0) {
                float theta = _cameraStateBase->theta;
                app->setCameraTheta(theta - rotation);
            }
            break;
        }
        default: break;
    }
    va_end(arguments);
}
void NetworkInstance::visualizeInterventions(std::vector<QString> &interventions)
{
    for (QString& item : interventions){
        QString name = item.split(" ")[0];
        nv_->getNode(nc_.getNetwork().getNode(name.toStdString()).getID())->originalState();
        setSelectedNode(nc_.getNetwork().getNode(name.toStdString()).getID());
        doIntervention();
    }
}
Example #5
0
void GuiRoadEditorCtrl::onSleep()
{
   Parent::onSleep();

   mMode = mSelectRoadMode;   
   mHoverNode = -1;
   mHoverRoad = NULL;
   setSelectedNode(-1);
}
void GuiRiverEditorCtrl::onSleep()
{
   Parent::onSleep();

   mMode = mSelectRiverMode;  
   mHoverNode = -1;
   mHoverRiver = NULL;
   setSelectedNode(-1);
   //mSelRiver = NULL;
   //mSelNode = -1;
}
void GuiRiverEditorCtrl::setSelectedRiver( River *river )
{
   mSelRiver = river;

   if ( mSelRiver != NULL )
      Con::executef( this, "onRiverSelected", river->scriptThis() );
   else
      Con::executef( this, "onRiverSelected" );

	if ( mSelRiver != river )
      setSelectedNode(-1);
}
Example #8
0
void GuiRoadEditorCtrl::setSelectedRoad( DecalRoad *road )
{
   mSelRoad = road;

   if ( road != NULL )
      Con::executef( this, "onRoadSelected", road->getIdString() );
   else
      Con::executef( this, "onRoadSelected" );

	if ( mSelRoad != road )
      setSelectedNode(-1);
}
void GuiRiverEditorCtrl::deleteSelectedNode()
{    
   if ( !mSelRiver || mSelNode == -1 )
      return;
   
   // If the River has only two nodes remaining,
   // delete the whole River.
   if ( mSelRiver->mNodes.size() <= 2 )
   {      
      deleteSelectedRiver( mMode != mAddNodeMode );
   }
   else
   {
      if ( mMode != mAddNodeMode )
         submitUndo( "Delete Node" );

      // Delete the SelectedNode of the SelectedRiver
      mSelRiver->deleteNode(mSelNode);
      mIsDirty = true;

      // We deleted the Node but not the River (it has nodes left)
      // so decrement the currently selected node.
      if ( mSelRiver->mNodes.size() <= mSelNode )
         setSelectedNode( mSelNode - 1 );
      else
      {
         // force gizmo to update to the selected nodes position
         // the index didn't change but the node it refers to did.
         U32 i = mSelNode;
         mSelNode = -1;
         setSelectedNode( i );
      }
   }

   // If you were in addNodeMode, 
   // deleting a node should ends it.
   //mMode = smNormalMode;
}
Example #10
0
void Mode::setActive(bool active) {
	_active = active;
	setSelectedNode(NULL);
	_container->setVisible(active);
	if(active) {
		app->cameraPush();
		app->setActiveScene(_scene);
		setSubMode(0);
		app->setNavMode(-1);
	} else {
		app->message(NULL);
		app->cameraPop();
		app->showScene();
	}
}
void CExpressionTreeDlg::OnContextMenu(CWnd *pWnd, CPoint point) {
  setSelectedNode(getNodeFromPoint(point));
  if(m_selectedNode == NULL) return;
  CMenu menu;
  if(!menu.LoadMenu(IDR_CONTEXTMENU_TREE)) {
    showWarning(_T("LoadMenu failed"));
    return;
  }
  if(m_selectedNode->isBreakPoint()) {
    removeMenuItem(menu, ID_SETBREAKPOINT);
  } else {
    removeMenuItem(menu, ID_CLEARBREAKPOINT);
  }
  menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x,point.y, this);
}
Example #12
0
void NavMesh::selectNodeClosestTo(const wxPoint &point)
{
	NavMeshNode *closestNode = nullptr;
	float closestDistance;
	for (NavMeshNode *node : nodes)
	{
		wxPoint pointToNode = wxPoint(node->getX(), node->getY()) - point;
		float thisDistance = pointToNode.x * pointToNode.x + pointToNode.y * pointToNode.y;

		if ((!closestNode || thisDistance < closestDistance) && thisDistance < SELECTION_RADIUS * SELECTION_RADIUS)
		{
			closestNode = node;
			closestDistance = thisDistance;
		}
	}

	setSelectedNode(closestNode);
}
Example #13
0
bool QgsComposerPolygon::_removeNode( const int index )
{
  if ( index < 0 || index >= mPolygon.size() )
    return false;

  mPolygon.remove( index );

  if ( mPolygon.size() < 3 )
    mPolygon.clear();
  else
  {
    int newSelectNode = index;
    if ( index == mPolygon.size() )
      newSelectNode = 0;
    setSelectedNode( newSelectNode );
  }

  return true;
}
Example #14
0
bool QgsLayoutItemPolyline::_removeNode( const int index )
{
  if ( index < 0 || index >= mPolygon.size() )
    return false;

  mPolygon.remove( index );

  if ( mPolygon.size() < 2 )
    mPolygon.clear();
  else
  {
    int newSelectNode = index;
    if ( index >= mPolygon.size() )
      newSelectNode = mPolygon.size() - 1;
    setSelectedNode( newSelectNode );
  }

  return true;
}
void GuiRiverEditorCtrl::deleteSelectedRiver( bool undoAble )
{
   AssertFatal( mSelRiver != NULL, "GuiRiverEditorCtrl::deleteSelectedRiver() - No River IS selected" );

   // Not undoAble? Just delete it.
   if ( !undoAble )
   {
      mSelRiver->deleteObject();
      mIsDirty = true;
      Con::executef( this, "onRiverSelected" );
      mSelNode = -1;

      return;
   }

   // Grab the mission editor undo manager.
   UndoManager *undoMan = NULL;
   if ( !Sim::findObject( "EUndoManager", undoMan ) )
   {
      // Couldn't find it? Well just delete the River.
      Con::errorf( "GuiRiverEditorCtrl::on3DMouseDown() - EUndoManager not found!" );    
      return;
   }
   else
   {
      // Create the UndoAction.
      MEDeleteUndoAction *action = new MEDeleteUndoAction("Deleted River");
      action->deleteObject( mSelRiver );
      mIsDirty = true;

      // Submit it.               
      undoMan->addAction( action );
   }

   // ScriptCallback with 'NULL' parameter for no River currently selected.
   Con::executef( this, "onRiverSelected" );

   // Clear the SelectedNode (it has been deleted along with the River).  
	setSelectedNode( -1 );
   mSelNode = -1;

   // SelectedRiver is a SimObjectPtr and will be NULL automatically.
}
Example #16
0
SceneGraph::SceneGraph() 
{
//	setHeaderFlag(false);
	setOption(SCENEGRAPH_OPTION_NONE);
	setBoundingBoxCenter(0.0f, 0.0f, 0.0f);
	setBoundingBoxSize(-1.0f, -1.0f, -1.0f);
	setSelectedShapeNode(NULL);
	setSelectedNode(NULL);

	mBackgroundNodeVector		= new Vector<BindableNode>;
	mFogNodeVector				= new Vector<BindableNode>;
	mNavigationInfoNodeVector	= new Vector<BindableNode>;
	mViewpointNodeVector		= new Vector<BindableNode>;	

	mDefaultBackgroundNode		= new BackgroundNode();
	mDefaultFogNode				= new FogNode();
	mDefaultNavigationInfoNode	= new NavigationInfoNode();
	mDefaultViewpointNode		= new ViewpointNode();

#ifdef SUPPORT_URL
	mUrl = new UrlFile();
#endif
}
Example #17
0
void GuiRoadEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
{
   if ( !isFirstResponder() )
      setFirstResponder();

   // Get the clicked terrain position.
   Point3F tPos;
   if ( !getTerrainPos( event, tPos ) )
      return;      

   mouseLock();

   // Find any road / node at the clicked position.
   // TODO: handle overlapping roads/nodes somehow, cycle through them.
   
   DecalRoad *roadPtr = NULL;
   S32 closestNodeIdx = -1;
   F32 closestDist = F32_MAX;
   DecalRoad *closestNodeRoad = NULL;

   // First, find the closest node in any road to the clicked position.
   for ( SimSetIterator iter(mRoadSet); *iter; ++iter )
   {
      roadPtr = static_cast<DecalRoad*>( *iter );
      U32 idx;
      if ( roadPtr->getClosestNode( tPos, idx ) )
      {
         Point3F nodePos = roadPtr->getNodePosition(idx);
         F32 dist = ( nodePos - tPos ).len();
         if ( dist < closestDist )
         {
            closestNodeIdx = idx;
            closestDist = dist;
            closestNodeRoad = roadPtr;
         }
      }
   }

   //
   // Second, determine if the screen-space node rectangle
   // contains the clicked position.

   bool nodeClicked = false;
   S32 clickedNodeIdx = -1;

   if ( closestNodeIdx != -1 )
   {
      Point3F nodePos = closestNodeRoad->getNodePosition( closestNodeIdx );

      Point3F temp;
      project( nodePos, &temp );
      Point2I screenPos( temp.x, temp.y );

      RectI nodeRect( screenPos - mNodeHalfSize, mNodeHalfSize * 2 );
      
      nodeClicked = nodeRect.pointInRect( event.mousePoint );
      if ( nodeClicked )
         clickedNodeIdx = closestNodeIdx;
   }

   //
   // Determine the clickedRoad
   //
   DecalRoad *clickedRoadPtr = NULL;
   U32 insertNodeIdx = 0;

   if ( nodeClicked && (mSelRoad == NULL || closestNodeRoad == mSelRoad) )
   {
      // If a node was clicked, the owning road is always
      // considered the clicked road.
      clickedRoadPtr = closestNodeRoad;
   }
   else
   {
      // check the selected road first
      if ( mSelRoad != NULL && mSelRoad->containsPoint( tPos, &insertNodeIdx ) )
      {
         clickedRoadPtr = mSelRoad;
         nodeClicked = false;
         clickedNodeIdx = -1;
      }
      else
      {
         // Otherwise, we must ask each road if it contains
         // the clicked pos.
         for ( SimSetIterator iter(mRoadSet); *iter; ++iter )
         {
            roadPtr = static_cast<DecalRoad*>( *iter );
            if ( roadPtr->containsPoint( tPos, &insertNodeIdx ) )
            {
               clickedRoadPtr = roadPtr;
               break;            
            }
         }
      }
   }

	// shortcuts
   bool dblClick = ( event.mouseClickCount > 1 );
	if( dblClick )
   { 
		if( mMode == mSelectRoadMode )
		{
			setMode( mAddRoadMode, true );
			return;
		}
		if( mMode == mAddNodeMode )
		{
			// Delete the node attached to the cursor.
			deleteSelectedNode();
			mMode = mAddRoadMode;
			return;
		}
	}

	//this check is here in order to bounce back from deleting a whole road with ctrl+z
	//this check places the editor back into addroadmode
	if ( mMode == mAddNodeMode )
	{
      if ( !mSelRoad )
         mMode = mAddRoadMode;
	}

	if ( mMode == mSelectRoadMode )
	{
      // Did not click on a road or a node.
      if ( !clickedRoadPtr  )
      {
         setSelectedRoad( NULL );
         setSelectedNode( -1 );
         
         return;
      }

      // Clicked on a road that wasn't the currently selected road.
      if ( clickedRoadPtr != mSelRoad )
      {
         setSelectedRoad( clickedRoadPtr );
         setSelectedNode( -1 );
         return;
      }

      // Clicked on a node in the currently selected road that wasn't
      // the currently selected node.
      if ( nodeClicked )
      {
         setSelectedNode( clickedNodeIdx );
         return;
      }

      
      // Clicked a position on the currently selected road
      // that did not contain a node.
      //U32 newNode = clickedRoadPtr->insertNode( tPos, mDefaultWidth, insertNodeIdx );                  
      //setSelectedNode( newNode );
	}
   else if ( mMode == mAddRoadMode )
   {
		if ( nodeClicked && clickedRoadPtr )
      {
			// A double-click on a node in Normal mode means set AddNode mode.  
         if ( clickedNodeIdx == 0 )
         {
				setSelectedRoad( clickedRoadPtr );
				setSelectedNode( clickedNodeIdx );

				mAddNodeIdx = clickedNodeIdx;
            mMode = mAddNodeMode;
            mSelNode = mSelRoad->insertNode( tPos, mDefaultWidth, mAddNodeIdx );
            mIsDirty = true;

				return;
         }
			else if ( clickedNodeIdx == clickedRoadPtr->mNodes.size() - 1 )
         {
				setSelectedRoad( clickedRoadPtr );
				setSelectedNode( clickedNodeIdx );

            mAddNodeIdx = U32_MAX;
            mMode = mAddNodeMode;
            mSelNode = mSelRoad->addNode( tPos, mDefaultWidth );
            mIsDirty = true;
				setSelectedNode( mSelNode );

				return;
         } 
		}

		DecalRoad *newRoad = new DecalRoad;
		

		newRoad->mMaterialName = mMaterialName;

      newRoad->registerObject();

      // Add to MissionGroup                              
      SimGroup *missionGroup;
      if ( !Sim::findObject( "MissionGroup", missionGroup ) )               
         Con::errorf( "GuiDecalRoadEditorCtrl - could not find MissionGroup to add new DecalRoad" );
      else
         missionGroup->addObject( newRoad );               

      newRoad->insertNode( tPos, mDefaultWidth, 0 );
      U32 newNode = newRoad->insertNode( tPos, mDefaultWidth, 1 );

      // Always add to the end of the road, the first node is the start.
      mAddNodeIdx = U32_MAX;
      
      setSelectedRoad( newRoad );      
      setSelectedNode( newNode );

      mMode = mAddNodeMode;

      // Disable the hover node while in addNodeMode, we
      // don't want some random node enlarged.
      mHoverNode = -1;

      // Grab the mission editor undo manager.
      UndoManager *undoMan = NULL;
      if ( !Sim::findObject( "EUndoManager", undoMan ) )
      {
         Con::errorf( "GuiRoadEditorCtrl::on3DMouseDown() - EUndoManager not found!" );
         return;           
      }

      // Create the UndoAction.
      MECreateUndoAction *action = new MECreateUndoAction("Create Road");
      action->addObject( newRoad );
      
      // Submit it.               
      undoMan->addAction( action );
		
		//send a callback to script after were done here if one exists
		if ( isMethod( "onRoadCreation" ) )
         Con::executef( this, "onRoadCreation" );

		return;
   }
	else if ( mMode == mAddNodeMode )
	{
		// Oops the road got deleted, maybe from an undo action?
      // Back to NormalMode.
      if ( mSelRoad )
      {
			// A double-click on a node in Normal mode means set AddNode mode.  
         if ( clickedNodeIdx == 0 )
         {
				submitUndo( "Add Node" );
				mAddNodeIdx = clickedNodeIdx;
            mMode = mAddNodeMode;
            mSelNode = mSelRoad->insertNode( tPos, mDefaultWidth, mAddNodeIdx );
            mIsDirty = true;
				setSelectedNode( mSelNode );

				return;
         }
			else
         {
				if( clickedRoadPtr && clickedNodeIdx == clickedRoadPtr->mNodes.size() - 1 )
				{
					submitUndo( "Add Node" );
					mAddNodeIdx = U32_MAX;
					mMode = mAddNodeMode;
					mSelNode = mSelRoad->addNode( tPos, mDefaultWidth );
               mIsDirty = true;
					setSelectedNode( mSelNode );

					return;
				}
				else
				{
					submitUndo( "Insert Node" );
					// A single-click on empty space while in
					// AddNode mode means insert / add a node.
					//submitUndo( "Add Node" );
					//F32 width = mSelRoad->getNodeWidth( mSelNode );
					U32 newNode = mSelRoad->insertNode( tPos, mDefaultWidth, mAddNodeIdx);
               mIsDirty = true;
					setSelectedNode( newNode );

					return;
				}
         } 
      }
	}
	else if ( mMode == mInsertPointMode  && mSelRoad != NULL)
	{
		if ( clickedRoadPtr == mSelRoad )
      {
			F32 w0 = mSelRoad->getNodeWidth( insertNodeIdx );
         F32 w1 = mSelRoad->getNodeWidth( insertNodeIdx + 1 );               
         F32 width = ( w0 + w1 ) * 0.5f;

         submitUndo( "Insert Node" );
         U32 newNode = mSelRoad->insertNode( tPos, width, insertNodeIdx + 1);  
         mIsDirty = true;
         setSelectedNode( newNode );

			return;
       }
	}
	else if ( mMode == mRemovePointMode  && mSelRoad != NULL)
	{
		if ( nodeClicked && clickedRoadPtr == mSelRoad )
      {
			setSelectedNode( clickedNodeIdx );
         deleteSelectedNode();
         return;
      }
	}
	else if ( mMode == mMovePointMode )
	{
		if ( nodeClicked && clickedRoadPtr == mSelRoad )
      {
			setSelectedNode( clickedNodeIdx );
         return;
      }
	}
	else if ( mMode == mScalePointMode )
	{
		if ( nodeClicked && clickedRoadPtr == mSelRoad )
      {
			setSelectedNode( clickedNodeIdx );
         return;
      }
	}
}
void GuiRiverEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
{
   mGizmo->on3DMouseDown( event );

   if ( !isFirstResponder() )
      setFirstResponder();
	
	// Get the raycast collision position
   Point3F tPos;
   if ( !getStaticPos( event, tPos ) )
		return;  

   // Construct a LineSegment from the camera position to 1000 meters away in
   // the direction clicked.
   // If that segment hits the terrain, truncate the ray to only be that length.

   // We will use a LineSegment/Sphere intersection test to determine if a RiverNode
   // was clicked.   

   Point3F startPnt = event.pos;
   Point3F endPnt = event.pos + event.vec * 1000.0f;

   RayInfo ri;   

   if ( gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri) )
      endPnt = ri.point;

   River *riverPtr = NULL;
   River *clickedRiverPtr = NULL;

   // Did we click on a river? check current selection first
   U32 insertNodeIdx = -1;
   Point3F collisionPnt;
   if ( mSelRiver != NULL && mSelRiver->collideRay( event.pos, event.vec, &insertNodeIdx, &collisionPnt ) )
   {
      clickedRiverPtr = mSelRiver;
   }
   else
   {
      for ( SimSetIterator iter(mRiverSet); *iter; ++iter )
      {
         riverPtr = static_cast<River*>( *iter );
         if ( riverPtr->collideRay( event.pos, event.vec, &insertNodeIdx, &collisionPnt ) )
         {
            clickedRiverPtr = riverPtr;
            break;
         }
      }
   }

   // Did we click on a riverNode?
   bool nodeClicked = false;   
   S32 clickedNodeIdx = -1;
   F32 clickedNodeDist = mNodeSphereRadius;

   // If we clicked on the currently selected river, only scan its nodes
   if ( mSelRiver != NULL && clickedRiverPtr == mSelRiver )
   {
      for ( U32 i = 0; i < mSelRiver->mNodes.size(); i++ )
      {
         const Point3F &nodePos = mSelRiver->mNodes[i].point;

         Point3F screenPos;
         project( nodePos, &screenPos );

         F32 dist = ( event.mousePoint - Point2I(screenPos.x, screenPos.y) ).len();
         if ( dist < clickedNodeDist )
         {
            clickedNodeDist = dist;
            clickedNodeIdx = i;
            nodeClicked = true;
         }
      }
   }
   else
   {
      for ( SimSetIterator iter(mRiverSet); *iter; ++iter )
      {
         riverPtr = static_cast<River*>( *iter );
         
         for ( U32 i = 0; i < riverPtr->mNodes.size(); i++ )
         {
            const Point3F &nodePos = riverPtr->mNodes[i].point;

            Point3F screenPos;
            project( nodePos, &screenPos );

            F32 dist = ( event.mousePoint - Point2I(screenPos.x, screenPos.y) ).len();
            if ( dist < clickedNodeDist )
            {
               // we found a hit!
               clickedNodeDist = dist;
               clickedNodeIdx = i;
               nodeClicked = true;
               clickedRiverPtr = riverPtr;
            }
         }
      }
   }
	
	// shortcuts
	bool dblClick = ( event.mouseClickCount > 1 );
	if( dblClick )
   { 
		if( mMode == mSelectRiverMode )
		{
			setMode( mAddRiverMode, true );
			return;
		}
		if( mMode == mAddNodeMode )
		{
			// Delete the node attached to the cursor.
			deleteSelectedNode();
			mMode = mAddRiverMode;
			return;
		}
	}

	//this check is here in order to bounce back from deleting a whole road with ctrl+z
	//this check places the editor back into addrivermode
	if ( mMode == mAddNodeMode )
	{
      if ( !mSelRiver )
         mMode = mAddRiverMode;
	}

	if ( mMode == mSelectRiverMode )
	{
      // Did not click on a River or a node.
      if ( !clickedRiverPtr  )
      {
         setSelectedRiver( NULL );
         setSelectedNode( -1 );
         
         return;
      }

      // Clicked on a River that wasn't the currently selected River.
      if ( clickedRiverPtr != mSelRiver )
      {
         setSelectedRiver( clickedRiverPtr );
         setSelectedNode( clickedNodeIdx );
         return;
      }

     // Clicked on a node in the currently selected River that wasn't
      // the currently selected node.
      if ( nodeClicked )
      {
         setSelectedNode( clickedNodeIdx );
         return;
      }
	}
   else if ( mMode == mAddRiverMode )
   {
		if ( nodeClicked )
      {
			// A double-click on a node in Normal mode means set AddNode mode.  
         if ( clickedNodeIdx == 0 )
         {
				setSelectedRiver( clickedRiverPtr );
				setSelectedNode( clickedNodeIdx );

				mAddNodeIdx = clickedNodeIdx;
            mMode = mAddNodeMode; 

            mSelNode = mSelRiver->insertNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal, mAddNodeIdx );
            mIsDirty = true;

				return;
         }
			else if ( clickedNodeIdx == clickedRiverPtr->mNodes.size() - 1 )
         {
				setSelectedRiver( clickedRiverPtr );
				setSelectedNode( clickedNodeIdx );

            mAddNodeIdx = U32_MAX;
				mMode = mAddNodeMode;

            mSelNode = mSelRiver->addNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal);
            mIsDirty = true;
				setSelectedNode( mSelNode );

				return;
         } 
		}

		if ( !isMethod( "createRiver" ) )
      {
			Con::errorf( "GuiRiverEditorCtrl::on3DMouseDown - createRiver method does not exist." );
         return;
      }

      const char *res = Con::executef( this, "createRiver" );

      River *newRiver;
      if ( !Sim::findObject( res, newRiver ) )
      {
         Con::errorf( "GuiRiverEditorCtrl::on3DMouseDown - createRiver method did not return a river object." );
         return;
      }                

      // Add to MissionGroup                              
      SimGroup *missionGroup;
      if ( !Sim::findObject( "MissionGroup", missionGroup ) )               
         Con::errorf( "GuiRiverEditorCtrl - could not find MissionGroup to add new River" );
      else
         missionGroup->addObject( newRiver );

      Point3F pos( endPnt );
      pos.z += mDefaultDepth * 0.5f;

      newRiver->insertNode( pos, mDefaultWidth, mDefaultDepth, mDefaultNormal, 0 );
      U32 newNode = newRiver->insertNode( pos, mDefaultWidth, mDefaultDepth, mDefaultNormal, 1 );

      // Always add to the end of the road, the first node is the start.
      mAddNodeIdx = U32_MAX;
      
      setSelectedRiver( newRiver );      
      setSelectedNode( newNode );

      mMode = mAddNodeMode;

      // Disable the hover node while in addNodeMode, we
      // don't want some random node enlarged.
      mHoverNode = -1;

      // Grab the mission editor undo manager.
      UndoManager *undoMan = NULL;
      if ( !Sim::findObject( "EUndoManager", undoMan ) )
      {
         Con::errorf( "GuiMeshRoadEditorCtrl::on3DMouseDown() - EUndoManager not found!" );
         return;           
      }

      // Create the UndoAction.
      MECreateUndoAction *action = new MECreateUndoAction("Create MeshRoad");
      action->addObject( newRiver );

      // Submit it.               
      undoMan->addAction( action );

		return;
   }
	else if ( mMode == mAddNodeMode )
	{
		// Oops the road got deleted, maybe from an undo action?
      // Back to NormalMode.
      if ( mSelRiver )
      {
			// A double-click on a node in Normal mode means set AddNode mode.  
         if ( clickedNodeIdx == 0 )
         {
				submitUndo( "Add Node" );
				mAddNodeIdx = clickedNodeIdx;
            mMode = mAddNodeMode;
            mSelNode = mSelRiver->insertNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal, mAddNodeIdx );
            mIsDirty = true;
				setSelectedNode( mSelNode );

				return;
         }
			else
         {
				if( clickedRiverPtr && clickedNodeIdx == clickedRiverPtr->mNodes.size() - 1 )
				{
					submitUndo( "Add Node" );
					mAddNodeIdx = U32_MAX;
					mMode = mAddNodeMode;
					U32 newNode = mSelRiver->addNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal);  
               mIsDirty = true;
					setSelectedNode( newNode );

					return;
				}
				else
				{
					submitUndo( "Insert Node" );
					// A single-click on empty space while in
					// AddNode mode means insert / add a node.
					//submitUndo( "Add Node" );
					//F32 width = mSelRiver->getNodeWidth( mSelNode );
					U32 newNode = mSelRiver->insertNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal, mAddNodeIdx);
               mIsDirty = true;
					setSelectedNode( newNode );

					return;
				}
			}
		}
	}
	else if ( mMode == mInsertPointMode && mSelRiver != NULL )
	{
		if ( clickedRiverPtr == mSelRiver )
      {
			// NOTE: I guess we have to determine the if the clicked ray intersects a road but not a specific node...
         // in order to handle inserting nodes in the same way as for DecalRoad

         U32 prevNodeIdx = insertNodeIdx;
         U32 nextNodeIdx = ( prevNodeIdx + 1 > mSelRiver->mNodes.size() - 1 ) ? prevNodeIdx : prevNodeIdx + 1;

         const RiverNode &prevNode = mSelRiver->mNodes[prevNodeIdx];
         const RiverNode &nextNode = mSelRiver->mNodes[nextNodeIdx];

         F32 width = ( prevNode.width + nextNode.width ) * 0.5f;
         F32 depth = ( prevNode.depth + nextNode.depth ) * 0.5f;
         Point3F normal = ( prevNode.normal + nextNode.normal ) * 0.5f;
         normal.normalize();

         submitUndo( "Insert Node" );
         U32 newNode = mSelRiver->insertNode( collisionPnt, width, depth, normal, insertNodeIdx + 1 );
         mIsDirty = true;
         setSelectedNode( newNode );

			return;
       }
	}
	else if ( mMode == mRemovePointMode && mSelRiver != NULL )
	{
		if ( nodeClicked && clickedRiverPtr == mSelRiver )
      {
			setSelectedNode( clickedNodeIdx );
         deleteSelectedNode();
         return;
      }
	}
	else if ( mMode == mMovePointMode )
	{
		if ( nodeClicked && clickedRiverPtr == mSelRiver )
      {
			setSelectedNode( clickedNodeIdx );
         return;
      }
	}
	else if ( mMode == mScalePointMode )
	{
		if ( nodeClicked && clickedRiverPtr == mSelRiver )
      {
			setSelectedNode( clickedNodeIdx );
         return;
      }
	}
	else if ( mMode == mRotatePointMode )
	{
		if ( nodeClicked && clickedRiverPtr == mSelRiver )
      {
			setSelectedNode( clickedNodeIdx );
         return;
      }
	}
}