1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
25 #include "r2_config.h"
27 #include "../interface_v3/interface_manager.h"
28 #include "nel/gui/event_descriptor.h"
29 #include "../motion/user_controls.h"
30 #include "../global.h"
31 #include "../entities.h"
32 #include "../water_map.h"
34 #include "../time_client.h"
35 #include "displayer_visual.h"
36 #include "../interface_v3/group_map.h"
37 #include "nel/gui/lua_ihm.h"
39 #include "nel/pacs/u_global_position.h"
40 #include "nel/pacs/u_global_retriever.h"
42 #include "nel/misc/matrix.h"
43 #include "nel/misc/vector_2f.h"
45 #include "nel/3d/u_landscape.h"
47 #include "nel/3d/packed_world.h"
53 extern NLPACS::UGlobalRetriever
*GR
;
56 using namespace NLMISC
;
62 const uint32 DEFAULT_ENTITY_MIN_OPACITY
= 128;
65 bool CTool::_MouseCaptured
= false;
66 NLMISC::CRefPtr
<NLMISC::CCDBNodeLeaf
> CTool::_UserCharFade
;
68 static const CVector cardinals
[] =
70 CVector(1.f
, 0.f
, 0.f
),
71 CVector(1.f
, 1.f
, 0.f
).normed(),
72 CVector(0.f
, 1.f
, 0.f
),
73 CVector(-1.f
, 1.f
, 0.f
).normed(),
74 CVector(-1.f
, 0.f
, 0.f
),
75 CVector(-1.f
, -1.f
, 0.f
).normed(),
76 CVector(0.f
, -1.f
, 0.f
),
77 CVector(1.f
, -1.f
, 0.f
).normed()
80 // ***************************************************************
83 _DoubleClickStartTime
= -1;
86 _AutoPanLastHandlingFrame
= 0;
92 // ***************************************************************
93 void CTool::startDoubleClickCheck()
95 //H_AUTO(R2_CTool_startDoubleClickCheck)
96 _DoubleClickStartTime
= T0
;
97 getMousePos(_DoubleClickX
, _DoubleClickY
);
100 // ***************************************************************
101 bool CTool::checkDoubleClick()
103 //H_AUTO(R2_CTool_checkDoubleClick)
104 if (_DoubleClickStartTime
== -1) return false;
105 if (T0
- _DoubleClickStartTime
>= CWidgetManager::getInstance()->getUserDblClickDelay()) return false;
108 const sint32 moveThrehsold
= 2;
109 // test that mouse hasn't moved too much between the 2 clicks
110 return abs(mx
- _DoubleClickX
) <= moveThrehsold
&& abs(my
- _DoubleClickY
) <= moveThrehsold
;
113 // ***************************************************************
114 bool CTool::isShiftDown()
116 //H_AUTO(R2_CTool_isShiftDown)
117 return Driver
->AsyncListener
.isKeyDown(KeySHIFT
) ||
118 Driver
->AsyncListener
.isKeyDown(KeyLSHIFT
) ||
119 Driver
->AsyncListener
.isKeyDown(KeyRSHIFT
);
122 // ***************************************************************
123 bool CTool::isCtrlDown()
125 //H_AUTO(R2_CTool_isCtrlDown)
126 return Driver
->AsyncListener
.isKeyDown(KeyCONTROL
) ||
127 Driver
->AsyncListener
.isKeyDown(KeyLCONTROL
) ||
128 Driver
->AsyncListener
.isKeyDown(KeyRCONTROL
);
131 // ***************************************************************
132 CInterfaceManager
&CTool::getUI()
134 //H_AUTO(R2_CTool_getUI)
135 return CEditor::getUI();
138 // ***************************************************************
139 void CTool::getScreenSize(uint32
&scrW
, uint32
&scrH
)
141 //H_AUTO(R2_CTool_getScreenSize)
142 CViewRenderer::getInstance()->getScreenSize(scrW
, scrH
);
145 // ***************************************************************
146 uint32
CTool::getScreenWidth()
148 //H_AUTO(R2_CTool_getScreenWidth)
150 CViewRenderer::getInstance()->getScreenSize(scrW
, scrH
);
154 // ***************************************************************
155 uint32
CTool::getScreenHeight()
157 //H_AUTO(R2_CTool_getScreenHeight)
159 CViewRenderer::getInstance()->getScreenSize(scrW
, scrH
);
163 // ***************************************************************
164 void CTool::getMousePos(sint32
&x
, sint32
&y
)
166 //H_AUTO(R2_CTool_getMousePos)
167 CViewPointer
*cursor
= static_cast< CViewPointer
* >( CWidgetManager::getInstance()->getPointer() );
173 cursor
->getPointerPos(x
, y
);
176 // ***************************************************************
177 void CTool::getMouseDown(bool &down
, sint32
&x
, sint32
&y
)
180 //H_AUTO(R2_CTool_getMousePos)
181 CViewPointer
*cursor
= static_cast< CViewPointer
* >( CWidgetManager::getInstance()->getPointer() );
187 down
= cursor
->getPointerDown(x
, y
);
190 // ***************************************************************
191 void CTool::getMouseMiddleDown(bool &down
, sint32
&x
, sint32
&y
)
193 //H_AUTO(R2_CTool_getMousePos)
194 CViewPointer
*cursor
= static_cast< CViewPointer
* >( CWidgetManager::getInstance()->getPointer() );
200 down
= cursor
->getPointerMiddleDown(x
, y
);
203 // ***************************************************************
204 void CTool::getMouseRightDown(bool &down
, sint32
&x
, sint32
&y
)
206 //H_AUTO(R2_CTool_getMousePos)
207 CViewPointer
*cursor
= static_cast< CViewPointer
* >( CWidgetManager::getInstance()->getPointer() );
213 down
= cursor
->getPointerRightDown(x
, y
);
217 // ***************************************************************
218 sint32
CTool::getMouseX()
220 //H_AUTO(R2_CTool_getMouseX)
226 // ***************************************************************
227 sint32
CTool::getMouseY()
229 //H_AUTO(R2_CTool_getMouseY)
235 // ***************************************************************
236 bool CTool::isMouseOnUI()
238 //H_AUTO(R2_CTool_isMouseOnUI)
239 return CWidgetManager::getInstance()->getWindowUnder(getMouseX(), getMouseY()) != NULL
;
243 // ***************************************************************
244 CGroupMap
*CTool::getWorldMap()
246 //H_AUTO(R2_CTool_getWorldMap)
247 static NLMISC::CRefPtr
<CGroupMap
> mapPtr
;
248 static volatile bool cacheTest
= true;
249 if (!mapPtr
|| !cacheTest
)
251 mapPtr
= dynamic_cast<CGroupMap
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:actual_map"));
256 // ***************************************************************
257 CGroupMap
*CTool::isMouseOnWorldMap()
259 //H_AUTO(R2_CTool_isMouseOnWorldMap)
260 const std::vector
<CInterfaceGroup
*> &groupsUnder
= CWidgetManager::getInstance()->getGroupsUnderPointer();
261 if (groupsUnder
.empty()) return NULL
;
262 for(uint k
= 0; k
< groupsUnder
.size(); ++k
)
264 CGroupMap
*gm
= dynamic_cast<CGroupMap
*>(groupsUnder
[k
]);
270 // ***************************************************************
271 CGroupContainer
*CTool::isMouseOnContainer()
273 //H_AUTO(R2_CTool_isMouseOnContainer)
274 const std::vector
<CInterfaceGroup
*> &groupsUnder
= CWidgetManager::getInstance()->getGroupsUnderPointer();
275 if (groupsUnder
.empty()) return NULL
;
276 for(uint k
= 0; k
< groupsUnder
.size(); ++k
)
278 CInterfaceGroup
* gc
= groupsUnder
[k
]->getParentContainer();
280 return static_cast< CGroupContainer
* >( gc
);
285 // ***************************************************************
286 void CTool::computeWorldViewRay(sint32 posX
, sint32 posY
, CWorldViewRay
&dest
)
288 //H_AUTO(R2_CTool_computeWorldViewRay)
289 CGroupMap
*gm
= isMouseOnWorldMap();
292 sint32 windowX
= posX
- gm
->getXReal();
293 sint32 windowY
= posY
- gm
->getYReal();
295 gm
->windowToMap(mapPos
, windowX
, windowY
);
296 if (mapPos
.x
>= 0.f
&& mapPos
.y
>= 0.f
&& mapPos
.x
<= 1.f
&& mapPos
.y
<= 1.f
)
299 gm
->mapToWorld(worldPos
, mapPos
);
300 dest
.Dir
= -CVector::K
;
301 dest
.Origin
.set(worldPos
.x
, worldPos
.y
, 10000.f
); // look from above
302 dest
.OnMiniMap
= true;
303 dest
.Right
= CVector(1.f
, 0.f
, 0.f
);
304 dest
.Up
= CVector(0.f
, 1.f
, 0.f
);
310 dest
.OnMiniMap
= true;
317 getScreenSize(scrW
, scrH
);
318 const NL3D::CFrustum
&fru
= MainCam
.getFrustum();
320 dest
.Dir
.x
= posX
/ (float) scrW
;
321 dest
.Dir
.x
= fru
.Left
+ (fru
.Right
- fru
.Left
) * dest
.Dir
.x
;
322 dest
.Dir
.z
= posY
/ (float) scrH
;
323 dest
.Dir
.z
= fru
.Bottom
+ (fru
.Top
- fru
.Bottom
) * dest
.Dir
.z
;
324 dest
.Dir
.y
= fru
.Near
;
326 dest
.Dir
/= fru
.Near
;
327 CMatrix camMatrix
= MainCam
.getMatrix();
328 dest
.Right
= camMatrix
.getI().normed();
329 dest
.Up
= camMatrix
.getK().normed();
330 dest
.Dir
= camMatrix
.mulVector(dest
.Dir
);
331 dest
.Origin
= camMatrix
.getPos();
332 dest
.OnMiniMap
= false;
335 // When looking upward, the camera may be "snapped" to the ground
336 // In this case, false intersection with the ground may be detected, so move forward
337 // in ray direction to resolve that problem
338 const float distBias
= 0.20f
;
339 dest
.Origin
+= distBias
* dest
.Dir
;
342 // ***************************************************************
343 bool CTool::isInScreen(sint32 x
, sint32 y
)
345 //H_AUTO(R2_CTool_isInScreen)
347 getScreenSize(scrW
, scrH
);
348 return x
>= 0 && y
>=0 && x
< (sint32
) scrW
&& y
< (sint32
) scrH
;
351 // ***************************************************************
352 CTool::TRayIntersectionType
CTool::getPacsType(const NLMISC::CVector
&pos
, float threshold
, NLPACS::UGlobalPosition
&destPos
)
354 //H_AUTO(R2_CTool_getPacsType)
355 if (!GR
) return NoIntersection
;
356 destPos
= GR
->retrievePosition(pos
, threshold
);
357 if (destPos
.InstanceId
!= -1)
359 float waterHeight
= 0.0f
;
360 if(GR
->isWaterPosition(destPos
, waterHeight
))
362 // for now, forbid to put something in water
363 return InvalidPacsPos
;
369 return InvalidPacsPos
;
373 // ***************************************************************
374 bool CTool::raytrace(const NLMISC::CVector
&segmentStart
, const NLMISC::CVector
&dir
, NLMISC::CVector
&inter
)
376 //H_AUTO(R2_CTool_raytrace)
377 // try precise collision first if ray not vertical (not supported by CollisionManager)
378 H_AUTO ( RZ_Client_Camera_Collision_For_R2
)
379 if (dir
.x
!= 0.f
|| dir
.y
!= 0.f
)
383 // use a shortest distance for collision manager (for speed)
384 CVector segmentEnd
= segmentStart
+ 100.f
* dir
;
385 float dist
= Landscape
->getRayCollision(segmentStart
, segmentEnd
);
388 inter
= segmentStart
+ dist
* (segmentEnd
- segmentStart
);
393 // else try with coarsest version of the island
394 // ... else try with coarsest version of the whole island
395 CPackedWorld
*pw
= getEditor().getIslandCollision().getPackedIsland();
398 if (pw
->raytrace(segmentStart
, segmentStart
+ 2000.f
* dir
, inter
))
407 // ***************************************************************
408 CTool::TRayIntersectionType
CTool::computeWorldMapIntersection(float x
, float y
, NLMISC::CVector
&inter
)
410 //H_AUTO(R2_CTool_computeWorldMapIntersection)
411 const CArray2D
<sint16
> &heightMap
= getEditor().getIslandCollision().getHeightMap();
412 if (!heightMap
.empty())
414 // here we take only the surface with a valid z, so the 'InvalidPacsPocs' case is not possible
415 if (computeNearestValidSurfaceFromHeightMap(x
, y
, inter
)) return ValidPacsPos
;
416 return NoIntersection
;
418 if (!GR
) return NoIntersection
;
419 // if heightmap not present then relies on old pacs test method...(transition code before all goes through the heightmap)
420 CVector
pos(x
, y
, 0.f
);
422 NLPACS::UGlobalPosition pacsPos
;
423 TRayIntersectionType interType
= getPacsType(pos
, 100000.f
, pacsPos
);
424 nlassert(interType
!= NoIntersection
);
425 CVector firstGuess
= pacsPos
.LocalPosition
.Estimation
;
428 // now we have the good z, try to refine pos using the camera collision
430 float bias
= 0.001f
; // if (dx == 0) and (dy == 0), the camera collision fails (not supported, visibly)
431 // workaround it by adding a small bias
432 if (interType
== InvalidPacsPos
)
434 // no good z here..., so must test the whole range
439 CVector refinedStart
= firstGuess
+ deltaZ
* CVector::K
+ bias
* CVector::I
;
440 CVector refinedEnd
= firstGuess
- deltaZ
* CVector::K
- bias
* CVector::I
;
442 float dist
= CollisionManager
->getCameraCollision(refinedStart
, refinedEnd
, 0.1f
, false);
443 if (dist
== 1.f
) return NoIntersection
;
445 inter
= refinedStart
+ dist
* (refinedEnd
- refinedStart
);
449 // ***************************************************************
450 inline bool CTool::isIslandValidPos(const CArray2D
<sint16
> &heightMap
, const CScenarioEntryPoints::CCompleteIsland
&islandDesc
, float x
, float y
)
452 //H_AUTO(R2_CTool_isIslandValidPos)
453 sint mapX
= (sint
) (x
- islandDesc
.XMin
);
454 sint mapY
= (sint
) (y
- islandDesc
.YMin
);
455 clamp(mapX
, 0, (sint
) heightMap
.getWidth() - 1);
456 clamp(mapY
, 0, (sint
) heightMap
.getHeight() - 1);
457 sint hmZ
= heightMap(mapX
, mapY
);
462 // do several raytracing test on the small region until a hit is found (at boundary of zones, welding is not perfect so it helps to remove this problem)
463 static bool areaRaytrace(CPackedWorld
&pw
, const CVector
&start
, const CVector
&end
, CVector
&inter
, CVector
*normal
)
465 //H_AUTO(R2_areaRaytrace)
466 static volatile float distMax
= 0.2f
;
467 static volatile float distStep
= 0.05f
;
468 if (pw
.raytrace(start
, end
, inter
, NULL
, normal
)) return true;
469 for (float dist
= distStep
; dist
<= distMax
; dist
+= distStep
)
472 for (uint k
= 0; k
< sizeofarray(cardinals
); ++k
)
474 CVector delta
= dist
* cardinals
[k
];
475 if (pw
.raytrace(start
+ delta
, end
+ delta
, inter
, NULL
, normal
))
477 inter
-= delta
; // remove correction
485 // ***************************************************************
486 bool CTool::computeNearestValidSurfaceFromHeightMap(float x
, float y
, NLMISC::CVector
&inter
)
488 //H_AUTO(R2_CTool_computeNearestValidSurfaceFromHeightMap)
489 const CArray2D
<sint16
> &heightMap
= getEditor().getIslandCollision().getHeightMap();
490 nlassert (!heightMap
.empty());
493 const CScenarioEntryPoints::CCompleteIsland
*islandDesc
= getEditor().getIslandCollision().getCurrIslandDesc();
494 if (!islandDesc
) return false;
496 sint mapX
= (sint
) (x
- islandDesc
->XMin
);
497 sint mapY
= (sint
) (y
- islandDesc
->YMin
);
499 if (mapX
< 0 || mapY
< 0 || mapX
>= (islandDesc
->XMax
- islandDesc
->XMin
) || mapY
>= (islandDesc
->YMax
- islandDesc
->YMin
)) return false;
500 sint hmZ
= heightMap(mapX
, mapY
);
501 if (hmZ
>= 0x7ffe) return false; // not an accessible pos
503 if (!isIslandValidPos(heightMap
, *islandDesc
, x
+ 0.5f
, y
) ||
504 !isIslandValidPos(heightMap
, *islandDesc
, x
- 0.5f
, y
) ||
505 !isIslandValidPos(heightMap
, *islandDesc
, x
, y
+ 0.5f
) ||
506 !isIslandValidPos(heightMap
, *islandDesc
, x
, y
- 0.5f
)) return false;
508 float z
= 1.f
+ 2.f
* hmZ
;
509 // this is a possibly valid position
510 // compute nearest surface from here, and see if not far from the intersection
511 CPackedWorld
*pw
= getEditor().getIslandCollision().getPackedIsland();
512 nlassert(pw
); // packed world should be always present when heightmap is
516 CVector
origin(x
, y
, z
);
517 CVector
bias(0.f
, 0.f
, 0.1f
);
518 NLMISC::CVector normal1
;
519 NLMISC::CVector normal2
;
520 static volatile float minAngleSin
= 0.2f
;
521 bool inter1Found
= areaRaytrace(*pw
, origin
- bias
, origin
+ 10000.f
* CVector::K
, inter1
, &normal1
);
522 bool inter2Found
= areaRaytrace(*pw
, origin
+ bias
, origin
- 10000.f
* CVector::K
, inter2
, &normal2
);
523 inter1Found
= inter1Found
&& normal1
.z
>= minAngleSin
;
524 inter2Found
= inter2Found
&& normal2
.z
>= minAngleSin
;
525 if (!inter1Found
&& !inter2Found
) return false;
527 if (inter1Found
&& inter2Found
)
529 // because z in heightmap in usually a 'ceil' of real height, tends to favor surface below
530 // to avoid special case were the cliff top is very close to the ground. add a bias for this (equal
531 // to the heightmap precision)
533 inter
= ((inter1
- origin
).norm() < (inter2
- origin
).norm()) ? inter1
: inter2
;
535 else if (inter1Found
)
546 // ***************************************************************
547 bool CTool::isValid2DPos(const NLMISC::CVector2f
&pos
)
549 //H_AUTO(R2_CTool_isValid2DPos)
550 return getEditor().getIslandCollision().isValidPos(CVector2f(pos
.x
, pos
.y
));
553 // ***************************************************************
554 CTool::TRayIntersectionType
CTool::computeLandscapeRayIntersection(const CWorldViewRay
&worldViewRay
, NLMISC::CVector
&inter
)
556 //H_AUTO(R2_CTool_computeLandscapeRayIntersection)
557 if (!worldViewRay
.Valid
) return NoIntersection
;
558 if (worldViewRay
.OnMiniMap
)
560 return computeWorldMapIntersection(worldViewRay
.Origin
.x
, worldViewRay
.Origin
.y
, inter
);
562 // Compute collision point with landscape
563 if (!raytrace(worldViewRay
.Origin
, worldViewRay
.Dir
, inter
))
565 // NB following code is intended to fix the problem of holes betweens zone in the packed collision
566 static volatile float bias
= 0.15f
;
568 for (uint k
= 0; k
< sizeofarray(cardinals
) && !found
; ++k
)
570 CVector delta
= bias
* (cardinals
[k
].x
* worldViewRay
.Right
+ cardinals
[k
].y
* worldViewRay
.Up
);
571 found
= raytrace(worldViewRay
.Origin
+ delta
, worldViewRay
.Dir
, inter
);
575 // Because of holes near zones boundaries, add a small bias
576 return NoIntersection
;
580 const CArray2D
<sint16
> &heightMap
= getEditor().getIslandCollision().getHeightMap();
581 if (!heightMap
.empty())
583 // if heightmap is present, use it because it gives us more reliable information
585 if (!computeNearestValidSurfaceFromHeightMap(inter
.x
, inter
.y
, surfPos
)) return InvalidPacsPos
;
586 static volatile float threshold
= 2.f
;
587 return (inter
- surfPos
).norm() < threshold
? ValidPacsPos
: InvalidPacsPos
;
590 // get pacs type at intersection
593 return NoIntersection
;
597 // see if pacs collisions are ok at that pos
598 NLPACS::UGlobalPosition dummyPos
;
599 return getPacsType(inter
, 2.f
, dummyPos
);
603 // **********************************************
604 void CTool::handleMouseOverPlayer(bool over
)
606 //H_AUTO(R2_CTool_handleMouseOverPlayer)
607 // If the mouse is over the player make the player transparent
608 CCDBNodeLeaf
*pNL
= _UserCharFade
? &*_UserCharFade
609 : &*(_UserCharFade
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:USER_CHAR_FADE", false));
610 if ((pNL
!= NULL
) && (pNL
->getValue32() == 1) && UserEntity
->selectable())
612 // If the nearest entity is the player, hide!
614 UserEntity
->makeTransparent(true);
616 UserEntity
->makeTransparent(false);
619 UserEntity
->makeTransparent(false);
622 // ***************************************************************
623 CInstance
*CTool::checkInstanceUnderMouse(IDisplayerUIHandle
**miniMapHandle
/*= NULL*/)
625 //H_AUTO(R2_CTool_checkInstanceUnderMouse)
626 // Get the pointer position (in pixels)
629 *miniMapHandle
= NULL
;
635 CGroupMap
*gm
= isMouseOnWorldMap();
638 CInstance
*inst
= getEditor().getSelectedInstance();
639 CDisplayerVisual
*currSelectedDV
= inst
? inst
->getDisplayerVisual() : NULL
;
640 sint32 mouseXInWindow
;
641 sint32 mouseYInWindow
;
642 gm
->getCorner(mouseXInWindow
, mouseYInWindow
, Hotspot_BL
);
643 mouseXInWindow
= x
- mouseXInWindow
;
644 mouseYInWindow
= y
- mouseYInWindow
;
645 IDisplayerUIHandle
*bestCandidate
= NULL
;
646 sint8 bestCandidateLayer
= -128;
647 // see if the element is under the mouse
648 const std::vector
<CCtrlBase
*> &ctrlsUnder
= CWidgetManager::getInstance()->getCtrlsUnderPointer();
649 for(sint k
= (sint
)ctrlsUnder
.size() - 1; k
>= 0; --k
)
651 IDisplayerUIHandle
*handle
= dynamic_cast<IDisplayerUIHandle
*>(ctrlsUnder
[k
]);
654 CDisplayerVisual
*dv
= handle
->getDisplayedInstance().getDisplayerVisual();
655 if (ctrlsUnder
[k
]->getRenderLayer() > bestCandidateLayer
||
656 (ctrlsUnder
[k
]->getRenderLayer() == bestCandidateLayer
&& currSelectedDV
== dv
)
660 if (dv
&& dv
->isSelectable())
663 if (handle
->contains(mouseXInWindow
, mouseYInWindow
))
665 bestCandidate
= handle
;
666 bestCandidateLayer
= ctrlsUnder
[k
]->getRenderLayer();
676 *miniMapHandle
= bestCandidate
;
678 return &(bestCandidate
->getDisplayedInstance());
681 // else asks lua if there's a selectable instance under the mouse
682 // (so that we don't need to know of the UI ..., world map is a special case)
684 CLuaState
&ls
= getEditor().getLua();
685 CLuaStackRestorer
lsr(&ls
, 0);
686 if (getEditor().callEnvMethod("getInstanceIdFromUIUnderMouse", 0, 1))
690 CInstance
*inst
= getEditor().getInstanceFromId(ls
.toString(1));
691 if (inst
) return inst
;
696 else if (!IsMouseFreeLook() && !CWidgetManager::getInstance()->getCapturePointerLeft() && !CWidgetManager::getInstance()->getCapturePointerRight())
699 if (isInScreen(x
, y
))
701 // Get the pointer position (in float)
703 cursX
= x
/ (float) getScreenWidth();
704 cursY
= y
/ (float) getScreenHeight();
706 // Get the entities under position
707 bool isPlayerUnderCursor
;
708 CInstance
*inst
= getEditor().getInstanceUnderPos(cursX
, cursY
, 2000.f
, isPlayerUnderCursor
);
709 handleMouseOverPlayer(isPlayerUnderCursor
);
717 // ***************************************************************
718 void CTool::handleMouseOverInstance(const char *cursorDefault
, const char *cursorOverUnselectedInstance
, const char *cursorOverSelectedInstance
)
720 //H_AUTO(R2_CTool_handleMouseOverInstance)
721 setMouseCursor(cursorDefault
);
722 CInstance
*instanceUnder
= checkInstanceUnderMouse();
725 getEditor().setFocusedInstance(NULL
);
729 getEditor().setFocusedInstance(instanceUnder
);
730 if (instanceUnder
!= getEditor().getSelectedInstance())
732 setMouseCursor(cursorOverUnselectedInstance
);
736 // indicate that the user can move the instance
737 setMouseCursor(cursorOverSelectedInstance
);
741 // ***************************************************************
742 bool CTool::onMouseRightButtonClicked()
744 //H_AUTO(R2_CTool_onMouseRightButtonClicked)
745 if (!getEditor().getFocusedInstance())
747 getEditor().setSelectedInstance(NULL
);
750 getEditor().setSelectedInstance(getEditor().getFocusedInstance());
751 getEditor().displayContextMenu();
755 // ***************************************************************
756 bool CTool::defaultRightButtonDownHandling()
758 //H_AUTO(R2_CTool_defaultRightButtonDownHandling)
759 /*if (!getEditor().getFocusedInstance())
761 // cancel any current selection, this will cause the default context menu to beshown
762 getEditor().setSelectedInstance(NULL);
765 getEditor().setSelectedInstance(getEditor().getFocusedInstance());
766 getEditor().displayContextMenu();
771 // ***************************************************************
772 void CTool::captureMouse()
774 //H_AUTO(R2_CTool_captureMouse)
775 CGroupMap
*gm
= isMouseOnWorldMap();
778 CWidgetManager::getInstance()->setCapturePointerLeft(gm
);
782 UserControls
.captureMouse();
783 CWidgetManager::getInstance()->enableMouseHandling(false);
785 CWidgetManager::getInstance()->setContextHelpActive(false);
786 _MouseCaptured
= true;
789 // ***************************************************************
790 void CTool::releaseMouse()
792 //H_AUTO(R2_CTool_releaseMouse)
793 CWidgetManager::getInstance()->setCapturePointerLeft(NULL
);
794 UserControls
.releaseMouse();
795 CWidgetManager::getInstance()->enableMouseHandling(true);
796 CWidgetManager::getInstance()->setContextHelpActive(true);
797 _MouseCaptured
= false;
800 // *********************************************************************************************************
801 bool CTool::isMouseCaptured()
803 //H_AUTO(R2_CTool_isMouseCaptured)
804 return _MouseCaptured
;
807 // *********************************************************************************************************
808 void CTool::setMouseCursor(const std::string
&cursorTexture
)
810 //H_AUTO(R2_CTool_setMouseCursor)
811 CViewPointer
*cursor
= static_cast< CViewPointer
* >( CWidgetManager::getInstance()->getPointer() );
814 cursor
->setCursor(cursorTexture
);
818 // ***************************************************************
819 bool CTool::handleEvent(const NLGUI::CEventDescriptor
&event
)
821 //H_AUTO(R2_CTool_handleEvent)
822 bool handled
= false;
823 if (event
.getType() == NLGUI::CEventDescriptor::mouse
)
825 NLGUI::CEventDescriptorMouse
&eventDesc
= (NLGUI::CEventDescriptorMouse
&)event
;
826 switch(eventDesc
.getEventTypeExtended())
828 case NLGUI::CEventDescriptorMouse::mousemove
:
829 handled
= onMouseMove();
831 case NLGUI::CEventDescriptorMouse::mouseleftdown
:
832 handled
= onMouseLeftButtonDown();
833 //if (handled) nlwarning("onMouseLeftButtonDown handled");
835 case NLGUI::CEventDescriptorMouse::mouserightdown
:
836 handled
= onMouseRightButtonDown();
837 //if (handled) nlwarning("onMouseRightButtonDown handled");
839 case NLGUI::CEventDescriptorMouse::mouseleftup
:
840 handled
= onMouseLeftButtonUp();
841 //if (handled) nlwarning("onMouseLeftButtonUp handled");
843 case NLGUI::CEventDescriptorMouse::mouserightup
:
844 handled
= onMouseRightButtonUp();
845 //if (handled) nlwarning("onMouseRightButtonUp handled");
849 if (event
.getType() == NLGUI::CEventDescriptor::system
)
851 const NLGUI::CEventDescriptorSystem
&eds
= (const NLGUI::CEventDescriptorSystem
&) event
;
852 if (eds
.getEventTypeExtended() == NLGUI::CEventDescriptorSystem::setfocus
)
854 const NLGUI::CEventDescriptorSetFocus
&edsf
= (const NLGUI::CEventDescriptorSetFocus
&) eds
;
855 if (edsf
.hasFocus() == true)
864 // ***************************************************************
865 CDynamicMapClient
&CTool::getDMC()
867 //H_AUTO(R2_CTool_getDMC)
868 return getEditor().getDMC();
871 // ***************************************************************
872 void CTool::handleWorldMapAutoPan(sint32
&outDx
, sint32
&outDy
)
874 //H_AUTO(R2_CTool_handleWorldMapAutoPan)
876 CGroupMap
*gm
= getWorldMap();
878 // if not handled at previous frame then reset
879 uint64 currFrameCounter
= Driver
->getSwapBufferCounter();
880 if (currFrameCounter
== _AutoPanLastHandlingFrame
) return; // already handled this frame
881 if (_AutoPanLastHandlingFrame
<= currFrameCounter
- 2)
886 // see if mouse pos is valid
889 if (!gm
->isIn(mx
, my
))
893 sint32 autoPanBorder
= CV_MapAutoPanBorder
.get();
895 gm
->computeMapRectInsideGroup(x
, y
, w
, h
);
896 sint32 dx
= (gm
->getXReal() + w
- mx
) <= autoPanBorder
? 1 : 0;
897 dx
-= (mx
- gm
->getXReal()) <= autoPanBorder
? 1 : 0;
898 sint32 dy
= (gm
->getYReal() + h
- my
) <= autoPanBorder
? 1 : 0;
899 dy
-= (my
- gm
->getYReal()) <= autoPanBorder
? 1 : 0;
906 _AutoPanLastHandlingFrame
= currFrameCounter
;
907 // select delay (shorter in fast-pan mode)
908 sint32 delay
= (_NumPans
> CV_MapAutoFastPanNumTicks
.get()) ? CV_MapAutoFastPanDeltaInMs
.get()
909 : CV_MapAutoPanDeltaInMs
.get();
911 _AutoPanDelay
+= DT64
;
912 if (_AutoPanDelay
>= delay
)
914 _AutoPanDelay
= _AutoPanDelay
% delay
;
915 sint32 panDelta
= CV_MapAutoPanSpeedInPixels
.get();
916 outDx
= panDelta
* dx
;
917 outDy
= panDelta
* dy
;
918 gm
->pan(outDx
, outDy
);
919 ++ _NumPans
; // one step toward 'fast pan' mode
925 // ***************************************************************
926 int CTool::luaIsPickTool(CLuaState
&ls
)
928 //H_AUTO(R2_CTool_luaIsPickTool)
929 CLuaIHM::checkArgCount(ls
, "isPickTool", 0);
930 ls
.push(isPickTool());
934 // ***************************************************************
935 void CTool::setContextHelp(const ucstring
&contextHelp
)
937 //H_AUTO(R2_CTool_setContextHelp)
938 // forward the call to lua (all ui handling done bye lua)
939 CLuaState
&ls
= getEditor().getLua();
940 CLuaStackChecker
lsc(&ls
);
941 #ifdef RYZOM_LUA_UCSTRING
942 CLuaIHM::push(ls
, contextHelp
);
944 ls
.push(contextHelp
.toUtf8());
946 getEditor().callEnvMethod("setToolContextHelp", 1, 0);
949 // ***************************************************************
950 NLMISC::CRGBA
CTool::getInvalidPosColor()
952 //H_AUTO(R2_CTool_getInvalidPosColor)
953 double duration
= CV_InaccessiblePosAnimDurationInMS
.get();
954 if (duration
<= 0) duration
= 0.1;
955 return blend(CV_InaccessiblePosColor0
.get(),
956 CV_InaccessiblePosColor1
.get(),
957 0.5f
+ 0.5f
* (float) cos(NLMISC::Pi
* fmod((double) T1
, duration
) / duration
));