Posted By

xterminhate on 03/05/13


Tagged

CGUIDynamicGrid


Versions (?)

CGUIDynamicGrid.cpp


 / Published in: C++
 

URL: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=9&t=48291&p=278332#p278332

http://irrlicht.sourceforge.net/forum/viewtopic.php?f=9&t=48291&p=278332#p278332

  1. // Xterm-in'Hate
  2.  
  3. //#ifdef _IRR_COMPILE_WITH_GUI_
  4.  
  5. #include "CGUIDynamicGrid.h"
  6. #include "IVideoDriver.h"
  7.  
  8. namespace irr
  9. {
  10. namespace gui
  11. {
  12.  
  13. //! constructor
  14. CGUIDynamicGrid::CGUIDynamicGrid(IGUIEnvironment* environment, IGUIElement* parent)
  15. : IGUIDynamicGrid( environment, parent ), isJointVisible( false ), Behavior(EGDGB_RESET)
  16. {
  17. #ifdef _DEBUG
  18. setDebugName("CGUIDynamicGrid");
  19. #endif
  20. }
  21.  
  22. //! destructor
  23. CGUIDynamicGrid::~CGUIDynamicGrid()
  24. {
  25. reset();
  26. }
  27.  
  28. void CGUIDynamicGrid::setJointVisible(bool visible)
  29. {
  30. isJointVisible = visible;
  31. }
  32.  
  33. void CGUIDynamicGrid::setBehavior(EGUI_DYNAMIC_GRID_BEHAVIOR behavior)
  34. {
  35. switch(Behavior)
  36. {
  37. case EGDGB_RESET:
  38. {
  39. if( behavior != EGDGB_RESET )
  40. {
  41. // init bones and jonts based on child GUI elements
  42. init();
  43. // then change behavior
  44. Behavior = behavior;
  45. }
  46. }
  47. break;
  48. case EGDGB_ATTACH_RUN_ONCE:
  49. {
  50. if( behavior == EGDGB_RESET )
  51. reset();
  52. // change behavior
  53. tryToAttachAll();
  54. Behavior = behavior;
  55. }
  56. break;
  57. case EGDGB_ATTACH_FOCUSED:
  58. {
  59. if( behavior == EGDGB_RESET )
  60. reset();
  61. // change behavior
  62. Behavior = behavior;
  63. }
  64. break;
  65. case EGDGB_RUN:
  66. {
  67. if( behavior == EGDGB_RESET )
  68. reset();
  69. // change behavior
  70. Behavior = behavior;
  71. }
  72. break;
  73. case EGDGB_DETACH_FOCUSED:
  74. {
  75. if( behavior == EGDGB_RESET )
  76. reset();
  77. // change behavior
  78. Behavior = behavior;
  79. }
  80. break;
  81. case EGDGB_DETACH_ALL:
  82. {
  83. if( behavior == EGDGB_RESET )
  84. reset();
  85. // change behavior
  86. Behavior = behavior;
  87. }
  88. break;
  89. }
  90. }
  91.  
  92. EGUI_DYNAMIC_GRID_BEHAVIOR CGUIDynamicGrid::getBehavior() const
  93. {
  94. return Behavior;
  95. }
  96.  
  97. void CGUIDynamicGrid::draw()
  98. {
  99. // update the size of the grid element (all screen)
  100. const core::rect<s32>& rect = Parent->getAbsolutePosition();
  101. DesiredRect = core::rect<s32>(0,0,rect.getWidth(),rect.getHeight());
  102. recalculateAbsolutePosition(true);
  103.  
  104. // apply dynamic grid algorithm
  105. snap(); // find a better place not to decrease FPS
  106.  
  107. if (!IsVisible)
  108. return;
  109.  
  110. if (isJointVisible)
  111. {
  112. video::IVideoDriver * driver = Environment->getVideoDriver();
  113. IGUISkin * skin = Environment->getSkin();
  114. core::list<bone*>::ConstIterator itb = Bones.begin();
  115. for (; itb != Bones.end(); ++itb)
  116. {
  117. for (size_t index = 0; index != joint::EJT_MAX; ++index)
  118. {
  119. const video::SColor color(255,0,255,0);
  120. const core::rect<s32> drawrect( rect.UpperLeftCorner + (*itb)->getJoint(index)->getPosition() - core::position2di(4,4),
  121. rect.UpperLeftCorner + (*itb)->getJoint(index)->getPosition() + core::position2di(4,4) );
  122. if ( (*itb)->getJoint(index)->isAttached() )
  123. {
  124. driver->draw2DRectangle(color, drawrect);
  125. }
  126. else
  127. {
  128. driver->draw2DRectangleOutline(drawrect,skin->getColor(EGDC_3D_SHADOW));
  129. }
  130. }
  131. }
  132. }
  133.  
  134. IGUIElement::draw();
  135. }
  136.  
  137. void CGUIDynamicGrid::init()
  138. {
  139. reset();
  140.  
  141. // create a bone per child element
  142. core::list<IGUIElement*>::ConstIterator ite = Children.begin();
  143. for (; ite != Children.end(); ++ite)
  144. {
  145. Bones.push_back( new bone( (*ite) ) );
  146. }
  147. }
  148.  
  149. void CGUIDynamicGrid::reset()
  150. {
  151. // delete all bones
  152. core::list<bone*>::Iterator itb = Bones.begin();
  153. for (; itb != Bones.end(); ++itb)
  154. {
  155. delete (*itb);
  156. }
  157. Bones.clear();
  158. }
  159.  
  160. void CGUIDynamicGrid::snap()
  161. {
  162. static u32 counter = 1; ///< 1 : because every bones and joints are initialzed with a null counter.
  163. switch(Behavior)
  164. {
  165. case EGDGB_RESET:
  166. {
  167.  
  168. }
  169. break;
  170. case EGDGB_ATTACH_RUN_ONCE:
  171. {
  172. tryToAttachAll();
  173. Behavior = EGDGB_RUN;
  174. }
  175. break;
  176. case EGDGB_ATTACH_FOCUSED:
  177. {
  178. IGUIElement* focused = Environment->getFocus();
  179. if ( focused )
  180. {
  181. bone* b;
  182. if ( hasBone(focused,b) )
  183. {
  184. b->update(counter);
  185. tryToAttach( b );
  186. ++counter;
  187. }
  188. }
  189. }
  190. break;
  191. case EGDGB_RUN:
  192. {
  193. IGUIElement* focused = Environment->getFocus();
  194. if ( focused )
  195. {
  196. bone* b;
  197. if ( hasBone(focused,b) )
  198. {
  199. b->update(counter);
  200. ++counter;
  201. }
  202. }
  203. }
  204. break;
  205. case EGDGB_DETACH_FOCUSED:
  206. {
  207. IGUIElement* focused = Environment->getFocus();
  208. if ( focused )
  209. {
  210. bone* b;
  211. if ( hasBone(focused,b) )
  212. {
  213. b->update(counter);
  214. b->dettach();
  215. ++counter;
  216. }
  217. }
  218. }
  219. break;
  220. case EGDGB_DETACH_ALL:
  221. {
  222. dettachAll();
  223. Behavior = EGDGB_RUN;
  224. }
  225. break;
  226. }
  227. }
  228.  
  229. void CGUIDynamicGrid::tryToAttach(bone* b)
  230. {
  231. core::list<bone*>::ConstIterator itb = Bones.begin();
  232. for (; itb != Bones.end(); ++itb)
  233. {
  234. // don't attach to itself
  235. if ( (*itb) == b || (*itb)->isAttachedToBone(b) )
  236. continue;
  237.  
  238. // a pair of joints...
  239. size_t j1, j2;
  240. if (b->canAttachToBone((*itb),j1,j2 ))
  241. {
  242. if( ! b->isRectCollidedBody( (*itb)))
  243. {
  244. b->attachToBone((*itb),j1,j2);
  245. b->consolidate();
  246. }
  247. }
  248. }
  249. }
  250.  
  251. void CGUIDynamicGrid::tryToAttachAll()
  252. {
  253. core::list<bone*>::ConstIterator itb = Bones.begin();
  254. for (; itb != Bones.end(); ++itb)
  255. {
  256. tryToAttach( (*itb) );
  257. }
  258. }
  259.  
  260. void CGUIDynamicGrid::dettachAll()
  261. {
  262. core::list<bone*>::ConstIterator itb = Bones.begin();
  263. for (; itb != Bones.end(); ++itb)
  264. {
  265. (*itb)->dettach();
  266. }
  267. }
  268.  
  269. CGUIDynamicGrid::bone* CGUIDynamicGrid::getBone(IGUIElement* element)
  270. {
  271. core::list<bone*>::ConstIterator itb = Bones.begin();
  272. for (; itb != Bones.end(); ++itb)
  273. {
  274. if ( (*itb)->own(element) )
  275. return (*itb);
  276. }
  277. return 0;
  278. }
  279.  
  280. bool CGUIDynamicGrid::hasBone(const IGUIElement* element, bone*& b) const
  281. {
  282. core::list<bone*>::ConstIterator itb = Bones.begin();
  283. for (; itb != Bones.end(); ++itb)
  284. {
  285. if ( (*itb)->own(element) )
  286. {
  287. b = (*itb);
  288. return true;
  289. }
  290. }
  291. return false;
  292. }
  293.  
  294. /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  295.  
  296. CGUIDynamicGrid::bone::bone(IGUIElement* element) :
  297. Element(element), Counter(0)
  298. {
  299. // create 8 joints per element (two at each corner)
  300. const core::rect<s32>& rect = Element->getRelativePosition();
  301. for (size_t index = 0; index != joint::EJT_MAX; ++index)
  302. {
  303. Joints[index] = new joint( (joint::EJOINT_TYPE)index, this, rect );
  304. }
  305. }
  306.  
  307. CGUIDynamicGrid::bone::~bone()
  308. {
  309. // delete all joints
  310. for (size_t index = 0; index != joint::EJT_MAX; ++index)
  311. {
  312. delete Joints[index];
  313. }
  314. }
  315.  
  316. CGUIDynamicGrid::joint* CGUIDynamicGrid::bone::getJoint(size_t index) const
  317. {
  318. return Joints[index];
  319. }
  320.  
  321. bool CGUIDynamicGrid::bone::own(const IGUIElement* element) const
  322. {
  323. return Element == element;
  324. }
  325.  
  326. bool CGUIDynamicGrid::bone::canAttachToBone(const bone* b, size_t& j1, size_t& j2) const
  327. {
  328. for (size_t index1=0; index1 != joint::EJT_MAX; ++index1)
  329. {
  330. if ( ! Joints[index1]->isAttached() )
  331. {
  332. for (size_t index2 = 0; index2 != joint::EJT_MAX; ++index2)
  333. {
  334. if (Joints[index1]->canAttachToJoint(b->getJoint(index2)))
  335. {
  336. j1 = index1;
  337. j2 = index2;
  338. return true;
  339. }
  340. }
  341. }
  342. };
  343. return false;
  344. }
  345.  
  346. void CGUIDynamicGrid::bone::attachToBone(bone* b, size_t j1, size_t j2)
  347. {
  348. Joints[j1]->attachToJoint(b->getJoint(j2));
  349. }
  350.  
  351.  
  352. void CGUIDynamicGrid::bone::dettach()
  353. {
  354. for (size_t index = 0; index != joint::EJT_MAX; ++index)
  355. {
  356. Joints[index]->dettach();
  357. }
  358. }
  359.  
  360. bool CGUIDynamicGrid::bone::isAttachedToBone(const bone* b) const
  361. {
  362. for (size_t index = 0; index != joint::EJT_MAX; ++index)
  363. {
  364. if (Joints[index]->isAttachedToBone(b))
  365. return true;
  366. }
  367. return false;
  368. }
  369.  
  370. // I have to do it recursively
  371. bool CGUIDynamicGrid::bone::isRectCollidedBodyRecursive(const CGUIDynamicGrid::bone* b, const core::rect<s32>& rect, core::list<const bone*>& body_bones_processed)
  372. {
  373. // check current bone
  374. if ( b->getElement()->getRelativePosition().isRectCollided( rect ) || b->getElement()->getRelativePosition() == rect )
  375. return true;
  376. // dont process twice this bone
  377. body_bones_processed.push_back(b);
  378. // process every attached bone, except those already processed
  379. for (size_t index = 0; index != joint::EJT_MAX; ++index)
  380. {
  381. if( b->getJoint(index)->isAttached() )
  382. {
  383. const bone* next = b->getJoint(index)->getAttachedBone();
  384. if( core::find( body_bones_processed.begin(), body_bones_processed.end(), next) == body_bones_processed.end() )
  385. {
  386. if ( isRectCollidedBodyRecursive( next, rect, body_bones_processed ) )
  387. {
  388. return true;
  389. }
  390. }
  391.  
  392. }
  393. }
  394. return false;
  395. }
  396.  
  397. void CGUIDynamicGrid::bone::listBonesRecursive(const bone* b,core::list<const bone*>& body_bones)
  398. {
  399. if( core::find( body_bones.begin(), body_bones.end(), b) == body_bones.end() )
  400. {
  401. body_bones.push_back(b);
  402. for (size_t index = 0; index != joint::EJT_MAX; ++index)
  403. {
  404. if( b->getJoint(index)->isAttached() )
  405. {
  406. const bone* next = b->getJoint(index)->getAttachedBone();
  407. listBonesRecursive(next,body_bones);
  408. }
  409. }
  410. }
  411. }
  412.  
  413. void CGUIDynamicGrid::bone::listBonesRecursive(bone* b,core::list<bone*>& body_bones)
  414. {
  415. if( core::find( body_bones.begin(), body_bones.end(), b) == body_bones.end() )
  416. {
  417. body_bones.push_back(b);
  418. for (size_t index = 0; index != joint::EJT_MAX; ++index)
  419. {
  420. if( b->getJoint(index)->isAttached() )
  421. {
  422. bone* next = b->getJoint(index)->getAttachedBone();
  423. listBonesRecursive(next,body_bones);
  424. }
  425. }
  426. }
  427. }
  428.  
  429. bool CGUIDynamicGrid::bone::isRectCollidedBody(const bone* b) const
  430. {
  431. core::list<const bone*> body_bones;
  432. listBonesRecursive(this,body_bones);
  433. core::list<const bone*>::ConstIterator itb = body_bones.begin();
  434. for (; itb != body_bones.end(); ++itb)
  435. {
  436. core::rect<s32> rect = (*itb)->getElement()->getRelativePosition();
  437. core::list<const bone*> body_bones_processed;
  438. if( (*itb)->isRectCollidedBodyRecursive(b,rect,body_bones_processed) )
  439. return true; // exit at once if collision detected
  440. }
  441. return false; // no collision
  442. }
  443.  
  444. ///! Attach together every bones of the body identified by THIS bone, by as many joints as possible
  445. void CGUIDynamicGrid::bone::consolidate()
  446. {
  447. /// \todo try to attach together each bone of one body, starting from this bone
  448. core::list<bone*> body_bones;
  449. listBonesRecursive(this,body_bones);
  450. core::list<bone*>::Iterator itb1 = body_bones.begin();
  451. for (; itb1 != body_bones.end(); ++itb1)
  452. {
  453. core::list<bone*>::Iterator itb2 = itb1+1;
  454. for (; itb2 != body_bones.end(); ++itb2)
  455. {
  456. // don't attach to itself
  457. if ( (*itb1) == (*itb2) )
  458. continue;
  459. // a pair of joints...
  460. (*itb2)->attachToBoneByAllPossibleJoints((*itb1));
  461. }
  462. }
  463. }
  464.  
  465. ///! Attach bones THIS and B with as many joint as possible
  466. void CGUIDynamicGrid::bone::attachToBoneByAllPossibleJoints(bone* b)
  467. {
  468. for (size_t index1 = 0; index1 != joint::EJT_MAX; ++index1)
  469. {
  470. if ( ! Joints[index1]->isAttached() )
  471. {
  472. for (size_t index2 = 0; index2 != joint::EJT_MAX; ++index2)
  473. {
  474. if( Joints[index1]->canAttachToJoint(b->getJoint(index2) ) )
  475. {
  476. Joints[index1]->attachToJoint(b->getJoint(index2));
  477. }
  478. }
  479. }
  480. }
  481. }
  482.  
  483. const IGUIElement* CGUIDynamicGrid::bone::getElement() const
  484. {
  485. return Element;
  486. }
  487.  
  488. void CGUIDynamicGrid::bone::update(u32 counter, const core::position2di& dist)
  489. {
  490. if (Counter != counter)
  491. {
  492. Counter = counter;
  493. Element->move( dist );
  494. const core::rect<s32>& rect = Element->getRelativePosition();
  495. for (size_t index = 0; index != joint::EJT_MAX; ++index )
  496. {
  497. Joints[index]->update(counter,rect);
  498. };
  499. }
  500. }
  501.  
  502. /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  503.  
  504. CGUIDynamicGrid::joint::joint(EJOINT_TYPE type, bone* parent_bone, const core::rect<s32>& rectangle) :
  505. Type( type ), ParentBone(parent_bone), AttachedJoint(0), Counter(0)
  506. {
  507. switch(Type)
  508. {
  509. case EJT_UPPER_RIGHT_TO_TOP:
  510. case EJT_UPPER_RIGHT_TO_RIGHT:
  511. Position = core::position2di( rectangle.LowerRightCorner.X, rectangle.UpperLeftCorner.Y );
  512. break;
  513. case EJT_LOWER_RIGHT_TO_RIGHT:
  514. case EJT_LOWER_RIGHT_TO_BOTTOM:
  515. Position = rectangle.LowerRightCorner;
  516. break;
  517. case EJT_LOWER_LEFT_TO_BOTTOM:
  518. case EJT_LOWER_LEFT_TO_LEFT:
  519. Position = core::position2di( rectangle.UpperLeftCorner.X, rectangle.LowerRightCorner.Y );
  520. break;
  521. case EJT_UPPER_LEFT_TO_LEFT:
  522. case EJT_UPPER_LEFT_TO_TOP:
  523. Position = rectangle.UpperLeftCorner;
  524. break;
  525. }
  526. }
  527.  
  528. CGUIDynamicGrid::joint::~joint()
  529. {
  530. // detach joint
  531. if ( AttachedJoint != 0 )
  532. AttachedJoint->AttachedJoint = 0;
  533. }
  534.  
  535. const core::position2di & CGUIDynamicGrid::joint::getPosition() const
  536. {
  537. return Position;
  538. }
  539.  
  540. CGUIDynamicGrid::joint::EJOINT_TYPE CGUIDynamicGrid::joint::getType() const
  541. {
  542. return Type;
  543. }
  544.  
  545. bool CGUIDynamicGrid::joint::isAttached() const
  546. {
  547. return AttachedJoint != 0;
  548. }
  549.  
  550. const bool joint_compatibility[8][8] =
  551. {
  552. { false, false, false, true, false, false, false, false }, // EJT_UPPER_RIGHT_TO_TOP
  553. { false, false, false, false, false, false, true, false }, // EJT_UPPER_RIGHT_TO_RIGHT
  554. { false, false, false, false, false, true, false, false }, // EJT_LOWER_RIGHT_TO_RIGHT
  555. { true, false, false, false, false, false, false, false }, // EJT_LOWER_RIGHT_TO_BOTTOM
  556. { false, false, false, false, false, false, false, true }, // EJT_LOWER_LEFT_TO_BOTTOM
  557. { false, false, true, false, false, false, false, false }, // EJT_LOWER_LEFT_TO_LEFT
  558. { false, true, false, false, false, false, false, false }, // EJT_UPPER_LEFT_TO_LEFT
  559. { false, false, false, false, true, false, false, false } // EJT_UPPER_LEFT_TO_TOP
  560. };
  561.  
  562. bool CGUIDynamicGrid::joint::canAttachToJoint(const joint* j) const
  563. {
  564. return joint_compatibility[Type][j->getType()] && ( Position.getDistanceFrom( j->getPosition() ) < 4 ); ///< Distance between two 'attachable' joint
  565. }
  566.  
  567. void CGUIDynamicGrid::joint::attachToJoint(joint* j)
  568. {
  569. AttachedJoint = j;
  570. j->AttachedJoint = this;
  571. }
  572.  
  573. void CGUIDynamicGrid::joint::dettach()
  574. {
  575. if( isAttached() )
  576. {
  577. // mutually detach joints
  578. AttachedJoint->AttachedJoint = 0;
  579. AttachedJoint = 0;
  580. }
  581. }
  582.  
  583. bool CGUIDynamicGrid::joint::isAttachedToBone(const bone* b) const
  584. {
  585. if( !isAttached() )
  586. return false;
  587.  
  588. return AttachedJoint->ParentBone == b;
  589. }
  590.  
  591. CGUIDynamicGrid::bone* CGUIDynamicGrid::joint::getAttachedBone() const
  592. {
  593. return AttachedJoint->ParentBone;
  594. }
  595.  
  596. void CGUIDynamicGrid::joint::update(u32 counter, const core::rect<s32>& rectangle)
  597. {
  598. if ( Counter != counter )
  599. {
  600. Counter = counter;
  601. switch(Type)
  602. {
  603. case EJT_UPPER_RIGHT_TO_TOP:
  604. case EJT_UPPER_RIGHT_TO_RIGHT:
  605. Position = core::position2di( rectangle.LowerRightCorner.X, rectangle.UpperLeftCorner.Y );
  606. break;
  607. case EJT_LOWER_RIGHT_TO_RIGHT:
  608. case EJT_LOWER_RIGHT_TO_BOTTOM:
  609. Position = rectangle.LowerRightCorner;
  610. break;
  611. case EJT_LOWER_LEFT_TO_BOTTOM:
  612. case EJT_LOWER_LEFT_TO_LEFT:
  613. Position = core::position2di( rectangle.UpperLeftCorner.X, rectangle.LowerRightCorner.Y );
  614. break;
  615. case EJT_UPPER_LEFT_TO_LEFT:
  616. case EJT_UPPER_LEFT_TO_TOP:
  617. Position = rectangle.UpperLeftCorner;
  618. break;
  619. }
  620. if ( AttachedJoint != 0 )
  621. {
  622. AttachedJoint->dragTo(counter,Position);
  623. }
  624. }
  625. }
  626.  
  627. void CGUIDynamicGrid::joint::dragTo(u32 counter, const core::position2di& position)
  628. {
  629. if (Counter != counter)
  630. {
  631. Counter = counter;
  632. const core::vector2di dist(position-Position);
  633. Position = position;
  634. ParentBone->update(counter,dist);
  635. }
  636. }
  637.  
  638. // xterminahte > if you have understood this code until this point, please, phone me and tell me how it is possible this is working not too bad ? ;-)
  639.  
  640. } // end namespace gui
  641. } // end namespace irr
  642.  
  643. //#endif // _IRR_COMPILE_WITH_GUI_

Report this snippet  

You need to login to post a comment.