Merge branch '138-toggle-free-look-with-hotkey' into main/gingo-test
[ryzomcore.git] / ryzom / client / src / r2 / displayer_visual_group.cpp
blobba7249fd9e2bc6a56688084cefddd50a1d948db9
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdpch.h"
23 #include "nel/misc/line.h"
24 #include "nel/3d/u_bone.h"
26 #include "nel/3d/u_landscape.h"
28 #include "nel/3d/zone.h"
30 #include "displayer_visual_group.h"
31 #include "r2_config.h"
32 #include "instance.h"
33 #include "editor.h"
34 #include "tool_draw_prim.h"
36 #include "../entity_cl.h"
37 #include "../global.h"
38 #include "../misc.h"
39 #include "../landscape_poly_drawer.h"
40 #include "nel/gui/ctrl_polygon.h"
41 #include "nel/gui/ctrl_quad.h"
42 #include "../time_client.h"
45 #ifdef DEBUG_NEW
46 #define new DEBUG_NEW
47 #endif
49 class CGroupMap;
51 using namespace R2;
52 using namespace std;
53 using namespace NLMISC;
54 using namespace NL3D;
56 extern ULandscape *Landscape;
58 namespace R2
61 // create a special selectable polygon
62 class CCtrlPolygonSelectable : public CCtrlPolygon, public IDisplayerUIHandle
64 public:
65 CCtrlPolygonSelectable( CViewBase::TCtorParam &param, CInstance &instance) : CCtrlPolygon(param), Instance(instance) {}
66 // from IDisplayerUIHandle
67 virtual CInstance &getDisplayedInstance() { return Instance; }
68 // from IDisplayerUIHandle
69 virtual bool contains(sint32 mouseXInWindow, sint32 mouseYInWindow) const
71 if (!_Parent) return false;
73 // relies on parent class CViewPolygon::contains
74 return CCtrlPolygon::contains(CVector2f(mouseXInWindow + 0.5f, mouseYInWindow + 0.5f));
76 // tooltip
77 virtual void getContextHelp(std::string &help) const
79 help = Instance.getDisplayName().toUtf8();
80 if (help == NLMISC::CI18N::get("uiR2EDNoName"))
81 help.clear();
83 bool emptyContextHelp() const { return true; }
84 bool wantInstantContextHelp() const { return true; }
85 // from CCtrlBase
86 virtual bool preciseHitTest(sint32 x, sint32 y) const
88 if (!_Parent) return false;
89 sint32 winX, winY;
90 _Parent->getCorner(winX, winY, _ParentPosRef);
91 return contains(x - winX, y - winY);
93 public:
94 CInstance &Instance;
95 protected:
96 // TMP TMP until matrix precision is solved
97 // from CCtrlPolygon
98 void computeScaledVertex(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src)
100 CGroupMap *gm = CTool::getWorldMap();
101 if (!gm) dest = CVector::Null;
102 else gm->worldToWindow(dest, src);
106 // create a special selectable polygon
107 class CCtrlQuadSelectable : public CCtrlQuad, public IDisplayerUIHandle
109 public:
110 CCtrlQuadSelectable( CViewBase::TCtorParam &param, CInstance &instance, uint edgeIndex) : CCtrlQuad(param), Instance(instance), EdgeIndex(edgeIndex) {}
111 // from IDisplayerUIHandle
112 virtual CInstance &getDisplayedInstance() { return Instance; }
113 // from IDisplayerUIHandle
114 virtual bool isEdge() const { return true; }
115 // from IDisplayerUIHandle
116 virtual uint getEdgeIndex() const { return EdgeIndex; }
117 // from IDisplayerUIHandle
118 virtual bool contains(sint32 mouseXInWindow, sint32 mouseYInWindow) const
120 if (!_Parent) return false;
122 // relies on parent class CViewPolygon::contains
123 return CCtrlQuad::contains(CVector2f(mouseXInWindow + 0.5f, mouseYInWindow + 0.5f));
125 // tooltip
126 virtual void getContextHelp(std::string &help) const
128 help = Instance.getDisplayName().toUtf8();
129 if (help == NLMISC::CI18N::get("uiR2EDNoName"))
130 help.clear();
132 bool emptyContextHelp() const { return true; }
133 bool wantInstantContextHelp() const { return true; }
134 // from CCtrlBase
135 virtual bool preciseHitTest(sint32 x, sint32 y) const
137 if (!_Parent) return false;
138 sint32 winX, winY;
139 _Parent->getCorner(winX, winY, _ParentPosRef);
140 return contains(x - winX, y - winY);
142 virtual bool handleEvent (const NLGUI::CEventDescriptor &/* event */)
144 return false;
146 public:
147 CInstance &Instance;
148 uint EdgeIndex;
153 // *********************************************************************************************************
154 CDisplayerVisualGroup::CDisplayerVisualGroup()
156 _ArrayName = "Components";
157 _DrawnThisFrame = false;
158 _TimeOver = 0;
159 _CurrPrimValid = true;
160 touch();
161 _Active = false;
162 _CurrPrimInaccessible = false;
163 _ContextualVisibilityActive = false;
164 _ContextualVisibilityDate = -1;
165 _VisibleLastFrame = false;
168 // *********************************************************************************************************
169 void CDisplayerVisualGroup::touch()
171 //H_AUTO(R2_CDisplayerVisualGroup_touch)
172 _PrimTouched = true;
173 _InstanceListTouched = true;
174 _AccessibilityTouched = true;
177 // *********************************************************************************************************
178 void CDisplayerVisualGroup::setDisplayedInstance(CInstance *instance)
180 //H_AUTO(R2_CDisplayerVisualGroup_setDisplayedInstance)
181 CDisplayerVisual::setDisplayedInstance(instance);
182 _Prim.DisplayedInstance = instance;
185 // *********************************************************************************************************
186 CCtrlPolygon *CDisplayerVisualGroup::CSelectablePrimRender::newCtrlPolygon() const
188 //H_AUTO(R2_CDisplayerVisualGroup_CSelectablePrimRender)
189 nlassert(DisplayedInstance);
190 CViewBase::TCtorParam param;
191 CCtrlPolygonSelectable *result = new CCtrlPolygonSelectable( param, *DisplayedInstance);
192 result->setId(DisplayedInstance->getId());
193 result->setToolTipParent(CCtrlBase::TTMouse);
194 result->setToolTipParentPosRef(Hotspot_BR);
195 result->setToolTipPosRef(Hotspot_TL);
196 return result;
199 // *********************************************************************************************************
200 CCtrlQuad *CDisplayerVisualGroup::CSelectablePrimRender::newCtrlQuad(uint edgeIndex) const
202 //H_AUTO(R2_CDisplayerVisualGroup_CSelectablePrimRender)
203 nlassert(DisplayedInstance);
204 CViewBase::TCtorParam param;
205 CCtrlQuadSelectable *result = new CCtrlQuadSelectable( param, *DisplayedInstance, edgeIndex);
206 result->setToolTipParent(CCtrlBase::TTMouse);
207 result->setToolTipParentPosRef(Hotspot_BR);
208 result->setToolTipPosRef(Hotspot_TL);
209 return result;
212 // *********************************************************************************************************
213 bool CDisplayerVisualGroup::init(const CLuaObject &parameters)
215 //H_AUTO(R2_CDisplayerVisualGroup_init)
216 CDisplayerVisual::init(parameters);
217 if (parameters["Look"].isTable())
219 _PrimLook.init(parameters["Look"]);
221 if (parameters["InvalidLook"].isTable())
223 _PrimLookInvalid.init(parameters["InvalidLook"]);
225 else
227 _PrimLookInvalid = _PrimLook;
229 _Prim.setLook(_PrimLook);
230 if (parameters["ArrayName"].isString())
232 _ArrayName = parameters["ArrayName"].toString();
234 // look for inaccessible parts (hardcoded for now)
235 CPrimLook inaccessibleLook;
236 inaccessibleLook.init(getEditor().getEnv()["PrimRender"]["RoadLookInaccessible"]);
237 inaccessibleLook.Shape = _PrimLook.Shape;
238 _InaccessiblePrim.setLook(inaccessibleLook);
240 // meshs
241 //_Links.setShapeName(parameters["ShapeName"].toString());
242 // decals
243 return true;
246 // *********************************************************************************************************
247 CDisplayerVisualGroup::~CDisplayerVisualGroup()
253 // *********************************************************************************************************
254 void CDisplayerVisualGroup::setActive(bool active)
256 //H_AUTO(R2_CDisplayerVisualGroup_setActive)
257 if (active == _Active) return;
258 CGroupMap *worldMap = CTool::getWorldMap();
259 if (worldMap)
261 if (active)
263 if (!_Prim.isAddedToWorldMap())
265 worldMap->addDeco(&_Prim);
268 else
270 if (_Prim.isAddedToWorldMap())
272 worldMap->removeDeco(&_Prim);
274 if (_InaccessiblePrim.isAddedToWorldMap())
276 worldMap->removeDeco(&_InaccessiblePrim);
280 if (active)
282 touch();
284 else
286 _Prim.clear();
288 _Active = active;
291 // *********************************************************************************************************
292 bool CDisplayerVisualGroup::getActive() const
294 //H_AUTO(R2_CDisplayerVisualGroup_getActive)
295 return _Active;
299 // *********************************************************************************************************
300 void CDisplayerVisualGroup::onAttrModified(const std::string &attrName, sint32 attrIndex)
302 //H_AUTO(R2_CDisplayerVisualGroup_onAttrModified)
303 CDisplayerVisual::onAttrModified(attrName, attrIndex);
304 // necessary to handle this because there no event for 'element removed from table' for now ...
305 if (attrName == _ArrayName)
307 touch();
309 /*else if (attrName == "DisplayMode")
311 touch();
312 updatePrimLook();
316 // *********************************************************************************************************
317 void CDisplayerVisualGroup::setDisplayMode(sint32 mode)
319 //H_AUTO(R2_CDisplayerVisualGroup_setDisplayMode)
320 CDisplayerVisual::setDisplayMode(mode);
321 touch();
322 updatePrimLook();
325 // *********************************************************************************************************
326 void CDisplayerVisualGroup::onParentDisplayModeChanged()
328 //H_AUTO(R2_CDisplayerVisualGroup_onParentDisplayModeChanged)
329 touch();
330 updatePrimLook();
333 // *********************************************************************************************************
334 void CDisplayerVisualGroup::updateWorldPos()
336 //H_AUTO(R2_CDisplayerVisualGroup_updateWorldPos)
337 CDisplayerVisual::updateWorldPos();
338 // must update position on next display
339 _PrimTouched = true;
340 _AccessibilityTouched = true;
343 // *********************************************************************************************************
344 bool CDisplayerVisualGroup::isInProjection(const NLMISC::CVector2f &pos) const
346 if (!_DrawnThisFrame) return false;
347 if ((sint)_Prim.getLook().Shape == (sint)ClosedPolyLine)
349 // poly test
350 if (_Poly2D.contains(pos, false)) return true;
352 // test intersection with all decals
353 return _Prim.contains(pos);
356 // *********************************************************************************************************
357 bool CDisplayerVisualGroup::isInProjectionBorder(const NLMISC::CVector2f &pos) const
359 if (isOnEdge(pos) != -1)
361 return true;
363 return false;
366 // *********************************************************************************************************
367 sint CDisplayerVisualGroup::isOnEdge(const NLMISC::CVector2f &pos) const
369 return _Prim.isOnEdge(pos);
372 // *********************************************************************************************************
373 uint CDisplayerVisualGroup::getFadeTimeInMS() const
375 return (uint) CV_RegionFadeTimeInMs.get();
379 // *********************************************************************************************************
380 void CDisplayerVisualGroup::onPostRender()
382 if (!_Active ||!getActualVisibility()) return;
383 updatePrimVertices();
384 updateAccessibility();
387 // *********************************************************************************************************
388 bool CDisplayerVisualGroup::isAccessible()
390 updateAccessibility();
391 return !_CurrPrimInaccessible;
394 // *********************************************************************************************************
395 void CDisplayerVisualGroup::updateAccessibility()
397 //H_AUTO(R2_CDisplayerVisualGroup_updateAccessibility)
398 if (getEditor().getIslandCollision().getPackedIsland() != _LastIsland)
400 _AccessibilityTouched = true;
403 if (!_AccessibilityTouched) return;
404 if (!_Active)
406 // if not active, don't update the flag !!! This only is a display flag
407 // only npc group use the 'star' shape for now ...
408 _CurrPrimInaccessible = false;
409 _AccessibilityTouched = false;
410 return;
412 _LastIsland = getEditor().getIslandCollision().getPackedIsland();
413 updatePrimVertices();
414 uint numVerts = (uint)_Prim.getVertices().size();
415 _CurrPrimInaccessible = false;
416 // Old version : path should be accessible along the edges
418 if (_Prim.getLook().Shape != CPrimLook::ClosedPolyLine) -- numVerts;
419 for (uint k = 0; k < numVerts; ++k)
421 if (!getEditor().getIslandCollision().isValidSegment(_Prim.getVertices()[k], _Prim.getVertices()[(k + 1) % _Prim.getVertices().size()]))
423 _CurrPrimInaccessible = true;
424 break;
428 // New version : path should be accessible at vertices only
429 for (uint k = 0; k < numVerts; ++k)
431 if (!getEditor().getIslandCollision().isValidPos(_Prim.getVertices()[k]))
433 _CurrPrimInaccessible = true;
434 break;
437 CGroupMap *gm = CTool::getWorldMap();
438 if (gm)
440 // error: no more display of inaccessible pos
442 if (_CurrPrimInaccessible)
444 _InaccessiblePrim.setVertices(_Prim.getVertices());
445 if (!_InaccessiblePrim.isAddedToWorldMap())
447 gm->addDeco(&_InaccessiblePrim);
450 else
452 if (_InaccessiblePrim.isAddedToWorldMap())
454 gm->removeDeco(&_InaccessiblePrim);
459 updatePrimLook();
460 _AccessibilityTouched = false;
463 // *********************************************************************************************************
464 void CDisplayerVisualGroup::updatePrimVertices()
466 //H_AUTO(R2_CDisplayerVisualGroup_updatePrimVertices)
467 if (!_Active) return;
468 if (!_PrimTouched) return;
469 updateInstanceList();
471 static std::vector<NLMISC::CVector> vertices;
472 vertices.clear();
473 _Poly2D.Vertices.clear();
474 for(uint k = 0; k < _Instances.size(); ++k)
476 if (_Instances[k])
478 vertices.push_back(_Instances[k]->evalLinkPoint(k == 0 && _Prim.getLook().Shape == CPrimLook::Star));
479 _Poly2D.Vertices.push_back(CVector(vertices.back().x, vertices.back().y, 0.f));
481 else
483 nlwarning("_Instances[%d] == 0", k);
487 if (_Prim.getLook().Shape == CPrimLook::ClosedPolyLine)
489 updateBoundingBox();
492 bool valid = true;
494 // test against the collision map : all traversed opsition must be valid else poly is invalid
496 if (_PrimLook.Shape == CPrimLook::ClosedPolyLine)
498 // test concave poly against map
500 // test against water
501 #err
503 else
505 // test polyline against map
506 R2::CScenarioEntryPoints::CCompleteIsland *island = getEditor().getIslandCollision().getCurrIslandDesc();
507 const NLMISC::CArray2D<sint16> &heightMap = getEditor().getIslandCollision().getHeightMap();
508 if (getEditor().getIslandCollision().getHeightMap())
512 // test against water
513 #err
517 // if displayed on the map, set a first time to see if poly is invalid
518 if (_PrimLook.Shape == CPrimLook::ClosedPolyLine)
520 if (_Prim.getWorldMapPoly())
522 _Prim.getWorldMapPoly()->setVertices(vertices);
523 valid = _Prim.getWorldMapPoly()->isValid();
526 if (valid != _CurrPrimValid)
528 _CurrPrimValid = valid;
529 updatePrimLook();
531 _Prim.setVertices(vertices);
532 _PrimTouched = false;
535 // *********************************************************************************************************
536 void CDisplayerVisualGroup::updateBoundingBox()
538 //H_AUTO(R2_CDisplayerVisualGroup_updateBoundingBox)
539 CLandscapePolyDrawer::computeBBoxFromPolygon(_Poly2D, _BBox);
542 // *********************************************************************************************************
543 void CDisplayerVisualGroup::updatePrimLook()
545 //H_AUTO(R2_CDisplayerVisualGroup_updatePrimLook)
546 TDisplayMode displayMode = getActualDisplayMode();
547 // if contextual visibility is enabled, then see if really visible
548 if (displayMode != DisplayModeHidden && _ContextualVisibilityActive && getDisplayedInstance()->isKindOf("BasePrimitive"))
550 if (!isContextuallyVisible())
552 displayMode = DisplayModeHidden;
556 if (displayMode == DisplayModeHidden)
558 _Prim.setActive(false);
559 _InaccessiblePrim.setActive(false);
560 return;
563 _Prim.setActive(true);
564 _InaccessiblePrim.setActive(true);
566 CPrimLook &look = (_CurrPrimValid && !_CurrPrimInaccessible) ? _PrimLook : _PrimLookInvalid;
567 CRGBA oldEdgeWMCol = look.EdgeLook.WorldMapColor;
568 CRGBA oldEdgeDecalCol = look.EdgeLook.DecalColor;
569 CRGBA oldVertexWMCol = look.VertexLook.WorldMapColor;
570 CRGBA oldVertexDecalCol = look.VertexLook.DecalColor;
571 CRGBA oldFirstVertexWMCol = look.FirstVertexLook.WorldMapColor;
572 CRGBA oldFirstVertexDecalCol = look.FirstVertexLook.DecalColor;
573 CRGBA col;
574 bool newCol = false;
575 switch(displayMode)
577 case DisplayModeFrozen:
578 col = getBlinkColor(CV_MapEntityFrozenColor.get());
579 newCol = true;
580 break;
581 case DisplayModeLocked:
582 col = getBlinkColor(CV_MapEntityLockedColor.get());
583 newCol = true;
584 break;
585 default:
586 break;
588 if (getDisplayFlag(FlagSelected) && !_CurrPrimInaccessible)
590 // NB : don't want the highlight if not all parts are accessible
591 // for readability
592 col = CV_MapEntitySelectColor.get();
593 newCol = true;
595 else if (getDisplayFlag(FlagHasFocus))
597 col = CV_MapEntityHighlightColor.get();
598 newCol = true;
600 if (newCol)
602 look.EdgeLook.WorldMapColor = col;
603 look.EdgeLook.DecalColor = col;
604 look.VertexLook.WorldMapColor = col;
605 look.VertexLook.DecalColor = col;
606 look.FirstVertexLook.WorldMapColor = col;
607 look.FirstVertexLook.DecalColor = col;
609 _Prim.setLook(look);
610 if (newCol)
612 look.EdgeLook.WorldMapColor = oldEdgeWMCol;
613 look.EdgeLook.DecalColor = oldEdgeDecalCol;
614 look.VertexLook.WorldMapColor = oldVertexWMCol;
615 look.VertexLook.DecalColor = oldVertexDecalCol;
616 look.FirstVertexLook.WorldMapColor = oldFirstVertexWMCol;
617 look.FirstVertexLook.DecalColor = oldFirstVertexDecalCol;
621 // *********************************************************************************************************
622 void CDisplayerVisualGroup::onFocus(bool focused)
624 //H_AUTO(R2_CDisplayerVisualGroup_onFocus)
625 CDisplayerVisual::onFocus(focused);
626 updatePrimLook();
629 // *********************************************************************************************************
630 void CDisplayerVisualGroup::onSelect(bool selected)
632 //H_AUTO(R2_CDisplayerVisualGroup_onSelect)
633 CDisplayerVisual::onSelect(selected);
634 updatePrimLook();
637 // *********************************************************************************************************
638 void CDisplayerVisualGroup::onPreRender()
640 //H_AUTO(R2_CDisplayerVisualGroup_onPreRender)
641 _DrawnThisFrame = false;
642 if (!_Active) return;
643 // see if render is on for primitives (don't use a config var because may be dynamically changed)
644 //if (!getEditor().getConfig()["PrimDisplayEnabled"].toBoolean()) return;
645 _DrawnThisFrame = true;
646 bool nowVisible = getActualVisibility();
647 if (_VisibleLastFrame != nowVisible)
649 touch();
650 updatePrimLook();
652 _VisibleLastFrame = nowVisible;
653 if (!nowVisible) return;
655 updatePrimVertices();
656 // progressive higlight
657 if (!getDisplayFlag(FlagSelected))
659 if (getDisplayFlag(FlagHasFocus))
661 _TimeOver += DT64;
662 if (_TimeOver > getFadeTimeInMS())
664 _TimeOver = getFadeTimeInMS();
667 else
669 _TimeOver -= DT64;
670 if (_TimeOver < 0)
672 _TimeOver = 0;
676 else
678 _TimeOver = 0;
680 float selectionFactor = 0.f;
681 if (_TimeOver != 0)
683 uint fadeTime = getFadeTimeInMS();
684 if (fadeTime != 0)
686 selectionFactor = (float) _TimeOver / fadeTime;
689 else
691 selectionFactor = getDisplayFlag(FlagHasFocus) ? 1.f : 0.f;
694 if (_Prim.getLook().Shape == CPrimLook::ClosedPolyLine && _CurrPrimValid)
696 CRGBA baseColor;
697 switch(getActualDisplayMode())
699 case DisplayModeVisible:
700 baseColor = CV_UnselectedRegionColor.get();
701 break;
702 case DisplayModeFrozen:
703 baseColor = CV_FrozenRegionColor.get();
704 break;
705 case DisplayModeLocked:
706 baseColor = CV_LockedRegionColor.get();
707 break;
708 default:
709 baseColor = CV_UnselectedRegionColor.get();
710 break;
712 CRGBA polyColor;
713 if (getDisplayFlag(FlagSelected))
715 polyColor = CV_SelectedRegionColor.get();
717 else
719 polyColor = getBlinkColor(blend(baseColor, CV_FocusedRegionColor.get(), selectionFactor));
721 _Prim.setWorldMapPolyColor(polyColor);
722 static volatile bool showPoly = true;
723 if (showPoly)
725 CLandscapePolyDrawer::getInstance().addPoly(_Poly2D, polyColor, _BBox);
729 if (getDisplayFlag(FlagSelected))
731 _Prim.setEmissive(getBlinkColor(CV_SelectedInstanceColor.get()));
733 else
735 _Prim.setEmissive(getBlinkColor(blend(CV_UnselectedInstanceColor.get(), CV_FocusedInstanceColor.get(), selectionFactor)));
739 _Prim.addDecalsToRenderList();
741 if (_CurrPrimInaccessible)
743 // CHANGE: no more display for inaccessible parts
744 // update color blinkking for inaccessible
745 /*CToolDrawPrim::updateInaccessiblePrimRenderLook(_InaccessiblePrim);
746 _InaccessiblePrim.addDecalsToRenderList();
753 // *********************************************************************************************************
754 void CDisplayerVisualGroup::updateInstanceList() const
756 //H_AUTO(R2_CDisplayerVisualGroup_updateInstanceList)
757 if (!_InstanceListTouched) return;
758 _InstanceListTouched = false;
759 _Instances.clear();
760 const CObject *sons = getProps().getAttr(_ArrayName);
761 if (!sons) return;
762 if (sons->getSize() == 0) return;
763 _Instances.resize(sons->getSize());
764 for(uint k = 0; k < sons->getSize(); ++k)
766 CInstance *inst = getEditor().getInstanceFromObject(sons->getValueAtPos(k));
767 if (inst)
769 _Instances[k] = inst->getDisplayerVisual();
774 // *********************************************************************************************************
775 NLMISC::CVector CDisplayerVisualGroup::evalLinkPoint(bool leader)
777 //H_AUTO(R2_NLMISC_CVector )
778 updateInstanceList();
779 if (!_Instances.empty())
781 return _Instances[0]->evalLinkPoint(leader);
783 else
785 nlwarning("_Instances[0] == 0");
786 return CVector::Null;
791 // *********************************************************************************************************
792 NLMISC::CVector CDisplayerVisualGroup::evalExitPoint()
794 //H_AUTO(R2_NLMISC_CVector )
795 updateInstanceList();
796 if (!_Instances.empty())
798 return _Instances.back()->evalLinkPoint();
800 else
802 nlwarning("_Instances[0] == 0");
803 return CVector::Null;
808 // *********************************************************************************************************
809 bool CDisplayerVisualGroup::evalEnterPoint(const NLMISC::CVector &startPoint, NLMISC::CVector &result)
811 //H_AUTO(R2_CDisplayerVisualGroup_evalEnterPoint)
812 updateInstanceList();
813 if (_Prim.getLook().Shape != CPrimLook::ClosedPolyLine)
815 if (!_Instances.empty())
817 result = _Instances[0]->getWorldPos().asVector();
818 return true;
820 return false;
822 _Poly2D.Vertices.resize(_Instances.size());
823 for(uint k = 0; k < _Instances.size(); ++k)
825 _Poly2D.Vertices[k] = _Instances[k]->getWorldPos().asVector();
827 if (_Poly2D.contains(startPoint, false))
829 return false;
831 float bestDist = FLT_MAX;
832 for(uint k = 0; k < _Instances.size(); ++k)
834 CVector v0 = _Instances[k]->getWorldPos().asVector();
835 CVector v1 = _Instances[(k + 1) % _Instances.size()]->getWorldPos().asVector();
836 CLine l(v0, v1);
837 CVector proj;
839 float coord = (startPoint - v0) * ((v1 - v0).normed());
840 float dist;
841 if (coord >= 0 && coord < (v1 - v0).norm())
843 l.project(startPoint, proj);
844 dist = (proj - startPoint).norm();
845 if (dist < bestDist)
847 bestDist = dist;
848 result = proj;
852 dist = (startPoint - v0).norm();
853 if (dist < bestDist)
855 bestDist = dist;
856 result = v0;
860 return bestDist != FLT_MAX;
863 // *********************************************************************************************************
864 const NLMISC::CMatrix &CDisplayerVisualGroup::getInvertedMatrix() const
866 //H_AUTO(R2_NLMISC_CMatrix )
867 return CMatrix::Identity; // all coordinates are in world ...
870 // *********************************************************************************************************
871 void CDisplayerVisualGroup::getSonsWorldPos2f(std::vector<NLMISC::CVector2f> &result)
873 //H_AUTO(R2_CDisplayerVisualGroup_getSonsWorldPos2f)
874 updateInstanceList();
875 result.clear();
876 for(uint k = 0; k < _Instances.size(); ++k)
878 result.push_back(_Instances[k]->getWorldPos2f());
882 // *********************************************************************************************************
883 void CDisplayerVisualGroup::getSons(std::vector<CDisplayerVisual *> &sons) const
885 //H_AUTO(R2_CDisplayerVisualGroup_getSons)
886 updateInstanceList();
887 sons.clear();
888 sons.insert(sons.begin(), _Instances.begin(), _Instances.end());
891 // *********************************************************************************************************
892 uint CDisplayerVisualGroup::getNumSons() const
894 //H_AUTO(R2_CDisplayerVisualGroup_getNumSons)
895 updateInstanceList();
896 return (uint)_Instances.size();
899 // *********************************************************************************************************
900 CDisplayerVisual *CDisplayerVisualGroup::getSon(uint index) const
902 //H_AUTO(R2_CDisplayerVisualGroup_getSon)
903 updateInstanceList();
904 nlassert(index < _Instances.size());
905 return _Instances[index];
908 // *********************************************************************************************************
909 void CDisplayerVisualGroup::setActiveRecurse(bool active)
911 //H_AUTO(R2_CDisplayerVisualGroup_setActiveRecurse)
912 setActive(active);
913 updateInstanceList();
914 for(uint k = 0; k < _Instances.size(); ++k)
916 _Instances[k]->setActive(active);
920 // *********************************************************************************************************
921 void CDisplayerVisualGroup::setContextualVisibilityActive(bool active)
923 //H_AUTO(R2_CDisplayerVisualGroup_setContextualVisibilityActive)
924 _ContextualVisibilityActive = active;
928 // *********************************************************************************************************
929 CDisplayerVisual::TDisplayMode CDisplayerVisualGroup::getActualDisplayMode() const
931 //H_AUTO(R2_CDisplayerVisualGroup_getActualDisplayMode)
932 TDisplayMode dm = CDisplayerVisual::getActualDisplayMode();
933 if (dm == DisplayModeHidden) return dm;
934 if (!_ContextualVisibilityActive || const_cast<CDisplayerVisualGroup *>(this)->isContextuallyVisible()) return dm;
935 return DisplayModeHidden;
939 // *********************************************************************************************************
940 bool CDisplayerVisualGroup::isContextuallyVisible()
942 //H_AUTO(R2_CDisplayerVisualGroup_isContextuallyVisible)
943 if (!_ContextualVisibilityActive) return true;
944 const CInstance *selection = getEditor().getSelectedInstance();
945 if (selection)
947 if (this == selection->getDisplayerVisual()) return true;
948 if (selection->getDisplayerVisual() && selection->getDisplayerVisual()->getParent() == this) return true;
950 return _ContextualVisibilityDate == T1;
955 } // R2