// 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 . #ifndef CL_GROUP_MAP_CL #define CL_GROUP_MAP_CL #include "nel/misc/vector_2f.h" #include "nel/misc/ucstring.h" #include "../client_sheets/world_sheet.h" #include "interface_group.h" #include "ctrl_button.h" #include "view_bitmap.h" #include "view_text.h" #include "animal_position_state.h" #include "../continent.h" // class CContinent; class CCDBNodeLeaf; class CWorldSheet; class CCtrlQuad; struct SMap; namespace NL3D { class UMaterial; class UDriver; class UTextureFile; } #define MISSIONS_DB_PATH "SERVER:MISSIONS" #define GROUP_MISSIONS_DB_PATH "SERVER:GROUP:MISSIONS" #define COMPASS_DB_PATH "SERVER:COMPASS" // const float RYZOM_MAP_MAX_SCALE = 8.f; class CLandMarkOptions { public: std::string LandMarkTexNormal; std::string LandMarkTexOver; std::string LandMarkTexPushed; NLMISC::CRGBA ColorNormal; NLMISC::CRGBA ColorOver; NLMISC::CRGBA ColorPushed; std::string LandMarkMenu; public: CLandMarkOptions() { ColorNormal = ColorOver = ColorPushed = NLMISC::CRGBA::White; } }; /** * Display of map and landmarks. * * There are several coordinate systems : * * - World coordinates : as usual * - Map coordinates : In the [0, 1] range. [0, 0] is the upper left of map, and [1, 1] is the lower right. * the corners of the map in world coordinates are given by their zone names (in the continent sheet) * - Screen coordinates : in pixels * - Window coordinates : the same as screen coordinate, but relative to that CInterfaceGroup * * \author Nicolas Vizerie * \author Nevrax France * \date 2003 */ class CGroupMap : public CInterfaceGroup { public: // external element to be displayed on the map struct IDeco { /** called when the element is added to the map. If the deco is an interface element, it could * add itself to this group child */ virtual void onAdd(CGroupMap &/* owner */) {} virtual void onRemove(CGroupMap &/* owner */) {} virtual void onPreRender(CGroupMap &/* owner */) {} /** Called when the map has been scrolled or scaled. The deco should update its pos here * */ virtual void onUpdate(CGroupMap &/* owner */) {} }; public: CGroupMap(const TCtorParam ¶m); ~CGroupMap(); // Add a decoration to the map. The map will call the 'onAdd' method. When this object is destroyed, it will call the 'onRemove' method void addDeco(IDeco *deco); // Remove a decoration from the map. This will also call the 'onRemove' method. It is up to the owner to delete it. void removeDeco(IDeco *deco); virtual void setActive (bool state); virtual void updateCoords(); virtual void checkCoords(); virtual void draw (); virtual bool handleEvent (const CEventDescriptor &event); virtual bool parse(xmlNodePtr cur, CInterfaceGroup * parentGroup); virtual bool getCtrlsUnder (sint32 x, sint32 y, sint32 clipX, sint32 clipY, sint32 clipW, sint32 clipH, std::vector &vICL); // Name of the map as filled in the ryzom.world file void setMap(const std::string &mapName); void setMap(SMap *map); // pan the map of the given number of pixels void pan(sint32 dx, sint32 dy); // center the map on the player void centerOnPlayer(); void setPlayerPos(const NLMISC::CVector2f &p) { _PlayerPos = p; } NLMISC::CVector2f getPlayerPos() const { return _PlayerPos; } // test if player is currently panning the map bool isPanning() const { return _Panning; } /** Change the scale. It will be clipped to the max possible value * The center of the scale transformation must be given in the map coordinates. */ void setScale(float newScale, const NLMISC::CVector2f ¢er); /** Change the scale. It will be clipped to the max possible value * The center of the scale is the center of current window */ void setScale(float newScale); // float getScale() const { return _UserScale; } /// add a user landmark (returns a pointer on its button).Coordinate are in the current map (not world coordinates) CCtrlButton *addUserLandMark(const NLMISC::CVector2f &pos, const ucstring &title, const CUserLandMark::EUserLandMarkType lmType); // remove a user landmark from a pointer on its button void removeUserLandMark(CCtrlButton *button); // update a user landmark from a pointer on its button void updateUserLandMark(CCtrlButton *button, const ucstring &newName, const CUserLandMark::EUserLandMarkType lmType); // get a user landmark from a pointer on its button CUserLandMark getUserLandMark(CCtrlButton *button) const; // get pos on the map of the last right click (in map coords) NLMISC::CVector2f getRightClickLastPos() const { return _RightClickLastPos; } // get number of user landmarks uint getNumUserLandMarks() const; // get the LandMarksOptions for a given landmark index CLandMarkOptions getUserLandMarkOptions(uint32 lmindex) const; // target the given landmark void targetLandmark(CCtrlButton *lm); // get the world position of a landmark or return vector Null if not found void getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos); // remove some landmarks if there are too many void removeExceedingUserLandMarks(uint maxNumber); //Remove and re-create UserLandMarks void updateUserLandMarks(); // set the selection axis pos & visibility void setSelectionAxis(bool active, const NLMISC::CVector2f &worldPos = NLMISC::CVector2f::Null); // convert a pos in world to a pos in the window, snapped to the best pixel (-> all elements jump to the next pixel at the same time when the map is panned, // avoiding annoying flickering) void worldToWindowSnapped(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const; void worldToWindow(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src) const; void mapToWindowSnapped(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const; // convert a pos in world to a pos in the map (in the [0, 1] range) void worldToMap(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src) const; // convert a pos in world to a pos in map (coords are in [0, 1] in the map) void mapToWorld(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src) const; // convert a pos in window in a pos in screen void windowToScreen(sint32 &destX, sint32 &destY, sint32 srcX, sint32 srcY) const; // convert a pos in the map to a pos on screen void mapToScreen(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const; // // convert a pos in the map to a pos relative to the current window (int result) void mapToWindow(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const; void mapToWindow(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src) const; // convert a pos on screen to a pos in map void screenToMap(NLMISC::CVector2f &dest, sint32 px, sint32 py) const; // convert a pos on window to a pos in map void windowToMap(NLMISC::CVector2f &dest, sint32 px, sint32 py) const; float getMeterPerPixel() const { return _MeterPerPixel; } // const NLMISC::CVector2f &getVisibleWorldMin() const { return _VisibleWorldMin; } const NLMISC::CVector2f &getVisibleWorldMax() const { return _VisibleWorldMax; } // compute pos of displayed map relative to this group (may be equal are smaller than this group extent // depending on the scale. void computeMapRectInsideGroup(sint32 &x, sint32 &y, sint32 &w, sint32 &h) const; // From CInterfaceElement : scale and offset must persist between virtual desktops virtual bool wantSerialConfig() const { return true; } // From CInterfaceElement virtual void serialConfig(NLMISC::IStream &f); // Server set all valid respawn points void addRespawnPoints(const CRespawnPointsMsg &rpm); bool isInDeathMode() { return _MapMode == MapMode_Death; } sint32 getRespawnSelected() const; void setRespawnSelected(sint32 nSpawnPointIndex); SMap *getCurMap() { return _CurMap; } SMap *getParentMap(SMap *map); const NLMISC::CVector2f &getWorldOffset() const { return _WorldOffset; } bool isIsland() const { return _IsIsland; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private: // A non rectangular button to click on zone of the map class CPolyButton : public CCtrlBase { public: CPolyButton(); virtual bool handleEvent (const CEventDescriptor &event); virtual void updateCoords(); virtual void draw () {} void drawPolyButton(); bool build(const NLLIGO::CPrimZone &concavePoly, CGroupMap *pMap, const std::string &sID); bool contains(const NLMISC::CVector2f &pos); public: NLLIGO::CPrimZone Zone; NLLIGO::CPrimZone ZoneReal; std::vector Polys; // Vertices in map pos std::vector PolysReal; // Vertices in screen pos CGroupMap *Map; std::string ID; static NL3D::UMaterial LineMat; }; typedef std::vector TPolyButtonVect; // a button representing a location on the map class CLandMarkButton : public CCtrlButton { public: NLMISC::CVector2f Pos; CContLandMark::TContLMType Type; bool HandleEvents; public: virtual bool handleEvent (const CEventDescriptor& event) { if (!HandleEvents) return false; return CCtrlButton::handleEvent(event); } virtual bool isCapturable() const { return HandleEvents; } virtual bool wantInstantContextHelp() const { return true; } // from CCtrlBase : avoid delay when the mouse is over CLandMarkButton(const TCtorParam ¶m) : CCtrlButton(param) { Type = CContLandMark::Unknown; Pos.set(0.f, 0.f); HandleEvents = true; } }; typedef std::vector TLandMarkButtonVect; // Text in the map class CLandMarkText : public CViewText { public: NLMISC::CVector2f Pos; CContLandMark::TContLMType Type; CLandMarkText(const TCtorParam ¶m) : CViewText(param) { Type = CContLandMark::Unknown; Pos.set(0.f, 0.f); } }; typedef std::vector TLandMarkTextVect; float getActualMaxScale() const; private: /////////////////////// // MULTIMAP HANDLING // /////////////////////// // Logical information to display the map CWorldSheet *_WorldSheet; SMap *_CurMap; CContinent *_CurContinent; // the last continent for which the map was displayed (can be NULL if world) NLMISC::CVector2f _MapMinCorner; // In world coordinates NLMISC::CVector2f _MapMaxCorner; bool _IsIsland; // true if current map is an island (island bitmap need not to be raised to the next // power of 2 TPolyButtonVect _PolyButtons; ////////////////////////////// // MAP & PLAYER POS TEXTURE // ////////////////////////////// std::string _PlayerPosTexName; // min height of the window sint32 _MinH; //sint32 _MinW; // offset of the map view (offset is in uv coords) NLMISC::CVector2f _Offset; float _UserScale; // user wanted scale float _Scale; // actual scale for drawing float _ScaleMax; float _ScaleMaxR2; float _MeterPerPixel; // float _WorldToMapDeltaX; float _WorldToMapDeltaY; // NLMISC::CVector2f _VisibleWorldMin; NLMISC::CVector2f _VisibleWorldMax; // continent map material NL3D::UMaterial _MapMaterial; // continent map texture NL3D::UTextureFile *_MapTF; // player pos map material NL3D::UMaterial _PlayerPosMaterial; // player pos map texture NL3D::UTextureFile *_PlayerPosTF; NL3D::UMaterial _FrustumMaterial; // continent map dimensions uint32 _MapTexW; // map texture width in pixels uint32 _MapTexH; // map texture height in pixels uint32 _PlayerPosTexW; // playerpos texture width in pixels uint32 _PlayerPosTexH; // playerpos texture height in pixels float _URatio; // == _MapTexW / nextPowerOf2(_MapTexW) float _VRatio; // == _MapTexH / nextPowerOf2(_MapTexH) bool _MapLoadFailure; // load failure for the map bool _PlayerPosLoadFailure; // load failure for the player pos sprite NLMISC::CVector2f _PlayerPos; // player pos ranging from 0.f to 1.f in the map NLMISC::CVector2f _OldPlayerPos; // old player pos in world // position of map relative to its parent. Maybe 0 unless the map is centred sint32 _MapX; sint32 _MapY; sint32 _MapW; sint32 _MapH; NLMISC::CRGBA _FrustumViewColor; NLMISC::CRGBA _FrustumViewColorOver; float _FrustumOverBlendFactor; uint _FrustumViewBlendTimeInMs; // selection axis CViewBitmap *_SelectionAxisH; CViewBitmap *_SelectionAxisV; //////////// // EVENTS // //////////// NLMISC::CVector2f _RightClickLastPos; bool _Panning; // does the user currently 'pan' the map ? bool _HasMoved; sint64 _PanStartDateInMs; sint64 _DeltaTimeBeforePanInMs; uint _DeltaPosBeforePan; // Panning sint32 _StartXForPaning; // start pos for panning (in map) sint32 _StartYForPaning; NLMISC::CVector2f _StartWorldOffsetForPaning; // World Offset Panning NLMISC::CVector2f _WorldOffset; /////////////// // LANDMARKS // /////////////// // landmarks of continent TLandMarkButtonVect _ContinentLM; TLandMarkTextVect _ContinentText; // landmarks from user TLandMarkButtonVect _UserLM; // landmarks for mission (one for each db entry) TLandMarkButtonVect _MissionLM; // landmark for target CLandMarkButton *_TargetLM; // landmark for home (user flat) CLandMarkButton *_HomeLM; // landmark for animals TLandMarkButtonVect _AnimalLM; // landmark for teammates TLandMarkButtonVect _TeammateLM; // CLandMarkOptions _ContinentLMOptions; CLandMarkOptions _MissionLMOptions; CLandMarkOptions _UserLMOptions; CLandMarkOptions _TargetLMOptions; CLandMarkOptions _HomeLMOptions; CLandMarkOptions _AnimalLMOptions; CLandMarkOptions _AnimalStableLMOptions; CLandMarkOptions _AnimalDeadLMOptions; CLandMarkOptions _TeammateLMOptions; // // last texts id for missions targets std::vector _MissionTargetTextIDs; // have the texts been received for mission targets ? std::vector _MissionTargetTextReceived; // ptr on db leaf for coordinates of special landmarks CCDBNodeLeaf *_TargetPos; CCDBNodeLeaf *_HomePos; // Animals State for landMarks std::vector > _AnimalPosStates; // Teammate State for landMarks std::vector > _TeammatePosStates; // Mission State for landMarks std::vector > _MissionPosStates; // ui id of compass for targetting std::string _CompassId; // user decorations typedef std::set TDecos; TDecos _Decos; ////////////////////// // Respawn handling // // //////////////// // enum TMapMode { MapMode_Normal = 0, MapMode_Death, MapMode_SpawnSquad }; TMapMode _MapMode; CLandMarkOptions _RespawnLMOptions; // landmark for respawn TLandMarkButtonVect _RespawnLM; sint32 _RespawnSelected; CViewBitmap *_RespawnSelectedBitmap; std::string _RespawnButton; // Positions are coming from server std::vector _RespawnPos; bool _RespawnPosReseted; CCtrlQuad *_FrustumView; // frustum on map for R2 editor // r2 islands std::vector _Islands; private: void loadPlayerPos(); void loadMap(); void unloadMap(); // void updateContinentInfo(); /** update a list of landmarks * This update their position on the map depending on offset and scale */ void updateLandMarkList(TLandMarkButtonVect &lm); void updateLandMarkTextList(TLandMarkTextVect &lm); // void removeLandMarks(TLandMarkButtonVect &lm); /** create landmarks from the continent (and remove previous ones) * this includes fixed and user landmarks */ void createContinentLandMarks(); void createLMWidgets(const std::vector &lms); // add a landmark in a list void addLandMark(TLandMarkButtonVect &destList, const NLMISC::CVector2f &pos, const ucstring &title, const CLandMarkOptions &options); // Create a landmark button, but do not add it to this group CLandMarkButton *createLandMarkButton(const CLandMarkOptions &options); // update a landmark button void updateLandMarkButton(CLandMarkButton *lmb, const CLandMarkOptions &options); // update the scale depending on the window size and the user scale void updateScale(); // compute real scale from user scale (this takes in account the size of the window) float computeRealScaleFromUserScale(float userScale) const; // compute the user scale needed to reach the given real scale on screen (this takes in account the size of the window) float computeUserScaleFromRealScale(float realScale) const; // eval map offset from its parent depending on scale void evalMapOffset(float userScale, float &scale, sint32 &x, sint32 &y) const; // compute _Offset from the _WorldOffset. Then clamp so that region outside the map can't be seen void computeOffsets(const NLMISC::CVector2f ¢erPos); void computeOffsets(); void updatePlayerPos(); // clamp offsets & change window size if necessary //void fitWindow(); // void updateButtonPos(CLandMarkButton &dest) const; // Update a landmark position from position given from the db as two int32's (before they're divided by 1000) void updateLMPosFromDBPos(CLandMarkButton *dest, sint32 x, sint32 y); // compute uv rect for current map (not including cropping) void computeUVRect(float &minU, float &minV, float &maxU, float &maxV) const; void updateSelectionAxisSize(); CViewBitmap *newSelectionAxis(NLMISC::CRGBA color); void computeFrustumQuad(CQuad &fruQuad) const; }; #endif