Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Selection.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. 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 General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "Selection.h"
21 
22 #include "graphics/Camera.h"
30 #include "ps/CLogger.h"
31 
32 std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables)
33 {
34  CVector3D origin, dir;
35  camera.BuildCameraRay(screenX, screenY, origin, dir);
36 
37  CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
38  ENSURE(cmpRangeManager);
39 
40  std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs
41 
43  for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
44  {
45  entity_id_t ent = it->first;
46  CEntityHandle handle = it->second->GetEntityHandle();
47 
48  // Check if this entity is only selectable in Atlas
49  if (!allowEditorSelectables && static_cast<ICmpSelectable*>(it->second)->IsEditorOnly())
50  continue;
51 
52  // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
53  if (cmpRangeManager->GetLosVisibility(handle, player) == ICmpRangeManager::VIS_HIDDEN)
54  continue;
55 
56  CmpPtr<ICmpVisual> cmpVisual(handle);
57  if (!cmpVisual)
58  continue;
59 
60  CVector3D center;
61  float tmin, tmax;
62 
63  CBoundingBoxOriented selectionBox = cmpVisual->GetSelectionBox();
64  if (selectionBox.IsEmpty())
65  {
66  if (!allowEditorSelectables)
67  continue;
68 
69  // Fall back to using old AABB selection method for decals
70  // see: http://trac.wildfiregames.com/ticket/1032
71  CBoundingBoxAligned aABBox = cmpVisual->GetBounds();
72  if (aABBox.IsEmpty())
73  continue;
74 
75  if (!aABBox.RayIntersect(origin, dir, tmin, tmax))
76  continue;
77 
78  aABBox.GetCentre(center);
79  }
80  else
81  {
82  if (!selectionBox.RayIntersect(origin, dir, tmin, tmax))
83  continue;
84 
85  center = selectionBox.m_Center;
86  }
87 
88  // Find the perpendicular distance from the object's centre to the picker ray
89 
90  float dist2;
91  CVector3D closest = origin + dir * (center - origin).Dot(dir);
92  dist2 = (closest - center).LengthSquared();
93 
94  hits.push_back(std::make_pair(dist2, ent));
95  }
96 
97  // Sort hits by distance
98  std::sort(hits.begin(), hits.end()); // lexicographic comparison
99 
100  // Extract the entity IDs
101  std::vector<entity_id_t> hitEnts;
102  hitEnts.reserve(hits.size());
103  for (size_t i = 0; i < hits.size(); ++i)
104  hitEnts.push_back(hits[i].second);
105  return hitEnts;
106 }
107 
108 std::vector<entity_id_t> EntitySelection::PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, player_id_t owner, bool allowEditorSelectables)
109 {
110  // Make sure sx0 <= sx1, and sy0 <= sy1
111  if (sx0 > sx1)
112  std::swap(sx0, sx1);
113  if (sy0 > sy1)
114  std::swap(sy0, sy1);
115 
116  CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
117  ENSURE(cmpRangeManager);
118 
119  std::vector<entity_id_t> hitEnts;
120 
122  for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
123  {
124  entity_id_t ent = it->first;
125  CEntityHandle handle = it->second->GetEntityHandle();
126 
127  // Check if this entity is only selectable in Atlas
128  if (static_cast<ICmpSelectable*>(it->second)->IsEditorOnly() && !allowEditorSelectables)
129  continue;
130 
131  // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
132  if (cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
133  continue;
134 
135  // Ignore entities not owned by 'owner'
136  CmpPtr<ICmpOwnership> cmpOwnership(handle);
137  if (owner != INVALID_PLAYER && (!cmpOwnership || cmpOwnership->GetOwner() != owner))
138  continue;
139 
140  // Find the current interpolated model position.
141  // (We just use the centre position and not the whole bounding box, because maybe
142  // that's better for users trying to select objects in busy areas)
143 
144  CmpPtr<ICmpVisual> cmpVisual(handle);
145  if (!cmpVisual)
146  continue;
147 
148  CVector3D position = cmpVisual->GetPosition();
149 
150  // Reject if it's not on-screen (e.g. it's behind the camera)
151 
152  if (!camera.GetFrustum().IsPointVisible(position))
153  continue;
154 
155  // Compare screen-space coordinates
156  float x, y;
157  camera.GetScreenCoordinates(position, x, y);
158  int ix = (int)x;
159  int iy = (int)y;
160  if (sx0 <= ix && ix <= sx1 && sy0 <= iy && iy <= sy1)
161  hitEnts.push_back(ent);
162  }
163 
164  return hitEnts;
165 }
166 
167 std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera,
168  const std::string& templateName, player_id_t owner, bool includeOffScreen, bool matchRank,
169  bool allowEditorSelectables, bool allowFoundations)
170 {
171  CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY);
172  CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
173 
174  std::vector<entity_id_t> hitEnts;
175 
177  for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
178  {
179  entity_id_t ent = it->first;
180  CEntityHandle handle = it->second->GetEntityHandle();
181 
182  // Check if this entity is only selectable in Atlas
183  if (static_cast<ICmpSelectable*>(it->second)->IsEditorOnly() && !allowEditorSelectables)
184  continue;
185 
186  if (matchRank)
187  {
188  // Exact template name matching, optionally also allowing foundations
189  std::string curTemplateName = cmpTemplateManager->GetCurrentTemplateName(ent);
190  bool matches = (curTemplateName == templateName ||
191  (allowFoundations && curTemplateName.substr(0, 11) == "foundation|" && curTemplateName.substr(11) == templateName));
192  if (!matches)
193  continue;
194  }
195 
196  // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
197  // In this case, the checking is done to avoid selecting garrisoned units
198  if (cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
199  continue;
200 
201  // Ignore entities not owned by 'owner'
202  CmpPtr<ICmpOwnership> cmpOwnership(simulation.GetSimContext(), ent);
203  if (owner != INVALID_PLAYER && (!cmpOwnership || cmpOwnership->GetOwner() != owner))
204  continue;
205 
206  // Ignore off screen entities
207  if (!includeOffScreen)
208  {
209  // Find the current interpolated model position.
210  CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent);
211  if (!cmpVisual)
212  continue;
213  CVector3D position = cmpVisual->GetPosition();
214 
215  // Reject if it's not on-screen (e.g. it's behind the camera)
216  if (!camera.GetFrustum().IsPointVisible(position))
217  continue;
218  }
219 
220  if (!matchRank)
221  {
222  // Match by selection group name
223  // (This is relatively expensive since it involves script calls, so do it after all other tests)
224  CmpPtr<ICmpIdentity> cmpIdentity(simulation.GetSimContext(), ent);
225  if (!cmpIdentity || cmpIdentity->GetSelectionGroupName() != templateName)
226  continue;
227  }
228 
229  hitEnts.push_back(ent);
230  }
231 
232  return hitEnts;
233 }
const CSimContext & GetSimContext() const
bool RayIntersect(const CVector3D &origin, const CVector3D &dir, float &tMin, float &tMax) const
Check if a given ray intersects this box.
virtual CVector3D GetPosition()=0
Get the world-space position of the base point of the object&#39;s visual representation.
Object wrapping an entity_id_t, with a SEntityComponentCache to support fast QueryInterface() / CmpPt...
Definition: Entity.h:80
std::vector< entity_id_t > PickSimilarEntities(CSimulation2 &simulation, const CCamera &camera, const std::string &templateName, player_id_t owner, bool includeOffScreen, bool matchRank, bool allowEditorSelectables, bool allowFoundations)
Finds all entities with the given entity template name, belonging to the given player.
Definition: Selection.cpp:167
static void swap(UniqueRange &p1, UniqueRange &p2)
Definition: unique_range.h:176
const CFrustum & GetFrustum() const
Definition: Camera.h:62
std::vector< entity_id_t > PickEntitiesAtPoint(CSimulation2 &simulation, const CCamera &camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables)
Finds all selectable entities under the given screen coordinates.
Definition: Selection.cpp:32
void GetCentre(CVector3D &centre) const
CVector3D m_Center
Centroid location of the box.
bool IsPointVisible(const CVector3D &point) const
Definition: Frustum.cpp:63
const InterfaceListUnordered & GetEntitiesWithInterfaceUnordered(int iid)
Returns a list of components implementing the given interface, and their associated entities...
virtual CBoundingBoxOriented GetSelectionBox()=0
Get the oriented world-space bounding box of the object&#39;s visual representation, clipped at the Y=0 p...
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton &#39;system&#39; components.
Definition: Entity.h:44
virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player, bool forceRetainInFog=false)=0
Returns the visibility status of the given entity, with respect to the given player.
Public API for simulation system.
Definition: Simulation2.h:46
int32_t player_id_t
valid player IDs are non-negative (see ICmpOwnership)
Definition: Player.h:24
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
Definition: Camera.h:39
virtual player_id_t GetOwner()=0
void GetScreenCoordinates(const CVector3D &world, float &x, float &y) const
Definition: Camera.cpp:192
A simplified syntax for accessing entity components.
Definition: CmpPtr.h:55
bool RayIntersect(const CVector3D &origin, const CVector3D &dir, float &tmin, float &tmax) const
Check if a given ray intersects this AABB.
void BuildCameraRay(int px, int py, CVector3D &origin, CVector3D &dir) const
Definition: Camera.cpp:167
virtual CBoundingBoxAligned GetBounds()=0
Get the world-space bounding box of the object&#39;s visual representation.
boost::unordered_map< entity_id_t, IComponent * > InterfaceListUnordered
Definition: Simulation2.h:197
static float LengthSquared(const SVec3 v)
Definition: mikktspace.cpp:107
static Handle handle(size_t idx, u64 tag)
Definition: h_mgr.cpp:121
virtual std::string GetCurrentTemplateName(entity_id_t ent)=0
Returns the name of the template most recently specified for the entity &#39;ent&#39;.
u32 entity_id_t
Entity ID type.
Definition: Entity.h:24
static const player_id_t INVALID_PLAYER
Definition: Player.h:26
Helper functions related to entity selection.
std::vector< entity_id_t > PickEntitiesInRect(CSimulation2 &simulation, const CCamera &camera, int sx0, int sy0, int sx1, int sy1, player_id_t owner, bool allowEditorSelectables)
Finds all selectable entities within the given screen coordinate rectangle, belonging to the given pl...
Definition: Selection.cpp:108