// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "displayer_visual.h" // r2 #include "instance.h" #include "editor.h" #include "tool_select_move.h" // #include "nel/misc/algo.h" #include "nel/misc/vector_2f.h" // #include "../time_client.h" #include "../interface_v3/lua_ihm.h" #include "../global.h" // #include "../interface_v3/interface_manager.h" #include "../interface_v3/group_in_scene.h" // #include "r2_config.h" using namespace NLMISC; extern uint SkipFrame; namespace R2 { // *************************************************************** CDisplayerVisual::CDisplayerVisual() : _DisplayFlags(FlagNone) { _BlinkStartDate = 0; _Pos.set(0, 0, 0); _WorldPos = _Pos; _IconInScene = NULL; _IconInSceneCreationFailed = false; _DisplayFlags = 0; _RotateInProgress = false; _MoveInProgress = false; // TODO nico : optim here : only one decal used at a time _LastCamDist = -100.f; _DisplayMode = DisplayModeVisible; _InheritDisplayMode = false; // filled at init by this displayer lua parameter _LastParentOk = false; _LastParent = NULL; } // *************************************************************** CDisplayerVisual::~CDisplayerVisual() { if (_IconInScene) { getEditor().getUI().unMakeWindow(_IconInScene); if (_IconInScene->getParent()) { _IconInScene->getParent()->delGroup(_IconInScene); } else { delete _IconInScene; } } } // *************************************************************** void CDisplayerVisual::setDisplayFlag(TDisplayFlags flag, bool on) { //H_AUTO(R2_CDisplayerVisual_setDisplayFlag) nlctassert(FlagCount <= 32); nlassert((uint) flag < FlagCount); setFlags(_DisplayFlags, 1 << flag, on); } // *************************************************************** bool CDisplayerVisual::getDisplayFlag(TDisplayFlags flag) const { //H_AUTO(R2_CDisplayerVisual_getDisplayFlag) nlctassert(FlagCount <= 32); nlassert((uint) flag < FlagCount); return (_DisplayFlags & (1 << flag)) != 0; } // *************************************************************** CDisplayerVisual *CDisplayerVisual::getParent() { if (_LastParentOk) return _LastParent; CDisplayerVisual *result = NULL; //H_AUTO(R2_CDisplayerVisual_getParent) CInstance *inst = getDisplayedInstance(); nlassert(inst); CInstance *parentInstance = inst->getParent(); if (parentInstance) { result = parentInstance->getDisplayerVisual(); } _LastParent = result; _LastParentOk = true; return result; } // *************************************************************** const CDisplayerVisual *CDisplayerVisual::getParent() const { //H_AUTO(R2_CDisplayerVisual_getParent) return (const_cast(this))->getParent(); /*CInstance *inst = getDisplayedInstance(); nlassert(inst); CInstance *parentInstance = inst->getParent(); if (parentInstance) { return parentInstance->getDisplayerVisual(); } return NULL;*/ } // *************************************************************** void CDisplayerVisual::onFocus(bool focused) { //H_AUTO(R2_CDisplayerVisual_onFocus) setDisplayFlag(FlagHasFocus, focused); } // *************************************************************** void CDisplayerVisual::onSelect(bool selected) { //H_AUTO(R2_CDisplayerVisual_onSelect) setDisplayFlag(FlagSelected, selected); } // *************************************************************** void CDisplayerVisual::onPostHrcMove() { //H_AUTO(R2_CDisplayerVisual_onPostHrcMove) _LastParentOk = false; // must update parent updateWorldPosRecurse(); } // *************************************************************** void CDisplayerVisual::blink() { //H_AUTO(R2_CDisplayerVisual_blink) _BlinkStartDate = T1; } // *************************************************************** int CDisplayerVisual::luaBlink(CLuaState &ls) { //H_AUTO(R2_CDisplayerVisual_luaBlink) CLuaIHM::checkArgCount(ls, "luaBlink", 1); blink(); return 0; } // *************************************************************** NLMISC::CRGBA CDisplayerVisual::getBlinkColor(NLMISC::CRGBA defaultColor, NLMISC::CRGBA blinkColor) const { //H_AUTO(R2_NLMISC_CRGBA ) const uint NUM_BLINKS = 3; const uint BLINK_LENGTH_IN_MS = 100; sint64 blink = (T1 - _BlinkStartDate) / BLINK_LENGTH_IN_MS; if (blink > NUM_BLINKS) return defaultColor; return !(blink & 1) ? blinkColor : defaultColor; } // ********************************************************************************************************* void CDisplayerVisual::onAttrModified(const std::string &attrName, sint32 /* attrIndex */) { //H_AUTO(R2_CDisplayerVisual_onAttrModified) if (attrName == "Position") { updatePos(); } /*else if (attrName == "DisplayMode") { updateDisplayMode(); uint numSons = getNumSons(); for(uint k = 0; k < numSons; ++k) { CDisplayerVisual *dv = getSon(k); if (dv) { dv->onParentDisplayModeChanged(); } } }*/ } // ********************************************************************************************************* /*void CDisplayerVisual::updateDisplayMode() { sint value = (sint) getNumber(&getProps(), "DisplayMode"); if (value >= 0 && value < DisplayModeCount) { TDisplayMode newDisplayMode = (TDisplayMode) value; if (newDisplayMode != _DisplayMode) { //if (newDisplayMode == DisplayModeFrozen && getEditor().getSelectedInstance() == getDisplayedInstance()) //{ // getEditor().setSelectedInstance(NULL); //} //_DisplayMode = newDisplayMode; } } else { nlwarning("Trying to set an invalid display mode : %d", (int) _DisplayMode); } }*/ // ********************************************************************************************************* void CDisplayerVisual::updatePos() { //H_AUTO(R2_CDisplayerVisual_updatePos) updateLocalPos(); updateWorldPosRecurse(); } // ********************************************************************************************************* void CDisplayerVisual::updateLocalPos() { //H_AUTO(R2_CDisplayerVisual_updateLocalPos) if (getProps().findAttr("Position")) { _Pos = getVector(getObject(&getProps(), "Position")); static volatile bool wantAssert = true; if (!isValidDouble(_Pos.x) || !isValidDouble(_Pos.y) ||!isValidDouble(_Pos.z)) { // nlassert(!wantAssert); BOMB_IF(wantAssert,"'wantAssert' was triggered",_Pos.set(0, 0, 0)); } } else { _Pos.set(0, 0, 0); } } // ********************************************************************************************************* bool CDisplayerVisual::inheritPos() const { //H_AUTO(R2_CDisplayerVisual_inheritPos) return getNumber(&getProps(), "InheritPos") != 0; } // ********************************************************************************************************* void CDisplayerVisual::updateWorldPos() { //H_AUTO(R2_CDisplayerVisual_updateWorldPos) CDisplayerVisual *parent = getParent(); if (parent && inheritPos()) { _WorldPos = parent->getWorldPos() + _Pos; } else { _WorldPos = _Pos; } static volatile bool wantAssert = true; if (!isValidDouble(_WorldPos.x) || !isValidDouble(_WorldPos.y) ||!isValidDouble(_WorldPos.z)) { nlassert(!wantAssert); } updateValidPosFlag(); } // ********************************************************************************************************* void CDisplayerVisual::updateValidPosFlag() { //H_AUTO(R2_CDisplayerVisual_updateValidPosFlag) // if I'm not a compound object, update my 'BadPos' flag if (!isCompound()) { // If I'm outside of current map then don't display the flag CScenarioEntryPoints::CCompleteIsland *islandDesc = getEditor().getIslandCollision().getCurrIslandDesc(); if (islandDesc) { if ((sint32) _WorldPos.x < islandDesc->XMin || (sint32) _WorldPos.x > islandDesc->XMax || (sint32) _WorldPos.y < islandDesc->YMin || (sint32) _WorldPos.y > islandDesc->YMax) { setDisplayFlag(FlagBadPos, false); return; } } setDisplayFlag(FlagBadPos, !getEditor().getIslandCollision().isValidPos(NLMISC::CVector(_WorldPos))); } } // ********************************************************************************************************* void CDisplayerVisual::updateWorldPosRecurse() { //H_AUTO(R2_CDisplayerVisual_updateWorldPosRecurse) struct CWorldPosUpdater : public IInstanceVisitor { virtual void visit(CInstance &inst) { if (inst.getDisplayerVisual()) { inst.getDisplayerVisual()->updateWorldPos(); } } }; nlassert(getDisplayedInstance()); CWorldPosUpdater worldPosUpdater; getDisplayedInstance()->visit(worldPosUpdater); } // ********************************************************************************************************* void CDisplayerVisual::onPostCreate() { //H_AUTO(R2_CDisplayerVisual_onPostCreate) _LastParentOk = false; updateLocalPos(); updateWorldPos(); // do not recurse here because sons pos have not been initialized yet //updateDisplayMode(); if (isActiveInCurrentAct()) { if (!getActive()) { setActive(true); } } } // ********************************************************************************************************* void CDisplayerVisual::onErase() { //H_AUTO(R2_CDisplayerVisual_onErase) if (getActive()) { setActive(false); } } // ********************************************************************************************************* void CDisplayerVisual::onPreActChanged() { //H_AUTO(R2_CDisplayerVisual_onPreActChanged) updatePos(); if (!isActiveInCurrentAct()) { if (getActive()) { setActive(false); } } } // ********************************************************************************************************* void CDisplayerVisual::onActChanged() { //H_AUTO(R2_CDisplayerVisual_onActChanged) updatePos(); if (isActiveInCurrentAct()) { if (!getActive()) { setActive(true); } } } // ********************************************************************************************************* void CDisplayerVisual::onContinentChanged() { //H_AUTO(R2_CDisplayerVisual_onContinentChanged) if (getActive()) { setActive(false); setActive(true); // force a refresh of collision (EntitiesManager::changeContinent updates the primitive, but broken for an unknown reason ...) } } // ********************************************************************************************************* bool CDisplayerVisual::isActiveInCurrentAct() const { //H_AUTO(R2_CDisplayerVisual_isActiveInCurrentAct) // parent act should be the base act (always exists), or the selected act CInstance *parentAct = getDisplayedInstance()->getParentAct(); if (parentAct == getEditor().getBaseAct() || parentAct == getEditor().getCurrentAct()) { return true; } return false; } // ********************************************************************************************************* void CDisplayerVisual::onPostRender() { //H_AUTO(R2_CDisplayerVisual_onPostRender) if (!getActive()) return; // if this entity is currently moving then don't display the 'stop' icon // (it is already drawn by the mouse cursor) if (getDisplayedInstance() == getEditor().getSelectedInstance() && dynamic_cast(getEditor().getCurrentTool())) { if (_IconInScene) { _IconInScene->setActive(false); } } else { if (getDisplayFlag(FlagBadPos)) { if (!_IconInScene && !_IconInSceneCreationFailed) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); const char *iconTemplateName = "r2ed_bad_pos_icon"; // if the in scene 'stop' window wasn't created, then create it now CInterfaceGroup *group = pIM->createGroupInstance (iconTemplateName , "ui:interface", NULL, 0); if (group) { _IconInScene = dynamic_cast(group); if (!_IconInScene) { nlwarning("Template %s has bad type : should be a derived group from CGroupInScene", iconTemplateName); delete group; _IconInSceneCreationFailed = true; } else { // Link to the interface pIM->addWindowToMasterGroup("ui:interface", group); CInterfaceGroup *pRoot = dynamic_cast(pIM->getElementFromId("ui:interface")); group->setParent(pRoot); if (pRoot) pRoot->addGroup (group); } } else { _IconInSceneCreationFailed = true; } } if (_IconInScene) { _IconInScene->setActive(true); // tmp set a position above head evalIconInScenePos(_IconInScene->Position); } } else { if (_IconInScene) { _IconInScene->setActive(false); } } } } // ********************************************************************************************************* void CDisplayerVisual::evalIconInScenePos(NLMISC::CVector &dest) const { //H_AUTO(R2_CDisplayerVisual_evalIconInScenePos) NLMISC::CAABBox selectBox = getSelectBox(); float radius = std::max(selectBox.getHalfSize().x, selectBox.getHalfSize().y); // use middle front of bbox for icon pos NLMISC::CVector result = getWorldPos().asVector() - radius * MainCam.getMatrix().getJ() + selectBox.getHalfSize().z * CVector::K; static volatile bool wantAssert = true; if (!isValidDouble(result.x) || !isValidDouble(result.y) ||!isValidDouble(result.z)) { nlassert(!wantAssert); return; } dest = result; } // ********************************************************************************************************* bool CDisplayerVisual::evalEnterPoint(const NLMISC::CVector &/* startPoint */, NLMISC::CVector &result) { //H_AUTO(R2_CDisplayerVisual_evalEnterPoint) result = evalLinkPoint(false); return true; } // ********************************************************************************************************* NLMISC::CVector CDisplayerVisual::evalExitPoint() { //H_AUTO(R2_NLMISC_CVector ) return evalLinkPoint(false); } // ********************************************************************************************************* void CDisplayerVisual::getSonsWorldPos2f(std::vector &result) { //H_AUTO(R2_CDisplayerVisual_getSonsWorldPos2f) result.clear(); } // ********************************************************************************************************* void CDisplayerVisual::getSons(std::vector &sons) const { //H_AUTO(R2_CDisplayerVisual_getSons) sons.clear(); // no sons by default } // ********************************************************************************************************* void CDisplayerVisual::setRotateInProgress(bool rotateInProgress) { //H_AUTO(R2_CDisplayerVisual_setRotateInProgress) _RotateInProgress = rotateInProgress; } // ********************************************************************************************************* void CDisplayerVisual::setMoveInProgress(bool moveInProgress) { //H_AUTO(R2_CDisplayerVisual_setMoveInProgress) _MoveInProgress = moveInProgress; } // ********************************************************************************************************* bool CDisplayerVisual::testNeedZEval() { //H_AUTO(R2_CDisplayerVisual_testNeedZEval) if (SkipFrame == 0) // don't update just after a tp because landscape hasn't been updated yet ... { float newCamDist = (MainCam.getMatrix().getPos() - _WorldPos).norm(); if (fabsf(newCamDist - _LastCamDist) >= 5.f) { _LastCamDist = newCamDist; updateValidPosFlag(); return true; } } else { _LastCamDist = -100.f; //nlwarning("Waiting skip frame : %d", (int) SkipFrame); } return false; } // ********************************************************************************************************* bool CDisplayerVisual::isSelectable() const { //H_AUTO(R2_CDisplayerVisual_isSelectable) static volatile bool bypass = false; if (bypass) return false; TDisplayMode dm = getActualDisplayMode(); return getDisplayedInstance()->getSelectableFromRoot() && (dm == DisplayModeVisible || dm == DisplayModeLocked); } // ********************************************************************************************************* CDisplayerVisual::TDisplayMode CDisplayerVisual::getActualDisplayMode() const { //H_AUTO(R2_CDisplayerVisual_getActualDisplayMode) static volatile bool bypass = false; if (bypass) { return CDisplayerVisual::DisplayModeVisible; } TDisplayMode dm; const CDisplayerVisual *parent = getParent(); if (_InheritDisplayMode && parent) { TDisplayMode parentDM = parent->getActualDisplayMode(); dm = parentDM == DisplayModeVisible ? _DisplayMode : parentDM; } else { dm= _DisplayMode; } static volatile bool bypass2 = false; if (bypass2) { return CDisplayerVisual::DisplayModeVisible; } if (!getDisplayedInstance()->getSelectableFromRoot() && dm != DisplayModeHidden) { dm = DisplayModeFrozen; } static volatile bool bypass3 = false; if (bypass3) { return CDisplayerVisual::DisplayModeVisible; } // If it is not an animation but a scenario started from ring access do not display things if ( CEditor::getIsStartingScenario() ) { return DisplayModeHidden; } return dm; } // ********************************************************************************************************* CRGBA CDisplayerVisual::getDisplayModeColorInScene() const { //H_AUTO(R2_CDisplayerVisual_getDisplayModeColorInScene) switch(getActualDisplayMode()) { case DisplayModeVisible: return CV_UnselectedInstanceColor.get(); case DisplayModeFrozen: return CV_FrozenInstanceColor.get(); case DisplayModeLocked: return CV_LockedInstanceColor.get(); case DisplayModeArray: return CV_ArrayInstanceColor.get(); default: return CRGBA(0, 0, 0 ,0); } } // ********************************************************************************************************* CRGBA CDisplayerVisual::getDisplayModeColorInMap() const { //H_AUTO(R2_CDisplayerVisual_getDisplayModeColorInMap) switch(getActualDisplayMode()) { case DisplayModeVisible: return CRGBA::White; case DisplayModeFrozen: return CV_MapEntityFrozenColor.get(); case DisplayModeLocked: return CV_MapEntityLockedColor.get(); case DisplayModeArray: return CV_ArrayInstanceColor.get(); default: return CRGBA(0, 0, 0 ,0); } } // ********************************************************************************************************* bool CDisplayerVisual::init(const CLuaObject ¶meters) { //H_AUTO(R2_CDisplayerVisual_init) if (parameters["InheritDisplayMode"].isBoolean()) { _InheritDisplayMode = parameters["InheritDisplayMode"].toBoolean(); } return CDisplayerBase::init(parameters); } // ********************************************************************************************************* void CDisplayerVisual::setDisplayMode(sint32 mode) { //H_AUTO(R2_CDisplayerVisual_setDisplayMode) if (mode == _DisplayMode) return; if (mode < 0 || mode >= DisplayModeCount) { nlwarning("Trying to set invalid display mode : %d", (int) mode); return; } _DisplayMode = (TDisplayMode) mode; uint numSons = getNumSons(); for(uint k = 0; k < numSons; ++k) { CDisplayerVisual *dv = getSon(k); if (dv) { dv->onParentDisplayModeChanged(); } } } } // R2