1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "displayer_visual_shape.h"
22 #include "r2_config.h"
25 #include "../entity_cl.h"
26 #include "../global.h"
28 #include "../pacs_client.h"
29 #include "verbose_clock.h"
31 #include "nel/3d/u_instance_material.h"
32 #include "nel/3d/u_shape_bank.h"
33 #include "nel/3d/u_visual_collision_manager.h"
34 #include "nel/3d/u_visual_collision_entity.h"
40 using namespace NLMISC
;
42 extern uint SkipFrame
;
47 // *********************************************************************************************************
48 CDisplayerVisualShape::CDisplayerVisualShape(const std::string
&shapeName
, float scale
, bool worldMapDisplay
)
50 _ShapeName
= shapeName
;
53 _BadShapeName
= false;
55 _VisualSnapToGroundDone
= false;
56 _VisualCollisionEntity
= NULL
;
57 _WorldMapDisplay
= worldMapDisplay
;
60 // *********************************************************************************************************
61 CDisplayerVisualShape::~CDisplayerVisualShape()
64 deleteVisualCollisionEntity();
67 // *********************************************************************************************************
68 void CDisplayerVisualShape::deleteVisualCollisionEntity()
70 //H_AUTO(R2_CDisplayerVisualShape_deleteVisualCollisionEntity)
73 if (_VisualCollisionEntity
)
75 CollisionManager
->deleteEntity(_VisualCollisionEntity
);
76 _VisualCollisionEntity
= NULL
;
81 // *********************************************************************************************************
82 void CDisplayerVisualShape::deleteShape()
84 //H_AUTO(R2_CDisplayerVisualShape_deleteShape)
85 if (!_Instance
.empty())
87 Scene
->deleteInstance(_Instance
);
89 if (_MapDeco
.isAddedToMap())
91 CGroupMap
*gm
= CTool::getWorldMap();
94 gm
->removeDeco(&_MapDeco
);
99 // *********************************************************************************************************
100 void CDisplayerVisualShape::onPreRender()
102 //H_AUTO(R2_CDisplayerVisualShape_onPreRender)
105 // a tp was done -> invalidate visual collision entity
106 deleteVisualCollisionEntity();
108 if (!_Instance
.empty())
110 bool inIsland
= false;
111 CIslandCollision
&col
= getEditor().getIslandCollision();
112 R2::CScenarioEntryPoints::CCompleteIsland
*currIsland
= col
.getCurrIslandDesc();
115 inIsland
= currIsland
->isIn(getWorldPos2f());
117 if (getActualVisibility() && inIsland
)
120 if (_WorldMapDisplay
&& !_MapDeco
.getActive())
122 _MapDeco
.setActive(true);
129 _MapDeco
.setActive(false);
132 if (!getActualVisibility()) return;
133 if (_BadShapeName
) return;
136 if (testNeedZEval()) _VisualSnapToGroundDone
= false;
137 if (!_VisualSnapToGroundDone
&& SkipFrame
== 0)
139 snapToGround(); // force visual snap to ground if not already done + icon update
144 if (!_Instance
.empty()) _BBoxMatrix
= _Instance
.getMatrix();
145 else _BBoxMatrix
= CMatrix::Identity
;
151 if (_Instance
.empty())
153 sint64 startTime
= 0;
154 static volatile bool bench
= false;
157 startTime
= CTime::getPerformanceTime();
159 _Instance
= Scene
->createInstance(_ShapeName
);
162 sint64 endTime
= CTime::getPerformanceTime();
163 nlwarning("clip time = %.2f ms", 1000.f
* CTime::ticksToSecond(endTime
- startTime
));
165 if (_Instance
.empty())
167 _BadShapeName
= true;
170 _Instance
.setTransformMode(NL3D::UTransform::DirectMatrix
);
171 _Instance
.enableCastShadowMap(true);
174 instanceMat
.setScale(_Scale
);
175 instanceMat
.setPos(getWorldPos().asVector());
176 _Instance
.setMatrix(instanceMat
);
177 _VisualSnapToGroundDone
= false;
178 visualSnapToGround(); // force visual snap to ground if not already done
182 if (!_Instance
.empty())
184 Scene
->deleteInstance(_Instance
);
188 if (!_Instance
.empty())
190 _BBoxMatrix
= _Instance
.getMatrix(); // ensure that bbox and shape displayed at same pos
191 // (events that modify the instance pos may be received after the display of this frame)
193 _MapDeco
.setInvalidPosFlag(getDisplayFlag(FlagBadPos
));
197 // *********************************************************************************************************
198 void CDisplayerVisualShape::drawBBox(NLMISC::CRGBA color
) const
200 //H_AUTO(R2_CDisplayerVisualShape_drawBBox)
201 if (getRotateInProgress()) return; // no drawn while drawing (bbox moved one frame too late, must solve this)
202 NLMISC::CAABBox bbox
;
203 _Instance
.getShapeAABBox(bbox
);
204 Driver
->setModelMatrix(_BBoxMatrix
);
205 ::drawBox(bbox
.getMin(), bbox
.getMax(), color
);
208 // *********************************************************************************************************
209 void CDisplayerVisualShape::onPostRender()
211 //H_AUTO(R2_CDisplayerVisualShape_onPostRender)
212 if (!_Active
|| !getActualVisibility()) return;
213 if (_BadShapeName
) return;
214 if (!_Instance
.empty())
216 if (getDisplayFlag(FlagSelected
))
218 //visualSnapToGround();
219 drawBBox(CRGBA::Green
);
220 setEmissive(_Instance
, getBlinkColor(CV_SelectedInstanceColor
.get()));
222 else if (getDisplayFlag(FlagHasFocus
))
224 //visualSnapToGround();
225 drawBBox(CRGBA::White
);
226 setEmissive(_Instance
, getBlinkColor(CV_FocusedInstanceColor
.get()));
230 CRGBA color
= getDisplayModeColorInScene();
231 setEmissive(_Instance
, color
);
232 ::makeInstanceTransparent(_Instance
, color
.A
, color
.A
!= 255);
235 CDisplayerVisual::onPostRender();
238 // *********************************************************************************************************
239 void CDisplayerVisualShape::onAttrModified(const std::string
&name
, sint32 index
)
241 //H_AUTO(R2_CDisplayerVisualShape_onAttrModified)
242 CDisplayerVisual::onAttrModified(name
, index
);
243 if (name
== "Position")
245 _VisualSnapToGroundDone
= false;
248 /*else if (name == "DisplayMode")
254 // *********************************************************************************************************
255 void CDisplayerVisualShape::setDisplayMode(sint32 mode
)
257 //H_AUTO(R2_CDisplayerVisualShape_setDisplayMode)
258 CDisplayerVisual::setDisplayMode(mode
);
263 // *********************************************************************************************************
264 void CDisplayerVisualShape::onParentDisplayModeChanged()
266 //H_AUTO(R2_CDisplayerVisualShape_onParentDisplayModeChanged)
270 // *********************************************************************************************************
271 void CDisplayerVisualShape::onFocus(bool focused
)
273 //H_AUTO(R2_CDisplayerVisualShape_onFocus)
274 CDisplayerVisual::onFocus(focused
);
278 // *********************************************************************************************************
279 void CDisplayerVisualShape::onSelect(bool selected
)
281 //H_AUTO(R2_CDisplayerVisualShape_onSelect)
282 CDisplayerVisual::onSelect(selected
);
287 // *********************************************************************************************************
288 void CDisplayerVisualShape::setActive(bool active
)
290 //H_AUTO(R2_CDisplayerVisualShape_setActive)
291 if (active
== _Active
) return;
298 if (!_MapDeco
.isAddedToMap() && _WorldMapDisplay
)
300 CGroupMap
*gm
= CTool::getWorldMap();
303 _MapDeco
.setDisplayedInstance(getDisplayedInstance(), false);
304 gm
->addDeco(&_MapDeco
);
305 _MapDeco
.invalidateCoords();
313 // *********************************************************************************************************
314 void CDisplayerVisualShape::updateMapDeco()
316 //H_AUTO(R2_CDisplayerVisualShape_updateMapDeco)
317 if (_MapDeco
.isAddedToMap())
319 CGroupMap
*gm
= CTool::getWorldMap();
322 _MapDeco
.onUpdate(*gm
);
323 _MapDeco
.invalidateCoords();
328 // *********************************************************************************************************
329 bool CDisplayerVisualShape::getActive() const
331 //H_AUTO(R2_CDisplayerVisualShape_getActive)
335 // *********************************************************************************************************
336 bool CDisplayerVisualShape::init(const CLuaObject
¶meters
)
338 //H_AUTO(R2_CDisplayerVisualSh_initSape)
339 _ShapeName
= parameters
["ShapeName"].toString();
340 if (parameters
["Scale"].isNumber())
342 _Scale
= parameters
["Scale"];
344 NL3D::UShapeBank
*shapeBank
= Driver
->getShapeBank();
347 shapeBank
->buildSystemGeometryForshape(_ShapeName
);
349 return CDisplayerVisual::init(parameters
);
352 // *********************************************************************************************************
353 bool CDisplayerVisualShape::getLastClip() const
355 //H_AUTO(R2_CDisplayerVisualShape_getLastClip)
356 if (_Instance
.empty()) return true;
357 return !_Instance
.getLastClippedState();
360 // *********************************************************************************************************
361 NLMISC::CAABBox
CDisplayerVisualShape::getSelectBox() const
363 //H_AUTO(R2_CDisplayerVisualShape_getSelectBox)
364 if (_Instance
.empty()) return CDisplayerVisual::getSelectBox();
365 // TODO nico : cache the bbox
366 NLMISC::CAABBox bbox
;
367 _Instance
.getShapeAABBox(bbox
);
368 bbox
.setMinMax(_Scale
* bbox
.getMin(), _Scale
* bbox
.getMax());
372 // *********************************************************************************************************
373 float CDisplayerVisualShape::preciseIntersectionTest(const NLMISC::CVector
&worldRayStart
,const NLMISC::CVector
&worldRayDir
) const
375 //H_AUTO(R2_CDisplayerVisualShape_preciseIntersectionTest)
376 if (_Instance
.empty()) return FLT_MAX
;
377 if(_Instance
.supportFastIntersect())
380 if (const_cast<NL3D::UInstance
&>(_Instance
).fastIntersect(worldRayStart
, worldRayDir
, dist2D
, distZ
, false))
391 // *********************************************************************************************************
392 const NLMISC::CMatrix
&CDisplayerVisualShape::getInvertedMatrix() const
394 //H_AUTO(R2_CDisplayerVisualShape_getInvertedMatrix)
395 // no rot part for now
396 _InvertedMatrix
.setPos(- getWorldPos().asVector());
397 return _InvertedMatrix
;
400 // *********************************************************************************************************
401 void CDisplayerVisualShape::updateWorldPos()
403 //H_AUTO(R2_CDisplayerVisualShape_updateWorldPos)
404 CDisplayerVisual::updateWorldPos();
405 // must always snap pos (if world pos was modified because of parent move,
406 // in this case our relative pos remains unmodified)
407 _VisualSnapToGroundDone
= false;
413 // *********************************************************************************************************
414 void CDisplayerVisualShape::snapToGround()
416 //H_AUTO(R2_CDisplayerVisualShape_snapToGround)
422 NLPACS::UGlobalPosition gpos
= GR
->retrievePosition(getWorldPos());
423 if (gpos
.InstanceId
!= -1)
425 CVector snappedPos
= GR
->getGlobalPosition(gpos
);
426 // locally modify the z
427 _WorldPos
.z
= snappedPos
.z
;
428 //setDisplayFlag(FlagBadPos, false);
432 //setDisplayFlag(FlagBadPos, true);
434 visualSnapToGround();
438 // *********************************************************************************************************
439 void CDisplayerVisualShape::visualSnapToGround()
441 //H_AUTO(R2_CDisplayerVisualShape_visualSnapToGround)
442 if (!_VisualSnapToGroundDone
)
444 if (!_Instance
.empty())
446 CMatrix mat
= _Instance
.getMatrix();
447 CVector pos3f
= _WorldPos
.asVector();
448 // VisualCollisionEntity's 'snap to ground' requires that the entity is not farther than 100 meters from it
449 // Eval first coarse height from height map + coarse collision mesh
450 CTool::TRayIntersectionType interType
= CTool::NoIntersection
;
451 static volatile bool coarseSnap
= true;
455 CTool::TRayIntersectionType interType
= CTool::computeWorldMapIntersection(pos3f
.x
, pos3f
.y
, inter
);
456 if (interType
!= CTool::NoIntersection
)
461 bool snapped
= false;
462 if (CollisionManager
)
464 // create if necessary
465 if (!_VisualCollisionEntity
)
467 _VisualCollisionEntity
= CollisionManager
->createEntity();
469 // eval finer pos from previous pos
470 snapped
= _VisualCollisionEntity
->snapToGround(pos3f
); // refine z from current pos
473 if (snapped
|| interType
!= CTool::NoIntersection
) // take precise version or else default to coarsest one
475 _WorldPos
.z
= pos3f
.z
;
477 _VisualSnapToGroundDone
= true;
478 mat
.setPos(_WorldPos
);
479 _Instance
.setMatrix(mat
);
484 // *********************************************************************************************************
485 NLMISC::CVector
CDisplayerVisualShape::evalLinkPoint(bool /* leader */)
487 //H_AUTO(R2_CDisplayerVisualShape_evalLinkPoint)
488 if (!_Instance
.empty())
490 visualSnapToGround();
491 // use the visual snapped pos instead
492 return _Instance
.getMatrix().getPos();
494 // return position that is visually snapped to the ground
499 // *********************************************************************************************************
500 void CDisplayerVisualShape::onAdd(CGroupMap
&/* owner */)
502 //H_AUTO(R2_CDisplayerVisualShape_onAdd)
506 // *********************************************************************************************************
507 void CDisplayerVisualShape::onRemove(CGroupMap
&/* owner */)
509 //H_AUTO(R2_CDisplayerVisualShape_onRemove)
512 // *********************************************************************************************************
513 void CDisplayerVisualShape::onPreRender(CGroupMap
&/* owner */)
515 //H_AUTO(R2_CDisplayerVisualShape_onPreRender)
519 // *********************************************************************************************************
520 void CDisplayerVisualShape::onUpdate(CGroupMap
&/* owner */)
522 //H_AUTO(R2_CDisplayerVisualShape_onUpdate)