Make PickEntitiesAtPoint faster yielding 1-3% overall performance improvement. Fixes #2358. Also removes some trailing whitespace.
This was SVN commit r14532.
This commit is contained in:
parent
729a795a44
commit
8226d75715
@ -36,6 +36,8 @@ var placementSupport = new PlacementSupport();
|
||||
var mouseX = 0;
|
||||
var mouseY = 0;
|
||||
var mouseIsOverObject = false;
|
||||
// Distance to search for a selatable entity in. Bigger numbers are slower.
|
||||
var SELECTION_SEARCH_RADIUS = 100;
|
||||
|
||||
// Number of pixels the mouse can move before the action is considered a drag
|
||||
var maxDragDelta = 4;
|
||||
@ -495,7 +497,7 @@ function determineAction(x, y, fromMinimap)
|
||||
var targets = [];
|
||||
var target = undefined;
|
||||
if (!fromMinimap)
|
||||
targets = Engine.PickEntitiesAtPoint(x, y);
|
||||
targets = Engine.PickEntitiesAtPoint(x, y, SELECTION_SEARCH_RADIUS);
|
||||
|
||||
if (targets.length)
|
||||
target = targets[0];
|
||||
@ -1108,7 +1110,7 @@ function handleInputAfterGui(ev)
|
||||
{
|
||||
case "mousemotion":
|
||||
// Highlight the first hovered entity (if any)
|
||||
var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
|
||||
var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y, SELECTION_SEARCH_RADIUS);
|
||||
if (ents.length)
|
||||
g_Selection.setHighlightList([ents[0]]);
|
||||
else
|
||||
@ -1162,7 +1164,7 @@ function handleInputAfterGui(ev)
|
||||
{
|
||||
case "mousemotion":
|
||||
// Highlight the first hovered entity (if any)
|
||||
var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
|
||||
var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y, SELECTION_SEARCH_RADIUS);
|
||||
if (ents.length)
|
||||
g_Selection.setHighlightList([ents[0]]);
|
||||
else
|
||||
@ -1212,14 +1214,14 @@ function handleInputAfterGui(ev)
|
||||
return false;
|
||||
}
|
||||
|
||||
var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
|
||||
var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y, SELECTION_SEARCH_RADIUS);
|
||||
g_Selection.setHighlightList(ents);
|
||||
return false;
|
||||
|
||||
case "mousebuttonup":
|
||||
if (ev.button == SDL_BUTTON_LEFT)
|
||||
{
|
||||
var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y);
|
||||
var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y, SELECTION_SEARCH_RADIUS);
|
||||
if (!ents.length)
|
||||
{
|
||||
if (!Engine.HotkeyIsPressed("selection.add") && !Engine.HotkeyIsPressed("selection.remove"))
|
||||
|
@ -293,7 +293,14 @@
|
||||
|
||||
<object size="0 128 100%-18 144" type="text" style="devCommandsText">Restrict camera</object>
|
||||
<object size="100%-16 128 100% 144" type="checkbox" style="StoneCrossBox" checked="true">
|
||||
<action on="Press">Engine.GameView_SetConstrainCameraEnabled(this.checked);</action>
|
||||
<action on="Press">
|
||||
Engine.GameView_SetConstrainCameraEnabled(this.checked);
|
||||
// Make selection more durable at the expense of speed if unchecked.
|
||||
if (this.checked)
|
||||
SELECTION_SEARCH_RADIUS -= 200;
|
||||
else
|
||||
SELECTION_SEARCH_RADIUS += 200;
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<object size="0 144 100%-18 160" type="text" style="devCommandsText">Reveal map</object>
|
||||
|
@ -148,9 +148,9 @@ void PostNetworkCommand(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal cmd)
|
||||
cmpCommandQueue->PostNetworkCommand(cmd2);
|
||||
}
|
||||
|
||||
std::vector<entity_id_t> PickEntitiesAtPoint(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x, int y)
|
||||
std::vector<entity_id_t> PickEntitiesAtPoint(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x, int y, int range)
|
||||
{
|
||||
return EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, g_Game->GetPlayerID(), false);
|
||||
return EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, g_Game->GetPlayerID(), false, range);
|
||||
}
|
||||
|
||||
std::vector<entity_id_t> PickFriendlyEntitiesInRect(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int x0, int y0, int x1, int y1, int player)
|
||||
@ -804,7 +804,7 @@ void GuiScriptingInit(ScriptInterface& scriptInterface)
|
||||
scriptInterface.RegisterFunction<void, CScriptVal, &PostNetworkCommand>("PostNetworkCommand");
|
||||
|
||||
// Entity picking
|
||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, &PickEntitiesAtPoint>("PickEntitiesAtPoint");
|
||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, &PickEntitiesAtPoint>("PickEntitiesAtPoint");
|
||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickFriendlyEntitiesInRect>("PickFriendlyEntitiesInRect");
|
||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, &PickFriendlyEntitiesOnScreen>("PickFriendlyEntitiesOnScreen");
|
||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, bool, bool, &PickSimilarFriendlyEntities>("PickSimilarFriendlyEntities");
|
||||
|
@ -97,17 +97,17 @@ static u32 CalcSharedLosMask(std::vector<player_id_t> players)
|
||||
* Checks whether v is in a parabolic range of (0,0,0)
|
||||
* The highest point of the paraboloid is (0,range/2,0)
|
||||
* and the circle of distance 'range' around (0,0,0) on height y=0 is part of the paraboloid
|
||||
*
|
||||
*
|
||||
* Avoids sqrting and overflowing.
|
||||
*/
|
||||
static bool InParabolicRange(CFixedVector3D v, fixed range)
|
||||
static bool InParabolicRange(CFixedVector3D v, fixed range)
|
||||
{
|
||||
i32 x = v.X.GetInternalValue(); // abs(x) <= 2^31
|
||||
i32 z = v.Z.GetInternalValue();
|
||||
u64 xx = (u64)FIXED_MUL_I64_I32_I32(x, x); // xx <= 2^62
|
||||
u64 zz = (u64)FIXED_MUL_I64_I32_I32(z, z);
|
||||
i64 d2 = (xx + zz) >> 1; // d2 <= 2^62 (no overflow)
|
||||
|
||||
|
||||
i32 y = v.Y.GetInternalValue();
|
||||
i32 c = range.GetInternalValue();
|
||||
i32 c_2 = c >> 1;
|
||||
@ -327,7 +327,7 @@ public:
|
||||
// will get confused when trying to run from enemies
|
||||
m_LosRevealAll.resize(MAX_LOS_PLAYER_ID+2,false);
|
||||
m_SharedLosMasks.resize(MAX_LOS_PLAYER_ID+2,0);
|
||||
|
||||
|
||||
m_LosCircular = false;
|
||||
m_TerrainVerticesPerSide = 0;
|
||||
|
||||
@ -601,6 +601,11 @@ public:
|
||||
debug_warn(L"inconsistent subdivs");
|
||||
}
|
||||
|
||||
SpatialSubdivision* GetSubdivision()
|
||||
{
|
||||
return & m_Subdivision;
|
||||
}
|
||||
|
||||
// Reinitialise subdivisions and LOS data, based on entity data
|
||||
void ResetDerivedData(bool skipLosState)
|
||||
{
|
||||
@ -844,7 +849,7 @@ public:
|
||||
if (!query.enabled)
|
||||
continue;
|
||||
|
||||
CmpPtr<ICmpPosition> cmpSourcePosition(query.source);
|
||||
CmpPtr<ICmpPosition> cmpSourcePosition(query.source);
|
||||
if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld())
|
||||
continue;
|
||||
|
||||
@ -858,9 +863,9 @@ public:
|
||||
removed.clear();
|
||||
// Return the 'added' list sorted by distance from the entity
|
||||
// (Don't bother sorting 'removed' because they might not even have positions or exist any more)
|
||||
std::set_difference(results.begin(), results.end(), query.lastMatch.begin(), query.lastMatch.end(),
|
||||
std::set_difference(results.begin(), results.end(), query.lastMatch.begin(), query.lastMatch.end(),
|
||||
std::back_inserter(added));
|
||||
std::set_difference(query.lastMatch.begin(), query.lastMatch.end(), results.begin(), results.end(),
|
||||
std::set_difference(query.lastMatch.begin(), query.lastMatch.end(), results.begin(), results.end(),
|
||||
std::back_inserter(removed));
|
||||
if (added.empty() && removed.empty())
|
||||
continue;
|
||||
@ -927,7 +932,7 @@ public:
|
||||
}
|
||||
}
|
||||
// Not the entire world, so check a parabolic range, or a regular range
|
||||
else if (q.parabolic)
|
||||
else if (q.parabolic)
|
||||
{
|
||||
// elevationBonus is part of the 3D position, as the source is really that much heigher
|
||||
CmpPtr<ICmpPosition> cmpSourcePosition(q.source);
|
||||
@ -944,7 +949,7 @@ public:
|
||||
|
||||
if (!TestEntityQuery(q, it->first, it->second))
|
||||
continue;
|
||||
|
||||
|
||||
CmpPtr<ICmpPosition> cmpSecondPosition(GetSimContext(), ents[i]);
|
||||
if (!cmpSecondPosition || !cmpSecondPosition->IsInWorld())
|
||||
continue;
|
||||
@ -952,8 +957,8 @@ public:
|
||||
|
||||
// Restrict based on precise distance
|
||||
if (!InParabolicRange(
|
||||
CFixedVector3D(it->second.x, secondPosition.Y, it->second.z)
|
||||
- pos3d,
|
||||
CFixedVector3D(it->second.x, secondPosition.Y, it->second.z)
|
||||
- pos3d,
|
||||
q.maxRange))
|
||||
continue;
|
||||
|
||||
@ -968,12 +973,12 @@ public:
|
||||
}
|
||||
}
|
||||
// check a regular range (i.e. not the entire world, and not parabolic)
|
||||
else
|
||||
else
|
||||
{
|
||||
// Get a quick list of entities that are potentially in range
|
||||
SpatialQueryArray ents;
|
||||
m_Subdivision.GetNear(ents, pos, q.maxRange);
|
||||
|
||||
|
||||
for (int i = 0; i < ents.size(); ++i)
|
||||
{
|
||||
EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
|
||||
@ -1002,7 +1007,7 @@ public:
|
||||
virtual entity_pos_t GetElevationAdaptedRange(CFixedVector3D pos, CFixedVector3D rot, entity_pos_t range, entity_pos_t elevationBonus, entity_pos_t angle)
|
||||
{
|
||||
entity_pos_t r = entity_pos_t::Zero() ;
|
||||
|
||||
|
||||
pos.Y += elevationBonus;
|
||||
entity_pos_t orientation = rot.Y;
|
||||
|
||||
@ -1022,26 +1027,26 @@ public:
|
||||
{
|
||||
r = r + CFixedVector2D(coords[2*i],coords[2*i+1]).Length() / part;
|
||||
}
|
||||
|
||||
|
||||
return r;
|
||||
|
||||
|
||||
}
|
||||
|
||||
virtual std::vector<entity_pos_t> getParabolicRangeForm(CFixedVector3D pos, entity_pos_t maxRange, entity_pos_t cutoff, entity_pos_t minAngle, entity_pos_t maxAngle, int numberOfSteps)
|
||||
virtual std::vector<entity_pos_t> getParabolicRangeForm(CFixedVector3D pos, entity_pos_t maxRange, entity_pos_t cutoff, entity_pos_t minAngle, entity_pos_t maxAngle, int numberOfSteps)
|
||||
{
|
||||
|
||||
|
||||
// angle = 0 goes in the positive Z direction
|
||||
entity_pos_t precision = entity_pos_t::FromInt((int)TERRAIN_TILE_SIZE)/8;
|
||||
|
||||
std::vector<entity_pos_t> r;
|
||||
|
||||
|
||||
|
||||
CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity());
|
||||
CmpPtr<ICmpWaterManager> cmpWaterManager(GetSystemEntity());
|
||||
entity_pos_t waterLevel = cmpWaterManager->GetWaterLevel(pos.X,pos.Z);
|
||||
entity_pos_t thisHeight = pos.Y > waterLevel ? pos.Y : waterLevel;
|
||||
|
||||
if (cmpTerrain)
|
||||
if (cmpTerrain)
|
||||
{
|
||||
for (int i = 0; i < numberOfSteps; i++)
|
||||
{
|
||||
@ -1064,7 +1069,7 @@ public:
|
||||
r.push_back(maxVector.Y);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Loop until vectors come close enough
|
||||
while ((maxVector - minVector).CompareLength(precision) > 0)
|
||||
{
|
||||
@ -1083,26 +1088,26 @@ public:
|
||||
minVector = newVector;
|
||||
minDistance = newDistance;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// new vector is out parabolic range, so this is a new maxVector
|
||||
maxVector = newVector;
|
||||
maxDistance = newDistance;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
r.push_back(maxVector.X);
|
||||
r.push_back(maxVector.Y);
|
||||
|
||||
|
||||
}
|
||||
r.push_back(r[0]);
|
||||
r.push_back(r[1]);
|
||||
r.push_back(r[1]);
|
||||
|
||||
}
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Query ConstructQuery(entity_id_t source,
|
||||
entity_pos_t minRange, entity_pos_t maxRange,
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flagsMask)
|
||||
@ -1150,7 +1155,7 @@ public:
|
||||
return;
|
||||
static CColor disabledRingColour(1, 0, 0, 1); // red
|
||||
static CColor enabledRingColour(0, 1, 0, 1); // green
|
||||
static CColor subdivColour(0, 0, 1, 1); // blue
|
||||
static CColor subdivColour(0, 0, 1, 1); // blue
|
||||
static CColor rayColour(1, 1, 0, 0.2f);
|
||||
|
||||
if (m_DebugOverlayDirty)
|
||||
@ -1173,26 +1178,26 @@ public:
|
||||
m_DebugOverlayLines.back().m_Color = (q.enabled ? enabledRingColour : disabledRingColour);
|
||||
SimRender::ConstructCircleOnGround(GetSimContext(), pos.X.ToFloat(), pos.Y.ToFloat(), q.maxRange.ToFloat(), m_DebugOverlayLines.back(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
else
|
||||
{
|
||||
// elevation bonus is part of the 3D position. As if the unit is really that much higher
|
||||
CFixedVector3D pos = cmpSourcePosition->GetPosition();
|
||||
CFixedVector3D pos = cmpSourcePosition->GetPosition();
|
||||
pos.Y += q.elevationBonus;
|
||||
|
||||
std::vector<entity_pos_t> coords;
|
||||
|
||||
|
||||
// Get the outline from cache if possible
|
||||
if (ParabolicRangesOutlines.find(q.source.GetId()) != ParabolicRangesOutlines.end())
|
||||
{
|
||||
EntityParabolicRangeOutline e = ParabolicRangesOutlines[q.source.GetId()];
|
||||
if (e.position == pos && e.range == q.maxRange)
|
||||
if (e.position == pos && e.range == q.maxRange)
|
||||
{
|
||||
// outline is cached correctly, use it
|
||||
coords = e.outline;
|
||||
coords = e.outline;
|
||||
}
|
||||
else
|
||||
{
|
||||
// outline was cached, but important parameters changed
|
||||
// outline was cached, but important parameters changed
|
||||
// (position, elevation, range)
|
||||
// update it
|
||||
coords = getParabolicRangeForm(pos,q.maxRange,q.maxRange*2, entity_pos_t::Zero(), entity_pos_t::FromFloat(2.0f*3.14f),70);
|
||||
@ -1202,9 +1207,9 @@ public:
|
||||
ParabolicRangesOutlines[q.source.GetId()] = e;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
// outline wasn't cached (first time you enable the range overlay
|
||||
// outline wasn't cached (first time you enable the range overlay
|
||||
// or you created a new entiy)
|
||||
// cache a new outline
|
||||
coords = getParabolicRangeForm(pos,q.maxRange,q.maxRange*2, entity_pos_t::Zero(), entity_pos_t::FromFloat(2.0f*3.14f),70);
|
||||
@ -1215,10 +1220,10 @@ public:
|
||||
e.outline = coords;
|
||||
ParabolicRangesOutlines[q.source.GetId()] = e;
|
||||
}
|
||||
|
||||
|
||||
CColor thiscolor = q.enabled ? enabledRingColour : disabledRingColour;
|
||||
|
||||
// draw the outline (piece by piece)
|
||||
|
||||
// draw the outline (piece by piece)
|
||||
for (size_t i = 3; i < coords.size(); i += 2)
|
||||
{
|
||||
std::vector<float> c;
|
||||
@ -1268,7 +1273,7 @@ public:
|
||||
{
|
||||
m_DebugOverlayLines.push_back(SOverlayLine());
|
||||
m_DebugOverlayLines.back().m_Color = subdivColour;
|
||||
|
||||
|
||||
float xpos = x*divSize + divSize/2;
|
||||
float zpos = y*divSize + divSize/2;
|
||||
SimRender::ConstructSquareOnGround(GetSimContext(), xpos, zpos, divSize, divSize, 0.0f,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "simulation2/system/Interface.h"
|
||||
#include "simulation2/helpers/Position.h"
|
||||
#include "simulation2/helpers/Player.h"
|
||||
#include "simulation2/helpers/Spatial.h"
|
||||
|
||||
#include "graphics/Terrain.h" // for TERRAIN_TILE_SIZE
|
||||
|
||||
@ -72,6 +73,12 @@ public:
|
||||
*/
|
||||
typedef u32 tag_t;
|
||||
|
||||
/**
|
||||
* Access the spatial subdivision kept by the range manager.
|
||||
* @return pointer to spatial subdivision structure.
|
||||
*/
|
||||
virtual SpatialSubdivision* GetSubdivision() = 0;
|
||||
|
||||
/**
|
||||
* Set the bounds of the world.
|
||||
* Entities should not be outside the bounds (else efficiency will suffer).
|
||||
@ -118,12 +125,12 @@ public:
|
||||
entity_pos_t minRange, entity_pos_t maxRange, std::vector<int> owners, int requiredInterface, u8 flags) = 0;
|
||||
|
||||
/**
|
||||
* Construct an active query of a paraboloic form around the unit.
|
||||
* Construct an active query of a paraboloic form around the unit.
|
||||
* The query will be disabled by default.
|
||||
* @param source the entity around which the range will be computed.
|
||||
* @param minRange non-negative minimum horizontal distance in metres (inclusive). MinRange doesn't do parabolic checks.
|
||||
* @param maxRange non-negative maximum distance in metres (inclusive) for units on the same elevation;
|
||||
* or -1.0 to ignore distance.
|
||||
* @param maxRange non-negative maximum distance in metres (inclusive) for units on the same elevation;
|
||||
* or -1.0 to ignore distance.
|
||||
* For units on a different elevation, a physical correct paraboloid with height=maxRange/2 above the unit is used to query them
|
||||
* @param elevationBonus extra bonus so the source can be placed higher and shoot further
|
||||
* @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
|
||||
|
@ -27,26 +27,43 @@
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
#include "simulation2/components/ICmpSelectable.h"
|
||||
#include "simulation2/components/ICmpVisual.h"
|
||||
#include "simulation2/helpers/Spatial.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Profiler2.h"
|
||||
|
||||
std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables)
|
||||
std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables, int range)
|
||||
{
|
||||
PROFILE2("PickEntitiesAtPoint");
|
||||
CVector3D origin, dir;
|
||||
camera.BuildCameraRay(screenX, screenY, origin, dir);
|
||||
|
||||
CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
|
||||
ENSURE(cmpRangeManager);
|
||||
|
||||
std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs
|
||||
/* We try to approximate where the mouse is hovering by drawing a ray from
|
||||
* the center of the camera and through the mouse then taking the position
|
||||
* at which the ray intersects the terrain. */
|
||||
// TODO: Do this smarter without being slow.
|
||||
CVector3D pos3d = camera.GetWorldCoordinates(screenX, screenY, true);
|
||||
// Change the position to 2D by removing the terrain height.
|
||||
CFixedVector2D pos(fixed::FromFloat(pos3d.X), fixed::FromFloat(pos3d.Z));
|
||||
|
||||
const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
|
||||
for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
|
||||
// Get a rough group of entities using our approximated origin.
|
||||
SpatialQueryArray ents;
|
||||
cmpRangeManager->GetSubdivision()->GetNear(ents, pos, entity_pos_t::FromInt(range));
|
||||
|
||||
// Filter for relevent entities and calculate precise distances.
|
||||
std::vector<std::pair<float, entity_id_t>> hits; // (dist^2, entity) pairs
|
||||
for (int i = 0; i < ents.size(); ++i)
|
||||
{
|
||||
entity_id_t ent = it->first;
|
||||
CEntityHandle handle = it->second->GetEntityHandle();
|
||||
CmpPtr<ICmpSelectable> cmpSelectable(simulation, ents[i]);
|
||||
if (!cmpSelectable)
|
||||
continue;
|
||||
|
||||
CEntityHandle handle = cmpSelectable->GetEntityHandle();
|
||||
|
||||
// Check if this entity is only selectable in Atlas
|
||||
if (!allowEditorSelectables && static_cast<ICmpSelectable*>(it->second)->IsEditorOnly())
|
||||
if (!allowEditorSelectables && cmpSelectable->IsEditorOnly())
|
||||
continue;
|
||||
|
||||
// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
|
||||
@ -86,12 +103,11 @@ std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simu
|
||||
}
|
||||
|
||||
// Find the perpendicular distance from the object's centre to the picker ray
|
||||
|
||||
float dist2;
|
||||
CVector3D closest = origin + dir * (center - origin).Dot(dir);
|
||||
dist2 = (closest - center).LengthSquared();
|
||||
|
||||
hits.push_back(std::make_pair(dist2, ent));
|
||||
hits.push_back(std::make_pair(dist2, ents[i]));
|
||||
}
|
||||
|
||||
// Sort hits by distance
|
||||
@ -107,6 +123,7 @@ std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simu
|
||||
|
||||
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)
|
||||
{
|
||||
PROFILE2("PickEntitiesInRect");
|
||||
// Make sure sx0 <= sx1, and sy0 <= sy1
|
||||
if (sx0 > sx1)
|
||||
std::swap(sx0, sx1);
|
||||
@ -148,7 +165,6 @@ std::vector<entity_id_t> EntitySelection::PickEntitiesInRect(CSimulation2& simul
|
||||
CVector3D position = cmpVisual->GetPosition();
|
||||
|
||||
// Reject if it's not on-screen (e.g. it's behind the camera)
|
||||
|
||||
if (!camera.GetFrustum().IsPointVisible(position))
|
||||
continue;
|
||||
|
||||
@ -168,6 +184,7 @@ std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simu
|
||||
const std::string& templateName, player_id_t owner, bool includeOffScreen, bool matchRank,
|
||||
bool allowEditorSelectables, bool allowFoundations)
|
||||
{
|
||||
PROFILE2("PickSimilarEntities");
|
||||
CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY);
|
||||
CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
|
||||
|
||||
|
@ -43,10 +43,11 @@ namespace EntitySelection
|
||||
* this value is ignored as the whole map is revealed.
|
||||
* @param allowEditorSelectables if true, all entities with the ICmpSelectable interface
|
||||
* will be selected (including decorative actors), else only those selectable ingame.
|
||||
* @param range Approximate range to check for entity in.
|
||||
*
|
||||
* @return ordered list of selected entities with the closest first.
|
||||
*/
|
||||
std::vector<entity_id_t> PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables);
|
||||
std::vector<entity_id_t> PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables, int range = 200);
|
||||
|
||||
/**
|
||||
* Finds all selectable entities within the given screen coordinate rectangle,
|
||||
|
@ -18,6 +18,7 @@
|
||||
#ifndef INCLUDED_SPATIAL
|
||||
#define INCLUDED_SPATIAL
|
||||
|
||||
#include "simulation2/system/Component.h"
|
||||
#include "simulation2/serialization/SerializeTemplates.h"
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user