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; }
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(); } }
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); }
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; }
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); }
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); }
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; }
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. }
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 }
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; } } }