guiRiverEditorCtrl.cpp
Engine/source/environment/editors/guiRiverEditorCtrl.cpp
Public Functions
ConsoleDocClass(GuiRiverEditorCtrl , "@brief GUI tool that makes up the <a href="/coding/class/classriver/">River</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Editor\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiRiverEditorCtrl , deleteNode , void , () , "deleteNode()" )
DefineEngineMethod(GuiRiverEditorCtrl , getMode , const char * , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getNodeDepth , F32 , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getNodeNormal , Point3F , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getNodePosition , Point3F , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getNodeWidth , F32 , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getSelectedRiver , S32 , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , regenerate , void , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setMode , void , (const char *mode) , "setMode( <a href="/coding/class/classstring/">String</a> <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> )" )
DefineEngineMethod(GuiRiverEditorCtrl , setNodeDepth , void , (F32 depth) , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setNodeNormal , void , (Point3F normal) , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setNodePosition , void , (Point3F pos) , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setNodeWidth , void , (F32 width) , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setSelectedRiver , void , (const char *objName) , ("") , "" )
Detailed Description
Public Functions
ConsoleDocClass(GuiRiverEditorCtrl , "@brief GUI tool that makes up the <a href="/coding/class/classriver/">River</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Editor\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiRiverEditorCtrl , deleteNode , void , () , "deleteNode()" )
DefineEngineMethod(GuiRiverEditorCtrl , getMode , const char * , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getNodeDepth , F32 , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getNodeNormal , Point3F , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getNodePosition , Point3F , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getNodeWidth , F32 , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , getSelectedRiver , S32 , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , regenerate , void , () , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setMode , void , (const char *mode) , "setMode( <a href="/coding/class/classstring/">String</a> <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> )" )
DefineEngineMethod(GuiRiverEditorCtrl , setNodeDepth , void , (F32 depth) , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setNodeNormal , void , (Point3F normal) , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setNodePosition , void , (Point3F pos) , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setNodeWidth , void , (F32 width) , "" )
DefineEngineMethod(GuiRiverEditorCtrl , setSelectedRiver , void , (const char *objName) , ("") , "" )
IMPLEMENT_CONOBJECT(GuiRiverEditorCtrl )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "environment/editors/guiRiverEditorCtrl.h" 26 27#include "console/consoleTypes.h" 28#include "console/engineAPI.h" 29#include "environment/river.h" 30#include "renderInstance/renderPassManager.h" 31#include "collision/collision.h" 32#include "math/util/frustum.h" 33#include "math/mathUtils.h" 34#include "gfx/gfxPrimitiveBuffer.h" 35#include "gfx/gfxTextureHandle.h" 36#include "gfx/gfxTransformSaver.h" 37#include "gfx/primBuilder.h" 38#include "gfx/gfxDrawUtil.h" 39#include "scene/sceneRenderState.h" 40#include "scene/sceneManager.h" 41#include "gui/core/guiCanvas.h" 42#include "gui/buttons/guiButtonCtrl.h" 43#include "gui/worldEditor/undoActions.h" 44#include "T3D/gameBase/gameConnection.h" 45#include "T3D/prefab.h" 46 47#include "T3D/Scene.h" 48 49IMPLEMENT_CONOBJECT(GuiRiverEditorCtrl); 50 51ConsoleDocClass( GuiRiverEditorCtrl, 52 "@brief GUI tool that makes up the River Editor\n\n" 53 "Editor use only.\n\n" 54 "@internal" 55); 56 57GuiRiverEditorCtrl::GuiRiverEditorCtrl() 58 : mDefaultWidth( 10.0f ), 59 mDefaultDepth( 5.0f ), 60 mDefaultNormal( 0, 0, 1 ) 61{ 62 // Each of the mode names directly correlates with the River Editor's 63 // tool palette 64 mSelectRiverMode = "RiverEditorSelectMode"; 65 mAddRiverMode = "RiverEditorAddRiverMode"; 66 mMovePointMode = "RiverEditorMoveMode"; 67 mRotatePointMode = "RiverEditorRotateMode"; 68 mScalePointMode = "RiverEditorScaleMode"; 69 mAddNodeMode = "RiverEditorAddNodeMode"; 70 mInsertPointMode = "RiverEditorInsertPointMode"; 71 mRemovePointMode = "RiverEditorRemovePointMode"; 72 73 mMode = mSelectRiverMode; 74 75 mRiverSet = NULL; 76 mSelNode = -1; 77 mSelRiver = NULL; 78 mHoverRiver = NULL; 79 mAddNodeIdx = 0; 80 mHoverNode = -1; 81 82 mInsertIdx = -1; 83 84 mStartWidth = -1.0f; 85 mStartHeight = -1.0f; 86 mStartX = 0; 87 88 mSavedDrag = false; 89 mIsDirty = false; 90 91 mNodeHalfSize.set(4,4); 92 93 mNodeSphereRadius = 15.0f; 94 mNodeSphereFillColor.set( 15,15,100,145 ); 95 mNodeSphereLineColor.set( 25,25,25,0 ); 96 mHoverSplineColor.set( 255,0,0,255 ); 97 mSelectedSplineColor.set( 0,255,0,255 ); 98 mHoverNodeColor.set( 255,255,255,255 ); 99 100 mStartDragMousePoint = InvalidMousePoint; 101 //mMoveNodeCursor = NULL; 102 //mAddNodeCursor = NULL; 103 //mInsertNodeCursor = NULL; 104 //mResizeNodeCursor = NULL; 105} 106 107GuiRiverEditorCtrl::~GuiRiverEditorCtrl() 108{ 109 // nothing to do 110} 111 112void GuiRiverEditorUndoAction::undo() 113{ 114 River *river = NULL; 115 if ( !Sim::findObject( mObjId, river ) ) 116 return; 117 118 // Temporarily save the Rivers current data. 119 F32 metersPerSeg = river->mMetersPerSegment; 120 Vector<RiverNode> nodes; 121 nodes.merge( river->mNodes ); 122 123 // Restore the River properties saved in the UndoAction 124 river->mMetersPerSegment = mMetersPerSegment; 125 126 // Restore the Nodes saved in the UndoAction 127 river->mNodes.clear(); 128 for ( U32 i = 0; i < mNodes.size(); i++ ) 129 { 130 river->_addNode( mNodes[i].point, mNodes[i].width, mNodes[i].depth, mNodes[i].normal ); 131 } 132 133 // Regenerate the River 134 river->regenerate(); 135 136 // If applicable set the selected River and node 137 mRiverEditor->mSelRiver = river; 138 mRiverEditor->mSelNode = -1; 139 140 // Now save the previous River data in this UndoAction 141 // since an undo action must become a redo action and vice-versa 142 mMetersPerSegment = metersPerSeg; 143 mNodes.clear(); 144 mNodes.merge( nodes ); 145} 146 147bool GuiRiverEditorCtrl::onAdd() 148{ 149 if( !Parent::onAdd() ) 150 return false; 151 152 mRiverSet = River::getServerSet(); 153 154 GFXStateBlockDesc desc; 155 desc.fillMode = GFXFillSolid; 156 desc.setBlend( false ); 157 desc.setZReadWrite( false, false ); 158 desc.setCullMode( GFXCullNone ); 159 160 mZDisableSB = GFX->createStateBlock(desc); 161 162 desc.setZReadWrite( true, true ); 163 mZEnableSB = GFX->createStateBlock(desc); 164 165 SceneManager::getPreRenderSignal().notify( this, &GuiRiverEditorCtrl::_prepRenderImage ); 166 167 return true; 168} 169 170void GuiRiverEditorCtrl::initPersistFields() 171{ 172 addField( "DefaultWidth", TypeF32, Offset( mDefaultWidth, GuiRiverEditorCtrl ) ); 173 addField( "DefaultDepth", TypeF32, Offset( mDefaultDepth, GuiRiverEditorCtrl ) ); 174 addField( "DefaultNormal", TypePoint3F,Offset( mDefaultNormal, GuiRiverEditorCtrl ) ); 175 addField( "HoverSplineColor", TypeColorI, Offset( mHoverSplineColor, GuiRiverEditorCtrl ) ); 176 addField( "SelectedSplineColor", TypeColorI, Offset( mSelectedSplineColor, GuiRiverEditorCtrl ) ); 177 addField( "HoverNodeColor", TypeColorI, Offset( mHoverNodeColor, GuiRiverEditorCtrl ) ); 178 addField( "isDirty", TypeBool, Offset( mIsDirty, GuiRiverEditorCtrl ) ); 179 //addField( "MoveNodeCursor", TYPEID< SimObject >(), Offset( mMoveNodeCursor, GuiRiverEditorCtrl) ); 180 //addField( "AddNodeCursor", TYPEID< SimObject >(), Offset( mAddNodeCursor, GuiRiverEditorCtrl) ); 181 //addField( "InsertNodeCursor", TYPEID< SimObject >(), Offset( mInsertNodeCursor, GuiRiverEditorCtrl) ); 182 //addField( "ResizeNodeCursor", TYPEID< SimObject >(), Offset( mResizeNodeCursor, GuiRiverEditorCtrl) ); 183 184 Parent::initPersistFields(); 185} 186 187void GuiRiverEditorCtrl::onSleep() 188{ 189 Parent::onSleep(); 190 191 mMode = mSelectRiverMode; 192 mHoverNode = -1; 193 mHoverRiver = NULL; 194 setSelectedNode(-1); 195 //mSelRiver = NULL; 196 //mSelNode = -1; 197} 198 199void GuiRiverEditorCtrl::get3DCursor( GuiCursor *&cursor, 200 bool &visible, 201 const Gui3DMouseEvent &event_ ) 202{ 203 //cursor = mAddNodeCursor; 204 //visible = false; 205 206 cursor = NULL; 207 visible = false; 208 209 GuiCanvas *root = getRoot(); 210 if ( !root ) 211 return; 212 213 S32 currCursor = PlatformCursorController::curArrow; 214 215 if ( root->mCursorChanged == currCursor ) 216 return; 217 218 PlatformWindow *window = root->getPlatformWindow(); 219 PlatformCursorController *controller = window->getCursorController(); 220 221 // We've already changed the cursor, 222 // so set it back before we change it again. 223 if( root->mCursorChanged != -1) 224 controller->popCursor(); 225 226 // Now change the cursor shape 227 controller->pushCursor(currCursor); 228 root->mCursorChanged = currCursor; 229} 230 231void GuiRiverEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event) 232{ 233 _process3DMouseDown( event ); 234 235 mGizmo->on3DMouseDown( event ); 236 237 if ( !isFirstResponder() ) 238 setFirstResponder(); 239} 240 241void GuiRiverEditorCtrl::_process3DMouseDown( const Gui3DMouseEvent& event ) 242{ 243 // Get the raycast collision position 244 Point3F tPos; 245 if ( !getStaticPos( event, tPos ) ) 246 return; 247 248 mouseLock(); 249 250 // Construct a LineSegment from the camera position to 1000 meters away in 251 // the direction clicked. 252 // If that segment hits the terrain, truncate the ray to only be that length. 253 254 // We will use a LineSegment/Sphere intersection test to determine if a RiverNode 255 // was clicked. 256 257 Point3F startPnt = event.pos; 258 Point3F endPnt = event.pos + event.vec * 1000.0f; 259 260 RayInfo ri; 261 262 if ( gServerContainer.castRay(startPnt, endPnt, StaticShapeObjectType, &ri) ) 263 endPnt = ri.point; 264 265 River *riverPtr = NULL; 266 River *clickedRiverPtr = NULL; 267 268 // Did we click on a river? check current selection first 269 U32 insertNodeIdx = -1; 270 Point3F collisionPnt; 271 if ( mSelRiver != NULL && mSelRiver->collideRay( event.pos, event.vec, &insertNodeIdx, &collisionPnt ) ) 272 { 273 clickedRiverPtr = mSelRiver; 274 } 275 else 276 { 277 for ( SimSetIterator iter(mRiverSet); *iter; ++iter ) 278 { 279 riverPtr = static_cast<River*>( *iter ); 280 281 // Do not select or edit a River within a Prefab. 282 if ( Prefab::getPrefabByChild(riverPtr) ) 283 continue; 284 285 if ( riverPtr->collideRay( event.pos, event.vec, &insertNodeIdx, &collisionPnt ) ) 286 { 287 clickedRiverPtr = riverPtr; 288 break; 289 } 290 } 291 } 292 293 // Did we click on a riverNode? 294 bool nodeClicked = false; 295 S32 clickedNodeIdx = -1; 296 F32 clickedNodeDist = mNodeSphereRadius; 297 298 // If we clicked on the currently selected river, only scan its nodes 299 if ( mSelRiver != NULL && clickedRiverPtr == mSelRiver ) 300 { 301 for ( U32 i = 0; i < mSelRiver->mNodes.size(); i++ ) 302 { 303 const Point3F &nodePos = mSelRiver->mNodes[i].point; 304 305 Point3F screenPos; 306 project( nodePos, &screenPos ); 307 308 F32 dist = ( event.mousePoint - Point2I(screenPos.x, screenPos.y) ).len(); 309 if ( dist < clickedNodeDist ) 310 { 311 clickedNodeDist = dist; 312 clickedNodeIdx = i; 313 insertNodeIdx = i; 314 nodeClicked = true; 315 } 316 } 317 } 318 else 319 { 320 for ( SimSetIterator iter(mRiverSet); *iter; ++iter ) 321 { 322 riverPtr = static_cast<River*>( *iter ); 323 324 // Do not select or edit a River within a Prefab. 325 if ( Prefab::getPrefabByChild(riverPtr) ) 326 continue; 327 328 for ( U32 i = 0; i < riverPtr->mNodes.size(); i++ ) 329 { 330 const Point3F &nodePos = riverPtr->mNodes[i].point; 331 332 Point3F screenPos; 333 project( nodePos, &screenPos ); 334 335 F32 dist = ( event.mousePoint - Point2I(screenPos.x, screenPos.y) ).len(); 336 if ( dist < clickedNodeDist ) 337 { 338 // we found a hit! 339 clickedNodeDist = dist; 340 clickedNodeIdx = i; 341 insertNodeIdx = i; 342 nodeClicked = true; 343 clickedRiverPtr = riverPtr; 344 } 345 } 346 } 347 } 348 349 // shortcuts 350 bool dblClick = ( event.mouseClickCount > 1 ); 351 if( dblClick ) 352 { 353 if( mMode == mSelectRiverMode ) 354 { 355 setMode( mAddRiverMode, true ); 356 return; 357 } 358 if( mMode == mAddNodeMode ) 359 { 360 // Delete the node attached to the cursor. 361 deleteSelectedNode(); 362 mMode = mAddRiverMode; 363 return; 364 } 365 } 366 367 //this check is here in order to bounce back from deleting a whole road with ctrl+z 368 //this check places the editor back into addrivermode 369 if ( mMode == mAddNodeMode ) 370 { 371 if ( !mSelRiver ) 372 mMode = mAddRiverMode; 373 } 374 375 if ( mMode == mSelectRiverMode ) 376 { 377 // Did not click on a River or a node. 378 if ( !clickedRiverPtr ) 379 { 380 setSelectedRiver( NULL ); 381 setSelectedNode( -1 ); 382 383 return; 384 } 385 386 // Clicked on a River that wasn't the currently selected River. 387 if ( clickedRiverPtr != mSelRiver ) 388 { 389 setSelectedRiver( clickedRiverPtr ); 390 setSelectedNode( clickedNodeIdx ); 391 return; 392 } 393 394 // Clicked on a node in the currently selected River that wasn't 395 // the currently selected node. 396 if ( nodeClicked ) 397 { 398 setSelectedNode( clickedNodeIdx ); 399 return; 400 } 401 } 402 else if ( mMode == mAddRiverMode ) 403 { 404 if ( nodeClicked ) 405 { 406 // A double-click on a node in Normal mode means set AddNode mode. 407 if ( clickedNodeIdx == 0 ) 408 { 409 setSelectedRiver( clickedRiverPtr ); 410 setSelectedNode( clickedNodeIdx ); 411 412 mAddNodeIdx = clickedNodeIdx; 413 mMode = mAddNodeMode; 414 415 mSelNode = mSelRiver->insertNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal, mAddNodeIdx ); 416 mIsDirty = true; 417 418 return; 419 } 420 else if ( clickedNodeIdx == clickedRiverPtr->mNodes.size() - 1 ) 421 { 422 setSelectedRiver( clickedRiverPtr ); 423 setSelectedNode( clickedNodeIdx ); 424 425 mAddNodeIdx = U32_MAX; 426 mMode = mAddNodeMode; 427 428 mSelNode = mSelRiver->addNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal); 429 mIsDirty = true; 430 setSelectedNode( mSelNode ); 431 432 return; 433 } 434 } 435 436 if ( !isMethod( "createRiver" ) ) 437 { 438 Con::errorf( "GuiRiverEditorCtrl::on3DMouseDown - createRiver method does not exist." ); 439 return; 440 } 441 442 const char *res = Con::executef( this, "createRiver" ); 443 444 River *newRiver; 445 if ( !Sim::findObject( res, newRiver ) ) 446 { 447 Con::errorf( "GuiRiverEditorCtrl::on3DMouseDown - createRiver method did not return a river object." ); 448 return; 449 } 450 451 // Add to Scene 452 Scene* scene = Scene::getRootScene(); 453 if ( !scene ) 454 Con::errorf( "GuiRiverEditorCtrl - could not find root Scene to add new River" ); 455 else 456 scene->addObject( newRiver ); 457 458 Point3F pos( endPnt ); 459 pos.z += mDefaultDepth * 0.5f; 460 461 newRiver->insertNode( pos, mDefaultWidth, mDefaultDepth, mDefaultNormal, 0 ); 462 U32 newNode = newRiver->insertNode( pos, mDefaultWidth, mDefaultDepth, mDefaultNormal, 1 ); 463 464 // Always add to the end of the road, the first node is the start. 465 mAddNodeIdx = U32_MAX; 466 467 setSelectedRiver( newRiver ); 468 setSelectedNode( newNode ); 469 470 mMode = mAddNodeMode; 471 472 // Disable the hover node while in addNodeMode, we 473 // don't want some random node enlarged. 474 mHoverNode = -1; 475 476 // Grab the mission editor undo manager. 477 UndoManager *undoMan = NULL; 478 if ( !Sim::findObject( "EUndoManager", undoMan ) ) 479 { 480 Con::errorf( "GuiMeshRoadEditorCtrl::on3DMouseDown() - EUndoManager not found!" ); 481 return; 482 } 483 484 // Create the UndoAction. 485 MECreateUndoAction *action = new MECreateUndoAction("Create MeshRoad"); 486 action->addObject( newRiver ); 487 488 // Submit it. 489 undoMan->addAction( action ); 490 491 return; 492 } 493 else if ( mMode == mAddNodeMode ) 494 { 495 // Oops the road got deleted, maybe from an undo action? 496 // Back to NormalMode. 497 if ( mSelRiver ) 498 { 499 // A double-click on a node in Normal mode means set AddNode mode. 500 if ( clickedNodeIdx == 0 ) 501 { 502 submitUndo( "Add Node" ); 503 mAddNodeIdx = clickedNodeIdx; 504 mMode = mAddNodeMode; 505 mSelNode = mSelRiver->insertNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal, mAddNodeIdx ); 506 mIsDirty = true; 507 setSelectedNode( mSelNode ); 508 509 return; 510 } 511 else 512 { 513 if( clickedRiverPtr && clickedNodeIdx == clickedRiverPtr->mNodes.size() - 1 ) 514 { 515 submitUndo( "Add Node" ); 516 mAddNodeIdx = U32_MAX; 517 mMode = mAddNodeMode; 518 U32 newNode = mSelRiver->addNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal); 519 mIsDirty = true; 520 setSelectedNode( newNode ); 521 522 return; 523 } 524 else 525 { 526 submitUndo( "Insert Node" ); 527 // A single-click on empty space while in 528 // AddNode mode means insert / add a node. 529 //submitUndo( "Add Node" ); 530 //F32 width = mSelRiver->getNodeWidth( mSelNode ); 531 U32 newNode = mSelRiver->insertNode( tPos, mDefaultWidth, mDefaultDepth, mDefaultNormal, mAddNodeIdx); 532 mIsDirty = true; 533 setSelectedNode( newNode ); 534 535 return; 536 } 537 } 538 } 539 } 540 else if ( mMode == mInsertPointMode && mSelRiver != NULL ) 541 { 542 if ( clickedRiverPtr == mSelRiver ) 543 { 544 // NOTE: I guess we have to determine the if the clicked ray intersects a road but not a specific node... 545 // in order to handle inserting nodes in the same way as for DecalRoad 546 547 U32 prevNodeIdx = insertNodeIdx; 548 U32 nextNodeIdx = ( prevNodeIdx + 1 > mSelRiver->mNodes.size() - 1 ) ? prevNodeIdx : prevNodeIdx + 1; 549 550 const RiverNode &prevNode = mSelRiver->mNodes[prevNodeIdx]; 551 const RiverNode &nextNode = mSelRiver->mNodes[nextNodeIdx]; 552 553 F32 width = ( prevNode.width + nextNode.width ) * 0.5f; 554 F32 depth = ( prevNode.depth + nextNode.depth ) * 0.5f; 555 Point3F normal = ( prevNode.normal + nextNode.normal ) * 0.5f; 556 normal.normalize(); 557 558 submitUndo( "Insert Node" ); 559 U32 newNode = mSelRiver->insertNode( collisionPnt, width, depth, normal, insertNodeIdx + 1 ); 560 mIsDirty = true; 561 setSelectedNode( newNode ); 562 563 return; 564 } 565 } 566 else if ( mMode == mRemovePointMode && mSelRiver != NULL ) 567 { 568 if ( nodeClicked && clickedRiverPtr == mSelRiver ) 569 { 570 setSelectedNode( clickedNodeIdx ); 571 deleteSelectedNode(); 572 return; 573 } 574 } 575 else if ( mMode == mMovePointMode ) 576 { 577 if ( nodeClicked && clickedRiverPtr == mSelRiver ) 578 { 579 setSelectedNode( clickedNodeIdx ); 580 return; 581 } 582 } 583 else if ( mMode == mScalePointMode ) 584 { 585 if ( nodeClicked && clickedRiverPtr == mSelRiver ) 586 { 587 setSelectedNode( clickedNodeIdx ); 588 return; 589 } 590 } 591 else if ( mMode == mRotatePointMode ) 592 { 593 if ( nodeClicked && clickedRiverPtr == mSelRiver ) 594 { 595 setSelectedNode( clickedNodeIdx ); 596 return; 597 } 598 } 599} 600 601void GuiRiverEditorCtrl::on3DRightMouseDown(const Gui3DMouseEvent & event) 602{ 603 //mIsPanning = true; 604} 605 606void GuiRiverEditorCtrl::on3DRightMouseUp(const Gui3DMouseEvent & event) 607{ 608 //mIsPanning = false; 609} 610 611void GuiRiverEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event) 612{ 613 // Keep the Gizmo up to date. 614 mGizmo->on3DMouseUp( event ); 615 616 mStartWidth = -1.0f; 617 mStartHeight = -1.0f; 618 mSavedDrag = false; 619 620 mouseUnlock(); 621} 622 623void GuiRiverEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event) 624{ 625 if ( mSelRiver != NULL && mMode == mAddNodeMode ) 626 { 627 Point3F pos; 628 if ( getStaticPos( event, pos ) ) 629 { 630 pos.z += mSelRiver->getNodeDepth(mSelNode) * 0.5f; 631 mSelRiver->setNodePosition( mSelNode, pos ); 632 mIsDirty = true; 633 } 634 635 return; 636 } 637 638 if ( mSelRiver != NULL && mSelNode != -1 ) 639 mGizmo->on3DMouseMove( event ); 640 641 // Is cursor hovering over a river? 642 if ( mMode == mSelectRiverMode ) 643 { 644 mHoverRiver = NULL; 645 646 Point3F startPnt = event.pos; 647 Point3F endPnt = event.pos + event.vec * 1000.0f; 648 649 RayInfo ri; 650 651 if ( gServerContainer.castRay(startPnt, endPnt, StaticShapeObjectType, &ri) ) 652 endPnt = ri.point; 653 654 River *pRiver = NULL; 655 656 for ( SimSetIterator iter(mRiverSet); *iter; ++iter ) 657 { 658 pRiver = static_cast<River*>( *iter ); 659 660 // Do not select or edit a River within a Prefab. 661 if ( Prefab::getPrefabByChild(pRiver) ) 662 continue; 663 664 if ( pRiver->collideRay( event.pos, event.vec ) ) 665 { 666 mHoverRiver = pRiver; 667 break; 668 } 669 } 670 } 671 672 // Is cursor hovering over a RiverNode? 673 if ( mHoverRiver ) 674 { 675 River *pRiver = mHoverRiver; 676 677 S32 hoverNodeIdx = -1; 678 F32 hoverNodeDist = mNodeSphereRadius; 679 680 //for ( SimSetIterator iter(mRiverSet); *iter; ++iter ) 681 //{ 682 // River *pRiver = static_cast<River*>( *iter ); 683 684 for ( U32 i = 0; i < pRiver->mNodes.size(); i++ ) 685 { 686 const Point3F &nodePos = pRiver->mNodes[i].point; 687 688 Point3F screenPos; 689 project( nodePos, &screenPos ); 690 691 F32 dist = ( event.mousePoint - Point2I(screenPos.x, screenPos.y) ).len(); 692 if ( dist < hoverNodeDist ) 693 { 694 // we found a hit! 695 hoverNodeDist = dist; 696 hoverNodeIdx = i; 697 } 698 } 699 //} 700 701 mHoverNode = hoverNodeIdx; 702 } 703} 704 705void GuiRiverEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event) 706{ 707 // Drags are only used to transform nodes 708 if ( !mSelRiver || mSelNode == -1 || 709 ( mMode != mMovePointMode && mMode != mScalePointMode && mMode != mRotatePointMode ) ) 710 return; 711 712 // If we haven't already saved, 713 // save an undo action to get back to this state, 714 // before we make any modifications to the selected node. 715 if ( !mSavedDrag ) 716 { 717 submitUndo( "Modify Node" ); 718 mSavedDrag = true; 719 } 720 721 // Let the gizmo handle the drag, eg, modify its transforms 722 mGizmo->on3DMouseDragged( event ); 723 if ( mGizmo->isDirty() ) 724 { 725 Point3F pos = mGizmo->getPosition(); 726 Point3F scale = mGizmo->getScale(); 727 const MatrixF &mat = mGizmo->getTransform(); 728 VectorF normal; 729 mat.getColumn( 2, &normal ); 730 731 mSelRiver->setNode( pos, scale.x, scale.z, normal, mSelNode ); 732 mIsDirty = true; 733 } 734 Con::executef( this, "onNodeModified", Con::getIntArg(mSelNode) ); 735 /* 736 // If we are just starting a new drag, 737 // we need to save the starting screen position of the mouse, 738 // and the starting position of the selected node. 739 if ( mStartDragMousePoint == InvalidMousePoint ) 740 { 741 mStartDragMousePoint = event.mousePoint; 742 mStartDragNodePos = mSelRiver->getNodePosition( mSelNode ); 743 } 744 745 MathUtils::Line clickLine; 746 clickLine.p = event.pos; 747 clickLine.d = event.vec; 748 749 MathUtils::Line axisLine; 750 axisLine.p = mStartDragNodePos; 751 axisLine.d = mGizmo.selectionToAxisVector( mGizmoSelection ); 752 753 MathUtils::LineSegment segment; 754 755 MathUtils::mShortestSegmentBetweenLines( clickLine, axisLine, segment ); 756 757 // Segment.p1 is the closest point on the axis line, 758 // We want to put the selected gizmo handle at that point, 759 // So calculate the offset from the handle to the centerPoint to 760 // determine the gizmo's position. 761 mSelRiver->setNodePosition( mSelNode, segment.p1 ); 762 */ 763 764 /* 765 // Convert the delta (dragged mouse distance) from screen space 766 // into world space. 767 Point2I deltaScreen = event.mousePoint - mStartDragMousePoint; 768 769 F32 worldDist = ( event.pos - mStartDragNodePos ).len(); 770 771 Point2F deltaWorld; 772 deltaWorld.x = GFX->unprojectRadius( worldDist, deltaScreen.x ); 773 deltaWorld.y = GFX->unprojectRadius( worldDist, deltaScreen.y ); 774 775 // Now modify the selected node depending on the kind of operation we are doing. 776 if ( mGizmoSelection == Gizmo::Axis_X ) 777 { 778 Point3F newPos = mStartDragNodePos; 779 newPos.x += deltaWorld.x; 780 mSelRiver->setNodePosition( mSelNode, newPos ); 781 } 782 else if ( mGizmoSelection == Gizmo::Axis_Y ) 783 { 784 Point3F newPos = mStartDragNodePos; 785 newPos.y += deltaWorld.x; 786 mSelRiver->setNodePosition( mSelNode, newPos ); 787 } 788 else if ( mGizmoSelection == Gizmo::Axis_Z ) 789 { 790 Point3F newPos = mStartDragNodePos; 791 newPos.z += deltaWorld.y; 792 mSelRiver->setNodePosition( mSelNode, newPos ); 793 } 794 */ 795 796 /* 797 F32 height = mStartHeight + deltaWorldX; 798 Con::printf( "height = %g", height ); 799 800 mSelRiver->setNodeHeight( mSelNode, height ); 801 802 Con::executef( this, "onNodeHeightModified", Con::getFloatArg(height) ); 803 804 805 if ( event.modifier & SI_PRIMARY_CTRL ) 806 { 807 //Point3F tPos; 808 //if ( !getStaticPos( event, tPos ) ) 809 // return; 810 811 if ( mStartHeight == -1.0f ) 812 { 813 mStartHeight = mSelRiver->mNodes[mSelNode].point.z; 814 815 mStartX = event.mousePoint.x; 816 mStartWorld = mSelRiver->mNodes[mSelNode].point; 817 } 818 819 S32 deltaScreenX = event.mousePoint.x - mStartX; 820 821 F32 worldDist = ( event.pos - mStartWorld ).len(); 822 823 F32 deltaWorldX = GFX->unprojectRadius( worldDist, deltaScreenX ); 824 825 F32 height = mStartHeight + deltaWorldX; 826 Con::printf( "height = %g", height ); 827 828 mSelRiver->setNodeHeight( mSelNode, height ); 829 830 Con::executef( this, "onNodeHeightModified", Con::getFloatArg(height) ); 831 } 832 else if ( event.modifier & SI_SHIFT ) 833 { 834 Point3F tPos; 835 if ( !getStaticPos( event, tPos ) ) 836 return; 837 838 if ( mStartWidth == -1.0f ) 839 { 840 mStartWidth = mSelRiver->mNodes[mSelNode].width; 841 842 mStartX = event.mousePoint.x; 843 mStartWorld = tPos; 844 } 845 846 S32 deltaScreenX = event.mousePoint.x - mStartX; 847 848 F32 worldDist = ( event.pos - mStartWorld ).len(); 849 850 F32 deltaWorldX = GFX->unprojectRadius( worldDist, deltaScreenX ); 851 852 F32 width = mStartWidth + deltaWorldX; 853 854 mSelRiver->setNodeWidth( mSelNode, width ); 855 856 Con::executef( this, "onNodeWidthModified", Con::getFloatArg(width) ); 857 } 858 else 859 { 860 Point3F tPos; 861 if ( !getStaticPos( event, tPos ) ) 862 return; 863 else if ( mGizmoSelection == Gizmo::Axis_Y ) 864 { 865 Point3F newPos = mStartDragNodePos; 866 newPos.y += deltaWorld.x; 867 mSelRiver->setNodePosition( mSelNode, newPos ); 868 } 869 mSelRiver->setNodePosition( mSelNode, tPos ); 870 } 871 */ 872} 873 874void GuiRiverEditorCtrl::on3DMouseEnter(const Gui3DMouseEvent & event) 875{ 876 // nothing to do 877} 878 879void GuiRiverEditorCtrl::on3DMouseLeave(const Gui3DMouseEvent & event) 880{ 881 // nothing to do 882} 883 884bool GuiRiverEditorCtrl::onKeyDown(const GuiEvent& event) 885{ 886 if( event.keyCode == KEY_RETURN && mMode == mAddNodeMode ) 887 { 888 // Delete the node attached to the cursor. 889 deleteSelectedNode(); 890 mMode = mAddRiverMode; 891 return true; 892 } 893 894 return false; 895} 896 897void GuiRiverEditorCtrl::updateGuiInfo() 898{ 899 // nothing to do 900} 901 902void GuiRiverEditorCtrl::onRender( Point2I offset, const RectI &updateRect ) 903{ 904 PROFILE_SCOPE( GuiRiverEditorCtrl_OnRender ); 905 906 Parent::onRender( offset, updateRect ); 907 return; 908} 909 910void GuiRiverEditorCtrl::renderScene(const RectI & updateRect) 911{ 912 //GFXDrawUtil *drawer = GFX->getDrawUtil(); 913 914 GFX->setStateBlock( mZDisableSB ); 915 916 // get the projected size... 917 GameConnection* connection = GameConnection::getConnectionToServer(); 918 if(!connection) 919 return; 920 921 // Grab the camera's transform 922 MatrixF mat; 923 connection->getControlCameraTransform(0, &mat); 924 925 // Get the camera position 926 Point3F camPos; 927 mat.getColumn(3,&camPos); 928 929 if ( mHoverRiver && mHoverRiver != mSelRiver ) 930 { 931 _drawRiverSpline( mHoverRiver, mHoverSplineColor ); 932 } 933 934 if ( mSelRiver ) 935 { 936 _drawRiverSpline( mSelRiver, mSelectedSplineColor ); 937 938 // Render Gizmo for selected node if were in either of the three transform modes 939 if ( mSelNode != -1 && ( mMode == mMovePointMode || mMode == mScalePointMode || mMode == mRotatePointMode ) ) 940 { 941 if( mMode == mMovePointMode ) 942 { 943 mGizmo->getProfile()->mode = MoveMode; 944 } 945 else if( mMode == mScalePointMode ) 946 { 947 mGizmo->getProfile()->mode = ScaleMode; 948 } 949 else if( mMode == mRotatePointMode ) 950 { 951 mGizmo->getProfile()->mode = RotateMode; 952 } 953 954 const RiverNode &node = mSelRiver->mNodes[mSelNode]; 955 956 MatrixF objMat = mSelRiver->getNodeTransform(mSelNode); 957 Point3F objScale( node.width, 1.0f, node.depth ); 958 Point3F worldPos = node.point; 959 960 mGizmo->set( objMat, worldPos, objScale ); 961 962 mGizmo->renderGizmo( mLastCameraQuery.cameraMatrix, mLastCameraQuery.fov ); 963 964 // Render Gizmo text 965 //mGizmo->renderText( mSaveViewport, mSaveModelview, mSaveProjection ); 966 } 967 } 968 969 // Now draw all the 2d stuff! 970 GFX->setClipRect(updateRect); 971 972 // Draw Control nodes for selecting and highlighted rivers 973 if ( mHoverRiver ) 974 _drawRiverControlNodes( mHoverRiver, mHoverSplineColor ); 975 if ( mSelRiver ) 976 _drawRiverControlNodes( mSelRiver, mSelectedSplineColor ); 977} 978 979void GuiRiverEditorCtrl::_drawRiverSpline( River *river, const ColorI &color ) 980{ 981 if ( river->mSlices.size() <= 1 ) 982 return; 983 984 if ( River::smShowSpline ) 985 { 986 // Render the River center-line 987 PrimBuild::color( color ); 988 PrimBuild::begin( GFXLineStrip, river->mSlices.size() ); 989 for ( U32 i = 0; i < river->mSlices.size(); i++ ) 990 { 991 PrimBuild::vertex3fv( river->mSlices[i].p1 ); 992 } 993 PrimBuild::end(); 994 } 995 996 if ( River::smWireframe ) 997 { 998 // Left-side line 999 PrimBuild::color3i( 100, 100, 100 ); 1000 PrimBuild::begin( GFXLineStrip, river->mSlices.size() ); 1001 for ( U32 i = 0; i < river->mSlices.size(); i++ ) 1002 { 1003 PrimBuild::vertex3fv( river->mSlices[i].p0 ); 1004 } 1005 PrimBuild::end(); 1006 1007 // Right-side line 1008 PrimBuild::begin( GFXLineStrip, river->mSlices.size() ); 1009 for ( U32 i = 0; i < river->mSlices.size(); i++ ) 1010 { 1011 PrimBuild::vertex3fv( river->mSlices[i].p2 ); 1012 } 1013 PrimBuild::end(); 1014 1015 // Cross-sections 1016 PrimBuild::begin( GFXLineList, river->mSlices.size() * 2 ); 1017 for ( U32 i = 0; i < river->mSlices.size(); i++ ) 1018 { 1019 PrimBuild::vertex3fv( river->mSlices[i].p0 ); 1020 PrimBuild::vertex3fv( river->mSlices[i].p2 ); 1021 } 1022 PrimBuild::end(); 1023 } 1024 // Segment 1025} 1026 1027void GuiRiverEditorCtrl::_drawRiverControlNodes( River *river, const ColorI &color ) 1028{ 1029 if ( !River::smShowSpline ) 1030 return; 1031 1032 RectI bounds = getBounds(); 1033 1034 GFXDrawUtil *drawer = GFX->getDrawUtil(); 1035 1036 bool isSelected = ( river == mSelRiver ); 1037 bool isHighlighted = ( river == mHoverRiver ); 1038 1039 for ( U32 i = 0; i < river->mNodes.size(); i++ ) 1040 { 1041 if ( false && isSelected && mSelNode == i ) 1042 continue; 1043 1044 const Point3F &wpos = river->mNodes[i].point; 1045 1046 Point3F spos; 1047 project( wpos, &spos ); 1048 1049 if ( spos.z > 1.0f ) 1050 continue; 1051 1052 Point2I posi; 1053 posi.x = spos.x; 1054 posi.y = spos.y; 1055 1056 if ( !bounds.pointInRect( posi ) ) 1057 continue; 1058 1059 ColorI theColor = color; 1060 Point2I nodeHalfSize = mNodeHalfSize; 1061 1062 if ( isHighlighted && mHoverNode == i ) 1063 { 1064 //theColor = mHoverNodeColor; 1065 nodeHalfSize += Point2I(2,2); 1066 } 1067 1068 if ( isSelected ) 1069 { 1070 if ( mSelNode == i ) 1071 { 1072 theColor.set(0,0,255); 1073 } 1074 else if ( i == 0 ) 1075 { 1076 theColor.set(0,255,0); 1077 } 1078 else if ( i == river->mNodes.size() - 1 ) 1079 { 1080 theColor.set(255,0,0); 1081 } 1082 } 1083 1084 drawer->drawRectFill( posi - nodeHalfSize, posi + nodeHalfSize, theColor ); 1085 } 1086} 1087 1088bool GuiRiverEditorCtrl::getStaticPos( const Gui3DMouseEvent & event, Point3F &tpos ) 1089{ 1090 // Find clicked point on the terrain 1091 1092 Point3F startPnt = event.pos; 1093 Point3F endPnt = event.pos + event.vec * 1000.0f; 1094 1095 RayInfo ri; 1096 bool hit; 1097 1098 hit = gServerContainer.castRay(startPnt, endPnt, StaticShapeObjectType, &ri); 1099 tpos = ri.point; 1100 1101 return hit; 1102} 1103 1104void GuiRiverEditorCtrl::deleteSelectedNode() 1105{ 1106 if ( !mSelRiver || mSelNode == -1 ) 1107 return; 1108 1109 // If the River has only two nodes remaining, 1110 // delete the whole River. 1111 if ( mSelRiver->mNodes.size() <= 2 ) 1112 { 1113 deleteSelectedRiver( mMode != mAddNodeMode ); 1114 } 1115 else 1116 { 1117 if ( mMode != mAddNodeMode ) 1118 submitUndo( "Delete Node" ); 1119 1120 // Delete the SelectedNode of the SelectedRiver 1121 mSelRiver->deleteNode(mSelNode); 1122 mIsDirty = true; 1123 1124 // We deleted the Node but not the River (it has nodes left) 1125 // so decrement the currently selected node. 1126 if ( mSelRiver->mNodes.size() <= mSelNode ) 1127 setSelectedNode( mSelNode - 1 ); 1128 else 1129 { 1130 // force gizmo to update to the selected nodes position 1131 // the index didn't change but the node it refers to did. 1132 U32 i = mSelNode; 1133 mSelNode = -1; 1134 setSelectedNode( i ); 1135 } 1136 } 1137 1138 // If you were in addNodeMode, 1139 // deleting a node should ends it. 1140 //mMode = smNormalMode; 1141} 1142 1143void GuiRiverEditorCtrl::deleteSelectedRiver( bool undoAble ) 1144{ 1145 AssertFatal( mSelRiver != NULL, "GuiRiverEditorCtrl::deleteSelectedRiver() - No River IS selected" ); 1146 1147 // Not undoAble? Just delete it. 1148 if ( !undoAble ) 1149 { 1150 mSelRiver->deleteObject(); 1151 mIsDirty = true; 1152 Con::executef( this, "onRiverSelected" ); 1153 mSelNode = -1; 1154 1155 return; 1156 } 1157 1158 // Grab the mission editor undo manager. 1159 UndoManager *undoMan = NULL; 1160 if ( !Sim::findObject( "EUndoManager", undoMan ) ) 1161 { 1162 // Couldn't find it? Well just delete the River. 1163 Con::errorf( "GuiRiverEditorCtrl::on3DMouseDown() - EUndoManager not found!" ); 1164 return; 1165 } 1166 else 1167 { 1168 // Create the UndoAction. 1169 MEDeleteUndoAction *action = new MEDeleteUndoAction("Deleted River"); 1170 action->deleteObject( mSelRiver ); 1171 mIsDirty = true; 1172 1173 // Submit it. 1174 undoMan->addAction( action ); 1175 } 1176 1177 // ScriptCallback with 'NULL' parameter for no River currently selected. 1178 Con::executef( this, "onRiverSelected" ); 1179 1180 // Clear the SelectedNode (it has been deleted along with the River). 1181 setSelectedNode( -1 ); 1182 mSelNode = -1; 1183 1184 // SelectedRiver is a SimObjectPtr and will be NULL automatically. 1185} 1186 1187void GuiRiverEditorCtrl::setMode( String mode, bool sourceShortcut = false ) 1188{ 1189 mMode = mode; 1190 1191 if( sourceShortcut ) 1192 Con::executef( this, "paletteSync", mode ); 1193} 1194 1195void GuiRiverEditorCtrl::setSelectedRiver( River *river ) 1196{ 1197 mSelRiver = river; 1198 1199 if ( mSelRiver != NULL ) 1200 Con::executef( this, "onRiverSelected", river->getIdString() ); 1201 else 1202 Con::executef( this, "onRiverSelected" ); 1203 1204 if ( mSelRiver != river ) 1205 setSelectedNode(-1); 1206} 1207 1208void GuiRiverEditorCtrl::setNodeWidth( F32 width ) 1209{ 1210 if ( mSelRiver && mSelNode != -1 ) 1211 { 1212 mSelRiver->setNodeWidth( mSelNode, width ); 1213 mIsDirty = true; 1214 } 1215} 1216 1217F32 GuiRiverEditorCtrl::getNodeWidth() 1218{ 1219 if ( mSelRiver && mSelNode != -1 ) 1220 return mSelRiver->getNodeWidth( mSelNode ); 1221 1222 return 0.0f; 1223} 1224 1225void GuiRiverEditorCtrl::setNodeDepth(F32 depth) 1226{ 1227 if ( mSelRiver && mSelNode != -1 ) 1228 { 1229 mSelRiver->setNodeDepth( mSelNode, depth ); 1230 mIsDirty = true; 1231 } 1232} 1233 1234F32 GuiRiverEditorCtrl::getNodeDepth() 1235{ 1236 if ( mSelRiver && mSelNode != -1 ) 1237 return mSelRiver->getNodeDepth( mSelNode ); 1238 1239 return 0.0f; 1240} 1241 1242void GuiRiverEditorCtrl::setNodePosition(const Point3F& pos) 1243{ 1244 if ( mSelRiver && mSelNode != -1 ) 1245 { 1246 mSelRiver->setNodePosition( mSelNode, pos ); 1247 mIsDirty = true; 1248 } 1249} 1250 1251Point3F GuiRiverEditorCtrl::getNodePosition() 1252{ 1253 if ( mSelRiver && mSelNode != -1 ) 1254 return mSelRiver->getNodePosition( mSelNode ); 1255 1256 return Point3F( 0, 0, 0 ); 1257} 1258 1259void GuiRiverEditorCtrl::setNodeNormal( const VectorF &normal ) 1260{ 1261 if ( mSelRiver && mSelNode != -1 ) 1262 { 1263 mSelRiver->setNodeNormal( mSelNode, normal ); 1264 mIsDirty = true; 1265 } 1266} 1267 1268VectorF GuiRiverEditorCtrl::getNodeNormal() 1269{ 1270 if ( mSelRiver && mSelNode != -1 ) 1271 return mSelRiver->getNodeNormal( mSelNode ); 1272 1273 return VectorF::Zero; 1274} 1275 1276void GuiRiverEditorCtrl::setSelectedNode( S32 node ) 1277{ 1278 //if ( mSelNode == node ) 1279 // return; 1280 1281 mSelNode = node; 1282 if ( mSelNode != -1 ) 1283 { 1284 const RiverNode &curNode = mSelRiver->mNodes[mSelNode]; 1285 1286 MatrixF objMat = mSelRiver->getNodeTransform(mSelNode); 1287 Point3F objScale(curNode.width, 1.0f, curNode.depth ); 1288 Point3F worldPos = curNode.point; 1289 1290 mGizmo->set( objMat, worldPos, objScale ); 1291 } 1292 1293 if ( mSelNode != -1 ) 1294 Con::executef( this, "onNodeSelected", Con::getIntArg(mSelNode) ); 1295 else 1296 Con::executef( this, "onNodeSelected", Con::getIntArg(-1) ); 1297} 1298 1299void GuiRiverEditorCtrl::submitUndo( const UTF8 *name ) 1300{ 1301 // Grab the mission editor undo manager. 1302 UndoManager *undoMan = NULL; 1303 if ( !Sim::findObject( "EUndoManager", undoMan ) ) 1304 { 1305 Con::errorf( "GuiRiverEditorCtrl::submitUndo() - EUndoManager not found!" ); 1306 return; 1307 } 1308 1309 // Setup the action. 1310 GuiRiverEditorUndoAction *action = new GuiRiverEditorUndoAction( name ); 1311 1312 action->mObjId = mSelRiver->getId(); 1313 action->mMetersPerSegment = mSelRiver->mMetersPerSegment; 1314 action->mSegmentsPerBatch = mSelRiver->mSegmentsPerBatch; 1315 action->mRiverEditor = this; 1316 1317 for( U32 i = 0; i < mSelRiver->mNodes.size(); i++ ) 1318 { 1319 action->mNodes.push_back( mSelRiver->mNodes[i] ); 1320 } 1321 1322 undoMan->addAction( action ); 1323} 1324 1325void GuiRiverEditorCtrl::_prepRenderImage( SceneManager* sceneGraph, const SceneRenderState* state ) 1326{ 1327 if ( isAwake() && River::smEditorOpen && mSelRiver ) 1328 { 1329 ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 1330 ri->type = RenderPassManager::RIT_Editor; 1331 ri->renderDelegate.bind( this, &GuiRiverEditorCtrl::_renderSelectedRiver ); 1332 ri->defaultKey = 100; 1333 state->getRenderPass()->addInst( ri ); 1334 } 1335} 1336 1337void GuiRiverEditorCtrl::_renderSelectedRiver( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *matInst ) 1338{ 1339 if ( !mSelRiver || !River::smEditorOpen) 1340 return; 1341 1342 GFXTransformSaver saver; 1343 1344 GFX->setStateBlock( mZEnableSB ); 1345 1346 if ( River::smShowWalls && mSelRiver->mSlices.size() > 1 ) 1347 { 1348 Point3F offset(0,0,1); 1349 1350 // Render the River volume 1351 PrimBuild::begin( GFXTriangleList, 18 * mSelRiver->mSlices.size() - 1 ); 1352 1353 for ( U32 i = 0; i < mSelRiver->mSlices.size() - 1; i++ ) 1354 { 1355 const RiverSlice &slice = mSelRiver->mSlices[i]; 1356 const RiverSlice &nextSlice = mSelRiver->mSlices[i+1]; 1357 1358 // Top face 1359 //drawer->drawQuad( slice.p0, nextSlice.p0, nextSlice.p2, slice.p2, colorRed, true ); 1360 //PrimBuild::color3i( 0, 0, 255 ); 1361 //PrimBuild::vertex3fv( slice.p0 ); 1362 //PrimBuild::vertex3fv( nextSlice.p0 ); 1363 //PrimBuild::vertex3fv( nextSlice.p2 ); 1364 //PrimBuild::vertex3fv( slice.p0 ); 1365 //PrimBuild::vertex3fv( nextSlice.p2 ); 1366 //PrimBuild::vertex3fv( slice.p2 ); 1367 1368 // Bottom face 1369 PrimBuild::color3i( 0, 255, 0 ); 1370 PrimBuild::vertex3fv( slice.pb0 ); 1371 PrimBuild::vertex3fv( nextSlice.pb0 ); 1372 PrimBuild::vertex3fv( nextSlice.pb2 ); 1373 PrimBuild::vertex3fv( slice.pb0 ); 1374 PrimBuild::vertex3fv( nextSlice.pb2 ); 1375 PrimBuild::vertex3fv( slice.pb2 ); 1376 1377 // Left face 1378 PrimBuild::color3i( 255, 0, 0 ); 1379 PrimBuild::vertex3fv( slice.pb0 ); 1380 PrimBuild::vertex3fv( nextSlice.pb0 ); 1381 PrimBuild::vertex3fv( nextSlice.p0 ); 1382 PrimBuild::vertex3fv( slice.pb0 ); 1383 PrimBuild::vertex3fv( nextSlice.p0 ); 1384 PrimBuild::vertex3fv( slice.p0 ); 1385 1386 // Right face 1387 PrimBuild::color3i( 255, 0, 0 ); 1388 PrimBuild::vertex3fv( slice.p2 ); 1389 PrimBuild::vertex3fv( nextSlice.p2 ); 1390 PrimBuild::vertex3fv( nextSlice.pb2 ); 1391 PrimBuild::vertex3fv( slice.p2 ); 1392 PrimBuild::vertex3fv( nextSlice.pb2 ); 1393 PrimBuild::vertex3fv( slice.pb2 ); 1394 } 1395 1396 PrimBuild::end(); 1397 } 1398} 1399 1400DefineEngineMethod( GuiRiverEditorCtrl, deleteNode, void, (), , "deleteNode()" ) 1401{ 1402 object->deleteSelectedNode(); 1403} 1404 1405DefineEngineMethod( GuiRiverEditorCtrl, getMode, const char*, (), , "" ) 1406{ 1407 return object->getMode(); 1408} 1409 1410DefineEngineMethod( GuiRiverEditorCtrl, setMode, void, ( const char * mode ), , "setMode( String mode )" ) 1411{ 1412 String newMode = ( mode ); 1413 object->setMode( newMode ); 1414} 1415 1416DefineEngineMethod( GuiRiverEditorCtrl, getNodeWidth, F32, (), , "" ) 1417{ 1418 return object->getNodeWidth(); 1419} 1420 1421DefineEngineMethod( GuiRiverEditorCtrl, setNodeWidth, void, ( F32 width ), , "" ) 1422{ 1423 object->setNodeWidth( width ); 1424} 1425 1426DefineEngineMethod( GuiRiverEditorCtrl, getNodeDepth, F32, (), , "" ) 1427{ 1428 return object->getNodeDepth(); 1429} 1430 1431DefineEngineMethod( GuiRiverEditorCtrl, setNodeDepth, void, ( F32 depth ), , "" ) 1432{ 1433 object->setNodeDepth( depth ); 1434} 1435 1436DefineEngineMethod( GuiRiverEditorCtrl, getNodePosition, Point3F, (), , "" ) 1437{ 1438 1439 return object->getNodePosition(); 1440} 1441 1442DefineEngineMethod( GuiRiverEditorCtrl, setNodePosition, void, (Point3F pos), , "" ) 1443{ 1444 object->setNodePosition( pos ); 1445} 1446 1447DefineEngineMethod( GuiRiverEditorCtrl, getNodeNormal, Point3F, (), , "" ) 1448{ 1449 1450 return object->getNodeNormal(); 1451} 1452 1453DefineEngineMethod( GuiRiverEditorCtrl, setNodeNormal, void, (Point3F normal), , "" ) 1454{ 1455 1456 object->setNodeNormal( normal ); 1457} 1458 1459DefineEngineMethod( GuiRiverEditorCtrl, setSelectedRiver, void, (const char * objName), (""), "" ) 1460{ 1461 if (String::compare( objName,"" )==0) 1462 object->setSelectedRiver(NULL); 1463 else 1464 { 1465 River *river = NULL; 1466 if ( Sim::findObject( objName, river ) ) 1467 object->setSelectedRiver(river); 1468 } 1469} 1470 1471DefineEngineMethod( GuiRiverEditorCtrl, getSelectedRiver, S32, (), , "" ) 1472{ 1473 River *river = object->getSelectedRiver(); 1474 if ( !river ) 1475 return NULL; 1476 1477 return river->getId(); 1478} 1479 1480DefineEngineMethod( GuiRiverEditorCtrl, regenerate, void, (), , "" ) 1481{ 1482 River *river = object->getSelectedRiver(); 1483 if ( river ) 1484 river->regenerate(); 1485} 1486