Ticket #3410: corners-complete_v2.patch

File corners-complete_v2.patch, 27.0 KB (added by elexis, 9 years ago)

Rebased. Diff the patches too see that they are identical, except to the function that was removed in r17103.

  • source/simulation2/components/CCmpObstructionManager.cpp

    public:  
    465465    virtual bool TestStaticShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, std::vector<entity_id_t>* out);
    466466    virtual bool TestUnitShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, std::vector<entity_id_t>* out);
    467467
    468     virtual void Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate);
     468    virtual void Rasterize(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate);
    469469    virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares);
    470470    virtual void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter);
    471471
    private:  
    647647        return (m_WorldX0 <= p.X && p.X <= m_WorldX1 && m_WorldZ0 <= p.Y && p.Y <= m_WorldZ1);
    648648    }
    649649
    650     void RasterizeHelper(Grid<NavcellData>& grid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance = fixed::Zero());
     650    void RasterizeHelper(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance = fixed::Zero());
    651651};
    652652
    653653REGISTER_COMPONENT_TYPE(ObstructionManager)
    bool CCmpObstructionManager::TestUnitSha  
    826826        return false; // didn't collide, if we got this far
    827827}
    828828
    829 void CCmpObstructionManager::Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate)
     829void CCmpObstructionManager::Rasterize(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate)
    830830{
    831831    PROFILE3("Rasterize");
    832832
    void CCmpObstructionManager::Rasterize(G  
    836836    // Pass classes will get shapes rasterized on them depending on their Obstruction value.
    837837    // Classes with another value than "pathfinding" should not use Clearance.
    838838
    839     std::map<entity_pos_t, u16> pathfindingMasks;
    840     u16 foundationMask = 0;
     839    std::map<entity_pos_t, pass_class_t> pathfindingMasks;
     840    pass_class_t foundationMask = 0;
    841841    for (const PathfinderPassability& passability : passClasses)
    842842    {
    843843        switch (passability.m_Obstructions)
    void CCmpObstructionManager::Rasterize(G  
    863863    // so they should be the only ones rasterized using with the help of m_Dirty*Shapes vectors.
    864864
    865865    for (auto& maskPair : pathfindingMasks)
    866         RasterizeHelper(grid, FLAG_BLOCK_PATHFINDING, fullUpdate, maskPair.second, maskPair.first);
     866        RasterizeHelper(grid, cornerGrid, FLAG_BLOCK_PATHFINDING, fullUpdate, maskPair.second, maskPair.first);
    867867
    868     RasterizeHelper(grid, FLAG_BLOCK_FOUNDATION, fullUpdate, foundationMask);
     868    RasterizeHelper(grid, cornerGrid, FLAG_BLOCK_FOUNDATION, fullUpdate, foundationMask);
    869869
    870870    m_DirtyStaticShapes.clear();
    871871    m_DirtyUnitShapes.clear();
    872872}
    873873
    874 void CCmpObstructionManager::RasterizeHelper(Grid<NavcellData>& grid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance)
     874void CCmpObstructionManager::RasterizeHelper(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance)
    875875{
     876    ENSURE(grid.m_W == cornerGrid.m_W && grid.m_H == cornerGrid.m_H);
     877
    876878    for (auto& pair : m_StaticShapes)
    877879    {
    878880        const StaticShape& shape = pair.second;
    void CCmpObstructionManager::RasterizeHe  
    886888        ObstructionSquare square = { shape.x, shape.z, shape.u, shape.v, shape.hw, shape.hh };
    887889        SimRasterize::Spans spans;
    888890        SimRasterize::RasterizeRectWithClearance(spans, square, clearance, Pathfinding::NAVCELL_SIZE);
    889         for (SimRasterize::Span& span : spans)
     891        for (const SimRasterize::Span& span : spans)
    890892        {
    891893            i16 j = Clamp(span.j, (i16)0, (i16)(grid.m_H-1));
    892894            i16 i0 = std::max(span.i0, (i16)0);
    893895            i16 i1 = std::min(span.i1, (i16)grid.m_W);
    894896
    895897            for (i16 i = i0; i < i1; ++i)
    896                 grid.set(i, j, grid.get(i, j) | appliedMask);
     898                Pathfinding::CombinedGridsSet(grid, cornerGrid, i, j, span.corners[i-span.i0], appliedMask);
    897899        }
    898900    }
    899901
    void CCmpObstructionManager::RasterizeHe  
    913915        Pathfinding::NearestNavcell(center.X + r, center.Y + r, i1, j1, grid.m_W, grid.m_H);
    914916        for (u16 j = j0+1; j < j1; ++j)
    915917            for (u16 i = i0+1; i < i1; ++i)
    916                 grid.set(i, j, grid.get(i, j) | appliedMask);
     918                Pathfinding::CombinedGridsSet(grid, cornerGrid, i, j, Pathfinding::PassableCorner::NONE, appliedMask);
    917919    }
    918920}
    919921
    void CCmpObstructionManager::GetUnitsOnO  
    10111013        {
    10121014            if (j == span.j && span.i0 <= i && i < span.i1)
    10131015            {
    1014                 out.push_back(shape.entity);
    1015                 break;
     1016                if (span.corners[i-span.i0] == Pathfinding::PassableCorner::NONE)
     1017                {
     1018                    out.push_back(shape.entity);
     1019                    break;
     1020                }
    10161021            }
    10171022        }
    10181023    }
  • source/simulation2/components/CCmpPathfinder.cpp

    void CCmpPathfinder::Init(const CParamNo  
    5050    m_MapSize = 0;
    5151    m_Grid = NULL;
    5252    m_TerrainOnlyGrid = NULL;
     53    m_CornerGrid = NULL;
     54    m_TerrainOnlyCornerGrid = NULL;
    5355
    5456    m_ObstructionsDirty.Clean();
    5557    m_PreserveUpdateInformations = false;
    void CCmpPathfinder::Deinit()  
    107109
    108110    SAFE_DELETE(m_Grid);
    109111    SAFE_DELETE(m_TerrainOnlyGrid);
     112    SAFE_DELETE(m_CornerGrid);
     113    SAFE_DELETE(m_TerrainOnlyCornerGrid);
    110114}
    111115
    112116struct SerializeLongRequest
    const Grid<NavcellData>& CCmpPathfinder:  
    266270 * Euclidean distances; currently it effectively does dist=max(dx,dy) instead.
    267271 * This would only really be a problem for big clearances.
    268272 */
    269 static void ExpandImpassableCells(Grid<NavcellData>& grid, u16 clearance, pass_class_t mask)
     273static void ExpandImpassableCells(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, u16 clearance, pass_class_t mask)
    270274{
    271275    PROFILE3("ExpandImpassableCells");
    272276
    static void ExpandImpassableCells(Grid<N  
    314318        {
    315319            // Add the mask if blocked by at least one nearby cell
    316320            if (numBlocked)
    317                 grid.set(i, j, grid.get(i, j) | mask);
     321                Pathfinding::CombinedGridsSet(grid, cornerGrid, i, j, Pathfinding::PassableCorner::NONE, mask);
    318322
    319323            // Slide the numBlocked window along:
    320324            // remove the old j-clearance value, add the new (j+1)+clearance
    void CCmpPathfinder::UpdateGrid()  
    464468    {
    465469        SAFE_DELETE(m_Grid);
    466470        SAFE_DELETE(m_TerrainOnlyGrid);
     471        SAFE_DELETE(m_CornerGrid);
     472        SAFE_DELETE(m_TerrainOnlyCornerGrid);
    467473    }
    468474
    469475    // Initialise the terrain data when first needed
    void CCmpPathfinder::UpdateGrid()  
    472478        m_MapSize = terrainSize;
    473479        m_Grid = new Grid<NavcellData>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE);
    474480        m_TerrainOnlyGrid = new Grid<NavcellData>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE);
     481        m_CornerGrid = new Grid<CornerPassability>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE);
     482        m_TerrainOnlyCornerGrid = new Grid<CornerPassability>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE);
    475483
    476484        m_ObstructionsDirty.dirty = true;
    477485        m_ObstructionsDirty.globallyDirty = true;
    void CCmpPathfinder::UpdateGrid()  
    493501        TerrainUpdateHelper();
    494502
    495503        *m_Grid = *m_TerrainOnlyGrid;
     504        *m_CornerGrid = *m_TerrainOnlyCornerGrid;
    496505
    497506        m_TerrainDirty = false;
    498507        m_ObstructionsDirty.globalRecompute = true;
    void CCmpPathfinder::UpdateGrid()  
    503512        ENSURE(m_Grid->m_W == m_TerrainOnlyGrid->m_W && m_Grid->m_H == m_TerrainOnlyGrid->m_H);
    504513        memcpy(m_Grid->m_Data, m_TerrainOnlyGrid->m_Data, (m_Grid->m_W)*(m_Grid->m_H)*sizeof(NavcellData));
    505514
     515        ENSURE(m_CornerGrid->m_W == m_TerrainOnlyCornerGrid->m_W && m_CornerGrid->m_H == m_TerrainOnlyCornerGrid->m_H);
     516        memcpy(m_CornerGrid->m_Data, m_TerrainOnlyCornerGrid->m_Data, (m_CornerGrid->m_W)*(m_CornerGrid->m_H)*sizeof(CornerPassability));
     517
    506518        m_ObstructionsDirty.globallyDirty = true;
    507519    }
    508520    else
    509521    {
    510522        ENSURE(m_Grid->m_W == m_ObstructionsDirty.dirtinessGrid.m_W && m_Grid->m_H == m_ObstructionsDirty.dirtinessGrid.m_H);
     523        ENSURE(m_CornerGrid->m_W == m_ObstructionsDirty.dirtinessGrid.m_W && m_CornerGrid->m_H == m_ObstructionsDirty.dirtinessGrid.m_H);
    511524        ENSURE(m_Grid->m_W == m_TerrainOnlyGrid->m_W && m_Grid->m_H == m_TerrainOnlyGrid->m_H);
     525        ENSURE(m_CornerGrid->m_W == m_TerrainOnlyCornerGrid->m_W && m_CornerGrid->m_H == m_TerrainOnlyCornerGrid->m_H);
    512526
    513527        for (u16 i = 0; i < m_ObstructionsDirty.dirtinessGrid.m_W; ++i)
    514528            for (u16 j = 0; j < m_ObstructionsDirty.dirtinessGrid.m_H; ++j)
    515529                if (m_ObstructionsDirty.dirtinessGrid.get(i, j) == 1)
     530                {
    516531                    m_Grid->set(i, j, m_TerrainOnlyGrid->get(i, j));
     532                    m_CornerGrid->set(i, j, m_TerrainOnlyCornerGrid->get(i, j));
     533                }
    517534    }
    518535
    519536    // Add obstructions onto the grid
    520     cmpObstructionManager->Rasterize(*m_Grid, m_PassClasses, m_ObstructionsDirty.globalRecompute);
     537    cmpObstructionManager->Rasterize(*m_Grid, *m_CornerGrid, m_PassClasses, m_ObstructionsDirty.globalRecompute);
    521538
    522539    // Update the long-range pathfinder
    523540    if (m_ObstructionsDirty.globallyDirty)
    524541    {
    525542        std::map<std::string, pass_class_t> nonPathfindingPassClasses, pathfindingPassClasses;
    526543        GetPassabilityClasses(nonPathfindingPassClasses, pathfindingPassClasses);
    527         m_LongPathfinder.Reload(m_Grid, nonPathfindingPassClasses, pathfindingPassClasses);
     544        m_LongPathfinder.Reload(m_Grid, nonPathfindingPassClasses, pathfindingPassClasses, m_CornerGrid);
    528545    }
    529546    else
    530         m_LongPathfinder.Update(m_Grid, m_ObstructionsDirty.dirtinessGrid);
     547        m_LongPathfinder.Update(m_Grid, m_ObstructionsDirty.dirtinessGrid, m_CornerGrid);
    531548
    532549    // Notify the units that their current paths can be invalid now.
    533550    // The passability map will be globally dirty after init, or rejoining, loading a saved game, etc.
    void CCmpPathfinder::TerrainUpdateHelper  
    565582        m_MapSize = terrainSize;
    566583
    567584        SAFE_DELETE(m_TerrainOnlyGrid);
     585        SAFE_DELETE(m_TerrainOnlyCornerGrid);
    568586        m_TerrainOnlyGrid = new Grid<NavcellData>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE);
     587        m_TerrainOnlyCornerGrid = new Grid<CornerPassability>(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE);
    569588    }
    570589
    571590    Grid<u16> shoreGrid = ComputeShoreGrid();
    void CCmpPathfinder::TerrainUpdateHelper  
    601620
    602621            // Compute the passability for every class for this cell
    603622            NavcellData t = 0;
     623            CornerPassability c = 0;
    604624            for (PathfinderPassability& passability : m_PassClasses)
     625            {
    605626                if (!passability.IsPassable(depth, slope, shoredist))
     627                {
     628                    Pathfinding::SetPassableCornerBits(c, Pathfinding::PassableCorner::NONE, passability.m_Mask);
    606629                    t |= passability.m_Mask;
     630                }
     631            }
    607632
    608633            m_TerrainOnlyGrid->set(i, j, t);
     634            m_TerrainOnlyCornerGrid->set(i, j, c);
    609635        }
    610636    }
    611637
    void CCmpPathfinder::TerrainUpdateHelper  
    636662                    + (j*2 + 1 - h)*(j*2 + 1 - h);
    637663
    638664                if (dist2 >= (w - 2*edgeSize) * (h - 2*edgeSize))
    639                     m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) | edgeMask);
     665                    Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask);
    640666            }
    641667        }
    642668    }
    void CCmpPathfinder::TerrainUpdateHelper  
    644670    {
    645671        for (u16 j = 0; j < h; ++j)
    646672            for (u16 i = 0; i < edgeSize; ++i)
    647                 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) | edgeMask);
     673                Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask);
    648674        for (u16 j = 0; j < h; ++j)
    649675            for (u16 i = w-edgeSize+1; i < w; ++i)
    650                 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) | edgeMask);
     676                Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask);
    651677        for (u16 j = 0; j < edgeSize; ++j)
    652678            for (u16 i = edgeSize; i < w-edgeSize+1; ++i)
    653                 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) | edgeMask);
     679                Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask);
    654680        for (u16 j = h-edgeSize+1; j < h; ++j)
    655681            for (u16 i = edgeSize; i < w-edgeSize+1; ++i)
    656                 m_TerrainOnlyGrid->set(i, j, m_TerrainOnlyGrid->get(i, j) | edgeMask);
     682                Pathfinding::CombinedGridsSet(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, i, j, Pathfinding::PassableCorner::NONE, edgeMask);
    657683    }
    658684
    659685    if (!expandPassability)
    void CCmpPathfinder::TerrainUpdateHelper  
    670696            continue;
    671697
    672698        int clearance = (passability.m_Clearance / Pathfinding::NAVCELL_SIZE).ToInt_RoundToInfinity();
    673         ExpandImpassableCells(*m_TerrainOnlyGrid, clearance, passability.m_Mask);
     699        ExpandImpassableCells(*m_TerrainOnlyGrid, *m_TerrainOnlyCornerGrid, clearance, passability.m_Mask);
    674700    }
    675701}
    676702
  • source/simulation2/components/CCmpPathfinder_Common.h

    public:  
    108108    u16 m_MapSize; // tiles per side
    109109    Grid<NavcellData>* m_Grid; // terrain/passability information
    110110    Grid<NavcellData>* m_TerrainOnlyGrid; // same as m_Grid, but only with terrain, to avoid some recomputations
     111    Grid<CornerPassability>* m_CornerGrid; // corner terrain/passability information
     112    Grid<CornerPassability>* m_TerrainOnlyCornerGrid; // same as m_CornerGrid, but only with terrain, to avoid some recomputations
    111113
    112114    // Update data, used for clever updates and then stored for the AI manager
    113115    GridUpdateInformation m_ObstructionsDirty;
  • source/simulation2/components/ICmpObstructionManager.h

    public:  
    205205
    206206    /**
    207207     * Convert the current set of shapes onto a navcell grid, for all passability classes contained in @p passClasses.
     208     * Also computes the corner passabilities for each of those navcells.
    208209     * If @p fullUpdate is false, the function will only go through dirty shapes.
    209210     * Shapes are expanded by the @p passClasses clearances, by ORing their masks onto the @p grid.
    210211     */
    211     virtual void Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate) = 0;
     212    virtual void Rasterize(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate) = 0;
    212213
    213214    /**
    214215     * Gets dirtiness information and resets it afterwards. Then it's the role of CCmpPathfinder
  • source/simulation2/helpers/LongPathfinder.cpp

    void LongPathfinder::ComputeJPSPath(enti  
    965965    {
    966966        PathfindTile& n = state.tiles->get(ip, jp);
    967967        entity_pos_t x, z;
    968         Pathfinding::NavcellCenter(ip, jp, x, z);
     968        GetPassablePoint(ip, jp, x, z, passClass);
    969969        path.m_Waypoints.emplace_back(Waypoint{ x, z });
    970970
    971971        // Follow the predecessor link
    972972        ip = n.GetPredI(ip);
    973973        jp = n.GetPredJ(jp);
    974974    }
    975     // The last waypoint is slightly incorrect (it's not the goal but the center
    976     // of the navcell of the goal), so replace it
     975    // The last waypoint is slightly incorrect, we have to replace it by the goal position
    977976    if (!path.m_Waypoints.empty())
    978977        path.m_Waypoints.front() = { state.goal.x, state.goal.z };
    979978
    void LongPathfinder::ComputeJPSPath(enti  
    986985    m_DebugGoal = state.goal;
    987986}
    988987
     988void LongPathfinder::GetPassablePoint(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z, pass_class_t passClass) const
     989{
     990    if (m_CornerGrid)
     991        Pathfinding::NavcellCorner(i, j, x, z, Pathfinding::GetPassableCorner(m_CornerGrid->get(i, j), passClass));
     992    else
     993        Pathfinding::NavcellCenter(i, j, x, z);
     994}
     995
    989996void LongPathfinder::ImprovePathWaypoints(WaypointPath& path, pass_class_t passClass, entity_pos_t maxDist, entity_pos_t x0, entity_pos_t z0)
    990997{
    991998    if (path.m_Waypoints.empty())
  • source/simulation2/helpers/LongPathfinder.h

    public:  
    185185
    186186    void Reload(Grid<NavcellData>* passabilityGrid,
    187187        const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks,
    188         const std::map<std::string, pass_class_t>& pathfindingPassClassMasks)
     188        const std::map<std::string, pass_class_t>& pathfindingPassClassMasks,
     189        Grid<CornerPassability>* cornerGrid = NULL)
    189190    {
    190191        m_Grid = passabilityGrid;
     192
     193        if (cornerGrid)
     194        {
     195            ASSERT(passabilityGrid->m_W == cornerGrid->m_W && passabilityGrid.m_H == cornerGrid.m_H);
     196            m_CornerGrid = cornerGrid;
     197        }
     198
    191199        ASSERT(passabilityGrid->m_H == passabilityGrid->m_W);
    192200        m_GridSize = passabilityGrid->m_W;
    193201
    public:  
    196204        m_PathfinderHier.Recompute(passabilityGrid, nonPathfindingPassClassMasks, pathfindingPassClassMasks);
    197205    }
    198206
    199     void Update(Grid<NavcellData>* passabilityGrid, const Grid<u8>& dirtinessGrid)
     207    void Update(Grid<NavcellData>* passabilityGrid, const Grid<u8>& dirtinessGrid, Grid<CornerPassability>* cornerGrid = NULL)
    200208    {
    201209        m_Grid = passabilityGrid;
     210       
     211        if (cornerGrid)
     212        {
     213            ASSERT(passabilityGrid->m_W == cornerGrid->m_W && passabilityGrid.m_H == cornerGrid.m_H);
     214            m_CornerGrid = cornerGrid;
     215        }
     216
    202217        ASSERT(passabilityGrid->m_H == passabilityGrid->m_W);
    203218        ASSERT(m_GridSize == passabilityGrid->m_H);
    204219
    public:  
    250265    }
    251266
    252267    Grid<NavcellData>* m_Grid;
     268    Grid<CornerPassability>* m_CornerGrid;
    253269    u16 m_GridSize;
    254270
    255271    // Debugging - output from last pathfind operation:
    private:  
    285301    // Helper functions for ComputePath
    286302
    287303    /**
     304     * Use the corner grid, if any, to determine a passable point of the cell.
     305     */
     306    void GetPassablePoint(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z, pass_class_t passClass) const;
     307
     308    /**
    288309     * Given a path with an arbitrary collection of waypoints, updates the
    289310     * waypoints to be nicer. Calls "Testline" between waypoints
    290311     * so that bended paths can become straight if there's nothing in between
  • source/simulation2/helpers/Pathfinding.h

    typedef u16 NavcellData; // 1 bit per pa  
    102102#define PASS_CLASS_MASK_FROM_INDEX(id) ((pass_class_t)(1u << id))
    103103#define SPECIAL_PASS_CLASS PASS_CLASS_MASK_FROM_INDEX((PASS_CLASS_BITS-1)) // 16th bit, used for special in-place computations
    104104
     105typedef u64 CornerPassability; // 3 bits (see Pathfinding::PassableCorner) per passability class (up to PASS_CLASS_BITS)
     106
    105107namespace Pathfinding
    106108{
    107109    /**
    namespace Pathfinding  
    245247                j += dj;
    246248        }
    247249    }
     250
     251    /**
     252     * Corner passability values for a given passability class. Takes 3 bits.
     253     *
     254     * A cell can be passable but with an obstruction crossing it, so we
     255     * have to determine one of the corners that is actually accessible.
     256     */
     257    enum PassableCorner
     258    {
     259        ALL = 0x0,
     260        NONE = 0x1,
     261        TOP_LEFT = 0x2,
     262        TOP_RIGHT = 0x3,
     263        BOTTOM_LEFT = 0x4,
     264        BOTTOM_RIGHT = 0x5
     265    };
     266
     267    inline void NavcellCorner(u16 i, u16 j, entity_pos_t& x, entity_pos_t& z, const PassableCorner& corner)
     268    {
     269        switch (corner)
     270        {
     271        case Pathfinding::ALL:
     272        case Pathfinding::NONE: // this could happen when leaving an impassable
     273            NavcellCenter(i, j, x, z);
     274            return;
     275        case Pathfinding::TOP_LEFT:
     276            x = entity_pos_t::FromInt(i).Multiply(NAVCELL_SIZE);
     277            z = entity_pos_t::FromInt(j).Multiply(NAVCELL_SIZE);
     278            return;
     279        case Pathfinding::TOP_RIGHT:
     280            x = entity_pos_t::FromInt(i+1).Multiply(NAVCELL_SIZE);
     281            z = entity_pos_t::FromInt(j).Multiply(NAVCELL_SIZE);
     282            return;
     283        case Pathfinding::BOTTOM_LEFT:
     284            x = entity_pos_t::FromInt(i).Multiply(NAVCELL_SIZE);
     285            z = entity_pos_t::FromInt(j+1).Multiply(NAVCELL_SIZE);
     286            return;
     287        case Pathfinding::BOTTOM_RIGHT:
     288            x = entity_pos_t::FromInt(i+1).Multiply(NAVCELL_SIZE);
     289            z = entity_pos_t::FromInt(j+1).Multiply(NAVCELL_SIZE);
     290            return;
     291        default:
     292            LOGWARNING("Unknown corner passability");
     293            return;
     294        }
     295    }
     296
     297    inline PassableCorner GetPassableCorner(const CornerPassability& cornerPassability, pass_class_t passClass)
     298    {
     299        // Determine the bit position in the mask
     300        ENSURE(passClass);
     301        int i = 0;
     302        while (!(passClass & (1u << i)))
     303            ++i;
     304
     305        PassableCorner ret = static_cast<PassableCorner>((cornerPassability >> 3*i) & 0x7);
     306        return ret;
     307    }
     308
     309    inline void SetPassableCornerBits(CornerPassability& cornerPassability, const PassableCorner& passableCorner, pass_class_t mask)
     310    {
     311        // This function will be called by Rasterize so it has to support incremental overwritings:
     312        // - ALL can only overwrite ALL (so it doesn't do anything)
     313        // - single corner values can overwrite single corner values (consistent with the rasterization code) and ALL
     314        // - NONE can overwrite anything
     315
     316        if (passableCorner == PassableCorner::ALL)
     317            return; // nothing to actually do
     318
     319        for (int i = 0; i < PASS_CLASS_BITS; ++i)
     320        {
     321            if (!(mask & (0x1 << i)))
     322                continue;
     323
     324            PassableCorner oldValue = static_cast<PassableCorner>((cornerPassability >> 3*i) & 0x7);
     325            if (passableCorner != PassableCorner::NONE && oldValue == PassableCorner::NONE)
     326                continue; // can't overwrite
     327
     328            cornerPassability &= (~(0x7 << 3*i)); // erase
     329            cornerPassability |= passableCorner << 3*i;
     330        }
     331    }
     332
     333    // Apply @p mask onto both grids in adapted ways.
     334    inline void CombinedGridsSet(Grid<NavcellData>& grid, Grid<CornerPassability>& cornerGrid, int i, int j, const PassableCorner& cornerValue, pass_class_t mask)
     335    {
     336        if (cornerValue == PassableCorner::NONE)
     337            grid.set(i, j, grid.get(i, j) | mask);
     338
     339        CornerPassability cornerPassability = cornerGrid.get(i, j);
     340        Pathfinding::SetPassableCornerBits(cornerPassability, cornerValue, mask);
     341        cornerGrid.set(i, j, cornerPassability);
     342    }
    248343}
    249344
    250345/*
  • source/simulation2/helpers/Rasterize.cpp

    void SimRasterize::RasterizeRectWithClea  
    4141
    4242    for (i16 j = j0; j < j1; ++j)
    4343    {
    44         // Find the min/max range of cells that are strictly inside the square+clearance.
    45         // (Since the square+clearance is a convex shape, we can just test each
    46         // corner of each cell is inside the shape.)
    47         // (TODO: This potentially does a lot of redundant work.)
     44        // Find the min/max range of cells that are inside the square+clearance.
     45        // Since the square+clearance is a convex shape, we can just rely on corners for everything.
     46
     47        std::vector<Pathfinding::PassableCorner> corners;
     48        corners.reserve(i1 - i0);
     49
     50        bool foundTouchingCell = false;
    4851        i16 spanI0 = std::numeric_limits<i16>::max();
    4952        i16 spanI1 = std::numeric_limits<i16>::min();
    5053        for (i16 i = i0; i < i1; ++i)
    5154        {
     55            Pathfinding::PassableCorner corner = Pathfinding::PassableCorner::NONE;
     56            int cornerCount = 0;
     57
    5258            if (Geometry::DistanceToSquare(
    5359                CFixedVector2D(cellSize*i, cellSize*j) - CFixedVector2D(shape.x, shape.z),
    5460                shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh), true) > clearance)
    5561            {
    56                 continue;
     62                corner = Pathfinding::PassableCorner::TOP_LEFT;
     63                ++cornerCount;
    5764            }
    5865
    5966            if (Geometry::DistanceToSquare(
    6067                CFixedVector2D(cellSize*(i+1), cellSize*j) - CFixedVector2D(shape.x, shape.z),
    6168                shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh), true) > clearance)
    6269            {
    63                 continue;
     70                corner = Pathfinding::PassableCorner::TOP_RIGHT;
     71                ++cornerCount;
    6472            }
    6573
    6674            if (Geometry::DistanceToSquare(
    6775                CFixedVector2D(cellSize*i, cellSize*(j+1)) - CFixedVector2D(shape.x, shape.z),
    6876                shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh), true) > clearance)
    6977            {
    70                 continue;
     78                corner = Pathfinding::PassableCorner::BOTTOM_LEFT;
     79                ++cornerCount;
    7180            }
    7281
    7382            if (Geometry::DistanceToSquare(
    7483                CFixedVector2D(cellSize*(i+1), cellSize*(j+1)) - CFixedVector2D(shape.x, shape.z),
    7584                shape.u, shape.v, CFixedVector2D(shape.hw, shape.hh), true) > clearance)
    7685            {
    77                 continue;
     86                corner = Pathfinding::PassableCorner::BOTTOM_RIGHT;
     87                ++cornerCount;
    7888            }
    7989
    80             spanI0 = std::min(spanI0, i);
    81             spanI1 = std::max(spanI1, (i16)(i+1));
     90            if (cornerCount == 4)
     91                corner = Pathfinding::PassableCorner::ALL;
     92
     93            if (!foundTouchingCell)
     94            {
     95                if (corner == Pathfinding::PassableCorner::ALL)
     96                    continue;
     97
     98                foundTouchingCell = true;
     99                spanI0 = i;
     100                spanI1 = i+1;
     101                corners.push_back(corner);
     102            }
     103            else
     104            {
     105                spanI1 = i+1;
     106                corners.push_back(corner);
     107            }
    82108        }
    83109
    84110        // Add non-empty spans onto the list
    85         if (spanI0 < spanI1)
     111        if (foundTouchingCell)
    86112        {
    87             Span span = { spanI0, spanI1, j };
    88             spans.push_back(span);
     113            ENSURE(spanI0 < spanI1 && corners.size() == (size_t)(spanI1-spanI0));
     114            spans.emplace_back(Span{ spanI0, spanI1, j, corners });
    89115        }
    90116    }
    91117}
  • source/simulation2/helpers/Rasterize.h

     
    1 /* Copyright (C) 2012 Wildfire Games.
     1/* Copyright (C) 2015 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    namespace SimRasterize  
    2929{
    3030
    3131/**
    32  * Represents the set of cells (i,j) where i0 <= i < i1
     32 * Represents the set of cells (i,j) where i0 <= i < i1.
     33 * The corner passability of the cell (i0+k,j) is corners[k].
    3334 */
    3435struct Span
    3536{
    3637    i16 i0;
    3738    i16 i1;
    3839    i16 j;
     40    std::vector<Pathfinding::PassableCorner> corners;
    3941};
    4042
    4143typedef std::vector<Span> Spans;
    typedef std::vector<Span> Spans;  
    4345/**
    4446 * Converts an ObstructionSquare @p shape (a rotated rectangle),
    4547 * expanded by the given @p clearance,
    46  * into a list of spans of cells that are strictly inside the shape.
     48 * into a list of spans of cells that are at least partially inside the shape.
     49 * The caller must check corner passability values for each cell inside a span
     50 * to determine whether they are strictly inside the shape.
    4751 */
    4852void RasterizeRectWithClearance(Spans& spans,
    4953    const ICmpObstructionManager::ObstructionSquare& shape,