Ticket #2961: pickEntsInRectRework.patch

File pickEntsInRectRework.patch, 4.6 KB (added by Alex, 9 years ago)

Rework of the PickEntitiesInRect? method - It takes ~0ms until it returns now, even on huge maps in late-game!

  • source/simulation2/helpers/Selection.cpp

    diff --git a/source/simulation2/helpers/Selection.cpp b/source/simulation2/helpers/Selection.cpp
    index d0e3d04..30f847c 100644
    a b std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simu  
    121121    return hitEnts;
    122122}
    123123
     124/**
     125 * Used by EntitySelection::PickEntitiesInRect.
     126 */
     127static bool CheckEntityVisibleAndInRect(CEntityHandle handle, CmpPtr<ICmpRangeManager> cmpRangeManager, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, player_id_t owner, bool allowEditorSelectables)
     128{
     129    // Check if this entity is only selectable in Atlas
     130    CmpPtr<ICmpSelectable> cmpSelectable(handle);
     131    if (!cmpSelectable || (!allowEditorSelectables && cmpSelectable->IsEditorOnly()))
     132        return false;
     133
     134    // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
     135    if (cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
     136        return false;
     137
     138    // Find the current interpolated model position.
     139    // (We just use the centre position and not the whole bounding box, because maybe
     140    // that's better for users trying to select objects in busy areas)
     141
     142    CmpPtr<ICmpVisual> cmpVisual(handle);
     143    if (!cmpVisual)
     144        return false;
     145
     146    CVector3D position = cmpVisual->GetPosition();
     147
     148    // Reject if it's not on-screen (e.g. it's behind the camera)
     149    if (!camera.GetFrustum().IsPointVisible(position))
     150        return false;
     151
     152    // Compare screen-space coordinates
     153    float x, y;
     154    camera.GetScreenCoordinates(position, x, y);
     155    int ix = (int)x;
     156    int iy = (int)y;
     157    return sx0 <= ix && ix <= sx1 && sy0 <= iy && iy <= sy1;
     158}
     159
    124160std::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)
    125161{
    126162    PROFILE2("PickEntitiesInRect");
    std::vector<entity_id_t> EntitySelection::PickEntitiesInRect(CSimulation2& simul  
    135171
    136172    std::vector<entity_id_t> hitEnts;
    137173
    138     const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
    139     for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
     174    if(owner != INVALID_PLAYER)
    140175    {
    141         entity_id_t ent = it->first;
    142         CEntityHandle handle = it->second->GetEntityHandle();
    143 
    144         // Check if this entity is only selectable in Atlas
    145         if (static_cast<ICmpSelectable*>(it->second)->IsEditorOnly() && !allowEditorSelectables)
    146             continue;
    147 
    148         // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
    149         if (cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
    150             continue;
    151 
    152         // Ignore entities not owned by 'owner'
    153         CmpPtr<ICmpOwnership> cmpOwnership(handle);
    154         if (owner != INVALID_PLAYER && (!cmpOwnership || cmpOwnership->GetOwner() != owner))
    155             continue;
    156 
    157         // Find the current interpolated model position.
    158         // (We just use the centre position and not the whole bounding box, because maybe
    159         // that's better for users trying to select objects in busy areas)
    160 
    161         CmpPtr<ICmpVisual> cmpVisual(handle);
    162         if (!cmpVisual)
    163             continue;
    164 
    165         CVector3D position = cmpVisual->GetPosition();
    166 
    167         // Reject if it's not on-screen (e.g. it's behind the camera)
    168         if (!camera.GetFrustum().IsPointVisible(position))
    169             continue;
    170 
    171         // Compare screen-space coordinates
    172         float x, y;
    173         camera.GetScreenCoordinates(position, x, y);
    174         int ix = (int)x;
    175         int iy = (int)y;
    176         if (sx0 <= ix && ix <= sx1 && sy0 <= iy && iy <= sy1)
    177             hitEnts.push_back(ent);
     176        CComponentManager& componentManager = simulation.GetSimContext().GetComponentManager();
     177        std::vector<entity_id_t> ents = cmpRangeManager->GetEntitiesByPlayer(owner);
     178        for (std::vector<entity_id_t>::iterator it = ents.begin(); it != ents.end(); ++it)
     179        {
     180            if (CheckEntityVisibleAndInRect(componentManager.LookupEntityHandle(*it), cmpRangeManager, camera, sx0, sy0, sx1, sy1, owner, allowEditorSelectables))
     181                hitEnts.push_back(*it);
     182        }
     183    }
     184    else // owner == INVALID_PLAYER; Used when selecting units in Atlas or other mods that allow all kinds of selectables to be selected.
     185    {
     186        const CSimulation2::InterfaceListUnordered& selectableEnts = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
     187        for (CSimulation2::InterfaceListUnordered::const_iterator it = selectableEnts.begin(); it != selectableEnts.end(); ++it)
     188        {
     189            if (CheckEntityVisibleAndInRect(it->second->GetEntityHandle(), cmpRangeManager, camera, sx0, sy0, sx1, sy1, owner, allowEditorSelectables))
     190                hitEnts.push_back(it->first);
     191        }
    178192    }
    179193
    180194    return hitEnts;