// 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);
virtual ~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(NLMISC::CQuad &fruQuad) const;
};
#endif